diff --git a/sdrbase/audio/audiodevicemanager.cpp b/sdrbase/audio/audiodevicemanager.cpp index d83003ad3..1c24fb727 100644 --- a/sdrbase/audio/audiodevicemanager.cpp +++ b/sdrbase/audio/audiodevicemanager.cpp @@ -96,6 +96,8 @@ AudioDeviceManager::AudioDeviceManager() m_defaultInputStarted = false; m_defaultOutputStarted = false; + + connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection); } AudioDeviceManager::~AudioDeviceManager() @@ -281,6 +283,7 @@ void AudioDeviceManager::addAudioSink(AudioFifo* audioFifo, MessageQueue *sample } qDebug("AudioDeviceManager::addAudioSink: new AudioOutputDevice on thread: %p", thread); + audioOutputDevice->setManagerMessageQueue(&m_inputMessageQueue); audioOutputDevice->moveToThread(thread); QObject::connect( @@ -445,7 +448,6 @@ void AudioDeviceManager::startAudioOutput(int outputDeviceIndex) AudioOutputDevice::MsgStart *msg = AudioOutputDevice::MsgStart::create(outputDeviceIndex, sampleRate); m_audioOutputs[outputDeviceIndex]->getInputMessageQueue()->push(msg); - m_audioOutputInfos[deviceName].sampleRate = sampleRate; // FIXME: possible change of sample rate in AudioOutputDevice m_audioOutputInfos[deviceName].udpAddress = udpAddress; m_audioOutputInfos[deviceName].udpPort = udpPort; m_audioOutputInfos[deviceName].copyToUDP = copyAudioToUDP; @@ -488,7 +490,7 @@ void AudioDeviceManager::startAudioInput(int inputDeviceIndex) m_audioInputs[inputDeviceIndex]->start(inputDeviceIndex, sampleRate); m_audioInputs[inputDeviceIndex]->setVolume(volume); - m_audioInputInfos[deviceName].sampleRate = m_audioInputs[inputDeviceIndex]->getRate(); + m_audioInputInfos[deviceName].sampleRate = m_audioInputs[inputDeviceIndex]->getRate(); // FIXME m_audioInputInfos[deviceName].volume = volume; m_defaultInputStarted = (inputDeviceIndex == -1); } @@ -671,17 +673,6 @@ void AudioDeviceManager::setOutputDeviceInfo(int outputDeviceIndex, const Output AudioOutputDevice::MsgStart *msgStart = AudioOutputDevice::MsgStart::create(outputDeviceIndex, deviceInfo.sampleRate); audioOutput->getInputMessageQueue()->push(msgStart); - - m_audioOutputInfos[deviceName].sampleRate = audioOutput->getRate(); // store actual sample rate - - // send message to attached channels - QList::const_iterator it = m_outputDeviceSinkMessageQueues[outputDeviceIndex].begin(); - - for (; it != m_outputDeviceSinkMessageQueues[outputDeviceIndex].end(); ++it) - { - DSPConfigureAudio *msg = new DSPConfigureAudio(m_audioOutputInfos[deviceName].sampleRate, DSPConfigureAudio::AudioOutput); - (*it)->push(msg); - } } audioOutput->setUdpCopyToUDP(deviceInfo.copyToUDP); @@ -724,18 +715,6 @@ void AudioDeviceManager::unsetOutputDeviceInfo(int outputDeviceIndex) stopAudioOutput(outputDeviceIndex); startAudioOutput(outputDeviceIndex); - - if (oldDeviceInfo.sampleRate != m_audioOutputInfos[deviceName].sampleRate) - { - // send message to attached channels - QList::const_iterator it = m_outputDeviceSinkMessageQueues[outputDeviceIndex].begin(); - - for (; it != m_outputDeviceSinkMessageQueues[outputDeviceIndex].end(); ++it) - { - DSPConfigureAudio *msg = new DSPConfigureAudio(m_audioOutputInfos[deviceName].sampleRate, DSPConfigureAudio::AudioOutput); - (*it)->push(msg); - } - } } void AudioDeviceManager::unsetInputDeviceInfo(int inputDeviceIndex) @@ -865,3 +844,40 @@ void AudioDeviceManager::debugAudioOutputInfos() const << " decimationFactor: " << it.value().udpDecimationFactor; } } + +bool AudioDeviceManager::handleMessage(const Message& msg) +{ + if (AudioOutputDevice::MsgReportSampleRate::match(msg)) + { + AudioOutputDevice::MsgReportSampleRate& report = (AudioOutputDevice::MsgReportSampleRate&) msg; + int deviceIndex = report.getDeviceIndex(); + const QString& deviceName = report.getDeviceName(); + int sampleRate = report.getSampleRate(); + qDebug("AudioDeviceManager::handleMessage: AudioOutputDevice::MsgReportSampleRate: device(%d) %s: rate: %d", + deviceIndex, qPrintable(deviceName), sampleRate); + m_audioOutputInfos[deviceName].sampleRate = sampleRate; + + // send message to attached channels + for (auto& messageQueue : m_outputDeviceSinkMessageQueues[deviceIndex]) + { + DSPConfigureAudio *msg = new DSPConfigureAudio(m_audioOutputInfos[deviceName].sampleRate, DSPConfigureAudio::AudioOutput); + messageQueue->push(msg); + } + + return true; + } + + return false; +} + +void AudioDeviceManager::handleInputMessages() +{ + Message* message; + + while ((message = m_inputMessageQueue.pop()) != nullptr) + { + if (handleMessage(*message)) { + delete message; + } + } +} diff --git a/sdrbase/audio/audiodevicemanager.h b/sdrbase/audio/audiodevicemanager.h index 02b9ebe7b..e8cb29b3c 100644 --- a/sdrbase/audio/audiodevicemanager.h +++ b/sdrbase/audio/audiodevicemanager.h @@ -22,18 +22,20 @@ #include #include #include +#include #include "audio/audioinputdevice.h" #include "audio/audiooutputdevice.h" #include "audio/audiodeviceinfo.h" +#include "util/messagequeue.h" #include "export.h" class QThread; class QDataStream; class AudioFifo; -class MessageQueue; -class SDRBASE_API AudioDeviceManager { +class SDRBASE_API AudioDeviceManager : public QObject { + Q_OBJECT public: class InputDeviceInfo { @@ -149,6 +151,8 @@ private: bool m_defaultOutputStarted; //!< True if the default audio output (-1) has already been started bool m_defaultInputStarted; //!< True if the default audio input (-1) has already been started + MessageQueue m_inputMessageQueue; + void resetToDefaults(); QByteArray serialize() const; bool deserialize(const QByteArray& data); @@ -166,7 +170,12 @@ private: void deserializeOutputMap(QByteArray& data); void debugAudioOutputInfos() const; + bool handleMessage(const Message& cmd); + friend class MainSettings; + +private slots: + void handleInputMessages(); }; QDataStream& operator<<(QDataStream& ds, const AudioDeviceManager::InputDeviceInfo& info); diff --git a/sdrbase/audio/audiooutputdevice.cpp b/sdrbase/audio/audiooutputdevice.cpp index 23b8e6ae5..d6cd997d1 100644 --- a/sdrbase/audio/audiooutputdevice.cpp +++ b/sdrbase/audio/audiooutputdevice.cpp @@ -32,6 +32,7 @@ MESSAGE_CLASS_DEFINITION(AudioOutputDevice::MsgStart, Message) MESSAGE_CLASS_DEFINITION(AudioOutputDevice::MsgStop, Message) +MESSAGE_CLASS_DEFINITION(AudioOutputDevice::MsgReportSampleRate, Message) AudioOutputDevice::AudioOutputDevice() : m_audioOutput(nullptr), @@ -47,7 +48,8 @@ AudioOutputDevice::AudioOutputDevice() : m_recordSilenceTime(0), m_recordSilenceNbSamples(0), m_recordSilenceCount(0), - m_audioFifos() + m_audioFifos(), + m_managerMessageQueue(nullptr) { connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection); } @@ -66,18 +68,18 @@ AudioOutputDevice::~AudioOutputDevice() // m_audioFifos.clear(); } -bool AudioOutputDevice::start(int device, int rate) +bool AudioOutputDevice::start(int deviceIndex, int sampleRate) { // if (m_audioOutput) { // return true; // } // if (m_audioUsageCount == 0) // { - qDebug("AudioOutputDevice::start: device: %d rate: %d thread: %p", device, rate, QThread::currentThread()); + qDebug("AudioOutputDevice::start: device: %d rate: %d thread: %p", deviceIndex, sampleRate, QThread::currentThread()); QMutexLocker mutexLocker(&m_mutex); AudioDeviceInfo devInfo; - if (device < 0) + if (deviceIndex < 0) { devInfo = AudioDeviceInfo::defaultOutputDevice(); qWarning("AudioOutputDevice::start: using system default device %s", qPrintable(devInfo.defaultOutputDevice().deviceName())); @@ -86,15 +88,16 @@ bool AudioOutputDevice::start(int device, int rate) { QList devicesInfo = AudioDeviceInfo::availableOutputDevices(); - if (device < devicesInfo.size()) + if (deviceIndex < devicesInfo.size()) { - devInfo = devicesInfo[device]; - qWarning("AudioOutputDevice::start: using audio device #%d: %s", device, qPrintable(devInfo.deviceName())); + devInfo = devicesInfo[deviceIndex]; + qWarning("AudioOutputDevice::start: using audio device #%d: %s", deviceIndex, qPrintable(devInfo.deviceName())); } else { devInfo = AudioDeviceInfo::defaultOutputDevice(); - qWarning("AudioOutputDevice::start: audio device #%d does not exist. Using system default device %s", device, qPrintable(devInfo.defaultOutputDevice().deviceName())); + qWarning("AudioOutputDevice::start: audio device #%d does not exist. Using system default device %s", deviceIndex, qPrintable(devInfo.defaultOutputDevice().deviceName())); + deviceIndex = -1; } } @@ -104,7 +107,7 @@ bool AudioOutputDevice::start(int device, int rate) m_audioFormat = devInfo.deviceInfo().preferredFormat(); #endif - m_audioFormat.setSampleRate(rate); + m_audioFormat.setSampleRate(sampleRate); m_audioFormat.setChannelCount(2); #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) m_audioFormat.setSampleFormat(QAudioFormat::Int16); @@ -118,7 +121,7 @@ bool AudioOutputDevice::start(int device, int rate) if (!devInfo.isFormatSupported(m_audioFormat)) { #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - qWarning("AudioOutputDevice::start: format %d Hz 2xS16LE audio/pcm not supported.", rate); + qWarning("AudioOutputDevice::start: format %d Hz 2xS16LE audio/pcm not supported.", sampleRate); #else m_audioFormat = devInfo.deviceInfo().nearestFormat(m_audioFormat); std::ostringstream os; @@ -128,7 +131,7 @@ bool AudioOutputDevice::start(int device, int rate) << " codec: " << m_audioFormat.codec().toStdString() << " byteOrder: " << (m_audioFormat.byteOrder() == QAudioFormat::BigEndian ? "BE" : "LE") << " sampleType: " << (int) m_audioFormat.sampleType(); - qWarning("AudioOutputDevice::start: format %d Hz 2xS16LE audio/pcm not supported. Using: %s", rate, os.str().c_str()); + qWarning("AudioOutputDevice::start: format %d Hz 2xS16LE audio/pcm not supported. Using: %s", sampleRate, os.str().c_str()); #endif } else @@ -161,7 +164,7 @@ bool AudioOutputDevice::start(int device, int rate) // m_audioOutput->setBufferSize(m_audioFormat.sampleRate() / 5); FIXME: does not work generally m_recordSilenceNbSamples = (m_recordSilenceTime * m_audioFormat.sampleRate()) / 10; // time in 100'ś ms - QIODevice::open(QIODevice::ReadOnly); + QIODevice::open(QIODevice::ReadOnly | QIODevice::Unbuffered); m_audioOutput->start(this); @@ -170,6 +173,10 @@ bool AudioOutputDevice::start(int device, int rate) } else { qDebug("AudioOutputDevice::start: started buffer: %d bytes", m_audioOutput->bufferSize()); } + + if (m_managerMessageQueue) { + m_managerMessageQueue->push(AudioOutputDevice::MsgReportSampleRate::create(deviceIndex, devInfo.deviceName(), m_audioFormat.sampleRate())); + } // } // // m_audioUsageCount++; diff --git a/sdrbase/audio/audiooutputdevice.h b/sdrbase/audio/audiooutputdevice.h index 5d8bab6eb..6b9de11f6 100644 --- a/sdrbase/audio/audiooutputdevice.h +++ b/sdrbase/audio/audiooutputdevice.h @@ -77,6 +77,30 @@ public: { } }; + class MsgReportSampleRate : public Message { + MESSAGE_CLASS_DECLARATION + public: + int getDeviceIndex() const { return m_deviceIndex; } + const QString& getDeviceName() const { return m_deviceName; } + int getSampleRate() const { return m_sampleRate; } + + static MsgReportSampleRate* create(int deviceIndex, const QString& deviceName, int sampleRate) { + return new MsgReportSampleRate(deviceIndex, deviceName, sampleRate); + } + + private: + int m_deviceIndex; + QString m_deviceName; + int m_sampleRate; + + MsgReportSampleRate(int deviceIndex, const QString& deviceName, int sampleRate) : + Message(), + m_deviceIndex(deviceIndex), + m_deviceName(deviceName), + m_sampleRate(sampleRate) + { } + }; + enum UDPChannelMode { UDPChannelLeft, @@ -118,6 +142,7 @@ public: void setDeviceName(const QString& deviceName) { m_deviceName = deviceName;} MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + void setManagerMessageQueue(MessageQueue *messageQueue) { m_managerMessageQueue = messageQueue; } private: QRecursiveMutex m_mutex; @@ -147,6 +172,7 @@ private: QString m_deviceName; MessageQueue m_inputMessageQueue; + MessageQueue *m_managerMessageQueue; //virtual bool open(OpenMode mode); virtual qint64 readData(char* data, qint64 maxLen); @@ -155,7 +181,7 @@ private: void writeSampleToFile(qint16 lSample, qint16 rSample); bool handleMessage(const Message& cmd); - bool start(int device, int rate); + bool start(int deviceIndex, int sampleRate); void stop(); friend class AudioOutputPipe;