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
33 #include <alsa/asoundlib.h>
38 snd_pcm_format_t format
;
48 static void *alsa_handle
;
49 #define MAKE_FUNC(f) static typeof(f) * p##f
50 MAKE_FUNC(snd_strerror
);
51 MAKE_FUNC(snd_pcm_open
);
52 MAKE_FUNC(snd_pcm_close
);
53 MAKE_FUNC(snd_pcm_nonblock
);
54 MAKE_FUNC(snd_pcm_frames_to_bytes
);
55 MAKE_FUNC(snd_pcm_hw_params_malloc
);
56 MAKE_FUNC(snd_pcm_hw_params_free
);
57 MAKE_FUNC(snd_pcm_hw_params_any
);
58 MAKE_FUNC(snd_pcm_hw_params_set_access
);
59 MAKE_FUNC(snd_pcm_hw_params_set_format
);
60 MAKE_FUNC(snd_pcm_hw_params_set_channels
);
61 MAKE_FUNC(snd_pcm_hw_params_set_periods_near
);
62 MAKE_FUNC(snd_pcm_hw_params_set_rate_near
);
63 MAKE_FUNC(snd_pcm_hw_params_set_rate
);
64 MAKE_FUNC(snd_pcm_hw_params_set_buffer_size_near
);
65 MAKE_FUNC(snd_pcm_hw_params_set_buffer_size_min
);
66 MAKE_FUNC(snd_pcm_hw_params
);
67 MAKE_FUNC(snd_pcm_prepare
);
68 MAKE_FUNC(snd_pcm_start
);
69 MAKE_FUNC(snd_pcm_resume
);
70 MAKE_FUNC(snd_pcm_state
);
71 MAKE_FUNC(snd_pcm_avail_update
);
72 MAKE_FUNC(snd_pcm_areas_silence
);
73 MAKE_FUNC(snd_pcm_mmap_begin
);
74 MAKE_FUNC(snd_pcm_mmap_commit
);
75 MAKE_FUNC(snd_pcm_drain
);
76 MAKE_FUNC(snd_pcm_info_malloc
);
77 MAKE_FUNC(snd_pcm_info_free
);
78 MAKE_FUNC(snd_pcm_info_set_device
);
79 MAKE_FUNC(snd_pcm_info_set_subdevice
);
80 MAKE_FUNC(snd_pcm_info_set_stream
);
81 MAKE_FUNC(snd_pcm_info_get_name
);
82 MAKE_FUNC(snd_ctl_pcm_next_device
);
83 MAKE_FUNC(snd_ctl_pcm_info
);
84 MAKE_FUNC(snd_ctl_open
);
85 MAKE_FUNC(snd_ctl_close
);
86 MAKE_FUNC(snd_ctl_card_info_malloc
);
87 MAKE_FUNC(snd_ctl_card_info_free
);
88 MAKE_FUNC(snd_ctl_card_info
);
89 MAKE_FUNC(snd_ctl_card_info_get_name
);
90 MAKE_FUNC(snd_card_next
);
93 #define MAX_DEVICES 16
94 #define MAX_ALL_DEVICES 32
96 static DevMap allDevNameMap
[MAX_ALL_DEVICES
];
97 static ALCchar
*alsaDeviceList
[MAX_DEVICES
];
98 static ALCchar
*alsaCaptureDeviceList
[MAX_DEVICES
];
100 static int xrun_recovery(snd_pcm_t
*handle
, int err
)
104 err
= psnd_pcm_prepare(handle
);
106 err
= psnd_pcm_start(handle
);
108 AL_PRINT("prepare failed: %s\n", psnd_strerror(err
));
110 else if (err
== -ESTRPIPE
)
112 while ((err
= psnd_pcm_resume(handle
)) == -EAGAIN
)
113 usleep(1); /* wait until the suspend flag is released */
116 err
= psnd_pcm_prepare(handle
);
118 err
= psnd_pcm_start(handle
);
120 AL_PRINT("prepare failed: %s\n", psnd_strerror(err
));
127 static ALuint
ALSAProc(ALvoid
*ptr
)
129 ALCdevice
*pDevice
= (ALCdevice
*)ptr
;
130 alsa_data
*data
= (alsa_data
*)pDevice
->ExtraData
;
131 const snd_pcm_channel_area_t
*areas
= NULL
;
132 snd_pcm_sframes_t avail
, commitres
;
133 snd_pcm_uframes_t offset
, frames
;
138 while(!data
->killNow
)
140 snd_pcm_state_t state
= psnd_pcm_state(data
->pcmHandle
);
141 if(state
== SND_PCM_STATE_XRUN
)
143 err
= xrun_recovery(data
->pcmHandle
, -EPIPE
);
146 AL_PRINT("XRUN recovery failed: %s\n", psnd_strerror(err
));
150 else if (state
== SND_PCM_STATE_SUSPENDED
)
152 err
= xrun_recovery(data
->pcmHandle
, -ESTRPIPE
);
155 AL_PRINT("SUSPEND recovery failed: %s\n", psnd_strerror(err
));
160 avail
= psnd_pcm_avail_update(data
->pcmHandle
);
163 err
= xrun_recovery(data
->pcmHandle
, avail
);
166 AL_PRINT("available update failed: %s\n", psnd_strerror(err
));
171 // make sure there's frames to process
178 // it is possible that contiguous areas are smaller, thus we use a loop
183 err
= psnd_pcm_mmap_begin(data
->pcmHandle
, &areas
, &offset
, &frames
);
186 err
= xrun_recovery(data
->pcmHandle
, err
);
188 AL_PRINT("mmap begin error: %s\n", psnd_strerror(err
));
192 SuspendContext(NULL
);
193 WritePtr
= (char*)areas
->addr
+ (offset
* areas
->step
/ 8);
194 WriteCnt
= psnd_pcm_frames_to_bytes(data
->pcmHandle
, frames
);
195 aluMixData(pDevice
->Context
, WritePtr
, WriteCnt
, pDevice
->Format
);
196 ProcessContext(NULL
);
198 commitres
= psnd_pcm_mmap_commit(data
->pcmHandle
, offset
, frames
);
199 if (commitres
< 0 || (commitres
-frames
) != 0)
201 AL_PRINT("mmap commit error: %s\n",
202 psnd_strerror(commitres
>= 0 ? -EPIPE
: commitres
));
213 static void fill_silence(snd_pcm_t
*pcmHandle
, snd_pcm_format_t alsaFormat
, int channels
)
215 const snd_pcm_channel_area_t
*areas
= NULL
;
216 snd_pcm_sframes_t avail
, commitres
;
217 snd_pcm_uframes_t offset
, frames
;
220 avail
= psnd_pcm_avail_update(pcmHandle
);
223 err
= xrun_recovery(pcmHandle
, avail
);
226 AL_PRINT("available update failed: %s\n", psnd_strerror(err
));
231 // it is possible that contiguous areas are smaller, thus we use a loop
236 err
= psnd_pcm_mmap_begin(pcmHandle
, &areas
, &offset
, &frames
);
239 err
= xrun_recovery(pcmHandle
, err
);
242 AL_PRINT("mmap begin error: %s\n", psnd_strerror(err
));
248 psnd_pcm_areas_silence(areas
, offset
, channels
, frames
, alsaFormat
);
250 commitres
= psnd_pcm_mmap_commit(pcmHandle
, offset
, frames
);
251 if (commitres
< 0 || (commitres
-frames
) != 0)
253 AL_PRINT("mmap commit error: %s\n",
254 psnd_strerror(commitres
>= 0 ? -EPIPE
: commitres
));
262 static ALCboolean
alsa_open_playback(ALCdevice
*device
, const ALCchar
*deviceName
)
264 snd_pcm_uframes_t bufferSizeInFrames
;
265 snd_pcm_hw_params_t
*p
= NULL
;
266 unsigned int periods
;
272 strncpy(driver
, GetConfigValue("alsa", "default", "default"), sizeof(driver
)-1);
273 driver
[sizeof(driver
)-1] = 0;
278 for(idx
= 0;idx
< MAX_ALL_DEVICES
;idx
++)
280 if(allDevNameMap
[idx
].name
&&
281 strcmp(deviceName
, allDevNameMap
[idx
].name
) == 0)
283 device
->szDeviceName
= allDevNameMap
[idx
].name
;
285 sprintf(driver
, "hw:%d,%d", allDevNameMap
[idx
].card
, allDevNameMap
[idx
].dev
);
289 for(idx
= 0;idx
< MAX_DEVICES
;idx
++)
291 if(alsaDeviceList
[idx
] &&
292 strcmp(deviceName
, alsaDeviceList
[idx
]) == 0)
294 device
->szDeviceName
= alsaDeviceList
[idx
];
296 sprintf(driver
, "hw:%zd,0", idx
-1);
303 device
->szDeviceName
= alsaDeviceList
[0];
306 data
= (alsa_data
*)calloc(1, sizeof(alsa_data
));
308 i
= psnd_pcm_open(&data
->pcmHandle
, driver
, SND_PCM_STREAM_PLAYBACK
, SND_PCM_NONBLOCK
);
312 i
= psnd_pcm_open(&data
->pcmHandle
, driver
, SND_PCM_STREAM_PLAYBACK
, SND_PCM_NONBLOCK
);
316 i
= psnd_pcm_nonblock(data
->pcmHandle
, 0);
318 psnd_pcm_close(data
->pcmHandle
);
323 AL_PRINT("Could not open playback device '%s': %s\n", driver
, psnd_strerror(i
));
327 switch(device
->Format
)
329 case AL_FORMAT_MONO8
:
330 case AL_FORMAT_STEREO8
:
331 case AL_FORMAT_QUAD8
:
332 data
->format
= SND_PCM_FORMAT_U8
;
334 case AL_FORMAT_MONO16
:
335 case AL_FORMAT_STEREO16
:
336 case AL_FORMAT_QUAD16
:
337 data
->format
= SND_PCM_FORMAT_S16
;
340 data
->format
= SND_PCM_FORMAT_UNKNOWN
;
341 AL_PRINT("Unknown format?! %x\n", device
->Format
);
344 periods
= GetConfigValueInt("alsa", "periods", 4);
345 if((int)periods
<= 0)
347 bufferSizeInFrames
= device
->UpdateFreq
;
349 psnd_pcm_hw_params_malloc(&p
);
350 #define ok(func, str) (i=(func),((i<0)?(err=(str)),0:1))
351 /* start with the largest configuration space possible */
352 if(!(ok(psnd_pcm_hw_params_any(data
->pcmHandle
, p
), "any") &&
353 /* set interleaved access */
354 ok(psnd_pcm_hw_params_set_access(data
->pcmHandle
, p
, SND_PCM_ACCESS_MMAP_INTERLEAVED
), "set access") &&
355 /* set format (implicitly sets sample bits) */
356 ok(psnd_pcm_hw_params_set_format(data
->pcmHandle
, p
, data
->format
), "set format") &&
357 /* set channels (implicitly sets frame bits) */
358 ok(psnd_pcm_hw_params_set_channels(data
->pcmHandle
, p
, device
->Channels
), "set channels") &&
359 /* set periods (implicitly constrains period/buffer parameters) */
360 ok(psnd_pcm_hw_params_set_periods_near(data
->pcmHandle
, p
, &periods
, NULL
), "set periods near") &&
361 /* set rate (implicitly constrains period/buffer parameters) */
362 ok(psnd_pcm_hw_params_set_rate_near(data
->pcmHandle
, p
, &device
->Frequency
, NULL
), "set rate near") &&
363 /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */
364 ok(psnd_pcm_hw_params_set_buffer_size_near(data
->pcmHandle
, p
, &bufferSizeInFrames
), "set buffer size near") &&
365 /* install and prepare hardware configuration */
366 ok(psnd_pcm_hw_params(data
->pcmHandle
, p
), "set params")))
368 AL_PRINT("%s failed: %s\n", err
, psnd_strerror(i
));
369 psnd_pcm_hw_params_free(p
);
370 psnd_pcm_close(data
->pcmHandle
);
375 psnd_pcm_hw_params_free(p
);
377 device
->MaxNoOfSources
= 256;
378 device
->UpdateFreq
= bufferSizeInFrames
;
380 i
= psnd_pcm_prepare(data
->pcmHandle
);
383 AL_PRINT("prepare error: %s\n", psnd_strerror(i
));
384 psnd_pcm_close(data
->pcmHandle
);
389 fill_silence(data
->pcmHandle
, data
->format
, device
->Channels
);
390 i
= psnd_pcm_start(data
->pcmHandle
);
393 AL_PRINT("start error: %s\n", psnd_strerror(i
));
394 psnd_pcm_close(data
->pcmHandle
);
399 device
->ExtraData
= data
;
400 data
->thread
= StartThread(ALSAProc
, device
);
401 if(data
->thread
== NULL
)
403 psnd_pcm_close(data
->pcmHandle
);
404 device
->ExtraData
= NULL
;
412 static void alsa_close_playback(ALCdevice
*device
)
414 alsa_data
*data
= (alsa_data
*)device
->ExtraData
;
416 StopThread(data
->thread
);
417 psnd_pcm_close(data
->pcmHandle
);
420 device
->ExtraData
= NULL
;
424 static ALCboolean
alsa_open_capture(ALCdevice
*pDevice
, const ALCchar
*deviceName
, ALCuint frequency
, ALCenum format
, ALCsizei SampleSize
)
426 snd_pcm_format_t alsaFormat
;
427 snd_pcm_hw_params_t
*p
;
428 unsigned int periods
= 4;
429 snd_pcm_uframes_t bufferSizeInFrames
= SampleSize
;
435 strncpy(driver
, GetConfigValue("alsa", "capture", "default"), sizeof(driver
)-1);
436 driver
[sizeof(driver
)-1] = 0;
441 for(idx
= 0;idx
< MAX_DEVICES
;idx
++)
443 if(alsaCaptureDeviceList
[idx
] &&
444 strcmp(deviceName
, alsaCaptureDeviceList
[idx
]) == 0)
446 pDevice
->szDeviceName
= alsaCaptureDeviceList
[idx
];
448 sprintf(driver
, "hw:%zd,0", idx
-1);
455 pDevice
->szDeviceName
= alsaCaptureDeviceList
[0];
458 data
= (alsa_data
*)calloc(1, sizeof(alsa_data
));
460 i
= psnd_pcm_open(&data
->pcmHandle
, driver
, SND_PCM_STREAM_CAPTURE
, SND_PCM_NONBLOCK
);
464 i
= psnd_pcm_open(&data
->pcmHandle
, driver
, SND_PCM_STREAM_CAPTURE
, SND_PCM_NONBLOCK
);
468 i
= psnd_pcm_nonblock(data
->pcmHandle
, 0);
470 psnd_pcm_close(data
->pcmHandle
);
475 AL_PRINT("Could not open capture device '%s': %s\n", driver
, psnd_strerror(i
));
479 switch(aluBytesFromFormat(format
))
482 alsaFormat
= SND_PCM_FORMAT_U8
;
485 alsaFormat
= SND_PCM_FORMAT_S16
;
488 alsaFormat
= SND_PCM_FORMAT_UNKNOWN
;
489 AL_PRINT("Unknown format?! %x\n", format
);
492 psnd_pcm_hw_params_malloc(&p
);
493 #define ok(func, str) (i=(func),((i<0)?(err=(str)),0:1))
494 /* start with the largest configuration space possible */
495 if(!(ok(psnd_pcm_hw_params_any(data
->pcmHandle
, p
), "any") &&
496 /* set interleaved access */
497 ok(psnd_pcm_hw_params_set_access(data
->pcmHandle
, p
, SND_PCM_ACCESS_MMAP_INTERLEAVED
), "set access") &&
498 /* set format (implicitly sets sample bits) */
499 ok(psnd_pcm_hw_params_set_format(data
->pcmHandle
, p
, alsaFormat
), "set format") &&
500 /* set channels (implicitly sets frame bits) */
501 ok(psnd_pcm_hw_params_set_channels(data
->pcmHandle
, p
, pDevice
->Channels
), "set channels") &&
502 /* set periods (implicitly constrains period/buffer parameters) */
503 ok(psnd_pcm_hw_params_set_periods_near(data
->pcmHandle
, p
, &periods
, NULL
), "set periods near") &&
504 /* set rate (implicitly constrains period/buffer parameters) */
505 ok(psnd_pcm_hw_params_set_rate(data
->pcmHandle
, p
, frequency
, 0), "set rate") &&
506 /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */
507 ok(psnd_pcm_hw_params_set_buffer_size_min(data
->pcmHandle
, p
, &bufferSizeInFrames
), "set buffer size min") &&
508 /* install and prepare hardware configuration */
509 ok(psnd_pcm_hw_params(data
->pcmHandle
, p
), "set params")))
511 AL_PRINT("%s failed: %s\n", err
, psnd_strerror(i
));
512 psnd_pcm_hw_params_free(p
);
513 psnd_pcm_close(data
->pcmHandle
);
518 psnd_pcm_hw_params_free(p
);
520 i
= psnd_pcm_prepare(data
->pcmHandle
);
523 AL_PRINT("prepare error: %s\n", psnd_strerror(i
));
524 psnd_pcm_close(data
->pcmHandle
);
529 pDevice
->ExtraData
= data
;
533 static void alsa_close_capture(ALCdevice
*pDevice
)
535 alsa_data
*data
= (alsa_data
*)pDevice
->ExtraData
;
536 psnd_pcm_close(data
->pcmHandle
);
539 pDevice
->ExtraData
= NULL
;
542 static void alsa_start_capture(ALCdevice
*pDevice
)
544 alsa_data
*data
= (alsa_data
*)pDevice
->ExtraData
;
545 psnd_pcm_start(data
->pcmHandle
);
548 static void alsa_stop_capture(ALCdevice
*pDevice
)
550 alsa_data
*data
= (alsa_data
*)pDevice
->ExtraData
;
551 psnd_pcm_drain(data
->pcmHandle
);
554 static void alsa_capture_samples(ALCdevice
*pDevice
, ALCvoid
*pBuffer
, ALCuint lSamples
)
556 alsa_data
*data
= (alsa_data
*)pDevice
->ExtraData
;
557 const snd_pcm_channel_area_t
*areas
= NULL
;
558 snd_pcm_sframes_t frames
, commitres
;
559 snd_pcm_uframes_t size
, offset
;
562 frames
= psnd_pcm_avail_update(data
->pcmHandle
);
565 err
= xrun_recovery(data
->pcmHandle
, frames
);
567 AL_PRINT("available update failed: %s\n", psnd_strerror(err
));
569 frames
= psnd_pcm_avail_update(data
->pcmHandle
);
571 if (frames
< (snd_pcm_sframes_t
)lSamples
)
573 SetALCError(ALC_INVALID_VALUE
);
577 // it is possible that contiguous areas are smaller, thus we use a loop
584 err
= psnd_pcm_mmap_begin(data
->pcmHandle
, &areas
, &offset
, &size
);
587 err
= xrun_recovery(data
->pcmHandle
, err
);
590 AL_PRINT("mmap begin error: %s\n", psnd_strerror(err
));
596 Pointer
= (char*)areas
->addr
+ (offset
* areas
->step
/ 8);
597 Count
= size
* pDevice
->FrameSize
;
599 memcpy(pBuffer
, Pointer
, Count
);
600 pBuffer
= (char*)pBuffer
+ Count
;
602 commitres
= psnd_pcm_mmap_commit(data
->pcmHandle
, offset
, size
);
603 if (commitres
< 0 || (commitres
-size
) != 0)
605 AL_PRINT("mmap commit error: %s\n",
606 psnd_strerror(commitres
>= 0 ? -EPIPE
: commitres
));
614 static ALCuint
alsa_available_samples(ALCdevice
*pDevice
)
616 alsa_data
*data
= (alsa_data
*)pDevice
->ExtraData
;
617 snd_pcm_sframes_t frames
= psnd_pcm_avail_update(data
->pcmHandle
);
620 int err
= xrun_recovery(data
->pcmHandle
, frames
);
622 AL_PRINT("available update failed: %s\n", psnd_strerror(err
));
624 frames
= psnd_pcm_avail_update(data
->pcmHandle
);
625 if(frames
< 0) /* ew.. */
626 SetALCError(ALC_INVALID_DEVICE
);
628 return max(frames
, 0);
632 BackendFuncs alsa_funcs
= {
639 alsa_capture_samples
,
640 alsa_available_samples
643 void alc_alsa_init(BackendFuncs
*func_list
)
646 int card
, err
, dev
, idx
= 1;
647 snd_ctl_card_info_t
*info
;
648 snd_pcm_info_t
*pcminfo
;
649 snd_pcm_stream_t stream
= SND_PCM_STREAM_PLAYBACK
;
653 *func_list
= alsa_funcs
;
656 alsa_handle
= dlopen("libasound.so.2", RTLD_NOW
);
661 #define LOAD_FUNC(f) do { \
662 p##f = (typeof(f)*)dlsym(alsa_handle, #f); \
663 if((str=dlerror()) != NULL) \
665 dlclose(alsa_handle); \
666 alsa_handle = NULL; \
667 AL_PRINT("Could not load %s from libasound.so.2: %s\n", #f, str); \
674 #define LOAD_FUNC(f) p##f = f
677 LOAD_FUNC(snd_strerror
);
678 LOAD_FUNC(snd_pcm_open
);
679 LOAD_FUNC(snd_pcm_close
);
680 LOAD_FUNC(snd_pcm_nonblock
);
681 LOAD_FUNC(snd_pcm_frames_to_bytes
);
682 LOAD_FUNC(snd_pcm_hw_params_malloc
);
683 LOAD_FUNC(snd_pcm_hw_params_free
);
684 LOAD_FUNC(snd_pcm_hw_params_any
);
685 LOAD_FUNC(snd_pcm_hw_params_set_access
);
686 LOAD_FUNC(snd_pcm_hw_params_set_format
);
687 LOAD_FUNC(snd_pcm_hw_params_set_channels
);
688 LOAD_FUNC(snd_pcm_hw_params_set_periods_near
);
689 LOAD_FUNC(snd_pcm_hw_params_set_rate_near
);
690 LOAD_FUNC(snd_pcm_hw_params_set_rate
);
691 LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_near
);
692 LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_min
);
693 LOAD_FUNC(snd_pcm_hw_params
);
694 LOAD_FUNC(snd_pcm_prepare
);
695 LOAD_FUNC(snd_pcm_start
);
696 LOAD_FUNC(snd_pcm_resume
);
697 LOAD_FUNC(snd_pcm_state
);
698 LOAD_FUNC(snd_pcm_avail_update
);
699 LOAD_FUNC(snd_pcm_areas_silence
);
700 LOAD_FUNC(snd_pcm_mmap_begin
);
701 LOAD_FUNC(snd_pcm_mmap_commit
);
702 LOAD_FUNC(snd_pcm_drain
);
704 LOAD_FUNC(snd_pcm_info_malloc
);
705 LOAD_FUNC(snd_pcm_info_free
);
706 LOAD_FUNC(snd_pcm_info_set_device
);
707 LOAD_FUNC(snd_pcm_info_set_subdevice
);
708 LOAD_FUNC(snd_pcm_info_set_stream
);
709 LOAD_FUNC(snd_pcm_info_get_name
);
710 LOAD_FUNC(snd_ctl_pcm_next_device
);
711 LOAD_FUNC(snd_ctl_pcm_info
);
712 LOAD_FUNC(snd_ctl_open
);
713 LOAD_FUNC(snd_ctl_close
);
714 LOAD_FUNC(snd_ctl_card_info_malloc
);
715 LOAD_FUNC(snd_ctl_card_info_free
);
716 LOAD_FUNC(snd_ctl_card_info
);
717 LOAD_FUNC(snd_ctl_card_info_get_name
);
718 LOAD_FUNC(snd_card_next
);
722 psnd_ctl_card_info_malloc(&info
);
723 psnd_pcm_info_malloc(&pcminfo
);
726 if(psnd_card_next(&card
) < 0 || card
< 0)
727 AL_PRINT("no playback cards found...\n");
730 alsaDeviceList
[0] = AppendDeviceList("ALSA Software on default");
731 allDevNameMap
[0].name
= AppendAllDeviceList("ALSA Software on default");
735 sprintf(name
, "hw:%d", card
);
736 if ((err
= psnd_ctl_open(&handle
, name
, 0)) < 0) {
737 AL_PRINT("control open (%i): %s\n", card
, psnd_strerror(err
));
740 if ((err
= psnd_ctl_card_info(handle
, info
)) < 0) {
741 AL_PRINT("control hardware info (%i): %s\n", card
, psnd_strerror(err
));
742 psnd_ctl_close(handle
);
745 if(card
< MAX_DEVICES
-1) {
746 snprintf(name
, sizeof(name
), "ALSA Software on %s",
747 psnd_ctl_card_info_get_name(info
));
748 alsaDeviceList
[card
+1] = AppendDeviceList(name
);
752 while (idx
< MAX_ALL_DEVICES
) {
753 const char *cname
, *dname
;
755 if (psnd_ctl_pcm_next_device(handle
, &dev
)<0)
756 AL_PRINT("snd_ctl_pcm_next_device failed\n");
759 psnd_pcm_info_set_device(pcminfo
, dev
);
760 psnd_pcm_info_set_subdevice(pcminfo
, 0);
761 psnd_pcm_info_set_stream(pcminfo
, stream
);
762 if ((err
= psnd_ctl_pcm_info(handle
, pcminfo
)) < 0) {
764 AL_PRINT("control digital audio info (%i): %s\n", card
, psnd_strerror(err
));
768 cname
= psnd_ctl_card_info_get_name(info
);
769 dname
= psnd_pcm_info_get_name(pcminfo
);
770 snprintf(name
, sizeof(name
), "ALSA Software on %s [%s]",
772 allDevNameMap
[idx
].name
= AppendAllDeviceList(name
);
773 allDevNameMap
[idx
].card
= card
;
774 allDevNameMap
[idx
].dev
= dev
;
777 psnd_ctl_close(handle
);
779 if(psnd_card_next(&card
) < 0) {
780 AL_PRINT("snd_card_next failed\n");
786 stream
= SND_PCM_STREAM_CAPTURE
;
789 if(psnd_card_next(&card
) < 0 || card
< 0) {
790 AL_PRINT("no capture cards found...\n");
791 psnd_pcm_info_free(pcminfo
);
792 psnd_ctl_card_info_free(info
);
796 alsaCaptureDeviceList
[0] = AppendCaptureDeviceList("ALSA Capture on default");
799 sprintf(name
, "hw:%d", card
);
801 if ((err
= psnd_ctl_open(&handle
, name
, 0)) < 0) {
802 AL_PRINT("control open (%i): %s\n", card
, psnd_strerror(err
));
804 if (err
>= 0 && (err
= psnd_ctl_card_info(handle
, info
)) < 0) {
805 AL_PRINT("control hardware info (%i): %s\n", card
, psnd_strerror(err
));
806 psnd_ctl_close(handle
);
808 else if (err
>= 0 && card
< MAX_DEVICES
-1)
810 snprintf(name
, sizeof(name
), "ALSA Capture on %s",
811 psnd_ctl_card_info_get_name(info
));
812 alsaCaptureDeviceList
[card
+1] = AppendCaptureDeviceList(name
);
814 if(handle
) psnd_ctl_close(handle
);
815 if(psnd_card_next(&card
) < 0) {
816 AL_PRINT("snd_card_next failed\n");
820 psnd_pcm_info_free(pcminfo
);
821 psnd_ctl_card_info_free(info
);