mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
Refactor audio out of code, better resource management
Fixes #739 and fixes #777
This commit is contained in:
parent
6c1d2bc9ac
commit
c1f2e9a71d
6
qtox.pro
6
qtox.pro
|
@ -154,7 +154,8 @@ HEADERS += src/widget/form/addfriendform.h \
|
|||
src/widget/toxsave.h \
|
||||
src/autoupdate.h \
|
||||
src/misc/serialize.h \
|
||||
src/widget/form/settings/advancedform.h
|
||||
src/widget/form/settings/advancedform.h \
|
||||
src/audio.h
|
||||
|
||||
SOURCES += \
|
||||
src/widget/form/addfriendform.cpp \
|
||||
|
@ -220,4 +221,5 @@ SOURCES += \
|
|||
src/widget/toxsave.cpp \
|
||||
src/autoupdate.cpp \
|
||||
src/misc/serialize.cpp \
|
||||
src/widget/form/settings/advancedform.cpp
|
||||
src/widget/form/settings/advancedform.cpp \
|
||||
src/audio.cpp
|
||||
|
|
112
src/audio.cpp
Normal file
112
src/audio.cpp
Normal file
|
@ -0,0 +1,112 @@
|
|||
#include "audio.h"
|
||||
#include "src/core.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
std::atomic<int> Audio::userCount{0};
|
||||
ALCdevice* Audio::alInDev{nullptr};
|
||||
ALCdevice* Audio::alOutDev{nullptr};
|
||||
ALCcontext* Audio::alContext{0};
|
||||
ALuint Audio::alMainSource{0};
|
||||
|
||||
void Audio::suscribeInput()
|
||||
{
|
||||
if (userCount++)
|
||||
if (alInDev)
|
||||
alcCaptureStart(alInDev);
|
||||
}
|
||||
|
||||
void Audio::unsuscribeInput()
|
||||
{
|
||||
if (--userCount)
|
||||
if (alInDev)
|
||||
alcCaptureStop(alInDev);
|
||||
}
|
||||
|
||||
void Audio::openInput(const QString& inDevDescr)
|
||||
{
|
||||
auto* tmp = alInDev;
|
||||
alInDev = nullptr;
|
||||
alcCaptureCloseDevice(tmp);
|
||||
int stereoFlag = av_DefaultSettings.audio_channels==1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
|
||||
if (inDevDescr.isEmpty())
|
||||
alInDev = alcCaptureOpenDevice(nullptr,av_DefaultSettings.audio_sample_rate, stereoFlag,
|
||||
(av_DefaultSettings.audio_frame_duration * av_DefaultSettings.audio_sample_rate * 4)
|
||||
/ 1000 * av_DefaultSettings.audio_channels);
|
||||
else
|
||||
alInDev = alcCaptureOpenDevice(inDevDescr.toStdString().c_str(),av_DefaultSettings.audio_sample_rate, stereoFlag,
|
||||
(av_DefaultSettings.audio_frame_duration * av_DefaultSettings.audio_sample_rate * 4)
|
||||
/ 1000 * av_DefaultSettings.audio_channels);
|
||||
if (!alInDev)
|
||||
qWarning() << "Audio: Cannot open input audio device";
|
||||
else
|
||||
qDebug() << "Audio: Opening audio input "<<inDevDescr;
|
||||
|
||||
Core::getInstance()->resetCallSources(); // Force to regen each group call's sources
|
||||
|
||||
// Restart the capture if necessary
|
||||
if (userCount.load() != 0)
|
||||
alcCaptureStart(alInDev);
|
||||
}
|
||||
|
||||
void Audio::openOutput(const QString& outDevDescr)
|
||||
{
|
||||
auto* tmp = alOutDev;
|
||||
alOutDev = nullptr;
|
||||
alcCloseDevice(tmp);
|
||||
if (outDevDescr.isEmpty())
|
||||
alOutDev = alcOpenDevice(nullptr);
|
||||
else
|
||||
alOutDev = alcOpenDevice(outDevDescr.toStdString().c_str());
|
||||
if (!alOutDev)
|
||||
{
|
||||
qWarning() << "Audio: Cannot open output audio device";
|
||||
}
|
||||
else
|
||||
{
|
||||
alcDestroyContext(alContext);
|
||||
alContext=alcCreateContext(alOutDev,nullptr);
|
||||
if (!alcMakeContextCurrent(alContext))
|
||||
{
|
||||
qWarning() << "Audio: Cannot create output audio context";
|
||||
alcCloseDevice(alOutDev);
|
||||
}
|
||||
else
|
||||
alGenSources(1, &alMainSource);
|
||||
|
||||
|
||||
qDebug() << "Audio: Opening audio output "<<outDevDescr;
|
||||
}
|
||||
|
||||
Core::getInstance()->resetCallSources(); // Force to regen each group call's sources
|
||||
}
|
||||
|
||||
void Audio::closeInput()
|
||||
{
|
||||
if (alInDev)
|
||||
alcCaptureCloseDevice(alInDev);
|
||||
|
||||
userCount = 0;
|
||||
}
|
||||
|
||||
void Audio::closeOutput()
|
||||
{
|
||||
if (alContext)
|
||||
{
|
||||
alcMakeContextCurrent(nullptr);
|
||||
alcDestroyContext(alContext);
|
||||
}
|
||||
|
||||
if (alOutDev)
|
||||
alcCloseDevice(alOutDev);
|
||||
}
|
||||
|
||||
void Audio::playMono16Sound(const QByteArray& data)
|
||||
{
|
||||
ALuint buffer;
|
||||
alGenBuffers(1, &buffer);
|
||||
alBufferData(buffer, AL_FORMAT_MONO16, data.data(), data.size(), 44100);
|
||||
alSourcei(alMainSource, AL_BUFFER, buffer);
|
||||
alSourcePlay(alMainSource);
|
||||
alDeleteBuffers(1, &buffer);
|
||||
}
|
43
src/audio.h
Normal file
43
src/audio.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
#ifndef AUDIO_H
|
||||
#define AUDIO_H
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
#include <OpenAL/al.h>
|
||||
#include <OpenAL/alc.h>
|
||||
#else
|
||||
#include <AL/al.h>
|
||||
#include <AL/alc.h>
|
||||
#endif
|
||||
|
||||
class QString;
|
||||
class QByteArray;
|
||||
|
||||
class Audio
|
||||
{
|
||||
public:
|
||||
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.
|
||||
|
||||
static void openInput(const QString& inDevDescr); ///< Open an input device, use before suscribing
|
||||
static void openOutput(const QString& outDevDescr); ///< Open an output device
|
||||
|
||||
static void closeInput(); ///< Close an input device, please don't use unless everyone's unsuscribed
|
||||
static void closeOutput(); ///< Close an output device
|
||||
|
||||
static void playMono16Sound(const QByteArray& data); ///< Play a 44100Hz mono 16bit PCM sound
|
||||
|
||||
public:
|
||||
static ALCdevice* alOutDev, *alInDev;
|
||||
static ALCcontext* alContext;
|
||||
static ALuint alMainSource;
|
||||
|
||||
private:
|
||||
Audio();
|
||||
|
||||
private:
|
||||
static std::atomic<int> userCount;
|
||||
};
|
||||
|
||||
#endif // AUDIO_H
|
107
src/core.cpp
107
src/core.cpp
|
@ -20,6 +20,7 @@
|
|||
#include "misc/settings.h"
|
||||
#include "widget/widget.h"
|
||||
#include "historykeeper.h"
|
||||
#include "src/audio.h"
|
||||
|
||||
#include <tox/tox.h>
|
||||
#include <tox/toxencryptsave.h>
|
||||
|
@ -69,6 +70,8 @@ Core::Core(Camera* cam, QThread *CoreThread, QString loadPath) :
|
|||
|
||||
for (int i=0; i<TOXAV_MAX_CALLS;i++)
|
||||
{
|
||||
calls[i].active = false;
|
||||
calls[i].alSource = 0;
|
||||
calls[i].sendAudioTimer = new QTimer();
|
||||
calls[i].sendVideoTimer = new QTimer();
|
||||
calls[i].sendAudioTimer->moveToThread(coreThread);
|
||||
|
@ -78,38 +81,9 @@ Core::Core(Camera* cam, QThread *CoreThread, QString loadPath) :
|
|||
|
||||
// OpenAL init
|
||||
QString outDevDescr = Settings::getInstance().getOutDev(); ;
|
||||
if (outDevDescr.isEmpty())
|
||||
alOutDev = alcOpenDevice(nullptr);
|
||||
else
|
||||
alOutDev = alcOpenDevice(outDevDescr.toStdString().c_str());
|
||||
if (!alOutDev)
|
||||
{
|
||||
qWarning() << "Core: Cannot open output audio device";
|
||||
}
|
||||
else
|
||||
{
|
||||
alContext=alcCreateContext(alOutDev,nullptr);
|
||||
if (!alcMakeContextCurrent(alContext))
|
||||
{
|
||||
qWarning() << "Core: Cannot create output audio context";
|
||||
alcCloseDevice(alOutDev);
|
||||
}
|
||||
else
|
||||
alGenSources(1, &alMainSource);
|
||||
}
|
||||
|
||||
Audio::openOutput(outDevDescr);
|
||||
QString inDevDescr = Settings::getInstance().getInDev();
|
||||
int stereoFlag = av_DefaultSettings.audio_channels==1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
|
||||
if (inDevDescr.isEmpty())
|
||||
alInDev = alcCaptureOpenDevice(nullptr,av_DefaultSettings.audio_sample_rate, stereoFlag,
|
||||
(av_DefaultSettings.audio_frame_duration * av_DefaultSettings.audio_sample_rate * 4)
|
||||
/ 1000 * av_DefaultSettings.audio_channels);
|
||||
else
|
||||
alInDev = alcCaptureOpenDevice(inDevDescr.toStdString().c_str(),av_DefaultSettings.audio_sample_rate, stereoFlag,
|
||||
(av_DefaultSettings.audio_frame_duration * av_DefaultSettings.audio_sample_rate * 4)
|
||||
/ 1000 * av_DefaultSettings.audio_channels);
|
||||
if (!alInDev)
|
||||
qWarning() << "Core: Cannot open input audio device";
|
||||
Audio::openInput(inDevDescr);
|
||||
}
|
||||
|
||||
Core::~Core()
|
||||
|
@ -125,15 +99,8 @@ Core::~Core()
|
|||
videobuf=nullptr;
|
||||
}
|
||||
|
||||
if (alContext)
|
||||
{
|
||||
alcMakeContextCurrent(nullptr);
|
||||
alcDestroyContext(alContext);
|
||||
}
|
||||
if (alOutDev)
|
||||
alcCloseDevice(alOutDev);
|
||||
if (alInDev)
|
||||
alcCaptureCloseDevice(alInDev);
|
||||
Audio::closeInput();
|
||||
Audio::closeOutput();
|
||||
|
||||
clearPassword(Core::ptMain);
|
||||
clearPassword(Core::ptHistory);
|
||||
|
@ -1876,64 +1843,20 @@ void Core::setNospam(uint32_t nospam)
|
|||
tox_set_nospam(tox, nospam);
|
||||
}
|
||||
|
||||
void Core::useAudioInput(const QString& inDevDescr)
|
||||
void Core::resetCallSources()
|
||||
{
|
||||
auto* tmp = alInDev;
|
||||
alInDev = nullptr;
|
||||
alcCaptureCloseDevice(tmp);
|
||||
int stereoFlag = av_DefaultSettings.audio_channels==1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
|
||||
if (inDevDescr.isEmpty())
|
||||
alInDev = alcCaptureOpenDevice(nullptr,av_DefaultSettings.audio_sample_rate, stereoFlag,
|
||||
(av_DefaultSettings.audio_frame_duration * av_DefaultSettings.audio_sample_rate * 4)
|
||||
/ 1000 * av_DefaultSettings.audio_channels);
|
||||
else
|
||||
alInDev = alcCaptureOpenDevice(inDevDescr.toStdString().c_str(),av_DefaultSettings.audio_sample_rate, stereoFlag,
|
||||
(av_DefaultSettings.audio_frame_duration * av_DefaultSettings.audio_sample_rate * 4)
|
||||
/ 1000 * av_DefaultSettings.audio_channels);
|
||||
if (!alInDev)
|
||||
qWarning() << "Core: Cannot open input audio device";
|
||||
else
|
||||
qDebug() << "Core: Opening audio input "<<inDevDescr;
|
||||
|
||||
// Force to regen each call's sources
|
||||
for (ToxGroupCall& call : groupCalls)
|
||||
call.alSources.clear();
|
||||
|
||||
// Force to restart any call's capture
|
||||
if (alInDev)
|
||||
alcCaptureStart(alInDev);
|
||||
}
|
||||
|
||||
void Core::useAudioOutput(const QString& outDevDescr)
|
||||
{
|
||||
auto* tmp = alOutDev;
|
||||
alOutDev = nullptr;
|
||||
alcCloseDevice(tmp);
|
||||
if (outDevDescr.isEmpty())
|
||||
alOutDev = alcOpenDevice(nullptr);
|
||||
else
|
||||
alOutDev = alcOpenDevice(outDevDescr.toStdString().c_str());
|
||||
if (!alOutDev)
|
||||
for (ToxCall& call : calls)
|
||||
{
|
||||
qWarning() << "Core: Cannot open output audio device";
|
||||
}
|
||||
else
|
||||
{
|
||||
alcDestroyContext(alContext);
|
||||
alContext=alcCreateContext(alOutDev,nullptr);
|
||||
if (!alcMakeContextCurrent(alContext))
|
||||
if (call.active && call.alSource)
|
||||
{
|
||||
qWarning() << "Core: Cannot create output audio context";
|
||||
alcCloseDevice(alOutDev);
|
||||
ALuint tmp = call.alSource;
|
||||
call.alSource = 0;
|
||||
alDeleteSources(1, &tmp);
|
||||
|
||||
alGenSources(1, &call.alSource);
|
||||
}
|
||||
else
|
||||
alGenSources(1, &alMainSource);
|
||||
|
||||
|
||||
qDebug() << "Core: Opening audio output "<<outDevDescr;
|
||||
}
|
||||
|
||||
// Force to regen each call's sources
|
||||
for (ToxGroupCall& call : groupCalls)
|
||||
call.alSources.clear();
|
||||
}
|
||||
|
|
10
src/core.h
10
src/core.h
|
@ -76,8 +76,7 @@ public:
|
|||
bool isPasswordSet(PasswordType passtype);
|
||||
bool isReady(); ///< Most of the API shouldn't be used until Core is ready, call start() first
|
||||
|
||||
void useAudioInput(const QString &name);
|
||||
void useAudioOutput(const QString &name);
|
||||
void resetCallSources(); ///< Forces to regenerate each call's audio sources
|
||||
|
||||
public slots:
|
||||
void start(); ///< Initializes the core, must be called before anything else
|
||||
|
@ -286,7 +285,7 @@ private:
|
|||
QList<DhtServer> dhtServerList;
|
||||
int dhtServerId;
|
||||
static QList<ToxFile> fileSendQueue, fileRecvQueue;
|
||||
static ToxCall calls[];
|
||||
static ToxCall calls[TOXAV_MAX_CALLS];
|
||||
static QHash<int, ToxGroupCall> groupCalls; // Maps group IDs to ToxGroupCalls
|
||||
QMutex fileSendMutex, messageSendMutex;
|
||||
bool ready;
|
||||
|
@ -296,12 +295,7 @@ private:
|
|||
static const int videobufsize;
|
||||
static uint8_t* videobuf;
|
||||
|
||||
static ALCdevice* alOutDev, *alInDev;
|
||||
static ALCcontext* alContext;
|
||||
|
||||
static QThread *coreThread;
|
||||
public:
|
||||
static ALuint alMainSource;
|
||||
};
|
||||
|
||||
#endif // CORE_HPP
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include "core.h"
|
||||
#include "video/camera.h"
|
||||
#include "audio.h"
|
||||
#include <QDebug>
|
||||
#include <QTimer>
|
||||
|
||||
|
@ -23,10 +24,6 @@ ToxCall Core::calls[TOXAV_MAX_CALLS];
|
|||
const int Core::videobufsize{TOXAV_MAX_VIDEO_WIDTH * TOXAV_MAX_VIDEO_HEIGHT * 4};
|
||||
uint8_t* Core::videobuf;
|
||||
|
||||
ALCdevice* Core::alOutDev, *Core::alInDev;
|
||||
ALCcontext* Core::alContext;
|
||||
ALuint Core::alMainSource;
|
||||
|
||||
bool Core::anyActiveCalls()
|
||||
{
|
||||
for (auto& call : calls)
|
||||
|
@ -53,8 +50,7 @@ void Core::prepareCall(int friendId, int callId, ToxAv* toxav, bool videoEnabled
|
|||
qWarning() << QString("Error starting call %1: toxav_prepare_transmission failed with %2").arg(callId).arg(r);
|
||||
|
||||
// Audio
|
||||
alGenSources(1, &calls[callId].alSource);
|
||||
alcCaptureStart(alInDev);
|
||||
Audio::suscribeInput();
|
||||
|
||||
// Go
|
||||
calls[callId].active = true;
|
||||
|
@ -197,7 +193,7 @@ void Core::cleanupCall(int callId)
|
|||
calls[callId].sendVideoTimer->stop();
|
||||
if (calls[callId].videoEnabled)
|
||||
Camera::getInstance()->unsubscribe();
|
||||
alcCaptureStop(alInDev);
|
||||
Audio::unsuscribeInput();
|
||||
}
|
||||
|
||||
void Core::playCallAudio(ToxAv* toxav, int32_t callId, int16_t *data, int samples, void *user_data)
|
||||
|
@ -207,6 +203,9 @@ void Core::playCallAudio(ToxAv* toxav, int32_t callId, int16_t *data, int sample
|
|||
if (!calls[callId].active)
|
||||
return;
|
||||
|
||||
if (!calls[callId].alSource)
|
||||
alGenSources(1, &calls[callId].alSource);
|
||||
|
||||
ToxAvCSettings dest;
|
||||
if(toxav_get_peer_csettings(toxav, callId, 0, &dest) == 0)
|
||||
playAudioBuffer(calls[callId].alSource, data, samples, dest.audio_channels, dest.audio_sample_rate);
|
||||
|
@ -217,7 +216,7 @@ void Core::sendCallAudio(int callId, ToxAv* toxav)
|
|||
if (!calls[callId].active)
|
||||
return;
|
||||
|
||||
if (calls[callId].muteMic || !alInDev)
|
||||
if (calls[callId].muteMic || !Audio::alInDev)
|
||||
{
|
||||
calls[callId].sendAudioTimer->start();
|
||||
return;
|
||||
|
@ -229,11 +228,11 @@ void Core::sendCallAudio(int callId, ToxAv* toxav)
|
|||
|
||||
bool frame = false;
|
||||
ALint samples;
|
||||
alcGetIntegerv(alInDev, ALC_CAPTURE_SAMPLES, sizeof(samples), &samples);
|
||||
alcGetIntegerv(Audio::alInDev, ALC_CAPTURE_SAMPLES, sizeof(samples), &samples);
|
||||
if(samples >= framesize)
|
||||
{
|
||||
memset(buf, 0, bufsize); // Avoid uninitialized values (Valgrind)
|
||||
alcCaptureSamples(alInDev, buf, framesize);
|
||||
alcCaptureSamples(Audio::alInDev, buf, framesize);
|
||||
frame = 1;
|
||||
}
|
||||
|
||||
|
@ -619,8 +618,7 @@ void Core::joinGroupCall(int groupId)
|
|||
groupCalls[groupId].codecSettings.max_video_height = TOXAV_MAX_VIDEO_HEIGHT;
|
||||
|
||||
// Audio
|
||||
//alGenSources(1, &groupCalls[groupId].alSource);
|
||||
alcCaptureStart(alInDev);
|
||||
Audio::suscribeInput();
|
||||
|
||||
// Go
|
||||
Core* core = Core::getInstance();
|
||||
|
@ -640,8 +638,8 @@ void Core::leaveGroupCall(int groupId)
|
|||
groupCalls[groupId].active = false;
|
||||
disconnect(groupCalls[groupId].sendAudioTimer,0,0,0);
|
||||
groupCalls[groupId].sendAudioTimer->stop();
|
||||
alcCaptureStop(alInDev);
|
||||
groupCalls[groupId].alSources.clear();
|
||||
Audio::unsuscribeInput();
|
||||
}
|
||||
|
||||
void Core::sendGroupCallAudio(int groupId, ToxAv* toxav)
|
||||
|
@ -649,7 +647,7 @@ void Core::sendGroupCallAudio(int groupId, ToxAv* toxav)
|
|||
if (!groupCalls[groupId].active)
|
||||
return;
|
||||
|
||||
if (groupCalls[groupId].muteMic || !alInDev)
|
||||
if (groupCalls[groupId].muteMic || !Audio::alInDev)
|
||||
{
|
||||
groupCalls[groupId].sendAudioTimer->start();
|
||||
return;
|
||||
|
@ -661,11 +659,11 @@ void Core::sendGroupCallAudio(int groupId, ToxAv* toxav)
|
|||
|
||||
bool frame = false;
|
||||
ALint samples;
|
||||
alcGetIntegerv(alInDev, ALC_CAPTURE_SAMPLES, sizeof(samples), &samples);
|
||||
alcGetIntegerv(Audio::alInDev, ALC_CAPTURE_SAMPLES, sizeof(samples), &samples);
|
||||
if(samples >= framesize)
|
||||
{
|
||||
memset(buf, 0, bufsize); // Avoid uninitialized values (Valgrind)
|
||||
alcCaptureSamples(alInDev, buf, framesize);
|
||||
alcCaptureSamples(Audio::alInDev, buf, framesize);
|
||||
frame = 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
#include "avform.h"
|
||||
#include "ui_avsettings.h"
|
||||
#include "src/misc/settings.h"
|
||||
#include "src/core.h"
|
||||
#include "src/audio.h"
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
#include <OpenAL/al.h>
|
||||
|
@ -180,11 +180,11 @@ void AVForm::getAudioOutDevices()
|
|||
void AVForm::onInDevChanged(const QString &deviceDescriptor)
|
||||
{
|
||||
Settings::getInstance().setInDev(deviceDescriptor);
|
||||
Core::getInstance()->useAudioInput(deviceDescriptor);
|
||||
Audio::openInput(deviceDescriptor);
|
||||
}
|
||||
|
||||
void AVForm::onOutDevChanged(const QString& deviceDescriptor)
|
||||
{
|
||||
Settings::getInstance().setOutDev(deviceDescriptor);
|
||||
Core::getInstance()->useAudioOutput(deviceDescriptor);
|
||||
Audio::openOutput(deviceDescriptor);
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "src/historykeeper.h"
|
||||
#include "form/inputpassworddialog.h"
|
||||
#include "src/autoupdate.h"
|
||||
#include "src/audio.h"
|
||||
#include <QMessageBox>
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
|
@ -807,11 +808,7 @@ void Widget::newMessageAlert(GenericChatroomWidget* chat)
|
|||
sndFile.close();
|
||||
}
|
||||
|
||||
ALuint buffer;
|
||||
alGenBuffers(1, &buffer);
|
||||
alBufferData(buffer, AL_FORMAT_MONO16, sndData.data(), sndData.size(), 44100);
|
||||
alSourcei(core->alMainSource, AL_BUFFER, buffer);
|
||||
alSourcePlay(core->alMainSource);
|
||||
Audio::playMono16Sound(sndData);
|
||||
}
|
||||
|
||||
void Widget::playRingtone()
|
||||
|
@ -827,11 +824,7 @@ void Widget::playRingtone()
|
|||
sndFile1.close();
|
||||
}
|
||||
|
||||
ALuint buffer;
|
||||
alGenBuffers(1, &buffer);
|
||||
alBufferData(buffer, AL_FORMAT_MONO16, sndData1.data(), sndData1.size(), 44100);
|
||||
alSourcei(core->alMainSource, AL_BUFFER, buffer);
|
||||
alSourcePlay(core->alMainSource);
|
||||
Audio::playMono16Sound(sndData1);
|
||||
}
|
||||
|
||||
void Widget::onFriendRequestReceived(const QString& userId, const QString& message)
|
||||
|
|
Loading…
Reference in New Issue
Block a user