Use more proper enum names for the resampler
[openal-soft.git] / Alc / backends / alsa.c
blobfa059e44d826d792001c0a671c6599fa25348fa6
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_test_format);
64 MAKE_FUNC(snd_pcm_hw_params_test_channels);
65 MAKE_FUNC(snd_pcm_hw_params);
66 MAKE_FUNC(snd_pcm_sw_params_malloc);
67 MAKE_FUNC(snd_pcm_sw_params_current);
68 MAKE_FUNC(snd_pcm_sw_params_set_avail_min);
69 MAKE_FUNC(snd_pcm_sw_params_set_stop_threshold);
70 MAKE_FUNC(snd_pcm_sw_params);
71 MAKE_FUNC(snd_pcm_sw_params_free);
72 MAKE_FUNC(snd_pcm_prepare);
73 MAKE_FUNC(snd_pcm_start);
74 MAKE_FUNC(snd_pcm_resume);
75 MAKE_FUNC(snd_pcm_reset);
76 MAKE_FUNC(snd_pcm_wait);
77 MAKE_FUNC(snd_pcm_state);
78 MAKE_FUNC(snd_pcm_avail_update);
79 MAKE_FUNC(snd_pcm_areas_silence);
80 MAKE_FUNC(snd_pcm_mmap_begin);
81 MAKE_FUNC(snd_pcm_mmap_commit);
82 MAKE_FUNC(snd_pcm_readi);
83 MAKE_FUNC(snd_pcm_writei);
84 MAKE_FUNC(snd_pcm_drain);
85 MAKE_FUNC(snd_pcm_recover);
86 MAKE_FUNC(snd_pcm_info_malloc);
87 MAKE_FUNC(snd_pcm_info_free);
88 MAKE_FUNC(snd_pcm_info_set_device);
89 MAKE_FUNC(snd_pcm_info_set_subdevice);
90 MAKE_FUNC(snd_pcm_info_set_stream);
91 MAKE_FUNC(snd_pcm_info_get_name);
92 MAKE_FUNC(snd_ctl_pcm_next_device);
93 MAKE_FUNC(snd_ctl_pcm_info);
94 MAKE_FUNC(snd_ctl_open);
95 MAKE_FUNC(snd_ctl_close);
96 MAKE_FUNC(snd_ctl_card_info_malloc);
97 MAKE_FUNC(snd_ctl_card_info_free);
98 MAKE_FUNC(snd_ctl_card_info);
99 MAKE_FUNC(snd_ctl_card_info_get_name);
100 MAKE_FUNC(snd_ctl_card_info_get_id);
101 MAKE_FUNC(snd_card_next);
102 #undef MAKE_FUNC
104 #define snd_strerror psnd_strerror
105 #define snd_pcm_open psnd_pcm_open
106 #define snd_pcm_close psnd_pcm_close
107 #define snd_pcm_nonblock psnd_pcm_nonblock
108 #define snd_pcm_frames_to_bytes psnd_pcm_frames_to_bytes
109 #define snd_pcm_bytes_to_frames psnd_pcm_bytes_to_frames
110 #define snd_pcm_hw_params_malloc psnd_pcm_hw_params_malloc
111 #define snd_pcm_hw_params_free psnd_pcm_hw_params_free
112 #define snd_pcm_hw_params_any psnd_pcm_hw_params_any
113 #define snd_pcm_hw_params_set_access psnd_pcm_hw_params_set_access
114 #define snd_pcm_hw_params_set_format psnd_pcm_hw_params_set_format
115 #define snd_pcm_hw_params_set_channels psnd_pcm_hw_params_set_channels
116 #define snd_pcm_hw_params_set_periods_near psnd_pcm_hw_params_set_periods_near
117 #define snd_pcm_hw_params_set_rate_near psnd_pcm_hw_params_set_rate_near
118 #define snd_pcm_hw_params_set_rate psnd_pcm_hw_params_set_rate
119 #define snd_pcm_hw_params_set_rate_resample psnd_pcm_hw_params_set_rate_resample
120 #define snd_pcm_hw_params_set_buffer_time_near psnd_pcm_hw_params_set_buffer_time_near
121 #define snd_pcm_hw_params_set_period_time_near psnd_pcm_hw_params_set_period_time_near
122 #define snd_pcm_hw_params_set_buffer_size_near psnd_pcm_hw_params_set_buffer_size_near
123 #define snd_pcm_hw_params_set_period_size_near psnd_pcm_hw_params_set_period_size_near
124 #define snd_pcm_hw_params_set_buffer_size_min psnd_pcm_hw_params_set_buffer_size_min
125 #define snd_pcm_hw_params_get_buffer_size psnd_pcm_hw_params_get_buffer_size
126 #define snd_pcm_hw_params_get_period_size psnd_pcm_hw_params_get_period_size
127 #define snd_pcm_hw_params_get_access psnd_pcm_hw_params_get_access
128 #define snd_pcm_hw_params_get_periods psnd_pcm_hw_params_get_periods
129 #define snd_pcm_hw_params_test_format psnd_pcm_hw_params_test_format
130 #define snd_pcm_hw_params_test_channels psnd_pcm_hw_params_test_channels
131 #define snd_pcm_hw_params psnd_pcm_hw_params
132 #define snd_pcm_sw_params_malloc psnd_pcm_sw_params_malloc
133 #define snd_pcm_sw_params_current psnd_pcm_sw_params_current
134 #define snd_pcm_sw_params_set_avail_min psnd_pcm_sw_params_set_avail_min
135 #define snd_pcm_sw_params_set_stop_threshold psnd_pcm_sw_params_set_stop_threshold
136 #define snd_pcm_sw_params psnd_pcm_sw_params
137 #define snd_pcm_sw_params_free psnd_pcm_sw_params_free
138 #define snd_pcm_prepare psnd_pcm_prepare
139 #define snd_pcm_start psnd_pcm_start
140 #define snd_pcm_resume psnd_pcm_resume
141 #define snd_pcm_reset psnd_pcm_reset
142 #define snd_pcm_wait psnd_pcm_wait
143 #define snd_pcm_state psnd_pcm_state
144 #define snd_pcm_avail_update psnd_pcm_avail_update
145 #define snd_pcm_areas_silence psnd_pcm_areas_silence
146 #define snd_pcm_mmap_begin psnd_pcm_mmap_begin
147 #define snd_pcm_mmap_commit psnd_pcm_mmap_commit
148 #define snd_pcm_readi psnd_pcm_readi
149 #define snd_pcm_writei psnd_pcm_writei
150 #define snd_pcm_drain psnd_pcm_drain
151 #define snd_pcm_recover psnd_pcm_recover
152 #define snd_pcm_info_malloc psnd_pcm_info_malloc
153 #define snd_pcm_info_free psnd_pcm_info_free
154 #define snd_pcm_info_set_device psnd_pcm_info_set_device
155 #define snd_pcm_info_set_subdevice psnd_pcm_info_set_subdevice
156 #define snd_pcm_info_set_stream psnd_pcm_info_set_stream
157 #define snd_pcm_info_get_name psnd_pcm_info_get_name
158 #define snd_ctl_pcm_next_device psnd_ctl_pcm_next_device
159 #define snd_ctl_pcm_info psnd_ctl_pcm_info
160 #define snd_ctl_open psnd_ctl_open
161 #define snd_ctl_close psnd_ctl_close
162 #define snd_ctl_card_info_malloc psnd_ctl_card_info_malloc
163 #define snd_ctl_card_info_free psnd_ctl_card_info_free
164 #define snd_ctl_card_info psnd_ctl_card_info
165 #define snd_ctl_card_info_get_name psnd_ctl_card_info_get_name
166 #define snd_ctl_card_info_get_id psnd_ctl_card_info_get_id
167 #define snd_card_next psnd_card_next
168 #endif
171 static ALCboolean alsa_load(void)
173 if(!alsa_handle)
175 #ifdef HAVE_DYNLOAD
176 alsa_handle = LoadLib("libasound.so.2");
177 if(!alsa_handle)
178 return ALC_FALSE;
180 #define LOAD_FUNC(f) do { \
181 p##f = GetSymbol(alsa_handle, #f); \
182 if(p##f == NULL) { \
183 CloseLib(alsa_handle); \
184 alsa_handle = NULL; \
185 return ALC_FALSE; \
187 } while(0)
188 LOAD_FUNC(snd_strerror);
189 LOAD_FUNC(snd_pcm_open);
190 LOAD_FUNC(snd_pcm_close);
191 LOAD_FUNC(snd_pcm_nonblock);
192 LOAD_FUNC(snd_pcm_frames_to_bytes);
193 LOAD_FUNC(snd_pcm_bytes_to_frames);
194 LOAD_FUNC(snd_pcm_hw_params_malloc);
195 LOAD_FUNC(snd_pcm_hw_params_free);
196 LOAD_FUNC(snd_pcm_hw_params_any);
197 LOAD_FUNC(snd_pcm_hw_params_set_access);
198 LOAD_FUNC(snd_pcm_hw_params_set_format);
199 LOAD_FUNC(snd_pcm_hw_params_set_channels);
200 LOAD_FUNC(snd_pcm_hw_params_set_periods_near);
201 LOAD_FUNC(snd_pcm_hw_params_set_rate_near);
202 LOAD_FUNC(snd_pcm_hw_params_set_rate);
203 LOAD_FUNC(snd_pcm_hw_params_set_rate_resample);
204 LOAD_FUNC(snd_pcm_hw_params_set_buffer_time_near);
205 LOAD_FUNC(snd_pcm_hw_params_set_period_time_near);
206 LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_near);
207 LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_min);
208 LOAD_FUNC(snd_pcm_hw_params_set_period_size_near);
209 LOAD_FUNC(snd_pcm_hw_params_get_buffer_size);
210 LOAD_FUNC(snd_pcm_hw_params_get_period_size);
211 LOAD_FUNC(snd_pcm_hw_params_get_access);
212 LOAD_FUNC(snd_pcm_hw_params_get_periods);
213 LOAD_FUNC(snd_pcm_hw_params_test_format);
214 LOAD_FUNC(snd_pcm_hw_params_test_channels);
215 LOAD_FUNC(snd_pcm_hw_params);
216 LOAD_FUNC(snd_pcm_sw_params_malloc);
217 LOAD_FUNC(snd_pcm_sw_params_current);
218 LOAD_FUNC(snd_pcm_sw_params_set_avail_min);
219 LOAD_FUNC(snd_pcm_sw_params_set_stop_threshold);
220 LOAD_FUNC(snd_pcm_sw_params);
221 LOAD_FUNC(snd_pcm_sw_params_free);
222 LOAD_FUNC(snd_pcm_prepare);
223 LOAD_FUNC(snd_pcm_start);
224 LOAD_FUNC(snd_pcm_resume);
225 LOAD_FUNC(snd_pcm_reset);
226 LOAD_FUNC(snd_pcm_wait);
227 LOAD_FUNC(snd_pcm_state);
228 LOAD_FUNC(snd_pcm_avail_update);
229 LOAD_FUNC(snd_pcm_areas_silence);
230 LOAD_FUNC(snd_pcm_mmap_begin);
231 LOAD_FUNC(snd_pcm_mmap_commit);
232 LOAD_FUNC(snd_pcm_readi);
233 LOAD_FUNC(snd_pcm_writei);
234 LOAD_FUNC(snd_pcm_drain);
235 LOAD_FUNC(snd_pcm_recover);
236 LOAD_FUNC(snd_pcm_info_malloc);
237 LOAD_FUNC(snd_pcm_info_free);
238 LOAD_FUNC(snd_pcm_info_set_device);
239 LOAD_FUNC(snd_pcm_info_set_subdevice);
240 LOAD_FUNC(snd_pcm_info_set_stream);
241 LOAD_FUNC(snd_pcm_info_get_name);
242 LOAD_FUNC(snd_ctl_pcm_next_device);
243 LOAD_FUNC(snd_ctl_pcm_info);
244 LOAD_FUNC(snd_ctl_open);
245 LOAD_FUNC(snd_ctl_close);
246 LOAD_FUNC(snd_ctl_card_info_malloc);
247 LOAD_FUNC(snd_ctl_card_info_free);
248 LOAD_FUNC(snd_ctl_card_info);
249 LOAD_FUNC(snd_ctl_card_info_get_name);
250 LOAD_FUNC(snd_ctl_card_info_get_id);
251 LOAD_FUNC(snd_card_next);
252 #undef LOAD_FUNC
253 #else
254 alsa_handle = (void*)0xDEADBEEF;
255 #endif
257 return ALC_TRUE;
261 typedef struct {
262 snd_pcm_t *pcmHandle;
264 ALvoid *buffer;
265 ALsizei size;
267 ALboolean doCapture;
268 RingBuffer *ring;
270 volatile int killNow;
271 ALvoid *thread;
272 } alsa_data;
274 typedef struct {
275 ALCchar *name;
276 char *device;
277 } DevMap;
279 static DevMap *allDevNameMap;
280 static ALuint numDevNames;
281 static DevMap *allCaptureDevNameMap;
282 static ALuint numCaptureDevNames;
285 static const char *prefix_name(snd_pcm_stream_t stream)
287 assert(stream == SND_PCM_STREAM_PLAYBACK || stream == SND_PCM_STREAM_CAPTURE);
288 return (stream==SND_PCM_STREAM_PLAYBACK) ? "device-prefix" : "capture-prefix";
291 static DevMap *probe_devices(snd_pcm_stream_t stream, ALuint *count)
293 snd_ctl_t *handle;
294 int card, err, dev, idx;
295 snd_ctl_card_info_t *info;
296 snd_pcm_info_t *pcminfo;
297 DevMap *DevList;
299 snd_ctl_card_info_malloc(&info);
300 snd_pcm_info_malloc(&pcminfo);
302 card = -1;
303 if((err=snd_card_next(&card)) < 0)
304 ERR("Failed to find a card: %s\n", snd_strerror(err));
306 DevList = malloc(sizeof(DevMap) * 1);
307 DevList[0].name = strdup("ALSA Default");
308 DevList[0].device = NULL;
309 idx = 1;
310 while(card >= 0)
312 char name[256];
314 sprintf(name, "hw:%d", card);
315 if((err = snd_ctl_open(&handle, name, 0)) < 0)
317 ERR("control open (hw:%d): %s\n", card, snd_strerror(err));
318 goto next_card;
320 if((err = snd_ctl_card_info(handle, info)) < 0)
322 ERR("control hardware info (hw:%d): %s\n", card, snd_strerror(err));
323 snd_ctl_close(handle);
324 goto next_card;
327 dev = -1;
328 while(1)
330 const char *cname, *dname, *cid;
331 void *temp;
333 if(snd_ctl_pcm_next_device(handle, &dev) < 0)
334 ERR("snd_ctl_pcm_next_device failed\n");
335 if(dev < 0)
336 break;
338 snd_pcm_info_set_device(pcminfo, dev);
339 snd_pcm_info_set_subdevice(pcminfo, 0);
340 snd_pcm_info_set_stream(pcminfo, stream);
341 if((err = snd_ctl_pcm_info(handle, pcminfo)) < 0) {
342 if(err != -ENOENT)
343 ERR("control digital audio info (hw:%d): %s\n", card, snd_strerror(err));
344 continue;
347 temp = realloc(DevList, sizeof(DevMap) * (idx+1));
348 if(temp)
350 const char *prefix = "plughw:";
351 char devname[128];
353 DevList = temp;
354 cname = snd_ctl_card_info_get_name(info);
355 dname = snd_pcm_info_get_name(pcminfo);
356 cid = snd_ctl_card_info_get_id(info);
358 snprintf(devname, sizeof(devname), "%s-%s-%d", prefix_name(stream), cid, dev);
359 if(!ConfigValueStr("alsa", devname, &prefix))
361 snprintf(devname, sizeof(devname), "%s-%s", prefix_name(stream), cid);
362 if(!ConfigValueStr("alsa", devname, &prefix))
363 ConfigValueStr("alsa", prefix_name(stream), &prefix);
366 snprintf(name, sizeof(name), "%s, %s (CARD=%s,DEV=%d)",
367 cname, dname, cid, dev);
368 snprintf(devname, sizeof(devname), "%sCARD=%s,DEV=%d",
369 prefix, cid, dev);
371 DevList[idx].name = strdup(name);
372 DevList[idx].device = strdup(devname);
373 idx++;
376 snd_ctl_close(handle);
377 next_card:
378 if(snd_card_next(&card) < 0) {
379 ERR("snd_card_next failed\n");
380 break;
384 snd_pcm_info_free(pcminfo);
385 snd_ctl_card_info_free(info);
387 *count = idx;
388 return DevList;
392 static int xrun_recovery(snd_pcm_t *handle, int err)
394 err = snd_pcm_recover(handle, err, 1);
395 if(err < 0)
396 ERR("recover failed: %s\n", snd_strerror(err));
397 return err;
400 static int verify_state(snd_pcm_t *handle)
402 snd_pcm_state_t state = snd_pcm_state(handle);
403 if(state == SND_PCM_STATE_DISCONNECTED)
404 return -ENODEV;
405 if(state == SND_PCM_STATE_XRUN)
407 int err = xrun_recovery(handle, -EPIPE);
408 if(err < 0) return err;
410 else if(state == SND_PCM_STATE_SUSPENDED)
412 int err = xrun_recovery(handle, -ESTRPIPE);
413 if(err < 0) return err;
416 return state;
420 static ALuint ALSAProc(ALvoid *ptr)
422 ALCdevice *pDevice = (ALCdevice*)ptr;
423 alsa_data *data = (alsa_data*)pDevice->ExtraData;
424 const snd_pcm_channel_area_t *areas = NULL;
425 snd_pcm_uframes_t update_size, num_updates;
426 snd_pcm_sframes_t avail, commitres;
427 snd_pcm_uframes_t offset, frames;
428 char *WritePtr;
429 int err;
431 SetRTPriority();
433 update_size = pDevice->UpdateSize;
434 num_updates = pDevice->NumUpdates;
435 while(!data->killNow)
437 int state = verify_state(data->pcmHandle);
438 if(state < 0)
440 ERR("Invalid state detected: %s\n", snd_strerror(state));
441 aluHandleDisconnect(pDevice);
442 break;
445 avail = snd_pcm_avail_update(data->pcmHandle);
446 if(avail < 0)
448 ERR("available update failed: %s\n", snd_strerror(avail));
449 continue;
452 if((snd_pcm_uframes_t)avail > update_size*(num_updates+1))
454 WARN("available samples exceeds the buffer size\n");
455 snd_pcm_reset(data->pcmHandle);
456 continue;
459 // make sure there's frames to process
460 if((snd_pcm_uframes_t)avail < update_size)
462 if(state != SND_PCM_STATE_RUNNING)
464 err = snd_pcm_start(data->pcmHandle);
465 if(err < 0)
467 ERR("start failed: %s\n", snd_strerror(err));
468 continue;
471 if(snd_pcm_wait(data->pcmHandle, 1000) == 0)
472 ERR("Wait timeout... buffer size too low?\n");
473 continue;
475 avail -= avail%update_size;
477 // it is possible that contiguous areas are smaller, thus we use a loop
478 while(avail > 0)
480 frames = avail;
482 err = snd_pcm_mmap_begin(data->pcmHandle, &areas, &offset, &frames);
483 if(err < 0)
485 ERR("mmap begin error: %s\n", snd_strerror(err));
486 break;
489 WritePtr = (char*)areas->addr + (offset * areas->step / 8);
490 aluMixData(pDevice, WritePtr, frames);
492 commitres = snd_pcm_mmap_commit(data->pcmHandle, offset, frames);
493 if(commitres < 0 || (commitres-frames) != 0)
495 ERR("mmap commit error: %s\n",
496 snd_strerror(commitres >= 0 ? -EPIPE : commitres));
497 break;
500 avail -= frames;
504 return 0;
507 static ALuint ALSANoMMapProc(ALvoid *ptr)
509 ALCdevice *pDevice = (ALCdevice*)ptr;
510 alsa_data *data = (alsa_data*)pDevice->ExtraData;
511 snd_pcm_sframes_t avail;
512 char *WritePtr;
514 SetRTPriority();
516 while(!data->killNow)
518 int state = verify_state(data->pcmHandle);
519 if(state < 0)
521 ERR("Invalid state detected: %s\n", snd_strerror(state));
522 aluHandleDisconnect(pDevice);
523 break;
526 WritePtr = data->buffer;
527 avail = data->size / snd_pcm_frames_to_bytes(data->pcmHandle, 1);
528 aluMixData(pDevice, WritePtr, avail);
530 while(avail > 0)
532 int ret = snd_pcm_writei(data->pcmHandle, WritePtr, avail);
533 switch (ret)
535 case -EAGAIN:
536 continue;
537 case -ESTRPIPE:
538 case -EPIPE:
539 case -EINTR:
540 ret = snd_pcm_recover(data->pcmHandle, ret, 1);
541 if(ret < 0)
542 avail = 0;
543 break;
544 default:
545 if (ret >= 0)
547 WritePtr += snd_pcm_frames_to_bytes(data->pcmHandle, ret);
548 avail -= ret;
550 break;
552 if (ret < 0)
554 ret = snd_pcm_prepare(data->pcmHandle);
555 if(ret < 0)
556 break;
561 return 0;
564 static ALCenum alsa_open_playback(ALCdevice *device, const ALCchar *deviceName)
566 const char *driver = "default";
567 alsa_data *data;
568 int i;
570 ConfigValueStr("alsa", "device", &driver);
572 if(!deviceName)
573 deviceName = alsaDevice;
574 else if(strcmp(deviceName, alsaDevice) != 0)
576 size_t idx;
578 if(!allDevNameMap)
579 allDevNameMap = probe_devices(SND_PCM_STREAM_PLAYBACK, &numDevNames);
581 for(idx = 0;idx < numDevNames;idx++)
583 if(allDevNameMap[idx].name &&
584 strcmp(deviceName, allDevNameMap[idx].name) == 0)
586 if(idx > 0)
587 driver = allDevNameMap[idx].device;
588 break;
591 if(idx == numDevNames)
592 return ALC_INVALID_VALUE;
595 data = (alsa_data*)calloc(1, sizeof(alsa_data));
597 i = snd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
598 if(i >= 0)
600 i = snd_pcm_nonblock(data->pcmHandle, 0);
601 if(i < 0)
602 snd_pcm_close(data->pcmHandle);
604 if(i < 0)
606 free(data);
607 ERR("Could not open playback device '%s': %s\n", driver, snd_strerror(i));
608 return ALC_OUT_OF_MEMORY;
611 device->szDeviceName = strdup(deviceName);
612 device->ExtraData = data;
613 return ALC_NO_ERROR;
616 static void alsa_close_playback(ALCdevice *device)
618 alsa_data *data = (alsa_data*)device->ExtraData;
620 snd_pcm_close(data->pcmHandle);
621 free(data);
622 device->ExtraData = NULL;
625 static ALCboolean alsa_reset_playback(ALCdevice *device)
627 alsa_data *data = (alsa_data*)device->ExtraData;
628 snd_pcm_uframes_t periodSizeInFrames;
629 unsigned int periodLen, bufferLen;
630 snd_pcm_sw_params_t *sp = NULL;
631 snd_pcm_hw_params_t *p = NULL;
632 snd_pcm_access_t access;
633 snd_pcm_format_t format;
634 unsigned int periods;
635 unsigned int rate;
636 int allowmmap;
637 char *err;
638 int i;
641 format = -1;
642 switch(device->FmtType)
644 case DevFmtByte:
645 format = SND_PCM_FORMAT_S8;
646 break;
647 case DevFmtUByte:
648 format = SND_PCM_FORMAT_U8;
649 break;
650 case DevFmtShort:
651 format = SND_PCM_FORMAT_S16;
652 break;
653 case DevFmtUShort:
654 format = SND_PCM_FORMAT_U16;
655 break;
656 case DevFmtFloat:
657 format = SND_PCM_FORMAT_FLOAT;
658 break;
661 allowmmap = GetConfigValueBool("alsa", "mmap", 1);
662 periods = device->NumUpdates;
663 periodLen = (ALuint64)device->UpdateSize * 1000000 / device->Frequency;
664 bufferLen = periodLen * periods;
665 rate = device->Frequency;
667 err = NULL;
668 snd_pcm_hw_params_malloc(&p);
670 if((i=snd_pcm_hw_params_any(data->pcmHandle, p)) < 0)
671 err = "any";
672 /* set interleaved access */
673 if(i >= 0 && (!allowmmap || (i=snd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_MMAP_INTERLEAVED)) < 0))
675 if(periods > 2)
677 periods--;
678 bufferLen = periodLen * periods;
680 if((i=snd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
681 err = "set access";
683 /* set format (implicitly sets sample bits) */
684 if(i >= 0 && (i=snd_pcm_hw_params_test_format(data->pcmHandle, p, format)) < 0)
686 static const struct {
687 snd_pcm_format_t format;
688 enum DevFmtType fmttype;
689 } formatlist[] = {
690 { SND_PCM_FORMAT_FLOAT, DevFmtFloat },
691 { SND_PCM_FORMAT_S16, DevFmtShort },
692 { SND_PCM_FORMAT_U16, DevFmtUShort },
693 { SND_PCM_FORMAT_S8, DevFmtByte },
694 { SND_PCM_FORMAT_U8, DevFmtUByte },
696 size_t k;
698 err = "test format";
699 for(k = 0;k < sizeof(formatlist)/sizeof(formatlist[0]);k++)
701 format = formatlist[k].format;
702 if((i=snd_pcm_hw_params_test_format(data->pcmHandle, p, format)) >= 0)
704 device->FmtType = formatlist[k].fmttype;
705 break;
709 if(i >= 0 && (i=snd_pcm_hw_params_set_format(data->pcmHandle, p, format)) < 0)
710 err = "set format";
711 /* set channels (implicitly sets frame bits) */
712 if(i >= 0 && (i=snd_pcm_hw_params_test_channels(data->pcmHandle, p, ChannelsFromDevFmt(device->FmtChans))) < 0)
714 static const enum DevFmtChannels channellist[] = {
715 DevFmtStereo,
716 DevFmtQuad,
717 DevFmtX51,
718 DevFmtX71,
719 DevFmtMono,
721 size_t k;
723 err = "test channels";
724 for(k = 0;k < sizeof(channellist)/sizeof(channellist[0]);k++)
726 if((i=snd_pcm_hw_params_test_channels(data->pcmHandle, p, ChannelsFromDevFmt(channellist[k]))) >= 0)
728 device->FmtChans = channellist[k];
729 break;
733 if(i >= 0 && (i=snd_pcm_hw_params_set_channels(data->pcmHandle, p, ChannelsFromDevFmt(device->FmtChans))) < 0)
734 err = "set channels";
735 if(i >= 0 && (i=snd_pcm_hw_params_set_rate_resample(data->pcmHandle, p, 0)) < 0)
737 ERR("Failed to disable ALSA resampler\n");
738 i = 0;
740 /* set rate (implicitly constrains period/buffer parameters) */
741 if(i >= 0 && (i=snd_pcm_hw_params_set_rate_near(data->pcmHandle, p, &rate, NULL)) < 0)
742 err = "set rate near";
743 /* set buffer time (implicitly constrains period/buffer parameters) */
744 if(i >= 0 && (i=snd_pcm_hw_params_set_buffer_time_near(data->pcmHandle, p, &bufferLen, NULL)) < 0)
745 err = "set buffer time near";
746 /* set period time in frame units (implicitly sets buffer size/bytes/time and period size/bytes) */
747 if(i >= 0 && (i=snd_pcm_hw_params_set_period_time_near(data->pcmHandle, p, &periodLen, NULL)) < 0)
748 err = "set period time near";
749 /* install and prepare hardware configuration */
750 if(i >= 0 && (i=snd_pcm_hw_params(data->pcmHandle, p)) < 0)
751 err = "set params";
752 if(i >= 0 && (i=snd_pcm_hw_params_get_access(p, &access)) < 0)
753 err = "get access";
754 if(i >= 0 && (i=snd_pcm_hw_params_get_period_size(p, &periodSizeInFrames, NULL)) < 0)
755 err = "get period size";
756 if(i >= 0 && (i=snd_pcm_hw_params_get_periods(p, &periods, NULL)) < 0)
757 err = "get periods";
758 if(i < 0)
760 ERR("%s failed: %s\n", err, snd_strerror(i));
761 snd_pcm_hw_params_free(p);
762 return ALC_FALSE;
765 snd_pcm_hw_params_free(p);
767 err = NULL;
768 snd_pcm_sw_params_malloc(&sp);
770 if((i=snd_pcm_sw_params_current(data->pcmHandle, sp)) != 0)
771 err = "sw current";
772 if(i == 0 && (i=snd_pcm_sw_params_set_avail_min(data->pcmHandle, sp, periodSizeInFrames)) != 0)
773 err = "sw set avail min";
774 if(i == 0 && (i=snd_pcm_sw_params_set_stop_threshold(data->pcmHandle, sp, periodSizeInFrames*periods)) != 0)
775 err = "sw set stop threshold";
776 if(i == 0 && (i=snd_pcm_sw_params(data->pcmHandle, sp)) != 0)
777 err = "sw set params";
778 if(i != 0)
780 ERR("%s failed: %s\n", err, snd_strerror(i));
781 snd_pcm_sw_params_free(sp);
782 return ALC_FALSE;
785 snd_pcm_sw_params_free(sp);
787 device->Frequency = rate;
788 SetDefaultChannelOrder(device);
790 data->size = snd_pcm_frames_to_bytes(data->pcmHandle, periodSizeInFrames);
791 if(access == SND_PCM_ACCESS_RW_INTERLEAVED)
793 /* Increase periods by one, since the temp buffer counts as an extra
794 * period */
795 periods++;
796 data->buffer = malloc(data->size);
797 if(!data->buffer)
799 ERR("buffer malloc failed\n");
800 return ALC_FALSE;
802 device->UpdateSize = periodSizeInFrames;
803 device->NumUpdates = periods;
804 data->thread = StartThread(ALSANoMMapProc, device);
806 else
808 i = snd_pcm_prepare(data->pcmHandle);
809 if(i < 0)
811 ERR("prepare error: %s\n", snd_strerror(i));
812 return ALC_FALSE;
814 device->UpdateSize = periodSizeInFrames;
815 device->NumUpdates = periods;
816 data->thread = StartThread(ALSAProc, device);
818 if(data->thread == NULL)
820 ERR("Could not create playback thread\n");
821 free(data->buffer);
822 data->buffer = NULL;
823 return ALC_FALSE;
826 return ALC_TRUE;
829 static void alsa_stop_playback(ALCdevice *device)
831 alsa_data *data = (alsa_data*)device->ExtraData;
833 if(data->thread)
835 data->killNow = 1;
836 StopThread(data->thread);
837 data->thread = NULL;
839 data->killNow = 0;
840 free(data->buffer);
841 data->buffer = NULL;
845 static ALCenum alsa_open_capture(ALCdevice *pDevice, const ALCchar *deviceName)
847 const char *driver = "default";
848 snd_pcm_hw_params_t *p;
849 snd_pcm_uframes_t bufferSizeInFrames;
850 snd_pcm_uframes_t periodSizeInFrames;
851 snd_pcm_format_t format;
852 ALuint frameSize;
853 alsa_data *data;
854 char *err;
855 int i;
857 ConfigValueStr("alsa", "capture", &driver);
859 if(!allCaptureDevNameMap)
860 allCaptureDevNameMap = probe_devices(SND_PCM_STREAM_CAPTURE, &numCaptureDevNames);
862 if(!deviceName)
863 deviceName = allCaptureDevNameMap[0].name;
864 else
866 size_t idx;
868 for(idx = 0;idx < numCaptureDevNames;idx++)
870 if(allCaptureDevNameMap[idx].name &&
871 strcmp(deviceName, allCaptureDevNameMap[idx].name) == 0)
873 if(idx > 0)
874 driver = allCaptureDevNameMap[idx].device;
875 break;
878 if(idx == numCaptureDevNames)
879 return ALC_INVALID_VALUE;
882 data = (alsa_data*)calloc(1, sizeof(alsa_data));
884 i = snd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
885 if(i < 0)
887 ERR("Could not open capture device '%s': %s\n", driver, snd_strerror(i));
888 free(data);
889 return ALC_INVALID_VALUE;
892 format = -1;
893 switch(pDevice->FmtType)
895 case DevFmtByte:
896 format = SND_PCM_FORMAT_S8;
897 break;
898 case DevFmtUByte:
899 format = SND_PCM_FORMAT_U8;
900 break;
901 case DevFmtShort:
902 format = SND_PCM_FORMAT_S16;
903 break;
904 case DevFmtUShort:
905 format = SND_PCM_FORMAT_U16;
906 break;
907 case DevFmtFloat:
908 format = SND_PCM_FORMAT_FLOAT;
909 break;
912 err = NULL;
913 bufferSizeInFrames = maxu(pDevice->UpdateSize*pDevice->NumUpdates,
914 100*pDevice->Frequency/1000);
915 periodSizeInFrames = minu(bufferSizeInFrames, 50*pDevice->Frequency/1000);
916 snd_pcm_hw_params_malloc(&p);
918 if((i=snd_pcm_hw_params_any(data->pcmHandle, p)) < 0)
919 err = "any";
920 /* set interleaved access */
921 if(i >= 0 && (i=snd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
922 err = "set access";
923 /* set format (implicitly sets sample bits) */
924 if(i >= 0 && (i=snd_pcm_hw_params_set_format(data->pcmHandle, p, format)) < 0)
925 err = "set format";
926 /* set channels (implicitly sets frame bits) */
927 if(i >= 0 && (i=snd_pcm_hw_params_set_channels(data->pcmHandle, p, ChannelsFromDevFmt(pDevice->FmtChans))) < 0)
928 err = "set channels";
929 /* set rate (implicitly constrains period/buffer parameters) */
930 if(i >= 0 && (i=snd_pcm_hw_params_set_rate(data->pcmHandle, p, pDevice->Frequency, 0)) < 0)
931 err = "set rate near";
932 /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */
933 if(i >= 0 && (i=snd_pcm_hw_params_set_buffer_size_near(data->pcmHandle, p, &bufferSizeInFrames)) < 0)
934 err = "set buffer size near";
935 /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */
936 if(i >= 0 && (i=snd_pcm_hw_params_set_period_size_near(data->pcmHandle, p, &periodSizeInFrames, NULL)) < 0)
937 err = "set period size near";
938 /* install and prepare hardware configuration */
939 if(i >= 0 && (i=snd_pcm_hw_params(data->pcmHandle, p)) < 0)
940 err = "set params";
941 if(i < 0)
943 ERR("%s failed: %s\n", err, snd_strerror(i));
944 snd_pcm_hw_params_free(p);
945 goto error;
948 if((i=snd_pcm_hw_params_get_period_size(p, &bufferSizeInFrames, NULL)) < 0)
950 ERR("get size failed: %s\n", snd_strerror(i));
951 snd_pcm_hw_params_free(p);
952 goto error;
955 snd_pcm_hw_params_free(p);
957 frameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);
959 data->ring = CreateRingBuffer(frameSize, pDevice->UpdateSize*pDevice->NumUpdates);
960 if(!data->ring)
962 ERR("ring buffer create failed\n");
963 goto error;
966 data->size = snd_pcm_frames_to_bytes(data->pcmHandle, bufferSizeInFrames);
967 data->buffer = malloc(data->size);
968 if(!data->buffer)
970 ERR("buffer malloc failed\n");
971 goto error;
974 pDevice->szDeviceName = strdup(deviceName);
976 pDevice->ExtraData = data;
977 return ALC_NO_ERROR;
979 error:
980 free(data->buffer);
981 DestroyRingBuffer(data->ring);
982 snd_pcm_close(data->pcmHandle);
983 free(data);
985 pDevice->ExtraData = NULL;
986 return ALC_INVALID_VALUE;
989 static void alsa_close_capture(ALCdevice *pDevice)
991 alsa_data *data = (alsa_data*)pDevice->ExtraData;
993 snd_pcm_close(data->pcmHandle);
994 DestroyRingBuffer(data->ring);
996 free(data->buffer);
997 free(data);
998 pDevice->ExtraData = NULL;
1001 static void alsa_start_capture(ALCdevice *Device)
1003 alsa_data *data = (alsa_data*)Device->ExtraData;
1004 int err;
1006 err = snd_pcm_start(data->pcmHandle);
1007 if(err < 0)
1009 ERR("start failed: %s\n", snd_strerror(err));
1010 aluHandleDisconnect(Device);
1012 else
1013 data->doCapture = AL_TRUE;
1016 static void alsa_stop_capture(ALCdevice *Device)
1018 alsa_data *data = (alsa_data*)Device->ExtraData;
1019 snd_pcm_drain(data->pcmHandle);
1020 data->doCapture = AL_FALSE;
1023 static ALCenum alsa_capture_samples(ALCdevice *Device, ALCvoid *Buffer, ALCuint Samples)
1025 alsa_data *data = (alsa_data*)Device->ExtraData;
1026 ReadRingBuffer(data->ring, Buffer, Samples);
1027 return ALC_NO_ERROR;
1030 static ALCuint alsa_available_samples(ALCdevice *Device)
1032 alsa_data *data = (alsa_data*)Device->ExtraData;
1033 snd_pcm_sframes_t avail;
1035 avail = (Device->Connected ? snd_pcm_avail_update(data->pcmHandle) : 0);
1036 if(avail < 0)
1038 ERR("avail update failed: %s\n", snd_strerror(avail));
1040 if((avail=snd_pcm_recover(data->pcmHandle, avail, 1)) >= 0)
1042 if(data->doCapture)
1043 avail = snd_pcm_start(data->pcmHandle);
1044 if(avail >= 0)
1045 avail = snd_pcm_avail_update(data->pcmHandle);
1047 if(avail < 0)
1049 ERR("restore error: %s\n", snd_strerror(avail));
1050 aluHandleDisconnect(Device);
1053 while(avail > 0)
1055 snd_pcm_sframes_t amt;
1057 amt = snd_pcm_bytes_to_frames(data->pcmHandle, data->size);
1058 if(avail < amt) amt = avail;
1060 amt = snd_pcm_readi(data->pcmHandle, data->buffer, amt);
1061 if(amt < 0)
1063 ERR("read error: %s\n", snd_strerror(amt));
1065 if(amt == -EAGAIN)
1066 continue;
1067 if((amt=snd_pcm_recover(data->pcmHandle, amt, 1)) >= 0)
1069 if(data->doCapture)
1070 amt = snd_pcm_start(data->pcmHandle);
1071 if(amt >= 0)
1072 amt = snd_pcm_avail_update(data->pcmHandle);
1074 if(amt < 0)
1076 ERR("restore error: %s\n", snd_strerror(amt));
1077 aluHandleDisconnect(Device);
1078 break;
1080 avail = amt;
1081 continue;
1084 WriteRingBuffer(data->ring, data->buffer, amt);
1085 avail -= amt;
1088 return RingBufferSize(data->ring);
1092 static const BackendFuncs alsa_funcs = {
1093 alsa_open_playback,
1094 alsa_close_playback,
1095 alsa_reset_playback,
1096 alsa_stop_playback,
1097 alsa_open_capture,
1098 alsa_close_capture,
1099 alsa_start_capture,
1100 alsa_stop_capture,
1101 alsa_capture_samples,
1102 alsa_available_samples
1105 ALCboolean alc_alsa_init(BackendFuncs *func_list)
1107 if(!alsa_load())
1108 return ALC_FALSE;
1109 *func_list = alsa_funcs;
1110 return ALC_TRUE;
1113 void alc_alsa_deinit(void)
1115 ALuint i;
1117 for(i = 0;i < numDevNames;++i)
1118 free(allDevNameMap[i].device);
1119 free(allDevNameMap);
1120 allDevNameMap = NULL;
1121 numDevNames = 0;
1123 for(i = 0;i < numCaptureDevNames;++i)
1124 free(allCaptureDevNameMap[i].device);
1125 free(allCaptureDevNameMap);
1126 allCaptureDevNameMap = NULL;
1127 numCaptureDevNames = 0;
1129 #ifdef HAVE_DYNLOAD
1130 if(alsa_handle)
1131 CloseLib(alsa_handle);
1132 alsa_handle = NULL;
1133 #endif
1136 void alc_alsa_probe(enum DevProbe type)
1138 ALuint i;
1140 switch(type)
1142 case DEVICE_PROBE:
1143 AppendDeviceList(alsaDevice);
1144 break;
1146 case ALL_DEVICE_PROBE:
1147 for(i = 0;i < numDevNames;++i)
1148 free(allDevNameMap[i].device);
1150 free(allDevNameMap);
1151 allDevNameMap = probe_devices(SND_PCM_STREAM_PLAYBACK, &numDevNames);
1153 for(i = 0;i < numDevNames;++i)
1154 AppendAllDeviceList(allDevNameMap[i].name);
1155 break;
1157 case CAPTURE_DEVICE_PROBE:
1158 for(i = 0;i < numCaptureDevNames;++i)
1159 free(allCaptureDevNameMap[i].device);
1161 free(allCaptureDevNameMap);
1162 allCaptureDevNameMap = probe_devices(SND_PCM_STREAM_CAPTURE, &numCaptureDevNames);
1164 for(i = 0;i < numCaptureDevNames;++i)
1165 AppendCaptureDeviceList(allCaptureDevNameMap[i].name);
1166 break;