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>
36 #include "backends/base.h"
43 snd_pcm_channel_setup_t csetup
;
44 snd_pcm_channel_params_t cparams
;
58 TYPEDEF_VECTOR(DevMap
, vector_DevMap
)
60 static vector_DevMap DeviceNameMap
;
61 static vector_DevMap CaptureNameMap
;
63 static const ALCchar qsaDevice
[] = "QSA Default";
68 {SND_PCM_SFMT_FLOAT_LE
},
69 {SND_PCM_SFMT_S32_LE
},
70 {SND_PCM_SFMT_U32_LE
},
71 {SND_PCM_SFMT_S16_LE
},
72 {SND_PCM_SFMT_U16_LE
},
109 static void deviceList(int type
, vector_DevMap
*devmap
)
112 snd_pcm_info_t pcminfo
;
113 int max_cards
, card
, err
, dev
;
116 struct snd_ctl_hw_info info
;
118 max_cards
= snd_cards();
122 VECTOR_RESIZE(*devmap
, 0, max_cards
+1);
124 entry
.name
= strdup(qsaDevice
);
127 VECTOR_PUSH_BACK(*devmap
, entry
);
129 for(card
= 0;card
< max_cards
;card
++)
131 if((err
=snd_ctl_open(&handle
, card
)) < 0)
134 if((err
=snd_ctl_hw_info(handle
, &info
)) < 0)
136 snd_ctl_close(handle
);
140 for(dev
= 0;dev
< (int)info
.pcmdevs
;dev
++)
142 if((err
=snd_ctl_pcm_info(handle
, dev
, &pcminfo
)) < 0)
145 if((type
==SND_PCM_CHANNEL_PLAYBACK
&& (pcminfo
.flags
&SND_PCM_INFO_PLAYBACK
)) ||
146 (type
==SND_PCM_CHANNEL_CAPTURE
&& (pcminfo
.flags
&SND_PCM_INFO_CAPTURE
)))
148 snprintf(name
, sizeof(name
), "%s [%s] (hw:%d,%d)", info
.name
, pcminfo
.name
, card
, dev
);
149 entry
.name
= strdup(name
);
153 VECTOR_PUSH_BACK(*devmap
, entry
);
154 TRACE("Got device \"%s\", card %d, dev %d\n", name
, card
, dev
);
157 snd_ctl_close(handle
);
162 /* Wrappers to use an old-style backend with the new interface. */
163 typedef struct PlaybackWrapper
{
164 DERIVE_FROM_TYPE(ALCbackend
);
168 static void PlaybackWrapper_Construct(PlaybackWrapper
*self
, ALCdevice
*device
);
169 static void PlaybackWrapper_Destruct(PlaybackWrapper
*self
);
170 static ALCenum
PlaybackWrapper_open(PlaybackWrapper
*self
, const ALCchar
*name
);
171 static ALCboolean
PlaybackWrapper_reset(PlaybackWrapper
*self
);
172 static ALCboolean
PlaybackWrapper_start(PlaybackWrapper
*self
);
173 static void PlaybackWrapper_stop(PlaybackWrapper
*self
);
174 static DECLARE_FORWARD2(PlaybackWrapper
, ALCbackend
, ALCenum
, captureSamples
, void*, ALCuint
)
175 static DECLARE_FORWARD(PlaybackWrapper
, ALCbackend
, ALCuint
, availableSamples
)
176 static DECLARE_FORWARD(PlaybackWrapper
, ALCbackend
, ClockLatency
, getClockLatency
)
177 static DECLARE_FORWARD(PlaybackWrapper
, ALCbackend
, void, lock
)
178 static DECLARE_FORWARD(PlaybackWrapper
, ALCbackend
, void, unlock
)
179 DECLARE_DEFAULT_ALLOCATORS(PlaybackWrapper
)
180 DEFINE_ALCBACKEND_VTABLE(PlaybackWrapper
);
183 FORCE_ALIGN
static int qsa_proc_playback(void *ptr
)
185 PlaybackWrapper
*self
= ptr
;
186 ALCdevice
*device
= STATIC_CAST(ALCbackend
,self
)->mDevice
;
187 qsa_data
*data
= self
->ExtraData
;
188 snd_pcm_channel_status_t status
;
189 struct sched_param param
;
190 struct timeval timeout
;
197 althrd_setname(althrd_current(), MIXER_THREAD_NAME
);
199 /* Increase default 10 priority to 11 to avoid jerky sound */
200 SchedGet(0, 0, ¶m
);
201 param
.sched_priority
=param
.sched_curpriority
+1;
202 SchedSet(0, 0, SCHED_NOCHANGE
, ¶m
);
204 const ALint frame_size
= FrameSizeFromDevFmt(
205 device
->FmtChans
, device
->FmtType
, device
->AmbiOrder
208 V0(device
->Backend
,lock
)();
209 while(!data
->killNow
)
212 FD_SET(data
->audio_fd
, &wfds
);
216 /* Select also works like time slice to OS */
217 V0(device
->Backend
,unlock
)();
218 sret
= select(data
->audio_fd
+1, NULL
, &wfds
, NULL
, &timeout
);
219 V0(device
->Backend
,lock
)();
222 ERR("select error: %s\n", strerror(errno
));
223 aluHandleDisconnect(device
, "Failed waiting for playback buffer: %s", strerror(errno
));
228 ERR("select timeout\n");
233 write_ptr
= data
->buffer
;
234 aluMixData(device
, write_ptr
, len
/frame_size
);
235 while(len
>0 && !data
->killNow
)
237 int wrote
= snd_pcm_plugin_write(data
->pcmHandle
, write_ptr
, len
);
240 if(errno
==EAGAIN
|| errno
==EWOULDBLOCK
)
243 memset(&status
, 0, sizeof(status
));
244 status
.channel
= SND_PCM_CHANNEL_PLAYBACK
;
246 snd_pcm_plugin_status(data
->pcmHandle
, &status
);
248 /* we need to reinitialize the sound channel if we've underrun the buffer */
249 if(status
.status
== SND_PCM_STATUS_UNDERRUN
||
250 status
.status
== SND_PCM_STATUS_READY
)
252 if(snd_pcm_plugin_prepare(data
->pcmHandle
, SND_PCM_CHANNEL_PLAYBACK
) < 0)
254 aluHandleDisconnect(device
, "Playback recovery failed");
266 V0(device
->Backend
,unlock
)();
275 static ALCenum
qsa_open_playback(PlaybackWrapper
*self
, const ALCchar
* deviceName
)
277 ALCdevice
*device
= STATIC_CAST(ALCbackend
,self
)->mDevice
;
282 data
= (qsa_data
*)calloc(1, sizeof(qsa_data
));
284 return ALC_OUT_OF_MEMORY
;
287 deviceName
= qsaDevice
;
289 if(strcmp(deviceName
, qsaDevice
) == 0)
290 status
= snd_pcm_open_preferred(&data
->pcmHandle
, &card
, &dev
, SND_PCM_OPEN_PLAYBACK
);
295 if(VECTOR_SIZE(DeviceNameMap
) == 0)
296 deviceList(SND_PCM_CHANNEL_PLAYBACK
, &DeviceNameMap
);
298 #define MATCH_DEVNAME(iter) ((iter)->name && strcmp(deviceName, (iter)->name)==0)
299 VECTOR_FIND_IF(iter
, const DevMap
, DeviceNameMap
, MATCH_DEVNAME
);
301 if(iter
== VECTOR_END(DeviceNameMap
))
304 return ALC_INVALID_DEVICE
;
307 status
= snd_pcm_open(&data
->pcmHandle
, iter
->card
, iter
->dev
, SND_PCM_OPEN_PLAYBACK
);
313 return ALC_INVALID_DEVICE
;
316 data
->audio_fd
= snd_pcm_file_descriptor(data
->pcmHandle
, SND_PCM_CHANNEL_PLAYBACK
);
317 if(data
->audio_fd
< 0)
319 snd_pcm_close(data
->pcmHandle
);
321 return ALC_INVALID_DEVICE
;
324 alstr_copy_cstr(&device
->DeviceName
, deviceName
);
325 self
->ExtraData
= data
;
330 static void qsa_close_playback(PlaybackWrapper
*self
)
332 qsa_data
*data
= self
->ExtraData
;
334 if (data
->buffer
!=NULL
)
340 snd_pcm_close(data
->pcmHandle
);
343 self
->ExtraData
= NULL
;
346 static ALCboolean
qsa_reset_playback(PlaybackWrapper
*self
)
348 ALCdevice
*device
= STATIC_CAST(ALCbackend
,self
)->mDevice
;
349 qsa_data
*data
= self
->ExtraData
;
352 switch(device
->FmtType
)
355 format
=SND_PCM_SFMT_S8
;
358 format
=SND_PCM_SFMT_U8
;
361 format
=SND_PCM_SFMT_S16_LE
;
364 format
=SND_PCM_SFMT_U16_LE
;
367 format
=SND_PCM_SFMT_S32_LE
;
370 format
=SND_PCM_SFMT_U32_LE
;
373 format
=SND_PCM_SFMT_FLOAT_LE
;
377 /* we actually don't want to block on writes */
378 snd_pcm_nonblock_mode(data
->pcmHandle
, 1);
379 /* Disable mmap to control data transfer to the audio device */
380 snd_pcm_plugin_set_disable(data
->pcmHandle
, PLUGIN_DISABLE_MMAP
);
381 snd_pcm_plugin_set_disable(data
->pcmHandle
, PLUGIN_DISABLE_BUFFER_PARTIAL_BLOCKS
);
383 // configure a sound channel
384 memset(&data
->cparams
, 0, sizeof(data
->cparams
));
385 data
->cparams
.channel
=SND_PCM_CHANNEL_PLAYBACK
;
386 data
->cparams
.mode
=SND_PCM_MODE_BLOCK
;
387 data
->cparams
.start_mode
=SND_PCM_START_FULL
;
388 data
->cparams
.stop_mode
=SND_PCM_STOP_STOP
;
390 data
->cparams
.buf
.block
.frag_size
=device
->UpdateSize
*
391 FrameSizeFromDevFmt(device
->FmtChans
, device
->FmtType
, device
->AmbiOrder
);
392 data
->cparams
.buf
.block
.frags_max
=device
->NumUpdates
;
393 data
->cparams
.buf
.block
.frags_min
=device
->NumUpdates
;
395 data
->cparams
.format
.interleave
=1;
396 data
->cparams
.format
.rate
=device
->Frequency
;
397 data
->cparams
.format
.voices
=ChannelsFromDevFmt(device
->FmtChans
, device
->AmbiOrder
);
398 data
->cparams
.format
.format
=format
;
400 if ((snd_pcm_plugin_params(data
->pcmHandle
, &data
->cparams
))<0)
402 int original_rate
=data
->cparams
.format
.rate
;
403 int original_voices
=data
->cparams
.format
.voices
;
404 int original_format
=data
->cparams
.format
.format
;
408 for (it
=0; it
<1; it
++)
410 /* Check for second pass */
413 original_rate
=ratelist
[0].rate
;
414 original_voices
=channellist
[0].channels
;
415 original_format
=formatlist
[0].format
;
419 /* At first downgrade sample format */
422 if (formatlist
[jt
].format
==data
->cparams
.format
.format
)
424 data
->cparams
.format
.format
=formatlist
[jt
+1].format
;
427 if (formatlist
[jt
].format
==0)
429 data
->cparams
.format
.format
=0;
435 if (data
->cparams
.format
.format
==0)
437 data
->cparams
.format
.format
=original_format
;
439 /* At secod downgrade sample rate */
442 if (ratelist
[jt
].rate
==data
->cparams
.format
.rate
)
444 data
->cparams
.format
.rate
=ratelist
[jt
+1].rate
;
447 if (ratelist
[jt
].rate
==0)
449 data
->cparams
.format
.rate
=0;
455 if (data
->cparams
.format
.rate
==0)
457 data
->cparams
.format
.rate
=original_rate
;
458 data
->cparams
.format
.format
=original_format
;
460 /* At third downgrade channels number */
463 if(channellist
[jt
].channels
==data
->cparams
.format
.voices
)
465 data
->cparams
.format
.voices
=channellist
[jt
+1].channels
;
468 if (channellist
[jt
].channels
==0)
470 data
->cparams
.format
.voices
=0;
477 if (data
->cparams
.format
.voices
==0)
483 data
->cparams
.buf
.block
.frag_size
=device
->UpdateSize
*
484 data
->cparams
.format
.voices
*
485 snd_pcm_format_width(data
->cparams
.format
.format
)/8;
486 data
->cparams
.buf
.block
.frags_max
=device
->NumUpdates
;
487 data
->cparams
.buf
.block
.frags_min
=device
->NumUpdates
;
488 if ((snd_pcm_plugin_params(data
->pcmHandle
, &data
->cparams
))<0)
498 if (data
->cparams
.format
.voices
!=0)
504 if (data
->cparams
.format
.voices
==0)
510 if ((snd_pcm_plugin_prepare(data
->pcmHandle
, SND_PCM_CHANNEL_PLAYBACK
))<0)
515 memset(&data
->csetup
, 0, sizeof(data
->csetup
));
516 data
->csetup
.channel
=SND_PCM_CHANNEL_PLAYBACK
;
517 if (snd_pcm_plugin_setup(data
->pcmHandle
, &data
->csetup
)<0)
522 /* now fill back to the our AL device */
523 device
->Frequency
=data
->cparams
.format
.rate
;
525 switch (data
->cparams
.format
.voices
)
528 device
->FmtChans
=DevFmtMono
;
531 device
->FmtChans
=DevFmtStereo
;
534 device
->FmtChans
=DevFmtQuad
;
537 device
->FmtChans
=DevFmtX51
;
540 device
->FmtChans
=DevFmtX61
;
543 device
->FmtChans
=DevFmtX71
;
546 device
->FmtChans
=DevFmtMono
;
550 switch (data
->cparams
.format
.format
)
552 case SND_PCM_SFMT_S8
:
553 device
->FmtType
=DevFmtByte
;
555 case SND_PCM_SFMT_U8
:
556 device
->FmtType
=DevFmtUByte
;
558 case SND_PCM_SFMT_S16_LE
:
559 device
->FmtType
=DevFmtShort
;
561 case SND_PCM_SFMT_U16_LE
:
562 device
->FmtType
=DevFmtUShort
;
564 case SND_PCM_SFMT_S32_LE
:
565 device
->FmtType
=DevFmtInt
;
567 case SND_PCM_SFMT_U32_LE
:
568 device
->FmtType
=DevFmtUInt
;
570 case SND_PCM_SFMT_FLOAT_LE
:
571 device
->FmtType
=DevFmtFloat
;
574 device
->FmtType
=DevFmtShort
;
578 SetDefaultChannelOrder(device
);
580 device
->UpdateSize
=data
->csetup
.buf
.block
.frag_size
/
581 FrameSizeFromDevFmt(device
->FmtChans
, device
->FmtType
, device
->AmbiOrder
);
582 device
->NumUpdates
=data
->csetup
.buf
.block
.frags
;
584 data
->size
=data
->csetup
.buf
.block
.frag_size
;
585 data
->buffer
=malloc(data
->size
);
594 static ALCboolean
qsa_start_playback(PlaybackWrapper
*self
)
596 qsa_data
*data
= self
->ExtraData
;
599 if(althrd_create(&data
->thread
, qsa_proc_playback
, self
) != althrd_success
)
605 static void qsa_stop_playback(PlaybackWrapper
*self
)
607 qsa_data
*data
= self
->ExtraData
;
614 althrd_join(data
->thread
, &res
);
618 static void PlaybackWrapper_Construct(PlaybackWrapper
*self
, ALCdevice
*device
)
620 ALCbackend_Construct(STATIC_CAST(ALCbackend
, self
), device
);
621 SET_VTABLE2(PlaybackWrapper
, ALCbackend
, self
);
623 self
->ExtraData
= NULL
;
626 static void PlaybackWrapper_Destruct(PlaybackWrapper
*self
)
629 qsa_close_playback(self
);
631 ALCbackend_Destruct(STATIC_CAST(ALCbackend
, self
));
634 static ALCenum
PlaybackWrapper_open(PlaybackWrapper
*self
, const ALCchar
*name
)
636 return qsa_open_playback(self
, name
);
639 static ALCboolean
PlaybackWrapper_reset(PlaybackWrapper
*self
)
641 return qsa_reset_playback(self
);
644 static ALCboolean
PlaybackWrapper_start(PlaybackWrapper
*self
)
646 return qsa_start_playback(self
);
649 static void PlaybackWrapper_stop(PlaybackWrapper
*self
)
651 qsa_stop_playback(self
);
660 typedef struct CaptureWrapper
{
661 DERIVE_FROM_TYPE(ALCbackend
);
665 static void CaptureWrapper_Construct(CaptureWrapper
*self
, ALCdevice
*device
);
666 static void CaptureWrapper_Destruct(CaptureWrapper
*self
);
667 static ALCenum
CaptureWrapper_open(CaptureWrapper
*self
, const ALCchar
*name
);
668 static DECLARE_FORWARD(CaptureWrapper
, ALCbackend
, ALCboolean
, reset
)
669 static ALCboolean
CaptureWrapper_start(CaptureWrapper
*self
);
670 static void CaptureWrapper_stop(CaptureWrapper
*self
);
671 static ALCenum
CaptureWrapper_captureSamples(CaptureWrapper
*self
, void *buffer
, ALCuint samples
);
672 static ALCuint
CaptureWrapper_availableSamples(CaptureWrapper
*self
);
673 static DECLARE_FORWARD(CaptureWrapper
, ALCbackend
, ClockLatency
, getClockLatency
)
674 static DECLARE_FORWARD(CaptureWrapper
, ALCbackend
, void, lock
)
675 static DECLARE_FORWARD(CaptureWrapper
, ALCbackend
, void, unlock
)
676 DECLARE_DEFAULT_ALLOCATORS(CaptureWrapper
)
677 DEFINE_ALCBACKEND_VTABLE(CaptureWrapper
);
680 static ALCenum
qsa_open_capture(CaptureWrapper
*self
, const ALCchar
*deviceName
)
682 ALCdevice
*device
= STATIC_CAST(ALCbackend
,self
)->mDevice
;
688 data
=(qsa_data
*)calloc(1, sizeof(qsa_data
));
691 return ALC_OUT_OF_MEMORY
;
695 deviceName
= qsaDevice
;
697 if(strcmp(deviceName
, qsaDevice
) == 0)
698 status
= snd_pcm_open_preferred(&data
->pcmHandle
, &card
, &dev
, SND_PCM_OPEN_CAPTURE
);
703 if(VECTOR_SIZE(CaptureNameMap
) == 0)
704 deviceList(SND_PCM_CHANNEL_CAPTURE
, &CaptureNameMap
);
706 #define MATCH_DEVNAME(iter) ((iter)->name && strcmp(deviceName, (iter)->name)==0)
707 VECTOR_FIND_IF(iter
, const DevMap
, CaptureNameMap
, MATCH_DEVNAME
);
709 if(iter
== VECTOR_END(CaptureNameMap
))
712 return ALC_INVALID_DEVICE
;
715 status
= snd_pcm_open(&data
->pcmHandle
, iter
->card
, iter
->dev
, SND_PCM_OPEN_CAPTURE
);
721 return ALC_INVALID_DEVICE
;
724 data
->audio_fd
= snd_pcm_file_descriptor(data
->pcmHandle
, SND_PCM_CHANNEL_CAPTURE
);
725 if(data
->audio_fd
< 0)
727 snd_pcm_close(data
->pcmHandle
);
729 return ALC_INVALID_DEVICE
;
732 alstr_copy_cstr(&device
->DeviceName
, deviceName
);
733 self
->ExtraData
= data
;
735 switch (device
->FmtType
)
738 format
=SND_PCM_SFMT_S8
;
741 format
=SND_PCM_SFMT_U8
;
744 format
=SND_PCM_SFMT_S16_LE
;
747 format
=SND_PCM_SFMT_U16_LE
;
750 format
=SND_PCM_SFMT_S32_LE
;
753 format
=SND_PCM_SFMT_U32_LE
;
756 format
=SND_PCM_SFMT_FLOAT_LE
;
760 /* we actually don't want to block on reads */
761 snd_pcm_nonblock_mode(data
->pcmHandle
, 1);
762 /* Disable mmap to control data transfer to the audio device */
763 snd_pcm_plugin_set_disable(data
->pcmHandle
, PLUGIN_DISABLE_MMAP
);
765 /* configure a sound channel */
766 memset(&data
->cparams
, 0, sizeof(data
->cparams
));
767 data
->cparams
.mode
=SND_PCM_MODE_BLOCK
;
768 data
->cparams
.channel
=SND_PCM_CHANNEL_CAPTURE
;
769 data
->cparams
.start_mode
=SND_PCM_START_GO
;
770 data
->cparams
.stop_mode
=SND_PCM_STOP_STOP
;
772 data
->cparams
.buf
.block
.frag_size
=device
->UpdateSize
*
773 FrameSizeFromDevFmt(device
->FmtChans
, device
->FmtType
, device
->AmbiOrder
);
774 data
->cparams
.buf
.block
.frags_max
=device
->NumUpdates
;
775 data
->cparams
.buf
.block
.frags_min
=device
->NumUpdates
;
777 data
->cparams
.format
.interleave
=1;
778 data
->cparams
.format
.rate
=device
->Frequency
;
779 data
->cparams
.format
.voices
=ChannelsFromDevFmt(device
->FmtChans
, device
->AmbiOrder
);
780 data
->cparams
.format
.format
=format
;
782 if(snd_pcm_plugin_params(data
->pcmHandle
, &data
->cparams
) < 0)
784 snd_pcm_close(data
->pcmHandle
);
787 return ALC_INVALID_VALUE
;
793 static void qsa_close_capture(CaptureWrapper
*self
)
795 qsa_data
*data
= self
->ExtraData
;
797 if (data
->pcmHandle
!=NULL
)
798 snd_pcm_close(data
->pcmHandle
);
801 self
->ExtraData
= NULL
;
804 static void qsa_start_capture(CaptureWrapper
*self
)
806 qsa_data
*data
= self
->ExtraData
;
809 if ((rstatus
=snd_pcm_plugin_prepare(data
->pcmHandle
, SND_PCM_CHANNEL_CAPTURE
))<0)
811 ERR("capture prepare failed: %s\n", snd_strerror(rstatus
));
815 memset(&data
->csetup
, 0, sizeof(data
->csetup
));
816 data
->csetup
.channel
=SND_PCM_CHANNEL_CAPTURE
;
817 if ((rstatus
=snd_pcm_plugin_setup(data
->pcmHandle
, &data
->csetup
))<0)
819 ERR("capture setup failed: %s\n", snd_strerror(rstatus
));
823 snd_pcm_capture_go(data
->pcmHandle
);
826 static void qsa_stop_capture(CaptureWrapper
*self
)
828 qsa_data
*data
= self
->ExtraData
;
829 snd_pcm_capture_flush(data
->pcmHandle
);
832 static ALCuint
qsa_available_samples(CaptureWrapper
*self
)
834 ALCdevice
*device
= STATIC_CAST(ALCbackend
,self
)->mDevice
;
835 qsa_data
*data
= self
->ExtraData
;
836 snd_pcm_channel_status_t status
;
837 ALint frame_size
= FrameSizeFromDevFmt(device
->FmtChans
, device
->FmtType
, device
->AmbiOrder
);
841 memset(&status
, 0, sizeof (status
));
842 status
.channel
=SND_PCM_CHANNEL_CAPTURE
;
843 snd_pcm_plugin_status(data
->pcmHandle
, &status
);
844 if ((status
.status
==SND_PCM_STATUS_OVERRUN
) ||
845 (status
.status
==SND_PCM_STATUS_READY
))
847 if ((rstatus
=snd_pcm_plugin_prepare(data
->pcmHandle
, SND_PCM_CHANNEL_CAPTURE
))<0)
849 ERR("capture prepare failed: %s\n", snd_strerror(rstatus
));
850 aluHandleDisconnect(device
, "Failed capture recovery: %s", snd_strerror(rstatus
));
854 snd_pcm_capture_go(data
->pcmHandle
);
858 free_size
=data
->csetup
.buf
.block
.frag_size
*data
->csetup
.buf
.block
.frags
;
859 free_size
-=status
.free
;
861 return free_size
/frame_size
;
864 static ALCenum
qsa_capture_samples(CaptureWrapper
*self
, ALCvoid
*buffer
, ALCuint samples
)
866 ALCdevice
*device
= STATIC_CAST(ALCbackend
,self
)->mDevice
;
867 qsa_data
*data
= self
->ExtraData
;
869 snd_pcm_channel_status_t status
;
872 struct timeval timeout
;
874 ALint frame_size
=FrameSizeFromDevFmt(device
->FmtChans
, device
->FmtType
, device
->AmbiOrder
);
875 ALint len
=samples
*frame_size
;
883 FD_SET(data
->audio_fd
, &rfds
);
887 /* Select also works like time slice to OS */
889 selectret
=select(data
->audio_fd
+1, &rfds
, NULL
, NULL
, &timeout
);
893 aluHandleDisconnect(device
, "Failed to check capture samples");
894 return ALC_INVALID_DEVICE
;
898 if (FD_ISSET(data
->audio_fd
, &rfds
))
900 bytes_read
=snd_pcm_plugin_read(data
->pcmHandle
, read_ptr
, len
);
908 if ((errno
==EAGAIN
) || (errno
==EWOULDBLOCK
))
913 memset(&status
, 0, sizeof (status
));
914 status
.channel
=SND_PCM_CHANNEL_CAPTURE
;
915 snd_pcm_plugin_status(data
->pcmHandle
, &status
);
917 /* we need to reinitialize the sound channel if we've overrun the buffer */
918 if ((status
.status
==SND_PCM_STATUS_OVERRUN
) ||
919 (status
.status
==SND_PCM_STATUS_READY
))
921 if ((rstatus
=snd_pcm_plugin_prepare(data
->pcmHandle
, SND_PCM_CHANNEL_CAPTURE
))<0)
923 ERR("capture prepare failed: %s\n", snd_strerror(rstatus
));
924 aluHandleDisconnect(device
, "Failed capture recovery: %s",
925 snd_strerror(rstatus
));
926 return ALC_INVALID_DEVICE
;
928 snd_pcm_capture_go(data
->pcmHandle
);
933 read_ptr
+=bytes_read
;
942 static void CaptureWrapper_Construct(CaptureWrapper
*self
, ALCdevice
*device
)
944 ALCbackend_Construct(STATIC_CAST(ALCbackend
, self
), device
);
945 SET_VTABLE2(CaptureWrapper
, ALCbackend
, self
);
947 self
->ExtraData
= NULL
;
950 static void CaptureWrapper_Destruct(CaptureWrapper
*self
)
953 qsa_close_capture(self
);
955 ALCbackend_Destruct(STATIC_CAST(ALCbackend
, self
));
958 static ALCenum
CaptureWrapper_open(CaptureWrapper
*self
, const ALCchar
*name
)
960 return qsa_open_capture(self
, name
);
963 static ALCboolean
CaptureWrapper_start(CaptureWrapper
*self
)
965 qsa_start_capture(self
);
969 static void CaptureWrapper_stop(CaptureWrapper
*self
)
971 qsa_stop_capture(self
);
974 static ALCenum
CaptureWrapper_captureSamples(CaptureWrapper
*self
, void *buffer
, ALCuint samples
)
976 return qsa_capture_samples(self
, buffer
, samples
);
979 static ALCuint
CaptureWrapper_availableSamples(CaptureWrapper
*self
)
981 return qsa_available_samples(self
);
985 typedef struct ALCqsaBackendFactory
{
986 DERIVE_FROM_TYPE(ALCbackendFactory
);
987 } ALCqsaBackendFactory
;
988 #define ALCQSABACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCqsaBackendFactory, ALCbackendFactory) } }
990 static ALCboolean
ALCqsaBackendFactory_init(ALCqsaBackendFactory
* UNUSED(self
));
991 static void ALCqsaBackendFactory_deinit(ALCqsaBackendFactory
* UNUSED(self
));
992 static ALCboolean
ALCqsaBackendFactory_querySupport(ALCqsaBackendFactory
* UNUSED(self
), ALCbackend_Type type
);
993 static void ALCqsaBackendFactory_probe(ALCqsaBackendFactory
* UNUSED(self
), enum DevProbe type
);
994 static ALCbackend
* ALCqsaBackendFactory_createBackend(ALCqsaBackendFactory
* UNUSED(self
), ALCdevice
*device
, ALCbackend_Type type
);
995 DEFINE_ALCBACKENDFACTORY_VTABLE(ALCqsaBackendFactory
);
997 static ALCboolean
ALCqsaBackendFactory_init(ALCqsaBackendFactory
* UNUSED(self
))
1002 static void ALCqsaBackendFactory_deinit(ALCqsaBackendFactory
* UNUSED(self
))
1004 #define FREE_NAME(iter) free((iter)->name)
1005 VECTOR_FOR_EACH(DevMap
, DeviceNameMap
, FREE_NAME
);
1006 VECTOR_DEINIT(DeviceNameMap
);
1008 VECTOR_FOR_EACH(DevMap
, CaptureNameMap
, FREE_NAME
);
1009 VECTOR_DEINIT(CaptureNameMap
);
1013 static ALCboolean
ALCqsaBackendFactory_querySupport(ALCqsaBackendFactory
* UNUSED(self
), ALCbackend_Type type
)
1015 if(type
== ALCbackend_Playback
|| type
== ALCbackend_Capture
)
1020 static void ALCqsaBackendFactory_probe(ALCqsaBackendFactory
* UNUSED(self
), enum DevProbe type
)
1024 case ALL_DEVICE_PROBE
:
1025 #define FREE_NAME(iter) free((iter)->name)
1026 VECTOR_FOR_EACH(DevMap
, DeviceNameMap
, FREE_NAME
);
1027 VECTOR_RESIZE(DeviceNameMap
, 0, 0);
1030 deviceList(SND_PCM_CHANNEL_PLAYBACK
, &DeviceNameMap
);
1031 #define APPEND_DEVICE(iter) AppendAllDevicesList((iter)->name)
1032 VECTOR_FOR_EACH(const DevMap
, DeviceNameMap
, APPEND_DEVICE
);
1033 #undef APPEND_DEVICE
1036 case CAPTURE_DEVICE_PROBE
:
1037 #define FREE_NAME(iter) free((iter)->name)
1038 VECTOR_FOR_EACH(DevMap
, CaptureNameMap
, FREE_NAME
);
1039 VECTOR_RESIZE(CaptureNameMap
, 0, 0);
1042 deviceList(SND_PCM_CHANNEL_CAPTURE
, &CaptureNameMap
);
1043 #define APPEND_DEVICE(iter) AppendCaptureDeviceList((iter)->name)
1044 VECTOR_FOR_EACH(const DevMap
, CaptureNameMap
, APPEND_DEVICE
);
1045 #undef APPEND_DEVICE
1050 static ALCbackend
* ALCqsaBackendFactory_createBackend(ALCqsaBackendFactory
* UNUSED(self
), ALCdevice
*device
, ALCbackend_Type type
)
1052 if(type
== ALCbackend_Playback
)
1054 PlaybackWrapper
*backend
;
1055 NEW_OBJ(backend
, PlaybackWrapper
)(device
);
1056 if(!backend
) return NULL
;
1057 return STATIC_CAST(ALCbackend
, backend
);
1059 if(type
== ALCbackend_Capture
)
1061 CaptureWrapper
*backend
;
1062 NEW_OBJ(backend
, CaptureWrapper
)(device
);
1063 if(!backend
) return NULL
;
1064 return STATIC_CAST(ALCbackend
, backend
);
1070 ALCbackendFactory
*ALCqsaBackendFactory_getFactory(void)
1072 static ALCqsaBackendFactory factory
= ALCQSABACKENDFACTORY_INITIALIZER
;
1073 return STATIC_CAST(ALCbackendFactory
, &factory
);