Restart the device automatically if stuck with read stream errors

This commit is contained in:
vsonnier 2017-08-13 22:14:12 +02:00
parent c64baab99d
commit acc6d2a31d
3 changed files with 47 additions and 7 deletions

View File

@ -84,7 +84,7 @@ static int audioCallback(void *outputBuffer, void * /* inputBuffer */, unsigned
} }
if (status) { 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()) { if (src->boundThreads.empty()) {

View File

@ -8,6 +8,7 @@
#include <string> #include <string>
#include <algorithm> #include <algorithm>
#include <SoapySDR/Logger.h> #include <SoapySDR/Logger.h>
#include <chrono>
#define TARGET_DISPLAY_FPS 60 #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 //Called in an infinite loop, read SaopySDR device to build
// a 'this.numElems' sized batch of samples (SDRThreadIQData) and push it into iqDataOutQueue. // 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. //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; int flags;
long long timeNs; long long timeNs;
@ -234,6 +235,8 @@ void SDRThread::readStream(SDRThreadIQDataQueuePtr iqDataOutQueue) {
} }
} //end if numOverflow > 0 } //end if numOverflow > 0
int readStreamCode = 0;
//2. attempt readStream() at most nElems, by mtElems-sized chunks, append in dataOut->data directly. //2. attempt readStream() at most nElems, by mtElems-sized chunks, append in dataOut->data directly.
while (n_read < nElems && !stopping) { while (n_read < nElems && !stopping) {
@ -241,6 +244,8 @@ void SDRThread::readStream(SDRThreadIQDataQueuePtr iqDataOutQueue) {
//from which SoapySDR effectively returns n_stream_read. //from which SoapySDR effectively returns n_stream_read.
int n_stream_read = device->readStream(stream, buffs, mtElems, flags, timeNs); 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 the n_stream_read <= 0, bail out from reading.
if (n_stream_read == 0) { if (n_stream_read == 0) {
std::cout << "SDRThread::readStream(): 2. SoapySDR read blocking..." << std::endl; std::cout << "SDRThread::readStream(): 2. SoapySDR read blocking..." << std::endl;
@ -362,10 +367,15 @@ void SDRThread::readStream(SDRThreadIQDataQueuePtr iqDataOutQueue) {
//saturation, let a chance to the other threads to consume the existing samples //saturation, let a chance to the other threads to consume the existing samples
std::this_thread::yield(); std::this_thread::yield();
} }
return readStreamCode;
} }
void SDRThread::readLoop() { void SDRThread::readLoop() {
#define STREAM_READ_WATCHDOG_S (2)
SDRThreadIQDataQueuePtr iqDataOutQueue = std::static_pointer_cast<SDRThreadIQDataQueue>( getOutputQueue("IQDataOutput")); SDRThreadIQDataQueuePtr iqDataOutQueue = std::static_pointer_cast<SDRThreadIQDataQueue>( getOutputQueue("IQDataOutput"));
if (iqDataOutQueue == nullptr) { if (iqDataOutQueue == nullptr) {
@ -374,10 +384,35 @@ void SDRThread::readLoop() {
updateGains(); updateGains();
auto streamWatchDog = std::chrono::steady_clock::now();
while (!stopping.load()) { while (!stopping.load()) {
updateSettings(); 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<double> 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(); iqDataOutQueue->flush();
} }

View File

@ -47,12 +47,17 @@ class SDRThread : public IOThread {
private: private:
bool init(); bool init();
void deinit(); 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(); void readLoop();
public: public:
SDRThread(); SDRThread();
~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(); virtual void run();