Reset the ALSA device if the number of available samples grows too large
[openal-soft/android.git] / Alc / backends / alsa.c
blob362b25da96f608bda08ce4f68331498fb207f02f
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 static void *alsa_handle;
36 #ifdef HAVE_DYNLOAD
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_set_access);
48 MAKE_FUNC(snd_pcm_hw_params_set_format);
49 MAKE_FUNC(snd_pcm_hw_params_set_channels);
50 MAKE_FUNC(snd_pcm_hw_params_set_periods_near);
51 MAKE_FUNC(snd_pcm_hw_params_set_rate_near);
52 MAKE_FUNC(snd_pcm_hw_params_set_rate);
53 MAKE_FUNC(snd_pcm_hw_params_set_rate_resample);
54 MAKE_FUNC(snd_pcm_hw_params_set_buffer_time_near);
55 MAKE_FUNC(snd_pcm_hw_params_set_period_time_near);
56 MAKE_FUNC(snd_pcm_hw_params_set_buffer_size_near);
57 MAKE_FUNC(snd_pcm_hw_params_set_period_size_near);
58 MAKE_FUNC(snd_pcm_hw_params_set_buffer_size_min);
59 MAKE_FUNC(snd_pcm_hw_params_get_buffer_size);
60 MAKE_FUNC(snd_pcm_hw_params_get_period_size);
61 MAKE_FUNC(snd_pcm_hw_params_get_access);
62 MAKE_FUNC(snd_pcm_hw_params_get_periods);
63 MAKE_FUNC(snd_pcm_hw_params);
64 MAKE_FUNC(snd_pcm_sw_params_malloc);
65 MAKE_FUNC(snd_pcm_sw_params_current);
66 MAKE_FUNC(snd_pcm_sw_params_set_avail_min);
67 MAKE_FUNC(snd_pcm_sw_params_set_stop_threshold);
68 MAKE_FUNC(snd_pcm_sw_params);
69 MAKE_FUNC(snd_pcm_sw_params_free);
70 MAKE_FUNC(snd_pcm_prepare);
71 MAKE_FUNC(snd_pcm_start);
72 MAKE_FUNC(snd_pcm_resume);
73 MAKE_FUNC(snd_pcm_reset);
74 MAKE_FUNC(snd_pcm_wait);
75 MAKE_FUNC(snd_pcm_state);
76 MAKE_FUNC(snd_pcm_avail_update);
77 MAKE_FUNC(snd_pcm_areas_silence);
78 MAKE_FUNC(snd_pcm_mmap_begin);
79 MAKE_FUNC(snd_pcm_mmap_commit);
80 MAKE_FUNC(snd_pcm_readi);
81 MAKE_FUNC(snd_pcm_writei);
82 MAKE_FUNC(snd_pcm_drain);
83 MAKE_FUNC(snd_pcm_recover);
84 MAKE_FUNC(snd_pcm_info_malloc);
85 MAKE_FUNC(snd_pcm_info_free);
86 MAKE_FUNC(snd_pcm_info_set_device);
87 MAKE_FUNC(snd_pcm_info_set_subdevice);
88 MAKE_FUNC(snd_pcm_info_set_stream);
89 MAKE_FUNC(snd_pcm_info_get_name);
90 MAKE_FUNC(snd_ctl_pcm_next_device);
91 MAKE_FUNC(snd_ctl_pcm_info);
92 MAKE_FUNC(snd_ctl_open);
93 MAKE_FUNC(snd_ctl_close);
94 MAKE_FUNC(snd_ctl_card_info_malloc);
95 MAKE_FUNC(snd_ctl_card_info_free);
96 MAKE_FUNC(snd_ctl_card_info);
97 MAKE_FUNC(snd_ctl_card_info_get_name);
98 MAKE_FUNC(snd_ctl_card_info_get_id);
99 MAKE_FUNC(snd_card_next);
100 #undef MAKE_FUNC
102 #define snd_strerror psnd_strerror
103 #define snd_pcm_open psnd_pcm_open
104 #define snd_pcm_close psnd_pcm_close
105 #define snd_pcm_nonblock psnd_pcm_nonblock
106 #define snd_pcm_frames_to_bytes psnd_pcm_frames_to_bytes
107 #define snd_pcm_bytes_to_frames psnd_pcm_bytes_to_frames
108 #define snd_pcm_hw_params_malloc psnd_pcm_hw_params_malloc
109 #define snd_pcm_hw_params_free psnd_pcm_hw_params_free
110 #define snd_pcm_hw_params_any psnd_pcm_hw_params_any
111 #define snd_pcm_hw_params_set_access psnd_pcm_hw_params_set_access
112 #define snd_pcm_hw_params_set_format psnd_pcm_hw_params_set_format
113 #define snd_pcm_hw_params_set_channels psnd_pcm_hw_params_set_channels
114 #define snd_pcm_hw_params_set_periods_near psnd_pcm_hw_params_set_periods_near
115 #define snd_pcm_hw_params_set_rate_near psnd_pcm_hw_params_set_rate_near
116 #define snd_pcm_hw_params_set_rate psnd_pcm_hw_params_set_rate
117 #define snd_pcm_hw_params_set_rate_resample psnd_pcm_hw_params_set_rate_resample
118 #define snd_pcm_hw_params_set_buffer_time_near psnd_pcm_hw_params_set_buffer_time_near
119 #define snd_pcm_hw_params_set_period_time_near psnd_pcm_hw_params_set_period_time_near
120 #define snd_pcm_hw_params_set_buffer_size_near psnd_pcm_hw_params_set_buffer_size_near
121 #define snd_pcm_hw_params_set_period_size_near psnd_pcm_hw_params_set_period_size_near
122 #define snd_pcm_hw_params_set_buffer_size_min psnd_pcm_hw_params_set_buffer_size_min
123 #define snd_pcm_hw_params_get_buffer_size psnd_pcm_hw_params_get_buffer_size
124 #define snd_pcm_hw_params_get_period_size psnd_pcm_hw_params_get_period_size
125 #define snd_pcm_hw_params_get_access psnd_pcm_hw_params_get_access
126 #define snd_pcm_hw_params_get_periods psnd_pcm_hw_params_get_periods
127 #define snd_pcm_hw_params psnd_pcm_hw_params
128 #define snd_pcm_sw_params_malloc psnd_pcm_sw_params_malloc
129 #define snd_pcm_sw_params_current psnd_pcm_sw_params_current
130 #define snd_pcm_sw_params_set_avail_min psnd_pcm_sw_params_set_avail_min
131 #define snd_pcm_sw_params_set_stop_threshold psnd_pcm_sw_params_set_stop_threshold
132 #define snd_pcm_sw_params psnd_pcm_sw_params
133 #define snd_pcm_sw_params_free psnd_pcm_sw_params_free
134 #define snd_pcm_prepare psnd_pcm_prepare
135 #define snd_pcm_start psnd_pcm_start
136 #define snd_pcm_resume psnd_pcm_resume
137 #define snd_pcm_reset psnd_pcm_reset
138 #define snd_pcm_wait psnd_pcm_wait
139 #define snd_pcm_state psnd_pcm_state
140 #define snd_pcm_avail_update psnd_pcm_avail_update
141 #define snd_pcm_areas_silence psnd_pcm_areas_silence
142 #define snd_pcm_mmap_begin psnd_pcm_mmap_begin
143 #define snd_pcm_mmap_commit psnd_pcm_mmap_commit
144 #define snd_pcm_readi psnd_pcm_readi
145 #define snd_pcm_writei psnd_pcm_writei
146 #define snd_pcm_drain psnd_pcm_drain
147 #define snd_pcm_recover psnd_pcm_recover
148 #define snd_pcm_info_malloc psnd_pcm_info_malloc
149 #define snd_pcm_info_free psnd_pcm_info_free
150 #define snd_pcm_info_set_device psnd_pcm_info_set_device
151 #define snd_pcm_info_set_subdevice psnd_pcm_info_set_subdevice
152 #define snd_pcm_info_set_stream psnd_pcm_info_set_stream
153 #define snd_pcm_info_get_name psnd_pcm_info_get_name
154 #define snd_ctl_pcm_next_device psnd_ctl_pcm_next_device
155 #define snd_ctl_pcm_info psnd_ctl_pcm_info
156 #define snd_ctl_open psnd_ctl_open
157 #define snd_ctl_close psnd_ctl_close
158 #define snd_ctl_card_info_malloc psnd_ctl_card_info_malloc
159 #define snd_ctl_card_info_free psnd_ctl_card_info_free
160 #define snd_ctl_card_info psnd_ctl_card_info
161 #define snd_ctl_card_info_get_name psnd_ctl_card_info_get_name
162 #define snd_ctl_card_info_get_id psnd_ctl_card_info_get_id
163 #define snd_card_next psnd_card_next
164 #endif
167 static ALCboolean alsa_load(void)
169 if(!alsa_handle)
171 #ifdef HAVE_DYNLOAD
172 alsa_handle = LoadLib("libasound.so.2");
173 if(!alsa_handle)
174 return ALC_FALSE;
176 #define LOAD_FUNC(f) do { \
177 p##f = GetSymbol(alsa_handle, #f); \
178 if(p##f == NULL) { \
179 CloseLib(alsa_handle); \
180 alsa_handle = NULL; \
181 return ALC_FALSE; \
183 } while(0)
184 LOAD_FUNC(snd_strerror);
185 LOAD_FUNC(snd_pcm_open);
186 LOAD_FUNC(snd_pcm_close);
187 LOAD_FUNC(snd_pcm_nonblock);
188 LOAD_FUNC(snd_pcm_frames_to_bytes);
189 LOAD_FUNC(snd_pcm_bytes_to_frames);
190 LOAD_FUNC(snd_pcm_hw_params_malloc);
191 LOAD_FUNC(snd_pcm_hw_params_free);
192 LOAD_FUNC(snd_pcm_hw_params_any);
193 LOAD_FUNC(snd_pcm_hw_params_set_access);
194 LOAD_FUNC(snd_pcm_hw_params_set_format);
195 LOAD_FUNC(snd_pcm_hw_params_set_channels);
196 LOAD_FUNC(snd_pcm_hw_params_set_periods_near);
197 LOAD_FUNC(snd_pcm_hw_params_set_rate_near);
198 LOAD_FUNC(snd_pcm_hw_params_set_rate);
199 LOAD_FUNC(snd_pcm_hw_params_set_rate_resample);
200 LOAD_FUNC(snd_pcm_hw_params_set_buffer_time_near);
201 LOAD_FUNC(snd_pcm_hw_params_set_period_time_near);
202 LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_near);
203 LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_min);
204 LOAD_FUNC(snd_pcm_hw_params_set_period_size_near);
205 LOAD_FUNC(snd_pcm_hw_params_get_buffer_size);
206 LOAD_FUNC(snd_pcm_hw_params_get_period_size);
207 LOAD_FUNC(snd_pcm_hw_params_get_access);
208 LOAD_FUNC(snd_pcm_hw_params_get_periods);
209 LOAD_FUNC(snd_pcm_hw_params);
210 LOAD_FUNC(snd_pcm_sw_params_malloc);
211 LOAD_FUNC(snd_pcm_sw_params_current);
212 LOAD_FUNC(snd_pcm_sw_params_set_avail_min);
213 LOAD_FUNC(snd_pcm_sw_params_set_stop_threshold);
214 LOAD_FUNC(snd_pcm_sw_params);
215 LOAD_FUNC(snd_pcm_sw_params_free);
216 LOAD_FUNC(snd_pcm_prepare);
217 LOAD_FUNC(snd_pcm_start);
218 LOAD_FUNC(snd_pcm_resume);
219 LOAD_FUNC(snd_pcm_reset);
220 LOAD_FUNC(snd_pcm_wait);
221 LOAD_FUNC(snd_pcm_state);
222 LOAD_FUNC(snd_pcm_avail_update);
223 LOAD_FUNC(snd_pcm_areas_silence);
224 LOAD_FUNC(snd_pcm_mmap_begin);
225 LOAD_FUNC(snd_pcm_mmap_commit);
226 LOAD_FUNC(snd_pcm_readi);
227 LOAD_FUNC(snd_pcm_writei);
228 LOAD_FUNC(snd_pcm_drain);
229 LOAD_FUNC(snd_pcm_recover);
230 LOAD_FUNC(snd_pcm_info_malloc);
231 LOAD_FUNC(snd_pcm_info_free);
232 LOAD_FUNC(snd_pcm_info_set_device);
233 LOAD_FUNC(snd_pcm_info_set_subdevice);
234 LOAD_FUNC(snd_pcm_info_set_stream);
235 LOAD_FUNC(snd_pcm_info_get_name);
236 LOAD_FUNC(snd_ctl_pcm_next_device);
237 LOAD_FUNC(snd_ctl_pcm_info);
238 LOAD_FUNC(snd_ctl_open);
239 LOAD_FUNC(snd_ctl_close);
240 LOAD_FUNC(snd_ctl_card_info_malloc);
241 LOAD_FUNC(snd_ctl_card_info_free);
242 LOAD_FUNC(snd_ctl_card_info);
243 LOAD_FUNC(snd_ctl_card_info_get_name);
244 LOAD_FUNC(snd_ctl_card_info_get_id);
245 LOAD_FUNC(snd_card_next);
246 #undef LOAD_FUNC
247 #else
248 alsa_handle = (void*)0xDEADBEEF;
249 #endif
251 return ALC_TRUE;
255 typedef struct {
256 snd_pcm_t *pcmHandle;
258 ALvoid *buffer;
259 ALsizei size;
261 ALboolean doCapture;
262 RingBuffer *ring;
264 volatile int killNow;
265 ALvoid *thread;
266 } alsa_data;
268 typedef struct {
269 ALCchar *name;
270 char *card;
271 int dev;
272 } DevMap;
274 static DevMap *allDevNameMap;
275 static ALuint numDevNames;
276 static DevMap *allCaptureDevNameMap;
277 static ALuint numCaptureDevNames;
279 static const char *device_prefix;
280 static const char *capture_prefix;
283 static DevMap *probe_devices(snd_pcm_stream_t stream, ALuint *count)
285 snd_ctl_t *handle;
286 int card, err, dev, idx;
287 snd_ctl_card_info_t *info;
288 snd_pcm_info_t *pcminfo;
289 DevMap *DevList;
290 char name[1024];
292 snd_ctl_card_info_malloc(&info);
293 snd_pcm_info_malloc(&pcminfo);
295 card = -1;
296 if((err=snd_card_next(&card)) < 0)
297 ERR("Failed to find a card: %s\n", snd_strerror(err));
299 DevList = malloc(sizeof(DevMap) * 1);
300 DevList[0].name = strdup("ALSA Default");
301 DevList[0].card = NULL;
302 DevList[0].dev = 0;
303 idx = 1;
304 while(card >= 0)
306 sprintf(name, "hw:%d", card);
307 if((err = snd_ctl_open(&handle, name, 0)) < 0)
309 ERR("control open (%i): %s\n", card, snd_strerror(err));
310 goto next_card;
312 if((err = snd_ctl_card_info(handle, info)) < 0)
314 ERR("control hardware info (%i): %s\n", card, snd_strerror(err));
315 snd_ctl_close(handle);
316 goto next_card;
319 dev = -1;
320 while(1)
322 const char *cname, *dname, *cid;
323 void *temp;
325 if(snd_ctl_pcm_next_device(handle, &dev) < 0)
326 ERR("snd_ctl_pcm_next_device failed\n");
327 if(dev < 0)
328 break;
330 snd_pcm_info_set_device(pcminfo, dev);
331 snd_pcm_info_set_subdevice(pcminfo, 0);
332 snd_pcm_info_set_stream(pcminfo, stream);
333 if((err = snd_ctl_pcm_info(handle, pcminfo)) < 0) {
334 if(err != -ENOENT)
335 ERR("control digital audio info (%i): %s\n", card, snd_strerror(err));
336 continue;
339 temp = realloc(DevList, sizeof(DevMap) * (idx+1));
340 if(temp)
342 DevList = temp;
343 cname = snd_ctl_card_info_get_name(info);
344 dname = snd_pcm_info_get_name(pcminfo);
345 cid = snd_ctl_card_info_get_id(info);
346 snprintf(name, sizeof(name), "%s, %s (CARD=%s,DEV=%d)",
347 cname, dname, cid, dev);
348 DevList[idx].name = strdup(name);
349 DevList[idx].card = strdup(cid);
350 DevList[idx].dev = dev;
351 idx++;
354 snd_ctl_close(handle);
355 next_card:
356 if(snd_card_next(&card) < 0) {
357 ERR("snd_card_next failed\n");
358 break;
362 snd_pcm_info_free(pcminfo);
363 snd_ctl_card_info_free(info);
365 *count = idx;
366 return DevList;
370 static int xrun_recovery(snd_pcm_t *handle, int err)
372 err = snd_pcm_recover(handle, err, 1);
373 if(err < 0)
374 ERR("recover failed: %s\n", snd_strerror(err));
375 return err;
378 static int verify_state(snd_pcm_t *handle)
380 snd_pcm_state_t state = snd_pcm_state(handle);
381 if(state == SND_PCM_STATE_DISCONNECTED)
382 return -ENODEV;
383 if(state == SND_PCM_STATE_XRUN)
385 int err = xrun_recovery(handle, -EPIPE);
386 if(err < 0) return err;
388 else if(state == SND_PCM_STATE_SUSPENDED)
390 int err = xrun_recovery(handle, -ESTRPIPE);
391 if(err < 0) return err;
394 return state;
398 static ALuint ALSAProc(ALvoid *ptr)
400 ALCdevice *pDevice = (ALCdevice*)ptr;
401 alsa_data *data = (alsa_data*)pDevice->ExtraData;
402 const snd_pcm_channel_area_t *areas = NULL;
403 snd_pcm_uframes_t update_size, num_updates;
404 snd_pcm_sframes_t avail, commitres;
405 snd_pcm_uframes_t offset, frames;
406 char *WritePtr;
407 int err;
409 SetRTPriority();
411 update_size = pDevice->UpdateSize;
412 num_updates = pDevice->NumUpdates;
413 while(!data->killNow)
415 int state = verify_state(data->pcmHandle);
416 if(state < 0)
418 ERR("Invalid state detected: %s\n", snd_strerror(state));
419 aluHandleDisconnect(pDevice);
420 break;
423 avail = snd_pcm_avail_update(data->pcmHandle);
424 if(avail < 0)
426 ERR("available update failed: %s\n", snd_strerror(avail));
427 continue;
430 if((snd_pcm_uframes_t)avail > update_size*(num_updates+1))
432 WARN("available samples exceeds the buffer size\n");
433 snd_pcm_reset(data->pcmHandle);
434 continue;
437 // make sure there's frames to process
438 if((snd_pcm_uframes_t)avail < update_size)
440 if(state != SND_PCM_STATE_RUNNING)
442 err = snd_pcm_start(data->pcmHandle);
443 if(err < 0)
445 ERR("start failed: %s\n", snd_strerror(err));
446 continue;
449 if(snd_pcm_wait(data->pcmHandle, 1000) == 0)
450 ERR("Wait timeout... buffer size too low?\n");
451 continue;
453 avail -= avail%update_size;
455 // it is possible that contiguous areas are smaller, thus we use a loop
456 while(avail > 0)
458 frames = avail;
460 err = snd_pcm_mmap_begin(data->pcmHandle, &areas, &offset, &frames);
461 if(err < 0)
463 ERR("mmap begin error: %s\n", snd_strerror(err));
464 break;
467 WritePtr = (char*)areas->addr + (offset * areas->step / 8);
468 aluMixData(pDevice, WritePtr, frames);
470 commitres = snd_pcm_mmap_commit(data->pcmHandle, offset, frames);
471 if(commitres < 0 || (commitres-frames) != 0)
473 ERR("mmap commit error: %s\n",
474 snd_strerror(commitres >= 0 ? -EPIPE : commitres));
475 break;
478 avail -= frames;
482 return 0;
485 static ALuint ALSANoMMapProc(ALvoid *ptr)
487 ALCdevice *pDevice = (ALCdevice*)ptr;
488 alsa_data *data = (alsa_data*)pDevice->ExtraData;
489 snd_pcm_sframes_t avail;
490 char *WritePtr;
492 SetRTPriority();
494 while(!data->killNow)
496 int state = verify_state(data->pcmHandle);
497 if(state < 0)
499 ERR("Invalid state detected: %s\n", snd_strerror(state));
500 aluHandleDisconnect(pDevice);
501 break;
504 WritePtr = data->buffer;
505 avail = data->size / snd_pcm_frames_to_bytes(data->pcmHandle, 1);
506 aluMixData(pDevice, WritePtr, avail);
508 while(avail > 0)
510 int ret = snd_pcm_writei(data->pcmHandle, WritePtr, avail);
511 switch (ret)
513 case -EAGAIN:
514 continue;
515 case -ESTRPIPE:
516 case -EPIPE:
517 case -EINTR:
518 ret = snd_pcm_recover(data->pcmHandle, ret, 1);
519 if(ret < 0)
520 avail = 0;
521 break;
522 default:
523 if (ret >= 0)
525 WritePtr += snd_pcm_frames_to_bytes(data->pcmHandle, ret);
526 avail -= ret;
528 break;
530 if (ret < 0)
532 ret = snd_pcm_prepare(data->pcmHandle);
533 if(ret < 0)
534 break;
539 return 0;
542 static ALCenum alsa_open_playback(ALCdevice *device, const ALCchar *deviceName)
544 const char *driver = "default";
545 alsa_data *data;
546 char str[128];
547 int i;
549 ConfigValueStr("alsa", "device", &driver);
551 if(!deviceName)
552 deviceName = alsaDevice;
553 else if(strcmp(deviceName, alsaDevice) != 0)
555 size_t idx;
557 if(!allDevNameMap)
558 allDevNameMap = probe_devices(SND_PCM_STREAM_PLAYBACK, &numDevNames);
560 for(idx = 0;idx < numDevNames;idx++)
562 if(allDevNameMap[idx].name &&
563 strcmp(deviceName, allDevNameMap[idx].name) == 0)
565 if(idx > 0)
567 snprintf(str, sizeof(str), "%sCARD=%s,DEV=%d", device_prefix,
568 allDevNameMap[idx].card, allDevNameMap[idx].dev);
569 driver = str;
571 break;
574 if(idx == numDevNames)
575 return ALC_INVALID_VALUE;
578 data = (alsa_data*)calloc(1, sizeof(alsa_data));
580 i = snd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
581 if(i >= 0)
583 i = snd_pcm_nonblock(data->pcmHandle, 0);
584 if(i < 0)
585 snd_pcm_close(data->pcmHandle);
587 if(i < 0)
589 free(data);
590 ERR("Could not open playback device '%s': %s\n", driver, snd_strerror(i));
591 return ALC_OUT_OF_MEMORY;
594 device->szDeviceName = strdup(deviceName);
595 device->ExtraData = data;
596 return ALC_NO_ERROR;
599 static void alsa_close_playback(ALCdevice *device)
601 alsa_data *data = (alsa_data*)device->ExtraData;
603 snd_pcm_close(data->pcmHandle);
604 free(data);
605 device->ExtraData = NULL;
608 static ALCboolean alsa_reset_playback(ALCdevice *device)
610 alsa_data *data = (alsa_data*)device->ExtraData;
611 snd_pcm_uframes_t periodSizeInFrames;
612 unsigned int periodLen, bufferLen;
613 snd_pcm_sw_params_t *sp = NULL;
614 snd_pcm_hw_params_t *p = NULL;
615 snd_pcm_access_t access;
616 snd_pcm_format_t format;
617 unsigned int periods;
618 unsigned int rate;
619 int allowmmap;
620 char *err;
621 int i;
624 format = -1;
625 switch(device->FmtType)
627 case DevFmtByte:
628 format = SND_PCM_FORMAT_S8;
629 break;
630 case DevFmtUByte:
631 format = SND_PCM_FORMAT_U8;
632 break;
633 case DevFmtShort:
634 format = SND_PCM_FORMAT_S16;
635 break;
636 case DevFmtUShort:
637 format = SND_PCM_FORMAT_U16;
638 break;
639 case DevFmtFloat:
640 format = SND_PCM_FORMAT_FLOAT;
641 break;
644 allowmmap = GetConfigValueBool("alsa", "mmap", 1);
645 periods = device->NumUpdates;
646 periodLen = (ALuint64)device->UpdateSize * 1000000 / device->Frequency;
647 bufferLen = periodLen * periods;
648 rate = device->Frequency;
650 err = NULL;
651 snd_pcm_hw_params_malloc(&p);
653 if((i=snd_pcm_hw_params_any(data->pcmHandle, p)) < 0)
654 err = "any";
655 /* set interleaved access */
656 if(i >= 0 && (!allowmmap || (i=snd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_MMAP_INTERLEAVED)) < 0))
658 if(periods > 2)
660 periods--;
661 bufferLen = periodLen * periods;
663 if((i=snd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
664 err = "set access";
666 /* set format (implicitly sets sample bits) */
667 if(i >= 0 && (i=snd_pcm_hw_params_set_format(data->pcmHandle, p, format)) < 0)
669 device->FmtType = DevFmtFloat;
670 if(format == SND_PCM_FORMAT_FLOAT ||
671 (i=snd_pcm_hw_params_set_format(data->pcmHandle, p, SND_PCM_FORMAT_FLOAT)) < 0)
673 device->FmtType = DevFmtShort;
674 if(format == SND_PCM_FORMAT_S16 ||
675 (i=snd_pcm_hw_params_set_format(data->pcmHandle, p, SND_PCM_FORMAT_S16)) < 0)
677 device->FmtType = DevFmtUByte;
678 if(format == SND_PCM_FORMAT_U8 ||
679 (i=snd_pcm_hw_params_set_format(data->pcmHandle, p, SND_PCM_FORMAT_U8)) < 0)
680 err = "set format";
684 /* set channels (implicitly sets frame bits) */
685 if(i >= 0 && (i=snd_pcm_hw_params_set_channels(data->pcmHandle, p, ChannelsFromDevFmt(device->FmtChans))) < 0)
687 if((i=snd_pcm_hw_params_set_channels(data->pcmHandle, p, 2)) < 0)
689 if((i=snd_pcm_hw_params_set_channels(data->pcmHandle, p, 1)) < 0)
690 err = "set channels";
691 else
693 if((device->Flags&DEVICE_CHANNELS_REQUEST))
694 ERR("Failed to set %s, got Mono instead\n", DevFmtChannelsString(device->FmtChans));
695 device->FmtChans = DevFmtMono;
698 else
700 if((device->Flags&DEVICE_CHANNELS_REQUEST))
701 ERR("Failed to set %s, got Stereo instead\n", DevFmtChannelsString(device->FmtChans));
702 device->FmtChans = DevFmtStereo;
704 device->Flags &= ~DEVICE_CHANNELS_REQUEST;
706 if(i >= 0 && (i=snd_pcm_hw_params_set_rate_resample(data->pcmHandle, p, 0)) < 0)
708 ERR("Failed to disable ALSA resampler\n");
709 i = 0;
711 /* set rate (implicitly constrains period/buffer parameters) */
712 if(i >= 0 && (i=snd_pcm_hw_params_set_rate_near(data->pcmHandle, p, &rate, NULL)) < 0)
713 err = "set rate near";
714 /* set buffer time (implicitly constrains period/buffer parameters) */
715 if(i >= 0 && (i=snd_pcm_hw_params_set_buffer_time_near(data->pcmHandle, p, &bufferLen, NULL)) < 0)
716 err = "set buffer time near";
717 /* set period time in frame units (implicitly sets buffer size/bytes/time and period size/bytes) */
718 if(i >= 0 && (i=snd_pcm_hw_params_set_period_time_near(data->pcmHandle, p, &periodLen, NULL)) < 0)
719 err = "set period time near";
720 /* install and prepare hardware configuration */
721 if(i >= 0 && (i=snd_pcm_hw_params(data->pcmHandle, p)) < 0)
722 err = "set params";
723 if(i >= 0 && (i=snd_pcm_hw_params_get_access(p, &access)) < 0)
724 err = "get access";
725 if(i >= 0 && (i=snd_pcm_hw_params_get_period_size(p, &periodSizeInFrames, NULL)) < 0)
726 err = "get period size";
727 if(i >= 0 && (i=snd_pcm_hw_params_get_periods(p, &periods, NULL)) < 0)
728 err = "get periods";
729 if(i < 0)
731 ERR("%s failed: %s\n", err, snd_strerror(i));
732 snd_pcm_hw_params_free(p);
733 return ALC_FALSE;
736 snd_pcm_hw_params_free(p);
738 err = NULL;
739 snd_pcm_sw_params_malloc(&sp);
741 if((i=snd_pcm_sw_params_current(data->pcmHandle, sp)) != 0)
742 err = "sw current";
743 if(i == 0 && (i=snd_pcm_sw_params_set_avail_min(data->pcmHandle, sp, periodSizeInFrames)) != 0)
744 err = "sw set avail min";
745 if(i == 0 && (i=snd_pcm_sw_params_set_stop_threshold(data->pcmHandle, sp, periodSizeInFrames*periods)) != 0)
746 err = "sw set stop threshold";
747 if(i == 0 && (i=snd_pcm_sw_params(data->pcmHandle, sp)) != 0)
748 err = "sw set params";
749 if(i != 0)
751 ERR("%s failed: %s\n", err, snd_strerror(i));
752 snd_pcm_sw_params_free(sp);
753 return ALC_FALSE;
756 snd_pcm_sw_params_free(sp);
758 if(device->Frequency != rate)
760 if((device->Flags&DEVICE_FREQUENCY_REQUEST))
761 ERR("Failed to set %dhz, got %dhz instead\n", device->Frequency, rate);
762 device->Flags &= ~DEVICE_FREQUENCY_REQUEST;
763 device->Frequency = rate;
766 SetDefaultChannelOrder(device);
768 data->size = snd_pcm_frames_to_bytes(data->pcmHandle, periodSizeInFrames);
769 if(access == SND_PCM_ACCESS_RW_INTERLEAVED)
771 /* Increase periods by one, since the temp buffer counts as an extra
772 * period */
773 periods++;
774 data->buffer = malloc(data->size);
775 if(!data->buffer)
777 ERR("buffer malloc failed\n");
778 return ALC_FALSE;
780 device->UpdateSize = periodSizeInFrames;
781 device->NumUpdates = periods;
782 data->thread = StartThread(ALSANoMMapProc, device);
784 else
786 i = snd_pcm_prepare(data->pcmHandle);
787 if(i < 0)
789 ERR("prepare error: %s\n", snd_strerror(i));
790 return ALC_FALSE;
792 device->UpdateSize = periodSizeInFrames;
793 device->NumUpdates = periods;
794 data->thread = StartThread(ALSAProc, device);
796 if(data->thread == NULL)
798 ERR("Could not create playback thread\n");
799 free(data->buffer);
800 data->buffer = NULL;
801 return ALC_FALSE;
804 return ALC_TRUE;
807 static void alsa_stop_playback(ALCdevice *device)
809 alsa_data *data = (alsa_data*)device->ExtraData;
811 if(data->thread)
813 data->killNow = 1;
814 StopThread(data->thread);
815 data->thread = NULL;
817 data->killNow = 0;
818 free(data->buffer);
819 data->buffer = NULL;
823 static ALCenum alsa_open_capture(ALCdevice *pDevice, const ALCchar *deviceName)
825 const char *driver = "default";
826 snd_pcm_hw_params_t *p;
827 snd_pcm_uframes_t bufferSizeInFrames;
828 snd_pcm_uframes_t periodSizeInFrames;
829 snd_pcm_format_t format;
830 ALuint frameSize;
831 alsa_data *data;
832 char str[128];
833 char *err;
834 int i;
836 ConfigValueStr("alsa", "capture", &driver);
838 if(!allCaptureDevNameMap)
839 allCaptureDevNameMap = probe_devices(SND_PCM_STREAM_CAPTURE, &numCaptureDevNames);
841 if(!deviceName)
842 deviceName = allCaptureDevNameMap[0].name;
843 else
845 size_t idx;
847 for(idx = 0;idx < numCaptureDevNames;idx++)
849 if(allCaptureDevNameMap[idx].name &&
850 strcmp(deviceName, allCaptureDevNameMap[idx].name) == 0)
852 if(idx > 0)
854 snprintf(str, sizeof(str), "%sCARD=%s,DEV=%d", capture_prefix,
855 allCaptureDevNameMap[idx].card, allCaptureDevNameMap[idx].dev);
856 driver = str;
858 break;
861 if(idx == numCaptureDevNames)
862 return ALC_INVALID_VALUE;
865 data = (alsa_data*)calloc(1, sizeof(alsa_data));
867 i = snd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
868 if(i < 0)
870 ERR("Could not open capture device '%s': %s\n", driver, snd_strerror(i));
871 free(data);
872 return ALC_INVALID_VALUE;
875 format = -1;
876 switch(pDevice->FmtType)
878 case DevFmtByte:
879 format = SND_PCM_FORMAT_S8;
880 break;
881 case DevFmtUByte:
882 format = SND_PCM_FORMAT_U8;
883 break;
884 case DevFmtShort:
885 format = SND_PCM_FORMAT_S16;
886 break;
887 case DevFmtUShort:
888 format = SND_PCM_FORMAT_U16;
889 break;
890 case DevFmtFloat:
891 format = SND_PCM_FORMAT_FLOAT;
892 break;
895 err = NULL;
896 bufferSizeInFrames = maxu(pDevice->UpdateSize*pDevice->NumUpdates,
897 100*pDevice->Frequency/1000);
898 periodSizeInFrames = minu(bufferSizeInFrames, 50*pDevice->Frequency/1000);
899 snd_pcm_hw_params_malloc(&p);
901 if((i=snd_pcm_hw_params_any(data->pcmHandle, p)) < 0)
902 err = "any";
903 /* set interleaved access */
904 if(i >= 0 && (i=snd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
905 err = "set access";
906 /* set format (implicitly sets sample bits) */
907 if(i >= 0 && (i=snd_pcm_hw_params_set_format(data->pcmHandle, p, format)) < 0)
908 err = "set format";
909 /* set channels (implicitly sets frame bits) */
910 if(i >= 0 && (i=snd_pcm_hw_params_set_channels(data->pcmHandle, p, ChannelsFromDevFmt(pDevice->FmtChans))) < 0)
911 err = "set channels";
912 /* set rate (implicitly constrains period/buffer parameters) */
913 if(i >= 0 && (i=snd_pcm_hw_params_set_rate(data->pcmHandle, p, pDevice->Frequency, 0)) < 0)
914 err = "set rate near";
915 /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */
916 if(i >= 0 && (i=snd_pcm_hw_params_set_buffer_size_near(data->pcmHandle, p, &bufferSizeInFrames)) < 0)
917 err = "set buffer size near";
918 /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */
919 if(i >= 0 && (i=snd_pcm_hw_params_set_period_size_near(data->pcmHandle, p, &periodSizeInFrames, NULL)) < 0)
920 err = "set period size near";
921 /* install and prepare hardware configuration */
922 if(i >= 0 && (i=snd_pcm_hw_params(data->pcmHandle, p)) < 0)
923 err = "set params";
924 if(i < 0)
926 ERR("%s failed: %s\n", err, snd_strerror(i));
927 snd_pcm_hw_params_free(p);
928 goto error;
931 if((i=snd_pcm_hw_params_get_period_size(p, &bufferSizeInFrames, NULL)) < 0)
933 ERR("get size failed: %s\n", snd_strerror(i));
934 snd_pcm_hw_params_free(p);
935 goto error;
938 snd_pcm_hw_params_free(p);
940 frameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);
942 data->ring = CreateRingBuffer(frameSize, pDevice->UpdateSize*pDevice->NumUpdates);
943 if(!data->ring)
945 ERR("ring buffer create failed\n");
946 goto error;
949 data->size = snd_pcm_frames_to_bytes(data->pcmHandle, bufferSizeInFrames);
950 data->buffer = malloc(data->size);
951 if(!data->buffer)
953 ERR("buffer malloc failed\n");
954 goto error;
957 pDevice->szDeviceName = strdup(deviceName);
959 pDevice->ExtraData = data;
960 return ALC_NO_ERROR;
962 error:
963 free(data->buffer);
964 DestroyRingBuffer(data->ring);
965 snd_pcm_close(data->pcmHandle);
966 free(data);
968 pDevice->ExtraData = NULL;
969 return ALC_INVALID_VALUE;
972 static void alsa_close_capture(ALCdevice *pDevice)
974 alsa_data *data = (alsa_data*)pDevice->ExtraData;
976 snd_pcm_close(data->pcmHandle);
977 DestroyRingBuffer(data->ring);
979 free(data->buffer);
980 free(data);
981 pDevice->ExtraData = NULL;
984 static void alsa_start_capture(ALCdevice *Device)
986 alsa_data *data = (alsa_data*)Device->ExtraData;
987 int err;
989 err = snd_pcm_start(data->pcmHandle);
990 if(err < 0)
992 ERR("start failed: %s\n", snd_strerror(err));
993 aluHandleDisconnect(Device);
995 else
996 data->doCapture = AL_TRUE;
999 static void alsa_stop_capture(ALCdevice *Device)
1001 alsa_data *data = (alsa_data*)Device->ExtraData;
1002 snd_pcm_drain(data->pcmHandle);
1003 data->doCapture = AL_FALSE;
1006 static ALCenum alsa_capture_samples(ALCdevice *Device, ALCvoid *Buffer, ALCuint Samples)
1008 alsa_data *data = (alsa_data*)Device->ExtraData;
1009 ReadRingBuffer(data->ring, Buffer, Samples);
1010 return ALC_NO_ERROR;
1013 static ALCuint alsa_available_samples(ALCdevice *Device)
1015 alsa_data *data = (alsa_data*)Device->ExtraData;
1016 snd_pcm_sframes_t avail;
1018 avail = (Device->Connected ? snd_pcm_avail_update(data->pcmHandle) : 0);
1019 if(avail < 0)
1021 ERR("avail update failed: %s\n", snd_strerror(avail));
1023 if((avail=snd_pcm_recover(data->pcmHandle, avail, 1)) >= 0)
1025 if(data->doCapture)
1026 avail = snd_pcm_start(data->pcmHandle);
1027 if(avail >= 0)
1028 avail = snd_pcm_avail_update(data->pcmHandle);
1030 if(avail < 0)
1032 ERR("restore error: %s\n", snd_strerror(avail));
1033 aluHandleDisconnect(Device);
1036 while(avail > 0)
1038 snd_pcm_sframes_t amt;
1040 amt = snd_pcm_bytes_to_frames(data->pcmHandle, data->size);
1041 if(avail < amt) amt = avail;
1043 amt = snd_pcm_readi(data->pcmHandle, data->buffer, amt);
1044 if(amt < 0)
1046 ERR("read error: %s\n", snd_strerror(amt));
1048 if(amt == -EAGAIN)
1049 continue;
1050 if((amt=snd_pcm_recover(data->pcmHandle, amt, 1)) >= 0)
1052 if(data->doCapture)
1053 amt = snd_pcm_start(data->pcmHandle);
1054 if(amt >= 0)
1055 amt = snd_pcm_avail_update(data->pcmHandle);
1057 if(amt < 0)
1059 ERR("restore error: %s\n", snd_strerror(amt));
1060 aluHandleDisconnect(Device);
1061 break;
1063 avail = amt;
1064 continue;
1067 WriteRingBuffer(data->ring, data->buffer, amt);
1068 avail -= amt;
1071 return RingBufferSize(data->ring);
1075 static const BackendFuncs alsa_funcs = {
1076 alsa_open_playback,
1077 alsa_close_playback,
1078 alsa_reset_playback,
1079 alsa_stop_playback,
1080 alsa_open_capture,
1081 alsa_close_capture,
1082 alsa_start_capture,
1083 alsa_stop_capture,
1084 alsa_capture_samples,
1085 alsa_available_samples
1088 ALCboolean alc_alsa_init(BackendFuncs *func_list)
1090 if(!alsa_load())
1091 return ALC_FALSE;
1092 device_prefix = GetConfigValue("alsa", "device-prefix", "plughw:");
1093 capture_prefix = GetConfigValue("alsa", "capture-prefix", "plughw:");
1094 *func_list = alsa_funcs;
1095 return ALC_TRUE;
1098 void alc_alsa_deinit(void)
1100 ALuint i;
1102 for(i = 0;i < numDevNames;++i)
1104 free(allDevNameMap[i].name);
1105 free(allDevNameMap[i].card);
1107 free(allDevNameMap);
1108 allDevNameMap = NULL;
1109 numDevNames = 0;
1111 for(i = 0;i < numCaptureDevNames;++i)
1113 free(allCaptureDevNameMap[i].name);
1114 free(allCaptureDevNameMap[i].card);
1116 free(allCaptureDevNameMap);
1117 allCaptureDevNameMap = NULL;
1118 numCaptureDevNames = 0;
1120 #ifdef HAVE_DYNLOAD
1121 if(alsa_handle)
1122 CloseLib(alsa_handle);
1123 alsa_handle = NULL;
1124 #endif
1127 void alc_alsa_probe(enum DevProbe type)
1129 ALuint i;
1131 switch(type)
1133 case DEVICE_PROBE:
1134 AppendDeviceList(alsaDevice);
1135 break;
1137 case ALL_DEVICE_PROBE:
1138 for(i = 0;i < numDevNames;++i)
1140 free(allDevNameMap[i].name);
1141 free(allDevNameMap[i].card);
1144 free(allDevNameMap);
1145 allDevNameMap = probe_devices(SND_PCM_STREAM_PLAYBACK, &numDevNames);
1147 for(i = 0;i < numDevNames;++i)
1148 AppendAllDeviceList(allDevNameMap[i].name);
1149 break;
1151 case CAPTURE_DEVICE_PROBE:
1152 for(i = 0;i < numCaptureDevNames;++i)
1154 free(allCaptureDevNameMap[i].name);
1155 free(allCaptureDevNameMap[i].card);
1158 free(allCaptureDevNameMap);
1159 allCaptureDevNameMap = probe_devices(SND_PCM_STREAM_CAPTURE, &numCaptureDevNames);
1161 for(i = 0;i < numCaptureDevNames;++i)
1162 AppendCaptureDeviceList(allCaptureDevNameMap[i].name);
1163 break;