Allow reading audio from ALSA directly if the requested length is supported
[openal-soft.git] / Alc / backends / alsa.c
blob7b46a9c24a6b8cc7f1ac47bb8c5669117f7823e2
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_drop);
86 MAKE_FUNC(snd_pcm_recover);
87 MAKE_FUNC(snd_pcm_info_malloc);
88 MAKE_FUNC(snd_pcm_info_free);
89 MAKE_FUNC(snd_pcm_info_set_device);
90 MAKE_FUNC(snd_pcm_info_set_subdevice);
91 MAKE_FUNC(snd_pcm_info_set_stream);
92 MAKE_FUNC(snd_pcm_info_get_name);
93 MAKE_FUNC(snd_ctl_pcm_next_device);
94 MAKE_FUNC(snd_ctl_pcm_info);
95 MAKE_FUNC(snd_ctl_open);
96 MAKE_FUNC(snd_ctl_close);
97 MAKE_FUNC(snd_ctl_card_info_malloc);
98 MAKE_FUNC(snd_ctl_card_info_free);
99 MAKE_FUNC(snd_ctl_card_info);
100 MAKE_FUNC(snd_ctl_card_info_get_name);
101 MAKE_FUNC(snd_ctl_card_info_get_id);
102 MAKE_FUNC(snd_card_next);
103 #undef MAKE_FUNC
105 #define snd_strerror psnd_strerror
106 #define snd_pcm_open psnd_pcm_open
107 #define snd_pcm_close psnd_pcm_close
108 #define snd_pcm_nonblock psnd_pcm_nonblock
109 #define snd_pcm_frames_to_bytes psnd_pcm_frames_to_bytes
110 #define snd_pcm_bytes_to_frames psnd_pcm_bytes_to_frames
111 #define snd_pcm_hw_params_malloc psnd_pcm_hw_params_malloc
112 #define snd_pcm_hw_params_free psnd_pcm_hw_params_free
113 #define snd_pcm_hw_params_any psnd_pcm_hw_params_any
114 #define snd_pcm_hw_params_set_access psnd_pcm_hw_params_set_access
115 #define snd_pcm_hw_params_set_format psnd_pcm_hw_params_set_format
116 #define snd_pcm_hw_params_set_channels psnd_pcm_hw_params_set_channels
117 #define snd_pcm_hw_params_set_periods_near psnd_pcm_hw_params_set_periods_near
118 #define snd_pcm_hw_params_set_rate_near psnd_pcm_hw_params_set_rate_near
119 #define snd_pcm_hw_params_set_rate psnd_pcm_hw_params_set_rate
120 #define snd_pcm_hw_params_set_rate_resample psnd_pcm_hw_params_set_rate_resample
121 #define snd_pcm_hw_params_set_buffer_time_near psnd_pcm_hw_params_set_buffer_time_near
122 #define snd_pcm_hw_params_set_period_time_near psnd_pcm_hw_params_set_period_time_near
123 #define snd_pcm_hw_params_set_buffer_size_near psnd_pcm_hw_params_set_buffer_size_near
124 #define snd_pcm_hw_params_set_period_size_near psnd_pcm_hw_params_set_period_size_near
125 #define snd_pcm_hw_params_set_buffer_size_min psnd_pcm_hw_params_set_buffer_size_min
126 #define snd_pcm_hw_params_get_buffer_size psnd_pcm_hw_params_get_buffer_size
127 #define snd_pcm_hw_params_get_period_size psnd_pcm_hw_params_get_period_size
128 #define snd_pcm_hw_params_get_access psnd_pcm_hw_params_get_access
129 #define snd_pcm_hw_params_get_periods psnd_pcm_hw_params_get_periods
130 #define snd_pcm_hw_params_test_format psnd_pcm_hw_params_test_format
131 #define snd_pcm_hw_params_test_channels psnd_pcm_hw_params_test_channels
132 #define snd_pcm_hw_params psnd_pcm_hw_params
133 #define snd_pcm_sw_params_malloc psnd_pcm_sw_params_malloc
134 #define snd_pcm_sw_params_current psnd_pcm_sw_params_current
135 #define snd_pcm_sw_params_set_avail_min psnd_pcm_sw_params_set_avail_min
136 #define snd_pcm_sw_params_set_stop_threshold psnd_pcm_sw_params_set_stop_threshold
137 #define snd_pcm_sw_params psnd_pcm_sw_params
138 #define snd_pcm_sw_params_free psnd_pcm_sw_params_free
139 #define snd_pcm_prepare psnd_pcm_prepare
140 #define snd_pcm_start psnd_pcm_start
141 #define snd_pcm_resume psnd_pcm_resume
142 #define snd_pcm_reset psnd_pcm_reset
143 #define snd_pcm_wait psnd_pcm_wait
144 #define snd_pcm_state psnd_pcm_state
145 #define snd_pcm_avail_update psnd_pcm_avail_update
146 #define snd_pcm_areas_silence psnd_pcm_areas_silence
147 #define snd_pcm_mmap_begin psnd_pcm_mmap_begin
148 #define snd_pcm_mmap_commit psnd_pcm_mmap_commit
149 #define snd_pcm_readi psnd_pcm_readi
150 #define snd_pcm_writei psnd_pcm_writei
151 #define snd_pcm_drain psnd_pcm_drain
152 #define snd_pcm_drop psnd_pcm_drop
153 #define snd_pcm_recover psnd_pcm_recover
154 #define snd_pcm_info_malloc psnd_pcm_info_malloc
155 #define snd_pcm_info_free psnd_pcm_info_free
156 #define snd_pcm_info_set_device psnd_pcm_info_set_device
157 #define snd_pcm_info_set_subdevice psnd_pcm_info_set_subdevice
158 #define snd_pcm_info_set_stream psnd_pcm_info_set_stream
159 #define snd_pcm_info_get_name psnd_pcm_info_get_name
160 #define snd_ctl_pcm_next_device psnd_ctl_pcm_next_device
161 #define snd_ctl_pcm_info psnd_ctl_pcm_info
162 #define snd_ctl_open psnd_ctl_open
163 #define snd_ctl_close psnd_ctl_close
164 #define snd_ctl_card_info_malloc psnd_ctl_card_info_malloc
165 #define snd_ctl_card_info_free psnd_ctl_card_info_free
166 #define snd_ctl_card_info psnd_ctl_card_info
167 #define snd_ctl_card_info_get_name psnd_ctl_card_info_get_name
168 #define snd_ctl_card_info_get_id psnd_ctl_card_info_get_id
169 #define snd_card_next psnd_card_next
170 #endif
173 static ALCboolean alsa_load(void)
175 if(!alsa_handle)
177 #ifdef HAVE_DYNLOAD
178 alsa_handle = LoadLib("libasound.so.2");
179 if(!alsa_handle)
180 return ALC_FALSE;
182 #define LOAD_FUNC(f) do { \
183 p##f = GetSymbol(alsa_handle, #f); \
184 if(p##f == NULL) { \
185 CloseLib(alsa_handle); \
186 alsa_handle = NULL; \
187 return ALC_FALSE; \
189 } while(0)
190 LOAD_FUNC(snd_strerror);
191 LOAD_FUNC(snd_pcm_open);
192 LOAD_FUNC(snd_pcm_close);
193 LOAD_FUNC(snd_pcm_nonblock);
194 LOAD_FUNC(snd_pcm_frames_to_bytes);
195 LOAD_FUNC(snd_pcm_bytes_to_frames);
196 LOAD_FUNC(snd_pcm_hw_params_malloc);
197 LOAD_FUNC(snd_pcm_hw_params_free);
198 LOAD_FUNC(snd_pcm_hw_params_any);
199 LOAD_FUNC(snd_pcm_hw_params_set_access);
200 LOAD_FUNC(snd_pcm_hw_params_set_format);
201 LOAD_FUNC(snd_pcm_hw_params_set_channels);
202 LOAD_FUNC(snd_pcm_hw_params_set_periods_near);
203 LOAD_FUNC(snd_pcm_hw_params_set_rate_near);
204 LOAD_FUNC(snd_pcm_hw_params_set_rate);
205 LOAD_FUNC(snd_pcm_hw_params_set_rate_resample);
206 LOAD_FUNC(snd_pcm_hw_params_set_buffer_time_near);
207 LOAD_FUNC(snd_pcm_hw_params_set_period_time_near);
208 LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_near);
209 LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_min);
210 LOAD_FUNC(snd_pcm_hw_params_set_period_size_near);
211 LOAD_FUNC(snd_pcm_hw_params_get_buffer_size);
212 LOAD_FUNC(snd_pcm_hw_params_get_period_size);
213 LOAD_FUNC(snd_pcm_hw_params_get_access);
214 LOAD_FUNC(snd_pcm_hw_params_get_periods);
215 LOAD_FUNC(snd_pcm_hw_params_test_format);
216 LOAD_FUNC(snd_pcm_hw_params_test_channels);
217 LOAD_FUNC(snd_pcm_hw_params);
218 LOAD_FUNC(snd_pcm_sw_params_malloc);
219 LOAD_FUNC(snd_pcm_sw_params_current);
220 LOAD_FUNC(snd_pcm_sw_params_set_avail_min);
221 LOAD_FUNC(snd_pcm_sw_params_set_stop_threshold);
222 LOAD_FUNC(snd_pcm_sw_params);
223 LOAD_FUNC(snd_pcm_sw_params_free);
224 LOAD_FUNC(snd_pcm_prepare);
225 LOAD_FUNC(snd_pcm_start);
226 LOAD_FUNC(snd_pcm_resume);
227 LOAD_FUNC(snd_pcm_reset);
228 LOAD_FUNC(snd_pcm_wait);
229 LOAD_FUNC(snd_pcm_state);
230 LOAD_FUNC(snd_pcm_avail_update);
231 LOAD_FUNC(snd_pcm_areas_silence);
232 LOAD_FUNC(snd_pcm_mmap_begin);
233 LOAD_FUNC(snd_pcm_mmap_commit);
234 LOAD_FUNC(snd_pcm_readi);
235 LOAD_FUNC(snd_pcm_writei);
236 LOAD_FUNC(snd_pcm_drain);
237 LOAD_FUNC(snd_pcm_drop);
238 LOAD_FUNC(snd_pcm_recover);
239 LOAD_FUNC(snd_pcm_info_malloc);
240 LOAD_FUNC(snd_pcm_info_free);
241 LOAD_FUNC(snd_pcm_info_set_device);
242 LOAD_FUNC(snd_pcm_info_set_subdevice);
243 LOAD_FUNC(snd_pcm_info_set_stream);
244 LOAD_FUNC(snd_pcm_info_get_name);
245 LOAD_FUNC(snd_ctl_pcm_next_device);
246 LOAD_FUNC(snd_ctl_pcm_info);
247 LOAD_FUNC(snd_ctl_open);
248 LOAD_FUNC(snd_ctl_close);
249 LOAD_FUNC(snd_ctl_card_info_malloc);
250 LOAD_FUNC(snd_ctl_card_info_free);
251 LOAD_FUNC(snd_ctl_card_info);
252 LOAD_FUNC(snd_ctl_card_info_get_name);
253 LOAD_FUNC(snd_ctl_card_info_get_id);
254 LOAD_FUNC(snd_card_next);
255 #undef LOAD_FUNC
256 #else
257 alsa_handle = (void*)0xDEADBEEF;
258 #endif
260 return ALC_TRUE;
264 typedef struct {
265 snd_pcm_t *pcmHandle;
267 ALvoid *buffer;
268 ALsizei size;
270 ALboolean doCapture;
271 RingBuffer *ring;
273 snd_pcm_sframes_t last_avail;
275 volatile int killNow;
276 ALvoid *thread;
277 } alsa_data;
279 typedef struct {
280 ALCchar *name;
281 char *device;
282 } DevMap;
284 static DevMap *allDevNameMap;
285 static ALuint numDevNames;
286 static DevMap *allCaptureDevNameMap;
287 static ALuint numCaptureDevNames;
290 static const char *prefix_name(snd_pcm_stream_t stream)
292 assert(stream == SND_PCM_STREAM_PLAYBACK || stream == SND_PCM_STREAM_CAPTURE);
293 return (stream==SND_PCM_STREAM_PLAYBACK) ? "device-prefix" : "capture-prefix";
296 static DevMap *probe_devices(snd_pcm_stream_t stream, ALuint *count)
298 const char *main_prefix = "plughw:";
299 snd_ctl_t *handle;
300 int card, err, dev, idx;
301 snd_ctl_card_info_t *info;
302 snd_pcm_info_t *pcminfo;
303 DevMap *DevList;
305 snd_ctl_card_info_malloc(&info);
306 snd_pcm_info_malloc(&pcminfo);
308 DevList = malloc(sizeof(DevMap) * 1);
309 DevList[0].name = strdup(alsaDevice);
310 DevList[0].device = strdup(GetConfigValue("alsa", (stream==SND_PCM_STREAM_PLAYBACK) ?
311 "device" : "capture", "default"));
312 idx = 1;
314 card = -1;
315 if((err=snd_card_next(&card)) < 0)
316 ERR("Failed to find a card: %s\n", snd_strerror(err));
317 ConfigValueStr("alsa", prefix_name(stream), &main_prefix);
318 while(card >= 0)
320 const char *card_prefix = main_prefix;
321 const char *cardname, *cardid;
322 char name[256];
324 snprintf(name, sizeof(name), "hw:%d", card);
325 if((err = snd_ctl_open(&handle, name, 0)) < 0)
327 ERR("control open (hw:%d): %s\n", card, snd_strerror(err));
328 goto next_card;
330 if((err = snd_ctl_card_info(handle, info)) < 0)
332 ERR("control hardware info (hw:%d): %s\n", card, snd_strerror(err));
333 snd_ctl_close(handle);
334 goto next_card;
337 cardname = snd_ctl_card_info_get_name(info);
338 cardid = snd_ctl_card_info_get_id(info);
340 snprintf(name, sizeof(name), "%s-%s", prefix_name(stream), cardid);
341 ConfigValueStr("alsa", name, &card_prefix);
343 dev = -1;
344 while(1)
346 const char *devname;
347 void *temp;
349 if(snd_ctl_pcm_next_device(handle, &dev) < 0)
350 ERR("snd_ctl_pcm_next_device failed\n");
351 if(dev < 0)
352 break;
354 snd_pcm_info_set_device(pcminfo, dev);
355 snd_pcm_info_set_subdevice(pcminfo, 0);
356 snd_pcm_info_set_stream(pcminfo, stream);
357 if((err = snd_ctl_pcm_info(handle, pcminfo)) < 0) {
358 if(err != -ENOENT)
359 ERR("control digital audio info (hw:%d): %s\n", card, snd_strerror(err));
360 continue;
363 temp = realloc(DevList, sizeof(DevMap) * (idx+1));
364 if(temp)
366 const char *device_prefix = card_prefix;
367 char device[128];
369 DevList = temp;
370 devname = snd_pcm_info_get_name(pcminfo);
372 snprintf(name, sizeof(name), "%s-%s-%d", prefix_name(stream), cardid, dev);
373 ConfigValueStr("alsa", name, &device_prefix);
375 snprintf(name, sizeof(name), "%s, %s (CARD=%s,DEV=%d)",
376 cardname, devname, cardid, dev);
377 snprintf(device, sizeof(device), "%sCARD=%s,DEV=%d",
378 device_prefix, cardid, dev);
380 TRACE("Got device \"%s\", \"%s\"\n", name, device);
381 DevList[idx].name = strdup(name);
382 DevList[idx].device = strdup(device);
383 idx++;
386 snd_ctl_close(handle);
387 next_card:
388 if(snd_card_next(&card) < 0) {
389 ERR("snd_card_next failed\n");
390 break;
394 snd_pcm_info_free(pcminfo);
395 snd_ctl_card_info_free(info);
397 *count = idx;
398 return DevList;
402 static int verify_state(snd_pcm_t *handle)
404 snd_pcm_state_t state = snd_pcm_state(handle);
405 int err;
407 switch(state)
409 case SND_PCM_STATE_OPEN:
410 case SND_PCM_STATE_SETUP:
411 case SND_PCM_STATE_PREPARED:
412 case SND_PCM_STATE_RUNNING:
413 case SND_PCM_STATE_DRAINING:
414 case SND_PCM_STATE_PAUSED:
415 /* All Okay */
416 break;
418 case SND_PCM_STATE_XRUN:
419 if((err=snd_pcm_recover(handle, -EPIPE, 1)) < 0)
420 return err;
421 break;
422 case SND_PCM_STATE_SUSPENDED:
423 if((err=snd_pcm_recover(handle, -ESTRPIPE, 1)) < 0)
424 return err;
425 break;
426 case SND_PCM_STATE_DISCONNECTED:
427 return -ENODEV;
430 return state;
434 static ALuint ALSAProc(ALvoid *ptr)
436 ALCdevice *pDevice = (ALCdevice*)ptr;
437 alsa_data *data = (alsa_data*)pDevice->ExtraData;
438 const snd_pcm_channel_area_t *areas = NULL;
439 snd_pcm_uframes_t update_size, num_updates;
440 snd_pcm_sframes_t avail, commitres;
441 snd_pcm_uframes_t offset, frames;
442 char *WritePtr;
443 int err;
445 SetRTPriority();
447 update_size = pDevice->UpdateSize;
448 num_updates = pDevice->NumUpdates;
449 while(!data->killNow)
451 int state = verify_state(data->pcmHandle);
452 if(state < 0)
454 ERR("Invalid state detected: %s\n", snd_strerror(state));
455 aluHandleDisconnect(pDevice);
456 break;
459 avail = snd_pcm_avail_update(data->pcmHandle);
460 if(avail < 0)
462 ERR("available update failed: %s\n", snd_strerror(avail));
463 continue;
466 if((snd_pcm_uframes_t)avail > update_size*(num_updates+1))
468 WARN("available samples exceeds the buffer size\n");
469 snd_pcm_reset(data->pcmHandle);
470 continue;
473 // make sure there's frames to process
474 if((snd_pcm_uframes_t)avail < update_size)
476 if(state != SND_PCM_STATE_RUNNING)
478 err = snd_pcm_start(data->pcmHandle);
479 if(err < 0)
481 ERR("start failed: %s\n", snd_strerror(err));
482 continue;
485 if(snd_pcm_wait(data->pcmHandle, 1000) == 0)
486 ERR("Wait timeout... buffer size too low?\n");
487 continue;
489 avail -= avail%update_size;
491 // it is possible that contiguous areas are smaller, thus we use a loop
492 while(avail > 0)
494 frames = avail;
496 err = snd_pcm_mmap_begin(data->pcmHandle, &areas, &offset, &frames);
497 if(err < 0)
499 ERR("mmap begin error: %s\n", snd_strerror(err));
500 break;
503 WritePtr = (char*)areas->addr + (offset * areas->step / 8);
504 aluMixData(pDevice, WritePtr, frames);
506 commitres = snd_pcm_mmap_commit(data->pcmHandle, offset, frames);
507 if(commitres < 0 || (commitres-frames) != 0)
509 ERR("mmap commit error: %s\n",
510 snd_strerror(commitres >= 0 ? -EPIPE : commitres));
511 break;
514 avail -= frames;
518 return 0;
521 static ALuint ALSANoMMapProc(ALvoid *ptr)
523 ALCdevice *pDevice = (ALCdevice*)ptr;
524 alsa_data *data = (alsa_data*)pDevice->ExtraData;
525 snd_pcm_sframes_t avail;
526 char *WritePtr;
528 SetRTPriority();
530 while(!data->killNow)
532 int state = verify_state(data->pcmHandle);
533 if(state < 0)
535 ERR("Invalid state detected: %s\n", snd_strerror(state));
536 aluHandleDisconnect(pDevice);
537 break;
540 WritePtr = data->buffer;
541 avail = data->size / snd_pcm_frames_to_bytes(data->pcmHandle, 1);
542 aluMixData(pDevice, WritePtr, avail);
544 while(avail > 0)
546 int ret = snd_pcm_writei(data->pcmHandle, WritePtr, avail);
547 switch (ret)
549 case -EAGAIN:
550 continue;
551 case -ESTRPIPE:
552 case -EPIPE:
553 case -EINTR:
554 ret = snd_pcm_recover(data->pcmHandle, ret, 1);
555 if(ret < 0)
556 avail = 0;
557 break;
558 default:
559 if (ret >= 0)
561 WritePtr += snd_pcm_frames_to_bytes(data->pcmHandle, ret);
562 avail -= ret;
564 break;
566 if (ret < 0)
568 ret = snd_pcm_prepare(data->pcmHandle);
569 if(ret < 0)
570 break;
575 return 0;
578 static ALCenum alsa_open_playback(ALCdevice *device, const ALCchar *deviceName)
580 const char *driver = NULL;
581 alsa_data *data;
582 int err;
584 if(!allDevNameMap)
585 allDevNameMap = probe_devices(SND_PCM_STREAM_PLAYBACK, &numDevNames);
587 if(!deviceName && numDevNames > 0)
589 deviceName = allDevNameMap[0].name;
590 driver = allDevNameMap[0].device;
592 else
594 size_t idx;
596 for(idx = 0;idx < numDevNames;idx++)
598 if(strcmp(deviceName, allDevNameMap[idx].name) == 0)
600 driver = allDevNameMap[idx].device;
601 break;
604 if(idx == numDevNames)
605 return ALC_INVALID_VALUE;
608 data = (alsa_data*)calloc(1, sizeof(alsa_data));
610 err = snd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
611 if(err >= 0)
613 err = snd_pcm_nonblock(data->pcmHandle, 0);
614 if(err < 0) snd_pcm_close(data->pcmHandle);
616 if(err < 0)
618 free(data);
619 ERR("Could not open playback device '%s': %s\n", driver, snd_strerror(err));
620 return ALC_OUT_OF_MEMORY;
623 device->szDeviceName = strdup(deviceName);
624 device->ExtraData = data;
625 return ALC_NO_ERROR;
628 static void alsa_close_playback(ALCdevice *device)
630 alsa_data *data = (alsa_data*)device->ExtraData;
632 snd_pcm_close(data->pcmHandle);
633 free(data);
634 device->ExtraData = NULL;
637 static ALCboolean alsa_reset_playback(ALCdevice *device)
639 alsa_data *data = (alsa_data*)device->ExtraData;
640 snd_pcm_uframes_t periodSizeInFrames;
641 unsigned int periodLen, bufferLen;
642 snd_pcm_sw_params_t *sp = NULL;
643 snd_pcm_hw_params_t *hp = NULL;
644 snd_pcm_access_t access;
645 snd_pcm_format_t format;
646 unsigned int periods;
647 unsigned int rate;
648 const char *funcerr;
649 int allowmmap;
650 int err;
653 format = -1;
654 switch(device->FmtType)
656 case DevFmtByte:
657 format = SND_PCM_FORMAT_S8;
658 break;
659 case DevFmtUByte:
660 format = SND_PCM_FORMAT_U8;
661 break;
662 case DevFmtShort:
663 format = SND_PCM_FORMAT_S16;
664 break;
665 case DevFmtUShort:
666 format = SND_PCM_FORMAT_U16;
667 break;
668 case DevFmtInt:
669 format = SND_PCM_FORMAT_S32;
670 break;
671 case DevFmtUInt:
672 format = SND_PCM_FORMAT_U32;
673 break;
674 case DevFmtFloat:
675 format = SND_PCM_FORMAT_FLOAT;
676 break;
679 allowmmap = GetConfigValueBool("alsa", "mmap", 1);
680 periods = device->NumUpdates;
681 periodLen = (ALuint64)device->UpdateSize * 1000000 / device->Frequency;
682 bufferLen = periodLen * periods;
683 rate = device->Frequency;
685 snd_pcm_hw_params_malloc(&hp);
686 #define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error
687 CHECK(snd_pcm_hw_params_any(data->pcmHandle, hp));
688 /* set interleaved access */
689 if(!allowmmap || snd_pcm_hw_params_set_access(data->pcmHandle, hp, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0)
691 if(periods > 2)
693 periods--;
694 bufferLen = periodLen * periods;
696 CHECK(snd_pcm_hw_params_set_access(data->pcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED));
698 /* test and set format (implicitly sets sample bits) */
699 if(snd_pcm_hw_params_test_format(data->pcmHandle, hp, format) < 0)
701 static const struct {
702 snd_pcm_format_t format;
703 enum DevFmtType fmttype;
704 } formatlist[] = {
705 { SND_PCM_FORMAT_FLOAT, DevFmtFloat },
706 { SND_PCM_FORMAT_S32, DevFmtInt },
707 { SND_PCM_FORMAT_U32, DevFmtUInt },
708 { SND_PCM_FORMAT_S16, DevFmtShort },
709 { SND_PCM_FORMAT_U16, DevFmtUShort },
710 { SND_PCM_FORMAT_S8, DevFmtByte },
711 { SND_PCM_FORMAT_U8, DevFmtUByte },
713 size_t k;
715 for(k = 0;k < COUNTOF(formatlist);k++)
717 format = formatlist[k].format;
718 if(snd_pcm_hw_params_test_format(data->pcmHandle, hp, format) >= 0)
720 device->FmtType = formatlist[k].fmttype;
721 break;
725 CHECK(snd_pcm_hw_params_set_format(data->pcmHandle, hp, format));
726 /* test and set channels (implicitly sets frame bits) */
727 if(snd_pcm_hw_params_test_channels(data->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans)) < 0)
729 static const enum DevFmtChannels channellist[] = {
730 DevFmtStereo,
731 DevFmtQuad,
732 DevFmtX51,
733 DevFmtX71,
734 DevFmtMono,
736 size_t k;
738 for(k = 0;k < COUNTOF(channellist);k++)
740 if(snd_pcm_hw_params_test_channels(data->pcmHandle, hp, ChannelsFromDevFmt(channellist[k])) >= 0)
742 device->FmtChans = channellist[k];
743 break;
747 CHECK(snd_pcm_hw_params_set_channels(data->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans)));
748 /* set rate (implicitly constrains period/buffer parameters) */
749 if(snd_pcm_hw_params_set_rate_resample(data->pcmHandle, hp, 0) < 0)
750 ERR("Failed to disable ALSA resampler\n");
751 CHECK(snd_pcm_hw_params_set_rate_near(data->pcmHandle, hp, &rate, NULL));
752 /* set buffer time (implicitly constrains period/buffer parameters) */
753 CHECK(snd_pcm_hw_params_set_buffer_time_near(data->pcmHandle, hp, &bufferLen, NULL));
754 /* set period time (implicitly sets buffer size/bytes/time and period size/bytes) */
755 CHECK(snd_pcm_hw_params_set_period_time_near(data->pcmHandle, hp, &periodLen, NULL));
756 /* install and prepare hardware configuration */
757 CHECK(snd_pcm_hw_params(data->pcmHandle, hp));
758 /* retrieve configuration info */
759 CHECK(snd_pcm_hw_params_get_access(hp, &access));
760 CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, NULL));
761 CHECK(snd_pcm_hw_params_get_periods(hp, &periods, NULL));
763 snd_pcm_hw_params_free(hp);
764 hp = NULL;
765 snd_pcm_sw_params_malloc(&sp);
767 CHECK(snd_pcm_sw_params_current(data->pcmHandle, sp));
768 CHECK(snd_pcm_sw_params_set_avail_min(data->pcmHandle, sp, periodSizeInFrames));
769 CHECK(snd_pcm_sw_params_set_stop_threshold(data->pcmHandle, sp, periodSizeInFrames*periods));
770 CHECK(snd_pcm_sw_params(data->pcmHandle, sp));
771 #undef CHECK
772 snd_pcm_sw_params_free(sp);
773 sp = NULL;
775 device->Frequency = rate;
776 SetDefaultChannelOrder(device);
778 data->size = snd_pcm_frames_to_bytes(data->pcmHandle, periodSizeInFrames);
779 if(access == SND_PCM_ACCESS_RW_INTERLEAVED)
781 /* Increase periods by one, since the temp buffer counts as an extra
782 * period */
783 periods++;
784 data->buffer = malloc(data->size);
785 if(!data->buffer)
787 ERR("buffer malloc failed\n");
788 return ALC_FALSE;
790 device->UpdateSize = periodSizeInFrames;
791 device->NumUpdates = periods;
792 data->thread = StartThread(ALSANoMMapProc, device);
794 else
796 err = snd_pcm_prepare(data->pcmHandle);
797 if(err < 0)
799 ERR("snd_pcm_prepare(data->pcmHandle) failed: %s\n", snd_strerror(err));
800 return ALC_FALSE;
802 device->UpdateSize = periodSizeInFrames;
803 device->NumUpdates = periods;
804 data->thread = StartThread(ALSAProc, device);
806 if(data->thread == NULL)
808 ERR("Could not create playback thread\n");
809 free(data->buffer);
810 data->buffer = NULL;
811 return ALC_FALSE;
814 return ALC_TRUE;
816 error:
817 ERR("%s failed: %s\n", funcerr, snd_strerror(err));
818 if(hp) snd_pcm_hw_params_free(hp);
819 if(sp) snd_pcm_sw_params_free(sp);
820 return ALC_FALSE;
823 static void alsa_stop_playback(ALCdevice *device)
825 alsa_data *data = (alsa_data*)device->ExtraData;
827 if(data->thread)
829 data->killNow = 1;
830 StopThread(data->thread);
831 data->thread = NULL;
833 data->killNow = 0;
834 free(data->buffer);
835 data->buffer = NULL;
839 static ALCenum alsa_open_capture(ALCdevice *pDevice, const ALCchar *deviceName)
841 const char *driver = NULL;
842 snd_pcm_hw_params_t *hp;
843 snd_pcm_uframes_t bufferSizeInFrames;
844 snd_pcm_uframes_t periodSizeInFrames;
845 ALboolean needring = AL_FALSE;
846 snd_pcm_format_t format;
847 const char *funcerr;
848 alsa_data *data;
849 int err;
851 if(!allCaptureDevNameMap)
852 allCaptureDevNameMap = probe_devices(SND_PCM_STREAM_CAPTURE, &numCaptureDevNames);
854 if(!deviceName && numCaptureDevNames > 0)
856 deviceName = allCaptureDevNameMap[0].name;
857 driver = allCaptureDevNameMap[0].device;
859 else
861 size_t idx;
863 for(idx = 0;idx < numCaptureDevNames;idx++)
865 if(strcmp(deviceName, allCaptureDevNameMap[idx].name) == 0)
867 driver = allCaptureDevNameMap[idx].device;
868 break;
871 if(idx == numCaptureDevNames)
872 return ALC_INVALID_VALUE;
875 data = (alsa_data*)calloc(1, sizeof(alsa_data));
877 err = snd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
878 if(err < 0)
880 ERR("Could not open capture device '%s': %s\n", driver, snd_strerror(err));
881 free(data);
882 return ALC_INVALID_VALUE;
885 format = -1;
886 switch(pDevice->FmtType)
888 case DevFmtByte:
889 format = SND_PCM_FORMAT_S8;
890 break;
891 case DevFmtUByte:
892 format = SND_PCM_FORMAT_U8;
893 break;
894 case DevFmtShort:
895 format = SND_PCM_FORMAT_S16;
896 break;
897 case DevFmtUShort:
898 format = SND_PCM_FORMAT_U16;
899 break;
900 case DevFmtInt:
901 format = SND_PCM_FORMAT_S32;
902 break;
903 case DevFmtUInt:
904 format = SND_PCM_FORMAT_U32;
905 break;
906 case DevFmtFloat:
907 format = SND_PCM_FORMAT_FLOAT;
908 break;
911 funcerr = NULL;
912 bufferSizeInFrames = maxu(pDevice->UpdateSize*pDevice->NumUpdates,
913 100*pDevice->Frequency/1000);
914 periodSizeInFrames = minu(bufferSizeInFrames, 25*pDevice->Frequency/1000);
916 snd_pcm_hw_params_malloc(&hp);
917 #define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error
918 CHECK(snd_pcm_hw_params_any(data->pcmHandle, hp));
919 /* set interleaved access */
920 CHECK(snd_pcm_hw_params_set_access(data->pcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED));
921 /* set format (implicitly sets sample bits) */
922 CHECK(snd_pcm_hw_params_set_format(data->pcmHandle, hp, format));
923 /* set channels (implicitly sets frame bits) */
924 CHECK(snd_pcm_hw_params_set_channels(data->pcmHandle, hp, ChannelsFromDevFmt(pDevice->FmtChans)));
925 /* set rate (implicitly constrains period/buffer parameters) */
926 CHECK(snd_pcm_hw_params_set_rate(data->pcmHandle, hp, pDevice->Frequency, 0));
927 /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */
928 if(snd_pcm_hw_params_set_buffer_size_min(data->pcmHandle, hp, &bufferSizeInFrames) < 0)
930 TRACE("Buffer too large, using intermediate ring buffer\n");
931 needring = AL_TRUE;
932 CHECK(snd_pcm_hw_params_set_buffer_size_near(data->pcmHandle, hp, &bufferSizeInFrames));
934 /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */
935 CHECK(snd_pcm_hw_params_set_period_size_near(data->pcmHandle, hp, &periodSizeInFrames, NULL));
936 /* install and prepare hardware configuration */
937 CHECK(snd_pcm_hw_params(data->pcmHandle, hp));
938 /* retrieve configuration info */
939 CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, NULL));
940 #undef CHECK
941 snd_pcm_hw_params_free(hp);
942 hp = NULL;
944 if(needring)
946 data->ring = CreateRingBuffer(FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType),
947 pDevice->UpdateSize*pDevice->NumUpdates);
948 if(!data->ring)
950 ERR("ring buffer create failed\n");
951 goto error2;
954 data->size = snd_pcm_frames_to_bytes(data->pcmHandle, periodSizeInFrames);
955 data->buffer = malloc(data->size);
956 if(!data->buffer)
958 ERR("buffer malloc failed\n");
959 goto error2;
963 pDevice->szDeviceName = strdup(deviceName);
965 pDevice->ExtraData = data;
966 return ALC_NO_ERROR;
968 error:
969 ERR("%s failed: %s\n", funcerr, snd_strerror(err));
970 if(hp) snd_pcm_hw_params_free(hp);
972 error2:
973 free(data->buffer);
974 DestroyRingBuffer(data->ring);
975 snd_pcm_close(data->pcmHandle);
976 free(data);
978 pDevice->ExtraData = NULL;
979 return ALC_INVALID_VALUE;
982 static void alsa_close_capture(ALCdevice *pDevice)
984 alsa_data *data = (alsa_data*)pDevice->ExtraData;
986 snd_pcm_close(data->pcmHandle);
987 DestroyRingBuffer(data->ring);
989 free(data->buffer);
990 free(data);
991 pDevice->ExtraData = NULL;
994 static void alsa_start_capture(ALCdevice *Device)
996 alsa_data *data = (alsa_data*)Device->ExtraData;
997 int err;
999 err = snd_pcm_start(data->pcmHandle);
1000 if(err < 0)
1002 ERR("start failed: %s\n", snd_strerror(err));
1003 aluHandleDisconnect(Device);
1005 else
1006 data->doCapture = AL_TRUE;
1009 static ALCenum alsa_capture_samples(ALCdevice *Device, ALCvoid *Buffer, ALCuint Samples)
1011 alsa_data *data = (alsa_data*)Device->ExtraData;
1013 if(data->ring)
1015 ReadRingBuffer(data->ring, Buffer, Samples);
1016 return ALC_NO_ERROR;
1019 data->last_avail -= Samples;
1020 while(Device->Connected && Samples > 0)
1022 snd_pcm_sframes_t amt = 0;
1024 if(data->size > 0)
1026 /* First get any data stored from the last stop */
1027 amt = snd_pcm_bytes_to_frames(data->pcmHandle, data->size);
1028 if((snd_pcm_uframes_t)amt > Samples) amt = Samples;
1030 amt = snd_pcm_frames_to_bytes(data->pcmHandle, amt);
1031 memmove(Buffer, data->buffer, amt);
1033 if(data->size > amt)
1035 memmove(data->buffer, data->buffer+amt, data->size - amt);
1036 data->size -= amt;
1038 else
1040 free(data->buffer);
1041 data->buffer = NULL;
1042 data->size = 0;
1044 amt = snd_pcm_bytes_to_frames(data->pcmHandle, amt);
1046 else if(data->doCapture)
1047 amt = snd_pcm_readi(data->pcmHandle, Buffer, Samples);
1048 if(amt < 0)
1050 ERR("read error: %s\n", snd_strerror(amt));
1052 if(amt == -EAGAIN)
1053 continue;
1054 if((amt=snd_pcm_recover(data->pcmHandle, amt, 1)) >= 0)
1056 if(data->doCapture)
1057 amt = snd_pcm_start(data->pcmHandle);
1058 if(amt >= 0)
1059 amt = snd_pcm_avail_update(data->pcmHandle);
1061 if(amt < 0)
1063 ERR("restore error: %s\n", snd_strerror(amt));
1064 aluHandleDisconnect(Device);
1065 break;
1067 /* If the amount available is less than what's asked, we lost it
1068 * during recovery. So just give silence instead. */
1069 if((snd_pcm_uframes_t)amt < Samples)
1070 break;
1071 continue;
1074 Buffer = (ALbyte*)Buffer + amt;
1075 Samples -= amt;
1077 if(Samples > 0)
1078 memset(Buffer, ((Device->FmtType == DevFmtUByte) ? 0x80 : 0),
1079 snd_pcm_frames_to_bytes(data->pcmHandle, Samples));
1081 return ALC_NO_ERROR;
1084 static ALCuint alsa_available_samples(ALCdevice *Device)
1086 alsa_data *data = (alsa_data*)Device->ExtraData;
1087 snd_pcm_sframes_t avail = 0;
1089 if(Device->Connected && data->doCapture)
1090 avail = snd_pcm_avail_update(data->pcmHandle);
1091 if(avail < 0)
1093 ERR("avail update failed: %s\n", snd_strerror(avail));
1095 if((avail=snd_pcm_recover(data->pcmHandle, avail, 1)) >= 0)
1097 if(data->doCapture)
1098 avail = snd_pcm_start(data->pcmHandle);
1099 if(avail >= 0)
1100 avail = snd_pcm_avail_update(data->pcmHandle);
1102 if(avail < 0)
1104 ERR("restore error: %s\n", snd_strerror(avail));
1105 aluHandleDisconnect(Device);
1109 if(!data->ring)
1111 if(avail < 0) avail = 0;
1112 avail += snd_pcm_bytes_to_frames(data->pcmHandle, data->size);
1113 if(avail > data->last_avail) data->last_avail = avail;
1114 return data->last_avail;
1117 while(avail > 0)
1119 snd_pcm_sframes_t amt;
1121 amt = snd_pcm_bytes_to_frames(data->pcmHandle, data->size);
1122 if(avail < amt) amt = avail;
1124 amt = snd_pcm_readi(data->pcmHandle, data->buffer, amt);
1125 if(amt < 0)
1127 ERR("read error: %s\n", snd_strerror(amt));
1129 if(amt == -EAGAIN)
1130 continue;
1131 if((amt=snd_pcm_recover(data->pcmHandle, amt, 1)) >= 0)
1133 if(data->doCapture)
1134 amt = snd_pcm_start(data->pcmHandle);
1135 if(amt >= 0)
1136 amt = snd_pcm_avail_update(data->pcmHandle);
1138 if(amt < 0)
1140 ERR("restore error: %s\n", snd_strerror(amt));
1141 aluHandleDisconnect(Device);
1142 break;
1144 avail = amt;
1145 continue;
1148 WriteRingBuffer(data->ring, data->buffer, amt);
1149 avail -= amt;
1152 return RingBufferSize(data->ring);
1155 static void alsa_stop_capture(ALCdevice *Device)
1157 alsa_data *data = (alsa_data*)Device->ExtraData;
1158 ALCuint avail;
1159 int err;
1161 /* OpenAL requires access to unread audio after stopping, but ALSA's
1162 * snd_pcm_drain is unreliable and snd_pcm_drop drops it. Capture what's
1163 * available now so it'll be available later after the drop. */
1164 avail = alsa_available_samples(Device);
1165 if(!data->ring && avail > 0)
1167 /* The ring buffer implicitly captures when checking availability.
1168 * Direct access needs to explicitly capture it into temp storage. */
1169 ALsizei size;
1170 void *ptr;
1172 size = snd_pcm_frames_to_bytes(data->pcmHandle, avail);
1173 ptr = realloc(data->buffer, size);
1174 if(ptr)
1176 data->buffer = ptr;
1177 alsa_capture_samples(Device, data->buffer, avail);
1178 data->size = size;
1181 err = snd_pcm_drop(data->pcmHandle);
1182 if(err < 0)
1183 ERR("drop failed: %s\n", snd_strerror(err));
1184 data->doCapture = AL_FALSE;
1188 static const BackendFuncs alsa_funcs = {
1189 alsa_open_playback,
1190 alsa_close_playback,
1191 alsa_reset_playback,
1192 alsa_stop_playback,
1193 alsa_open_capture,
1194 alsa_close_capture,
1195 alsa_start_capture,
1196 alsa_stop_capture,
1197 alsa_capture_samples,
1198 alsa_available_samples
1201 ALCboolean alc_alsa_init(BackendFuncs *func_list)
1203 if(!alsa_load())
1204 return ALC_FALSE;
1205 *func_list = alsa_funcs;
1206 return ALC_TRUE;
1209 void alc_alsa_deinit(void)
1211 ALuint i;
1213 for(i = 0;i < numDevNames;++i)
1214 free(allDevNameMap[i].device);
1215 free(allDevNameMap);
1216 allDevNameMap = NULL;
1217 numDevNames = 0;
1219 for(i = 0;i < numCaptureDevNames;++i)
1220 free(allCaptureDevNameMap[i].device);
1221 free(allCaptureDevNameMap);
1222 allCaptureDevNameMap = NULL;
1223 numCaptureDevNames = 0;
1225 #ifdef HAVE_DYNLOAD
1226 if(alsa_handle)
1227 CloseLib(alsa_handle);
1228 alsa_handle = NULL;
1229 #endif
1232 void alc_alsa_probe(enum DevProbe type)
1234 ALuint i;
1236 switch(type)
1238 case ALL_DEVICE_PROBE:
1239 for(i = 0;i < numDevNames;++i)
1240 free(allDevNameMap[i].device);
1242 free(allDevNameMap);
1243 allDevNameMap = probe_devices(SND_PCM_STREAM_PLAYBACK, &numDevNames);
1245 for(i = 0;i < numDevNames;++i)
1246 AppendAllDeviceList(allDevNameMap[i].name);
1247 break;
1249 case CAPTURE_DEVICE_PROBE:
1250 for(i = 0;i < numCaptureDevNames;++i)
1251 free(allCaptureDevNameMap[i].device);
1253 free(allCaptureDevNameMap);
1254 allCaptureDevNameMap = probe_devices(SND_PCM_STREAM_CAPTURE, &numCaptureDevNames);
1256 for(i = 0;i < numCaptureDevNames;++i)
1257 AppendCaptureDeviceList(allCaptureDevNameMap[i].name);
1258 break;