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 printf("Can't recover from underrun, 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 printf("Can't recover from suspend, 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 fprintf(stderr
, "XRUN recovery failed: %s\n", psnd_strerror(err
));
150 else if (state
== SND_PCM_STATE_SUSPENDED
)
152 err
= xrun_recovery(data
->pcmHandle
, -ESTRPIPE
);
155 fprintf(stderr
, "SUSPEND recovery failed: %s\n", psnd_strerror(err
));
160 avail
= psnd_pcm_avail_update(data
->pcmHandle
);
163 err
= xrun_recovery(data
->pcmHandle
, avail
);
166 fprintf(stderr
, "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 fprintf(stderr
, "mmap begin error: %s\n", psnd_strerror(err
));
192 SuspendContext(NULL
);
195 // If we have an active context, mix data directly into output
197 WritePtr
= (char*)areas
->addr
+ (offset
* areas
->step
/ 8);
198 WriteCnt
= psnd_pcm_frames_to_bytes(data
->pcmHandle
, frames
);
200 aluMixData(pDevice
->Context
, WritePtr
, WriteCnt
, pDevice
->Format
);
203 psnd_pcm_areas_silence(areas
, offset
, pDevice
->Channels
, frames
, data
->format
);
204 ProcessContext(NULL
);
206 commitres
= psnd_pcm_mmap_commit(data
->pcmHandle
, offset
, frames
);
207 if (commitres
< 0 || (commitres
-frames
) != 0)
209 fprintf(stderr
, "mmap commit error: %s\n",
210 psnd_strerror(commitres
>= 0 ? -EPIPE
: commitres
));
221 static void fill_silence(snd_pcm_t
*pcmHandle
, snd_pcm_format_t alsaFormat
, int channels
)
223 const snd_pcm_channel_area_t
*areas
= NULL
;
224 snd_pcm_sframes_t avail
, commitres
;
225 snd_pcm_uframes_t offset
, frames
;
228 avail
= psnd_pcm_avail_update(pcmHandle
);
231 err
= xrun_recovery(pcmHandle
, avail
);
234 fprintf(stderr
, "available update failed: %s\n", psnd_strerror(err
));
239 // it is possible that contiguous areas are smaller, thus we use a loop
244 err
= psnd_pcm_mmap_begin(pcmHandle
, &areas
, &offset
, &frames
);
247 err
= xrun_recovery(pcmHandle
, err
);
250 fprintf(stderr
, "mmap begin error: %s\n", psnd_strerror(err
));
256 psnd_pcm_areas_silence(areas
, offset
, channels
, frames
, alsaFormat
);
258 commitres
= psnd_pcm_mmap_commit(pcmHandle
, offset
, frames
);
259 if (commitres
< 0 || (commitres
-frames
) != 0)
261 fprintf(stderr
, "mmap commit error: %s\n",
262 psnd_strerror(commitres
>= 0 ? -EPIPE
: commitres
));
270 static ALCboolean
alsa_open_playback(ALCdevice
*device
, const ALCchar
*deviceName
)
272 snd_pcm_uframes_t bufferSizeInFrames
;
273 snd_pcm_hw_params_t
*p
= NULL
;
274 unsigned int periods
;
279 strncpy(driver
, GetConfigValue("alsa", "default", "default"), sizeof(driver
)-1);
280 driver
[sizeof(driver
)-1] = 0;
285 for(idx
= 0;idx
< MAX_ALL_DEVICES
;idx
++)
287 if(allDevNameMap
[idx
].name
&&
288 strcmp(deviceName
, allDevNameMap
[idx
].name
) == 0)
291 sprintf(driver
, "hw:%d,%d", allDevNameMap
[idx
].card
, allDevNameMap
[idx
].dev
);
295 for(idx
= 0;idx
< MAX_DEVICES
;idx
++)
297 if(alsaDeviceList
[idx
] &&
298 strcmp(deviceName
, alsaDeviceList
[idx
]) == 0)
301 sprintf(driver
, "hw:%d,0", idx
-1);
309 strcpy(device
->szDeviceName
, deviceName
);
311 strcpy(device
->szDeviceName
, alsaDeviceList
[0]);
314 data
= (alsa_data
*)calloc(1, sizeof(alsa_data
));
316 i
= psnd_pcm_open(&data
->pcmHandle
, driver
, SND_PCM_STREAM_PLAYBACK
, SND_PCM_NONBLOCK
);
320 i
= psnd_pcm_open(&data
->pcmHandle
, driver
, SND_PCM_STREAM_PLAYBACK
, SND_PCM_NONBLOCK
);
324 i
= psnd_pcm_nonblock(data
->pcmHandle
, 0);
326 psnd_pcm_close(data
->pcmHandle
);
334 switch(device
->Format
)
336 case AL_FORMAT_MONO8
:
337 case AL_FORMAT_STEREO8
:
338 case AL_FORMAT_QUAD8
:
339 data
->format
= SND_PCM_FORMAT_U8
;
341 case AL_FORMAT_MONO16
:
342 case AL_FORMAT_STEREO16
:
343 case AL_FORMAT_QUAD16
:
344 data
->format
= SND_PCM_FORMAT_S16
;
347 data
->format
= SND_PCM_FORMAT_UNKNOWN
;
348 fprintf(stderr
, "Unknown format?! %x\n", device
->Format
);
351 periods
= GetConfigValueInt("alsa", "periods", 4);
352 if((int)periods
<= 0)
354 bufferSizeInFrames
= device
->UpdateFreq
;
356 psnd_pcm_hw_params_malloc(&p
);
357 #define ok(func, str) (i=(func),((i<0)?fprintf(stderr,"%s failed: %s\n", str, psnd_strerror(i)),0:1))
358 /* start with the largest configuration space possible */
359 if(!(ok(psnd_pcm_hw_params_any(data
->pcmHandle
, p
), "any") &&
360 /* set interleaved access */
361 ok(psnd_pcm_hw_params_set_access(data
->pcmHandle
, p
, SND_PCM_ACCESS_MMAP_INTERLEAVED
), "set access") &&
362 /* set format (implicitly sets sample bits) */
363 ok(psnd_pcm_hw_params_set_format(data
->pcmHandle
, p
, data
->format
), "set format") &&
364 /* set channels (implicitly sets frame bits) */
365 ok(psnd_pcm_hw_params_set_channels(data
->pcmHandle
, p
, device
->Channels
), "set channels") &&
366 /* set periods (implicitly constrains period/buffer parameters) */
367 ok(psnd_pcm_hw_params_set_periods_near(data
->pcmHandle
, p
, &periods
, NULL
), "set periods near") &&
368 /* set rate (implicitly constrains period/buffer parameters) */
369 ok(psnd_pcm_hw_params_set_rate_near(data
->pcmHandle
, p
, &device
->Frequency
, NULL
), "set rate near") &&
370 /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */
371 ok(psnd_pcm_hw_params_set_buffer_size_near(data
->pcmHandle
, p
, &bufferSizeInFrames
), "set buffer size near") &&
372 /* install and prepare hardware configuration */
373 ok(psnd_pcm_hw_params(data
->pcmHandle
, p
), "set params")))
375 psnd_pcm_hw_params_free(p
);
376 psnd_pcm_close(data
->pcmHandle
);
381 psnd_pcm_hw_params_free(p
);
383 device
->MaxNoOfSources
= 256;
384 device
->UpdateFreq
= bufferSizeInFrames
;
386 i
= psnd_pcm_prepare(data
->pcmHandle
);
389 fprintf(stderr
, "prepare error: %s\n", psnd_strerror(i
));
390 psnd_pcm_close(data
->pcmHandle
);
395 fill_silence(data
->pcmHandle
, data
->format
, device
->Channels
);
396 i
= psnd_pcm_start(data
->pcmHandle
);
399 fprintf(stderr
, "start error: %s\n", psnd_strerror(i
));
400 psnd_pcm_close(data
->pcmHandle
);
405 device
->ExtraData
= data
;
406 data
->thread
= StartThread(ALSAProc
, device
);
407 if(data
->thread
== NULL
)
409 psnd_pcm_close(data
->pcmHandle
);
410 device
->ExtraData
= NULL
;
418 static void alsa_close_playback(ALCdevice
*device
)
420 alsa_data
*data
= (alsa_data
*)device
->ExtraData
;
422 StopThread(data
->thread
);
423 psnd_pcm_close(data
->pcmHandle
);
426 device
->ExtraData
= NULL
;
430 static ALCboolean
alsa_open_capture(ALCdevice
*pDevice
, const ALCchar
*deviceName
, ALCuint frequency
, ALCenum format
, ALCsizei SampleSize
)
432 snd_pcm_format_t alsaFormat
;
433 snd_pcm_hw_params_t
*p
;
434 unsigned int periods
= 4;
435 snd_pcm_uframes_t bufferSizeInFrames
= SampleSize
;
440 strncpy(driver
, GetConfigValue("alsa", "capture", "default"), sizeof(driver
)-1);
441 driver
[sizeof(driver
)-1] = 0;
446 for(idx
= 0;idx
< MAX_DEVICES
;idx
++)
448 if(alsaCaptureDeviceList
[idx
] &&
449 strcmp(deviceName
, alsaCaptureDeviceList
[idx
]) == 0)
452 sprintf(driver
, "hw:%d,0", idx
-1);
460 strcpy(pDevice
->szDeviceName
, deviceName
);
462 strcpy(pDevice
->szDeviceName
, alsaCaptureDeviceList
[0]);
465 data
= (alsa_data
*)calloc(1, sizeof(alsa_data
));
467 i
= psnd_pcm_open(&data
->pcmHandle
, driver
, SND_PCM_STREAM_CAPTURE
, SND_PCM_NONBLOCK
);
471 i
= psnd_pcm_open(&data
->pcmHandle
, driver
, SND_PCM_STREAM_CAPTURE
, SND_PCM_NONBLOCK
);
475 i
= psnd_pcm_nonblock(data
->pcmHandle
, 0);
477 psnd_pcm_close(data
->pcmHandle
);
485 switch(aluBytesFromFormat(format
))
488 alsaFormat
= SND_PCM_FORMAT_U8
;
491 alsaFormat
= SND_PCM_FORMAT_S16
;
494 alsaFormat
= SND_PCM_FORMAT_UNKNOWN
;
495 fprintf(stderr
, "Unknown format?! %x\n", format
);
498 psnd_pcm_hw_params_malloc(&p
);
499 #define ok(func, str) (i=(func),((i<0)?fprintf(stderr,"%s failed\n", str),0:1))
500 /* start with the largest configuration space possible */
501 if(!(ok(psnd_pcm_hw_params_any(data
->pcmHandle
, p
), "any") &&
502 /* set interleaved access */
503 ok(psnd_pcm_hw_params_set_access(data
->pcmHandle
, p
, SND_PCM_ACCESS_MMAP_INTERLEAVED
), "set access") &&
504 /* set format (implicitly sets sample bits) */
505 ok(psnd_pcm_hw_params_set_format(data
->pcmHandle
, p
, alsaFormat
), "set format") &&
506 /* set channels (implicitly sets frame bits) */
507 ok(psnd_pcm_hw_params_set_channels(data
->pcmHandle
, p
, pDevice
->Channels
), "set channels") &&
508 /* set periods (implicitly constrains period/buffer parameters) */
509 ok(psnd_pcm_hw_params_set_periods_near(data
->pcmHandle
, p
, &periods
, NULL
), "set periods near") &&
510 /* set rate (implicitly constrains period/buffer parameters) */
511 ok(psnd_pcm_hw_params_set_rate(data
->pcmHandle
, p
, frequency
, 0), "set rate") &&
512 /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */
513 ok(psnd_pcm_hw_params_set_buffer_size_min(data
->pcmHandle
, p
, &bufferSizeInFrames
), "set buffer size min") &&
514 /* install and prepare hardware configuration */
515 ok(psnd_pcm_hw_params(data
->pcmHandle
, p
), "set params")))
517 psnd_pcm_hw_params_free(p
);
518 psnd_pcm_close(data
->pcmHandle
);
523 psnd_pcm_hw_params_free(p
);
525 i
= psnd_pcm_prepare(data
->pcmHandle
);
528 fprintf(stderr
, "prepare error: %s\n", psnd_strerror(i
));
529 psnd_pcm_close(data
->pcmHandle
);
534 pDevice
->ExtraData
= data
;
538 static void alsa_close_capture(ALCdevice
*pDevice
)
540 alsa_data
*data
= (alsa_data
*)pDevice
->ExtraData
;
541 psnd_pcm_close(data
->pcmHandle
);
544 pDevice
->ExtraData
= NULL
;
547 static void alsa_start_capture(ALCdevice
*pDevice
)
549 alsa_data
*data
= (alsa_data
*)pDevice
->ExtraData
;
550 psnd_pcm_start(data
->pcmHandle
);
553 static void alsa_stop_capture(ALCdevice
*pDevice
)
555 alsa_data
*data
= (alsa_data
*)pDevice
->ExtraData
;
556 psnd_pcm_drain(data
->pcmHandle
);
559 static void alsa_capture_samples(ALCdevice
*pDevice
, ALCvoid
*pBuffer
, ALCuint lSamples
)
561 alsa_data
*data
= (alsa_data
*)pDevice
->ExtraData
;
562 const snd_pcm_channel_area_t
*areas
= NULL
;
563 snd_pcm_sframes_t frames
, commitres
;
564 snd_pcm_uframes_t size
, offset
;
567 frames
= psnd_pcm_avail_update(data
->pcmHandle
);
570 err
= xrun_recovery(data
->pcmHandle
, frames
);
572 fprintf(stderr
, "available update failed: %s\n", psnd_strerror(err
));
574 frames
= psnd_pcm_avail_update(data
->pcmHandle
);
576 if (frames
< (snd_pcm_sframes_t
)lSamples
)
578 SetALCError(ALC_INVALID_VALUE
);
582 // it is possible that contiguous areas are smaller, thus we use a loop
589 err
= psnd_pcm_mmap_begin(data
->pcmHandle
, &areas
, &offset
, &size
);
592 err
= xrun_recovery(data
->pcmHandle
, err
);
595 fprintf(stderr
, "mmap begin error: %s\n", psnd_strerror(err
));
601 Pointer
= (char*)areas
->addr
+ (offset
* areas
->step
/ 8);
602 Count
= size
* pDevice
->FrameSize
;
604 memcpy(pBuffer
, Pointer
, Count
);
605 pBuffer
= (char*)pBuffer
+ Count
;
607 commitres
= psnd_pcm_mmap_commit(data
->pcmHandle
, offset
, size
);
608 if (commitres
< 0 || (commitres
-size
) != 0)
610 fprintf(stderr
, "mmap commit error: %s\n",
611 psnd_strerror(commitres
>= 0 ? -EPIPE
: commitres
));
619 static ALCuint
alsa_available_samples(ALCdevice
*pDevice
)
621 alsa_data
*data
= (alsa_data
*)pDevice
->ExtraData
;
622 snd_pcm_sframes_t frames
= psnd_pcm_avail_update(data
->pcmHandle
);
625 int err
= xrun_recovery(data
->pcmHandle
, frames
);
627 fprintf(stderr
, "available update failed: %s\n", psnd_strerror(err
));
629 frames
= psnd_pcm_avail_update(data
->pcmHandle
);
630 if(frames
< 0) /* ew.. */
631 SetALCError(ALC_INVALID_DEVICE
);
633 return max(frames
, 0);
637 BackendFuncs alsa_funcs
= {
644 alsa_capture_samples
,
645 alsa_available_samples
648 void alc_alsa_init(BackendFuncs
*func_list
)
650 #define error(...) do { \
651 fprintf(stderr, __VA_ARGS__); \
652 fprintf(stderr, "\n"); \
655 int card
, err
, dev
, idx
= 1;
656 snd_ctl_card_info_t
*info
;
657 snd_pcm_info_t
*pcminfo
;
658 snd_pcm_stream_t stream
= SND_PCM_STREAM_PLAYBACK
;
662 *func_list
= alsa_funcs
;
665 alsa_handle
= dlopen("libasound.so.2", RTLD_NOW
);
670 #define LOAD_FUNC(f) do { \
671 p##f = (typeof(f)*)dlsym(alsa_handle, #f); \
672 if((str=dlerror()) != NULL) \
674 dlclose(alsa_handle); \
675 alsa_handle = NULL; \
676 error("Could not load %s from libasound.so.2: %s", #f, str); \
683 #define LOAD_FUNC(f) p##f = f
686 LOAD_FUNC(snd_strerror
);
687 LOAD_FUNC(snd_pcm_open
);
688 LOAD_FUNC(snd_pcm_close
);
689 LOAD_FUNC(snd_pcm_nonblock
);
690 LOAD_FUNC(snd_pcm_frames_to_bytes
);
691 LOAD_FUNC(snd_pcm_hw_params_malloc
);
692 LOAD_FUNC(snd_pcm_hw_params_free
);
693 LOAD_FUNC(snd_pcm_hw_params_any
);
694 LOAD_FUNC(snd_pcm_hw_params_set_access
);
695 LOAD_FUNC(snd_pcm_hw_params_set_format
);
696 LOAD_FUNC(snd_pcm_hw_params_set_channels
);
697 LOAD_FUNC(snd_pcm_hw_params_set_periods_near
);
698 LOAD_FUNC(snd_pcm_hw_params_set_rate_near
);
699 LOAD_FUNC(snd_pcm_hw_params_set_rate
);
700 LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_near
);
701 LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_min
);
702 LOAD_FUNC(snd_pcm_hw_params
);
703 LOAD_FUNC(snd_pcm_prepare
);
704 LOAD_FUNC(snd_pcm_start
);
705 LOAD_FUNC(snd_pcm_resume
);
706 LOAD_FUNC(snd_pcm_state
);
707 LOAD_FUNC(snd_pcm_avail_update
);
708 LOAD_FUNC(snd_pcm_areas_silence
);
709 LOAD_FUNC(snd_pcm_mmap_begin
);
710 LOAD_FUNC(snd_pcm_mmap_commit
);
711 LOAD_FUNC(snd_pcm_drain
);
713 LOAD_FUNC(snd_pcm_info_malloc
);
714 LOAD_FUNC(snd_pcm_info_free
);
715 LOAD_FUNC(snd_pcm_info_set_device
);
716 LOAD_FUNC(snd_pcm_info_set_subdevice
);
717 LOAD_FUNC(snd_pcm_info_set_stream
);
718 LOAD_FUNC(snd_pcm_info_get_name
);
719 LOAD_FUNC(snd_ctl_pcm_next_device
);
720 LOAD_FUNC(snd_ctl_pcm_info
);
721 LOAD_FUNC(snd_ctl_open
);
722 LOAD_FUNC(snd_ctl_close
);
723 LOAD_FUNC(snd_ctl_card_info_malloc
);
724 LOAD_FUNC(snd_ctl_card_info_free
);
725 LOAD_FUNC(snd_ctl_card_info
);
726 LOAD_FUNC(snd_ctl_card_info_get_name
);
727 LOAD_FUNC(snd_card_next
);
731 psnd_ctl_card_info_malloc(&info
);
732 psnd_pcm_info_malloc(&pcminfo
);
735 if(psnd_card_next(&card
) < 0 || card
< 0)
736 error("no playback cards found...");
739 alsaDeviceList
[0] = AppendDeviceList("ALSA Software on default");
740 allDevNameMap
[0].name
= AppendAllDeviceList("ALSA Software on default");
744 sprintf(name
, "hw:%d", card
);
745 if ((err
= psnd_ctl_open(&handle
, name
, 0)) < 0) {
746 error("control open (%i): %s", card
, psnd_strerror(err
));
749 if ((err
= psnd_ctl_card_info(handle
, info
)) < 0) {
750 error("control hardware info (%i): %s", card
, psnd_strerror(err
));
751 psnd_ctl_close(handle
);
754 if(card
< MAX_DEVICES
-1) {
755 snprintf(name
, sizeof(name
), "ALSA Software on %s",
756 psnd_ctl_card_info_get_name(info
));
757 alsaDeviceList
[card
+1] = AppendDeviceList(name
);
761 while (idx
< MAX_ALL_DEVICES
) {
762 if (psnd_ctl_pcm_next_device(handle
, &dev
)<0)
763 error("snd_ctl_pcm_next_device");
766 psnd_pcm_info_set_device(pcminfo
, dev
);
767 psnd_pcm_info_set_subdevice(pcminfo
, 0);
768 psnd_pcm_info_set_stream(pcminfo
, stream
);
769 if ((err
= psnd_ctl_pcm_info(handle
, pcminfo
)) < 0) {
771 error("control digital audio info (%i): %s", card
, psnd_strerror(err
));
774 snprintf(name
, sizeof(name
), "ALSA Software on %s [%s]",
775 psnd_ctl_card_info_get_name(info
),
776 psnd_pcm_info_get_name(pcminfo
));
777 allDevNameMap
[idx
].name
= AppendAllDeviceList(name
);
778 allDevNameMap
[idx
].card
= card
;
779 allDevNameMap
[idx
].dev
= dev
;
782 psnd_ctl_close(handle
);
784 if(psnd_card_next(&card
) < 0) {
785 error("snd_card_next");
791 stream
= SND_PCM_STREAM_CAPTURE
;
794 if(psnd_card_next(&card
) < 0 || card
< 0) {
795 error("no capture cards found...");
796 psnd_pcm_info_free(pcminfo
);
797 psnd_ctl_card_info_free(info
);
801 alsaCaptureDeviceList
[0] = AppendCaptureDeviceList("ALSA Capture on default");
804 sprintf(name
, "hw:%d", card
);
806 if ((err
= psnd_ctl_open(&handle
, name
, 0)) < 0) {
807 error("control open (%i): %s", card
, psnd_strerror(err
));
809 if (err
>= 0 && (err
= psnd_ctl_card_info(handle
, info
)) < 0) {
810 error("control hardware info (%i): %s", card
, psnd_strerror(err
));
811 psnd_ctl_close(handle
);
813 else if (err
>= 0 && card
< MAX_DEVICES
-1)
815 snprintf(name
, sizeof(name
), "ALSA Capture on %s",
816 psnd_ctl_card_info_get_name(info
));
817 alsaCaptureDeviceList
[card
+1] = AppendCaptureDeviceList(name
);
819 if(handle
) psnd_ctl_close(handle
);
820 if(psnd_card_next(&card
) < 0) {
821 error("snd_card_next");
825 psnd_pcm_info_free(pcminfo
);
826 psnd_ctl_card_info_free(info
);