Remove 'v' from the source enum names
[openal-soft.git] / Alc / backends / alsa.c
blob5ff6307f141d0cbf57080eefeba8d4582489c47a
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"
28 #include "alu.h"
30 #include <alsa/asoundlib.h>
33 static const ALCchar alsaDevice[] = "ALSA Default";
36 #ifdef HAVE_DYNLOAD
37 static void *alsa_handle;
38 #define MAKE_FUNC(f) static typeof(f) * p##f
39 MAKE_FUNC(snd_strerror);
40 MAKE_FUNC(snd_pcm_open);
41 MAKE_FUNC(snd_pcm_close);
42 MAKE_FUNC(snd_pcm_nonblock);
43 MAKE_FUNC(snd_pcm_frames_to_bytes);
44 MAKE_FUNC(snd_pcm_bytes_to_frames);
45 MAKE_FUNC(snd_pcm_hw_params_malloc);
46 MAKE_FUNC(snd_pcm_hw_params_free);
47 MAKE_FUNC(snd_pcm_hw_params_any);
48 MAKE_FUNC(snd_pcm_hw_params_current);
49 MAKE_FUNC(snd_pcm_hw_params_set_access);
50 MAKE_FUNC(snd_pcm_hw_params_set_format);
51 MAKE_FUNC(snd_pcm_hw_params_set_channels);
52 MAKE_FUNC(snd_pcm_hw_params_set_periods_near);
53 MAKE_FUNC(snd_pcm_hw_params_set_rate_near);
54 MAKE_FUNC(snd_pcm_hw_params_set_rate);
55 MAKE_FUNC(snd_pcm_hw_params_set_rate_resample);
56 MAKE_FUNC(snd_pcm_hw_params_set_buffer_time_near);
57 MAKE_FUNC(snd_pcm_hw_params_set_period_time_near);
58 MAKE_FUNC(snd_pcm_hw_params_set_buffer_size_near);
59 MAKE_FUNC(snd_pcm_hw_params_set_period_size_near);
60 MAKE_FUNC(snd_pcm_hw_params_set_buffer_size_min);
61 MAKE_FUNC(snd_pcm_hw_params_get_buffer_time_min);
62 MAKE_FUNC(snd_pcm_hw_params_get_buffer_time_max);
63 MAKE_FUNC(snd_pcm_hw_params_get_period_time_min);
64 MAKE_FUNC(snd_pcm_hw_params_get_period_time_max);
65 MAKE_FUNC(snd_pcm_hw_params_get_buffer_size);
66 MAKE_FUNC(snd_pcm_hw_params_get_period_size);
67 MAKE_FUNC(snd_pcm_hw_params_get_access);
68 MAKE_FUNC(snd_pcm_hw_params_get_periods);
69 MAKE_FUNC(snd_pcm_hw_params_test_format);
70 MAKE_FUNC(snd_pcm_hw_params_test_channels);
71 MAKE_FUNC(snd_pcm_hw_params);
72 MAKE_FUNC(snd_pcm_sw_params_malloc);
73 MAKE_FUNC(snd_pcm_sw_params_current);
74 MAKE_FUNC(snd_pcm_sw_params_set_avail_min);
75 MAKE_FUNC(snd_pcm_sw_params_set_stop_threshold);
76 MAKE_FUNC(snd_pcm_sw_params);
77 MAKE_FUNC(snd_pcm_sw_params_free);
78 MAKE_FUNC(snd_pcm_prepare);
79 MAKE_FUNC(snd_pcm_start);
80 MAKE_FUNC(snd_pcm_resume);
81 MAKE_FUNC(snd_pcm_reset);
82 MAKE_FUNC(snd_pcm_wait);
83 MAKE_FUNC(snd_pcm_delay);
84 MAKE_FUNC(snd_pcm_state);
85 MAKE_FUNC(snd_pcm_avail_update);
86 MAKE_FUNC(snd_pcm_areas_silence);
87 MAKE_FUNC(snd_pcm_mmap_begin);
88 MAKE_FUNC(snd_pcm_mmap_commit);
89 MAKE_FUNC(snd_pcm_readi);
90 MAKE_FUNC(snd_pcm_writei);
91 MAKE_FUNC(snd_pcm_drain);
92 MAKE_FUNC(snd_pcm_drop);
93 MAKE_FUNC(snd_pcm_recover);
94 MAKE_FUNC(snd_pcm_info_malloc);
95 MAKE_FUNC(snd_pcm_info_free);
96 MAKE_FUNC(snd_pcm_info_set_device);
97 MAKE_FUNC(snd_pcm_info_set_subdevice);
98 MAKE_FUNC(snd_pcm_info_set_stream);
99 MAKE_FUNC(snd_pcm_info_get_name);
100 MAKE_FUNC(snd_ctl_pcm_next_device);
101 MAKE_FUNC(snd_ctl_pcm_info);
102 MAKE_FUNC(snd_ctl_open);
103 MAKE_FUNC(snd_ctl_close);
104 MAKE_FUNC(snd_ctl_card_info_malloc);
105 MAKE_FUNC(snd_ctl_card_info_free);
106 MAKE_FUNC(snd_ctl_card_info);
107 MAKE_FUNC(snd_ctl_card_info_get_name);
108 MAKE_FUNC(snd_ctl_card_info_get_id);
109 MAKE_FUNC(snd_card_next);
110 MAKE_FUNC(snd_config_update_free_global);
111 #undef MAKE_FUNC
113 #define snd_strerror psnd_strerror
114 #define snd_pcm_open psnd_pcm_open
115 #define snd_pcm_close psnd_pcm_close
116 #define snd_pcm_nonblock psnd_pcm_nonblock
117 #define snd_pcm_frames_to_bytes psnd_pcm_frames_to_bytes
118 #define snd_pcm_bytes_to_frames psnd_pcm_bytes_to_frames
119 #define snd_pcm_hw_params_malloc psnd_pcm_hw_params_malloc
120 #define snd_pcm_hw_params_free psnd_pcm_hw_params_free
121 #define snd_pcm_hw_params_any psnd_pcm_hw_params_any
122 #define snd_pcm_hw_params_current psnd_pcm_hw_params_current
123 #define snd_pcm_hw_params_set_access psnd_pcm_hw_params_set_access
124 #define snd_pcm_hw_params_set_format psnd_pcm_hw_params_set_format
125 #define snd_pcm_hw_params_set_channels psnd_pcm_hw_params_set_channels
126 #define snd_pcm_hw_params_set_periods_near psnd_pcm_hw_params_set_periods_near
127 #define snd_pcm_hw_params_set_rate_near psnd_pcm_hw_params_set_rate_near
128 #define snd_pcm_hw_params_set_rate psnd_pcm_hw_params_set_rate
129 #define snd_pcm_hw_params_set_rate_resample psnd_pcm_hw_params_set_rate_resample
130 #define snd_pcm_hw_params_set_buffer_time_near psnd_pcm_hw_params_set_buffer_time_near
131 #define snd_pcm_hw_params_set_period_time_near psnd_pcm_hw_params_set_period_time_near
132 #define snd_pcm_hw_params_set_buffer_size_near psnd_pcm_hw_params_set_buffer_size_near
133 #define snd_pcm_hw_params_set_period_size_near psnd_pcm_hw_params_set_period_size_near
134 #define snd_pcm_hw_params_set_buffer_size_min psnd_pcm_hw_params_set_buffer_size_min
135 #define snd_pcm_hw_params_get_buffer_time_min psnd_pcm_hw_params_get_buffer_time_min
136 #define snd_pcm_hw_params_get_buffer_time_max psnd_pcm_hw_params_get_buffer_time_max
137 #define snd_pcm_hw_params_get_period_time_min psnd_pcm_hw_params_get_period_time_min
138 #define snd_pcm_hw_params_get_period_time_max psnd_pcm_hw_params_get_period_time_max
139 #define snd_pcm_hw_params_get_buffer_size psnd_pcm_hw_params_get_buffer_size
140 #define snd_pcm_hw_params_get_period_size psnd_pcm_hw_params_get_period_size
141 #define snd_pcm_hw_params_get_access psnd_pcm_hw_params_get_access
142 #define snd_pcm_hw_params_get_periods psnd_pcm_hw_params_get_periods
143 #define snd_pcm_hw_params_test_format psnd_pcm_hw_params_test_format
144 #define snd_pcm_hw_params_test_channels psnd_pcm_hw_params_test_channels
145 #define snd_pcm_hw_params psnd_pcm_hw_params
146 #define snd_pcm_sw_params_malloc psnd_pcm_sw_params_malloc
147 #define snd_pcm_sw_params_current psnd_pcm_sw_params_current
148 #define snd_pcm_sw_params_set_avail_min psnd_pcm_sw_params_set_avail_min
149 #define snd_pcm_sw_params_set_stop_threshold psnd_pcm_sw_params_set_stop_threshold
150 #define snd_pcm_sw_params psnd_pcm_sw_params
151 #define snd_pcm_sw_params_free psnd_pcm_sw_params_free
152 #define snd_pcm_prepare psnd_pcm_prepare
153 #define snd_pcm_start psnd_pcm_start
154 #define snd_pcm_resume psnd_pcm_resume
155 #define snd_pcm_reset psnd_pcm_reset
156 #define snd_pcm_wait psnd_pcm_wait
157 #define snd_pcm_delay psnd_pcm_delay
158 #define snd_pcm_state psnd_pcm_state
159 #define snd_pcm_avail_update psnd_pcm_avail_update
160 #define snd_pcm_areas_silence psnd_pcm_areas_silence
161 #define snd_pcm_mmap_begin psnd_pcm_mmap_begin
162 #define snd_pcm_mmap_commit psnd_pcm_mmap_commit
163 #define snd_pcm_readi psnd_pcm_readi
164 #define snd_pcm_writei psnd_pcm_writei
165 #define snd_pcm_drain psnd_pcm_drain
166 #define snd_pcm_drop psnd_pcm_drop
167 #define snd_pcm_recover psnd_pcm_recover
168 #define snd_pcm_info_malloc psnd_pcm_info_malloc
169 #define snd_pcm_info_free psnd_pcm_info_free
170 #define snd_pcm_info_set_device psnd_pcm_info_set_device
171 #define snd_pcm_info_set_subdevice psnd_pcm_info_set_subdevice
172 #define snd_pcm_info_set_stream psnd_pcm_info_set_stream
173 #define snd_pcm_info_get_name psnd_pcm_info_get_name
174 #define snd_ctl_pcm_next_device psnd_ctl_pcm_next_device
175 #define snd_ctl_pcm_info psnd_ctl_pcm_info
176 #define snd_ctl_open psnd_ctl_open
177 #define snd_ctl_close psnd_ctl_close
178 #define snd_ctl_card_info_malloc psnd_ctl_card_info_malloc
179 #define snd_ctl_card_info_free psnd_ctl_card_info_free
180 #define snd_ctl_card_info psnd_ctl_card_info
181 #define snd_ctl_card_info_get_name psnd_ctl_card_info_get_name
182 #define snd_ctl_card_info_get_id psnd_ctl_card_info_get_id
183 #define snd_card_next psnd_card_next
184 #define snd_config_update_free_global psnd_config_update_free_global
185 #endif
188 static ALCboolean alsa_load(void)
190 #ifdef HAVE_DYNLOAD
191 if(!alsa_handle)
193 alsa_handle = LoadLib("libasound.so.2");
194 if(!alsa_handle)
195 return ALC_FALSE;
197 #define LOAD_FUNC(f) do { \
198 p##f = GetSymbol(alsa_handle, #f); \
199 if(p##f == NULL) { \
200 CloseLib(alsa_handle); \
201 alsa_handle = NULL; \
202 return ALC_FALSE; \
204 } while(0)
205 LOAD_FUNC(snd_strerror);
206 LOAD_FUNC(snd_pcm_open);
207 LOAD_FUNC(snd_pcm_close);
208 LOAD_FUNC(snd_pcm_nonblock);
209 LOAD_FUNC(snd_pcm_frames_to_bytes);
210 LOAD_FUNC(snd_pcm_bytes_to_frames);
211 LOAD_FUNC(snd_pcm_hw_params_malloc);
212 LOAD_FUNC(snd_pcm_hw_params_free);
213 LOAD_FUNC(snd_pcm_hw_params_any);
214 LOAD_FUNC(snd_pcm_hw_params_current);
215 LOAD_FUNC(snd_pcm_hw_params_set_access);
216 LOAD_FUNC(snd_pcm_hw_params_set_format);
217 LOAD_FUNC(snd_pcm_hw_params_set_channels);
218 LOAD_FUNC(snd_pcm_hw_params_set_periods_near);
219 LOAD_FUNC(snd_pcm_hw_params_set_rate_near);
220 LOAD_FUNC(snd_pcm_hw_params_set_rate);
221 LOAD_FUNC(snd_pcm_hw_params_set_rate_resample);
222 LOAD_FUNC(snd_pcm_hw_params_set_buffer_time_near);
223 LOAD_FUNC(snd_pcm_hw_params_set_period_time_near);
224 LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_near);
225 LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_min);
226 LOAD_FUNC(snd_pcm_hw_params_set_period_size_near);
227 LOAD_FUNC(snd_pcm_hw_params_get_buffer_time_min);
228 LOAD_FUNC(snd_pcm_hw_params_get_buffer_time_max);
229 LOAD_FUNC(snd_pcm_hw_params_get_period_time_min);
230 LOAD_FUNC(snd_pcm_hw_params_get_period_time_max);
231 LOAD_FUNC(snd_pcm_hw_params_get_buffer_size);
232 LOAD_FUNC(snd_pcm_hw_params_get_period_size);
233 LOAD_FUNC(snd_pcm_hw_params_get_access);
234 LOAD_FUNC(snd_pcm_hw_params_get_periods);
235 LOAD_FUNC(snd_pcm_hw_params_test_format);
236 LOAD_FUNC(snd_pcm_hw_params_test_channels);
237 LOAD_FUNC(snd_pcm_hw_params);
238 LOAD_FUNC(snd_pcm_sw_params_malloc);
239 LOAD_FUNC(snd_pcm_sw_params_current);
240 LOAD_FUNC(snd_pcm_sw_params_set_avail_min);
241 LOAD_FUNC(snd_pcm_sw_params_set_stop_threshold);
242 LOAD_FUNC(snd_pcm_sw_params);
243 LOAD_FUNC(snd_pcm_sw_params_free);
244 LOAD_FUNC(snd_pcm_prepare);
245 LOAD_FUNC(snd_pcm_start);
246 LOAD_FUNC(snd_pcm_resume);
247 LOAD_FUNC(snd_pcm_reset);
248 LOAD_FUNC(snd_pcm_wait);
249 LOAD_FUNC(snd_pcm_delay);
250 LOAD_FUNC(snd_pcm_state);
251 LOAD_FUNC(snd_pcm_avail_update);
252 LOAD_FUNC(snd_pcm_areas_silence);
253 LOAD_FUNC(snd_pcm_mmap_begin);
254 LOAD_FUNC(snd_pcm_mmap_commit);
255 LOAD_FUNC(snd_pcm_readi);
256 LOAD_FUNC(snd_pcm_writei);
257 LOAD_FUNC(snd_pcm_drain);
258 LOAD_FUNC(snd_pcm_drop);
259 LOAD_FUNC(snd_pcm_recover);
260 LOAD_FUNC(snd_pcm_info_malloc);
261 LOAD_FUNC(snd_pcm_info_free);
262 LOAD_FUNC(snd_pcm_info_set_device);
263 LOAD_FUNC(snd_pcm_info_set_subdevice);
264 LOAD_FUNC(snd_pcm_info_set_stream);
265 LOAD_FUNC(snd_pcm_info_get_name);
266 LOAD_FUNC(snd_ctl_pcm_next_device);
267 LOAD_FUNC(snd_ctl_pcm_info);
268 LOAD_FUNC(snd_ctl_open);
269 LOAD_FUNC(snd_ctl_close);
270 LOAD_FUNC(snd_ctl_card_info_malloc);
271 LOAD_FUNC(snd_ctl_card_info_free);
272 LOAD_FUNC(snd_ctl_card_info);
273 LOAD_FUNC(snd_ctl_card_info_get_name);
274 LOAD_FUNC(snd_ctl_card_info_get_id);
275 LOAD_FUNC(snd_card_next);
276 LOAD_FUNC(snd_config_update_free_global);
277 #undef LOAD_FUNC
279 #endif
280 return ALC_TRUE;
284 typedef struct {
285 snd_pcm_t *pcmHandle;
287 ALvoid *buffer;
288 ALsizei size;
290 ALboolean doCapture;
291 RingBuffer *ring;
293 snd_pcm_sframes_t last_avail;
295 volatile int killNow;
296 ALvoid *thread;
297 } alsa_data;
299 typedef struct {
300 ALCchar *name;
301 char *device;
302 } DevMap;
304 static DevMap *allDevNameMap;
305 static ALuint numDevNames;
306 static DevMap *allCaptureDevNameMap;
307 static ALuint numCaptureDevNames;
310 static const char *prefix_name(snd_pcm_stream_t stream)
312 assert(stream == SND_PCM_STREAM_PLAYBACK || stream == SND_PCM_STREAM_CAPTURE);
313 return (stream==SND_PCM_STREAM_PLAYBACK) ? "device-prefix" : "capture-prefix";
316 static DevMap *probe_devices(snd_pcm_stream_t stream, ALuint *count)
318 const char *main_prefix = "plughw:";
319 snd_ctl_t *handle;
320 int card, err, dev, idx;
321 snd_ctl_card_info_t *info;
322 snd_pcm_info_t *pcminfo;
323 DevMap *DevList;
325 snd_ctl_card_info_malloc(&info);
326 snd_pcm_info_malloc(&pcminfo);
328 DevList = malloc(sizeof(DevMap) * 1);
329 DevList[0].name = strdup(alsaDevice);
330 DevList[0].device = strdup(GetConfigValue("alsa", (stream==SND_PCM_STREAM_PLAYBACK) ?
331 "device" : "capture", "default"));
332 idx = 1;
334 card = -1;
335 if((err=snd_card_next(&card)) < 0)
336 ERR("Failed to find a card: %s\n", snd_strerror(err));
337 ConfigValueStr("alsa", prefix_name(stream), &main_prefix);
338 while(card >= 0)
340 const char *card_prefix = main_prefix;
341 const char *cardname, *cardid;
342 char name[256];
344 snprintf(name, sizeof(name), "hw:%d", card);
345 if((err = snd_ctl_open(&handle, name, 0)) < 0)
347 ERR("control open (hw:%d): %s\n", card, snd_strerror(err));
348 goto next_card;
350 if((err = snd_ctl_card_info(handle, info)) < 0)
352 ERR("control hardware info (hw:%d): %s\n", card, snd_strerror(err));
353 snd_ctl_close(handle);
354 goto next_card;
357 cardname = snd_ctl_card_info_get_name(info);
358 cardid = snd_ctl_card_info_get_id(info);
360 snprintf(name, sizeof(name), "%s-%s", prefix_name(stream), cardid);
361 ConfigValueStr("alsa", name, &card_prefix);
363 dev = -1;
364 while(1)
366 const char *devname;
367 void *temp;
369 if(snd_ctl_pcm_next_device(handle, &dev) < 0)
370 ERR("snd_ctl_pcm_next_device failed\n");
371 if(dev < 0)
372 break;
374 snd_pcm_info_set_device(pcminfo, dev);
375 snd_pcm_info_set_subdevice(pcminfo, 0);
376 snd_pcm_info_set_stream(pcminfo, stream);
377 if((err = snd_ctl_pcm_info(handle, pcminfo)) < 0) {
378 if(err != -ENOENT)
379 ERR("control digital audio info (hw:%d): %s\n", card, snd_strerror(err));
380 continue;
383 temp = realloc(DevList, sizeof(DevMap) * (idx+1));
384 if(temp)
386 const char *device_prefix = card_prefix;
387 char device[128];
389 DevList = temp;
390 devname = snd_pcm_info_get_name(pcminfo);
392 snprintf(name, sizeof(name), "%s-%s-%d", prefix_name(stream), cardid, dev);
393 ConfigValueStr("alsa", name, &device_prefix);
395 snprintf(name, sizeof(name), "%s, %s (CARD=%s,DEV=%d)",
396 cardname, devname, cardid, dev);
397 snprintf(device, sizeof(device), "%sCARD=%s,DEV=%d",
398 device_prefix, cardid, dev);
400 TRACE("Got device \"%s\", \"%s\"\n", name, device);
401 DevList[idx].name = strdup(name);
402 DevList[idx].device = strdup(device);
403 idx++;
406 snd_ctl_close(handle);
407 next_card:
408 if(snd_card_next(&card) < 0) {
409 ERR("snd_card_next failed\n");
410 break;
414 snd_pcm_info_free(pcminfo);
415 snd_ctl_card_info_free(info);
417 *count = idx;
418 return DevList;
422 static int verify_state(snd_pcm_t *handle)
424 snd_pcm_state_t state = snd_pcm_state(handle);
425 int err;
427 switch(state)
429 case SND_PCM_STATE_OPEN:
430 case SND_PCM_STATE_SETUP:
431 case SND_PCM_STATE_PREPARED:
432 case SND_PCM_STATE_RUNNING:
433 case SND_PCM_STATE_DRAINING:
434 case SND_PCM_STATE_PAUSED:
435 /* All Okay */
436 break;
438 case SND_PCM_STATE_XRUN:
439 if((err=snd_pcm_recover(handle, -EPIPE, 1)) < 0)
440 return err;
441 break;
442 case SND_PCM_STATE_SUSPENDED:
443 if((err=snd_pcm_recover(handle, -ESTRPIPE, 1)) < 0)
444 return err;
445 break;
446 case SND_PCM_STATE_DISCONNECTED:
447 return -ENODEV;
450 return state;
454 static ALuint ALSAProc(ALvoid *ptr)
456 ALCdevice *Device = (ALCdevice*)ptr;
457 alsa_data *data = (alsa_data*)Device->ExtraData;
458 const snd_pcm_channel_area_t *areas = NULL;
459 snd_pcm_uframes_t update_size, num_updates;
460 snd_pcm_sframes_t avail, commitres;
461 snd_pcm_uframes_t offset, frames;
462 char *WritePtr;
463 int err;
465 SetRTPriority();
467 update_size = Device->UpdateSize;
468 num_updates = Device->NumUpdates;
469 while(!data->killNow)
471 int state = verify_state(data->pcmHandle);
472 if(state < 0)
474 ERR("Invalid state detected: %s\n", snd_strerror(state));
475 ALCdevice_Lock(Device);
476 aluHandleDisconnect(Device);
477 ALCdevice_Unlock(Device);
478 break;
481 avail = snd_pcm_avail_update(data->pcmHandle);
482 if(avail < 0)
484 ERR("available update failed: %s\n", snd_strerror(avail));
485 continue;
488 if((snd_pcm_uframes_t)avail > update_size*(num_updates+1))
490 WARN("available samples exceeds the buffer size\n");
491 snd_pcm_reset(data->pcmHandle);
492 continue;
495 // make sure there's frames to process
496 if((snd_pcm_uframes_t)avail < update_size)
498 if(state != SND_PCM_STATE_RUNNING)
500 err = snd_pcm_start(data->pcmHandle);
501 if(err < 0)
503 ERR("start failed: %s\n", snd_strerror(err));
504 continue;
507 if(snd_pcm_wait(data->pcmHandle, 1000) == 0)
508 ERR("Wait timeout... buffer size too low?\n");
509 continue;
511 avail -= avail%update_size;
513 // it is possible that contiguous areas are smaller, thus we use a loop
514 ALCdevice_Lock(Device);
515 while(avail > 0)
517 frames = avail;
519 err = snd_pcm_mmap_begin(data->pcmHandle, &areas, &offset, &frames);
520 if(err < 0)
522 ERR("mmap begin error: %s\n", snd_strerror(err));
523 break;
526 WritePtr = (char*)areas->addr + (offset * areas->step / 8);
527 aluMixData(Device, WritePtr, frames);
529 commitres = snd_pcm_mmap_commit(data->pcmHandle, offset, frames);
530 if(commitres < 0 || (commitres-frames) != 0)
532 ERR("mmap commit error: %s\n",
533 snd_strerror(commitres >= 0 ? -EPIPE : commitres));
534 break;
537 avail -= frames;
539 ALCdevice_Unlock(Device);
542 return 0;
545 static ALuint ALSANoMMapProc(ALvoid *ptr)
547 ALCdevice *Device = (ALCdevice*)ptr;
548 alsa_data *data = (alsa_data*)Device->ExtraData;
549 snd_pcm_uframes_t update_size, num_updates;
550 snd_pcm_sframes_t avail;
551 char *WritePtr;
552 int err;
554 SetRTPriority();
556 update_size = Device->UpdateSize;
557 num_updates = Device->NumUpdates;
558 while(!data->killNow)
560 int state = verify_state(data->pcmHandle);
561 if(state < 0)
563 ERR("Invalid state detected: %s\n", snd_strerror(state));
564 ALCdevice_Lock(Device);
565 aluHandleDisconnect(Device);
566 ALCdevice_Unlock(Device);
567 break;
570 avail = snd_pcm_avail_update(data->pcmHandle);
571 if(avail < 0)
573 ERR("available update failed: %s\n", snd_strerror(avail));
574 continue;
577 if((snd_pcm_uframes_t)avail > update_size*num_updates)
579 WARN("available samples exceeds the buffer size\n");
580 snd_pcm_reset(data->pcmHandle);
581 continue;
584 if((snd_pcm_uframes_t)avail < update_size)
586 if(state != SND_PCM_STATE_RUNNING)
588 err = snd_pcm_start(data->pcmHandle);
589 if(err < 0)
591 ERR("start failed: %s\n", snd_strerror(err));
592 continue;
595 if(snd_pcm_wait(data->pcmHandle, 1000) == 0)
596 ERR("Wait timeout... buffer size too low?\n");
597 continue;
600 ALCdevice_Lock(Device);
601 WritePtr = data->buffer;
602 avail = snd_pcm_bytes_to_frames(data->pcmHandle, data->size);
603 aluMixData(Device, WritePtr, avail);
605 while(avail > 0)
607 int ret = snd_pcm_writei(data->pcmHandle, WritePtr, avail);
608 switch (ret)
610 case -EAGAIN:
611 continue;
612 case -ESTRPIPE:
613 case -EPIPE:
614 case -EINTR:
615 ret = snd_pcm_recover(data->pcmHandle, ret, 1);
616 if(ret < 0)
617 avail = 0;
618 break;
619 default:
620 if (ret >= 0)
622 WritePtr += snd_pcm_frames_to_bytes(data->pcmHandle, ret);
623 avail -= ret;
625 break;
627 if (ret < 0)
629 ret = snd_pcm_prepare(data->pcmHandle);
630 if(ret < 0)
631 break;
634 ALCdevice_Unlock(Device);
637 return 0;
640 static ALCenum alsa_open_playback(ALCdevice *device, const ALCchar *deviceName)
642 const char *driver = NULL;
643 alsa_data *data;
644 int err;
646 if(deviceName)
648 size_t idx;
650 if(!allDevNameMap)
651 allDevNameMap = probe_devices(SND_PCM_STREAM_PLAYBACK, &numDevNames);
653 for(idx = 0;idx < numDevNames;idx++)
655 if(strcmp(deviceName, allDevNameMap[idx].name) == 0)
657 driver = allDevNameMap[idx].device;
658 break;
661 if(idx == numDevNames)
662 return ALC_INVALID_VALUE;
664 else
666 deviceName = alsaDevice;
667 driver = GetConfigValue("alsa", "device", "default");
670 data = (alsa_data*)calloc(1, sizeof(alsa_data));
672 err = snd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
673 if(err < 0)
675 free(data);
676 ERR("Could not open playback device '%s': %s\n", driver, snd_strerror(err));
677 return ALC_OUT_OF_MEMORY;
680 /* Free alsa's global config tree. Otherwise valgrind reports a ton of leaks. */
681 snd_config_update_free_global();
683 device->DeviceName = strdup(deviceName);
684 device->ExtraData = data;
685 return ALC_NO_ERROR;
688 static void alsa_close_playback(ALCdevice *device)
690 alsa_data *data = (alsa_data*)device->ExtraData;
692 snd_pcm_close(data->pcmHandle);
693 free(data);
694 device->ExtraData = NULL;
697 static ALCboolean alsa_reset_playback(ALCdevice *device)
699 alsa_data *data = (alsa_data*)device->ExtraData;
700 snd_pcm_uframes_t periodSizeInFrames;
701 unsigned int periodLen, bufferLen;
702 snd_pcm_sw_params_t *sp = NULL;
703 snd_pcm_hw_params_t *hp = NULL;
704 snd_pcm_access_t access;
705 snd_pcm_format_t format;
706 unsigned int periods;
707 unsigned int rate;
708 const char *funcerr;
709 int allowmmap;
710 int err;
712 format = -1;
713 switch(device->FmtType)
715 case DevFmtByte:
716 format = SND_PCM_FORMAT_S8;
717 break;
718 case DevFmtUByte:
719 format = SND_PCM_FORMAT_U8;
720 break;
721 case DevFmtShort:
722 format = SND_PCM_FORMAT_S16;
723 break;
724 case DevFmtUShort:
725 format = SND_PCM_FORMAT_U16;
726 break;
727 case DevFmtInt:
728 format = SND_PCM_FORMAT_S32;
729 break;
730 case DevFmtUInt:
731 format = SND_PCM_FORMAT_U32;
732 break;
733 case DevFmtFloat:
734 format = SND_PCM_FORMAT_FLOAT;
735 break;
738 allowmmap = GetConfigValueBool("alsa", "mmap", 1);
739 periods = device->NumUpdates;
740 periodLen = (ALuint64)device->UpdateSize * 1000000 / device->Frequency;
741 bufferLen = periodLen * periods;
742 rate = device->Frequency;
744 snd_pcm_hw_params_malloc(&hp);
745 #define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error
746 CHECK(snd_pcm_hw_params_any(data->pcmHandle, hp));
747 /* set interleaved access */
748 if(!allowmmap || snd_pcm_hw_params_set_access(data->pcmHandle, hp, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0)
750 /* No mmap */
751 CHECK(snd_pcm_hw_params_set_access(data->pcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED));
753 /* test and set format (implicitly sets sample bits) */
754 if(snd_pcm_hw_params_test_format(data->pcmHandle, hp, format) < 0)
756 static const struct {
757 snd_pcm_format_t format;
758 enum DevFmtType fmttype;
759 } formatlist[] = {
760 { SND_PCM_FORMAT_FLOAT, DevFmtFloat },
761 { SND_PCM_FORMAT_S32, DevFmtInt },
762 { SND_PCM_FORMAT_U32, DevFmtUInt },
763 { SND_PCM_FORMAT_S16, DevFmtShort },
764 { SND_PCM_FORMAT_U16, DevFmtUShort },
765 { SND_PCM_FORMAT_S8, DevFmtByte },
766 { SND_PCM_FORMAT_U8, DevFmtUByte },
768 size_t k;
770 for(k = 0;k < COUNTOF(formatlist);k++)
772 format = formatlist[k].format;
773 if(snd_pcm_hw_params_test_format(data->pcmHandle, hp, format) >= 0)
775 device->FmtType = formatlist[k].fmttype;
776 break;
780 CHECK(snd_pcm_hw_params_set_format(data->pcmHandle, hp, format));
781 /* test and set channels (implicitly sets frame bits) */
782 if(snd_pcm_hw_params_test_channels(data->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans)) < 0)
784 static const enum DevFmtChannels channellist[] = {
785 DevFmtStereo,
786 DevFmtQuad,
787 DevFmtX51,
788 DevFmtX71,
789 DevFmtMono,
791 size_t k;
793 for(k = 0;k < COUNTOF(channellist);k++)
795 if(snd_pcm_hw_params_test_channels(data->pcmHandle, hp, ChannelsFromDevFmt(channellist[k])) >= 0)
797 device->FmtChans = channellist[k];
798 break;
802 CHECK(snd_pcm_hw_params_set_channels(data->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans)));
803 /* set rate (implicitly constrains period/buffer parameters) */
804 if(snd_pcm_hw_params_set_rate_resample(data->pcmHandle, hp, 0) < 0)
805 ERR("Failed to disable ALSA resampler\n");
806 CHECK(snd_pcm_hw_params_set_rate_near(data->pcmHandle, hp, &rate, NULL));
807 /* set buffer time (implicitly constrains period/buffer parameters) */
808 if(snd_pcm_hw_params_set_buffer_time_near(data->pcmHandle, hp, &bufferLen, NULL) < 0)
809 ERR("snd_pcm_hw_params_set_buffer_time_near failed: %s\n", snd_strerror(err));
810 /* set period time (implicitly sets buffer size/bytes/time and period size/bytes) */
811 if(snd_pcm_hw_params_set_period_time_near(data->pcmHandle, hp, &periodLen, NULL) < 0)
812 ERR("snd_pcm_hw_params_set_period_time_near failed: %s\n", snd_strerror(err));
813 /* install and prepare hardware configuration */
814 CHECK(snd_pcm_hw_params(data->pcmHandle, hp));
815 /* retrieve configuration info */
816 CHECK(snd_pcm_hw_params_get_access(hp, &access));
817 CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, NULL));
818 CHECK(snd_pcm_hw_params_get_periods(hp, &periods, NULL));
820 snd_pcm_hw_params_free(hp);
821 hp = NULL;
822 snd_pcm_sw_params_malloc(&sp);
824 CHECK(snd_pcm_sw_params_current(data->pcmHandle, sp));
825 CHECK(snd_pcm_sw_params_set_avail_min(data->pcmHandle, sp, periodSizeInFrames));
826 CHECK(snd_pcm_sw_params_set_stop_threshold(data->pcmHandle, sp, periodSizeInFrames*periods));
827 CHECK(snd_pcm_sw_params(data->pcmHandle, sp));
828 #undef CHECK
829 snd_pcm_sw_params_free(sp);
830 sp = NULL;
832 device->NumUpdates = periods;
833 device->UpdateSize = periodSizeInFrames;
834 device->Frequency = rate;
836 SetDefaultChannelOrder(device);
838 return ALC_TRUE;
840 error:
841 ERR("%s failed: %s\n", funcerr, snd_strerror(err));
842 if(hp) snd_pcm_hw_params_free(hp);
843 if(sp) snd_pcm_sw_params_free(sp);
844 return ALC_FALSE;
847 static ALCboolean alsa_start_playback(ALCdevice *device)
849 alsa_data *data = (alsa_data*)device->ExtraData;
850 snd_pcm_hw_params_t *hp = NULL;
851 snd_pcm_access_t access;
852 const char *funcerr;
853 int err;
855 snd_pcm_hw_params_malloc(&hp);
856 #define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error
857 CHECK(snd_pcm_hw_params_current(data->pcmHandle, hp));
858 /* retrieve configuration info */
859 CHECK(snd_pcm_hw_params_get_access(hp, &access));
860 #undef CHECK
861 snd_pcm_hw_params_free(hp);
862 hp = NULL;
864 data->size = snd_pcm_frames_to_bytes(data->pcmHandle, device->UpdateSize);
865 if(access == SND_PCM_ACCESS_RW_INTERLEAVED)
867 data->buffer = malloc(data->size);
868 if(!data->buffer)
870 ERR("buffer malloc failed\n");
871 return ALC_FALSE;
873 data->thread = StartThread(ALSANoMMapProc, device);
875 else
877 err = snd_pcm_prepare(data->pcmHandle);
878 if(err < 0)
880 ERR("snd_pcm_prepare(data->pcmHandle) failed: %s\n", snd_strerror(err));
881 return ALC_FALSE;
883 data->thread = StartThread(ALSAProc, device);
885 if(data->thread == NULL)
887 ERR("Could not create playback thread\n");
888 free(data->buffer);
889 data->buffer = NULL;
890 return ALC_FALSE;
893 return ALC_TRUE;
895 error:
896 ERR("%s failed: %s\n", funcerr, snd_strerror(err));
897 if(hp) snd_pcm_hw_params_free(hp);
898 return ALC_FALSE;
901 static void alsa_stop_playback(ALCdevice *device)
903 alsa_data *data = (alsa_data*)device->ExtraData;
905 if(data->thread)
907 data->killNow = 1;
908 StopThread(data->thread);
909 data->thread = NULL;
911 data->killNow = 0;
912 free(data->buffer);
913 data->buffer = NULL;
917 static ALCenum alsa_open_capture(ALCdevice *Device, const ALCchar *deviceName)
919 const char *driver = NULL;
920 snd_pcm_hw_params_t *hp;
921 snd_pcm_uframes_t bufferSizeInFrames;
922 snd_pcm_uframes_t periodSizeInFrames;
923 ALboolean needring = AL_FALSE;
924 snd_pcm_format_t format;
925 const char *funcerr;
926 alsa_data *data;
927 int err;
929 if(deviceName)
931 size_t idx;
933 if(!allCaptureDevNameMap)
934 allCaptureDevNameMap = probe_devices(SND_PCM_STREAM_CAPTURE, &numCaptureDevNames);
936 for(idx = 0;idx < numCaptureDevNames;idx++)
938 if(strcmp(deviceName, allCaptureDevNameMap[idx].name) == 0)
940 driver = allCaptureDevNameMap[idx].device;
941 break;
944 if(idx == numCaptureDevNames)
945 return ALC_INVALID_VALUE;
947 else
949 deviceName = alsaDevice;
950 driver = GetConfigValue("alsa", "capture", "default");
953 data = (alsa_data*)calloc(1, sizeof(alsa_data));
955 err = snd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
956 if(err < 0)
958 ERR("Could not open capture device '%s': %s\n", driver, snd_strerror(err));
959 free(data);
960 return ALC_INVALID_VALUE;
963 /* Free alsa's global config tree. Otherwise valgrind reports a ton of leaks. */
964 snd_config_update_free_global();
966 format = -1;
967 switch(Device->FmtType)
969 case DevFmtByte:
970 format = SND_PCM_FORMAT_S8;
971 break;
972 case DevFmtUByte:
973 format = SND_PCM_FORMAT_U8;
974 break;
975 case DevFmtShort:
976 format = SND_PCM_FORMAT_S16;
977 break;
978 case DevFmtUShort:
979 format = SND_PCM_FORMAT_U16;
980 break;
981 case DevFmtInt:
982 format = SND_PCM_FORMAT_S32;
983 break;
984 case DevFmtUInt:
985 format = SND_PCM_FORMAT_U32;
986 break;
987 case DevFmtFloat:
988 format = SND_PCM_FORMAT_FLOAT;
989 break;
992 funcerr = NULL;
993 bufferSizeInFrames = maxu(Device->UpdateSize*Device->NumUpdates,
994 100*Device->Frequency/1000);
995 periodSizeInFrames = minu(bufferSizeInFrames, 25*Device->Frequency/1000);
997 snd_pcm_hw_params_malloc(&hp);
998 #define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error
999 CHECK(snd_pcm_hw_params_any(data->pcmHandle, hp));
1000 /* set interleaved access */
1001 CHECK(snd_pcm_hw_params_set_access(data->pcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED));
1002 /* set format (implicitly sets sample bits) */
1003 CHECK(snd_pcm_hw_params_set_format(data->pcmHandle, hp, format));
1004 /* set channels (implicitly sets frame bits) */
1005 CHECK(snd_pcm_hw_params_set_channels(data->pcmHandle, hp, ChannelsFromDevFmt(Device->FmtChans)));
1006 /* set rate (implicitly constrains period/buffer parameters) */
1007 CHECK(snd_pcm_hw_params_set_rate(data->pcmHandle, hp, Device->Frequency, 0));
1008 /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */
1009 if(snd_pcm_hw_params_set_buffer_size_min(data->pcmHandle, hp, &bufferSizeInFrames) < 0)
1011 TRACE("Buffer too large, using intermediate ring buffer\n");
1012 needring = AL_TRUE;
1013 CHECK(snd_pcm_hw_params_set_buffer_size_near(data->pcmHandle, hp, &bufferSizeInFrames));
1015 /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */
1016 CHECK(snd_pcm_hw_params_set_period_size_near(data->pcmHandle, hp, &periodSizeInFrames, NULL));
1017 /* install and prepare hardware configuration */
1018 CHECK(snd_pcm_hw_params(data->pcmHandle, hp));
1019 /* retrieve configuration info */
1020 CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, NULL));
1021 #undef CHECK
1022 snd_pcm_hw_params_free(hp);
1023 hp = NULL;
1025 if(needring)
1027 data->ring = CreateRingBuffer(FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType),
1028 Device->UpdateSize*Device->NumUpdates);
1029 if(!data->ring)
1031 ERR("ring buffer create failed\n");
1032 goto error2;
1035 data->size = snd_pcm_frames_to_bytes(data->pcmHandle, periodSizeInFrames);
1036 data->buffer = malloc(data->size);
1037 if(!data->buffer)
1039 ERR("buffer malloc failed\n");
1040 goto error2;
1044 Device->DeviceName = strdup(deviceName);
1046 Device->ExtraData = data;
1047 return ALC_NO_ERROR;
1049 error:
1050 ERR("%s failed: %s\n", funcerr, snd_strerror(err));
1051 if(hp) snd_pcm_hw_params_free(hp);
1053 error2:
1054 free(data->buffer);
1055 DestroyRingBuffer(data->ring);
1056 snd_pcm_close(data->pcmHandle);
1057 free(data);
1059 Device->ExtraData = NULL;
1060 return ALC_INVALID_VALUE;
1063 static void alsa_close_capture(ALCdevice *Device)
1065 alsa_data *data = (alsa_data*)Device->ExtraData;
1067 snd_pcm_close(data->pcmHandle);
1068 DestroyRingBuffer(data->ring);
1070 free(data->buffer);
1071 free(data);
1072 Device->ExtraData = NULL;
1075 static void alsa_start_capture(ALCdevice *Device)
1077 alsa_data *data = (alsa_data*)Device->ExtraData;
1078 int err;
1080 err = snd_pcm_start(data->pcmHandle);
1081 if(err < 0)
1083 ERR("start failed: %s\n", snd_strerror(err));
1084 aluHandleDisconnect(Device);
1086 else
1087 data->doCapture = AL_TRUE;
1090 static ALCenum alsa_capture_samples(ALCdevice *Device, ALCvoid *Buffer, ALCuint Samples)
1092 alsa_data *data = (alsa_data*)Device->ExtraData;
1094 if(data->ring)
1096 ReadRingBuffer(data->ring, Buffer, Samples);
1097 return ALC_NO_ERROR;
1100 data->last_avail -= Samples;
1101 while(Device->Connected && Samples > 0)
1103 snd_pcm_sframes_t amt = 0;
1105 if(data->size > 0)
1107 /* First get any data stored from the last stop */
1108 amt = snd_pcm_bytes_to_frames(data->pcmHandle, data->size);
1109 if((snd_pcm_uframes_t)amt > Samples) amt = Samples;
1111 amt = snd_pcm_frames_to_bytes(data->pcmHandle, amt);
1112 memmove(Buffer, data->buffer, amt);
1114 if(data->size > amt)
1116 memmove(data->buffer, data->buffer+amt, data->size - amt);
1117 data->size -= amt;
1119 else
1121 free(data->buffer);
1122 data->buffer = NULL;
1123 data->size = 0;
1125 amt = snd_pcm_bytes_to_frames(data->pcmHandle, amt);
1127 else if(data->doCapture)
1128 amt = snd_pcm_readi(data->pcmHandle, Buffer, Samples);
1129 if(amt < 0)
1131 ERR("read error: %s\n", snd_strerror(amt));
1133 if(amt == -EAGAIN)
1134 continue;
1135 if((amt=snd_pcm_recover(data->pcmHandle, amt, 1)) >= 0)
1137 amt = snd_pcm_start(data->pcmHandle);
1138 if(amt >= 0)
1139 amt = snd_pcm_avail_update(data->pcmHandle);
1141 if(amt < 0)
1143 ERR("restore error: %s\n", snd_strerror(amt));
1144 aluHandleDisconnect(Device);
1145 break;
1147 /* If the amount available is less than what's asked, we lost it
1148 * during recovery. So just give silence instead. */
1149 if((snd_pcm_uframes_t)amt < Samples)
1150 break;
1151 continue;
1154 Buffer = (ALbyte*)Buffer + amt;
1155 Samples -= amt;
1157 if(Samples > 0)
1158 memset(Buffer, ((Device->FmtType == DevFmtUByte) ? 0x80 : 0),
1159 snd_pcm_frames_to_bytes(data->pcmHandle, Samples));
1161 return ALC_NO_ERROR;
1164 static ALCuint alsa_available_samples(ALCdevice *Device)
1166 alsa_data *data = (alsa_data*)Device->ExtraData;
1167 snd_pcm_sframes_t avail = 0;
1169 if(Device->Connected && data->doCapture)
1170 avail = snd_pcm_avail_update(data->pcmHandle);
1171 if(avail < 0)
1173 ERR("avail update failed: %s\n", snd_strerror(avail));
1175 if((avail=snd_pcm_recover(data->pcmHandle, avail, 1)) >= 0)
1177 if(data->doCapture)
1178 avail = snd_pcm_start(data->pcmHandle);
1179 if(avail >= 0)
1180 avail = snd_pcm_avail_update(data->pcmHandle);
1182 if(avail < 0)
1184 ERR("restore error: %s\n", snd_strerror(avail));
1185 aluHandleDisconnect(Device);
1189 if(!data->ring)
1191 if(avail < 0) avail = 0;
1192 avail += snd_pcm_bytes_to_frames(data->pcmHandle, data->size);
1193 if(avail > data->last_avail) data->last_avail = avail;
1194 return data->last_avail;
1197 while(avail > 0)
1199 snd_pcm_sframes_t amt;
1201 amt = snd_pcm_bytes_to_frames(data->pcmHandle, data->size);
1202 if(avail < amt) amt = avail;
1204 amt = snd_pcm_readi(data->pcmHandle, data->buffer, amt);
1205 if(amt < 0)
1207 ERR("read error: %s\n", snd_strerror(amt));
1209 if(amt == -EAGAIN)
1210 continue;
1211 if((amt=snd_pcm_recover(data->pcmHandle, amt, 1)) >= 0)
1213 if(data->doCapture)
1214 amt = snd_pcm_start(data->pcmHandle);
1215 if(amt >= 0)
1216 amt = snd_pcm_avail_update(data->pcmHandle);
1218 if(amt < 0)
1220 ERR("restore error: %s\n", snd_strerror(amt));
1221 aluHandleDisconnect(Device);
1222 break;
1224 avail = amt;
1225 continue;
1228 WriteRingBuffer(data->ring, data->buffer, amt);
1229 avail -= amt;
1232 return RingBufferSize(data->ring);
1235 static void alsa_stop_capture(ALCdevice *Device)
1237 alsa_data *data = (alsa_data*)Device->ExtraData;
1238 ALCuint avail;
1239 int err;
1241 /* OpenAL requires access to unread audio after stopping, but ALSA's
1242 * snd_pcm_drain is unreliable and snd_pcm_drop drops it. Capture what's
1243 * available now so it'll be available later after the drop. */
1244 avail = alsa_available_samples(Device);
1245 if(!data->ring && avail > 0)
1247 /* The ring buffer implicitly captures when checking availability.
1248 * Direct access needs to explicitly capture it into temp storage. */
1249 ALsizei size;
1250 void *ptr;
1252 size = snd_pcm_frames_to_bytes(data->pcmHandle, avail);
1253 ptr = realloc(data->buffer, size);
1254 if(ptr)
1256 data->buffer = ptr;
1257 alsa_capture_samples(Device, data->buffer, avail);
1258 data->size = size;
1261 err = snd_pcm_drop(data->pcmHandle);
1262 if(err < 0)
1263 ERR("drop failed: %s\n", snd_strerror(err));
1264 data->doCapture = AL_FALSE;
1268 static ALint64 alsa_get_latency(ALCdevice *device)
1270 alsa_data *data = (alsa_data*)device->ExtraData;
1271 snd_pcm_sframes_t delay = 0;
1272 int err;
1274 if((err=snd_pcm_delay(data->pcmHandle, &delay)) < 0)
1276 ERR("Failed to get pcm delay: %s\n", snd_strerror(err));
1277 return 0;
1279 return maxi64((ALint64)delay*1000000000/device->Frequency, 0);
1283 static const BackendFuncs alsa_funcs = {
1284 alsa_open_playback,
1285 alsa_close_playback,
1286 alsa_reset_playback,
1287 alsa_start_playback,
1288 alsa_stop_playback,
1289 alsa_open_capture,
1290 alsa_close_capture,
1291 alsa_start_capture,
1292 alsa_stop_capture,
1293 alsa_capture_samples,
1294 alsa_available_samples,
1295 ALCdevice_LockDefault,
1296 ALCdevice_UnlockDefault,
1297 alsa_get_latency
1300 ALCboolean alc_alsa_init(BackendFuncs *func_list)
1302 if(!alsa_load())
1303 return ALC_FALSE;
1304 *func_list = alsa_funcs;
1305 return ALC_TRUE;
1308 void alc_alsa_deinit(void)
1310 ALuint i;
1312 for(i = 0;i < numDevNames;++i)
1314 free(allDevNameMap[i].name);
1315 free(allDevNameMap[i].device);
1317 free(allDevNameMap);
1318 allDevNameMap = NULL;
1319 numDevNames = 0;
1321 for(i = 0;i < numCaptureDevNames;++i)
1323 free(allCaptureDevNameMap[i].name);
1324 free(allCaptureDevNameMap[i].device);
1326 free(allCaptureDevNameMap);
1327 allCaptureDevNameMap = NULL;
1328 numCaptureDevNames = 0;
1330 #ifdef HAVE_DYNLOAD
1331 if(alsa_handle)
1332 CloseLib(alsa_handle);
1333 alsa_handle = NULL;
1334 #endif
1337 void alc_alsa_probe(enum DevProbe type)
1339 ALuint i;
1341 switch(type)
1343 case ALL_DEVICE_PROBE:
1344 for(i = 0;i < numDevNames;++i)
1346 free(allDevNameMap[i].name);
1347 free(allDevNameMap[i].device);
1350 free(allDevNameMap);
1351 allDevNameMap = probe_devices(SND_PCM_STREAM_PLAYBACK, &numDevNames);
1353 for(i = 0;i < numDevNames;++i)
1354 AppendAllDevicesList(allDevNameMap[i].name);
1355 break;
1357 case CAPTURE_DEVICE_PROBE:
1358 for(i = 0;i < numCaptureDevNames;++i)
1360 free(allCaptureDevNameMap[i].name);
1361 free(allCaptureDevNameMap[i].device);
1364 free(allCaptureDevNameMap);
1365 allCaptureDevNameMap = probe_devices(SND_PCM_STREAM_CAPTURE, &numCaptureDevNames);
1367 for(i = 0;i < numCaptureDevNames;++i)
1368 AppendCaptureDeviceList(allCaptureDevNameMap[i].name);
1369 break;