CHANGE(client): Remove bundled Opus version

Since newer versions of libsndfile now link to the system-wide installed
Opus version (on Linux distros), there would be a conflict between
symbols defined in the system-wide installation and the self-built
(bundled) Opus library.
This, as it turned out, can lead for instance to failing assertions due
to pointer identities no longer holding because e.g. a function from the
self-built Opus version ends up calling a sub-function from the
system-wide Opus installation instead. This is also the root cause for
the infamous "Opus crash" or "Audio wizard crash".

In order to avoid these issues, we don't ship a bundled Opus version
anymore and instead make it a build prerequisite to have Opus installed
on your system.

Fixes #5302
This commit is contained in:
Robert Adam 2022-12-27 19:49:57 +01:00
parent ca79e9a470
commit d11fd05062
19 changed files with 59 additions and 310 deletions

View File

@ -12,6 +12,6 @@ sudo apt-get -y install build-essential g++-multilib ninja-build pkg-config \
libboost-dev libssl-dev libprotobuf-dev protobuf-compiler libprotoc-dev \ libboost-dev libssl-dev libprotobuf-dev protobuf-compiler libprotoc-dev \
libcap-dev libxi-dev \ libcap-dev libxi-dev \
libasound2-dev libasound2-plugins libasound2-plugins-extra\ libasound2-dev libasound2-plugins libasound2-plugins-extra\
libogg-dev libsndfile1-dev libspeechd-dev \ libogg-dev libsndfile1-dev libopus-dev libspeechd-dev \
libavahi-compat-libdnssd-dev libzeroc-ice-dev \ libavahi-compat-libdnssd-dev libzeroc-ice-dev \
zsync appstream libpoco-dev zsync appstream libpoco-dev

View File

@ -8,7 +8,7 @@ freebsd_instance:
freebsd_task: freebsd_task:
pkg_script: pkg_script:
- pkg update && pkg upgrade -y - pkg update && pkg upgrade -y
- pkg install -y git ninja pkgconf cmake qt5-buildtools qt5-qmake qt5-linguisttools qt5-concurrent qt5-network qt5-xml qt5-sql qt5-svg qt5-testlib boost-libs libsndfile protobuf ice avahi-libdns poco - pkg install -y git ninja pkgconf cmake qt5-buildtools qt5-qmake qt5-linguisttools qt5-concurrent qt5-network qt5-xml qt5-sql qt5-svg qt5-testlib boost-libs libsndfile protobuf ice avahi-libdns poco opus
fetch_submodules_script: git submodule --quiet update --init --recursive fetch_submodules_script: git submodule --quiet update --init --recursive
build_script: build_script:
- mkdir build && cd build - mkdir build && cd build

View File

@ -23,6 +23,7 @@ sudo apt -y install \
libasound2-plugins-extra \ libasound2-plugins-extra \
libogg-dev \ libogg-dev \
libsndfile1-dev \ libsndfile1-dev \
libopus-dev \
libspeechd-dev \ libspeechd-dev \
libavahi-compat-libdnssd-dev \ libavahi-compat-libdnssd-dev \
libzeroc-ice-dev \ libzeroc-ice-dev \

3
.gitmodules vendored
View File

@ -1,6 +1,3 @@
[submodule "3rdparty/opus"]
path = 3rdparty/opus
url = https://github.com/mumble-voip/opus.git
[submodule "3rdparty/minhook"] [submodule "3rdparty/minhook"]
path = 3rdparty/minhook path = 3rdparty/minhook
url = https://github.com/mumble-voip/minhook.git url = https://github.com/mumble-voip/minhook.git

1
3rdparty/opus vendored

@ -1 +0,0 @@
Subproject commit 027cd11ed732d02456d1f049081d24b4626d5cb9

View File

@ -28,6 +28,7 @@ sudo apt install \
libasound2-dev \ libasound2-dev \
libogg-dev \ libogg-dev \
libsndfile1-dev \ libsndfile1-dev \
libopus-dev \
libspeechd-dev \ libspeechd-dev \
libavahi-compat-libdnssd-dev \ libavahi-compat-libdnssd-dev \
libxcb-xinerama0 \ libxcb-xinerama0 \

View File

@ -44,11 +44,6 @@ Use the bundled GSL version instead of looking for one on the system
Build the included version of nlohmann_json instead of looking for one on the system Build the included version of nlohmann_json instead of looking for one on the system
(Default: ON) (Default: ON)
### bundled-opus
Build the included version of Opus instead of looking for one on the system.
(Default: ON)
### bundled-rnnoise ### bundled-rnnoise
Build the included version of RNNoise instead of looking for one on the system. Build the included version of RNNoise instead of looking for one on the system.
@ -134,21 +129,6 @@ Whether or not tests that need a working internet connection should be included
Build a heavily optimized version, specific to the machine it's being compiled on. Build a heavily optimized version, specific to the machine it's being compiled on.
(Default: OFF) (Default: OFF)
### OPUS_BUILD_SHARED_LIBRARY
(No description available)
(Default: ON)
### OPUS_BUILD_TESTS
(No description available)
(Default: OFF)
### OPUS_STACK_PROTECTOR
(No description available)
(Default: OFF)
### oss ### oss
Build support for OSS. Build support for OSS.

View File

@ -86,7 +86,6 @@ public class ClientInstaller : MumbleInstall {
// 64 bit // 64 bit
this.Platform = WixSharp.Platform.x64; this.Platform = WixSharp.Platform.x64;
binaries = new List<string>() { binaries = new List<string>() {
"opus.dll",
"rnnoise.dll", "rnnoise.dll",
"speexdsp.dll", "speexdsp.dll",
"mumble.exe", "mumble.exe",
@ -107,7 +106,6 @@ public class ClientInstaller : MumbleInstall {
// 32 bit // 32 bit
this.Platform = WixSharp.Platform.x86; this.Platform = WixSharp.Platform.x86;
binaries = new List<string>() { binaries = new List<string>() {
"opus.dll",
"rnnoise.dll", "rnnoise.dll",
"speexdsp.dll", "speexdsp.dll",
"mumble.exe", "mumble.exe",

View File

@ -22,7 +22,6 @@ repoRoot = os.path.normpath(os.path.join(os.path.dirname(__file__), ".."))
# List of (3rdparty) licenses [<variableName>, <pathToLicenseFile>, <DisplayName>, <URL>, (<define-guard>)?] # List of (3rdparty) licenses [<variableName>, <pathToLicenseFile>, <DisplayName>, <URL>, (<define-guard>)?]
licenses = [ licenses = [
["licenseMumble", "LICENSE", "Mumble", "https://www.mumble.info/"], ["licenseMumble", "LICENSE", "Mumble", "https://www.mumble.info/"],
["licenseOpus", "3rdparty/opus/COPYING", "Opus", "http://www.opus-codec.org/"],
["licenseSPEEXDSP", "3rdparty/speexdsp/COPYING", "SpeexDSP", "http://www.speex.org/"], ["licenseSPEEXDSP", "3rdparty/speexdsp/COPYING", "SpeexDSP", "http://www.speex.org/"],
["licenseOpenSSL", "3rdPartyLicenses/openssl_license.txt", "OpenSSL", "http://www.openssl.org/"], ["licenseOpenSSL", "3rdPartyLicenses/openssl_license.txt", "OpenSSL", "http://www.openssl.org/"],
["licenseLibsndfile", "3rdPartyLicenses/libsndfile_license.txt", "libsndfile", "http://www.mega-nerd.com/libsndfile/"], ["licenseLibsndfile", "3rdPartyLicenses/libsndfile_license.txt", "libsndfile", "http://www.mega-nerd.com/libsndfile/"],

View File

@ -8,7 +8,6 @@
#include "AudioInput.h" #include "AudioInput.h"
#include "AudioOutput.h" #include "AudioOutput.h"
#include "Log.h" #include "Log.h"
#include "OpusCodec.h"
#include "PacketDataStream.h" #include "PacketDataStream.h"
#include "PluginManager.h" #include "PluginManager.h"
#include "Global.h" #include "Global.h"
@ -18,33 +17,9 @@
#include <cstring> #include <cstring>
class CodecInit : public DeferInit {
public:
void initialize();
void destroy();
};
#define DOUBLE_RAND (rand() / static_cast< double >(RAND_MAX)) #define DOUBLE_RAND (rand() / static_cast< double >(RAND_MAX))
LoopUser LoopUser::lpLoopy; LoopUser LoopUser::lpLoopy;
CodecInit ciInit;
void CodecInit::initialize() {
OpusCodec *oCodec = new OpusCodec();
if (oCodec->isValid()) {
oCodec->report();
Global::get().oCodec = oCodec;
} else {
Log::logOrDefer(
Log::CriticalError,
QObject::tr("CodecInit: Failed to load Opus, it will not be available for encoding/decoding audio."));
delete oCodec;
}
}
void CodecInit::destroy() {
delete Global::get().oCodec;
}
LoopUser::LoopUser() { LoopUser::LoopUser() {
qsName = QLatin1String("Loopy"); qsName = QLatin1String("Loopy");

View File

@ -10,7 +10,6 @@
#include "MainWindow.h" #include "MainWindow.h"
#include "MumbleProtocol.h" #include "MumbleProtocol.h"
#include "NetworkConfig.h" #include "NetworkConfig.h"
#include "OpusCodec.h"
#include "PacketDataStream.h" #include "PacketDataStream.h"
#include "PluginManager.h" #include "PluginManager.h"
#include "ServerHandler.h" #include "ServerHandler.h"
@ -19,6 +18,8 @@
#include "VoiceRecorder.h" #include "VoiceRecorder.h"
#include "Global.h" #include "Global.h"
#include <opus.h>
#ifdef USE_RNNOISE #ifdef USE_RNNOISE
extern "C" { extern "C" {
# include "rnnoise.h" # include "rnnoise.h"
@ -228,25 +229,21 @@ AudioInput::AudioInput() : opusBuffer(Global::get().s.iFramesPerPacket * (SAMPLE
m_codec = Mumble::Protocol::AudioCodec::Opus; m_codec = Mumble::Protocol::AudioCodec::Opus;
activityState = ActivityStateActive; activityState = ActivityStateActive;
oCodec = nullptr;
opusState = nullptr; opusState = nullptr;
oCodec = Global::get().oCodec; if (bAllowLowDelay && iAudioQuality >= 64000) { // > 64 kbit/s bitrate and low delay allowed
if (oCodec) { opusState = opus_encoder_create(SAMPLE_RATE, 1, OPUS_APPLICATION_RESTRICTED_LOWDELAY, nullptr);
if (bAllowLowDelay && iAudioQuality >= 64000) { // > 64 kbit/s bitrate and low delay allowed qWarning("AudioInput: Opus encoder set for low delay");
opusState = oCodec->opus_encoder_create(SAMPLE_RATE, 1, OPUS_APPLICATION_RESTRICTED_LOWDELAY, nullptr); } else if (iAudioQuality >= 32000) { // > 32 kbit/s bitrate
qWarning("AudioInput: Opus encoder set for low delay"); opusState = opus_encoder_create(SAMPLE_RATE, 1, OPUS_APPLICATION_AUDIO, nullptr);
} else if (iAudioQuality >= 32000) { // > 32 kbit/s bitrate qWarning("AudioInput: Opus encoder set for high quality speech");
opusState = oCodec->opus_encoder_create(SAMPLE_RATE, 1, OPUS_APPLICATION_AUDIO, nullptr); } else {
qWarning("AudioInput: Opus encoder set for high quality speech"); opusState = opus_encoder_create(SAMPLE_RATE, 1, OPUS_APPLICATION_VOIP, nullptr);
} else { qWarning("AudioInput: Opus encoder set for low quality speech");
opusState = oCodec->opus_encoder_create(SAMPLE_RATE, 1, OPUS_APPLICATION_VOIP, nullptr);
qWarning("AudioInput: Opus encoder set for low quality speech");
}
oCodec->opus_encoder_ctl(opusState, OPUS_SET_VBR(0)); // CBR
} }
opus_encoder_ctl(opusState, OPUS_SET_VBR(0)); // CBR
#ifdef USE_RNNOISE #ifdef USE_RNNOISE
denoiseState = rnnoise_create(nullptr); denoiseState = rnnoise_create(nullptr);
#endif #endif
@ -296,7 +293,7 @@ AudioInput::~AudioInput() {
wait(); wait();
if (opusState) { if (opusState) {
oCodec->opus_encoder_destroy(opusState); opus_encoder_destroy(opusState);
} }
#ifdef USE_RNNOISE #ifdef USE_RNNOISE
@ -846,18 +843,14 @@ void AudioInput::selectNoiseCancel() {
int AudioInput::encodeOpusFrame(short *source, int size, EncodingOutputBuffer &buffer) { int AudioInput::encodeOpusFrame(short *source, int size, EncodingOutputBuffer &buffer) {
int len; int len;
if (!oCodec) {
return 0;
}
if (bResetEncoder) { if (bResetEncoder) {
oCodec->opus_encoder_ctl(opusState, OPUS_RESET_STATE, nullptr); opus_encoder_ctl(opusState, OPUS_RESET_STATE, nullptr);
bResetEncoder = false; bResetEncoder = false;
} }
oCodec->opus_encoder_ctl(opusState, OPUS_SET_BITRATE(iAudioQuality)); opus_encoder_ctl(opusState, OPUS_SET_BITRATE(iAudioQuality));
len = oCodec->opus_encode(opusState, source, size, &buffer[0], static_cast< opus_int32 >(buffer.size())); len = opus_encode(opusState, source, size, &buffer[0], static_cast< opus_int32 >(buffer.size()));
const int tenMsFrameCount = (size / iFrameSize); const int tenMsFrameCount = (size / iFrameSize);
iBitrate = (len * 100 * 8) / tenMsFrameCount; iBitrate = (len * 100 * 8) / tenMsFrameCount;
return len; return len;

View File

@ -30,7 +30,6 @@
#include "Timer.h" #include "Timer.h"
class AudioInput; class AudioInput;
class OpusCodec;
struct OpusEncoder; struct OpusEncoder;
struct DenoiseState; struct DenoiseState;
typedef boost::shared_ptr< AudioInput > AudioInputPtr; typedef boost::shared_ptr< AudioInput > AudioInputPtr;
@ -187,7 +186,6 @@ private:
inMixerFunc chooseMixer(const unsigned int nchan, SampleFormat sf, quint64 mask); inMixerFunc chooseMixer(const unsigned int nchan, SampleFormat sf, quint64 mask);
void resetAudioProcessor(); void resetAudioProcessor();
OpusCodec *oCodec;
OpusEncoder *opusState; OpusEncoder *opusState;
DenoiseState *denoiseState; DenoiseState *denoiseState;
bool selectCodec(); bool selectCodec();

View File

@ -7,11 +7,12 @@
#include "Audio.h" #include "Audio.h"
#include "ClientUser.h" #include "ClientUser.h"
#include "OpusCodec.h"
#include "PacketDataStream.h" #include "PacketDataStream.h"
#include "Utils.h" #include "Utils.h"
#include "Global.h" #include "Global.h"
#include <opus.h>
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <cmath> #include <cmath>
@ -59,7 +60,6 @@ AudioOutputSpeech::AudioOutputSpeech(ClientUser *user, unsigned int freq, Mumble
: AudioOutputUser(user->qsName), iMixerFreq(freq), m_codec(codec), p(user) { : AudioOutputUser(user->qsName), iMixerFreq(freq), m_codec(codec), p(user) {
int err; int err;
oCodec = nullptr;
opusState = nullptr; opusState = nullptr;
bHasTerminator = false; bHasTerminator = false;
@ -80,13 +80,10 @@ AudioOutputSpeech::AudioOutputSpeech(ClientUser *user, unsigned int freq, Mumble
// Always pretend Stereo mode is true by default. since opus will convert mono stream to stereo stream. // Always pretend Stereo mode is true by default. since opus will convert mono stream to stereo stream.
// https://tools.ietf.org/html/rfc6716#section-2.1.2 // https://tools.ietf.org/html/rfc6716#section-2.1.2
bStereo = true; bStereo = true;
oCodec = Global::get().oCodec; opusState = opus_decoder_create(iSampleRate, bStereo ? 2 : 1, nullptr);
if (oCodec) { opus_decoder_ctl(opusState,
opusState = oCodec->opus_decoder_create(iSampleRate, bStereo ? 2 : 1, nullptr); OPUS_SET_PHASE_INVERSION_DISABLED(1)); // Disable phase inversion for better mono downmix.
oCodec->opus_decoder_ctl(
opusState, OPUS_SET_PHASE_INVERSION_DISABLED(1)); // Disable phase inversion for better mono downmix.
}
// iAudioBufferSize: size (in unit of float) of the buffer used to store decoded pcm data. // iAudioBufferSize: size (in unit of float) of the buffer used to store decoded pcm data.
// For opus, the maximum frame size of a packet is 60ms. // For opus, the maximum frame size of a packet is 60ms.
@ -157,7 +154,7 @@ AudioOutputSpeech::AudioOutputSpeech(ClientUser *user, unsigned int freq, Mumble
AudioOutputSpeech::~AudioOutputSpeech() { AudioOutputSpeech::~AudioOutputSpeech() {
if (opusState) { if (opusState) {
oCodec->opus_decoder_destroy(opusState); opus_decoder_destroy(opusState);
} }
if (srs) if (srs)
@ -186,12 +183,9 @@ void AudioOutputSpeech::addFrameToBuffer(const Mumble::Protocol::AudioData &audi
assert(m_codec == Mumble::Protocol::AudioCodec::Opus); assert(m_codec == Mumble::Protocol::AudioCodec::Opus);
assert(audioData.usedCodec == m_codec); assert(audioData.usedCodec == m_codec);
if (oCodec) { samples = opus_decoder_get_nb_samples(opusState, audioData.payload.data(),
samples = audioData.payload.size()); // this function return samples per channel
oCodec->opus_decoder_get_nb_samples(opusState, audioData.payload.data(), samples *= 2; // since we assume all input stream is stereo.
audioData.payload.size()); // this function return samples per channel
samples *= 2; // since we assume all input stream is stereo.
}
// We can't handle frames which are not a multiple of our configured framesize. // We can't handle frames which are not a multiple of our configured framesize.
if (samples % iFrameSize != 0) { if (samples % iFrameSize != 0) {
@ -334,28 +328,25 @@ bool AudioOutputSpeech::prepareSampleBuffer(unsigned int frameCount) {
assert(m_codec == Mumble::Protocol::AudioCodec::Opus); assert(m_codec == Mumble::Protocol::AudioCodec::Opus);
if (oCodec) { if (qba.isEmpty() || !(p && p->bLocalMute)) {
if (qba.isEmpty() || !(p && p->bLocalMute)) { // If qba is empty, we have to let Opus know about the packet loss
// If qba is empty, we have to let Opus know about the packet loss // Otherwise if the associated user is not locally muted, we want to decode the audio
// Otherwise if the associated user is not locally muted, we want to decode the audio // packet normally in order to be able to play it.
// packet normally in order to be able to play it. decodedSamples = opus_decode_float(
decodedSamples = oCodec->opus_decode_float( opusState, qba.isEmpty() ? nullptr : reinterpret_cast< const unsigned char * >(qba.constData()),
opusState, qba.size(), pOut, iAudioBufferSize, 0);
qba.isEmpty() ? nullptr : reinterpret_cast< const unsigned char * >(qba.constData()), } else {
qba.size(), pOut, iAudioBufferSize, 0); // If the packet is non-empty, but the associated user is locally muted,
} else { // we don't have to decode the packet. Instead it is enough to know how many
// If the packet is non-empty, but the associated user is locally muted, // samples it contained so that we can then mute the appropriate output length
// we don't have to decode the packet. Instead it is enough to know how many decodedSamples = opus_packet_get_samples_per_frame(
// samples it contained so that we can then mute the appropriate output length reinterpret_cast< const unsigned char * >(qba.constData()), SAMPLE_RATE);
decodedSamples = oCodec->opus_packet_get_samples_per_frame(
reinterpret_cast< const unsigned char * >(qba.constData()), SAMPLE_RATE);
}
// The returned sample count we get from the Opus functions refer to samples per channel.
// Thus in order to get the total amount, we have to multiply by the channel count.
decodedSamples *= channels;
} }
// The returned sample count we get from the Opus functions refer to samples per channel.
// Thus in order to get the total amount, we have to multiply by the channel count.
decodedSamples *= channels;
if (decodedSamples < 0) { if (decodedSamples < 0) {
decodedSamples = iFrameSize; decodedSamples = iFrameSize;
memset(pOut, 0, iFrameSize * sizeof(float)); memset(pOut, 0, iFrameSize * sizeof(float));
@ -395,10 +386,8 @@ bool AudioOutputSpeech::prepareSampleBuffer(unsigned int frameCount) {
} }
} else { } else {
assert(m_codec == Mumble::Protocol::AudioCodec::Opus); assert(m_codec == Mumble::Protocol::AudioCodec::Opus);
if (oCodec) { decodedSamples = opus_decode_float(opusState, nullptr, 0, pOut, iFrameSize, 0);
decodedSamples = oCodec->opus_decode_float(opusState, nullptr, 0, pOut, iFrameSize, 0); decodedSamples *= channels;
decodedSamples *= channels;
}
if (decodedSamples < 0) { if (decodedSamples < 0) {
decodedSamples = iFrameSize; decodedSamples = iFrameSize;

View File

@ -18,7 +18,6 @@
#include <mutex> #include <mutex>
#include <vector> #include <vector>
class OpusCodec;
class ClientUser; class ClientUser;
struct OpusDecoder; struct OpusDecoder;
@ -55,7 +54,6 @@ protected:
JitterBuffer *jbJitter; JitterBuffer *jbJitter;
int iMissCount; int iMissCount;
OpusCodec *oCodec;
OpusDecoder *opusState; OpusDecoder *opusState;
QList< QByteArray > qlFrames; QList< QByteArray > qlFrames;

View File

@ -22,7 +22,6 @@ option(update "Check for updates by default." ON)
option(translations "Include languages other than English." ON) option(translations "Include languages other than English." ON)
option(bundle-qt-translations "Bundle Qt's translations as well" ${static}) option(bundle-qt-translations "Bundle Qt's translations as well" ${static})
option(bundled-opus "Build the included version of Opus instead of looking for one on the system." ON)
option(bundled-speex "Build the included version of Speex instead of looking for one on the system." ON) option(bundled-speex "Build the included version of Speex instead of looking for one on the system." ON)
option(rnnoise "Use RNNoise for machine learning noise reduction." ON) option(rnnoise "Use RNNoise for machine learning noise reduction." ON)
option(bundled-rnnoise "Build the included version of RNNoise instead of looking for one on the system." ${rnnoise}) option(bundled-rnnoise "Build the included version of RNNoise instead of looking for one on the system." ${rnnoise})
@ -184,8 +183,6 @@ set(MUMBLE_SOURCES
"NetworkConfig.cpp" "NetworkConfig.cpp"
"NetworkConfig.h" "NetworkConfig.h"
"NetworkConfig.ui" "NetworkConfig.ui"
"OpusCodec.cpp"
"OpusCodec.h"
"PluginConfig.cpp" "PluginConfig.cpp"
"PluginConfig.h" "PluginConfig.h"
"PluginConfig.ui" "PluginConfig.ui"
@ -694,37 +691,15 @@ else()
endif() endif()
endif() endif()
if(bundled-opus) find_pkg("opus;Opus" REQUIRED)
option(OPUS_BUILD_SHARED_LIBRARY "" ON) target_include_directories(mumble_client_object_lib PUBLIC ${opus_INCLUDE_DIRS})
option(OPUS_BUILD_TESTS "" OFF) target_link_libraries(mumble_client_object_lib PUBLIC ${opus_LIBRARIES})
if(MINGW) if(TARGET opus)
option(OPUS_STACK_PROTECTOR "" OFF) target_link_libraries(mumble_client_object_lib PUBLIC opus)
endif() elseif(TARGET Opus)
target_link_libraries(mumble_client_object_lib PUBLIC Opus)
add_subdirectory("${3RDPARTY_DIR}/opus" "${CMAKE_CURRENT_BINARY_DIR}/opus" EXCLUDE_FROM_ALL) elseif(TARGET Opus::opus)
target_link_libraries(mumble_client_object_lib PUBLIC Opus::opus)
# Disable all warnings that the Opus code may emit
disable_warnings_for_all_targets_in("${3RDPARTY_DIR}/opus")
# Opus doesn't work in unity builds
set_target_properties(opus PROPERTIES UNITY_BUILD FALSE)
add_dependencies(mumble_client_object_lib opus)
target_include_directories(mumble_client_object_lib PUBLIC "${3RDPARTY_DIR}/opus/include")
if(WIN32)
# Shared library on Windows (e.g. ".dll")
set_target_properties(opus PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
else()
# Shared library on UNIX (e.g. ".so")
set_target_properties(opus PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
endif()
install_library(opus mumble_client)
else()
find_pkg(opus REQUIRED)
target_include_directories(mumble_client_object_lib PUBLIC ${opus_INCLUDE_DIRS})
endif() endif()
if(bundled-speex) if(bundled-speex)

View File

@ -31,7 +31,6 @@ class Overlay;
class LCD; class LCD;
class Zeroconf; class Zeroconf;
class OverlayClient; class OverlayClient;
class OpusCodec;
class LogEmitter; class LogEmitter;
class DeveloperConsole; class DeveloperConsole;
class TalkingUI; class TalkingUI;
@ -96,7 +95,6 @@ public:
int iMaxBandwidth; int iMaxBandwidth;
int iAudioBandwidth; int iAudioBandwidth;
QDir qdBasePath; QDir qdBasePath;
OpusCodec *oCodec;
bool bAttenuateOthers; bool bAttenuateOthers;
/// If set the AudioOutput::mix will forcefully adjust the volume of all /// If set the AudioOutput::mix will forcefully adjust the volume of all
/// non-priority speakers. /// non-priority speakers.

View File

@ -21,7 +21,6 @@
#include "Log.h" #include "Log.h"
#include "Net.h" #include "Net.h"
#include "NetworkConfig.h" #include "NetworkConfig.h"
#include "OpusCodec.h"
#include "GlobalShortcut.h" #include "GlobalShortcut.h"
#include "GlobalShortcutTypes.h" #include "GlobalShortcutTypes.h"
#ifdef USE_OVERLAY #ifdef USE_OVERLAY

View File

@ -1,100 +0,0 @@
// Copyright 2018-2022 The Mumble Developers. All rights reserved.
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file at the root of the
// Mumble source tree or at <https://www.mumble.info/LICENSE>.
#include "OpusCodec.h"
#include "Audio.h"
#include "MumbleApplication.h"
#include "Version.h"
#ifdef Q_CC_GNU
# define RESOLVE(var) \
{ \
var = reinterpret_cast< __typeof__(var) >(qlOpus.resolve(#var)); \
bValid = bValid && var; \
}
#else
# define RESOLVE(var) \
{ \
*reinterpret_cast< void ** >(&var) = static_cast< void * >(qlOpus.resolve(#var)); \
bValid = bValid && var; \
}
#endif
OpusCodec::OpusCodec() {
bValid = false;
qlOpus.setLoadHints(QLibrary::ResolveAllSymbolsHint);
QStringList alternatives;
#if defined(Q_OS_MAC)
alternatives << QString::fromLatin1("libopus0.dylib");
alternatives << QString::fromLatin1("opus0.dylib");
alternatives << QString::fromLatin1("libopus.dylib");
alternatives << QString::fromLatin1("opus.dylib");
#elif defined(Q_OS_UNIX)
alternatives << QString::fromLatin1("libopus.so.0");
alternatives << QString::fromLatin1("libopus0.so");
alternatives << QString::fromLatin1("libopus.so");
alternatives << QString::fromLatin1("opus.so");
#else
alternatives << QString::fromLatin1("opus0.dll");
alternatives << QString::fromLatin1("opus.dll");
#endif
QStringList basePaths;
basePaths << MumbleApplication::instance()->applicationVersionRootPath() + "/";
#ifdef Q_OS_MAC
basePaths << QApplication::instance()->applicationDirPath() + "/../Codecs/";
#endif
#ifdef MUMBLE_LIBRARY_PATH
basePaths << MUMTEXT(MUMBLE_LIBRARY_PATH) "/";
#endif
basePaths << ""; // General search without telling it a particular path to look for
for (const QString &basePath : basePaths) {
for (const QString &libName : alternatives) {
qlOpus.setFileName(basePath + libName);
if (qlOpus.load()) {
bValid = true;
break;
}
}
if (bValid) {
break;
}
}
RESOLVE(opus_get_version_string);
RESOLVE(opus_encode);
RESOLVE(opus_decode_float);
RESOLVE(opus_encoder_create);
RESOLVE(opus_encoder_ctl);
RESOLVE(opus_encoder_destroy);
RESOLVE(opus_decoder_create);
RESOLVE(opus_decoder_ctl);
RESOLVE(opus_decoder_destroy);
RESOLVE(opus_decoder_get_nb_samples);
RESOLVE(opus_packet_get_samples_per_frame);
}
OpusCodec::~OpusCodec() {
qlOpus.unload();
}
bool OpusCodec::isValid() const {
return bValid;
}
void OpusCodec::report() const {
qDebug("%s from %s", opus_get_version_string(), qPrintable(qlOpus.fileName()));
}
#undef RESOLVE

View File

@ -1,51 +0,0 @@
// Copyright 2018-2022 The Mumble Developers. All rights reserved.
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file at the root of the
// Mumble source tree or at <https://www.mumble.info/LICENSE>.
#ifndef MUMBLE_MUMBLE_OPUSCODEC_H_
#define MUMBLE_MUMBLE_OPUSCODEC_H_
#include <opus.h>
#include <QtCore/QLibrary>
#ifndef Q_OS_WIN
# define __cdecl
#endif
/// Loads Opus from a shared library and acts as a wrapper for its functions.
class OpusCodec {
private:
Q_DISABLE_COPY(OpusCodec)
protected:
QLibrary qlOpus;
bool bValid;
public:
OpusCodec();
virtual ~OpusCodec();
bool isValid() const;
void report() const;
const char *(__cdecl *opus_get_version_string)();
OpusEncoder *(__cdecl *opus_encoder_create)(opus_int32 Fs, int channels, int application, int *error);
int(__cdecl *opus_encoder_ctl)(OpusEncoder *st, int request, ...);
void(__cdecl *opus_encoder_destroy)(OpusEncoder *st);
OpusDecoder *(__cdecl *opus_decoder_create)(opus_int32 Fs, int channels, int *error);
int(__cdecl *opus_decoder_ctl)(OpusDecoder *st, int request, ...);
void(__cdecl *opus_decoder_destroy)(OpusDecoder *st);
int(__cdecl *opus_encode)(OpusEncoder *st, const opus_int16 *pcm, int frame_size, unsigned char *compressed,
int nbCompressedBytes);
int(__cdecl *opus_decode_float)(OpusDecoder *st, const unsigned char *data, opus_int32 len, float *pcm,
int frame_size, int decode_fec);
int(__cdecl *opus_decoder_get_nb_samples)(OpusDecoder *st, const unsigned char packet[], opus_int32 len);
int(__cdecl *opus_packet_get_samples_per_frame)(const unsigned char *data, opus_int32 Fs);
};
#endif // OPUSCODEC_H_