mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-25 21:15:07 +02:00
Allow local echo when audio input and output devices have different sample rates
This commit is contained in:
parent
b0ace1c098
commit
cabe9eab81
2 changed files with 30 additions and 14 deletions
|
@ -291,6 +291,7 @@ AudioClient::AudioClient() :
|
||||||
_inputToNetworkResampler(NULL),
|
_inputToNetworkResampler(NULL),
|
||||||
_networkToOutputResampler(NULL),
|
_networkToOutputResampler(NULL),
|
||||||
_localToOutputResampler(NULL),
|
_localToOutputResampler(NULL),
|
||||||
|
_loopbackResampler(NULL),
|
||||||
_audioLimiter(AudioConstants::SAMPLE_RATE, OUTPUT_CHANNEL_COUNT),
|
_audioLimiter(AudioConstants::SAMPLE_RATE, OUTPUT_CHANNEL_COUNT),
|
||||||
_outgoingAvatarAudioSequenceNumber(0),
|
_outgoingAvatarAudioSequenceNumber(0),
|
||||||
_audioOutputIODevice(_localInjectorsStream, _receivedAudioStream, this),
|
_audioOutputIODevice(_localInjectorsStream, _receivedAudioStream, this),
|
||||||
|
@ -762,6 +763,11 @@ void AudioClient::stop() {
|
||||||
qCDebug(audioclient) << "AudioClient::stop(), requesting switchOutputToAudioDevice() to shut down";
|
qCDebug(audioclient) << "AudioClient::stop(), requesting switchOutputToAudioDevice() to shut down";
|
||||||
switchOutputToAudioDevice(QAudioDeviceInfo(), true);
|
switchOutputToAudioDevice(QAudioDeviceInfo(), true);
|
||||||
|
|
||||||
|
if (_loopbackResampler) {
|
||||||
|
delete _loopbackResampler;
|
||||||
|
_loopbackResampler = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// Stop triggering the checks
|
// Stop triggering the checks
|
||||||
QObject::disconnect(_checkPeakValuesTimer, &QTimer::timeout, nullptr, nullptr);
|
QObject::disconnect(_checkPeakValuesTimer, &QTimer::timeout, nullptr, nullptr);
|
||||||
QObject::disconnect(_checkDevicesTimer, &QTimer::timeout, nullptr, nullptr);
|
QObject::disconnect(_checkDevicesTimer, &QTimer::timeout, nullptr, nullptr);
|
||||||
|
@ -1085,13 +1091,6 @@ void AudioClient::handleLocalEchoAndReverb(QByteArray& inputByteArray) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: we assume the inputFormat and the outputFormat are the same, since on any modern
|
|
||||||
// multimedia OS they should be. If there is a device that this is not true for, we can
|
|
||||||
// add back support to do resampling.
|
|
||||||
if (_inputFormat.sampleRate() != _outputFormat.sampleRate()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if this person wants local loopback add that to the locally injected audio
|
// if this person wants local loopback add that to the locally injected audio
|
||||||
// if there is reverb apply it to local audio and substract the origin samples
|
// if there is reverb apply it to local audio and substract the origin samples
|
||||||
|
|
||||||
|
@ -1108,21 +1107,30 @@ void AudioClient::handleLocalEchoAndReverb(QByteArray& inputByteArray) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if required, create loopback resampler
|
||||||
|
if (_inputFormat.sampleRate() != _outputFormat.sampleRate() && !_loopbackResampler) {
|
||||||
|
qCDebug(audioclient) << "Resampling" << _inputFormat.sampleRate() << "to" << _outputFormat.sampleRate() << "for audio loopback.";
|
||||||
|
|
||||||
|
int channelCount = (_inputFormat.channelCount() == 2 && _outputFormat.channelCount() == 2) ? 2 : 1;
|
||||||
|
_loopbackResampler = new AudioSRC(_inputFormat.sampleRate(), _outputFormat.sampleRate(), channelCount);
|
||||||
|
}
|
||||||
|
|
||||||
static QByteArray loopBackByteArray;
|
static QByteArray loopBackByteArray;
|
||||||
|
|
||||||
int numInputSamples = inputByteArray.size() / AudioConstants::SAMPLE_SIZE;
|
int numInputSamples = inputByteArray.size() / AudioConstants::SAMPLE_SIZE;
|
||||||
int numLoopbackSamples = (numInputSamples * OUTPUT_CHANNEL_COUNT) / _inputFormat.channelCount();
|
int numInputFrames = numInputSamples / _inputFormat.channelCount();
|
||||||
|
int numLoopbackFrames = (numInputFrames * _outputFormat.sampleRate() + _inputFormat.sampleRate() - 1) / _inputFormat.sampleRate();
|
||||||
|
int numLoopbackSamples = numLoopbackFrames * OUTPUT_CHANNEL_COUNT;
|
||||||
|
|
||||||
loopBackByteArray.resize(numLoopbackSamples * AudioConstants::SAMPLE_SIZE);
|
loopBackByteArray.resize(numLoopbackSamples * AudioConstants::SAMPLE_SIZE);
|
||||||
|
|
||||||
int16_t* inputSamples = reinterpret_cast<int16_t*>(inputByteArray.data());
|
int16_t* inputSamples = reinterpret_cast<int16_t*>(inputByteArray.data());
|
||||||
int16_t* loopbackSamples = reinterpret_cast<int16_t*>(loopBackByteArray.data());
|
int16_t* loopbackSamples = reinterpret_cast<int16_t*>(loopBackByteArray.data());
|
||||||
|
|
||||||
// upmix mono to stereo
|
possibleResampling(_loopbackResampler,
|
||||||
if (!sampleChannelConversion(inputSamples, loopbackSamples, numInputSamples, _inputFormat.channelCount(), OUTPUT_CHANNEL_COUNT)) {
|
inputSamples, loopbackSamples,
|
||||||
// no conversion, just copy the samples
|
numInputSamples, numLoopbackSamples,
|
||||||
memcpy(loopbackSamples, inputSamples, numInputSamples * AudioConstants::SAMPLE_SIZE);
|
_inputFormat.channelCount(), OUTPUT_CHANNEL_COUNT);
|
||||||
}
|
|
||||||
|
|
||||||
// apply stereo reverb at the source, to the loopback audio
|
// apply stereo reverb at the source, to the loopback audio
|
||||||
if (!_shouldEchoLocally && hasReverb) {
|
if (!_shouldEchoLocally && hasReverb) {
|
||||||
|
@ -1892,15 +1900,22 @@ bool AudioClient::switchOutputToAudioDevice(const QAudioDeviceInfo outputDeviceI
|
||||||
_outputDeviceInfo = QAudioDeviceInfo();
|
_outputDeviceInfo = QAudioDeviceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cleanup any resamplers
|
||||||
if (_networkToOutputResampler) {
|
if (_networkToOutputResampler) {
|
||||||
// if we were using an input to network resampler, delete it here
|
|
||||||
delete _networkToOutputResampler;
|
delete _networkToOutputResampler;
|
||||||
_networkToOutputResampler = NULL;
|
_networkToOutputResampler = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_localToOutputResampler) {
|
||||||
delete _localToOutputResampler;
|
delete _localToOutputResampler;
|
||||||
_localToOutputResampler = NULL;
|
_localToOutputResampler = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_loopbackResampler) {
|
||||||
|
delete _loopbackResampler;
|
||||||
|
_loopbackResampler = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (isShutdownRequest) {
|
if (isShutdownRequest) {
|
||||||
qCDebug(audioclient) << "The audio output device has shut down.";
|
qCDebug(audioclient) << "The audio output device has shut down.";
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -390,6 +390,7 @@ private:
|
||||||
AudioSRC* _inputToNetworkResampler;
|
AudioSRC* _inputToNetworkResampler;
|
||||||
AudioSRC* _networkToOutputResampler;
|
AudioSRC* _networkToOutputResampler;
|
||||||
AudioSRC* _localToOutputResampler;
|
AudioSRC* _localToOutputResampler;
|
||||||
|
AudioSRC* _loopbackResampler;
|
||||||
|
|
||||||
// for network audio (used by network audio thread)
|
// for network audio (used by network audio thread)
|
||||||
int16_t _networkScratchBuffer[AudioConstants::NETWORK_FRAME_SAMPLES_AMBISONIC];
|
int16_t _networkScratchBuffer[AudioConstants::NETWORK_FRAME_SAMPLES_AMBISONIC];
|
||||||
|
|
Loading…
Reference in a new issue