Use a separate backend callback to start playback of the device
[openal-soft.git] / Alc / backends / alsa.c
blobfa5ef1a6273473a50678ac162f979fa058af5d73
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 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., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, 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 <memory.h>
27 #include "alMain.h"
29 #include <alsa/asoundlib.h>
32 static const ALCchar alsaDevice[] = "ALSA Default";
35 #ifdef HAVE_DYNLOAD
36 static void *alsa_handle;
37 #define MAKE_FUNC(f) static typeof(f) * p##f
38 MAKE_FUNC(snd_strerror);
39 MAKE_FUNC(snd_pcm_open);
40 MAKE_FUNC(snd_pcm_close);
41 MAKE_FUNC(snd_pcm_nonblock);
42 MAKE_FUNC(snd_pcm_frames_to_bytes);
43 MAKE_FUNC(snd_pcm_bytes_to_frames);
44 MAKE_FUNC(snd_pcm_hw_params_malloc);
45 MAKE_FUNC(snd_pcm_hw_params_free);
46 MAKE_FUNC(snd_pcm_hw_params_any);
47 MAKE_FUNC(snd_pcm_hw_params_current);
48 MAKE_FUNC(snd_pcm_hw_params_set_access);
49 MAKE_FUNC(snd_pcm_hw_params_set_format);
50 MAKE_FUNC(snd_pcm_hw_params_set_channels);
51 MAKE_FUNC(snd_pcm_hw_params_set_periods_near);
52 MAKE_FUNC(snd_pcm_hw_params_set_rate_near);
53 MAKE_FUNC(snd_pcm_hw_params_set_rate);
54 MAKE_FUNC(snd_pcm_hw_params_set_rate_resample);
55 MAKE_FUNC(snd_pcm_hw_params_set_buffer_time_near);
56 MAKE_FUNC(snd_pcm_hw_params_set_period_time_near);
57 MAKE_FUNC(snd_pcm_hw_params_set_buffer_size_near);
58 MAKE_FUNC(snd_pcm_hw_params_set_period_size_near);
59 MAKE_FUNC(snd_pcm_hw_params_set_buffer_size_min);
60 MAKE_FUNC(snd_pcm_hw_params_get_buffer_size);
61 MAKE_FUNC(snd_pcm_hw_params_get_period_size);
62 MAKE_FUNC(snd_pcm_hw_params_get_access);
63 MAKE_FUNC(snd_pcm_hw_params_get_periods);
64 MAKE_FUNC(snd_pcm_hw_params_test_format);
65 MAKE_FUNC(snd_pcm_hw_params_test_channels);
66 MAKE_FUNC(snd_pcm_hw_params);
67 MAKE_FUNC(snd_pcm_sw_params_malloc);
68 MAKE_FUNC(snd_pcm_sw_params_current);
69 MAKE_FUNC(snd_pcm_sw_params_set_avail_min);
70 MAKE_FUNC(snd_pcm_sw_params_set_stop_threshold);
71 MAKE_FUNC(snd_pcm_sw_params);
72 MAKE_FUNC(snd_pcm_sw_params_free);
73 MAKE_FUNC(snd_pcm_prepare);
74 MAKE_FUNC(snd_pcm_start);
75 MAKE_FUNC(snd_pcm_resume);
76 MAKE_FUNC(snd_pcm_reset);
77 MAKE_FUNC(snd_pcm_wait);
78 MAKE_FUNC(snd_pcm_state);
79 MAKE_FUNC(snd_pcm_avail_update);
80 MAKE_FUNC(snd_pcm_areas_silence);
81 MAKE_FUNC(snd_pcm_mmap_begin);
82 MAKE_FUNC(snd_pcm_mmap_commit);
83 MAKE_FUNC(snd_pcm_readi);
84 MAKE_FUNC(snd_pcm_writei);
85 MAKE_FUNC(snd_pcm_drain);
86 MAKE_FUNC(snd_pcm_drop);
87 MAKE_FUNC(snd_pcm_recover);
88 MAKE_FUNC(snd_pcm_info_malloc);
89 MAKE_FUNC(snd_pcm_info_free);
90 MAKE_FUNC(snd_pcm_info_set_device);
91 MAKE_FUNC(snd_pcm_info_set_subdevice);
92 MAKE_FUNC(snd_pcm_info_set_stream);
93 MAKE_FUNC(snd_pcm_info_get_name);
94 MAKE_FUNC(snd_ctl_pcm_next_device);
95 MAKE_FUNC(snd_ctl_pcm_info);
96 MAKE_FUNC(snd_ctl_open);
97 MAKE_FUNC(snd_ctl_close);
98 MAKE_FUNC(snd_ctl_card_info_malloc);
99 MAKE_FUNC(snd_ctl_card_info_free);
100 MAKE_FUNC(snd_ctl_card_info);
101 MAKE_FUNC(snd_ctl_card_info_get_name);
102 MAKE_FUNC(snd_ctl_card_info_get_id);
103 MAKE_FUNC(snd_card_next);
104 #undef MAKE_FUNC
106 #define snd_strerror psnd_strerror
107 #define snd_pcm_open psnd_pcm_open
108 #define snd_pcm_close psnd_pcm_close
109 #define snd_pcm_nonblock psnd_pcm_nonblock
110 #define snd_pcm_frames_to_bytes psnd_pcm_frames_to_bytes
111 #define snd_pcm_bytes_to_frames psnd_pcm_bytes_to_frames
112 #define snd_pcm_hw_params_malloc psnd_pcm_hw_params_malloc
113 #define snd_pcm_hw_params_free psnd_pcm_hw_params_free
114 #define snd_pcm_hw_params_any psnd_pcm_hw_params_any
115 #define snd_pcm_hw_params_current psnd_pcm_hw_params_current
116 #define snd_pcm_hw_params_set_access psnd_pcm_hw_params_set_access
117 #define snd_pcm_hw_params_set_format psnd_pcm_hw_params_set_format
118 #define snd_pcm_hw_params_set_channels psnd_pcm_hw_params_set_channels
119 #define snd_pcm_hw_params_set_periods_near psnd_pcm_hw_params_set_periods_near
120 #define snd_pcm_hw_params_set_rate_near psnd_pcm_hw_params_set_rate_near
121 #define snd_pcm_hw_params_set_rate psnd_pcm_hw_params_set_rate
122 #define snd_pcm_hw_params_set_rate_resample psnd_pcm_hw_params_set_rate_resample
123 #define snd_pcm_hw_params_set_buffer_time_near psnd_pcm_hw_params_set_buffer_time_near
124 #define snd_pcm_hw_params_set_period_time_near psnd_pcm_hw_params_set_period_time_near
125 #define snd_pcm_hw_params_set_buffer_size_near psnd_pcm_hw_params_set_buffer_size_near
126 #define snd_pcm_hw_params_set_period_size_near psnd_pcm_hw_params_set_period_size_near
127 #define snd_pcm_hw_params_set_buffer_size_min psnd_pcm_hw_params_set_buffer_size_min
128 #define snd_pcm_hw_params_get_buffer_size psnd_pcm_hw_params_get_buffer_size
129 #define snd_pcm_hw_params_get_period_size psnd_pcm_hw_params_get_period_size
130 #define snd_pcm_hw_params_get_access psnd_pcm_hw_params_get_access
131 #define snd_pcm_hw_params_get_periods psnd_pcm_hw_params_get_periods
132 #define snd_pcm_hw_params_test_format psnd_pcm_hw_params_test_format
133 #define snd_pcm_hw_params_test_channels psnd_pcm_hw_params_test_channels
134 #define snd_pcm_hw_params psnd_pcm_hw_params
135 #define snd_pcm_sw_params_malloc psnd_pcm_sw_params_malloc
136 #define snd_pcm_sw_params_current psnd_pcm_sw_params_current
137 #define snd_pcm_sw_params_set_avail_min psnd_pcm_sw_params_set_avail_min
138 #define snd_pcm_sw_params_set_stop_threshold psnd_pcm_sw_params_set_stop_threshold
139 #define snd_pcm_sw_params psnd_pcm_sw_params
140 #define snd_pcm_sw_params_free psnd_pcm_sw_params_free
141 #define snd_pcm_prepare psnd_pcm_prepare
142 #define snd_pcm_start psnd_pcm_start
143 #define snd_pcm_resume psnd_pcm_resume
144 #define snd_pcm_reset psnd_pcm_reset
145 #define snd_pcm_wait psnd_pcm_wait
146 #define snd_pcm_state psnd_pcm_state
147 #define snd_pcm_avail_update psnd_pcm_avail_update
148 #define snd_pcm_areas_silence psnd_pcm_areas_silence
149 #define snd_pcm_mmap_begin psnd_pcm_mmap_begin
150 #define snd_pcm_mmap_commit psnd_pcm_mmap_commit
151 #define snd_pcm_readi psnd_pcm_readi
152 #define snd_pcm_writei psnd_pcm_writei
153 #define snd_pcm_drain psnd_pcm_drain
154 #define snd_pcm_drop psnd_pcm_drop
155 #define snd_pcm_recover psnd_pcm_recover
156 #define snd_pcm_info_malloc psnd_pcm_info_malloc
157 #define snd_pcm_info_free psnd_pcm_info_free
158 #define snd_pcm_info_set_device psnd_pcm_info_set_device
159 #define snd_pcm_info_set_subdevice psnd_pcm_info_set_subdevice
160 #define snd_pcm_info_set_stream psnd_pcm_info_set_stream
161 #define snd_pcm_info_get_name psnd_pcm_info_get_name
162 #define snd_ctl_pcm_next_device psnd_ctl_pcm_next_device
163 #define snd_ctl_pcm_info psnd_ctl_pcm_info
164 #define snd_ctl_open psnd_ctl_open
165 #define snd_ctl_close psnd_ctl_close
166 #define snd_ctl_card_info_malloc psnd_ctl_card_info_malloc
167 #define snd_ctl_card_info_free psnd_ctl_card_info_free
168 #define snd_ctl_card_info psnd_ctl_card_info
169 #define snd_ctl_card_info_get_name psnd_ctl_card_info_get_name
170 #define snd_ctl_card_info_get_id psnd_ctl_card_info_get_id
171 #define snd_card_next psnd_card_next
172 #endif
175 static ALCboolean alsa_load(void)
177 #ifdef HAVE_DYNLOAD
178 if(!alsa_handle)
180 alsa_handle = LoadLib("libasound.so.2");
181 if(!alsa_handle)
182 return ALC_FALSE;
184 #define LOAD_FUNC(f) do { \
185 p##f = GetSymbol(alsa_handle, #f); \
186 if(p##f == NULL) { \
187 CloseLib(alsa_handle); \
188 alsa_handle = NULL; \
189 return ALC_FALSE; \
191 } while(0)
192 LOAD_FUNC(snd_strerror);
193 LOAD_FUNC(snd_pcm_open);
194 LOAD_FUNC(snd_pcm_close);
195 LOAD_FUNC(snd_pcm_nonblock);
196 LOAD_FUNC(snd_pcm_frames_to_bytes);
197 LOAD_FUNC(snd_pcm_bytes_to_frames);
198 LOAD_FUNC(snd_pcm_hw_params_malloc);
199 LOAD_FUNC(snd_pcm_hw_params_free);
200 LOAD_FUNC(snd_pcm_hw_params_any);
201 LOAD_FUNC(snd_pcm_hw_params_current);
202 LOAD_FUNC(snd_pcm_hw_params_set_access);
203 LOAD_FUNC(snd_pcm_hw_params_set_format);
204 LOAD_FUNC(snd_pcm_hw_params_set_channels);
205 LOAD_FUNC(snd_pcm_hw_params_set_periods_near);
206 LOAD_FUNC(snd_pcm_hw_params_set_rate_near);
207 LOAD_FUNC(snd_pcm_hw_params_set_rate);
208 LOAD_FUNC(snd_pcm_hw_params_set_rate_resample);
209 LOAD_FUNC(snd_pcm_hw_params_set_buffer_time_near);
210 LOAD_FUNC(snd_pcm_hw_params_set_period_time_near);
211 LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_near);
212 LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_min);
213 LOAD_FUNC(snd_pcm_hw_params_set_period_size_near);
214 LOAD_FUNC(snd_pcm_hw_params_get_buffer_size);
215 LOAD_FUNC(snd_pcm_hw_params_get_period_size);
216 LOAD_FUNC(snd_pcm_hw_params_get_access);
217 LOAD_FUNC(snd_pcm_hw_params_get_periods);
218 LOAD_FUNC(snd_pcm_hw_params_test_format);
219 LOAD_FUNC(snd_pcm_hw_params_test_channels);
220 LOAD_FUNC(snd_pcm_hw_params);
221 LOAD_FUNC(snd_pcm_sw_params_malloc);
222 LOAD_FUNC(snd_pcm_sw_params_current);
223 LOAD_FUNC(snd_pcm_sw_params_set_avail_min);
224 LOAD_FUNC(snd_pcm_sw_params_set_stop_threshold);
225 LOAD_FUNC(snd_pcm_sw_params);
226 LOAD_FUNC(snd_pcm_sw_params_free);
227 LOAD_FUNC(snd_pcm_prepare);
228 LOAD_FUNC(snd_pcm_start);
229 LOAD_FUNC(snd_pcm_resume);
230 LOAD_FUNC(snd_pcm_reset);
231 LOAD_FUNC(snd_pcm_wait);
232 LOAD_FUNC(snd_pcm_state);
233 LOAD_FUNC(snd_pcm_avail_update);
234 LOAD_FUNC(snd_pcm_areas_silence);
235 LOAD_FUNC(snd_pcm_mmap_begin);
236 LOAD_FUNC(snd_pcm_mmap_commit);
237 LOAD_FUNC(snd_pcm_readi);
238 LOAD_FUNC(snd_pcm_writei);
239 LOAD_FUNC(snd_pcm_drain);
240 LOAD_FUNC(snd_pcm_drop);
241 LOAD_FUNC(snd_pcm_recover);
242 LOAD_FUNC(snd_pcm_info_malloc);
243 LOAD_FUNC(snd_pcm_info_free);
244 LOAD_FUNC(snd_pcm_info_set_device);
245 LOAD_FUNC(snd_pcm_info_set_subdevice);
246 LOAD_FUNC(snd_pcm_info_set_stream);
247 LOAD_FUNC(snd_pcm_info_get_name);
248 LOAD_FUNC(snd_ctl_pcm_next_device);
249 LOAD_FUNC(snd_ctl_pcm_info);
250 LOAD_FUNC(snd_ctl_open);
251 LOAD_FUNC(snd_ctl_close);
252 LOAD_FUNC(snd_ctl_card_info_malloc);
253 LOAD_FUNC(snd_ctl_card_info_free);
254 LOAD_FUNC(snd_ctl_card_info);
255 LOAD_FUNC(snd_ctl_card_info_get_name);
256 LOAD_FUNC(snd_ctl_card_info_get_id);
257 LOAD_FUNC(snd_card_next);
258 #undef LOAD_FUNC
260 #endif
261 return ALC_TRUE;
265 typedef struct {
266 snd_pcm_t *pcmHandle;
268 ALvoid *buffer;
269 ALsizei size;
271 ALboolean doCapture;
272 RingBuffer *ring;
274 snd_pcm_sframes_t last_avail;
276 volatile int killNow;
277 ALvoid *thread;
278 } alsa_data;
280 typedef struct {
281 ALCchar *name;
282 char *device;
283 } DevMap;
285 static DevMap *allDevNameMap;
286 static ALuint numDevNames;
287 static DevMap *allCaptureDevNameMap;
288 static ALuint numCaptureDevNames;
291 static const char *prefix_name(snd_pcm_stream_t stream)
293 assert(stream == SND_PCM_STREAM_PLAYBACK || stream == SND_PCM_STREAM_CAPTURE);
294 return (stream==SND_PCM_STREAM_PLAYBACK) ? "device-prefix" : "capture-prefix";
297 static DevMap *probe_devices(snd_pcm_stream_t stream, ALuint *count)
299 const char *main_prefix = "plughw:";
300 snd_ctl_t *handle;
301 int card, err, dev, idx;
302 snd_ctl_card_info_t *info;
303 snd_pcm_info_t *pcminfo;
304 DevMap *DevList;
306 snd_ctl_card_info_malloc(&info);
307 snd_pcm_info_malloc(&pcminfo);
309 DevList = malloc(sizeof(DevMap) * 1);
310 DevList[0].name = strdup(alsaDevice);
311 DevList[0].device = strdup(GetConfigValue("alsa", (stream==SND_PCM_STREAM_PLAYBACK) ?
312 "device" : "capture", "default"));
313 idx = 1;
315 card = -1;
316 if((err=snd_card_next(&card)) < 0)
317 ERR("Failed to find a card: %s\n", snd_strerror(err));
318 ConfigValueStr("alsa", prefix_name(stream), &main_prefix);
319 while(card >= 0)
321 const char *card_prefix = main_prefix;
322 const char *cardname, *cardid;
323 char name[256];
325 snprintf(name, sizeof(name), "hw:%d", card);
326 if((err = snd_ctl_open(&handle, name, 0)) < 0)
328 ERR("control open (hw:%d): %s\n", card, snd_strerror(err));
329 goto next_card;
331 if((err = snd_ctl_card_info(handle, info)) < 0)
333 ERR("control hardware info (hw:%d): %s\n", card, snd_strerror(err));
334 snd_ctl_close(handle);
335 goto next_card;
338 cardname = snd_ctl_card_info_get_name(info);
339 cardid = snd_ctl_card_info_get_id(info);
341 snprintf(name, sizeof(name), "%s-%s", prefix_name(stream), cardid);
342 ConfigValueStr("alsa", name, &card_prefix);
344 dev = -1;
345 while(1)
347 const char *devname;
348 void *temp;
350 if(snd_ctl_pcm_next_device(handle, &dev) < 0)
351 ERR("snd_ctl_pcm_next_device failed\n");
352 if(dev < 0)
353 break;
355 snd_pcm_info_set_device(pcminfo, dev);
356 snd_pcm_info_set_subdevice(pcminfo, 0);
357 snd_pcm_info_set_stream(pcminfo, stream);
358 if((err = snd_ctl_pcm_info(handle, pcminfo)) < 0) {
359 if(err != -ENOENT)
360 ERR("control digital audio info (hw:%d): %s\n", card, snd_strerror(err));
361 continue;
364 temp = realloc(DevList, sizeof(DevMap) * (idx+1));
365 if(temp)
367 const char *device_prefix = card_prefix;
368 char device[128];
370 DevList = temp;
371 devname = snd_pcm_info_get_name(pcminfo);
373 snprintf(name, sizeof(name), "%s-%s-%d", prefix_name(stream), cardid, dev);
374 ConfigValueStr("alsa", name, &device_prefix);
376 snprintf(name, sizeof(name), "%s, %s (CARD=%s,DEV=%d)",
377 cardname, devname, cardid, dev);
378 snprintf(device, sizeof(device), "%sCARD=%s,DEV=%d",
379 device_prefix, cardid, dev);
381 TRACE("Got device \"%s\", \"%s\"\n", name, device);
382 DevList[idx].name = strdup(name);
383 DevList[idx].device = strdup(device);
384 idx++;
387 snd_ctl_close(handle);
388 next_card:
389 if(snd_card_next(&card) < 0) {
390 ERR("snd_card_next failed\n");
391 break;
395 snd_pcm_info_free(pcminfo);
396 snd_ctl_card_info_free(info);
398 *count = idx;
399 return DevList;
403 static int verify_state(snd_pcm_t *handle)
405 snd_pcm_state_t state = snd_pcm_state(handle);
406 int err;
408 switch(state)
410 case SND_PCM_STATE_OPEN:
411 case SND_PCM_STATE_SETUP:
412 case SND_PCM_STATE_PREPARED:
413 case SND_PCM_STATE_RUNNING:
414 case SND_PCM_STATE_DRAINING:
415 case SND_PCM_STATE_PAUSED:
416 /* All Okay */
417 break;
419 case SND_PCM_STATE_XRUN:
420 if((err=snd_pcm_recover(handle, -EPIPE, 1)) < 0)
421 return err;
422 break;
423 case SND_PCM_STATE_SUSPENDED:
424 if((err=snd_pcm_recover(handle, -ESTRPIPE, 1)) < 0)
425 return err;
426 break;
427 case SND_PCM_STATE_DISCONNECTED:
428 return -ENODEV;
431 return state;
435 static ALuint ALSAProc(ALvoid *ptr)
437 ALCdevice *pDevice = (ALCdevice*)ptr;
438 alsa_data *data = (alsa_data*)pDevice->ExtraData;
439 const snd_pcm_channel_area_t *areas = NULL;
440 snd_pcm_uframes_t update_size, num_updates;
441 snd_pcm_sframes_t avail, commitres;
442 snd_pcm_uframes_t offset, frames;
443 char *WritePtr;
444 int err;
446 SetRTPriority();
448 update_size = pDevice->UpdateSize;
449 num_updates = pDevice->NumUpdates;
450 while(!data->killNow)
452 int state = verify_state(data->pcmHandle);
453 if(state < 0)
455 ERR("Invalid state detected: %s\n", snd_strerror(state));
456 aluHandleDisconnect(pDevice);
457 break;
460 avail = snd_pcm_avail_update(data->pcmHandle);
461 if(avail < 0)
463 ERR("available update failed: %s\n", snd_strerror(avail));
464 continue;
467 if((snd_pcm_uframes_t)avail > update_size*(num_updates+1))
469 WARN("available samples exceeds the buffer size\n");
470 snd_pcm_reset(data->pcmHandle);
471 continue;
474 // make sure there's frames to process
475 if((snd_pcm_uframes_t)avail < update_size)
477 if(state != SND_PCM_STATE_RUNNING)
479 err = snd_pcm_start(data->pcmHandle);
480 if(err < 0)
482 ERR("start failed: %s\n", snd_strerror(err));
483 continue;
486 if(snd_pcm_wait(data->pcmHandle, 1000) == 0)
487 ERR("Wait timeout... buffer size too low?\n");
488 continue;
490 avail -= avail%update_size;
492 // it is possible that contiguous areas are smaller, thus we use a loop
493 while(avail > 0)
495 frames = avail;
497 err = snd_pcm_mmap_begin(data->pcmHandle, &areas, &offset, &frames);
498 if(err < 0)
500 ERR("mmap begin error: %s\n", snd_strerror(err));
501 break;
504 WritePtr = (char*)areas->addr + (offset * areas->step / 8);
505 aluMixData(pDevice, WritePtr, frames);
507 commitres = snd_pcm_mmap_commit(data->pcmHandle, offset, frames);
508 if(commitres < 0 || (commitres-frames) != 0)
510 ERR("mmap commit error: %s\n",
511 snd_strerror(commitres >= 0 ? -EPIPE : commitres));
512 break;
515 avail -= frames;
519 return 0;
522 static ALuint ALSANoMMapProc(ALvoid *ptr)
524 ALCdevice *pDevice = (ALCdevice*)ptr;
525 alsa_data *data = (alsa_data*)pDevice->ExtraData;
526 snd_pcm_sframes_t avail;
527 char *WritePtr;
529 SetRTPriority();
531 while(!data->killNow)
533 int state = verify_state(data->pcmHandle);
534 if(state < 0)
536 ERR("Invalid state detected: %s\n", snd_strerror(state));
537 aluHandleDisconnect(pDevice);
538 break;
541 WritePtr = data->buffer;
542 avail = data->size / snd_pcm_frames_to_bytes(data->pcmHandle, 1);
543 aluMixData(pDevice, WritePtr, avail);
545 while(avail > 0)
547 int ret = snd_pcm_writei(data->pcmHandle, WritePtr, avail);
548 switch (ret)
550 case -EAGAIN:
551 continue;
552 case -ESTRPIPE:
553 case -EPIPE:
554 case -EINTR:
555 ret = snd_pcm_recover(data->pcmHandle, ret, 1);
556 if(ret < 0)
557 avail = 0;
558 break;
559 default:
560 if (ret >= 0)
562 WritePtr += snd_pcm_frames_to_bytes(data->pcmHandle, ret);
563 avail -= ret;
565 break;
567 if (ret < 0)
569 ret = snd_pcm_prepare(data->pcmHandle);
570 if(ret < 0)
571 break;
576 return 0;
579 static ALCenum alsa_open_playback(ALCdevice *device, const ALCchar *deviceName)
581 const char *driver = NULL;
582 alsa_data *data;
583 int err;
585 if(deviceName)
587 size_t idx;
589 if(!allDevNameMap)
590 allDevNameMap = probe_devices(SND_PCM_STREAM_PLAYBACK, &numDevNames);
592 for(idx = 0;idx < numDevNames;idx++)
594 if(strcmp(deviceName, allDevNameMap[idx].name) == 0)
596 driver = allDevNameMap[idx].device;
597 break;
600 if(idx == numDevNames)
601 return ALC_INVALID_VALUE;
603 else
605 deviceName = alsaDevice;
606 driver = GetConfigValue("alsa", "device", "default");
609 data = (alsa_data*)calloc(1, sizeof(alsa_data));
611 err = snd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
612 if(err >= 0)
614 err = snd_pcm_nonblock(data->pcmHandle, 0);
615 if(err < 0) snd_pcm_close(data->pcmHandle);
617 if(err < 0)
619 free(data);
620 ERR("Could not open playback device '%s': %s\n", driver, snd_strerror(err));
621 return ALC_OUT_OF_MEMORY;
624 device->szDeviceName = strdup(deviceName);
625 device->ExtraData = data;
626 return ALC_NO_ERROR;
629 static void alsa_close_playback(ALCdevice *device)
631 alsa_data *data = (alsa_data*)device->ExtraData;
633 snd_pcm_close(data->pcmHandle);
634 free(data);
635 device->ExtraData = NULL;
638 static ALCboolean alsa_reset_playback(ALCdevice *device)
640 alsa_data *data = (alsa_data*)device->ExtraData;
641 snd_pcm_uframes_t periodSizeInFrames;
642 unsigned int periodLen, bufferLen;
643 snd_pcm_sw_params_t *sp = NULL;
644 snd_pcm_hw_params_t *hp = NULL;
645 snd_pcm_access_t access;
646 snd_pcm_format_t format;
647 unsigned int periods;
648 unsigned int rate;
649 const char *funcerr;
650 int allowmmap;
651 int err;
653 format = -1;
654 switch(device->FmtType)
656 case DevFmtByte:
657 format = SND_PCM_FORMAT_S8;
658 break;
659 case DevFmtUByte:
660 format = SND_PCM_FORMAT_U8;
661 break;
662 case DevFmtShort:
663 format = SND_PCM_FORMAT_S16;
664 break;
665 case DevFmtUShort:
666 format = SND_PCM_FORMAT_U16;
667 break;
668 case DevFmtInt:
669 format = SND_PCM_FORMAT_S32;
670 break;
671 case DevFmtUInt:
672 format = SND_PCM_FORMAT_U32;
673 break;
674 case DevFmtFloat:
675 format = SND_PCM_FORMAT_FLOAT;
676 break;
679 allowmmap = GetConfigValueBool("alsa", "mmap", 1);
680 periods = device->NumUpdates;
681 periodLen = (ALuint64)device->UpdateSize * 1000000 / device->Frequency;
682 bufferLen = periodLen * periods;
683 rate = device->Frequency;
685 snd_pcm_hw_params_malloc(&hp);
686 #define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error
687 CHECK(snd_pcm_hw_params_any(data->pcmHandle, hp));
688 /* set interleaved access */
689 if(!allowmmap || snd_pcm_hw_params_set_access(data->pcmHandle, hp, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0)
691 if(periods > 2)
693 periods--;
694 bufferLen = periodLen * periods;
696 CHECK(snd_pcm_hw_params_set_access(data->pcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED));
698 /* test and set format (implicitly sets sample bits) */
699 if(snd_pcm_hw_params_test_format(data->pcmHandle, hp, format) < 0)
701 static const struct {
702 snd_pcm_format_t format;
703 enum DevFmtType fmttype;
704 } formatlist[] = {
705 { SND_PCM_FORMAT_FLOAT, DevFmtFloat },
706 { SND_PCM_FORMAT_S32, DevFmtInt },
707 { SND_PCM_FORMAT_U32, DevFmtUInt },
708 { SND_PCM_FORMAT_S16, DevFmtShort },
709 { SND_PCM_FORMAT_U16, DevFmtUShort },
710 { SND_PCM_FORMAT_S8, DevFmtByte },
711 { SND_PCM_FORMAT_U8, DevFmtUByte },
713 size_t k;
715 for(k = 0;k < COUNTOF(formatlist);k++)
717 format = formatlist[k].format;
718 if(snd_pcm_hw_params_test_format(data->pcmHandle, hp, format) >= 0)
720 device->FmtType = formatlist[k].fmttype;
721 break;
725 CHECK(snd_pcm_hw_params_set_format(data->pcmHandle, hp, format));
726 /* test and set channels (implicitly sets frame bits) */
727 if(snd_pcm_hw_params_test_channels(data->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans)) < 0)
729 static const enum DevFmtChannels channellist[] = {
730 DevFmtStereo,
731 DevFmtQuad,
732 DevFmtX51,
733 DevFmtX71,
734 DevFmtMono,
736 size_t k;
738 for(k = 0;k < COUNTOF(channellist);k++)
740 if(snd_pcm_hw_params_test_channels(data->pcmHandle, hp, ChannelsFromDevFmt(channellist[k])) >= 0)
742 device->FmtChans = channellist[k];
743 break;
747 CHECK(snd_pcm_hw_params_set_channels(data->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans)));
748 /* set rate (implicitly constrains period/buffer parameters) */
749 if(snd_pcm_hw_params_set_rate_resample(data->pcmHandle, hp, 0) < 0)
750 ERR("Failed to disable ALSA resampler\n");
751 CHECK(snd_pcm_hw_params_set_rate_near(data->pcmHandle, hp, &rate, NULL));
752 /* set buffer time (implicitly constrains period/buffer parameters) */
753 CHECK(snd_pcm_hw_params_set_buffer_time_near(data->pcmHandle, hp, &bufferLen, NULL));
754 /* set period time (implicitly sets buffer size/bytes/time and period size/bytes) */
755 CHECK(snd_pcm_hw_params_set_period_time_near(data->pcmHandle, hp, &periodLen, NULL));
756 /* install and prepare hardware configuration */
757 CHECK(snd_pcm_hw_params(data->pcmHandle, hp));
758 /* retrieve configuration info */
759 CHECK(snd_pcm_hw_params_get_access(hp, &access));
760 CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, NULL));
761 CHECK(snd_pcm_hw_params_get_periods(hp, &periods, NULL));
763 snd_pcm_hw_params_free(hp);
764 hp = NULL;
765 snd_pcm_sw_params_malloc(&sp);
767 CHECK(snd_pcm_sw_params_current(data->pcmHandle, sp));
768 CHECK(snd_pcm_sw_params_set_avail_min(data->pcmHandle, sp, periodSizeInFrames));
769 CHECK(snd_pcm_sw_params_set_stop_threshold(data->pcmHandle, sp, periodSizeInFrames*periods));
770 CHECK(snd_pcm_sw_params(data->pcmHandle, sp));
771 #undef CHECK
772 snd_pcm_sw_params_free(sp);
773 sp = NULL;
775 /* Increase periods by one, since the temp buffer counts as an extra
776 * period */
777 if(access == SND_PCM_ACCESS_RW_INTERLEAVED)
778 device->NumUpdates = periods+1;
779 else
780 device->NumUpdates = periods;
781 device->UpdateSize = periodSizeInFrames;
782 device->Frequency = rate;
784 SetDefaultChannelOrder(device);
786 return ALC_TRUE;
788 error:
789 ERR("%s failed: %s\n", funcerr, snd_strerror(err));
790 if(hp) snd_pcm_hw_params_free(hp);
791 if(sp) snd_pcm_sw_params_free(sp);
792 return ALC_FALSE;
795 static ALCboolean alsa_start_playback(ALCdevice *device)
797 alsa_data *data = (alsa_data*)device->ExtraData;
798 snd_pcm_hw_params_t *hp = NULL;
799 snd_pcm_access_t access;
800 const char *funcerr;
801 int err;
803 snd_pcm_hw_params_malloc(&hp);
804 #define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error
805 CHECK(snd_pcm_hw_params_current(data->pcmHandle, hp));
806 /* retrieve configuration info */
807 CHECK(snd_pcm_hw_params_get_access(hp, &access));
808 #undef CHECK
809 snd_pcm_hw_params_free(hp);
810 hp = NULL;
812 data->size = snd_pcm_frames_to_bytes(data->pcmHandle, device->UpdateSize);
813 if(access == SND_PCM_ACCESS_RW_INTERLEAVED)
815 data->buffer = malloc(data->size);
816 if(!data->buffer)
818 ERR("buffer malloc failed\n");
819 return ALC_FALSE;
821 data->thread = StartThread(ALSANoMMapProc, device);
823 else
825 err = snd_pcm_prepare(data->pcmHandle);
826 if(err < 0)
828 ERR("snd_pcm_prepare(data->pcmHandle) failed: %s\n", snd_strerror(err));
829 return ALC_FALSE;
831 data->thread = StartThread(ALSAProc, device);
833 if(data->thread == NULL)
835 ERR("Could not create playback thread\n");
836 free(data->buffer);
837 data->buffer = NULL;
838 return ALC_FALSE;
841 return ALC_TRUE;
843 error:
844 ERR("%s failed: %s\n", funcerr, snd_strerror(err));
845 if(hp) snd_pcm_hw_params_free(hp);
846 return ALC_FALSE;
849 static void alsa_stop_playback(ALCdevice *device)
851 alsa_data *data = (alsa_data*)device->ExtraData;
853 if(data->thread)
855 data->killNow = 1;
856 StopThread(data->thread);
857 data->thread = NULL;
859 data->killNow = 0;
860 free(data->buffer);
861 data->buffer = NULL;
865 static ALCenum alsa_open_capture(ALCdevice *pDevice, const ALCchar *deviceName)
867 const char *driver = NULL;
868 snd_pcm_hw_params_t *hp;
869 snd_pcm_uframes_t bufferSizeInFrames;
870 snd_pcm_uframes_t periodSizeInFrames;
871 ALboolean needring = AL_FALSE;
872 snd_pcm_format_t format;
873 const char *funcerr;
874 alsa_data *data;
875 int err;
877 if(deviceName)
879 size_t idx;
881 if(!allCaptureDevNameMap)
882 allCaptureDevNameMap = probe_devices(SND_PCM_STREAM_CAPTURE, &numCaptureDevNames);
884 for(idx = 0;idx < numCaptureDevNames;idx++)
886 if(strcmp(deviceName, allCaptureDevNameMap[idx].name) == 0)
888 driver = allCaptureDevNameMap[idx].device;
889 break;
892 if(idx == numCaptureDevNames)
893 return ALC_INVALID_VALUE;
895 else
897 deviceName = alsaDevice;
898 driver = GetConfigValue("alsa", "capture", "default");
901 data = (alsa_data*)calloc(1, sizeof(alsa_data));
903 err = snd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
904 if(err < 0)
906 ERR("Could not open capture device '%s': %s\n", driver, snd_strerror(err));
907 free(data);
908 return ALC_INVALID_VALUE;
911 format = -1;
912 switch(pDevice->FmtType)
914 case DevFmtByte:
915 format = SND_PCM_FORMAT_S8;
916 break;
917 case DevFmtUByte:
918 format = SND_PCM_FORMAT_U8;
919 break;
920 case DevFmtShort:
921 format = SND_PCM_FORMAT_S16;
922 break;
923 case DevFmtUShort:
924 format = SND_PCM_FORMAT_U16;
925 break;
926 case DevFmtInt:
927 format = SND_PCM_FORMAT_S32;
928 break;
929 case DevFmtUInt:
930 format = SND_PCM_FORMAT_U32;
931 break;
932 case DevFmtFloat:
933 format = SND_PCM_FORMAT_FLOAT;
934 break;
937 funcerr = NULL;
938 bufferSizeInFrames = maxu(pDevice->UpdateSize*pDevice->NumUpdates,
939 100*pDevice->Frequency/1000);
940 periodSizeInFrames = minu(bufferSizeInFrames, 25*pDevice->Frequency/1000);
942 snd_pcm_hw_params_malloc(&hp);
943 #define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error
944 CHECK(snd_pcm_hw_params_any(data->pcmHandle, hp));
945 /* set interleaved access */
946 CHECK(snd_pcm_hw_params_set_access(data->pcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED));
947 /* set format (implicitly sets sample bits) */
948 CHECK(snd_pcm_hw_params_set_format(data->pcmHandle, hp, format));
949 /* set channels (implicitly sets frame bits) */
950 CHECK(snd_pcm_hw_params_set_channels(data->pcmHandle, hp, ChannelsFromDevFmt(pDevice->FmtChans)));
951 /* set rate (implicitly constrains period/buffer parameters) */
952 CHECK(snd_pcm_hw_params_set_rate(data->pcmHandle, hp, pDevice->Frequency, 0));
953 /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */
954 if(snd_pcm_hw_params_set_buffer_size_min(data->pcmHandle, hp, &bufferSizeInFrames) < 0)
956 TRACE("Buffer too large, using intermediate ring buffer\n");
957 needring = AL_TRUE;
958 CHECK(snd_pcm_hw_params_set_buffer_size_near(data->pcmHandle, hp, &bufferSizeInFrames));
960 /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */
961 CHECK(snd_pcm_hw_params_set_period_size_near(data->pcmHandle, hp, &periodSizeInFrames, NULL));
962 /* install and prepare hardware configuration */
963 CHECK(snd_pcm_hw_params(data->pcmHandle, hp));
964 /* retrieve configuration info */
965 CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, NULL));
966 #undef CHECK
967 snd_pcm_hw_params_free(hp);
968 hp = NULL;
970 if(needring)
972 data->ring = CreateRingBuffer(FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType),
973 pDevice->UpdateSize*pDevice->NumUpdates);
974 if(!data->ring)
976 ERR("ring buffer create failed\n");
977 goto error2;
980 data->size = snd_pcm_frames_to_bytes(data->pcmHandle, periodSizeInFrames);
981 data->buffer = malloc(data->size);
982 if(!data->buffer)
984 ERR("buffer malloc failed\n");
985 goto error2;
989 pDevice->szDeviceName = strdup(deviceName);
991 pDevice->ExtraData = data;
992 return ALC_NO_ERROR;
994 error:
995 ERR("%s failed: %s\n", funcerr, snd_strerror(err));
996 if(hp) snd_pcm_hw_params_free(hp);
998 error2:
999 free(data->buffer);
1000 DestroyRingBuffer(data->ring);
1001 snd_pcm_close(data->pcmHandle);
1002 free(data);
1004 pDevice->ExtraData = NULL;
1005 return ALC_INVALID_VALUE;
1008 static void alsa_close_capture(ALCdevice *pDevice)
1010 alsa_data *data = (alsa_data*)pDevice->ExtraData;
1012 snd_pcm_close(data->pcmHandle);
1013 DestroyRingBuffer(data->ring);
1015 free(data->buffer);
1016 free(data);
1017 pDevice->ExtraData = NULL;
1020 static void alsa_start_capture(ALCdevice *Device)
1022 alsa_data *data = (alsa_data*)Device->ExtraData;
1023 int err;
1025 err = snd_pcm_start(data->pcmHandle);
1026 if(err < 0)
1028 ERR("start failed: %s\n", snd_strerror(err));
1029 aluHandleDisconnect(Device);
1031 else
1032 data->doCapture = AL_TRUE;
1035 static ALCenum alsa_capture_samples(ALCdevice *Device, ALCvoid *Buffer, ALCuint Samples)
1037 alsa_data *data = (alsa_data*)Device->ExtraData;
1039 if(data->ring)
1041 ReadRingBuffer(data->ring, Buffer, Samples);
1042 return ALC_NO_ERROR;
1045 data->last_avail -= Samples;
1046 while(Device->Connected && Samples > 0)
1048 snd_pcm_sframes_t amt = 0;
1050 if(data->size > 0)
1052 /* First get any data stored from the last stop */
1053 amt = snd_pcm_bytes_to_frames(data->pcmHandle, data->size);
1054 if((snd_pcm_uframes_t)amt > Samples) amt = Samples;
1056 amt = snd_pcm_frames_to_bytes(data->pcmHandle, amt);
1057 memmove(Buffer, data->buffer, amt);
1059 if(data->size > amt)
1061 memmove(data->buffer, data->buffer+amt, data->size - amt);
1062 data->size -= amt;
1064 else
1066 free(data->buffer);
1067 data->buffer = NULL;
1068 data->size = 0;
1070 amt = snd_pcm_bytes_to_frames(data->pcmHandle, amt);
1072 else if(data->doCapture)
1073 amt = snd_pcm_readi(data->pcmHandle, Buffer, Samples);
1074 if(amt < 0)
1076 ERR("read error: %s\n", snd_strerror(amt));
1078 if(amt == -EAGAIN)
1079 continue;
1080 if((amt=snd_pcm_recover(data->pcmHandle, amt, 1)) >= 0)
1082 amt = snd_pcm_start(data->pcmHandle);
1083 if(amt >= 0)
1084 amt = snd_pcm_avail_update(data->pcmHandle);
1086 if(amt < 0)
1088 ERR("restore error: %s\n", snd_strerror(amt));
1089 aluHandleDisconnect(Device);
1090 break;
1092 /* If the amount available is less than what's asked, we lost it
1093 * during recovery. So just give silence instead. */
1094 if((snd_pcm_uframes_t)amt < Samples)
1095 break;
1096 continue;
1099 Buffer = (ALbyte*)Buffer + amt;
1100 Samples -= amt;
1102 if(Samples > 0)
1103 memset(Buffer, ((Device->FmtType == DevFmtUByte) ? 0x80 : 0),
1104 snd_pcm_frames_to_bytes(data->pcmHandle, Samples));
1106 return ALC_NO_ERROR;
1109 static ALCuint alsa_available_samples(ALCdevice *Device)
1111 alsa_data *data = (alsa_data*)Device->ExtraData;
1112 snd_pcm_sframes_t avail = 0;
1114 if(Device->Connected && data->doCapture)
1115 avail = snd_pcm_avail_update(data->pcmHandle);
1116 if(avail < 0)
1118 ERR("avail update failed: %s\n", snd_strerror(avail));
1120 if((avail=snd_pcm_recover(data->pcmHandle, avail, 1)) >= 0)
1122 if(data->doCapture)
1123 avail = snd_pcm_start(data->pcmHandle);
1124 if(avail >= 0)
1125 avail = snd_pcm_avail_update(data->pcmHandle);
1127 if(avail < 0)
1129 ERR("restore error: %s\n", snd_strerror(avail));
1130 aluHandleDisconnect(Device);
1134 if(!data->ring)
1136 if(avail < 0) avail = 0;
1137 avail += snd_pcm_bytes_to_frames(data->pcmHandle, data->size);
1138 if(avail > data->last_avail) data->last_avail = avail;
1139 return data->last_avail;
1142 while(avail > 0)
1144 snd_pcm_sframes_t amt;
1146 amt = snd_pcm_bytes_to_frames(data->pcmHandle, data->size);
1147 if(avail < amt) amt = avail;
1149 amt = snd_pcm_readi(data->pcmHandle, data->buffer, amt);
1150 if(amt < 0)
1152 ERR("read error: %s\n", snd_strerror(amt));
1154 if(amt == -EAGAIN)
1155 continue;
1156 if((amt=snd_pcm_recover(data->pcmHandle, amt, 1)) >= 0)
1158 if(data->doCapture)
1159 amt = snd_pcm_start(data->pcmHandle);
1160 if(amt >= 0)
1161 amt = snd_pcm_avail_update(data->pcmHandle);
1163 if(amt < 0)
1165 ERR("restore error: %s\n", snd_strerror(amt));
1166 aluHandleDisconnect(Device);
1167 break;
1169 avail = amt;
1170 continue;
1173 WriteRingBuffer(data->ring, data->buffer, amt);
1174 avail -= amt;
1177 return RingBufferSize(data->ring);
1180 static void alsa_stop_capture(ALCdevice *Device)
1182 alsa_data *data = (alsa_data*)Device->ExtraData;
1183 ALCuint avail;
1184 int err;
1186 /* OpenAL requires access to unread audio after stopping, but ALSA's
1187 * snd_pcm_drain is unreliable and snd_pcm_drop drops it. Capture what's
1188 * available now so it'll be available later after the drop. */
1189 avail = alsa_available_samples(Device);
1190 if(!data->ring && avail > 0)
1192 /* The ring buffer implicitly captures when checking availability.
1193 * Direct access needs to explicitly capture it into temp storage. */
1194 ALsizei size;
1195 void *ptr;
1197 size = snd_pcm_frames_to_bytes(data->pcmHandle, avail);
1198 ptr = realloc(data->buffer, size);
1199 if(ptr)
1201 data->buffer = ptr;
1202 alsa_capture_samples(Device, data->buffer, avail);
1203 data->size = size;
1206 err = snd_pcm_drop(data->pcmHandle);
1207 if(err < 0)
1208 ERR("drop failed: %s\n", snd_strerror(err));
1209 data->doCapture = AL_FALSE;
1213 static const BackendFuncs alsa_funcs = {
1214 alsa_open_playback,
1215 alsa_close_playback,
1216 alsa_reset_playback,
1217 alsa_start_playback,
1218 alsa_stop_playback,
1219 alsa_open_capture,
1220 alsa_close_capture,
1221 alsa_start_capture,
1222 alsa_stop_capture,
1223 alsa_capture_samples,
1224 alsa_available_samples
1227 ALCboolean alc_alsa_init(BackendFuncs *func_list)
1229 if(!alsa_load())
1230 return ALC_FALSE;
1231 *func_list = alsa_funcs;
1232 return ALC_TRUE;
1235 void alc_alsa_deinit(void)
1237 ALuint i;
1239 for(i = 0;i < numDevNames;++i)
1241 free(allDevNameMap[i].name);
1242 free(allDevNameMap[i].device);
1244 free(allDevNameMap);
1245 allDevNameMap = NULL;
1246 numDevNames = 0;
1248 for(i = 0;i < numCaptureDevNames;++i)
1250 free(allCaptureDevNameMap[i].name);
1251 free(allCaptureDevNameMap[i].device);
1253 free(allCaptureDevNameMap);
1254 allCaptureDevNameMap = NULL;
1255 numCaptureDevNames = 0;
1257 #ifdef HAVE_DYNLOAD
1258 if(alsa_handle)
1259 CloseLib(alsa_handle);
1260 alsa_handle = NULL;
1261 #endif
1264 void alc_alsa_probe(enum DevProbe type)
1266 ALuint i;
1268 switch(type)
1270 case ALL_DEVICE_PROBE:
1271 for(i = 0;i < numDevNames;++i)
1273 free(allDevNameMap[i].name);
1274 free(allDevNameMap[i].device);
1277 free(allDevNameMap);
1278 allDevNameMap = probe_devices(SND_PCM_STREAM_PLAYBACK, &numDevNames);
1280 for(i = 0;i < numDevNames;++i)
1281 AppendAllDeviceList(allDevNameMap[i].name);
1282 break;
1284 case CAPTURE_DEVICE_PROBE:
1285 for(i = 0;i < numCaptureDevNames;++i)
1287 free(allCaptureDevNameMap[i].name);
1288 free(allCaptureDevNameMap[i].device);
1291 free(allCaptureDevNameMap);
1292 allCaptureDevNameMap = probe_devices(SND_PCM_STREAM_CAPTURE, &numCaptureDevNames);
1294 for(i = 0;i < numCaptureDevNames;++i)
1295 AppendCaptureDeviceList(allCaptureDevNameMap[i].name);
1296 break;