mirror of
https://github.com/f4exb/sdrangel.git
synced 2025-05-23 18:52:28 -04:00
Indicate audio FIFO underflow/overflow. Don't zero pad audio output, if some audio is available.
This commit is contained in:
parent
8337e2c7b2
commit
45e9c3f37c
@ -95,6 +95,7 @@ public:
|
|||||||
double getMagSq() const { return m_running ? m_basebandSink->getMagSq() : 0.0; }
|
double getMagSq() const { return m_running ? m_basebandSink->getMagSq() : 0.0; }
|
||||||
bool getSquelchOpen() const { return m_running && m_basebandSink->getSquelchOpen(); }
|
bool getSquelchOpen() const { return m_running && m_basebandSink->getSquelchOpen(); }
|
||||||
int getAudioSampleRate() const { return m_running ? m_basebandSink->getAudioSampleRate() : 0; }
|
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)
|
void getMagSqLevels(double& avg, double& peak, int& nbSamples)
|
||||||
{
|
{
|
||||||
|
@ -44,6 +44,8 @@ WFMDemodBaseband::WFMDemodBaseband()
|
|||||||
m_channelSampleRate = 0;
|
m_channelSampleRate = 0;
|
||||||
|
|
||||||
connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
|
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()
|
WFMDemodBaseband::~WFMDemodBaseband()
|
||||||
@ -188,3 +190,13 @@ void WFMDemodBaseband::setBasebandSampleRate(int sampleRate)
|
|||||||
m_channelizer->setBasebandSampleRate(sampleRate);
|
m_channelizer->setBasebandSampleRate(sampleRate);
|
||||||
m_sink.applyChannelSettings(m_channelizer->getChannelSampleRate(), m_channelizer->getChannelFrequencyOffset());
|
m_sink.applyChannelSettings(m_channelizer->getChannelSampleRate(), m_channelizer->getChannelFrequencyOffset());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WFMDemodBaseband::audioUnderflow()
|
||||||
|
{
|
||||||
|
m_audioFifoErrorDateTime = QDateTime::currentDateTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WFMDemodBaseband::audioOverflow()
|
||||||
|
{
|
||||||
|
m_audioFifoErrorDateTime = QDateTime::currentDateTime();
|
||||||
|
}
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QRecursiveMutex>
|
#include <QRecursiveMutex>
|
||||||
|
#include <QDateTime>
|
||||||
|
|
||||||
#include "dsp/samplesinkfifo.h"
|
#include "dsp/samplesinkfifo.h"
|
||||||
#include "util/message.h"
|
#include "util/message.h"
|
||||||
@ -73,6 +74,7 @@ public:
|
|||||||
void setChannel(ChannelAPI *channel);
|
void setChannel(ChannelAPI *channel);
|
||||||
void setFifoLabel(const QString& label) { m_sampleFifo.setLabel(label); }
|
void setFifoLabel(const QString& label) { m_sampleFifo.setLabel(label); }
|
||||||
void setAudioFifoLabel(const QString& label) { m_sink.setAudioFifoLabel(label); }
|
void setAudioFifoLabel(const QString& label) { m_sink.setAudioFifoLabel(label); }
|
||||||
|
QDateTime getAudioFifoErrorDateTime() { return m_audioFifoErrorDateTime; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SampleSinkFifo m_sampleFifo;
|
SampleSinkFifo m_sampleFifo;
|
||||||
@ -82,6 +84,7 @@ private:
|
|||||||
MessageQueue m_inputMessageQueue; //!< Queue for asynchronous inbound communication
|
MessageQueue m_inputMessageQueue; //!< Queue for asynchronous inbound communication
|
||||||
WFMDemodSettings m_settings;
|
WFMDemodSettings m_settings;
|
||||||
QRecursiveMutex m_mutex;
|
QRecursiveMutex m_mutex;
|
||||||
|
QDateTime m_audioFifoErrorDateTime;
|
||||||
|
|
||||||
bool handleMessage(const Message& cmd);
|
bool handleMessage(const Message& cmd);
|
||||||
void applySettings(const WFMDemodSettings& settings, bool force = false);
|
void applySettings(const WFMDemodSettings& settings, bool force = false);
|
||||||
@ -89,6 +92,8 @@ private:
|
|||||||
private slots:
|
private slots:
|
||||||
void handleInputMessages();
|
void handleInputMessages();
|
||||||
void handleData(); //!< Handle data when samples have to be processed
|
void handleData(); //!< Handle data when samples have to be processed
|
||||||
|
void audioUnderflow();
|
||||||
|
void audioOverflow();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // INCLUDE_WFMDEMODBASEBAND_H
|
#endif // INCLUDE_WFMDEMODBASEBAND_H
|
||||||
|
@ -218,7 +218,8 @@ WFMDemodGUI::WFMDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban
|
|||||||
m_basebandSampleRate(1),
|
m_basebandSampleRate(1),
|
||||||
m_basicSettingsShown(false),
|
m_basicSettingsShown(false),
|
||||||
m_squelchOpen(false),
|
m_squelchOpen(false),
|
||||||
m_audioSampleRate(-1)
|
m_audioSampleRate(-1),
|
||||||
|
m_recentAudioFifoError(false)
|
||||||
{
|
{
|
||||||
setAttribute(Qt::WA_DeleteOnClose, true);
|
setAttribute(Qt::WA_DeleteOnClose, true);
|
||||||
m_helpURL = "plugins/channelrx/demodwfm/readme.md";
|
m_helpURL = "plugins/channelrx/demodwfm/readme.md";
|
||||||
@ -361,11 +362,15 @@ void WFMDemodGUI::tick()
|
|||||||
|
|
||||||
int audioSampleRate = m_wfmDemod->getAudioSampleRate();
|
int audioSampleRate = m_wfmDemod->getAudioSampleRate();
|
||||||
bool squelchOpen = m_wfmDemod->getSquelchOpen();
|
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) {
|
if (audioSampleRate < 0) {
|
||||||
ui->audioMute->setStyleSheet("QToolButton { background-color : red; }");
|
ui->audioMute->setStyleSheet("QToolButton { background-color : red; }");
|
||||||
|
} else if (recentAudioFifoError) {
|
||||||
|
ui->audioMute->setStyleSheet("QToolButton { background-color : rgb(120,120,0); }");
|
||||||
} else if (squelchOpen) {
|
} else if (squelchOpen) {
|
||||||
ui->audioMute->setStyleSheet("QToolButton { background-color : green; }");
|
ui->audioMute->setStyleSheet("QToolButton { background-color : green; }");
|
||||||
} else {
|
} else {
|
||||||
@ -374,6 +379,7 @@ void WFMDemodGUI::tick()
|
|||||||
|
|
||||||
m_audioSampleRate = audioSampleRate;
|
m_audioSampleRate = audioSampleRate;
|
||||||
m_squelchOpen = squelchOpen;
|
m_squelchOpen = squelchOpen;
|
||||||
|
m_recentAudioFifoError = recentAudioFifoError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,6 +58,7 @@ private:
|
|||||||
bool m_audioMute;
|
bool m_audioMute;
|
||||||
bool m_squelchOpen;
|
bool m_squelchOpen;
|
||||||
int m_audioSampleRate;
|
int m_audioSampleRate;
|
||||||
|
bool m_recentAudioFifoError;
|
||||||
|
|
||||||
WFMDemod* m_wfmDemod;
|
WFMDemod* m_wfmDemod;
|
||||||
MessageQueue m_inputMessageQueue;
|
MessageQueue m_inputMessageQueue;
|
||||||
|
@ -68,6 +68,7 @@ private:
|
|||||||
signals:
|
signals:
|
||||||
void dataReady();
|
void dataReady();
|
||||||
void overflow(int nsamples);
|
void overflow(int nsamples);
|
||||||
|
void underflow();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // INCLUDE_AUDIOFIFO_H
|
#endif // INCLUDE_AUDIOFIFO_H
|
||||||
|
@ -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
|
memset(&m_mixBuffer[0], 0x00, 2 * samplesPerBuffer * sizeof(m_mixBuffer[0])); // start with silence
|
||||||
|
|
||||||
// sum up a block from all fifos
|
// sum up a block from all fifos
|
||||||
@ -380,10 +387,11 @@ qint64 AudioOutputDevice::readData(char* data, qint64 maxLen)
|
|||||||
const qint16* src = (const qint16*) data;
|
const qint16* src = (const qint16*) data;
|
||||||
std::vector<qint32>::iterator dst = m_mixBuffer.begin();
|
std::vector<qint32>::iterator dst = m_mixBuffer.begin();
|
||||||
|
|
||||||
// if (samples != framesPerBuffer)
|
if (samples != samplesPerBuffer)
|
||||||
// {
|
{
|
||||||
// qDebug("AudioOutputDevice::readData: read %d samples vs %d requested", samples, framesPerBuffer);
|
//qDebug("AudioOutputDevice::readData: read %d samples vs %d requested", samples, samplesPerBuffer);
|
||||||
// }
|
emit (*it)->underflow();
|
||||||
|
}
|
||||||
|
|
||||||
for (unsigned int i = 0; i < samples; i++)
|
for (unsigned int i = 0; i < samples; i++)
|
||||||
{
|
{
|
||||||
@ -541,8 +549,11 @@ qint64 AudioOutputDevice::bytesAvailable() const
|
|||||||
// If we return 0 from this twice in a row, audio will stop.
|
// 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
|
// 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
|
// when readData is called, that will output silence
|
||||||
if (available == 0) {
|
if (available == 0)
|
||||||
available = 2048; // Is there a better value to use?
|
{
|
||||||
|
// 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
|
return available * 2 * 2; // 2 Channels of 16-bit data
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user