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 \
|
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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
3
.gitmodules
vendored
@ -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
3rdparty/opus
vendored
@ -1 +0,0 @@
|
|||||||
Subproject commit 027cd11ed732d02456d1f049081d24b4626d5cb9
|
|
||||||
@ -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 \
|
||||||
|
|||||||
@ -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.
|
||||||
|
|||||||
@ -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",
|
||||||
|
|||||||
@ -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/"],
|
||||||
|
|||||||
@ -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");
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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();
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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.
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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