/// drivers.
const unsigned int SampleRate = 48000;
-// The minimum frame duration in milliseconds. The audio interfaces will
-// use one half of this as a period size. It should be the smallest frame
-// we expect a modem/protocol/codec combination to use. If it's too large,
-// latency will be overlong.
-const unsigned int MinimumFrameDuration = 10;
-
-// The maximum frame duration in milliseconds. The audio interfaces will
-// use 2 times this as a buffer size. It must be an integer multiple of
-// MinimumFrameDuration, or ALSA will complain. It should be the largest
-// frame we expect a modem/protocol/codec combination to use.
-// If a modem/framer/codec combination specify a frame duration larger than
-// this, it's an error.
-// If it's too large, ALSA bugs surface (Or is it my lack of
-// understanding?) and cause long delays.
-const unsigned int MaximumFrameDuration = 100;
+// The audio frame duration in milliseconds. The audio interfaces will
+// use this as a period size. It should be 1/2 of the smallest codec frame
+// size we expect to use.
+const unsigned int AudioFrameDuration = 10;
/// Allocate memory and copy a string into it, so that it is permanently
/// stored.
class AudioInALSA : public AudioInput {
private:
static const int overlong_delay = ((double)SampleRate / 1000.0)
- * MaximumFrameDuration;
+ * AudioFrameDuration * 2;
char * const parameters;
snd_pcm_t * handle;
SND_PCM_ACCESS_RW_INTERLEAVED,
1,
SampleRate,
- (int)ceil(((double)SampleRate / 1000.0) * MinimumFrameDuration / 2),
- (int)ceil(((double)SampleRate / 1000.0) * MaximumFrameDuration));
+ (int)ceil((double)SampleRate / 1000.0) * AudioFrameDuration,
+ (int)ceil((double)SampleRate / 1000.0) * AudioFrameDuration);
snd_pcm_start(handle);
}
std::size_t
AudioInALSA::ready()
{
- static const int min_frame_size = (int)ceil(
- ((double)SampleRate * 1000.0) * MinimumFrameDuration);
-
snd_pcm_sframes_t available = 0;
snd_pcm_sframes_t delay = 0;
int error;
if ( !started ) {
snd_pcm_start(handle);
- return min_frame_size;
+ return ((double)SampleRate / 1000.0) * AudioFrameDuration;
}
error = snd_pcm_avail_delay(handle, &available, &delay);
std::cerr << "ALSA input \"" << parameters << "\": overlong delay, dropped "
<< seconds << " seconds of input." << std::endl;
- return min_frame_size / 2;
+ return 0;
}
if ( error == -EPIPE ) {
private:
char * const parameters;
snd_pcm_t * handle;
- std::size_t min_frame_size;
bool started;
void
AudioOutALSA::AudioOutALSA(const char * p)
: AudioOutput("alsa", p), parameters(strdup(p)),
- min_frame_size(
- (int)ceil(((double)SampleRate / 1000.0) * MinimumFrameDuration)),
started(false)
{
handle = ALSASetup(
SND_PCM_ACCESS_RW_INTERLEAVED,
1,
SampleRate,
- min_frame_size / 2,
- min_frame_size * 8);
+ (int)ceil((double)SampleRate / 1000.0) * AudioFrameDuration,
+ (int)ceil((double)SampleRate / 1000.0) * AudioFrameDuration);
snd_pcm_pause(handle, 1);
}
int error;
if ( !started )
- return min_frame_size;
+ return ((double)SampleRate / 1000.0) * AudioFrameDuration;
error = snd_pcm_avail_delay(handle, &available, &delay);
- if ( delay > (((double)SampleRate / 1000.0) * MaximumFrameDuration) ) {
+ if ( delay > (((double)SampleRate / 1000.0) * AudioFrameDuration * 2) ) {
const double seconds = (double)delay / (double)SampleRate;
std::cerr << "ALSA output \"" << parameters
snd_pcm_recover(handle, error, 1);
snd_pcm_pause(handle, 1);
started = false;
- return min_frame_size;
+ return 0;
if ( error < 0 )
return 0;
FIFO out_fifo;
bool ptt_digital;
bool ptt_ssb;
- std::size_t min_frame_duration;
- struct timespec next_frame_time;
void key_down();
void key_up();
if ( bytes_to_decode > 0 )
codec_fifo.get_done(bytes_to_decode);
- if ( result > 0 ) {
- // std::cerr << '.';
+ if ( result > 0 )
out_fifo.put_done(result * 2);
-
- // Calculate a time one millisecond short of when the next frame
- // should start. We can sleep until then.
- const long duration = ((min_frame_duration - 1) * 1000000);
-
- next_frame_time.tv_sec = start_time.tv_sec;
- next_frame_time.tv_nsec = start_time.tv_nsec + duration;
- next_frame_time.tv_sec += next_frame_time.tv_nsec / 1000000000;
- next_frame_time.tv_nsec %= 1000000000;
- }
- else {
-
- // std::cerr << '+';
-
- // Go to sleep for a millisecond and try again. We could poll the
- // I/O interfaces for ready instead.
- next_frame_time = start_time;
- next_frame_time.tv_nsec += 1000000;
- next_frame_time.tv_sec += next_frame_time.tv_nsec / 1000000000;
- next_frame_time.tv_nsec %= 1000000000;
- }
}
}
void
Run::run()
{
- min_frame_duration = MinimumFrameDuration;
- min_frame_duration = max(min_frame_duration, i->modem->min_frame_duration());
- min_frame_duration = max(min_frame_duration, i->codec->min_frame_duration());
- min_frame_duration = max(min_frame_duration, i->framer->min_frame_duration());
-
- std::cerr << "The minimum frame duration is "
- << min_frame_duration << " milliseconds." << std::endl;
- if ( min_frame_duration > MaximumFrameDuration ) {
- std::ostringstream str;
-
- str << "At " << __FILE__ << ":" << __LINE__ << std::endl;
- str << "min_frame_duration of " << min_frame_duration;
- str << " is larger than MaximumFrameDuration of ";
- str << MaximumFrameDuration << '.' << std::endl;
- str << "A Modem, Framer, or Codec returned min_frame_duration() that";
- str << " was too large," << std::endl;
- str << "or MaximumFrameDuration must be increased.";
- throw std::runtime_error(str.str().c_str());
- }
- assert(min_frame_duration < 1000000);
-
while ( true ) {
receive();
- clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next_frame_time, 0);
}
}