1 #include "audiodevice.h"
5 #include "playbackconfig.h"
6 #include "preferences.h"
7 #include "recordconfig.h"
13 AudioALSA::AudioALSA(AudioDevice *device)
14 : AudioLowLevel(device)
19 timer_lock = new Mutex("AudioALSA::timer_lock");
24 AudioALSA::~AudioALSA()
30 void AudioALSA::list_devices(ArrayList<char*> *devices, int pcm_title, int mode)
33 int card, err, dev, idx;
34 snd_ctl_card_info_t *info;
35 snd_pcm_info_t *pcminfo;
36 char string[BCTEXTLEN];
37 snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK;
42 stream = SND_PCM_STREAM_CAPTURE;
45 stream = SND_PCM_STREAM_PLAYBACK;
49 snd_ctl_card_info_alloca(&info);
50 snd_pcm_info_alloca(&pcminfo);
53 #define DEFAULT_DEVICE "default"
54 char *result = new char[strlen(DEFAULT_DEVICE) + 1];
55 devices->append(result);
56 devices->set_array_delete(); // since we are allocating by new[]
57 strcpy(result, DEFAULT_DEVICE);
59 while(snd_card_next(&card) >= 0)
63 sprintf(name, "hw:%i", card);
65 if((err = snd_ctl_open(&handle, name, 0)) < 0)
67 printf("AudioALSA::list_devices card=%i: %s\n", card, snd_strerror(err));
71 if((err = snd_ctl_card_info(handle, info)) < 0)
73 printf("AudioALSA::list_devices card=%i: %s\n", card, snd_strerror(err));
74 snd_ctl_close(handle);
83 if(snd_ctl_pcm_next_device(handle, &dev) < 0)
84 printf("AudioALSA::list_devices: snd_ctl_pcm_next_device\n");
89 snd_pcm_info_set_device(pcminfo, dev);
90 snd_pcm_info_set_subdevice(pcminfo, 0);
91 snd_pcm_info_set_stream(pcminfo, stream);
93 if((err = snd_ctl_pcm_info(handle, pcminfo)) < 0)
96 printf("AudioALSA::list_devices card=%i: %s\n", card, snd_strerror(err));
102 sprintf(string, "plughw:%d,%d", card, dev);
103 // strcpy(string, "cards.pcm.front");
107 sprintf(string, "%s #%d",
108 snd_ctl_card_info_get_name(info),
112 char *result = devices->append(new char[strlen(string) + 1]);
113 strcpy(result, string);
116 snd_ctl_close(handle);
119 // snd_ctl_card_info_free(info);
120 // snd_pcm_info_free(pcminfo);
123 void AudioALSA::translate_name(char *output, char *input)
125 ArrayList<char*> titles;
126 ArrayList<char*> pcm_titles;
128 if(device->r) mode = MODERECORD;
130 if(device->w) mode = MODEPLAY;
132 list_devices(&titles, 0, mode);
133 list_devices(&pcm_titles, 1, mode);
135 sprintf(output, "default");
136 for(int i = 0; i < titles.total; i++)
138 //printf("AudioALSA::translate_name %s %s\n", titles.values[i], pcm_titles.values[i]);
139 if(!strcasecmp(titles.values[i], input))
141 strcpy(output, pcm_titles.values[i]);
146 titles.remove_all_objects();
147 pcm_titles.remove_all_objects();
150 snd_pcm_format_t AudioALSA::translate_format(int format)
155 return SND_PCM_FORMAT_S8;
158 return SND_PCM_FORMAT_S16_LE;
161 return SND_PCM_FORMAT_S24_LE;
164 return SND_PCM_FORMAT_S32_LE;
169 void AudioALSA::set_params(snd_pcm_t *dsp,
175 snd_pcm_hw_params_t *params;
176 snd_pcm_sw_params_t *swparams;
179 snd_pcm_hw_params_alloca(¶ms);
180 snd_pcm_sw_params_alloca(&swparams);
181 err = snd_pcm_hw_params_any(dsp, params);
185 printf("AudioALSA::set_params: no PCM configurations available\n");
189 snd_pcm_hw_params_set_access(dsp,
191 SND_PCM_ACCESS_RW_INTERLEAVED);
192 snd_pcm_hw_params_set_format(dsp,
194 translate_format(bits));
195 snd_pcm_hw_params_set_channels(dsp,
198 snd_pcm_hw_params_set_rate_near(dsp,
200 (unsigned int*)&samplerate,
203 // Buffers written must be equal to period_time
208 buffer_time = 10000000;
209 period_time = (int)((int64_t)samples * 1000000 / samplerate);
213 buffer_time = (int)((int64_t)samples * 1000000 * 2 / samplerate + 0.5);
214 period_time = samples * samplerate / 1000000;
218 //printf("AudioALSA::set_params 1 %d %d %d\n", samples, buffer_time, period_time);
219 snd_pcm_hw_params_set_buffer_time_near(dsp,
221 (unsigned int*)&buffer_time,
223 snd_pcm_hw_params_set_period_time_near(dsp,
225 (unsigned int*)&period_time,
227 //printf("AudioALSA::set_params 5 %d %d\n", buffer_time, period_time);
228 err = snd_pcm_hw_params(dsp, params);
231 printf("AudioALSA::set_params: hw_params failed\n");
235 snd_pcm_uframes_t chunk_size = 1024;
236 snd_pcm_uframes_t buffer_size = 262144;
237 snd_pcm_hw_params_get_period_size(params, &chunk_size, 0);
238 snd_pcm_hw_params_get_buffer_size(params, &buffer_size);
239 //printf("AudioALSA::set_params 10 %d %d\n", chunk_size, buffer_size);
241 snd_pcm_sw_params_current(dsp, swparams);
242 size_t xfer_align = 1 /* snd_pcm_sw_params_get_xfer_align(swparams) */;
243 unsigned int sleep_min = 0;
244 err = snd_pcm_sw_params_set_sleep_min(dsp, swparams, sleep_min);
246 err = snd_pcm_sw_params_set_avail_min(dsp, swparams, n);
247 err = snd_pcm_sw_params_set_xfer_align(dsp, swparams, xfer_align);
248 if(snd_pcm_sw_params(dsp, swparams) < 0)
250 printf("AudioALSA::set_params: snd_pcm_sw_params failed\n");
253 device->device_buffer = samples * bits / 8 * channels;
255 //printf("AudioALSA::set_params 100 %d %d\n", samples, device->device_buffer);
257 // snd_pcm_hw_params_free(params);
258 // snd_pcm_sw_params_free(swparams);
261 int AudioALSA::open_input()
263 char pcm_name[BCTEXTLEN];
264 snd_pcm_stream_t stream = SND_PCM_STREAM_CAPTURE;
268 device->in_channels = device->get_ichannels();
269 device->in_bits = device->in_config->alsa_in_bits;
271 translate_name(pcm_name, device->in_config->alsa_in_device);
272 //printf("AudioALSA::open_input %s\n", pcm_name);
274 // err = snd_pcm_open(&dsp_in, pcm_name, stream, open_mode);
275 err = snd_pcm_open(&dsp_in, device->in_config->alsa_in_device, stream, open_mode);
279 printf("AudioALSA::open_input: %s\n", snd_strerror(err));
284 device->get_ichannels(),
285 device->in_config->alsa_in_bits,
286 device->in_samplerate,
292 int AudioALSA::open_output()
294 char pcm_name[BCTEXTLEN];
295 snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK;
299 device->out_channels = device->get_ochannels();
300 device->out_bits = device->out_config->alsa_out_bits;
302 translate_name(pcm_name, device->out_config->alsa_out_device);
304 // err = snd_pcm_open(&dsp_out, pcm_name, stream, open_mode);
305 err = snd_pcm_open(&dsp_out, device->out_config->alsa_out_device, stream, open_mode);
310 printf("AudioALSA::open_output %s: %s\n", pcm_name, snd_strerror(err));
315 device->get_ochannels(),
316 device->out_config->alsa_out_bits,
317 device->out_samplerate,
318 device->out_samples);
323 int AudioALSA::open_duplex()
325 // ALSA always opens 2 devices
329 int AudioALSA::close_output()
331 if(device->w && dsp_out)
333 snd_pcm_close(dsp_out);
338 int AudioALSA::close_input()
342 // snd_pcm_reset(dsp_in);
343 snd_pcm_drop(dsp_in);
344 snd_pcm_drain(dsp_in);
345 snd_pcm_close(dsp_in);
350 int AudioALSA::close_all()
356 snd_pcm_close(dsp_duplex);
364 int64_t AudioALSA::device_position()
366 timer_lock->lock("AudioALSA::device_position");
367 int64_t result = samples_written +
368 timer->get_scaled_difference(device->out_samplerate) -
370 // printf("AudioALSA::device_position 1 %lld %lld %d %lld\n",
372 // timer->get_scaled_difference(device->out_samplerate),
374 // samples_written + timer->get_scaled_difference(device->out_samplerate) - delay);
375 timer_lock->unlock();
379 int AudioALSA::read_buffer(char *buffer, int size)
381 //printf("AudioALSA::read_buffer 1\n");
391 while(attempts < 1 && !done)
393 if(snd_pcm_readi(get_input(),
395 size / (device->in_bits / 8) / device->get_ichannels()) < 0)
397 printf("AudioALSA::read_buffer overrun at sample %lld\n",
398 device->total_samples_read);
399 // snd_pcm_resume(get_input());
410 int AudioALSA::write_buffer(char *buffer, int size)
412 // Don't give up and drop the buffer on the first error.
415 int samples = size / (device->out_bits / 8) / device->get_ochannels();
417 if(!get_output()) return 0;
419 while(attempts < 2 && !done && !interrupted)
421 // Buffers written must be equal to period_time
423 snd_pcm_sframes_t delay;
424 snd_pcm_delay(get_output(), &delay);
425 snd_pcm_avail_update(get_output());
427 device->Thread::enable_cancel();
428 if(snd_pcm_writei(get_output(),
432 device->Thread::disable_cancel();
433 printf("AudioALSA::write_buffer underrun at sample %lld\n",
434 device->current_position());
435 // snd_pcm_resume(get_output());
442 device->Thread::disable_cancel();
449 timer_lock->lock("AudioALSA::write_buffer");
452 samples_written += samples;
453 timer_lock->unlock();
458 int AudioALSA::flush_device()
460 if(get_output()) snd_pcm_drain(get_output());
464 int AudioALSA::interrupt_playback()
469 // Interrupts the playback but may not have caused snd_pcm_writei to exit.
470 // With some soundcards it causes snd_pcm_writei to freeze for a few seconds.
471 if(!device->out_config->interrupt_workaround)
472 snd_pcm_drop(get_output());
474 // Makes sure the current buffer finishes before stopping.
475 // snd_pcm_drain(get_output());
477 // The only way to ensure snd_pcm_writei exits, but
478 // got a lot of crashes when doing this.
479 // device->Thread::cancel();
485 snd_pcm_t* AudioALSA::get_output()
487 if(device->w) return dsp_out;
489 if(device->d) return dsp_duplex;
493 snd_pcm_t* AudioALSA::get_input()
495 if(device->r) return dsp_in;
497 if(device->d) return dsp_duplex;
505 // c-file-style: "linux"