mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
Add experimental echo cancellation to qTox
It compiles with modified OpenAL (unchanged logic otherwise), but effectiveness needs testing (like uTox)
This commit is contained in:
parent
1c3bcd000c
commit
15917d1a01
|
@ -333,3 +333,23 @@ bool Audio::tryCaptureSamples(uint8_t* buf, int framesize)
|
||||||
alcCaptureSamples(Audio::alInDev, buf, framesize);
|
alcCaptureSamples(Audio::alInDev, buf, framesize);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef QTOX_FILTER_AUDIO
|
||||||
|
#include "audiofilterer.h"
|
||||||
|
#include <AL/alext.h>
|
||||||
|
|
||||||
|
void Audio::getEchoesToFilter(AudioFilterer* filterer, int framesize)
|
||||||
|
{
|
||||||
|
#ifdef ALC_LOOPBACK_CAPTURE_SAMPLES
|
||||||
|
ALint samples;
|
||||||
|
alcGetIntegerv(Audio::alOutDev, ALC_LOOPBACK_CAPTURE_SAMPLES, sizeof(samples), &samples);
|
||||||
|
if (samples >= framesize)
|
||||||
|
{
|
||||||
|
int16_t buf[framesize];
|
||||||
|
alcCaptureSamplesLoopback(Audio::alOutDev, buf, framesize);
|
||||||
|
filterer->passAudioOutput(buf, framesize);
|
||||||
|
filterer->setEchoDelayMs(5); // This 5ms is configurable I believe
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -36,6 +36,7 @@ class QTimer;
|
||||||
class QThread;
|
class QThread;
|
||||||
class QMutex;
|
class QMutex;
|
||||||
struct Tox;
|
struct Tox;
|
||||||
|
class AudioFilterer;
|
||||||
|
|
||||||
class Audio : QObject
|
class Audio : QObject
|
||||||
{
|
{
|
||||||
|
@ -64,6 +65,11 @@ public:
|
||||||
static void playGroupAudioQueued(Tox*, int group, int peer, const int16_t* data,
|
static void playGroupAudioQueued(Tox*, int group, int peer, const int16_t* data,
|
||||||
unsigned samples, uint8_t channels, unsigned sample_rate, void*);
|
unsigned samples, uint8_t channels, unsigned sample_rate, void*);
|
||||||
|
|
||||||
|
#ifdef QTOX_FILTER_AUDIO
|
||||||
|
static void getEchoesToFilter(AudioFilterer* filter, int framesize);
|
||||||
|
// is a null op #ifndef ALC_LOOPBACK_CAPTURE_SAMPLES
|
||||||
|
#endif
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
/// Must be called from the audio thread, plays a group call's received audio
|
/// Must be called from the audio thread, plays a group call's received audio
|
||||||
void playGroupAudio(int group, int peer, const int16_t* data,
|
void playGroupAudio(int group, int peer, const int16_t* data,
|
||||||
|
|
|
@ -35,15 +35,28 @@ void AudioFilterer::closeFilter()
|
||||||
filter = nullptr;
|
filter = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AudioFilterer::filterAudio(int16_t* data, int framesize)
|
||||||
void AudioFilterer::filterAudio(int16_t* data, int framesize)
|
|
||||||
{
|
{
|
||||||
if (!filter)
|
return filter && 0 == filter_audio(filter, (int16_t*) data, framesize);
|
||||||
return;
|
|
||||||
|
|
||||||
filter_audio(filter, (int16_t*) data, framesize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Enable/disable filters. 1 to enable, 0 to disable. */
|
||||||
|
bool AudioFilterer::enableDisableFilters(int echo, int noise, int gain)
|
||||||
|
{
|
||||||
|
return filter && 0 == enable_disable_filters(filter, echo, noise, gain);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Give the audio output from your software to this function so it knows what echo to cancel from the frame */
|
||||||
|
bool AudioFilterer::passAudioOutput(const int16_t *data, int samples)
|
||||||
|
{
|
||||||
|
return filter && 0 == pass_audio_output(filter, data, samples);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tell the echo canceller how much time in ms it takes for audio to be played and recorded back after. */
|
||||||
|
bool AudioFilterer::setEchoDelayMs(int16_t msInSndCardBuf)
|
||||||
|
{
|
||||||
|
return filter && 0 == set_echo_delay_ms(filter, msInSndCardBuf);
|
||||||
|
}
|
||||||
|
|
||||||
AudioFilterer::~AudioFilterer()
|
AudioFilterer::~AudioFilterer()
|
||||||
{
|
{
|
||||||
|
|
|
@ -28,11 +28,20 @@ class AudioFilterer
|
||||||
public:
|
public:
|
||||||
explicit AudioFilterer() = default;
|
explicit AudioFilterer() = default;
|
||||||
~AudioFilterer();
|
~AudioFilterer();
|
||||||
|
|
||||||
void startFilter(unsigned int fs);
|
void startFilter(unsigned int fs);
|
||||||
void filterAudio(int16_t* data, int framesize);
|
|
||||||
void closeFilter();
|
void closeFilter();
|
||||||
|
|
||||||
|
/* Enable/disable filters. 1 to enable, 0 to disable. */
|
||||||
|
bool enableDisableFilters(int echo, int noise, int gain);
|
||||||
|
|
||||||
|
bool filterAudio(int16_t* data, int samples);
|
||||||
|
|
||||||
|
/* Give the audio output from your software to this function so it knows what echo to cancel from the frame */
|
||||||
|
bool passAudioOutput(const int16_t *data, int samples);
|
||||||
|
|
||||||
|
/* Tell the echo canceller how much time in ms it takes for audio to be played and recorded back after. */
|
||||||
|
bool setEchoDelayMs(int16_t msInSndCardBuf);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Filter_Audio* filter{nullptr};
|
struct Filter_Audio* filter{nullptr};
|
||||||
};
|
};
|
||||||
|
|
|
@ -258,7 +258,12 @@ void Core::sendCallAudio(int callId, ToxAv* toxav)
|
||||||
{
|
{
|
||||||
#ifdef QTOX_FILTER_AUDIO
|
#ifdef QTOX_FILTER_AUDIO
|
||||||
if (filterer[callId])
|
if (filterer[callId])
|
||||||
|
{
|
||||||
|
// is a null op #ifndef ALC_LOOPBACK_CAPTURE_SAMPLES
|
||||||
|
Audio::getEchoesToFilter(filterer[callId], framesize);
|
||||||
|
|
||||||
filterer[callId]->filterAudio((int16_t*) buf, framesize);
|
filterer[callId]->filterAudio((int16_t*) buf, framesize);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uint8_t dest[bufsize];
|
uint8_t dest[bufsize];
|
||||||
|
|
Loading…
Reference in New Issue
Block a user