2 * OpenAL cross platform audio library
3 * Copyright (C) 2011-2013 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
28 #include <sys/select.h>
29 #include <sys/asoundlib.h>
30 #include <sys/neutrino.h>
41 snd_pcm_channel_setup_t csetup
;
42 snd_pcm_channel_params_t cparams
;
57 static const ALCchar qsaDevice
[] = "QSA Default";
58 static DevMap
* allDevNameMap
;
59 static ALuint numDevNames
;
60 static DevMap
* allCaptureDevNameMap
;
61 static ALuint numCaptureDevNames
;
66 {SND_PCM_SFMT_FLOAT_LE
},
67 {SND_PCM_SFMT_S32_LE
},
68 {SND_PCM_SFMT_U32_LE
},
69 {SND_PCM_SFMT_S16_LE
},
70 {SND_PCM_SFMT_U16_LE
},
107 static DevMap
*deviceList(int type
, ALuint
*count
)
110 snd_pcm_info_t pcminfo
;
111 int max_cards
, card
, err
, dev
, num_devices
, idx
;
114 struct snd_ctl_hw_info info
;
119 max_cards
=snd_cards();
126 dev_list
=malloc(sizeof(DevMap
)*1);
127 dev_list
[0].name
=strdup(qsaDevice
);
130 for (card
=0; card
<max_cards
; card
++)
132 if ((err
=snd_ctl_open(&handle
, card
))<0)
136 if ((err
=snd_ctl_hw_info(handle
, &info
))<0)
138 snd_ctl_close(handle
);
142 for (dev
=0; dev
<(int)info
.pcmdevs
; dev
++)
144 if ((err
=snd_ctl_pcm_info(handle
, dev
, &pcminfo
)) < 0)
149 if ((type
==SND_PCM_CHANNEL_PLAYBACK
&& (pcminfo
.flags
&SND_PCM_INFO_PLAYBACK
)) ||
150 (type
==SND_PCM_CHANNEL_CAPTURE
&& (pcminfo
.flags
&SND_PCM_INFO_CAPTURE
)))
152 temp
=realloc(dev_list
, sizeof(DevMap
)*(num_devices
+1));
156 snprintf(name
, sizeof(name
), "%s [%s] (hw:%d,%d)", info
.name
, pcminfo
.name
, card
, dev
);
157 dev_list
[num_devices
].name
=strdup(name
);
158 dev_list
[num_devices
].card
=card
;
159 dev_list
[num_devices
].dev
=dev
;
164 snd_ctl_close (handle
);
173 FORCE_ALIGN
static int qsa_proc_playback(void* ptr
)
175 ALCdevice
* device
=(ALCdevice
*)ptr
;
176 qsa_data
* data
=(qsa_data
*)device
->ExtraData
;
179 snd_pcm_channel_status_t status
;
180 struct sched_param param
;
183 struct timeval timeout
;
186 althrd_setname(althrd_current(), MIXER_THREAD_NAME
);
188 /* Increase default 10 priority to 11 to avoid jerky sound */
189 SchedGet(0, 0, ¶m
);
190 param
.sched_priority
=param
.sched_curpriority
+1;
191 SchedSet(0, 0, SCHED_NOCHANGE
, ¶m
);
193 ALint frame_size
=FrameSizeFromDevFmt(device
->FmtChans
, device
->FmtType
);
195 while (!data
->killNow
)
197 ALint len
=data
->size
;
198 write_ptr
=data
->buffer
;
200 avail
=len
/frame_size
;
201 aluMixData(device
, write_ptr
, avail
);
203 while (len
>0 && !data
->killNow
)
206 FD_SET(data
->audio_fd
, &wfds
);
210 /* Select also works like time slice to OS */
211 selectret
=select(data
->audio_fd
+1, NULL
, &wfds
, NULL
, &timeout
);
215 aluHandleDisconnect(device
);
220 if (FD_ISSET(data
->audio_fd
, &wfds
))
227 int wrote
=snd_pcm_plugin_write(data
->pcmHandle
, write_ptr
, len
);
231 if ((errno
==EAGAIN
) || (errno
==EWOULDBLOCK
))
236 memset(&status
, 0, sizeof (status
));
237 status
.channel
=SND_PCM_CHANNEL_PLAYBACK
;
239 snd_pcm_plugin_status(data
->pcmHandle
, &status
);
241 /* we need to reinitialize the sound channel if we've underrun the buffer */
242 if ((status
.status
==SND_PCM_STATUS_UNDERRUN
) ||
243 (status
.status
==SND_PCM_STATUS_READY
))
245 if ((snd_pcm_plugin_prepare(data
->pcmHandle
, SND_PCM_CHANNEL_PLAYBACK
))<0)
247 aluHandleDisconnect(device
);
267 static ALCenum
qsa_open_playback(ALCdevice
* device
, const ALCchar
* deviceName
)
274 strncpy(driver
, GetConfigValue("qsa", "device", qsaDevice
), sizeof(driver
)-1);
275 driver
[sizeof(driver
)-1]=0;
277 data
=(qsa_data
*)calloc(1, sizeof(qsa_data
));
280 return ALC_OUT_OF_MEMORY
;
288 if (strcmp(deviceName
, qsaDevice
)==0)
292 deviceName
=qsaDevice
;
295 status
=snd_pcm_open_preferred(&data
->pcmHandle
, &card
, &dev
, SND_PCM_OPEN_PLAYBACK
);
303 allDevNameMap
=deviceList(SND_PCM_CHANNEL_PLAYBACK
, &numDevNames
);
306 for (idx
=0; idx
<numDevNames
; idx
++)
308 if (allDevNameMap
[idx
].name
&& strcmp(deviceName
, allDevNameMap
[idx
].name
)==0)
316 if (idx
==numDevNames
)
319 return ALC_INVALID_DEVICE
;
322 status
=snd_pcm_open(&data
->pcmHandle
, allDevNameMap
[idx
].card
, allDevNameMap
[idx
].dev
, SND_PCM_OPEN_PLAYBACK
);
328 return ALC_INVALID_DEVICE
;
331 data
->audio_fd
=snd_pcm_file_descriptor(data
->pcmHandle
, SND_PCM_CHANNEL_PLAYBACK
);
332 if (data
->audio_fd
<0)
335 return ALC_INVALID_DEVICE
;
338 al_string_copy_cstr(&device
->DeviceName
, deviceName
);
339 device
->ExtraData
= data
;
344 static void qsa_close_playback(ALCdevice
* device
)
346 qsa_data
* data
=(qsa_data
*)device
->ExtraData
;
348 if (data
->buffer
!=NULL
)
354 snd_pcm_close(data
->pcmHandle
);
357 device
->ExtraData
=NULL
;
360 static ALCboolean
qsa_reset_playback(ALCdevice
* device
)
362 qsa_data
* data
=(qsa_data
*)device
->ExtraData
;
365 switch(device
->FmtType
)
368 format
=SND_PCM_SFMT_S8
;
371 format
=SND_PCM_SFMT_U8
;
374 format
=SND_PCM_SFMT_S16_LE
;
377 format
=SND_PCM_SFMT_U16_LE
;
380 format
=SND_PCM_SFMT_S32_LE
;
383 format
=SND_PCM_SFMT_U32_LE
;
386 format
=SND_PCM_SFMT_FLOAT_LE
;
390 /* we actually don't want to block on writes */
391 snd_pcm_nonblock_mode(data
->pcmHandle
, 1);
392 /* Disable mmap to control data transfer to the audio device */
393 snd_pcm_plugin_set_disable(data
->pcmHandle
, PLUGIN_DISABLE_MMAP
);
394 snd_pcm_plugin_set_disable(data
->pcmHandle
, PLUGIN_DISABLE_BUFFER_PARTIAL_BLOCKS
);
396 // configure a sound channel
397 memset(&data
->cparams
, 0, sizeof(data
->cparams
));
398 data
->cparams
.channel
=SND_PCM_CHANNEL_PLAYBACK
;
399 data
->cparams
.mode
=SND_PCM_MODE_BLOCK
;
400 data
->cparams
.start_mode
=SND_PCM_START_FULL
;
401 data
->cparams
.stop_mode
=SND_PCM_STOP_STOP
;
403 data
->cparams
.buf
.block
.frag_size
=device
->UpdateSize
*
404 ChannelsFromDevFmt(device
->FmtChans
)*BytesFromDevFmt(device
->FmtType
);
405 data
->cparams
.buf
.block
.frags_max
=device
->NumUpdates
;
406 data
->cparams
.buf
.block
.frags_min
=device
->NumUpdates
;
408 data
->cparams
.format
.interleave
=1;
409 data
->cparams
.format
.rate
=device
->Frequency
;
410 data
->cparams
.format
.voices
=ChannelsFromDevFmt(device
->FmtChans
);
411 data
->cparams
.format
.format
=format
;
413 if ((snd_pcm_plugin_params(data
->pcmHandle
, &data
->cparams
))<0)
415 int original_rate
=data
->cparams
.format
.rate
;
416 int original_voices
=data
->cparams
.format
.voices
;
417 int original_format
=data
->cparams
.format
.format
;
421 for (it
=0; it
<1; it
++)
423 /* Check for second pass */
426 original_rate
=ratelist
[0].rate
;
427 original_voices
=channellist
[0].channels
;
428 original_format
=formatlist
[0].format
;
432 /* At first downgrade sample format */
435 if (formatlist
[jt
].format
==data
->cparams
.format
.format
)
437 data
->cparams
.format
.format
=formatlist
[jt
+1].format
;
440 if (formatlist
[jt
].format
==0)
442 data
->cparams
.format
.format
=0;
448 if (data
->cparams
.format
.format
==0)
450 data
->cparams
.format
.format
=original_format
;
452 /* At secod downgrade sample rate */
455 if (ratelist
[jt
].rate
==data
->cparams
.format
.rate
)
457 data
->cparams
.format
.rate
=ratelist
[jt
+1].rate
;
460 if (ratelist
[jt
].rate
==0)
462 data
->cparams
.format
.rate
=0;
468 if (data
->cparams
.format
.rate
==0)
470 data
->cparams
.format
.rate
=original_rate
;
471 data
->cparams
.format
.format
=original_format
;
473 /* At third downgrade channels number */
476 if(channellist
[jt
].channels
==data
->cparams
.format
.voices
)
478 data
->cparams
.format
.voices
=channellist
[jt
+1].channels
;
481 if (channellist
[jt
].channels
==0)
483 data
->cparams
.format
.voices
=0;
490 if (data
->cparams
.format
.voices
==0)
496 data
->cparams
.buf
.block
.frag_size
=device
->UpdateSize
*
497 data
->cparams
.format
.voices
*
498 snd_pcm_format_width(data
->cparams
.format
.format
)/8;
499 data
->cparams
.buf
.block
.frags_max
=device
->NumUpdates
;
500 data
->cparams
.buf
.block
.frags_min
=device
->NumUpdates
;
501 if ((snd_pcm_plugin_params(data
->pcmHandle
, &data
->cparams
))<0)
511 if (data
->cparams
.format
.voices
!=0)
517 if (data
->cparams
.format
.voices
==0)
523 if ((snd_pcm_plugin_prepare(data
->pcmHandle
, SND_PCM_CHANNEL_PLAYBACK
))<0)
528 memset(&data
->csetup
, 0, sizeof(data
->csetup
));
529 data
->csetup
.channel
=SND_PCM_CHANNEL_PLAYBACK
;
530 if (snd_pcm_plugin_setup(data
->pcmHandle
, &data
->csetup
)<0)
535 /* now fill back to the our AL device */
536 device
->Frequency
=data
->cparams
.format
.rate
;
538 switch (data
->cparams
.format
.voices
)
541 device
->FmtChans
=DevFmtMono
;
544 device
->FmtChans
=DevFmtStereo
;
547 device
->FmtChans
=DevFmtQuad
;
550 device
->FmtChans
=DevFmtX51
;
553 device
->FmtChans
=DevFmtX61
;
556 device
->FmtChans
=DevFmtX71
;
559 device
->FmtChans
=DevFmtMono
;
563 switch (data
->cparams
.format
.format
)
565 case SND_PCM_SFMT_S8
:
566 device
->FmtType
=DevFmtByte
;
568 case SND_PCM_SFMT_U8
:
569 device
->FmtType
=DevFmtUByte
;
571 case SND_PCM_SFMT_S16_LE
:
572 device
->FmtType
=DevFmtShort
;
574 case SND_PCM_SFMT_U16_LE
:
575 device
->FmtType
=DevFmtUShort
;
577 case SND_PCM_SFMT_S32_LE
:
578 device
->FmtType
=DevFmtInt
;
580 case SND_PCM_SFMT_U32_LE
:
581 device
->FmtType
=DevFmtUInt
;
583 case SND_PCM_SFMT_FLOAT_LE
:
584 device
->FmtType
=DevFmtFloat
;
587 device
->FmtType
=DevFmtShort
;
591 SetDefaultChannelOrder(device
);
593 device
->UpdateSize
=data
->csetup
.buf
.block
.frag_size
/
594 (ChannelsFromDevFmt(device
->FmtChans
)*BytesFromDevFmt(device
->FmtType
));
595 device
->NumUpdates
=data
->csetup
.buf
.block
.frags
;
597 data
->size
=data
->csetup
.buf
.block
.frag_size
;
598 data
->buffer
=malloc(data
->size
);
607 static ALCboolean
qsa_start_playback(ALCdevice
* device
)
609 qsa_data
*data
= (qsa_data
*)device
->ExtraData
;
612 if(althrd_create(&data
->thread
, qsa_proc_playback
, device
) != althrd_success
)
618 static void qsa_stop_playback(ALCdevice
* device
)
620 qsa_data
*data
= (qsa_data
*)device
->ExtraData
;
627 althrd_join(data
->thread
, &res
);
634 static ALCenum
qsa_open_capture(ALCdevice
* device
, const ALCchar
* deviceName
)
642 strncpy(driver
, GetConfigValue("qsa", "capture", qsaDevice
), sizeof(driver
)-1);
643 driver
[sizeof(driver
)-1]=0;
645 data
=(qsa_data
*)calloc(1, sizeof(qsa_data
));
648 return ALC_OUT_OF_MEMORY
;
656 if (strcmp(deviceName
, qsaDevice
)==0)
660 deviceName
=qsaDevice
;
663 status
=snd_pcm_open_preferred(&data
->pcmHandle
, &card
, &dev
, SND_PCM_OPEN_CAPTURE
);
669 if (!allCaptureDevNameMap
)
671 allCaptureDevNameMap
=deviceList(SND_PCM_CHANNEL_CAPTURE
, &numDevNames
);
674 for (idx
=0; idx
<numDevNames
; idx
++)
676 if (allCaptureDevNameMap
[idx
].name
&& strcmp(deviceName
, allCaptureDevNameMap
[idx
].name
)==0)
684 if (idx
==numDevNames
)
687 return ALC_INVALID_DEVICE
;
690 status
=snd_pcm_open(&data
->pcmHandle
, allCaptureDevNameMap
[idx
].card
, allCaptureDevNameMap
[idx
].dev
, SND_PCM_OPEN_CAPTURE
);
696 return ALC_INVALID_DEVICE
;
699 data
->audio_fd
=snd_pcm_file_descriptor(data
->pcmHandle
, SND_PCM_CHANNEL_CAPTURE
);
700 if (data
->audio_fd
<0)
703 return ALC_INVALID_DEVICE
;
706 al_string_copy_cstr(&device
->DeviceName
, deviceName
);
707 device
->ExtraData
= data
;
709 switch (device
->FmtType
)
712 format
=SND_PCM_SFMT_S8
;
715 format
=SND_PCM_SFMT_U8
;
718 format
=SND_PCM_SFMT_S16_LE
;
721 format
=SND_PCM_SFMT_U16_LE
;
724 format
=SND_PCM_SFMT_S32_LE
;
727 format
=SND_PCM_SFMT_U32_LE
;
730 format
=SND_PCM_SFMT_FLOAT_LE
;
734 /* we actually don't want to block on reads */
735 snd_pcm_nonblock_mode(data
->pcmHandle
, 1);
736 /* Disable mmap to control data transfer to the audio device */
737 snd_pcm_plugin_set_disable(data
->pcmHandle
, PLUGIN_DISABLE_MMAP
);
739 /* configure a sound channel */
740 memset(&data
->cparams
, 0, sizeof(data
->cparams
));
741 data
->cparams
.mode
=SND_PCM_MODE_BLOCK
;
742 data
->cparams
.channel
=SND_PCM_CHANNEL_CAPTURE
;
743 data
->cparams
.start_mode
=SND_PCM_START_GO
;
744 data
->cparams
.stop_mode
=SND_PCM_STOP_STOP
;
746 data
->cparams
.buf
.block
.frag_size
=device
->UpdateSize
*
747 ChannelsFromDevFmt(device
->FmtChans
)*BytesFromDevFmt(device
->FmtType
);
748 data
->cparams
.buf
.block
.frags_max
=device
->NumUpdates
;
749 data
->cparams
.buf
.block
.frags_min
=device
->NumUpdates
;
751 data
->cparams
.format
.interleave
=1;
752 data
->cparams
.format
.rate
=device
->Frequency
;
753 data
->cparams
.format
.voices
=ChannelsFromDevFmt(device
->FmtChans
);
754 data
->cparams
.format
.format
=format
;
756 if ((snd_pcm_plugin_params(data
->pcmHandle
, &data
->cparams
))<0)
758 int original_rate
=data
->cparams
.format
.rate
;
759 int original_voices
=data
->cparams
.format
.voices
;
760 int original_format
=data
->cparams
.format
.format
;
764 for (it
=0; it
<1; it
++)
766 /* Check for second pass */
769 original_rate
=ratelist
[0].rate
;
770 original_voices
=channellist
[0].channels
;
771 original_format
=formatlist
[0].format
;
775 /* At first downgrade sample format */
778 if (formatlist
[jt
].format
==data
->cparams
.format
.format
)
780 data
->cparams
.format
.format
=formatlist
[jt
+1].format
;
783 if (formatlist
[jt
].format
==0)
785 data
->cparams
.format
.format
=0;
791 if (data
->cparams
.format
.format
==0)
793 data
->cparams
.format
.format
=original_format
;
795 /* At secod downgrade sample rate */
798 if (ratelist
[jt
].rate
==data
->cparams
.format
.rate
)
800 data
->cparams
.format
.rate
=ratelist
[jt
+1].rate
;
803 if (ratelist
[jt
].rate
==0)
805 data
->cparams
.format
.rate
=0;
811 if (data
->cparams
.format
.rate
==0)
813 data
->cparams
.format
.rate
=original_rate
;
814 data
->cparams
.format
.format
=original_format
;
816 /* At third downgrade channels number */
819 if(channellist
[jt
].channels
==data
->cparams
.format
.voices
)
821 data
->cparams
.format
.voices
=channellist
[jt
+1].channels
;
824 if (channellist
[jt
].channels
==0)
826 data
->cparams
.format
.voices
=0;
833 if (data
->cparams
.format
.voices
==0)
839 data
->cparams
.buf
.block
.frag_size
=device
->UpdateSize
*
840 data
->cparams
.format
.voices
*
841 snd_pcm_format_width(data
->cparams
.format
.format
)/8;
842 data
->cparams
.buf
.block
.frags_max
=device
->NumUpdates
;
843 data
->cparams
.buf
.block
.frags_min
=device
->NumUpdates
;
844 if ((snd_pcm_plugin_params(data
->pcmHandle
, &data
->cparams
))<0)
854 if (data
->cparams
.format
.voices
!=0)
860 if (data
->cparams
.format
.voices
==0)
862 return ALC_INVALID_VALUE
;
866 /* now fill back to the our AL device */
867 device
->Frequency
=data
->cparams
.format
.rate
;
869 switch (data
->cparams
.format
.voices
)
872 device
->FmtChans
=DevFmtMono
;
875 device
->FmtChans
=DevFmtStereo
;
878 device
->FmtChans
=DevFmtQuad
;
881 device
->FmtChans
=DevFmtX51
;
884 device
->FmtChans
=DevFmtX61
;
887 device
->FmtChans
=DevFmtX71
;
890 device
->FmtChans
=DevFmtMono
;
894 switch (data
->cparams
.format
.format
)
896 case SND_PCM_SFMT_S8
:
897 device
->FmtType
=DevFmtByte
;
899 case SND_PCM_SFMT_U8
:
900 device
->FmtType
=DevFmtUByte
;
902 case SND_PCM_SFMT_S16_LE
:
903 device
->FmtType
=DevFmtShort
;
905 case SND_PCM_SFMT_U16_LE
:
906 device
->FmtType
=DevFmtUShort
;
908 case SND_PCM_SFMT_S32_LE
:
909 device
->FmtType
=DevFmtInt
;
911 case SND_PCM_SFMT_U32_LE
:
912 device
->FmtType
=DevFmtUInt
;
914 case SND_PCM_SFMT_FLOAT_LE
:
915 device
->FmtType
=DevFmtFloat
;
918 device
->FmtType
=DevFmtShort
;
925 static void qsa_close_capture(ALCdevice
* device
)
927 qsa_data
* data
=(qsa_data
*)device
->ExtraData
;
929 if (data
->pcmHandle
!=NULL
)
931 snd_pcm_close(data
->pcmHandle
);
934 device
->ExtraData
=NULL
;
937 static void qsa_start_capture(ALCdevice
* device
)
939 qsa_data
* data
=(qsa_data
*)device
->ExtraData
;
942 if ((rstatus
=snd_pcm_plugin_prepare(data
->pcmHandle
, SND_PCM_CHANNEL_CAPTURE
))<0)
944 ERR("capture prepare failed: %s\n", snd_strerror(rstatus
));
948 memset(&data
->csetup
, 0, sizeof(data
->csetup
));
949 data
->csetup
.channel
=SND_PCM_CHANNEL_CAPTURE
;
950 if ((rstatus
=snd_pcm_plugin_setup(data
->pcmHandle
, &data
->csetup
))<0)
952 ERR("capture setup failed: %s\n", snd_strerror(rstatus
));
956 snd_pcm_capture_go(data
->pcmHandle
);
958 device
->UpdateSize
=data
->csetup
.buf
.block
.frag_size
/
959 (ChannelsFromDevFmt(device
->FmtChans
)*BytesFromDevFmt(device
->FmtType
));
960 device
->NumUpdates
=data
->csetup
.buf
.block
.frags
;
963 static void qsa_stop_capture(ALCdevice
* device
)
965 qsa_data
* data
=(qsa_data
*)device
->ExtraData
;
967 snd_pcm_capture_flush(data
->pcmHandle
);
970 static ALCuint
qsa_available_samples(ALCdevice
* device
)
972 qsa_data
* data
=(qsa_data
*)device
->ExtraData
;
973 snd_pcm_channel_status_t status
;
974 ALint frame_size
=FrameSizeFromDevFmt(device
->FmtChans
, device
->FmtType
);
978 memset(&status
, 0, sizeof (status
));
979 status
.channel
=SND_PCM_CHANNEL_CAPTURE
;
980 snd_pcm_plugin_status(data
->pcmHandle
, &status
);
981 if ((status
.status
==SND_PCM_STATUS_OVERRUN
) ||
982 (status
.status
==SND_PCM_STATUS_READY
))
984 if ((rstatus
=snd_pcm_plugin_prepare(data
->pcmHandle
, SND_PCM_CHANNEL_CAPTURE
))<0)
986 ERR("capture prepare failed: %s\n", snd_strerror(rstatus
));
987 aluHandleDisconnect(device
);
991 snd_pcm_capture_go(data
->pcmHandle
);
995 free_size
=data
->csetup
.buf
.block
.frag_size
*data
->csetup
.buf
.block
.frags
;
996 free_size
-=status
.free
;
998 return free_size
/frame_size
;
1001 static ALCenum
qsa_capture_samples(ALCdevice
*device
, ALCvoid
*buffer
, ALCuint samples
)
1003 qsa_data
* data
=(qsa_data
*)device
->ExtraData
;
1005 snd_pcm_channel_status_t status
;
1008 struct timeval timeout
;
1010 ALint frame_size
=FrameSizeFromDevFmt(device
->FmtChans
, device
->FmtType
);
1011 ALint len
=samples
*frame_size
;
1019 FD_SET(data
->audio_fd
, &rfds
);
1023 /* Select also works like time slice to OS */
1025 selectret
=select(data
->audio_fd
+1, &rfds
, NULL
, NULL
, &timeout
);
1029 aluHandleDisconnect(device
);
1030 return ALC_INVALID_DEVICE
;
1034 if (FD_ISSET(data
->audio_fd
, &rfds
))
1036 bytes_read
=snd_pcm_plugin_read(data
->pcmHandle
, read_ptr
, len
);
1044 if ((errno
==EAGAIN
) || (errno
==EWOULDBLOCK
))
1049 memset(&status
, 0, sizeof (status
));
1050 status
.channel
=SND_PCM_CHANNEL_CAPTURE
;
1051 snd_pcm_plugin_status(data
->pcmHandle
, &status
);
1053 /* we need to reinitialize the sound channel if we've overrun the buffer */
1054 if ((status
.status
==SND_PCM_STATUS_OVERRUN
) ||
1055 (status
.status
==SND_PCM_STATUS_READY
))
1057 if ((rstatus
=snd_pcm_plugin_prepare(data
->pcmHandle
, SND_PCM_CHANNEL_CAPTURE
))<0)
1059 ERR("capture prepare failed: %s\n", snd_strerror(rstatus
));
1060 aluHandleDisconnect(device
);
1061 return ALC_INVALID_DEVICE
;
1063 snd_pcm_capture_go(data
->pcmHandle
);
1068 read_ptr
+=bytes_read
;
1073 return ALC_NO_ERROR
;
1076 static const BackendFuncs qsa_funcs
= {
1086 qsa_capture_samples
,
1087 qsa_available_samples
1090 ALCboolean
alc_qsa_init(BackendFuncs
* func_list
)
1092 *func_list
=qsa_funcs
;
1097 void alc_qsa_deinit(void)
1101 for (i
=0; i
<numDevNames
; ++i
)
1103 free(allDevNameMap
[i
].name
);
1105 free(allDevNameMap
);
1109 for (i
=0; i
<numCaptureDevNames
; ++i
)
1111 free(allCaptureDevNameMap
[i
].name
);
1113 free(allCaptureDevNameMap
);
1114 allCaptureDevNameMap
=NULL
;
1115 numCaptureDevNames
=0;
1118 void alc_qsa_probe(enum DevProbe type
)
1124 case ALL_DEVICE_PROBE
:
1125 for (i
=0; i
<numDevNames
; ++i
)
1127 free(allDevNameMap
[i
].name
);
1129 free(allDevNameMap
);
1131 allDevNameMap
=deviceList(SND_PCM_CHANNEL_PLAYBACK
, &numDevNames
);
1132 for (i
=0; i
<numDevNames
; ++i
)
1134 AppendAllDevicesList(allDevNameMap
[i
].name
);
1137 case CAPTURE_DEVICE_PROBE
:
1138 for (i
=0; i
<numCaptureDevNames
; ++i
)
1140 free(allCaptureDevNameMap
[i
].name
);
1142 free(allCaptureDevNameMap
);
1144 allCaptureDevNameMap
=deviceList(SND_PCM_CHANNEL_CAPTURE
, &numCaptureDevNames
);
1145 for (i
=0; i
<numCaptureDevNames
; ++i
)
1147 AppendCaptureDeviceList(allCaptureDevNameMap
[i
].name
);