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:
parent
9ae4a0a79c
commit
8be80bb5ea
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
58
core.cpp
58
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,
|
||||
|
|
Loading…
Reference in New Issue
Block a user