Print the error when reporting snd_pcm_delay failure
[openal-soft/openal-hmr.git] / Alc / backends / alsa.c
blobb4bf83c7bcf18d75a4983502ffb84a0b3715c86e
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_time_min);
61 MAKE_FUNC(snd_pcm_hw_params_get_buffer_time_max);
62 MAKE_FUNC(snd_pcm_hw_params_get_period_time_min);
63 MAKE_FUNC(snd_pcm_hw_params_get_period_time_max);
64 MAKE_FUNC(snd_pcm_hw_params_get_buffer_size);
65 MAKE_FUNC(snd_pcm_hw_params_get_period_size);
66 MAKE_FUNC(snd_pcm_hw_params_get_access);
67 MAKE_FUNC(snd_pcm_hw_params_get_periods);
68 MAKE_FUNC(snd_pcm_hw_params_test_format);
69 MAKE_FUNC(snd_pcm_hw_params_test_channels);
70 MAKE_FUNC(snd_pcm_hw_params);
71 MAKE_FUNC(snd_pcm_sw_params_malloc);
72 MAKE_FUNC(snd_pcm_sw_params_current);
73 MAKE_FUNC(snd_pcm_sw_params_set_avail_min);
74 MAKE_FUNC(snd_pcm_sw_params_set_stop_threshold);
75 MAKE_FUNC(snd_pcm_sw_params);
76 MAKE_FUNC(snd_pcm_sw_params_free);
77 MAKE_FUNC(snd_pcm_prepare);
78 MAKE_FUNC(snd_pcm_start);
79 MAKE_FUNC(snd_pcm_resume);
80 MAKE_FUNC(snd_pcm_reset);
81 MAKE_FUNC(snd_pcm_wait);
82 MAKE_FUNC(snd_pcm_delay);
83 MAKE_FUNC(snd_pcm_state);
84 MAKE_FUNC(snd_pcm_avail_update);
85 MAKE_FUNC(snd_pcm_areas_silence);
86 MAKE_FUNC(snd_pcm_mmap_begin);
87 MAKE_FUNC(snd_pcm_mmap_commit);
88 MAKE_FUNC(snd_pcm_readi);
89 MAKE_FUNC(snd_pcm_writei);
90 MAKE_FUNC(snd_pcm_drain);
91 MAKE_FUNC(snd_pcm_drop);
92 MAKE_FUNC(snd_pcm_recover);
93 MAKE_FUNC(snd_pcm_info_malloc);
94 MAKE_FUNC(snd_pcm_info_free);
95 MAKE_FUNC(snd_pcm_info_set_device);
96 MAKE_FUNC(snd_pcm_info_set_subdevice);
97 MAKE_FUNC(snd_pcm_info_set_stream);
98 MAKE_FUNC(snd_pcm_info_get_name);
99 MAKE_FUNC(snd_ctl_pcm_next_device);
100 MAKE_FUNC(snd_ctl_pcm_info);
101 MAKE_FUNC(snd_ctl_open);
102 MAKE_FUNC(snd_ctl_close);
103 MAKE_FUNC(snd_ctl_card_info_malloc);
104 MAKE_FUNC(snd_ctl_card_info_free);
105 MAKE_FUNC(snd_ctl_card_info);
106 MAKE_FUNC(snd_ctl_card_info_get_name);
107 MAKE_FUNC(snd_ctl_card_info_get_id);
108 MAKE_FUNC(snd_card_next);
109 #undef MAKE_FUNC
111 #define snd_strerror psnd_strerror
112 #define snd_pcm_open psnd_pcm_open
113 #define snd_pcm_close psnd_pcm_close
114 #define snd_pcm_nonblock psnd_pcm_nonblock
115 #define snd_pcm_frames_to_bytes psnd_pcm_frames_to_bytes
116 #define snd_pcm_bytes_to_frames psnd_pcm_bytes_to_frames
117 #define snd_pcm_hw_params_malloc psnd_pcm_hw_params_malloc
118 #define snd_pcm_hw_params_free psnd_pcm_hw_params_free
119 #define snd_pcm_hw_params_any psnd_pcm_hw_params_any
120 #define snd_pcm_hw_params_current psnd_pcm_hw_params_current
121 #define snd_pcm_hw_params_set_access psnd_pcm_hw_params_set_access
122 #define snd_pcm_hw_params_set_format psnd_pcm_hw_params_set_format
123 #define snd_pcm_hw_params_set_channels psnd_pcm_hw_params_set_channels
124 #define snd_pcm_hw_params_set_periods_near psnd_pcm_hw_params_set_periods_near
125 #define snd_pcm_hw_params_set_rate_near psnd_pcm_hw_params_set_rate_near
126 #define snd_pcm_hw_params_set_rate psnd_pcm_hw_params_set_rate
127 #define snd_pcm_hw_params_set_rate_resample psnd_pcm_hw_params_set_rate_resample
128 #define snd_pcm_hw_params_set_buffer_time_near psnd_pcm_hw_params_set_buffer_time_near
129 #define snd_pcm_hw_params_set_period_time_near psnd_pcm_hw_params_set_period_time_near
130 #define snd_pcm_hw_params_set_buffer_size_near psnd_pcm_hw_params_set_buffer_size_near
131 #define snd_pcm_hw_params_set_period_size_near psnd_pcm_hw_params_set_period_size_near
132 #define snd_pcm_hw_params_set_buffer_size_min psnd_pcm_hw_params_set_buffer_size_min
133 #define snd_pcm_hw_params_get_buffer_time_min psnd_pcm_hw_params_get_buffer_time_min
134 #define snd_pcm_hw_params_get_buffer_time_max psnd_pcm_hw_params_get_buffer_time_max
135 #define snd_pcm_hw_params_get_period_time_min psnd_pcm_hw_params_get_period_time_min
136 #define snd_pcm_hw_params_get_period_time_max psnd_pcm_hw_params_get_period_time_max
137 #define snd_pcm_hw_params_get_buffer_size psnd_pcm_hw_params_get_buffer_size
138 #define snd_pcm_hw_params_get_period_size psnd_pcm_hw_params_get_period_size
139 #define snd_pcm_hw_params_get_access psnd_pcm_hw_params_get_access
140 #define snd_pcm_hw_params_get_periods psnd_pcm_hw_params_get_periods
141 #define snd_pcm_hw_params_test_format psnd_pcm_hw_params_test_format
142 #define snd_pcm_hw_params_test_channels psnd_pcm_hw_params_test_channels
143 #define snd_pcm_hw_params psnd_pcm_hw_params
144 #define snd_pcm_sw_params_malloc psnd_pcm_sw_params_malloc
145 #define snd_pcm_sw_params_current psnd_pcm_sw_params_current
146 #define snd_pcm_sw_params_set_avail_min psnd_pcm_sw_params_set_avail_min
147 #define snd_pcm_sw_params_set_stop_threshold psnd_pcm_sw_params_set_stop_threshold
148 #define snd_pcm_sw_params psnd_pcm_sw_params
149 #define snd_pcm_sw_params_free psnd_pcm_sw_params_free
150 #define snd_pcm_prepare psnd_pcm_prepare
151 #define snd_pcm_start psnd_pcm_start
152 #define snd_pcm_resume psnd_pcm_resume
153 #define snd_pcm_reset psnd_pcm_reset
154 #define snd_pcm_wait psnd_pcm_wait
155 #define snd_pcm_delay psnd_pcm_delay
156 #define snd_pcm_state psnd_pcm_state
157 #define snd_pcm_avail_update psnd_pcm_avail_update
158 #define snd_pcm_areas_silence psnd_pcm_areas_silence
159 #define snd_pcm_mmap_begin psnd_pcm_mmap_begin
160 #define snd_pcm_mmap_commit psnd_pcm_mmap_commit
161 #define snd_pcm_readi psnd_pcm_readi
162 #define snd_pcm_writei psnd_pcm_writei
163 #define snd_pcm_drain psnd_pcm_drain
164 #define snd_pcm_drop psnd_pcm_drop
165 #define snd_pcm_recover psnd_pcm_recover
166 #define snd_pcm_info_malloc psnd_pcm_info_malloc
167 #define snd_pcm_info_free psnd_pcm_info_free
168 #define snd_pcm_info_set_device psnd_pcm_info_set_device
169 #define snd_pcm_info_set_subdevice psnd_pcm_info_set_subdevice
170 #define snd_pcm_info_set_stream psnd_pcm_info_set_stream
171 #define snd_pcm_info_get_name psnd_pcm_info_get_name
172 #define snd_ctl_pcm_next_device psnd_ctl_pcm_next_device
173 #define snd_ctl_pcm_info psnd_ctl_pcm_info
174 #define snd_ctl_open psnd_ctl_open
175 #define snd_ctl_close psnd_ctl_close
176 #define snd_ctl_card_info_malloc psnd_ctl_card_info_malloc
177 #define snd_ctl_card_info_free psnd_ctl_card_info_free
178 #define snd_ctl_card_info psnd_ctl_card_info
179 #define snd_ctl_card_info_get_name psnd_ctl_card_info_get_name
180 #define snd_ctl_card_info_get_id psnd_ctl_card_info_get_id
181 #define snd_card_next psnd_card_next
182 #endif
185 static ALCboolean alsa_load(void)
187 #ifdef HAVE_DYNLOAD
188 if(!alsa_handle)
190 alsa_handle = LoadLib("libasound.so.2");
191 if(!alsa_handle)
192 return ALC_FALSE;
194 #define LOAD_FUNC(f) do { \
195 p##f = GetSymbol(alsa_handle, #f); \
196 if(p##f == NULL) { \
197 CloseLib(alsa_handle); \
198 alsa_handle = NULL; \
199 return ALC_FALSE; \
201 } while(0)
202 LOAD_FUNC(snd_strerror);
203 LOAD_FUNC(snd_pcm_open);
204 LOAD_FUNC(snd_pcm_close);
205 LOAD_FUNC(snd_pcm_nonblock);
206 LOAD_FUNC(snd_pcm_frames_to_bytes);
207 LOAD_FUNC(snd_pcm_bytes_to_frames);
208 LOAD_FUNC(snd_pcm_hw_params_malloc);
209 LOAD_FUNC(snd_pcm_hw_params_free);
210 LOAD_FUNC(snd_pcm_hw_params_any);
211 LOAD_FUNC(snd_pcm_hw_params_current);
212 LOAD_FUNC(snd_pcm_hw_params_set_access);
213 LOAD_FUNC(snd_pcm_hw_params_set_format);
214 LOAD_FUNC(snd_pcm_hw_params_set_channels);
215 LOAD_FUNC(snd_pcm_hw_params_set_periods_near);
216 LOAD_FUNC(snd_pcm_hw_params_set_rate_near);
217 LOAD_FUNC(snd_pcm_hw_params_set_rate);
218 LOAD_FUNC(snd_pcm_hw_params_set_rate_resample);
219 LOAD_FUNC(snd_pcm_hw_params_set_buffer_time_near);
220 LOAD_FUNC(snd_pcm_hw_params_set_period_time_near);
221 LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_near);
222 LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_min);
223 LOAD_FUNC(snd_pcm_hw_params_set_period_size_near);
224 LOAD_FUNC(snd_pcm_hw_params_get_buffer_time_min);
225 LOAD_FUNC(snd_pcm_hw_params_get_buffer_time_max);
226 LOAD_FUNC(snd_pcm_hw_params_get_period_time_min);
227 LOAD_FUNC(snd_pcm_hw_params_get_period_time_max);
228 LOAD_FUNC(snd_pcm_hw_params_get_buffer_size);
229 LOAD_FUNC(snd_pcm_hw_params_get_period_size);
230 LOAD_FUNC(snd_pcm_hw_params_get_access);
231 LOAD_FUNC(snd_pcm_hw_params_get_periods);
232 LOAD_FUNC(snd_pcm_hw_params_test_format);
233 LOAD_FUNC(snd_pcm_hw_params_test_channels);
234 LOAD_FUNC(snd_pcm_hw_params);
235 LOAD_FUNC(snd_pcm_sw_params_malloc);
236 LOAD_FUNC(snd_pcm_sw_params_current);
237 LOAD_FUNC(snd_pcm_sw_params_set_avail_min);
238 LOAD_FUNC(snd_pcm_sw_params_set_stop_threshold);
239 LOAD_FUNC(snd_pcm_sw_params);
240 LOAD_FUNC(snd_pcm_sw_params_free);
241 LOAD_FUNC(snd_pcm_prepare);
242 LOAD_FUNC(snd_pcm_start);
243 LOAD_FUNC(snd_pcm_resume);
244 LOAD_FUNC(snd_pcm_reset);
245 LOAD_FUNC(snd_pcm_wait);
246 LOAD_FUNC(snd_pcm_delay);
247 LOAD_FUNC(snd_pcm_state);
248 LOAD_FUNC(snd_pcm_avail_update);
249 LOAD_FUNC(snd_pcm_areas_silence);
250 LOAD_FUNC(snd_pcm_mmap_begin);
251 LOAD_FUNC(snd_pcm_mmap_commit);
252 LOAD_FUNC(snd_pcm_readi);
253 LOAD_FUNC(snd_pcm_writei);
254 LOAD_FUNC(snd_pcm_drain);
255 LOAD_FUNC(snd_pcm_drop);
256 LOAD_FUNC(snd_pcm_recover);
257 LOAD_FUNC(snd_pcm_info_malloc);
258 LOAD_FUNC(snd_pcm_info_free);
259 LOAD_FUNC(snd_pcm_info_set_device);
260 LOAD_FUNC(snd_pcm_info_set_subdevice);
261 LOAD_FUNC(snd_pcm_info_set_stream);
262 LOAD_FUNC(snd_pcm_info_get_name);
263 LOAD_FUNC(snd_ctl_pcm_next_device);
264 LOAD_FUNC(snd_ctl_pcm_info);
265 LOAD_FUNC(snd_ctl_open);
266 LOAD_FUNC(snd_ctl_close);
267 LOAD_FUNC(snd_ctl_card_info_malloc);
268 LOAD_FUNC(snd_ctl_card_info_free);
269 LOAD_FUNC(snd_ctl_card_info);
270 LOAD_FUNC(snd_ctl_card_info_get_name);
271 LOAD_FUNC(snd_ctl_card_info_get_id);
272 LOAD_FUNC(snd_card_next);
273 #undef LOAD_FUNC
275 #endif
276 return ALC_TRUE;
280 typedef struct {
281 snd_pcm_t *pcmHandle;
283 ALvoid *buffer;
284 ALsizei size;
286 ALboolean doCapture;
287 RingBuffer *ring;
289 snd_pcm_sframes_t last_avail;
291 volatile int killNow;
292 ALvoid *thread;
293 } alsa_data;
295 typedef struct {
296 ALCchar *name;
297 char *device;
298 } DevMap;
300 static DevMap *allDevNameMap;
301 static ALuint numDevNames;
302 static DevMap *allCaptureDevNameMap;
303 static ALuint numCaptureDevNames;
306 static const char *prefix_name(snd_pcm_stream_t stream)
308 assert(stream == SND_PCM_STREAM_PLAYBACK || stream == SND_PCM_STREAM_CAPTURE);
309 return (stream==SND_PCM_STREAM_PLAYBACK) ? "device-prefix" : "capture-prefix";
312 static DevMap *probe_devices(snd_pcm_stream_t stream, ALuint *count)
314 const char *main_prefix = "plughw:";
315 snd_ctl_t *handle;
316 int card, err, dev, idx;
317 snd_ctl_card_info_t *info;
318 snd_pcm_info_t *pcminfo;
319 DevMap *DevList;
321 snd_ctl_card_info_malloc(&info);
322 snd_pcm_info_malloc(&pcminfo);
324 DevList = malloc(sizeof(DevMap) * 1);
325 DevList[0].name = strdup(alsaDevice);
326 DevList[0].device = strdup(GetConfigValue("alsa", (stream==SND_PCM_STREAM_PLAYBACK) ?
327 "device" : "capture", "default"));
328 idx = 1;
330 card = -1;
331 if((err=snd_card_next(&card)) < 0)
332 ERR("Failed to find a card: %s\n", snd_strerror(err));
333 ConfigValueStr("alsa", prefix_name(stream), &main_prefix);
334 while(card >= 0)
336 const char *card_prefix = main_prefix;
337 const char *cardname, *cardid;
338 char name[256];
340 snprintf(name, sizeof(name), "hw:%d", card);
341 if((err = snd_ctl_open(&handle, name, 0)) < 0)
343 ERR("control open (hw:%d): %s\n", card, snd_strerror(err));
344 goto next_card;
346 if((err = snd_ctl_card_info(handle, info)) < 0)
348 ERR("control hardware info (hw:%d): %s\n", card, snd_strerror(err));
349 snd_ctl_close(handle);
350 goto next_card;
353 cardname = snd_ctl_card_info_get_name(info);
354 cardid = snd_ctl_card_info_get_id(info);
356 snprintf(name, sizeof(name), "%s-%s", prefix_name(stream), cardid);
357 ConfigValueStr("alsa", name, &card_prefix);
359 dev = -1;
360 while(1)
362 const char *devname;
363 void *temp;
365 if(snd_ctl_pcm_next_device(handle, &dev) < 0)
366 ERR("snd_ctl_pcm_next_device failed\n");
367 if(dev < 0)
368 break;
370 snd_pcm_info_set_device(pcminfo, dev);
371 snd_pcm_info_set_subdevice(pcminfo, 0);
372 snd_pcm_info_set_stream(pcminfo, stream);
373 if((err = snd_ctl_pcm_info(handle, pcminfo)) < 0) {
374 if(err != -ENOENT)
375 ERR("control digital audio info (hw:%d): %s\n", card, snd_strerror(err));
376 continue;
379 temp = realloc(DevList, sizeof(DevMap) * (idx+1));
380 if(temp)
382 const char *device_prefix = card_prefix;
383 char device[128];
385 DevList = temp;
386 devname = snd_pcm_info_get_name(pcminfo);
388 snprintf(name, sizeof(name), "%s-%s-%d", prefix_name(stream), cardid, dev);
389 ConfigValueStr("alsa", name, &device_prefix);
391 snprintf(name, sizeof(name), "%s, %s (CARD=%s,DEV=%d)",
392 cardname, devname, cardid, dev);
393 snprintf(device, sizeof(device), "%sCARD=%s,DEV=%d",
394 device_prefix, cardid, dev);
396 TRACE("Got device \"%s\", \"%s\"\n", name, device);
397 DevList[idx].name = strdup(name);
398 DevList[idx].device = strdup(device);
399 idx++;
402 snd_ctl_close(handle);
403 next_card:
404 if(snd_card_next(&card) < 0) {
405 ERR("snd_card_next failed\n");
406 break;
410 snd_pcm_info_free(pcminfo);
411 snd_ctl_card_info_free(info);
413 *count = idx;
414 return DevList;
418 static int verify_state(snd_pcm_t *handle)
420 snd_pcm_state_t state = snd_pcm_state(handle);
421 int err;
423 switch(state)
425 case SND_PCM_STATE_OPEN:
426 case SND_PCM_STATE_SETUP:
427 case SND_PCM_STATE_PREPARED:
428 case SND_PCM_STATE_RUNNING:
429 case SND_PCM_STATE_DRAINING:
430 case SND_PCM_STATE_PAUSED:
431 /* All Okay */
432 break;
434 case SND_PCM_STATE_XRUN:
435 if((err=snd_pcm_recover(handle, -EPIPE, 1)) < 0)
436 return err;
437 break;
438 case SND_PCM_STATE_SUSPENDED:
439 if((err=snd_pcm_recover(handle, -ESTRPIPE, 1)) < 0)
440 return err;
441 break;
442 case SND_PCM_STATE_DISCONNECTED:
443 return -ENODEV;
446 return state;
450 static ALuint ALSAProc(ALvoid *ptr)
452 ALCdevice *Device = (ALCdevice*)ptr;
453 alsa_data *data = (alsa_data*)Device->ExtraData;
454 const snd_pcm_channel_area_t *areas = NULL;
455 snd_pcm_uframes_t update_size, num_updates;
456 snd_pcm_sframes_t avail, commitres;
457 snd_pcm_uframes_t offset, frames;
458 char *WritePtr;
459 int err;
461 SetRTPriority();
463 update_size = Device->UpdateSize;
464 num_updates = Device->NumUpdates;
465 while(!data->killNow)
467 int state = verify_state(data->pcmHandle);
468 if(state < 0)
470 ERR("Invalid state detected: %s\n", snd_strerror(state));
471 aluHandleDisconnect(Device);
472 break;
475 avail = snd_pcm_avail_update(data->pcmHandle);
476 if(avail < 0)
478 ERR("available update failed: %s\n", snd_strerror(avail));
479 continue;
482 if((snd_pcm_uframes_t)avail > update_size*(num_updates+1))
484 WARN("available samples exceeds the buffer size\n");
485 snd_pcm_reset(data->pcmHandle);
486 continue;
489 // make sure there's frames to process
490 if((snd_pcm_uframes_t)avail < update_size)
492 if(state != SND_PCM_STATE_RUNNING)
494 err = snd_pcm_start(data->pcmHandle);
495 if(err < 0)
497 ERR("start failed: %s\n", snd_strerror(err));
498 continue;
501 if(snd_pcm_wait(data->pcmHandle, 1000) == 0)
502 ERR("Wait timeout... buffer size too low?\n");
503 continue;
505 avail -= avail%update_size;
507 // it is possible that contiguous areas are smaller, thus we use a loop
508 ALCdevice_Lock(Device);
509 while(avail > 0)
511 frames = avail;
513 err = snd_pcm_mmap_begin(data->pcmHandle, &areas, &offset, &frames);
514 if(err < 0)
516 ERR("mmap begin error: %s\n", snd_strerror(err));
517 break;
520 WritePtr = (char*)areas->addr + (offset * areas->step / 8);
521 aluMixData(Device, WritePtr, frames);
523 commitres = snd_pcm_mmap_commit(data->pcmHandle, offset, frames);
524 if(commitres < 0 || (commitres-frames) != 0)
526 ERR("mmap commit error: %s\n",
527 snd_strerror(commitres >= 0 ? -EPIPE : commitres));
528 break;
531 avail -= frames;
533 ALCdevice_Unlock(Device);
536 return 0;
539 static ALuint ALSANoMMapProc(ALvoid *ptr)
541 ALCdevice *Device = (ALCdevice*)ptr;
542 alsa_data *data = (alsa_data*)Device->ExtraData;
543 snd_pcm_uframes_t update_size, num_updates;
544 snd_pcm_sframes_t avail;
545 char *WritePtr;
546 int err;
548 SetRTPriority();
550 update_size = Device->UpdateSize;
551 num_updates = Device->NumUpdates;
552 while(!data->killNow)
554 int state = verify_state(data->pcmHandle);
555 if(state < 0)
557 ERR("Invalid state detected: %s\n", snd_strerror(state));
558 aluHandleDisconnect(Device);
559 break;
562 avail = snd_pcm_avail_update(data->pcmHandle);
563 if(avail < 0)
565 ERR("available update failed: %s\n", snd_strerror(avail));
566 continue;
569 if((snd_pcm_uframes_t)avail > update_size*num_updates)
571 WARN("available samples exceeds the buffer size\n");
572 snd_pcm_reset(data->pcmHandle);
573 continue;
576 if((snd_pcm_uframes_t)avail < update_size)
578 if(state != SND_PCM_STATE_RUNNING)
580 err = snd_pcm_start(data->pcmHandle);
581 if(err < 0)
583 ERR("start failed: %s\n", snd_strerror(err));
584 continue;
587 if(snd_pcm_wait(data->pcmHandle, 1000) == 0)
588 ERR("Wait timeout... buffer size too low?\n");
589 continue;
592 ALCdevice_Lock(Device);
593 WritePtr = data->buffer;
594 avail = snd_pcm_bytes_to_frames(data->pcmHandle, data->size);
595 aluMixData(Device, WritePtr, avail);
597 while(avail > 0)
599 int ret = snd_pcm_writei(data->pcmHandle, WritePtr, avail);
600 switch (ret)
602 case -EAGAIN:
603 continue;
604 case -ESTRPIPE:
605 case -EPIPE:
606 case -EINTR:
607 ret = snd_pcm_recover(data->pcmHandle, ret, 1);
608 if(ret < 0)
609 avail = 0;
610 break;
611 default:
612 if (ret >= 0)
614 WritePtr += snd_pcm_frames_to_bytes(data->pcmHandle, ret);
615 avail -= ret;
617 break;
619 if (ret < 0)
621 ret = snd_pcm_prepare(data->pcmHandle);
622 if(ret < 0)
623 break;
626 ALCdevice_Unlock(Device);
629 return 0;
632 static ALCenum alsa_open_playback(ALCdevice *device, const ALCchar *deviceName)
634 const char *driver = NULL;
635 alsa_data *data;
636 int err;
638 if(deviceName)
640 size_t idx;
642 if(!allDevNameMap)
643 allDevNameMap = probe_devices(SND_PCM_STREAM_PLAYBACK, &numDevNames);
645 for(idx = 0;idx < numDevNames;idx++)
647 if(strcmp(deviceName, allDevNameMap[idx].name) == 0)
649 driver = allDevNameMap[idx].device;
650 break;
653 if(idx == numDevNames)
654 return ALC_INVALID_VALUE;
656 else
658 deviceName = alsaDevice;
659 driver = GetConfigValue("alsa", "device", "default");
662 data = (alsa_data*)calloc(1, sizeof(alsa_data));
664 err = snd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
665 if(err < 0)
667 free(data);
668 ERR("Could not open playback device '%s': %s\n", driver, snd_strerror(err));
669 return ALC_OUT_OF_MEMORY;
672 device->DeviceName = strdup(deviceName);
673 device->ExtraData = data;
674 return ALC_NO_ERROR;
677 static void alsa_close_playback(ALCdevice *device)
679 alsa_data *data = (alsa_data*)device->ExtraData;
681 snd_pcm_close(data->pcmHandle);
682 free(data);
683 device->ExtraData = NULL;
686 static ALCboolean alsa_reset_playback(ALCdevice *device)
688 alsa_data *data = (alsa_data*)device->ExtraData;
689 snd_pcm_uframes_t periodSizeInFrames;
690 unsigned int periodLen, bufferLen;
691 snd_pcm_sw_params_t *sp = NULL;
692 snd_pcm_hw_params_t *hp = NULL;
693 snd_pcm_access_t access;
694 snd_pcm_format_t format;
695 unsigned int periods;
696 unsigned int rate;
697 const char *funcerr;
698 int allowmmap;
699 int err;
701 format = -1;
702 switch(device->FmtType)
704 case DevFmtByte:
705 format = SND_PCM_FORMAT_S8;
706 break;
707 case DevFmtUByte:
708 format = SND_PCM_FORMAT_U8;
709 break;
710 case DevFmtShort:
711 format = SND_PCM_FORMAT_S16;
712 break;
713 case DevFmtUShort:
714 format = SND_PCM_FORMAT_U16;
715 break;
716 case DevFmtInt:
717 format = SND_PCM_FORMAT_S32;
718 break;
719 case DevFmtUInt:
720 format = SND_PCM_FORMAT_U32;
721 break;
722 case DevFmtFloat:
723 format = SND_PCM_FORMAT_FLOAT;
724 break;
727 allowmmap = GetConfigValueBool("alsa", "mmap", 1);
728 periods = device->NumUpdates;
729 periodLen = (ALuint64)device->UpdateSize * 1000000 / device->Frequency;
730 bufferLen = periodLen * periods;
731 rate = device->Frequency;
733 snd_pcm_hw_params_malloc(&hp);
734 #define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error
735 CHECK(snd_pcm_hw_params_any(data->pcmHandle, hp));
736 /* set interleaved access */
737 if(!allowmmap || snd_pcm_hw_params_set_access(data->pcmHandle, hp, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0)
739 /* No mmap */
740 CHECK(snd_pcm_hw_params_set_access(data->pcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED));
742 /* test and set format (implicitly sets sample bits) */
743 if(snd_pcm_hw_params_test_format(data->pcmHandle, hp, format) < 0)
745 static const struct {
746 snd_pcm_format_t format;
747 enum DevFmtType fmttype;
748 } formatlist[] = {
749 { SND_PCM_FORMAT_FLOAT, DevFmtFloat },
750 { SND_PCM_FORMAT_S32, DevFmtInt },
751 { SND_PCM_FORMAT_U32, DevFmtUInt },
752 { SND_PCM_FORMAT_S16, DevFmtShort },
753 { SND_PCM_FORMAT_U16, DevFmtUShort },
754 { SND_PCM_FORMAT_S8, DevFmtByte },
755 { SND_PCM_FORMAT_U8, DevFmtUByte },
757 size_t k;
759 for(k = 0;k < COUNTOF(formatlist);k++)
761 format = formatlist[k].format;
762 if(snd_pcm_hw_params_test_format(data->pcmHandle, hp, format) >= 0)
764 device->FmtType = formatlist[k].fmttype;
765 break;
769 CHECK(snd_pcm_hw_params_set_format(data->pcmHandle, hp, format));
770 /* test and set channels (implicitly sets frame bits) */
771 if(snd_pcm_hw_params_test_channels(data->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans)) < 0)
773 static const enum DevFmtChannels channellist[] = {
774 DevFmtStereo,
775 DevFmtQuad,
776 DevFmtX51,
777 DevFmtX71,
778 DevFmtMono,
780 size_t k;
782 for(k = 0;k < COUNTOF(channellist);k++)
784 if(snd_pcm_hw_params_test_channels(data->pcmHandle, hp, ChannelsFromDevFmt(channellist[k])) >= 0)
786 device->FmtChans = channellist[k];
787 break;
791 CHECK(snd_pcm_hw_params_set_channels(data->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans)));
792 /* set rate (implicitly constrains period/buffer parameters) */
793 if(snd_pcm_hw_params_set_rate_resample(data->pcmHandle, hp, 0) < 0)
794 ERR("Failed to disable ALSA resampler\n");
795 CHECK(snd_pcm_hw_params_set_rate_near(data->pcmHandle, hp, &rate, NULL));
796 /* set buffer time (implicitly constrains period/buffer parameters) */
797 if(snd_pcm_hw_params_set_buffer_time_near(data->pcmHandle, hp, &bufferLen, NULL) < 0)
798 ERR("snd_pcm_hw_params_set_buffer_time_near failed: %s\n", snd_strerror(err));
799 /* set period time (implicitly sets buffer size/bytes/time and period size/bytes) */
800 if(snd_pcm_hw_params_set_period_time_near(data->pcmHandle, hp, &periodLen, NULL) < 0)
801 ERR("snd_pcm_hw_params_set_period_time_near failed: %s\n", snd_strerror(err));
802 /* install and prepare hardware configuration */
803 CHECK(snd_pcm_hw_params(data->pcmHandle, hp));
804 /* retrieve configuration info */
805 CHECK(snd_pcm_hw_params_get_access(hp, &access));
806 CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, NULL));
807 CHECK(snd_pcm_hw_params_get_periods(hp, &periods, NULL));
809 snd_pcm_hw_params_free(hp);
810 hp = NULL;
811 snd_pcm_sw_params_malloc(&sp);
813 CHECK(snd_pcm_sw_params_current(data->pcmHandle, sp));
814 CHECK(snd_pcm_sw_params_set_avail_min(data->pcmHandle, sp, periodSizeInFrames));
815 CHECK(snd_pcm_sw_params_set_stop_threshold(data->pcmHandle, sp, periodSizeInFrames*periods));
816 CHECK(snd_pcm_sw_params(data->pcmHandle, sp));
817 #undef CHECK
818 snd_pcm_sw_params_free(sp);
819 sp = NULL;
821 device->NumUpdates = periods;
822 device->UpdateSize = periodSizeInFrames;
823 device->Frequency = rate;
825 SetDefaultChannelOrder(device);
827 return ALC_TRUE;
829 error:
830 ERR("%s failed: %s\n", funcerr, snd_strerror(err));
831 if(hp) snd_pcm_hw_params_free(hp);
832 if(sp) snd_pcm_sw_params_free(sp);
833 return ALC_FALSE;
836 static ALCboolean alsa_start_playback(ALCdevice *device)
838 alsa_data *data = (alsa_data*)device->ExtraData;
839 snd_pcm_hw_params_t *hp = NULL;
840 snd_pcm_access_t access;
841 const char *funcerr;
842 int err;
844 snd_pcm_hw_params_malloc(&hp);
845 #define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error
846 CHECK(snd_pcm_hw_params_current(data->pcmHandle, hp));
847 /* retrieve configuration info */
848 CHECK(snd_pcm_hw_params_get_access(hp, &access));
849 #undef CHECK
850 snd_pcm_hw_params_free(hp);
851 hp = NULL;
853 data->size = snd_pcm_frames_to_bytes(data->pcmHandle, device->UpdateSize);
854 if(access == SND_PCM_ACCESS_RW_INTERLEAVED)
856 data->buffer = malloc(data->size);
857 if(!data->buffer)
859 ERR("buffer malloc failed\n");
860 return ALC_FALSE;
862 data->thread = StartThread(ALSANoMMapProc, device);
864 else
866 err = snd_pcm_prepare(data->pcmHandle);
867 if(err < 0)
869 ERR("snd_pcm_prepare(data->pcmHandle) failed: %s\n", snd_strerror(err));
870 return ALC_FALSE;
872 data->thread = StartThread(ALSAProc, device);
874 if(data->thread == NULL)
876 ERR("Could not create playback thread\n");
877 free(data->buffer);
878 data->buffer = NULL;
879 return ALC_FALSE;
882 return ALC_TRUE;
884 error:
885 ERR("%s failed: %s\n", funcerr, snd_strerror(err));
886 if(hp) snd_pcm_hw_params_free(hp);
887 return ALC_FALSE;
890 static void alsa_stop_playback(ALCdevice *device)
892 alsa_data *data = (alsa_data*)device->ExtraData;
894 if(data->thread)
896 data->killNow = 1;
897 StopThread(data->thread);
898 data->thread = NULL;
900 data->killNow = 0;
901 free(data->buffer);
902 data->buffer = NULL;
906 static ALCenum alsa_open_capture(ALCdevice *Device, const ALCchar *deviceName)
908 const char *driver = NULL;
909 snd_pcm_hw_params_t *hp;
910 snd_pcm_uframes_t bufferSizeInFrames;
911 snd_pcm_uframes_t periodSizeInFrames;
912 ALboolean needring = AL_FALSE;
913 snd_pcm_format_t format;
914 const char *funcerr;
915 alsa_data *data;
916 int err;
918 if(deviceName)
920 size_t idx;
922 if(!allCaptureDevNameMap)
923 allCaptureDevNameMap = probe_devices(SND_PCM_STREAM_CAPTURE, &numCaptureDevNames);
925 for(idx = 0;idx < numCaptureDevNames;idx++)
927 if(strcmp(deviceName, allCaptureDevNameMap[idx].name) == 0)
929 driver = allCaptureDevNameMap[idx].device;
930 break;
933 if(idx == numCaptureDevNames)
934 return ALC_INVALID_VALUE;
936 else
938 deviceName = alsaDevice;
939 driver = GetConfigValue("alsa", "capture", "default");
942 data = (alsa_data*)calloc(1, sizeof(alsa_data));
944 err = snd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
945 if(err < 0)
947 ERR("Could not open capture device '%s': %s\n", driver, snd_strerror(err));
948 free(data);
949 return ALC_INVALID_VALUE;
952 format = -1;
953 switch(Device->FmtType)
955 case DevFmtByte:
956 format = SND_PCM_FORMAT_S8;
957 break;
958 case DevFmtUByte:
959 format = SND_PCM_FORMAT_U8;
960 break;
961 case DevFmtShort:
962 format = SND_PCM_FORMAT_S16;
963 break;
964 case DevFmtUShort:
965 format = SND_PCM_FORMAT_U16;
966 break;
967 case DevFmtInt:
968 format = SND_PCM_FORMAT_S32;
969 break;
970 case DevFmtUInt:
971 format = SND_PCM_FORMAT_U32;
972 break;
973 case DevFmtFloat:
974 format = SND_PCM_FORMAT_FLOAT;
975 break;
978 funcerr = NULL;
979 bufferSizeInFrames = maxu(Device->UpdateSize*Device->NumUpdates,
980 100*Device->Frequency/1000);
981 periodSizeInFrames = minu(bufferSizeInFrames, 25*Device->Frequency/1000);
983 snd_pcm_hw_params_malloc(&hp);
984 #define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error
985 CHECK(snd_pcm_hw_params_any(data->pcmHandle, hp));
986 /* set interleaved access */
987 CHECK(snd_pcm_hw_params_set_access(data->pcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED));
988 /* set format (implicitly sets sample bits) */
989 CHECK(snd_pcm_hw_params_set_format(data->pcmHandle, hp, format));
990 /* set channels (implicitly sets frame bits) */
991 CHECK(snd_pcm_hw_params_set_channels(data->pcmHandle, hp, ChannelsFromDevFmt(Device->FmtChans)));
992 /* set rate (implicitly constrains period/buffer parameters) */
993 CHECK(snd_pcm_hw_params_set_rate(data->pcmHandle, hp, Device->Frequency, 0));
994 /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */
995 if(snd_pcm_hw_params_set_buffer_size_min(data->pcmHandle, hp, &bufferSizeInFrames) < 0)
997 TRACE("Buffer too large, using intermediate ring buffer\n");
998 needring = AL_TRUE;
999 CHECK(snd_pcm_hw_params_set_buffer_size_near(data->pcmHandle, hp, &bufferSizeInFrames));
1001 /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */
1002 CHECK(snd_pcm_hw_params_set_period_size_near(data->pcmHandle, hp, &periodSizeInFrames, NULL));
1003 /* install and prepare hardware configuration */
1004 CHECK(snd_pcm_hw_params(data->pcmHandle, hp));
1005 /* retrieve configuration info */
1006 CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, NULL));
1007 #undef CHECK
1008 snd_pcm_hw_params_free(hp);
1009 hp = NULL;
1011 if(needring)
1013 data->ring = CreateRingBuffer(FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType),
1014 Device->UpdateSize*Device->NumUpdates);
1015 if(!data->ring)
1017 ERR("ring buffer create failed\n");
1018 goto error2;
1021 data->size = snd_pcm_frames_to_bytes(data->pcmHandle, periodSizeInFrames);
1022 data->buffer = malloc(data->size);
1023 if(!data->buffer)
1025 ERR("buffer malloc failed\n");
1026 goto error2;
1030 Device->DeviceName = strdup(deviceName);
1032 Device->ExtraData = data;
1033 return ALC_NO_ERROR;
1035 error:
1036 ERR("%s failed: %s\n", funcerr, snd_strerror(err));
1037 if(hp) snd_pcm_hw_params_free(hp);
1039 error2:
1040 free(data->buffer);
1041 DestroyRingBuffer(data->ring);
1042 snd_pcm_close(data->pcmHandle);
1043 free(data);
1045 Device->ExtraData = NULL;
1046 return ALC_INVALID_VALUE;
1049 static void alsa_close_capture(ALCdevice *Device)
1051 alsa_data *data = (alsa_data*)Device->ExtraData;
1053 snd_pcm_close(data->pcmHandle);
1054 DestroyRingBuffer(data->ring);
1056 free(data->buffer);
1057 free(data);
1058 Device->ExtraData = NULL;
1061 static void alsa_start_capture(ALCdevice *Device)
1063 alsa_data *data = (alsa_data*)Device->ExtraData;
1064 int err;
1066 err = snd_pcm_start(data->pcmHandle);
1067 if(err < 0)
1069 ERR("start failed: %s\n", snd_strerror(err));
1070 aluHandleDisconnect(Device);
1072 else
1073 data->doCapture = AL_TRUE;
1076 static ALCenum alsa_capture_samples(ALCdevice *Device, ALCvoid *Buffer, ALCuint Samples)
1078 alsa_data *data = (alsa_data*)Device->ExtraData;
1080 if(data->ring)
1082 ReadRingBuffer(data->ring, Buffer, Samples);
1083 return ALC_NO_ERROR;
1086 data->last_avail -= Samples;
1087 while(Device->Connected && Samples > 0)
1089 snd_pcm_sframes_t amt = 0;
1091 if(data->size > 0)
1093 /* First get any data stored from the last stop */
1094 amt = snd_pcm_bytes_to_frames(data->pcmHandle, data->size);
1095 if((snd_pcm_uframes_t)amt > Samples) amt = Samples;
1097 amt = snd_pcm_frames_to_bytes(data->pcmHandle, amt);
1098 memmove(Buffer, data->buffer, amt);
1100 if(data->size > amt)
1102 memmove(data->buffer, data->buffer+amt, data->size - amt);
1103 data->size -= amt;
1105 else
1107 free(data->buffer);
1108 data->buffer = NULL;
1109 data->size = 0;
1111 amt = snd_pcm_bytes_to_frames(data->pcmHandle, amt);
1113 else if(data->doCapture)
1114 amt = snd_pcm_readi(data->pcmHandle, Buffer, Samples);
1115 if(amt < 0)
1117 ERR("read error: %s\n", snd_strerror(amt));
1119 if(amt == -EAGAIN)
1120 continue;
1121 if((amt=snd_pcm_recover(data->pcmHandle, amt, 1)) >= 0)
1123 amt = snd_pcm_start(data->pcmHandle);
1124 if(amt >= 0)
1125 amt = snd_pcm_avail_update(data->pcmHandle);
1127 if(amt < 0)
1129 ERR("restore error: %s\n", snd_strerror(amt));
1130 aluHandleDisconnect(Device);
1131 break;
1133 /* If the amount available is less than what's asked, we lost it
1134 * during recovery. So just give silence instead. */
1135 if((snd_pcm_uframes_t)amt < Samples)
1136 break;
1137 continue;
1140 Buffer = (ALbyte*)Buffer + amt;
1141 Samples -= amt;
1143 if(Samples > 0)
1144 memset(Buffer, ((Device->FmtType == DevFmtUByte) ? 0x80 : 0),
1145 snd_pcm_frames_to_bytes(data->pcmHandle, Samples));
1147 return ALC_NO_ERROR;
1150 static ALCuint alsa_available_samples(ALCdevice *Device)
1152 alsa_data *data = (alsa_data*)Device->ExtraData;
1153 snd_pcm_sframes_t avail = 0;
1155 if(Device->Connected && data->doCapture)
1156 avail = snd_pcm_avail_update(data->pcmHandle);
1157 if(avail < 0)
1159 ERR("avail update failed: %s\n", snd_strerror(avail));
1161 if((avail=snd_pcm_recover(data->pcmHandle, avail, 1)) >= 0)
1163 if(data->doCapture)
1164 avail = snd_pcm_start(data->pcmHandle);
1165 if(avail >= 0)
1166 avail = snd_pcm_avail_update(data->pcmHandle);
1168 if(avail < 0)
1170 ERR("restore error: %s\n", snd_strerror(avail));
1171 aluHandleDisconnect(Device);
1175 if(!data->ring)
1177 if(avail < 0) avail = 0;
1178 avail += snd_pcm_bytes_to_frames(data->pcmHandle, data->size);
1179 if(avail > data->last_avail) data->last_avail = avail;
1180 return data->last_avail;
1183 while(avail > 0)
1185 snd_pcm_sframes_t amt;
1187 amt = snd_pcm_bytes_to_frames(data->pcmHandle, data->size);
1188 if(avail < amt) amt = avail;
1190 amt = snd_pcm_readi(data->pcmHandle, data->buffer, amt);
1191 if(amt < 0)
1193 ERR("read error: %s\n", snd_strerror(amt));
1195 if(amt == -EAGAIN)
1196 continue;
1197 if((amt=snd_pcm_recover(data->pcmHandle, amt, 1)) >= 0)
1199 if(data->doCapture)
1200 amt = snd_pcm_start(data->pcmHandle);
1201 if(amt >= 0)
1202 amt = snd_pcm_avail_update(data->pcmHandle);
1204 if(amt < 0)
1206 ERR("restore error: %s\n", snd_strerror(amt));
1207 aluHandleDisconnect(Device);
1208 break;
1210 avail = amt;
1211 continue;
1214 WriteRingBuffer(data->ring, data->buffer, amt);
1215 avail -= amt;
1218 return RingBufferSize(data->ring);
1221 static void alsa_stop_capture(ALCdevice *Device)
1223 alsa_data *data = (alsa_data*)Device->ExtraData;
1224 ALCuint avail;
1225 int err;
1227 /* OpenAL requires access to unread audio after stopping, but ALSA's
1228 * snd_pcm_drain is unreliable and snd_pcm_drop drops it. Capture what's
1229 * available now so it'll be available later after the drop. */
1230 avail = alsa_available_samples(Device);
1231 if(!data->ring && avail > 0)
1233 /* The ring buffer implicitly captures when checking availability.
1234 * Direct access needs to explicitly capture it into temp storage. */
1235 ALsizei size;
1236 void *ptr;
1238 size = snd_pcm_frames_to_bytes(data->pcmHandle, avail);
1239 ptr = realloc(data->buffer, size);
1240 if(ptr)
1242 data->buffer = ptr;
1243 alsa_capture_samples(Device, data->buffer, avail);
1244 data->size = size;
1247 err = snd_pcm_drop(data->pcmHandle);
1248 if(err < 0)
1249 ERR("drop failed: %s\n", snd_strerror(err));
1250 data->doCapture = AL_FALSE;
1254 static ALint64 alsa_get_latency(ALCdevice *device)
1256 alsa_data *data = (alsa_data*)device->ExtraData;
1257 snd_pcm_sframes_t delay = 0;
1258 int err;
1260 if((err=snd_pcm_delay(data->pcmHandle, &delay)) < 0)
1262 ERR("Failed to get pcm delay: %s\n", snd_strerror(err));
1263 return 0;
1265 return maxi64((ALint64)delay*1000000000/device->Frequency, 0);
1269 static const BackendFuncs alsa_funcs = {
1270 alsa_open_playback,
1271 alsa_close_playback,
1272 alsa_reset_playback,
1273 alsa_start_playback,
1274 alsa_stop_playback,
1275 alsa_open_capture,
1276 alsa_close_capture,
1277 alsa_start_capture,
1278 alsa_stop_capture,
1279 alsa_capture_samples,
1280 alsa_available_samples,
1281 ALCdevice_LockDefault,
1282 ALCdevice_UnlockDefault,
1283 alsa_get_latency
1286 ALCboolean alc_alsa_init(BackendFuncs *func_list)
1288 if(!alsa_load())
1289 return ALC_FALSE;
1290 *func_list = alsa_funcs;
1291 return ALC_TRUE;
1294 void alc_alsa_deinit(void)
1296 ALuint i;
1298 for(i = 0;i < numDevNames;++i)
1300 free(allDevNameMap[i].name);
1301 free(allDevNameMap[i].device);
1303 free(allDevNameMap);
1304 allDevNameMap = NULL;
1305 numDevNames = 0;
1307 for(i = 0;i < numCaptureDevNames;++i)
1309 free(allCaptureDevNameMap[i].name);
1310 free(allCaptureDevNameMap[i].device);
1312 free(allCaptureDevNameMap);
1313 allCaptureDevNameMap = NULL;
1314 numCaptureDevNames = 0;
1316 #ifdef HAVE_DYNLOAD
1317 if(alsa_handle)
1318 CloseLib(alsa_handle);
1319 alsa_handle = NULL;
1320 #endif
1323 void alc_alsa_probe(enum DevProbe type)
1325 ALuint i;
1327 switch(type)
1329 case ALL_DEVICE_PROBE:
1330 for(i = 0;i < numDevNames;++i)
1332 free(allDevNameMap[i].name);
1333 free(allDevNameMap[i].device);
1336 free(allDevNameMap);
1337 allDevNameMap = probe_devices(SND_PCM_STREAM_PLAYBACK, &numDevNames);
1339 for(i = 0;i < numDevNames;++i)
1340 AppendAllDevicesList(allDevNameMap[i].name);
1341 break;
1343 case CAPTURE_DEVICE_PROBE:
1344 for(i = 0;i < numCaptureDevNames;++i)
1346 free(allCaptureDevNameMap[i].name);
1347 free(allCaptureDevNameMap[i].device);
1350 free(allCaptureDevNameMap);
1351 allCaptureDevNameMap = probe_devices(SND_PCM_STREAM_CAPTURE, &numCaptureDevNames);
1353 for(i = 0;i < numCaptureDevNames;++i)
1354 AppendCaptureDeviceList(allCaptureDevNameMap[i].name);
1355 break;