zenilib  0.5.3.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
alsa.c
Go to the documentation of this file.
1 
21 #include "config.h"
22 
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <memory.h>
26 
27 #include "alMain.h"
28 #include "alu.h"
29 
30 #include <alsa/asoundlib.h>
31 
32 
33 static const ALCchar alsaDevice[] = "ALSA Default";
34 
35 
36 #ifdef HAVE_DYNLOAD
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);
111 #undef MAKE_FUNC
112 
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
185 #endif
186 
187 
188 static ALCboolean alsa_load(void)
189 {
190 #ifdef HAVE_DYNLOAD
191  if(!alsa_handle)
192  {
193  alsa_handle = LoadLib("libasound.so.2");
194  if(!alsa_handle)
195  return ALC_FALSE;
196 
197 #define LOAD_FUNC(f) do { \
198  p##f = GetSymbol(alsa_handle, #f); \
199  if(p##f == NULL) { \
200  CloseLib(alsa_handle); \
201  alsa_handle = NULL; \
202  return ALC_FALSE; \
203  } \
204 } while(0)
205  LOAD_FUNC(snd_strerror);
206  LOAD_FUNC(snd_pcm_open);
207  LOAD_FUNC(snd_pcm_close);
208  LOAD_FUNC(snd_pcm_nonblock);
209  LOAD_FUNC(snd_pcm_frames_to_bytes);
210  LOAD_FUNC(snd_pcm_bytes_to_frames);
211  LOAD_FUNC(snd_pcm_hw_params_malloc);
212  LOAD_FUNC(snd_pcm_hw_params_free);
213  LOAD_FUNC(snd_pcm_hw_params_any);
214  LOAD_FUNC(snd_pcm_hw_params_current);
215  LOAD_FUNC(snd_pcm_hw_params_set_access);
216  LOAD_FUNC(snd_pcm_hw_params_set_format);
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);
220  LOAD_FUNC(snd_pcm_hw_params_set_rate);
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);
233  LOAD_FUNC(snd_pcm_hw_params_get_access);
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);
237  LOAD_FUNC(snd_pcm_hw_params);
238  LOAD_FUNC(snd_pcm_sw_params_malloc);
239  LOAD_FUNC(snd_pcm_sw_params_current);
240  LOAD_FUNC(snd_pcm_sw_params_set_avail_min);
241  LOAD_FUNC(snd_pcm_sw_params_set_stop_threshold);
242  LOAD_FUNC(snd_pcm_sw_params);
243  LOAD_FUNC(snd_pcm_sw_params_free);
244  LOAD_FUNC(snd_pcm_prepare);
245  LOAD_FUNC(snd_pcm_start);
246  LOAD_FUNC(snd_pcm_resume);
247  LOAD_FUNC(snd_pcm_reset);
248  LOAD_FUNC(snd_pcm_wait);
249  LOAD_FUNC(snd_pcm_delay);
250  LOAD_FUNC(snd_pcm_state);
251  LOAD_FUNC(snd_pcm_avail_update);
252  LOAD_FUNC(snd_pcm_areas_silence);
253  LOAD_FUNC(snd_pcm_mmap_begin);
254  LOAD_FUNC(snd_pcm_mmap_commit);
255  LOAD_FUNC(snd_pcm_readi);
256  LOAD_FUNC(snd_pcm_writei);
257  LOAD_FUNC(snd_pcm_drain);
258  LOAD_FUNC(snd_pcm_drop);
259  LOAD_FUNC(snd_pcm_recover);
260  LOAD_FUNC(snd_pcm_info_malloc);
261  LOAD_FUNC(snd_pcm_info_free);
262  LOAD_FUNC(snd_pcm_info_set_device);
263  LOAD_FUNC(snd_pcm_info_set_subdevice);
264  LOAD_FUNC(snd_pcm_info_set_stream);
265  LOAD_FUNC(snd_pcm_info_get_name);
266  LOAD_FUNC(snd_ctl_pcm_next_device);
267  LOAD_FUNC(snd_ctl_pcm_info);
268  LOAD_FUNC(snd_ctl_open);
269  LOAD_FUNC(snd_ctl_close);
270  LOAD_FUNC(snd_ctl_card_info_malloc);
271  LOAD_FUNC(snd_ctl_card_info_free);
272  LOAD_FUNC(snd_ctl_card_info);
273  LOAD_FUNC(snd_ctl_card_info_get_name);
274  LOAD_FUNC(snd_ctl_card_info_get_id);
275  LOAD_FUNC(snd_card_next);
276  LOAD_FUNC(snd_config_update_free_global);
277 #undef LOAD_FUNC
278  }
279 #endif
280  return ALC_TRUE;
281 }
282 
283 
284 typedef struct {
285  snd_pcm_t *pcmHandle;
286 
287  ALvoid *buffer;
288  ALsizei size;
289 
290  ALboolean doCapture;
291  RingBuffer *ring;
292 
293  snd_pcm_sframes_t last_avail;
294 
295  volatile int killNow;
296  ALvoid *thread;
297 } alsa_data;
298 
299 typedef struct {
300  ALCchar *name;
301  char *device;
302 } DevMap;
303 
304 static DevMap *allDevNameMap;
306 static DevMap *allCaptureDevNameMap;
308 
309 
310 static const char *prefix_name(snd_pcm_stream_t stream)
311 {
312  assert(stream == SND_PCM_STREAM_PLAYBACK || stream == SND_PCM_STREAM_CAPTURE);
313  return (stream==SND_PCM_STREAM_PLAYBACK) ? "device-prefix" : "capture-prefix";
314 }
315 
316 static DevMap *probe_devices(snd_pcm_stream_t stream, ALuint *count)
317 {
318  const char *main_prefix = "plughw:";
319  snd_ctl_t *handle;
320  int card, err, dev, idx;
321  snd_ctl_card_info_t *info;
322  snd_pcm_info_t *pcminfo;
323  DevMap *DevList;
324 
325  snd_ctl_card_info_malloc(&info);
326  snd_pcm_info_malloc(&pcminfo);
327 
328  DevList = malloc(sizeof(DevMap) * 1);
329  DevList[0].name = strdup(alsaDevice);
330  DevList[0].device = strdup(GetConfigValue("alsa", (stream==SND_PCM_STREAM_PLAYBACK) ?
331  "device" : "capture", "default"));
332  idx = 1;
333 
334  card = -1;
335  if((err=snd_card_next(&card)) < 0)
336  ERR("Failed to find a card: %s\n", snd_strerror(err));
337  ConfigValueStr("alsa", prefix_name(stream), &main_prefix);
338  while(card >= 0)
339  {
340  const char *card_prefix = main_prefix;
341  const char *cardname, *cardid;
342  char name[256];
343 
344  snprintf(name, sizeof(name), "hw:%d", card);
345  if((err = snd_ctl_open(&handle, name, 0)) < 0)
346  {
347  ERR("control open (hw:%d): %s\n", card, snd_strerror(err));
348  goto next_card;
349  }
350  if((err = snd_ctl_card_info(handle, info)) < 0)
351  {
352  ERR("control hardware info (hw:%d): %s\n", card, snd_strerror(err));
353  snd_ctl_close(handle);
354  goto next_card;
355  }
356 
357  cardname = snd_ctl_card_info_get_name(info);
358  cardid = snd_ctl_card_info_get_id(info);
359 
360  snprintf(name, sizeof(name), "%s-%s", prefix_name(stream), cardid);
361  ConfigValueStr("alsa", name, &card_prefix);
362 
363  dev = -1;
364  while(1)
365  {
366  const char *devname;
367  void *temp;
368 
369  if(snd_ctl_pcm_next_device(handle, &dev) < 0)
370  ERR("snd_ctl_pcm_next_device failed\n");
371  if(dev < 0)
372  break;
373 
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) {
378  if(err != -ENOENT)
379  ERR("control digital audio info (hw:%d): %s\n", card, snd_strerror(err));
380  continue;
381  }
382 
383  temp = realloc(DevList, sizeof(DevMap) * (idx+1));
384  if(temp)
385  {
386  const char *device_prefix = card_prefix;
387  char device[128];
388 
389  DevList = temp;
390  devname = snd_pcm_info_get_name(pcminfo);
391 
392  snprintf(name, sizeof(name), "%s-%s-%d", prefix_name(stream), cardid, dev);
393  ConfigValueStr("alsa", name, &device_prefix);
394 
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);
399 
400  TRACE("Got device \"%s\", \"%s\"\n", name, device);
401  DevList[idx].name = strdup(name);
402  DevList[idx].device = strdup(device);
403  idx++;
404  }
405  }
406  snd_ctl_close(handle);
407  next_card:
408  if(snd_card_next(&card) < 0) {
409  ERR("snd_card_next failed\n");
410  break;
411  }
412  }
413 
414  snd_pcm_info_free(pcminfo);
415  snd_ctl_card_info_free(info);
416 
417  *count = idx;
418  return DevList;
419 }
420 
421 
422 static int verify_state(snd_pcm_t *handle)
423 {
424  snd_pcm_state_t state = snd_pcm_state(handle);
425  int err;
426 
427  switch(state)
428  {
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:
435  /* All Okay */
436  break;
437 
438  case SND_PCM_STATE_XRUN:
439  if((err=snd_pcm_recover(handle, -EPIPE, 1)) < 0)
440  return err;
441  break;
442  case SND_PCM_STATE_SUSPENDED:
443  if((err=snd_pcm_recover(handle, -ESTRPIPE, 1)) < 0)
444  return err;
445  break;
446  case SND_PCM_STATE_DISCONNECTED:
447  return -ENODEV;
448  }
449 
450  return state;
451 }
452 
453 
454 static ALuint ALSAProc(ALvoid *ptr)
455 {
456  ALCdevice *Device = (ALCdevice*)ptr;
457  alsa_data *data = (alsa_data*)Device->ExtraData;
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;
462  char *WritePtr;
463  int err;
464 
465  SetRTPriority();
466 
467  update_size = Device->UpdateSize;
468  num_updates = Device->NumUpdates;
469  while(!data->killNow)
470  {
471  int state = verify_state(data->pcmHandle);
472  if(state < 0)
473  {
474  ERR("Invalid state detected: %s\n", snd_strerror(state));
475  ALCdevice_Lock(Device);
476  aluHandleDisconnect(Device);
477  ALCdevice_Unlock(Device);
478  break;
479  }
480 
481  avail = snd_pcm_avail_update(data->pcmHandle);
482  if(avail < 0)
483  {
484  ERR("available update failed: %s\n", snd_strerror(avail));
485  continue;
486  }
487 
488  if((snd_pcm_uframes_t)avail > update_size*(num_updates+1))
489  {
490  WARN("available samples exceeds the buffer size\n");
491  snd_pcm_reset(data->pcmHandle);
492  continue;
493  }
494 
495  // make sure there's frames to process
496  if((snd_pcm_uframes_t)avail < update_size)
497  {
498  if(state != SND_PCM_STATE_RUNNING)
499  {
500  err = snd_pcm_start(data->pcmHandle);
501  if(err < 0)
502  {
503  ERR("start failed: %s\n", snd_strerror(err));
504  continue;
505  }
506  }
507  if(snd_pcm_wait(data->pcmHandle, 1000) == 0)
508  ERR("Wait timeout... buffer size too low?\n");
509  continue;
510  }
511  avail -= avail%update_size;
512 
513  // it is possible that contiguous areas are smaller, thus we use a loop
514  ALCdevice_Lock(Device);
515  while(avail > 0)
516  {
517  frames = avail;
518 
519  err = snd_pcm_mmap_begin(data->pcmHandle, &areas, &offset, &frames);
520  if(err < 0)
521  {
522  ERR("mmap begin error: %s\n", snd_strerror(err));
523  break;
524  }
525 
526  WritePtr = (char*)areas->addr + (offset * areas->step / 8);
527  aluMixData(Device, WritePtr, frames);
528 
529  commitres = snd_pcm_mmap_commit(data->pcmHandle, offset, frames);
530  if(commitres < 0 || (commitres-frames) != 0)
531  {
532  ERR("mmap commit error: %s\n",
533  snd_strerror(commitres >= 0 ? -EPIPE : commitres));
534  break;
535  }
536 
537  avail -= frames;
538  }
539  ALCdevice_Unlock(Device);
540  }
541 
542  return 0;
543 }
544 
546 {
547  ALCdevice *Device = (ALCdevice*)ptr;
548  alsa_data *data = (alsa_data*)Device->ExtraData;
549  snd_pcm_uframes_t update_size, num_updates;
550  snd_pcm_sframes_t avail;
551  char *WritePtr;
552  int err;
553 
554  SetRTPriority();
555 
556  update_size = Device->UpdateSize;
557  num_updates = Device->NumUpdates;
558  while(!data->killNow)
559  {
560  int state = verify_state(data->pcmHandle);
561  if(state < 0)
562  {
563  ERR("Invalid state detected: %s\n", snd_strerror(state));
564  ALCdevice_Lock(Device);
565  aluHandleDisconnect(Device);
566  ALCdevice_Unlock(Device);
567  break;
568  }
569 
570  avail = snd_pcm_avail_update(data->pcmHandle);
571  if(avail < 0)
572  {
573  ERR("available update failed: %s\n", snd_strerror(avail));
574  continue;
575  }
576 
577  if((snd_pcm_uframes_t)avail > update_size*num_updates)
578  {
579  WARN("available samples exceeds the buffer size\n");
580  snd_pcm_reset(data->pcmHandle);
581  continue;
582  }
583 
584  if((snd_pcm_uframes_t)avail < update_size)
585  {
586  if(state != SND_PCM_STATE_RUNNING)
587  {
588  err = snd_pcm_start(data->pcmHandle);
589  if(err < 0)
590  {
591  ERR("start failed: %s\n", snd_strerror(err));
592  continue;
593  }
594  }
595  if(snd_pcm_wait(data->pcmHandle, 1000) == 0)
596  ERR("Wait timeout... buffer size too low?\n");
597  continue;
598  }
599 
600  ALCdevice_Lock(Device);
601  WritePtr = data->buffer;
602  avail = snd_pcm_bytes_to_frames(data->pcmHandle, data->size);
603  aluMixData(Device, WritePtr, avail);
604 
605  while(avail > 0)
606  {
607  int ret = snd_pcm_writei(data->pcmHandle, WritePtr, avail);
608  switch (ret)
609  {
610  case -EAGAIN:
611  continue;
612  case -ESTRPIPE:
613  case -EPIPE:
614  case -EINTR:
615  ret = snd_pcm_recover(data->pcmHandle, ret, 1);
616  if(ret < 0)
617  avail = 0;
618  break;
619  default:
620  if (ret >= 0)
621  {
622  WritePtr += snd_pcm_frames_to_bytes(data->pcmHandle, ret);
623  avail -= ret;
624  }
625  break;
626  }
627  if (ret < 0)
628  {
629  ret = snd_pcm_prepare(data->pcmHandle);
630  if(ret < 0)
631  break;
632  }
633  }
634  ALCdevice_Unlock(Device);
635  }
636 
637  return 0;
638 }
639 
640 static ALCenum alsa_open_playback(ALCdevice *device, const ALCchar *deviceName)
641 {
642  const char *driver = NULL;
643  alsa_data *data;
644  int err;
645 
646  if(deviceName)
647  {
648  size_t idx;
649 
650  if(!allDevNameMap)
651  allDevNameMap = probe_devices(SND_PCM_STREAM_PLAYBACK, &numDevNames);
652 
653  for(idx = 0;idx < numDevNames;idx++)
654  {
655  if(strcmp(deviceName, allDevNameMap[idx].name) == 0)
656  {
657  driver = allDevNameMap[idx].device;
658  break;
659  }
660  }
661  if(idx == numDevNames)
662  return ALC_INVALID_VALUE;
663  }
664  else
665  {
666  deviceName = alsaDevice;
667  driver = GetConfigValue("alsa", "device", "default");
668  }
669 
670  data = (alsa_data*)calloc(1, sizeof(alsa_data));
671 
672  err = snd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
673  if(err < 0)
674  {
675  free(data);
676  ERR("Could not open playback device '%s': %s\n", driver, snd_strerror(err));
677  return ALC_OUT_OF_MEMORY;
678  }
679 
680  /* Free alsa's global config tree. Otherwise valgrind reports a ton of leaks. */
681  snd_config_update_free_global();
682 
683  device->DeviceName = strdup(deviceName);
684  device->ExtraData = data;
685  return ALC_NO_ERROR;
686 }
687 
688 static void alsa_close_playback(ALCdevice *device)
689 {
690  alsa_data *data = (alsa_data*)device->ExtraData;
691 
692  snd_pcm_close(data->pcmHandle);
693  free(data);
694  device->ExtraData = NULL;
695 }
696 
698 {
699  alsa_data *data = (alsa_data*)device->ExtraData;
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;
704  snd_pcm_access_t access;
705  snd_pcm_format_t format;
706  unsigned int periods;
707  unsigned int rate;
708  const char *funcerr;
709  int allowmmap;
710  int err;
711 
712  format = -1;
713  switch(device->FmtType)
714  {
715  case DevFmtByte:
716  format = SND_PCM_FORMAT_S8;
717  break;
718  case DevFmtUByte:
719  format = SND_PCM_FORMAT_U8;
720  break;
721  case DevFmtShort:
722  format = SND_PCM_FORMAT_S16;
723  break;
724  case DevFmtUShort:
725  format = SND_PCM_FORMAT_U16;
726  break;
727  case DevFmtInt:
728  format = SND_PCM_FORMAT_S32;
729  break;
730  case DevFmtUInt:
731  format = SND_PCM_FORMAT_U32;
732  break;
733  case DevFmtFloat:
734  format = SND_PCM_FORMAT_FLOAT;
735  break;
736  }
737 
738  allowmmap = GetConfigValueBool("alsa", "mmap", 1);
739  periods = device->NumUpdates;
740  periodLen = (ALuint64)device->UpdateSize * 1000000 / device->Frequency;
741  bufferLen = periodLen * periods;
742  rate = device->Frequency;
743 
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));
747  /* set interleaved access */
748  if(!allowmmap || snd_pcm_hw_params_set_access(data->pcmHandle, hp, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0)
749  {
750  /* No mmap */
751  CHECK(snd_pcm_hw_params_set_access(data->pcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED));
752  }
753  /* test and set format (implicitly sets sample bits) */
754  if(snd_pcm_hw_params_test_format(data->pcmHandle, hp, format) < 0)
755  {
756  static const struct {
757  snd_pcm_format_t format;
758  enum DevFmtType fmttype;
759  } formatlist[] = {
760  { SND_PCM_FORMAT_FLOAT, DevFmtFloat },
761  { SND_PCM_FORMAT_S32, DevFmtInt },
762  { SND_PCM_FORMAT_U32, DevFmtUInt },
763  { SND_PCM_FORMAT_S16, DevFmtShort },
764  { SND_PCM_FORMAT_U16, DevFmtUShort },
765  { SND_PCM_FORMAT_S8, DevFmtByte },
766  { SND_PCM_FORMAT_U8, DevFmtUByte },
767  };
768  size_t k;
769 
770  for(k = 0;k < COUNTOF(formatlist);k++)
771  {
772  format = formatlist[k].format;
773  if(snd_pcm_hw_params_test_format(data->pcmHandle, hp, format) >= 0)
774  {
775  device->FmtType = formatlist[k].fmttype;
776  break;
777  }
778  }
779  }
780  CHECK(snd_pcm_hw_params_set_format(data->pcmHandle, hp, format));
781  /* test and set channels (implicitly sets frame bits) */
782  if(snd_pcm_hw_params_test_channels(data->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans)) < 0)
783  {
784  static const enum DevFmtChannels channellist[] = {
785  DevFmtStereo,
786  DevFmtQuad,
787  DevFmtX51,
788  DevFmtX71,
789  DevFmtMono,
790  };
791  size_t k;
792 
793  for(k = 0;k < COUNTOF(channellist);k++)
794  {
795  if(snd_pcm_hw_params_test_channels(data->pcmHandle, hp, ChannelsFromDevFmt(channellist[k])) >= 0)
796  {
797  device->FmtChans = channellist[k];
798  break;
799  }
800  }
801  }
802  CHECK(snd_pcm_hw_params_set_channels(data->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans)));
803  /* set rate (implicitly constrains period/buffer parameters) */
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));
807  /* set buffer time (implicitly constrains period/buffer parameters) */
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));
810  /* set period time (implicitly sets buffer size/bytes/time and period size/bytes) */
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));
813  /* install and prepare hardware configuration */
814  CHECK(snd_pcm_hw_params(data->pcmHandle, hp));
815  /* retrieve configuration info */
816  CHECK(snd_pcm_hw_params_get_access(hp, &access));
817  CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, NULL));
818  CHECK(snd_pcm_hw_params_get_periods(hp, &periods, NULL));
819 
820  snd_pcm_hw_params_free(hp);
821  hp = NULL;
822  snd_pcm_sw_params_malloc(&sp);
823 
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));
828 #undef CHECK
829  snd_pcm_sw_params_free(sp);
830  sp = NULL;
831 
832  device->NumUpdates = periods;
833  device->UpdateSize = periodSizeInFrames;
834  device->Frequency = rate;
835 
836  SetDefaultChannelOrder(device);
837 
838  return ALC_TRUE;
839 
840 error:
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);
844  return ALC_FALSE;
845 }
846 
848 {
849  alsa_data *data = (alsa_data*)device->ExtraData;
850  snd_pcm_hw_params_t *hp = NULL;
851  snd_pcm_access_t access;
852  const char *funcerr;
853  int err;
854 
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));
858  /* retrieve configuration info */
859  CHECK(snd_pcm_hw_params_get_access(hp, &access));
860 #undef CHECK
861  snd_pcm_hw_params_free(hp);
862  hp = NULL;
863 
864  data->size = snd_pcm_frames_to_bytes(data->pcmHandle, device->UpdateSize);
865  if(access == SND_PCM_ACCESS_RW_INTERLEAVED)
866  {
867  data->buffer = malloc(data->size);
868  if(!data->buffer)
869  {
870  ERR("buffer malloc failed\n");
871  return ALC_FALSE;
872  }
873  data->thread = StartThread(ALSANoMMapProc, device);
874  }
875  else
876  {
877  err = snd_pcm_prepare(data->pcmHandle);
878  if(err < 0)
879  {
880  ERR("snd_pcm_prepare(data->pcmHandle) failed: %s\n", snd_strerror(err));
881  return ALC_FALSE;
882  }
883  data->thread = StartThread(ALSAProc, device);
884  }
885  if(data->thread == NULL)
886  {
887  ERR("Could not create playback thread\n");
888  free(data->buffer);
889  data->buffer = NULL;
890  return ALC_FALSE;
891  }
892 
893  return ALC_TRUE;
894 
895 error:
896  ERR("%s failed: %s\n", funcerr, snd_strerror(err));
897  if(hp) snd_pcm_hw_params_free(hp);
898  return ALC_FALSE;
899 }
900 
901 static void alsa_stop_playback(ALCdevice *device)
902 {
903  alsa_data *data = (alsa_data*)device->ExtraData;
904 
905  if(data->thread)
906  {
907  data->killNow = 1;
908  StopThread(data->thread);
909  data->thread = NULL;
910  }
911  data->killNow = 0;
912  free(data->buffer);
913  data->buffer = NULL;
914 }
915 
916 
917 static ALCenum alsa_open_capture(ALCdevice *Device, const ALCchar *deviceName)
918 {
919  const char *driver = NULL;
920  snd_pcm_hw_params_t *hp;
921  snd_pcm_uframes_t bufferSizeInFrames;
922  snd_pcm_uframes_t periodSizeInFrames;
923  ALboolean needring = AL_FALSE;
924  snd_pcm_format_t format;
925  const char *funcerr;
926  alsa_data *data;
927  int err;
928 
929  if(deviceName)
930  {
931  size_t idx;
932 
934  allCaptureDevNameMap = probe_devices(SND_PCM_STREAM_CAPTURE, &numCaptureDevNames);
935 
936  for(idx = 0;idx < numCaptureDevNames;idx++)
937  {
938  if(strcmp(deviceName, allCaptureDevNameMap[idx].name) == 0)
939  {
940  driver = allCaptureDevNameMap[idx].device;
941  break;
942  }
943  }
944  if(idx == numCaptureDevNames)
945  return ALC_INVALID_VALUE;
946  }
947  else
948  {
949  deviceName = alsaDevice;
950  driver = GetConfigValue("alsa", "capture", "default");
951  }
952 
953  data = (alsa_data*)calloc(1, sizeof(alsa_data));
954 
955  err = snd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
956  if(err < 0)
957  {
958  ERR("Could not open capture device '%s': %s\n", driver, snd_strerror(err));
959  free(data);
960  return ALC_INVALID_VALUE;
961  }
962 
963  /* Free alsa's global config tree. Otherwise valgrind reports a ton of leaks. */
964  snd_config_update_free_global();
965 
966  format = -1;
967  switch(Device->FmtType)
968  {
969  case DevFmtByte:
970  format = SND_PCM_FORMAT_S8;
971  break;
972  case DevFmtUByte:
973  format = SND_PCM_FORMAT_U8;
974  break;
975  case DevFmtShort:
976  format = SND_PCM_FORMAT_S16;
977  break;
978  case DevFmtUShort:
979  format = SND_PCM_FORMAT_U16;
980  break;
981  case DevFmtInt:
982  format = SND_PCM_FORMAT_S32;
983  break;
984  case DevFmtUInt:
985  format = SND_PCM_FORMAT_U32;
986  break;
987  case DevFmtFloat:
988  format = SND_PCM_FORMAT_FLOAT;
989  break;
990  }
991 
992  funcerr = NULL;
993  bufferSizeInFrames = maxu(Device->UpdateSize*Device->NumUpdates,
994  100*Device->Frequency/1000);
995  periodSizeInFrames = minu(bufferSizeInFrames, 25*Device->Frequency/1000);
996 
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));
1000  /* set interleaved access */
1001  CHECK(snd_pcm_hw_params_set_access(data->pcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED));
1002  /* set format (implicitly sets sample bits) */
1003  CHECK(snd_pcm_hw_params_set_format(data->pcmHandle, hp, format));
1004  /* set channels (implicitly sets frame bits) */
1005  CHECK(snd_pcm_hw_params_set_channels(data->pcmHandle, hp, ChannelsFromDevFmt(Device->FmtChans)));
1006  /* set rate (implicitly constrains period/buffer parameters) */
1007  CHECK(snd_pcm_hw_params_set_rate(data->pcmHandle, hp, Device->Frequency, 0));
1008  /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */
1009  if(snd_pcm_hw_params_set_buffer_size_min(data->pcmHandle, hp, &bufferSizeInFrames) < 0)
1010  {
1011  TRACE("Buffer too large, using intermediate ring buffer\n");
1012  needring = AL_TRUE;
1013  CHECK(snd_pcm_hw_params_set_buffer_size_near(data->pcmHandle, hp, &bufferSizeInFrames));
1014  }
1015  /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */
1016  CHECK(snd_pcm_hw_params_set_period_size_near(data->pcmHandle, hp, &periodSizeInFrames, NULL));
1017  /* install and prepare hardware configuration */
1018  CHECK(snd_pcm_hw_params(data->pcmHandle, hp));
1019  /* retrieve configuration info */
1020  CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, NULL));
1021 #undef CHECK
1022  snd_pcm_hw_params_free(hp);
1023  hp = NULL;
1024 
1025  if(needring)
1026  {
1027  data->ring = CreateRingBuffer(FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType),
1028  Device->UpdateSize*Device->NumUpdates);
1029  if(!data->ring)
1030  {
1031  ERR("ring buffer create failed\n");
1032  goto error2;
1033  }
1034 
1035  data->size = snd_pcm_frames_to_bytes(data->pcmHandle, periodSizeInFrames);
1036  data->buffer = malloc(data->size);
1037  if(!data->buffer)
1038  {
1039  ERR("buffer malloc failed\n");
1040  goto error2;
1041  }
1042  }
1043 
1044  Device->DeviceName = strdup(deviceName);
1045 
1046  Device->ExtraData = data;
1047  return ALC_NO_ERROR;
1048 
1049 error:
1050  ERR("%s failed: %s\n", funcerr, snd_strerror(err));
1051  if(hp) snd_pcm_hw_params_free(hp);
1052 
1053 error2:
1054  free(data->buffer);
1055  DestroyRingBuffer(data->ring);
1056  snd_pcm_close(data->pcmHandle);
1057  free(data);
1058 
1059  Device->ExtraData = NULL;
1060  return ALC_INVALID_VALUE;
1061 }
1062 
1063 static void alsa_close_capture(ALCdevice *Device)
1064 {
1065  alsa_data *data = (alsa_data*)Device->ExtraData;
1066 
1067  snd_pcm_close(data->pcmHandle);
1068  DestroyRingBuffer(data->ring);
1069 
1070  free(data->buffer);
1071  free(data);
1072  Device->ExtraData = NULL;
1073 }
1074 
1075 static void alsa_start_capture(ALCdevice *Device)
1076 {
1077  alsa_data *data = (alsa_data*)Device->ExtraData;
1078  int err;
1079 
1080  err = snd_pcm_start(data->pcmHandle);
1081  if(err < 0)
1082  {
1083  ERR("start failed: %s\n", snd_strerror(err));
1084  aluHandleDisconnect(Device);
1085  }
1086  else
1087  data->doCapture = AL_TRUE;
1088 }
1089 
1090 static ALCenum alsa_capture_samples(ALCdevice *Device, ALCvoid *Buffer, ALCuint Samples)
1091 {
1092  alsa_data *data = (alsa_data*)Device->ExtraData;
1093 
1094  if(data->ring)
1095  {
1096  ReadRingBuffer(data->ring, Buffer, Samples);
1097  return ALC_NO_ERROR;
1098  }
1099 
1100  data->last_avail -= Samples;
1101  while(Device->Connected && Samples > 0)
1102  {
1103  snd_pcm_sframes_t amt = 0;
1104 
1105  if(data->size > 0)
1106  {
1107  /* First get any data stored from the last stop */
1108  amt = snd_pcm_bytes_to_frames(data->pcmHandle, data->size);
1109  if((snd_pcm_uframes_t)amt > Samples) amt = Samples;
1110 
1111  amt = snd_pcm_frames_to_bytes(data->pcmHandle, amt);
1112  memmove(Buffer, data->buffer, amt);
1113 
1114  if(data->size > amt)
1115  {
1116  memmove(data->buffer, data->buffer+amt, data->size - amt);
1117  data->size -= amt;
1118  }
1119  else
1120  {
1121  free(data->buffer);
1122  data->buffer = NULL;
1123  data->size = 0;
1124  }
1125  amt = snd_pcm_bytes_to_frames(data->pcmHandle, amt);
1126  }
1127  else if(data->doCapture)
1128  amt = snd_pcm_readi(data->pcmHandle, Buffer, Samples);
1129  if(amt < 0)
1130  {
1131  ERR("read error: %s\n", snd_strerror(amt));
1132 
1133  if(amt == -EAGAIN)
1134  continue;
1135  if((amt=snd_pcm_recover(data->pcmHandle, amt, 1)) >= 0)
1136  {
1137  amt = snd_pcm_start(data->pcmHandle);
1138  if(amt >= 0)
1139  amt = snd_pcm_avail_update(data->pcmHandle);
1140  }
1141  if(amt < 0)
1142  {
1143  ERR("restore error: %s\n", snd_strerror(amt));
1144  aluHandleDisconnect(Device);
1145  break;
1146  }
1147  /* If the amount available is less than what's asked, we lost it
1148  * during recovery. So just give silence instead. */
1149  if((snd_pcm_uframes_t)amt < Samples)
1150  break;
1151  continue;
1152  }
1153 
1154  Buffer = (ALbyte*)Buffer + amt;
1155  Samples -= amt;
1156  }
1157  if(Samples > 0)
1158  memset(Buffer, ((Device->FmtType == DevFmtUByte) ? 0x80 : 0),
1159  snd_pcm_frames_to_bytes(data->pcmHandle, Samples));
1160 
1161  return ALC_NO_ERROR;
1162 }
1163 
1165 {
1166  alsa_data *data = (alsa_data*)Device->ExtraData;
1167  snd_pcm_sframes_t avail = 0;
1168 
1169  if(Device->Connected && data->doCapture)
1170  avail = snd_pcm_avail_update(data->pcmHandle);
1171  if(avail < 0)
1172  {
1173  ERR("avail update failed: %s\n", snd_strerror(avail));
1174 
1175  if((avail=snd_pcm_recover(data->pcmHandle, avail, 1)) >= 0)
1176  {
1177  if(data->doCapture)
1178  avail = snd_pcm_start(data->pcmHandle);
1179  if(avail >= 0)
1180  avail = snd_pcm_avail_update(data->pcmHandle);
1181  }
1182  if(avail < 0)
1183  {
1184  ERR("restore error: %s\n", snd_strerror(avail));
1185  aluHandleDisconnect(Device);
1186  }
1187  }
1188 
1189  if(!data->ring)
1190  {
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;
1195  }
1196 
1197  while(avail > 0)
1198  {
1199  snd_pcm_sframes_t amt;
1200 
1201  amt = snd_pcm_bytes_to_frames(data->pcmHandle, data->size);
1202  if(avail < amt) amt = avail;
1203 
1204  amt = snd_pcm_readi(data->pcmHandle, data->buffer, amt);
1205  if(amt < 0)
1206  {
1207  ERR("read error: %s\n", snd_strerror(amt));
1208 
1209  if(amt == -EAGAIN)
1210  continue;
1211  if((amt=snd_pcm_recover(data->pcmHandle, amt, 1)) >= 0)
1212  {
1213  if(data->doCapture)
1214  amt = snd_pcm_start(data->pcmHandle);
1215  if(amt >= 0)
1216  amt = snd_pcm_avail_update(data->pcmHandle);
1217  }
1218  if(amt < 0)
1219  {
1220  ERR("restore error: %s\n", snd_strerror(amt));
1221  aluHandleDisconnect(Device);
1222  break;
1223  }
1224  avail = amt;
1225  continue;
1226  }
1227 
1228  WriteRingBuffer(data->ring, data->buffer, amt);
1229  avail -= amt;
1230  }
1231 
1232  return RingBufferSize(data->ring);
1233 }
1234 
1235 static void alsa_stop_capture(ALCdevice *Device)
1236 {
1237  alsa_data *data = (alsa_data*)Device->ExtraData;
1238  ALCuint avail;
1239  int err;
1240 
1241  /* OpenAL requires access to unread audio after stopping, but ALSA's
1242  * snd_pcm_drain is unreliable and snd_pcm_drop drops it. Capture what's
1243  * available now so it'll be available later after the drop. */
1244  avail = alsa_available_samples(Device);
1245  if(!data->ring && avail > 0)
1246  {
1247  /* The ring buffer implicitly captures when checking availability.
1248  * Direct access needs to explicitly capture it into temp storage. */
1249  ALsizei size;
1250  void *ptr;
1251 
1252  size = snd_pcm_frames_to_bytes(data->pcmHandle, avail);
1253  ptr = realloc(data->buffer, size);
1254  if(ptr)
1255  {
1256  data->buffer = ptr;
1257  alsa_capture_samples(Device, data->buffer, avail);
1258  data->size = size;
1259  }
1260  }
1261  err = snd_pcm_drop(data->pcmHandle);
1262  if(err < 0)
1263  ERR("drop failed: %s\n", snd_strerror(err));
1264  data->doCapture = AL_FALSE;
1265 }
1266 
1267 
1268 static ALint64 alsa_get_latency(ALCdevice *device)
1269 {
1270  alsa_data *data = (alsa_data*)device->ExtraData;
1271  snd_pcm_sframes_t delay = 0;
1272  int err;
1273 
1274  if((err=snd_pcm_delay(data->pcmHandle, &delay)) < 0)
1275  {
1276  ERR("Failed to get pcm delay: %s\n", snd_strerror(err));
1277  return 0;
1278  }
1279  return maxi64((ALint64)delay*1000000000/device->Frequency, 0);
1280 }
1281 
1282 
1283 static const BackendFuncs alsa_funcs = {
1298 };
1299 
1301 {
1302  if(!alsa_load())
1303  return ALC_FALSE;
1304  *func_list = alsa_funcs;
1305  return ALC_TRUE;
1306 }
1307 
1309 {
1310  ALuint i;
1311 
1312  for(i = 0;i < numDevNames;++i)
1313  {
1314  free(allDevNameMap[i].name);
1315  free(allDevNameMap[i].device);
1316  }
1318  allDevNameMap = NULL;
1319  numDevNames = 0;
1320 
1321  for(i = 0;i < numCaptureDevNames;++i)
1322  {
1324  free(allCaptureDevNameMap[i].device);
1325  }
1328  numCaptureDevNames = 0;
1329 
1330 #ifdef HAVE_DYNLOAD
1331  if(alsa_handle)
1332  CloseLib(alsa_handle);
1333  alsa_handle = NULL;
1334 #endif
1335 }
1336 
1338 {
1339  ALuint i;
1340 
1341  switch(type)
1342  {
1343  case ALL_DEVICE_PROBE:
1344  for(i = 0;i < numDevNames;++i)
1345  {
1346  free(allDevNameMap[i].name);
1347  free(allDevNameMap[i].device);
1348  }
1349 
1351  allDevNameMap = probe_devices(SND_PCM_STREAM_PLAYBACK, &numDevNames);
1352 
1353  for(i = 0;i < numDevNames;++i)
1355  break;
1356 
1357  case CAPTURE_DEVICE_PROBE:
1358  for(i = 0;i < numCaptureDevNames;++i)
1359  {
1360  free(allCaptureDevNameMap[i].name);
1361  free(allCaptureDevNameMap[i].device);
1362  }
1363 
1365  allCaptureDevNameMap = probe_devices(SND_PCM_STREAM_CAPTURE, &numCaptureDevNames);
1366 
1367  for(i = 0;i < numCaptureDevNames;++i)
1369  break;
1370  }
1371 }
int ConfigValueStr(const char *blockName, const char *keyName, const char **ret)
Definition: alcConfig.c:316
ALCboolean Connected
Definition: alMain.h:564
void ALvoid
Definition: al.h:74
static ALCboolean alsa_start_playback(ALCdevice *device)
Definition: alsa.c:847
#define ALC_TRUE
Definition: alc.h:84
GLint GLenum GLsizei GLsizei GLsizei GLint GLenum GLenum type
Definition: gl2ext.h:845
#define AL_TRUE
Definition: al.h:86
char * strdup(const char *inStr)
Definition: strdup.c:6
#define NULL
Definition: ftobjs.h:61
#define TRACE(...)
Definition: alMain.h:806
int32_t k
Definition: e_log.c:102
GLuint GLuint stream
Definition: glew.h:6573
static ALint64 alsa_get_latency(ALCdevice *device)
Definition: alsa.c:1268
#define memmove
Definition: SDL_qsort.c:81
int ALsizei
Definition: al.h:62
SDL_EventEntry * free
Definition: SDL_events.c:80
ALuint Frequency
Definition: alMain.h:569
DevFmtType
Definition: alMain.h:496
ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
Definition: ALu.c:970
static ALuint ALSANoMMapProc(ALvoid *ptr)
Definition: alsa.c:545
#define memset
Definition: SDL_malloc.c:633
#define AL_FALSE
Definition: al.h:83
static void alsa_close_capture(ALCdevice *Device)
Definition: alsa.c:1063
EGLImageKHR EGLint * name
Definition: eglext.h:284
#define assert(x)
Definition: SDL_malloc.c:1234
static ALuint ALSAProc(ALvoid *ptr)
Definition: alsa.c:454
ALsizei RingBufferSize(RingBuffer *ring)
Definition: alcRing.c:67
void SetDefaultChannelOrder(ALCdevice *device)
Definition: ALc.c:1352
const char * GetConfigValue(const char *blockName, const char *keyName, const char *def)
Definition: alcConfig.c:278
void AppendCaptureDeviceList(const ALCchar *name)
#define CHECK(x)
unsigned int ALCuint
Definition: alc.h:60
#define calloc
Definition: SDL_malloc.c:636
static void alsa_close_playback(ALCdevice *device)
Definition: alsa.c:688
void alc_alsa_probe(enum DevProbe type)
Definition: alsa.c:1337
ALvoid aluHandleDisconnect(ALCdevice *device)
Definition: ALu.c:1176
char ALCchar
Definition: alc.h:42
signed char ALbyte
Definition: al.h:44
ret
Definition: glew_str_glx.c:2
static ALCboolean alsa_load(void)
Definition: alsa.c:188
#define ALCdevice_Unlock(a)
Definition: alMain.h:647
static DevMap * probe_devices(snd_pcm_stream_t stream, ALuint *count)
Definition: alsa.c:316
struct RingBuffer RingBuffer
Definition: alMain.h:750
void alc_alsa_deinit(void)
Definition: alsa.c:1308
EGLContext EGLenum EGLClientBuffer buffer
Definition: eglext.h:87
void * ExtraData
Definition: alMain.h:630
#define ALC_FALSE
Definition: alc.h:81
int GetConfigValueBool(const char *blockName, const char *keyName, int def)
Definition: alcConfig.c:356
static __inline ALint64 maxi64(ALint64 a, ALint64 b)
Definition: alu.h:77
ALuint StopThread(ALvoid *thread)
Definition: alcThread.c:131
FT_UInt idx
Definition: cffcmap.c:125
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl2ext.h:848
FT_Error error
Definition: cffdrivr.c:407
static const char * prefix_name(snd_pcm_stream_t stream)
Definition: alsa.c:310
static ALCboolean alsa_reset_playback(ALCdevice *device)
Definition: alsa.c:697
GLint GLsizei count
Definition: gl2ext.h:1011
static const ALCchar alsaDevice[]
Definition: alsa.c:33
RingBuffer * CreateRingBuffer(ALsizei frame_size, ALsizei length)
Definition: alcRing.c:41
#define LOAD_FUNC(f)
#define realloc
Definition: SDL_malloc.c:637
static ALCenum alsa_capture_samples(ALCdevice *Device, ALCvoid *Buffer, ALCuint Samples)
Definition: alsa.c:1090
GLint GLenum GLsizei GLsizei GLsizei GLint GLenum format
Definition: gl2ext.h:845
static ALCuint alsa_available_samples(ALCdevice *Device)
Definition: alsa.c:1164
static DevMap * allDevNameMap
Definition: alsa.c:304
unsigned int ALuint
Definition: al.h:59
ALCboolean alc_alsa_init(BackendFuncs *func_list)
Definition: alsa.c:1300
void SetRTPriority(void)
Definition: helpers.c:470
#define WARN(...)
Definition: alMain.h:811
enum DevFmtChannels FmtChans
Definition: alMain.h:572
static __inline ALuint minu(ALuint a, ALuint b)
Definition: alu.h:61
static void alsa_stop_playback(ALCdevice *device)
Definition: alsa.c:901
static DevMap * allCaptureDevNameMap
Definition: alsa.c:306
static SDL_Thread * thread
#define ALC_NO_ERROR
Definition: alc.h:102
void ALCdevice_LockDefault(ALCdevice *device)
Definition: ALc.c:1277
#define malloc
Definition: SDL_malloc.c:635
char ALCboolean
Definition: alc.h:39
static ALCenum alsa_open_capture(ALCdevice *Device, const ALCchar *deviceName)
Definition: alsa.c:917
GLintptr offset
Definition: glew.h:1668
static void alsa_start_capture(ALCdevice *Device)
Definition: alsa.c:1075
static ALuint numDevNames
Definition: alsa.c:305
GLenum access
Definition: glew.h:3469
void ALCvoid
Definition: alc.h:75
#define ERR(...)
Definition: alMain.h:816
ALuint UpdateSize
Definition: alMain.h:570
ALuint NumUpdates
Definition: alMain.h:571
enum DevFmtType FmtType
Definition: alMain.h:573
ALCchar * DeviceName
Definition: alMain.h:575
char ALboolean
Definition: al.h:38
#define ALC_INVALID_VALUE
Definition: alc.h:114
#define ALC_OUT_OF_MEMORY
Definition: alc.h:117
void ReadRingBuffer(RingBuffer *ring, ALubyte *data, ALsizei len)
Definition: alcRing.c:108
static int verify_state(snd_pcm_t *handle)
Definition: alsa.c:422
EGLImageKHR EGLint EGLint * handle
Definition: eglext.h:284
int i
Definition: pngrutil.c:1377
int ALCenum
Definition: alc.h:66
static const BackendFuncs alsa_funcs
Definition: alsa.c:1283
void DestroyRingBuffer(RingBuffer *ring)
Definition: alcRing.c:58
void ALCdevice_UnlockDefault(ALCdevice *device)
Definition: ALc.c:1281
static __inline ALuint maxu(ALuint a, ALuint b)
Definition: alu.h:63
static void alsa_stop_capture(ALCdevice *Device)
Definition: alsa.c:1235
DevFmtChannels
Definition: alMain.h:507
void WriteRingBuffer(RingBuffer *ring, const ALubyte *data, ALsizei len)
Definition: alcRing.c:78
ALuint ChannelsFromDevFmt(enum DevFmtChannels chans)
Definition: ALc.c:1179
#define ALCdevice_Lock(a)
Definition: alMain.h:646
static ALuint numCaptureDevNames
Definition: alsa.c:307
static ALCenum alsa_open_playback(ALCdevice *device, const ALCchar *deviceName)
Definition: alsa.c:640
void AppendAllDevicesList(const ALCchar *name)
#define COUNTOF(x)
Definition: alMain.h:63
ALvoid * StartThread(ALuint(*func)(ALvoid *), ALvoid *ptr)
Definition: alcThread.c:100
DevProbe
Definition: alMain.h:383
static __inline ALuint FrameSizeFromDevFmt(enum DevFmtChannels chans, enum DevFmtType type)
Definition: alMain.h:523
GLsizei size
Definition: gl2ext.h:1467