mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-07-10 21:07:22 +02:00
Merge pull request #15936 from sethalves/webrtc
acoustic echo cancellation
This commit is contained in:
commit
41bcbf6dbd
13 changed files with 388 additions and 44 deletions
24
cmake/macros/TargetWebRTC.cmake
Normal file
24
cmake/macros/TargetWebRTC.cmake
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#
|
||||||
|
# Copyright 2019 High Fidelity, Inc.
|
||||||
|
#
|
||||||
|
# Distributed under the Apache License, Version 2.0.
|
||||||
|
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
#
|
||||||
|
macro(TARGET_WEBRTC)
|
||||||
|
if (ANDROID)
|
||||||
|
# I don't yet have working libwebrtc for android
|
||||||
|
# include(SelectLibraryConfigurations)
|
||||||
|
# set(INSTALL_DIR ${HIFI_ANDROID_PRECOMPILED}/webrtc/webrtc)
|
||||||
|
# set(WEBRTC_INCLUDE_DIRS "${INSTALL_DIR}/include/webrtc")
|
||||||
|
# set(WEBRTC_LIBRARY_DEBUG ${INSTALL_DIR}/debug/lib/libwebrtc.a)
|
||||||
|
# set(WEBRTC_LIBRARY_RELEASE ${INSTALL_DIR}/lib/libwebrtc.a)
|
||||||
|
# select_library_configurations(WEBRTC)
|
||||||
|
else()
|
||||||
|
set(WEBRTC_INCLUDE_DIRS "${VCPKG_INSTALL_ROOT}/include/webrtc")
|
||||||
|
find_library(WEBRTC_LIBRARY NAMES webrtc PATHS ${VCPKG_INSTALL_ROOT}/lib/ NO_DEFAULT_PATH)
|
||||||
|
target_include_directories(${TARGET_NAME} SYSTEM PUBLIC ${WEBRTC_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(${TARGET_NAME} ${WEBRTC_LIBRARY})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
endmacro()
|
|
@ -1,4 +1,4 @@
|
||||||
Source: hifi-deps
|
Source: hifi-deps
|
||||||
Version: 0.1
|
Version: 0.1
|
||||||
Description: Collected dependencies for High Fidelity applications
|
Description: Collected dependencies for High Fidelity applications
|
||||||
Build-Depends: bullet3, draco, etc2comp, glm, nvtt, openexr (!android), openssl (windows), tbb (!android&!osx), zlib
|
Build-Depends: bullet3, draco, etc2comp, glm, nvtt, openexr (!android), openssl (windows), tbb (!android&!osx), zlib, webrtc (!android)
|
||||||
|
|
3
cmake/ports/webrtc/CONTROL
Normal file
3
cmake/ports/webrtc/CONTROL
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
Source: webrtc
|
||||||
|
Version: 20190626
|
||||||
|
Description: WebRTC
|
36
cmake/ports/webrtc/portfile.cmake
Normal file
36
cmake/ports/webrtc/portfile.cmake
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
include(vcpkg_common_functions)
|
||||||
|
set(WEBRTC_VERSION 20190626)
|
||||||
|
set(MASTER_COPY_SOURCE_PATH ${CURRENT_BUILDTREES_DIR}/src)
|
||||||
|
|
||||||
|
if (ANDROID)
|
||||||
|
# this is handled by hifi_android.py
|
||||||
|
elseif (WIN32)
|
||||||
|
vcpkg_download_distfile(
|
||||||
|
WEBRTC_SOURCE_ARCHIVE
|
||||||
|
URLS https://hifi-public.s3.amazonaws.com/seth/webrtc-20190626-windows.zip
|
||||||
|
SHA512 c0848eddb1579b3bb0496b8785e24f30470f3c477145035fd729264a326a467b9467ae9f426aa5d72d168ad9e9bf2c279150744832736bdf39064d24b04de1a3
|
||||||
|
FILENAME webrtc-20190626-windows.zip
|
||||||
|
)
|
||||||
|
elseif (APPLE)
|
||||||
|
vcpkg_download_distfile(
|
||||||
|
WEBRTC_SOURCE_ARCHIVE
|
||||||
|
URLS https://hifi-public.s3.amazonaws.com/seth/webrtc-20190626-osx.tar.gz
|
||||||
|
SHA512 fc70cec1b5ee87395137b7090f424e2fc2300fc17d744d5ffa1cf7aa0e0f1a069a9d72ba1ad2fb4a640ebeb6c218bda24351ba0083e1ff96c4a4b5032648a9d2
|
||||||
|
FILENAME webrtc-20190626-osx.tar.gz
|
||||||
|
)
|
||||||
|
else ()
|
||||||
|
# else Linux desktop
|
||||||
|
vcpkg_download_distfile(
|
||||||
|
WEBRTC_SOURCE_ARCHIVE
|
||||||
|
URLS https://hifi-public.s3.amazonaws.com/seth/webrtc-20190626-linux.tar.gz
|
||||||
|
SHA512 07d7776551aa78cb09a3ef088a8dee7762735c168c243053b262083d90a1d258cec66dc386f6903da5c4461921a3c2db157a1ee106a2b47e7756cb424b66cc43
|
||||||
|
FILENAME webrtc-20190626-linux.tar.gz
|
||||||
|
)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
vcpkg_extract_source_archive(${WEBRTC_SOURCE_ARCHIVE})
|
||||||
|
|
||||||
|
file(COPY ${MASTER_COPY_SOURCE_PATH}/webrtc/include DESTINATION ${CURRENT_PACKAGES_DIR})
|
||||||
|
file(COPY ${MASTER_COPY_SOURCE_PATH}/webrtc/lib DESTINATION ${CURRENT_PACKAGES_DIR})
|
||||||
|
file(COPY ${MASTER_COPY_SOURCE_PATH}/webrtc/share DESTINATION ${CURRENT_PACKAGES_DIR})
|
||||||
|
file(COPY ${MASTER_COPY_SOURCE_PATH}/webrtc/debug DESTINATION ${CURRENT_PACKAGES_DIR})
|
|
@ -94,6 +94,10 @@ ANDROID_PACKAGES = {
|
||||||
'checksum': 'ddcb23df336b08017042ba4786db1d9e',
|
'checksum': 'ddcb23df336b08017042ba4786db1d9e',
|
||||||
'sharedLibFolder': 'lib',
|
'sharedLibFolder': 'lib',
|
||||||
'includeLibs': {'libbreakpad_client.a'}
|
'includeLibs': {'libbreakpad_client.a'}
|
||||||
|
},
|
||||||
|
'webrtc': {
|
||||||
|
'file': 'webrtc-20190626-android.tar.gz',
|
||||||
|
'checksum': 'e2dccd3d8efdcba6d428c87ba7fb2a53'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -166,16 +166,16 @@ Rectangle {
|
||||||
x: 2 * margins.paddings;
|
x: 2 * margins.paddings;
|
||||||
width: parent.width;
|
width: parent.width;
|
||||||
// switch heights + 2 * top margins
|
// switch heights + 2 * top margins
|
||||||
height: (root.switchHeight) * 3 + 48;
|
height: (root.switchHeight) * 6 + 48;
|
||||||
anchors.top: firstSeparator.bottom;
|
anchors.top: firstSeparator.bottom;
|
||||||
anchors.topMargin: 10;
|
anchors.topMargin: 10;
|
||||||
|
|
||||||
// mute is in its own row
|
|
||||||
Item {
|
Item {
|
||||||
id: switchContainer;
|
id: switchContainer;
|
||||||
x: margins.paddings;
|
x: margins.paddings;
|
||||||
width: parent.width / 2;
|
width: parent.width / 2;
|
||||||
height: parent.height;
|
height: parent.height;
|
||||||
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left;
|
anchors.left: parent.left;
|
||||||
HifiControlsUit.Switch {
|
HifiControlsUit.Switch {
|
||||||
id: muteMic;
|
id: muteMic;
|
||||||
|
@ -222,12 +222,29 @@ Rectangle {
|
||||||
}
|
}
|
||||||
|
|
||||||
HifiControlsUit.Switch {
|
HifiControlsUit.Switch {
|
||||||
id: pttSwitch
|
id: acousticEchoCancellationSwitch;
|
||||||
height: root.switchHeight;
|
height: root.switchHeight;
|
||||||
switchWidth: root.switchWidth;
|
switchWidth: root.switchWidth;
|
||||||
anchors.top: noiseReductionSwitch.bottom
|
anchors.top: noiseReductionSwitch.bottom
|
||||||
anchors.topMargin: 24
|
anchors.topMargin: 24
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
|
labelTextOn: "Echo Cancellation";
|
||||||
|
labelTextSize: 16;
|
||||||
|
backgroundOnColor: "#E3E3E3";
|
||||||
|
checked: AudioScriptingInterface.acousticEchoCancellation;
|
||||||
|
onCheckedChanged: {
|
||||||
|
AudioScriptingInterface.acousticEchoCancellation = checked;
|
||||||
|
checked = Qt.binding(function() { return AudioScriptingInterface.acousticEchoCancellation; });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HifiControlsUit.Switch {
|
||||||
|
id: pttSwitch
|
||||||
|
height: root.switchHeight;
|
||||||
|
switchWidth: root.switchWidth;
|
||||||
|
anchors.top: acousticEchoCancellationSwitch.bottom;
|
||||||
|
anchors.topMargin: 24
|
||||||
|
anchors.left: parent.left
|
||||||
labelTextOn: (bar.currentIndex === 0) ? qsTr("Push To Talk (T)") : qsTr("Push To Talk");
|
labelTextOn: (bar.currentIndex === 0) ? qsTr("Push To Talk (T)") : qsTr("Push To Talk");
|
||||||
labelTextSize: 16;
|
labelTextSize: 16;
|
||||||
backgroundOnColor: "#E3E3E3";
|
backgroundOnColor: "#E3E3E3";
|
||||||
|
@ -298,7 +315,6 @@ Rectangle {
|
||||||
checked = Qt.binding(function() { return AudioScriptingInterface.isStereoInput; }); // restore binding
|
checked = Qt.binding(function() { return AudioScriptingInterface.isStereoInput; }); // restore binding
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -222,6 +222,17 @@ Flickable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SimplifiedControls.Switch {
|
||||||
|
id: acousticEchoCancellationSwitch
|
||||||
|
Layout.preferredHeight: 18
|
||||||
|
Layout.preferredWidth: parent.width
|
||||||
|
labelTextOn: "Acoustic Echo Cancellation"
|
||||||
|
checked: AudioScriptingInterface.acousticEchoCancellation
|
||||||
|
onClicked: {
|
||||||
|
AudioScriptingInterface.acousticEchoCancellation = !AudioScriptingInterface.acousticEchoCancellation;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ QString Audio::HMD { "VR" };
|
||||||
|
|
||||||
Setting::Handle<bool> enableNoiseReductionSetting { QStringList { Audio::AUDIO, "NoiseReduction" }, true };
|
Setting::Handle<bool> enableNoiseReductionSetting { QStringList { Audio::AUDIO, "NoiseReduction" }, true };
|
||||||
Setting::Handle<bool> enableWarnWhenMutedSetting { QStringList { Audio::AUDIO, "WarnWhenMuted" }, true };
|
Setting::Handle<bool> enableWarnWhenMutedSetting { QStringList { Audio::AUDIO, "WarnWhenMuted" }, true };
|
||||||
|
Setting::Handle<bool> enableAcousticEchoCancellationSetting { QStringList { Audio::AUDIO, "AcousticEchoCancellation" }, true };
|
||||||
|
|
||||||
|
|
||||||
float Audio::loudnessToLevel(float loudness) {
|
float Audio::loudnessToLevel(float loudness) {
|
||||||
|
@ -40,12 +41,14 @@ Audio::Audio() : _devices(_contextIsHMD) {
|
||||||
connect(client, &AudioClient::muteToggled, this, &Audio::setMuted);
|
connect(client, &AudioClient::muteToggled, this, &Audio::setMuted);
|
||||||
connect(client, &AudioClient::noiseReductionChanged, this, &Audio::enableNoiseReduction);
|
connect(client, &AudioClient::noiseReductionChanged, this, &Audio::enableNoiseReduction);
|
||||||
connect(client, &AudioClient::warnWhenMutedChanged, this, &Audio::enableWarnWhenMuted);
|
connect(client, &AudioClient::warnWhenMutedChanged, this, &Audio::enableWarnWhenMuted);
|
||||||
|
connect(client, &AudioClient::acousticEchoCancellationChanged, this, &Audio::enableAcousticEchoCancellation);
|
||||||
connect(client, &AudioClient::inputLoudnessChanged, this, &Audio::onInputLoudnessChanged);
|
connect(client, &AudioClient::inputLoudnessChanged, this, &Audio::onInputLoudnessChanged);
|
||||||
connect(client, &AudioClient::inputVolumeChanged, this, &Audio::setInputVolume);
|
connect(client, &AudioClient::inputVolumeChanged, this, &Audio::setInputVolume);
|
||||||
connect(this, &Audio::contextChanged, &_devices, &AudioDevices::onContextChanged);
|
connect(this, &Audio::contextChanged, &_devices, &AudioDevices::onContextChanged);
|
||||||
connect(this, &Audio::pushingToTalkChanged, this, &Audio::handlePushedToTalk);
|
connect(this, &Audio::pushingToTalkChanged, this, &Audio::handlePushedToTalk);
|
||||||
enableNoiseReduction(enableNoiseReductionSetting.get());
|
enableNoiseReduction(enableNoiseReductionSetting.get());
|
||||||
enableWarnWhenMuted(enableWarnWhenMutedSetting.get());
|
enableWarnWhenMuted(enableWarnWhenMutedSetting.get());
|
||||||
|
enableAcousticEchoCancellation(enableAcousticEchoCancellationSetting.get());
|
||||||
onContextChanged();
|
onContextChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,6 +280,28 @@ void Audio::enableWarnWhenMuted(bool enable) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Audio::acousticEchoCancellationEnabled() const {
|
||||||
|
return resultWithReadLock<bool>([&] {
|
||||||
|
return _enableAcousticEchoCancellation;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Audio::enableAcousticEchoCancellation(bool enable) {
|
||||||
|
bool changed = false;
|
||||||
|
withWriteLock([&] {
|
||||||
|
if (_enableAcousticEchoCancellation != enable) {
|
||||||
|
_enableAcousticEchoCancellation = enable;
|
||||||
|
auto client = DependencyManager::get<AudioClient>().data();
|
||||||
|
QMetaObject::invokeMethod(client, "setAcousticEchoCancellation", Q_ARG(bool, enable), Q_ARG(bool, false));
|
||||||
|
enableAcousticEchoCancellationSetting.set(enable);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (changed) {
|
||||||
|
emit acousticEchoCancellationChanged(enable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
float Audio::getInputVolume() const {
|
float Audio::getInputVolume() const {
|
||||||
return resultWithReadLock<bool>([&] {
|
return resultWithReadLock<bool>([&] {
|
||||||
return _inputVolume;
|
return _inputVolume;
|
||||||
|
|
|
@ -72,6 +72,9 @@ class Audio : public AudioScriptingInterface, protected ReadWriteLockable {
|
||||||
* @property {number} systemInjectorGain - The gain (relative volume) that system sounds are played at.
|
* @property {number} systemInjectorGain - The gain (relative volume) that system sounds are played at.
|
||||||
* @property {number} pushingToTalkOutputGainDesktop - The gain (relative volume) that all sounds are played at when the user is holding
|
* @property {number} pushingToTalkOutputGainDesktop - The gain (relative volume) that all sounds are played at when the user is holding
|
||||||
* the push-to-talk key in Desktop mode.
|
* the push-to-talk key in Desktop mode.
|
||||||
|
* @property {boolean} acousticEchoCancellation - <code>true</code> if audio-echo-cancellation is enabled, otherwise
|
||||||
|
* <code>false</code>. When enabled, sound from the audio output will be suppressed when it echos back to the
|
||||||
|
* input audio signal.
|
||||||
*
|
*
|
||||||
* @comment The following properties are from AudioScriptingInterface.h.
|
* @comment The following properties are from AudioScriptingInterface.h.
|
||||||
* @property {boolean} isStereoInput - <code>true</code> if the input audio is being used in stereo, otherwise
|
* @property {boolean} isStereoInput - <code>true</code> if the input audio is being used in stereo, otherwise
|
||||||
|
@ -85,6 +88,8 @@ class Audio : public AudioScriptingInterface, protected ReadWriteLockable {
|
||||||
Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged)
|
Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged)
|
||||||
Q_PROPERTY(bool noiseReduction READ noiseReductionEnabled WRITE enableNoiseReduction NOTIFY noiseReductionChanged)
|
Q_PROPERTY(bool noiseReduction READ noiseReductionEnabled WRITE enableNoiseReduction NOTIFY noiseReductionChanged)
|
||||||
Q_PROPERTY(bool warnWhenMuted READ warnWhenMutedEnabled WRITE enableWarnWhenMuted NOTIFY warnWhenMutedChanged)
|
Q_PROPERTY(bool warnWhenMuted READ warnWhenMutedEnabled WRITE enableWarnWhenMuted NOTIFY warnWhenMutedChanged)
|
||||||
|
Q_PROPERTY(bool acousticEchoCancellation
|
||||||
|
READ acousticEchoCancellationEnabled WRITE enableAcousticEchoCancellation NOTIFY acousticEchoCancellationChanged)
|
||||||
Q_PROPERTY(float inputVolume READ getInputVolume WRITE setInputVolume NOTIFY inputVolumeChanged)
|
Q_PROPERTY(float inputVolume READ getInputVolume WRITE setInputVolume NOTIFY inputVolumeChanged)
|
||||||
Q_PROPERTY(float inputLevel READ getInputLevel NOTIFY inputLevelChanged)
|
Q_PROPERTY(float inputLevel READ getInputLevel NOTIFY inputLevelChanged)
|
||||||
Q_PROPERTY(bool clipping READ isClipping NOTIFY clippingChanged)
|
Q_PROPERTY(bool clipping READ isClipping NOTIFY clippingChanged)
|
||||||
|
@ -115,6 +120,7 @@ public:
|
||||||
bool isMuted() const;
|
bool isMuted() const;
|
||||||
bool noiseReductionEnabled() const;
|
bool noiseReductionEnabled() const;
|
||||||
bool warnWhenMutedEnabled() const;
|
bool warnWhenMutedEnabled() const;
|
||||||
|
bool acousticEchoCancellationEnabled() const;
|
||||||
float getInputVolume() const;
|
float getInputVolume() const;
|
||||||
float getInputLevel() const;
|
float getInputLevel() const;
|
||||||
bool isClipping() const;
|
bool isClipping() const;
|
||||||
|
@ -396,6 +402,14 @@ signals:
|
||||||
*/
|
*/
|
||||||
void warnWhenMutedChanged(bool isEnabled);
|
void warnWhenMutedChanged(bool isEnabled);
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Triggered when acoustic echo cancellation is enabled or disabled.
|
||||||
|
* @function Audio.acousticEchoCancellationChanged
|
||||||
|
* @param {boolean} isEnabled - <code>true</code> if acoustic echo cancellation is enabled, otherwise <code>false</code>.
|
||||||
|
* @returns {Signal}
|
||||||
|
*/
|
||||||
|
void acousticEchoCancellationChanged(bool isEnabled);
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Triggered when the input audio volume changes.
|
* Triggered when the input audio volume changes.
|
||||||
* @function Audio.inputVolumeChanged
|
* @function Audio.inputVolumeChanged
|
||||||
|
@ -494,6 +508,7 @@ private slots:
|
||||||
void setMuted(bool muted);
|
void setMuted(bool muted);
|
||||||
void enableNoiseReduction(bool enable);
|
void enableNoiseReduction(bool enable);
|
||||||
void enableWarnWhenMuted(bool enable);
|
void enableWarnWhenMuted(bool enable);
|
||||||
|
void enableAcousticEchoCancellation(bool enable);
|
||||||
void setInputVolume(float volume);
|
void setInputVolume(float volume);
|
||||||
void onInputLoudnessChanged(float loudness, bool isClipping);
|
void onInputLoudnessChanged(float loudness, bool isClipping);
|
||||||
|
|
||||||
|
@ -512,6 +527,7 @@ private:
|
||||||
bool _isClipping { false };
|
bool _isClipping { false };
|
||||||
bool _enableNoiseReduction { true }; // Match default value of AudioClient::_isNoiseGateEnabled.
|
bool _enableNoiseReduction { true }; // Match default value of AudioClient::_isNoiseGateEnabled.
|
||||||
bool _enableWarnWhenMuted { true };
|
bool _enableWarnWhenMuted { true };
|
||||||
|
bool _enableAcousticEchoCancellation { true }; // AudioClient::_isAECEnabled
|
||||||
bool _contextIsHMD { false };
|
bool _contextIsHMD { false };
|
||||||
AudioDevices* getDevices() { return &_devices; }
|
AudioDevices* getDevices() { return &_devices; }
|
||||||
AudioDevices _devices;
|
AudioDevices _devices;
|
||||||
|
|
|
@ -7,6 +7,11 @@ link_hifi_libraries(audio plugins)
|
||||||
include_hifi_library_headers(shared)
|
include_hifi_library_headers(shared)
|
||||||
include_hifi_library_headers(networking)
|
include_hifi_library_headers(networking)
|
||||||
|
|
||||||
|
if (ANDROID)
|
||||||
|
else ()
|
||||||
|
target_webrtc()
|
||||||
|
endif ()
|
||||||
|
|
||||||
# append audio includes to our list of includes to bubble
|
# append audio includes to our list of includes to bubble
|
||||||
target_include_directories(${TARGET_NAME} PUBLIC "${HIFI_LIBRARY_DIR}/audio/src")
|
target_include_directories(${TARGET_NAME} PUBLIC "${HIFI_LIBRARY_DIR}/audio/src")
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN 1
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <Mmsystem.h>
|
#include <Mmsystem.h>
|
||||||
#include <mmdeviceapi.h>
|
#include <mmdeviceapi.h>
|
||||||
|
@ -286,6 +286,7 @@ AudioClient::AudioClient() :
|
||||||
_shouldEchoLocally(false),
|
_shouldEchoLocally(false),
|
||||||
_shouldEchoToServer(false),
|
_shouldEchoToServer(false),
|
||||||
_isNoiseGateEnabled(true),
|
_isNoiseGateEnabled(true),
|
||||||
|
_isAECEnabled(true),
|
||||||
_reverb(false),
|
_reverb(false),
|
||||||
_reverbOptions(&_scriptReverbOptions),
|
_reverbOptions(&_scriptReverbOptions),
|
||||||
_inputToNetworkResampler(NULL),
|
_inputToNetworkResampler(NULL),
|
||||||
|
@ -302,6 +303,7 @@ AudioClient::AudioClient() :
|
||||||
_isHeadsetPluggedIn(false),
|
_isHeadsetPluggedIn(false),
|
||||||
#endif
|
#endif
|
||||||
_orientationGetter(DEFAULT_ORIENTATION_GETTER) {
|
_orientationGetter(DEFAULT_ORIENTATION_GETTER) {
|
||||||
|
|
||||||
// avoid putting a lock in the device callback
|
// avoid putting a lock in the device callback
|
||||||
assert(_localSamplesAvailable.is_lock_free());
|
assert(_localSamplesAvailable.is_lock_free());
|
||||||
|
|
||||||
|
@ -353,6 +355,10 @@ AudioClient::AudioClient() :
|
||||||
|
|
||||||
configureReverb();
|
configureReverb();
|
||||||
|
|
||||||
|
#if defined(WEBRTC_ENABLED)
|
||||||
|
configureWebrtc();
|
||||||
|
#endif
|
||||||
|
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
auto& packetReceiver = nodeList->getPacketReceiver();
|
auto& packetReceiver = nodeList->getPacketReceiver();
|
||||||
packetReceiver.registerListener(PacketType::AudioStreamStats, &_stats, "processStreamStatsPacket");
|
packetReceiver.registerListener(PacketType::AudioStreamStats, &_stats, "processStreamStatsPacket");
|
||||||
|
@ -1084,6 +1090,131 @@ void AudioClient::setReverbOptions(const AudioEffectOptions* options) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(WEBRTC_ENABLED)
|
||||||
|
|
||||||
|
static void deinterleaveToFloat(const int16_t* src, float* const* dst, int numFrames, int numChannels) {
|
||||||
|
for (int i = 0; i < numFrames; i++) {
|
||||||
|
for (int ch = 0; ch < numChannels; ch++) {
|
||||||
|
float f = *src++;
|
||||||
|
f *= (1/32768.0f); // scale
|
||||||
|
dst[ch][i] = f; // deinterleave
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void interleaveToInt16(const float* const* src, int16_t* dst, int numFrames, int numChannels) {
|
||||||
|
for (int i = 0; i < numFrames; i++) {
|
||||||
|
for (int ch = 0; ch < numChannels; ch++) {
|
||||||
|
float f = src[ch][i];
|
||||||
|
f *= 32768.0f; // scale
|
||||||
|
f += (f < 0.0f) ? -0.5f : 0.5f; // round
|
||||||
|
f = std::max(std::min(f, 32767.0f), -32768.0f); // saturate
|
||||||
|
*dst++ = (int16_t)f; // interleave
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioClient::configureWebrtc() {
|
||||||
|
_apm = webrtc::AudioProcessingBuilder().Create();
|
||||||
|
|
||||||
|
webrtc::AudioProcessing::Config config;
|
||||||
|
|
||||||
|
config.pre_amplifier.enabled = false;
|
||||||
|
config.high_pass_filter.enabled = false;
|
||||||
|
config.echo_canceller.enabled = true;
|
||||||
|
config.echo_canceller.mobile_mode = false;
|
||||||
|
config.echo_canceller.use_legacy_aec = false;
|
||||||
|
config.noise_suppression.enabled = false;
|
||||||
|
config.noise_suppression.level = webrtc::AudioProcessing::Config::NoiseSuppression::kModerate;
|
||||||
|
config.voice_detection.enabled = false;
|
||||||
|
config.gain_controller1.enabled = false;
|
||||||
|
config.gain_controller2.enabled = false;
|
||||||
|
config.gain_controller2.fixed_digital.gain_db = 0.0f;
|
||||||
|
config.gain_controller2.adaptive_digital.enabled = false;
|
||||||
|
config.residual_echo_detector.enabled = true;
|
||||||
|
config.level_estimation.enabled = false;
|
||||||
|
|
||||||
|
_apm->ApplyConfig(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
// rebuffer into 10ms chunks
|
||||||
|
void AudioClient::processWebrtcFarEnd(const int16_t* samples, int numFrames, int numChannels, int sampleRate) {
|
||||||
|
|
||||||
|
const webrtc::StreamConfig streamConfig = webrtc::StreamConfig(sampleRate, numChannels);
|
||||||
|
const int numChunk = (int)streamConfig.num_frames();
|
||||||
|
|
||||||
|
if (sampleRate > WEBRTC_SAMPLE_RATE_MAX) {
|
||||||
|
qCWarning(audioclient) << "WebRTC does not support" << sampleRate << "output sample rate.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (numChannels > WEBRTC_CHANNELS_MAX) {
|
||||||
|
qCWarning(audioclient) << "WebRTC does not support" << numChannels << "output channels.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (numFrames > 0) {
|
||||||
|
|
||||||
|
// number of frames to fill
|
||||||
|
int numFill = std::min(numFrames, numChunk - _numFifoFarEnd);
|
||||||
|
|
||||||
|
// refill fifo
|
||||||
|
memcpy(&_fifoFarEnd[_numFifoFarEnd], samples, numFill * numChannels * sizeof(int16_t));
|
||||||
|
samples += numFill * numChannels;
|
||||||
|
numFrames -= numFill;
|
||||||
|
_numFifoFarEnd += numFill;
|
||||||
|
|
||||||
|
if (_numFifoFarEnd == numChunk) {
|
||||||
|
|
||||||
|
// convert audio format
|
||||||
|
float buffer[WEBRTC_CHANNELS_MAX][WEBRTC_FRAMES_MAX];
|
||||||
|
float* const buffers[WEBRTC_CHANNELS_MAX] = { buffer[0], buffer[1] };
|
||||||
|
deinterleaveToFloat(_fifoFarEnd, buffers, numChunk, numChannels);
|
||||||
|
|
||||||
|
// process one chunk
|
||||||
|
int error = _apm->ProcessReverseStream(buffers, streamConfig, streamConfig, buffers);
|
||||||
|
if (error != _apm->kNoError) {
|
||||||
|
qCWarning(audioclient) << "WebRTC ProcessReverseStream() returned ERROR:" << error;
|
||||||
|
}
|
||||||
|
_numFifoFarEnd = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioClient::processWebrtcNearEnd(int16_t* samples, int numFrames, int numChannels, int sampleRate) {
|
||||||
|
|
||||||
|
const webrtc::StreamConfig streamConfig = webrtc::StreamConfig(sampleRate, numChannels);
|
||||||
|
const int numChunk = (int)streamConfig.num_frames();
|
||||||
|
|
||||||
|
if (sampleRate > WEBRTC_SAMPLE_RATE_MAX) {
|
||||||
|
qCWarning(audioclient) << "WebRTC does not support" << sampleRate << "input sample rate.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (numChannels > WEBRTC_CHANNELS_MAX) {
|
||||||
|
qCWarning(audioclient) << "WebRTC does not support" << numChannels << "input channels.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (numFrames != numChunk) {
|
||||||
|
qCWarning(audioclient) << "WebRTC requires exactly 10ms of input.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert audio format
|
||||||
|
float buffer[WEBRTC_CHANNELS_MAX][WEBRTC_FRAMES_MAX];
|
||||||
|
float* const buffers[WEBRTC_CHANNELS_MAX] = { buffer[0], buffer[1] };
|
||||||
|
deinterleaveToFloat(samples, buffers, numFrames, numChannels);
|
||||||
|
|
||||||
|
// process one chunk
|
||||||
|
int error = _apm->ProcessStream(buffers, streamConfig, streamConfig, buffers);
|
||||||
|
if (error != _apm->kNoError) {
|
||||||
|
qCWarning(audioclient) << "WebRTC ProcessStream() returned ERROR:" << error;
|
||||||
|
} else {
|
||||||
|
// modify samples in-place
|
||||||
|
interleaveToInt16(buffers, samples, numFrames, numChannels);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // WEBRTC_ENABLED
|
||||||
|
|
||||||
void AudioClient::handleLocalEchoAndReverb(QByteArray& inputByteArray) {
|
void AudioClient::handleLocalEchoAndReverb(QByteArray& inputByteArray) {
|
||||||
// If there is server echo, reverb will be applied to the recieved audio stream so no need to have it here.
|
// If there is server echo, reverb will be applied to the recieved audio stream so no need to have it here.
|
||||||
bool hasReverb = _reverb || _receivedAudioStream.hasReverb();
|
bool hasReverb = _reverb || _receivedAudioStream.hasReverb();
|
||||||
|
@ -1262,6 +1393,13 @@ void AudioClient::handleMicAudioInput() {
|
||||||
|
|
||||||
_inputRingBuffer.readSamples(inputAudioSamples.get(), inputSamplesRequired);
|
_inputRingBuffer.readSamples(inputAudioSamples.get(), inputSamplesRequired);
|
||||||
|
|
||||||
|
#if defined(WEBRTC_ENABLED)
|
||||||
|
if (_isAECEnabled) {
|
||||||
|
processWebrtcNearEnd(inputAudioSamples.get(), inputSamplesRequired / _inputFormat.channelCount(),
|
||||||
|
_inputFormat.channelCount(), _inputFormat.sampleRate());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// detect loudness and clipping on the raw input
|
// detect loudness and clipping on the raw input
|
||||||
bool isClipping = false;
|
bool isClipping = false;
|
||||||
float loudness = computeLoudness(inputAudioSamples.get(), inputSamplesRequired, _inputFormat.channelCount(), isClipping);
|
float loudness = computeLoudness(inputAudioSamples.get(), inputSamplesRequired, _inputFormat.channelCount(), isClipping);
|
||||||
|
@ -1574,6 +1712,15 @@ void AudioClient::setWarnWhenMuted(bool enable, bool emitSignal) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AudioClient::setAcousticEchoCancellation(bool enable, bool emitSignal) {
|
||||||
|
if (_isAECEnabled != enable) {
|
||||||
|
_isAECEnabled = enable;
|
||||||
|
if (emitSignal) {
|
||||||
|
emit acousticEchoCancellationChanged(_isAECEnabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool AudioClient::setIsStereoInput(bool isStereoInput) {
|
bool AudioClient::setIsStereoInput(bool isStereoInput) {
|
||||||
bool stereoInputChanged = false;
|
bool stereoInputChanged = false;
|
||||||
if (isStereoInput != _isStereoInput && _inputDeviceInfo.supportedChannelCounts().contains(2)) {
|
if (isStereoInput != _isStereoInput && _inputDeviceInfo.supportedChannelCounts().contains(2)) {
|
||||||
|
@ -2107,15 +2254,16 @@ qint64 AudioClient::AudioOutputIODevice::readData(char * data, qint64 maxSize) {
|
||||||
return maxSize;
|
return maxSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
// samples requested from OUTPUT_CHANNEL_COUNT
|
// max samples requested from OUTPUT_CHANNEL_COUNT
|
||||||
int deviceChannelCount = _audio->_outputFormat.channelCount();
|
int deviceChannelCount = _audio->_outputFormat.channelCount();
|
||||||
int samplesRequested = (int)(maxSize / AudioConstants::SAMPLE_SIZE) * OUTPUT_CHANNEL_COUNT / deviceChannelCount;
|
int maxSamplesRequested = (int)(maxSize / AudioConstants::SAMPLE_SIZE) * OUTPUT_CHANNEL_COUNT / deviceChannelCount;
|
||||||
// restrict samplesRequested to the size of our mix/scratch buffers
|
// restrict samplesRequested to the size of our mix/scratch buffers
|
||||||
samplesRequested = std::min(samplesRequested, _audio->_outputPeriod);
|
maxSamplesRequested = std::min(maxSamplesRequested, _audio->_outputPeriod);
|
||||||
|
|
||||||
int16_t* scratchBuffer = _audio->_outputScratchBuffer;
|
int16_t* scratchBuffer = _audio->_outputScratchBuffer;
|
||||||
float* mixBuffer = _audio->_outputMixBuffer;
|
float* mixBuffer = _audio->_outputMixBuffer;
|
||||||
|
|
||||||
|
int samplesRequested = maxSamplesRequested;
|
||||||
int networkSamplesPopped;
|
int networkSamplesPopped;
|
||||||
if ((networkSamplesPopped = _receivedAudioStream.popSamples(samplesRequested, false)) > 0) {
|
if ((networkSamplesPopped = _receivedAudioStream.popSamples(samplesRequested, false)) > 0) {
|
||||||
qCDebug(audiostream, "Read %d samples from buffer (%d available, %d requested)", networkSamplesPopped, _receivedAudioStream.getSamplesAvailable(), samplesRequested);
|
qCDebug(audiostream, "Read %d samples from buffer (%d available, %d requested)", networkSamplesPopped, _receivedAudioStream.getSamplesAvailable(), samplesRequested);
|
||||||
|
@ -2160,9 +2308,12 @@ qint64 AudioClient::AudioOutputIODevice::readData(char * data, qint64 maxSize) {
|
||||||
});
|
});
|
||||||
|
|
||||||
int samplesPopped = std::max(networkSamplesPopped, injectorSamplesPopped);
|
int samplesPopped = std::max(networkSamplesPopped, injectorSamplesPopped);
|
||||||
int framesPopped = samplesPopped / AudioConstants::STEREO;
|
if (samplesPopped == 0) {
|
||||||
int bytesWritten;
|
// nothing on network, don't grab anything from injectors, and fill with silence
|
||||||
if (samplesPopped > 0) {
|
samplesPopped = maxSamplesRequested;
|
||||||
|
memset(mixBuffer, 0, samplesPopped * sizeof(float));
|
||||||
|
}
|
||||||
|
int framesPopped = samplesPopped / OUTPUT_CHANNEL_COUNT;
|
||||||
|
|
||||||
// apply output gain
|
// apply output gain
|
||||||
float newGain = _audio->_outputGain.load(std::memory_order_acquire);
|
float newGain = _audio->_outputGain.load(std::memory_order_acquire);
|
||||||
|
@ -2171,34 +2322,31 @@ qint64 AudioClient::AudioOutputIODevice::readData(char * data, qint64 maxSize) {
|
||||||
|
|
||||||
applyGainSmoothing<OUTPUT_CHANNEL_COUNT>(mixBuffer, framesPopped, oldGain, newGain);
|
applyGainSmoothing<OUTPUT_CHANNEL_COUNT>(mixBuffer, framesPopped, oldGain, newGain);
|
||||||
|
|
||||||
if (deviceChannelCount == OUTPUT_CHANNEL_COUNT) {
|
|
||||||
// limit the audio
|
// limit the audio
|
||||||
_audio->_audioLimiter.render(mixBuffer, (int16_t*)data, framesPopped);
|
|
||||||
} else {
|
|
||||||
_audio->_audioLimiter.render(mixBuffer, scratchBuffer, framesPopped);
|
_audio->_audioLimiter.render(mixBuffer, scratchBuffer, framesPopped);
|
||||||
|
|
||||||
// upmix or downmix to deviceChannelCount
|
#if defined(WEBRTC_ENABLED)
|
||||||
if (deviceChannelCount > OUTPUT_CHANNEL_COUNT) {
|
if (_audio->_isAECEnabled) {
|
||||||
|
_audio->processWebrtcFarEnd(scratchBuffer, framesPopped, OUTPUT_CHANNEL_COUNT, _audio->_outputFormat.sampleRate());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// if required, upmix or downmix to deviceChannelCount
|
||||||
|
if (deviceChannelCount == OUTPUT_CHANNEL_COUNT) {
|
||||||
|
memcpy(data, scratchBuffer, samplesPopped * AudioConstants::SAMPLE_SIZE);
|
||||||
|
} else if (deviceChannelCount > OUTPUT_CHANNEL_COUNT) {
|
||||||
int extraChannels = deviceChannelCount - OUTPUT_CHANNEL_COUNT;
|
int extraChannels = deviceChannelCount - OUTPUT_CHANNEL_COUNT;
|
||||||
channelUpmix(scratchBuffer, (int16_t*)data, samplesPopped, extraChannels);
|
channelUpmix(scratchBuffer, (int16_t*)data, samplesPopped, extraChannels);
|
||||||
} else {
|
} else {
|
||||||
channelDownmix(scratchBuffer, (int16_t*)data, samplesPopped);
|
channelDownmix(scratchBuffer, (int16_t*)data, samplesPopped);
|
||||||
}
|
}
|
||||||
}
|
int bytesWritten = framesPopped * AudioConstants::SAMPLE_SIZE * deviceChannelCount;
|
||||||
|
|
||||||
bytesWritten = framesPopped * AudioConstants::SAMPLE_SIZE * deviceChannelCount;
|
|
||||||
assert(bytesWritten <= maxSize);
|
assert(bytesWritten <= maxSize);
|
||||||
|
|
||||||
} else {
|
|
||||||
// nothing on network, don't grab anything from injectors, and just return 0s
|
|
||||||
memset(data, 0, maxSize);
|
|
||||||
bytesWritten = maxSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
// send output buffer for recording
|
// send output buffer for recording
|
||||||
if (_audio->_isRecording) {
|
if (_audio->_isRecording) {
|
||||||
Lock lock(_recordMutex);
|
Lock lock(_recordMutex);
|
||||||
_audio->_audioFileWav.addRawAudioChunk(reinterpret_cast<char*>(scratchBuffer), bytesWritten);
|
_audio->_audioFileWav.addRawAudioChunk(data, bytesWritten);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bytesAudioOutputUnplayed = _audio->_audioOutput->bufferSize() - _audio->_audioOutput->bytesFree();
|
int bytesAudioOutputUnplayed = _audio->_audioOutput->bufferSize() - _audio->_audioOutput->bytesFree();
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include <AbstractAudioInterface.h>
|
#include <AbstractAudioInterface.h>
|
||||||
#include <AudioEffectOptions.h>
|
#include <AudioEffectOptions.h>
|
||||||
#include <AudioStreamStats.h>
|
#include <AudioStreamStats.h>
|
||||||
|
#include <shared/WebRTC.h>
|
||||||
|
|
||||||
#include <DependencyManager.h>
|
#include <DependencyManager.h>
|
||||||
#include <HifiSockAddr.h>
|
#include <HifiSockAddr.h>
|
||||||
|
@ -215,6 +216,9 @@ public slots:
|
||||||
void setWarnWhenMuted(bool isNoiseGateEnabled, bool emitSignal = true);
|
void setWarnWhenMuted(bool isNoiseGateEnabled, bool emitSignal = true);
|
||||||
bool isWarnWhenMutedEnabled() const { return _warnWhenMuted; }
|
bool isWarnWhenMutedEnabled() const { return _warnWhenMuted; }
|
||||||
|
|
||||||
|
void setAcousticEchoCancellation(bool isAECEnabled, bool emitSignal = true);
|
||||||
|
bool isAcousticEchoCancellationEnabled() const { return _isAECEnabled; }
|
||||||
|
|
||||||
virtual bool getLocalEcho() override { return _shouldEchoLocally; }
|
virtual bool getLocalEcho() override { return _shouldEchoLocally; }
|
||||||
virtual void setLocalEcho(bool localEcho) override { _shouldEchoLocally = localEcho; }
|
virtual void setLocalEcho(bool localEcho) override { _shouldEchoLocally = localEcho; }
|
||||||
virtual void toggleLocalEcho() override { _shouldEchoLocally = !_shouldEchoLocally; }
|
virtual void toggleLocalEcho() override { _shouldEchoLocally = !_shouldEchoLocally; }
|
||||||
|
@ -256,6 +260,7 @@ signals:
|
||||||
void muteToggled(bool muted);
|
void muteToggled(bool muted);
|
||||||
void noiseReductionChanged(bool noiseReductionEnabled);
|
void noiseReductionChanged(bool noiseReductionEnabled);
|
||||||
void warnWhenMutedChanged(bool warnWhenMutedEnabled);
|
void warnWhenMutedChanged(bool warnWhenMutedEnabled);
|
||||||
|
void acousticEchoCancellationChanged(bool acousticEchoCancellationEnabled);
|
||||||
void mutedByMixer();
|
void mutedByMixer();
|
||||||
void inputReceived(const QByteArray& inputSamples);
|
void inputReceived(const QByteArray& inputSamples);
|
||||||
void inputLoudnessChanged(float loudness, bool isClipping);
|
void inputLoudnessChanged(float loudness, bool isClipping);
|
||||||
|
@ -377,6 +382,7 @@ private:
|
||||||
bool _shouldEchoToServer;
|
bool _shouldEchoToServer;
|
||||||
bool _isNoiseGateEnabled;
|
bool _isNoiseGateEnabled;
|
||||||
bool _warnWhenMuted;
|
bool _warnWhenMuted;
|
||||||
|
bool _isAECEnabled;
|
||||||
|
|
||||||
bool _reverb;
|
bool _reverb;
|
||||||
AudioEffectOptions _scriptReverbOptions;
|
AudioEffectOptions _scriptReverbOptions;
|
||||||
|
@ -414,9 +420,23 @@ private:
|
||||||
// Adds Reverb
|
// Adds Reverb
|
||||||
void configureReverb();
|
void configureReverb();
|
||||||
void updateReverbOptions();
|
void updateReverbOptions();
|
||||||
|
|
||||||
void handleLocalEchoAndReverb(QByteArray& inputByteArray);
|
void handleLocalEchoAndReverb(QByteArray& inputByteArray);
|
||||||
|
|
||||||
|
#if defined(WEBRTC_ENABLED)
|
||||||
|
static const int WEBRTC_SAMPLE_RATE_MAX = 96000;
|
||||||
|
static const int WEBRTC_CHANNELS_MAX = 2;
|
||||||
|
static const int WEBRTC_FRAMES_MAX = webrtc::AudioProcessing::kChunkSizeMs * WEBRTC_SAMPLE_RATE_MAX / 1000;
|
||||||
|
|
||||||
|
webrtc::AudioProcessing* _apm { nullptr };
|
||||||
|
|
||||||
|
int16_t _fifoFarEnd[WEBRTC_CHANNELS_MAX * WEBRTC_FRAMES_MAX] {};
|
||||||
|
int _numFifoFarEnd = 0; // numFrames saved in fifo
|
||||||
|
|
||||||
|
void configureWebrtc();
|
||||||
|
void processWebrtcFarEnd(const int16_t* samples, int numFrames, int numChannels, int sampleRate);
|
||||||
|
void processWebrtcNearEnd(int16_t* samples, int numFrames, int numChannels, int sampleRate);
|
||||||
|
#endif
|
||||||
|
|
||||||
bool switchInputToAudioDevice(const QAudioDeviceInfo inputDeviceInfo, bool isShutdownRequest = false);
|
bool switchInputToAudioDevice(const QAudioDeviceInfo inputDeviceInfo, bool isShutdownRequest = false);
|
||||||
bool switchOutputToAudioDevice(const QAudioDeviceInfo outputDeviceInfo, bool isShutdownRequest = false);
|
bool switchOutputToAudioDevice(const QAudioDeviceInfo outputDeviceInfo, bool isShutdownRequest = false);
|
||||||
|
|
||||||
|
|
36
libraries/shared/src/shared/WebRTC.h
Normal file
36
libraries/shared/src/shared/WebRTC.h
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
//
|
||||||
|
// WebRTC.h
|
||||||
|
// libraries/shared/src/shared/
|
||||||
|
//
|
||||||
|
// Copyright 2019 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef hifi_WebRTC_h
|
||||||
|
#define hifi_WebRTC_h
|
||||||
|
|
||||||
|
#if defined(Q_OS_MAC)
|
||||||
|
# define WEBRTC_ENABLED 1
|
||||||
|
# define WEBRTC_POSIX 1
|
||||||
|
#elif defined(Q_OS_WIN)
|
||||||
|
# define WEBRTC_ENABLED 1
|
||||||
|
# define WEBRTC_WIN 1
|
||||||
|
# define NOMINMAX 1
|
||||||
|
# define WIN32_LEAN_AND_MEAN 1
|
||||||
|
#elif defined(Q_OS_ANDROID)
|
||||||
|
// I don't yet have a working libwebrtc for android
|
||||||
|
// # define WEBRTC_ENABLED 1
|
||||||
|
// # define WEBRTC_POSIX 1
|
||||||
|
#elif defined(Q_OS_LINUX)
|
||||||
|
# define WEBRTC_ENABLED 1
|
||||||
|
# define WEBRTC_POSIX 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(WEBRTC_ENABLED)
|
||||||
|
# include <modules/audio_processing/include/audio_processing.h>
|
||||||
|
# include "modules/audio_processing/audio_processing_impl.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // hifi_WebRTC_h
|
Loading…
Reference in a new issue