From c2655fc265a43e25322086726f3436224ce35a45 Mon Sep 17 00:00:00 2001 From: Mikkel Krautz Date: Thu, 9 Aug 2012 23:53:09 +0200 Subject: Mumble: allow client to use SBCELT for CELT decoding via CONFIG(sbcelt). --- .gitmodules | 3 + INSTALL | 6 ++ celt-0.7.0-build/celt-0.7.0-build.pro | 9 ++- macx/scripts/osxdist.py | 44 ++++++------- main.pro | 15 +++-- opus-build/opus-build.pro | 5 +- sbcelt-helper-build/sbcelt-helper-build.pro | 84 ++++++++++++++++++++++++ sbcelt-lib-build/sbcelt-lib-build.pro | 69 ++++++++++++++++++++ sbcelt-src | 1 + src/mumble/Audio.cpp | 10 +++ src/mumble/CELTCodec.h | 11 ++++ src/mumble/CELTCodec_sbcelt.cpp | 99 +++++++++++++++++++++++++++++ src/mumble/main.cpp | 9 +++ src/mumble/mumble.pro | 26 +++++--- src/mumble/mumble_pch.hpp | 3 + 15 files changed, 353 insertions(+), 41 deletions(-) create mode 100644 sbcelt-helper-build/sbcelt-helper-build.pro create mode 100644 sbcelt-lib-build/sbcelt-lib-build.pro create mode 160000 sbcelt-src create mode 100644 src/mumble/CELTCodec_sbcelt.cpp diff --git a/.gitmodules b/.gitmodules index 47299c4cf..128f194fd 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,3 +10,6 @@ [submodule "opus-src"] path = opus-src url = git://git.xiph.org/opus.git +[submodule "sbcelt-src"] + path = sbcelt-src + url = git://github.com/mumble-voip/sbcelt.git diff --git a/INSTALL b/INSTALL index 1b733bf02..1ccf28f78 100644 --- a/INSTALL +++ b/INSTALL @@ -65,6 +65,12 @@ CONFIG+=no-bundled-speex (Mumble) Note that this requires your system-installed Speex to be at least version 1.2.0. +CONFIG+=sbcelt (Mumble, Linux, OSX, FreeBSD) + Use the SBCELT library for decoding CELT frames. Enabling this option will + build Mumble in a mode that forces all CELT frames to be decoded in a + separate, sandboxed, helper process. CELT frames will still be encoded using + Mumble's bundled CELT library. This option implies CONFIG+=bundled-celt. + CONFIG+=optimize Build a heavily optimized version, specific to the machine it's being compiled on. diff --git a/celt-0.7.0-build/celt-0.7.0-build.pro b/celt-0.7.0-build/celt-0.7.0-build.pro index 482c7bc00..66b18ec40 100644 --- a/celt-0.7.0-build/celt-0.7.0-build.pro +++ b/celt-0.7.0-build/celt-0.7.0-build.pro @@ -28,8 +28,13 @@ TARGET = celt0 DEFINES += HAVE_CONFIG_H TARGET_VERSION_EXT = .$$VERSION -CONFIG(static) { - CONFIG -= static +CONFIG(sbcelt) { + TARGET = celt + CONFIG += static +} else { + CONFIG(static) { + CONFIG -= static + } } QMAKE_CFLAGS -= -fPIE -pie diff --git a/macx/scripts/osxdist.py b/macx/scripts/osxdist.py index 6c02aa3c4..4c6c44b00 100755 --- a/macx/scripts/osxdist.py +++ b/macx/scripts/osxdist.py @@ -101,17 +101,15 @@ class AppBundle(object): dst = os.path.join(self.bundle, 'Contents', 'MacOS', 'murmur.ini') shutil.copy('scripts/murmur.ini.osx', dst) - def copy_g15helper(self): + def copy_helper(self, fn): ''' - Copy the Mumble G15 helper daemon into our Mumble app bundle. + Copy a helper binary into the Mumble app bundle. ''' - if os.path.exists(os.path.join(self.bundle, '..', 'mumble-g15-helper')): - print ' * Copying G15 helper' - src = os.path.join(self.bundle, '..', 'mumble-g15-helper') - dst = os.path.join(self.bundle, 'Contents', 'MacOS', 'mumble-g15-helper') + if os.path.exists(os.path.join(self.bundle, '..', fn)): + print ' * Copying helper binary: %s' % fn + src = os.path.join(self.bundle, '..', fn) + dst = os.path.join(self.bundle, 'Contents', 'MacOS', fn) shutil.copy(src, dst) - else: - print ' * No G15 helper found, skipping...' def copy_resources(self, rsrcs): ''' @@ -135,13 +133,15 @@ class AppBundle(object): def copy_codecs(self): ''' - Copy over dynamic CELT libraries. + Try to copy the dynamic CELT libraries into the App Bundle. ''' - print ' * Copying CELT libraries.' + print ' * Attempting to copy CELT libraries into App Bundle' dst = os.path.join(self.bundle, 'Contents', 'Codecs') os.makedirs(dst) - shutil.copy('release/libcelt0.0.7.0.dylib', dst) - shutil.copy('release/libcelt0.0.11.0.dylib', dst) + codecs = ('release/libcelt0.0.7.0.dylib', 'release/libcelt0.0.11.0.dylib') + for codec in codecs: + if os.path.exists(codec): + shutil.copy(codec, dst) def copy_plugins(self): ''' @@ -323,7 +323,8 @@ if __name__ == '__main__': a = AppBundle('release/Mumble.app', ver) if not options.no_server: a.copy_murmur() - a.copy_g15helper() + a.copy_helper('mumble-g15-helper') + a.copy_helper('sbcelt-helper') a.copy_codecs() a.copy_plugins() a.copy_resources(['icons/mumble.icns']) @@ -338,21 +339,18 @@ if __name__ == '__main__': # Sign our binaries, etc. if options.developer_id: print ' * Signing binaries with Developer ID `%s\'' % options.developer_id - binaries = [ - # 1.2.x + binaries = ( 'release/Mumble.app', 'release/Mumble.app/Contents/Plugins/liblink.dylib', 'release/Mumble.app/Contents/Plugins/libmanual.dylib', 'release/Mumble.app/Contents/Codecs/libcelt0.0.7.0.dylib', 'release/Mumble.app/Contents/Codecs/libcelt0.0.11.0.dylib', - ] - g15path = 'release/Mumble.app/Contents/MacOS/mumble-g15-helper' - if os.path.exists(g15path): - binaries.append(g15path) - if not options.no_server: - binaries.append('release/Mumble.app/Contents/MacOS/murmurd') - - codesign(binaries) + 'release/Mumble.app/Contents/MacOS/mumble-g15-helper', + 'release/Mumble.app/Contents/MacOS/sbcelt-helper', + 'release/Mumble.app/Contents/MacOS/murmurd', + ) + availableBinaries = [bin for bin in binaries if os.path.exists(bin)] + codesign(availableBinaries) print '' if options.only_appbundle: diff --git a/main.pro b/main.pro index 0ec04a2e7..1937a0f24 100644 --- a/main.pro +++ b/main.pro @@ -5,14 +5,19 @@ CONFIG *= ordered debug_and_release unix:!CONFIG(bundled-speex):system(pkg-config --atleast-version=1.2 speexdsp) { CONFIG *= no-bundled-speex } - unix:!CONFIG(bundled-celt):system(pkg-config --atleast-version=0.7.0 celt) { - CONFIG *= no-bundled-celt - } !CONFIG(no-bundled-speex) { SUBDIRS *= speexbuild } - !CONFIG(no-bundled-celt) { - SUBDIRS *= celt-0.7.0-build celt-0.11.0-build + + CONFIG(sbcelt) { + SUBDIRS *= celt-0.7.0-build sbcelt-lib-build sbcelt-helper-build + } else { + unix:!CONFIG(bundled-celt):system(pkg-config --atleast-version=0.7.0 celt) { + CONFIG *= no-bundled-celt + } + !CONFIG(no-bundled-celt) { + SUBDIRS *= celt-0.7.0-build celt-0.11.0-build + } } !CONFIG(no-opus) { diff --git a/opus-build/opus-build.pro b/opus-build/opus-build.pro index 1da7355e0..82da5a997 100644 --- a/opus-build/opus-build.pro +++ b/opus-build/opus-build.pro @@ -39,7 +39,10 @@ win32 { } } -unix:INCLUDEPATH += ../$$BUILDDIR +unix { + QMAKE_CFLAGS += -x c++ + INCLUDEPATH += ../$$BUILDDIR +} DIST = config.h diff --git a/sbcelt-helper-build/sbcelt-helper-build.pro b/sbcelt-helper-build/sbcelt-helper-build.pro new file mode 100644 index 000000000..3c2bb1aad --- /dev/null +++ b/sbcelt-helper-build/sbcelt-helper-build.pro @@ -0,0 +1,84 @@ +include (../compiler.pri) + +BUILDDIR=$$basename(PWD) +SOURCEDIR=$$replace(BUILDDIR,-helper-build,-src) +CELTDIR=../celt-0.7.0-src/libcelt + +!exists($$CELTDIR/../COPYING) { + message("The $$CELTDIR/ directory was not found. You need to do the following:") + message("") + message("Use CELT Git:") + message("git submodule init") + message("git submodule update") + message("") + error("Aborting configuration") +} + +!exists(../$$SOURCEDIR/LICENSE) { + message("The $$SOURCEDIR/ directory was not found. You need to do the following:") + message("") + message("Use SBCELT Git:") + message("git submodule init") + message("git submodule update") + message("") + error("Aborting configuration") +} + +TEMPLATE = app +CONFIG -= qt app_bundle +CONFIG *= debug_and_release +CONFIG -= warn-on +VPATH = ../$$SOURCEDIR/helper +TARGET = sbcelt-helper +DEFINES += HAVE_CONFIG_H +INCLUDEPATH += ../$$SOURCEDIR/helper ../$$SOURCEDIR/lib ../$$SOURCEDIR $$CELTDIR +LIBS += -lpthread + +SOURCES = \ + $$CELTDIR/bands.c \ + $$CELTDIR/celt.c \ + $$CELTDIR/cwrs.c \ + $$CELTDIR/entcode.c \ + $$CELTDIR/entdec.c \ + $$CELTDIR/entenc.c \ + $$CELTDIR/header.c \ + $$CELTDIR/kiss_fft.c \ + $$CELTDIR/kiss_fftr.c \ + $$CELTDIR/laplace.c \ + $$CELTDIR/mdct.c \ + $$CELTDIR/modes.c \ + $$CELTDIR/pitch.c \ + $$CELTDIR/psy.c \ + $$CELTDIR/quant_bands.c \ + $$CELTDIR/rangedec.c \ + $$CELTDIR/rangeenc.c \ + $$CELTDIR/rate.c \ + $$CELTDIR/vq.c \ + sbcelt-helper.c \ + alloc.c + +unix:!macx { + UNAME=$$system(uname -s) + contains(UNAME, Linux) { + SOURCES *= ../lib/futex-linux.c seccomp-sandbox.c sbcelt-sandbox-linux.c pdeath-linux.c + LIBS += -lrt + } + contains(UNAME, FreeBSD) { + SOURCES *= ../lib/futex-freebsd.c sbcelt-sandbox-freebsd.c pdeath-kqueue.c + } +} + +macx { + SOURCES *= ../lib/futex-stub.c sbcelt-sandbox-darwin.c pdeath-kqueue.c +} + +CONFIG(release, debug|release) { + DESTDIR = ../release +} + +CONFIG(debug, debug|release) { + DEFINES *= USE_LOGFILE + DESTDIR = ../debug/ +} + +include(../symbols.pri) diff --git a/sbcelt-lib-build/sbcelt-lib-build.pro b/sbcelt-lib-build/sbcelt-lib-build.pro new file mode 100644 index 000000000..46113e194 --- /dev/null +++ b/sbcelt-lib-build/sbcelt-lib-build.pro @@ -0,0 +1,69 @@ +include(../compiler.pri) + +BUILDDIR=$$basename(PWD) +SOURCEDIR=$$replace(BUILDDIR,-lib-build,-src) +CELTDIR=../celt-0.7.0-src + +!exists($$CELTDIR/COPYING) { + message("The $$CELTDIR/ directory was not found. You need to do the following:") + message("") + message("Use CELT Git:") + message("git submodule init") + message("git submodule update") + message("") + error("Aborting configuration") +} + +!exists(../$$SOURCEDIR/LICENSE) { + message("The $$SOURCEDIR/ directory was not found. You need to do the following:") + message("") + message("Use SBCELT Git:") + message("git submodule init") + message("git submodule update") + message("") + error("Aborting configuration") +} + +TEMPLATE = lib +CONFIG -= qt +CONFIG += debug_and_release +CONFIG -= warn_on +CONFIG += warn_off +CONFIG += static +VPATH = ../$$SOURCEDIR/lib +TARGET = sbcelt +INCLUDEPATH = $$CELTDIR/libcelt +DEFINES += SBCELT_PREFIX_API + +QMAKE_CFLAGS -= -fPIE -pie + +unix { + INCLUDEPATH += ../$$BUILDDIR +} + +SOURCES *= libsbcelt.c mtime.c stub.c + +unix:!macx { + UNAME=$$system(uname -s) + contains(UNAME, Linux) { + SOURCES *= futex-linux.c closefrom.c + } + contains(UNAME, FreeBSD) { + SOURCES *= futex-freebsd.c closefrom-sys.c + } +} + +macx { + SOURCES *= futex-stub.c closefrom.c +} + +CONFIG(debug, debug|release) { + CONFIG += console + DESTDIR = ../debug +} + +CONFIG(release, debug|release) { + DESTDIR = ../release +} + +include(../symbols.pri) diff --git a/sbcelt-src b/sbcelt-src new file mode 160000 index 000000000..a2ce9cf9b --- /dev/null +++ b/sbcelt-src @@ -0,0 +1 @@ +Subproject commit a2ce9cf9b83f043a94ba73bd1216013ff56eba91 diff --git a/src/mumble/Audio.cpp b/src/mumble/Audio.cpp index 6ecac3bef..86758f065 100644 --- a/src/mumble/Audio.cpp +++ b/src/mumble/Audio.cpp @@ -57,6 +57,15 @@ void CodecInit::initialize() { return; } +#ifdef USE_SBCELT + codec = new CELTCodecSBCELT(); + if (codec->isValid()) { + codec->report(); + g.qmCodecs.insert(codec->bitstreamVersion(), codec); + } else { + delete codec; + } +#else codec = new CELTCodec070(QLatin1String("0.7.0")); if (codec->isValid()) { codec->report(); @@ -86,6 +95,7 @@ void CodecInit::initialize() { delete codec; } } +#endif } void CodecInit::destroy() { diff --git a/src/mumble/CELTCodec.h b/src/mumble/CELTCodec.h index 2a87725bc..cdcf6bd19 100644 --- a/src/mumble/CELTCodec.h +++ b/src/mumble/CELTCodec.h @@ -111,4 +111,15 @@ class CELTCodec011 : public CELTCodec { virtual int decode_float(CELTDecoder *st, const unsigned char *data, int len, float *pcm); }; +class CELTCodecSBCELT : public CELTCodec { + protected: + const CELTMode *cmSBCELTMode; + public: + CELTCodecSBCELT(); + virtual CELTEncoder *encoderCreate(); + virtual CELTDecoder *decoderCreate(); + virtual int encode(CELTEncoder *st, const celt_int16 *pcm, unsigned char *compressed, int nbCompressedBytes); + virtual int decode_float(CELTDecoder *st, const unsigned char *data, int len, float *pcm); +}; + #endif // CELTCODEC_H_ diff --git a/src/mumble/CELTCodec_sbcelt.cpp b/src/mumble/CELTCodec_sbcelt.cpp new file mode 100644 index 000000000..c6877c783 --- /dev/null +++ b/src/mumble/CELTCodec_sbcelt.cpp @@ -0,0 +1,99 @@ +/* Copyright (C) 2005-2011, Thorvald Natvig + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + - Neither the name of the Mumble Developers nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "mumble_pch.hpp" + +#include "CELTCodec.h" + +#include "Audio.h" +#include "Version.h" + +CELTCodec::CELTCodec(const QString &version) { + bValid = true; + cmMode = NULL; + qsVersion = version; + iBitstreamVersion = INT_MIN; + + this->celt_encoder_destroy = ::celt_encoder_destroy; + this->celt_encoder_ctl = ::celt_encoder_ctl; + + this->celt_decoder_destroy = ::celt_decoder_destroy; + this->celt_decoder_ctl = ::celt_decoder_ctl; +} + +CELTCodec::~CELTCodec() { + if (cmMode) + ::celt_mode_destroy(const_cast(cmMode)); +} + +bool CELTCodec::isValid() const { + return bValid; +} + +int CELTCodec::bitstreamVersion() const { + if (cmMode && iBitstreamVersion == INT_MIN) + ::celt_mode_info(cmMode, CELT_GET_BITSTREAM_VERSION, reinterpret_cast(&iBitstreamVersion)); + + return iBitstreamVersion; +} + +QString CELTCodec::version() const { + return qsVersion; +} + +void CELTCodec::report() const { + qWarning("CELT bitstream %08x from internal CELT with SBCELT decoding", bitstreamVersion()); +} + +CELTCodecSBCELT::CELTCodecSBCELT() : CELTCodec(QLatin1String("0.7.0")) { + if (bValid) { + cmMode = ::celt_mode_create(SAMPLE_RATE, SAMPLE_RATE / 100, NULL); + cmSBCELTMode = ::sbcelt_mode_create(SAMPLE_RATE, SAMPLE_RATE / 100, NULL); + + this->celt_decoder_destroy = ::sbcelt_decoder_destroy; + this->celt_decoder_ctl = ::sbcelt_decoder_ctl; + } +} + +CELTEncoder *CELTCodecSBCELT::encoderCreate() { + return ::celt_encoder_create(cmMode, 1, NULL); +} + +CELTDecoder *CELTCodecSBCELT::decoderCreate() { + return ::sbcelt_decoder_create(cmSBCELTMode, 1, NULL); +} + +int CELTCodecSBCELT::encode(CELTEncoder *st, const celt_int16 *pcm, unsigned char *compressed, int nbCompressedBytes) { + return ::celt_encode(st, pcm, NULL, compressed, nbCompressedBytes); +} + +int CELTCodecSBCELT::decode_float(CELTDecoder *st, const unsigned char *data, int len, float *pcm) { + return ::sbcelt_decode_float(st, data, len, pcm); +} \ No newline at end of file diff --git a/src/mumble/main.cpp b/src/mumble/main.cpp index 109cbc362..0368a1a88 100644 --- a/src/mumble/main.cpp +++ b/src/mumble/main.cpp @@ -153,6 +153,15 @@ int main(int argc, char **argv) { a.setOrganizationDomain(QLatin1String("mumble.sourceforge.net")); a.setQuitOnLastWindowClosed(false); + #ifdef USE_SBCELT + { + // For now, force Mumble to use sbcelt-helper from the same directory as the 'mumble' executable. + QDir d(a.applicationDirPath()); + QString helper = d.absoluteFilePath(QString::fromLatin1("sbcelt-helper")); + setenv("SBCELT_HELPER_BINARY", helper.toUtf8().constData(), 1); + } +#endif + Global::g_global_struct = new Global(); qsrand(QDateTime::currentDateTime().toTime_t()); diff --git a/src/mumble/mumble.pro b/src/mumble/mumble.pro index 74fa9eb42..02d2383f2 100644 --- a/src/mumble/mumble.pro +++ b/src/mumble/mumble.pro @@ -45,16 +45,22 @@ CONFIG(no-bundled-speex) { LIBS *= -lspeex } -unix:!CONFIG(bundled-celt):system(pkg-config --atleast-version=0.7.0 celt) { - CONFIG *= no-bundled-celt -} - -CONFIG(no-bundled-celt) { - INCLUDEPATH *= /usr/include/celt -} - -!CONFIG(no-bundled-celt) { - INCLUDEPATH *= ../../celt-0.7.0-src/libcelt +CONFIG(sbcelt) { + SOURCES -= CELTCodec.cpp + SOURCES += CELTCodec_sbcelt.cpp + INCLUDEPATH *= ../../celt-0.7.0-src/libcelt ../../sbcelt-src + LIBS *= -lcelt -lsbcelt + DEFINES *= SBCELT_PREFIX_API SBCELT_COMPAT_API USE_SBCELT +} else { + unix:!CONFIG(bundled-celt):system(pkg-config --atleast-version=0.7.0 celt) { + CONFIG *= no-bundled-celt + } + CONFIG(no-bundled-celt) { + INCLUDEPATH *= /usr/include/celt + } + !CONFIG(no-bundled-celt) { + INCLUDEPATH *= ../../celt-0.7.0-src/libcelt + } } !win32 { diff --git a/src/mumble/mumble_pch.hpp b/src/mumble/mumble_pch.hpp index 71f735163..fc5358a80 100644 --- a/src/mumble/mumble_pch.hpp +++ b/src/mumble/mumble_pch.hpp @@ -53,6 +53,9 @@ #include #undef __int64_t #include +#ifdef USE_SBCELT +#include +#endif #include #include #include -- cgit v1.2.3