From: bruceperens Date: Fri, 25 Apr 2014 00:35:48 +0000 (+0000) Subject: Make ALSA more tolerant of differing hardware. X-Git-Url: http://git.whiteaudio.com/gitweb/?a=commitdiff_plain;h=4efca6b15f212d9be5a09e16a086b9a0bb74f42d;p=freetel-svn-tracking.git Make ALSA more tolerant of differing hardware. git-svn-id: https://svn.code.sf.net/p/freetel/code@1555 01035d8c-6547-0410-b346-abe4f91aad63 --- diff --git a/freedv-server/source/drivers.h b/freedv-server/source/drivers.h index e49e6497..954587cc 100644 --- a/freedv-server/source/drivers.h +++ b/freedv-server/source/drivers.h @@ -63,20 +63,16 @@ const unsigned int SamplesPerMillisecond = ((double)SampleRate / 1000.0); /// size we expect to use. const unsigned int AudioFrameDuration = 10; -/// The number of audio samples in an audio frame. -/// -const unsigned int AudioFrameSamples = SamplesPerMillisecond - * AudioFrameDuration; - -/// The maximum frame duration in milliseconds. This will be used to set -/// buffer sizes. It must be larger than the frame duration used by your -/// modem/framer/codec combination, or they will stall. -const unsigned int MaximumFrameDuration = 100; +/// The number of audio samples in an audio frame. Audio frames must be a +/// power of two (this is a common hardware requirement) and must be shorter +/// than any codec/modem frame in the program. +const unsigned int AudioFrameSamples = 512; /// The number of audio samples in the maximum-duration frame. +/// This must be a power of two (this is a common hardware requirement) and +/// must be at least twice the value of AudioFrameSamples. /// -const unsigned int MaximumFrameSamples = SamplesPerMillisecond - * MaximumFrameDuration; +const unsigned int MaximumFrameSamples = 32768; /// Allocate memory and copy a string into it, so that it is permanently /// stored. diff --git a/freedv-server/source/platform/linux/alsa.cpp b/freedv-server/source/platform/linux/alsa.cpp index 2cd1a75f..7b69fa66 100644 --- a/freedv-server/source/platform/linux/alsa.cpp +++ b/freedv-server/source/platform/linux/alsa.cpp @@ -228,6 +228,7 @@ namespace FreeDV { int error; snd_pcm_t * handle = 0; snd_pcm_hw_params_t * hw_params = 0; + snd_pcm_sw_params_t * sw_params = 0; error = open_by_longname(&handle, name, stream, mode); if ( error < 0 ) { @@ -241,53 +242,73 @@ namespace FreeDV { return 0; } - if ( (error = snd_pcm_hw_params_malloc(&hw_params)) < 0 ) { - snd_pcm_close(handle); - do_throw(error, name, stream, "ALSA hardare parameter allocation"); - } - - if ( (error = snd_pcm_hw_params_any(handle, hw_params )) < 0 ) { - snd_pcm_close(handle); - do_throw(error, name, stream, "Get configuration space for device"); - } - - if ( (error = snd_pcm_hw_params_set_format(handle, hw_params, format )) < 0 ) { - snd_pcm_close(handle); - do_throw(error, name, stream, "Set format"); - } - - if ( (error = snd_pcm_hw_params_set_access(handle, hw_params, access )) < 0 ) { - snd_pcm_close(handle); - do_throw(error, name, stream, "Set access"); - } + try { + if ( (error = snd_pcm_hw_params_malloc(&hw_params)) < 0 ) + do_throw(error, name, stream, "ALSA hardare parameter allocation"); + + if ( (error = snd_pcm_hw_params_any(handle, hw_params )) < 0 ) + do_throw(error, name, stream, "Get configuration space for device"); + + if ( (error = snd_pcm_hw_params_set_format(handle, hw_params, format )) < 0 ) + do_throw(error, name, stream, "Set format"); + + if ( (error = snd_pcm_hw_params_set_access(handle, hw_params, access )) < 0 ) + do_throw(error, name, stream, "Set access"); + + if ( (error = snd_pcm_hw_params_set_channels(handle, hw_params, channels )) < 0 ) + do_throw(error, name, stream, "Set channels"); + + if ( (error = snd_pcm_hw_params_set_rate(handle, hw_params, rate, 0 )) < 0 ) + do_throw(error, name, stream, "Set rate"); + + if ( (error = snd_pcm_hw_params_set_period_size_near(handle, hw_params, &period_size, 0)) < 0 ) + do_throw(error, name, stream, "Set I/O period size"); + + if ( (error = snd_pcm_hw_params_set_buffer_size_near(handle, hw_params, &buffer_size)) < 0 ) + do_throw(error, name, stream, "Set I/O buffer size"); + + if ( (error = snd_pcm_hw_params(handle, hw_params)) < 0 ) + do_throw(error, name, stream, "ALSA hardware parameter select"); + + snd_pcm_hw_params_free(hw_params); + + if ((error = snd_pcm_sw_params_malloc(&sw_params)) < 0) + do_throw(error, name, stream, "ALSA software parameter allocate"); + + if ((error = snd_pcm_sw_params_current(handle, sw_params)) < 0) + do_throw(error, name, stream, "ALSA get software parameters"); + + if ((error = snd_pcm_sw_params_set_avail_min(handle, sw_params, + period_size)) < 0) + do_throw(error, name, stream, "ALSA software set minimum available."); + + if (( error = snd_pcm_sw_params_set_period_event(handle, sw_params, 1)) + < 0 ) + do_throw(error, name, stream, "ALSA software set period event."); - if ( (error = snd_pcm_hw_params_set_channels(handle, hw_params, channels )) < 0 ) { - snd_pcm_close(handle); - do_throw(error, name, stream, "Set channels"); - } + if ((error = snd_pcm_sw_params_set_start_threshold(handle, sw_params, period_size)) + < 0) + do_throw(error, name, stream, + "ALSA set software start threshold"); - if ( (error = snd_pcm_hw_params_set_rate(handle, hw_params, rate, 0 )) < 0 ) { - snd_pcm_close(handle); - do_throw(error, name, stream, "Set rate"); - } + if (( error = snd_pcm_sw_params_set_stop_threshold(handle, sw_params, + buffer_size + 1)) < 0 ) + do_throw(error, name, stream, + "ALSA set software stop threshold"); - if ( (error = snd_pcm_hw_params_set_period_size_near(handle, hw_params, &period_size, 0)) < 0 ) { - snd_pcm_close(handle); - do_throw(error, name, stream, "Set I/O period size"); - } + if ((error = snd_pcm_sw_params(handle, sw_params)) < 0) + do_throw(error, name, stream, "ALSA set software parameters"); + + snd_pcm_sw_params_free(sw_params); - if ( (error = snd_pcm_hw_params_set_buffer_size_near(handle, hw_params, &buffer_size)) < 0 ) { - snd_pcm_close(handle); - do_throw(error, name, stream, "Set I/O buffer size"); + if ((error = snd_pcm_prepare(handle)) < 0) + do_throw(error, name, stream, "ALSA prepare audio interface for use"); } - - if ( (error = snd_pcm_hw_params(handle, hw_params)) < 0 ) { + catch (...) + { snd_pcm_close(handle); - do_throw(error, name, stream, "ALSA hardware parameter select"); + throw; // Re-throws the current exception without modification. } - - snd_pcm_hw_params_free(hw_params); - return handle; } } diff --git a/freedv-server/source/platform/linux/audio_in_alsa.cpp b/freedv-server/source/platform/linux/audio_in_alsa.cpp index 2a805302..6d95544a 100644 --- a/freedv-server/source/platform/linux/audio_in_alsa.cpp +++ b/freedv-server/source/platform/linux/audio_in_alsa.cpp @@ -82,7 +82,7 @@ namespace FreeDV { SND_PCM_ACCESS_RW_INTERLEAVED, 1, SampleRate, - AudioFrameSamples, + AudioFrameSamples, AudioFrameSamples * 2); if ( handle == 0 ) @@ -188,6 +188,7 @@ namespace FreeDV { if ( error == -EPIPE ) { snd_pcm_recover(handle, error, 1); + snd_pcm_start(handle); std::cerr << "ALSA input \"" << parameters << "\": ready underrun." << std::endl; return 0; } diff --git a/freedv-server/source/platform/linux/audio_out_alsa.cpp b/freedv-server/source/platform/linux/audio_out_alsa.cpp index bbeb2c49..6f370c0f 100644 --- a/freedv-server/source/platform/linux/audio_out_alsa.cpp +++ b/freedv-server/source/platform/linux/audio_out_alsa.cpp @@ -122,7 +122,7 @@ namespace FreeDV { // a shared clock, and the more expensive equipment that supports it, // to avoid this problem. // - int16_t buf[AudioFrameSamples / 100]; + int16_t buf[AudioFrameSamples]; memset(buf, 0, sizeof(buf)); snd_pcm_writei(handle, buf, sizeof(buf) / sizeof(*buf)); } @@ -177,7 +177,7 @@ namespace FreeDV { return AudioFrameSamples; error = snd_pcm_avail_delay(handle, &available, &delay); - if ( delay > (AudioFrameSamples * 4) ) { + if ( delay > (AudioFrameSamples * 8) ) { const double seconds = (double)delay / (double)SampleRate; std::cerr << "ALSA output \"" << parameters