Code transmit drain.
authorbruceperens <bruceperens@01035d8c-6547-0410-b346-abe4f91aad63>
Fri, 25 Apr 2014 02:36:56 +0000 (02:36 +0000)
committerbruceperens <bruceperens@01035d8c-6547-0410-b346-abe4f91aad63>
Fri, 25 Apr 2014 02:36:56 +0000 (02:36 +0000)
git-svn-id: https://svn.code.sf.net/p/freetel/code@1560 01035d8c-6547-0410-b346-abe4f91aad63

freedv-server/source/audio_sink.cpp
freedv-server/source/drivers.h
freedv-server/source/platform/linux/audio_out_alsa.cpp
freedv-server/source/run.cpp

index 89c4a953e6693fc295008fd649818f5ebe5ce621..52cbe1c8f0636a03e7f8e95ed2387aba701259ad 100644 (file)
@@ -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)
   {
index 954587cc65d60a15ce051fd32d5bd3fc966e4dbd..020279b9e57122147eb7c9604d117a72455e17c4 100644 (file)
@@ -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
index 6f370c0fc6bf7b0ca3de8aed53b7878418ae2075..b8e50b142a88b2e179acab8ac95eec53e9dd61e5 100644 (file)
@@ -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.
index a2d0e754d901a64c57c4b9a5ff46d0e40a35cf0f..b675f9e2add11274dd4baf8de5be53d93e60341b 100644 (file)
@@ -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);
   }