mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
feat(audio): make echo cancellation work and improve some minor stuff
This commit is contained in:
parent
9c603e8654
commit
5d60f09df4
|
@ -100,7 +100,7 @@ public:
|
||||||
static constexpr uint32_t AUDIO_FRAME_DURATION = 20;
|
static constexpr uint32_t AUDIO_FRAME_DURATION = 20;
|
||||||
static constexpr uint32_t AUDIO_FRAME_SAMPLE_COUNT =
|
static constexpr uint32_t AUDIO_FRAME_SAMPLE_COUNT =
|
||||||
AUDIO_FRAME_DURATION * AUDIO_SAMPLE_RATE / 1000;
|
AUDIO_FRAME_DURATION * AUDIO_SAMPLE_RATE / 1000;
|
||||||
static constexpr uint32_t AUDIO_CHANNELS = 2;
|
static constexpr uint32_t AUDIO_CHANNELS = 1;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void frameAvailable(const int16_t* pcm, size_t sample_count, uint8_t channels,
|
void frameAvailable(const int16_t* pcm, size_t sample_count, uint8_t channels,
|
||||||
|
|
|
@ -316,7 +316,7 @@ bool OpenAL2::initOutput(const QString& deviceName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for the needed extensions for echo cancelation
|
// check for the needed extensions for echo cancelation
|
||||||
if (echoCancelSupported = (alcIsExtensionPresent(NULL, "ALC_SOFT_loopback") == AL_TRUE)) {
|
if (echoCancelSupported = (alcIsExtensionPresent(alOutDev, "ALC_SOFT_loopback") == AL_TRUE)) {
|
||||||
qDebug() << "Device supports loopback";
|
qDebug() << "Device supports loopback";
|
||||||
}
|
}
|
||||||
if (alIsExtensionPresent("AL_SOFT_source_latency") == AL_TRUE) {
|
if (alIsExtensionPresent("AL_SOFT_source_latency") == AL_TRUE) {
|
||||||
|
@ -540,17 +540,10 @@ void OpenAL2::playMono16SoundCleanup()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Called on the captureTimer events to capture audio
|
* @brief Handle audio output
|
||||||
*/
|
*/
|
||||||
void OpenAL2::doAudio()
|
void OpenAL2::doOutput()
|
||||||
{
|
{
|
||||||
QMutexLocker lock(&audioLock);
|
|
||||||
|
|
||||||
static int outBufcnt = 0;
|
|
||||||
static double outLatency = 0;
|
|
||||||
|
|
||||||
// output section
|
|
||||||
if(echoCancelSupported && outputInitialized) {
|
|
||||||
alcMakeContextCurrent(alOutContext);
|
alcMakeContextCurrent(alOutContext);
|
||||||
ALuint bufids[PROXY_BUFFER_COUNT];
|
ALuint bufids[PROXY_BUFFER_COUNT];
|
||||||
ALint processed = 0, queued = 0;
|
ALint processed = 0, queued = 0;
|
||||||
|
@ -572,10 +565,11 @@ void OpenAL2::doAudio()
|
||||||
LPALGETSOURCEDVSOFT alGetSourcedvSOFT =
|
LPALGETSOURCEDVSOFT alGetSourcedvSOFT =
|
||||||
reinterpret_cast<LPALGETSOURCEDVSOFT> (alcGetProcAddress(alOutDev, "alGetSourcedvSOFT"));
|
reinterpret_cast<LPALGETSOURCEDVSOFT> (alcGetProcAddress(alOutDev, "alGetSourcedvSOFT"));
|
||||||
ALdouble latency[2] = {0};
|
ALdouble latency[2] = {0};
|
||||||
|
if(alGetSourcedvSOFT) {
|
||||||
alGetSourcedvSOFT(alProxySource, AL_SEC_OFFSET_LATENCY_SOFT, latency);
|
alGetSourcedvSOFT(alProxySource, AL_SEC_OFFSET_LATENCY_SOFT, latency);
|
||||||
checkAlError();
|
checkAlError();
|
||||||
|
}
|
||||||
//qDebug() << "Playback latency: " << latency[1] << "offset: " << latency[0];
|
//qDebug() << "Playback latency: " << latency[1] << "offset: " << latency[0];
|
||||||
outLatency = latency[1];
|
|
||||||
|
|
||||||
ALshort outBuf[AUDIO_FRAME_SAMPLE_COUNT * AUDIO_CHANNELS] = {0};
|
ALshort outBuf[AUDIO_FRAME_SAMPLE_COUNT * AUDIO_CHANNELS] = {0};
|
||||||
alcMakeContextCurrent(alProxyContext);
|
alcMakeContextCurrent(alProxyContext);
|
||||||
|
@ -587,18 +581,18 @@ void OpenAL2::doAudio()
|
||||||
alBufferData(bufids[0], (AUDIO_CHANNELS == 1) ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16, outBuf,
|
alBufferData(bufids[0], (AUDIO_CHANNELS == 1) ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16, outBuf,
|
||||||
AUDIO_FRAME_SAMPLE_COUNT * 2 * AUDIO_CHANNELS, AUDIO_SAMPLE_RATE);
|
AUDIO_FRAME_SAMPLE_COUNT * 2 * AUDIO_CHANNELS, AUDIO_SAMPLE_RATE);
|
||||||
alSourceQueueBuffers(alProxySource, 1, bufids);
|
alSourceQueueBuffers(alProxySource, 1, bufids);
|
||||||
++outBufcnt;
|
|
||||||
|
|
||||||
// initialize echo canceler if supported
|
// initialize echo canceler if supported
|
||||||
if(!filterer) {
|
if(!filterer) {
|
||||||
filterer = new_filter_audio(AUDIO_SAMPLE_RATE);
|
filterer = new_filter_audio(AUDIO_SAMPLE_RATE);
|
||||||
int16_t filterLatency = outLatency*1000 + AUDIO_FRAME_DURATION;
|
int16_t filterLatency = latency[1]*1000*2 + AUDIO_FRAME_DURATION;
|
||||||
qDebug() << "Setting filter delay to: " << filterLatency << "ms";
|
qDebug() << "Setting filter delay to: " << filterLatency << "ms";
|
||||||
set_echo_delay_ms(filterer, filterLatency);
|
set_echo_delay_ms(filterer, filterLatency);
|
||||||
|
enable_disable_filters(filterer, 1, 1, 1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// do echo cancel
|
// do echo cancel
|
||||||
pass_audio_output(filterer, outBuf, AUDIO_FRAME_SAMPLE_COUNT);
|
int retVal = pass_audio_output(filterer, outBuf, AUDIO_FRAME_SAMPLE_COUNT);
|
||||||
|
|
||||||
ALint state;
|
ALint state;
|
||||||
alGetSourcei(alProxySource, AL_SOURCE_STATE, &state);
|
alGetSourcei(alProxySource, AL_SOURCE_STATE, &state);
|
||||||
|
@ -608,30 +602,27 @@ void OpenAL2::doAudio()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// input section
|
/**
|
||||||
|
* @brief handles recording of audio frames
|
||||||
if (!alInDev || !inSubscriptions)
|
*/
|
||||||
return;
|
void OpenAL2::doInput()
|
||||||
|
{
|
||||||
ALint curSamples = 0;
|
ALint curSamples = 0;
|
||||||
alcGetIntegerv(alInDev, ALC_CAPTURE_SAMPLES, sizeof(curSamples), &curSamples);
|
alcGetIntegerv(alInDev, ALC_CAPTURE_SAMPLES, sizeof(curSamples), &curSamples);
|
||||||
if (curSamples < AUDIO_FRAME_SAMPLE_COUNT)
|
if (curSamples < AUDIO_FRAME_SAMPLE_COUNT) {
|
||||||
return;
|
return;
|
||||||
// check for dropped buffers in echo cancel
|
|
||||||
if(outBufcnt > 1) {
|
|
||||||
qDebug() << "Echo cancel frame dropped";
|
|
||||||
}
|
}
|
||||||
outBufcnt = 0;
|
|
||||||
|
|
||||||
int16_t buf[AUDIO_FRAME_SAMPLE_COUNT * AUDIO_CHANNELS];
|
int16_t buf[AUDIO_FRAME_SAMPLE_COUNT * AUDIO_CHANNELS];
|
||||||
alcCaptureSamples(alInDev, buf, AUDIO_FRAME_SAMPLE_COUNT);
|
alcCaptureSamples(alInDev, buf, AUDIO_FRAME_SAMPLE_COUNT);
|
||||||
|
|
||||||
|
int retVal = 0;
|
||||||
if(echoCancelSupported && filterer) {
|
if(echoCancelSupported && filterer) {
|
||||||
filter_audio(filterer, buf, AUDIO_FRAME_SAMPLE_COUNT);
|
retVal = filter_audio(filterer, buf, AUDIO_FRAME_SAMPLE_COUNT);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (quint32 i = 0; i < AUDIO_FRAME_SAMPLE_COUNT * AUDIO_CHANNELS; ++i) {
|
|
||||||
// gain amplification with clipping to 16-bit boundaries
|
// gain amplification with clipping to 16-bit boundaries
|
||||||
|
for (quint32 i = 0; i < AUDIO_FRAME_SAMPLE_COUNT * AUDIO_CHANNELS; ++i) {
|
||||||
int ampPCM =
|
int ampPCM =
|
||||||
qBound<int>(std::numeric_limits<int16_t>::min(), qRound(buf[i] * inputGainFactor()),
|
qBound<int>(std::numeric_limits<int16_t>::min(), qRound(buf[i] * inputGainFactor()),
|
||||||
std::numeric_limits<int16_t>::max());
|
std::numeric_limits<int16_t>::max());
|
||||||
|
@ -642,6 +633,27 @@ void OpenAL2::doAudio()
|
||||||
emit Audio::frameAvailable(buf, AUDIO_FRAME_SAMPLE_COUNT, AUDIO_CHANNELS, AUDIO_SAMPLE_RATE);
|
emit Audio::frameAvailable(buf, AUDIO_FRAME_SAMPLE_COUNT, AUDIO_CHANNELS, AUDIO_SAMPLE_RATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Called on the captureTimer events to capture audio
|
||||||
|
*/
|
||||||
|
void OpenAL2::doAudio()
|
||||||
|
{
|
||||||
|
QMutexLocker lock(&audioLock);
|
||||||
|
|
||||||
|
// output section
|
||||||
|
if(echoCancelSupported && outputInitialized && !peerSources.isEmpty()) {
|
||||||
|
doOutput();
|
||||||
|
} else {
|
||||||
|
kill_filter_audio(filterer);
|
||||||
|
filterer = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// input section
|
||||||
|
if (alInDev && inSubscriptions) {
|
||||||
|
doInput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns true if the output device is open
|
* @brief Returns true if the output device is open
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -106,6 +106,8 @@ private:
|
||||||
void playMono16SoundCleanup();
|
void playMono16SoundCleanup();
|
||||||
void doAudio();
|
void doAudio();
|
||||||
qreal inputGainFactor() const;
|
qreal inputGainFactor() const;
|
||||||
|
void doInput();
|
||||||
|
void doOutput();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QThread* audioThread;
|
QThread* audioThread;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user