30 #include <alsa/asoundlib.h>
37 static void *alsa_handle;
38 #define MAKE_FUNC(f) static typeof(f) * p##f
39 MAKE_FUNC(snd_strerror);
40 MAKE_FUNC(snd_pcm_open);
41 MAKE_FUNC(snd_pcm_close);
42 MAKE_FUNC(snd_pcm_nonblock);
43 MAKE_FUNC(snd_pcm_frames_to_bytes);
44 MAKE_FUNC(snd_pcm_bytes_to_frames);
45 MAKE_FUNC(snd_pcm_hw_params_malloc);
46 MAKE_FUNC(snd_pcm_hw_params_free);
47 MAKE_FUNC(snd_pcm_hw_params_any);
48 MAKE_FUNC(snd_pcm_hw_params_current);
49 MAKE_FUNC(snd_pcm_hw_params_set_access);
50 MAKE_FUNC(snd_pcm_hw_params_set_format);
51 MAKE_FUNC(snd_pcm_hw_params_set_channels);
52 MAKE_FUNC(snd_pcm_hw_params_set_periods_near);
53 MAKE_FUNC(snd_pcm_hw_params_set_rate_near);
54 MAKE_FUNC(snd_pcm_hw_params_set_rate);
55 MAKE_FUNC(snd_pcm_hw_params_set_rate_resample);
56 MAKE_FUNC(snd_pcm_hw_params_set_buffer_time_near);
57 MAKE_FUNC(snd_pcm_hw_params_set_period_time_near);
58 MAKE_FUNC(snd_pcm_hw_params_set_buffer_size_near);
59 MAKE_FUNC(snd_pcm_hw_params_set_period_size_near);
60 MAKE_FUNC(snd_pcm_hw_params_set_buffer_size_min);
61 MAKE_FUNC(snd_pcm_hw_params_get_buffer_time_min);
62 MAKE_FUNC(snd_pcm_hw_params_get_buffer_time_max);
63 MAKE_FUNC(snd_pcm_hw_params_get_period_time_min);
64 MAKE_FUNC(snd_pcm_hw_params_get_period_time_max);
65 MAKE_FUNC(snd_pcm_hw_params_get_buffer_size);
66 MAKE_FUNC(snd_pcm_hw_params_get_period_size);
67 MAKE_FUNC(snd_pcm_hw_params_get_access);
68 MAKE_FUNC(snd_pcm_hw_params_get_periods);
69 MAKE_FUNC(snd_pcm_hw_params_test_format);
70 MAKE_FUNC(snd_pcm_hw_params_test_channels);
71 MAKE_FUNC(snd_pcm_hw_params);
72 MAKE_FUNC(snd_pcm_sw_params_malloc);
73 MAKE_FUNC(snd_pcm_sw_params_current);
74 MAKE_FUNC(snd_pcm_sw_params_set_avail_min);
75 MAKE_FUNC(snd_pcm_sw_params_set_stop_threshold);
76 MAKE_FUNC(snd_pcm_sw_params);
77 MAKE_FUNC(snd_pcm_sw_params_free);
78 MAKE_FUNC(snd_pcm_prepare);
79 MAKE_FUNC(snd_pcm_start);
80 MAKE_FUNC(snd_pcm_resume);
81 MAKE_FUNC(snd_pcm_reset);
82 MAKE_FUNC(snd_pcm_wait);
83 MAKE_FUNC(snd_pcm_delay);
84 MAKE_FUNC(snd_pcm_state);
85 MAKE_FUNC(snd_pcm_avail_update);
86 MAKE_FUNC(snd_pcm_areas_silence);
87 MAKE_FUNC(snd_pcm_mmap_begin);
88 MAKE_FUNC(snd_pcm_mmap_commit);
89 MAKE_FUNC(snd_pcm_readi);
90 MAKE_FUNC(snd_pcm_writei);
91 MAKE_FUNC(snd_pcm_drain);
92 MAKE_FUNC(snd_pcm_drop);
93 MAKE_FUNC(snd_pcm_recover);
94 MAKE_FUNC(snd_pcm_info_malloc);
95 MAKE_FUNC(snd_pcm_info_free);
96 MAKE_FUNC(snd_pcm_info_set_device);
97 MAKE_FUNC(snd_pcm_info_set_subdevice);
98 MAKE_FUNC(snd_pcm_info_set_stream);
99 MAKE_FUNC(snd_pcm_info_get_name);
100 MAKE_FUNC(snd_ctl_pcm_next_device);
101 MAKE_FUNC(snd_ctl_pcm_info);
102 MAKE_FUNC(snd_ctl_open);
103 MAKE_FUNC(snd_ctl_close);
104 MAKE_FUNC(snd_ctl_card_info_malloc);
105 MAKE_FUNC(snd_ctl_card_info_free);
106 MAKE_FUNC(snd_ctl_card_info);
107 MAKE_FUNC(snd_ctl_card_info_get_name);
108 MAKE_FUNC(snd_ctl_card_info_get_id);
109 MAKE_FUNC(snd_card_next);
110 MAKE_FUNC(snd_config_update_free_global);
113 #define snd_strerror psnd_strerror
114 #define snd_pcm_open psnd_pcm_open
115 #define snd_pcm_close psnd_pcm_close
116 #define snd_pcm_nonblock psnd_pcm_nonblock
117 #define snd_pcm_frames_to_bytes psnd_pcm_frames_to_bytes
118 #define snd_pcm_bytes_to_frames psnd_pcm_bytes_to_frames
119 #define snd_pcm_hw_params_malloc psnd_pcm_hw_params_malloc
120 #define snd_pcm_hw_params_free psnd_pcm_hw_params_free
121 #define snd_pcm_hw_params_any psnd_pcm_hw_params_any
122 #define snd_pcm_hw_params_current psnd_pcm_hw_params_current
123 #define snd_pcm_hw_params_set_access psnd_pcm_hw_params_set_access
124 #define snd_pcm_hw_params_set_format psnd_pcm_hw_params_set_format
125 #define snd_pcm_hw_params_set_channels psnd_pcm_hw_params_set_channels
126 #define snd_pcm_hw_params_set_periods_near psnd_pcm_hw_params_set_periods_near
127 #define snd_pcm_hw_params_set_rate_near psnd_pcm_hw_params_set_rate_near
128 #define snd_pcm_hw_params_set_rate psnd_pcm_hw_params_set_rate
129 #define snd_pcm_hw_params_set_rate_resample psnd_pcm_hw_params_set_rate_resample
130 #define snd_pcm_hw_params_set_buffer_time_near psnd_pcm_hw_params_set_buffer_time_near
131 #define snd_pcm_hw_params_set_period_time_near psnd_pcm_hw_params_set_period_time_near
132 #define snd_pcm_hw_params_set_buffer_size_near psnd_pcm_hw_params_set_buffer_size_near
133 #define snd_pcm_hw_params_set_period_size_near psnd_pcm_hw_params_set_period_size_near
134 #define snd_pcm_hw_params_set_buffer_size_min psnd_pcm_hw_params_set_buffer_size_min
135 #define snd_pcm_hw_params_get_buffer_time_min psnd_pcm_hw_params_get_buffer_time_min
136 #define snd_pcm_hw_params_get_buffer_time_max psnd_pcm_hw_params_get_buffer_time_max
137 #define snd_pcm_hw_params_get_period_time_min psnd_pcm_hw_params_get_period_time_min
138 #define snd_pcm_hw_params_get_period_time_max psnd_pcm_hw_params_get_period_time_max
139 #define snd_pcm_hw_params_get_buffer_size psnd_pcm_hw_params_get_buffer_size
140 #define snd_pcm_hw_params_get_period_size psnd_pcm_hw_params_get_period_size
141 #define snd_pcm_hw_params_get_access psnd_pcm_hw_params_get_access
142 #define snd_pcm_hw_params_get_periods psnd_pcm_hw_params_get_periods
143 #define snd_pcm_hw_params_test_format psnd_pcm_hw_params_test_format
144 #define snd_pcm_hw_params_test_channels psnd_pcm_hw_params_test_channels
145 #define snd_pcm_hw_params psnd_pcm_hw_params
146 #define snd_pcm_sw_params_malloc psnd_pcm_sw_params_malloc
147 #define snd_pcm_sw_params_current psnd_pcm_sw_params_current
148 #define snd_pcm_sw_params_set_avail_min psnd_pcm_sw_params_set_avail_min
149 #define snd_pcm_sw_params_set_stop_threshold psnd_pcm_sw_params_set_stop_threshold
150 #define snd_pcm_sw_params psnd_pcm_sw_params
151 #define snd_pcm_sw_params_free psnd_pcm_sw_params_free
152 #define snd_pcm_prepare psnd_pcm_prepare
153 #define snd_pcm_start psnd_pcm_start
154 #define snd_pcm_resume psnd_pcm_resume
155 #define snd_pcm_reset psnd_pcm_reset
156 #define snd_pcm_wait psnd_pcm_wait
157 #define snd_pcm_delay psnd_pcm_delay
158 #define snd_pcm_state psnd_pcm_state
159 #define snd_pcm_avail_update psnd_pcm_avail_update
160 #define snd_pcm_areas_silence psnd_pcm_areas_silence
161 #define snd_pcm_mmap_begin psnd_pcm_mmap_begin
162 #define snd_pcm_mmap_commit psnd_pcm_mmap_commit
163 #define snd_pcm_readi psnd_pcm_readi
164 #define snd_pcm_writei psnd_pcm_writei
165 #define snd_pcm_drain psnd_pcm_drain
166 #define snd_pcm_drop psnd_pcm_drop
167 #define snd_pcm_recover psnd_pcm_recover
168 #define snd_pcm_info_malloc psnd_pcm_info_malloc
169 #define snd_pcm_info_free psnd_pcm_info_free
170 #define snd_pcm_info_set_device psnd_pcm_info_set_device
171 #define snd_pcm_info_set_subdevice psnd_pcm_info_set_subdevice
172 #define snd_pcm_info_set_stream psnd_pcm_info_set_stream
173 #define snd_pcm_info_get_name psnd_pcm_info_get_name
174 #define snd_ctl_pcm_next_device psnd_ctl_pcm_next_device
175 #define snd_ctl_pcm_info psnd_ctl_pcm_info
176 #define snd_ctl_open psnd_ctl_open
177 #define snd_ctl_close psnd_ctl_close
178 #define snd_ctl_card_info_malloc psnd_ctl_card_info_malloc
179 #define snd_ctl_card_info_free psnd_ctl_card_info_free
180 #define snd_ctl_card_info psnd_ctl_card_info
181 #define snd_ctl_card_info_get_name psnd_ctl_card_info_get_name
182 #define snd_ctl_card_info_get_id psnd_ctl_card_info_get_id
183 #define snd_card_next psnd_card_next
184 #define snd_config_update_free_global psnd_config_update_free_global
193 alsa_handle = LoadLib(
"libasound.so.2");
197 #define LOAD_FUNC(f) do { \
198 p##f = GetSymbol(alsa_handle, #f); \
200 CloseLib(alsa_handle); \
201 alsa_handle = NULL; \
217 LOAD_FUNC(snd_pcm_hw_params_set_channels);
218 LOAD_FUNC(snd_pcm_hw_params_set_periods_near);
219 LOAD_FUNC(snd_pcm_hw_params_set_rate_near);
221 LOAD_FUNC(snd_pcm_hw_params_set_rate_resample);
222 LOAD_FUNC(snd_pcm_hw_params_set_buffer_time_near);
223 LOAD_FUNC(snd_pcm_hw_params_set_period_time_near);
224 LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_near);
225 LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_min);
226 LOAD_FUNC(snd_pcm_hw_params_set_period_size_near);
227 LOAD_FUNC(snd_pcm_hw_params_get_buffer_time_min);
228 LOAD_FUNC(snd_pcm_hw_params_get_buffer_time_max);
229 LOAD_FUNC(snd_pcm_hw_params_get_period_time_min);
230 LOAD_FUNC(snd_pcm_hw_params_get_period_time_max);
231 LOAD_FUNC(snd_pcm_hw_params_get_buffer_size);
232 LOAD_FUNC(snd_pcm_hw_params_get_period_size);
234 LOAD_FUNC(snd_pcm_hw_params_get_periods);
235 LOAD_FUNC(snd_pcm_hw_params_test_format);
236 LOAD_FUNC(snd_pcm_hw_params_test_channels);
240 LOAD_FUNC(snd_pcm_sw_params_set_avail_min);
241 LOAD_FUNC(snd_pcm_sw_params_set_stop_threshold);
276 LOAD_FUNC(snd_config_update_free_global);
285 snd_pcm_t *pcmHandle;
293 snd_pcm_sframes_t last_avail;
295 volatile int killNow;
312 assert(stream == SND_PCM_STREAM_PLAYBACK || stream == SND_PCM_STREAM_CAPTURE);
313 return (stream==SND_PCM_STREAM_PLAYBACK) ?
"device-prefix" :
"capture-prefix";
318 const char *main_prefix =
"plughw:";
320 int card, err, dev,
idx;
321 snd_ctl_card_info_t *info;
322 snd_pcm_info_t *pcminfo;
325 snd_ctl_card_info_malloc(&info);
326 snd_pcm_info_malloc(&pcminfo);
328 DevList =
malloc(
sizeof(DevMap) * 1);
331 "device" :
"capture",
"default"));
335 if((err=snd_card_next(&card)) < 0)
336 ERR(
"Failed to find a card: %s\n", snd_strerror(err));
340 const char *card_prefix = main_prefix;
341 const char *cardname, *cardid;
344 snprintf(name,
sizeof(name),
"hw:%d", card);
345 if((err = snd_ctl_open(&handle, name, 0)) < 0)
347 ERR(
"control open (hw:%d): %s\n", card, snd_strerror(err));
350 if((err = snd_ctl_card_info(handle, info)) < 0)
352 ERR(
"control hardware info (hw:%d): %s\n", card, snd_strerror(err));
353 snd_ctl_close(handle);
357 cardname = snd_ctl_card_info_get_name(info);
358 cardid = snd_ctl_card_info_get_id(info);
360 snprintf(name,
sizeof(name),
"%s-%s",
prefix_name(stream), cardid);
369 if(snd_ctl_pcm_next_device(handle, &dev) < 0)
370 ERR(
"snd_ctl_pcm_next_device failed\n");
374 snd_pcm_info_set_device(pcminfo, dev);
375 snd_pcm_info_set_subdevice(pcminfo, 0);
376 snd_pcm_info_set_stream(pcminfo, stream);
377 if((err = snd_ctl_pcm_info(handle, pcminfo)) < 0) {
379 ERR(
"control digital audio info (hw:%d): %s\n", card, snd_strerror(err));
383 temp =
realloc(DevList,
sizeof(DevMap) * (idx+1));
386 const char *device_prefix = card_prefix;
390 devname = snd_pcm_info_get_name(pcminfo);
392 snprintf(name,
sizeof(name),
"%s-%s-%d",
prefix_name(stream), cardid, dev);
395 snprintf(name,
sizeof(name),
"%s, %s (CARD=%s,DEV=%d)",
396 cardname, devname, cardid, dev);
397 snprintf(device,
sizeof(device),
"%sCARD=%s,DEV=%d",
398 device_prefix, cardid, dev);
400 TRACE(
"Got device \"%s\", \"%s\"\n", name, device);
406 snd_ctl_close(handle);
408 if(snd_card_next(&card) < 0) {
409 ERR(
"snd_card_next failed\n");
414 snd_pcm_info_free(pcminfo);
415 snd_ctl_card_info_free(info);
424 snd_pcm_state_t state = snd_pcm_state(handle);
429 case SND_PCM_STATE_OPEN:
430 case SND_PCM_STATE_SETUP:
431 case SND_PCM_STATE_PREPARED:
432 case SND_PCM_STATE_RUNNING:
433 case SND_PCM_STATE_DRAINING:
434 case SND_PCM_STATE_PAUSED:
438 case SND_PCM_STATE_XRUN:
439 if((err=snd_pcm_recover(handle, -EPIPE, 1)) < 0)
442 case SND_PCM_STATE_SUSPENDED:
443 if((err=snd_pcm_recover(handle, -ESTRPIPE, 1)) < 0)
446 case SND_PCM_STATE_DISCONNECTED:
458 const snd_pcm_channel_area_t *areas =
NULL;
459 snd_pcm_uframes_t update_size, num_updates;
460 snd_pcm_sframes_t avail, commitres;
461 snd_pcm_uframes_t
offset, frames;
469 while(!data->killNow)
474 ERR(
"Invalid state detected: %s\n", snd_strerror(state));
481 avail = snd_pcm_avail_update(data->pcmHandle);
484 ERR(
"available update failed: %s\n", snd_strerror(avail));
488 if((snd_pcm_uframes_t)avail > update_size*(num_updates+1))
490 WARN(
"available samples exceeds the buffer size\n");
491 snd_pcm_reset(data->pcmHandle);
496 if((snd_pcm_uframes_t)avail < update_size)
498 if(state != SND_PCM_STATE_RUNNING)
500 err = snd_pcm_start(data->pcmHandle);
503 ERR(
"start failed: %s\n", snd_strerror(err));
507 if(snd_pcm_wait(data->pcmHandle, 1000) == 0)
508 ERR(
"Wait timeout... buffer size too low?\n");
511 avail -= avail%update_size;
519 err = snd_pcm_mmap_begin(data->pcmHandle, &areas, &offset, &frames);
522 ERR(
"mmap begin error: %s\n", snd_strerror(err));
526 WritePtr = (
char*)areas->addr + (offset * areas->step / 8);
529 commitres = snd_pcm_mmap_commit(data->pcmHandle, offset, frames);
530 if(commitres < 0 || (commitres-frames) != 0)
532 ERR(
"mmap commit error: %s\n",
533 snd_strerror(commitres >= 0 ? -EPIPE : commitres));
549 snd_pcm_uframes_t update_size, num_updates;
550 snd_pcm_sframes_t avail;
558 while(!data->killNow)
563 ERR(
"Invalid state detected: %s\n", snd_strerror(state));
570 avail = snd_pcm_avail_update(data->pcmHandle);
573 ERR(
"available update failed: %s\n", snd_strerror(avail));
577 if((snd_pcm_uframes_t)avail > update_size*num_updates)
579 WARN(
"available samples exceeds the buffer size\n");
580 snd_pcm_reset(data->pcmHandle);
584 if((snd_pcm_uframes_t)avail < update_size)
586 if(state != SND_PCM_STATE_RUNNING)
588 err = snd_pcm_start(data->pcmHandle);
591 ERR(
"start failed: %s\n", snd_strerror(err));
595 if(snd_pcm_wait(data->pcmHandle, 1000) == 0)
596 ERR(
"Wait timeout... buffer size too low?\n");
601 WritePtr = data->buffer;
602 avail = snd_pcm_bytes_to_frames(data->pcmHandle, data->size);
607 int ret = snd_pcm_writei(data->pcmHandle, WritePtr, avail);
615 ret = snd_pcm_recover(data->pcmHandle, ret, 1);
622 WritePtr += snd_pcm_frames_to_bytes(data->pcmHandle, ret);
629 ret = snd_pcm_prepare(data->pcmHandle);
642 const char *driver =
NULL;
661 if(idx == numDevNames)
670 data = (alsa_data*)
calloc(1,
sizeof(alsa_data));
672 err = snd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
676 ERR(
"Could not open playback device '%s': %s\n", driver, snd_strerror(err));
681 snd_config_update_free_global();
692 snd_pcm_close(data->pcmHandle);
700 snd_pcm_uframes_t periodSizeInFrames;
701 unsigned int periodLen, bufferLen;
702 snd_pcm_sw_params_t *sp =
NULL;
703 snd_pcm_hw_params_t *hp =
NULL;
706 unsigned int periods;
716 format = SND_PCM_FORMAT_S8;
719 format = SND_PCM_FORMAT_U8;
722 format = SND_PCM_FORMAT_S16;
725 format = SND_PCM_FORMAT_U16;
728 format = SND_PCM_FORMAT_S32;
731 format = SND_PCM_FORMAT_U32;
734 format = SND_PCM_FORMAT_FLOAT;
741 bufferLen = periodLen * periods;
744 snd_pcm_hw_params_malloc(&hp);
745 #define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error
746 CHECK(snd_pcm_hw_params_any(data->pcmHandle, hp));
748 if(!allowmmap || snd_pcm_hw_params_set_access(data->pcmHandle, hp, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0)
751 CHECK(snd_pcm_hw_params_set_access(data->pcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED));
754 if(snd_pcm_hw_params_test_format(data->pcmHandle, hp,
format) < 0)
756 static const struct {
770 for(k = 0;k <
COUNTOF(formatlist);k++)
773 if(snd_pcm_hw_params_test_format(data->pcmHandle, hp,
format) >= 0)
775 device->
FmtType = formatlist[
k].fmttype;
780 CHECK(snd_pcm_hw_params_set_format(data->pcmHandle, hp,
format));
793 for(k = 0;k <
COUNTOF(channellist);k++)
795 if(snd_pcm_hw_params_test_channels(data->pcmHandle, hp,
ChannelsFromDevFmt(channellist[k])) >= 0)
804 if(snd_pcm_hw_params_set_rate_resample(data->pcmHandle, hp, 0) < 0)
805 ERR(
"Failed to disable ALSA resampler\n");
806 CHECK(snd_pcm_hw_params_set_rate_near(data->pcmHandle, hp, &rate,
NULL));
808 if(snd_pcm_hw_params_set_buffer_time_near(data->pcmHandle, hp, &bufferLen,
NULL) < 0)
809 ERR(
"snd_pcm_hw_params_set_buffer_time_near failed: %s\n", snd_strerror(err));
811 if(snd_pcm_hw_params_set_period_time_near(data->pcmHandle, hp, &periodLen,
NULL) < 0)
812 ERR(
"snd_pcm_hw_params_set_period_time_near failed: %s\n", snd_strerror(err));
814 CHECK(snd_pcm_hw_params(data->pcmHandle, hp));
817 CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames,
NULL));
818 CHECK(snd_pcm_hw_params_get_periods(hp, &periods,
NULL));
820 snd_pcm_hw_params_free(hp);
822 snd_pcm_sw_params_malloc(&sp);
824 CHECK(snd_pcm_sw_params_current(data->pcmHandle, sp));
825 CHECK(snd_pcm_sw_params_set_avail_min(data->pcmHandle, sp, periodSizeInFrames));
826 CHECK(snd_pcm_sw_params_set_stop_threshold(data->pcmHandle, sp, periodSizeInFrames*periods));
827 CHECK(snd_pcm_sw_params(data->pcmHandle, sp));
829 snd_pcm_sw_params_free(sp);
841 ERR(
"%s failed: %s\n", funcerr, snd_strerror(err));
842 if(hp) snd_pcm_hw_params_free(hp);
843 if(sp) snd_pcm_sw_params_free(sp);
850 snd_pcm_hw_params_t *hp =
NULL;
855 snd_pcm_hw_params_malloc(&hp);
856 #define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error
857 CHECK(snd_pcm_hw_params_current(data->pcmHandle, hp));
861 snd_pcm_hw_params_free(hp);
864 data->size = snd_pcm_frames_to_bytes(data->pcmHandle, device->
UpdateSize);
865 if(
access == SND_PCM_ACCESS_RW_INTERLEAVED)
867 data->buffer =
malloc(data->size);
870 ERR(
"buffer malloc failed\n");
877 err = snd_pcm_prepare(data->pcmHandle);
880 ERR(
"snd_pcm_prepare(data->pcmHandle) failed: %s\n", snd_strerror(err));
885 if(data->thread ==
NULL)
887 ERR(
"Could not create playback thread\n");
896 ERR(
"%s failed: %s\n", funcerr, snd_strerror(err));
897 if(hp) snd_pcm_hw_params_free(hp);
919 const char *driver =
NULL;
920 snd_pcm_hw_params_t *hp;
921 snd_pcm_uframes_t bufferSizeInFrames;
922 snd_pcm_uframes_t periodSizeInFrames;
944 if(idx == numCaptureDevNames)
953 data = (alsa_data*)
calloc(1,
sizeof(alsa_data));
955 err = snd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
958 ERR(
"Could not open capture device '%s': %s\n", driver, snd_strerror(err));
964 snd_config_update_free_global();
970 format = SND_PCM_FORMAT_S8;
973 format = SND_PCM_FORMAT_U8;
976 format = SND_PCM_FORMAT_S16;
979 format = SND_PCM_FORMAT_U16;
982 format = SND_PCM_FORMAT_S32;
985 format = SND_PCM_FORMAT_U32;
988 format = SND_PCM_FORMAT_FLOAT;
995 periodSizeInFrames =
minu(bufferSizeInFrames, 25*Device->
Frequency/1000);
997 snd_pcm_hw_params_malloc(&hp);
998 #define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error
999 CHECK(snd_pcm_hw_params_any(data->pcmHandle, hp));
1001 CHECK(snd_pcm_hw_params_set_access(data->pcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED));
1003 CHECK(snd_pcm_hw_params_set_format(data->pcmHandle, hp, format));
1007 CHECK(snd_pcm_hw_params_set_rate(data->pcmHandle, hp, Device->
Frequency, 0));
1009 if(snd_pcm_hw_params_set_buffer_size_min(data->pcmHandle, hp, &bufferSizeInFrames) < 0)
1011 TRACE(
"Buffer too large, using intermediate ring buffer\n");
1013 CHECK(snd_pcm_hw_params_set_buffer_size_near(data->pcmHandle, hp, &bufferSizeInFrames));
1016 CHECK(snd_pcm_hw_params_set_period_size_near(data->pcmHandle, hp, &periodSizeInFrames,
NULL));
1018 CHECK(snd_pcm_hw_params(data->pcmHandle, hp));
1020 CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames,
NULL));
1022 snd_pcm_hw_params_free(hp);
1031 ERR(
"ring buffer create failed\n");
1035 data->size = snd_pcm_frames_to_bytes(data->pcmHandle, periodSizeInFrames);
1036 data->buffer =
malloc(data->size);
1039 ERR(
"buffer malloc failed\n");
1050 ERR(
"%s failed: %s\n", funcerr, snd_strerror(err));
1051 if(hp) snd_pcm_hw_params_free(hp);
1056 snd_pcm_close(data->pcmHandle);
1067 snd_pcm_close(data->pcmHandle);
1080 err = snd_pcm_start(data->pcmHandle);
1083 ERR(
"start failed: %s\n", snd_strerror(err));
1100 data->last_avail -= Samples;
1103 snd_pcm_sframes_t amt = 0;
1108 amt = snd_pcm_bytes_to_frames(data->pcmHandle, data->size);
1109 if((snd_pcm_uframes_t)amt > Samples) amt = Samples;
1111 amt = snd_pcm_frames_to_bytes(data->pcmHandle, amt);
1112 memmove(Buffer, data->buffer, amt);
1114 if(data->size > amt)
1116 memmove(data->buffer, data->buffer+amt, data->size - amt);
1122 data->buffer =
NULL;
1125 amt = snd_pcm_bytes_to_frames(data->pcmHandle, amt);
1127 else if(data->doCapture)
1128 amt = snd_pcm_readi(data->pcmHandle, Buffer, Samples);
1131 ERR(
"read error: %s\n", snd_strerror(amt));
1135 if((amt=snd_pcm_recover(data->pcmHandle, amt, 1)) >= 0)
1137 amt = snd_pcm_start(data->pcmHandle);
1139 amt = snd_pcm_avail_update(data->pcmHandle);
1143 ERR(
"restore error: %s\n", snd_strerror(amt));
1149 if((snd_pcm_uframes_t)amt < Samples)
1154 Buffer = (
ALbyte*)Buffer + amt;
1159 snd_pcm_frames_to_bytes(data->pcmHandle, Samples));
1167 snd_pcm_sframes_t avail = 0;
1169 if(Device->
Connected && data->doCapture)
1170 avail = snd_pcm_avail_update(data->pcmHandle);
1173 ERR(
"avail update failed: %s\n", snd_strerror(avail));
1175 if((avail=snd_pcm_recover(data->pcmHandle, avail, 1)) >= 0)
1178 avail = snd_pcm_start(data->pcmHandle);
1180 avail = snd_pcm_avail_update(data->pcmHandle);
1184 ERR(
"restore error: %s\n", snd_strerror(avail));
1191 if(avail < 0) avail = 0;
1192 avail += snd_pcm_bytes_to_frames(data->pcmHandle, data->size);
1193 if(avail > data->last_avail) data->last_avail = avail;
1194 return data->last_avail;
1199 snd_pcm_sframes_t amt;
1201 amt = snd_pcm_bytes_to_frames(data->pcmHandle, data->size);
1202 if(avail < amt) amt = avail;
1204 amt = snd_pcm_readi(data->pcmHandle, data->buffer, amt);
1207 ERR(
"read error: %s\n", snd_strerror(amt));
1211 if((amt=snd_pcm_recover(data->pcmHandle, amt, 1)) >= 0)
1214 amt = snd_pcm_start(data->pcmHandle);
1216 amt = snd_pcm_avail_update(data->pcmHandle);
1220 ERR(
"restore error: %s\n", snd_strerror(amt));
1245 if(!data->ring && avail > 0)
1252 size = snd_pcm_frames_to_bytes(data->pcmHandle, avail);
1253 ptr =
realloc(data->buffer, size);
1261 err = snd_pcm_drop(data->pcmHandle);
1263 ERR(
"drop failed: %s\n", snd_strerror(err));
1271 snd_pcm_sframes_t delay = 0;
1274 if((err=snd_pcm_delay(data->pcmHandle, &delay)) < 0)
1276 ERR(
"Failed to get pcm delay: %s\n", snd_strerror(err));
1328 numCaptureDevNames = 0;
1332 CloseLib(alsa_handle);
int ConfigValueStr(const char *blockName, const char *keyName, const char **ret)
static ALCboolean alsa_start_playback(ALCdevice *device)
GLint GLenum GLsizei GLsizei GLsizei GLint GLenum GLenum type
char * strdup(const char *inStr)
static ALint64 alsa_get_latency(ALCdevice *device)
ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
static ALuint ALSANoMMapProc(ALvoid *ptr)
static void alsa_close_capture(ALCdevice *Device)
EGLImageKHR EGLint * name
static ALuint ALSAProc(ALvoid *ptr)
ALsizei RingBufferSize(RingBuffer *ring)
void SetDefaultChannelOrder(ALCdevice *device)
const char * GetConfigValue(const char *blockName, const char *keyName, const char *def)
void AppendCaptureDeviceList(const ALCchar *name)
static void alsa_close_playback(ALCdevice *device)
void alc_alsa_probe(enum DevProbe type)
ALvoid aluHandleDisconnect(ALCdevice *device)
static ALCboolean alsa_load(void)
#define ALCdevice_Unlock(a)
static DevMap * probe_devices(snd_pcm_stream_t stream, ALuint *count)
struct RingBuffer RingBuffer
void alc_alsa_deinit(void)
EGLContext EGLenum EGLClientBuffer buffer
int GetConfigValueBool(const char *blockName, const char *keyName, int def)
static __inline ALint64 maxi64(ALint64 a, ALint64 b)
ALuint StopThread(ALvoid *thread)
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
static const char * prefix_name(snd_pcm_stream_t stream)
static ALCboolean alsa_reset_playback(ALCdevice *device)
static const ALCchar alsaDevice[]
RingBuffer * CreateRingBuffer(ALsizei frame_size, ALsizei length)
static ALCenum alsa_capture_samples(ALCdevice *Device, ALCvoid *Buffer, ALCuint Samples)
GLint GLenum GLsizei GLsizei GLsizei GLint GLenum format
static ALCuint alsa_available_samples(ALCdevice *Device)
static DevMap * allDevNameMap
ALCboolean alc_alsa_init(BackendFuncs *func_list)
enum DevFmtChannels FmtChans
static __inline ALuint minu(ALuint a, ALuint b)
static void alsa_stop_playback(ALCdevice *device)
static DevMap * allCaptureDevNameMap
static SDL_Thread * thread
void ALCdevice_LockDefault(ALCdevice *device)
static ALCenum alsa_open_capture(ALCdevice *Device, const ALCchar *deviceName)
static void alsa_start_capture(ALCdevice *Device)
static ALuint numDevNames
#define ALC_INVALID_VALUE
#define ALC_OUT_OF_MEMORY
void ReadRingBuffer(RingBuffer *ring, ALubyte *data, ALsizei len)
static int verify_state(snd_pcm_t *handle)
EGLImageKHR EGLint EGLint * handle
static const BackendFuncs alsa_funcs
void DestroyRingBuffer(RingBuffer *ring)
void ALCdevice_UnlockDefault(ALCdevice *device)
static __inline ALuint maxu(ALuint a, ALuint b)
static void alsa_stop_capture(ALCdevice *Device)
void WriteRingBuffer(RingBuffer *ring, const ALubyte *data, ALsizei len)
ALuint ChannelsFromDevFmt(enum DevFmtChannels chans)
#define ALCdevice_Lock(a)
static ALuint numCaptureDevNames
static ALCenum alsa_open_playback(ALCdevice *device, const ALCchar *deviceName)
void AppendAllDevicesList(const ALCchar *name)
ALvoid * StartThread(ALuint(*func)(ALvoid *), ALvoid *ptr)
static __inline ALuint FrameSizeFromDevFmt(enum DevFmtChannels chans, enum DevFmtType type)