mirror of
https://github.com/mumble-voip/mumble.git
synced 2025-10-26 11:19:16 +00:00
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:
parent
ca79e9a470
commit
d11fd05062
@ -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 \
|
||||
libcap-dev libxi-dev \
|
||||
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 \
|
||||
zsync appstream libpoco-dev
|
||||
|
||||
@ -8,7 +8,7 @@ freebsd_instance:
|
||||
freebsd_task:
|
||||
pkg_script:
|
||||
- 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
|
||||
build_script:
|
||||
- mkdir build && cd build
|
||||
|
||||
@ -23,6 +23,7 @@ sudo apt -y install \
|
||||
libasound2-plugins-extra \
|
||||
libogg-dev \
|
||||
libsndfile1-dev \
|
||||
libopus-dev \
|
||||
libspeechd-dev \
|
||||
libavahi-compat-libdnssd-dev \
|
||||
libzeroc-ice-dev \
|
||||
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -1,6 +1,3 @@
|
||||
[submodule "3rdparty/opus"]
|
||||
path = 3rdparty/opus
|
||||
url = https://github.com/mumble-voip/opus.git
|
||||
[submodule "3rdparty/minhook"]
|
||||
path = 3rdparty/minhook
|
||||
url = https://github.com/mumble-voip/minhook.git
|
||||
|
||||
1
3rdparty/opus
vendored
1
3rdparty/opus
vendored
@ -1 +0,0 @@
|
||||
Subproject commit 027cd11ed732d02456d1f049081d24b4626d5cb9
|
||||
@ -28,6 +28,7 @@ sudo apt install \
|
||||
libasound2-dev \
|
||||
libogg-dev \
|
||||
libsndfile1-dev \
|
||||
libopus-dev \
|
||||
libspeechd-dev \
|
||||
libavahi-compat-libdnssd-dev \
|
||||
libxcb-xinerama0 \
|
||||
|
||||
@ -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
|
||||
(Default: ON)
|
||||
|
||||
### bundled-opus
|
||||
|
||||
Build the included version of Opus instead of looking for one on the system.
|
||||
(Default: ON)
|
||||
|
||||
### bundled-rnnoise
|
||||
|
||||
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.
|
||||
(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
|
||||
|
||||
Build support for OSS.
|
||||
|
||||
@ -86,7 +86,6 @@ public class ClientInstaller : MumbleInstall {
|
||||
// 64 bit
|
||||
this.Platform = WixSharp.Platform.x64;
|
||||
binaries = new List<string>() {
|
||||
"opus.dll",
|
||||
"rnnoise.dll",
|
||||
"speexdsp.dll",
|
||||
"mumble.exe",
|
||||
@ -107,7 +106,6 @@ public class ClientInstaller : MumbleInstall {
|
||||
// 32 bit
|
||||
this.Platform = WixSharp.Platform.x86;
|
||||
binaries = new List<string>() {
|
||||
"opus.dll",
|
||||
"rnnoise.dll",
|
||||
"speexdsp.dll",
|
||||
"mumble.exe",
|
||||
|
||||
@ -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>)?]
|
||||
licenses = [
|
||||
["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/"],
|
||||
["licenseOpenSSL", "3rdPartyLicenses/openssl_license.txt", "OpenSSL", "http://www.openssl.org/"],
|
||||
["licenseLibsndfile", "3rdPartyLicenses/libsndfile_license.txt", "libsndfile", "http://www.mega-nerd.com/libsndfile/"],
|
||||
|
||||
@ -8,7 +8,6 @@
|
||||
#include "AudioInput.h"
|
||||
#include "AudioOutput.h"
|
||||
#include "Log.h"
|
||||
#include "OpusCodec.h"
|
||||
#include "PacketDataStream.h"
|
||||
#include "PluginManager.h"
|
||||
#include "Global.h"
|
||||
@ -18,33 +17,9 @@
|
||||
#include <cstring>
|
||||
|
||||
|
||||
class CodecInit : public DeferInit {
|
||||
public:
|
||||
void initialize();
|
||||
void destroy();
|
||||
};
|
||||
|
||||
#define DOUBLE_RAND (rand() / static_cast< double >(RAND_MAX))
|
||||
|
||||
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() {
|
||||
qsName = QLatin1String("Loopy");
|
||||
|
||||
@ -10,7 +10,6 @@
|
||||
#include "MainWindow.h"
|
||||
#include "MumbleProtocol.h"
|
||||
#include "NetworkConfig.h"
|
||||
#include "OpusCodec.h"
|
||||
#include "PacketDataStream.h"
|
||||
#include "PluginManager.h"
|
||||
#include "ServerHandler.h"
|
||||
@ -19,6 +18,8 @@
|
||||
#include "VoiceRecorder.h"
|
||||
#include "Global.h"
|
||||
|
||||
#include <opus.h>
|
||||
|
||||
#ifdef USE_RNNOISE
|
||||
extern "C" {
|
||||
# include "rnnoise.h"
|
||||
@ -228,25 +229,21 @@ AudioInput::AudioInput() : opusBuffer(Global::get().s.iFramesPerPacket * (SAMPLE
|
||||
m_codec = Mumble::Protocol::AudioCodec::Opus;
|
||||
|
||||
activityState = ActivityStateActive;
|
||||
oCodec = nullptr;
|
||||
opusState = nullptr;
|
||||
|
||||
oCodec = Global::get().oCodec;
|
||||
if (oCodec) {
|
||||
if (bAllowLowDelay && iAudioQuality >= 64000) { // > 64 kbit/s bitrate and low delay allowed
|
||||
opusState = oCodec->opus_encoder_create(SAMPLE_RATE, 1, OPUS_APPLICATION_RESTRICTED_LOWDELAY, nullptr);
|
||||
qWarning("AudioInput: Opus encoder set for low delay");
|
||||
} else if (iAudioQuality >= 32000) { // > 32 kbit/s bitrate
|
||||
opusState = oCodec->opus_encoder_create(SAMPLE_RATE, 1, OPUS_APPLICATION_AUDIO, nullptr);
|
||||
qWarning("AudioInput: Opus encoder set for high quality speech");
|
||||
} else {
|
||||
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
|
||||
if (bAllowLowDelay && iAudioQuality >= 64000) { // > 64 kbit/s bitrate and low delay allowed
|
||||
opusState = opus_encoder_create(SAMPLE_RATE, 1, OPUS_APPLICATION_RESTRICTED_LOWDELAY, nullptr);
|
||||
qWarning("AudioInput: Opus encoder set for low delay");
|
||||
} else if (iAudioQuality >= 32000) { // > 32 kbit/s bitrate
|
||||
opusState = opus_encoder_create(SAMPLE_RATE, 1, OPUS_APPLICATION_AUDIO, nullptr);
|
||||
qWarning("AudioInput: Opus encoder set for high quality speech");
|
||||
} else {
|
||||
opusState = opus_encoder_create(SAMPLE_RATE, 1, OPUS_APPLICATION_VOIP, nullptr);
|
||||
qWarning("AudioInput: Opus encoder set for low quality speech");
|
||||
}
|
||||
|
||||
opus_encoder_ctl(opusState, OPUS_SET_VBR(0)); // CBR
|
||||
|
||||
#ifdef USE_RNNOISE
|
||||
denoiseState = rnnoise_create(nullptr);
|
||||
#endif
|
||||
@ -296,7 +293,7 @@ AudioInput::~AudioInput() {
|
||||
wait();
|
||||
|
||||
if (opusState) {
|
||||
oCodec->opus_encoder_destroy(opusState);
|
||||
opus_encoder_destroy(opusState);
|
||||
}
|
||||
|
||||
#ifdef USE_RNNOISE
|
||||
@ -846,18 +843,14 @@ void AudioInput::selectNoiseCancel() {
|
||||
|
||||
int AudioInput::encodeOpusFrame(short *source, int size, EncodingOutputBuffer &buffer) {
|
||||
int len;
|
||||
if (!oCodec) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (bResetEncoder) {
|
||||
oCodec->opus_encoder_ctl(opusState, OPUS_RESET_STATE, nullptr);
|
||||
opus_encoder_ctl(opusState, OPUS_RESET_STATE, nullptr);
|
||||
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);
|
||||
iBitrate = (len * 100 * 8) / tenMsFrameCount;
|
||||
return len;
|
||||
|
||||
@ -30,7 +30,6 @@
|
||||
#include "Timer.h"
|
||||
|
||||
class AudioInput;
|
||||
class OpusCodec;
|
||||
struct OpusEncoder;
|
||||
struct DenoiseState;
|
||||
typedef boost::shared_ptr< AudioInput > AudioInputPtr;
|
||||
@ -187,7 +186,6 @@ private:
|
||||
inMixerFunc chooseMixer(const unsigned int nchan, SampleFormat sf, quint64 mask);
|
||||
void resetAudioProcessor();
|
||||
|
||||
OpusCodec *oCodec;
|
||||
OpusEncoder *opusState;
|
||||
DenoiseState *denoiseState;
|
||||
bool selectCodec();
|
||||
|
||||
@ -7,11 +7,12 @@
|
||||
|
||||
#include "Audio.h"
|
||||
#include "ClientUser.h"
|
||||
#include "OpusCodec.h"
|
||||
#include "PacketDataStream.h"
|
||||
#include "Utils.h"
|
||||
#include "Global.h"
|
||||
|
||||
#include <opus.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
@ -59,7 +60,6 @@ AudioOutputSpeech::AudioOutputSpeech(ClientUser *user, unsigned int freq, Mumble
|
||||
: AudioOutputUser(user->qsName), iMixerFreq(freq), m_codec(codec), p(user) {
|
||||
int err;
|
||||
|
||||
oCodec = nullptr;
|
||||
opusState = nullptr;
|
||||
|
||||
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.
|
||||
// https://tools.ietf.org/html/rfc6716#section-2.1.2
|
||||
bStereo = true;
|
||||
oCodec = Global::get().oCodec;
|
||||
if (oCodec) {
|
||||
opusState = oCodec->opus_decoder_create(iSampleRate, bStereo ? 2 : 1, nullptr);
|
||||
oCodec->opus_decoder_ctl(
|
||||
opusState, OPUS_SET_PHASE_INVERSION_DISABLED(1)); // Disable phase inversion for better mono downmix.
|
||||
}
|
||||
bStereo = true;
|
||||
opusState = opus_decoder_create(iSampleRate, bStereo ? 2 : 1, nullptr);
|
||||
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.
|
||||
// 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() {
|
||||
if (opusState) {
|
||||
oCodec->opus_decoder_destroy(opusState);
|
||||
opus_decoder_destroy(opusState);
|
||||
}
|
||||
|
||||
if (srs)
|
||||
@ -186,12 +183,9 @@ void AudioOutputSpeech::addFrameToBuffer(const Mumble::Protocol::AudioData &audi
|
||||
assert(m_codec == Mumble::Protocol::AudioCodec::Opus);
|
||||
assert(audioData.usedCodec == m_codec);
|
||||
|
||||
if (oCodec) {
|
||||
samples =
|
||||
oCodec->opus_decoder_get_nb_samples(opusState, audioData.payload.data(),
|
||||
audioData.payload.size()); // this function return samples per channel
|
||||
samples *= 2; // since we assume all input stream is stereo.
|
||||
}
|
||||
samples = opus_decoder_get_nb_samples(opusState, audioData.payload.data(),
|
||||
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.
|
||||
if (samples % iFrameSize != 0) {
|
||||
@ -334,28 +328,25 @@ bool AudioOutputSpeech::prepareSampleBuffer(unsigned int frameCount) {
|
||||
|
||||
assert(m_codec == Mumble::Protocol::AudioCodec::Opus);
|
||||
|
||||
if (oCodec) {
|
||||
if (qba.isEmpty() || !(p && p->bLocalMute)) {
|
||||
// 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
|
||||
// packet normally in order to be able to play it.
|
||||
decodedSamples = oCodec->opus_decode_float(
|
||||
opusState,
|
||||
qba.isEmpty() ? nullptr : reinterpret_cast< const unsigned char * >(qba.constData()),
|
||||
qba.size(), pOut, iAudioBufferSize, 0);
|
||||
} else {
|
||||
// If the packet is non-empty, but the associated user is locally muted,
|
||||
// we don't have to decode the packet. Instead it is enough to know how many
|
||||
// samples it contained so that we can then mute the appropriate output length
|
||||
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;
|
||||
if (qba.isEmpty() || !(p && p->bLocalMute)) {
|
||||
// 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
|
||||
// packet normally in order to be able to play it.
|
||||
decodedSamples = opus_decode_float(
|
||||
opusState, qba.isEmpty() ? nullptr : reinterpret_cast< const unsigned char * >(qba.constData()),
|
||||
qba.size(), pOut, iAudioBufferSize, 0);
|
||||
} else {
|
||||
// If the packet is non-empty, but the associated user is locally muted,
|
||||
// we don't have to decode the packet. Instead it is enough to know how many
|
||||
// samples it contained so that we can then mute the appropriate output length
|
||||
decodedSamples = 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;
|
||||
|
||||
if (decodedSamples < 0) {
|
||||
decodedSamples = iFrameSize;
|
||||
memset(pOut, 0, iFrameSize * sizeof(float));
|
||||
@ -395,10 +386,8 @@ bool AudioOutputSpeech::prepareSampleBuffer(unsigned int frameCount) {
|
||||
}
|
||||
} else {
|
||||
assert(m_codec == Mumble::Protocol::AudioCodec::Opus);
|
||||
if (oCodec) {
|
||||
decodedSamples = oCodec->opus_decode_float(opusState, nullptr, 0, pOut, iFrameSize, 0);
|
||||
decodedSamples *= channels;
|
||||
}
|
||||
decodedSamples = opus_decode_float(opusState, nullptr, 0, pOut, iFrameSize, 0);
|
||||
decodedSamples *= channels;
|
||||
|
||||
if (decodedSamples < 0) {
|
||||
decodedSamples = iFrameSize;
|
||||
|
||||
@ -18,7 +18,6 @@
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
class OpusCodec;
|
||||
class ClientUser;
|
||||
struct OpusDecoder;
|
||||
|
||||
@ -55,7 +54,6 @@ protected:
|
||||
JitterBuffer *jbJitter;
|
||||
int iMissCount;
|
||||
|
||||
OpusCodec *oCodec;
|
||||
OpusDecoder *opusState;
|
||||
|
||||
QList< QByteArray > qlFrames;
|
||||
|
||||
@ -22,7 +22,6 @@ option(update "Check for updates by default." ON)
|
||||
option(translations "Include languages other than English." ON)
|
||||
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(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})
|
||||
@ -184,8 +183,6 @@ set(MUMBLE_SOURCES
|
||||
"NetworkConfig.cpp"
|
||||
"NetworkConfig.h"
|
||||
"NetworkConfig.ui"
|
||||
"OpusCodec.cpp"
|
||||
"OpusCodec.h"
|
||||
"PluginConfig.cpp"
|
||||
"PluginConfig.h"
|
||||
"PluginConfig.ui"
|
||||
@ -694,37 +691,15 @@ else()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(bundled-opus)
|
||||
option(OPUS_BUILD_SHARED_LIBRARY "" ON)
|
||||
option(OPUS_BUILD_TESTS "" OFF)
|
||||
if(MINGW)
|
||||
option(OPUS_STACK_PROTECTOR "" OFF)
|
||||
endif()
|
||||
|
||||
add_subdirectory("${3RDPARTY_DIR}/opus" "${CMAKE_CURRENT_BINARY_DIR}/opus" EXCLUDE_FROM_ALL)
|
||||
|
||||
# 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})
|
||||
find_pkg("opus;Opus" REQUIRED)
|
||||
target_include_directories(mumble_client_object_lib PUBLIC ${opus_INCLUDE_DIRS})
|
||||
target_link_libraries(mumble_client_object_lib PUBLIC ${opus_LIBRARIES})
|
||||
if(TARGET opus)
|
||||
target_link_libraries(mumble_client_object_lib PUBLIC opus)
|
||||
elseif(TARGET Opus)
|
||||
target_link_libraries(mumble_client_object_lib PUBLIC Opus)
|
||||
elseif(TARGET Opus::opus)
|
||||
target_link_libraries(mumble_client_object_lib PUBLIC Opus::opus)
|
||||
endif()
|
||||
|
||||
if(bundled-speex)
|
||||
|
||||
@ -31,7 +31,6 @@ class Overlay;
|
||||
class LCD;
|
||||
class Zeroconf;
|
||||
class OverlayClient;
|
||||
class OpusCodec;
|
||||
class LogEmitter;
|
||||
class DeveloperConsole;
|
||||
class TalkingUI;
|
||||
@ -96,7 +95,6 @@ public:
|
||||
int iMaxBandwidth;
|
||||
int iAudioBandwidth;
|
||||
QDir qdBasePath;
|
||||
OpusCodec *oCodec;
|
||||
bool bAttenuateOthers;
|
||||
/// If set the AudioOutput::mix will forcefully adjust the volume of all
|
||||
/// non-priority speakers.
|
||||
|
||||
@ -21,7 +21,6 @@
|
||||
#include "Log.h"
|
||||
#include "Net.h"
|
||||
#include "NetworkConfig.h"
|
||||
#include "OpusCodec.h"
|
||||
#include "GlobalShortcut.h"
|
||||
#include "GlobalShortcutTypes.h"
|
||||
#ifdef USE_OVERLAY
|
||||
|
||||
@ -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
|
||||
@ -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_
|
||||
Loading…
Reference in New Issue
Block a user