Skip to content

Commit

Permalink
Merge pull request #1887 from srcejon/audio_errors
Browse files Browse the repository at this point in the history
Indicate audio FIFO underflow/overflow in GUI
  • Loading branch information
f4exb authored Nov 14, 2023
2 parents a3fa916 + 0464b40 commit fe12d7f
Show file tree
Hide file tree
Showing 7 changed files with 45 additions and 8 deletions.
1 change: 1 addition & 0 deletions plugins/channelrx/demodwfm/wfmdemod.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ class WFMDemod : public BasebandSampleSink, public ChannelAPI {
double getMagSq() const { return m_running ? m_basebandSink->getMagSq() : 0.0; }
bool getSquelchOpen() const { return m_running && m_basebandSink->getSquelchOpen(); }
int getAudioSampleRate() const { return m_running ? m_basebandSink->getAudioSampleRate() : 0; }
QDateTime getAudioFifoErrorDateTime() const { return m_running ? m_basebandSink->getAudioFifoErrorDateTime() : QDateTime(); }

void getMagSqLevels(double& avg, double& peak, int& nbSamples)
{
Expand Down
12 changes: 12 additions & 0 deletions plugins/channelrx/demodwfm/wfmdemodbaseband.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ WFMDemodBaseband::WFMDemodBaseband()
m_channelSampleRate = 0;

connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
connect(m_sink.getAudioFifo(), &AudioFifo::underflow, this, &WFMDemodBaseband::audioUnderflow);
connect(m_sink.getAudioFifo(), &AudioFifo::overflow, this, &WFMDemodBaseband::audioOverflow);
}

WFMDemodBaseband::~WFMDemodBaseband()
Expand Down Expand Up @@ -188,3 +190,13 @@ void WFMDemodBaseband::setBasebandSampleRate(int sampleRate)
m_channelizer->setBasebandSampleRate(sampleRate);
m_sink.applyChannelSettings(m_channelizer->getChannelSampleRate(), m_channelizer->getChannelFrequencyOffset());
}

void WFMDemodBaseband::audioUnderflow()
{
m_audioFifoErrorDateTime = QDateTime::currentDateTime();
}

void WFMDemodBaseband::audioOverflow()
{
m_audioFifoErrorDateTime = QDateTime::currentDateTime();
}
5 changes: 5 additions & 0 deletions plugins/channelrx/demodwfm/wfmdemodbaseband.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include <QObject>
#include <QRecursiveMutex>
#include <QDateTime>

#include "dsp/samplesinkfifo.h"
#include "util/message.h"
Expand Down Expand Up @@ -73,6 +74,7 @@ class WFMDemodBaseband : public QObject
void setChannel(ChannelAPI *channel);
void setFifoLabel(const QString& label) { m_sampleFifo.setLabel(label); }
void setAudioFifoLabel(const QString& label) { m_sink.setAudioFifoLabel(label); }
QDateTime getAudioFifoErrorDateTime() { return m_audioFifoErrorDateTime; }

private:
SampleSinkFifo m_sampleFifo;
Expand All @@ -82,13 +84,16 @@ class WFMDemodBaseband : public QObject
MessageQueue m_inputMessageQueue; //!< Queue for asynchronous inbound communication
WFMDemodSettings m_settings;
QRecursiveMutex m_mutex;
QDateTime m_audioFifoErrorDateTime;

bool handleMessage(const Message& cmd);
void applySettings(const WFMDemodSettings& settings, bool force = false);

private slots:
void handleInputMessages();
void handleData(); //!< Handle data when samples have to be processed
void audioUnderflow();
void audioOverflow();
};

#endif // INCLUDE_WFMDEMODBASEBAND_H
10 changes: 8 additions & 2 deletions plugins/channelrx/demodwfm/wfmdemodgui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,8 @@ WFMDemodGUI::WFMDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban
m_basebandSampleRate(1),
m_basicSettingsShown(false),
m_squelchOpen(false),
m_audioSampleRate(-1)
m_audioSampleRate(-1),
m_recentAudioFifoError(false)
{
setAttribute(Qt::WA_DeleteOnClose, true);
m_helpURL = "plugins/channelrx/demodwfm/readme.md";
Expand Down Expand Up @@ -362,11 +363,15 @@ void WFMDemodGUI::tick()

int audioSampleRate = m_wfmDemod->getAudioSampleRate();
bool squelchOpen = m_wfmDemod->getSquelchOpen();
int secsSinceAudioFifoError = m_wfmDemod->getAudioFifoErrorDateTime().secsTo(QDateTime::currentDateTime());
bool recentAudioFifoError = (secsSinceAudioFifoError < 1) && squelchOpen;

if ((audioSampleRate != m_audioSampleRate) || (squelchOpen != m_squelchOpen))
if ((audioSampleRate != m_audioSampleRate) || (squelchOpen != m_squelchOpen) || (recentAudioFifoError != m_recentAudioFifoError))
{
if (audioSampleRate < 0) {
ui->audioMute->setStyleSheet("QToolButton { background-color : red; }");
} else if (recentAudioFifoError) {
ui->audioMute->setStyleSheet("QToolButton { background-color : rgb(120,120,0); }");
} else if (squelchOpen) {
ui->audioMute->setStyleSheet("QToolButton { background-color : green; }");
} else {
Expand All @@ -375,6 +380,7 @@ void WFMDemodGUI::tick()

m_audioSampleRate = audioSampleRate;
m_squelchOpen = squelchOpen;
m_recentAudioFifoError = recentAudioFifoError;
}
}

Expand Down
1 change: 1 addition & 0 deletions plugins/channelrx/demodwfm/wfmdemodgui.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ public slots:
bool m_audioMute;
bool m_squelchOpen;
int m_audioSampleRate;
bool m_recentAudioFifoError;

WFMDemod* m_wfmDemod;
MessageQueue m_inputMessageQueue;
Expand Down
1 change: 1 addition & 0 deletions sdrbase/audio/audiofifo.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ class SDRBASE_API AudioFifo : public QObject {
signals:
void dataReady();
void overflow(int nsamples);
void underflow();
};

#endif // INCLUDE_AUDIOFIFO_H
23 changes: 17 additions & 6 deletions sdrbase/audio/audiooutputdevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,13 @@ qint64 AudioOutputDevice::readData(char* data, qint64 maxLen)
}
}

// See how much data we have available
// If we have less than the requested amount, we only output what we have
// If we have no data, then we output some zeros to avoid underflow
// (bytesAvailable() returns this amount when none available)
unsigned int samplesAvailable = bytesAvailable() / 4;
samplesPerBuffer = std::min(samplesAvailable, samplesPerBuffer);

memset(&m_mixBuffer[0], 0x00, 2 * samplesPerBuffer * sizeof(m_mixBuffer[0])); // start with silence

// sum up a block from all fifos
Expand All @@ -380,10 +387,11 @@ qint64 AudioOutputDevice::readData(char* data, qint64 maxLen)
const qint16* src = (const qint16*) data;
std::vector<qint32>::iterator dst = m_mixBuffer.begin();

// if (samples != framesPerBuffer)
// {
// qDebug("AudioOutputDevice::readData: read %d samples vs %d requested", samples, framesPerBuffer);
// }
if (samples != samplesPerBuffer)
{
//qDebug("AudioOutputDevice::readData: read %d samples vs %d requested", samples, samplesPerBuffer);
emit (*it)->underflow();
}

for (unsigned int i = 0; i < samples; i++)
{
Expand Down Expand Up @@ -541,8 +549,11 @@ qint64 AudioOutputDevice::bytesAvailable() const
// If we return 0 from this twice in a row, audio will stop.
// So we always return a value, and if we don't have enough data in the FIFOs
// when readData is called, that will output silence
if (available == 0) {
available = 2048; // Is there a better value to use?
if (available == 0)
{
// Use a small value, so padding is minimized, but not too small, we get underflow again straightaway
// Could make this a function of sample rate
available = 512;
}
return available * 2 * 2; // 2 Channels of 16-bit data
}
Expand Down

0 comments on commit fe12d7f

Please sign in to comment.