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

Move group audio playing to Audio singletong/thread

This is a bit of a quick fix for a new bug, as but part of cleaning up the audio code and moving it to the Audio singleton
This commit is contained in:
Tux3 / Mlkj / !Lev.uXFMLA 2014-11-19 22:26:04 +01:00
parent 4d4067cf88
commit 599c246ec7
No known key found for this signature in database
GPG Key ID: 7E086DD661263264
6 changed files with 113 additions and 28 deletions

View File

@ -19,13 +19,31 @@
#include "src/core.h"
#include <QDebug>
#include <QThread>
#include <cassert>
std::atomic<int> Audio::userCount{0};
Audio* Audio::instance{nullptr};
QThread* Audio::audioThread{nullptr};
ALCdevice* Audio::alInDev{nullptr};
ALCdevice* Audio::alOutDev{nullptr};
ALCcontext* Audio::alContext{0};
ALCcontext* Audio::alContext{nullptr};
ALuint Audio::alMainSource{0};
Audio& Audio::getInstance()
{
if (!instance)
{
instance = new Audio();
audioThread = new QThread(instance);
audioThread->setObjectName("qTox Audio");
audioThread->start();
instance->moveToThread(audioThread);
}
return *instance;
}
void Audio::suscribeInput()
{
if (!userCount++ && alInDev)
@ -125,3 +143,64 @@ void Audio::playMono16Sound(const QByteArray& data)
alSourcePlay(alMainSource);
alDeleteBuffers(1, &buffer);
}
void Audio::playGroupAudioQueued(Tox*,int group, int peer, const int16_t* data,
unsigned samples, uint8_t channels, unsigned sample_rate,void*)
{
QMetaObject::invokeMethod(instance, "playGroupAudio", Qt::BlockingQueuedConnection,
Q_ARG(int,group), Q_ARG(int,peer), Q_ARG(const int16_t*,data),
Q_ARG(unsigned,samples), Q_ARG(uint8_t,channels), Q_ARG(unsigned,sample_rate));
}
void Audio::playGroupAudio(int group, int peer, const int16_t* data,
unsigned samples, uint8_t channels, unsigned sample_rate)
{
assert(QThread::currentThread() == audioThread);
ToxGroupCall& call = Core::groupCalls[group];
if (!call.active || call.muteVol)
return;
if (!call.alSources.contains(peer))
alGenSources(1, &call.alSources[peer]);
playAudioBuffer(call.alSources[peer], data, samples, channels, sample_rate);
}
void Audio::playAudioBuffer(ALuint alSource, const int16_t *data, int samples, unsigned channels, int sampleRate)
{
assert(channels == 1 || channels == 2);
ALuint bufid;
ALint processed = 0, queued = 16;
alGetSourcei(alSource, AL_BUFFERS_PROCESSED, &processed);
alGetSourcei(alSource, AL_BUFFERS_QUEUED, &queued);
alSourcei(alSource, AL_LOOPING, AL_FALSE);
if(processed)
{
ALuint bufids[processed];
alSourceUnqueueBuffers(alSource, processed, bufids);
alDeleteBuffers(processed - 1, bufids + 1);
bufid = bufids[0];
}
else if(queued < 16)
{
alGenBuffers(1, &bufid);
}
else
{
qDebug() << "Audio: Dropped frame";
return;
}
alBufferData(bufid, (channels == 1) ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16, data,
samples * 2 * channels, sampleRate);
alSourceQueueBuffers(alSource, 1, &bufid);
ALint state;
alGetSourcei(alSource, AL_SOURCE_STATE, &state);
if(state != AL_PLAYING)
alSourcePlay(alSource);
}

View File

@ -18,6 +18,8 @@
#ifndef AUDIO_H
#define AUDIO_H
#include <QObject>
#include <QHash>
#include <atomic>
#if defined(__APPLE__) && defined(__MACH__)
@ -30,10 +32,17 @@
class QString;
class QByteArray;
class QTimer;
class QThread;
struct Tox;
class Audio
class Audio : QObject
{
Q_OBJECT
public:
static Audio& getInstance(); ///< Returns the singleton's instance. Will construct on first call.
static void suscribeInput(); ///< Call when you need to capture sound from the open input device.
static void unsuscribeInput(); ///< Call once you don't need to capture on the open input device anymore.
@ -45,15 +54,28 @@ public:
static void playMono16Sound(const QByteArray& data); ///< Play a 44100Hz mono 16bit PCM sound
/// May be called from any thread, will always queue a call to playGroupAudio
/// The first and last argument are ignored, but allow direct compatibility with toxcore
static void playGroupAudioQueued(Tox*, int group, int peer, const int16_t* data,
unsigned samples, uint8_t channels, unsigned sample_rate, void*);
public slots:
/// Must be called from the audio thread, plays a group call's received audio
void playGroupAudio(int group, int peer, const int16_t* data,
unsigned samples, uint8_t channels, unsigned sample_rate);
public:
static QThread* audioThread;
static ALCdevice* alOutDev, *alInDev;
static ALCcontext* alContext;
static ALuint alMainSource;
private:
Audio();
explicit Audio()=default;
static void playAudioBuffer(ALuint alSource, const int16_t *data, int samples, unsigned channels, int sampleRate);
private:
static Audio* instance;
static std::atomic<int> userCount;
};

View File

@ -56,8 +56,7 @@ Core::Core(Camera* cam, QThread *CoreThread, QString loadPath) :
coreThread = CoreThread;
audioThread = new QThread();
audioThread->start();
Audio::getInstance();
videobuf = new uint8_t[videobufsize];
@ -1496,7 +1495,8 @@ int Core::joinGroupchat(int32_t friendnumber, uint8_t type, const uint8_t* frien
else if (type == TOX_GROUPCHAT_TYPE_AV)
{
qDebug() << QString("Trying to join AV groupchat invite sent by friend %1").arg(friendnumber);
return toxav_join_av_groupchat(tox, friendnumber, friend_group_public_key, length, playGroupAudio, const_cast<Core*>(this));
return toxav_join_av_groupchat(tox, friendnumber, friend_group_public_key, length,
&Audio::playGroupAudioQueued, const_cast<Core*>(this));
}
else
{
@ -1641,7 +1641,7 @@ void Core::createGroup(uint8_t type)
}
else if (type == TOX_GROUPCHAT_TYPE_AV)
{
emit emptyGroupCreated(toxav_add_av_groupchat(tox, playGroupAudio, this));
emit emptyGroupCreated(toxav_add_av_groupchat(tox, &Audio::playGroupAudioQueued, this));
}
else
{

View File

@ -250,8 +250,6 @@ private:
static void onAvPeerTimeout(void* toxav, int32_t call_index, void* core);
static void onAvMediaChange(void *toxav, int32_t call_index, void* core);
static void playGroupAudio(Tox* tox, int groupnumber, int friendgroupnumber, const int16_t* out_audio,
unsigned out_audio_samples, uint8_t decoder_channels, unsigned audio_sample_rate, void* userdata);
static void sendGroupCallAudio(int groupId, ToxAv* toxav);
static void prepareCall(int friendId, int callId, ToxAv *toxav, bool videoEnabled);
@ -295,7 +293,9 @@ private:
static const int videobufsize;
static uint8_t* videobuf;
static QThread *coreThread, *audioThread;
static QThread *coreThread;
friend class Audio; ///< Audio can access our calls directly to reduce latency
};
#endif // CORE_HPP

View File

@ -23,7 +23,6 @@
ToxCall Core::calls[TOXAV_MAX_CALLS];
const int Core::videobufsize{TOXAV_MAX_VIDEO_WIDTH * TOXAV_MAX_VIDEO_HEIGHT * 4};
uint8_t* Core::videobuf;
QThread* Core::audioThread{nullptr};
bool Core::anyActiveCalls()
{
@ -590,22 +589,6 @@ VideoSource *Core::getVideoSourceFromCall(int callNumber)
return &calls[callNumber].videoSource;
}
void Core::playGroupAudio(Tox* /*tox*/, int groupnumber, int friendgroupnumber, const int16_t* out_audio,
unsigned out_audio_samples, uint8_t decoder_channels, unsigned audio_sample_rate, void* /*userdata*/)
{
if (!groupCalls[groupnumber].active)
return;
if (groupCalls[groupnumber].muteVol)
return;
if (!groupCalls[groupnumber].alSources.contains(friendgroupnumber))
alGenSources(1, &groupCalls[groupnumber].alSources[friendgroupnumber]);
playAudioBuffer(groupCalls[groupnumber].alSources[friendgroupnumber], out_audio,
out_audio_samples, decoder_channels, audio_sample_rate);
}
void Core::joinGroupCall(int groupId)
{
qDebug() << QString("Core: Joining group call %1").arg(groupId);
@ -631,7 +614,6 @@ void Core::joinGroupCall(int groupId)
groupCalls[groupId].sendAudioTimer->setSingleShot(true);
connect(groupCalls[groupId].sendAudioTimer, &QTimer::timeout, [=](){sendGroupCallAudio(groupId,toxav);});
groupCalls[groupId].sendAudioTimer->start();
groupCalls[groupId].sendAudioTimer->moveToThread(audioThread);
}
void Core::leaveGroupCall(int groupId)

View File

@ -187,6 +187,7 @@ void Widget::init()
qRegisterMetaType<vpx_image>("vpx_image");
qRegisterMetaType<uint8_t>("uint8_t");
qRegisterMetaType<uint16_t>("uint16_t");
qRegisterMetaType<const int16_t*>("const int16_t*");
qRegisterMetaType<int32_t>("int32_t");
qRegisterMetaType<int64_t>("int64_t");
qRegisterMetaType<QPixmap>("QPixmap");
@ -196,6 +197,7 @@ void Widget::init()
QString profilePath = detectProfile();
coreThread = new QThread(this);
coreThread->setObjectName("qTox Core");
core = new Core(Camera::getInstance(), coreThread, profilePath);
core->moveToThread(coreThread);
connect(coreThread, &QThread::started, core, &Core::start);