From 8be80bb5ea07e65b05f2f056f125f5e4985c548b Mon Sep 17 00:00:00 2001 From: Alexandr Kutuzov Date: Mon, 14 Jul 2014 22:16:44 +0900 Subject: [PATCH] audio fully working --- audioinputproxy.cpp | 22 +++++++++++------ audioinputproxy.h | 10 +++++--- audiooutputproxy.cpp | 30 ++++++++++------------- audiooutputproxy.h | 3 ++- core.cpp | 58 +++++++++++++++++++++++--------------------- core.h | 1 - 6 files changed, 66 insertions(+), 58 deletions(-) diff --git a/audioinputproxy.cpp b/audioinputproxy.cpp index c43446d4c..373cfa92a 100644 --- a/audioinputproxy.cpp +++ b/audioinputproxy.cpp @@ -7,9 +7,10 @@ AudioInputProxy::AudioInputProxy(QObject *parent) : QIODevice(parent), callback(nullptr), - ring_buffer(new MemRing(RING_SIZE)) + ring_buffer(new MemRing(RING_SIZE)) { - open(QIODevice::ReadWrite); + open(QIODevice::ReadWrite | QIODevice::Unbuffered); + qDebug() << "AudioInputProxy::AudioInputProxy"; } AudioInputProxy::~AudioInputProxy() @@ -18,25 +19,32 @@ AudioInputProxy::~AudioInputProxy() delete ring_buffer; ring_buffer = 0; } + close(); + qDebug() << "AudioInputProxy::~AudioInputProxy"; } qint64 AudioInputProxy::readData(char *data, qint64 len) { - qDebug() << "AudioInputProxy::readData" << len; - return ring_buffer->pull(data, len); + qDebug() << "AudioInputProxy::read" << len; + return ring_buffer->pull((int16_t*)data, len/2)*2; } qint64 AudioInputProxy::writeData(const char* data, qint64 len) { - qDebug() << "AudioInputProxy::writeData" << len; - ring_buffer->push((char*)data, len); + qDebug() << "AudioInputProxy::write" << len; + auto ret = ring_buffer->push((int16_t*)data, len/2)*2; if (callback != nullptr) { callback(); } - return len; + return ret; } qint64 AudioInputProxy::bytesAvailable() const { return ring_buffer->readSpace() + QIODevice::bytesAvailable(); } + +bool AudioInputProxy::isSequential() const +{ + return true; +} diff --git a/audioinputproxy.h b/audioinputproxy.h index 40fe2f72d..20c597eed 100644 --- a/audioinputproxy.h +++ b/audioinputproxy.h @@ -13,13 +13,15 @@ public: virtual ~AudioInputProxy(); std::function< void() > callback; - - qint64 readData(char *data, qint64 maxlen); - qint64 writeData(const char *data, qint64 len); qint64 bytesAvailable() const; +protected: + qint64 readData(char *data, qint64 maxlen); + qint64 writeData(const char *data, qint64 len); + bool isSequential() const; + private: - MemRing *ring_buffer; + MemRing *ring_buffer; }; #endif // AUDIOINPUTPROXY_H diff --git a/audiooutputproxy.cpp b/audiooutputproxy.cpp index e4d9289a9..18fffe116 100644 --- a/audiooutputproxy.cpp +++ b/audiooutputproxy.cpp @@ -6,9 +6,10 @@ AudioOutputProxy::AudioOutputProxy(QObject *parent) : QIODevice(parent), - ring_buffer(new MemRing(RING_SIZE)) + ring_buffer(new MemRing(RING_SIZE)) { - open(QIODevice::ReadWrite); + open(QIODevice::ReadWrite | QIODevice::Unbuffered); + qDebug() << "AudioOutputProxy::AudioOutputProxy"; } AudioOutputProxy::~AudioOutputProxy() @@ -17,33 +18,28 @@ AudioOutputProxy::~AudioOutputProxy() delete ring_buffer; ring_buffer = 0; } - close(); + qDebug() << "AudioOutputProxy::~AudioOutputProxy"; } qint64 AudioOutputProxy::readData(char *data, qint64 len) { - qDebug() << "AudioOutputProxy::readData" << len; - - size_t ret = ring_buffer->pull(data, len); - if (ret < (size_t)len) { - memset(data + ret, 0, len-ret); - } - - return len; // device will be closed if we will return != len + qDebug() << "AudioOutputProxy::read" << len; + return ring_buffer->pull((int16_t*)data, len/2)*2; } qint64 AudioOutputProxy::writeData(const char* data, qint64 len) { - qDebug() << "AudioOutputProxy::writeData" << len; - if (len > RING_SIZE/8) { - len = RING_SIZE/8; - } - - return ring_buffer->push((char*)data, len); +// qDebug() << "AudioOutputProxy::write" << len; + return ring_buffer->push((int16_t*)data, len/2)*2; } qint64 AudioOutputProxy::bytesAvailable() const { return ring_buffer->readSpace() + QIODevice::bytesAvailable(); } + +bool AudioOutputProxy::isSequential() const +{ + return true; +} diff --git a/audiooutputproxy.h b/audiooutputproxy.h index b1283761a..24536d1c5 100644 --- a/audiooutputproxy.h +++ b/audiooutputproxy.h @@ -15,9 +15,10 @@ protected: qint64 readData(char *data, qint64 maxlen); qint64 writeData(const char *data, qint64 len); qint64 bytesAvailable() const; + bool isSequential() const; private: - MemRing *ring_buffer; + MemRing *ring_buffer; }; #endif // AUDIOOUTPUTPROXY_H diff --git a/core.cpp b/core.cpp index 0c3ff200b..510aaa43b 100644 --- a/core.cpp +++ b/core.cpp @@ -1242,13 +1242,9 @@ void Core::prepareCall(int friendId, int callId, ToxAv* toxav, bool videoEnabled format.setCodec("audio/pcm"); format.setByteOrder(QAudioFormat::LittleEndian); format.setSampleType(QAudioFormat::SignedInt); - if (!QAudioDeviceInfo::defaultOutputDevice().isFormatSupported(format)) - { - calls[callId].audioOutput = nullptr; - qWarning() << "Core: Raw audio format not supported by output backend, cannot play audio."; - } - else if (calls[callId].audioOutput==nullptr) // TODO: shouldn't it be undefined behaviour? + if (QAudioDeviceInfo::defaultOutputDevice().isFormatSupported(format)) { + qDebug() << "Core: opening output device"; calls[callId].audioOutput = new QAudioOutput(format); calls[callId].audioOutputProxy = new AudioOutputProxy(); // TODO: init with proper parent calls[callId].audioOutput->start(calls[callId].audioOutputProxy); @@ -1257,16 +1253,14 @@ void Core::prepareCall(int friendId, int callId, ToxAv* toxav, bool videoEnabled { qWarning() << QString("Core: Error %1 when starting audio output").arg(error); } + } else { + qFatal("Core: Raw audio format not supported by output backend, cannot play audio."); } // Start input - if (!QAudioDeviceInfo::defaultInputDevice().isFormatSupported(format)) - { - calls[callId].audioInput = nullptr; - qWarning() << "Default input format not supported, cannot record audio"; - } - else if (calls[callId].audioInput==nullptr) // TODO: shouldn't it be undefined behaviour? + if (QAudioDeviceInfo::defaultInputDevice().isFormatSupported(format)) { + qDebug() << "Core: opening input device"; calls[callId].audioInput = new QAudioInput(format); calls[callId].audioInputProxy = new AudioInputProxy(); // TODO: init with proper parent calls[callId].audioInputProxy->callback = [=]() { Core::sendCallAudio(callId, toxav); }; @@ -1276,6 +1270,8 @@ void Core::prepareCall(int friendId, int callId, ToxAv* toxav, bool videoEnabled { qWarning() << QString("Core: Error %1 when starting audio input").arg(error); } + } else { + qFatal("Default input format not supported, cannot record audio"); } // Go @@ -1299,15 +1295,21 @@ void Core::cleanupCall(int callId) if (calls[callId].audioOutput != nullptr) { calls[callId].audioOutput->stop(); + delete calls[callId].audioOutput; + calls[callId].audioOutput = nullptr; } if (calls[callId].audioInput != nullptr) { calls[callId].audioInput->stop(); + delete calls[callId].audioInput; + calls[callId].audioInput = nullptr; } if (calls[callId].videoEnabled) Widget::getInstance()->getCamera()->unsuscribe(); + calls[callId].audioInputProxy->deleteLater(); calls[callId].audioInputProxy = nullptr; // TODO: test that harakiri here goes well + calls[callId].audioOutputProxy->deleteLater(); calls[callId].audioOutputProxy = nullptr; // and here too calls[callId].framesize = 0; delete [] calls[callId].audio_packet_samples; calls[callId].audio_packet_samples = nullptr; @@ -1316,26 +1318,24 @@ void Core::cleanupCall(int callId) void Core::playCallAudio(ToxAv*, int32_t callId, int16_t *data, int length) { - qDebug() << "playCallAudio callback" << calls[callId].active; if (!calls[callId].active) return; + calls[callId].audioOutputProxy->write((char*)data, length*2); + + // TODO: we can subscribes int state = calls[callId].audioOutput->state(); - if (state == QAudio::ActiveState) { // TODO: check if deadlock possible. - qint64 written = 0; - while (written != length*2) { - written += calls[callId].audioOutputProxy->write((char*)data+written, length*2-written); - } + if (state == QAudio::ActiveState) { + // everything is fine + } else if (state == QAudio::SuspendedState) { + calls[callId].audioOutput->resume(); + qWarning()<< "Core::playCallAudio() audioOutput state is suspended"; + } else if (state == QAudio::IdleState) { +// qWarning() << "Core::playCallAudio() audioOutput state is idle"; + } else if (state == QAudio::StoppedState) { + qWarning() << "Core::playCallAudio() audioOutput state is stopped"; } else { - if (state == QAudio::SuspendedState) { // TODO: we can subscribe - qWarning()<< "Core::playCallAudio() audioOutput state is suspended"; - } else if (state == QAudio::StoppedState) { - qWarning() << "Core::playCallAudio() audioOutput state is stopped"; - } else if (state == QAudio::IdleState) { - qWarning() << "Core::playCallAudio() audioOutput state is idle"; - } else { - qWarning() << "Core::playCallAudio() audioOutput state is unknown: " << state; - } + qWarning() << "Core::playCallAudio() audioOutput state is unknown: " << state; } int error = calls[callId].audioOutput->error(); // TODO: we can subscribe @@ -1346,7 +1346,7 @@ void Core::playCallAudio(ToxAv*, int32_t callId, int16_t *data, int length) } else if (error == QAudio::IOError) { qWarning() << "Core::playCallAudio() audioOutput IOError"; } else if (error == QAudio::UnderrunError) { - qWarning() << "Core::playCallAudio() audioOutput UnderrunError"; +// qWarning() << "Core::playCallAudio() audioOutput UnderrunError"; } else if (error == QAudio::FatalError) { qWarning() << "Core::playCallAudio() audioOutput FatalError"; } else { @@ -1365,6 +1365,8 @@ void Core::sendCallAudio(int callId, ToxAv* toxav) return; } + calls[callId].audioInputProxy->read(calls[callId].audio_packet_samples, calls[callId].framesize*2); + int result = toxav_prepare_audio_frame(toxav, callId, (uint8_t*)calls[callId].audio_packet_data, calls[callId].framesize*2, diff --git a/core.h b/core.h index f01b47939..7639eb42c 100644 --- a/core.h +++ b/core.h @@ -101,7 +101,6 @@ public: AudioOutputProxy *audioOutputProxy; QAudioOutput* audioOutput; QAudioInput* audioInput; - QIODevice* audioInputDevice; ToxAvCodecSettings codecSettings; QTimer *sendVideoTimer; int callId;