Add a comment about CoeffCount being 0
[openal-soft.git] / Alc / backends / qsa.c
bloba1fbce636afdac4aac7029246932555a568f31bf
1 /**
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
21 #include "config.h"
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <sched.h>
26 #include <errno.h>
27 #include <memory.h>
28 #include <sys/select.h>
29 #include <sys/asoundlib.h>
30 #include <sys/neutrino.h>
32 #include "alMain.h"
33 #include "alu.h"
34 #include "threads.h"
37 typedef struct {
38 snd_pcm_t* pcmHandle;
39 int audio_fd;
41 snd_pcm_channel_setup_t csetup;
42 snd_pcm_channel_params_t cparams;
44 ALvoid* buffer;
45 ALsizei size;
47 volatile int killNow;
48 althrd_t thread;
49 } qsa_data;
51 typedef struct {
52 ALCchar* name;
53 int card;
54 int dev;
55 } DevMap;
56 TYPEDEF_VECTOR(DevMap, vector_DevMap)
58 static vector_DevMap DeviceNameMap;
59 static vector_DevMap CaptureNameMap;
61 static const ALCchar qsaDevice[] = "QSA Default";
63 static const struct {
64 int32_t format;
65 } formatlist[] = {
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},
71 {SND_PCM_SFMT_S8},
72 {SND_PCM_SFMT_U8},
73 {0},
76 static const struct {
77 int32_t rate;
78 } ratelist[] = {
79 {192000},
80 {176400},
81 {96000},
82 {88200},
83 {48000},
84 {44100},
85 {32000},
86 {24000},
87 {22050},
88 {16000},
89 {12000},
90 {11025},
91 {8000},
92 {0},
95 static const struct {
96 int32_t channels;
97 } channellist[] = {
98 {8},
99 {7},
100 {6},
101 {4},
102 {2},
103 {1},
104 {0},
107 static void deviceList(int type, vector_DevMap *devmap)
109 snd_ctl_t* handle;
110 snd_pcm_info_t pcminfo;
111 int max_cards, card, err, dev;
112 DevMap entry;
113 char name[1024];
114 struct snd_ctl_hw_info info;
116 max_cards = snd_cards();
117 if(max_cards < 0)
118 return;
120 VECTOR_RESERVE(*devmap, max_cards+1);
121 VECTOR_RESIZE(*devmap, 0);
123 entry.name = strdup(qsaDevice);
124 entry.card = 0;
125 entry.dev = 0;
126 VECTOR_PUSH_BACK(*devmap, entry);
128 for(card = 0;card < max_cards;card++)
130 if((err=snd_ctl_open(&handle, card)) < 0)
131 continue;
133 if((err=snd_ctl_hw_info(handle, &info)) < 0)
135 snd_ctl_close(handle);
136 continue;
139 for(dev = 0;dev < (int)info.pcmdevs;dev++)
141 if((err=snd_ctl_pcm_info(handle, dev, &pcminfo)) < 0)
142 continue;
144 if((type==SND_PCM_CHANNEL_PLAYBACK && (pcminfo.flags&SND_PCM_INFO_PLAYBACK)) ||
145 (type==SND_PCM_CHANNEL_CAPTURE && (pcminfo.flags&SND_PCM_INFO_CAPTURE)))
147 snprintf(name, sizeof(name), "%s [%s] (hw:%d,%d)", info.name, pcminfo.name, card, dev);
148 entry.name = strdup(name);
149 entry.card = card;
150 entry.dev = dev;
152 VECTOR_PUSH_BACK(*devmap, entry);
153 TRACE("Got device \"%s\", card %d, dev %d\n", name, card, dev);
156 snd_ctl_close(handle);
161 FORCE_ALIGN static int qsa_proc_playback(void* ptr)
163 ALCdevice* device=(ALCdevice*)ptr;
164 qsa_data* data=(qsa_data*)device->ExtraData;
165 char* write_ptr;
166 int avail;
167 snd_pcm_channel_status_t status;
168 struct sched_param param;
169 fd_set wfds;
170 int selectret;
171 struct timeval timeout;
173 SetRTPriority();
174 althrd_setname(althrd_current(), MIXER_THREAD_NAME);
176 /* Increase default 10 priority to 11 to avoid jerky sound */
177 SchedGet(0, 0, &param);
178 param.sched_priority=param.sched_curpriority+1;
179 SchedSet(0, 0, SCHED_NOCHANGE, &param);
181 ALint frame_size=FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
183 while (!data->killNow)
185 ALint len=data->size;
186 write_ptr=data->buffer;
188 avail=len/frame_size;
189 aluMixData(device, write_ptr, avail);
191 while (len>0 && !data->killNow)
193 FD_ZERO(&wfds);
194 FD_SET(data->audio_fd, &wfds);
195 timeout.tv_sec=2;
196 timeout.tv_usec=0;
198 /* Select also works like time slice to OS */
199 selectret=select(data->audio_fd+1, NULL, &wfds, NULL, &timeout);
200 switch (selectret)
202 case -1:
203 aluHandleDisconnect(device);
204 return 1;
205 case 0:
206 break;
207 default:
208 if (FD_ISSET(data->audio_fd, &wfds))
210 break;
212 break;
215 int wrote=snd_pcm_plugin_write(data->pcmHandle, write_ptr, len);
217 if (wrote<=0)
219 if ((errno==EAGAIN) || (errno==EWOULDBLOCK))
221 continue;
224 memset(&status, 0, sizeof (status));
225 status.channel=SND_PCM_CHANNEL_PLAYBACK;
227 snd_pcm_plugin_status(data->pcmHandle, &status);
229 /* we need to reinitialize the sound channel if we've underrun the buffer */
230 if ((status.status==SND_PCM_STATUS_UNDERRUN) ||
231 (status.status==SND_PCM_STATUS_READY))
233 if ((snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_PLAYBACK))<0)
235 aluHandleDisconnect(device);
236 break;
240 else
242 write_ptr+=wrote;
243 len-=wrote;
248 return 0;
251 /************/
252 /* Playback */
253 /************/
255 static ALCenum qsa_open_playback(ALCdevice* device, const ALCchar* deviceName)
257 qsa_data *data;
258 int card, dev;
259 int status;
261 data = (qsa_data*)calloc(1, sizeof(qsa_data));
262 if(data == NULL)
263 return ALC_OUT_OF_MEMORY;
265 if(!deviceName)
266 deviceName = qsaDevice;
268 if(strcmp(deviceName, qsaDevice) == 0)
269 status = snd_pcm_open_preferred(&data->pcmHandle, &card, &dev, SND_PCM_OPEN_PLAYBACK);
270 else
272 const DevMap *iter;
274 if(VECTOR_SIZE(DeviceNameMap) == 0)
275 deviceList(SND_PCM_CHANNEL_PLAYBACK, &DeviceNameMap);
277 #define MATCH_DEVNAME(iter) ((iter)->name && strcmp(deviceName, (iter)->name)==0)
278 VECTOR_FIND_IF(iter, const DevMap, DeviceNameMap, MATCH_DEVNAME);
279 #undef MATCH_DEVNAME
280 if(iter == VECTOR_END(DeviceNameMap))
282 free(data);
283 return ALC_INVALID_DEVICE;
286 status = snd_pcm_open(&data->pcmHandle, iter->card, iter->dev, SND_PCM_OPEN_PLAYBACK);
289 if(status < 0)
291 free(data);
292 return ALC_INVALID_DEVICE;
295 data->audio_fd = snd_pcm_file_descriptor(data->pcmHandle, SND_PCM_CHANNEL_PLAYBACK);
296 if(data->audio_fd < 0)
298 snd_pcm_close(data->pcmHandle);
299 free(data);
300 return ALC_INVALID_DEVICE;
303 al_string_copy_cstr(&device->DeviceName, deviceName);
304 device->ExtraData = data;
306 return ALC_NO_ERROR;
309 static void qsa_close_playback(ALCdevice* device)
311 qsa_data* data=(qsa_data*)device->ExtraData;
313 if (data->buffer!=NULL)
315 free(data->buffer);
316 data->buffer=NULL;
319 snd_pcm_close(data->pcmHandle);
320 free(data);
322 device->ExtraData=NULL;
325 static ALCboolean qsa_reset_playback(ALCdevice* device)
327 qsa_data* data=(qsa_data*)device->ExtraData;
328 int32_t format=-1;
330 switch(device->FmtType)
332 case DevFmtByte:
333 format=SND_PCM_SFMT_S8;
334 break;
335 case DevFmtUByte:
336 format=SND_PCM_SFMT_U8;
337 break;
338 case DevFmtShort:
339 format=SND_PCM_SFMT_S16_LE;
340 break;
341 case DevFmtUShort:
342 format=SND_PCM_SFMT_U16_LE;
343 break;
344 case DevFmtInt:
345 format=SND_PCM_SFMT_S32_LE;
346 break;
347 case DevFmtUInt:
348 format=SND_PCM_SFMT_U32_LE;
349 break;
350 case DevFmtFloat:
351 format=SND_PCM_SFMT_FLOAT_LE;
352 break;
355 /* we actually don't want to block on writes */
356 snd_pcm_nonblock_mode(data->pcmHandle, 1);
357 /* Disable mmap to control data transfer to the audio device */
358 snd_pcm_plugin_set_disable(data->pcmHandle, PLUGIN_DISABLE_MMAP);
359 snd_pcm_plugin_set_disable(data->pcmHandle, PLUGIN_DISABLE_BUFFER_PARTIAL_BLOCKS);
361 // configure a sound channel
362 memset(&data->cparams, 0, sizeof(data->cparams));
363 data->cparams.channel=SND_PCM_CHANNEL_PLAYBACK;
364 data->cparams.mode=SND_PCM_MODE_BLOCK;
365 data->cparams.start_mode=SND_PCM_START_FULL;
366 data->cparams.stop_mode=SND_PCM_STOP_STOP;
368 data->cparams.buf.block.frag_size=device->UpdateSize*
369 ChannelsFromDevFmt(device->FmtChans)*BytesFromDevFmt(device->FmtType);
370 data->cparams.buf.block.frags_max=device->NumUpdates;
371 data->cparams.buf.block.frags_min=device->NumUpdates;
373 data->cparams.format.interleave=1;
374 data->cparams.format.rate=device->Frequency;
375 data->cparams.format.voices=ChannelsFromDevFmt(device->FmtChans);
376 data->cparams.format.format=format;
378 if ((snd_pcm_plugin_params(data->pcmHandle, &data->cparams))<0)
380 int original_rate=data->cparams.format.rate;
381 int original_voices=data->cparams.format.voices;
382 int original_format=data->cparams.format.format;
383 int it;
384 int jt;
386 for (it=0; it<1; it++)
388 /* Check for second pass */
389 if (it==1)
391 original_rate=ratelist[0].rate;
392 original_voices=channellist[0].channels;
393 original_format=formatlist[0].format;
396 do {
397 /* At first downgrade sample format */
398 jt=0;
399 do {
400 if (formatlist[jt].format==data->cparams.format.format)
402 data->cparams.format.format=formatlist[jt+1].format;
403 break;
405 if (formatlist[jt].format==0)
407 data->cparams.format.format=0;
408 break;
410 jt++;
411 } while(1);
413 if (data->cparams.format.format==0)
415 data->cparams.format.format=original_format;
417 /* At secod downgrade sample rate */
418 jt=0;
419 do {
420 if (ratelist[jt].rate==data->cparams.format.rate)
422 data->cparams.format.rate=ratelist[jt+1].rate;
423 break;
425 if (ratelist[jt].rate==0)
427 data->cparams.format.rate=0;
428 break;
430 jt++;
431 } while(1);
433 if (data->cparams.format.rate==0)
435 data->cparams.format.rate=original_rate;
436 data->cparams.format.format=original_format;
438 /* At third downgrade channels number */
439 jt=0;
440 do {
441 if(channellist[jt].channels==data->cparams.format.voices)
443 data->cparams.format.voices=channellist[jt+1].channels;
444 break;
446 if (channellist[jt].channels==0)
448 data->cparams.format.voices=0;
449 break;
451 jt++;
452 } while(1);
455 if (data->cparams.format.voices==0)
457 break;
461 data->cparams.buf.block.frag_size=device->UpdateSize*
462 data->cparams.format.voices*
463 snd_pcm_format_width(data->cparams.format.format)/8;
464 data->cparams.buf.block.frags_max=device->NumUpdates;
465 data->cparams.buf.block.frags_min=device->NumUpdates;
466 if ((snd_pcm_plugin_params(data->pcmHandle, &data->cparams))<0)
468 continue;
470 else
472 break;
474 } while(1);
476 if (data->cparams.format.voices!=0)
478 break;
482 if (data->cparams.format.voices==0)
484 return ALC_FALSE;
488 if ((snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_PLAYBACK))<0)
490 return ALC_FALSE;
493 memset(&data->csetup, 0, sizeof(data->csetup));
494 data->csetup.channel=SND_PCM_CHANNEL_PLAYBACK;
495 if (snd_pcm_plugin_setup(data->pcmHandle, &data->csetup)<0)
497 return ALC_FALSE;
500 /* now fill back to the our AL device */
501 device->Frequency=data->cparams.format.rate;
503 switch (data->cparams.format.voices)
505 case 1:
506 device->FmtChans=DevFmtMono;
507 break;
508 case 2:
509 device->FmtChans=DevFmtStereo;
510 break;
511 case 4:
512 device->FmtChans=DevFmtQuad;
513 break;
514 case 6:
515 device->FmtChans=DevFmtX51;
516 break;
517 case 7:
518 device->FmtChans=DevFmtX61;
519 break;
520 case 8:
521 device->FmtChans=DevFmtX71;
522 break;
523 default:
524 device->FmtChans=DevFmtMono;
525 break;
528 switch (data->cparams.format.format)
530 case SND_PCM_SFMT_S8:
531 device->FmtType=DevFmtByte;
532 break;
533 case SND_PCM_SFMT_U8:
534 device->FmtType=DevFmtUByte;
535 break;
536 case SND_PCM_SFMT_S16_LE:
537 device->FmtType=DevFmtShort;
538 break;
539 case SND_PCM_SFMT_U16_LE:
540 device->FmtType=DevFmtUShort;
541 break;
542 case SND_PCM_SFMT_S32_LE:
543 device->FmtType=DevFmtInt;
544 break;
545 case SND_PCM_SFMT_U32_LE:
546 device->FmtType=DevFmtUInt;
547 break;
548 case SND_PCM_SFMT_FLOAT_LE:
549 device->FmtType=DevFmtFloat;
550 break;
551 default:
552 device->FmtType=DevFmtShort;
553 break;
556 SetDefaultChannelOrder(device);
558 device->UpdateSize=data->csetup.buf.block.frag_size/
559 (ChannelsFromDevFmt(device->FmtChans)*BytesFromDevFmt(device->FmtType));
560 device->NumUpdates=data->csetup.buf.block.frags;
562 data->size=data->csetup.buf.block.frag_size;
563 data->buffer=malloc(data->size);
564 if (!data->buffer)
566 return ALC_FALSE;
569 return ALC_TRUE;
572 static ALCboolean qsa_start_playback(ALCdevice* device)
574 qsa_data *data = (qsa_data*)device->ExtraData;
576 data->killNow = 0;
577 if(althrd_create(&data->thread, qsa_proc_playback, device) != althrd_success)
578 return ALC_FALSE;
580 return ALC_TRUE;
583 static void qsa_stop_playback(ALCdevice* device)
585 qsa_data *data = (qsa_data*)device->ExtraData;
586 int res;
588 if(data->killNow)
589 return;
591 data->killNow = 1;
592 althrd_join(data->thread, &res);
595 /***********/
596 /* Capture */
597 /***********/
599 static ALCenum qsa_open_capture(ALCdevice* device, const ALCchar* deviceName)
601 qsa_data *data;
602 int card, dev;
603 int format=-1;
604 int status;
606 data=(qsa_data*)calloc(1, sizeof(qsa_data));
607 if (data==NULL)
609 return ALC_OUT_OF_MEMORY;
612 if(!deviceName)
613 deviceName = qsaDevice;
615 if(strcmp(deviceName, qsaDevice) == 0)
616 status = snd_pcm_open_preferred(&data->pcmHandle, &card, &dev, SND_PCM_OPEN_CAPTURE);
617 else
619 const DevMap *iter;
621 if(VECTOR_SIZE(CaptureNameMap) == 0)
622 deviceList(SND_PCM_CHANNEL_CAPTURE, &CaptureNameMap);
624 #define MATCH_DEVNAME(iter) ((iter)->name && strcmp(deviceName, (iter)->name)==0)
625 VECTOR_FIND_IF(iter, const DevMap, CaptureNameMap, MATCH_DEVNAME);
626 #undef MATCH_DEVNAME
627 if(iter == VECTOR_END(CaptureNameMap))
629 free(data);
630 return ALC_INVALID_DEVICE;
633 status = snd_pcm_open(&data->pcmHandle, iter->card, iter->dev, SND_PCM_OPEN_CAPTURE);
636 if(status < 0)
638 free(data);
639 return ALC_INVALID_DEVICE;
642 data->audio_fd = snd_pcm_file_descriptor(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE);
643 if(data->audio_fd < 0)
645 snd_pcm_close(data->pcmHandle);
646 free(data);
647 return ALC_INVALID_DEVICE;
650 al_string_copy_cstr(&device->DeviceName, deviceName);
651 device->ExtraData = data;
653 switch (device->FmtType)
655 case DevFmtByte:
656 format=SND_PCM_SFMT_S8;
657 break;
658 case DevFmtUByte:
659 format=SND_PCM_SFMT_U8;
660 break;
661 case DevFmtShort:
662 format=SND_PCM_SFMT_S16_LE;
663 break;
664 case DevFmtUShort:
665 format=SND_PCM_SFMT_U16_LE;
666 break;
667 case DevFmtInt:
668 format=SND_PCM_SFMT_S32_LE;
669 break;
670 case DevFmtUInt:
671 format=SND_PCM_SFMT_U32_LE;
672 break;
673 case DevFmtFloat:
674 format=SND_PCM_SFMT_FLOAT_LE;
675 break;
678 /* we actually don't want to block on reads */
679 snd_pcm_nonblock_mode(data->pcmHandle, 1);
680 /* Disable mmap to control data transfer to the audio device */
681 snd_pcm_plugin_set_disable(data->pcmHandle, PLUGIN_DISABLE_MMAP);
683 /* configure a sound channel */
684 memset(&data->cparams, 0, sizeof(data->cparams));
685 data->cparams.mode=SND_PCM_MODE_BLOCK;
686 data->cparams.channel=SND_PCM_CHANNEL_CAPTURE;
687 data->cparams.start_mode=SND_PCM_START_GO;
688 data->cparams.stop_mode=SND_PCM_STOP_STOP;
690 data->cparams.buf.block.frag_size=device->UpdateSize*
691 ChannelsFromDevFmt(device->FmtChans)*BytesFromDevFmt(device->FmtType);
692 data->cparams.buf.block.frags_max=device->NumUpdates;
693 data->cparams.buf.block.frags_min=device->NumUpdates;
695 data->cparams.format.interleave=1;
696 data->cparams.format.rate=device->Frequency;
697 data->cparams.format.voices=ChannelsFromDevFmt(device->FmtChans);
698 data->cparams.format.format=format;
700 if(snd_pcm_plugin_params(data->pcmHandle, &data->cparams) < 0)
702 snd_pcm_close(data->pcmHandle);
703 free(data);
704 device->ExtraData=NULL;
706 return ALC_INVALID_VALUE;
709 return ALC_NO_ERROR;
712 static void qsa_close_capture(ALCdevice* device)
714 qsa_data* data=(qsa_data*)device->ExtraData;
716 if (data->pcmHandle!=NULL)
717 snd_pcm_close(data->pcmHandle);
719 free(data);
720 device->ExtraData=NULL;
723 static void qsa_start_capture(ALCdevice* device)
725 qsa_data* data=(qsa_data*)device->ExtraData;
726 int rstatus;
728 if ((rstatus=snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE))<0)
730 ERR("capture prepare failed: %s\n", snd_strerror(rstatus));
731 return;
734 memset(&data->csetup, 0, sizeof(data->csetup));
735 data->csetup.channel=SND_PCM_CHANNEL_CAPTURE;
736 if ((rstatus=snd_pcm_plugin_setup(data->pcmHandle, &data->csetup))<0)
738 ERR("capture setup failed: %s\n", snd_strerror(rstatus));
739 return;
742 snd_pcm_capture_go(data->pcmHandle);
745 static void qsa_stop_capture(ALCdevice* device)
747 qsa_data* data=(qsa_data*)device->ExtraData;
749 snd_pcm_capture_flush(data->pcmHandle);
752 static ALCuint qsa_available_samples(ALCdevice* device)
754 qsa_data* data=(qsa_data*)device->ExtraData;
755 snd_pcm_channel_status_t status;
756 ALint frame_size=FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
757 ALint free_size;
758 int rstatus;
760 memset(&status, 0, sizeof (status));
761 status.channel=SND_PCM_CHANNEL_CAPTURE;
762 snd_pcm_plugin_status(data->pcmHandle, &status);
763 if ((status.status==SND_PCM_STATUS_OVERRUN) ||
764 (status.status==SND_PCM_STATUS_READY))
766 if ((rstatus=snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE))<0)
768 ERR("capture prepare failed: %s\n", snd_strerror(rstatus));
769 aluHandleDisconnect(device);
770 return 0;
773 snd_pcm_capture_go(data->pcmHandle);
774 return 0;
777 free_size=data->csetup.buf.block.frag_size*data->csetup.buf.block.frags;
778 free_size-=status.free;
780 return free_size/frame_size;
783 static ALCenum qsa_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint samples)
785 qsa_data* data=(qsa_data*)device->ExtraData;
786 char* read_ptr;
787 snd_pcm_channel_status_t status;
788 fd_set rfds;
789 int selectret;
790 struct timeval timeout;
791 int bytes_read;
792 ALint frame_size=FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
793 ALint len=samples*frame_size;
794 int rstatus;
796 read_ptr=buffer;
798 while (len>0)
800 FD_ZERO(&rfds);
801 FD_SET(data->audio_fd, &rfds);
802 timeout.tv_sec=2;
803 timeout.tv_usec=0;
805 /* Select also works like time slice to OS */
806 bytes_read=0;
807 selectret=select(data->audio_fd+1, &rfds, NULL, NULL, &timeout);
808 switch (selectret)
810 case -1:
811 aluHandleDisconnect(device);
812 return ALC_INVALID_DEVICE;
813 case 0:
814 break;
815 default:
816 if (FD_ISSET(data->audio_fd, &rfds))
818 bytes_read=snd_pcm_plugin_read(data->pcmHandle, read_ptr, len);
819 break;
821 break;
824 if (bytes_read<=0)
826 if ((errno==EAGAIN) || (errno==EWOULDBLOCK))
828 continue;
831 memset(&status, 0, sizeof (status));
832 status.channel=SND_PCM_CHANNEL_CAPTURE;
833 snd_pcm_plugin_status(data->pcmHandle, &status);
835 /* we need to reinitialize the sound channel if we've overrun the buffer */
836 if ((status.status==SND_PCM_STATUS_OVERRUN) ||
837 (status.status==SND_PCM_STATUS_READY))
839 if ((rstatus=snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE))<0)
841 ERR("capture prepare failed: %s\n", snd_strerror(rstatus));
842 aluHandleDisconnect(device);
843 return ALC_INVALID_DEVICE;
845 snd_pcm_capture_go(data->pcmHandle);
848 else
850 read_ptr+=bytes_read;
851 len-=bytes_read;
855 return ALC_NO_ERROR;
858 static const BackendFuncs qsa_funcs= {
859 qsa_open_playback,
860 qsa_close_playback,
861 qsa_reset_playback,
862 qsa_start_playback,
863 qsa_stop_playback,
864 qsa_open_capture,
865 qsa_close_capture,
866 qsa_start_capture,
867 qsa_stop_capture,
868 qsa_capture_samples,
869 qsa_available_samples
872 ALCboolean alc_qsa_init(BackendFuncs* func_list)
874 *func_list = qsa_funcs;
875 return ALC_TRUE;
878 void alc_qsa_deinit(void)
880 #define FREE_NAME(iter) free((iter)->name)
881 VECTOR_FOR_EACH(DevMap, DeviceNameMap, FREE_NAME);
882 VECTOR_DEINIT(DeviceNameMap);
884 VECTOR_FOR_EACH(DevMap, CaptureNameMap, FREE_NAME);
885 VECTOR_DEINIT(CaptureNameMap);
886 #undef FREE_NAME
889 void alc_qsa_probe(enum DevProbe type)
891 switch (type)
893 case ALL_DEVICE_PROBE:
894 #define FREE_NAME(iter) free((iter)->name)
895 VECTOR_FOR_EACH(DevMap, DeviceNameMap, FREE_NAME);
896 #undef FREE_NAME
897 VECTOR_RESIZE(DeviceNameMap, 0);
899 deviceList(SND_PCM_CHANNEL_PLAYBACK, &DeviceNameMap);
900 #define APPEND_DEVICE(iter) AppendAllDevicesList((iter)->name)
901 VECTOR_FOR_EACH(const DevMap, DeviceNameMap, APPEND_DEVICE);
902 #undef APPEND_DEVICE
903 break;
905 case CAPTURE_DEVICE_PROBE:
906 #define FREE_NAME(iter) free((iter)->name)
907 VECTOR_FOR_EACH(DevMap, CaptureNameMap, FREE_NAME);
908 #undef FREE_NAME
909 VECTOR_RESIZE(CaptureNameMap, 0);
911 deviceList(SND_PCM_CHANNEL_CAPTURE, &CaptureNameMap);
912 #define APPEND_DEVICE(iter) AppendCaptureDeviceList((iter)->name)
913 VECTOR_FOR_EACH(const DevMap, CaptureNameMap, APPEND_DEVICE);
914 #undef APPEND_DEVICE
915 break;