diff --git a/build_scripts/Windows/build-libs/Makefile b/build_scripts/Windows/build-libs/Makefile index e6927150f..8bab46b92 100644 --- a/build_scripts/Windows/build-libs/Makefile +++ b/build_scripts/Windows/build-libs/Makefile @@ -4,7 +4,6 @@ MINIUPNPC_VERSION=2.0 OPENSSL_VERSION=1.1.1h SPEEX_VERSION=1.2.0 SPEEXDSP_VERSION=1.2rc3 -OPENCV_VERSION=4.5.0 LIBXML2_VERSION=2.9.7 LIBXSLT_VERSION=1.1.32 CURL_VERSION=7.58.0 @@ -19,7 +18,7 @@ DOWNLOAD_PATH?=download BUILD_PATH=build LIBS_PATH?=libs -all: dirs zlib bzip2 miniupnpc openssl speex speexdsp opencv libxml2 libxslt curl sqlcipher libmicrohttpd ffmpeg rapidjson xapian copylibs +all: dirs zlib bzip2 miniupnpc openssl speex speexdsp libxml2 libxslt curl sqlcipher libmicrohttpd ffmpeg rapidjson xapian copylibs download: \ $(DOWNLOAD_PATH)/zlib-$(ZLIB_VERSION).tar.gz \ @@ -28,7 +27,6 @@ download: \ $(DOWNLOAD_PATH)/openssl-$(OPENSSL_VERSION).tar.gz \ $(DOWNLOAD_PATH)/speex-$(SPEEX_VERSION).tar.gz \ $(DOWNLOAD_PATH)/speexdsp-$(SPEEXDSP_VERSION).tar.gz \ - $(DOWNLOAD_PATH)/opencv-$(OPENCV_VERSION).tar.gz \ $(DOWNLOAD_PATH)/libxml2-$(LIBXML2_VERSION).tar.gz \ $(DOWNLOAD_PATH)/libxslt-$(LIBXSLT_VERSION).tar.gz \ $(DOWNLOAD_PATH)/curl-$(CURL_VERSION).tar.gz \ @@ -187,31 +185,6 @@ $(BUILD_PATH)/speexdsp-$(SPEEXDSP_VERSION): $(DOWNLOAD_PATH)/speexdsp-$(SPEEXDSP rm -r -f speexdsp-$(SPEEXDSP_VERSION) mv $(BUILD_PATH)/speexdsp-$(SPEEXDSP_VERSION).tmp $(BUILD_PATH)/speexdsp-$(SPEEXDSP_VERSION) -opencv: $(BUILD_PATH)/opencv-$(OPENCV_VERSION) - -$(DOWNLOAD_PATH)/opencv-$(OPENCV_VERSION).tar.gz: - wget --no-check-certificate https://github.com/opencv/opencv/archive/$(OPENCV_VERSION).tar.gz -O $(DOWNLOAD_PATH)/opencv-$(OPENCV_VERSION).tar.gz - -$(BUILD_PATH)/opencv-$(OPENCV_VERSION): $(DOWNLOAD_PATH)/opencv-$(OPENCV_VERSION).tar.gz - # prepare - rm -r -f $(BUILD_PATH)/opencv-* - tar xvf $(DOWNLOAD_PATH)/opencv-$(OPENCV_VERSION).tar.gz - # Remove version numbers from libraries. Is there a switch? - sed -i -e's/\(ocv_update(OPENCV_DLLVERSION \).*$$/\1"")/' opencv-$(OPENCV_VERSION)/CMakeLists.txt - # build - mkdir -p opencv-$(OPENCV_VERSION)/build - #cd opencv-$(OPENCV_VERSION)/build && cmake .. -G"MSYS Makefiles" -DCMAKE_BUILD_TYPE=Release -DBUILD_PERF_TESTS=OFF -DBUILD_TESTS=OFF -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX="`pwd`/../../build" - cd opencv-$(OPENCV_VERSION)/build && cmake .. -G"MSYS Makefiles" -DCMAKE_BUILD_TYPE=Release -DBUILD_PERF_TESTS=OFF -DBUILD_TESTS=OFF -DBUILD_SHARED_LIBS=OFF -DENABLE_CXX11=ON -DCMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS} -DSTRSAFE_NO_DEPRECATE" -DCMAKE_INSTALL_PREFIX="`pwd`/install" - cd opencv-$(OPENCV_VERSION)/build && make install - # copy files - mkdir -p $(BUILD_PATH)/opencv-$(OPENCV_VERSION).tmp/include - cp -r opencv-$(OPENCV_VERSION)/build/install/include/* $(BUILD_PATH)/opencv-$(OPENCV_VERSION).tmp/include/ - mkdir -p $(BUILD_PATH)/opencv-$(OPENCV_VERSION).tmp/lib/opencv - cp -r opencv-$(OPENCV_VERSION)/build/install/x64/mingw/staticlib/* $(BUILD_PATH)/opencv-$(OPENCV_VERSION).tmp/lib/opencv/ - # cleanup - rm -r -f opencv-$(OPENCV_VERSION) - mv $(BUILD_PATH)/opencv-$(OPENCV_VERSION).tmp $(BUILD_PATH)/opencv-$(OPENCV_VERSION) - libxml2: $(BUILD_PATH)/libxml2-$(LIBXML2_VERSION) $(DOWNLOAD_PATH)/libxml2-$(LIBXML2_VERSION).tar.gz: diff --git a/libretroshare/src/libretroshare.pro b/libretroshare/src/libretroshare.pro index 84d18944e..da5f25ba4 100644 --- a/libretroshare/src/libretroshare.pro +++ b/libretroshare/src/libretroshare.pro @@ -137,7 +137,6 @@ PUBLIC_HEADERS = retroshare/rsdisc.h \ retroshare/rsmsgs.h \ retroshare/rsnotify.h \ retroshare/rspeers.h \ - retroshare/rsrank.h \ retroshare/rsstatus.h \ retroshare/rsturtle.h \ retroshare/rsbanlist.h \ @@ -348,13 +347,13 @@ HEADERS += ft/ftchunkmap.h \ ft/ftturtlefiletransferitem.h HEADERS += crypto/chacha20.h \ - crypto/rsaes.h \ - crypto/hashstream.h \ - crypto/rscrypto.h + crypto/rsaes.h \ + crypto/hashstream.h \ + crypto/rscrypto.h -HEADERS += directory_updater.h \ - directory_list.h \ - p3filelists.h +HEADERS += file_sharing/directory_updater.h \ + file_sharing/directory_list.h \ + file_sharing/p3filelists.h HEADERS += chat/distantchat.h \ chat/p3chatservice.h \ @@ -416,7 +415,7 @@ HEADERS += grouter/groutercache.h \ retroshare/rsgrouter.h \ grouter/grouteritems.h \ grouter/p3grouter.h \ - grouter/rsgroutermatrix.h \ + grouter/groutermatrix.h \ grouter/groutertypes.h \ grouter/grouterclientservice.h @@ -429,7 +428,6 @@ HEADERS += rsitems/rsitem.h \ rsitems/rsmsgitems.h \ serialiser/rsserial.h \ rsitems/rsserviceids.h \ - serialiser/rsserviceitems.h \ rsitems/rsstatusitems.h \ serialiser/rstlvaddrs.h \ serialiser/rstlvbase.h \ diff --git a/libretroshare/src/retroshare/rshistory.h b/libretroshare/src/retroshare/rshistory.h index f8eb7ecaa..faa649f2d 100644 --- a/libretroshare/src/retroshare/rshistory.h +++ b/libretroshare/src/retroshare/rshistory.h @@ -41,7 +41,7 @@ static const uint32_t RS_HISTORY_TYPE_PRIVATE = 1 ; static const uint32_t RS_HISTORY_TYPE_LOBBY = 2 ; static const uint32_t RS_HISTORY_TYPE_DISTANT = 3 ; -class HistoryMsg +class HistoryMsg: RsSerializable { public: HistoryMsg() @@ -52,7 +52,18 @@ public: recvTime = 0; } -public: + virtual void serial_process(RsGenericSerializer::SerializeJob j, RsGenericSerializer::SerializeContext& ctx) override + { + RS_SERIAL_PROCESS(msgId); + RS_SERIAL_PROCESS(chatPeerId); + RS_SERIAL_PROCESS(incoming); + RS_SERIAL_PROCESS(peerId); + RS_SERIAL_PROCESS(peerName); + RS_SERIAL_PROCESS(sendTime); + RS_SERIAL_PROCESS(recvTime); + RS_SERIAL_PROCESS(message); + } + uint32_t msgId; RsPeerId chatPeerId; bool incoming; @@ -71,20 +82,80 @@ class RsHistory { public: virtual bool chatIdToVirtualPeerId(const ChatId &chat_id, RsPeerId &peer_id) = 0; - virtual bool getMessages(const ChatId &chatPeerId, std::list &msgs, uint32_t loadCount) = 0; + + /*! + * @brief Retrieves the history of messages for a given chatId + * @jsonapi{development} + * @param[in] chatPeerId Chat Id for which the history needs to be retrieved + * @param[out] msgs retrieved messages + * @param[in] loadCount maximum number of messages to get + * @return true if messages can be retrieved, false otherwise. + */ + virtual bool getMessages(const ChatId& chatPeerId, std::list &msgs, uint32_t loadCount) = 0; + + /*! + * @brief Retrieves a specific message from the history + * @jsonapi{development} + * @param[in] msgId Id of the message to get + * @param[out] msg retrieved message + * @return true if message can be retrieved, false otherwise. + */ virtual bool getMessage(uint32_t msgId, HistoryMsg &msg) = 0; - virtual void removeMessages(const std::list &msgIds) = 0; - virtual void clear(const ChatId &chatPeerId) = 0; - virtual bool getEnable(uint32_t chat_type) = 0; - virtual void setEnable(uint32_t chat_type, bool enable) = 0; + /*! + * @brief Remove messages from the history + * @jsonapi{development} + * @param[in] msgIds list of messages to remove + */ + virtual void removeMessages(const std::list& msgIds) = 0; + /*! + * @brief clears the message history for a given chat peer + * @jsonapi{development} + * @param[in] chatPeerID Id of the chat/peer for which the history needs to be wiped + */ + virtual void clear(const ChatId &chatPeerId) = 0; + + /*! + * @brief Get whether chat history is enabled or not + * @jsonapi{development} + * @param[in] chat_type Type of chat (see list of constants above) + * @return true when the information is available + */ + virtual bool getEnable(uint32_t chat_type) = 0; + + /*! + * @brief Set whether chat history is enabled or not + * @jsonapi{development} + * @param[in] chat_type Type of chat (see list of constants above) + * @param[in] enabled Desired state of the variable + */ + virtual void setEnable(uint32_t chat_type, bool enable) = 0; + + /*! + * @brief Retrieves the maximum storage time period for messages in history + * @return max storage duration of chat. + */ virtual uint32_t getMaxStorageDuration() = 0; - virtual void setMaxStorageDuration(uint32_t seconds) = 0; + /*! + * @brief Sets the maximum storage time period for messages in history + * @param[in] seconds max storage duration time in seconds + */ + virtual void setMaxStorageDuration(uint32_t seconds) = 0; - // 0 = no limit, >0 count of saved messages - virtual uint32_t getSaveCount(uint32_t chat_type) = 0; - virtual void setSaveCount(uint32_t chat_type, uint32_t count) = 0; + /*! + * @brief Gets the maximum number of messages to save + * @param[in] chat_type Type of chat for that number limit + * @return maximum number of messages to save + */ + virtual uint32_t getSaveCount(uint32_t chat_type) = 0; + + /*! + * @brief Sets the maximum number of messages to save + * @param[in] chat_type Type of chat for that number limit + * @param[in] count Max umber of messages, 0 meaning indefinitly + */ + virtual void setSaveCount(uint32_t chat_type, uint32_t count) = 0; }; #endif diff --git a/libretroshare/src/retroshare/rsidentity.h b/libretroshare/src/retroshare/rsidentity.h index 0c8c364e3..36b1f4bb8 100644 --- a/libretroshare/src/retroshare/rsidentity.h +++ b/libretroshare/src/retroshare/rsidentity.h @@ -4,7 +4,8 @@ * libretroshare: retroshare core library * * * * Copyright (C) 2012 Robert Fernie * - * Copyright (C) 2019 Gioacchino Mazzurco * + * Copyright (C) 2019-2021 Gioacchino Mazzurco * + * Copyright (C) 2021 Asociación Civil Altermundi * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * @@ -131,23 +132,25 @@ struct RsGxsIdGroup : RsSerializable // ??? 160 bits. Sha1CheckSum mPgpIdHash; - // Need a signature as proof - otherwise anyone could add others Hashes. - // This is a string, as the length is variable. - std::string mPgpIdSign; - // Recognition Strings. MAX# defined above. + /** Need a signature as proof - otherwise anyone could add others Hashes. + * This is a string, as the length is variable. + * TODO: Thing like this should actually be a byte array (pointer+size), + * using an std::string breaks the JSON serialization, as a workaround this + * field is ignored by JSON serial operations */ + std::string mPgpIdSign; + + /// Unused RS_DEPRECATED std::list mRecognTags; - // Avatar - RsGxsImage mImage ; - rstime_t mLastUsageTS ; + RsGxsImage mImage; /// Avatar + rstime_t mLastUsageTS; - // Not Serialised - for GUI's benefit. - bool mPgpLinked; - bool mPgpKnown; - bool mIsAContact; // change that into flags one day - RsPgpId mPgpId; - GxsReputation mReputation; + bool mPgpLinked; + bool mPgpKnown; + bool mIsAContact; + RsPgpId mPgpId; + GxsReputation mReputation; /// @see RsSerializable void serial_process( RsGenericSerializer::SerializeJob j, diff --git a/libretroshare/src/rsitems/rsgxsiditems.h b/libretroshare/src/rsitems/rsgxsiditems.h index 440247403..e18ae9759 100644 --- a/libretroshare/src/rsitems/rsgxsiditems.h +++ b/libretroshare/src/rsitems/rsgxsiditems.h @@ -3,7 +3,9 @@ * * * libretroshare: retroshare core library * * * - * Copyright 2012-2012 by Robert Fernie * + * Copyright (C) 2012 Robert Fernie * + * Copyright (C) 2021 Gioacchino Mazzurco * + * Copyright (C) 2021 Asociación Civil Altermundi * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * @@ -19,8 +21,7 @@ * along with this program. If not, see . * * * *******************************************************************************/ -#ifndef RS_GXS_IDENTITY_ITEMS_H -#define RS_GXS_IDENTITY_ITEMS_H +#pragma once #include @@ -57,15 +58,20 @@ public: bool toGxsIdGroup(RsGxsIdGroup &group, bool moveImage); Sha1CheckSum mPgpIdHash; - // Need a signature as proof - otherwise anyone could add others Hashes. - // This is a string, as the length is variable. - std::string mPgpIdSign; - // Recognition Strings. MAX# defined above. - std::list mRecognTags; + /** Need a signature as proof - otherwise anyone could add others Hashes. + * This is a string, as the length is variable. + * TODO: this should actually be a byte array (pointer+size), using an + * std::string breaks the JSON serialization. + * Be careful refactoring this as it may break retrocompatibility as this + * item is sent over the network */ + std::string mPgpIdSign; - // Avatar - RsTlvImage mImage ; + /// Unused + RS_DEPRECATED std::list mRecognTags; + + /// Avatar + RsTlvImage mImage; }; struct RsGxsIdLocalInfoItem : public RsGxsIdItem @@ -89,5 +95,3 @@ public: virtual RsItem *create_item(uint16_t service_id,uint8_t item_subtype) const ; }; - -#endif /* RS_GXS_IDENTITY_ITEMS_H */ diff --git a/libretroshare/src/services/p3idservice.cc b/libretroshare/src/services/p3idservice.cc index d35d3afe0..7182b6a25 100644 --- a/libretroshare/src/services/p3idservice.cc +++ b/libretroshare/src/services/p3idservice.cc @@ -2,7 +2,8 @@ * libretroshare/src/services: p3idservice.cc * * * * Copyright (C) 2012-2014 Robert Fernie * - * Copyright (C) 2017-2019 Gioacchino Mazzurco * + * Copyright (C) 2017-2021 Gioacchino Mazzurco * + * Copyright (C) 2021 Asociación Civil Altermundi * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * @@ -4960,7 +4961,21 @@ void RsGxsIdGroup::serial_process( { RS_SERIAL_PROCESS(mMeta); RS_SERIAL_PROCESS(mPgpIdHash); - RS_SERIAL_PROCESS(mPgpIdSign); + switch(j) + { + /* mPgpIdSign is declared as std::string but it is a disguised raw memory + * chunk, serializing it as plain string breaks JSON and eventually + * teminals if it get printed, it should have been declared as a raw memory + * chunk in the first place, but as of today just ignoring it in *JSON and + * PRINT operations seems a reasonable workaround */ + case RsGenericSerializer::SerializeJob::PRINT: // [[fallthrough]] + case RsGenericSerializer::SerializeJob::TO_JSON: // [[fallthrough]] + case RsGenericSerializer::SerializeJob::FROM_JSON: + break; + default: + RS_SERIAL_PROCESS(mPgpIdSign); + break; + } RS_SERIAL_PROCESS(mImage); RS_SERIAL_PROCESS(mLastUsageTS); RS_SERIAL_PROCESS(mPgpKnown); diff --git a/libretroshare/src/util/rsdir.cc b/libretroshare/src/util/rsdir.cc index 8556b8198..1a6375297 100644 --- a/libretroshare/src/util/rsdir.cc +++ b/libretroshare/src/util/rsdir.cc @@ -4,8 +4,8 @@ * libretroshare: retroshare core library * * * * Copyright (C) 2004-2007 Robert Fernie * - * Copyright (C) 2020 Gioacchino Mazzurco * - * Copyright (C) 2020 Asociación Civil Altermundi * + * Copyright (C) 2020-2021 Gioacchino Mazzurco * + * Copyright (C) 2020-2021 Asociación Civil Altermundi * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * @@ -64,6 +64,26 @@ * #define RSDIR_DEBUG 1 ****/ +#if __cplusplus < 201703L +bool std::filesystem::create_directories(const std::string& path) +{ + for( std::string::size_type lastIndex = 0; lastIndex < std::string::npos; + lastIndex = path.find('/', lastIndex) ) + { + std::string&& curDir = path.substr(0, ++lastIndex); + if(!RsDirUtil::checkCreateDirectory(curDir)) + { + RsErr() << __PRETTY_FUNCTION__ << " failure creating: " << curDir + << " of: " << path << std::endl; + return false; + } + } + return true; +} +#else +# include +#endif // __cplusplus < 201703L + std::string RsDirUtil::getTopDir(const std::string& dir) { std::string top; @@ -528,24 +548,6 @@ bool RsDirUtil::checkCreateDirectory(const std::string& dir) return true; } -#if __cplusplus < 201703L -bool std::filesystem::create_directories(const std::string& path) -{ - for( std::string::size_type lastIndex = 0; lastIndex < std::string::npos; - lastIndex = path.find('/', lastIndex) ) - { - std::string&& curDir = path.substr(0, ++lastIndex); - if(!RsDirUtil::checkCreateDirectory(curDir)) - { - RsErr() << __PRETTY_FUNCTION__ << " failure creating: " << curDir - << " of: " << path << std::endl; - return false; - } - } - return true; -} -#endif // __cplusplus < 201703L - std::string RsDirUtil::removeSymLinks(const std::string& path) { #if defined(WINDOWS_SYS) || defined(__APPLE__) || defined(__ANDROID__) diff --git a/plugins/VOIP/VOIP.pro b/plugins/VOIP/VOIP.pro index 66e20cdee..1ec4defa4 100644 --- a/plugins/VOIP/VOIP.pro +++ b/plugins/VOIP/VOIP.pro @@ -53,7 +53,6 @@ linux-* { PKGCONFIG += libavcodec libavutil PKGCONFIG += speex speexdsp - PKGCONFIG += opencv4 } else { LIBS += -lspeex -lspeexdsp -lavcodec -lavutil } @@ -64,39 +63,6 @@ win32 { DEPENDPATH += . $$INC_DIR INCLUDEPATH += . $$INC_DIR - - USE_PRECOMPILED_LIBS = - for(lib, RS_LIB_DIR) { -#message(Scanning $$lib) - isEmpty(USE_PRECOMPILED_LIBS) { - exists($$lib/opencv/libopencv_core.a) { - message(Get pre-compiled opencv libraries here:) - message($$lib/opencv) - LIBS += -L"$$lib/opencv" - USE_PRECOMPILED_LIBS = 1 - } - exists($$lib/libopencv_core.dll.a) { - message(Get pre-compiled opencv libraries here:) - message($$lib) - LIBS += -L"$$lib" - USE_PRECOMPILED_LIBS = 1 - } - } - } - isEmpty(USE_PRECOMPILED_LIBS) { - message(Use system opencv libraries.) - } - - LIBS += -lopencv_core -lopencv_highgui -lopencv_imgproc -lopencv_videoio -lopencv_imgcodecs -llibwebp -llibtiff -llibpng -llibopenjp2 -lIlmImf - LIBS += -lole32 -loleaut32 -luuid -lvfw32 - - # Check for msys2 - !isEmpty(PREFIX_MSYS2) { - message(Use msys2 opencv4.) - INCLUDEPATH += "$${PREFIX_MSYS2}/include/opencv4" - } else { - LIBS += -llibjpeg-turbo -lzlib - } } #################################### MacOSX ##################################### @@ -105,30 +71,6 @@ macx { DEPENDPATH += . $$INC_DIR INCLUDEPATH += . $$INC_DIR - - #OPENCV_VERSION = "249" - USE_PRECOMPILED_LIBS = - for(lib, LIB_DIR) { -#message(Scanning $$lib) - exists( $$lib/opencv/libopencv_core*.dylib) { - isEmpty(USE_PRECOMPILED_LIBS) { - message(Get pre-compiled opencv libraries here:) - message($$lib) - LIBS += -L"$$lib/opencv" - LIBS += -lopencv_core -lopencv_highgui -lopencv_imgproc - USE_PRECOMPILED_LIBS = 1 - } - } - exists( $$lib/libopencv_videoio*.dylib) { - message(videoio found in opencv libraries.) - message($$lib) - LIBS += -lopencv_videoio - } - } - isEmpty(USE_PRECOMPILED_LIBS) { - message(Use system opencv libraries.) - LIBS += -lopencv_core -lopencv_highgui -lopencv_imgproc - } } @@ -138,9 +80,9 @@ QMAKE_CXXFLAGS += -D__STDC_CONSTANT_MACROS QMAKE_CXXFLAGS *= -Wall SOURCES = VOIPPlugin.cpp \ + gui/VOIPConfigPanel.cpp \ services/p3VOIP.cc \ services/rsVOIPItems.cc \ - gui/AudioInputConfig.cpp \ gui/AudioStats.cpp \ gui/AudioWizard.cpp \ gui/SpeexProcessor.cpp \ @@ -154,9 +96,9 @@ SOURCES = VOIPPlugin.cpp \ gui/VOIPToasterNotify.cpp HEADERS = VOIPPlugin.h \ + gui/VOIPConfigPanel.h \ services/p3VOIP.h \ services/rsVOIPItems.h \ - gui/AudioInputConfig.h \ gui/AudioStats.h \ gui/AudioWizard.h \ gui/SpeexProcessor.h \ @@ -170,9 +112,10 @@ HEADERS = VOIPPlugin.h \ gui/VOIPToasterNotify.h \ interface/rsVOIP.h -FORMS = gui/AudioInputConfig.ui \ +FORMS = \ gui/AudioStats.ui \ gui/AudioWizard.ui \ + gui/VOIPConfigPanel.ui \ gui/VOIPToasterItem.ui TARGET = VOIP diff --git a/plugins/VOIP/VOIPPlugin.cpp b/plugins/VOIP/VOIPPlugin.cpp index e5b412858..75719e156 100644 --- a/plugins/VOIP/VOIPPlugin.cpp +++ b/plugins/VOIP/VOIPPlugin.cpp @@ -31,14 +31,13 @@ #include "VOIPPlugin.h" #include "interface/rsVOIP.h" -#include "gui/AudioInputConfig.h" +#include "gui/VOIPConfigPanel.h" #include "gui/VOIPChatWidgetHolder.h" #include "gui/VOIPGUIHandler.h" #include "gui/VOIPNotify.h" #include "gui/SoundManager.h" #include "gui/chat/ChatWidget.h" -#include #include #define IMAGE_VOIP ":/images/talking_on.svg" @@ -113,7 +112,7 @@ ConfigPage *VOIPPlugin::qt_config_page() const // The config pages are deleted when config is closed, so it's important not to static the // created object. // - return new AudioInputConfig() ; + return new VOIPConfigPanel() ; } QDialog *VOIPPlugin::qt_about_page() const @@ -188,8 +187,6 @@ std::string VOIPPlugin::getPluginName() const void VOIPPlugin::getLibraries(std::list &libraries) { - libraries.push_back(RsLibraryInfo("OpenCV", CV_VERSION)); - const char *speexVersion = NULL; if (speex_lib_ctl(SPEEX_LIB_GET_VERSION_STRING, &speexVersion) == 0 && speexVersion) { libraries.push_back(RsLibraryInfo("Speex", speexVersion)); diff --git a/plugins/VOIP/gui/AudioStats.cpp b/plugins/VOIP/gui/AudioStats.cpp index 536cf0a1d..96ea93b83 100644 --- a/plugins/VOIP/gui/AudioStats.cpp +++ b/plugins/VOIP/gui/AudioStats.cpp @@ -25,7 +25,7 @@ #include #include "AudioStats.h" -#include "AudioInputConfig.h" +#include "VOIPConfigPanel.h" //#include "Global.h" //#include "smallft.h" diff --git a/plugins/VOIP/gui/AudioWizard.ui b/plugins/VOIP/gui/AudioWizard.ui index dfe9578f6..22d848fc4 100644 --- a/plugins/VOIP/gui/AudioWizard.ui +++ b/plugins/VOIP/gui/AudioWizard.ui @@ -202,7 +202,16 @@ - + + 0 + + + 0 + + + 0 + + 0 diff --git a/plugins/VOIP/gui/QVideoDevice.cpp b/plugins/VOIP/gui/QVideoDevice.cpp index 1a3d084db..57fa12d51 100644 --- a/plugins/VOIP/gui/QVideoDevice.cpp +++ b/plugins/VOIP/gui/QVideoDevice.cpp @@ -18,15 +18,18 @@ * * *******************************************************************************/ -#include -#include -#include - #include #include +#include +#include +#include +#include +#include #include "QVideoDevice.h" #include "VideoProcessor.h" +// #define DEBUG_QVIDEODEVICE 1 + QVideoInputDevice::QVideoInputDevice(QWidget *parent) :QObject(parent) { @@ -36,16 +39,28 @@ QVideoInputDevice::QVideoInputDevice(QWidget *parent) _echo_output_device = NULL ; } -bool QVideoInputDevice::stopped() +QVideoInputDevice::~QVideoInputDevice() +{ + stop() ; + _video_processor = NULL ; + + delete _image_capture; + delete _capture_device; + delete _timer; +} + +bool QVideoInputDevice::stopped() const { return _timer == NULL ; } void QVideoInputDevice::stop() { + _capture_device_info = QCameraInfo(); + if(_timer != NULL) { - QObject::disconnect(_timer,SIGNAL(timeout()),this,SLOT(grabFrame())) ; + _capture_device->stop(); _timer->stop() ; delete _timer ; _timer = NULL ; @@ -53,57 +68,118 @@ void QVideoInputDevice::stop() if(_capture_device != NULL) { // the camera will be deinitialized automatically in VideoCapture destructor - _capture_device->release(); - delete _capture_device ; + delete _image_capture ; + delete _capture_device ; + _capture_device = NULL ; - } + _image_capture = NULL ; + } + if(_echo_output_device != NULL) + _echo_output_device->showFrameOff() ; } -void QVideoInputDevice::start() +void QVideoInputDevice::getAvailableDevices(QList& device_desc) +{ + device_desc.clear(); + + QList dev_list = QCameraInfo::availableCameras(); + + for(auto& cam:dev_list) + device_desc.push_back(cam.deviceName()); +} + +void QVideoInputDevice::start(const QString& description) { // make sure everything is re-initialised // stop() ; - // Initialise la capture - static const int cam_id = 0 ; - _capture_device = new cv::VideoCapture(cam_id); + QCameraInfo caminfo ; - if(!_capture_device->isOpened()) - { - std::cerr << "Cannot initialise camera. Something's wrong." << std::endl; - return ; - } + if(description.isNull()) + caminfo = QCameraInfo::defaultCamera(); + else + { + auto cam_list = QCameraInfo::availableCameras(); - _timer = new QTimer ; - QObject::connect(_timer,SIGNAL(timeout()),this,SLOT(grabFrame())) ; + for(auto& s:cam_list) + if(s.deviceName() == description) + caminfo = s; + } - _timer->start(50) ; // 10 images per second. + if(caminfo.isNull()) + { + std::cerr << "No video camera available in this system!" << std::endl; + return ; + } + _capture_device_info = caminfo; + _capture_device = new QCamera(caminfo); + + if(_capture_device->error() != QCamera::NoError) + { + emit cameraCaptureInfo(CANNOT_INITIALIZE_CAMERA,_capture_device->error()); + std::cerr << "Cannot initialise camera. Something's wrong." << std::endl; + return; + } + _capture_device->setCaptureMode(QCamera::CaptureStillImage); + + if(_capture_device->error() == QCamera::NoError) + emit cameraCaptureInfo(CAMERA_IS_READY,QCamera::NoError); + + _image_capture = new QCameraImageCapture(_capture_device); + + if(!_image_capture->isCaptureDestinationSupported(QCameraImageCapture::CaptureToBuffer)) + { + emit cameraCaptureInfo(CAMERA_IS_READY,QCamera::NoError); + + delete _capture_device; + delete _image_capture; + return; + } + + _image_capture->setCaptureDestination(QCameraImageCapture::CaptureToBuffer); + + QObject::connect(_image_capture,SIGNAL(imageAvailable(int,QVideoFrame)),this,SLOT(grabFrame(int,QVideoFrame))); + QObject::connect(this,SIGNAL(cameraCaptureInfo(CameraStatus,QCamera::Error)),this,SLOT(errorHandling(CameraStatus,QCamera::Error))); + + _timer = new QTimer ; + QObject::connect(_timer,SIGNAL(timeout()),_image_capture,SLOT(capture())) ; + + _timer->start(50) ; // 10 images per second. + + _capture_device->start(); } -void QVideoInputDevice::grabFrame() +void QVideoInputDevice::errorHandling(CameraStatus status,QCamera::Error error) { - if(!_timer) - return ; - - cv::Mat frame; - if(!_capture_device->read(frame)) +#ifdef DEBUG_QVIDEODEVICE + std::cerr << "Received msg from camera capture: status=" << (int)status << " error=" << (int)error << std::endl; +#endif + if(status == CANNOT_INITIALIZE_CAMERA) { - std::cerr << "(EE) Cannot capture image from camera. Something's wrong." << std::endl; - return ; + std::cerr << "Cannot initialize camera. Make sure to install package libqt5multimedia5-plugins, as this is a common cause for camera not being found." << std::endl; + } +} + +void QVideoInputDevice::grabFrame(int id,QVideoFrame frame) +{ + if(frame.size().isEmpty()) + { + std::cerr << "Empty frame!" ; + return; } - // get the image data + frame.map(QAbstractVideoBuffer::ReadOnly); + QByteArray data((const char *)frame.bits(), frame.mappedBytes()); + QBuffer buffer; + buffer.setData(data); + buffer.open(QIODevice::ReadOnly); + QImageReader reader(&buffer, "JPG"); + reader.setScaledSize(QSize(640,480)); + QImage image(reader.read()); - if(frame.channels() != 3) - { - std::cerr << "(EE) expected 3 channels. Got " << frame.channels() << std::endl; - return ; - } - - // convert to RGB and copy to new buffer, because cvQueryFrame tells us to not modify the buffer - cv::Mat img_rgb; - cv::cvtColor(frame, img_rgb, CV_BGR2RGB); - QImage image = QImage(img_rgb.data,img_rgb.cols,img_rgb.rows,QImage::Format_RGB888); +#ifdef DEBUG_QVIDEODEVICE + std::cerr << "Frame " << id << ". Pixel format: " << frame.pixelFormat() << ". Size: " << image.size().width() << " x " << image.size().height() << std::endl; // if(frame.pixelFormat() != QVideoFrame::Format_Jpeg) +#endif if(_video_processor != NULL) { @@ -128,16 +204,12 @@ bool QVideoInputDevice::getNextEncodedPacket(RsVOIPDataChunk& chunk) uint32_t QVideoInputDevice::currentBandwidth() const { - return _video_processor->currentBandwidthOut() ; + if(stopped()) + return 0; + else + return _video_processor->currentBandwidthOut() ; } -QVideoInputDevice::~QVideoInputDevice() -{ - stop() ; - _video_processor = NULL ; -} - - QVideoOutputDevice::QVideoOutputDevice(QWidget *parent) : QLabel(parent) { @@ -152,7 +224,9 @@ void QVideoOutputDevice::showFrameOff() void QVideoOutputDevice::showFrame(const QImage& img) { +#ifdef DEBUG_QVIDEODEVICE std::cerr << "img.size = " << img.width() << " x " << img.height() << std::endl; +#endif setPixmap(QPixmap::fromImage(img).scaled( QSize(height()*4/3,height()),Qt::IgnoreAspectRatio,Qt::SmoothTransformation)) ; } diff --git a/plugins/VOIP/gui/QVideoDevice.h b/plugins/VOIP/gui/QVideoDevice.h index e0c21778e..63d83b4e1 100644 --- a/plugins/VOIP/gui/QVideoDevice.h +++ b/plugins/VOIP/gui/QVideoDevice.h @@ -21,13 +21,14 @@ #pragma once #include +#include +#include #include "interface/rsVOIP.h" -#include "opencv2/opencv.hpp" - #include "gui/VideoProcessor.h" class VideoEncoder ; +class QCameraImageCapture; // Responsible from displaying the video. The source of the video is // a VideoDecoder object, which uses a codec. @@ -49,7 +50,7 @@ class QVideoInputDevice: public QObject Q_OBJECT public: - QVideoInputDevice(QWidget *parent = 0) ; + QVideoInputDevice(QWidget *parent = 0) ; ~QVideoInputDevice() ; // Captured images are sent to this encoder. Can be NULL. @@ -71,19 +72,35 @@ class QVideoInputDevice: public QObject // control - void start() ; + void start(const QString &description = QString()) ; void stop() ; - bool stopped(); + bool stopped() const; + + enum CameraStatus { + CAMERA_IS_READY = 0x00, + CANNOT_INITIALIZE_CAMERA = 0x01, + CAMERA_CANNOT_GRAB_FRAMES = 0x02 + }; + + // Gets the list of available devices. The id string for each device can be used when creating a QVideoDevice + + static void getAvailableDevices(QList& device_desc); + + QString currentCameraDescriptionString() const { return _capture_device_info.deviceName(); } protected slots: - void grabFrame() ; + void grabFrame(int id, QVideoFrame f) ; + void errorHandling(CameraStatus status,QCamera::Error error); signals: void networkPacketReady() ; + void cameraCaptureInfo(CameraStatus status,QCamera::Error qt_cam_err_code); private: VideoProcessor *_video_processor ; QTimer *_timer ; - cv::VideoCapture *_capture_device ; + QCamera *_capture_device; + QCameraImageCapture *_image_capture; + QCameraInfo _capture_device_info; QVideoOutputDevice *_echo_output_device ; diff --git a/plugins/VOIP/gui/AudioInputConfig.cpp b/plugins/VOIP/gui/VOIPConfigPanel.cpp similarity index 50% rename from plugins/VOIP/gui/AudioInputConfig.cpp rename to plugins/VOIP/gui/VOIPConfigPanel.cpp index b063d5e48..b30df639c 100644 --- a/plugins/VOIP/gui/AudioInputConfig.cpp +++ b/plugins/VOIP/gui/VOIPConfigPanel.cpp @@ -19,14 +19,14 @@ * along with this program. If not, see . * * * *******************************************************************************/ -#pragma once #include "AudioStats.h" -#include "AudioInputConfig.h" +#include "VOIPConfigPanel.h" #include "audiodevicehelper.h" #include "AudioWizard.h" #include "gui/VideoProcessor.h" -#include "gui/common/RSGraphWidget.h" +#include "gui/VideoProcessor.h" +#include "util/misc.h" #include "util/RsProtectedTimer.h" #include @@ -80,7 +80,7 @@ voipGraph::voipGraph(QWidget *parent) } /** Constructor */ -AudioInputConfig::AudioInputConfig(QWidget * parent, Qt::WindowFlags flags) +VOIPConfigPanel::VOIPConfigPanel(QWidget * parent, Qt::WindowFlags flags) : ConfigPage(parent, flags) { std::cerr << "Creating audioInputConfig object" << std::endl; @@ -92,19 +92,57 @@ AudioInputConfig::AudioInputConfig(QWidget * parent, Qt::WindowFlags flags) inputAudioProcessor = NULL; inputAudioDevice = NULL; - abSpeech = NULL; qtTick = NULL; + ui.qcbTransmit->addItem(tr("Continuous"), RsVOIP::AudioTransmitContinous); + ui.qcbTransmit->addItem(tr("Voice Activity"), RsVOIP::AudioTransmitVAD); + ui.qcbTransmit->addItem(tr("Push To Talk"), RsVOIP::AudioTransmitPushToTalk); + + ui.abSpeech->qcBelow = Qt::red; + ui.abSpeech->qcInside = Qt::yellow; + ui.abSpeech->qcAbove = Qt::green; + + QList input_devices; + QVideoInputDevice::getAvailableDevices(input_devices); + ui.inputDevice_CB->clear(); + ui.inputDevice_CB->addItem(tr("[No video]"),QString("")); + for(auto& s:input_devices) + ui.inputDevice_CB->addItem(s,QVariant(s)); + + if(!input_devices.empty()) + whileBlocking(ui.inputDevice_CB)->setCurrentIndex(1); // select default cam + + connect( ui.qsTransmitHold, SIGNAL( valueChanged ( int ) ), this, SLOT( on_qsTransmitHold_valueChanged(int) ) ); + connect( ui.qsNoise, SIGNAL( valueChanged ( int ) ), this, SLOT( on_qsNoise_valueChanged(int) ) ); + connect( ui.qsAmp, SIGNAL( valueChanged ( int ) ), this, SLOT( on_qsAmp_valueChanged(int) ) ); + connect( ui.qcbTransmit, SIGNAL( currentIndexChanged ( int ) ), this, SLOT( on_qcbTransmit_currentIndexChanged(int) ) ); + connect( ui.inputDevice_CB, SIGNAL( currentIndexChanged ( int ) ), this, SLOT( on_changedCurrentInputDevice(int) ) ); +} + +void VOIPConfigPanel::showEvent(QShowEvent *) +{ + std::cerr << "Creating the audio pipeline" << std::endl; + + inputAudioProcessor = new QtSpeex::SpeexInputProcessor(); + inputAudioProcessor->open(QIODevice::WriteOnly | QIODevice::Unbuffered); + + inputAudioDevice = AudioDeviceHelper::getPreferedInputDevice(); + inputAudioDevice->start(inputAudioProcessor); + + connect(inputAudioProcessor, SIGNAL(networkPacketReady()), this, SLOT(emptyBuffer())); + + std::cerr << "Creating the video pipeline" << std::endl; + // Create the video pipeline. // + videoInput = new QVideoInputDevice(this) ; - videoInput->setEchoVideoTarget(ui.videoDisplay) ; videoProcessor = new VideoProcessor() ; videoProcessor->setDisplayTarget(NULL) ; videoProcessor->setMaximumBandwidth(ui.availableBW_SB->value()) ; - + videoInput->setVideoProcessor(videoProcessor) ; graph_source = new voipGraphSource ; @@ -114,17 +152,43 @@ AudioInputConfig::AudioInputConfig(QWidget * parent, Qt::WindowFlags flags) graph_source->setCollectionTimeLimit(1000*300) ; graph_source->start() ; + if(ui.showEncoded_CB->isChecked()) + { + videoInput->setEchoVideoTarget(nullptr) ; + videoProcessor->setDisplayTarget(ui.videoDisplay) ; + } + else + { + videoInput->setEchoVideoTarget(ui.videoDisplay) ; + videoProcessor->setDisplayTarget(nullptr); + } + QObject::connect(ui.showEncoded_CB,SIGNAL(toggled(bool)),this,SLOT(togglePreview(bool))) ; QObject::connect(ui.availableBW_SB,SIGNAL(valueChanged(double)),this,SLOT(updateAvailableBW(double))) ; + + loadSettings(); + + qtTick = new RsProtectedTimer(this); + connect( qtTick, SIGNAL( timeout ( ) ), this, SLOT( on_Tick_timeout() ) ); + qtTick->start(20); + + videoInput->start(); } -void AudioInputConfig::updateAvailableBW(double r) +void VOIPConfigPanel::hideEvent(QHideEvent *) +{ + std::cerr << "Deleting the video pipeline" << std::endl; + + clearPipeline(); +} + +void VOIPConfigPanel::updateAvailableBW(double r) { std::cerr << "Setting max bandwidth to " << r << " KB/s" << std::endl; videoProcessor->setMaximumBandwidth((uint32_t)(r*1024)) ; } -void AudioInputConfig::togglePreview(bool b) +void VOIPConfigPanel::togglePreview(bool b) { if(b) { @@ -138,148 +202,98 @@ void AudioInputConfig::togglePreview(bool b) } } -AudioInputConfig::~AudioInputConfig() +VOIPConfigPanel::~VOIPConfigPanel() { - disconnect( qtTick, SIGNAL( timeout ( ) ), this, SLOT( on_Tick_timeout() ) ); - - graph_source->stop() ; - graph_source->setVideoInput(NULL) ; - + clearPipeline(); +} + +void VOIPConfigPanel::clearPipeline() +{ + delete qtTick; + + graph_source->stop() ; + graph_source->setVideoInput(NULL) ; + graph_source=nullptr; // is deleted by setSource below. This is a bad design. + + ui.voipBwGraph->setSource(nullptr); + std::cerr << "Deleting audioInputConfig object" << std::endl; if(videoInput != NULL) { videoInput->stop() ; delete videoInput ; + + videoInput = nullptr; } + delete videoProcessor; + videoProcessor = nullptr; if (inputAudioDevice) { inputAudioDevice->stop(); delete inputAudioDevice ; - inputAudioDevice = NULL ; + inputAudioDevice = nullptr ; } if(inputAudioProcessor) { delete inputAudioProcessor ; - inputAudioProcessor = NULL ; + inputAudioProcessor = nullptr ; } } -/** Loads the settings for this page */ -void AudioInputConfig::load() +void VOIPConfigPanel::load() { - //connect( ui.allowIpDeterminationCB, SIGNAL( toggled( bool ) ), this, SLOT( toggleIpDetermination(bool) ) ); - //connect( ui.allowTunnelConnectionCB, SIGNAL( toggled( bool ) ), this, SLOT( toggleTunnelConnection(bool) ) ); - - qtTick = new RsProtectedTimer(this); - connect( qtTick, SIGNAL( timeout ( ) ), this, SLOT( on_Tick_timeout() ) ); - qtTick->start(20); - /*if (AudioInputRegistrar::qmNew) { - QList keys = AudioInputRegistrar::qmNew->keys(); - foreach(QString key, keys) { - qcbSystem->addItem(key); - } - } - qcbSystem->setEnabled(qcbSystem->count() > 1);*/ - - ui.qcbTransmit->addItem(tr("Continuous"), RsVOIP::AudioTransmitContinous); - ui.qcbTransmit->addItem(tr("Voice Activity"), RsVOIP::AudioTransmitVAD); - ui.qcbTransmit->addItem(tr("Push To Talk"), RsVOIP::AudioTransmitPushToTalk); - - abSpeech = new AudioBar(); - abSpeech->qcBelow = Qt::red; - abSpeech->qcInside = Qt::yellow; - abSpeech->qcAbove = Qt::green; - //abSpeech->setGeometry(9,20,50,10); - ui.qwVadLayout_2->addWidget(abSpeech,0,0,1,0); - - //on_qcbPushClick_clicked(g.s.bPushClick); - //ui.on_Tick_timeout(); - loadSettings(); } +/** Loads the settings for this page */ -void AudioInputConfig::loadSettings() { - /*QList keys; +void VOIPConfigPanel::loadSettings() +{ + ui.qcbTransmit->setCurrentIndex(rsVOIP->getVoipATransmit()); + on_qcbTransmit_currentIndexChanged(rsVOIP->getVoipATransmit()); + ui.qsTransmitHold->setValue(rsVOIP->getVoipVoiceHold()); + on_qsTransmitHold_valueChanged(rsVOIP->getVoipVoiceHold()); + ui.qsTransmitMin->setValue(rsVOIP->getVoipfVADmin()); + ui.qsTransmitMax->setValue(rsVOIP->getVoipfVADmax()); + ui.qcbEchoCancel->setChecked(rsVOIP->getVoipEchoCancel()); - if (AudioInputRegistrar::qmNew) - keys=AudioInputRegistrar::qmNew->keys(); - else - keys.clear(); - i=keys.indexOf(AudioInputRegistrar::current); - if (i >= 0) - loadComboBox(qcbSystem, i); + if (rsVOIP->getVoipiNoiseSuppress() != 0) + ui.qsNoise->setValue(-rsVOIP->getVoipiNoiseSuppress()); + else + ui.qsNoise->setValue(14); - loadCheckBox(qcbExclusive, r.bExclusiveInput);*/ + on_qsNoise_valueChanged(-rsVOIP->getVoipiNoiseSuppress()); - //qlePushClickPathOn->setText(r.qsPushClickOn); - //qlePushClickPathOff->setText(r.qsPushClickOff); + ui.qsAmp->setValue(20000 - rsVOIP->getVoipiMinLoudness()); + on_qsAmp_valueChanged(20000 - rsVOIP->getVoipiMinLoudness()); - /*loadComboBox(qcbTransmit, r.atTransmit); - loadSlider(qsTransmitHold, r.iVoiceHold); - loadSlider(qsTransmitMin, iroundf(r.fVADmin * 32767.0f + 0.5f)); - loadSlider(qsTransmitMax, iroundf(r.fVADmax * 32767.0f + 0.5f)); - loadSlider(qsFrames, (r.iFramesPerPacket == 1) ? 1 : (r.iFramesPerPacket/2 + 1)); - loadSlider(qsDoublePush, iroundf(static_cast(r.uiDoublePush) / 1000.f + 0.5f));*/ - ui.qcbTransmit->setCurrentIndex(rsVOIP->getVoipATransmit()); - on_qcbTransmit_currentIndexChanged(rsVOIP->getVoipATransmit()); - ui.qsTransmitHold->setValue(rsVOIP->getVoipVoiceHold()); - on_qsTransmitHold_valueChanged(rsVOIP->getVoipVoiceHold()); - ui.qsTransmitMin->setValue(rsVOIP->getVoipfVADmin()); - ui.qsTransmitMax->setValue(rsVOIP->getVoipfVADmax()); - ui.qcbEchoCancel->setChecked(rsVOIP->getVoipEchoCancel()); - //ui.qsDoublePush->setValue(iroundf(static_cast(r.uiDoublePush) / 1000.f + 0.5f)); - - //loadCheckBox(qcbPushClick, r.bPushClick); - //loadSlider(qsQuality, r.iQuality); - if (rsVOIP->getVoipiNoiseSuppress() != 0) - ui.qsNoise->setValue(-rsVOIP->getVoipiNoiseSuppress()); - else - ui.qsNoise->setValue(14); - - on_qsNoise_valueChanged(-rsVOIP->getVoipiNoiseSuppress()); - - ui.qsAmp->setValue(20000 - rsVOIP->getVoipiMinLoudness()); - on_qsAmp_valueChanged(20000 - rsVOIP->getVoipiMinLoudness()); - //loadSlider(qsIdle, r.iIdleTime); - - /*int echo = 0; - if (r.bEcho) - echo = r.bEchoMulti ? 2 : 1; - - loadComboBox(qcbEcho, echo);*/ - connect( ui.qsTransmitHold, SIGNAL( valueChanged ( int ) ), this, SLOT( on_qsTransmitHold_valueChanged(int) ) ); - connect( ui.qsNoise, SIGNAL( valueChanged ( int ) ), this, SLOT( on_qsNoise_valueChanged(int) ) ); - connect( ui.qsAmp, SIGNAL( valueChanged ( int ) ), this, SLOT( on_qsAmp_valueChanged(int) ) ); - connect( ui.qcbTransmit, SIGNAL( currentIndexChanged ( int ) ), this, SLOT( on_qcbTransmit_currentIndexChanged(int) ) ); - loaded = true; - - std::cerr << "AudioInputConfig:: starting video." << std::endl; - videoInput->start() ; + loaded = true; } -bool AudioInputConfig::save(QString &/*errmsg*/) {//mainly useless beacause saving occurs in realtime - //s.iQuality = qsQuality->value(); - rsVOIP->setVoipiNoiseSuppress((ui.qsNoise->value() == 14) ? 0 : - ui.qsNoise->value()); - rsVOIP->setVoipiMinLoudness(20000 - ui.qsAmp->value()); - rsVOIP->setVoipVoiceHold(ui.qsTransmitHold->value()); - rsVOIP->setVoipfVADmin(ui.qsTransmitMin->value()); - rsVOIP->setVoipfVADmax(ui.qsTransmitMax->value()); - /*s.uiDoublePush = qsDoublePush->value() * 1000;*/ - rsVOIP->setVoipATransmit(static_cast(ui.qcbTransmit->currentIndex() )); - rsVOIP->setVoipEchoCancel(ui.qcbEchoCancel->isChecked()); +bool VOIPConfigPanel::save(QString &/*errmsg*/) +{ + //mainly useless beacause saving occurs in realtime + //s.iQuality = qsQuality->value(); + rsVOIP->setVoipiNoiseSuppress((ui.qsNoise->value() == 14) ? 0 : - ui.qsNoise->value()); + rsVOIP->setVoipiMinLoudness(20000 - ui.qsAmp->value()); + rsVOIP->setVoipVoiceHold(ui.qsTransmitHold->value()); + rsVOIP->setVoipfVADmin(ui.qsTransmitMin->value()); + rsVOIP->setVoipfVADmax(ui.qsTransmitMax->value()); + /*s.uiDoublePush = qsDoublePush->value() * 1000;*/ + rsVOIP->setVoipATransmit(static_cast(ui.qcbTransmit->currentIndex() )); + rsVOIP->setVoipEchoCancel(ui.qcbEchoCancel->isChecked()); - return true; + return true; } -void AudioInputConfig::on_qsTransmitHold_valueChanged(int v) { +void VOIPConfigPanel::on_qsTransmitHold_valueChanged(int v) { float val = static_cast(v * FRAME_SIZE); val = val / SAMPLING_RATE; ui.qlTransmitHold->setText(tr("%1 s").arg(val, 0, 'f', 2)); rsVOIP->setVoipVoiceHold(v); } -void AudioInputConfig::on_qsNoise_valueChanged(int v) { +void VOIPConfigPanel::on_qsNoise_valueChanged(int v) { QPalette pal; if (v < 15) { @@ -292,19 +306,19 @@ void AudioInputConfig::on_qsNoise_valueChanged(int v) { rsVOIP->setVoipiNoiseSuppress(- ui.qsNoise->value()); } -void AudioInputConfig::on_qsAmp_valueChanged(int v) { +void VOIPConfigPanel::on_qsAmp_valueChanged(int v) { v = 20000 - v; float d = 20000.0f/static_cast(v); ui.qlAmp->setText(QString::fromLatin1("%1").arg(d, 0, 'f', 2)); rsVOIP->setVoipiMinLoudness(20000 - ui.qsAmp->value()); } -void AudioInputConfig::on_qcbEchoCancel_clicked() { +void VOIPConfigPanel::on_qcbEchoCancel_clicked() { rsVOIP->setVoipEchoCancel(ui.qcbEchoCancel->isChecked()); } -void AudioInputConfig::on_qcbTransmit_currentIndexChanged(int v) { +void VOIPConfigPanel::on_qcbTransmit_currentIndexChanged(int v) { switch (v) { case 0: ui.qswTransmit->setCurrentWidget(ui.qwContinuous); @@ -321,34 +335,25 @@ void AudioInputConfig::on_qcbTransmit_currentIndexChanged(int v) { } -void AudioInputConfig::on_Tick_timeout() +void VOIPConfigPanel::on_Tick_timeout() { - if (!inputAudioProcessor) - { - inputAudioProcessor = new QtSpeex::SpeexInputProcessor(); - inputAudioProcessor->open(QIODevice::WriteOnly | QIODevice::Unbuffered); + // update the sound capture bar - if (!inputAudioDevice) { - inputAudioDevice = AudioDeviceHelper::getPreferedInputDevice(); - } - inputAudioDevice->start(inputAudioProcessor); - connect(inputAudioProcessor, SIGNAL(networkPacketReady()), this, SLOT(emptyBuffer())); - } + ui.abSpeech->iBelow = ui.qsTransmitMin->value(); + ui.abSpeech->iAbove = ui.qsTransmitMax->value(); - abSpeech->iBelow = ui.qsTransmitMin->value(); - abSpeech->iAbove = ui.qsTransmitMax->value(); - if (loaded) { - rsVOIP->setVoipfVADmin(ui.qsTransmitMin->value()); - rsVOIP->setVoipfVADmax(ui.qsTransmitMax->value()); - } + if (loaded) { + rsVOIP->setVoipfVADmin(ui.qsTransmitMin->value()); + rsVOIP->setVoipfVADmax(ui.qsTransmitMax->value()); + } - abSpeech->iValue = iroundf(inputAudioProcessor->dVoiceAcivityLevel * 32767.0f + 0.5f); + ui.abSpeech->iValue = iroundf(inputAudioProcessor->dVoiceAcivityLevel * 32767.0f + 0.5f); + ui.abSpeech->update(); + + // also transmit encoded video - abSpeech->update(); - - // also transmit encoded video RsVOIPDataChunk chunk ; - + while((!videoInput->stopped()) && videoInput->getNextEncodedPacket(chunk)) { videoProcessor->receiveEncodedData(chunk) ; @@ -356,14 +361,103 @@ void AudioInputConfig::on_Tick_timeout() } } -void AudioInputConfig::emptyBuffer() { +void VOIPConfigPanel::emptyBuffer() { while(inputAudioProcessor->hasPendingPackets()) { inputAudioProcessor->getNetworkPacket(); //that will purge the buffer } } -void AudioInputConfig::on_qpbAudioWizard_clicked() { +void VOIPConfigPanel::on_qpbAudioWizard_clicked() { AudioWizard aw(this); aw.exec(); loadSettings(); } + +void VOIPConfigPanel::on_changedCurrentInputDevice(int i) +{ + QString s = dynamic_cast(sender())->itemData(i).toString(); + + videoInput->stop(); + + // check that the camera still exists + + QList input_devices; + QVideoInputDevice::getAvailableDevices(input_devices); + + for(const QString& cams:input_devices) + if(s == cams) + { + std::cerr << "Switching to camera \"" << s.toStdString() << "\"" << std::endl; + + videoInput->start(s); + + return; + } + + // if not, re-create the ComboBox + + checkAvailableCameras(); +} + +void VOIPConfigPanel::checkAvailableCameras() +{ + // save current camera + QString current_cam = videoInput->currentCameraDescriptionString(); + + // Check that the list of cams we had previously is the same than the list of available camera. + + QList input_devices; + QVideoInputDevice::getAvailableDevices(input_devices); + + bool same = true; + if(input_devices.size() != ui.inputDevice_CB->count()) + same = false; + + if(same) + { + int n=0; + for(auto& s:input_devices) + { + if(ui.inputDevice_CB->itemData(n).toString() != s) + { + same = false; + break; + } + n++; + } + } + + // If not, re-add them to the comboBox and make sure to re-select the same camera. + + if(!same) + { + whileBlocking(ui.inputDevice_CB)->clear(); // remove existing entries + whileBlocking(ui.inputDevice_CB)->addItem(tr("[No video]"),QString("")); + int n=0; + int found_index = -1; + + for(auto& s:input_devices) + { + whileBlocking(ui.inputDevice_CB)->addItem(s,QVariant(s)); + + if(s == current_cam) + found_index = n; + + n++; + } + + if(found_index >= 0) + ui.inputDevice_CB->setCurrentIndex(found_index); + else + ui.inputDevice_CB->setCurrentIndex(0); // no video + } +} + + + + + + + + + diff --git a/plugins/VOIP/gui/AudioInputConfig.h b/plugins/VOIP/gui/VOIPConfigPanel.h similarity index 77% rename from plugins/VOIP/gui/AudioInputConfig.h rename to plugins/VOIP/gui/VOIPConfigPanel.h index 3dd2cecae..dcfc0323b 100644 --- a/plugins/VOIP/gui/AudioInputConfig.h +++ b/plugins/VOIP/gui/VOIPConfigPanel.h @@ -19,7 +19,6 @@ * * *******************************************************************************/ #pragma once -#pragma once #include #include @@ -46,9 +45,9 @@ private: voipGraphSource *_src ; }; -#include "ui_AudioInputConfig.h" +#include "ui_VOIPConfigPanel.h" -class AudioInputConfig : public ConfigPage +class VOIPConfigPanel : public ConfigPage { Q_OBJECT @@ -60,33 +59,37 @@ class AudioInputConfig : public ConfigPage //VideoDecoder *videoDecoder ; //VideoEncoder *videoEncoder ; QVideoInputDevice *videoInput ; - VideoProcessor *videoProcessor ; + VideoProcessor *videoProcessor ; bool loaded; + QString currentCameraDescription; voipGraphSource *graph_source ; protected: QTimer *qtTick; - /*void hideEvent(QHideEvent *event); - void showEvent(QShowEvent *event);*/ + void clearPipeline(); public: /** Default Constructor */ - AudioInputConfig(QWidget * parent = 0, Qt::WindowFlags flags = 0); + VOIPConfigPanel(QWidget * parent = 0, Qt::WindowFlags flags = 0); /** Default Destructor */ - ~AudioInputConfig(); + ~VOIPConfigPanel(); /** Saves the changes on this page */ - virtual bool save(QString &errmsg); + virtual bool save(QString &errmsg)override ; /** Loads the settings for this page */ - virtual void load(); + virtual void load()override ; - virtual QPixmap iconPixmap() const { return QPixmap(":/images/talking_on.svg") ; } - virtual QString pageName() const { return tr("VOIP") ; } - virtual QString helpText() const { return ""; } + virtual QPixmap iconPixmap() const override { return QPixmap(":/images/talking_on.svg") ; } + virtual QString pageName() const override { return tr("VOIP") ; } + virtual QString helpText() const override { return ""; } + virtual void showEvent(QShowEvent *) override; + virtual void hideEvent(QHideEvent *event) override; private slots: - void updateAvailableBW(double r); + void on_changedCurrentInputDevice(int i); + void checkAvailableCameras(); + void updateAvailableBW(double r); void loadSettings(); void emptyBuffer(); void togglePreview(bool) ; diff --git a/plugins/VOIP/gui/AudioInputConfig.ui b/plugins/VOIP/gui/VOIPConfigPanel.ui similarity index 55% rename from plugins/VOIP/gui/AudioInputConfig.ui rename to plugins/VOIP/gui/VOIPConfigPanel.ui index 62e8c98a6..178436808 100644 --- a/plugins/VOIP/gui/AudioInputConfig.ui +++ b/plugins/VOIP/gui/VOIPConfigPanel.ui @@ -10,50 +10,289 @@ 832 - + - - - Audio Wizard + + + Video + + + + + + + + 170 + 128 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + + + + Input device: + + + + + + + + + + + 0 + 0 + + + + Available bandwidth: + + + + + + + <html><head/><body><p>Use this field to simulate the maximum bandwidth available so as to preview what the encoded video will look like with the corresponding compression rate.</p></body></html> + + + KB/s + + + 1 + + + 2.000000000000000 + + + 200.000000000000000 + + + 30.000000000000000 + + + + + + + + 0 + 0 + + + + <html><head/><body><p>Display encoded (and then decoded) frame, to check the codec's quality. If not selected, the image above only shows the frame that is grabbed from your camera.</p></body></html> + + + preview + + + + + + - - - - 0 - 0 - - + - Transmission + Audio - - - - - &Transmit + + + + + + 30 + 0 + - - qcbTransmit + + - - + + + + true + - When to transmit your speech + Noise suppression - <b>This sets when speech should be transmitted.</b><br /><i>Continuous</i> - All the time<br /><i>Voice Activity</i> - When you are speaking clearly.<br /><i>Push To Talk</i> - When you hold down the hotkey set under <i>Shortcuts</i>. + <b>This sets the amount of noise suppression to apply.</b><br />The higher this value, the more aggressively stationary noise will be suppressed. + + + 14 + + + 60 + + + 5 + + + Qt::Horizontal - + + + + Noise Suppression + + + qsNoise + + + + + + + + 30 + 0 + + + + + + + + + + + Maximum amplification of input sound + + + <b>Maximum amplification of input.</b><br />RetroShare normalizes the input volume before compressing, and this sets how much it's allowed to amplify.<br />The actual level is continually updated based on your current speech pattern, but it will never go above the level specified here.<br />If the <i>Microphone loudness</i> level of the audio statistics hover around 100%, you probably want to set this to 2.0 or so, but if, like most people, you are unable to reach 100%, set this to something much higher.<br />Ideally, set it so <i>Microphone Loudness * Amplification Factor >= 100</i>, even when you're speaking really soft.<br /><br />Note that there is no harm in setting this to maximum, but RetroShare will start picking up other conversations if you leave it to auto-tune to that level. + + + 19500 + + + 500 + + + 2000 + + + Qt::Horizontal + + + + + + + Amplification + + + qsAmp + + + + + + + + + + 0 + 0 + + + + Echo Cancellation Processing + + + false + + + + + + + + + + 0 + 0 + + + + &Transmit: + + + qcbTransmit + + + + + + + When to transmit your speech + + + <b>This sets when speech should be transmitted.</b><br /><i>Continuous</i> - All the time<br /><i>Voice Activity</i> - When you are speaking clearly.<br /><i>Push To Talk</i> - When you hold down the hotkey set under <i>Shortcuts</i>. + + + + + + + + + + 0 + 0 + + + + Audio Wizard + + + + + + + + + 0 + 0 + + - 2 + 1 @@ -231,218 +470,21 @@ - - - - - - - - - Audio Processing - - - - - - Noise Suppression - - - qsNoise - - - - - - - true - - - Noise suppression - - - <b>This sets the amount of noise suppression to apply.</b><br />The higher this value, the more aggressively stationary noise will be suppressed. - - - 14 - - - 60 - - - 5 - - - Qt::Horizontal - - - - - - - - 30 - 0 - - - - - - - - - - - Amplification - - - qsAmp - - - - - - - Maximum amplification of input sound - - - <b>Maximum amplification of input.</b><br />RetroShare normalizes the input volume before compressing, and this sets how much it's allowed to amplify.<br />The actual level is continually updated based on your current speech pattern, but it will never go above the level specified here.<br />If the <i>Microphone loudness</i> level of the audio statistics hover around 100%, you probably want to set this to 2.0 or so, but if, like most people, you are unable to reach 100%, set this to something much higher.<br />Ideally, set it so <i>Microphone Loudness * Amplification Factor >= 100</i>, even when you're speaking really soft.<br /><br />Note that there is no harm in setting this to maximum, but RetroShare will start picking up other conversations if you leave it to auto-tune to that level. - - - 19500 - - - 500 - - - 2000 - - - Qt::Horizontal - - - - - - - - 30 - 0 - - - - - - - - - - - Echo Cancellation Processing - - - false - - - - - - - - - - - - Video Processing - - - - - - 170 - 128 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - - 0 - 0 - - - - QFrame::StyledPanel - - - QFrame::Raised - - + - - - - - Available bandwidth: - - - - - - - <html><head/><body><p>Use this field to simulate the maximum bandwidth available so as to preview what the encoded video will look like with the corresponding compression rate.</p></body></html> - - - KB/s - - - 1 - - - 2.000000000000000 - - - 200.000000000000000 - - - 30.000000000000000 - - - - - - - - - <html><head/><body><p>Display encoded (and then decoded) frame, to check the codec's quality. If not selected, the image above only shows the frame that is grabbed from your camera.</p></body></html> - - - preview - - - - - + Qt::Vertical - 1 - 151 + 20 + 40 @@ -459,12 +501,17 @@ voipGraph QFrame -
gui/AudioInputConfig.h
+
gui/VOIPConfigPanel.h
+ 1 +
+ + AudioBar + QWidget +
gui/AudioStats.h
1
- qcbTransmit qsDoublePush qsTransmitHold qsTransmitMin