Store the ambisonic order separate from the channel enum
[openal-soft.git] / Alc / backends / alsa.c
blob40b687790bb65c8c72c16330ee1e3ac61032f3cd
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.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include "config.h"
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <memory.h>
27 #include "alMain.h"
28 #include "alu.h"
29 #include "threads.h"
30 #include "compat.h"
32 #include "backends/base.h"
34 #include <alsa/asoundlib.h>
37 static const ALCchar alsaDevice[] = "ALSA Default";
40 #ifdef HAVE_DYNLOAD
41 #define ALSA_FUNCS(MAGIC) \
42 MAGIC(snd_strerror); \
43 MAGIC(snd_pcm_open); \
44 MAGIC(snd_pcm_close); \
45 MAGIC(snd_pcm_nonblock); \
46 MAGIC(snd_pcm_frames_to_bytes); \
47 MAGIC(snd_pcm_bytes_to_frames); \
48 MAGIC(snd_pcm_hw_params_malloc); \
49 MAGIC(snd_pcm_hw_params_free); \
50 MAGIC(snd_pcm_hw_params_any); \
51 MAGIC(snd_pcm_hw_params_current); \
52 MAGIC(snd_pcm_hw_params_set_access); \
53 MAGIC(snd_pcm_hw_params_set_format); \
54 MAGIC(snd_pcm_hw_params_set_channels); \
55 MAGIC(snd_pcm_hw_params_set_periods_near); \
56 MAGIC(snd_pcm_hw_params_set_rate_near); \
57 MAGIC(snd_pcm_hw_params_set_rate); \
58 MAGIC(snd_pcm_hw_params_set_rate_resample); \
59 MAGIC(snd_pcm_hw_params_set_buffer_time_near); \
60 MAGIC(snd_pcm_hw_params_set_period_time_near); \
61 MAGIC(snd_pcm_hw_params_set_buffer_size_near); \
62 MAGIC(snd_pcm_hw_params_set_period_size_near); \
63 MAGIC(snd_pcm_hw_params_set_buffer_size_min); \
64 MAGIC(snd_pcm_hw_params_get_buffer_time_min); \
65 MAGIC(snd_pcm_hw_params_get_buffer_time_max); \
66 MAGIC(snd_pcm_hw_params_get_period_time_min); \
67 MAGIC(snd_pcm_hw_params_get_period_time_max); \
68 MAGIC(snd_pcm_hw_params_get_buffer_size); \
69 MAGIC(snd_pcm_hw_params_get_period_size); \
70 MAGIC(snd_pcm_hw_params_get_access); \
71 MAGIC(snd_pcm_hw_params_get_periods); \
72 MAGIC(snd_pcm_hw_params_test_format); \
73 MAGIC(snd_pcm_hw_params_test_channels); \
74 MAGIC(snd_pcm_hw_params); \
75 MAGIC(snd_pcm_sw_params_malloc); \
76 MAGIC(snd_pcm_sw_params_current); \
77 MAGIC(snd_pcm_sw_params_set_avail_min); \
78 MAGIC(snd_pcm_sw_params_set_stop_threshold); \
79 MAGIC(snd_pcm_sw_params); \
80 MAGIC(snd_pcm_sw_params_free); \
81 MAGIC(snd_pcm_prepare); \
82 MAGIC(snd_pcm_start); \
83 MAGIC(snd_pcm_resume); \
84 MAGIC(snd_pcm_reset); \
85 MAGIC(snd_pcm_wait); \
86 MAGIC(snd_pcm_delay); \
87 MAGIC(snd_pcm_state); \
88 MAGIC(snd_pcm_avail_update); \
89 MAGIC(snd_pcm_areas_silence); \
90 MAGIC(snd_pcm_mmap_begin); \
91 MAGIC(snd_pcm_mmap_commit); \
92 MAGIC(snd_pcm_readi); \
93 MAGIC(snd_pcm_writei); \
94 MAGIC(snd_pcm_drain); \
95 MAGIC(snd_pcm_drop); \
96 MAGIC(snd_pcm_recover); \
97 MAGIC(snd_pcm_info_malloc); \
98 MAGIC(snd_pcm_info_free); \
99 MAGIC(snd_pcm_info_set_device); \
100 MAGIC(snd_pcm_info_set_subdevice); \
101 MAGIC(snd_pcm_info_set_stream); \
102 MAGIC(snd_pcm_info_get_name); \
103 MAGIC(snd_ctl_pcm_next_device); \
104 MAGIC(snd_ctl_pcm_info); \
105 MAGIC(snd_ctl_open); \
106 MAGIC(snd_ctl_close); \
107 MAGIC(snd_ctl_card_info_malloc); \
108 MAGIC(snd_ctl_card_info_free); \
109 MAGIC(snd_ctl_card_info); \
110 MAGIC(snd_ctl_card_info_get_name); \
111 MAGIC(snd_ctl_card_info_get_id); \
112 MAGIC(snd_card_next); \
113 MAGIC(snd_config_update_free_global)
115 static void *alsa_handle;
116 #define MAKE_FUNC(f) static __typeof(f) * p##f
117 ALSA_FUNCS(MAKE_FUNC);
118 #undef MAKE_FUNC
120 #define snd_strerror psnd_strerror
121 #define snd_pcm_open psnd_pcm_open
122 #define snd_pcm_close psnd_pcm_close
123 #define snd_pcm_nonblock psnd_pcm_nonblock
124 #define snd_pcm_frames_to_bytes psnd_pcm_frames_to_bytes
125 #define snd_pcm_bytes_to_frames psnd_pcm_bytes_to_frames
126 #define snd_pcm_hw_params_malloc psnd_pcm_hw_params_malloc
127 #define snd_pcm_hw_params_free psnd_pcm_hw_params_free
128 #define snd_pcm_hw_params_any psnd_pcm_hw_params_any
129 #define snd_pcm_hw_params_current psnd_pcm_hw_params_current
130 #define snd_pcm_hw_params_set_access psnd_pcm_hw_params_set_access
131 #define snd_pcm_hw_params_set_format psnd_pcm_hw_params_set_format
132 #define snd_pcm_hw_params_set_channels psnd_pcm_hw_params_set_channels
133 #define snd_pcm_hw_params_set_periods_near psnd_pcm_hw_params_set_periods_near
134 #define snd_pcm_hw_params_set_rate_near psnd_pcm_hw_params_set_rate_near
135 #define snd_pcm_hw_params_set_rate psnd_pcm_hw_params_set_rate
136 #define snd_pcm_hw_params_set_rate_resample psnd_pcm_hw_params_set_rate_resample
137 #define snd_pcm_hw_params_set_buffer_time_near psnd_pcm_hw_params_set_buffer_time_near
138 #define snd_pcm_hw_params_set_period_time_near psnd_pcm_hw_params_set_period_time_near
139 #define snd_pcm_hw_params_set_buffer_size_near psnd_pcm_hw_params_set_buffer_size_near
140 #define snd_pcm_hw_params_set_period_size_near psnd_pcm_hw_params_set_period_size_near
141 #define snd_pcm_hw_params_set_buffer_size_min psnd_pcm_hw_params_set_buffer_size_min
142 #define snd_pcm_hw_params_get_buffer_time_min psnd_pcm_hw_params_get_buffer_time_min
143 #define snd_pcm_hw_params_get_buffer_time_max psnd_pcm_hw_params_get_buffer_time_max
144 #define snd_pcm_hw_params_get_period_time_min psnd_pcm_hw_params_get_period_time_min
145 #define snd_pcm_hw_params_get_period_time_max psnd_pcm_hw_params_get_period_time_max
146 #define snd_pcm_hw_params_get_buffer_size psnd_pcm_hw_params_get_buffer_size
147 #define snd_pcm_hw_params_get_period_size psnd_pcm_hw_params_get_period_size
148 #define snd_pcm_hw_params_get_access psnd_pcm_hw_params_get_access
149 #define snd_pcm_hw_params_get_periods psnd_pcm_hw_params_get_periods
150 #define snd_pcm_hw_params_test_format psnd_pcm_hw_params_test_format
151 #define snd_pcm_hw_params_test_channels psnd_pcm_hw_params_test_channels
152 #define snd_pcm_hw_params psnd_pcm_hw_params
153 #define snd_pcm_sw_params_malloc psnd_pcm_sw_params_malloc
154 #define snd_pcm_sw_params_current psnd_pcm_sw_params_current
155 #define snd_pcm_sw_params_set_avail_min psnd_pcm_sw_params_set_avail_min
156 #define snd_pcm_sw_params_set_stop_threshold psnd_pcm_sw_params_set_stop_threshold
157 #define snd_pcm_sw_params psnd_pcm_sw_params
158 #define snd_pcm_sw_params_free psnd_pcm_sw_params_free
159 #define snd_pcm_prepare psnd_pcm_prepare
160 #define snd_pcm_start psnd_pcm_start
161 #define snd_pcm_resume psnd_pcm_resume
162 #define snd_pcm_reset psnd_pcm_reset
163 #define snd_pcm_wait psnd_pcm_wait
164 #define snd_pcm_delay psnd_pcm_delay
165 #define snd_pcm_state psnd_pcm_state
166 #define snd_pcm_avail_update psnd_pcm_avail_update
167 #define snd_pcm_areas_silence psnd_pcm_areas_silence
168 #define snd_pcm_mmap_begin psnd_pcm_mmap_begin
169 #define snd_pcm_mmap_commit psnd_pcm_mmap_commit
170 #define snd_pcm_readi psnd_pcm_readi
171 #define snd_pcm_writei psnd_pcm_writei
172 #define snd_pcm_drain psnd_pcm_drain
173 #define snd_pcm_drop psnd_pcm_drop
174 #define snd_pcm_recover psnd_pcm_recover
175 #define snd_pcm_info_malloc psnd_pcm_info_malloc
176 #define snd_pcm_info_free psnd_pcm_info_free
177 #define snd_pcm_info_set_device psnd_pcm_info_set_device
178 #define snd_pcm_info_set_subdevice psnd_pcm_info_set_subdevice
179 #define snd_pcm_info_set_stream psnd_pcm_info_set_stream
180 #define snd_pcm_info_get_name psnd_pcm_info_get_name
181 #define snd_ctl_pcm_next_device psnd_ctl_pcm_next_device
182 #define snd_ctl_pcm_info psnd_ctl_pcm_info
183 #define snd_ctl_open psnd_ctl_open
184 #define snd_ctl_close psnd_ctl_close
185 #define snd_ctl_card_info_malloc psnd_ctl_card_info_malloc
186 #define snd_ctl_card_info_free psnd_ctl_card_info_free
187 #define snd_ctl_card_info psnd_ctl_card_info
188 #define snd_ctl_card_info_get_name psnd_ctl_card_info_get_name
189 #define snd_ctl_card_info_get_id psnd_ctl_card_info_get_id
190 #define snd_card_next psnd_card_next
191 #define snd_config_update_free_global psnd_config_update_free_global
192 #endif
195 static ALCboolean alsa_load(void)
197 ALCboolean error = ALC_FALSE;
199 #ifdef HAVE_DYNLOAD
200 if(!alsa_handle)
202 al_string missing_funcs = AL_STRING_INIT_STATIC();
204 alsa_handle = LoadLib("libasound.so.2");
205 if(!alsa_handle)
207 WARN("Failed to load %s\n", "libasound.so.2");
208 return ALC_FALSE;
211 error = ALC_FALSE;
212 #define LOAD_FUNC(f) do { \
213 p##f = GetSymbol(alsa_handle, #f); \
214 if(p##f == NULL) { \
215 error = ALC_TRUE; \
216 alstr_append_cstr(&missing_funcs, "\n" #f); \
218 } while(0)
219 ALSA_FUNCS(LOAD_FUNC);
220 #undef LOAD_FUNC
222 if(error)
224 WARN("Missing expected functions:%s\n", alstr_get_cstr(missing_funcs));
225 CloseLib(alsa_handle);
226 alsa_handle = NULL;
228 alstr_reset(&missing_funcs);
230 #endif
232 return !error;
236 typedef struct {
237 al_string name;
238 al_string device_name;
239 } DevMap;
240 TYPEDEF_VECTOR(DevMap, vector_DevMap)
242 static vector_DevMap PlaybackDevices;
243 static vector_DevMap CaptureDevices;
245 static void clear_devlist(vector_DevMap *devlist)
247 #define FREE_DEV(i) do { \
248 AL_STRING_DEINIT((i)->name); \
249 AL_STRING_DEINIT((i)->device_name); \
250 } while(0)
251 VECTOR_FOR_EACH(DevMap, *devlist, FREE_DEV);
252 VECTOR_RESIZE(*devlist, 0, 0);
253 #undef FREE_DEV
257 static const char *prefix_name(snd_pcm_stream_t stream)
259 assert(stream == SND_PCM_STREAM_PLAYBACK || stream == SND_PCM_STREAM_CAPTURE);
260 return (stream==SND_PCM_STREAM_PLAYBACK) ? "device-prefix" : "capture-prefix";
263 static void probe_devices(snd_pcm_stream_t stream, vector_DevMap *DeviceList)
265 const char *main_prefix = "plughw:";
266 snd_ctl_t *handle;
267 snd_ctl_card_info_t *info;
268 snd_pcm_info_t *pcminfo;
269 int card, err, dev;
270 DevMap entry;
272 clear_devlist(DeviceList);
274 snd_ctl_card_info_malloc(&info);
275 snd_pcm_info_malloc(&pcminfo);
277 AL_STRING_INIT(entry.name);
278 AL_STRING_INIT(entry.device_name);
279 alstr_copy_cstr(&entry.name, alsaDevice);
280 alstr_copy_cstr(&entry.device_name, GetConfigValue(NULL, "alsa", (stream==SND_PCM_STREAM_PLAYBACK) ?
281 "device" : "capture", "default"));
282 VECTOR_PUSH_BACK(*DeviceList, entry);
284 card = -1;
285 if((err=snd_card_next(&card)) < 0)
286 ERR("Failed to find a card: %s\n", snd_strerror(err));
287 ConfigValueStr(NULL, "alsa", prefix_name(stream), &main_prefix);
288 while(card >= 0)
290 const char *card_prefix = main_prefix;
291 const char *cardname, *cardid;
292 char name[256];
294 snprintf(name, sizeof(name), "hw:%d", card);
295 if((err = snd_ctl_open(&handle, name, 0)) < 0)
297 ERR("control open (hw:%d): %s\n", card, snd_strerror(err));
298 goto next_card;
300 if((err = snd_ctl_card_info(handle, info)) < 0)
302 ERR("control hardware info (hw:%d): %s\n", card, snd_strerror(err));
303 snd_ctl_close(handle);
304 goto next_card;
307 cardname = snd_ctl_card_info_get_name(info);
308 cardid = snd_ctl_card_info_get_id(info);
310 snprintf(name, sizeof(name), "%s-%s", prefix_name(stream), cardid);
311 ConfigValueStr(NULL, "alsa", name, &card_prefix);
313 dev = -1;
314 while(1)
316 const char *device_prefix = card_prefix;
317 const char *devname;
318 char device[128];
320 if(snd_ctl_pcm_next_device(handle, &dev) < 0)
321 ERR("snd_ctl_pcm_next_device failed\n");
322 if(dev < 0)
323 break;
325 snd_pcm_info_set_device(pcminfo, dev);
326 snd_pcm_info_set_subdevice(pcminfo, 0);
327 snd_pcm_info_set_stream(pcminfo, stream);
328 if((err = snd_ctl_pcm_info(handle, pcminfo)) < 0) {
329 if(err != -ENOENT)
330 ERR("control digital audio info (hw:%d): %s\n", card, snd_strerror(err));
331 continue;
334 devname = snd_pcm_info_get_name(pcminfo);
336 snprintf(name, sizeof(name), "%s-%s-%d", prefix_name(stream), cardid, dev);
337 ConfigValueStr(NULL, "alsa", name, &device_prefix);
339 snprintf(name, sizeof(name), "%s, %s (CARD=%s,DEV=%d)",
340 cardname, devname, cardid, dev);
341 snprintf(device, sizeof(device), "%sCARD=%s,DEV=%d",
342 device_prefix, cardid, dev);
344 TRACE("Got device \"%s\", \"%s\"\n", name, device);
345 AL_STRING_INIT(entry.name);
346 AL_STRING_INIT(entry.device_name);
347 alstr_copy_cstr(&entry.name, name);
348 alstr_copy_cstr(&entry.device_name, device);
349 VECTOR_PUSH_BACK(*DeviceList, entry);
351 snd_ctl_close(handle);
352 next_card:
353 if(snd_card_next(&card) < 0) {
354 ERR("snd_card_next failed\n");
355 break;
359 snd_pcm_info_free(pcminfo);
360 snd_ctl_card_info_free(info);
364 static int verify_state(snd_pcm_t *handle)
366 snd_pcm_state_t state = snd_pcm_state(handle);
367 int err;
369 switch(state)
371 case SND_PCM_STATE_OPEN:
372 case SND_PCM_STATE_SETUP:
373 case SND_PCM_STATE_PREPARED:
374 case SND_PCM_STATE_RUNNING:
375 case SND_PCM_STATE_DRAINING:
376 case SND_PCM_STATE_PAUSED:
377 /* All Okay */
378 break;
380 case SND_PCM_STATE_XRUN:
381 if((err=snd_pcm_recover(handle, -EPIPE, 1)) < 0)
382 return err;
383 break;
384 case SND_PCM_STATE_SUSPENDED:
385 if((err=snd_pcm_recover(handle, -ESTRPIPE, 1)) < 0)
386 return err;
387 break;
388 case SND_PCM_STATE_DISCONNECTED:
389 return -ENODEV;
392 return state;
396 typedef struct ALCplaybackAlsa {
397 DERIVE_FROM_TYPE(ALCbackend);
399 snd_pcm_t *pcmHandle;
401 ALvoid *buffer;
402 ALsizei size;
404 volatile int killNow;
405 althrd_t thread;
406 } ALCplaybackAlsa;
408 static int ALCplaybackAlsa_mixerProc(void *ptr);
409 static int ALCplaybackAlsa_mixerNoMMapProc(void *ptr);
411 static void ALCplaybackAlsa_Construct(ALCplaybackAlsa *self, ALCdevice *device);
412 static DECLARE_FORWARD(ALCplaybackAlsa, ALCbackend, void, Destruct)
413 static ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name);
414 static void ALCplaybackAlsa_close(ALCplaybackAlsa *self);
415 static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self);
416 static ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self);
417 static void ALCplaybackAlsa_stop(ALCplaybackAlsa *self);
418 static DECLARE_FORWARD2(ALCplaybackAlsa, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
419 static DECLARE_FORWARD(ALCplaybackAlsa, ALCbackend, ALCuint, availableSamples)
420 static ClockLatency ALCplaybackAlsa_getClockLatency(ALCplaybackAlsa *self);
421 static DECLARE_FORWARD(ALCplaybackAlsa, ALCbackend, void, lock)
422 static DECLARE_FORWARD(ALCplaybackAlsa, ALCbackend, void, unlock)
423 DECLARE_DEFAULT_ALLOCATORS(ALCplaybackAlsa)
425 DEFINE_ALCBACKEND_VTABLE(ALCplaybackAlsa);
428 static void ALCplaybackAlsa_Construct(ALCplaybackAlsa *self, ALCdevice *device)
430 ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
431 SET_VTABLE2(ALCplaybackAlsa, ALCbackend, self);
435 static int ALCplaybackAlsa_mixerProc(void *ptr)
437 ALCplaybackAlsa *self = (ALCplaybackAlsa*)ptr;
438 ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
439 const snd_pcm_channel_area_t *areas = NULL;
440 snd_pcm_uframes_t update_size, num_updates;
441 snd_pcm_sframes_t avail, commitres;
442 snd_pcm_uframes_t offset, frames;
443 char *WritePtr;
444 int err;
446 SetRTPriority();
447 althrd_setname(althrd_current(), MIXER_THREAD_NAME);
449 update_size = device->UpdateSize;
450 num_updates = device->NumUpdates;
451 while(!self->killNow)
453 int state = verify_state(self->pcmHandle);
454 if(state < 0)
456 ERR("Invalid state detected: %s\n", snd_strerror(state));
457 ALCplaybackAlsa_lock(self);
458 aluHandleDisconnect(device);
459 ALCplaybackAlsa_unlock(self);
460 break;
463 avail = snd_pcm_avail_update(self->pcmHandle);
464 if(avail < 0)
466 ERR("available update failed: %s\n", snd_strerror(avail));
467 continue;
470 if((snd_pcm_uframes_t)avail > update_size*(num_updates+1))
472 WARN("available samples exceeds the buffer size\n");
473 snd_pcm_reset(self->pcmHandle);
474 continue;
477 // make sure there's frames to process
478 if((snd_pcm_uframes_t)avail < update_size)
480 if(state != SND_PCM_STATE_RUNNING)
482 err = snd_pcm_start(self->pcmHandle);
483 if(err < 0)
485 ERR("start failed: %s\n", snd_strerror(err));
486 continue;
489 if(snd_pcm_wait(self->pcmHandle, 1000) == 0)
490 ERR("Wait timeout... buffer size too low?\n");
491 continue;
493 avail -= avail%update_size;
495 // it is possible that contiguous areas are smaller, thus we use a loop
496 ALCplaybackAlsa_lock(self);
497 while(avail > 0)
499 frames = avail;
501 err = snd_pcm_mmap_begin(self->pcmHandle, &areas, &offset, &frames);
502 if(err < 0)
504 ERR("mmap begin error: %s\n", snd_strerror(err));
505 break;
508 WritePtr = (char*)areas->addr + (offset * areas->step / 8);
509 aluMixData(device, WritePtr, frames);
511 commitres = snd_pcm_mmap_commit(self->pcmHandle, offset, frames);
512 if(commitres < 0 || (commitres-frames) != 0)
514 ERR("mmap commit error: %s\n",
515 snd_strerror(commitres >= 0 ? -EPIPE : commitres));
516 break;
519 avail -= frames;
521 ALCplaybackAlsa_unlock(self);
524 return 0;
527 static int ALCplaybackAlsa_mixerNoMMapProc(void *ptr)
529 ALCplaybackAlsa *self = (ALCplaybackAlsa*)ptr;
530 ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
531 snd_pcm_uframes_t update_size, num_updates;
532 snd_pcm_sframes_t avail;
533 char *WritePtr;
534 int err;
536 SetRTPriority();
537 althrd_setname(althrd_current(), MIXER_THREAD_NAME);
539 update_size = device->UpdateSize;
540 num_updates = device->NumUpdates;
541 while(!self->killNow)
543 int state = verify_state(self->pcmHandle);
544 if(state < 0)
546 ERR("Invalid state detected: %s\n", snd_strerror(state));
547 ALCplaybackAlsa_lock(self);
548 aluHandleDisconnect(device);
549 ALCplaybackAlsa_unlock(self);
550 break;
553 avail = snd_pcm_avail_update(self->pcmHandle);
554 if(avail < 0)
556 ERR("available update failed: %s\n", snd_strerror(avail));
557 continue;
560 if((snd_pcm_uframes_t)avail > update_size*num_updates)
562 WARN("available samples exceeds the buffer size\n");
563 snd_pcm_reset(self->pcmHandle);
564 continue;
567 if((snd_pcm_uframes_t)avail < update_size)
569 if(state != SND_PCM_STATE_RUNNING)
571 err = snd_pcm_start(self->pcmHandle);
572 if(err < 0)
574 ERR("start failed: %s\n", snd_strerror(err));
575 continue;
578 if(snd_pcm_wait(self->pcmHandle, 1000) == 0)
579 ERR("Wait timeout... buffer size too low?\n");
580 continue;
583 ALCplaybackAlsa_lock(self);
584 WritePtr = self->buffer;
585 avail = snd_pcm_bytes_to_frames(self->pcmHandle, self->size);
586 aluMixData(device, WritePtr, avail);
588 while(avail > 0)
590 int ret = snd_pcm_writei(self->pcmHandle, WritePtr, avail);
591 switch (ret)
593 case -EAGAIN:
594 continue;
595 #if ESTRPIPE != EPIPE
596 case -ESTRPIPE:
597 #endif
598 case -EPIPE:
599 case -EINTR:
600 ret = snd_pcm_recover(self->pcmHandle, ret, 1);
601 if(ret < 0)
602 avail = 0;
603 break;
604 default:
605 if (ret >= 0)
607 WritePtr += snd_pcm_frames_to_bytes(self->pcmHandle, ret);
608 avail -= ret;
610 break;
612 if (ret < 0)
614 ret = snd_pcm_prepare(self->pcmHandle);
615 if(ret < 0)
616 break;
619 ALCplaybackAlsa_unlock(self);
622 return 0;
626 static ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name)
628 ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
629 const char *driver = NULL;
630 int err;
632 if(name)
634 const DevMap *iter;
636 if(VECTOR_SIZE(PlaybackDevices) == 0)
637 probe_devices(SND_PCM_STREAM_PLAYBACK, &PlaybackDevices);
639 #define MATCH_NAME(i) (alstr_cmp_cstr((i)->name, name) == 0)
640 VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME);
641 #undef MATCH_NAME
642 if(iter == VECTOR_END(PlaybackDevices))
643 return ALC_INVALID_VALUE;
644 driver = alstr_get_cstr(iter->device_name);
646 else
648 name = alsaDevice;
649 driver = GetConfigValue(NULL, "alsa", "device", "default");
652 TRACE("Opening device \"%s\"\n", driver);
653 err = snd_pcm_open(&self->pcmHandle, driver, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
654 if(err < 0)
656 ERR("Could not open playback device '%s': %s\n", driver, snd_strerror(err));
657 return ALC_OUT_OF_MEMORY;
660 /* Free alsa's global config tree. Otherwise valgrind reports a ton of leaks. */
661 snd_config_update_free_global();
663 alstr_copy_cstr(&device->DeviceName, name);
665 return ALC_NO_ERROR;
668 static void ALCplaybackAlsa_close(ALCplaybackAlsa *self)
670 snd_pcm_close(self->pcmHandle);
673 static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self)
675 ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
676 snd_pcm_uframes_t periodSizeInFrames;
677 unsigned int periodLen, bufferLen;
678 snd_pcm_sw_params_t *sp = NULL;
679 snd_pcm_hw_params_t *hp = NULL;
680 snd_pcm_format_t format = -1;
681 snd_pcm_access_t access;
682 unsigned int periods;
683 unsigned int rate;
684 const char *funcerr;
685 int allowmmap;
686 int dir;
687 int err;
689 switch(device->FmtType)
691 case DevFmtByte:
692 format = SND_PCM_FORMAT_S8;
693 break;
694 case DevFmtUByte:
695 format = SND_PCM_FORMAT_U8;
696 break;
697 case DevFmtShort:
698 format = SND_PCM_FORMAT_S16;
699 break;
700 case DevFmtUShort:
701 format = SND_PCM_FORMAT_U16;
702 break;
703 case DevFmtInt:
704 format = SND_PCM_FORMAT_S32;
705 break;
706 case DevFmtUInt:
707 format = SND_PCM_FORMAT_U32;
708 break;
709 case DevFmtFloat:
710 format = SND_PCM_FORMAT_FLOAT;
711 break;
714 allowmmap = GetConfigValueBool(alstr_get_cstr(device->DeviceName), "alsa", "mmap", 1);
715 periods = device->NumUpdates;
716 periodLen = (ALuint64)device->UpdateSize * 1000000 / device->Frequency;
717 bufferLen = periodLen * periods;
718 rate = device->Frequency;
720 snd_pcm_hw_params_malloc(&hp);
721 #define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error
722 CHECK(snd_pcm_hw_params_any(self->pcmHandle, hp));
723 /* set interleaved access */
724 if(!allowmmap || snd_pcm_hw_params_set_access(self->pcmHandle, hp, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0)
726 /* No mmap */
727 CHECK(snd_pcm_hw_params_set_access(self->pcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED));
729 /* test and set format (implicitly sets sample bits) */
730 if(snd_pcm_hw_params_test_format(self->pcmHandle, hp, format) < 0)
732 static const struct {
733 snd_pcm_format_t format;
734 enum DevFmtType fmttype;
735 } formatlist[] = {
736 { SND_PCM_FORMAT_FLOAT, DevFmtFloat },
737 { SND_PCM_FORMAT_S32, DevFmtInt },
738 { SND_PCM_FORMAT_U32, DevFmtUInt },
739 { SND_PCM_FORMAT_S16, DevFmtShort },
740 { SND_PCM_FORMAT_U16, DevFmtUShort },
741 { SND_PCM_FORMAT_S8, DevFmtByte },
742 { SND_PCM_FORMAT_U8, DevFmtUByte },
744 size_t k;
746 for(k = 0;k < COUNTOF(formatlist);k++)
748 format = formatlist[k].format;
749 if(snd_pcm_hw_params_test_format(self->pcmHandle, hp, format) >= 0)
751 device->FmtType = formatlist[k].fmttype;
752 break;
756 CHECK(snd_pcm_hw_params_set_format(self->pcmHandle, hp, format));
757 /* test and set channels (implicitly sets frame bits) */
758 if(snd_pcm_hw_params_test_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder)) < 0)
760 static const enum DevFmtChannels channellist[] = {
761 DevFmtStereo,
762 DevFmtQuad,
763 DevFmtX51,
764 DevFmtX71,
765 DevFmtMono,
767 size_t k;
769 for(k = 0;k < COUNTOF(channellist);k++)
771 if(snd_pcm_hw_params_test_channels(self->pcmHandle, hp, ChannelsFromDevFmt(channellist[k], 0)) >= 0)
773 device->FmtChans = channellist[k];
774 device->AmbiOrder = 0;
775 break;
779 CHECK(snd_pcm_hw_params_set_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder)));
780 /* set rate (implicitly constrains period/buffer parameters) */
781 if(!GetConfigValueBool(alstr_get_cstr(device->DeviceName), "alsa", "allow-resampler", 0) ||
782 !(device->Flags&DEVICE_FREQUENCY_REQUEST))
784 if(snd_pcm_hw_params_set_rate_resample(self->pcmHandle, hp, 0) < 0)
785 ERR("Failed to disable ALSA resampler\n");
787 else if(snd_pcm_hw_params_set_rate_resample(self->pcmHandle, hp, 1) < 0)
788 ERR("Failed to enable ALSA resampler\n");
789 CHECK(snd_pcm_hw_params_set_rate_near(self->pcmHandle, hp, &rate, NULL));
790 /* set buffer time (implicitly constrains period/buffer parameters) */
791 if((err=snd_pcm_hw_params_set_buffer_time_near(self->pcmHandle, hp, &bufferLen, NULL)) < 0)
792 ERR("snd_pcm_hw_params_set_buffer_time_near failed: %s\n", snd_strerror(err));
793 /* set period time (implicitly sets buffer size/bytes/time and period size/bytes) */
794 if((err=snd_pcm_hw_params_set_period_time_near(self->pcmHandle, hp, &periodLen, NULL)) < 0)
795 ERR("snd_pcm_hw_params_set_period_time_near failed: %s\n", snd_strerror(err));
796 /* install and prepare hardware configuration */
797 CHECK(snd_pcm_hw_params(self->pcmHandle, hp));
798 /* retrieve configuration info */
799 CHECK(snd_pcm_hw_params_get_access(hp, &access));
800 CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, NULL));
801 CHECK(snd_pcm_hw_params_get_periods(hp, &periods, &dir));
802 if(dir != 0)
803 WARN("Inexact period count: %u (%d)\n", periods, dir);
805 snd_pcm_hw_params_free(hp);
806 hp = NULL;
807 snd_pcm_sw_params_malloc(&sp);
809 CHECK(snd_pcm_sw_params_current(self->pcmHandle, sp));
810 CHECK(snd_pcm_sw_params_set_avail_min(self->pcmHandle, sp, periodSizeInFrames));
811 CHECK(snd_pcm_sw_params_set_stop_threshold(self->pcmHandle, sp, periodSizeInFrames*periods));
812 CHECK(snd_pcm_sw_params(self->pcmHandle, sp));
813 #undef CHECK
814 snd_pcm_sw_params_free(sp);
815 sp = NULL;
817 device->NumUpdates = periods;
818 device->UpdateSize = periodSizeInFrames;
819 device->Frequency = rate;
821 SetDefaultChannelOrder(device);
823 return ALC_TRUE;
825 error:
826 ERR("%s failed: %s\n", funcerr, snd_strerror(err));
827 if(hp) snd_pcm_hw_params_free(hp);
828 if(sp) snd_pcm_sw_params_free(sp);
829 return ALC_FALSE;
832 static ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self)
834 ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
835 int (*thread_func)(void*) = NULL;
836 snd_pcm_hw_params_t *hp = NULL;
837 snd_pcm_access_t access;
838 const char *funcerr;
839 int err;
841 snd_pcm_hw_params_malloc(&hp);
842 #define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error
843 CHECK(snd_pcm_hw_params_current(self->pcmHandle, hp));
844 /* retrieve configuration info */
845 CHECK(snd_pcm_hw_params_get_access(hp, &access));
846 #undef CHECK
847 snd_pcm_hw_params_free(hp);
848 hp = NULL;
850 self->size = snd_pcm_frames_to_bytes(self->pcmHandle, device->UpdateSize);
851 if(access == SND_PCM_ACCESS_RW_INTERLEAVED)
853 self->buffer = al_malloc(16, self->size);
854 if(!self->buffer)
856 ERR("buffer malloc failed\n");
857 return ALC_FALSE;
859 thread_func = ALCplaybackAlsa_mixerNoMMapProc;
861 else
863 err = snd_pcm_prepare(self->pcmHandle);
864 if(err < 0)
866 ERR("snd_pcm_prepare(data->pcmHandle) failed: %s\n", snd_strerror(err));
867 return ALC_FALSE;
869 thread_func = ALCplaybackAlsa_mixerProc;
871 self->killNow = 0;
872 if(althrd_create(&self->thread, thread_func, self) != althrd_success)
874 ERR("Could not create playback thread\n");
875 al_free(self->buffer);
876 self->buffer = NULL;
877 return ALC_FALSE;
880 return ALC_TRUE;
882 error:
883 ERR("%s failed: %s\n", funcerr, snd_strerror(err));
884 if(hp) snd_pcm_hw_params_free(hp);
885 return ALC_FALSE;
888 static void ALCplaybackAlsa_stop(ALCplaybackAlsa *self)
890 int res;
892 if(self->killNow)
893 return;
895 self->killNow = 1;
896 althrd_join(self->thread, &res);
898 al_free(self->buffer);
899 self->buffer = NULL;
902 static ClockLatency ALCplaybackAlsa_getClockLatency(ALCplaybackAlsa *self)
904 ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
905 snd_pcm_sframes_t delay = 0;
906 ClockLatency ret;
907 int err;
909 ALCplaybackAlsa_lock(self);
910 ret.ClockTime = GetDeviceClockTime(device);
911 if((err=snd_pcm_delay(self->pcmHandle, &delay)) < 0)
913 ERR("Failed to get pcm delay: %s\n", snd_strerror(err));
914 delay = 0;
916 if(delay < 0) delay = 0;
917 ret.Latency = delay * DEVICE_CLOCK_RES / device->Frequency;
918 ALCplaybackAlsa_unlock(self);
920 return ret;
924 typedef struct ALCcaptureAlsa {
925 DERIVE_FROM_TYPE(ALCbackend);
927 snd_pcm_t *pcmHandle;
929 ALvoid *buffer;
930 ALsizei size;
932 ALboolean doCapture;
933 ll_ringbuffer_t *ring;
935 snd_pcm_sframes_t last_avail;
936 } ALCcaptureAlsa;
938 static void ALCcaptureAlsa_Construct(ALCcaptureAlsa *self, ALCdevice *device);
939 static DECLARE_FORWARD(ALCcaptureAlsa, ALCbackend, void, Destruct)
940 static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name);
941 static void ALCcaptureAlsa_close(ALCcaptureAlsa *self);
942 static DECLARE_FORWARD(ALCcaptureAlsa, ALCbackend, ALCboolean, reset)
943 static ALCboolean ALCcaptureAlsa_start(ALCcaptureAlsa *self);
944 static void ALCcaptureAlsa_stop(ALCcaptureAlsa *self);
945 static ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buffer, ALCuint samples);
946 static ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self);
947 static ClockLatency ALCcaptureAlsa_getClockLatency(ALCcaptureAlsa *self);
948 static DECLARE_FORWARD(ALCcaptureAlsa, ALCbackend, void, lock)
949 static DECLARE_FORWARD(ALCcaptureAlsa, ALCbackend, void, unlock)
950 DECLARE_DEFAULT_ALLOCATORS(ALCcaptureAlsa)
952 DEFINE_ALCBACKEND_VTABLE(ALCcaptureAlsa);
955 static void ALCcaptureAlsa_Construct(ALCcaptureAlsa *self, ALCdevice *device)
957 ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
958 SET_VTABLE2(ALCcaptureAlsa, ALCbackend, self);
962 static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name)
964 ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
965 const char *driver = NULL;
966 snd_pcm_hw_params_t *hp;
967 snd_pcm_uframes_t bufferSizeInFrames;
968 snd_pcm_uframes_t periodSizeInFrames;
969 ALboolean needring = AL_FALSE;
970 snd_pcm_format_t format = -1;
971 const char *funcerr;
972 int err;
974 if(name)
976 const DevMap *iter;
978 if(VECTOR_SIZE(CaptureDevices) == 0)
979 probe_devices(SND_PCM_STREAM_CAPTURE, &CaptureDevices);
981 #define MATCH_NAME(i) (alstr_cmp_cstr((i)->name, name) == 0)
982 VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME);
983 #undef MATCH_NAME
984 if(iter == VECTOR_END(CaptureDevices))
985 return ALC_INVALID_VALUE;
986 driver = alstr_get_cstr(iter->device_name);
988 else
990 name = alsaDevice;
991 driver = GetConfigValue(NULL, "alsa", "capture", "default");
994 TRACE("Opening device \"%s\"\n", driver);
995 err = snd_pcm_open(&self->pcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
996 if(err < 0)
998 ERR("Could not open capture device '%s': %s\n", driver, snd_strerror(err));
999 return ALC_INVALID_VALUE;
1002 /* Free alsa's global config tree. Otherwise valgrind reports a ton of leaks. */
1003 snd_config_update_free_global();
1005 switch(device->FmtType)
1007 case DevFmtByte:
1008 format = SND_PCM_FORMAT_S8;
1009 break;
1010 case DevFmtUByte:
1011 format = SND_PCM_FORMAT_U8;
1012 break;
1013 case DevFmtShort:
1014 format = SND_PCM_FORMAT_S16;
1015 break;
1016 case DevFmtUShort:
1017 format = SND_PCM_FORMAT_U16;
1018 break;
1019 case DevFmtInt:
1020 format = SND_PCM_FORMAT_S32;
1021 break;
1022 case DevFmtUInt:
1023 format = SND_PCM_FORMAT_U32;
1024 break;
1025 case DevFmtFloat:
1026 format = SND_PCM_FORMAT_FLOAT;
1027 break;
1030 funcerr = NULL;
1031 bufferSizeInFrames = maxu(device->UpdateSize*device->NumUpdates,
1032 100*device->Frequency/1000);
1033 periodSizeInFrames = minu(bufferSizeInFrames, 25*device->Frequency/1000);
1035 snd_pcm_hw_params_malloc(&hp);
1036 #define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error
1037 CHECK(snd_pcm_hw_params_any(self->pcmHandle, hp));
1038 /* set interleaved access */
1039 CHECK(snd_pcm_hw_params_set_access(self->pcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED));
1040 /* set format (implicitly sets sample bits) */
1041 CHECK(snd_pcm_hw_params_set_format(self->pcmHandle, hp, format));
1042 /* set channels (implicitly sets frame bits) */
1043 CHECK(snd_pcm_hw_params_set_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder)));
1044 /* set rate (implicitly constrains period/buffer parameters) */
1045 CHECK(snd_pcm_hw_params_set_rate(self->pcmHandle, hp, device->Frequency, 0));
1046 /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */
1047 if(snd_pcm_hw_params_set_buffer_size_min(self->pcmHandle, hp, &bufferSizeInFrames) < 0)
1049 TRACE("Buffer too large, using intermediate ring buffer\n");
1050 needring = AL_TRUE;
1051 CHECK(snd_pcm_hw_params_set_buffer_size_near(self->pcmHandle, hp, &bufferSizeInFrames));
1053 /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */
1054 CHECK(snd_pcm_hw_params_set_period_size_near(self->pcmHandle, hp, &periodSizeInFrames, NULL));
1055 /* install and prepare hardware configuration */
1056 CHECK(snd_pcm_hw_params(self->pcmHandle, hp));
1057 /* retrieve configuration info */
1058 CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, NULL));
1059 #undef CHECK
1060 snd_pcm_hw_params_free(hp);
1061 hp = NULL;
1063 if(needring)
1065 self->ring = ll_ringbuffer_create(
1066 device->UpdateSize*device->NumUpdates + 1,
1067 FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder)
1069 if(!self->ring)
1071 ERR("ring buffer create failed\n");
1072 goto error2;
1076 alstr_copy_cstr(&device->DeviceName, name);
1078 return ALC_NO_ERROR;
1080 error:
1081 ERR("%s failed: %s\n", funcerr, snd_strerror(err));
1082 if(hp) snd_pcm_hw_params_free(hp);
1084 error2:
1085 ll_ringbuffer_free(self->ring);
1086 self->ring = NULL;
1087 snd_pcm_close(self->pcmHandle);
1089 return ALC_INVALID_VALUE;
1092 static void ALCcaptureAlsa_close(ALCcaptureAlsa *self)
1094 snd_pcm_close(self->pcmHandle);
1095 ll_ringbuffer_free(self->ring);
1097 al_free(self->buffer);
1098 self->buffer = NULL;
1101 static ALCboolean ALCcaptureAlsa_start(ALCcaptureAlsa *self)
1103 int err = snd_pcm_start(self->pcmHandle);
1104 if(err < 0)
1106 ERR("start failed: %s\n", snd_strerror(err));
1107 aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice);
1108 return ALC_FALSE;
1111 self->doCapture = AL_TRUE;
1112 return ALC_TRUE;
1115 static void ALCcaptureAlsa_stop(ALCcaptureAlsa *self)
1117 ALCuint avail;
1118 int err;
1120 /* OpenAL requires access to unread audio after stopping, but ALSA's
1121 * snd_pcm_drain is unreliable and snd_pcm_drop drops it. Capture what's
1122 * available now so it'll be available later after the drop. */
1123 avail = ALCcaptureAlsa_availableSamples(self);
1124 if(!self->ring && avail > 0)
1126 /* The ring buffer implicitly captures when checking availability.
1127 * Direct access needs to explicitly capture it into temp storage. */
1128 ALsizei size;
1129 void *ptr;
1131 size = snd_pcm_frames_to_bytes(self->pcmHandle, avail);
1132 ptr = al_malloc(16, size);
1133 if(ptr)
1135 ALCcaptureAlsa_captureSamples(self, ptr, avail);
1136 al_free(self->buffer);
1137 self->buffer = ptr;
1138 self->size = size;
1141 err = snd_pcm_drop(self->pcmHandle);
1142 if(err < 0)
1143 ERR("drop failed: %s\n", snd_strerror(err));
1144 self->doCapture = AL_FALSE;
1147 static ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buffer, ALCuint samples)
1149 ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
1151 if(self->ring)
1153 ll_ringbuffer_read(self->ring, buffer, samples);
1154 return ALC_NO_ERROR;
1157 self->last_avail -= samples;
1158 while(device->Connected && samples > 0)
1160 snd_pcm_sframes_t amt = 0;
1162 if(self->size > 0)
1164 /* First get any data stored from the last stop */
1165 amt = snd_pcm_bytes_to_frames(self->pcmHandle, self->size);
1166 if((snd_pcm_uframes_t)amt > samples) amt = samples;
1168 amt = snd_pcm_frames_to_bytes(self->pcmHandle, amt);
1169 memcpy(buffer, self->buffer, amt);
1171 if(self->size > amt)
1173 memmove(self->buffer, self->buffer+amt, self->size - amt);
1174 self->size -= amt;
1176 else
1178 al_free(self->buffer);
1179 self->buffer = NULL;
1180 self->size = 0;
1182 amt = snd_pcm_bytes_to_frames(self->pcmHandle, amt);
1184 else if(self->doCapture)
1185 amt = snd_pcm_readi(self->pcmHandle, buffer, samples);
1186 if(amt < 0)
1188 ERR("read error: %s\n", snd_strerror(amt));
1190 if(amt == -EAGAIN)
1191 continue;
1192 if((amt=snd_pcm_recover(self->pcmHandle, amt, 1)) >= 0)
1194 amt = snd_pcm_start(self->pcmHandle);
1195 if(amt >= 0)
1196 amt = snd_pcm_avail_update(self->pcmHandle);
1198 if(amt < 0)
1200 ERR("restore error: %s\n", snd_strerror(amt));
1201 aluHandleDisconnect(device);
1202 break;
1204 /* If the amount available is less than what's asked, we lost it
1205 * during recovery. So just give silence instead. */
1206 if((snd_pcm_uframes_t)amt < samples)
1207 break;
1208 continue;
1211 buffer = (ALbyte*)buffer + amt;
1212 samples -= amt;
1214 if(samples > 0)
1215 memset(buffer, ((device->FmtType == DevFmtUByte) ? 0x80 : 0),
1216 snd_pcm_frames_to_bytes(self->pcmHandle, samples));
1218 return ALC_NO_ERROR;
1221 static ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self)
1223 ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
1224 snd_pcm_sframes_t avail = 0;
1226 if(device->Connected && self->doCapture)
1227 avail = snd_pcm_avail_update(self->pcmHandle);
1228 if(avail < 0)
1230 ERR("avail update failed: %s\n", snd_strerror(avail));
1232 if((avail=snd_pcm_recover(self->pcmHandle, avail, 1)) >= 0)
1234 if(self->doCapture)
1235 avail = snd_pcm_start(self->pcmHandle);
1236 if(avail >= 0)
1237 avail = snd_pcm_avail_update(self->pcmHandle);
1239 if(avail < 0)
1241 ERR("restore error: %s\n", snd_strerror(avail));
1242 aluHandleDisconnect(device);
1246 if(!self->ring)
1248 if(avail < 0) avail = 0;
1249 avail += snd_pcm_bytes_to_frames(self->pcmHandle, self->size);
1250 if(avail > self->last_avail) self->last_avail = avail;
1251 return self->last_avail;
1254 while(avail > 0)
1256 ll_ringbuffer_data_t vec[2];
1257 snd_pcm_sframes_t amt;
1259 ll_ringbuffer_get_write_vector(self->ring, vec);
1260 if(vec[0].len == 0) break;
1262 amt = (vec[0].len < (snd_pcm_uframes_t)avail) ?
1263 vec[0].len : (snd_pcm_uframes_t)avail;
1264 amt = snd_pcm_readi(self->pcmHandle, vec[0].buf, amt);
1265 if(amt < 0)
1267 ERR("read error: %s\n", snd_strerror(amt));
1269 if(amt == -EAGAIN)
1270 continue;
1271 if((amt=snd_pcm_recover(self->pcmHandle, amt, 1)) >= 0)
1273 if(self->doCapture)
1274 amt = snd_pcm_start(self->pcmHandle);
1275 if(amt >= 0)
1276 amt = snd_pcm_avail_update(self->pcmHandle);
1278 if(amt < 0)
1280 ERR("restore error: %s\n", snd_strerror(amt));
1281 aluHandleDisconnect(device);
1282 break;
1284 avail = amt;
1285 continue;
1288 ll_ringbuffer_write_advance(self->ring, amt);
1289 avail -= amt;
1292 return ll_ringbuffer_read_space(self->ring);
1295 static ClockLatency ALCcaptureAlsa_getClockLatency(ALCcaptureAlsa *self)
1297 ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
1298 snd_pcm_sframes_t delay = 0;
1299 ClockLatency ret;
1300 int err;
1302 ALCcaptureAlsa_lock(self);
1303 ret.ClockTime = GetDeviceClockTime(device);
1304 if((err=snd_pcm_delay(self->pcmHandle, &delay)) < 0)
1306 ERR("Failed to get pcm delay: %s\n", snd_strerror(err));
1307 delay = 0;
1309 if(delay < 0) delay = 0;
1310 ret.Latency = delay * DEVICE_CLOCK_RES / device->Frequency;
1311 ALCcaptureAlsa_unlock(self);
1313 return ret;
1317 static inline void AppendAllDevicesList2(const DevMap *entry)
1318 { AppendAllDevicesList(alstr_get_cstr(entry->name)); }
1319 static inline void AppendCaptureDeviceList2(const DevMap *entry)
1320 { AppendCaptureDeviceList(alstr_get_cstr(entry->name)); }
1322 typedef struct ALCalsaBackendFactory {
1323 DERIVE_FROM_TYPE(ALCbackendFactory);
1324 } ALCalsaBackendFactory;
1325 #define ALCALSABACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCalsaBackendFactory, ALCbackendFactory) } }
1327 static ALCboolean ALCalsaBackendFactory_init(ALCalsaBackendFactory* UNUSED(self))
1329 VECTOR_INIT(PlaybackDevices);
1330 VECTOR_INIT(CaptureDevices);
1332 if(!alsa_load())
1333 return ALC_FALSE;
1334 return ALC_TRUE;
1337 static void ALCalsaBackendFactory_deinit(ALCalsaBackendFactory* UNUSED(self))
1339 clear_devlist(&PlaybackDevices);
1340 VECTOR_DEINIT(PlaybackDevices);
1342 clear_devlist(&CaptureDevices);
1343 VECTOR_DEINIT(CaptureDevices);
1345 #ifdef HAVE_DYNLOAD
1346 if(alsa_handle)
1347 CloseLib(alsa_handle);
1348 alsa_handle = NULL;
1349 #endif
1352 static ALCboolean ALCalsaBackendFactory_querySupport(ALCalsaBackendFactory* UNUSED(self), ALCbackend_Type type)
1354 if(type == ALCbackend_Playback || type == ALCbackend_Capture)
1355 return ALC_TRUE;
1356 return ALC_FALSE;
1359 static void ALCalsaBackendFactory_probe(ALCalsaBackendFactory* UNUSED(self), enum DevProbe type)
1361 switch(type)
1363 case ALL_DEVICE_PROBE:
1364 probe_devices(SND_PCM_STREAM_PLAYBACK, &PlaybackDevices);
1365 VECTOR_FOR_EACH(const DevMap, PlaybackDevices, AppendAllDevicesList2);
1366 break;
1368 case CAPTURE_DEVICE_PROBE:
1369 probe_devices(SND_PCM_STREAM_CAPTURE, &CaptureDevices);
1370 VECTOR_FOR_EACH(const DevMap, CaptureDevices, AppendCaptureDeviceList2);
1371 break;
1375 static ALCbackend* ALCalsaBackendFactory_createBackend(ALCalsaBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
1377 if(type == ALCbackend_Playback)
1379 ALCplaybackAlsa *backend;
1380 NEW_OBJ(backend, ALCplaybackAlsa)(device);
1381 if(!backend) return NULL;
1382 return STATIC_CAST(ALCbackend, backend);
1384 if(type == ALCbackend_Capture)
1386 ALCcaptureAlsa *backend;
1387 NEW_OBJ(backend, ALCcaptureAlsa)(device);
1388 if(!backend) return NULL;
1389 return STATIC_CAST(ALCbackend, backend);
1392 return NULL;
1395 DEFINE_ALCBACKENDFACTORY_VTABLE(ALCalsaBackendFactory);
1398 ALCbackendFactory *ALCalsaBackendFactory_getFactory(void)
1400 static ALCalsaBackendFactory factory = ALCALSABACKENDFACTORY_INITIALIZER;
1401 return STATIC_CAST(ALCbackendFactory, &factory);