Make sure the ALSA device list is reset if no cards are found
[openal-soft.git] / Alc / alsa.c
bloba4c23df9b3c5053383e77fa8da1f7d30f8f19f3e
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>
26 #ifdef HAVE_DLFCN_H
27 #include <dlfcn.h>
28 #endif
29 #include "alMain.h"
30 #include "AL/al.h"
31 #include "AL/alc.h"
33 #include <alsa/asoundlib.h>
36 typedef struct {
37 snd_pcm_t *pcmHandle;
39 ALvoid *buffer;
40 ALsizei size;
42 RingBuffer *ring;
43 int doCapture;
45 volatile int killNow;
46 ALvoid *thread;
47 } alsa_data;
49 typedef struct {
50 ALCchar *name;
51 int card, dev;
52 } DevMap;
54 static void *alsa_handle;
55 #define MAKE_FUNC(f) static typeof(f) * p##f
56 MAKE_FUNC(snd_strerror);
57 MAKE_FUNC(snd_pcm_open);
58 MAKE_FUNC(snd_pcm_close);
59 MAKE_FUNC(snd_pcm_nonblock);
60 MAKE_FUNC(snd_pcm_frames_to_bytes);
61 MAKE_FUNC(snd_pcm_hw_params_malloc);
62 MAKE_FUNC(snd_pcm_hw_params_free);
63 MAKE_FUNC(snd_pcm_hw_params_any);
64 MAKE_FUNC(snd_pcm_hw_params_set_access);
65 MAKE_FUNC(snd_pcm_hw_params_set_format);
66 MAKE_FUNC(snd_pcm_hw_params_set_channels);
67 MAKE_FUNC(snd_pcm_hw_params_set_periods_near);
68 MAKE_FUNC(snd_pcm_hw_params_set_rate_near);
69 MAKE_FUNC(snd_pcm_hw_params_set_rate);
70 MAKE_FUNC(snd_pcm_hw_params_set_buffer_size_near);
71 MAKE_FUNC(snd_pcm_hw_params_set_period_size_near);
72 MAKE_FUNC(snd_pcm_hw_params_set_buffer_size_min);
73 MAKE_FUNC(snd_pcm_hw_params_get_buffer_size);
74 MAKE_FUNC(snd_pcm_hw_params_get_period_size);
75 MAKE_FUNC(snd_pcm_hw_params_get_access);
76 MAKE_FUNC(snd_pcm_hw_params_get_periods);
77 MAKE_FUNC(snd_pcm_hw_params);
78 MAKE_FUNC(snd_pcm_sw_params_malloc);
79 MAKE_FUNC(snd_pcm_sw_params_current);
80 MAKE_FUNC(snd_pcm_sw_params_set_avail_min);
81 MAKE_FUNC(snd_pcm_sw_params);
82 MAKE_FUNC(snd_pcm_sw_params_free);
83 MAKE_FUNC(snd_pcm_prepare);
84 MAKE_FUNC(snd_pcm_start);
85 MAKE_FUNC(snd_pcm_resume);
86 MAKE_FUNC(snd_pcm_wait);
87 MAKE_FUNC(snd_pcm_state);
88 MAKE_FUNC(snd_pcm_avail_update);
89 MAKE_FUNC(snd_pcm_areas_silence);
90 MAKE_FUNC(snd_pcm_mmap_begin);
91 MAKE_FUNC(snd_pcm_mmap_commit);
92 MAKE_FUNC(snd_pcm_readi);
93 MAKE_FUNC(snd_pcm_writei);
94 MAKE_FUNC(snd_pcm_drain);
95 MAKE_FUNC(snd_pcm_info_malloc);
96 MAKE_FUNC(snd_pcm_info_free);
97 MAKE_FUNC(snd_pcm_info_set_device);
98 MAKE_FUNC(snd_pcm_info_set_subdevice);
99 MAKE_FUNC(snd_pcm_info_set_stream);
100 MAKE_FUNC(snd_pcm_info_get_name);
101 MAKE_FUNC(snd_ctl_pcm_next_device);
102 MAKE_FUNC(snd_ctl_pcm_info);
103 MAKE_FUNC(snd_ctl_open);
104 MAKE_FUNC(snd_ctl_close);
105 MAKE_FUNC(snd_ctl_card_info_malloc);
106 MAKE_FUNC(snd_ctl_card_info_free);
107 MAKE_FUNC(snd_ctl_card_info);
108 MAKE_FUNC(snd_ctl_card_info_get_name);
109 MAKE_FUNC(snd_card_next);
110 #undef MAKE_FUNC
113 static const ALCchar alsaDevice[] = "ALSA Software";
114 static DevMap *allDevNameMap;
115 static ALuint numDevNames;
116 static DevMap *allCaptureDevNameMap;
117 static ALuint numCaptureDevNames;
118 static volatile ALuint load_count;
121 void alsa_load(void)
123 if(load_count == 0)
125 char *str;
127 #ifdef HAVE_DLFCN_H
128 alsa_handle = dlopen("libasound.so.2", RTLD_NOW);
129 if(!alsa_handle)
130 return;
131 dlerror();
133 #define LOAD_FUNC(f) do { \
134 p##f = dlsym(alsa_handle, #f); \
135 if((str=dlerror()) != NULL) \
137 dlclose(alsa_handle); \
138 alsa_handle = NULL; \
139 AL_PRINT("Could not load %s from libasound.so.2: %s\n", #f, str); \
140 return; \
142 } while(0)
143 #else
144 str = NULL;
145 alsa_handle = (void*)0xDEADBEEF;
146 #define LOAD_FUNC(f) p##f = f
147 #endif
149 LOAD_FUNC(snd_strerror);
150 LOAD_FUNC(snd_pcm_open);
151 LOAD_FUNC(snd_pcm_close);
152 LOAD_FUNC(snd_pcm_nonblock);
153 LOAD_FUNC(snd_pcm_frames_to_bytes);
154 LOAD_FUNC(snd_pcm_hw_params_malloc);
155 LOAD_FUNC(snd_pcm_hw_params_free);
156 LOAD_FUNC(snd_pcm_hw_params_any);
157 LOAD_FUNC(snd_pcm_hw_params_set_access);
158 LOAD_FUNC(snd_pcm_hw_params_set_format);
159 LOAD_FUNC(snd_pcm_hw_params_set_channels);
160 LOAD_FUNC(snd_pcm_hw_params_set_periods_near);
161 LOAD_FUNC(snd_pcm_hw_params_set_rate_near);
162 LOAD_FUNC(snd_pcm_hw_params_set_rate);
163 LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_near);
164 LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_min);
165 LOAD_FUNC(snd_pcm_hw_params_set_period_size_near);
166 LOAD_FUNC(snd_pcm_hw_params_get_buffer_size);
167 LOAD_FUNC(snd_pcm_hw_params_get_period_size);
168 LOAD_FUNC(snd_pcm_hw_params_get_access);
169 LOAD_FUNC(snd_pcm_hw_params_get_periods);
170 LOAD_FUNC(snd_pcm_hw_params);
171 LOAD_FUNC(snd_pcm_sw_params_malloc);
172 LOAD_FUNC(snd_pcm_sw_params_current);
173 LOAD_FUNC(snd_pcm_sw_params_set_avail_min);
174 LOAD_FUNC(snd_pcm_sw_params);
175 LOAD_FUNC(snd_pcm_sw_params_free);
176 LOAD_FUNC(snd_pcm_prepare);
177 LOAD_FUNC(snd_pcm_start);
178 LOAD_FUNC(snd_pcm_resume);
179 LOAD_FUNC(snd_pcm_wait);
180 LOAD_FUNC(snd_pcm_state);
181 LOAD_FUNC(snd_pcm_avail_update);
182 LOAD_FUNC(snd_pcm_areas_silence);
183 LOAD_FUNC(snd_pcm_mmap_begin);
184 LOAD_FUNC(snd_pcm_mmap_commit);
185 LOAD_FUNC(snd_pcm_readi);
186 LOAD_FUNC(snd_pcm_writei);
187 LOAD_FUNC(snd_pcm_drain);
189 LOAD_FUNC(snd_pcm_info_malloc);
190 LOAD_FUNC(snd_pcm_info_free);
191 LOAD_FUNC(snd_pcm_info_set_device);
192 LOAD_FUNC(snd_pcm_info_set_subdevice);
193 LOAD_FUNC(snd_pcm_info_set_stream);
194 LOAD_FUNC(snd_pcm_info_get_name);
195 LOAD_FUNC(snd_ctl_pcm_next_device);
196 LOAD_FUNC(snd_ctl_pcm_info);
197 LOAD_FUNC(snd_ctl_open);
198 LOAD_FUNC(snd_ctl_close);
199 LOAD_FUNC(snd_ctl_card_info_malloc);
200 LOAD_FUNC(snd_ctl_card_info_free);
201 LOAD_FUNC(snd_ctl_card_info);
202 LOAD_FUNC(snd_ctl_card_info_get_name);
203 LOAD_FUNC(snd_card_next);
205 #undef LOAD_FUNC
207 ++load_count;
210 void alsa_unload(void)
212 if(load_count == 0 || --load_count > 0)
213 return;
215 #ifdef HAVE_DLFCN_H
216 dlclose(alsa_handle);
217 #endif
218 alsa_handle = NULL;
222 static int xrun_recovery(snd_pcm_t *handle, int err)
224 if (err == -EPIPE)
225 { /* under-run */
226 err = psnd_pcm_prepare(handle);
227 if (err < 0)
228 AL_PRINT("prepare failed: %s\n", psnd_strerror(err));
230 else if (err == -ESTRPIPE)
232 while ((err = psnd_pcm_resume(handle)) == -EAGAIN)
233 Sleep(1); /* wait until the suspend flag is released */
234 if (err < 0)
236 err = psnd_pcm_prepare(handle);
237 if (err < 0)
238 AL_PRINT("prepare failed: %s\n", psnd_strerror(err));
241 return err;
244 static int verify_state(snd_pcm_t *handle)
246 snd_pcm_state_t state = psnd_pcm_state(handle);
247 if(state == SND_PCM_STATE_DISCONNECTED)
248 return -ENODEV;
249 if(state == SND_PCM_STATE_XRUN)
251 int err = xrun_recovery(handle, -EPIPE);
252 if(err < 0) return err;
254 else if(state == SND_PCM_STATE_SUSPENDED)
256 int err = xrun_recovery(handle, -ESTRPIPE);
257 if(err < 0) return err;
260 return state;
264 static ALuint ALSAProc(ALvoid *ptr)
266 ALCdevice *pDevice = (ALCdevice*)ptr;
267 alsa_data *data = (alsa_data*)pDevice->ExtraData;
268 const snd_pcm_channel_area_t *areas = NULL;
269 snd_pcm_sframes_t avail, commitres;
270 snd_pcm_uframes_t offset, frames;
271 char *WritePtr;
272 int err;
274 while(!data->killNow)
276 int state = verify_state(data->pcmHandle);
277 if(state < 0)
279 AL_PRINT("Invalid state detected: %s\n", psnd_strerror(state));
280 aluHandleDisconnect(pDevice);
281 break;
284 avail = psnd_pcm_avail_update(data->pcmHandle);
285 if(avail < 0)
287 AL_PRINT("available update failed: %s\n", psnd_strerror(avail));
288 continue;
291 // make sure there's frames to process
292 if((snd_pcm_uframes_t)avail < pDevice->UpdateSize)
294 if(state != SND_PCM_STATE_RUNNING)
296 err = psnd_pcm_start(data->pcmHandle);
297 if(err < 0)
299 AL_PRINT("start failed: %s\n", psnd_strerror(err));
300 continue;
303 if(psnd_pcm_wait(data->pcmHandle, 1000) == 0)
304 AL_PRINT("Wait timeout... buffer size too low?\n");
305 continue;
307 avail -= avail%pDevice->UpdateSize;
309 // it is possible that contiguous areas are smaller, thus we use a loop
310 while(avail > 0)
312 frames = avail;
314 err = psnd_pcm_mmap_begin(data->pcmHandle, &areas, &offset, &frames);
315 if(err < 0)
317 AL_PRINT("mmap begin error: %s\n", psnd_strerror(err));
318 break;
321 WritePtr = (char*)areas->addr + (offset * areas->step / 8);
322 aluMixData(pDevice, WritePtr, frames);
324 commitres = psnd_pcm_mmap_commit(data->pcmHandle, offset, frames);
325 if(commitres < 0 || (commitres-frames) != 0)
327 AL_PRINT("mmap commit error: %s\n",
328 psnd_strerror(commitres >= 0 ? -EPIPE : commitres));
329 break;
332 avail -= frames;
336 return 0;
339 static ALuint ALSANoMMapProc(ALvoid *ptr)
341 ALCdevice *pDevice = (ALCdevice*)ptr;
342 alsa_data *data = (alsa_data*)pDevice->ExtraData;
343 snd_pcm_sframes_t avail;
344 char *WritePtr;
346 while(!data->killNow)
348 int state = verify_state(data->pcmHandle);
349 if(state < 0)
351 AL_PRINT("Invalid state detected: %s\n", psnd_strerror(state));
352 aluHandleDisconnect(pDevice);
353 break;
356 WritePtr = data->buffer;
357 avail = data->size / psnd_pcm_frames_to_bytes(data->pcmHandle, 1);
358 aluMixData(pDevice, WritePtr, avail);
360 while(avail > 0)
362 int ret = psnd_pcm_writei(data->pcmHandle, WritePtr, avail);
363 switch (ret)
365 case -EAGAIN:
366 continue;
367 case -ESTRPIPE:
368 while((ret=psnd_pcm_resume(data->pcmHandle)) == -EAGAIN)
369 Sleep(1);
370 break;
371 case -EPIPE:
372 break;
373 default:
374 if (ret >= 0)
376 WritePtr += psnd_pcm_frames_to_bytes(data->pcmHandle, ret);
377 avail -= ret;
379 break;
381 if (ret < 0)
383 ret = psnd_pcm_prepare(data->pcmHandle);
384 if(ret < 0)
385 break;
390 return 0;
393 static ALuint ALSANoMMapCaptureProc(ALvoid *ptr)
395 ALCdevice *pDevice = (ALCdevice*)ptr;
396 alsa_data *data = (alsa_data*)pDevice->ExtraData;
397 snd_pcm_sframes_t avail;
399 while(!data->killNow)
401 int state = verify_state(data->pcmHandle);
402 if(state < 0)
404 AL_PRINT("Invalid state detected: %s\n", psnd_strerror(state));
405 aluHandleDisconnect(pDevice);
406 break;
409 avail = (snd_pcm_uframes_t)data->size / psnd_pcm_frames_to_bytes(data->pcmHandle, 1);
410 avail = psnd_pcm_readi(data->pcmHandle, data->buffer, avail);
411 switch(avail)
413 case -EAGAIN:
414 continue;
415 case -ESTRPIPE:
416 while((avail=psnd_pcm_resume(data->pcmHandle)) == -EAGAIN)
417 Sleep(1);
418 break;
419 case -EPIPE:
420 break;
421 default:
422 if (avail >= 0 && data->doCapture)
423 WriteRingBuffer(data->ring, data->buffer, avail);
424 break;
426 if(avail < 0)
428 avail = psnd_pcm_prepare(data->pcmHandle);
429 if(avail < 0)
430 AL_PRINT("prepare error: %s\n", psnd_strerror(avail));
434 return 0;
437 static ALCboolean alsa_open_playback(ALCdevice *device, const ALCchar *deviceName)
439 alsa_data *data;
440 char driver[64];
441 int i;
443 strncpy(driver, GetConfigValue("alsa", "device", "default"), sizeof(driver)-1);
444 driver[sizeof(driver)-1] = 0;
445 if(!deviceName)
446 deviceName = alsaDevice;
447 else if(strcmp(deviceName, alsaDevice) != 0)
449 size_t idx;
451 for(idx = 0;idx < numDevNames;idx++)
453 if(allDevNameMap[idx].name &&
454 strcmp(deviceName, allDevNameMap[idx].name) == 0)
456 if(idx > 0)
457 sprintf(driver, "hw:%d,%d", allDevNameMap[idx].card, allDevNameMap[idx].dev);
458 break;
461 if(idx == numDevNames)
462 return ALC_FALSE;
465 alsa_load();
466 if(!alsa_handle)
467 return ALC_FALSE;
469 data = (alsa_data*)calloc(1, sizeof(alsa_data));
471 i = psnd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
472 if(i < 0)
474 Sleep(200);
475 i = psnd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
477 if(i >= 0)
479 i = psnd_pcm_nonblock(data->pcmHandle, 0);
480 if(i < 0)
481 psnd_pcm_close(data->pcmHandle);
483 if(i < 0)
485 free(data);
486 AL_PRINT("Could not open playback device '%s': %s\n", driver, psnd_strerror(i));
487 alsa_unload();
488 return ALC_FALSE;
491 device->szDeviceName = strdup(deviceName);
492 device->ExtraData = data;
493 return ALC_TRUE;
496 static void alsa_close_playback(ALCdevice *device)
498 alsa_data *data = (alsa_data*)device->ExtraData;
500 psnd_pcm_close(data->pcmHandle);
501 free(data);
502 device->ExtraData = NULL;
504 alsa_unload();
507 static ALCboolean alsa_reset_playback(ALCdevice *device)
509 alsa_data *data = (alsa_data*)device->ExtraData;
510 snd_pcm_uframes_t periodSizeInFrames;
511 snd_pcm_sw_params_t *sp = NULL;
512 snd_pcm_hw_params_t *p = NULL;
513 snd_pcm_access_t access;
514 snd_pcm_format_t format;
515 unsigned int periods;
516 unsigned int rate;
517 int allowmmap;
518 char *err;
519 int i;
522 switch(aluBytesFromFormat(device->Format))
524 case 1:
525 format = SND_PCM_FORMAT_U8;
526 break;
527 case 2:
528 format = SND_PCM_FORMAT_S16;
529 break;
530 case 4:
531 format = SND_PCM_FORMAT_FLOAT;
532 break;
533 default:
534 AL_PRINT("Unknown format: 0x%x\n", device->Format);
535 return ALC_FALSE;
538 allowmmap = GetConfigValueBool("alsa", "mmap", 1);
539 periods = device->NumUpdates;
540 periodSizeInFrames = device->UpdateSize;
541 rate = device->Frequency;
543 err = NULL;
544 psnd_pcm_hw_params_malloc(&p);
546 if((i=psnd_pcm_hw_params_any(data->pcmHandle, p)) < 0)
547 err = "any";
548 /* set interleaved access */
549 if(err == NULL && (!allowmmap || (i=psnd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_MMAP_INTERLEAVED)) < 0))
551 if(periods > 2) periods--;
552 if((i=psnd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
553 err = "set access";
555 /* set format (implicitly sets sample bits) */
556 if(err == NULL && (i=psnd_pcm_hw_params_set_format(data->pcmHandle, p, format)) < 0)
558 switch(aluChannelsFromFormat(device->Format))
560 case 1: device->Format = AL_FORMAT_MONO16; break;
561 case 2: device->Format = AL_FORMAT_STEREO16; break;
562 case 4: device->Format = AL_FORMAT_QUAD16; break;
563 case 6: device->Format = AL_FORMAT_51CHN16; break;
564 case 7: device->Format = AL_FORMAT_61CHN16; break;
565 case 8: device->Format = AL_FORMAT_71CHN16; break;
567 if((i=psnd_pcm_hw_params_set_format(data->pcmHandle, p, SND_PCM_FORMAT_S16)) < 0)
569 switch(aluChannelsFromFormat(device->Format))
571 case 1: device->Format = AL_FORMAT_MONO8; break;
572 case 2: device->Format = AL_FORMAT_STEREO8; break;
573 case 4: device->Format = AL_FORMAT_QUAD8; break;
574 case 6: device->Format = AL_FORMAT_51CHN8; break;
575 case 7: device->Format = AL_FORMAT_61CHN8; break;
576 case 8: device->Format = AL_FORMAT_71CHN8; break;
578 if((i=psnd_pcm_hw_params_set_format(data->pcmHandle, p, SND_PCM_FORMAT_U8)) < 0)
579 err = "set format";
582 /* set channels (implicitly sets frame bits) */
583 if(err == NULL && (i=psnd_pcm_hw_params_set_channels(data->pcmHandle, p, aluChannelsFromFormat(device->Format))) < 0)
585 switch(aluBytesFromFormat(device->Format))
587 case 1: device->Format = AL_FORMAT_MONO8; break;
588 case 2: device->Format = AL_FORMAT_MONO16; break;
589 case 4: device->Format = AL_FORMAT_MONO_FLOAT32; break;
591 if((i=psnd_pcm_hw_params_set_channels(data->pcmHandle, p, 1)) < 0)
592 err = "set channels";
594 /* set periods (implicitly constrains period/buffer parameters) */
595 if(err == NULL && (i=psnd_pcm_hw_params_set_periods_near(data->pcmHandle, p, &periods, NULL)) < 0)
596 err = "set periods near";
597 /* set rate (implicitly constrains period/buffer parameters) */
598 if(err == NULL && (i=psnd_pcm_hw_params_set_rate_near(data->pcmHandle, p, &rate, NULL)) < 0)
599 err = "set rate near";
600 /* set period size in frame units (implicitly sets buffer size/bytes/time and period time/bytes) */
601 if(err == NULL && (i=psnd_pcm_hw_params_set_period_size_near(data->pcmHandle, p, &periodSizeInFrames, NULL)) < 0)
602 err = "set period size near";
603 /* install and prepare hardware configuration */
604 if(err == NULL && (i=psnd_pcm_hw_params(data->pcmHandle, p)) < 0)
605 err = "set params";
606 if(err == NULL && (i=psnd_pcm_hw_params_get_access(p, &access)) < 0)
607 err = "get access";
608 if(err == NULL && (i=psnd_pcm_hw_params_get_period_size(p, &periodSizeInFrames, NULL)) < 0)
609 err = "get period size";
610 if(err == NULL && (i=psnd_pcm_hw_params_get_periods(p, &periods, NULL)) < 0)
611 err = "get periods";
612 if(err != NULL)
614 AL_PRINT("%s failed: %s\n", err, psnd_strerror(i));
615 psnd_pcm_hw_params_free(p);
616 return ALC_FALSE;
619 psnd_pcm_hw_params_free(p);
621 err = NULL;
622 psnd_pcm_sw_params_malloc(&sp);
624 if((i=psnd_pcm_sw_params_current(data->pcmHandle, sp)) != 0)
625 err = "sw current";
626 if(err == NULL && (i=psnd_pcm_sw_params_set_avail_min(data->pcmHandle, sp, periodSizeInFrames)) != 0)
627 err = "sw set avail min";
628 if(err == NULL && (i=psnd_pcm_sw_params(data->pcmHandle, sp)) != 0)
629 err = "sw set params";
630 if(err != NULL)
632 AL_PRINT("%s failed: %s\n", err, psnd_strerror(i));
633 psnd_pcm_sw_params_free(sp);
634 return ALC_FALSE;
637 psnd_pcm_sw_params_free(sp);
639 data->size = psnd_pcm_frames_to_bytes(data->pcmHandle, periodSizeInFrames);
640 if(access == SND_PCM_ACCESS_RW_INTERLEAVED)
642 /* Increase periods by one, since the temp buffer counts as an extra
643 * period */
644 periods++;
645 data->buffer = malloc(data->size);
646 if(!data->buffer)
648 AL_PRINT("buffer malloc failed\n");
649 return ALC_FALSE;
651 data->thread = StartThread(ALSANoMMapProc, device);
653 else
655 i = psnd_pcm_prepare(data->pcmHandle);
656 if(i < 0)
658 AL_PRINT("prepare error: %s\n", psnd_strerror(i));
659 return ALC_FALSE;
661 data->thread = StartThread(ALSAProc, device);
663 if(data->thread == NULL)
665 AL_PRINT("Could not create playback thread\n");
666 free(data->buffer);
667 data->buffer = NULL;
668 return ALC_FALSE;
671 device->UpdateSize = periodSizeInFrames;
672 device->NumUpdates = periods;
673 device->Frequency = rate;
675 return ALC_TRUE;
678 static void alsa_stop_playback(ALCdevice *device)
680 alsa_data *data = (alsa_data*)device->ExtraData;
682 if(data->thread)
684 data->killNow = 1;
685 StopThread(data->thread);
686 data->thread = NULL;
688 free(data->buffer);
689 data->buffer = NULL;
693 static ALCboolean alsa_open_capture(ALCdevice *pDevice, const ALCchar *deviceName)
695 const char *devName;
696 snd_pcm_hw_params_t *p;
697 snd_pcm_uframes_t bufferSizeInFrames;
698 snd_pcm_format_t format;
699 ALuint frameSize;
700 alsa_data *data;
701 char driver[64];
702 char *err;
703 int i;
705 strncpy(driver, GetConfigValue("alsa", "capture", "default"), sizeof(driver)-1);
706 driver[sizeof(driver)-1] = 0;
707 if(!deviceName)
708 deviceName = allCaptureDevNameMap[0].name;
709 else
711 size_t idx;
713 for(idx = 0;idx < numCaptureDevNames;idx++)
715 if(allCaptureDevNameMap[idx].name &&
716 strcmp(deviceName, allCaptureDevNameMap[idx].name) == 0)
718 devName = allCaptureDevNameMap[idx].name;
719 if(idx > 0)
720 sprintf(driver, "plughw:%d,%d", allCaptureDevNameMap[idx].card, allCaptureDevNameMap[idx].dev);
721 break;
724 if(idx == numCaptureDevNames)
725 return ALC_FALSE;
728 alsa_load();
729 if(!alsa_handle)
730 return ALC_FALSE;
732 data = (alsa_data*)calloc(1, sizeof(alsa_data));
734 i = psnd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
735 if(i < 0)
737 Sleep(200);
738 i = psnd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
740 if(i >= 0)
742 i = psnd_pcm_nonblock(data->pcmHandle, 0);
743 if(i < 0)
744 psnd_pcm_close(data->pcmHandle);
746 if(i < 0)
748 AL_PRINT("Could not open capture device '%s': %s\n", driver, psnd_strerror(i));
749 free(data);
750 alsa_unload();
751 return ALC_FALSE;
754 switch(aluBytesFromFormat(pDevice->Format))
756 case 1:
757 format = SND_PCM_FORMAT_U8;
758 break;
759 case 2:
760 format = SND_PCM_FORMAT_S16;
761 break;
762 case 4:
763 format = SND_PCM_FORMAT_FLOAT;
764 break;
765 default:
766 AL_PRINT("Unknown format: 0x%x\n", pDevice->Format);
767 goto error;
770 err = NULL;
771 bufferSizeInFrames = pDevice->UpdateSize * pDevice->NumUpdates;
772 psnd_pcm_hw_params_malloc(&p);
774 if((i=psnd_pcm_hw_params_any(data->pcmHandle, p)) < 0)
775 err = "any";
776 /* set interleaved access */
777 if(err == NULL && (i=psnd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
778 err = "set access";
779 /* set format (implicitly sets sample bits) */
780 if(err == NULL && (i=psnd_pcm_hw_params_set_format(data->pcmHandle, p, format)) < 0)
781 err = "set format";
782 /* set channels (implicitly sets frame bits) */
783 if(err == NULL && (i=psnd_pcm_hw_params_set_channels(data->pcmHandle, p, aluChannelsFromFormat(pDevice->Format))) < 0)
784 err = "set channels";
785 /* set rate (implicitly constrains period/buffer parameters) */
786 if(err == NULL && (i=psnd_pcm_hw_params_set_rate(data->pcmHandle, p, pDevice->Frequency, 0)) < 0)
787 err = "set rate near";
788 /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */
789 if(err == NULL && (i=psnd_pcm_hw_params_set_buffer_size_near(data->pcmHandle, p, &bufferSizeInFrames)) < 0)
790 err = "set buffer size near";
791 /* install and prepare hardware configuration */
792 if(err == NULL && (i=psnd_pcm_hw_params(data->pcmHandle, p)) < 0)
793 err = "set params";
794 if(err != NULL)
796 AL_PRINT("%s failed: %s\n", err, psnd_strerror(i));
797 psnd_pcm_hw_params_free(p);
798 goto error;
801 if((i=psnd_pcm_hw_params_get_period_size(p, &bufferSizeInFrames, NULL)) < 0)
803 AL_PRINT("get size failed: %s\n", psnd_strerror(i));
804 psnd_pcm_hw_params_free(p);
805 goto error;
808 psnd_pcm_hw_params_free(p);
810 frameSize = aluChannelsFromFormat(pDevice->Format);
811 frameSize *= aluBytesFromFormat(pDevice->Format);
813 data->ring = CreateRingBuffer(frameSize, pDevice->UpdateSize*pDevice->NumUpdates);
814 if(!data->ring)
816 AL_PRINT("ring buffer create failed\n");
817 goto error;
820 data->size = psnd_pcm_frames_to_bytes(data->pcmHandle, bufferSizeInFrames);
821 data->buffer = malloc(data->size);
822 if(!data->buffer)
824 AL_PRINT("buffer malloc failed\n");
825 goto error;
828 pDevice->ExtraData = data;
829 data->thread = StartThread(ALSANoMMapCaptureProc, pDevice);
830 if(data->thread == NULL)
832 AL_PRINT("Could not create capture thread\n");
833 goto error;
836 pDevice->szDeviceName = strdup(deviceName);
837 return ALC_TRUE;
839 error:
840 free(data->buffer);
841 DestroyRingBuffer(data->ring);
842 psnd_pcm_close(data->pcmHandle);
843 free(data);
844 alsa_unload();
846 pDevice->ExtraData = NULL;
847 return ALC_FALSE;
850 static void alsa_close_capture(ALCdevice *pDevice)
852 alsa_data *data = (alsa_data*)pDevice->ExtraData;
854 data->killNow = 1;
855 StopThread(data->thread);
857 psnd_pcm_close(data->pcmHandle);
858 DestroyRingBuffer(data->ring);
860 free(data->buffer);
861 free(data);
862 pDevice->ExtraData = NULL;
864 alsa_unload();
867 static void alsa_start_capture(ALCdevice *pDevice)
869 alsa_data *data = (alsa_data*)pDevice->ExtraData;
870 data->doCapture = 1;
873 static void alsa_stop_capture(ALCdevice *pDevice)
875 alsa_data *data = (alsa_data*)pDevice->ExtraData;
876 data->doCapture = 0;
879 static void alsa_capture_samples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples)
881 alsa_data *data = (alsa_data*)pDevice->ExtraData;
883 if(lSamples <= (ALCuint)RingBufferSize(data->ring))
884 ReadRingBuffer(data->ring, pBuffer, lSamples);
885 else
886 alcSetError(ALC_INVALID_VALUE);
889 static ALCuint alsa_available_samples(ALCdevice *pDevice)
891 alsa_data *data = (alsa_data*)pDevice->ExtraData;
892 return RingBufferSize(data->ring);
896 BackendFuncs alsa_funcs = {
897 alsa_open_playback,
898 alsa_close_playback,
899 alsa_reset_playback,
900 alsa_stop_playback,
901 alsa_open_capture,
902 alsa_close_capture,
903 alsa_start_capture,
904 alsa_stop_capture,
905 alsa_capture_samples,
906 alsa_available_samples
909 void alc_alsa_init(BackendFuncs *func_list)
911 *func_list = alsa_funcs;
914 void alc_alsa_deinit(void)
916 ALuint i;
918 for(i = 0;i < numDevNames;++i)
919 free(allDevNameMap[i].name);
920 free(allDevNameMap);
921 allDevNameMap = NULL;
922 numDevNames = 0;
924 for(i = 0;i < numCaptureDevNames;++i)
925 free(allCaptureDevNameMap[i].name);
926 free(allCaptureDevNameMap);
927 allCaptureDevNameMap = NULL;
928 numCaptureDevNames = 0;
931 void alc_alsa_probe(int type)
933 snd_ctl_t *handle;
934 int card, err, dev, idx;
935 snd_ctl_card_info_t *info;
936 snd_pcm_info_t *pcminfo;
937 snd_pcm_stream_t stream;
938 char name[128];
939 ALuint i;
941 alsa_load();
942 if(!alsa_handle) return;
944 psnd_ctl_card_info_malloc(&info);
945 psnd_pcm_info_malloc(&pcminfo);
947 card = -1;
948 if((err=psnd_card_next(&card)) < 0)
949 AL_PRINT("Failed to find a card: %s\n", psnd_strerror(err));
951 if(type == DEVICE_PROBE)
952 AppendDeviceList(alsaDevice);
953 else if(type == ALL_DEVICE_PROBE)
955 stream = SND_PCM_STREAM_PLAYBACK;
957 for(i = 0;i < numDevNames;++i)
958 free(allDevNameMap[i].name);
960 allDevNameMap = realloc(allDevNameMap, sizeof(DevMap) * 1);
961 allDevNameMap[0].name = strdup("ALSA Software on default");
962 AppendAllDeviceList(allDevNameMap[0].name);
964 idx = 1;
965 while(card >= 0) {
966 sprintf(name, "hw:%d", card);
967 if ((err = psnd_ctl_open(&handle, name, 0)) < 0) {
968 AL_PRINT("control open (%i): %s\n", card, psnd_strerror(err));
969 goto next_card;
971 if ((err = psnd_ctl_card_info(handle, info)) < 0) {
972 AL_PRINT("control hardware info (%i): %s\n", card, psnd_strerror(err));
973 psnd_ctl_close(handle);
974 goto next_card;
977 dev = -1;
978 while(1) {
979 const char *cname, *dname;
980 void *temp;
982 if (psnd_ctl_pcm_next_device(handle, &dev)<0)
983 AL_PRINT("snd_ctl_pcm_next_device failed\n");
984 if (dev < 0)
985 break;
987 psnd_pcm_info_set_device(pcminfo, dev);
988 psnd_pcm_info_set_subdevice(pcminfo, 0);
989 psnd_pcm_info_set_stream(pcminfo, stream);
990 if ((err = psnd_ctl_pcm_info(handle, pcminfo)) < 0) {
991 if (err != -ENOENT)
992 AL_PRINT("control digital audio info (%i): %s\n", card, psnd_strerror(err));
993 continue;
996 temp = realloc(allDevNameMap, sizeof(DevMap) * (idx+1));
997 if(temp)
999 allDevNameMap = temp;
1000 cname = psnd_ctl_card_info_get_name(info);
1001 dname = psnd_pcm_info_get_name(pcminfo);
1002 snprintf(name, sizeof(name), "ALSA Software on %s [%s] (hw:%d,%d)",
1003 cname, dname, card, dev);
1004 AppendAllDeviceList(name);
1005 allDevNameMap[idx].name = strdup(name);
1006 allDevNameMap[idx].card = card;
1007 allDevNameMap[idx].dev = dev;
1008 idx++;
1011 psnd_ctl_close(handle);
1012 next_card:
1013 if(psnd_card_next(&card) < 0) {
1014 AL_PRINT("snd_card_next failed\n");
1015 break;
1018 numDevNames = idx;
1020 else if(type == CAPTURE_DEVICE_PROBE)
1022 stream = SND_PCM_STREAM_CAPTURE;
1024 for(i = 0;i < numCaptureDevNames;++i)
1025 free(allCaptureDevNameMap[i].name);
1027 allCaptureDevNameMap = realloc(allCaptureDevNameMap, sizeof(DevMap) * 1);
1028 allCaptureDevNameMap[0].name = strdup("ALSA Capture on default");
1029 AppendCaptureDeviceList(allCaptureDevNameMap[0].name);
1031 idx = 1;
1032 while (card >= 0) {
1033 sprintf(name, "hw:%d", card);
1034 handle = NULL;
1035 if ((err = psnd_ctl_open(&handle, name, 0)) < 0) {
1036 AL_PRINT("control open (%i): %s\n", card, psnd_strerror(err));
1038 if (err >= 0 && (err = psnd_ctl_card_info(handle, info)) < 0) {
1039 AL_PRINT("control hardware info (%i): %s\n", card, psnd_strerror(err));
1041 else if (err >= 0)
1043 dev = -1;
1044 while(1) {
1045 const char *cname, *dname;
1046 void *temp;
1048 if (psnd_ctl_pcm_next_device(handle, &dev)<0)
1049 AL_PRINT("snd_ctl_pcm_next_device failed\n");
1050 if (dev < 0)
1051 break;
1052 psnd_pcm_info_set_device(pcminfo, dev);
1053 psnd_pcm_info_set_subdevice(pcminfo, 0);
1054 psnd_pcm_info_set_stream(pcminfo, stream);
1055 if ((err = psnd_ctl_pcm_info(handle, pcminfo)) < 0) {
1056 if (err != -ENOENT)
1057 AL_PRINT("control digital audio info (%i): %s\n", card, psnd_strerror(err));
1058 continue;
1061 temp = realloc(allCaptureDevNameMap, sizeof(DevMap) * (idx+1));
1062 if(temp)
1064 allCaptureDevNameMap = temp;
1065 cname = psnd_ctl_card_info_get_name(info);
1066 dname = psnd_pcm_info_get_name(pcminfo);
1067 snprintf(name, sizeof(name), "ALSA Capture on %s [%s] (hw:%d,%d)",
1068 cname, dname, card, dev);
1069 AppendCaptureDeviceList(name);
1070 allCaptureDevNameMap[idx].name = strdup(name);
1071 allCaptureDevNameMap[idx].card = card;
1072 allCaptureDevNameMap[idx].dev = dev;
1073 idx++;
1077 if(handle) psnd_ctl_close(handle);
1078 if(psnd_card_next(&card) < 0) {
1079 AL_PRINT("snd_card_next failed\n");
1080 break;
1083 numCaptureDevNames = idx;
1086 psnd_pcm_info_free(pcminfo);
1087 psnd_ctl_card_info_free(info);
1089 alsa_unload();