mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-11-04 05:30:32 -05:00 
			
		
		
		
	Merge pull request #1887 from srcejon/audio_errors
Indicate audio FIFO underflow/overflow in GUI
This commit is contained in:
		
						commit
						fe12d7f875
					
				@ -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";
 | 
				
			||||||
@ -362,11 +363,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 {
 | 
				
			||||||
@ -375,6 +380,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