diff --git a/bootstrap.sh b/bootstrap.sh index 3188d9ecc..d705a02c0 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -15,6 +15,7 @@ SODIUM_VER=1.0.0 # directory names of cloned repositories SODIUM_DIR=libsodium-$SODIUM_VER TOX_CORE_DIR=libtoxcore-latest +FILTER_AUDIO_DIR=filter_audio # this boolean describes whether the installation of # libsodium should be skipped or not @@ -42,6 +43,11 @@ if [ -z "$TOX_CORE_DIR" ]; then exit 1 fi +if [ -z "$FILTER_AUDIO_DIR" ]; then + echo "internal error detected!" + echo "FILTER_AUDIO_DIR should not be empty... aborting" + exit 1 +fi ########## check input parameters ########## @@ -95,7 +101,7 @@ mkdir -p ${BASE_DIR} # if exists, otherwise cloning them may fail rm -rf ${BASE_DIR}/${SODIUM_DIR} rm -rf ${BASE_DIR}/${TOX_CORE_DIR} - +rm -rf ${BASE_DIR}/${FILTER_AUDIO_DIR} ############### install step ############### @@ -122,6 +128,12 @@ if [[ $TOX_ONLY = "false" ]]; then fi popd + + if [[ $GLOBAL = "false" ]]; then + ./install_libfilteraudio.sh ${BASE_DIR}/${FILTER_AUDIO_DIR} ${BASE_DIR} + else + ./install_libfilteraudio.sh ${BASE_DIR}/${FILTER_AUDIO_DIR} + fi fi # clone current master of libtoxcore diff --git a/install_libfilteraudio.sh b/install_libfilteraudio.sh new file mode 100755 index 000000000..010bcbbac --- /dev/null +++ b/install_libfilteraudio.sh @@ -0,0 +1,40 @@ +#!/bin/sh + +if [ -z $1 ]; then + SOURCE_DIR="filter_audio/" +else + SOURCE_DIR="$1/" +fi + +if [ -z "$2" ]; then + LIB_DIR="/usr/local/lib/" + INCLUDE_DIR="/usr/local/include/" +else + LIB_DIR="$2/lib/" + INCLUDE_DIR="$2/include/" +fi + +echo "Cloning filter_audio from GitHub.com" +git clone https://github.com/irungentoo/filter_audio.git $SOURCE_DIR + +echo "Compiling filter_audio" +cd $SOURCE_DIR +gcc -c -fPIC filter_audio.c aec/*.c agc/*.c ns/*.c other/*.c -lm -lpthread + +echo "Creating shared object file" +gcc *.o -shared -o libfilteraudio.so + +echo "Cleaning up" +rm *.o + +muhcmd="cp libfilteraudio.so $LIB_DIR" +[ -z "$2" ] && muhcmd="sudo $muhcmd" +echo "Installing libfilteraudio.so with $muhcmd" +$muhcmd + +muhcmd="cp *.h $INCLUDE_DIR" +[ -z "$2" ] && muhcmd="sudo $muhcmd" +echo "Installing include files with $muhcmd" +$muhcmd + +echo "Finished." diff --git a/qtox.pro b/qtox.pro index cbd4f3dc1..46be9d92d 100644 --- a/qtox.pro +++ b/qtox.pro @@ -59,6 +59,12 @@ contains(DISABLE_PLATFORM_EXT, YES) { DEFINES += QTOX_PLATFORM_EXT } +contains(DISABLE_FILTER_AUDIO, YES) { + +} else { + DEFINES += QTOX_FILTER_AUDIO +} + contains(JENKINS,YES) { INCLUDEPATH += ./libs/include/ } else { @@ -78,6 +84,7 @@ win32 { QMAKE_INFO_PLIST = osx/info.plist LIBS += -L$$PWD/libs/lib/ -ltoxcore -ltoxav -ltoxencryptsave -ltoxdns -lsodium -lvpx -framework OpenAL -lopencv_core -lopencv_highgui contains(DEFINES, QTOX_PLATFORM_EXT) { LIBS += -framework IOKit -framework CoreFoundation } + contains(DEFINES, QTOX_FILTER_AUDIO) { } } else { # If we're building a package, static link libtox[core,av] and libsodium, since they are not provided by any package contains(STATICPKG, YES) { @@ -94,8 +101,16 @@ win32 { LIBS += -lX11 -lXss } + contains(DEFINES, QTOX_FILTER_AUDIO) { + contains(STATICPKG, YES) { + LIBS += -Wl,-Bstatic -lfilteraudio + } else { + LIBS += -lfilteraudio + } + } + contains(JENKINS, YES) { - LIBS = ./libs/lib/libtoxav.a ./libs/lib/libvpx.a ./libs/lib/libopus.a ./libs/lib/libtoxdns.a ./libs/lib/libtoxencryptsave.a ./libs/lib/libtoxcore.a ./libs/lib/libsodium.a /usr/lib/libopencv_core.so /usr/lib/libopencv_highgui.so /usr/lib/libopencv_imgproc.so -lopenal -lX11 -lXss -s + LIBS = ./libs/lib/libtoxav.a ./libs/lib/libvpx.a ./libs/lib/libopus.a ./libs/lib/libtoxdns.a ./libs/lib/libtoxencryptsave.a ./libs/lib/libtoxcore.a ./libs/lib/libsodium.a ./libs/lib/libfilteraudio.a /usr/lib/libopencv_core.so /usr/lib/libopencv_highgui.so /usr/lib/libopencv_imgproc.so -lopenal -lX11 -lXss -s } } } @@ -234,6 +249,11 @@ SOURCES += \ src/widget/form/settings/advancedform.cpp \ src/audio.cpp +contains(DEFINES, QTOX_FILTER_AUDIO) { + HEADERS += src/audiofilterer.h + SOURCES += src/audiofilterer.cpp +} + contains(DEFINES, QTOX_PLATFORM_EXT) { HEADERS += src/platform/timer.h SOURCES += src/platform/timer_osx.cpp \ diff --git a/src/audiofilterer.cpp b/src/audiofilterer.cpp new file mode 100644 index 000000000..2253a6f60 --- /dev/null +++ b/src/audiofilterer.cpp @@ -0,0 +1,53 @@ +/* + Copyright (C) 2014 by Project Tox + + This file is part of qTox, a Qt-based graphical interface for Tox. + + This program is libre software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the COPYING file for more details. +*/ + + +#ifdef QTOX_FILTER_AUDIO + +#include "audiofilterer.h" +extern "C"{ +#include +} + +void AudioFilterer::startFilter(unsigned int fs) +{ + closeFilter(); + filter = new_filter_audio(fs); +} + +void AudioFilterer::closeFilter() +{ + if (filter) + kill_filter_audio(filter); + filter = nullptr; +} + + +void AudioFilterer::filterAudio(int16_t* data, int framesize) +{ + if (!filter) + return; + + filter_audio(filter, (int16_t*) data, framesize); +} + + +AudioFilterer::~AudioFilterer() +{ + closeFilter(); +} + +#endif // QTOX_FILTER_AUDIO diff --git a/src/audiofilterer.h b/src/audiofilterer.h new file mode 100644 index 000000000..3a61d4e9f --- /dev/null +++ b/src/audiofilterer.h @@ -0,0 +1,41 @@ +/* + Copyright (C) 2014 by Project Tox + + This file is part of qTox, a Qt-based graphical interface for Tox. + + This program is libre software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the COPYING file for more details. +*/ + +#ifdef QTOX_FILTER_AUDIO +#ifndef AUDIOFILTERER_H +#define AUDIOFILTERER_H +#include + +#ifndef _FILTER_AUDIO +typedef struct Filter_Audio Filter_Audio; +#endif + +class AudioFilterer +{ +public: + explicit AudioFilterer() = default; + ~AudioFilterer(); + + void startFilter(unsigned int fs); + void filterAudio(int16_t* data, int framesize); + void closeFilter(); + +private: + struct Filter_Audio* filter{nullptr}; +}; + +#endif // AUDIOFILTERER_H +#endif // QTOX_FILTER_AUDIO diff --git a/src/core.h b/src/core.h index 2f323bca2..ffa4ba0c9 100644 --- a/src/core.h +++ b/src/core.h @@ -33,6 +33,9 @@ class QTimer; class QString; class CString; class VideoSource; +#ifdef QTOX_FILTER_AUDIO +class AudioFilterer; +#endif class Core : public QObject { @@ -283,6 +286,9 @@ private: int dhtServerId; static QList fileSendQueue, fileRecvQueue; static ToxCall calls[TOXAV_MAX_CALLS]; +#ifdef QTOX_FILTER_AUDIO + static AudioFilterer * filterer[TOXAV_MAX_CALLS]; +#endif static QHash groupCalls; // Maps group IDs to ToxGroupCalls QMutex fileSendMutex, messageSendMutex; bool ready; diff --git a/src/coreav.cpp b/src/coreav.cpp index 13f6dd8c0..5fb12e128 100644 --- a/src/coreav.cpp +++ b/src/coreav.cpp @@ -17,10 +17,17 @@ #include "core.h" #include "video/camera.h" #include "audio.h" +#ifdef QTOX_FILTER_AUDIO +#include "audiofilterer.h" +#endif +#include "misc/settings.h" #include #include ToxCall Core::calls[TOXAV_MAX_CALLS]; +#ifdef QTOX_FILTER_AUDIO +AudioFilterer * Core::filterer[TOXAV_MAX_CALLS] { nullptr}; +#endif const int Core::videobufsize{TOXAV_MAX_VIDEO_WIDTH * TOXAV_MAX_VIDEO_HEIGHT * 4}; uint8_t* Core::videobuf; @@ -65,6 +72,19 @@ void Core::prepareCall(int friendId, int callId, ToxAv* toxav, bool videoEnabled calls[callId].sendVideoTimer->start(); Camera::getInstance()->subscribe(); } + +#ifdef QTOX_FILTER_AUDIO + if (Settings::getInstance().getFilterAudio()) + { + Core::filterer[callId] = new AudioFilterer(); + filterer[callId]->startFilter(48000); + } + else + { + delete filterer[callId]; + filterer[callId] = nullptr; + } +#endif } void Core::onAvMediaChange(void* toxav, int32_t callId, void* core) @@ -246,8 +266,16 @@ void Core::sendCallAudio(int callId, ToxAv* toxav) return; } +#ifdef QTOX_FILTER_AUDIO + if (filterer[callId]) + { + filterer[callId]->filterAudio((int16_t*) buf, framesize); + } +#endif if ((r = toxav_send_audio(toxav, callId, dest, r)) < 0) + { qDebug() << "Core: toxav_send_audio error"; + } } calls[callId].sendAudioTimer->start(); } @@ -294,14 +322,16 @@ void Core::sendCallVideo(int callId) void Core::micMuteToggle(int callId) { - if (calls[callId].active) { + if (calls[callId].active) + { calls[callId].muteMic = !calls[callId].muteMic; } } void Core::volMuteToggle(int callId) { - if (calls[callId].active) { + if (calls[callId].active) + { calls[callId].muteVol = !calls[callId].muteVol; alSourcef(calls[callId].alSource, AL_GAIN, calls[callId].muteVol ? 0.f : 1.f); } @@ -321,6 +351,15 @@ void Core::onAvCancel(void* _toxav, int32_t callId, void* core) calls[callId].active = false; +#ifdef QTOX_FILTER_AUDIO + if (filterer[callId]) + { + filterer[callId]->closeFilter(); + delete filterer[callId]; + filterer[callId] = nullptr; + } +#endif + emit static_cast(core)->avCancel(friendId, callId); } diff --git a/src/misc/settings.cpp b/src/misc/settings.cpp index b14fe2e34..ad2c9fbb3 100644 --- a/src/misc/settings.cpp +++ b/src/misc/settings.cpp @@ -198,6 +198,7 @@ void Settings::load() s.beginGroup("Audio"); inDev = s.value("inDev", "").toString(); outDev = s.value("outDev", "").toString(); + filterAudio = s.value("filterAudio", false).toBool(); s.endGroup(); // Read the embedded DHT bootsrap nodes list if needed @@ -340,6 +341,7 @@ void Settings::save(QString path, bool writeFriends) s.beginGroup("Audio"); s.setValue("inDev", inDev); s.setValue("outDev", outDev); + s.setValue("filterAudio", filterAudio); s.endGroup(); if (!writeFriends || currentProfile.isEmpty()) // Core::switchConfiguration @@ -898,6 +900,16 @@ void Settings::setOutDev(const QString& deviceSpecifier) outDev = deviceSpecifier; } +bool Settings::getFilterAudio() const +{ + return filterAudio; +} + +void Settings::setFilterAudio(bool newValue) +{ + filterAudio = newValue; +} + QString Settings::getFriendAdress(const QString &publicKey) const { QString key = ToxID::fromString(publicKey).publicKey; diff --git a/src/misc/settings.h b/src/misc/settings.h index 848ade407..64ff6009e 100644 --- a/src/misc/settings.h +++ b/src/misc/settings.h @@ -128,6 +128,9 @@ public: QString getOutDev() const; void setOutDev(const QString& deviceSpecifier); + bool getFilterAudio() const; + void setFilterAudio(bool newValue); + // Assume all widgets have unique names // Don't use it to save every single thing you want to save, use it // for some general purpose widgets, such as MainWindows or Splitters, @@ -298,6 +301,7 @@ private: // Audio QString inDev; QString outDev; + bool filterAudio; struct friendProp { diff --git a/src/widget/form/settings/avform.cpp b/src/widget/form/settings/avform.cpp index a506b287a..31f9b6dd9 100644 --- a/src/widget/form/settings/avform.cpp +++ b/src/widget/form/settings/avform.cpp @@ -33,12 +33,19 @@ AVForm::AVForm() : bodyUI = new Ui::AVSettings; bodyUI->setupUi(this); +#ifdef QTOX_FILTER_AUDIO + bodyUI->filterAudio->setChecked(Settings::getInstance().getFilterAudio()); +#else + bodyUI->filterAudio->setDisabled(true); +#endif + connect(Camera::getInstance(), &Camera::propProbingFinished, this, &AVForm::onPropProbingFinished); connect(Camera::getInstance(), &Camera::resolutionProbingFinished, this, &AVForm::onResProbingFinished); auto qcomboboxIndexChanged = (void(QComboBox::*)(const QString&)) &QComboBox::currentIndexChanged; connect(bodyUI->inDevCombobox, qcomboboxIndexChanged, this, &AVForm::onInDevChanged); connect(bodyUI->outDevCombobox, qcomboboxIndexChanged, this, &AVForm::onOutDevChanged); + connect(bodyUI->filterAudio, SIGNAL(toggled(bool)), this, SLOT(onFilterAudioToggled(bool))); connect(bodyUI->rescanButton, &QPushButton::clicked, this, [=](){getAudioInDevices(); getAudioOutDevices();}); } @@ -189,3 +196,8 @@ void AVForm::onOutDevChanged(const QString& deviceDescriptor) Settings::getInstance().setOutDev(deviceDescriptor); Audio::openOutput(deviceDescriptor); } + +void AVForm::onFilterAudioToggled(bool filterAudio) +{ + Settings::getInstance().setFilterAudio(filterAudio); +} diff --git a/src/widget/form/settings/avform.h b/src/widget/form/settings/avform.h index 2d1e873ad..64b34d410 100644 --- a/src/widget/form/settings/avform.h +++ b/src/widget/form/settings/avform.h @@ -52,6 +52,7 @@ private slots: // audio void onInDevChanged(const QString& deviceDescriptor); void onOutDevChanged(const QString& deviceDescriptor); + void onFilterAudioToggled(bool filterAudio); // camera void onPropProbingFinished(Camera::Prop prop, double val); diff --git a/src/widget/form/settings/avsettings.ui b/src/widget/form/settings/avsettings.ui index f7e1afc8d..e46c7d43f 100644 --- a/src/widget/form/settings/avsettings.ui +++ b/src/widget/form/settings/avsettings.ui @@ -30,8 +30,8 @@ 0 0 - 810 - 496 + 808 + 618 @@ -96,6 +96,13 @@ + + + + Filter audio + + +