Uncommented beaudio code
[pwlib.git] / src / ptlib / unix / qsa.cxx
blobde186ab917e61abeef60a7f5018fa81790ea4d86
1 /*
2 * qsa.cxx
4 * QNX Sound Architecture
5 */
7 #pragma implementation "sound.h"
9 #include <ptlib.h>
10 #include <stdio.h>
11 #include <sys/asoundlib.h>
13 typedef struct _SoundHandleEntry {
14 struct _SoundHandleEntry *next;
16 int handle;
17 int direction;
19 unsigned numChannels;
20 unsigned sampleRate;
21 unsigned bitsPerSample;
22 unsigned fragmentValue;
23 BOOL isInitialised;
25 snd_pcm_t *pcm_handle;
26 int card;
27 int dev;
28 snd_mixer_t *mixer_handle;
29 snd_mixer_group_t group;
30 } SoundHandleEntry;
32 static SoundHandleEntry *SoundHandleList;
33 static pthread_rwlock_t SoundHandleLock = PTHREAD_RWLOCK_INITIALIZER;
35 static int snd_openmode[2] = {SND_PCM_OPEN_CAPTURE, SND_PCM_OPEN_PLAYBACK};
36 static int snd_chnmode[2] = {SND_PCM_CHANNEL_CAPTURE, SND_PCM_CHANNEL_PLAYBACK};
38 PSound::PSound(unsigned channels,
39 unsigned samplesPerSecond,
40 unsigned bitsPerSample,
41 PINDEX bufferSize,
42 const BYTE * buffer)
44 encoding = 0;
45 numChannels = channels;
46 sampleRate = samplesPerSecond;
47 sampleSize = bitsPerSample;
48 SetSize(bufferSize);
49 if (buffer != NULL)
50 memcpy(GetPointer(), buffer, bufferSize);
54 PSound::PSound(const PFilePath & filename)
56 encoding = 0;
57 numChannels = 1;
58 sampleRate = 8000;
59 sampleSize = 16;
60 Load(filename);
64 PSound & PSound::operator=(const PBYTEArray & data)
66 PBYTEArray::operator=(data);
67 return *this;
71 void PSound::SetFormat(unsigned channels,
72 unsigned samplesPerSecond,
73 unsigned bitsPerSample)
75 encoding = 0;
76 numChannels = channels;
77 sampleRate = samplesPerSecond;
78 sampleSize = bitsPerSample;
79 formatInfo.SetSize(0);
83 BOOL PSound::Load(const PFilePath & /*filename*/)
85 return FALSE;
89 BOOL PSound::Save(const PFilePath & /*filename*/)
91 return FALSE;
95 BOOL PSound::Play()
97 PSoundChannel channel(PSoundChannel::GetDefaultDevice(PSoundChannel::Player),
98 PSoundChannel::Player);
99 if (!channel.IsOpen())
100 return FALSE;
102 return channel.PlaySound(*this, TRUE);
106 BOOL PSound::PlayFile(const PFilePath & file, BOOL wait)
108 PSoundChannel channel(PSoundChannel::GetDefaultDevice(PSoundChannel::Player),
109 PSoundChannel::Player);
110 if (!channel.IsOpen())
111 return FALSE;
113 return channel.PlayFile(file, wait);
117 PSoundChannel::PSoundChannel()
119 Construct();
123 PSoundChannel::PSoundChannel(const PString & device,
124 Directions dir,
125 unsigned numChannels,
126 unsigned sampleRate,
127 unsigned bitsPerSample)
129 Construct();
130 Open(device, dir, numChannels, sampleRate, bitsPerSample);
134 void PSoundChannel::Construct()
136 os_handle = -1;
140 PSoundChannel::~PSoundChannel()
142 Close();
146 PStringArray PSoundChannel::GetDeviceNames(Directions dir)
148 PStringList devices;
149 PDirectory devdir = "/dev/snd";
151 if (!devdir.Open())
152 return NULL;
154 do {
155 PString filename = devdir.GetEntryName();
156 PString devname = devdir + filename;
158 if ((filename.GetLength() > 3) && (filename.Left(3) == "pcm") &&
159 (filename.Right(1) == (dir == Recorder ? "r" : "p")))
161 int fd = ::open(filename, O_RDONLY);
162 if (fd >= 0) {
163 devices.AppendString(filename);
164 ::close(fd);
167 } while (devdir.Next());
168 return devices;
172 PString PSoundChannel::GetDefaultDevice(Directions dir)
174 PString filename;
176 if (dir == Player)
177 filename = "/dev/snd/pcmPreferredp";
178 else
179 filename = "/dev/snd/pcmPreferredc";
181 int fd = ::open(filename, O_RDONLY);
182 // PTRACE(1, "GetDefaultDevice; fd = " << fd << ", filename ='" << filename <<"'\n");
183 if (fd >=0) {
184 ::close (fd);
185 return filename;
186 } else {
187 return (filename = "/dev/null");
192 BOOL PSoundChannel::Open(const PString & _device,
193 Directions _dir,
194 unsigned _numChannels,
195 unsigned _sampleRate,
196 unsigned _bitsPerSample)
198 Close();
200 // make the direction value 1 or 2
201 int dir = _dir + 1;
203 SoundHandleEntry *entry;
205 pthread_rwlock_wrlock(&SoundHandleLock);
206 for (entry = SoundHandleList; entry && entry->handle != os_handle; entry = entry->next);
208 if (entry) {
210 PTRACE(6, "OSS\tOpen occured for existing entry");
212 // see if the sound channel is already open in this direction
213 if ((entry->direction & dir) != 0) {
214 pthread_rwlock_unlock(&SoundHandleLock);
215 return FALSE;
218 // flag this entry as open in this direction
219 entry->direction |= dir;
220 os_handle = entry->handle;
221 } else {
223 PTRACE(6, "OSS\tOpen occured for new entry");
225 SoundHandleEntry *entry = (SoundHandleEntry *)::malloc(sizeof(*entry));
227 if (!entry) {
228 pthread_rwlock_unlock(&SoundHandleLock);
229 return FALSE;
232 // this is the first time this device has been used
233 // open the device in read/write mode always
234 if (((_dir == Player) && _device == "/dev/snd/pcmPreferredp") ||
235 ((_dir == Recorder) && _device == "/dev/snd/pcmPreferredc"))
237 os_handle = snd_pcm_open_preferred(&entry->pcm_handle, &entry->card, &entry->dev, snd_openmode[_dir]);
238 } else {
239 if (sscanf(_device, "/dev/snd/pcmC%iD%i", &entry->card, &entry->dev) != 2) {
240 errno = ESRCH;
241 return ConvertOSError(os_handle);
243 os_handle = snd_pcm_open(&entry->pcm_handle, entry->card, entry->dev, snd_openmode[_dir]);
246 if (os_handle < 0) {
247 errno = -os_handle;
248 os_handle = 0;
249 return ConvertOSError(os_handle);
252 if (snd_pcm_plugin_set_disable(entry->pcm_handle, PLUGIN_DISABLE_MMAP) < 0)
253 return FALSE;
255 // save the information into the dictionary entry
256 os_handle = snd_pcm_file_descriptor(entry->pcm_handle, snd_chnmode[_dir]);
257 entry->handle = os_handle;
258 entry->direction = dir;
259 entry->numChannels = mNumChannels = _numChannels;
260 entry->sampleRate = actualSampleRate = mSampleRate = _sampleRate;
261 entry->bitsPerSample = mBitsPerSample = _bitsPerSample;
262 entry->isInitialised = FALSE;
263 entry->fragmentValue = 0x7fff0008;
264 entry->mixer_handle = 0;
266 entry->next = SoundHandleList;
267 SoundHandleList = entry;
269 pthread_rwlock_unlock(&SoundHandleLock);
271 // save the direction and device
272 direction = _dir;
273 device = _device;
274 isInitialised = FALSE;
276 return TRUE;
279 BOOL PSoundChannel::Setup()
281 if (os_handle < 0) {
282 PTRACE(6, "OSS\tSkipping setup of " << device << " as not open");
283 return FALSE;
286 if (isInitialised) {
287 PTRACE(6, "OSS\tSkipping setup of " << device << " as instance already initialised");
288 return TRUE;
291 SoundHandleEntry *entry;
292 pthread_rwlock_rdlock(&SoundHandleLock);
293 for (entry = SoundHandleList; entry && entry->handle != os_handle;
294 entry = entry->next);
296 // set default return status
297 BOOL stat = TRUE;
299 // do not re-initialise initialised devices
300 if (entry->isInitialised) {
301 pthread_rwlock_unlock(&SoundHandleLock);
302 PTRACE(6, "OSS\tSkipping setup for " << device << " as already initialised");
303 return stat;
306 PTRACE(6, "OSS\tInitialising " << device << "(" << (void *)(&entry) << ")");
308 stat = FALSE;
310 mBitsPerSample = entry->bitsPerSample;
311 mNumChannels = entry->numChannels;
312 mSampleRate = entry->sampleRate;
314 snd_pcm_channel_params_t pp;
316 memset(&pp, 0, sizeof(pp));
317 pp.channel = snd_chnmode[direction];
318 pp.mode = SND_PCM_MODE_BLOCK;
319 pp.start_mode = (direction == Player) ? SND_PCM_START_FULL : SND_PCM_START_DATA;
320 pp.stop_mode = SND_PCM_STOP_STOP;
321 pp.buf.block.frags_min = 1;
322 pp.buf.block.frag_size = 1 << (entry->fragmentValue & 0xffff);
323 pp.buf.block.frags_max = ((unsigned)entry->fragmentValue >> 16) & 0x7fff;
324 if (pp.buf.block.frags_max == 0)
325 pp.buf.block.frags_max = 65536;
327 pp.format.interleave = 1;
328 pp.format.rate = entry->sampleRate;
329 pp.format.voices = entry->numChannels;
331 #if PBYTE_ORDER == PLITTLE_ENDIAN
332 pp.format.format = (entry->bitsPerSample == 16) ? SND_PCM_SFMT_S16_LE : SND_PCM_SFMT_U8;
333 #else
334 pp.format.format = (entry->bitsPerSample == 16) ? SND_PCM_SFMT_S16_BE : SND_PCM_SFMT_U8;
335 #endif
337 if (snd_pcm_plugin_params(entry->pcm_handle, &pp) < 0) {
338 pthread_rwlock_unlock(&SoundHandleLock);
339 return stat;
342 if (snd_pcm_plugin_prepare(entry->pcm_handle, snd_chnmode[direction]) < 0) {
343 pthread_rwlock_unlock(&SoundHandleLock);
344 return stat;
347 /* also open the mixer */
348 snd_pcm_channel_setup_t setup;
350 memset(&setup, 0, sizeof(setup));
351 memset(&entry->group, 0, sizeof(entry->group));
352 setup.channel = snd_chnmode[direction];
353 setup.mixer_gid = &entry->group.gid;
355 if (snd_pcm_plugin_setup(entry->pcm_handle, &setup) < 0) {
356 pthread_rwlock_unlock(&SoundHandleLock);
357 return FALSE;
360 if (snd_mixer_open(&entry->mixer_handle, entry->card, setup.mixer_device) < 0) {
361 pthread_rwlock_unlock(&SoundHandleLock);
362 return FALSE;
365 actualSampleRate = setup.format.rate;
366 stat = TRUE;
368 #if PTRACING
369 PTRACE(4, "QSA: Frag Size = " << setup.buf.block.frag_size
370 << ", Rate = " << setup.format.rate
371 << ", Mixer Pcm Group [" << entry->group.gid.name << "]\n");
372 #endif
374 pthread_rwlock_unlock(&SoundHandleLock);
375 // ensure device is marked as initialised
376 isInitialised = TRUE;
377 entry->isInitialised = TRUE;
379 return stat;
382 BOOL PSoundChannel::Close()
384 // if the channel isn't open, do nothing
385 if (os_handle < 0)
386 return TRUE;
388 SoundHandleEntry *entry, **entryp;
390 pthread_rwlock_wrlock(&SoundHandleLock);
391 for (entryp = &SoundHandleList, entry = *entryp; entry && entry->handle != os_handle;
392 entryp = &entry->next, entry = *entryp);
394 if (!entry) {
395 pthread_rwlock_unlock(&SoundHandleLock);
396 return TRUE;
399 // modify the directions bit mask in the dictionary
400 entry->direction ^= (direction+1);
402 // if this is the last usage of this entry, then remove it
403 if (entry->direction == 0) {
404 snd_mixer_close(entry->mixer_handle);
405 snd_pcm_plugin_flush(entry->pcm_handle, snd_chnmode[direction]);
406 snd_pcm_close(entry->pcm_handle);
407 *entryp = entry->next;
408 ::free(entry);
409 os_handle = -1;
410 pthread_rwlock_unlock(&SoundHandleLock);
411 return PChannel::Close();
414 // flag this channel as closed
415 pthread_rwlock_unlock(&SoundHandleLock);
416 return TRUE;
419 BOOL PSoundChannel::Write(const void * buf, PINDEX len)
421 if (!Setup())
422 return FALSE;
424 if (os_handle < 0)
425 return FALSE;
427 SoundHandleEntry * entry;
428 pthread_rwlock_rdlock(&SoundHandleLock);
429 for (entry = SoundHandleList; entry && entry->handle != os_handle;
430 entry = entry->next);
432 snd_pcm_channel_status_t status;
433 int written = 0;
435 while ((written += snd_pcm_plugin_write(entry->pcm_handle, buf, len)) < len)
437 memset(&status, 0, sizeof(status));
438 status.channel = SND_PCM_CHANNEL_PLAYBACK;
439 if (snd_pcm_plugin_status(entry->pcm_handle, &status) < 0) {
440 pthread_rwlock_unlock(&SoundHandleLock);
441 return FALSE;
443 if (status.status == SND_PCM_STATUS_READY ||
444 status.status == SND_PCM_STATUS_UNDERRUN)
446 if (snd_pcm_plugin_prepare(entry->pcm_handle, snd_chnmode[direction]) < 0) {
447 pthread_rwlock_unlock(&SoundHandleLock);
448 return FALSE;
451 if (written < 0)
452 written = 0;
454 pthread_rwlock_unlock(&SoundHandleLock);
455 return TRUE;
458 BOOL PSoundChannel::Read(void * buf, PINDEX len)
460 lastReadCount = 0;
462 if (!Setup())
463 return FALSE;
465 if (os_handle < 0)
466 return FALSE;
468 SoundHandleEntry * entry;
469 pthread_rwlock_rdlock(&SoundHandleLock);
470 for (entry = SoundHandleList; entry && entry->handle != os_handle;
471 entry = entry->next);
473 PTRACE(6, "QSA\tRead start");
475 lastReadCount = snd_pcm_plugin_read(entry->pcm_handle, buf, len);
477 if (lastReadCount < len) {
478 snd_pcm_channel_status_t status;
480 memset(&status, 0, sizeof(status));
481 status.channel = SND_PCM_CHANNEL_CAPTURE;
482 if (snd_pcm_plugin_status(entry->pcm_handle, &status) < 0) {
483 pthread_rwlock_unlock(&SoundHandleLock);
484 PTRACE(6, "QSA\tRead failed");
485 return FALSE;
488 if (status.status == SND_PCM_STATUS_READY ||
489 status.status == SND_PCM_STATUS_OVERRUN) {
490 if (snd_pcm_plugin_prepare(entry->pcm_handle, SND_PCM_CHANNEL_CAPTURE) < 0) {
491 pthread_rwlock_unlock(&SoundHandleLock);
492 PTRACE(6, "QSA\tRead failed");
493 return FALSE;
496 PTRACE(6, "QSA\tRead completed short - " << lastReadCount << " vs " << len);
497 } else {
498 PTRACE(6, "QSA\tRead completed");
500 pthread_rwlock_unlock(&SoundHandleLock);
501 return TRUE;
504 BOOL PSoundChannel::SetFormat(unsigned numChannels,
505 unsigned sampleRate,
506 unsigned bitsPerSample)
508 if (os_handle < 0)
509 return SetErrorValues(NotOpen, EBADF);
511 // check parameters
512 PAssert((bitsPerSample == 8) || (bitsPerSample == 16), PInvalidParameter);
513 PAssert(numChannels >= 1 && numChannels <= 2, PInvalidParameter);
515 SoundHandleEntry * entry;
516 pthread_rwlock_rdlock(&SoundHandleLock);
517 for (entry = SoundHandleList; entry && entry->handle != os_handle;
518 entry = entry->next);
520 if (entry->isInitialised) {
521 if ((numChannels != entry->numChannels) ||
522 (sampleRate != entry->sampleRate) ||
523 (bitsPerSample != entry->bitsPerSample)) {
524 pthread_rwlock_unlock(&SoundHandleLock);
525 PTRACE(6, "OSS\tTried to change read/write format without stopping");
526 return FALSE;
528 pthread_rwlock_unlock(&SoundHandleLock);
529 return TRUE;
532 if (direction == Player) {
533 snd_pcm_plugin_playback_drain(entry->pcm_handle);
536 entry->numChannels = numChannels;
537 entry->sampleRate = sampleRate;
538 entry->bitsPerSample = bitsPerSample;
539 entry->isInitialised = FALSE;
540 pthread_rwlock_unlock(&SoundHandleLock);
542 // mark this channel as uninitialised
543 isInitialised = FALSE;
545 return TRUE;
548 // Get the number of channels (mono/stereo) in the sound.
549 unsigned PSoundChannel::GetChannels() const
551 return mNumChannels;
554 // Get the sample rate in samples per second.
555 unsigned PSoundChannel::GetSampleRate() const
557 return actualSampleRate;
560 // Get the sample size in bits per sample.
561 unsigned PSoundChannel::GetSampleSize() const
563 return mBitsPerSample;
567 BOOL PSoundChannel::SetBuffers(PINDEX size, PINDEX count)
569 if (os_handle < 0)
570 return SetErrorValues(NotOpen, EBADF);
572 //PINDEX totalSize = size * count;
574 //size = 16;
575 //count = (totalSize + 15) / 16;
577 PAssert(size > 0 && count > 0 && count < 65536, PInvalidParameter);
578 int arg = 1;
579 while (size > (PINDEX)(1 << arg))
580 arg++;
582 arg |= count << 16;
584 SoundHandleEntry * entry;
585 pthread_rwlock_rdlock(&SoundHandleLock);
586 for (entry = SoundHandleList; entry && entry->handle != os_handle;
587 entry = entry->next);
589 if (entry->isInitialised) {
590 if (entry->fragmentValue != (unsigned)arg) {
591 pthread_rwlock_unlock(&SoundHandleLock);
592 PTRACE(6, "OSS\tTried to change buffers without stopping");
593 return FALSE;
595 pthread_rwlock_unlock(&SoundHandleLock);
596 return TRUE;
599 if (direction == Player) {
600 snd_pcm_plugin_playback_drain(entry->pcm_handle);
603 // set information in the common record
604 entry->fragmentValue = arg;
605 entry->isInitialised = FALSE;
606 pthread_rwlock_unlock(&SoundHandleLock);
608 // flag this channel as not initialised
609 isInitialised = FALSE;
611 return TRUE;
615 BOOL PSoundChannel::GetBuffers(PINDEX & size, PINDEX & count)
617 if (os_handle < 0)
618 return SetErrorValues(NotOpen, EBADF);
620 SoundHandleEntry * entry;
621 pthread_rwlock_rdlock(&SoundHandleLock);
622 for (entry = SoundHandleList; entry && entry->handle != os_handle;
623 entry = entry->next);
625 int arg = entry->fragmentValue;
627 count = arg >> 16;
628 size = 1 << (arg&0xffff);
629 pthread_rwlock_unlock(&SoundHandleLock);
631 return TRUE;
635 BOOL PSoundChannel::PlaySound(const PSound & sound, BOOL wait)
637 if (os_handle < 0)
638 return SetErrorValues(NotOpen, EBADF);
640 Abort();
642 if (!Write((const BYTE *)sound, sound.GetSize()))
643 return FALSE;
645 if (wait)
646 return WaitForPlayCompletion();
648 return TRUE;
652 BOOL PSoundChannel::PlayFile(const PFilePath & filename, BOOL wait)
654 if (os_handle < 0)
655 return SetErrorValues(NotOpen, EBADF);
657 PFile file(filename, PFile::ReadOnly);
658 if (!file.IsOpen())
659 return FALSE;
661 for (;;) {
662 BYTE buffer[256];
663 if (!file.Read(buffer, 256))
664 break;
665 PINDEX len = file.GetLastReadCount();
666 if (len == 0)
667 break;
668 if (!Write(buffer, len))
669 break;
672 file.Close();
674 if (wait)
675 return WaitForPlayCompletion();
677 return TRUE;
681 BOOL PSoundChannel::HasPlayCompleted()
683 if (os_handle < 0)
684 return SetErrorValues(NotOpen, EBADF);
686 SoundHandleEntry * entry;
687 pthread_rwlock_rdlock(&SoundHandleLock);
688 for (entry = SoundHandleList; entry && entry->handle != os_handle;
689 entry = entry->next);
691 snd_pcm_channel_status_t status;
692 memset(&status, 0, sizeof(status));
693 status.channel = snd_chnmode[direction];
695 if (snd_pcm_plugin_status(entry->pcm_handle, &status) < 0) {
696 pthread_rwlock_unlock(&SoundHandleLock);
697 return FALSE;
700 int ret = (abs(status.free) / (entry->bitsPerSample / 8));
701 pthread_rwlock_unlock(&SoundHandleLock);
702 return ret;
705 BOOL PSoundChannel::WaitForPlayCompletion()
707 if (os_handle < 0)
708 return SetErrorValues(NotOpen, EBADF);
710 SoundHandleEntry * entry;
711 pthread_rwlock_rdlock(&SoundHandleLock);
712 for (entry = SoundHandleList; entry && entry->handle != os_handle;
713 entry = entry->next);
715 if (snd_pcm_playback_flush(entry->pcm_handle) < 0) {
716 pthread_rwlock_unlock(&SoundHandleLock);
717 return FALSE;
720 pthread_rwlock_unlock(&SoundHandleLock);
721 return TRUE;
725 BOOL PSoundChannel::RecordSound(PSound & sound)
727 if (os_handle < 0)
728 return SetErrorValues(NotOpen, EBADF);
730 return FALSE;
734 BOOL PSoundChannel::RecordFile(const PFilePath & filename)
736 if (os_handle < 0)
737 return SetErrorValues(NotOpen, EBADF);
739 return FALSE;
743 BOOL PSoundChannel::StartRecording()
745 if (os_handle < 0)
746 return SetErrorValues(NotOpen, EBADF);
748 int fd = os_handle;
749 fd_set fds;
750 FD_ZERO(&fds);
751 FD_SET(fd, &fds);
752 struct timeval instant = {0, 0};
753 return ConvertOSError(::select(fd + 1, &fds, NULL, NULL, &instant));
757 BOOL PSoundChannel::IsRecordBufferFull()
759 if (os_handle < 0)
760 return SetErrorValues(NotOpen, EBADF);
762 PTRACE(1, "IsRecordBufferFull()\n");
763 /* do I suppose to get the status, and check sth ? */
764 return TRUE;
768 BOOL PSoundChannel::AreAllRecordBuffersFull()
770 if (os_handle < 0)
771 return SetErrorValues(NotOpen, EBADF);
773 PTRACE(1, "AreAllRecordBuffersFull()\n");
774 /* do I suppose to get the status, and check sth ? */
775 return TRUE;
779 BOOL PSoundChannel::WaitForRecordBufferFull()
781 if (os_handle < 0)
782 return SetErrorValues(NotOpen, EBADF);
784 PTRACE(1, "WaitForRecordBufferFull()\n");
785 return PXSetIOBlock(PXReadBlock, readTimeout);
789 BOOL PSoundChannel::WaitForAllRecordBuffersFull()
791 PTRACE(1, "WaitForAllRecordBuffersFull()\n");
792 return FALSE;
796 BOOL PSoundChannel::Abort()
798 if (direction == Player && os_handle != -1) {
799 SoundHandleEntry * entry;
800 pthread_rwlock_rdlock(&SoundHandleLock);
801 for (entry = SoundHandleList; entry && entry->handle != os_handle;
802 entry = entry->next);
804 snd_pcm_plugin_playback_drain(entry->pcm_handle);
805 pthread_rwlock_unlock(&SoundHandleLock);
807 return TRUE;
811 BOOL PSoundChannel::SetVolume(unsigned newVal)
813 if (os_handle < 0)
815 return FALSE;
818 SoundHandleEntry *entry;
819 pthread_rwlock_rdlock(&SoundHandleLock);
820 for (entry = SoundHandleList; entry && entry->handle != os_handle;
821 entry = entry->next);
823 int ret;
825 if ((ret = snd_mixer_group_read(entry->mixer_handle, &entry->group)) < 0)
827 pthread_rwlock_unlock(&SoundHandleLock);
828 cerr << "snd_mixer_group_read: " << strerror(-ret) << endl;
829 return FALSE;
832 /* QSA treat the newVal as a percentage */
833 newVal = (newVal * (entry->group.max - entry->group.min) / 100) + entry->group.min;
835 entry->group.volume.names.front_left = newVal;
836 entry->group.volume.names.front_right = newVal;
838 if ((ret = snd_mixer_group_write(entry->mixer_handle, &entry->group)) < 0)
840 pthread_rwlock_unlock(&SoundHandleLock);
841 cerr << "snd_mixer_group_write: " << strerror(-ret) << endl;
842 return FALSE;
844 pthread_rwlock_unlock(&SoundHandleLock);
845 return TRUE;
848 BOOL PSoundChannel::GetVolume(unsigned &devVol)
850 if (os_handle == 0)
852 return FALSE;
855 SoundHandleEntry *entry;
856 pthread_rwlock_rdlock(&SoundHandleLock);
857 for (entry = SoundHandleList; entry && entry->handle != os_handle;
858 entry = entry->next);
860 int ret;
862 if ((ret = snd_mixer_group_read(entry->mixer_handle, &entry->group)) < 0)
864 pthread_rwlock_unlock(&SoundHandleLock);
865 return FALSE;
867 pthread_rwlock_unlock(&SoundHandleLock);
869 /* return the percentage */
870 devVol = (unsigned)(entry->group.volume.names.front_left - entry->group.min) * 100
871 / (entry->group.max - entry->group.min);
873 return TRUE;
878 // End of file