diff --git a/sdrbase/audio/audiodevicemanager.cpp b/sdrbase/audio/audiodevicemanager.cpp index 1c24fb727..cb66d9d28 100644 --- a/sdrbase/audio/audiodevicemanager.cpp +++ b/sdrbase/audio/audiodevicemanager.cpp @@ -102,18 +102,32 @@ AudioDeviceManager::AudioDeviceManager() AudioDeviceManager::~AudioDeviceManager() { - QMap::iterator ait = m_audioOutputs.begin(); + QMap::iterator aoit = m_audioOutputs.begin(); - for (; ait != m_audioOutputs.end(); ++ait) { - (*ait)->getInputMessageQueue()->push(AudioOutputDevice::MsgStop::create()); + for (; aoit != m_audioOutputs.end(); ++aoit) { + (*aoit)->getInputMessageQueue()->push(AudioOutputDevice::MsgStop::create()); } - QMap::iterator it = m_audioOutputThreads.begin(); + QMap::iterator otit = m_audioOutputThreads.begin(); - for (; it != m_audioOutputThreads.end(); ++it) + for (; otit != m_audioOutputThreads.end(); ++otit) { - (*it)->exit(); - (*it)->wait(); + (*otit)->exit(); + (*otit)->wait(); + } + + QMap::iterator aiit = m_audioInputs.begin(); + + for (; aiit != m_audioInputs.end(); ++aiit) { + (*aiit)->getInputMessageQueue()->push(AudioInputDevice::MsgStop::create()); + } + + QMap::iterator itit = m_audioInputThreads.begin(); + + for (; itit != m_audioInputThreads.end(); ++itit) + { + (*itit)->exit(); + (*itit)->wait(); } } @@ -356,8 +370,37 @@ void AudioDeviceManager::addAudioSource(AudioFifo* audioFifo, MessageQueue *samp { qDebug("AudioDeviceManager::addAudioSource: %d: %p", inputDeviceIndex, audioFifo); - if (m_audioInputs.find(inputDeviceIndex) == m_audioInputs.end()) { - m_audioInputs[inputDeviceIndex] = new AudioInputDevice(); + if (m_audioInputs.find(inputDeviceIndex) == m_audioInputs.end()) + { + QThread *thread = new QThread(); + AudioInputDevice *audioInputDevice = new AudioInputDevice(); + m_audioInputs[inputDeviceIndex] = audioInputDevice; + m_audioInputThreads[inputDeviceIndex] = thread; + + if (inputDeviceIndex < 0) { + audioInputDevice->setDeviceName("System default"); + } else { + audioInputDevice->setDeviceName(m_outputDevicesInfo[inputDeviceIndex].deviceName()); + } + + qDebug("AudioDeviceManager::addAudioSource: new AudioInputDevice on thread: %p", thread); + audioInputDevice->setManagerMessageQueue(&m_inputMessageQueue); + audioInputDevice->moveToThread(thread); + + QObject::connect( + thread, + &QThread::finished, + audioInputDevice, + &QObject::deleteLater + ); + QObject::connect( + thread, + &QThread::finished, + thread, + &QThread::deleteLater + ); + + thread->start(); } if ((m_audioInputs[inputDeviceIndex]->getNbFifos() == 0) && @@ -488,9 +531,10 @@ void AudioDeviceManager::startAudioInput(int inputDeviceIndex) volume = m_audioInputInfos[deviceName].volume; } - m_audioInputs[inputDeviceIndex]->start(inputDeviceIndex, sampleRate); + AudioInputDevice::MsgStart *msg = AudioInputDevice::MsgStart::create(inputDeviceIndex, sampleRate); + m_audioInputs[inputDeviceIndex]->getInputMessageQueue()->push(msg); + m_audioInputs[inputDeviceIndex]->setVolume(volume); - m_audioInputInfos[deviceName].sampleRate = m_audioInputs[inputDeviceIndex]->getRate(); // FIXME m_audioInputInfos[deviceName].volume = volume; m_defaultInputStarted = (inputDeviceIndex == -1); } @@ -502,7 +546,8 @@ void AudioDeviceManager::startAudioInput(int inputDeviceIndex) void AudioDeviceManager::stopAudioInput(int inputDeviceIndex) { - m_audioInputs[inputDeviceIndex]->stop(); + AudioInputDevice::MsgStop *msg = AudioInputDevice::MsgStop::create(); + m_audioInputs[inputDeviceIndex]->getInputMessageQueue()->push(msg); } bool AudioDeviceManager::getInputDeviceInfo(const QString& deviceName, InputDeviceInfo& deviceInfo) const @@ -621,18 +666,11 @@ void AudioDeviceManager::setInputDeviceInfo(int inputDeviceIndex, const InputDev if (oldDeviceInfo.sampleRate != deviceInfo.sampleRate) { - audioInput->stop(); - audioInput->start(inputDeviceIndex, deviceInfo.sampleRate); - m_audioInputInfos[deviceName].sampleRate = audioInput->getRate(); // store actual sample rate + AudioInputDevice::MsgStop *msgStop = AudioInputDevice::MsgStop::create(); + audioInput->getInputMessageQueue()->push(msgStop); - // send message to attached channels - QList::const_iterator it = m_inputDeviceSourceMessageQueues[inputDeviceIndex].begin(); - - for (; it != m_inputDeviceSourceMessageQueues[inputDeviceIndex].end(); ++it) - { - DSPConfigureAudio *msg = new DSPConfigureAudio(m_audioInputInfos[deviceName].sampleRate, DSPConfigureAudio::AudioInput); - (*it)->push(msg); - } + AudioInputDevice::MsgStart *msgStart = AudioInputDevice::MsgStart::create(inputDeviceIndex, deviceInfo.sampleRate); + audioInput->getInputMessageQueue()->push(msgStart); } audioInput->setVolume(deviceInfo.volume); @@ -743,18 +781,6 @@ void AudioDeviceManager::unsetInputDeviceInfo(int inputDeviceIndex) stopAudioInput(inputDeviceIndex); startAudioInput(inputDeviceIndex); - - if (oldDeviceInfo.sampleRate != m_audioInputInfos[deviceName].sampleRate) - { - // send message to attached channels - QList::const_iterator it = m_inputDeviceSourceMessageQueues[inputDeviceIndex].begin(); - - for (; it != m_inputDeviceSourceMessageQueues[inputDeviceIndex].end(); ++it) - { - DSPConfigureAudio *msg = new DSPConfigureAudio(m_audioInputInfos[deviceName].sampleRate, DSPConfigureAudio::AudioInput); - (*it)->push(msg); - } - } } void AudioDeviceManager::inputInfosCleanup() @@ -866,6 +892,25 @@ bool AudioDeviceManager::handleMessage(const Message& msg) return true; } + else if (AudioInputDevice::MsgReportSampleRate::match(msg)) + { + AudioInputDevice::MsgReportSampleRate& report = (AudioInputDevice::MsgReportSampleRate&) msg; + int deviceIndex = report.getDeviceIndex(); + const QString& deviceName = report.getDeviceName(); + int sampleRate = report.getSampleRate(); + qDebug("AudioDeviceManager::handleMessage: AudioInputDevice::MsgReportSampleRate: device(%d) %s: rate: %d", + deviceIndex, qPrintable(deviceName), sampleRate); + m_audioInputInfos[deviceName].sampleRate = sampleRate; + + // send message to attached channels + for (auto& messageQueue : m_inputDeviceSourceMessageQueues[deviceIndex]) + { + DSPConfigureAudio *msg = new DSPConfigureAudio(m_audioInputInfos[deviceName].sampleRate, DSPConfigureAudio::AudioInput); + messageQueue->push(msg); + } + + return true; + } return false; } diff --git a/sdrbase/audio/audiodevicemanager.h b/sdrbase/audio/audiodevicemanager.h index e8cb29b3c..1a3df2372 100644 --- a/sdrbase/audio/audiodevicemanager.h +++ b/sdrbase/audio/audiodevicemanager.h @@ -146,6 +146,7 @@ private: QMap m_audioFifoToSourceMessageQueues; //!< audio source FIFO to attached source message queue QMap > m_inputDeviceSourceMessageQueues; //!< sink message queues attached to device QMap m_audioInputs; //!< audio device index to audio input map (index -1 is default device) + QMap m_audioInputThreads; //!< audio device index to audio input threads map QMap m_audioInputInfos; //!< audio device name to audio input device info bool m_defaultOutputStarted; //!< True if the default audio output (-1) has already been started diff --git a/sdrbase/audio/audioinputdevice.cpp b/sdrbase/audio/audioinputdevice.cpp index a1ccb0d70..9d586cd54 100644 --- a/sdrbase/audio/audioinputdevice.cpp +++ b/sdrbase/audio/audioinputdevice.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) #include #else @@ -27,6 +28,10 @@ #include "audio/audiodeviceinfo.h" #include "audio/audiofifo.h" +MESSAGE_CLASS_DEFINITION(AudioInputDevice::MsgStart, Message) +MESSAGE_CLASS_DEFINITION(AudioInputDevice::MsgStop, Message) +MESSAGE_CLASS_DEFINITION(AudioInputDevice::MsgReportSampleRate, Message) + AudioInputDevice::AudioInputDevice() : m_audioInput(0), m_audioUsageCount(0), @@ -34,26 +39,28 @@ AudioInputDevice::AudioInputDevice() : m_volume(0.5f), m_audioFifos() { + connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection); } AudioInputDevice::~AudioInputDevice() { - stop(); + // stop(); - QMutexLocker mutexLocker(&m_mutex); + // QMutexLocker mutexLocker(&m_mutex); - for (std::list::iterator it = m_audioFifos.begin(); it != m_audioFifos.end(); ++it) - { - delete *it; - } + // for (std::list::iterator it = m_audioFifos.begin(); it != m_audioFifos.end(); ++it) + // { + // delete *it; + // } - m_audioFifos.clear(); + // m_audioFifos.clear(); } bool AudioInputDevice::start(int device, int rate) { - if (m_audioUsageCount == 0) - { + // if (m_audioUsageCount == 0) + // { + qDebug("AudioInputDevice::start: device: %d rate: %d thread: %p", device, rate, QThread::currentThread()); QMutexLocker mutexLocker(&m_mutex); AudioDeviceInfo devInfo; @@ -127,40 +134,52 @@ bool AudioInputDevice::start(int device, int rate) #endif m_audioInput->setVolume(m_volume); - QIODevice::open(QIODevice::ReadWrite); + QIODevice::open(QIODevice::ReadWrite | QIODevice::Unbuffered); m_audioInput->start(this); - if (m_audioInput->state() != QAudio::ActiveState) - { + if (m_audioInput->state() != QAudio::ActiveState) { qWarning("AudioInputDevice::start: cannot start"); + } else { + qDebug("AudioInputDevice::start: started buffer: %d bytes", m_audioInput->bufferSize()); } - } + // } - m_audioUsageCount++; + // m_audioUsageCount++; return true; } void AudioInputDevice::stop() { - qDebug("AudioInputDevice::stop"); - - if (m_audioUsageCount > 0) - { - m_audioUsageCount--; - - if (m_audioUsageCount == 0) - { - qDebug("AudioInputDevice::stop: effectively close QIODevice"); - QMutexLocker mutexLocker(&m_mutex); - QIODevice::close(); - - if (!m_onExit) { - delete m_audioInput; - } - } + if (!m_audioInput) { + return; } + + qDebug("AudioInputDevice::stop: thread: %p", QThread::currentThread()); + QMutexLocker mutexLocker(&m_mutex); + m_audioInput->stop(); + QIODevice::close(); + delete m_audioInput; + m_audioInput = nullptr; + + // if (m_audioUsageCount > 0) + // { + // m_audioUsageCount--; + + // if (m_audioUsageCount == 0) + // { + // qDebug("AudioInputDevice::stop: effectively close QIODevice"); + // QMutexLocker mutexLocker(&m_mutex); + // QIODevice::close(); + + // if (!m_onExit) + // { + // delete m_audioInput; + // m_audioInput = nullptr; + // } + // } + // } } void AudioInputDevice::addFifo(AudioFifo* audioFifo) @@ -222,3 +241,32 @@ void AudioInputDevice::setVolume(float volume) if (m_audioInput != nullptr) m_audioInput->setVolume(m_volume); } + +bool AudioInputDevice::handleMessage(const Message& cmd) +{ + if (MsgStart::match(cmd)) + { + MsgStart ctl = (MsgStart&) cmd; + start(ctl.getDeviceIndex(), ctl.getSampleRate()); + return true; + } + else if (MsgStop::match(cmd)) + { + stop(); + return true; + } + + return false; +} + +void AudioInputDevice::handleInputMessages() +{ + Message* message; + + while ((message = m_inputMessageQueue.pop()) != nullptr) + { + if (handleMessage(*message)) { + delete message; + } + } +} diff --git a/sdrbase/audio/audioinputdevice.h b/sdrbase/audio/audioinputdevice.h index 8f3214a39..8becaddfb 100644 --- a/sdrbase/audio/audioinputdevice.h +++ b/sdrbase/audio/audioinputdevice.h @@ -24,6 +24,8 @@ #include #include #include "export.h" +#include "util/message.h" +#include "util/messagequeue.h" #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) class QAudioSource; @@ -35,12 +37,76 @@ class AudioOutputPipe; class SDRBASE_API AudioInputDevice : public QIODevice { + Q_OBJECT public: + class MsgStart : public Message { + MESSAGE_CLASS_DECLARATION + public: + int getDeviceIndex() const { return m_deviceIndex; } + int getSampleRate() const { return m_sampleRate; } + + static MsgStart* create(int deviceIndex, int sampleRate) { + return new MsgStart(deviceIndex, sampleRate); + } + + private: + int m_deviceIndex; + int m_sampleRate; + + MsgStart(int deviceIndex, int sampleRate) : + Message(), + m_deviceIndex(deviceIndex), + m_sampleRate(sampleRate) + { } + }; + + class MsgStop : public Message { + MESSAGE_CLASS_DECLARATION + public: + static MsgStop* create() { + return new MsgStop(); + } + + private: + + MsgStop() : + Message() + { } + }; + + 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) + { } + }; + AudioInputDevice(); virtual ~AudioInputDevice(); - bool start(int device, int rate); - void stop(); + bool startDirect(int deviceIndex, int sampleRate) { + return start(deviceIndex, sampleRate); + } + void stopDirect() { + stop(); + } void addFifo(AudioFifo* audioFifo); void removeFifo(AudioFifo* audioFifo); @@ -49,6 +115,10 @@ public: uint getRate() const { return m_audioFormat.sampleRate(); } void setOnExit(bool onExit) { m_onExit = onExit; } void setVolume(float volume); + void setDeviceName(const QString& deviceName) { m_deviceName = deviceName;} + + MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + void setManagerMessageQueue(MessageQueue *messageQueue) { m_managerMessageQueue = messageQueue; } private: QRecursiveMutex m_mutex; @@ -65,12 +135,25 @@ private: std::vector m_mixBuffer; QAudioFormat m_audioFormat; + QString m_deviceName; + + MessageQueue m_inputMessageQueue; + MessageQueue *m_managerMessageQueue; //virtual bool open(OpenMode mode); virtual qint64 readData(char* data, qint64 maxLen); virtual qint64 writeData(const char* data, qint64 len); + bool handleMessage(const Message& cmd); + bool start(int deviceIndex, int sampleRate); + void stop(); friend class AudioOutputPipe; + friend class AudioInput; + friend class FCDProInput; + friend class FCDProPlusInput; + +private slots: + void handleInputMessages(); };