1
0
mirror of https://github.com/qTox/qTox.git synced 2024-03-22 14:00:36 +08:00

audio fully working

This commit is contained in:
Alexandr Kutuzov 2014-07-14 22:16:44 +09:00
parent 9ae4a0a79c
commit 8be80bb5ea
6 changed files with 66 additions and 58 deletions

View File

@ -7,9 +7,10 @@
AudioInputProxy::AudioInputProxy(QObject *parent) :
QIODevice(parent),
callback(nullptr),
ring_buffer(new MemRing<char>(RING_SIZE))
ring_buffer(new MemRing<int16_t>(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;
}

View File

@ -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<char> *ring_buffer;
MemRing<int16_t> *ring_buffer;
};
#endif // AUDIOINPUTPROXY_H

View File

@ -6,9 +6,10 @@
AudioOutputProxy::AudioOutputProxy(QObject *parent) :
QIODevice(parent),
ring_buffer(new MemRing<char>(RING_SIZE))
ring_buffer(new MemRing<int16_t>(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;
}

View File

@ -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<char> *ring_buffer;
MemRing<int16_t> *ring_buffer;
};
#endif // AUDIOOUTPUTPROXY_H

View File

@ -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,

1
core.h
View File

@ -101,7 +101,6 @@ public:
AudioOutputProxy *audioOutputProxy;
QAudioOutput* audioOutput;
QAudioInput* audioInput;
QIODevice* audioInputDevice;
ToxAvCodecSettings codecSettings;
QTimer *sendVideoTimer;
int callId;