diff --git a/src/audio/AudioThread.cpp b/src/audio/AudioThread.cpp index 9498242..dec6450 100644 --- a/src/audio/AudioThread.cpp +++ b/src/audio/AudioThread.cpp @@ -84,7 +84,7 @@ static int audioCallback(void *outputBuffer, void * /* inputBuffer */, unsigned } if (status) { - std::cout << "Audio buffer underflow.." << (src->underflowCount++) << std::endl; + std::cout << "Audio buffer underflow.." << (src->underflowCount++) << std::endl << std::flush; } if (src->boundThreads.empty()) { diff --git a/src/sdr/SoapySDRThread.cpp b/src/sdr/SoapySDRThread.cpp index b8c5879..9890caa 100644 --- a/src/sdr/SoapySDRThread.cpp +++ b/src/sdr/SoapySDRThread.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #define TARGET_DISPLAY_FPS 60 @@ -191,7 +192,7 @@ void SDRThread::assureBufferMinSize(SDRThreadIQData * dataOut, size_t minSize) { //Called in an infinite loop, read SaopySDR device to build // a 'this.numElems' sized batch of samples (SDRThreadIQData) and push it into iqDataOutQueue. //this batch of samples is built to represent 1 frame / TARGET_DISPLAY_FPS. -void SDRThread::readStream(SDRThreadIQDataQueuePtr iqDataOutQueue) { +int SDRThread::readStream(SDRThreadIQDataQueuePtr iqDataOutQueue) { int flags; long long timeNs; @@ -234,12 +235,16 @@ void SDRThread::readStream(SDRThreadIQDataQueuePtr iqDataOutQueue) { } } //end if numOverflow > 0 + int readStreamCode = 0; + //2. attempt readStream() at most nElems, by mtElems-sized chunks, append in dataOut->data directly. while (n_read < nElems && !stopping) { //Whatever the number of remaining samples needed to reach nElems, we always try to read a mtElems-size chunk, //from which SoapySDR effectively returns n_stream_read. int n_stream_read = device->readStream(stream, buffs, mtElems, flags, timeNs); + + readStreamCode = n_stream_read; //if the n_stream_read <= 0, bail out from reading. if (n_stream_read == 0) { @@ -250,7 +255,7 @@ void SDRThread::readStream(SDRThreadIQDataQueuePtr iqDataOutQueue) { std::cout << "SDRThread::readStream(): 2. SoapySDR read failed with code: " << n_stream_read << std::endl; break; } - + //sucess read beyond nElems, so with overflow: if ((n_read + n_stream_read) > nElems) { @@ -362,10 +367,15 @@ void SDRThread::readStream(SDRThreadIQDataQueuePtr iqDataOutQueue) { //saturation, let a chance to the other threads to consume the existing samples std::this_thread::yield(); } + + return readStreamCode; } + void SDRThread::readLoop() { + #define STREAM_READ_WATCHDOG_S (2) + SDRThreadIQDataQueuePtr iqDataOutQueue = std::static_pointer_cast( getOutputQueue("IQDataOutput")); if (iqDataOutQueue == nullptr) { @@ -373,11 +383,36 @@ void SDRThread::readLoop() { } updateGains(); + + auto streamWatchDog = std::chrono::steady_clock::now(); while (!stopping.load()) { + updateSettings(); - readStream(iqDataOutQueue); - } + + if (readStream(iqDataOutQueue) > 0) { + // record the date of the last good read. + streamWatchDog = std::chrono::steady_clock::now(); + } + + auto now = std::chrono::steady_clock::now(); + + //check watchdog value: if the date is too old, deinit end init the device. + std::chrono::duration diff = now - streamWatchDog; + + if (diff.count() > STREAM_READ_WATCHDOG_S) { + + std::cout << "SDRThread::readStream(): Restarting stream after too many read erros..." << std::endl << std::flush; + + deinit(); + init(); + + streamWatchDog = std::chrono::steady_clock::now(); + + std::cout << "SDRThread::readStream(): stream restarted." << std::endl << std::flush; + } + } //End while + iqDataOutQueue->flush(); } diff --git a/src/sdr/SoapySDRThread.h b/src/sdr/SoapySDRThread.h index d704d37..2bb2084 100644 --- a/src/sdr/SoapySDRThread.h +++ b/src/sdr/SoapySDRThread.h @@ -47,13 +47,18 @@ class SDRThread : public IOThread { private: bool init(); void deinit(); - void readStream(SDRThreadIQDataQueuePtr iqDataOutQueue); + + //returns the SoapyDevice readStream return value, + //i.e if >= 0 the numbre of samples read, else if < 0 an error code. + int readStream(SDRThreadIQDataQueuePtr iqDataOutQueue); + void readLoop(); public: SDRThread(); ~SDRThread(); - enum SDRThreadState { SDR_THREAD_MESSAGE, SDR_THREAD_INITIALIZED, SDR_THREAD_FAILED }; + + enum SDRThreadState { SDR_THREAD_MESSAGE, SDR_THREAD_INITIALIZED, SDR_THREAD_FAILED}; virtual void run();