mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-11-25 09:18:54 -05:00
Run audio in on its own thread. For #1731
This commit is contained in:
parent
9a45a29ce2
commit
e51e8c23b2
@ -102,18 +102,32 @@ AudioDeviceManager::AudioDeviceManager()
|
||||
|
||||
AudioDeviceManager::~AudioDeviceManager()
|
||||
{
|
||||
QMap<int, AudioOutputDevice*>::iterator ait = m_audioOutputs.begin();
|
||||
QMap<int, AudioOutputDevice*>::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<int, QThread*>::iterator it = m_audioOutputThreads.begin();
|
||||
QMap<int, QThread*>::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<int, AudioInputDevice*>::iterator aiit = m_audioInputs.begin();
|
||||
|
||||
for (; aiit != m_audioInputs.end(); ++aiit) {
|
||||
(*aiit)->getInputMessageQueue()->push(AudioInputDevice::MsgStop::create());
|
||||
}
|
||||
|
||||
QMap<int, QThread*>::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<MessageQueue *>::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<MessageQueue *>::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;
|
||||
}
|
||||
|
@ -146,6 +146,7 @@ private:
|
||||
QMap<AudioFifo*, MessageQueue*> m_audioFifoToSourceMessageQueues; //!< audio source FIFO to attached source message queue
|
||||
QMap<int, QList<MessageQueue*> > m_inputDeviceSourceMessageQueues; //!< sink message queues attached to device
|
||||
QMap<int, AudioInputDevice*> m_audioInputs; //!< audio device index to audio input map (index -1 is default device)
|
||||
QMap<int, QThread*> m_audioInputThreads; //!< audio device index to audio input threads map
|
||||
QMap<QString, InputDeviceInfo> m_audioInputInfos; //!< audio device name to audio input device info
|
||||
|
||||
bool m_defaultOutputStarted; //!< True if the default audio output (-1) has already been started
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <string.h>
|
||||
#include <QDebug>
|
||||
#include <QAudioFormat>
|
||||
#include <QThread>
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
#include <QAudioSource>
|
||||
#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<AudioFifo*>::iterator it = m_audioFifos.begin(); it != m_audioFifos.end(); ++it)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
// for (std::list<AudioFifo*>::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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,8 @@
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#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<qint32> 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();
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user