From: bruceperens Date: Fri, 25 Apr 2014 02:36:56 +0000 (+0000) Subject: Code transmit drain. X-Git-Url: http://git.whiteaudio.com/gitweb/?a=commitdiff_plain;h=e065ff17cd514fe50723cde74e5deeaec6677f7d;p=freetel-svn-tracking.git Code transmit drain. git-svn-id: https://svn.code.sf.net/p/freetel/code@1560 01035d8c-6547-0410-b346-abe4f91aad63 --- diff --git a/freedv-server/source/audio_sink.cpp b/freedv-server/source/audio_sink.cpp index 89c4a953..52cbe1c8 100644 --- a/freedv-server/source/audio_sink.cpp +++ b/freedv-server/source/audio_sink.cpp @@ -18,6 +18,11 @@ namespace FreeDV { AudioSink(const char * parameters); ~AudioSink(); + /// Wait for all output to be sent to the audio device and then + // return. + virtual void + drain(); + /// Return file descriptors for poll() /// \param array The address of an array that will be written /// with a sequence of file descriptors. @@ -46,6 +51,11 @@ namespace FreeDV { { } + void + AudioSink::drain() + { + } + std::size_t AudioSink::write16(const std::int16_t *, std::size_t length) { diff --git a/freedv-server/source/drivers.h b/freedv-server/source/drivers.h index 954587cc..020279b9 100644 --- a/freedv-server/source/drivers.h +++ b/freedv-server/source/drivers.h @@ -352,6 +352,10 @@ public: /// virtual ~AudioOutput() = 0; + /// Wait for all output to be emitted by the audio device and then + // return. + virtual void drain() = 0; + /// Write audio from an array of the signed 16-bit integer type. /// Depending on the underlying device and its non-blocking status, /// this may write fewer bytes than requested. It's permissible for diff --git a/freedv-server/source/platform/linux/audio_out_alsa.cpp b/freedv-server/source/platform/linux/audio_out_alsa.cpp index 6f370c0f..b8e50b14 100644 --- a/freedv-server/source/platform/linux/audio_out_alsa.cpp +++ b/freedv-server/source/platform/linux/audio_out_alsa.cpp @@ -40,6 +40,11 @@ namespace FreeDV { AudioOutALSA(const char * parameters); ~AudioOutALSA(); + /// Wait for all output to be sent to the audio device and then + // return. + virtual void + drain(); + /// Return file descriptors for poll() /// \param array The address of an array that will be written /// with a sequence of file descriptors. @@ -106,12 +111,18 @@ namespace FreeDV { throw std::runtime_error(str.str().c_str()); } + void + AudioOutALSA::drain() + { + snd_pcm_wait(handle, 1000); + } + // Write audio into the "short" type. std::size_t AudioOutALSA::write16(const std::int16_t * array, std::size_t length) { if ( !started ) { - // Preload the audio output queue with a fraction of a frame of silence. + // Preload the audio output queue with some silence. // This makes underruns less likely. // This delays the output from where we would otherwise have started it. // Otherwise we tend to underrun repeatedly at startup time. diff --git a/freedv-server/source/run.cpp b/freedv-server/source/run.cpp index a2d0e754..b675f9e2 100644 --- a/freedv-server/source/run.cpp +++ b/freedv-server/source/run.cpp @@ -46,7 +46,7 @@ namespace FreeDV { NORETURN void do_throw(int error, const char * message); void reset(); - bool drain_digital(); + bool drain_digital(bool final); bool drain_ssb(bool final); void receive(); void start_receive(); @@ -126,16 +126,87 @@ namespace FreeDV { } bool - Run::drain_digital() + Run::drain_digital(bool final) { - return true; + if ( final ) { + if ( in_fifo.get_available() == 0 + && codec_fifo.get_available() == 0 + && out_fifo.get_available() == 0 ) { + i->transmitter->drain(); + std::cerr << "Drain digital returning TRUE." << std::endl; + return true; + } + } + + std::size_t samples_to_encode = in_fifo.get_available() / 2; + const std::size_t bytes_to_encode = codec_fifo.put_space(); + + if ( samples_to_encode > 0 && bytes_to_encode > 0 ) { + const std::size_t bytes_encoded = i->codec->encode16( + (std::int16_t *)in_fifo.get( + samples_to_encode * 2), + codec_fifo.put(bytes_to_encode), + bytes_to_encode, + &samples_to_encode); + + if ( samples_to_encode > 0 ) { + in_fifo.get_done(samples_to_encode * 2); + if ( bytes_encoded > 0 ) + codec_fifo.put_done(bytes_encoded); + } + else if ( final && samples_to_encode == 0 ) { + // The remainder of the samples in the codec queue are insufficient to + // fill a codec frame. + return true; + } + } + + std::size_t bytes_to_modulate = codec_fifo.get_available(); + const std::size_t samples_to_modulate = out_fifo.put_space() / 2; + + if ( bytes_to_modulate > 0 && samples_to_modulate > 0 ) { + const std::size_t samples_modulated = i->modem->modulate16( + codec_fifo.get(bytes_to_modulate), + (std::int16_t *)out_fifo.put(samples_to_modulate * 2), + &bytes_to_modulate, + samples_to_modulate); + + + if ( bytes_to_modulate > 0 ) { + codec_fifo.get_done(bytes_to_modulate); + + if ( samples_modulated > 0 ) + out_fifo.put_done(samples_modulated * 2); + } + else if ( final && bytes_to_modulate == 0 ) { + // The remainder of the samples in the modem queue are insufficient to + // fill a modem frame. + return true; + } + } + // Drain any data that the transmitter can take. + const std::size_t out_samples = min( + i->transmitter->ready(), + (out_fifo.get_available() / 2)); + + if ( out_samples > 0 ) { + const int result = i->transmitter->write16( + (std::int16_t *)out_fifo.get(out_samples * 2), + out_samples); + + if ( result > 0 ) + out_fifo.get_done(result * 2); + else if ( result < 0 ) + std::cerr << "Transmitter I/O error: " << strerror(errno) << std::endl; + } + return false; } bool Run::drain_ssb(bool final) { if ( final && in_fifo.get_available() == 0 ) { - // FIX: Must wait for the output to drain. + i->transmitter->drain(); return true; } @@ -309,7 +380,7 @@ namespace FreeDV { switch ( state ) { case DrainDigital: - if ( drain_digital() ) { + if ( drain_digital(true) ) { poll_fd_count = poll_fd_base; state = UnKey; } @@ -461,57 +532,9 @@ namespace FreeDV { else if ( result < 0 ) std::cerr << "Microphone I/O error: " << strerror(errno) << std::endl; } - - std::size_t samples_to_encode = in_fifo.get_available() / 2; - const std::size_t bytes_to_encode = codec_fifo.put_space(); - - if ( samples_to_encode > 0 && bytes_to_encode > 0 ) { - const std::size_t bytes_encoded = i->codec->encode16( - (std::int16_t *)in_fifo.get( - samples_to_encode * 2), - codec_fifo.put(bytes_to_encode), - bytes_to_encode, - &samples_to_encode); - - if ( samples_to_encode > 0 ) - in_fifo.get_done(samples_to_encode * 2); - - if ( bytes_encoded > 0 ) - codec_fifo.put_done(bytes_encoded); - } - - std::size_t bytes_to_modulate = codec_fifo.get_available(); - const std::size_t samples_to_modulate = out_fifo.put_space() / 2; - - if ( bytes_to_modulate > 0 && samples_to_modulate > 0 ) { - const std::size_t samples_modulated = i->modem->modulate16( - codec_fifo.get(bytes_to_modulate), - (std::int16_t *)out_fifo.put(samples_to_modulate * 2), - &bytes_to_modulate, - samples_to_modulate); - - - if ( bytes_to_modulate > 0 ) - codec_fifo.get_done(bytes_to_modulate); - - if ( samples_modulated > 0 ) - out_fifo.put_done(samples_modulated * 2); - } - // Drain any data that the transmitter can take. - const std::size_t out_samples = min( - i->transmitter->ready(), - (out_fifo.get_available() / 2)); - - if ( out_samples > 0 ) { - const int result = i->transmitter->write16( - (std::int16_t *)out_fifo.get(out_samples * 2), - out_samples); - if ( result > 0 ) - out_fifo.get_done(result * 2); - else if ( result < 0 ) - std::cerr << "Transmitter I/O error: " << strerror(errno) << std::endl; - } + // Encode, modulate, and output any microphone audio that's been captured. + drain_digital(false); } void @@ -533,7 +556,7 @@ namespace FreeDV { std::cerr << "Microphone I/O error: " << strerror(errno) << std::endl; } - // Drain any data that the transmitter can take. + // Output any microphone audio that's been captured. drain_ssb(false); }