From 305d211dfbb84547af74093191470e8d46bdf3b0 Mon Sep 17 00:00:00 2001 From: bruceperens Date: Tue, 11 Mar 2014 19:37:34 +0000 Subject: [PATCH] General clean-up. git-svn-id: https://svn.code.sf.net/p/freetel/code@1426 01035d8c-6547-0410-b346-abe4f91aad63 --- freedv-server/source/big_main.cpp | 27 +++--- freedv-server/source/drivers.h | 74 ++++++++-------- freedv-server/source/fifo.cpp | 9 +- freedv-server/source/interfaces.cpp | 29 ++++--- freedv-server/source/modem_noop.cpp | 1 + .../source/platform/linux/audio_out_alsa.cpp | 25 +++++- freedv-server/source/run.cpp | 84 +++++++++---------- freedv-server/source/test/fifo.cpp | 80 +++++++++--------- 8 files changed, 171 insertions(+), 158 deletions(-) diff --git a/freedv-server/source/big_main.cpp b/freedv-server/source/big_main.cpp index 86657dd1..7ba58c57 100644 --- a/freedv-server/source/big_main.cpp +++ b/freedv-server/source/big_main.cpp @@ -100,6 +100,19 @@ main(int argc, char * * argv) int command; while ((command = getopt_long(argc, argv, "c:Cdf:hi:k:l:m:M:p:P:r:t:x:", options, NULL)) != -1 ) { switch (command) { + case 0: + break; + case 'd': + drivers(); + exit(0); + default: + case 'h': + help(argv[0]); + exit(1); + case 'C': + // FIX: Operator overload doesn't work here. + i.print(cout, argv[0]) << endl; + exit(0); case 'c': case 'f': case 'i': @@ -123,20 +136,14 @@ main(int argc, char * * argv) Base * set = (Base *)1; + switch (command) { case 'c': set = i.codec = m->codec(driver, parameter); break; - case 'd': - drivers(); - exit(0); case 'f': set = i.framer = m->framer(driver, parameter); break; - default: - case 'h': - help(argv[0]); - exit(1); case 'i': set = i.user_interface = m->user_interface(driver, parameter, &i); break; @@ -167,12 +174,6 @@ main(int argc, char * * argv) case 'x': set = i.text_input = m->text_input(driver, parameter); break; - case 'C': - // FIX: Operator overload doesn't work here. - i.print(cout) << endl; - exit(0); - case 0: - break; } if ( set == 0 ) exit(1); diff --git a/freedv-server/source/drivers.h b/freedv-server/source/drivers.h index 4f1ca9ce..fb7f954e 100644 --- a/freedv-server/source/drivers.h +++ b/freedv-server/source/drivers.h @@ -32,7 +32,7 @@ namespace FreeDV { uint8_t * in; const uint8_t * out; - void out_overrun() const; + void get_overrun() const; uint8_t * reorder(std::size_t length); public: @@ -42,9 +42,36 @@ namespace FreeDV { ~FIFO(); + /// Returns the amount of data available to read. + /// \return The amount of data, in bytes, available to read. + inline std::size_t get_available() const { + return in - out; + } + + /// Return the address of output data of the requested length. + /// \param length The amount of data requested. This must be smaller + /// than or equal to the amount returned by get_available(). + /// \return The address of the data to be read. + inline const uint8_t * get(std::size_t length) { + if ( length > (std::size_t)(in - out) ) + get_overrun(); + return out; + } + + /// Finish the I/O after get(). + /// \param length The amount of data, in bytes, actually read. + /// This must be smaller than or equal to the amount passed to + /// get(). + inline void get_done(std::size_t length) { + out += length; + assert(out >= buffer && out <= buffer_end); + if ( out == in ) + out = in = buffer; + } + /// Returns the amount of space available for incoming data. /// \return The amount of space, in bytes, available for incoming data. - inline std::size_t incoming_available() const { + inline std::size_t put_space() const { return (buffer_end) - in + (out - buffer); } @@ -52,12 +79,12 @@ namespace FreeDV { /// Throws an error if we run the buffer out of space. Well-behaved code /// won't allocate a size that can't be drained before it is further /// written. - /// You must call incoming_done(length) when the I/O is completed. - /// The length passed to incoming_done() must be smaller than or equal - /// to the length passed to incoming_buffer(). + /// You must call put_done(length) when the I/O is completed. + /// The length passed to put_done() must be smaller than or equal + /// to the length passed to put(). /// \param io_length The size of buffer in chars requested. /// \return The address of the buffer for incoming data. - inline uint8_t * incoming_buffer(std::size_t io_length) { + inline uint8_t * put(std::size_t io_length) { const uint8_t * io_end = in + io_length; if ( io_end > buffer_end ) @@ -66,39 +93,14 @@ namespace FreeDV { return in; } - /// Complete the I/O after incoming_buffer(). + /// Complete the I/O after put(). /// \param length The amount of data actually written. This must be - /// smaller than or equal to the length passed to incoming_buffer(). - inline void incoming_done(std::size_t length) { + /// smaller than or equal to the length passed to put(). + inline void put_done(std::size_t length) { in += length; assert(in >= buffer && in <= buffer_end); } - /// Returns the amount of data available to read. - /// \return The amount of data, in bytes, available to read. - inline std::size_t outgoing_available() const { - return in - out; - } - - /// Return the address of output data of the requested length. - /// \param length The amount of data requested. This must be smaller - /// than or equal to the amount returned by outgoing_available(). - /// \return The address of the data to be read. - inline const uint8_t * outgoing_buffer(std::size_t length) { - if ( length > (std::size_t)(in - out) ) - out_overrun(); - return out; - } - - /// Finish the I/O after outgoing_buffer(). - /// \param length The amount of data, in bytes, actually read. - /// This must be smaller than or equal to the amount passed to - /// outgoing_buffer(). - inline void outgoing_done(std::size_t length) { - out += length; - assert(out >= buffer && out <= buffer_end); - } - /// Discard any buffered data. void reset(); }; @@ -689,7 +691,7 @@ namespace FreeDV { /// \return A reference to the provided stream, meant for the /// usual successive call paradigm of ostream operator << . virtual std::ostream & - print(std::ostream & stream) const; + print(std::ostream & stream, const char * program_name) const; }; /// Write the driver information from the Interfaces object onto a stream, @@ -702,7 +704,7 @@ namespace FreeDV { /// usual successive call paradigm of ostream operator << . inline std::ostream & operator << (std::ostream & stream, const Interfaces & interfaces) { - return interfaces.print(stream); + return interfaces.print(stream, 0); } // Most of the functions in the Driver and Enumerator namespaces are diff --git a/freedv-server/source/fifo.cpp b/freedv-server/source/fifo.cpp index b498bfa9..1e539784 100644 --- a/freedv-server/source/fifo.cpp +++ b/freedv-server/source/fifo.cpp @@ -15,7 +15,7 @@ namespace FreeDV { } void - FIFO::out_overrun() const + FIFO::get_overrun() const { throw std::runtime_error("FIFO outgoing data overrun."); } @@ -29,13 +29,6 @@ namespace FreeDV { // memmove() is specified to handle overlap properly. memmove(buffer, out, bytes); -#ifdef DEBUG - std::cerr << "FIFO reorder with copy. Size = " << size - << ", buffer = " << (void *)buffer << ", buffer_end = " - << (void *)buffer_end << ", in = " << (void *)in - << ", out = " << (void *)out - << std::endl; -#endif } out = buffer; in = buffer + bytes; diff --git a/freedv-server/source/interfaces.cpp b/freedv-server/source/interfaces.cpp index 0c47e1e9..a62b74e7 100644 --- a/freedv-server/source/interfaces.cpp +++ b/freedv-server/source/interfaces.cpp @@ -41,26 +41,29 @@ namespace FreeDV { transmitter = Driver::AudioSink(empty); if ( !receiver ) - receiver = Driver::Tone(empty); + receiver = Driver::Tone("1000,1.0"); if ( !user_interface ) user_interface = Driver::BlankPanel(empty, this); } std::ostream & - Interfaces::print(std::ostream & stream) const + Interfaces::print(std::ostream & stream, const char * program_name) const { - stream << "--codec=" << *codec << std::endl; - stream << "--gui=" << *user_interface << std::endl; - stream << "--keying=" << *keying_output << std::endl; - stream << "--loudspeaker=" << *loudspeaker << std::endl; - stream << "--microphone=" << *microphone << std::endl; - stream << "--modem=" << *modem << std::endl; - stream << "--ptt-digital=" << *ptt_input_digital << std::endl; - stream << "--ptt-ssb=" << *ptt_input_ssb << std::endl; - stream << "--receiver=" << *receiver << std::endl; - stream << "--text=" << *text_input << std::endl; - stream << "--transmitter=" << *transmitter << std::endl; + if ( program_name ) { + stream << program_name << " \\" << std::endl; + } + stream << "--codec=\"" << *codec << "\" \\" << std::endl; + stream << "--gui=\"" << *user_interface << "\" \\" << std::endl; + stream << "--keying=\"" << *keying_output << "\" \\" << std::endl; + stream << "--loudspeaker=\"" << *loudspeaker << "\" \\" << std::endl; + stream << "--microphone=\"" << *microphone << "\" \\" << std::endl; + stream << "--modem=\"" << *modem << "\" \\" << std::endl; + stream << "--ptt-digital=\"" << *ptt_input_digital << "\" \\" << std::endl; + stream << "--ptt-ssb=\"" << *ptt_input_ssb << "\" \\" << std::endl; + stream << "--receiver=\"" << *receiver << "\" \\" << std::endl; + stream << "--text=\"" << *text_input << "\" \\" << std::endl; + stream << "--transmitter=\"" << *transmitter << "\"" << std::endl; return stream; } diff --git a/freedv-server/source/modem_noop.cpp b/freedv-server/source/modem_noop.cpp index c0eeda04..dedb96e8 100644 --- a/freedv-server/source/modem_noop.cpp +++ b/freedv-server/source/modem_noop.cpp @@ -84,6 +84,7 @@ namespace FreeDV { std::size_t data_length) { const std::size_t length = min(data_length / 2, *sample_length); + memcpy(o, i, length * 2); *sample_length = length; return length; diff --git a/freedv-server/source/platform/linux/audio_out_alsa.cpp b/freedv-server/source/platform/linux/audio_out_alsa.cpp index 884a1bfb..fdccc741 100644 --- a/freedv-server/source/platform/linux/audio_out_alsa.cpp +++ b/freedv-server/source/platform/linux/audio_out_alsa.cpp @@ -1,6 +1,7 @@ /// The ALSA audio output driver. #include +#include #include "drivers.h" #include #include @@ -89,7 +90,17 @@ namespace FreeDV { std::size_t AudioOutALSA::write16(const std::int16_t * array, std::size_t length) { - const int result = snd_pcm_writei(handle, array, length); + // for ( std::size_t i = 0 ; i < length ; i++ ) + // std::cerr << array[i] << ' '; + + int result = snd_pcm_writei(handle, array, length); + if ( result == -EPIPE ) { + snd_pcm_recover(handle, result, 1); + result = snd_pcm_writei(handle, array, length); + std::cerr << "ALSA write underrun." << std::endl; + if ( result == -EPIPE ) + return 0; + } if ( result >= 0 ) return result; else { @@ -115,10 +126,18 @@ namespace FreeDV { { snd_pcm_sframes_t available = 0; - if ( (available = snd_pcm_avail(handle)) >= 0 ) + available = snd_pcm_avail(handle); + if ( available == -EPIPE ) { + snd_pcm_recover(handle, available, 1); + available = snd_pcm_avail(handle); + std::cerr << "ALSA write underrun." << std::endl; + } + if ( available >= 0 ) return available; + else if ( available == -EPIPE ) + return 0; else { - do_throw(available, "Get Available Frames"); + do_throw(available, "Get Frames Available for Write"); return 0; // do_throw doesn't return. } } diff --git a/freedv-server/source/run.cpp b/freedv-server/source/run.cpp index 252ba07e..5098a146 100644 --- a/freedv-server/source/run.cpp +++ b/freedv-server/source/run.cpp @@ -28,8 +28,8 @@ namespace FreeDV { bool begin_receive; bool begin_transmit; FIFO codec_fifo; - FIFO input_fifo; - FIFO output_fifo; + FIFO in_fifo; + FIFO out_fifo; bool ptt_digital; bool ptt_ssb; @@ -48,8 +48,8 @@ namespace FreeDV { Run::Run(Interfaces * interfaces) : i(interfaces), begin_receive(true), begin_transmit(false), - codec_fifo(TempSize * 2), input_fifo(TempSize * 2), - output_fifo(TempSize * 2), ptt_digital(false), ptt_ssb(false) + codec_fifo(TempSize * 2), in_fifo(TempSize * 2), + out_fifo(TempSize * 2), ptt_digital(false), ptt_ssb(false) { } @@ -60,9 +60,9 @@ namespace FreeDV { void Run::reset_fifos() { - input_fifo.reset(); + in_fifo.reset(); codec_fifo.reset(); - output_fifo.reset(); + out_fifo.reset(); } void @@ -94,84 +94,78 @@ namespace FreeDV { Run::receive() { // Drain any data that the loudspeaker can take. - const std::size_t output_samples = min( + const std::size_t out_samples = min( i->loudspeaker->ready(), - (output_fifo.outgoing_available() / 2)); + (out_fifo.get_available() / 2)); - if ( output_samples ) { + if ( out_samples ) { + std::int16_t * s = (std::int16_t *)out_fifo.get(out_samples * 2); + + for ( std::size_t i = 0; i < out_samples; i++ ) { + std::cerr << (double)s[i] / 32767.0 << ' '; + } const std::size_t result = i->loudspeaker->write16( - (std::int16_t *)output_fifo.outgoing_buffer( - output_samples * 2), - output_samples); + (std::int16_t *)out_fifo.get( + out_samples * 2), + out_samples); if ( result > 0 ) - output_fifo.outgoing_done(result * 2); + out_fifo.get_done(result * 2); else std::cerr << "Loudspeaker I/O error: " << strerror(errno) << std::endl; } // Fill any data that the receiver can provide. - const std::size_t input_samples = min( + const std::size_t in_samples = min( i->receiver->ready(), - (input_fifo.incoming_available() / 2)); + (in_fifo.put_space() / 2)); - if ( input_samples ) { + if ( in_samples ) { const std::size_t result = i->receiver->read16( - (std::int16_t *)input_fifo.incoming_buffer(input_samples * 2), - input_samples); + (std::int16_t *)in_fifo.put(in_samples * 2), + in_samples); if ( result > 0 ) - input_fifo.incoming_done(result * 2); + in_fifo.put_done(result * 2); else - std::cerr << "Loudspeaker I/O error: " << strerror(errno) << std::endl; + std::cerr << "Receiver I/O error: " << strerror(errno) << std::endl; } - const std::size_t frames_to_demodulate = (codec_fifo.incoming_available() - / i->modem->bytes_per_frame()); - - if ( frames_to_demodulate && input_fifo.outgoing_available() > i->modem->bytes_per_frame()) { - std::size_t samples_to_demodulate = input_fifo.outgoing_available() - / 2; - const std::size_t bytes_to_demodulate = frames_to_demodulate - * i->modem->bytes_per_frame(); + if ( in_fifo.get_available() > 0 ) { + std::size_t samples_to_demodulate = in_fifo.get_available() / 2; + const std::size_t bytes_to_demodulate = codec_fifo.put_space(); std::size_t result = i->modem->demodulate16( - (const std::int16_t *)input_fifo.outgoing_buffer( + (const std::int16_t *)in_fifo.get( samples_to_demodulate * 2), - codec_fifo.incoming_buffer(bytes_to_demodulate), + codec_fifo.put(bytes_to_demodulate), &samples_to_demodulate, bytes_to_demodulate); if ( samples_to_demodulate > 0 ) - input_fifo.outgoing_done(samples_to_demodulate * 2); + in_fifo.get_done(samples_to_demodulate * 2); if ( result > 0 ) - codec_fifo.incoming_done(result); + codec_fifo.put_done(result); } - const std::size_t frames_to_decode = - (output_fifo.incoming_available() / 2) - / i->codec->samples_per_frame(); - - if ( frames_to_decode > 0 - && codec_fifo.outgoing_available() > i->codec->bytes_per_frame() ) { - std::size_t bytes_to_decode = codec_fifo.outgoing_available(); + if ( codec_fifo.get_available() > 0 ) { + std::size_t bytes_to_decode = codec_fifo.get_available(); - const std::size_t samples_to_decode = frames_to_decode \ - * i->codec->samples_per_frame(); + const std::size_t samples_to_decode = out_fifo.put_space() / 2; const std::size_t result = i->codec->decode16( - codec_fifo.outgoing_buffer(bytes_to_decode), - (std::int16_t *)output_fifo.incoming_buffer( + codec_fifo.get(bytes_to_decode), + (std::int16_t *)out_fifo.put( samples_to_decode * 2), &bytes_to_decode, samples_to_decode); if ( bytes_to_decode > 0 ) - codec_fifo.outgoing_done(bytes_to_decode); + codec_fifo.get_done(bytes_to_decode); if ( result > 0 ) - output_fifo.incoming_done(result * 2); + out_fifo.put_done(result * 2); } } diff --git a/freedv-server/source/test/fifo.cpp b/freedv-server/source/test/fifo.cpp index 5333f5f2..7f1c66c2 100644 --- a/freedv-server/source/test/fifo.cpp +++ b/freedv-server/source/test/fifo.cpp @@ -24,58 +24,58 @@ protected: }; TEST_F(FIFOTest, CanFillAndDrain) { - ASSERT_EQ(100U, f->incoming_available()); - memset(f->incoming_buffer(100), 255, 100); - ASSERT_EQ(0U, f->outgoing_available()); - f->incoming_done(100); - ASSERT_EQ(100U, f->outgoing_available()); - ASSERT_EQ(0U, f->incoming_available()); - EXPECT_THROW(f->incoming_buffer(1), std::runtime_error); - ASSERT_EQ(100U, f->outgoing_available()); - ASSERT_NE((uint8_t *)0, f->outgoing_buffer(100)); - f->outgoing_done(100); - ASSERT_EQ(0U, f->outgoing_available()); - ASSERT_EQ(100U, f->incoming_available()); - ASSERT_EQ(100U, f->incoming_available()); - memset(f->incoming_buffer(100), 255, 100); - ASSERT_EQ(0U, f->outgoing_available()); - f->incoming_done(100); - ASSERT_EQ(100U, f->outgoing_available()); - ASSERT_EQ(0U, f->incoming_available()); + ASSERT_EQ(100U, f->put_space()); + memset(f->put(100), 255, 100); + ASSERT_EQ(0U, f->get_available()); + f->put_done(100); + ASSERT_EQ(100U, f->get_available()); + ASSERT_EQ(0U, f->put_space()); + EXPECT_THROW(f->put(1), std::runtime_error); + ASSERT_EQ(100U, f->get_available()); + ASSERT_NE((uint8_t *)0, f->get(100)); + f->get_done(100); + ASSERT_EQ(0U, f->get_available()); + ASSERT_EQ(100U, f->put_space()); + ASSERT_EQ(100U, f->put_space()); + memset(f->put(100), 255, 100); + ASSERT_EQ(0U, f->get_available()); + f->put_done(100); + ASSERT_EQ(100U, f->get_available()); + ASSERT_EQ(0U, f->put_space()); } TEST_F(FIFOTest, Reorder) { uint8_t * b; const uint8_t * r; - ASSERT_EQ(100U, f->incoming_available()); - ASSERT_NE((uint8_t *)0, b = f->incoming_buffer(99)); + ASSERT_EQ(100U, f->put_space()); + ASSERT_NE((uint8_t *)0, b = f->put(99)); memset(b, 0, 98); b[98] = 'b'; - f->incoming_done(99); - ASSERT_EQ(1U, f->incoming_available()); - ASSERT_EQ(99U, f->outgoing_available()); - ASSERT_NE((uint8_t *)0, f->outgoing_buffer(98)); - f->outgoing_done(98); - ASSERT_EQ(1U, f->outgoing_available()); - ASSERT_EQ(99U, f->incoming_available()); + f->put_done(99); + ASSERT_EQ(1U, f->put_space()); + ASSERT_EQ(99U, f->get_available()); + ASSERT_NE((uint8_t *)0, f->get(98)); + f->get_done(98); + ASSERT_EQ(1U, f->get_available()); + ASSERT_EQ(99U, f->put_space()); // This should cause reorder(). - ASSERT_NE((uint8_t *)0, b = f->incoming_buffer(2)); - f->incoming_done(0); - ASSERT_EQ(99U, f->incoming_available()); - ASSERT_EQ(1U, f->outgoing_available()); - ASSERT_NE((uint8_t *)0, r = f->outgoing_buffer(1)); + ASSERT_NE((uint8_t *)0, b = f->put(2)); + f->put_done(0); + ASSERT_EQ(99U, f->put_space()); + ASSERT_EQ(1U, f->get_available()); + ASSERT_NE((uint8_t *)0, r = f->get(1)); ASSERT_EQ('b', *r); - f->outgoing_done(1); + f->get_done(1); } TEST_F(FIFOTest, CanReset) { - ASSERT_EQ(100U, f->incoming_available()); - ASSERT_EQ(0U, f->outgoing_available()); - f->incoming_done(100); - ASSERT_EQ(100U, f->outgoing_available()); - ASSERT_EQ(0U, f->incoming_available()); + ASSERT_EQ(100U, f->put_space()); + ASSERT_EQ(0U, f->get_available()); + f->put_done(100); + ASSERT_EQ(100U, f->get_available()); + ASSERT_EQ(0U, f->put_space()); f->reset(); - ASSERT_EQ(0U, f->outgoing_available()); - ASSERT_EQ(100U, f->incoming_available()); + ASSERT_EQ(0U, f->get_available()); + ASSERT_EQ(100U, f->put_space()); } -- 2.25.1