From: bruceperens Date: Fri, 25 Apr 2014 19:42:42 +0000 (+0000) Subject: When draining the digital transmission before key-up, zero-fill the last frame X-Git-Url: http://git.whiteaudio.com/gitweb/?a=commitdiff_plain;h=2dc14b2b0e5b18ec8df52b7257f464b4f61bfc51;p=freetel-svn-tracking.git When draining the digital transmission before key-up, zero-fill the last frame so that a full codec and modem frame are encoded, even though there are not enough audio samples to fill them. git-svn-id: https://svn.code.sf.net/p/freetel/code@1563 01035d8c-6547-0410-b346-abe4f91aad63 --- diff --git a/freedv-server/source/codec_noop.cpp b/freedv-server/source/codec_noop.cpp index f898b82a..cdb3a81f 100644 --- a/freedv-server/source/codec_noop.cpp +++ b/freedv-server/source/codec_noop.cpp @@ -51,10 +51,10 @@ namespace FreeDV { std::size_t data_length, std::size_t *sample_length); - /// Return the minimum duration of a frame in milliseconds. - /// \return The minimum duration of a frame in milliseconds. - virtual int - min_frame_duration() const; + /// \return The number of samples required to encode a frame in the + /// currently-selected mode. + virtual std::size_t + samples_per_frame() const; }; CodecNoOp::CodecNoOp(const char * _parameters) @@ -96,14 +96,14 @@ namespace FreeDV { return 0; } memcpy(o, i, length * 2); - *sample_length = length / 2; - return length; + *sample_length = length; + return length * 2; } - int - CodecNoOp::min_frame_duration() const + std::size_t + CodecNoOp::samples_per_frame() const { - return FrameDuration; + return FrameSamples; } Codec * diff --git a/freedv-server/source/drivers.h b/freedv-server/source/drivers.h index 020279b9..4dd5222d 100644 --- a/freedv-server/source/drivers.h +++ b/freedv-server/source/drivers.h @@ -425,10 +425,10 @@ public: std::size_t data_length, std::size_t * sample_length) = 0; - /// Return the minimum duration of a frame in milliseconds. - /// \return The minimum duration of a frame in milliseconds. - virtual int - min_frame_duration() const = 0; + /// \return The number of samples required to encode a frame in the + /// currently-selected mode. + virtual std::size_t + samples_per_frame() const = 0; }; /// Virtual base class for protocol framers. @@ -556,10 +556,10 @@ public: std::size_t * data_length, std::size_t sample_length) = 0; - /// Return the minimum duration of a frame in milliseconds. - /// \return The minimum duration of a frame in milliseconds. - virtual int - min_frame_duration() const = 0; + /// \return The number of bytes required to encode a frame in the current + /// mode. + virtual std::size_t + bytes_per_frame() const = 0; }; /// Push-to-talk input driver. diff --git a/freedv-server/source/modem_noop.cpp b/freedv-server/source/modem_noop.cpp index f1580a6e..79af2139 100644 --- a/freedv-server/source/modem_noop.cpp +++ b/freedv-server/source/modem_noop.cpp @@ -54,11 +54,6 @@ namespace FreeDV { std::int16_t * o, \ std::size_t *data_length, std::size_t sample_length); - - /// Return the minimum duration of a frame in milliseconds. - /// \return The minimum duration of a frame in milliseconds. - virtual int - min_frame_duration() const; }; ModemNoOp::ModemNoOp(const char * _parameters) @@ -104,12 +99,6 @@ namespace FreeDV { return length; } - int - ModemNoOp::min_frame_duration() const - { - return 1; - } - Modem * Driver::ModemNoOp(const char * parameter) { diff --git a/freedv-server/source/run.cpp b/freedv-server/source/run.cpp index b675f9e2..3888ce70 100644 --- a/freedv-server/source/run.cpp +++ b/freedv-server/source/run.cpp @@ -128,19 +128,26 @@ namespace FreeDV { bool Run::drain_digital(bool final) { - 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 draining the last frame, make sure we have enough samples to encode + // the last codec frame. Fill with zero if necessary. + // FIX: Replace this with a state before un-key which fades out the + // microphone, ending at a codec frame boundary, thus avoiding the click + // we make here. + if ( final ) { + const std::size_t samples_per_frame = i->codec->samples_per_frame(); + if ( samples_to_encode < samples_per_frame && samples_to_encode > 0 ) { + const std::size_t fill = samples_per_frame - samples_to_encode; + const std::size_t bytes = fill * 2; + memset(in_fifo.put(bytes), 0, bytes); + in_fifo.put_done(bytes); + samples_to_encode += fill; + } + } + if ( samples_to_encode > 0 && bytes_to_encode > 0 ) { const std::size_t bytes_encoded = i->codec->encode16( (std::int16_t *)in_fifo.get( @@ -154,16 +161,27 @@ namespace FreeDV { 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 the codec is drained and we are draining the last modem frame, + // make sure we have enough bytes to encode the last modem frame. + // Fill with zero if necessary. + if ( final && in_fifo.get_available() == 0 ) { + const std::size_t bytes_per_frame = i->modem->bytes_per_frame(); + if ( bytes_to_modulate < bytes_per_frame && bytes_to_modulate > 0 ) { + const std::size_t fill = bytes_per_frame - bytes_to_modulate; + memset(codec_fifo.put(fill), 0, fill); + codec_fifo.put_done(fill); + bytes_to_modulate += fill; + // Leave this debugging message in place until I have a codec with + // a frame size less than a modem frame, and can test this block. + std::cerr << "Fill modem." << std::endl; + } + } + if ( bytes_to_modulate > 0 && samples_to_modulate > 0 ) { const std::size_t samples_modulated = i->modem->modulate16( codec_fifo.get(bytes_to_modulate), @@ -171,18 +189,12 @@ namespace FreeDV { &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( @@ -199,6 +211,16 @@ namespace FreeDV { else if ( result < 0 ) std::cerr << "Transmitter I/O error: " << strerror(errno) << std::endl; } + + if ( final ) { + if ( in_fifo.get_available() == 0 + && codec_fifo.get_available() == 0 + && out_fifo.get_available() == 0 ) { + i->transmitter->drain(); + return true; + } + } + return false; }