From 261df114d25e247066f1a270cdc455ef44b7d6e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20S=C5=82omkowski?= Date: Sun, 25 Oct 2015 14:26:53 +0100 Subject: [PATCH 01/59] Initial commit --- .gitignore | 28 +++++++++ LICENSE | 166 +++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 2 + 3 files changed, 196 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000000..b8bd0267bdf1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,28 @@ +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000000..341c30bda445 --- /dev/null +++ b/LICENSE @@ -0,0 +1,166 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. + diff --git a/README.md b/README.md new file mode 100644 index 000000000000..195f11b3204a --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# mumlib +Simple Mumble library using boost::asio, non-functional, still in development. From 6b846aff0521143596b5f494d9ac3f38c36c11fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20S=C5=82omkowski?= Date: Sun, 25 Oct 2015 14:40:16 +0100 Subject: [PATCH 02/59] Add source files from old repository. --- .gitignore | 6 + CMakeLists.txt | 59 ++++ include/mumlib.hpp | 47 +++ include/mumlib/Audio.hpp | 41 +++ include/mumlib/Callback.hpp | 318 +++++++++++++++++++++ include/mumlib/CryptState.hpp | 80 ++++++ include/mumlib/Transport.hpp | 128 +++++++++ include/mumlib/VarInt.hpp | 34 +++ include/mumlib/enums.hpp | 48 ++++ mumble.proto | 295 +++++++++++++++++++ mumlib_example.cpp | 54 ++++ src/Audio.cpp | 124 ++++++++ src/Callback.cpp | 182 ++++++++++++ src/CryptState.cpp | 286 +++++++++++++++++++ src/Transport.cpp | 520 ++++++++++++++++++++++++++++++++++ src/VarInt.cpp | 83 ++++++ src/mumlib.cpp | 244 ++++++++++++++++ 17 files changed, 2549 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 include/mumlib.hpp create mode 100644 include/mumlib/Audio.hpp create mode 100644 include/mumlib/Callback.hpp create mode 100644 include/mumlib/CryptState.hpp create mode 100644 include/mumlib/Transport.hpp create mode 100644 include/mumlib/VarInt.hpp create mode 100644 include/mumlib/enums.hpp create mode 100644 mumble.proto create mode 100644 mumlib_example.cpp create mode 100644 src/Audio.cpp create mode 100644 src/Callback.cpp create mode 100644 src/CryptState.cpp create mode 100644 src/Transport.cpp create mode 100644 src/VarInt.cpp create mode 100644 src/mumlib.cpp diff --git a/.gitignore b/.gitignore index b8bd0267bdf1..4286771d360d 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,9 @@ *.exe *.out *.app + +build/ + +# IntelliJ +*.iml +.idea/ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000000..c48446ceb089 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,59 @@ +cmake_minimum_required(VERSION 3.1.1) +project(libmumble) + +list(APPEND CMAKE_C_FLAGS " -std=c99 -g -Wall -pedantic ${CMAKE_C_FLAGS}") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") +add_definitions(-DOPT_TLS_GNUTLS -D_POSIX_C_SOURCE=200112L) + +INCLUDE(FindPkgConfig) +find_package(PkgConfig REQUIRED) +find_package(Boost COMPONENTS system unit_test_framework program_options filesystem REQUIRED) +find_package(OpenSSL REQUIRED) +find_package(Protobuf REQUIRED) + +pkg_check_modules(LOG4CPP "log4cpp") +pkg_check_modules(OPUS "opus") + + +INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIR}) +include_directories(${OPENSSL_INCLUDE_DIR}) +include_directories(${PROTOBUF_INCLUDE_DIRS}) +include_directories(${OPUS_INCLUDE_DIRS}) + +include_directories(${CMAKE_CURRENT_BINARY_DIR}) +include_directories(${LOG4CPP_INCLUDE_DIRS}) +include_directories(include) + +file(GLOB ProtoFiles "mumble.proto") + +set(MUMLIB_PUBLIC_HEADERS include/mumlib.hpp include/mumlib/VarInt.hpp) + +set(MUMLIB_PRIVATE_HEADERS + include/mumlib/Callback.hpp + include/mumlib/CryptState.hpp + include/mumlib/Transport.hpp + include/mumlib/Audio.hpp + include/mumlib/enums.hpp +) + +set(MUMLIB_SRC + src/mumlib.cpp + src/Callback.cpp + src/CryptState.cpp + src/VarInt.cpp + src/Transport.cpp + src/Audio.cpp +) + +PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS mumble.proto) + +add_library(mumlib SHARED ${MUMLIB_SRC} ${MUMLIB_PUBLIC_HEADERS} ${MUMLIB_PRIVATE_HEADERS} ${PROTO_SRCS} ${PROTO_HDRS}) +target_link_libraries(mumlib ${PROTOBUF_LIBRARIES}) +target_link_libraries(mumlib ${Boost_LIBRARIES}) +target_link_libraries(mumlib ${OPENSSL_LIBRARIES}) +target_link_libraries(mumlib ${LOG4CPP_LIBRARIES}) +target_link_libraries(mumlib ${OPUS_LIBRARIES}) + + +add_executable(mumlib_example mumlib_example.cpp) +target_link_libraries(mumlib_example mumlib) diff --git a/include/mumlib.hpp b/include/mumlib.hpp new file mode 100644 index 000000000000..a615e91e0f96 --- /dev/null +++ b/include/mumlib.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include "mumlib/Callback.hpp" + +#include +#include + +#include +#include + +namespace mumlib { + + using namespace std; + using namespace boost::asio; + + class MumlibException : public runtime_error { + public: + MumlibException(string message) : runtime_error(message) { } + }; + + struct _Mumlib_Private; + + + class Mumlib : boost::noncopyable { + public: + Mumlib(); + + Mumlib(io_service &ioService); + + ~Mumlib(); + + void setCallback(Callback &callback); + + void connect(string host, int port, string user, string password); + + void disconnect(); + + void run(); + + ConnectionState getConnectionState(); + + void sendAudioData(int16_t *pcmData, int pcmLength); + + private: + _Mumlib_Private *impl; + }; +} \ No newline at end of file diff --git a/include/mumlib/Audio.hpp b/include/mumlib/Audio.hpp new file mode 100644 index 000000000000..a71d73ff9cf3 --- /dev/null +++ b/include/mumlib/Audio.hpp @@ -0,0 +1,41 @@ +#pragma once + +#include "Transport.hpp" + +#include + +namespace mumlib { + + constexpr int SAMPLE_RATE = 48000; + + class AudioException : public MumlibException { + public: + AudioException(string message) : MumlibException(message) { } + }; + + class Audio : boost::noncopyable { + public: + Audio(); + + ~Audio(); + + + int decodeAudioPacket(AudioPacketType type, uint8_t *inputBuffer, int inputLength, int16_t *pcmBuffer, + int pcmBufferSize); + + int encodeAudioPacket( + int target, + int16_t *inputPcmBuffer, + int inputLength, + uint8_t *outputBuffer, + int outputBufferSize = MAX_UDP_LENGTH); + + private: + log4cpp::Category &logger; + + OpusDecoder *opusDecoder; + OpusEncoder *opusEncoder; + + int64_t outgoingSequenceNumber; + }; +} \ No newline at end of file diff --git a/include/mumlib/Callback.hpp b/include/mumlib/Callback.hpp new file mode 100644 index 000000000000..896f5b12f4cf --- /dev/null +++ b/include/mumlib/Callback.hpp @@ -0,0 +1,318 @@ +#pragma once + +#include +#include +#include + +namespace mumlib { + + using namespace std; + + class Callback { + public: + virtual void version_callback( + uint16_t major, + uint8_t minor, + uint8_t patch, + string release, + string os, + string os_version) { }; + + virtual void audio_callback( + uint8_t *pcm_data, + uint32_t pcm_data_size) { }; + + virtual void unsupported_audio_callback( + uint8_t *encoded_audio_data, + uint32_t encoded_audio_data_size) { }; + + virtual void serversync_callback( + string welcome_text, + int32_t session, + int32_t max_bandwidth, + int64_t permissions) { }; + + virtual void channelremove_callback(uint32_t channel_id) { }; + + virtual void channelstate_callback( + string name, + int32_t channel_id, + int32_t parent, + string description, + vector links, + vector inks_add, + vector links_remove, + bool temporary, + int32_t position) { }; + + virtual void userremove_callback( + uint32_t session, + int32_t actor, + string reason, + bool ban) { }; + + virtual void userstate_callback( + int32_t session, + int32_t actor, + string name, + int32_t user_id, + int32_t channel_id, + int32_t mute, + int32_t deaf, + int32_t suppress, + int32_t self_mute, + int32_t self_deaf, + string comment, + int32_t priority_speaker, + int32_t recording) { }; + + virtual void banlist_callback( + uint8_t *ip_data, + uint32_t ip_data_size, + uint32_t mask, + string name, + string hash, + string reason, + string start, + int32_t duration) { }; + + virtual void textmessage_callback( + uint32_t actor, + uint32_t n_session, + uint32_t *session, + uint32_t n_channel_id, + uint32_t *channel_id, + uint32_t n_tree_id, + uint32_t *tree_id, + string message) { }; + + virtual void permissiondenied_callback( + int32_t permission, + int32_t channel_id, + int32_t session, + string reason, + int32_t deny_type, + string name) { }; + + virtual void acl_callback() { }; + + virtual void queryusers_callback( + uint32_t n_ids, + uint32_t *ids, + uint32_t n_names, + string *names) { }; + + virtual void cryptsetup_callback( + uint32_t key_size, + uint8_t *key, + uint32_t client_nonce_size, + uint8_t *client_nonce, + uint32_t server_nonce_size, + uint8_t *server_nonce) { }; + + virtual void contextactionmodify_callback( + string action, + string text, + uint32_t m_context, + uint32_t operation) { }; + + virtual void contextaction_callback( + int32_t session, + int32_t channel_id, + string action) { }; + + virtual void userlist_callback( + uint32_t user_id, + string name, + string last_seen, + int32_t last_channel) { }; + + virtual void voicetarget_callback() { }; + + virtual void permissionquery_callback( + int32_t channel_id, + uint32_t permissions, + int32_t flush) { }; + + virtual void codecversion_callback( + int32_t alpha, + int32_t beta, + uint32_t prefer_alpha, + int32_t opus) { }; + + virtual void userstats_callback() { }; + + virtual void requestblob_callback() { }; + + virtual void serverconfig_callback( + uint32_t max_bandwidth, + string welcome_text, + uint32_t allow_html, + uint32_t message_length, + uint32_t image_message_length) { }; + + virtual void suggestconfig_callback( + uint32_t version, + uint32_t positional, + uint32_t push_to_talk) { }; + + }; + + class _BasicCallback_Private; + + class BasicCallback : public Callback { + public: + BasicCallback(); + + ~BasicCallback(); + + virtual void version_callback( + uint16_t major, + uint8_t minor, + uint8_t patch, + string release, + string os, + string os_version); + + virtual void audio_callback( + uint8_t *pcm_data, + uint32_t pcm_data_size); + + virtual void unsupported_audio_callback( + uint8_t *encoded_audio_data, + uint32_t encoded_audio_data_size); + + virtual void serversync_callback( + string welcome_text, + int32_t session, + int32_t max_bandwidth, + int64_t permissions); + + virtual void channelremove_callback(uint32_t channel_id); + + virtual void channelstate_callback( + string name, + int32_t channel_id, + int32_t parent, + string description, + vector links, + vector inks_add, + vector links_remove, + bool temporary, + int32_t position); + + virtual void userremove_callback( + uint32_t session, + int32_t actor, + string reason, + bool ban); + + virtual void userstate_callback( + int32_t session, + int32_t actor, + string name, + int32_t user_id, + int32_t channel_id, + int32_t mute, + int32_t deaf, + int32_t suppress, + int32_t self_mute, + int32_t self_deaf, + string comment, + int32_t priority_speaker, + int32_t recording); + + virtual void banlist_callback( + uint8_t *ip_data, + uint32_t ip_data_size, + uint32_t mask, + string name, + string hash, + string reason, + string start, + int32_t duration); + + virtual void textmessage_callback( + uint32_t actor, + uint32_t n_session, + uint32_t *session, + uint32_t n_channel_id, + uint32_t *channel_id, + uint32_t n_tree_id, + uint32_t *tree_id, + string message); + + virtual void permissiondenied_callback( + int32_t permission, + int32_t channel_id, + int32_t session, + string reason, + int32_t deny_type, + string name); + + virtual void acl_callback(); + + virtual void queryusers_callback( + uint32_t n_ids, + uint32_t *ids, + uint32_t n_names, + string *names); + + virtual void cryptsetup_callback( + uint32_t key_size, + uint8_t *key, + uint32_t client_nonce_size, + uint8_t *client_nonce, + uint32_t server_nonce_size, + uint8_t *server_nonce); + + virtual void contextactionmodify_callback( + string action, + string text, + uint32_t m_context, + uint32_t operation); + + virtual void contextaction_callback( + int32_t session, + int32_t channel_id, + string action); + + virtual void userlist_callback( + uint32_t user_id, + string name, + string last_seen, + int32_t last_channel); + + virtual void voicetarget_callback(); + + virtual void permissionquery_callback( + int32_t channel_id, + uint32_t permissions, + int32_t flush); + + virtual void codecversion_callback( + int32_t alpha, + int32_t beta, + uint32_t prefer_alpha, + int32_t opus); + + virtual void userstats_callback(); + + virtual void requestblob_callback(); + + virtual void serverconfig_callback( + uint32_t max_bandwidth, + string welcome_text, + uint32_t allow_html, + uint32_t message_length, + uint32_t image_message_length); + + virtual void suggestconfig_callback( + uint32_t version, + uint32_t positional, + uint32_t push_to_talk); + + private: + _BasicCallback_Private *impl; + }; +} \ No newline at end of file diff --git a/include/mumlib/CryptState.hpp b/include/mumlib/CryptState.hpp new file mode 100644 index 000000000000..cf5b61f2f63e --- /dev/null +++ b/include/mumlib/CryptState.hpp @@ -0,0 +1,80 @@ +/* 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. +*/ + +#pragma once + +#include +#include + +namespace mumlib { + + class CryptState : boost::noncopyable { + public: + unsigned char raw_key[AES_BLOCK_SIZE]; + unsigned char encrypt_iv[AES_BLOCK_SIZE]; + unsigned char decrypt_iv[AES_BLOCK_SIZE]; + unsigned char decrypt_history[0x100]; + + unsigned int uiGood; + unsigned int uiLate; + unsigned int uiLost; + unsigned int uiResync; + + unsigned int uiRemoteGood; + unsigned int uiRemoteLate; + unsigned int uiRemoteLost; + unsigned int uiRemoteResync; + + AES_KEY encrypt_key; + AES_KEY decrypt_key; + bool bInit; + + CryptState(); + + bool isValid() const; + + void setKey(const unsigned char *rkey, const unsigned char *eiv, const unsigned char *div); + + void setDecryptIV(const unsigned char *iv); + + void ocb_encrypt(const unsigned char *plain, unsigned char *encrypted, unsigned int len, + const unsigned char *nonce, + unsigned char *tag); + + void ocb_decrypt(const unsigned char *encrypted, unsigned char *plain, unsigned int len, + const unsigned char *nonce, + unsigned char *tag); + + bool decrypt(const unsigned char *source, unsigned char *dst, unsigned int crypted_length); + + void encrypt(const unsigned char *source, unsigned char *dst, unsigned int plain_length); + }; + +}; diff --git a/include/mumlib/Transport.hpp b/include/mumlib/Transport.hpp new file mode 100644 index 000000000000..4f3679f6bd4f --- /dev/null +++ b/include/mumlib/Transport.hpp @@ -0,0 +1,128 @@ +#pragma once + +#include "mumlib/CryptState.hpp" +#include "mumlib/VarInt.hpp" +#include "enums.hpp" + +#include +#include +#include +#include +#include + +#include +#include + +#include + +namespace mumlib { + + constexpr int MAX_UDP_LENGTH = 1024; + constexpr int MAX_TCP_LENGTH = 2048; + + using namespace std; + using namespace boost::asio; + using namespace boost::asio::ip; + + typedef function ProcessControlMessageFunction; + + typedef function ProcessEncodedAudioPacketFunction; + + class TransportException : public MumlibException { + public: + TransportException(string message) : MumlibException(message) { } + }; + + class Transport : boost::noncopyable { + public: + Transport(io_service &ioService, + ProcessControlMessageFunction processControlMessageFunc, + ProcessEncodedAudioPacketFunction processEncodedAudioPacketFunction, + bool noUdp = false); + + void connect(string host, + int port, + string user, + string password); + + void disconnect(); + + ConnectionState getConnectionState() { + return state; + } + + bool isUdpActive(); + + void sendControlMessage(MessageType type, google::protobuf::Message &message); + + void sendEncodedAudioPacket(uint8_t *buffer, int length); + + private: + log4cpp::Category &logger; + + io_service &ioService; + + pair connectionParams; + + pair credentials; + + ProcessControlMessageFunction processMessageFunction; + + ProcessEncodedAudioPacketFunction processEncodedAudioPacketFunction; + + const bool noUdp; + + volatile bool udpActive; + + ConnectionState state; + + udp::socket udpSocket; + ip::udp::endpoint udpReceiverEndpoint; + uint8_t udpIncomingBuffer[MAX_UDP_LENGTH]; + CryptState cryptState; + + ssl::context sslContext; + ssl::stream sslSocket; + uint8_t sslIncomingBuffer[MAX_TCP_LENGTH]; + + + deadline_timer pingTimer; + std::chrono::time_point lastReceivedUdpPacketTimestamp; + + boost::pool<> asyncBufferPool; + + void pingTimerTick(const boost::system::error_code &e); + + void sslConnectHandler(const boost::system::error_code &error); + + void sslHandshakeHandler(const boost::system::error_code &error); + + void doReceiveSsl(); + + void sendSsl(uint8_t *buff, int length); + + void sendSslAsync(uint8_t *buff, int length); + + void sendControlMessagePrivate(MessageType type, google::protobuf::Message &message); + + void sendSslPing(); + + void sendVersion(); + + void sendAuthentication(); + + void processMessageInternal(MessageType messageType, uint8_t *buffer, int length); + + void doReceiveUdp(); + + void sendUdpAsync(uint8_t *buff, int length); + + void sendUdpPing(); + + void throwTransportException(string message); + + void processAudioPacket(uint8_t *buff, int length); + }; + + +} diff --git a/include/mumlib/VarInt.hpp b/include/mumlib/VarInt.hpp new file mode 100644 index 000000000000..451c61e9b9b0 --- /dev/null +++ b/include/mumlib/VarInt.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include + +#include +#include +#include + +namespace mumlib { + class VarIntException : public MumlibException { + public: + VarIntException(std::string message) : MumlibException(message) { } + }; + + class VarInt { + public: + VarInt(uint8_t *encoded); + + VarInt(std::vector encoded); + + VarInt(int64_t value); + + int64_t getValue() const { + return this->value; + } + + std::vector getEncoded() const; + + private: + const int64_t value; + + int64_t parseVariant(uint8_t *buffer); + }; +} \ No newline at end of file diff --git a/include/mumlib/enums.hpp b/include/mumlib/enums.hpp new file mode 100644 index 000000000000..b4a9b436552d --- /dev/null +++ b/include/mumlib/enums.hpp @@ -0,0 +1,48 @@ +#pragma once + +namespace mumlib { + enum class MessageType { + VERSION = 0, + UDPTUNNEL = 1, + AUTHENTICATE = 2, + PING = 3, + REJECT = 4, + SERVERSYNC = 5, + CHANNELREMOVE = 6, + CHANNELSTATE = 7, + USERREMOVE = 8, + USERSTATE = 9, + BANLIST = 10, + TEXTMESSAGE = 11, + PERMISSIONDENIED = 12, + ACL = 13, + QUERYUSERS = 14, + CRYPTSETUP = 15, + CONTEXTACTIONMODIFY = 16, + CONTEXTACTION = 17, + USERLIST = 18, + VOICETARGET = 19, + PERMISSIONQUERY = 20, + CODECVERSION = 21, + USERSTATS = 22, + REQUESTBLOB = 23, + SERVERCONFIG = 24, + SUGGESTCONFIG = 25 + }; + + enum class ConnectionState { + NOT_CONNECTED, + IN_PROGRESS, + CONNECTED, + FAILED + }; + + enum class AudioPacketType { + CELT_Alpha, + Ping, + Speex, + CELT_Beta, + OPUS + }; + +} \ No newline at end of file diff --git a/mumble.proto b/mumble.proto new file mode 100644 index 000000000000..ad4f90e723ab --- /dev/null +++ b/mumble.proto @@ -0,0 +1,295 @@ +package MumbleProto; + +option optimize_for = SPEED; + +message Version { + optional uint32 version = 1; + optional string release = 2; + optional string os = 3; + optional string os_version = 4; +} + +message UDPTunnel { + required bytes packet = 1; +} + +message Authenticate { + optional string username = 1; + optional string password = 2; + repeated string tokens = 3; + repeated int32 celt_versions = 4; + optional bool opus = 5 [default = false]; +} + +message Ping { + optional uint64 timestamp = 1; + optional uint32 good = 2; + optional uint32 late = 3; + optional uint32 lost = 4; + optional uint32 resync = 5; + optional uint32 udp_packets = 6; + optional uint32 tcp_packets = 7; + optional float udp_ping_avg = 8; + optional float udp_ping_var = 9; + optional float tcp_ping_avg = 10; + optional float tcp_ping_var = 11; +} + +message Reject { + enum RejectType { + None = 0; + WrongVersion = 1; + InvalidUsername = 2; + WrongUserPW = 3; + WrongServerPW = 4; + UsernameInUse = 5; + ServerFull = 6; + NoCertificate = 7; + AuthenticatorFail = 8; + } + optional RejectType type = 1; + optional string reason = 2; +} + +message ServerSync { + optional uint32 session = 1; + optional uint32 max_bandwidth = 2; + optional string welcome_text = 3; + optional uint64 permissions = 4; +} + +message ChannelRemove { + required uint32 channel_id = 1; +} + +message ChannelState { + optional uint32 channel_id = 1; + optional uint32 parent = 2; + optional string name = 3; + repeated uint32 links = 4; + optional string description = 5; + repeated uint32 links_add = 6; + repeated uint32 links_remove = 7; + optional bool temporary = 8 [default = false]; + optional int32 position = 9 [default = 0]; + optional bytes description_hash = 10; +} + +message UserRemove { + required uint32 session = 1; + optional uint32 actor = 2; + optional string reason = 3; + optional bool ban = 4; +} + +message UserState { + optional uint32 session = 1; + optional uint32 actor = 2; + optional string name = 3; + optional uint32 user_id = 4; + optional uint32 channel_id = 5; + optional bool mute = 6; + optional bool deaf = 7; + optional bool suppress = 8; + optional bool self_mute = 9; + optional bool self_deaf = 10; + optional bytes texture = 11; + optional bytes plugin_context = 12; + optional string plugin_identity = 13; + optional string comment = 14; + optional string hash = 15; + optional bytes comment_hash = 16; + optional bytes texture_hash = 17; + optional bool priority_speaker = 18; + optional bool recording = 19; +} + +message BanList { + message BanEntry { + required bytes address = 1; + required uint32 mask = 2; + optional string name = 3; + optional string hash = 4; + optional string reason = 5; + optional string start = 6; + optional uint32 duration = 7; + } + repeated BanEntry bans = 1; + optional bool query = 2 [default = false]; +} + +message TextMessage { + optional uint32 actor = 1; + repeated uint32 session = 2; + repeated uint32 channel_id = 3; + repeated uint32 tree_id = 4; + required string message = 5; +} + +message PermissionDenied { + enum DenyType { + Text = 0; + Permission = 1; + SuperUser = 2; + ChannelName = 3; + TextTooLong = 4; + H9K = 5; + TemporaryChannel = 6; + MissingCertificate = 7; + UserName = 8; + ChannelFull = 9; + NestingLimit = 10; + } + optional uint32 permission = 1; + optional uint32 channel_id = 2; + optional uint32 session = 3; + optional string reason = 4; + optional DenyType type = 5; + optional string name = 6; +} + +message ACL { + message ChanGroup { + required string name = 1; + optional bool inherited = 2 [default = true]; + optional bool inherit = 3 [default = true]; + optional bool inheritable = 4 [default = true]; + repeated uint32 add = 5; + repeated uint32 remove = 6; + repeated uint32 inherited_members = 7; + } + message ChanACL { + optional bool apply_here = 1 [default = true]; + optional bool apply_subs = 2 [default = true]; + optional bool inherited = 3 [default = true]; + optional uint32 user_id = 4; + optional string group = 5; + optional uint32 grant = 6; + optional uint32 deny = 7; + } + required uint32 channel_id = 1; + optional bool inherit_acls = 2 [default = true]; + repeated ChanGroup groups = 3; + repeated ChanACL acls = 4; + optional bool query = 5 [default = false]; +} + +message QueryUsers { + repeated uint32 ids = 1; + repeated string names = 2; +} + +message CryptSetup { + optional bytes key = 1; + optional bytes client_nonce = 2; + optional bytes server_nonce = 3; +} + +message ContextActionModify { + enum Context { + Server = 0x01; + Channel = 0x02; + User = 0x04; + } + enum Operation { + Add = 0; + Remove = 1; + } + required string action = 1; + optional string text = 2; + optional uint32 context = 3; + optional Operation operation = 4; +} + +message ContextAction { + optional uint32 session = 1; + optional uint32 channel_id = 2; + required string action = 3; +} + +message UserList { + message User { + required uint32 user_id = 1; + optional string name = 2; + optional string last_seen = 3; + optional uint32 last_channel = 4; + } + repeated User users = 1; +} + +message VoiceTarget { + message Target { + repeated uint32 session = 1; + optional uint32 channel_id = 2; + optional string group = 3; + optional bool links = 4 [default = false]; + optional bool children = 5 [default = false]; + } + optional uint32 id = 1; + repeated Target targets = 2; +} + +message PermissionQuery { + optional uint32 channel_id = 1; + optional uint32 permissions = 2; + optional bool flush = 3 [default = false]; +} + +message CodecVersion { + required int32 alpha = 1; + required int32 beta = 2; + required bool prefer_alpha = 3 [default = true]; + optional bool opus = 4 [default = false]; +} + +message UserStats { + message Stats { + optional uint32 good = 1; + optional uint32 late = 2; + optional uint32 lost = 3; + optional uint32 resync = 4; + } + + optional uint32 session = 1; + optional bool stats_only = 2 [default = false]; + repeated bytes certificates = 3; + optional Stats from_client = 4; + optional Stats from_server = 5; + + optional uint32 udp_packets = 6; + optional uint32 tcp_packets = 7; + optional float udp_ping_avg = 8; + optional float udp_ping_var = 9; + optional float tcp_ping_avg = 10; + optional float tcp_ping_var = 11; + + optional Version version = 12; + repeated int32 celt_versions = 13; + optional bytes address = 14; + optional uint32 bandwidth = 15; + optional uint32 onlinesecs = 16; + optional uint32 idlesecs = 17; + optional bool strong_certificate = 18 [default = false]; + optional bool opus = 19 [default = false]; +} + +message RequestBlob { + repeated uint32 session_texture = 1; + repeated uint32 session_comment = 2; + repeated uint32 channel_description = 3; +} + +message ServerConfig { + optional uint32 max_bandwidth = 1; + optional string welcome_text = 2; + optional bool allow_html = 3; + optional uint32 message_length = 4; + optional uint32 image_message_length = 5; +} + +message SuggestConfig { + optional uint32 version = 1; + optional bool positional = 2; + optional bool push_to_talk = 3; +} + diff --git a/mumlib_example.cpp b/mumlib_example.cpp new file mode 100644 index 000000000000..86c162fbaa54 --- /dev/null +++ b/mumlib_example.cpp @@ -0,0 +1,54 @@ +#include "mumlib.hpp" + +#include "log4cpp/Category.hh" +#include "log4cpp/FileAppender.hh" +#include "log4cpp/OstreamAppender.hh" + +#include +#include +#include + +void audioSenderThreadFunction(mumlib::Mumlib *mum) { + while (mum->getConnectionState() != mumlib::ConnectionState::FAILED) { + if (mum->getConnectionState() == mumlib::ConnectionState::CONNECTED) { + constexpr double FREQUENCY = 1000; // Hz + constexpr int BUFF_SIZE = mumlib::SAMPLE_RATE / 100; // 10 ms + int16_t buff[BUFF_SIZE]; + + for (int i = 0; i < BUFF_SIZE; ++i) { + buff[i] = 10000 * std::sin(2.0 * M_PI * FREQUENCY * ((double) i) / ((double) mumlib::SAMPLE_RATE)); + } + + mum->sendAudioData(buff, BUFF_SIZE); + } + + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } +} + +int main(int argc, char *argv[]) { + + log4cpp::Appender *appender1 = new log4cpp::OstreamAppender("console", &std::cout); + appender1->setLayout(new log4cpp::BasicLayout()); + log4cpp::Category &logger = log4cpp::Category::getRoot(); + logger.setPriority(log4cpp::Priority::WARN); + logger.addAppender(appender1); + + if (argc < 3) { + logger.crit("Usage: %s {server} {password}", argv[0]); + return 1; + } + + mumlib::Mumlib mum; + + mumlib::BasicCallback callback; + mum.setCallback(callback); + + mum.connect(argv[1], 64738, "mumlib_example", argv[2]); + + std::thread audioSenderThread(audioSenderThreadFunction, &mum); + + mum.run(); + + return 0; +} \ No newline at end of file diff --git a/src/Audio.cpp b/src/Audio.cpp new file mode 100644 index 000000000000..7b54f9a1b449 --- /dev/null +++ b/src/Audio.cpp @@ -0,0 +1,124 @@ +#include "mumlib/Audio.hpp" + +#include + +mumlib::Audio::Audio() + : + logger(log4cpp::Category::getInstance("Mumlib.Audio")), + opusDecoder(nullptr), + opusEncoder(nullptr), + outgoingSequenceNumber(1) { + + int error; + + opusDecoder = opus_decoder_create(SAMPLE_RATE, 1, &error); + if (error != OPUS_OK) { + throw AudioException((boost::format("failed to initialize OPUS decoder: %s") % opus_strerror(error)).str()); + } + + opusEncoder = opus_encoder_create(SAMPLE_RATE, 1, OPUS_APPLICATION_VOIP, &error); + if (error != OPUS_OK) { + throw AudioException((boost::format("failed to initialize OPUS encoder: %s") % opus_strerror(error)).str()); + } + + opus_encoder_ctl(opusEncoder, OPUS_SET_VBR(0)); +} + +mumlib::Audio::~Audio() { + if (opusDecoder) { + opus_decoder_destroy(opusDecoder); + } + + if (opusEncoder) { + opus_encoder_destroy(opusEncoder); + } +} + +int mumlib::Audio::decodeAudioPacket(AudioPacketType type, + uint8_t *inputBuffer, + int inputLength, + int16_t *pcmBuffer, + int pcmBufferSize) { + + if (type != AudioPacketType::OPUS) { + throw AudioException("codecs other than OPUS are not supported"); + } + + int target = inputBuffer[0] & 0x1F; + + int64_t sessionId; + int64_t sequenceNumber; + int64_t opusDataLength; + + std::array varInts = {&sessionId, &sequenceNumber, &opusDataLength}; + + int dataPointer = 1; + for (int64_t *val : varInts) { + VarInt varInt(&inputBuffer[dataPointer]); + *val = varInt.getValue(); + dataPointer += varInt.getEncoded().size(); + } + + bool lastPacket = (opusDataLength & 0x2000) != 0; + opusDataLength = opusDataLength & 0x1fff; + + int outputSize = opus_decode(opusDecoder, + reinterpret_cast(&inputBuffer[dataPointer]), + opusDataLength, + pcmBuffer, + pcmBufferSize, + 0); + + if (outputSize <= 0) { + throw AudioException((boost::format("failed to decode %d B of OPUS data: %s") % inputLength % + opus_strerror(outputSize)).str()); + } + + logger.debug( + "Received %d B of OPUS data, decoded to %d B (target: %d, sessionID: %ld, seq num: %ld, last: %d).", + opusDataLength, + outputSize, + target, + sessionId, + sequenceNumber, + lastPacket); + + + return outputSize; +} + +int mumlib::Audio::encodeAudioPacket(int target, int16_t *inputPcmBuffer, int inputLength, uint8_t *outputBuffer, + int outputBufferSize) { + //if (!bPreviousVoice) + // opus_encoder_ctl(opusState, OPUS_RESET_STATE, NULL); //todo do something with it + + std::vector header; + + header.push_back(0x80 | target); + + auto sequenceNumberEnc = VarInt(outgoingSequenceNumber).getEncoded(); + header.insert(header.end(), sequenceNumberEnc.begin(), sequenceNumberEnc.end()); + + uint8_t tmpOpusBuffer[1024]; + const int outputSize = opus_encode(opusEncoder, + inputPcmBuffer, + inputLength, + tmpOpusBuffer, + min(outputBufferSize, 1024) + ); + + if (outputSize <= 0) { + throw AudioException((boost::format("failed to encode %d B of PCM data: %s") % inputLength % + opus_strerror(outputSize)).str()); + } + + auto outputSizeEnc = VarInt(outputSize).getEncoded(); + header.insert(header.end(), outputSizeEnc.begin(), outputSizeEnc.end()); + + memcpy(outputBuffer, &header[0], header.size()); + memcpy(outputBuffer + header.size(), tmpOpusBuffer, outputSize); + + outgoingSequenceNumber += 2; + + return outputSize + header.size(); +} diff --git a/src/Callback.cpp b/src/Callback.cpp new file mode 100644 index 000000000000..b330231826c1 --- /dev/null +++ b/src/Callback.cpp @@ -0,0 +1,182 @@ +#include "mumlib/Callback.hpp" + +#include +#include + +using namespace std; +using namespace mumlib; + +namespace mumlib { + struct _BasicCallback_Private : boost::noncopyable { + public: + _BasicCallback_Private() : logger(log4cpp::Category::getInstance("BasicCallback")) { } + + log4cpp::Category &logger; + }; +} + +mumlib::BasicCallback::BasicCallback() { + impl = new _BasicCallback_Private(); +} + +mumlib::BasicCallback::~BasicCallback() { + delete impl; +} + +void mumlib::BasicCallback::version_callback( + uint16_t major, + uint8_t minor, + uint8_t patch, + string release, + string os, + string os_version) { + impl->logger.debug("Version Callback: v%d.%d.%d. %s/%s/%s\n", major, minor, patch, release.c_str(), os.c_str(), + os_version.c_str()); +} + +void mumlib::BasicCallback::audio_callback( + uint8_t *pcm_data, + uint32_t pcm_data_size) { + impl->logger.debug("Received %d bytes of raw PCM data.", pcm_data_size); +} + +void mumlib::BasicCallback::unsupported_audio_callback( + uint8_t *encoded_audio_data, + uint32_t encoded_audio_data_size) { + impl->logger.debug("Received %d bytes of encoded audio data.", encoded_audio_data_size); +} + +void mumlib::BasicCallback::serversync_callback( + string welcome_text, + int32_t session, + int32_t max_bandwidth, + int64_t permissions) { + impl->logger.debug("Text: %s, session: %d, max bandwidth: %d, permissions: %d", welcome_text.c_str(), session, + max_bandwidth, permissions); +} + +void mumlib::BasicCallback::channelremove_callback(uint32_t channel_id) { } + +void mumlib::BasicCallback::channelstate_callback( + string name, + int32_t channel_id, + int32_t parent, + string description, + vector links, + vector inks_add, + vector links_remove, + bool temporary, + int32_t position) { + impl->logger.debug("Obtained channel state %d: %s, %s", channel_id, name.c_str(), description.c_str()); +} + +void mumlib::BasicCallback::userremove_callback( + uint32_t session, + int32_t actor, + string reason, + bool ban) { } + +void mumlib::BasicCallback::userstate_callback( + int32_t session, + int32_t actor, + string name, + int32_t user_id, + int32_t channel_id, + int32_t mute, + int32_t deaf, + int32_t suppress, + int32_t self_mute, + int32_t self_deaf, + string comment, + int32_t priority_speaker, + int32_t recording) { } + +void mumlib::BasicCallback::banlist_callback( + uint8_t *ip_data, + uint32_t ip_data_size, + uint32_t mask, + string name, + string hash, + string reason, + string start, + int32_t duration) { } + +void mumlib::BasicCallback::textmessage_callback( + uint32_t actor, + uint32_t n_session, + uint32_t *session, + uint32_t n_channel_id, + uint32_t *channel_id, + uint32_t n_tree_id, + uint32_t *tree_id, + string message) { } + +void mumlib::BasicCallback::permissiondenied_callback( + int32_t permission, + int32_t channel_id, + int32_t session, + string reason, + int32_t deny_type, + string name) { } + +void mumlib::BasicCallback::acl_callback() { } + +void mumlib::BasicCallback::queryusers_callback( + uint32_t n_ids, + uint32_t *ids, + uint32_t n_names, + string *names) { } + +void mumlib::BasicCallback::cryptsetup_callback( + uint32_t key_size, + uint8_t *key, + uint32_t client_nonce_size, + uint8_t *client_nonce, + uint32_t server_nonce_size, + uint8_t *server_nonce) { } + +void mumlib::BasicCallback::contextactionmodify_callback( + string action, + string text, + uint32_t m_context, + uint32_t operation) { } + +void mumlib::BasicCallback::contextaction_callback( + int32_t session, + int32_t channel_id, + string action) { } + +void mumlib::BasicCallback::userlist_callback( + uint32_t user_id, + string name, + string last_seen, + int32_t last_channel) { } + +void mumlib::BasicCallback::voicetarget_callback() { } + +void mumlib::BasicCallback::permissionquery_callback( + int32_t channel_id, + uint32_t permissions, + int32_t flush) { } + +void mumlib::BasicCallback::codecversion_callback( + int32_t alpha, + int32_t beta, + uint32_t prefer_alpha, + int32_t opus) { } + +void mumlib::BasicCallback::userstats_callback() { } + +void mumlib::BasicCallback::requestblob_callback() { } + +void mumlib::BasicCallback::serverconfig_callback( + uint32_t max_bandwidth, + string welcome_text, + uint32_t allow_html, + uint32_t message_length, + uint32_t image_message_length) { } + +void mumlib::BasicCallback::suggestconfig_callback( + uint32_t version, + uint32_t positional, + uint32_t push_to_talk) { } diff --git a/src/CryptState.cpp b/src/CryptState.cpp new file mode 100644 index 000000000000..0760374a3527 --- /dev/null +++ b/src/CryptState.cpp @@ -0,0 +1,286 @@ +/* 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. +*/ + +/* + * This code implements OCB-AES128. + * In the US, OCB is covered by patents. The inventor has given a license + * to all programs distributed under the GPL. + * Mumble is BSD (revised) licensed, meaning you can use the code in a + * closed-source program. If you do, you'll have to either replace + * OCB with something else or get yourself a license. + */ + + +#include "mumlib/CryptState.hpp" + +#include +#include + +using namespace std; + +mumlib::CryptState::CryptState() { + for (int i = 0; i < 0x100; i++) + decrypt_history[i] = 0; + bInit = false; + uiGood = uiLate = uiLost = uiResync = 0; + uiRemoteGood = uiRemoteLate = uiRemoteLost = uiRemoteResync = 0; +} + +bool mumlib::CryptState::isValid() const { + return bInit; +} + +void mumlib::CryptState::setKey(const unsigned char *rkey, const unsigned char *eiv, const unsigned char *div) { + memcpy(raw_key, rkey, AES_BLOCK_SIZE); + memcpy(encrypt_iv, eiv, AES_BLOCK_SIZE); + memcpy(decrypt_iv, div, AES_BLOCK_SIZE); + AES_set_encrypt_key(raw_key, 128, &encrypt_key); + AES_set_decrypt_key(raw_key, 128, &decrypt_key); + bInit = true; +} + +void mumlib::CryptState::setDecryptIV(const unsigned char *iv) { + memcpy(decrypt_iv, iv, AES_BLOCK_SIZE); +} + +void mumlib::CryptState::encrypt(const unsigned char *source, unsigned char *dst, unsigned int plain_length) { + unsigned char tag[AES_BLOCK_SIZE]; + + // First, increase our IV. + for (int i = 0; i < AES_BLOCK_SIZE; i++) + if (++encrypt_iv[i]) + break; + + ocb_encrypt(source, dst + 4, plain_length, encrypt_iv, tag); + + dst[0] = encrypt_iv[0]; + dst[1] = tag[0]; + dst[2] = tag[1]; + dst[3] = tag[2]; +} + +bool mumlib::CryptState::decrypt(const unsigned char *source, unsigned char *dst, unsigned int crypted_length) { + if (crypted_length < 4) + return false; + + unsigned int plain_length = crypted_length - 4; + + unsigned char saveiv[AES_BLOCK_SIZE]; + unsigned char ivbyte = source[0]; + bool restore = false; + unsigned char tag[AES_BLOCK_SIZE]; + + int lost = 0; + int late = 0; + + memcpy(saveiv, decrypt_iv, AES_BLOCK_SIZE); + + if (((decrypt_iv[0] + 1) & 0xFF) == ivbyte) { + // In order as expected. + if (ivbyte > decrypt_iv[0]) { + decrypt_iv[0] = ivbyte; + } else if (ivbyte < decrypt_iv[0]) { + decrypt_iv[0] = ivbyte; + for (int i = 1; i < AES_BLOCK_SIZE; i++) + if (++decrypt_iv[i]) + break; + } else { + return false; + } + } else { + // This is either out of order or a repeat. + + int diff = ivbyte - decrypt_iv[0]; + if (diff > 128) + diff = diff - 256; + else if (diff < -128) + diff = diff + 256; + + if ((ivbyte < decrypt_iv[0]) && (diff > -30) && (diff < 0)) { + // Late packet, but no wraparound. + late = 1; + lost = -1; + decrypt_iv[0] = ivbyte; + restore = true; + } else if ((ivbyte > decrypt_iv[0]) && (diff > -30) && (diff < 0)) { + // Last was 0x02, here comes 0xff from last round + late = 1; + lost = -1; + decrypt_iv[0] = ivbyte; + for (int i = 1; i < AES_BLOCK_SIZE; i++) + if (decrypt_iv[i]--) + break; + restore = true; + } else if ((ivbyte > decrypt_iv[0]) && (diff > 0)) { + // Lost a few packets, but beyond that we're good. + lost = ivbyte - decrypt_iv[0] - 1; + decrypt_iv[0] = ivbyte; + } else if ((ivbyte < decrypt_iv[0]) && (diff > 0)) { + // Lost a few packets, and wrapped around + lost = 256 - decrypt_iv[0] + ivbyte - 1; + decrypt_iv[0] = ivbyte; + for (int i = 1; i < AES_BLOCK_SIZE; i++) + if (++decrypt_iv[i]) + break; + } else { + return false; + } + + if (decrypt_history[decrypt_iv[0]] == decrypt_iv[1]) { + memcpy(decrypt_iv, saveiv, AES_BLOCK_SIZE); + return false; + } + } + + ocb_decrypt(source + 4, dst, plain_length, decrypt_iv, tag); + + if (memcmp(tag, source + 1, 3) != 0) { + memcpy(decrypt_iv, saveiv, AES_BLOCK_SIZE); + return false; + } + decrypt_history[decrypt_iv[0]] = decrypt_iv[1]; + + if (restore) + memcpy(decrypt_iv, saveiv, AES_BLOCK_SIZE); + + uiGood++; + uiLate += late; + uiLost += lost; + + return true; +} + +#define BLOCKSIZE 2 +#define SHIFTBITS 63 +typedef uint64_t subblock; + +#define SWAP64(x) ({register uint64_t __out, __in = (x); __asm__("bswap %q0" : "=r"(__out) : "0"(__in)); __out;}) +#define SWAPPED(x) SWAP64(x) + +typedef subblock keyblock[BLOCKSIZE]; + +static void inline XOR(subblock *dst, const subblock *a, const subblock *b) { + for (int i = 0; i < BLOCKSIZE; i++) { + dst[i] = a[i] ^ b[i]; + } +} + +static void inline S2(subblock *block) { + subblock carry = SWAPPED(block[0]) >> SHIFTBITS; + for (int i = 0; i < BLOCKSIZE - 1; i++) + block[i] = SWAPPED((SWAPPED(block[i]) << 1) | (SWAPPED(block[i + 1]) >> SHIFTBITS)); + block[BLOCKSIZE - 1] = SWAPPED((SWAPPED(block[BLOCKSIZE - 1]) << 1) ^ (carry * 0x87)); +} + +static void inline S3(subblock *block) { + subblock carry = SWAPPED(block[0]) >> SHIFTBITS; + for (int i = 0; i < BLOCKSIZE - 1; i++) + block[i] ^= SWAPPED((SWAPPED(block[i]) << 1) | (SWAPPED(block[i + 1]) >> SHIFTBITS)); + block[BLOCKSIZE - 1] ^= SWAPPED((SWAPPED(block[BLOCKSIZE - 1]) << 1) ^ (carry * 0x87)); +} + +static void inline ZERO(keyblock &block) { + for (int i = 0; i < BLOCKSIZE; i++) + block[i] = 0; +} + +#define AESencrypt(src, dst, key) AES_encrypt(reinterpret_cast(src),reinterpret_cast(dst), key); +#define AESdecrypt(src, dst, key) AES_decrypt(reinterpret_cast(src),reinterpret_cast(dst), key); + +void mumlib::CryptState::ocb_encrypt(const unsigned char *plain, unsigned char *encrypted, unsigned int len, + const unsigned char *nonce, unsigned char *tag) { + keyblock checksum, delta, tmp, pad; + + // Initialize + AESencrypt(nonce, delta, &encrypt_key); + ZERO(checksum); + + while (len > AES_BLOCK_SIZE) { + S2(delta); + XOR(tmp, delta, reinterpret_cast(plain)); + AESencrypt(tmp, tmp, &encrypt_key); + XOR(reinterpret_cast(encrypted), delta, tmp); + XOR(checksum, checksum, reinterpret_cast(plain)); + len -= AES_BLOCK_SIZE; + plain += AES_BLOCK_SIZE; + encrypted += AES_BLOCK_SIZE; + } + + S2(delta); + ZERO(tmp); + tmp[BLOCKSIZE - 1] = SWAPPED(len * 8); + XOR(tmp, tmp, delta); + AESencrypt(tmp, pad, &encrypt_key); + memcpy(tmp, plain, len); + memcpy(reinterpret_cast(tmp) + len, reinterpret_cast(pad) + len, + AES_BLOCK_SIZE - len); + XOR(checksum, checksum, tmp); + XOR(tmp, pad, tmp); + memcpy(encrypted, tmp, len); + + S3(delta); + XOR(tmp, delta, checksum); + AESencrypt(tmp, tag, &encrypt_key); +} + +void mumlib::CryptState::ocb_decrypt(const unsigned char *encrypted, unsigned char *plain, unsigned int len, + const unsigned char *nonce, unsigned char *tag) { + keyblock checksum, delta, tmp, pad; + + // Initialize + AESencrypt(nonce, delta, &encrypt_key); + ZERO(checksum); + + while (len > AES_BLOCK_SIZE) { + S2(delta); + XOR(tmp, delta, reinterpret_cast(encrypted)); + AESdecrypt(tmp, tmp, &decrypt_key); + XOR(reinterpret_cast(plain), delta, tmp); + XOR(checksum, checksum, reinterpret_cast(plain)); + len -= AES_BLOCK_SIZE; + plain += AES_BLOCK_SIZE; + encrypted += AES_BLOCK_SIZE; + } + + S2(delta); + ZERO(tmp); + tmp[BLOCKSIZE - 1] = SWAPPED(len * 8); + XOR(tmp, tmp, delta); + AESencrypt(tmp, pad, &encrypt_key); + memset(tmp, 0, AES_BLOCK_SIZE); + memcpy(tmp, encrypted, len); + XOR(tmp, tmp, pad); + XOR(checksum, checksum, tmp); + memcpy(plain, tmp, len); + + S3(delta); + XOR(tmp, delta, checksum); + AESencrypt(tmp, tag, &encrypt_key); +} diff --git a/src/Transport.cpp b/src/Transport.cpp new file mode 100644 index 000000000000..db23927fdbd3 --- /dev/null +++ b/src/Transport.cpp @@ -0,0 +1,520 @@ +#include "mumlib/Transport.hpp" + +#include "mumble.pb.h" + +#include + +using namespace std; + +static boost::posix_time::seconds PING_INTERVAL(5); + +const long CLIENT_VERSION = 0x010203; +const string CLIENT_RELEASE("Mumlib"); +const string CLIENT_OS("OS Unknown"); +const string CLIENT_OS_VERSION("1"); + +static map rejectMessages = { + {MumbleProto::Reject_RejectType_None, "no reason provided"}, + {MumbleProto::Reject_RejectType_WrongVersion, "wrong version"}, + {MumbleProto::Reject_RejectType_InvalidUsername, "invalid username"}, + {MumbleProto::Reject_RejectType_WrongUserPW, "wrong user password"}, + {MumbleProto::Reject_RejectType_WrongServerPW, "wrong server password"}, + {MumbleProto::Reject_RejectType_UsernameInUse, "username in use"}, + {MumbleProto::Reject_RejectType_ServerFull, "server full"}, + {MumbleProto::Reject_RejectType_NoCertificate, "no certificate provided"}, + {MumbleProto::Reject_RejectType_AuthenticatorFail, "authenticator fail"} +}; + +mumlib::Transport::Transport( + io_service &ioService, + mumlib::ProcessControlMessageFunction processMessageFunc, + ProcessEncodedAudioPacketFunction processEncodedAudioPacketFunction, + bool noUdp) : + logger(log4cpp::Category::getInstance("Mumlib.Transport")), + ioService(ioService), + processMessageFunction(processMessageFunc), + processEncodedAudioPacketFunction(processEncodedAudioPacketFunction), + noUdp(noUdp), + state(ConnectionState::NOT_CONNECTED), + udpSocket(ioService), + sslContext(ssl::context::sslv23), + sslSocket(ioService, sslContext), + pingTimer(ioService, PING_INTERVAL), + asyncBufferPool(max(MAX_UDP_LENGTH, MAX_TCP_LENGTH)) { + + pingTimer.async_wait(boost::bind(&Transport::pingTimerTick, this, _1)); +} + +void mumlib::Transport::connect( + std::string host, + int port, + std::string user, + std::string password) { + + state = ConnectionState::IN_PROGRESS; + + connectionParams = make_pair(host, port); + credentials = make_pair(user, password); + + udpActive = false; + + sslSocket.set_verify_mode(boost::asio::ssl::verify_peer); + + //todo for now it accepts every certificate, move it to callback + sslSocket.set_verify_callback([](bool preverified, boost::asio::ssl::verify_context &ctx) { + return true; + }); + + try { + if (not noUdp) { + ip::udp::resolver resolverUdp(ioService); + ip::udp::resolver::query queryUdp(ip::udp::v4(), host, to_string(port)); + udpReceiverEndpoint = *resolverUdp.resolve(queryUdp); + udpSocket.open(ip::udp::v4()); + + doReceiveUdp(); + } + + ip::tcp::resolver resolverTcp(ioService); + ip::tcp::resolver::query queryTcp(host, to_string(port)); + + async_connect(sslSocket.lowest_layer(), resolverTcp.resolve(queryTcp), + bind(&Transport::sslConnectHandler, this, boost::asio::placeholders::error)); + } catch (runtime_error &exp) { + throwTransportException(string("failed to establish connection: ") + exp.what()); + } +} + +void mumlib::Transport::disconnect() { + + state = ConnectionState::NOT_CONNECTED; + + sslSocket.shutdown(); + sslSocket.lowest_layer().shutdown(tcp::socket::shutdown_both); + + udpSocket.shutdown(udp::socket::shutdown_both); +} + + +void mumlib::Transport::sendVersion() { + MumbleProto::Version version; + + version.set_version(CLIENT_VERSION); + version.set_os(CLIENT_OS); + version.set_release(CLIENT_RELEASE); + version.set_os_version(CLIENT_OS_VERSION); + + logger.info("Sending version information."); + + sendControlMessagePrivate(MessageType::VERSION, version); +} + +void mumlib::Transport::sendAuthentication() { + string user, password; + tie(user, password) = credentials; + + MumbleProto::Authenticate authenticate; + authenticate.set_username(user); + authenticate.set_password(password); + authenticate.clear_celt_versions(); + authenticate.clear_tokens(); + authenticate.set_opus(true); + + logger.info("Sending authententication."); + + sendControlMessagePrivate(MessageType::AUTHENTICATE, authenticate); +} + +void mumlib::Transport::sendSslPing() { + MumbleProto::Ping ping; + ping.set_timestamp(std::time(nullptr)); + + logger.debug("Sending SSL ping."); + + sendControlMessagePrivate(MessageType::PING, ping); +} + + +bool mumlib::Transport::isUdpActive() { + return udpActive; +} + +void mumlib::Transport::doReceiveUdp() { + udpSocket.async_receive_from( + buffer(udpIncomingBuffer, MAX_UDP_LENGTH), + udpReceiverEndpoint, + [this](const boost::system::error_code &ec, size_t bytesTransferred) { + if (!ec and bytesTransferred > 0) { + logger.debug("Received UDP packet of %d B.", bytesTransferred); + + if (not cryptState.isValid()) { + throwTransportException("received UDP packet before CRYPT SETUP message"); + } else { + lastReceivedUdpPacketTimestamp = std::chrono::system_clock::now(); + + if (udpActive == false) { + udpActive = true; + logger.info("UDP is up."); + } + + uint8_t plainBuffer[1024]; + const int plainBufferLength = bytesTransferred - 4; + + bool success = cryptState.decrypt( + udpIncomingBuffer, plainBuffer, bytesTransferred); + + if (not success) { + throwTransportException("UDP packet decryption failed"); + } + + processAudioPacket(plainBuffer, plainBufferLength); + } + + doReceiveUdp(); + } else { + throwTransportException("UDP receive failed: " + ec.message()); + } + }); +} + +void mumlib::Transport::sslConnectHandler(const boost::system::error_code &error) { + if (!error) { + sslSocket.async_handshake(ssl::stream_base::client, + boost::bind(&Transport::sslHandshakeHandler, this, + boost::asio::placeholders::error)); + } + else { + throwTransportException((boost::format("Connect failed: %s.") % error.message()).str()); + } +} + +void mumlib::Transport::sslHandshakeHandler(const boost::system::error_code &error) { + if (!error) { + doReceiveSsl(); + + sendVersion(); + sendAuthentication(); + } + else { + throwTransportException((boost::format("Handshake failed: %s.") % error.message()).str()); + } +} + +void mumlib::Transport::pingTimerTick(const boost::system::error_code &e) { + if (state == ConnectionState::CONNECTED) { + + sendSslPing(); + + if (not noUdp) { + using namespace std::chrono; + + sendUdpPing(); + + if (udpActive) { + const int lastUdpReceivedMilliseconds = duration_cast( + system_clock::now() - lastReceivedUdpPacketTimestamp).count(); + + if (lastUdpReceivedMilliseconds > PING_INTERVAL.total_milliseconds() + 1000) { + udpActive = false; + logger.warn("Didn't receive UDP ping in %d ms, falling back to TCP.", lastUdpReceivedMilliseconds); + } + } + } + + pingTimer.expires_at(pingTimer.expires_at() + PING_INTERVAL); + pingTimer.async_wait(boost::bind(&Transport::pingTimerTick, this, _1)); + } +} + +void mumlib::Transport::sendUdpAsync(uint8_t *buff, int length) { + if (length > MAX_UDP_LENGTH - 4) { + throwTransportException("maximum allowed data length is %d" + to_string(MAX_UDP_LENGTH - 4)); + } + + auto *encryptedMsgBuff = asyncBufferPool.malloc(); + const int encryptedMsgLength = length + 4; + + cryptState.encrypt(buff, reinterpret_cast(encryptedMsgBuff), length); + + logger.debug("Sending %d B of data UDP asynchronously.", encryptedMsgLength); + + udpSocket.async_send_to( + boost::asio::buffer(encryptedMsgBuff, length + 4), + udpReceiverEndpoint, + [this, encryptedMsgBuff](const boost::system::error_code &ec, size_t bytesTransferred) { + asyncBufferPool.free(encryptedMsgBuff); + if (!ec and bytesTransferred > 0) { + logger.debug("Sent %d B via UDP.", bytesTransferred); + } else { + throwTransportException("UDP send failed: " + ec.message()); + } + }); +} + +void mumlib::Transport::doReceiveSsl() { + async_read( + sslSocket, + boost::asio::buffer(sslIncomingBuffer, MAX_TCP_LENGTH), + [this](const boost::system::error_code &error, size_t bytesTransferred) -> size_t { + if (bytesTransferred < 6) { + // we need the message header to determine the payload length + return 6 - bytesTransferred; + } + + const int payloadSize = ntohl(*reinterpret_cast(sslIncomingBuffer + 2)); + size_t remaining = payloadSize + 6 - bytesTransferred; + remaining = max(remaining, (size_t) 0); + + return remaining; + }, + [this](const boost::system::error_code &ec, size_t bytesTransferred) { + if (!ec and bytesTransferred > 0) { + + int messageType = ntohs(*reinterpret_cast(sslIncomingBuffer)); + + logger.debug("Received %d B of data (%d B payload, type %d).", bytesTransferred, + bytesTransferred - 6, messageType); + + processMessageInternal( + static_cast(messageType), + &sslIncomingBuffer[6], + bytesTransferred - 6); + + doReceiveSsl(); + } else { + throwTransportException("receive failed: " + ec.message()); + } + }); +} + +void mumlib::Transport::processMessageInternal(MessageType messageType, uint8_t *buffer, int length) { + switch (messageType) { + + case MessageType::UDPTUNNEL: { + logger.debug("Received %d B of encoded audio data via TCP.", length); + processAudioPacket(buffer, length); + } + break; + case MessageType::AUTHENTICATE: { + logger.warn("Authenticate message received after authenticated."); + } + break; + case MessageType::PING: { + MumbleProto::Ping ping; + ping.ParseFromArray(buffer, length); + stringstream log; + log << "Received ping."; + if (ping.has_good()) { + log << " good: " << ping.good(); + } + if (ping.has_late()) { + log << " late: " << ping.late(); + } + if (ping.has_lost()) { + log << " lost: " << ping.lost(); + } + if (ping.has_tcp_ping_avg()) { + log << " TCP avg: " << ping.tcp_ping_avg() << " ms"; + } + if (ping.has_udp_ping_avg()) { + log << " UDP avg: " << ping.udp_ping_avg() << " ms"; + } + logger.debug(log.str()); + } + break; + case MessageType::REJECT: { + MumbleProto::Reject reject; + reject.ParseFromArray(buffer, length); + + stringstream errorMesg; + errorMesg << "failed to authenticate"; + + if (reject.has_type()) { + errorMesg << ": " << rejectMessages.at(reject.type()); + } + + if (reject.has_reason()) { + errorMesg << ", reason: " << reject.reason(); + } + + throwTransportException(errorMesg.str()); + } + break; + case MessageType::SERVERSYNC: { + state = ConnectionState::CONNECTED; + + logger.debug("SERVERSYNC. Calling external ProcessControlMessageFunction."); + processMessageFunction(messageType, buffer, length); + } + break; + case MessageType::CRYPTSETUP: { + if (not noUdp) { + MumbleProto::CryptSetup cryptsetup; + cryptsetup.ParseFromArray(buffer, length); + + if (cryptsetup.client_nonce().length() != AES_BLOCK_SIZE + or cryptsetup.server_nonce().length() != AES_BLOCK_SIZE + or cryptsetup.key().length() != AES_BLOCK_SIZE) { + throwTransportException("one of cryptographic parameters has invalid length"); + } + + cryptState.setKey( + reinterpret_cast(cryptsetup.key().c_str()), + reinterpret_cast(cryptsetup.client_nonce().c_str()), + reinterpret_cast(cryptsetup.server_nonce().c_str())); + + if (not cryptState.isValid()) { + throwTransportException("crypt setup data not valid"); + } + + logger.info("Set up cryptography for UDP transport. Sending UDP ping."); + + sendUdpPing(); + + } else { + logger.info("Ignoring crypt setup message, because UDP is disabled."); + } + } + break; + case MessageType::VOICETARGET: { + MumbleProto::VoiceTarget voiceTarget; + voiceTarget.ParseFromArray(buffer, length); + logger.warn("VoiceTarget Message: I don't think the server ever sends this structure...."); + } + break; + default: { + logger.debug("Calling external ProcessControlMessageFunction."); + processMessageFunction(messageType, buffer, length); + } + break; + } +} + +void mumlib::Transport::sendUdpPing() { + logger.debug("Sending UDP ping."); + + vector message; + message.push_back(0x20); + + auto timestampVarint = VarInt(time(nullptr)).getEncoded(); + message.insert(message.end(), timestampVarint.begin(), timestampVarint.end()); + + sendUdpAsync(&message[0], message.size()); +} + +void mumlib::Transport::sendSsl(uint8_t *buff, int length) { + if (length > MAX_TCP_LENGTH) { + logger.warn("Sending %d B of data via SSL. Maximal allowed data length to receive is %d B.", length, + MAX_TCP_LENGTH); + } + + logger.debug("Sending %d bytes of data.", length); + + write(sslSocket, boost::asio::buffer(buff, length)); +} + +void mumlib::Transport::sendSslAsync(uint8_t *buff, int length) { + if (length > MAX_TCP_LENGTH) { + logger.warn("Sending %d B of data via SSL. Maximal allowed data length to receive is %d B.", length, + MAX_TCP_LENGTH); + } + + auto *asyncBuff = asyncBufferPool.malloc(); + + memcpy(asyncBuff, buff, length); + + logger.debug("Sending %d B of data asynchronously.", length); + + async_write( + sslSocket, + boost::asio::buffer(asyncBuff, length), + [this, asyncBuff](const boost::system::error_code &ec, size_t bytesTransferred) { + asyncBufferPool.free(asyncBuff); + logger.debug("Sent %d B.", bytesTransferred); + if (!ec and bytesTransferred > 0) { + + } else { + throwTransportException("send failed: " + ec.message()); + } + }); +} + +void mumlib::Transport::sendControlMessage(MessageType type, google::protobuf::Message &message) { + if (state != ConnectionState::CONNECTED) { + logger.warn("Connection not established."); + return; + } + sendControlMessagePrivate(type, message); +} + +void mumlib::Transport::sendControlMessagePrivate(MessageType type, google::protobuf::Message &message) { + + + const uint16_t type_network = htons(static_cast(type)); + + const int size = message.ByteSize(); + const uint32_t size_network = htonl(size); + + const int length = sizeof(type_network) + sizeof(size_network) + size; + + uint8_t buff[MAX_TCP_LENGTH]; + + memcpy(buff, &type_network, sizeof(type_network)); + + memcpy(buff + sizeof(type_network), &size_network, sizeof(size_network)); + + message.SerializeToArray(buff + sizeof(type_network) + sizeof(size_network), size); + + sendSsl(buff, length); +} + +void mumlib::Transport::throwTransportException(string message) { + state = ConnectionState::FAILED; + + throw TransportException(message); +} + +void mumlib::Transport::sendEncodedAudioPacket(uint8_t *buffer, int length) { + if (state != ConnectionState::CONNECTED) { + logger.warn("Connection not established."); + return; + } + + if (udpActive) { + logger.info("Sending %d B of audio data via UDP.", length); + sendUdpAsync(buffer, length); + } else { + logger.info("Sending %d B of audio data via TCP.", length); + + const uint16_t netUdptunnelType = htons(static_cast(MessageType::UDPTUNNEL)); + + const uint32_t netLength = htonl(length); + + const int packet = sizeof(netUdptunnelType) + sizeof(netLength) + length; + + uint8_t packetBuff[MAX_TCP_LENGTH]; + + memcpy(packetBuff, &netUdptunnelType, sizeof(netUdptunnelType)); + memcpy(packetBuff + sizeof(netUdptunnelType), &netLength, sizeof(netLength)); + memcpy(packetBuff + sizeof(netUdptunnelType) + sizeof(netLength), buffer, length); + + sendSslAsync(packetBuff, length + sizeof(netUdptunnelType) + sizeof(netLength)); + } +} + +void mumlib::Transport::processAudioPacket(uint8_t *buff, int length) { + AudioPacketType type = static_cast((buff[0] & 0xE0) >> 5); + switch (type) { + case AudioPacketType::CELT_Alpha: + case AudioPacketType::Speex: + case AudioPacketType::CELT_Beta: + case AudioPacketType::OPUS: + processEncodedAudioPacketFunction(type, buff, length); + break; + case AudioPacketType::Ping: + break; + default: + logger.error("Not recognized audio type: %xd.", buff[0]); + } +} + diff --git a/src/VarInt.cpp b/src/VarInt.cpp new file mode 100644 index 000000000000..2eeebf87438e --- /dev/null +++ b/src/VarInt.cpp @@ -0,0 +1,83 @@ +#include "mumlib/VarInt.hpp" + +#include + +mumlib::VarInt::VarInt(int64_t value) : value(value) { } + +mumlib::VarInt::VarInt(uint8_t *encoded) : value(parseVariant(encoded)) { } + +mumlib::VarInt::VarInt(std::vector encoded) : value(parseVariant(&encoded[0])) { } + +/* + * This code was taken from Mumble source code + * https://github.com/mumble-voip/mumble/blob/master/src/PacketDataStream.h + */ +int64_t mumlib::VarInt::parseVariant(uint8_t *buffer) { + int64_t v = buffer[0]; + if ((v & 0x80) == 0x00) { + return (v & 0x7F); + } else if ((v & 0xC0) == 0x80) { + return (v & 0x3F) << 8 | buffer[1]; + } else if ((v & 0xF0) == 0xF0) { + switch (v & 0xFC) { + case 0xF0: + return buffer[1] << 24 | buffer[2] << 16 | buffer[3] << 8 | buffer[4]; + case 0xF4: + throw VarIntException("currently unsupported 8-byte varint size"); + case 0xF8: + case 0xFC: + throw VarIntException("currently negative varints aren't supported"); + default: + break; + } + } else if ((v & 0xF0) == 0xE0) { + return (v & 0x0F) << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3]; + } else if ((v & 0xE0) == 0xC0) { + return (v & 0x1F) << 16 | buffer[1] << 8 | buffer[2]; + } + + throw VarIntException("invalid varint"); +} + +std::vector mumlib::VarInt::getEncoded() const { + std::vector encoded; + int64_t i = this->value; + + if ((i & 0x8000000000000000LL) && (~i < 0x100000000LL)) { + i = ~i; + if (i <= 0x3) { + encoded.push_back(0xFC | i); + return encoded; + } else { + encoded.push_back(0xF8); + } + } + + if (i < 0x80) { + encoded.push_back(i); + } else if (i < 0x4000) { + encoded.push_back(0x80 | (i >> 8)); + encoded.push_back(i & 0xFF); + } else if (i < 0x200000) { + encoded.push_back(0xC0 | (i >> 16)); + encoded.push_back((i >> 8) & 0xFF); + encoded.push_back(i & 0xFF); + } else if (i < 0x10000000) { + encoded.push_back(0xE0 | (i >> 24)); + encoded.push_back((i >> 16) & 0xFF); + encoded.push_back((i >> 8) & 0xFF); + encoded.push_back(i & 0xFF); + } else { + encoded.push_back(0xF4); + encoded.push_back((i >> 56) & 0xFF); + encoded.push_back((i >> 48) & 0xFF); + encoded.push_back((i >> 40) & 0xFF); + encoded.push_back((i >> 32) & 0xFF); + encoded.push_back((i >> 24) & 0xFF); + encoded.push_back((i >> 16) & 0xFF); + encoded.push_back((i >> 8) & 0xFF); + encoded.push_back(i & 0xFF); + } + + return encoded; +} diff --git a/src/mumlib.cpp b/src/mumlib.cpp new file mode 100644 index 000000000000..57ae2cf570ea --- /dev/null +++ b/src/mumlib.cpp @@ -0,0 +1,244 @@ +#include "mumlib.hpp" + +#include "mumlib/CryptState.hpp" +#include "mumlib/VarInt.hpp" +#include "mumlib/enums.hpp" +#include "mumlib/Transport.hpp" +#include "mumlib/Audio.hpp" + +#include +#include +#include + +#include + +using namespace std; +using namespace boost::asio; + +using namespace mumlib; + +namespace mumlib { + struct _Mumlib_Private : boost::noncopyable { + bool externalIoService; + io_service *ioService; + + Callback *callback; + + Transport *transport; + + Audio *audio; + + log4cpp::Category *logger; + + bool processIncomingTcpMessage(MessageType messageType, uint8_t *buffer, int length) { + switch (messageType) { + case MessageType::VERSION: { + MumbleProto::Version version; + version.ParseFromArray(buffer, length); + callback->version_callback( + version.version() >> 16, + version.version() >> 8 & 0xff, + version.version() & 0xff, + version.release(), + version.os(), + version.os_version()); + } + break; + case MessageType::SERVERSYNC: { + MumbleProto::ServerSync serverSync; + serverSync.ParseFromArray(buffer, length); + callback->serversync_callback( + serverSync.welcome_text(), + serverSync.session(), + serverSync.max_bandwidth(), + serverSync.permissions() + ); + } + break; + case MessageType::CHANNELREMOVE: { + MumbleProto::ChannelRemove channelRemove; + channelRemove.ParseFromArray(buffer, length); + callback->channelremove_callback(channelRemove.channel_id()); + } + break; + case MessageType::CHANNELSTATE: { + MumbleProto::ChannelState channelState; + channelState.ParseFromArray(buffer, length); + + int32_t channel_id = channelState.has_channel_id() ? channelState.channel_id() : -1; + int32_t parent = channelState.has_parent() ? channelState.parent() : -1; + + + bool temporary = channelState.has_temporary() ? channelState.temporary() + : false; //todo make sure it's correct to assume it's false + int position = channelState.has_position() ? channelState.position() : 0; + + vector links; + std::copy(channelState.links().begin(), channelState.links().end(), links.begin()); + + vector links_add; + std::copy(channelState.links_add().begin(), channelState.links_add().end(), links_add.begin()); + + vector links_remove; + std::copy(channelState.links_remove().begin(), channelState.links_remove().end(), + links_remove.begin()); + + callback->channelstate_callback( + channelState.name(), + channel_id, + parent, + channelState.description(), + links, + links_add, + links_remove, + temporary, + position + ); + } + break; + case MessageType::USERREMOVE: { + MumbleProto::UserRemove user_remove; + user_remove.ParseFromArray(buffer, length); + + int32_t actor = user_remove.has_actor() ? user_remove.actor() : -1; + bool ban = user_remove.has_ban() ? user_remove.ban() + : false; //todo make sure it's correct to assume it's false + + callback->userremove_callback( + user_remove.session(), + actor, + user_remove.reason(), + ban + ); + } + break; + case MessageType::USERSTATE: // 9 +// return MessageType::private_process_userstate(context, message, message_size); + + break; + case MessageType::BANLIST: // 10 +// return MessageType::private_process_banlist(context, message, message_size); + + break; + case MessageType::TEXTMESSAGE: // 11 +// return MessageType::private_process_textmessage(context, message, message_size); + + break; + case MessageType::PERMISSIONDENIED: // 12 +// return MessageType::private_process_permissiondenied(context, message, message_size); + + break; + case MessageType::ACL: // 13 +// return MessageType::private_process_acl(context, message, message_size); + + break; + case MessageType::QUERYUSERS: // 14 +// return MessageType::private_process_queryusers(context, message, message_size); + + break; + case MessageType::CONTEXTACTIONMODIFY: // 16 +// return MessageType::private_process_contextactionmodify(context, message, message_size); + + break; + case MessageType::CONTEXTACTION: // 17 +// return MessageType::private_process_contextaction(context, message, message_size); + + break; + case MessageType::USERLIST: // 18 +// return MessageType::private_process_userlist(context, message, message_size); + + break; + case MessageType::PERMISSIONQUERY: // 20 +// return MessageType::private_process_permission_query(context, message, message_size); + + break; + case MessageType::CODECVERSION: // 21 +// return MessageType::private_process_codecversion(context, message, message_size); + + break; + case MessageType::USERSTATS: // 22 +// return MessageType::private_process_userstats(context, message, message_size); + + break; + case MessageType::REQUESTBLOB: // 23 +// return MessageType::private_process_requestblob(context, message, message_size); + + break; + case MessageType::SERVERCONFIG: // 24 +// return MessageType::private_process_serverconfig(context, message, message_size); + + break; + case MessageType::SUGGESTCONFIG: // 25 +// return MessageType::private_process_suggestconfig(context, message, message_size); + break; + default: + throw MumlibException("unknown message type: " + to_string(static_cast(messageType))); + } + return true; + } + + bool processAudioPacket(AudioPacketType type, uint8_t *buffer, int length) { + logger->info("Got %d B of encoded audio data.", length); + int16_t pcmData[5000]; + audio->decodeAudioPacket(type, buffer, length, pcmData, 5000); + } + + }; + + + ConnectionState Mumlib::getConnectionState() { + return impl->transport->getConnectionState(); + } +} + +mumlib::Mumlib::Mumlib() : impl(new _Mumlib_Private) { + impl->logger = &(log4cpp::Category::getInstance("Mumlib.Mumlib")); + impl->externalIoService = false; + impl->ioService = new io_service(); + impl->audio = new Audio(); + impl->transport = new Transport( + *(impl->ioService), + boost::bind(&_Mumlib_Private::processIncomingTcpMessage, impl, _1, _2, _3), + boost::bind(&_Mumlib_Private::processAudioPacket, impl, _1, _2, _3) + ); +} + +mumlib::Mumlib::Mumlib(io_service &ioService) : impl(new _Mumlib_Private) { + //todo do this constructor + throw mumlib::MumlibException("not implented yet"); +} + +mumlib::Mumlib::~Mumlib() { + + if (not impl->externalIoService) { + delete impl->ioService; + } + + delete impl; +} + +void mumlib::Mumlib::setCallback(Callback &callback) { + impl->callback = &callback; +} + +void mumlib::Mumlib::connect(string host, int port, string user, string password) { + impl->transport->connect(host, port, user, password); +} + +void mumlib::Mumlib::disconnect() { + impl->transport->disconnect(); +} + +void mumlib::Mumlib::run() { + if (impl->externalIoService) { + throw MumlibException("can't call run() when using external io_service"); + } + + impl->ioService->run(); +} + +void mumlib::Mumlib::sendAudioData(int16_t *pcmData, int pcmLength) { + uint8_t encodedData[5000]; + int length = impl->audio->encodeAudioPacket(0, pcmData, pcmLength, encodedData, 5000); + impl->transport->sendEncodedAudioPacket(encodedData, length); +} \ No newline at end of file From a54a35265bce4241e3f95014924ff69cc5494fd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20S=C5=82omkowski?= Date: Sun, 25 Oct 2015 14:50:53 +0100 Subject: [PATCH 03/59] Update Mumble.proto to 1.2.10. --- CMakeLists.txt | 4 +- Mumble.proto | 544 ++++++++++++++++++++++++++++++++++++++++++++++ mumble.proto | 295 ------------------------- src/Transport.cpp | 4 +- src/mumlib.cpp | 2 +- 5 files changed, 548 insertions(+), 301 deletions(-) create mode 100644 Mumble.proto delete mode 100644 mumble.proto diff --git a/CMakeLists.txt b/CMakeLists.txt index c48446ceb089..e7a378c0bf02 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,8 +24,6 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR}) include_directories(${LOG4CPP_INCLUDE_DIRS}) include_directories(include) -file(GLOB ProtoFiles "mumble.proto") - set(MUMLIB_PUBLIC_HEADERS include/mumlib.hpp include/mumlib/VarInt.hpp) set(MUMLIB_PRIVATE_HEADERS @@ -45,7 +43,7 @@ set(MUMLIB_SRC src/Audio.cpp ) -PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS mumble.proto) +PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS Mumble.proto) add_library(mumlib SHARED ${MUMLIB_SRC} ${MUMLIB_PUBLIC_HEADERS} ${MUMLIB_PRIVATE_HEADERS} ${PROTO_SRCS} ${PROTO_HDRS}) target_link_libraries(mumlib ${PROTOBUF_LIBRARIES}) diff --git a/Mumble.proto b/Mumble.proto new file mode 100644 index 000000000000..92b873775f4c --- /dev/null +++ b/Mumble.proto @@ -0,0 +1,544 @@ +package MumbleProto; + +option optimize_for = SPEED; + +message Version { + // 2-byte Major, 1-byte Minor and 1-byte Patch version number. + optional uint32 version = 1; + // Client release name. + optional string release = 2; + // Client OS name. + optional string os = 3; + // Client OS version. + optional string os_version = 4; +} + +// Not used. Not even for tunneling UDP through TCP. +message UDPTunnel { + // Not used. + required bytes packet = 1; +} + +// Used by the client to send the authentication credentials to the server. +message Authenticate { + // UTF-8 encoded username. + optional string username = 1; + // Server or user password. + optional string password = 2; + // Additional access tokens for server ACL groups. + repeated string tokens = 3; + // A list of CELT bitstream version constants supported by the client. + repeated int32 celt_versions = 4; + optional bool opus = 5 [default = false]; +} + +// Sent by the client to notify the server that the client is still alive. +// Server must reply to the packet with the same timestamp and its own +// good/late/lost/resync numbers. None of the fields is strictly required. +message Ping { + // Client timestamp. Server should not attempt to decode. + optional uint64 timestamp = 1; + // The amount of good packets received. + optional uint32 good = 2; + // The amount of late packets received. + optional uint32 late = 3; + // The amount of packets never received. + optional uint32 lost = 4; + // The amount of nonce resyncs. + optional uint32 resync = 5; + // The total amount of UDP packets received. + optional uint32 udp_packets = 6; + // The total amount of TCP packets received. + optional uint32 tcp_packets = 7; + // UDP ping average. + optional float udp_ping_avg = 8; + // UDP ping variance. + optional float udp_ping_var = 9; + // TCP ping average. + optional float tcp_ping_avg = 10; + // TCP ping variance. + optional float tcp_ping_var = 11; +} + +// Sent by the server when it rejects the user connection. +message Reject { + enum RejectType { + // TODO ?? + None = 0; + // The client attempted to connect with an incompatible version. + WrongVersion = 1; + // The user name supplied by the client was invalid. + InvalidUsername = 2; + // The client attempted to authenticate as a user with a password but it + // was wrong. + WrongUserPW = 3; + // The client attempted to connect to a passworded server but the password + // was wrong. + WrongServerPW = 4; + // Supplied username is already in use. + UsernameInUse = 5; + // Server is currently full and cannot accept more users. + ServerFull = 6; + // The user did not provide a certificate but one is required. + NoCertificate = 7; + AuthenticatorFail = 8; + } + // Rejection type. + optional RejectType type = 1; + // Human readable rejection reason. + optional string reason = 2; +} + +// ServerSync message is sent by the server when it has authenticated the user +// and finished synchronizing the server state. +message ServerSync { + // The session of the current user. + optional uint32 session = 1; + // Maximum bandwidth that the user should use. + optional uint32 max_bandwidth = 2; + // Server welcome text. + optional string welcome_text = 3; + // Current user permissions TODO: Confirm?? + optional uint64 permissions = 4; +} + +// Sent by the client when it wants a channel removed. Sent by the server when +// a channel has been removed and clients should be notified. +message ChannelRemove { + required uint32 channel_id = 1; +} + +// Used to communicate channel properties between the client and the server. +// Sent by the server during the login process or when channel properties are +// updated. Client may use this message to update said channel properties. +message ChannelState { + // Unique ID for the channel within the server. + optional uint32 channel_id = 1; + // channel_id of the parent channel. + optional uint32 parent = 2; + // UTF-8 encoded channel name. + optional string name = 3; + // A collection of channel id values of the linked channels. Absent during + // the first channel listing. + repeated uint32 links = 4; + // UTF-8 encoded channel description. Only if the description is less than + // 128 bytes + optional string description = 5; + // A collection of channel_id values that should be added to links. + repeated uint32 links_add = 6; + // A collection of channel_id values that should be removed from links. + repeated uint32 links_remove = 7; + // True if the channel is temporary. + optional bool temporary = 8 [default = false]; + // Position weight to tweak the channel position in the channel list. + optional int32 position = 9 [default = 0]; + // SHA1 hash of the description if the description is 128 bytes or more. + optional bytes description_hash = 10; +} + +// Used to communicate user leaving or being kicked. May be sent by the client +// when it attempts to kick a user. Sent by the server when it informs the +// clients that a user is not present anymore. +message UserRemove { + // The user who is being kicked, identified by their session, not present + // when no one is being kicked. + required uint32 session = 1; + // The user who initiated the removal. Either the user who performs the kick + // or the user who is currently leaving. + optional uint32 actor = 2; + // Reason for the kick, stored as the ban reason if the user is banned. + optional string reason = 3; + // True if the kick should result in a ban. + optional bool ban = 4; +} + +// Sent by the server when it communicates new and changed users to client. +// First seen during login procedure. May be sent by the client when it wishes +// to alter its state. +message UserState { + // Unique user session ID of the user whose state this is, may change on + // reconnect. + optional uint32 session = 1; + // The session of the user who is updating this user. + optional uint32 actor = 2; + // User name, UTF-8 encoded. + optional string name = 3; + // Registered user ID if the user is registered. + optional uint32 user_id = 4; + // Channel on which the user is. + optional uint32 channel_id = 5; + // True if the user is muted by admin. + optional bool mute = 6; + // True if the user is deafened by admin. + optional bool deaf = 7; + // True if the user has been suppressed from talking by a reason other than + // being muted. + optional bool suppress = 8; + // True if the user has muted self. + optional bool self_mute = 9; + // True if the user has deafened self. + optional bool self_deaf = 10; + // User image if it is less than 128 bytes. + optional bytes texture = 11; + // TODO ?? + optional bytes plugin_context = 12; + // TODO ?? + optional string plugin_identity = 13; + // User comment if it is less than 128 bytes. + optional string comment = 14; + // The hash of the user certificate. + optional string hash = 15; + // SHA1 hash of the user comment if it 128 bytes or more. + optional bytes comment_hash = 16; + // SHA1 hash of the user picture if it 128 bytes or more. + optional bytes texture_hash = 17; + // True if the user is a priority speaker. + optional bool priority_speaker = 18; + // True if the user is currently recording. + optional bool recording = 19; +} + +// Relays information on the bans. The client may send the BanList message to +// either modify the list of bans or query them from the server. The server +// sends this list only after a client queries for it. +message BanList { + message BanEntry { + // Banned IP address. + required bytes address = 1; + // The length of the subnet mask for the ban. + required uint32 mask = 2; + // User name for identification purposes (does not affect the ban). + optional string name = 3; + // TODO ?? + optional string hash = 4; + // Reason for the ban (does not affect the ban). + optional string reason = 5; + // Ban start time. + optional string start = 6; + // Ban duration in seconds. + optional uint32 duration = 7; + } + // List of ban entries currently in place. + repeated BanEntry bans = 1; + // True if the server should return the list, false if it should replace old + // ban list with the one provided. + optional bool query = 2 [default = false]; +} + +// Used to send and broadcast text messages. +message TextMessage { + // The message sender, identified by its session. + optional uint32 actor = 1; + // Target users for the message, identified by their session. + repeated uint32 session = 2; + // The channels to which the message is sent, identified by their + // channel_ids. + repeated uint32 channel_id = 3; + // The root channels when sending message recursively to several channels, + // identified by their channel_ids. + repeated uint32 tree_id = 4; + // The UTF-8 encoded message. May be HTML if the server allows. + required string message = 5; +} + +message PermissionDenied { + enum DenyType { + // Operation denied for other reason, see reason field. + Text = 0; + // Permissions were denied. + Permission = 1; + // Cannot modify SuperUser. + SuperUser = 2; + // Invalid channel name. + ChannelName = 3; + // Text message too long. + TextTooLong = 4; + // The flux capacitor was spelled wrong. + H9K = 5; + // Operation not permitted in temporary channel. + TemporaryChannel = 6; + // Operation requires certificate. + MissingCertificate = 7; + // Invalid username. + UserName = 8; + // Channel is full. + ChannelFull = 9; + NestingLimit = 10; + } + // The denied permission when type is Permission. + optional uint32 permission = 1; + // channel_id for the channel where the permission was denied when type is + // Permission. + optional uint32 channel_id = 2; + // The user who was denied permissions, identified by session. + optional uint32 session = 3; + // Textual reason for the denial. + optional string reason = 4; + // Type of the denial. + optional DenyType type = 5; + // The name that is invalid when type is UserName. + optional string name = 6; +} + +message ACL { + message ChanGroup { + // Name of the channel group, UTF-8 encoded. + required string name = 1; + // True if the group has been inherited from the parent (Read only). + optional bool inherited = 2 [default = true]; + // True if the group members are inherited. + optional bool inherit = 3 [default = true]; + // True if the group can be inherited by sub channels. + optional bool inheritable = 4 [default = true]; + // Users explicitly included in this group, identified by user_id. + repeated uint32 add = 5; + // Users explicitly removed from this group in this channel if the group + // has been inherited, identified by user_id. + repeated uint32 remove = 6; + // Users inherited, identified by user_id. + repeated uint32 inherited_members = 7; + } + message ChanACL { + // True if this ACL applies to the current channel. + optional bool apply_here = 1 [default = true]; + // True if this ACL applies to the sub channels. + optional bool apply_subs = 2 [default = true]; + // True if the ACL has been inherited from the parent. + optional bool inherited = 3 [default = true]; + // ID of the user that is affected by this ACL. + optional uint32 user_id = 4; + // ID of the group that is affected by this ACL. + optional string group = 5; + // Bit flag field of the permissions granted by this ACL. + optional uint32 grant = 6; + // Bit flag field of the permissions denied by this ACL. + optional uint32 deny = 7; + } + // Channel ID of the channel this message affects. + required uint32 channel_id = 1; + // True if the channel inherits its parent's ACLs. + optional bool inherit_acls = 2 [default = true]; + // User group specifications. + repeated ChanGroup groups = 3; + // ACL specifications. + repeated ChanACL acls = 4; + // True if the message is a query for ACLs instead of setting them. + optional bool query = 5 [default = false]; +} + +// Client may use this message to refresh its registered user information. The +// client should fill the IDs or Names of the users it wants to refresh. The +// server fills the missing parts and sends the message back. +message QueryUsers { + // user_ids. + repeated uint32 ids = 1; + // User names in the same order as ids. + repeated string names = 2; +} + +// Used to initialize and resync the UDP encryption. Either side may request a +// resync by sending the message without any values filled. The resync is +// performed by sending the message with only the client or server nonce +// filled. +message CryptSetup { + // Encryption key. + optional bytes key = 1; + // Client nonce. + optional bytes client_nonce = 2; + // Server nonce. + optional bytes server_nonce = 3; +} + +message ContextActionModify { + enum Context { + // Action is applicable to the server. + Server = 0x01; + // Action can target a Channel. + Channel = 0x02; + // Action can target a User. + User = 0x04; + } + enum Operation { + Add = 0; + Remove = 1; + } + // The action name. + required string action = 1; + // The display name of the action. + optional string text = 2; + // Context bit flags defining where the action should be displayed. + optional uint32 context = 3; + optional Operation operation = 4; +} + +// Sent by the client when it wants to initiate a Context action. +message ContextAction { + // The target User for the action, identified by session. + optional uint32 session = 1; + // The target Channel for the action, identified by channel_id. + optional uint32 channel_id = 2; + // The action that should be executed. + required string action = 3; +} + +// Lists the registered users. +message UserList { + message User { + // Registered user ID. + required uint32 user_id = 1; + // Registered user name. + optional string name = 2; + optional string last_seen = 3; + optional uint32 last_channel = 4; + } + // A list of registered users. + repeated User users = 1; +} + +// Sent by the client when it wants to register or clear whisper targets. +// +// Note: The first available target ID is 1 as 0 is reserved for normal +// talking. Maximum target ID is 30. +message VoiceTarget { + message Target { + // Users that are included as targets. + repeated uint32 session = 1; + // Channels that are included as targets. + optional uint32 channel_id = 2; + // TODO ?? + optional string group = 3; + // True if the voice should follow links from the specified channel. + optional bool links = 4 [default = false]; + // True if the voice should also be sent to children of the specific + // channel. + optional bool children = 5 [default = false]; + } + // Voice target ID. + optional uint32 id = 1; + // The receivers that this voice target includes. + repeated Target targets = 2; +} + +// Sent by the client when it wants permissions for a certain channel. Sent by +// the server when it replies to the query or wants the user to resync all +// channel permissions. +message PermissionQuery { + // channel_id of the channel for which the permissions are queried. + optional uint32 channel_id = 1; + // Channel permissions. + optional uint32 permissions = 2; + // True if the client should drop its current permission information for all + // channels. + optional bool flush = 3 [default = false]; +} + +// Sent by the server to notify the users of the version of the CELT codec they +// should use. This may change during the connection when new users join. +message CodecVersion { + // The version of the CELT Alpha codec. + required int32 alpha = 1; + // The version of the CELT Beta codec. + required int32 beta = 2; + // True if the user should prefer Alpha over Beta. + required bool prefer_alpha = 3 [default = true]; + optional bool opus = 4 [default = false]; +} + +// Used to communicate user stats between the server and clients. +message UserStats { + message Stats { + // The amount of good packets received. + optional uint32 good = 1; + // The amount of late packets received. + optional uint32 late = 2; + // The amount of packets never received. + optional uint32 lost = 3; + // The amount of nonce resyncs. + optional uint32 resync = 4; + } + + // User whose stats these are. + optional uint32 session = 1; + // True if the message contains only mutable stats (packets, ping). + optional bool stats_only = 2 [default = false]; + // Full user certificate chain of the user certificate in DER format. + repeated bytes certificates = 3; + // Packet statistics for packets received from the client. + optional Stats from_client = 4; + // Packet statistics for packets sent by the server. + optional Stats from_server = 5; + + // Amount of UDP packets sent. + optional uint32 udp_packets = 6; + // Amount of TCP packets sent. + optional uint32 tcp_packets = 7; + // UDP ping average. + optional float udp_ping_avg = 8; + // UDP ping variance. + optional float udp_ping_var = 9; + // TCP ping average. + optional float tcp_ping_avg = 10; + // TCP ping variance. + optional float tcp_ping_var = 11; + + // Client version. + optional Version version = 12; + // A list of CELT bitstream version constants supported by the client of this + // user. + repeated int32 celt_versions = 13; + // Client IP address. + optional bytes address = 14; + // Bandwith used by this client. + optional uint32 bandwidth = 15; + // Connection duration. + optional uint32 onlinesecs = 16; + // Duration since last activity. + optional uint32 idlesecs = 17; + // True if the user has a strong certificate. + optional bool strong_certificate = 18 [default = false]; + optional bool opus = 19 [default = false]; +} + +// Used by the client to request binary data from the server. By default large +// comments or textures are not sent within standard messages but instead the +// hash is. If the client does not recognize the hash it may request the +// resource when it needs it. The client does so by sending a RequestBlob +// message with the correct fields filled with the user sessions or channel_ids +// it wants to receive. The server replies to this by sending a new +// UserState/ChannelState message with the resources filled even if they would +// normally be transmitted as hashes. +message RequestBlob { + // sessions of the requested UserState textures. + repeated uint32 session_texture = 1; + // sessions of the requested UserState comments. + repeated uint32 session_comment = 2; + // channel_ids of the requested ChannelState descriptions. + repeated uint32 channel_description = 3; +} + +// Sent by the server when it informs the clients on server configuration +// details. +message ServerConfig { + // The maximum bandwidth the clients should use. + optional uint32 max_bandwidth = 1; + // Server welcome text. + optional string welcome_text = 2; + // True if the server allows HTML. + optional bool allow_html = 3; + // Maximum text message length. + optional uint32 message_length = 4; + // Maximum image message length. + optional uint32 image_message_length = 5; +} + +// Sent by the server to inform the clients of suggested client configuration +// specified by the server administrator. +message SuggestConfig { + // Suggested client version. + optional uint32 version = 1; + // True if the administrator suggests positional audio to be used on this + // server. + optional bool positional = 2; + // True if the administrator suggests push to talk to be used on this server. + optional bool push_to_talk = 3; +} diff --git a/mumble.proto b/mumble.proto deleted file mode 100644 index ad4f90e723ab..000000000000 --- a/mumble.proto +++ /dev/null @@ -1,295 +0,0 @@ -package MumbleProto; - -option optimize_for = SPEED; - -message Version { - optional uint32 version = 1; - optional string release = 2; - optional string os = 3; - optional string os_version = 4; -} - -message UDPTunnel { - required bytes packet = 1; -} - -message Authenticate { - optional string username = 1; - optional string password = 2; - repeated string tokens = 3; - repeated int32 celt_versions = 4; - optional bool opus = 5 [default = false]; -} - -message Ping { - optional uint64 timestamp = 1; - optional uint32 good = 2; - optional uint32 late = 3; - optional uint32 lost = 4; - optional uint32 resync = 5; - optional uint32 udp_packets = 6; - optional uint32 tcp_packets = 7; - optional float udp_ping_avg = 8; - optional float udp_ping_var = 9; - optional float tcp_ping_avg = 10; - optional float tcp_ping_var = 11; -} - -message Reject { - enum RejectType { - None = 0; - WrongVersion = 1; - InvalidUsername = 2; - WrongUserPW = 3; - WrongServerPW = 4; - UsernameInUse = 5; - ServerFull = 6; - NoCertificate = 7; - AuthenticatorFail = 8; - } - optional RejectType type = 1; - optional string reason = 2; -} - -message ServerSync { - optional uint32 session = 1; - optional uint32 max_bandwidth = 2; - optional string welcome_text = 3; - optional uint64 permissions = 4; -} - -message ChannelRemove { - required uint32 channel_id = 1; -} - -message ChannelState { - optional uint32 channel_id = 1; - optional uint32 parent = 2; - optional string name = 3; - repeated uint32 links = 4; - optional string description = 5; - repeated uint32 links_add = 6; - repeated uint32 links_remove = 7; - optional bool temporary = 8 [default = false]; - optional int32 position = 9 [default = 0]; - optional bytes description_hash = 10; -} - -message UserRemove { - required uint32 session = 1; - optional uint32 actor = 2; - optional string reason = 3; - optional bool ban = 4; -} - -message UserState { - optional uint32 session = 1; - optional uint32 actor = 2; - optional string name = 3; - optional uint32 user_id = 4; - optional uint32 channel_id = 5; - optional bool mute = 6; - optional bool deaf = 7; - optional bool suppress = 8; - optional bool self_mute = 9; - optional bool self_deaf = 10; - optional bytes texture = 11; - optional bytes plugin_context = 12; - optional string plugin_identity = 13; - optional string comment = 14; - optional string hash = 15; - optional bytes comment_hash = 16; - optional bytes texture_hash = 17; - optional bool priority_speaker = 18; - optional bool recording = 19; -} - -message BanList { - message BanEntry { - required bytes address = 1; - required uint32 mask = 2; - optional string name = 3; - optional string hash = 4; - optional string reason = 5; - optional string start = 6; - optional uint32 duration = 7; - } - repeated BanEntry bans = 1; - optional bool query = 2 [default = false]; -} - -message TextMessage { - optional uint32 actor = 1; - repeated uint32 session = 2; - repeated uint32 channel_id = 3; - repeated uint32 tree_id = 4; - required string message = 5; -} - -message PermissionDenied { - enum DenyType { - Text = 0; - Permission = 1; - SuperUser = 2; - ChannelName = 3; - TextTooLong = 4; - H9K = 5; - TemporaryChannel = 6; - MissingCertificate = 7; - UserName = 8; - ChannelFull = 9; - NestingLimit = 10; - } - optional uint32 permission = 1; - optional uint32 channel_id = 2; - optional uint32 session = 3; - optional string reason = 4; - optional DenyType type = 5; - optional string name = 6; -} - -message ACL { - message ChanGroup { - required string name = 1; - optional bool inherited = 2 [default = true]; - optional bool inherit = 3 [default = true]; - optional bool inheritable = 4 [default = true]; - repeated uint32 add = 5; - repeated uint32 remove = 6; - repeated uint32 inherited_members = 7; - } - message ChanACL { - optional bool apply_here = 1 [default = true]; - optional bool apply_subs = 2 [default = true]; - optional bool inherited = 3 [default = true]; - optional uint32 user_id = 4; - optional string group = 5; - optional uint32 grant = 6; - optional uint32 deny = 7; - } - required uint32 channel_id = 1; - optional bool inherit_acls = 2 [default = true]; - repeated ChanGroup groups = 3; - repeated ChanACL acls = 4; - optional bool query = 5 [default = false]; -} - -message QueryUsers { - repeated uint32 ids = 1; - repeated string names = 2; -} - -message CryptSetup { - optional bytes key = 1; - optional bytes client_nonce = 2; - optional bytes server_nonce = 3; -} - -message ContextActionModify { - enum Context { - Server = 0x01; - Channel = 0x02; - User = 0x04; - } - enum Operation { - Add = 0; - Remove = 1; - } - required string action = 1; - optional string text = 2; - optional uint32 context = 3; - optional Operation operation = 4; -} - -message ContextAction { - optional uint32 session = 1; - optional uint32 channel_id = 2; - required string action = 3; -} - -message UserList { - message User { - required uint32 user_id = 1; - optional string name = 2; - optional string last_seen = 3; - optional uint32 last_channel = 4; - } - repeated User users = 1; -} - -message VoiceTarget { - message Target { - repeated uint32 session = 1; - optional uint32 channel_id = 2; - optional string group = 3; - optional bool links = 4 [default = false]; - optional bool children = 5 [default = false]; - } - optional uint32 id = 1; - repeated Target targets = 2; -} - -message PermissionQuery { - optional uint32 channel_id = 1; - optional uint32 permissions = 2; - optional bool flush = 3 [default = false]; -} - -message CodecVersion { - required int32 alpha = 1; - required int32 beta = 2; - required bool prefer_alpha = 3 [default = true]; - optional bool opus = 4 [default = false]; -} - -message UserStats { - message Stats { - optional uint32 good = 1; - optional uint32 late = 2; - optional uint32 lost = 3; - optional uint32 resync = 4; - } - - optional uint32 session = 1; - optional bool stats_only = 2 [default = false]; - repeated bytes certificates = 3; - optional Stats from_client = 4; - optional Stats from_server = 5; - - optional uint32 udp_packets = 6; - optional uint32 tcp_packets = 7; - optional float udp_ping_avg = 8; - optional float udp_ping_var = 9; - optional float tcp_ping_avg = 10; - optional float tcp_ping_var = 11; - - optional Version version = 12; - repeated int32 celt_versions = 13; - optional bytes address = 14; - optional uint32 bandwidth = 15; - optional uint32 onlinesecs = 16; - optional uint32 idlesecs = 17; - optional bool strong_certificate = 18 [default = false]; - optional bool opus = 19 [default = false]; -} - -message RequestBlob { - repeated uint32 session_texture = 1; - repeated uint32 session_comment = 2; - repeated uint32 channel_description = 3; -} - -message ServerConfig { - optional uint32 max_bandwidth = 1; - optional string welcome_text = 2; - optional bool allow_html = 3; - optional uint32 message_length = 4; - optional uint32 image_message_length = 5; -} - -message SuggestConfig { - optional uint32 version = 1; - optional bool positional = 2; - optional bool push_to_talk = 3; -} - diff --git a/src/Transport.cpp b/src/Transport.cpp index db23927fdbd3..fd8846154580 100644 --- a/src/Transport.cpp +++ b/src/Transport.cpp @@ -1,6 +1,6 @@ #include "mumlib/Transport.hpp" -#include "mumble.pb.h" +#include "Mumble.pb.h" #include @@ -8,7 +8,7 @@ using namespace std; static boost::posix_time::seconds PING_INTERVAL(5); -const long CLIENT_VERSION = 0x010203; +const long CLIENT_VERSION = 0x01020A; const string CLIENT_RELEASE("Mumlib"); const string CLIENT_OS("OS Unknown"); const string CLIENT_OS_VERSION("1"); diff --git a/src/mumlib.cpp b/src/mumlib.cpp index 57ae2cf570ea..88faa1a31299 100644 --- a/src/mumlib.cpp +++ b/src/mumlib.cpp @@ -10,7 +10,7 @@ #include #include -#include +#include using namespace std; using namespace boost::asio; From 58fee46c139b7a10520013442b7523a16b5818d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20S=C5=82omkowski?= Date: Tue, 27 Oct 2015 21:51:28 +0100 Subject: [PATCH 04/59] Complete callbacks. --- include/mumlib/Audio.hpp | 2 + include/mumlib/Callback.hpp | 134 ++++++++-------------- mumlib_example.cpp | 2 +- src/Audio.cpp | 2 +- src/Callback.cpp | 223 ++++++++++++++---------------------- src/Transport.cpp | 10 +- src/mumlib.cpp | 178 +++++++++++++++++++++------- 7 files changed, 272 insertions(+), 279 deletions(-) diff --git a/include/mumlib/Audio.hpp b/include/mumlib/Audio.hpp index a71d73ff9cf3..2010fdc14ade 100644 --- a/include/mumlib/Audio.hpp +++ b/include/mumlib/Audio.hpp @@ -8,6 +8,8 @@ namespace mumlib { constexpr int SAMPLE_RATE = 48000; + class MumlibException; + class AudioException : public MumlibException { public: AudioException(string message) : MumlibException(message) { } diff --git a/include/mumlib/Callback.hpp b/include/mumlib/Callback.hpp index 896f5b12f4cf..ebb712e85e50 100644 --- a/include/mumlib/Callback.hpp +++ b/include/mumlib/Callback.hpp @@ -10,7 +10,7 @@ namespace mumlib { class Callback { public: - virtual void version_callback( + virtual void version( uint16_t major, uint8_t minor, uint8_t patch, @@ -18,23 +18,23 @@ namespace mumlib { string os, string os_version) { }; - virtual void audio_callback( - uint8_t *pcm_data, + virtual void audio( + int16_t *pcm_data, uint32_t pcm_data_size) { }; - virtual void unsupported_audio_callback( + virtual void unsupportedAudio( uint8_t *encoded_audio_data, uint32_t encoded_audio_data_size) { }; - virtual void serversync_callback( + virtual void serverSync( string welcome_text, int32_t session, int32_t max_bandwidth, int64_t permissions) { }; - virtual void channelremove_callback(uint32_t channel_id) { }; + virtual void channelRemove(uint32_t channel_id) { }; - virtual void channelstate_callback( + virtual void channelState( string name, int32_t channel_id, int32_t parent, @@ -45,13 +45,13 @@ namespace mumlib { bool temporary, int32_t position) { }; - virtual void userremove_callback( + virtual void userRemove( uint32_t session, int32_t actor, string reason, bool ban) { }; - virtual void userstate_callback( + virtual void userState( int32_t session, int32_t actor, string name, @@ -66,8 +66,8 @@ namespace mumlib { int32_t priority_speaker, int32_t recording) { }; - virtual void banlist_callback( - uint8_t *ip_data, + virtual void banList( + const uint8_t *ip_data, uint32_t ip_data_size, uint32_t mask, string name, @@ -76,17 +76,14 @@ namespace mumlib { string start, int32_t duration) { }; - virtual void textmessage_callback( + virtual void textMessage( uint32_t actor, - uint32_t n_session, - uint32_t *session, - uint32_t n_channel_id, - uint32_t *channel_id, - uint32_t n_tree_id, - uint32_t *tree_id, + std::vector session, + std::vector channel_id, + std::vector tree_id, string message) { }; - virtual void permissiondenied_callback( + virtual void permissionDenied( int32_t permission, int32_t channel_id, int32_t session, @@ -94,64 +91,48 @@ namespace mumlib { int32_t deny_type, string name) { }; - virtual void acl_callback() { }; - - virtual void queryusers_callback( + virtual void queryUsers( uint32_t n_ids, uint32_t *ids, uint32_t n_names, string *names) { }; - virtual void cryptsetup_callback( - uint32_t key_size, - uint8_t *key, - uint32_t client_nonce_size, - uint8_t *client_nonce, - uint32_t server_nonce_size, - uint8_t *server_nonce) { }; - - virtual void contextactionmodify_callback( + virtual void contextActionModify( string action, string text, uint32_t m_context, uint32_t operation) { }; - virtual void contextaction_callback( + virtual void contextAction( int32_t session, int32_t channel_id, string action) { }; - virtual void userlist_callback( + virtual void userList( uint32_t user_id, string name, string last_seen, int32_t last_channel) { }; - virtual void voicetarget_callback() { }; - - virtual void permissionquery_callback( + virtual void permissionQuery( int32_t channel_id, uint32_t permissions, int32_t flush) { }; - virtual void codecversion_callback( + virtual void codecVersion( int32_t alpha, int32_t beta, uint32_t prefer_alpha, int32_t opus) { }; - virtual void userstats_callback() { }; - - virtual void requestblob_callback() { }; - - virtual void serverconfig_callback( + virtual void serverConfig( uint32_t max_bandwidth, string welcome_text, uint32_t allow_html, uint32_t message_length, uint32_t image_message_length) { }; - virtual void suggestconfig_callback( + virtual void suggestConfig( uint32_t version, uint32_t positional, uint32_t push_to_talk) { }; @@ -166,7 +147,7 @@ namespace mumlib { ~BasicCallback(); - virtual void version_callback( + virtual void version( uint16_t major, uint8_t minor, uint8_t patch, @@ -174,23 +155,23 @@ namespace mumlib { string os, string os_version); - virtual void audio_callback( - uint8_t *pcm_data, + virtual void audio( + int16_t *pcm_data, uint32_t pcm_data_size); - virtual void unsupported_audio_callback( + virtual void unsupportedAudio( uint8_t *encoded_audio_data, uint32_t encoded_audio_data_size); - virtual void serversync_callback( + virtual void serverSync( string welcome_text, int32_t session, int32_t max_bandwidth, int64_t permissions); - virtual void channelremove_callback(uint32_t channel_id); + virtual void channelRemove(uint32_t channel_id); - virtual void channelstate_callback( + virtual void channelState( string name, int32_t channel_id, int32_t parent, @@ -201,13 +182,13 @@ namespace mumlib { bool temporary, int32_t position); - virtual void userremove_callback( + virtual void userRemove( uint32_t session, int32_t actor, string reason, bool ban); - virtual void userstate_callback( + virtual void userState( int32_t session, int32_t actor, string name, @@ -222,8 +203,8 @@ namespace mumlib { int32_t priority_speaker, int32_t recording); - virtual void banlist_callback( - uint8_t *ip_data, + virtual void banList( + const uint8_t *ip_data, uint32_t ip_data_size, uint32_t mask, string name, @@ -232,17 +213,14 @@ namespace mumlib { string start, int32_t duration); - virtual void textmessage_callback( + virtual void textMessage( uint32_t actor, - uint32_t n_session, - uint32_t *session, - uint32_t n_channel_id, - uint32_t *channel_id, - uint32_t n_tree_id, - uint32_t *tree_id, + std::vector session, + std::vector channel_id, + std::vector tree_id, string message); - virtual void permissiondenied_callback( + virtual void permissionDenied( int32_t permission, int32_t channel_id, int32_t session, @@ -250,64 +228,48 @@ namespace mumlib { int32_t deny_type, string name); - virtual void acl_callback(); - - virtual void queryusers_callback( + virtual void queryUsers( uint32_t n_ids, uint32_t *ids, uint32_t n_names, string *names); - virtual void cryptsetup_callback( - uint32_t key_size, - uint8_t *key, - uint32_t client_nonce_size, - uint8_t *client_nonce, - uint32_t server_nonce_size, - uint8_t *server_nonce); - - virtual void contextactionmodify_callback( + virtual void contextActionModify( string action, string text, uint32_t m_context, uint32_t operation); - virtual void contextaction_callback( + virtual void contextAction( int32_t session, int32_t channel_id, string action); - virtual void userlist_callback( + virtual void userList( uint32_t user_id, string name, string last_seen, int32_t last_channel); - virtual void voicetarget_callback(); - - virtual void permissionquery_callback( + virtual void permissionQuery( int32_t channel_id, uint32_t permissions, int32_t flush); - virtual void codecversion_callback( + virtual void codecVersion( int32_t alpha, int32_t beta, uint32_t prefer_alpha, int32_t opus); - virtual void userstats_callback(); - - virtual void requestblob_callback(); - - virtual void serverconfig_callback( + virtual void serverConfig( uint32_t max_bandwidth, string welcome_text, uint32_t allow_html, uint32_t message_length, uint32_t image_message_length); - virtual void suggestconfig_callback( + virtual void suggestConfig( uint32_t version, uint32_t positional, uint32_t push_to_talk); diff --git a/mumlib_example.cpp b/mumlib_example.cpp index 86c162fbaa54..b41b8bbd6e32 100644 --- a/mumlib_example.cpp +++ b/mumlib_example.cpp @@ -31,7 +31,7 @@ int main(int argc, char *argv[]) { log4cpp::Appender *appender1 = new log4cpp::OstreamAppender("console", &std::cout); appender1->setLayout(new log4cpp::BasicLayout()); log4cpp::Category &logger = log4cpp::Category::getRoot(); - logger.setPriority(log4cpp::Priority::WARN); + logger.setPriority(log4cpp::Priority::DEBUG); logger.addAppender(appender1); if (argc < 3) { diff --git a/src/Audio.cpp b/src/Audio.cpp index 7b54f9a1b449..6052f06a06fb 100644 --- a/src/Audio.cpp +++ b/src/Audio.cpp @@ -4,7 +4,7 @@ mumlib::Audio::Audio() : - logger(log4cpp::Category::getInstance("Mumlib.Audio")), + logger(log4cpp::Category::getInstance("mumlib.Audio")), opusDecoder(nullptr), opusEncoder(nullptr), outgoingSequenceNumber(1) { diff --git a/src/Callback.cpp b/src/Callback.cpp index b330231826c1..f98f7ded00bc 100644 --- a/src/Callback.cpp +++ b/src/Callback.cpp @@ -9,10 +9,11 @@ using namespace mumlib; namespace mumlib { struct _BasicCallback_Private : boost::noncopyable { public: - _BasicCallback_Private() : logger(log4cpp::Category::getInstance("BasicCallback")) { } + _BasicCallback_Private() : logger(log4cpp::Category::getInstance("mumlib.BasicCallback")) { } log4cpp::Category &logger; }; + } mumlib::BasicCallback::BasicCallback() { @@ -23,160 +24,102 @@ mumlib::BasicCallback::~BasicCallback() { delete impl; } -void mumlib::BasicCallback::version_callback( +void mumlib::BasicCallback::version( uint16_t major, uint8_t minor, uint8_t patch, string release, string os, string os_version) { - impl->logger.debug("Version Callback: v%d.%d.%d. %s/%s/%s\n", major, minor, patch, release.c_str(), os.c_str(), + impl->logger.debug("version: v%d.%d.%d. %s/%s/%s\n", major, minor, patch, release.c_str(), os.c_str(), os_version.c_str()); } -void mumlib::BasicCallback::audio_callback( - uint8_t *pcm_data, +void mumlib::BasicCallback::audio( + int16_t *pcmData, uint32_t pcm_data_size) { - impl->logger.debug("Received %d bytes of raw PCM data.", pcm_data_size); + impl->logger.debug("audio: %d bytes of raw PCM data.", pcm_data_size); } -void mumlib::BasicCallback::unsupported_audio_callback( - uint8_t *encoded_audio_data, - uint32_t encoded_audio_data_size) { - impl->logger.debug("Received %d bytes of encoded audio data.", encoded_audio_data_size); +void BasicCallback::unsupportedAudio(uint8_t *encoded_audio_data, uint32_t encoded_audio_data_size) { + impl->logger.debug("unsupportedAudio: received %d bytes of encoded data.", encoded_audio_data_size); } -void mumlib::BasicCallback::serversync_callback( - string welcome_text, - int32_t session, - int32_t max_bandwidth, - int64_t permissions) { - impl->logger.debug("Text: %s, session: %d, max bandwidth: %d, permissions: %d", welcome_text.c_str(), session, +void BasicCallback::serverSync(string welcome_text, int32_t session, int32_t max_bandwidth, int64_t permissions) { + impl->logger.debug("serverSync: text: %s, session: %d, max bandwidth: %d, permissions: %d", welcome_text.c_str(), + session, max_bandwidth, permissions); } -void mumlib::BasicCallback::channelremove_callback(uint32_t channel_id) { } - -void mumlib::BasicCallback::channelstate_callback( - string name, - int32_t channel_id, - int32_t parent, - string description, - vector links, - vector inks_add, - vector links_remove, - bool temporary, - int32_t position) { - impl->logger.debug("Obtained channel state %d: %s, %s", channel_id, name.c_str(), description.c_str()); -} - -void mumlib::BasicCallback::userremove_callback( - uint32_t session, - int32_t actor, - string reason, - bool ban) { } - -void mumlib::BasicCallback::userstate_callback( - int32_t session, - int32_t actor, - string name, - int32_t user_id, - int32_t channel_id, - int32_t mute, - int32_t deaf, - int32_t suppress, - int32_t self_mute, - int32_t self_deaf, - string comment, - int32_t priority_speaker, - int32_t recording) { } - -void mumlib::BasicCallback::banlist_callback( - uint8_t *ip_data, - uint32_t ip_data_size, - uint32_t mask, - string name, - string hash, - string reason, - string start, - int32_t duration) { } - -void mumlib::BasicCallback::textmessage_callback( +void BasicCallback::channelRemove(uint32_t channel_id) { + impl->logger.debug("channelRemove: %d", channel_id); +} + +void BasicCallback::channelState(string name, int32_t channel_id, int32_t parent, string description, + vector links, vector inks_add, vector links_remove, + bool temporary, int32_t position) { + impl->logger.debug("channelState: %d: %s, %s", channel_id, name.c_str(), description.c_str()); +} + +void BasicCallback::userRemove(uint32_t session, int32_t actor, string reason, bool ban) { + impl->logger.debug("userRemove: session: %d, actor: %d, reason: %s, ban: %d.", session, actor, reason.c_str(), ban); +} + +void BasicCallback::userState(int32_t session, int32_t actor, string name, int32_t user_id, int32_t channel_id, + int32_t mute, int32_t deaf, int32_t suppress, int32_t self_mute, int32_t self_deaf, + string comment, int32_t priority_speaker, int32_t recording) { + impl->logger.debug("userState: %s: mute: %d, deaf: %d, suppress: %d, self mute: %d, self deaf: %d", + name.c_str(), mute, deaf, suppress, self_mute, self_deaf); +} + +void BasicCallback::banList(const uint8_t *ip_data, uint32_t ip_data_size, uint32_t mask, string name, string hash, + string reason, string start, int32_t duration) { + impl->logger.debug("banList: %s, hash: %s, reason: %s", name.c_str(), hash.c_str(), reason.c_str()); +} + +void BasicCallback::textMessage( uint32_t actor, - uint32_t n_session, - uint32_t *session, - uint32_t n_channel_id, - uint32_t *channel_id, - uint32_t n_tree_id, - uint32_t *tree_id, - string message) { } - -void mumlib::BasicCallback::permissiondenied_callback( - int32_t permission, - int32_t channel_id, - int32_t session, - string reason, - int32_t deny_type, - string name) { } - -void mumlib::BasicCallback::acl_callback() { } - -void mumlib::BasicCallback::queryusers_callback( - uint32_t n_ids, - uint32_t *ids, - uint32_t n_names, - string *names) { } - -void mumlib::BasicCallback::cryptsetup_callback( - uint32_t key_size, - uint8_t *key, - uint32_t client_nonce_size, - uint8_t *client_nonce, - uint32_t server_nonce_size, - uint8_t *server_nonce) { } - -void mumlib::BasicCallback::contextactionmodify_callback( - string action, - string text, - uint32_t m_context, - uint32_t operation) { } - -void mumlib::BasicCallback::contextaction_callback( - int32_t session, - int32_t channel_id, - string action) { } - -void mumlib::BasicCallback::userlist_callback( - uint32_t user_id, - string name, - string last_seen, - int32_t last_channel) { } - -void mumlib::BasicCallback::voicetarget_callback() { } - -void mumlib::BasicCallback::permissionquery_callback( - int32_t channel_id, - uint32_t permissions, - int32_t flush) { } - -void mumlib::BasicCallback::codecversion_callback( - int32_t alpha, - int32_t beta, - uint32_t prefer_alpha, - int32_t opus) { } - -void mumlib::BasicCallback::userstats_callback() { } - -void mumlib::BasicCallback::requestblob_callback() { } - -void mumlib::BasicCallback::serverconfig_callback( - uint32_t max_bandwidth, - string welcome_text, - uint32_t allow_html, - uint32_t message_length, - uint32_t image_message_length) { } - -void mumlib::BasicCallback::suggestconfig_callback( - uint32_t version, - uint32_t positional, - uint32_t push_to_talk) { } + std::vector session, + std::vector channel_id, + std::vector tree_id, + string message) { + impl->logger.debug("textMessage: %d: %s", actor, message.c_str()); +} + +void BasicCallback::permissionDenied(int32_t permission, int32_t channel_id, int32_t session, string reason, + int32_t deny_type, string name) { + impl->logger.debug("permissionDenied: %s %s", name.c_str(), reason.c_str()); +} + +void BasicCallback::queryUsers(uint32_t n_ids, uint32_t *ids, uint32_t n_names, string *names) { + impl->logger.debug("queryUsers: %d users", n_names); //todo make it more high-level +} + +void BasicCallback::contextActionModify(string action, string text, uint32_t m_context, uint32_t operation) { + impl->logger.debug("contextActionModify: "); +} + +void BasicCallback::contextAction(int32_t session, int32_t channel_id, string action) { + impl->logger.debug("contextAction."); +} + +void BasicCallback::userList(uint32_t user_id, string name, string last_seen, int32_t last_channel) { + impl->logger.debug("userList."); +} + +void BasicCallback::permissionQuery(int32_t channel_id, uint32_t permissions, int32_t flush) { + impl->logger.debug("permissionQuery."); +} + +void BasicCallback::codecVersion(int32_t alpha, int32_t beta, uint32_t prefer_alpha, int32_t opus) { + impl->logger.debug("codecVersion."); +} + +void BasicCallback::serverConfig(uint32_t max_bandwidth, string welcome_text, uint32_t allow_html, + uint32_t message_length, uint32_t image_message_length) { + impl->logger.debug("serverConfig: %s", welcome_text.c_str()); +} + +void BasicCallback::suggestConfig(uint32_t version, uint32_t positional, uint32_t push_to_talk) { + impl->logger.debug("suggestConfig."); +} diff --git a/src/Transport.cpp b/src/Transport.cpp index fd8846154580..19094015af54 100644 --- a/src/Transport.cpp +++ b/src/Transport.cpp @@ -30,7 +30,7 @@ mumlib::Transport::Transport( mumlib::ProcessControlMessageFunction processMessageFunc, ProcessEncodedAudioPacketFunction processEncodedAudioPacketFunction, bool noUdp) : - logger(log4cpp::Category::getInstance("Mumlib.Transport")), + logger(log4cpp::Category::getInstance("mumlib.Transport")), ioService(ioService), processMessageFunction(processMessageFunc), processEncodedAudioPacketFunction(processEncodedAudioPacketFunction), @@ -154,7 +154,7 @@ void mumlib::Transport::doReceiveUdp() { if (udpActive == false) { udpActive = true; - logger.info("UDP is up."); + logger.notice("UDP is up."); } uint8_t plainBuffer[1024]; @@ -376,12 +376,6 @@ void mumlib::Transport::processMessageInternal(MessageType messageType, uint8_t } } break; - case MessageType::VOICETARGET: { - MumbleProto::VoiceTarget voiceTarget; - voiceTarget.ParseFromArray(buffer, length); - logger.warn("VoiceTarget Message: I don't think the server ever sends this structure...."); - } - break; default: { logger.debug("Calling external ProcessControlMessageFunction."); processMessageFunction(messageType, buffer, length); diff --git a/src/mumlib.cpp b/src/mumlib.cpp index 88faa1a31299..e91229409126 100644 --- a/src/mumlib.cpp +++ b/src/mumlib.cpp @@ -1,11 +1,11 @@ -#include "mumlib.hpp" - #include "mumlib/CryptState.hpp" #include "mumlib/VarInt.hpp" #include "mumlib/enums.hpp" #include "mumlib/Transport.hpp" #include "mumlib/Audio.hpp" +#include "mumlib.hpp" + #include #include #include @@ -35,7 +35,7 @@ namespace mumlib { case MessageType::VERSION: { MumbleProto::Version version; version.ParseFromArray(buffer, length); - callback->version_callback( + callback->version( version.version() >> 16, version.version() >> 8 & 0xff, version.version() & 0xff, @@ -47,7 +47,7 @@ namespace mumlib { case MessageType::SERVERSYNC: { MumbleProto::ServerSync serverSync; serverSync.ParseFromArray(buffer, length); - callback->serversync_callback( + callback->serverSync( serverSync.welcome_text(), serverSync.session(), serverSync.max_bandwidth(), @@ -58,7 +58,7 @@ namespace mumlib { case MessageType::CHANNELREMOVE: { MumbleProto::ChannelRemove channelRemove; channelRemove.ParseFromArray(buffer, length); - callback->channelremove_callback(channelRemove.channel_id()); + callback->channelRemove(channelRemove.channel_id()); } break; case MessageType::CHANNELSTATE: { @@ -83,7 +83,7 @@ namespace mumlib { std::copy(channelState.links_remove().begin(), channelState.links_remove().end(), links_remove.begin()); - callback->channelstate_callback( + callback->channelState( channelState.name(), channel_id, parent, @@ -104,7 +104,7 @@ namespace mumlib { bool ban = user_remove.has_ban() ? user_remove.ban() : false; //todo make sure it's correct to assume it's false - callback->userremove_callback( + callback->userRemove( user_remove.session(), actor, user_remove.reason(), @@ -112,64 +112,150 @@ namespace mumlib { ); } break; - case MessageType::USERSTATE: // 9 -// return MessageType::private_process_userstate(context, message, message_size); - + case MessageType::USERSTATE: { + MumbleProto::UserState userState; + userState.ParseFromArray(buffer, length); + + // There are far too many things in this structure. Culling to the ones that are probably important + int32_t session = userState.has_session() ? userState.session() : -1; + int32_t actor = userState.has_actor() ? userState.actor() : -1; + int32_t user_id = userState.has_user_id() ? userState.user_id() : -1; + int32_t channel_id = userState.has_channel_id() ? userState.channel_id() : -1; + int32_t mute = userState.has_mute() ? userState.mute() : -1; + int32_t deaf = userState.has_deaf() ? userState.deaf() : -1; + int32_t suppress = userState.has_suppress() ? userState.suppress() : -1; + int32_t self_mute = userState.has_self_mute() ? userState.self_mute() : -1; + int32_t self_deaf = userState.has_self_deaf() ? userState.self_deaf() : -1; + int32_t priority_speaker = userState.has_priority_speaker() ? userState.priority_speaker() : -1; + int32_t recording = userState.has_recording() ? userState.recording() : -1; + + callback->userState(session, + actor, + userState.name(), + user_id, + channel_id, + mute, + deaf, + suppress, + self_mute, + self_deaf, + userState.comment(), + priority_speaker, + recording); + } break; - case MessageType::BANLIST: // 10 -// return MessageType::private_process_banlist(context, message, message_size); - + case MessageType::BANLIST: { + MumbleProto::BanList ban_list; + ban_list.ParseFromArray(buffer, length); + for (int i = 0; i < ban_list.bans_size(); i++) { + auto ban = ban_list.bans(i); + + const uint8_t *ip_data = reinterpret_cast(ban.address().c_str()); + uint32_t ip_data_size = ban.address().size(); + int32_t duration = ban.has_duration() ? ban.duration() : -1; + + callback->banList( + ip_data, + ip_data_size, + ban.mask(), + ban.name(), + ban.hash(), + ban.reason(), + ban.start(), + duration); + } + } break; - case MessageType::TEXTMESSAGE: // 11 -// return MessageType::private_process_textmessage(context, message, message_size); + case MessageType::TEXTMESSAGE: { + MumbleProto::TextMessage text_message; + text_message.ParseFromArray(buffer, length); + int32_t actor = text_message.has_actor() ? text_message.actor() : -1; + + vector sessions; + for (int i = 0; i < text_message.session_size(); ++i) { + sessions.push_back(text_message.session(i)); + } + + vector channel_ids; + for (int i = 0; i < text_message.channel_id_size(); ++i) { + channel_ids.push_back(text_message.channel_id(i)); + } + + vector tree_ids; + for (int i = 0; i < text_message.tree_id_size(); ++i) { + tree_ids.push_back(text_message.tree_id(i)); + } + + callback->textMessage(actor, sessions, channel_ids, tree_ids, text_message.message()); + } break; case MessageType::PERMISSIONDENIED: // 12 -// return MessageType::private_process_permissiondenied(context, message, message_size); - + logger->warn("PermissionDenied Message: support not implemented yet"); break; case MessageType::ACL: // 13 -// return MessageType::private_process_acl(context, message, message_size); - + logger->warn("ACL Message: support not implemented yet."); break; case MessageType::QUERYUSERS: // 14 -// return MessageType::private_process_queryusers(context, message, message_size); - + logger->warn("QueryUsers Message: support not implemented yet"); break; case MessageType::CONTEXTACTIONMODIFY: // 16 -// return MessageType::private_process_contextactionmodify(context, message, message_size); - + logger->warn("ContextActionModify Message: support not implemented yet"); break; case MessageType::CONTEXTACTION: // 17 -// return MessageType::private_process_contextaction(context, message, message_size); - + logger->warn("ContextAction Message: support not implemented yet"); break; case MessageType::USERLIST: // 18 -// return MessageType::private_process_userlist(context, message, message_size); - + logger->warn("UserList Message: support not implemented yet"); break; - case MessageType::PERMISSIONQUERY: // 20 -// return MessageType::private_process_permission_query(context, message, message_size); - + case MessageType::VOICETARGET: + logger->warn("VoiceTarget Message: I don't think the server ever sends this structure."); break; - case MessageType::CODECVERSION: // 21 -// return MessageType::private_process_codecversion(context, message, message_size); + case MessageType::PERMISSIONQUERY: { + MumbleProto::PermissionQuery permissionQuery; + permissionQuery.ParseFromArray(buffer, length); + + int32_t channel_id = permissionQuery.has_channel_id() ? permissionQuery.channel_id() : -1; + uint32_t permissions = permissionQuery.has_permissions() ? permissionQuery.permissions() : 0; + uint32_t flush = permissionQuery.has_flush() ? permissionQuery.flush() : -1; + callback->permissionQuery(channel_id, permissions, flush); + } break; - case MessageType::USERSTATS: // 22 -// return MessageType::private_process_userstats(context, message, message_size); + case MessageType::CODECVERSION: { + MumbleProto::CodecVersion codecVersion; + codecVersion.ParseFromArray(buffer, length); + int32_t alpha = codecVersion.alpha(); + int32_t beta = codecVersion.beta(); + uint32_t prefer_alpha = codecVersion.prefer_alpha(); + int32_t opus = codecVersion.has_opus() ? codecVersion.opus() : 0; + + callback->codecVersion(alpha, beta, prefer_alpha, opus); + } + break; + case MessageType::USERSTATS: + logger->warn("UserStats Message: support not implemented yet"); break; case MessageType::REQUESTBLOB: // 23 -// return MessageType::private_process_requestblob(context, message, message_size); - + logger->warn("RequestBlob Message: I don't think this is sent by the server."); break; - case MessageType::SERVERCONFIG: // 24 -// return MessageType::private_process_serverconfig(context, message, message_size); - + case MessageType::SERVERCONFIG: { + MumbleProto::ServerConfig serverConfig; + serverConfig.ParseFromArray(buffer, length); + + uint32_t max_bandwidth = serverConfig.has_max_bandwidth() ? serverConfig.max_bandwidth() : 0; + uint32_t allow_html = serverConfig.has_allow_html() ? serverConfig.allow_html() : 0; + uint32_t message_length = serverConfig.has_message_length() ? serverConfig.message_length() : 0; + uint32_t image_message_length = serverConfig.has_image_message_length() + ? serverConfig.image_message_length() : 0; + + callback->serverConfig(max_bandwidth, serverConfig.welcome_text(), allow_html, message_length, + image_message_length); + } break; case MessageType::SUGGESTCONFIG: // 25 -// return MessageType::private_process_suggestconfig(context, message, message_size); + logger->warn("SuggestConfig Message: support not implemented yet"); break; default: throw MumlibException("unknown message type: " + to_string(static_cast(messageType))); @@ -179,8 +265,14 @@ namespace mumlib { bool processAudioPacket(AudioPacketType type, uint8_t *buffer, int length) { logger->info("Got %d B of encoded audio data.", length); - int16_t pcmData[5000]; - audio->decodeAudioPacket(type, buffer, length, pcmData, 5000); + try { + int16_t pcmData[5000]; + int pcmDataLength = audio->decodeAudioPacket(type, buffer, length, pcmData, 5000); + callback->audio(pcmData, pcmDataLength); + } catch (mumlib::AudioException &exp) { + logger->warn("Audio decode error: %s, calling unsupportedAudio callback.", exp.what()); + callback->unsupportedAudio(buffer, length); + } } }; @@ -192,7 +284,7 @@ namespace mumlib { } mumlib::Mumlib::Mumlib() : impl(new _Mumlib_Private) { - impl->logger = &(log4cpp::Category::getInstance("Mumlib.Mumlib")); + impl->logger = &(log4cpp::Category::getInstance("mumlib.Mumlib")); impl->externalIoService = false; impl->ioService = new io_service(); impl->audio = new Audio(); From 6df4affb5e3083bccf451456d35e78a97af5555a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20S=C5=82omkowski?= Date: Tue, 27 Oct 2015 23:31:45 +0100 Subject: [PATCH 05/59] Refactor Mumlib_Private class. --- include/mumlib.hpp | 4 +- mumlib_example.cpp | 6 +- src/mumlib.cpp | 193 +++++++++++++++++++++++---------------------- 3 files changed, 104 insertions(+), 99 deletions(-) diff --git a/include/mumlib.hpp b/include/mumlib.hpp index a615e91e0f96..6b3e6faf7177 100644 --- a/include/mumlib.hpp +++ b/include/mumlib.hpp @@ -23,9 +23,9 @@ namespace mumlib { class Mumlib : boost::noncopyable { public: - Mumlib(); + Mumlib(Callback &callback); - Mumlib(io_service &ioService); + Mumlib(Callback &callback, io_service &ioService); ~Mumlib(); diff --git a/mumlib_example.cpp b/mumlib_example.cpp index b41b8bbd6e32..cd8021247eb5 100644 --- a/mumlib_example.cpp +++ b/mumlib_example.cpp @@ -31,7 +31,7 @@ int main(int argc, char *argv[]) { log4cpp::Appender *appender1 = new log4cpp::OstreamAppender("console", &std::cout); appender1->setLayout(new log4cpp::BasicLayout()); log4cpp::Category &logger = log4cpp::Category::getRoot(); - logger.setPriority(log4cpp::Priority::DEBUG); + logger.setPriority(log4cpp::Priority::NOTICE); logger.addAppender(appender1); if (argc < 3) { @@ -39,10 +39,8 @@ int main(int argc, char *argv[]) { return 1; } - mumlib::Mumlib mum; - mumlib::BasicCallback callback; - mum.setCallback(callback); + mumlib::Mumlib mum(callback); mum.connect(argv[1], 64738, "mumlib_example", argv[2]); diff --git a/src/mumlib.cpp b/src/mumlib.cpp index e91229409126..d3605806bafb 100644 --- a/src/mumlib.cpp +++ b/src/mumlib.cpp @@ -19,23 +19,56 @@ using namespace mumlib; namespace mumlib { struct _Mumlib_Private : boost::noncopyable { + log4cpp::Category &logger = log4cpp::Category::getInstance("mumlib.Mumlib"); + bool externalIoService; - io_service *ioService; + io_service &ioService; + + Callback &callback; + + Transport transport; - Callback *callback; + Audio audio; - Transport *transport; - Audio *audio; + _Mumlib_Private(Callback &callback) + : _Mumlib_Private(callback, *(new io_service())) { + externalIoService = false; + } + + _Mumlib_Private(Callback &callback, io_service &ioService) + : callback(callback), + ioService(ioService), + externalIoService(true), + transport(ioService, boost::bind(&_Mumlib_Private::processIncomingTcpMessage, this, _1, _2, _3), + boost::bind(&_Mumlib_Private::processAudioPacket, this, _1, _2, _3)) { } - log4cpp::Category *logger; + ~_Mumlib_Private() { + if (not externalIoService) { + delete &ioService; + } + } + + bool processAudioPacket(AudioPacketType type, uint8_t *buffer, int length) { + logger.info("Got %d B of encoded audio data.", length); + try { + int16_t pcmData[5000]; + int pcmDataLength = audio.decodeAudioPacket(type, buffer, length, pcmData, 5000); + callback.audio(pcmData, pcmDataLength); + } catch (mumlib::AudioException &exp) { + logger.warn("Audio decode error: %s, calling unsupportedAudio callback.", exp.what()); + callback.unsupportedAudio(buffer, length); + } + } + + private: bool processIncomingTcpMessage(MessageType messageType, uint8_t *buffer, int length) { switch (messageType) { case MessageType::VERSION: { MumbleProto::Version version; version.ParseFromArray(buffer, length); - callback->version( + callback.version( version.version() >> 16, version.version() >> 8 & 0xff, version.version() & 0xff, @@ -47,7 +80,7 @@ namespace mumlib { case MessageType::SERVERSYNC: { MumbleProto::ServerSync serverSync; serverSync.ParseFromArray(buffer, length); - callback->serverSync( + callback.serverSync( serverSync.welcome_text(), serverSync.session(), serverSync.max_bandwidth(), @@ -58,7 +91,7 @@ namespace mumlib { case MessageType::CHANNELREMOVE: { MumbleProto::ChannelRemove channelRemove; channelRemove.ParseFromArray(buffer, length); - callback->channelRemove(channelRemove.channel_id()); + callback.channelRemove(channelRemove.channel_id()); } break; case MessageType::CHANNELSTATE: { @@ -83,7 +116,7 @@ namespace mumlib { std::copy(channelState.links_remove().begin(), channelState.links_remove().end(), links_remove.begin()); - callback->channelState( + callback.channelState( channelState.name(), channel_id, parent, @@ -104,7 +137,7 @@ namespace mumlib { bool ban = user_remove.has_ban() ? user_remove.ban() : false; //todo make sure it's correct to assume it's false - callback->userRemove( + callback.userRemove( user_remove.session(), actor, user_remove.reason(), @@ -129,19 +162,19 @@ namespace mumlib { int32_t priority_speaker = userState.has_priority_speaker() ? userState.priority_speaker() : -1; int32_t recording = userState.has_recording() ? userState.recording() : -1; - callback->userState(session, - actor, - userState.name(), - user_id, - channel_id, - mute, - deaf, - suppress, - self_mute, - self_deaf, - userState.comment(), - priority_speaker, - recording); + callback.userState(session, + actor, + userState.name(), + user_id, + channel_id, + mute, + deaf, + suppress, + self_mute, + self_deaf, + userState.comment(), + priority_speaker, + recording); } break; case MessageType::BANLIST: { @@ -154,7 +187,7 @@ namespace mumlib { uint32_t ip_data_size = ban.address().size(); int32_t duration = ban.has_duration() ? ban.duration() : -1; - callback->banList( + callback.banList( ip_data, ip_data_size, ban.mask(), @@ -187,29 +220,29 @@ namespace mumlib { tree_ids.push_back(text_message.tree_id(i)); } - callback->textMessage(actor, sessions, channel_ids, tree_ids, text_message.message()); + callback.textMessage(actor, sessions, channel_ids, tree_ids, text_message.message()); } break; case MessageType::PERMISSIONDENIED: // 12 - logger->warn("PermissionDenied Message: support not implemented yet"); + logger.warn("PermissionDenied Message: support not implemented yet"); break; case MessageType::ACL: // 13 - logger->warn("ACL Message: support not implemented yet."); + logger.warn("ACL Message: support not implemented yet."); break; case MessageType::QUERYUSERS: // 14 - logger->warn("QueryUsers Message: support not implemented yet"); + logger.warn("QueryUsers Message: support not implemented yet"); break; case MessageType::CONTEXTACTIONMODIFY: // 16 - logger->warn("ContextActionModify Message: support not implemented yet"); + logger.warn("ContextActionModify Message: support not implemented yet"); break; case MessageType::CONTEXTACTION: // 17 - logger->warn("ContextAction Message: support not implemented yet"); + logger.warn("ContextAction Message: support not implemented yet"); break; case MessageType::USERLIST: // 18 - logger->warn("UserList Message: support not implemented yet"); + logger.warn("UserList Message: support not implemented yet"); break; case MessageType::VOICETARGET: - logger->warn("VoiceTarget Message: I don't think the server ever sends this structure."); + logger.warn("VoiceTarget Message: I don't think the server ever sends this structure."); break; case MessageType::PERMISSIONQUERY: { MumbleProto::PermissionQuery permissionQuery; @@ -219,7 +252,7 @@ namespace mumlib { uint32_t permissions = permissionQuery.has_permissions() ? permissionQuery.permissions() : 0; uint32_t flush = permissionQuery.has_flush() ? permissionQuery.flush() : -1; - callback->permissionQuery(channel_id, permissions, flush); + callback.permissionQuery(channel_id, permissions, flush); } break; case MessageType::CODECVERSION: { @@ -231,14 +264,14 @@ namespace mumlib { uint32_t prefer_alpha = codecVersion.prefer_alpha(); int32_t opus = codecVersion.has_opus() ? codecVersion.opus() : 0; - callback->codecVersion(alpha, beta, prefer_alpha, opus); + callback.codecVersion(alpha, beta, prefer_alpha, opus); } break; case MessageType::USERSTATS: - logger->warn("UserStats Message: support not implemented yet"); + logger.warn("UserStats Message: support not implemented yet"); break; case MessageType::REQUESTBLOB: // 23 - logger->warn("RequestBlob Message: I don't think this is sent by the server."); + logger.warn("RequestBlob Message: I don't think this is sent by the server."); break; case MessageType::SERVERCONFIG: { MumbleProto::ServerConfig serverConfig; @@ -250,12 +283,12 @@ namespace mumlib { uint32_t image_message_length = serverConfig.has_image_message_length() ? serverConfig.image_message_length() : 0; - callback->serverConfig(max_bandwidth, serverConfig.welcome_text(), allow_html, message_length, - image_message_length); + callback.serverConfig(max_bandwidth, serverConfig.welcome_text(), allow_html, message_length, + image_message_length); } break; case MessageType::SUGGESTCONFIG: // 25 - logger->warn("SuggestConfig Message: support not implemented yet"); + logger.warn("SuggestConfig Message: support not implemented yet"); break; default: throw MumlibException("unknown message type: " + to_string(static_cast(messageType))); @@ -263,74 +296,48 @@ namespace mumlib { return true; } - bool processAudioPacket(AudioPacketType type, uint8_t *buffer, int length) { - logger->info("Got %d B of encoded audio data.", length); - try { - int16_t pcmData[5000]; - int pcmDataLength = audio->decodeAudioPacket(type, buffer, length, pcmData, 5000); - callback->audio(pcmData, pcmDataLength); - } catch (mumlib::AudioException &exp) { - logger->warn("Audio decode error: %s, calling unsupportedAudio callback.", exp.what()); - callback->unsupportedAudio(buffer, length); - } - } }; - - ConnectionState Mumlib::getConnectionState() { - return impl->transport->getConnectionState(); + Mumlib::Mumlib(Callback &callback) + : impl(new _Mumlib_Private(callback)) { } -} -mumlib::Mumlib::Mumlib() : impl(new _Mumlib_Private) { - impl->logger = &(log4cpp::Category::getInstance("mumlib.Mumlib")); - impl->externalIoService = false; - impl->ioService = new io_service(); - impl->audio = new Audio(); - impl->transport = new Transport( - *(impl->ioService), - boost::bind(&_Mumlib_Private::processIncomingTcpMessage, impl, _1, _2, _3), - boost::bind(&_Mumlib_Private::processAudioPacket, impl, _1, _2, _3) - ); -} + Mumlib::Mumlib(Callback &callback, io_service &ioService) + : impl(new _Mumlib_Private(callback, ioService)) { } -mumlib::Mumlib::Mumlib(io_service &ioService) : impl(new _Mumlib_Private) { - //todo do this constructor - throw mumlib::MumlibException("not implented yet"); -} + Mumlib::~Mumlib() { + delete impl; + } -mumlib::Mumlib::~Mumlib() { - if (not impl->externalIoService) { - delete impl->ioService; + ConnectionState Mumlib::getConnectionState() { + return impl->transport.getConnectionState(); } - delete impl; -} + void Mumlib::setCallback(Callback &callback) { + impl->callback = callback; + } -void mumlib::Mumlib::setCallback(Callback &callback) { - impl->callback = &callback; -} + void Mumlib::connect(string host, int port, string user, string password) { + impl->transport.connect(host, port, user, password); + } -void mumlib::Mumlib::connect(string host, int port, string user, string password) { - impl->transport->connect(host, port, user, password); -} + void Mumlib::disconnect() { + impl->transport.disconnect(); + } -void mumlib::Mumlib::disconnect() { - impl->transport->disconnect(); -} + void Mumlib::run() { + if (impl->externalIoService) { + throw MumlibException("can't call run() when using external io_service"); + } -void mumlib::Mumlib::run() { - if (impl->externalIoService) { - throw MumlibException("can't call run() when using external io_service"); + impl->ioService.run(); } - impl->ioService->run(); + void Mumlib::sendAudioData(int16_t *pcmData, int pcmLength) { + uint8_t encodedData[5000]; + int length = impl->audio.encodeAudioPacket(0, pcmData, pcmLength, encodedData, 5000); + impl->transport.sendEncodedAudioPacket(encodedData, length); + } } - -void mumlib::Mumlib::sendAudioData(int16_t *pcmData, int pcmLength) { - uint8_t encodedData[5000]; - int length = impl->audio->encodeAudioPacket(0, pcmData, pcmLength, encodedData, 5000); - impl->transport->sendEncodedAudioPacket(encodedData, length); -} \ No newline at end of file From d289bf3134d2194b47b3a8ca5a7ed123c91148b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20S=C5=82omkowski?= Date: Wed, 28 Oct 2015 00:19:42 +0100 Subject: [PATCH 06/59] Change example to be simple echo. --- mumlib_example.cpp | 32 +++++++++----------------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/mumlib_example.cpp b/mumlib_example.cpp index cd8021247eb5..85025cdeac96 100644 --- a/mumlib_example.cpp +++ b/mumlib_example.cpp @@ -4,27 +4,14 @@ #include "log4cpp/FileAppender.hh" #include "log4cpp/OstreamAppender.hh" -#include -#include -#include +class MyCallback : public mumlib::BasicCallback { +public: + mumlib::Mumlib *mum; -void audioSenderThreadFunction(mumlib::Mumlib *mum) { - while (mum->getConnectionState() != mumlib::ConnectionState::FAILED) { - if (mum->getConnectionState() == mumlib::ConnectionState::CONNECTED) { - constexpr double FREQUENCY = 1000; // Hz - constexpr int BUFF_SIZE = mumlib::SAMPLE_RATE / 100; // 10 ms - int16_t buff[BUFF_SIZE]; - - for (int i = 0; i < BUFF_SIZE; ++i) { - buff[i] = 10000 * std::sin(2.0 * M_PI * FREQUENCY * ((double) i) / ((double) mumlib::SAMPLE_RATE)); - } - - mum->sendAudioData(buff, BUFF_SIZE); - } - - std::this_thread::sleep_for(std::chrono::milliseconds(10)); + virtual void audio(int16_t *pcm_data, uint32_t pcm_data_size) { + mum->sendAudioData(pcm_data, pcm_data_size); } -} +}; int main(int argc, char *argv[]) { @@ -39,13 +26,12 @@ int main(int argc, char *argv[]) { return 1; } - mumlib::BasicCallback callback; - mumlib::Mumlib mum(callback); + MyCallback myCallback; + mumlib::Mumlib mum(myCallback); + myCallback.mum = &mum; mum.connect(argv[1], 64738, "mumlib_example", argv[2]); - std::thread audioSenderThread(audioSenderThreadFunction, &mum); - mum.run(); return 0; From 5e060ead332527735adbb5d69adda811122998f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20S=C5=82omkowski?= Date: Fri, 30 Oct 2015 02:15:02 +0100 Subject: [PATCH 07/59] Add text message sending. --- include/mumlib.hpp | 4 ++-- mumlib_example.cpp | 10 ++++++++++ src/mumlib.cpp | 20 +++++++++++++++----- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/include/mumlib.hpp b/include/mumlib.hpp index 6b3e6faf7177..67e2855bf440 100644 --- a/include/mumlib.hpp +++ b/include/mumlib.hpp @@ -29,8 +29,6 @@ namespace mumlib { ~Mumlib(); - void setCallback(Callback &callback); - void connect(string host, int port, string user, string password); void disconnect(); @@ -41,6 +39,8 @@ namespace mumlib { void sendAudioData(int16_t *pcmData, int pcmLength); + void sendTextMessage(std::string message); + private: _Mumlib_Private *impl; }; diff --git a/mumlib_example.cpp b/mumlib_example.cpp index 85025cdeac96..e024f1903bab 100644 --- a/mumlib_example.cpp +++ b/mumlib_example.cpp @@ -11,6 +11,16 @@ class MyCallback : public mumlib::BasicCallback { virtual void audio(int16_t *pcm_data, uint32_t pcm_data_size) { mum->sendAudioData(pcm_data, pcm_data_size); } + + virtual void textMessage( + uint32_t actor, + std::vector session, + std::vector channel_id, + std::vector tree_id, + std::string message) { + mumlib::BasicCallback::textMessage(actor, session, channel_id, tree_id, message); + mum->sendTextMessage("someone said: " + message); + } }; int main(int argc, char *argv[]) { diff --git a/src/mumlib.cpp b/src/mumlib.cpp index d3605806bafb..16db5b0f0d36 100644 --- a/src/mumlib.cpp +++ b/src/mumlib.cpp @@ -30,6 +30,8 @@ namespace mumlib { Audio audio; + int sessionId = 0; + int channelId = 0; _Mumlib_Private(Callback &callback) : _Mumlib_Private(callback, *(new io_service())) { @@ -80,6 +82,9 @@ namespace mumlib { case MessageType::SERVERSYNC: { MumbleProto::ServerSync serverSync; serverSync.ParseFromArray(buffer, length); + + sessionId = serverSync.session(); + callback.serverSync( serverSync.welcome_text(), serverSync.session(), @@ -116,6 +121,8 @@ namespace mumlib { std::copy(channelState.links_remove().begin(), channelState.links_remove().end(), links_remove.begin()); + this->channelId = channel_id; + callback.channelState( channelState.name(), channel_id, @@ -310,15 +317,10 @@ namespace mumlib { delete impl; } - ConnectionState Mumlib::getConnectionState() { return impl->transport.getConnectionState(); } - void Mumlib::setCallback(Callback &callback) { - impl->callback = callback; - } - void Mumlib::connect(string host, int port, string user, string password) { impl->transport.connect(host, port, user, password); } @@ -340,4 +342,12 @@ namespace mumlib { int length = impl->audio.encodeAudioPacket(0, pcmData, pcmLength, encodedData, 5000); impl->transport.sendEncodedAudioPacket(encodedData, length); } + + void Mumlib::sendTextMessage(string message) { + MumbleProto::TextMessage textMessage; + textMessage.set_actor(impl->sessionId); + textMessage.add_channel_id(impl->channelId); + textMessage.set_message(message); + impl->transport.sendControlMessage(MessageType::TEXTMESSAGE, textMessage); + } } From 8d551006cced00f6a97504059aef6296a6d14c05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20S=C5=82omkowski?= Date: Wed, 4 Nov 2015 01:02:17 +0100 Subject: [PATCH 08/59] Clean up CMakeLists.txt. --- CMakeLists.txt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e7a378c0bf02..0703b25c8fc6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,13 +1,12 @@ -cmake_minimum_required(VERSION 3.1.1) -project(libmumble) +cmake_minimum_required(VERSION 3.0.1) +project(mumlib) -list(APPEND CMAKE_C_FLAGS " -std=c99 -g -Wall -pedantic ${CMAKE_C_FLAGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") add_definitions(-DOPT_TLS_GNUTLS -D_POSIX_C_SOURCE=200112L) INCLUDE(FindPkgConfig) find_package(PkgConfig REQUIRED) -find_package(Boost COMPONENTS system unit_test_framework program_options filesystem REQUIRED) +find_package(Boost COMPONENTS system REQUIRED) find_package(OpenSSL REQUIRED) find_package(Protobuf REQUIRED) From 1c2b09e36564368e1d494878ee6a9171e8f4d19e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20S=C5=82omkowski?= Date: Wed, 4 Nov 2015 01:19:18 +0100 Subject: [PATCH 09/59] Clean up includes. --- src/Callback.cpp | 2 +- src/mumlib.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Callback.cpp b/src/Callback.cpp index f98f7ded00bc..ffe97e0fe10a 100644 --- a/src/Callback.cpp +++ b/src/Callback.cpp @@ -1,6 +1,6 @@ #include "mumlib/Callback.hpp" -#include +#include #include using namespace std; diff --git a/src/mumlib.cpp b/src/mumlib.cpp index 16db5b0f0d36..8c0d93f6c27f 100644 --- a/src/mumlib.cpp +++ b/src/mumlib.cpp @@ -6,7 +6,7 @@ #include "mumlib.hpp" -#include +#include #include #include From a1bb86036c3a68731439de20cfe2a500332a8b2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20S=C5=82omkowski?= Date: Sat, 7 Nov 2015 19:21:48 +0100 Subject: [PATCH 10/59] Add README. --- README.md | 47 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 195f11b3204a..efae7540380d 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,45 @@ -# mumlib -Simple Mumble library using boost::asio, non-functional, still in development. +# mumlib - simple Mumble client library + +Fairy simple Mumble library written in C++, using *boost::asio* asynchronous networking framework. Library supports: + +* audio streaming through TCP and UDP channel +* text messaging + +Todo: + +* channel support +* user information +* remaining server messages (ACL, user stats etc) + +## Dependencies + +* Boost libraries +* OpenSSL +* *log4cpp* +* Opus library +* Google Protobuf: libraries and compiler +* CMake + +## Build + +The library uses CMake build system: + +``` +mkdir build && cd build +cmake .. +make +``` + +## Usage + +Sample usage is covered in *mumlib_example.cpp* file. Basically, you should extend *mumlib::Callback* class +to implement your own handlers. + +## Credits + +2015 Michał Słomkowski. The code is published under the terms of Lesser General Public License Version 3. + +The library contains code from following 3rd party projects: + +* official Mumble Client: https://github.com/mumble-voip/mumble +* *libmumble*: https://github.com/cornejo/libmumble \ No newline at end of file From a67dcedf0ca7e815ce94b05faf0a560548c6d0ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20S=C5=82omkowski?= Date: Mon, 9 Nov 2015 21:39:52 +0100 Subject: [PATCH 11/59] Add sequence reset after silence time. #2 --- include/mumlib/Audio.hpp | 6 ++++++ src/Audio.cpp | 41 ++++++++++++++++++++++++++++++++-------- 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/include/mumlib/Audio.hpp b/include/mumlib/Audio.hpp index 2010fdc14ade..765bc9b24f38 100644 --- a/include/mumlib/Audio.hpp +++ b/include/mumlib/Audio.hpp @@ -4,6 +4,8 @@ #include +#include + namespace mumlib { constexpr int SAMPLE_RATE = 48000; @@ -32,6 +34,8 @@ namespace mumlib { uint8_t *outputBuffer, int outputBufferSize = MAX_UDP_LENGTH); + void resetEncoder(); + private: log4cpp::Category &logger; @@ -39,5 +43,7 @@ namespace mumlib { OpusEncoder *opusEncoder; int64_t outgoingSequenceNumber; + + std::chrono::time_point lastEncodedAudioPacketTimestamp; }; } \ No newline at end of file diff --git a/src/Audio.cpp b/src/Audio.cpp index 6052f06a06fb..091fc268f6ec 100644 --- a/src/Audio.cpp +++ b/src/Audio.cpp @@ -2,12 +2,13 @@ #include +static boost::posix_time::seconds RESET_SEQUENCE_NUMBER_INTERVAL(5); + mumlib::Audio::Audio() - : - logger(log4cpp::Category::getInstance("mumlib.Audio")), - opusDecoder(nullptr), - opusEncoder(nullptr), - outgoingSequenceNumber(1) { + : logger(log4cpp::Category::getInstance("mumlib.Audio")), + opusDecoder(nullptr), + opusEncoder(nullptr), + outgoingSequenceNumber(0) { int error; @@ -22,6 +23,8 @@ mumlib::Audio::Audio() } opus_encoder_ctl(opusEncoder, OPUS_SET_VBR(0)); + + resetEncoder(); } mumlib::Audio::~Audio() { @@ -89,8 +92,16 @@ int mumlib::Audio::decodeAudioPacket(AudioPacketType type, int mumlib::Audio::encodeAudioPacket(int target, int16_t *inputPcmBuffer, int inputLength, uint8_t *outputBuffer, int outputBufferSize) { - //if (!bPreviousVoice) - // opus_encoder_ctl(opusState, OPUS_RESET_STATE, NULL); //todo do something with it + + using namespace std::chrono; + + const int lastAudioPacketSentInterval = duration_cast( + system_clock::now() - lastEncodedAudioPacketTimestamp).count(); + + if (lastAudioPacketSentInterval > RESET_SEQUENCE_NUMBER_INTERVAL.total_milliseconds() + 1000) { + logger.debug("Last audio packet was sent %d ms ago, resetting encoder.", lastAudioPacketSentInterval); + resetEncoder(); + } std::vector header; @@ -118,7 +129,21 @@ int mumlib::Audio::encodeAudioPacket(int target, int16_t *inputPcmBuffer, int in memcpy(outputBuffer, &header[0], header.size()); memcpy(outputBuffer + header.size(), tmpOpusBuffer, outputSize); - outgoingSequenceNumber += 2; + int incrementNumber = 100 * inputLength / SAMPLE_RATE; + + outgoingSequenceNumber += incrementNumber; + + lastEncodedAudioPacketTimestamp = std::chrono::system_clock::now(); return outputSize + header.size(); } + +void mumlib::Audio::resetEncoder() { + int status = opus_encoder_ctl(opusEncoder, OPUS_RESET_STATE, nullptr); + + if (status != OPUS_OK) { + throw AudioException((boost::format("failed to reset encoder: %s") % opus_strerror(status)).str()); + } + + outgoingSequenceNumber = 0; +} From ae1e71fffc67a010bd58de4fd2f73a1f20fbb21f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20S=C5=82omkowski?= Date: Tue, 17 Nov 2015 22:53:57 +0100 Subject: [PATCH 12/59] Add sequence and session numbers to audio callbacks. #3 --- include/mumlib.hpp | 2 +- include/mumlib/Audio.hpp | 18 ++++++-- include/mumlib/Callback.hpp | 12 ++++++ mumlib_example.cpp | 6 ++- src/Audio.cpp | 83 +++++++++++++++++++++++-------------- src/Callback.cpp | 20 ++++++--- src/mumlib.cpp | 33 ++++++++++++--- 7 files changed, 126 insertions(+), 48 deletions(-) diff --git a/include/mumlib.hpp b/include/mumlib.hpp index 67e2855bf440..b64f221d5412 100644 --- a/include/mumlib.hpp +++ b/include/mumlib.hpp @@ -27,7 +27,7 @@ namespace mumlib { Mumlib(Callback &callback, io_service &ioService); - ~Mumlib(); + virtual ~Mumlib(); void connect(string host, int port, string user, string password); diff --git a/include/mumlib/Audio.hpp b/include/mumlib/Audio.hpp index 765bc9b24f38..b00120cbf772 100644 --- a/include/mumlib/Audio.hpp +++ b/include/mumlib/Audio.hpp @@ -17,15 +17,27 @@ namespace mumlib { AudioException(string message) : MumlibException(message) { } }; + struct IncomingAudioPacket { + AudioPacketType type; + int target; + int64_t sessionId; + int64_t sequenceNumber; + uint8_t *audioPayload; + int audioPayloadLength; + }; + class Audio : boost::noncopyable { public: Audio(); - ~Audio(); + virtual ~Audio(); + IncomingAudioPacket decodeIncomingAudioPacket(uint8_t *inputBuffer, int inputBufferLength); - int decodeAudioPacket(AudioPacketType type, uint8_t *inputBuffer, int inputLength, int16_t *pcmBuffer, - int pcmBufferSize); + std::pair decodeOpusPayload(uint8_t *inputBuffer, + int inputLength, + int16_t *pcmBuffer, + int pcmBufferSize); int encodeAudioPacket( int target, diff --git a/include/mumlib/Callback.hpp b/include/mumlib/Callback.hpp index ebb712e85e50..bc668d9dcfa8 100644 --- a/include/mumlib/Callback.hpp +++ b/include/mumlib/Callback.hpp @@ -19,10 +19,16 @@ namespace mumlib { string os_version) { }; virtual void audio( + int target, + int sessionId, + int sequenceNumber, int16_t *pcm_data, uint32_t pcm_data_size) { }; virtual void unsupportedAudio( + int target, + int sessionId, + int sequenceNumber, uint8_t *encoded_audio_data, uint32_t encoded_audio_data_size) { }; @@ -156,10 +162,16 @@ namespace mumlib { string os_version); virtual void audio( + int target, + int sessionId, + int sequenceNumber, int16_t *pcm_data, uint32_t pcm_data_size); virtual void unsupportedAudio( + int target, + int sessionId, + int sequenceNumber, uint8_t *encoded_audio_data, uint32_t encoded_audio_data_size); diff --git a/mumlib_example.cpp b/mumlib_example.cpp index e024f1903bab..870e792953f7 100644 --- a/mumlib_example.cpp +++ b/mumlib_example.cpp @@ -8,7 +8,11 @@ class MyCallback : public mumlib::BasicCallback { public: mumlib::Mumlib *mum; - virtual void audio(int16_t *pcm_data, uint32_t pcm_data_size) { + virtual void audio(int target, + int sessionId, + int sequenceNumber, + int16_t *pcm_data, + uint32_t pcm_data_size) { mum->sendAudioData(pcm_data, pcm_data_size); } diff --git a/src/Audio.cpp b/src/Audio.cpp index 091fc268f6ec..b117a4f1c270 100644 --- a/src/Audio.cpp +++ b/src/Audio.cpp @@ -37,34 +37,25 @@ mumlib::Audio::~Audio() { } } -int mumlib::Audio::decodeAudioPacket(AudioPacketType type, - uint8_t *inputBuffer, - int inputLength, - int16_t *pcmBuffer, - int pcmBufferSize) { - - if (type != AudioPacketType::OPUS) { - throw AudioException("codecs other than OPUS are not supported"); - } - - int target = inputBuffer[0] & 0x1F; - - int64_t sessionId; - int64_t sequenceNumber; +std::pair mumlib::Audio::decodeOpusPayload(uint8_t *inputBuffer, + int inputLength, + int16_t *pcmBuffer, + int pcmBufferSize) { int64_t opusDataLength; - std::array varInts = {&sessionId, &sequenceNumber, &opusDataLength}; - - int dataPointer = 1; - for (int64_t *val : varInts) { - VarInt varInt(&inputBuffer[dataPointer]); - *val = varInt.getValue(); - dataPointer += varInt.getEncoded().size(); - } + int dataPointer = 0; + VarInt varInt(inputBuffer); + opusDataLength = varInt.getValue(); + dataPointer += varInt.getEncoded().size(); bool lastPacket = (opusDataLength & 0x2000) != 0; opusDataLength = opusDataLength & 0x1fff; + if (inputLength < opusDataLength + dataPointer) { + throw AudioException((boost::format("invalid Opus payload (%d B): header %d B, expected Opus data length %d B") + % inputLength % dataPointer % opusDataLength).str()); + } + int outputSize = opus_decode(opusDecoder, reinterpret_cast(&inputBuffer[dataPointer]), opusDataLength, @@ -77,17 +68,10 @@ int mumlib::Audio::decodeAudioPacket(AudioPacketType type, opus_strerror(outputSize)).str()); } - logger.debug( - "Received %d B of OPUS data, decoded to %d B (target: %d, sessionID: %ld, seq num: %ld, last: %d).", - opusDataLength, - outputSize, - target, - sessionId, - sequenceNumber, - lastPacket); - + logger.debug("%d B of Opus data decoded to %d PCM samples, last packet: %d.", + opusDataLength, outputSize, lastPacket); - return outputSize; + return std::make_pair(outputSize, lastPacket); } int mumlib::Audio::encodeAudioPacket(int target, int16_t *inputPcmBuffer, int inputLength, uint8_t *outputBuffer, @@ -147,3 +131,38 @@ void mumlib::Audio::resetEncoder() { outgoingSequenceNumber = 0; } + +mumlib::IncomingAudioPacket mumlib::Audio::decodeIncomingAudioPacket(uint8_t *inputBuffer, int inputBufferLength) { + mumlib::IncomingAudioPacket incomingAudioPacket; + + incomingAudioPacket.type = static_cast((inputBuffer[0] & 0xE0) >> 5); + incomingAudioPacket.target = inputBuffer[0] & 0x1F; + + std::array varInts = {&incomingAudioPacket.sessionId, &incomingAudioPacket.sequenceNumber}; + + int dataPointer = 1; + for (int64_t *val : varInts) { + VarInt varInt(&inputBuffer[dataPointer]); + *val = varInt.getValue(); + dataPointer += varInt.getEncoded().size(); + } + + incomingAudioPacket.audioPayload = &inputBuffer[dataPointer]; + incomingAudioPacket.audioPayloadLength = inputBufferLength - dataPointer; + + if (dataPointer >= inputBufferLength) { + throw AudioException((boost::format("invalid incoming audio packet (%d B): header %d B") % inputBufferLength % + dataPointer).str()); + } + + logger.debug( + "Received %d B of audio packet, %d B header, %d B payload (target: %d, sessionID: %ld, seq num: %ld).", + inputBufferLength, + dataPointer, + incomingAudioPacket.audioPayloadLength, + incomingAudioPacket.target, + incomingAudioPacket.sessionId, + incomingAudioPacket.sequenceNumber); + + return incomingAudioPacket; +} diff --git a/src/Callback.cpp b/src/Callback.cpp index ffe97e0fe10a..ea8fb804ddff 100644 --- a/src/Callback.cpp +++ b/src/Callback.cpp @@ -36,13 +36,23 @@ void mumlib::BasicCallback::version( } void mumlib::BasicCallback::audio( + int target, + int sessionId, + int sequenceNumber, int16_t *pcmData, uint32_t pcm_data_size) { - impl->logger.debug("audio: %d bytes of raw PCM data.", pcm_data_size); -} - -void BasicCallback::unsupportedAudio(uint8_t *encoded_audio_data, uint32_t encoded_audio_data_size) { - impl->logger.debug("unsupportedAudio: received %d bytes of encoded data.", encoded_audio_data_size); + impl->logger.debug("audio: %d bytes of raw PCM data, target: %d, session: %d, seq: %d.", + pcm_data_size, target, sessionId, sequenceNumber); +} + +void BasicCallback::unsupportedAudio( + int target, + int sessionId, + int sequenceNumber, + uint8_t *encoded_audio_data, + uint32_t encoded_audio_data_size) { + impl->logger.debug("unsupportedAudio: received %d bytes of encoded data, target: %d, session: %d, seq: %d.", + encoded_audio_data_size, target, sessionId, sequenceNumber); } void BasicCallback::serverSync(string welcome_text, int32_t session, int32_t max_bandwidth, int64_t permissions) { diff --git a/src/mumlib.cpp b/src/mumlib.cpp index 8c0d93f6c27f..f140a81b6903 100644 --- a/src/mumlib.cpp +++ b/src/mumlib.cpp @@ -45,7 +45,7 @@ namespace mumlib { transport(ioService, boost::bind(&_Mumlib_Private::processIncomingTcpMessage, this, _1, _2, _3), boost::bind(&_Mumlib_Private::processAudioPacket, this, _1, _2, _3)) { } - ~_Mumlib_Private() { + virtual ~_Mumlib_Private() { if (not externalIoService) { delete &ioService; } @@ -54,13 +54,34 @@ namespace mumlib { bool processAudioPacket(AudioPacketType type, uint8_t *buffer, int length) { logger.info("Got %d B of encoded audio data.", length); try { - int16_t pcmData[5000]; - int pcmDataLength = audio.decodeAudioPacket(type, buffer, length, pcmData, 5000); - callback.audio(pcmData, pcmDataLength); + auto incomingAudioPacket = audio.decodeIncomingAudioPacket(buffer, length); + + if (type == AudioPacketType::OPUS) { + int16_t pcmData[5000]; + auto status = audio.decodeOpusPayload(incomingAudioPacket.audioPayload, + incomingAudioPacket.audioPayloadLength, + pcmData, + 5000); + + callback.audio(incomingAudioPacket.target, + incomingAudioPacket.sessionId, + incomingAudioPacket.sequenceNumber, + pcmData, + status.first); + } else { + logger.warn("Incoming audio packet doesn't contain Opus data, calling unsupportedAudio callback."); + callback.unsupportedAudio(incomingAudioPacket.target, + incomingAudioPacket.sessionId, + incomingAudioPacket.sequenceNumber, + incomingAudioPacket.audioPayload, + incomingAudioPacket.audioPayloadLength); + } + } catch (mumlib::AudioException &exp) { - logger.warn("Audio decode error: %s, calling unsupportedAudio callback.", exp.what()); - callback.unsupportedAudio(buffer, length); + logger.error("Audio decode error: %s.", exp.what()); } + + return true; } private: From 0aee2849741424cb21b263a9a574460967ecb6d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20S=C5=82omkowski?= Date: Tue, 17 Nov 2015 23:09:18 +0100 Subject: [PATCH 13/59] Add 'override' to virtual function overloads. --- include/mumlib/Callback.hpp | 36 ++++++++++++++++++------------------ mumlib_example.cpp | 4 ++-- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/include/mumlib/Callback.hpp b/include/mumlib/Callback.hpp index bc668d9dcfa8..7ff4aa6b3c19 100644 --- a/include/mumlib/Callback.hpp +++ b/include/mumlib/Callback.hpp @@ -159,21 +159,21 @@ namespace mumlib { uint8_t patch, string release, string os, - string os_version); + string os_version) override; virtual void audio( int target, int sessionId, int sequenceNumber, int16_t *pcm_data, - uint32_t pcm_data_size); + uint32_t pcm_data_size) override; virtual void unsupportedAudio( int target, int sessionId, int sequenceNumber, uint8_t *encoded_audio_data, - uint32_t encoded_audio_data_size); + uint32_t encoded_audio_data_size) override; virtual void serverSync( string welcome_text, @@ -181,7 +181,7 @@ namespace mumlib { int32_t max_bandwidth, int64_t permissions); - virtual void channelRemove(uint32_t channel_id); + virtual void channelRemove(uint32_t channel_id) override; virtual void channelState( string name, @@ -192,13 +192,13 @@ namespace mumlib { vector inks_add, vector links_remove, bool temporary, - int32_t position); + int32_t position) override; virtual void userRemove( uint32_t session, int32_t actor, string reason, - bool ban); + bool ban) override; virtual void userState( int32_t session, @@ -213,7 +213,7 @@ namespace mumlib { int32_t self_deaf, string comment, int32_t priority_speaker, - int32_t recording); + int32_t recording) override; virtual void banList( const uint8_t *ip_data, @@ -223,14 +223,14 @@ namespace mumlib { string hash, string reason, string start, - int32_t duration); + int32_t duration) override; virtual void textMessage( uint32_t actor, std::vector session, std::vector channel_id, std::vector tree_id, - string message); + string message) override; virtual void permissionDenied( int32_t permission, @@ -238,53 +238,53 @@ namespace mumlib { int32_t session, string reason, int32_t deny_type, - string name); + string name) override; virtual void queryUsers( uint32_t n_ids, uint32_t *ids, uint32_t n_names, - string *names); + string *names) override; virtual void contextActionModify( string action, string text, uint32_t m_context, - uint32_t operation); + uint32_t operation) override; virtual void contextAction( int32_t session, int32_t channel_id, - string action); + string action) override; virtual void userList( uint32_t user_id, string name, string last_seen, - int32_t last_channel); + int32_t last_channel) override; virtual void permissionQuery( int32_t channel_id, uint32_t permissions, - int32_t flush); + int32_t flush) override; virtual void codecVersion( int32_t alpha, int32_t beta, uint32_t prefer_alpha, - int32_t opus); + int32_t opus) override; virtual void serverConfig( uint32_t max_bandwidth, string welcome_text, uint32_t allow_html, uint32_t message_length, - uint32_t image_message_length); + uint32_t image_message_length) override; virtual void suggestConfig( uint32_t version, uint32_t positional, - uint32_t push_to_talk); + uint32_t push_to_talk) override; private: _BasicCallback_Private *impl; diff --git a/mumlib_example.cpp b/mumlib_example.cpp index 870e792953f7..b4d3a4597866 100644 --- a/mumlib_example.cpp +++ b/mumlib_example.cpp @@ -12,7 +12,7 @@ class MyCallback : public mumlib::BasicCallback { int sessionId, int sequenceNumber, int16_t *pcm_data, - uint32_t pcm_data_size) { + uint32_t pcm_data_size) override { mum->sendAudioData(pcm_data, pcm_data_size); } @@ -21,7 +21,7 @@ class MyCallback : public mumlib::BasicCallback { std::vector session, std::vector channel_id, std::vector tree_id, - std::string message) { + std::string message) override { mumlib::BasicCallback::textMessage(actor, session, channel_id, tree_id, message); mum->sendTextMessage("someone said: " + message); } From f01b693eed787392beb7ee9352b555e309b6694a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20S=C5=82omkowski?= Date: Mon, 23 Nov 2015 20:28:44 +0100 Subject: [PATCH 14/59] Change CMake version to 2.8.0. --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0703b25c8fc6..9fbbab39783f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.0.1) +cmake_minimum_required(VERSION 2.8.0) project(mumlib) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") @@ -31,7 +31,7 @@ set(MUMLIB_PRIVATE_HEADERS include/mumlib/Transport.hpp include/mumlib/Audio.hpp include/mumlib/enums.hpp -) + ) set(MUMLIB_SRC src/mumlib.cpp @@ -40,7 +40,7 @@ set(MUMLIB_SRC src/VarInt.cpp src/Transport.cpp src/Audio.cpp -) + ) PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS Mumble.proto) From 783ba52665fc16c15de32eb781e505b16f86cb05 Mon Sep 17 00:00:00 2001 From: Matthias Larisch Date: Mon, 30 Nov 2015 20:24:54 +0100 Subject: [PATCH 15/59] Implement joinChannel command joinChannel moves the current user into the given channel identified by channel_id. --- include/mumlib.hpp | 4 +++- src/mumlib.cpp | 6 ++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/include/mumlib.hpp b/include/mumlib.hpp index b64f221d5412..992321c196fb 100644 --- a/include/mumlib.hpp +++ b/include/mumlib.hpp @@ -41,7 +41,9 @@ namespace mumlib { void sendTextMessage(std::string message); + void joinChannel(int channel_id); + private: _Mumlib_Private *impl; }; -} \ No newline at end of file +} diff --git a/src/mumlib.cpp b/src/mumlib.cpp index f140a81b6903..94d92b6d0e73 100644 --- a/src/mumlib.cpp +++ b/src/mumlib.cpp @@ -371,4 +371,10 @@ namespace mumlib { textMessage.set_message(message); impl->transport.sendControlMessage(MessageType::TEXTMESSAGE, textMessage); } + + void Mumlib::joinChannel(int channel_id) { + MumbleProto::UserState userState; + userState.set_channel_id(channel_id); + impl->transport.sendControlMessage(MessageType::USERSTATE, userState); + } } From fbe08c19d181911cfa350acaf48d7966e61ed785 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20S=C5=82omkowski?= Date: Fri, 4 Dec 2015 17:22:34 +0100 Subject: [PATCH 16/59] Add support for reconnecting after communication error. #4 --- include/mumlib/Transport.hpp | 2 ++ mumlib_example.cpp | 24 ++++++++++----- src/Transport.cpp | 57 ++++++++++++++++++++++++++++++------ src/mumlib.cpp | 9 +++++- 4 files changed, 75 insertions(+), 17 deletions(-) diff --git a/include/mumlib/Transport.hpp b/include/mumlib/Transport.hpp index 4f3679f6bd4f..433106f26f61 100644 --- a/include/mumlib/Transport.hpp +++ b/include/mumlib/Transport.hpp @@ -40,6 +40,8 @@ namespace mumlib { ProcessEncodedAudioPacketFunction processEncodedAudioPacketFunction, bool noUdp = false); + ~Transport(); + void connect(string host, int port, string user, diff --git a/mumlib_example.cpp b/mumlib_example.cpp index b4d3a4597866..b36383d39884 100644 --- a/mumlib_example.cpp +++ b/mumlib_example.cpp @@ -4,6 +4,10 @@ #include "log4cpp/FileAppender.hh" #include "log4cpp/OstreamAppender.hh" +#include +#include +#include + class MyCallback : public mumlib::BasicCallback { public: mumlib::Mumlib *mum; @@ -41,12 +45,18 @@ int main(int argc, char *argv[]) { } MyCallback myCallback; - mumlib::Mumlib mum(myCallback); - myCallback.mum = &mum; - - mum.connect(argv[1], 64738, "mumlib_example", argv[2]); - mum.run(); - - return 0; + while (true) { + try { + mumlib::Mumlib mum(myCallback); + myCallback.mum = &mum; + mum.connect(argv[1], 64738, "mumlib_example", argv[2]); + mum.run(); + } catch (mumlib::TransportException &exp) { + logger.error("TransportException: %s.", exp.what()); + + logger.notice("Attempting to reconnect in 5 s."); + std::this_thread::sleep_for(std::chrono::seconds(5)); + } + } } \ No newline at end of file diff --git a/src/Transport.cpp b/src/Transport.cpp index 19094015af54..a37c6785fba6 100644 --- a/src/Transport.cpp +++ b/src/Transport.cpp @@ -45,6 +45,10 @@ mumlib::Transport::Transport( pingTimer.async_wait(boost::bind(&Transport::pingTimerTick, this, _1)); } +mumlib::Transport::~Transport() { + disconnect(); +} + void mumlib::Transport::connect( std::string host, int port, @@ -87,12 +91,28 @@ void mumlib::Transport::connect( void mumlib::Transport::disconnect() { - state = ConnectionState::NOT_CONNECTED; + if (state != ConnectionState::NOT_CONNECTED) { + boost::system::error_code errorCode; + + // todo perform different operations for each ConnectionState + + sslSocket.shutdown(errorCode); + if (errorCode) { + logger.warn("SSL socket shutdown returned an error: %s.", errorCode.message().c_str()); + } + + sslSocket.lowest_layer().shutdown(tcp::socket::shutdown_both, errorCode); + if (errorCode) { + logger.warn("SSL socket lowest layer shutdown returned an error: %s.", errorCode.message().c_str()); + } - sslSocket.shutdown(); - sslSocket.lowest_layer().shutdown(tcp::socket::shutdown_both); + udpSocket.close(errorCode); + if (errorCode) { + logger.warn("UDP socket close returned error: %s.", errorCode.message().c_str()); + } - udpSocket.shutdown(udp::socket::shutdown_both); + state = ConnectionState::NOT_CONNECTED; + } } @@ -140,6 +160,10 @@ bool mumlib::Transport::isUdpActive() { } void mumlib::Transport::doReceiveUdp() { + if (state == ConnectionState::NOT_CONNECTED) { + return; + } + udpSocket.async_receive_from( buffer(udpIncomingBuffer, MAX_UDP_LENGTH), udpReceiverEndpoint, @@ -171,6 +195,8 @@ void mumlib::Transport::doReceiveUdp() { } doReceiveUdp(); + } else if (ec == boost::asio::error::operation_aborted) { + logger.debug("UDP receive function cancelled."); } else { throwTransportException("UDP receive failed: " + ec.message()); } @@ -220,10 +246,10 @@ void mumlib::Transport::pingTimerTick(const boost::system::error_code &e) { } } } - - pingTimer.expires_at(pingTimer.expires_at() + PING_INTERVAL); - pingTimer.async_wait(boost::bind(&Transport::pingTimerTick, this, _1)); } + + pingTimer.expires_at(pingTimer.expires_at() + PING_INTERVAL); + pingTimer.async_wait(boost::bind(&Transport::pingTimerTick, this, _1)); } void mumlib::Transport::sendUdpAsync(uint8_t *buff, int length) { @@ -252,6 +278,10 @@ void mumlib::Transport::sendUdpAsync(uint8_t *buff, int length) { } void mumlib::Transport::doReceiveSsl() { + if (state == ConnectionState::NOT_CONNECTED) { + return; + } + async_read( sslSocket, boost::asio::buffer(sslIncomingBuffer, MAX_TCP_LENGTH), @@ -385,6 +415,11 @@ void mumlib::Transport::processMessageInternal(MessageType messageType, uint8_t } void mumlib::Transport::sendUdpPing() { + if (state == ConnectionState::NOT_CONNECTED) { + logger.debug("State changed to NOT_CONNECTED, skipping UDP ping."); + return; + } + logger.debug("Sending UDP ping."); vector message; @@ -404,7 +439,11 @@ void mumlib::Transport::sendSsl(uint8_t *buff, int length) { logger.debug("Sending %d bytes of data.", length); - write(sslSocket, boost::asio::buffer(buff, length)); + try { + write(sslSocket, boost::asio::buffer(buff, length)); + } catch (boost::system::system_error &err) { + throwTransportException(std::string("SSL send failed: ") + err.what()); + } } void mumlib::Transport::sendSslAsync(uint8_t *buff, int length) { @@ -428,7 +467,7 @@ void mumlib::Transport::sendSslAsync(uint8_t *buff, int length) { if (!ec and bytesTransferred > 0) { } else { - throwTransportException("send failed: " + ec.message()); + throwTransportException("async SSL send failed: " + ec.message()); } }); } diff --git a/src/mumlib.cpp b/src/mumlib.cpp index f140a81b6903..0f19fad0e3b8 100644 --- a/src/mumlib.cpp +++ b/src/mumlib.cpp @@ -335,6 +335,8 @@ namespace mumlib { : impl(new _Mumlib_Private(callback, ioService)) { } Mumlib::~Mumlib() { + disconnect(); + delete impl; } @@ -347,7 +349,12 @@ namespace mumlib { } void Mumlib::disconnect() { - impl->transport.disconnect(); + if (not impl->externalIoService) { + impl->ioService.reset(); + } + if (impl->transport.getConnectionState() != ConnectionState::NOT_CONNECTED) { + impl->transport.disconnect(); + } } void Mumlib::run() { From 9b3af96222d6c9e3846a1c3285a7b3e7e5d47bba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20S=C5=82omkowski?= Date: Sun, 13 Dec 2015 02:43:05 +0100 Subject: [PATCH 17/59] Add additional receive error message. --- src/Transport.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Transport.cpp b/src/Transport.cpp index a37c6785fba6..a65bf2888e53 100644 --- a/src/Transport.cpp +++ b/src/Transport.cpp @@ -312,6 +312,8 @@ void mumlib::Transport::doReceiveSsl() { doReceiveSsl(); } else { + logger.error("SSL receiver error: %s. Bytes transferred: %d.", + ec.message().c_str(), bytesTransferred); throwTransportException("receive failed: " + ec.message()); } }); From 7e37c6eb7e54e99b74c340eede2b7713b352160e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20S=C5=82omkowski?= Date: Sun, 13 Dec 2015 22:35:01 +0100 Subject: [PATCH 18/59] Disable exception throwing if receive 0 bytes. #6 --- src/Transport.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Transport.cpp b/src/Transport.cpp index a65bf2888e53..ae25046eb521 100644 --- a/src/Transport.cpp +++ b/src/Transport.cpp @@ -314,7 +314,8 @@ void mumlib::Transport::doReceiveSsl() { } else { logger.error("SSL receiver error: %s. Bytes transferred: %d.", ec.message().c_str(), bytesTransferred); - throwTransportException("receive failed: " + ec.message()); + //todo temporarily disable exception throwing until issue #6 is solved + //throwTransportException("receive failed: " + ec.message()); } }); } From 4b8fad826327a79af7856f5d06efbb6546652cb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20S=C5=82omkowski?= Date: Mon, 14 Dec 2015 01:44:02 +0100 Subject: [PATCH 19/59] Add exception when input SSL buffer is overflown. #6 --- src/Transport.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Transport.cpp b/src/Transport.cpp index ae25046eb521..9838eeb36704 100644 --- a/src/Transport.cpp +++ b/src/Transport.cpp @@ -292,9 +292,16 @@ void mumlib::Transport::doReceiveSsl() { } const int payloadSize = ntohl(*reinterpret_cast(sslIncomingBuffer + 2)); - size_t remaining = payloadSize + 6 - bytesTransferred; + const int wholeMessageLength = payloadSize + 6; + size_t remaining = wholeMessageLength - bytesTransferred; remaining = max(remaining, (size_t) 0); + if (wholeMessageLength > MAX_TCP_LENGTH) { + throwTransportException( + (boost::format("message bigger (%d B) than max allowed size (%d B)") + % wholeMessageLength % MAX_TCP_LENGTH).str()); + } + return remaining; }, [this](const boost::system::error_code &ec, size_t bytesTransferred) { From 7a45a4c40dfe9074f572254ada8d34f4c59b4c72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20S=C5=82omkowski?= Date: Mon, 14 Dec 2015 02:36:25 +0100 Subject: [PATCH 20/59] Fix wrong channel texting after channel join. --- include/mumlib.hpp | 2 +- include/mumlib/Callback.hpp | 2 +- src/mumlib.cpp | 5 +++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/mumlib.hpp b/include/mumlib.hpp index 992321c196fb..5df4f50b1da6 100644 --- a/include/mumlib.hpp +++ b/include/mumlib.hpp @@ -41,7 +41,7 @@ namespace mumlib { void sendTextMessage(std::string message); - void joinChannel(int channel_id); + void joinChannel(int channelId); private: _Mumlib_Private *impl; diff --git a/include/mumlib/Callback.hpp b/include/mumlib/Callback.hpp index 7ff4aa6b3c19..a11b7b4a89d1 100644 --- a/include/mumlib/Callback.hpp +++ b/include/mumlib/Callback.hpp @@ -179,7 +179,7 @@ namespace mumlib { string welcome_text, int32_t session, int32_t max_bandwidth, - int64_t permissions); + int64_t permissions) override; virtual void channelRemove(uint32_t channel_id) override; diff --git a/src/mumlib.cpp b/src/mumlib.cpp index 3465d6d51229..10609cb8d482 100644 --- a/src/mumlib.cpp +++ b/src/mumlib.cpp @@ -379,9 +379,10 @@ namespace mumlib { impl->transport.sendControlMessage(MessageType::TEXTMESSAGE, textMessage); } - void Mumlib::joinChannel(int channel_id) { + void Mumlib::joinChannel(int channelId) { MumbleProto::UserState userState; - userState.set_channel_id(channel_id); + userState.set_channel_id(channelId); impl->transport.sendControlMessage(MessageType::USERSTATE, userState); + impl->channelId = channelId; } } From 2617016706eea8b0b7ce7417702617b3dcad0145 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20S=C5=82omkowski?= Date: Mon, 14 Dec 2015 22:44:32 +0100 Subject: [PATCH 21/59] Fix crash after channel linking. --- src/mumlib.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/mumlib.cpp b/src/mumlib.cpp index 10609cb8d482..a5dbb3ac5766 100644 --- a/src/mumlib.cpp +++ b/src/mumlib.cpp @@ -87,6 +87,8 @@ namespace mumlib { private: bool processIncomingTcpMessage(MessageType messageType, uint8_t *buffer, int length) { + logger.debug("Process incoming message: type %d, length: %d.", messageType, length); + switch (messageType) { case MessageType::VERSION: { MumbleProto::Version version; @@ -133,14 +135,19 @@ namespace mumlib { int position = channelState.has_position() ? channelState.position() : 0; vector links; - std::copy(channelState.links().begin(), channelState.links().end(), links.begin()); + for (int i = 0; i < channelState.links_size(); ++i) { + links.push_back(channelState.links(i)); + } vector links_add; - std::copy(channelState.links_add().begin(), channelState.links_add().end(), links_add.begin()); + for (int i = 0; i < channelState.links_add_size(); ++i) { + links_add.push_back(channelState.links_add(i)); + } vector links_remove; - std::copy(channelState.links_remove().begin(), channelState.links_remove().end(), - links_remove.begin()); + for (int i = 0; i < channelState.links_remove_size(); ++i) { + links_remove.push_back(channelState.links_remove(i)); + } this->channelId = channel_id; From a4f511d66823205679c7eac723ee3d23ea825fb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20S=C5=82omkowski?= Date: Mon, 14 Dec 2015 22:44:32 +0100 Subject: [PATCH 22/59] Fix crash after channel linking. (cherry picked from commit 2617016) --- src/mumlib.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/mumlib.cpp b/src/mumlib.cpp index 3465d6d51229..7bd325f1a067 100644 --- a/src/mumlib.cpp +++ b/src/mumlib.cpp @@ -87,6 +87,8 @@ namespace mumlib { private: bool processIncomingTcpMessage(MessageType messageType, uint8_t *buffer, int length) { + logger.debug("Process incoming message: type %d, length: %d.", messageType, length); + switch (messageType) { case MessageType::VERSION: { MumbleProto::Version version; @@ -133,14 +135,19 @@ namespace mumlib { int position = channelState.has_position() ? channelState.position() : 0; vector links; - std::copy(channelState.links().begin(), channelState.links().end(), links.begin()); + for (int i = 0; i < channelState.links_size(); ++i) { + links.push_back(channelState.links(i)); + } vector links_add; - std::copy(channelState.links_add().begin(), channelState.links_add().end(), links_add.begin()); + for (int i = 0; i < channelState.links_add_size(); ++i) { + links_add.push_back(channelState.links_add(i)); + } vector links_remove; - std::copy(channelState.links_remove().begin(), channelState.links_remove().end(), - links_remove.begin()); + for (int i = 0; i < channelState.links_remove_size(); ++i) { + links_remove.push_back(channelState.links_remove(i)); + } this->channelId = channel_id; From 44f2bbd5c3300912d9fa948c54c13eac10486cae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20S=C5=82omkowski?= Date: Wed, 20 Jan 2016 21:46:49 +0100 Subject: [PATCH 23/59] Increase SSL input buffer to handle images. #7 --- include/mumlib/Transport.hpp | 5 ++--- src/Transport.cpp | 3 +++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/include/mumlib/Transport.hpp b/include/mumlib/Transport.hpp index 433106f26f61..ccf94a72ce6d 100644 --- a/include/mumlib/Transport.hpp +++ b/include/mumlib/Transport.hpp @@ -18,7 +18,7 @@ namespace mumlib { constexpr int MAX_UDP_LENGTH = 1024; - constexpr int MAX_TCP_LENGTH = 2048; + constexpr int MAX_TCP_LENGTH = 129 * 1024; // 128 kB + some reserve using namespace std; using namespace boost::asio; @@ -85,8 +85,7 @@ namespace mumlib { ssl::context sslContext; ssl::stream sslSocket; - uint8_t sslIncomingBuffer[MAX_TCP_LENGTH]; - + uint8_t *sslIncomingBuffer; deadline_timer pingTimer; std::chrono::time_point lastReceivedUdpPacketTimestamp; diff --git a/src/Transport.cpp b/src/Transport.cpp index 9838eeb36704..f13451275954 100644 --- a/src/Transport.cpp +++ b/src/Transport.cpp @@ -42,11 +42,14 @@ mumlib::Transport::Transport( pingTimer(ioService, PING_INTERVAL), asyncBufferPool(max(MAX_UDP_LENGTH, MAX_TCP_LENGTH)) { + sslIncomingBuffer = new uint8_t[MAX_TCP_LENGTH]; + pingTimer.async_wait(boost::bind(&Transport::pingTimerTick, this, _1)); } mumlib::Transport::~Transport() { disconnect(); + delete[] sslIncomingBuffer; } void mumlib::Transport::connect( From b7720cc7f3dca118ff3e3f9de6ddcb0fc0293b23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20S=C5=82omkowski?= Date: Fri, 15 Apr 2016 03:13:56 +0200 Subject: [PATCH 24/59] Add support for changing Opus encoder bitrate. #11 --- include/mumlib.hpp | 11 +++++++++++ include/mumlib/Audio.hpp | 6 +++++- mumlib_example.cpp | 4 +++- src/Audio.cpp | 23 ++++++++++++++++++++++- src/mumlib.cpp | 28 ++++++++++++++++++++-------- 5 files changed, 61 insertions(+), 11 deletions(-) diff --git a/include/mumlib.hpp b/include/mumlib.hpp index 5df4f50b1da6..95afe0229e4b 100644 --- a/include/mumlib.hpp +++ b/include/mumlib.hpp @@ -10,6 +10,8 @@ namespace mumlib { + constexpr int DEFAULT_OPUS_ENCODER_BITRATE = 16000; + using namespace std; using namespace boost::asio; @@ -18,6 +20,11 @@ namespace mumlib { MumlibException(string message) : runtime_error(message) { } }; + struct MumlibConfiguration { + int opusEncoderBitrate = DEFAULT_OPUS_ENCODER_BITRATE; + // additional fields will be added in the future + }; + struct _Mumlib_Private; @@ -27,6 +34,10 @@ namespace mumlib { Mumlib(Callback &callback, io_service &ioService); + Mumlib(Callback &callback, MumlibConfiguration &configuration); + + Mumlib(Callback &callback, io_service &ioService, MumlibConfiguration &configuration); + virtual ~Mumlib(); void connect(string host, int port, string user, string password); diff --git a/include/mumlib/Audio.hpp b/include/mumlib/Audio.hpp index b00120cbf772..d98f41a1551f 100644 --- a/include/mumlib/Audio.hpp +++ b/include/mumlib/Audio.hpp @@ -28,7 +28,7 @@ namespace mumlib { class Audio : boost::noncopyable { public: - Audio(); + Audio(int opusEncoderBitrate = DEFAULT_OPUS_ENCODER_BITRATE); virtual ~Audio(); @@ -46,6 +46,10 @@ namespace mumlib { uint8_t *outputBuffer, int outputBufferSize = MAX_UDP_LENGTH); + void setOpusEncoderBitrate(int bitrate); + + int getOpusEncoderBitrate(); + void resetEncoder(); private: diff --git a/mumlib_example.cpp b/mumlib_example.cpp index b36383d39884..2e874d6249a0 100644 --- a/mumlib_example.cpp +++ b/mumlib_example.cpp @@ -48,7 +48,9 @@ int main(int argc, char *argv[]) { while (true) { try { - mumlib::Mumlib mum(myCallback); + mumlib::MumlibConfiguration conf; + conf.opusEncoderBitrate = 32000; + mumlib::Mumlib mum(myCallback, conf); myCallback.mum = &mum; mum.connect(argv[1], 64738, "mumlib_example", argv[2]); mum.run(); diff --git a/src/Audio.cpp b/src/Audio.cpp index b117a4f1c270..3ce75944b03e 100644 --- a/src/Audio.cpp +++ b/src/Audio.cpp @@ -4,7 +4,7 @@ static boost::posix_time::seconds RESET_SEQUENCE_NUMBER_INTERVAL(5); -mumlib::Audio::Audio() +mumlib::Audio::Audio(int opusEncoderBitrate) : logger(log4cpp::Category::getInstance("mumlib.Audio")), opusDecoder(nullptr), opusEncoder(nullptr), @@ -24,6 +24,8 @@ mumlib::Audio::Audio() opus_encoder_ctl(opusEncoder, OPUS_SET_VBR(0)); + setOpusEncoderBitrate(opusEncoderBitrate); + resetEncoder(); } @@ -37,6 +39,23 @@ mumlib::Audio::~Audio() { } } +void mumlib::Audio::setOpusEncoderBitrate(int bitrate) { + int error = opus_encoder_ctl(opusEncoder, OPUS_SET_BITRATE(bitrate)); + if (error != OPUS_OK) { + throw AudioException((boost::format("failed to initialize transmission bitrate to %d B/s: %s") + % bitrate % opus_strerror(error)).str()); + } +} + +int mumlib::Audio::getOpusEncoderBitrate() { + opus_int32 bitrate; + int error = opus_encoder_ctl(opusEncoder, OPUS_GET_BITRATE(&bitrate)); + if (error != OPUS_OK) { + throw AudioException((boost::format("failed to read Opus bitrate: %s") % opus_strerror(error)).str()); + } + return bitrate; +} + std::pair mumlib::Audio::decodeOpusPayload(uint8_t *inputBuffer, int inputLength, int16_t *pcmBuffer, @@ -166,3 +185,5 @@ mumlib::IncomingAudioPacket mumlib::Audio::decodeIncomingAudioPacket(uint8_t *in return incomingAudioPacket; } + + diff --git a/src/mumlib.cpp b/src/mumlib.cpp index a5dbb3ac5766..08197d1a39d4 100644 --- a/src/mumlib.cpp +++ b/src/mumlib.cpp @@ -33,17 +33,20 @@ namespace mumlib { int sessionId = 0; int channelId = 0; - _Mumlib_Private(Callback &callback) - : _Mumlib_Private(callback, *(new io_service())) { + _Mumlib_Private(Callback &callback, MumlibConfiguration &configuration) + : _Mumlib_Private(callback, *(new io_service()), configuration) { externalIoService = false; } - _Mumlib_Private(Callback &callback, io_service &ioService) + _Mumlib_Private(Callback &callback, io_service &ioService, MumlibConfiguration &configuration) : callback(callback), ioService(ioService), externalIoService(true), transport(ioService, boost::bind(&_Mumlib_Private::processIncomingTcpMessage, this, _1, _2, _3), - boost::bind(&_Mumlib_Private::processAudioPacket, this, _1, _2, _3)) { } + boost::bind(&_Mumlib_Private::processAudioPacket, this, _1, _2, _3)) { + + audio.setOpusEncoderBitrate(configuration.opusEncoderBitrate); + } virtual ~_Mumlib_Private() { if (not externalIoService) { @@ -334,12 +337,21 @@ namespace mumlib { }; - Mumlib::Mumlib(Callback &callback) - : impl(new _Mumlib_Private(callback)) { + Mumlib::Mumlib(Callback &callback) { + MumlibConfiguration conf; + impl = new _Mumlib_Private(callback, conf); } - Mumlib::Mumlib(Callback &callback, io_service &ioService) - : impl(new _Mumlib_Private(callback, ioService)) { } + Mumlib::Mumlib(Callback &callback, io_service &ioService) { + MumlibConfiguration conf; + impl = new _Mumlib_Private(callback, ioService, conf); + } + + Mumlib::Mumlib(Callback &callback, MumlibConfiguration &configuration) + : impl(new _Mumlib_Private(callback, configuration)) { } + + Mumlib::Mumlib(Callback &callback, io_service &ioService, MumlibConfiguration &configuration) + : impl(new _Mumlib_Private(callback, ioService, configuration)) { } Mumlib::~Mumlib() { disconnect(); From 449a2a0a9504bf0466a4d176f94e9d05809001be Mon Sep 17 00:00:00 2001 From: "Hunter N. Morgan" Date: Sun, 22 May 2016 21:19:53 -0500 Subject: [PATCH 25/59] Fix SWAP64 implementation to work on more platforms --- src/CryptState.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CryptState.cpp b/src/CryptState.cpp index 0760374a3527..9c5937a4b6d3 100644 --- a/src/CryptState.cpp +++ b/src/CryptState.cpp @@ -181,7 +181,7 @@ bool mumlib::CryptState::decrypt(const unsigned char *source, unsigned char *dst #define SHIFTBITS 63 typedef uint64_t subblock; -#define SWAP64(x) ({register uint64_t __out, __in = (x); __asm__("bswap %q0" : "=r"(__out) : "0"(__in)); __out;}) +#define SWAP64(x) (__builtin_bswap64(x)) #define SWAPPED(x) SWAP64(x) typedef subblock keyblock[BLOCKSIZE]; From c49e870d4b949166b78017a1a377656d94c4b1fb Mon Sep 17 00:00:00 2001 From: hungrymonkey Date: Sun, 1 Oct 2017 10:41:40 -0700 Subject: [PATCH 26/59] for some reason the shared library version does not seem to build --- modules/mumble/.gitignore | 4 ++++ modules/mumble/SCsub | 12 ++++++++++++ modules/mumble/config.py | 7 +++++++ modules/mumble/mumble.cpp | 30 ++++++++++++++++++++++++++++++ modules/mumble/mumble.h | 23 +++++++++++++++++++++++ modules/mumble/register_types.cpp | 15 +++++++++++++++ modules/mumble/register_types.h | 6 ++++++ 7 files changed, 97 insertions(+) create mode 100644 modules/mumble/.gitignore create mode 100644 modules/mumble/SCsub create mode 100644 modules/mumble/config.py create mode 100644 modules/mumble/mumble.cpp create mode 100644 modules/mumble/mumble.h create mode 100644 modules/mumble/register_types.cpp create mode 100644 modules/mumble/register_types.h diff --git a/modules/mumble/.gitignore b/modules/mumble/.gitignore new file mode 100644 index 000000000000..06833525e1e2 --- /dev/null +++ b/modules/mumble/.gitignore @@ -0,0 +1,4 @@ +*.backup +*.back +*.pyc +*.o diff --git a/modules/mumble/SCsub b/modules/mumble/SCsub new file mode 100644 index 000000000000..9ffc30b09a1b --- /dev/null +++ b/modules/mumble/SCsub @@ -0,0 +1,12 @@ +# SCsub +Import('env') + + +sources = [ + "register_types.cpp", + "mumble.cpp" +] + +module_env = env.Clone() +module_env.add_source_files(env.modules_sources,"*.cpp") +module_env.Append(CXXFLAGS=['-O2', '-std=c++11']) diff --git a/modules/mumble/config.py b/modules/mumble/config.py new file mode 100644 index 000000000000..b39f1d00103b --- /dev/null +++ b/modules/mumble/config.py @@ -0,0 +1,7 @@ +# config.py + +def can_build(platform): + return True + +def configure(env): + pass diff --git a/modules/mumble/mumble.cpp b/modules/mumble/mumble.cpp new file mode 100644 index 000000000000..2a5958ad0d75 --- /dev/null +++ b/modules/mumble/mumble.cpp @@ -0,0 +1,30 @@ +/* mumble.cpp */ + +#include "mumble.h" + +void Mumble::add(int value) { + + count+=value; +} + +void Mumble::reset() { + + count=0; +} + +int Mumble::get_total() const { + + return count; +} + +void Mumble::_bind_methods() { + ClassDB::bind_method(D_METHOD("add", "value"), &Mumble::add); + ClassDB::bind_method(D_METHOD("reset"), &Mumble::reset); + ClassDB::bind_method(D_METHOD("get_total"), &Mumble::get_total); + +} + +Mumble::Mumble() { + count=0; +} + diff --git a/modules/mumble/mumble.h b/modules/mumble/mumble.h new file mode 100644 index 000000000000..f52cb6ae8064 --- /dev/null +++ b/modules/mumble/mumble.h @@ -0,0 +1,23 @@ +/* mumble.h */ +#ifndef MUMBLE_H +#define MUMBLE_H + +#include "reference.h" + +class Mumble : public Reference { + GDCLASS(Mumble,Reference); + + int count; + +protected: + static void _bind_methods(); + +public: + void add(int value); + void reset(); + int get_total() const; + + Mumble(); +}; + +#endif diff --git a/modules/mumble/register_types.cpp b/modules/mumble/register_types.cpp new file mode 100644 index 000000000000..105c04e3d731 --- /dev/null +++ b/modules/mumble/register_types.cpp @@ -0,0 +1,15 @@ +/* register_types.cpp */ + +#include "register_types.h" +#include "class_db.h" +#include "mumble.h" + +void register_mumble_types() { + + ClassDB::register_class(); +} + +void unregister_mumble_types() { + //nothing to do here +} + diff --git a/modules/mumble/register_types.h b/modules/mumble/register_types.h new file mode 100644 index 000000000000..2febdf657abc --- /dev/null +++ b/modules/mumble/register_types.h @@ -0,0 +1,6 @@ +/* register_types.h */ + +void register_mumble_types(); +void unregister_mumble_types(); +/* yes, the word in the middle must be the same as the module folder name */ + From 9ce0c2c3844fad524a36bd0ee2daa20cb6606604 Mon Sep 17 00:00:00 2001 From: hungrymonkey Date: Sun, 1 Oct 2017 11:41:34 -0700 Subject: [PATCH 27/59] added callback skeleton --- modules/mumble/SCsub | 1 + modules/mumble/callback.cpp | 30 ++++++++++++++++++++++++++++++ modules/mumble/callback.h | 23 +++++++++++++++++++++++ modules/mumble/register_types.cpp | 2 ++ 4 files changed, 56 insertions(+) create mode 100644 modules/mumble/callback.cpp create mode 100644 modules/mumble/callback.h diff --git a/modules/mumble/SCsub b/modules/mumble/SCsub index 9ffc30b09a1b..9c227e7f8677 100644 --- a/modules/mumble/SCsub +++ b/modules/mumble/SCsub @@ -5,6 +5,7 @@ Import('env') sources = [ "register_types.cpp", "mumble.cpp" + "callback.cpp" ] module_env = env.Clone() diff --git a/modules/mumble/callback.cpp b/modules/mumble/callback.cpp new file mode 100644 index 000000000000..fa62abb1a5e6 --- /dev/null +++ b/modules/mumble/callback.cpp @@ -0,0 +1,30 @@ +/* callback.cpp */ + +#include "callback.h" + +void Callback::add(int value) { + + count+=value; +} + +void Callback::reset() { + + count=0; +} + +int Callback::get_total() const { + + return count; +} + +void Callback::_bind_methods() { + ClassDB::bind_method(D_METHOD("add", "value"), &Callback::add); + ClassDB::bind_method(D_METHOD("reset"), &Callback::reset); + ClassDB::bind_method(D_METHOD("get_total"), &Callback::get_total); + +} + +Callback::Callback() { + count=0; +} + diff --git a/modules/mumble/callback.h b/modules/mumble/callback.h new file mode 100644 index 000000000000..81b7b4e15afe --- /dev/null +++ b/modules/mumble/callback.h @@ -0,0 +1,23 @@ +/* callback.h */ +#ifndef CALLBACK_H +#define CALLBACK_H + +#include "reference.h" + +class Callback : public Reference { + GDCLASS(Callback,Reference); + + int count; + +protected: + static void _bind_methods(); + +public: + void add(int value); + void reset(); + int get_total() const; + + Callback(); +}; + +#endif diff --git a/modules/mumble/register_types.cpp b/modules/mumble/register_types.cpp index 105c04e3d731..04fa95c99c84 100644 --- a/modules/mumble/register_types.cpp +++ b/modules/mumble/register_types.cpp @@ -3,10 +3,12 @@ #include "register_types.h" #include "class_db.h" #include "mumble.h" +#include "callback.h" void register_mumble_types() { ClassDB::register_class(); + ClassDB::register_class(); } void unregister_mumble_types() { From 6ed35d565cfb4a15768aeefe64cf48ba89abfa71 Mon Sep 17 00:00:00 2001 From: hungrymonkey Date: Sun, 1 Oct 2017 12:00:33 -0700 Subject: [PATCH 28/59] I have to commit before adding git subtree mumlib --- modules/mumble/SCsub | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/modules/mumble/SCsub b/modules/mumble/SCsub index 9c227e7f8677..6e2d42f832cd 100644 --- a/modules/mumble/SCsub +++ b/modules/mumble/SCsub @@ -7,7 +7,23 @@ sources = [ "mumble.cpp" "callback.cpp" ] +thirdparty_dir = "#thirdparty/mumlib/" + +third_party_includes = [ + "include", + "include/mumlib" +] +third_party_sources = [ + "src/Audio.cpp", + "src/Callback.cpp", + "src/CrypState.cpp", + "src/Transport.cpp", + "src/VarInt.cpp", + "src/mumlib.cpp" +] module_env = env.Clone() +module_env.Append(CPPPATH=[ thirdparty_dir + "/" + dir for dir in third_party_includes]) +module_env.add_source_files(env.modules_sources, [ thirdparty_dir + '/' + dir for dir in third_party_sources ]) module_env.add_source_files(env.modules_sources,"*.cpp") module_env.Append(CXXFLAGS=['-O2', '-std=c++11']) From 9a4cb2c38a8fac1069b2a01fbddc1fa9fb0d2f86 Mon Sep 17 00:00:00 2001 From: hungrymonkey Date: Sun, 1 Oct 2017 12:23:14 -0700 Subject: [PATCH 29/59] .pb.h filename is blocking me from building, I have to check google proto docs --- modules/mumble/SCsub | 219 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 213 insertions(+), 6 deletions(-) diff --git a/modules/mumble/SCsub b/modules/mumble/SCsub index 6e2d42f832cd..c40bb1a6a33f 100644 --- a/modules/mumble/SCsub +++ b/modules/mumble/SCsub @@ -2,6 +2,214 @@ Import('env') +mumble_env = env.Clone() +if (env['builtin_opus'] != 'no'): + thirdparty_dir = "#thirdparty/opus/" + + thirdparty_sources = [ + "silk/tables_other.c", + "silk/sum_sqr_shift.c", + "silk/PLC.c", + "silk/dec_API.c", + "silk/decode_pulses.c", + "silk/inner_prod_aligned.c", + "silk/init_encoder.c", + "silk/interpolate.c", + "silk/stereo_encode_pred.c", + "silk/decode_frame.c", + "silk/NLSF_del_dec_quant.c", + "silk/VAD.c", + "silk/resampler_private_AR2.c", + "silk/NLSF_unpack.c", + "silk/resampler_down2.c", + "silk/sort.c", + "silk/resampler_private_IIR_FIR.c", + "silk/resampler_down2_3.c", + "silk/resampler_private_up2_HQ.c", + "silk/tables_gain.c", + "silk/stereo_find_predictor.c", + "silk/stereo_quant_pred.c", + "silk/NLSF_stabilize.c", + "silk/ana_filt_bank_1.c", + "silk/check_control_input.c", + "silk/bwexpander.c", + "silk/A2NLSF.c", + "silk/LPC_inv_pred_gain.c", + "silk/log2lin.c", + "silk/process_NLSFs.c", + "silk/sigm_Q15.c", + "silk/VQ_WMat_EC.c", + "silk/quant_LTP_gains.c", + "silk/resampler_private_down_FIR.c", + "silk/NLSF_decode.c", + "silk/control_codec.c", + "silk/NLSF_VQ_weights_laroia.c", + "silk/decode_pitch.c", + "silk/stereo_decode_pred.c", + "silk/tables_pulses_per_block.c", + "silk/init_decoder.c", + "silk/table_LSF_cos.c", + "silk/decode_core.c", + "silk/code_signs.c", + "silk/enc_API.c", + "silk/tables_LTP.c", + "silk/pitch_est_tables.c", + "silk/biquad_alt.c", + "silk/encode_indices.c", + "silk/tables_NLSF_CB_WB.c", + "silk/debug.c", + "silk/decode_parameters.c", + "silk/tables_pitch_lag.c", + "silk/NLSF2A.c", + "silk/resampler.c", + "silk/decode_indices.c", + "silk/NLSF_VQ.c", + "silk/bwexpander_32.c", + "silk/tables_NLSF_CB_NB_MB.c", + "silk/encode_pulses.c", + "silk/NSQ_del_dec.c", + "silk/control_SNR.c", + "silk/shell_coder.c", + "silk/NLSF_encode.c", + "silk/stereo_MS_to_LR.c", + "silk/stereo_LR_to_MS.c", + "silk/HP_variable_cutoff.c", + "silk/LPC_analysis_filter.c", + "silk/CNG.c", + "silk/decoder_set_fs.c", + "silk/resampler_rom.c", + "silk/control_audio_bandwidth.c", + "silk/lin2log.c", + "silk/LP_variable_cutoff.c", + "silk/NSQ.c", + "silk/gain_quant.c", + "celt/laplace.c", + "celt/vq.c", + "celt/quant_bands.c", + "celt/kiss_fft.c", + "celt/entcode.c", + "celt/entenc.c", + "celt/celt_lpc.c", + "celt/pitch.c", + "celt/rate.c", + "celt/mathops.c", + #"celt/arm/armcpu.c", + #"celt/arm/celt_neon_intr.c", + #"celt/arm/celt_ne10_mdct.c", + #"celt/arm/celt_ne10_fft.c", + #"celt/arm/arm_celt_map.c", + "celt/celt_encoder.c", + "celt/celt.c", + "celt/bands.c", + "celt/cwrs.c", + "celt/entdec.c", + "celt/celt_decoder.c", + "celt/mdct.c", + "celt/modes.c", + "repacketizer.c", + "mlp_data.c", + "opus_multistream.c", + "opusfile.c", + "opus_encoder.c", + "analysis.c", + "mlp.c", + "info.c", + "stream.c", + "opus_decoder.c", + "internal.c", + "wincerts.c", + "opus.c", + "opus_multistream_encoder.c", + "http.c", + "opus_multistream_decoder.c" + ] + + opus_sources_silk = [] + + if("opus_fixed_point" in env and env.opus_fixed_point == "yes"): + mumble_env.Append(CFLAGS=["-DFIXED_POINT"]) + opus_sources_silk = [ + "silk/fixed/schur64_FIX.c", + "silk/fixed/residual_energy16_FIX.c", + "silk/fixed/encode_frame_FIX.c", + "silk/fixed/regularize_correlations_FIX.c", + "silk/fixed/apply_sine_window_FIX.c", + "silk/fixed/solve_LS_FIX.c", + "silk/fixed/schur_FIX.c", + "silk/fixed/pitch_analysis_core_FIX.c", + "silk/fixed/noise_shape_analysis_FIX.c", + "silk/fixed/find_LTP_FIX.c", + "silk/fixed/vector_ops_FIX.c", + "silk/fixed/autocorr_FIX.c", + "silk/fixed/warped_autocorrelation_FIX.c", + "silk/fixed/find_pitch_lags_FIX.c", + "silk/fixed/k2a_Q16_FIX.c", + "silk/fixed/LTP_scale_ctrl_FIX.c", + "silk/fixed/corrMatrix_FIX.c", + "silk/fixed/prefilter_FIX.c", + "silk/fixed/find_LPC_FIX.c", + "silk/fixed/residual_energy_FIX.c", + "silk/fixed/process_gains_FIX.c", + "silk/fixed/LTP_analysis_filter_FIX.c", + "silk/fixed/k2a_FIX.c", + "silk/fixed/burg_modified_FIX.c", + "silk/fixed/find_pred_coefs_FIX.c" + ] + else: + opus_sources_silk = [ + "silk/float/LTP_scale_ctrl_FLP.c", + "silk/float/regularize_correlations_FLP.c", + "silk/float/corrMatrix_FLP.c", + "silk/float/LPC_analysis_filter_FLP.c", + "silk/float/levinsondurbin_FLP.c", + "silk/float/schur_FLP.c", + "silk/float/scale_vector_FLP.c", + "silk/float/apply_sine_window_FLP.c", + "silk/float/pitch_analysis_core_FLP.c", + "silk/float/wrappers_FLP.c", + "silk/float/bwexpander_FLP.c", + "silk/float/warped_autocorrelation_FLP.c", + "silk/float/solve_LS_FLP.c", + "silk/float/find_LPC_FLP.c", + "silk/float/autocorrelation_FLP.c", + "silk/float/find_pred_coefs_FLP.c", + "silk/float/find_pitch_lags_FLP.c", + "silk/float/burg_modified_FLP.c", + "silk/float/find_LTP_FLP.c", + "silk/float/energy_FLP.c", + "silk/float/sort_FLP.c", + "silk/float/LPC_inv_pred_gain_FLP.c", + "silk/float/k2a_FLP.c", + "silk/float/noise_shape_analysis_FLP.c", + "silk/float/inner_product_FLP.c", + "silk/float/process_gains_FLP.c", + "silk/float/encode_frame_FLP.c", + "silk/float/scale_copy_vector_FLP.c", + "silk/float/residual_energy_FLP.c", + "silk/float/LTP_analysis_filter_FLP.c", + "silk/float/prefilter_FLP.c" + ] + + thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources + opus_sources_silk] + + mumble_env.add_source_files(env.modules_sources, thirdparty_sources) + mumble_env.Append(CFLAGS=["-DHAVE_CONFIG_H"]) + + thirdparty_include_paths = [ + "", + "celt", + "opus", + "silk", + "silk/fixed", + "silk/float", + ] + mumble_env.Append(CPPPATH=[thirdparty_dir + "/" + dir for dir in thirdparty_include_paths]) + + # also requires libogg + if (env['builtin_libogg'] != 'no'): + mumble_env.Append(CPPPATH=["#thirdparty/libogg"]) + + sources = [ "register_types.cpp", "mumble.cpp" @@ -16,14 +224,13 @@ third_party_includes = [ third_party_sources = [ "src/Audio.cpp", "src/Callback.cpp", - "src/CrypState.cpp", + "src/CryptState.cpp", "src/Transport.cpp", "src/VarInt.cpp", "src/mumlib.cpp" ] -module_env = env.Clone() -module_env.Append(CPPPATH=[ thirdparty_dir + "/" + dir for dir in third_party_includes]) -module_env.add_source_files(env.modules_sources, [ thirdparty_dir + '/' + dir for dir in third_party_sources ]) -module_env.add_source_files(env.modules_sources,"*.cpp") -module_env.Append(CXXFLAGS=['-O2', '-std=c++11']) +mumble_env.Append(CPPPATH=[ thirdparty_dir + "/" + dir for dir in third_party_includes]) +mumble_env.add_source_files(env.modules_sources, [ thirdparty_dir + '/' + dir for dir in third_party_sources ]) +mumble_env.add_source_files(env.modules_sources,"*.cpp") +mumble_env.Append(CXXFLAGS=['-O2', '-std=c++11']) From 02dc2483859c9ab1386b4c6d03722cc9bd7f11b5 Mon Sep 17 00:00:00 2001 From: hungrymonkey Date: Sun, 1 Oct 2017 12:55:53 -0700 Subject: [PATCH 30/59] the protoc command is really crude but the whole things builds --- modules/mumble/SCsub | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/modules/mumble/SCsub b/modules/mumble/SCsub index c40bb1a6a33f..75852663d4e0 100644 --- a/modules/mumble/SCsub +++ b/modules/mumble/SCsub @@ -1,4 +1,10 @@ # SCsub + +build_mumlib_proto = "pushd ../../thirdparty/mumlib; \ +mkdir build; \ +protoc --proto_path=. --cpp_out=build/ Mumble.proto \ +popd;" + Import('env') @@ -219,7 +225,8 @@ thirdparty_dir = "#thirdparty/mumlib/" third_party_includes = [ "include", - "include/mumlib" + "include/mumlib", + "build" ] third_party_sources = [ "src/Audio.cpp", @@ -227,9 +234,11 @@ third_party_sources = [ "src/CryptState.cpp", "src/Transport.cpp", "src/VarInt.cpp", - "src/mumlib.cpp" + "src/mumlib.cpp", + "build/Mumble.pb.cc" ] - +file = mumble_env.Command('', [], build_mumlib_proto) +mumble_env.AlwaysBuild(file) mumble_env.Append(CPPPATH=[ thirdparty_dir + "/" + dir for dir in third_party_includes]) mumble_env.add_source_files(env.modules_sources, [ thirdparty_dir + '/' + dir for dir in third_party_sources ]) mumble_env.add_source_files(env.modules_sources,"*.cpp") From 09248329b6fc3bc3bc32c7d66119472ea12fd9be Mon Sep 17 00:00:00 2001 From: hungrymonkey Date: Sun, 1 Oct 2017 13:10:27 -0700 Subject: [PATCH 31/59] fix some issues so it can build, I did a really ugly hack and added subprocess call. I should look at scons docs better --- modules/mumble/SCsub | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/modules/mumble/SCsub b/modules/mumble/SCsub index 75852663d4e0..b79b54eceba7 100644 --- a/modules/mumble/SCsub +++ b/modules/mumble/SCsub @@ -1,10 +1,5 @@ # SCsub -build_mumlib_proto = "pushd ../../thirdparty/mumlib; \ -mkdir build; \ -protoc --proto_path=. --cpp_out=build/ Mumble.proto \ -popd;" - Import('env') @@ -237,8 +232,17 @@ third_party_sources = [ "src/mumlib.cpp", "build/Mumble.pb.cc" ] -file = mumble_env.Command('', [], build_mumlib_proto) -mumble_env.AlwaysBuild(file) +build_mumlib_proto = "pushd ../../thirdparty/mumlib; mkdir build;" + \ +"protoc --proto_path=. --cpp_out=build/ Mumble.proto; popd;" + +import subprocess +def subprocess_cmd(command): + process = subprocess.Popen(command,stdout=subprocess.PIPE, shell=True) + proc_stdout = process.communicate()[0].strip() + +## build .pb.h files +subprocess_cmd(build_mumlib_proto) + mumble_env.Append(CPPPATH=[ thirdparty_dir + "/" + dir for dir in third_party_includes]) mumble_env.add_source_files(env.modules_sources, [ thirdparty_dir + '/' + dir for dir in third_party_sources ]) mumble_env.add_source_files(env.modules_sources,"*.cpp") From ef1168773cab0abe174fc78404c318d32f3b7748 Mon Sep 17 00:00:00 2001 From: hungrymonkey Date: Sun, 1 Oct 2017 13:16:47 -0700 Subject: [PATCH 32/59] commit my old callback.h --- modules/mumble/SCsub | 1 + modules/mumble/callback.cpp | 60 ++++++++++++++++++++----------- modules/mumble/callback.h | 40 ++++++++++++++++----- modules/mumble/register_types.cpp | 2 +- modules/mumble/utils.cpp | 23 ++++++++++++ modules/mumble/utils.h | 10 ++++++ 6 files changed, 106 insertions(+), 30 deletions(-) create mode 100644 modules/mumble/utils.cpp create mode 100644 modules/mumble/utils.h diff --git a/modules/mumble/SCsub b/modules/mumble/SCsub index b79b54eceba7..b719dca09cdb 100644 --- a/modules/mumble/SCsub +++ b/modules/mumble/SCsub @@ -215,6 +215,7 @@ sources = [ "register_types.cpp", "mumble.cpp" "callback.cpp" + "utils.cpp" ] thirdparty_dir = "#thirdparty/mumlib/" diff --git a/modules/mumble/callback.cpp b/modules/mumble/callback.cpp index fa62abb1a5e6..7b6ac149b0e9 100644 --- a/modules/mumble/callback.cpp +++ b/modules/mumble/callback.cpp @@ -1,30 +1,50 @@ -/* callback.cpp */ - #include "callback.h" +#include "utils.h" +#include "variant.h" -void Callback::add(int value) { - - count+=value; +SimpleCallback::SimpleCallback(){ } - -void Callback::reset() { - - count=0; +SimpleCallback::~SimpleCallback(){ } -int Callback::get_total() const { - - return count; +void SimpleCallback::audio( int target, + int sessionId, + int sequenceNumber, + int16_t *pcm_data, + uint32_t pcm_data_size){ + int i = 0; } -void Callback::_bind_methods() { - ClassDB::bind_method(D_METHOD("add", "value"), &Callback::add); - ClassDB::bind_method(D_METHOD("reset"), &Callback::reset); - ClassDB::bind_method(D_METHOD("get_total"), &Callback::get_total); -} +void SimpleCallback::textMessage( + uint32_t actor, + std::vector session, + std::vector channel_id, + std::vector tree_id, + std::string message) { + + Variant *s = utils::cpp_vec2garr(session); + Variant *c = utils::cpp_vec2garr(channel_id); + Variant *t = utils::cpp_vec2garr(tree_id); + Variant *a = memnew( Variant(actor) ); + Variant *m = memnew( Variant(String(message.c_str()))); + Variant::CallError err; + const Variant *args[5] = {a, s, c, t, m}; + Variant result = this->text_handler->call_func( args, 5, err ); + memdelete( a); + memdelete( s); + memdelete( c); + memdelete( t); + memdelete( m); -Callback::Callback() { - count=0; } - +void SimpleCallback::_bind_methods(){ + ClassDB::bind_method(D_METHOD("setAudioHandler", "handler"), &SimpleCallback::setAudioHandler); + ClassDB::bind_method(D_METHOD("setTextHandler", "handler"), &SimpleCallback::setTextHandler); +} +void SimpleCallback::setAudioHandler( Object * handler){ + this->audio_handler = (FuncRef *)handler; +} +void SimpleCallback::setTextHandler( Object * handler){ + this->text_handler = (FuncRef *)handler; +} diff --git a/modules/mumble/callback.h b/modules/mumble/callback.h index 81b7b4e15afe..9d0d35ef3e03 100644 --- a/modules/mumble/callback.h +++ b/modules/mumble/callback.h @@ -1,23 +1,45 @@ /* callback.h */ -#ifndef CALLBACK_H -#define CALLBACK_H +#ifndef SimpleCALLBACK_H +#define SimpleCALLBACK_H #include "reference.h" +#include "ustring.h" +#include "func_ref.h" +#include +#include +#include -class Callback : public Reference { - GDCLASS(Callback,Reference); +class SimpleCallback : public mumlib::Callback, public Reference { + GDCLASS(SimpleCallback,Reference); - int count; +private: + FuncRef *audio_handler; + FuncRef *text_handler; protected: +// bool _set(const StringName &p_name, const Variant &p_value); +// bool _get(const StringName &p_name, Variant &r_ret) const; +// void _get_property_list(List *p_list) const; static void _bind_methods(); public: - void add(int value); - void reset(); - int get_total() const; - Callback(); + SimpleCallback(); + ~SimpleCallback(); + virtual void audio(int target, + int sessionId, + int sequenceNumber, + int16_t *pcm_data, + uint32_t pcm_data_size) ; + virtual void textMessage( + uint32_t actor, + std::vector session, + std::vector channel_id, + std::vector tree_id, + std::string message); + void setAudioHandler( Object * handle); + void setTextHandler( Object * handle); + }; #endif diff --git a/modules/mumble/register_types.cpp b/modules/mumble/register_types.cpp index 04fa95c99c84..0df991f8f9fd 100644 --- a/modules/mumble/register_types.cpp +++ b/modules/mumble/register_types.cpp @@ -8,7 +8,7 @@ void register_mumble_types() { ClassDB::register_class(); - ClassDB::register_class(); + ClassDB::register_class(); } void unregister_mumble_types() { diff --git a/modules/mumble/utils.cpp b/modules/mumble/utils.cpp new file mode 100644 index 000000000000..23a95a173491 --- /dev/null +++ b/modules/mumble/utils.cpp @@ -0,0 +1,23 @@ +#include "utils.h" +#include "variant.h" + + + +std::string utils::gstr2cpp_str(String s){ + std::wstring ws(s.c_str()); + std::string str(ws.begin(), ws.end()); + return str; +}; +String utils::cpp_str2gstr(std::string s){ + return String(s.c_str()); +} + +Variant *utils::cpp_vec2garr( const std::vector &v ){ + Array a; + a.resize(v.size()); + for( auto it = v.begin(); it != v.end(); it++){ + a.push_back(Variant( (signed int)*it)); + } + Variant * ret = memnew( Variant(a) ); + return ret; +} diff --git a/modules/mumble/utils.h b/modules/mumble/utils.h new file mode 100644 index 000000000000..cd643aa675c8 --- /dev/null +++ b/modules/mumble/utils.h @@ -0,0 +1,10 @@ +#include "ustring.h" +#include "array.h" +#include +#include + +namespace utils{ + std::string gstr2cpp_str(String s); + String cpp_str2gstr(std::string s); + Variant *cpp_vec2garr( const std::vector &v ); +} From 4bb26553b49d817177a65d26ba0d5d45e7901587 Mon Sep 17 00:00:00 2001 From: hungrymonkey Date: Sun, 1 Oct 2017 14:16:54 -0700 Subject: [PATCH 33/59] cleaning up some code before I start adding other stuff to mumble --- modules/mumble/SCsub | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/modules/mumble/SCsub b/modules/mumble/SCsub index b719dca09cdb..b4f6ac91d70d 100644 --- a/modules/mumble/SCsub +++ b/modules/mumble/SCsub @@ -217,21 +217,28 @@ sources = [ "callback.cpp" "utils.cpp" ] -thirdparty_dir = "#thirdparty/mumlib/" +thirdparty_dir = "#thirdparty" third_party_includes = [ - "include", - "include/mumlib", - "build" + "mumlib/include", + "mumlib/build" ] third_party_sources = [ - "src/Audio.cpp", - "src/Callback.cpp", - "src/CryptState.cpp", - "src/Transport.cpp", - "src/VarInt.cpp", - "src/mumlib.cpp", - "build/Mumble.pb.cc" + "mumlib/src/Audio.cpp", + "mumlib/src/Callback.cpp", + "mumlib/src/CryptState.cpp", + "mumlib/src/Transport.cpp", + "mumlib/src/VarInt.cpp", + "mumlib/src/mumlib.cpp", + "mumlib/build/Mumble.pb.cc" +] +third_party_system_lib = [ + "/usr/lib64/", + "/usr/lib" + +] +third_party_system_include = [ + "/usr/include" ] build_mumlib_proto = "pushd ../../thirdparty/mumlib; mkdir build;" + \ "protoc --proto_path=. --cpp_out=build/ Mumble.proto; popd;" @@ -244,6 +251,10 @@ def subprocess_cmd(command): ## build .pb.h files subprocess_cmd(build_mumlib_proto) +mumble_env.Append(CPPPATH=third_party_system_lib) +mumble_env.Append(CPPPATH=third_party_system_include) +mumble_env.Append(LIBS=['boost_system', 'protobuf', 'log4cpp']) + mumble_env.Append(CPPPATH=[ thirdparty_dir + "/" + dir for dir in third_party_includes]) mumble_env.add_source_files(env.modules_sources, [ thirdparty_dir + '/' + dir for dir in third_party_sources ]) mumble_env.add_source_files(env.modules_sources,"*.cpp") From 85c7594a7146a03f29506bc777126b4d7fbabd06 Mon Sep 17 00:00:00 2001 From: hungrymonkey Date: Sun, 1 Oct 2017 14:51:16 -0700 Subject: [PATCH 34/59] linked boost_system using system lib --- modules/SCsub | 2 +- modules/mumble/SCsub | 9 +++++---- modules/mumble/mumble.h | 5 +++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/modules/SCsub b/modules/SCsub index d1c0cdc05cb2..50560e2fc4a0 100644 --- a/modules/SCsub +++ b/modules/SCsub @@ -20,4 +20,4 @@ for x in env.module_list: lib = env_modules.Library("modules", env.modules_sources) -env.Prepend(LIBS=[lib]) +env.Prepend(LIBS=[lib,'boost_system']) diff --git a/modules/mumble/SCsub b/modules/mumble/SCsub index b4f6ac91d70d..aa835d2711e3 100644 --- a/modules/mumble/SCsub +++ b/modules/mumble/SCsub @@ -233,12 +233,13 @@ third_party_sources = [ "mumlib/build/Mumble.pb.cc" ] third_party_system_lib = [ - "/usr/lib64/", + "/usr/lib64", "/usr/lib" ] third_party_system_include = [ - "/usr/include" + "/usr/include", + "/usr/include/boost" ] build_mumlib_proto = "pushd ../../thirdparty/mumlib; mkdir build;" + \ "protoc --proto_path=. --cpp_out=build/ Mumble.proto; popd;" @@ -251,9 +252,9 @@ def subprocess_cmd(command): ## build .pb.h files subprocess_cmd(build_mumlib_proto) -mumble_env.Append(CPPPATH=third_party_system_lib) +mumble_env.Append(LIBPATH=third_party_system_lib) mumble_env.Append(CPPPATH=third_party_system_include) -mumble_env.Append(LIBS=['boost_system', 'protobuf', 'log4cpp']) +mumble_env.Append(LIBS=['protobuf', 'log4cpp']) mumble_env.Append(CPPPATH=[ thirdparty_dir + "/" + dir for dir in third_party_includes]) mumble_env.add_source_files(env.modules_sources, [ thirdparty_dir + '/' + dir for dir in third_party_sources ]) diff --git a/modules/mumble/mumble.h b/modules/mumble/mumble.h index f52cb6ae8064..42927f981e57 100644 --- a/modules/mumble/mumble.h +++ b/modules/mumble/mumble.h @@ -3,11 +3,12 @@ #define MUMBLE_H #include "reference.h" +#include -class Mumble : public Reference { +class Mumble : public Reference { GDCLASS(Mumble,Reference); - int count; + mumlib::Mumlib *mum; protected: static void _bind_methods(); From 250b32a0f4005667291a187c6ac861b25d62bae8 Mon Sep 17 00:00:00 2001 From: hungrymonkey Date: Sun, 1 Oct 2017 15:03:02 -0700 Subject: [PATCH 35/59] seems to compile, now. I have to work on callback setter --- modules/SCsub | 2 +- modules/mumble/SCsub | 7 +++---- modules/mumble/mumble.cpp | 39 +++++++++++++++++++++++++++------------ modules/mumble/mumble.h | 4 ++++ 4 files changed, 35 insertions(+), 17 deletions(-) diff --git a/modules/SCsub b/modules/SCsub index 50560e2fc4a0..5523451351f4 100644 --- a/modules/SCsub +++ b/modules/SCsub @@ -20,4 +20,4 @@ for x in env.module_list: lib = env_modules.Library("modules", env.modules_sources) -env.Prepend(LIBS=[lib,'boost_system']) +env.Prepend(LIBS=[lib,'boost_system', 'protobuf', 'log4cpp']) diff --git a/modules/mumble/SCsub b/modules/mumble/SCsub index aa835d2711e3..14b9aaca92a3 100644 --- a/modules/mumble/SCsub +++ b/modules/mumble/SCsub @@ -235,7 +235,6 @@ third_party_sources = [ third_party_system_lib = [ "/usr/lib64", "/usr/lib" - ] third_party_system_include = [ "/usr/include", @@ -252,9 +251,9 @@ def subprocess_cmd(command): ## build .pb.h files subprocess_cmd(build_mumlib_proto) -mumble_env.Append(LIBPATH=third_party_system_lib) -mumble_env.Append(CPPPATH=third_party_system_include) -mumble_env.Append(LIBS=['protobuf', 'log4cpp']) +#mumble_env.Append(LIBPATH=third_party_system_lib) +#mumble_env.Append(CPPPATH=third_party_system_include) +#mumble_env.Append(LIBS=['protobuf', 'log4cpp']) mumble_env.Append(CPPPATH=[ thirdparty_dir + "/" + dir for dir in third_party_includes]) mumble_env.add_source_files(env.modules_sources, [ thirdparty_dir + '/' + dir for dir in third_party_sources ]) diff --git a/modules/mumble/mumble.cpp b/modules/mumble/mumble.cpp index 2a5958ad0d75..0de939a7adf5 100644 --- a/modules/mumble/mumble.cpp +++ b/modules/mumble/mumble.cpp @@ -1,30 +1,45 @@ /* mumble.cpp */ #include "mumble.h" +#include "utils.h" -void Mumble::add(int value) { - count+=value; +void Mumble::_bind_methods() { + ClassDB::bind_method(D_METHOD("add", "value"), &Mumble::add); + ClassDB::bind_method(D_METHOD("reset"), &Mumble::reset); + ClassDB::bind_method(D_METHOD("get_total"), &Mumble::get_total); + + ClassDB::bind_method(D_METHOD("connect", "host", "port", "user", "password"), &Mumble::connect); + ClassDB::bind_method(D_METHOD("setCallback", "callback"), &Mumble::setCallback); +} +void Mumble::connect(String host, int port, String user, String password){ + std::string h = utils::gstr2cpp_str(host); + std::string u = utils::gstr2cpp_str(user); + std::string p = utils::gstr2cpp_str(password); + this->mum->connect(h, port, u, p); +} +void Mumble::setCallback(Object * callback){ +// SimpleCallback *cb = callback->cast_to(); +// mum = new mumlib::Mumlib(*cb); } -void Mumble::reset() { +Mumble::Mumble() { count=0; } -int Mumble::get_total() const { +void Mumble::add(int value) { - return count; + count+=value; } -void Mumble::_bind_methods() { - ClassDB::bind_method(D_METHOD("add", "value"), &Mumble::add); - ClassDB::bind_method(D_METHOD("reset"), &Mumble::reset); - ClassDB::bind_method(D_METHOD("get_total"), &Mumble::get_total); - -} +void Mumble::reset() { -Mumble::Mumble() { count=0; } + +int Mumble::get_total() const { + + return count; +} diff --git a/modules/mumble/mumble.h b/modules/mumble/mumble.h index 42927f981e57..b7a7c3ce3fcf 100644 --- a/modules/mumble/mumble.h +++ b/modules/mumble/mumble.h @@ -8,6 +8,8 @@ class Mumble : public Reference { GDCLASS(Mumble,Reference); int count; +private: + mumlib::MumlibConfiguration conf; mumlib::Mumlib *mum; protected: @@ -17,6 +19,8 @@ class Mumble : public Reference { void add(int value); void reset(); int get_total() const; + void connect(String host, int port, String user, String password); + void setCallback( Object * o ); Mumble(); }; From b7a8a224435f64b3fc821ad362a4991b59ecc1f5 Mon Sep 17 00:00:00 2001 From: hungrymonkey Date: Sun, 1 Oct 2017 15:26:59 -0700 Subject: [PATCH 36/59] i can might test, texting soon. woooooooooo --- modules/mumble/mumble.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/mumble/mumble.cpp b/modules/mumble/mumble.cpp index 0de939a7adf5..67f0d12bb793 100644 --- a/modules/mumble/mumble.cpp +++ b/modules/mumble/mumble.cpp @@ -1,6 +1,7 @@ /* mumble.cpp */ #include "mumble.h" +#include "callback.h" #include "utils.h" @@ -19,8 +20,8 @@ void Mumble::connect(String host, int port, String user, String password){ this->mum->connect(h, port, u, p); } void Mumble::setCallback(Object * callback){ -// SimpleCallback *cb = callback->cast_to(); -// mum = new mumlib::Mumlib(*cb); + SimpleCallback *cb = Object::cast_to(callback); + mum = new mumlib::Mumlib(*cb); } From 54dc285df3aa355077d795f9015883bedef98faa Mon Sep 17 00:00:00 2001 From: hungrymonkey Date: Sun, 1 Oct 2017 15:55:31 -0700 Subject: [PATCH 37/59] code compiles, I now have to test it in godot --- modules/mumble/mumble.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/modules/mumble/mumble.cpp b/modules/mumble/mumble.cpp index 67f0d12bb793..f43a9035fbc7 100644 --- a/modules/mumble/mumble.cpp +++ b/modules/mumble/mumble.cpp @@ -3,6 +3,11 @@ #include "mumble.h" #include "callback.h" #include "utils.h" +#include "os/thread.h" +#include "print_string.h" +#include +#include +#include "scene/main/timer.h" void Mumble::_bind_methods() { @@ -17,7 +22,20 @@ void Mumble::connect(String host, int port, String user, String password){ std::string h = utils::gstr2cpp_str(host); std::string u = utils::gstr2cpp_str(user); std::string p = utils::gstr2cpp_str(password); - this->mum->connect(h, port, u, p); + while(true){ + try{ + this->mum->connect(h, port, u, p); + this->mum->run(); + }catch (mumlib::TransportException &exp) { + print_line( "Mumble: error " + utils::cpp_str2gstr(exp.what())); + print_line( "Mumble: attempting to reconnect in 5s. "); + Timer * sleep = memnew(Timer); + sleep -> set_wait_time(5.0); + sleep -> start(); + memdelete(sleep); + + } + } } void Mumble::setCallback(Object * callback){ SimpleCallback *cb = Object::cast_to(callback); From 6a583327bc72d344f788c707e6cda9aa5a61478e Mon Sep 17 00:00:00 2001 From: hungrymonkey Date: Sun, 1 Oct 2017 17:01:46 -0700 Subject: [PATCH 38/59] it connect but it crash when trying to recieve a message --- modules/mumble/mumble.cpp | 4 ++-- modules/mumble/mumble.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/mumble/mumble.cpp b/modules/mumble/mumble.cpp index f43a9035fbc7..a0006253385b 100644 --- a/modules/mumble/mumble.cpp +++ b/modules/mumble/mumble.cpp @@ -15,10 +15,10 @@ void Mumble::_bind_methods() { ClassDB::bind_method(D_METHOD("reset"), &Mumble::reset); ClassDB::bind_method(D_METHOD("get_total"), &Mumble::get_total); - ClassDB::bind_method(D_METHOD("connect", "host", "port", "user", "password"), &Mumble::connect); + ClassDB::bind_method(D_METHOD("engage", "host", "port", "user", "password"), &Mumble::engage); ClassDB::bind_method(D_METHOD("setCallback", "callback"), &Mumble::setCallback); } -void Mumble::connect(String host, int port, String user, String password){ +void Mumble::engage(String host, int port, String user, String password) { std::string h = utils::gstr2cpp_str(host); std::string u = utils::gstr2cpp_str(user); std::string p = utils::gstr2cpp_str(password); diff --git a/modules/mumble/mumble.h b/modules/mumble/mumble.h index b7a7c3ce3fcf..679eaa231e8b 100644 --- a/modules/mumble/mumble.h +++ b/modules/mumble/mumble.h @@ -19,7 +19,7 @@ class Mumble : public Reference { void add(int value); void reset(); int get_total() const; - void connect(String host, int port, String user, String password); + void engage(String host, int port, String user, String password); void setCallback( Object * o ); Mumble(); From 1b4dc6b1940f5d3e64c02b0f4d8b6db5ddf5480b Mon Sep 17 00:00:00 2001 From: hungrymonkey Date: Sun, 1 Oct 2017 21:36:05 -0700 Subject: [PATCH 39/59] added audio data callback. i dont know if it work but I have to fix that other bug before i can test this callback --- modules/mumble/callback.cpp | 25 +++++++++++++++++++++++-- modules/mumble/callback.h | 15 +++++++++++++-- modules/mumble/mumble.cpp | 3 ++- modules/mumble/utils.cpp | 12 ++++++++++++ modules/mumble/utils.h | 1 + 5 files changed, 51 insertions(+), 5 deletions(-) diff --git a/modules/mumble/callback.cpp b/modules/mumble/callback.cpp index 7b6ac149b0e9..af43e88c1d47 100644 --- a/modules/mumble/callback.cpp +++ b/modules/mumble/callback.cpp @@ -1,6 +1,7 @@ #include "callback.h" #include "utils.h" #include "variant.h" +#include "print_string.h" SimpleCallback::SimpleCallback(){ } @@ -11,8 +12,19 @@ void SimpleCallback::audio( int target, int sessionId, int sequenceNumber, int16_t *pcm_data, - uint32_t pcm_data_size){ - int i = 0; + uint32_t pcm_data_size){ + + Variant *tar = memnew( Variant(target) ); + Variant *sid = memnew( Variant(sessionId) ); + Variant *snum = memnew( Variant(sequenceNumber) ); + Variant *pcm = utils::short2byte(pcm_data, pcm_data_size); + Variant::CallError err; + const Variant *args[4] = {tar, sid, snum, pcm}; + Variant result = audio_handler->call_func( args, 4, err); + memdelete( tar); + memdelete( sid); + memdelete( snum); + memdelete( pcm); } @@ -38,6 +50,15 @@ void SimpleCallback::textMessage( memdelete( m); } +void SimpleCallback::version( + uint16_t major, + uint8_t minor, + uint8_t patch, + std::string release, + std::string os, + std::string os_version){ + print_line("processing os: " + String(os.c_str()) ); +} void SimpleCallback::_bind_methods(){ ClassDB::bind_method(D_METHOD("setAudioHandler", "handler"), &SimpleCallback::setAudioHandler); ClassDB::bind_method(D_METHOD("setTextHandler", "handler"), &SimpleCallback::setTextHandler); diff --git a/modules/mumble/callback.h b/modules/mumble/callback.h index 9d0d35ef3e03..67a77f17295c 100644 --- a/modules/mumble/callback.h +++ b/modules/mumble/callback.h @@ -26,19 +26,30 @@ class SimpleCallback : public mumlib::Callback, public Reference { SimpleCallback(); ~SimpleCallback(); + + void setAudioHandler( Object * handle); + void setTextHandler( Object * handle); + virtual void audio(int target, int sessionId, int sequenceNumber, int16_t *pcm_data, uint32_t pcm_data_size) ; + virtual void textMessage( uint32_t actor, std::vector session, std::vector channel_id, std::vector tree_id, std::string message); - void setAudioHandler( Object * handle); - void setTextHandler( Object * handle); + + virtual void version( + uint16_t major, + uint8_t minor, + uint8_t patch, + std::string release, + std::string os, + std::string os_version); }; diff --git a/modules/mumble/mumble.cpp b/modules/mumble/mumble.cpp index a0006253385b..ce8ae9ee2c52 100644 --- a/modules/mumble/mumble.cpp +++ b/modules/mumble/mumble.cpp @@ -25,6 +25,7 @@ void Mumble::engage(String host, int port, String user, String password) { while(true){ try{ this->mum->connect(h, port, u, p); + print_line( "Mumble: connecting to " + host ); this->mum->run(); }catch (mumlib::TransportException &exp) { print_line( "Mumble: error " + utils::cpp_str2gstr(exp.what())); @@ -39,7 +40,7 @@ void Mumble::engage(String host, int port, String user, String password) { } void Mumble::setCallback(Object * callback){ SimpleCallback *cb = Object::cast_to(callback); - mum = new mumlib::Mumlib(*cb); + mum = new mumlib::Mumlib(*cb,conf); } diff --git a/modules/mumble/utils.cpp b/modules/mumble/utils.cpp index 23a95a173491..c73b4d8b3191 100644 --- a/modules/mumble/utils.cpp +++ b/modules/mumble/utils.cpp @@ -21,3 +21,15 @@ Variant *utils::cpp_vec2garr( const std::vector &v ){ Variant * ret = memnew( Variant(a) ); return ret; } +Variant *utils::short2byte( const int16_t * pcm_data, uint32_t size ){ + PoolByteArray d; + d.resize(size * 2); + for( int i=0; i > size; i++){ + d.push_back( pcm_data[i] & 0x00FF ); + d.push_back( pcm_data[i+1] & 0xFF00 >> 8); + } + Variant * ret = memnew( Variant(d) ); + return ret; + +} + diff --git a/modules/mumble/utils.h b/modules/mumble/utils.h index cd643aa675c8..794798055a3f 100644 --- a/modules/mumble/utils.h +++ b/modules/mumble/utils.h @@ -7,4 +7,5 @@ namespace utils{ std::string gstr2cpp_str(String s); String cpp_str2gstr(std::string s); Variant *cpp_vec2garr( const std::vector &v ); + Variant *short2byte( const int16_t * pcm_data, uint32_t size); } From 473002ba1dc1b22572a2ea140253518bd057f185 Mon Sep 17 00:00:00 2001 From: hungrymonkey Date: Sun, 1 Oct 2017 21:38:26 -0700 Subject: [PATCH 40/59] fix a small logical error with converting short to byte --- modules/mumble/utils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mumble/utils.cpp b/modules/mumble/utils.cpp index c73b4d8b3191..e91820af287a 100644 --- a/modules/mumble/utils.cpp +++ b/modules/mumble/utils.cpp @@ -26,7 +26,7 @@ Variant *utils::short2byte( const int16_t * pcm_data, uint32_t size ){ d.resize(size * 2); for( int i=0; i > size; i++){ d.push_back( pcm_data[i] & 0x00FF ); - d.push_back( pcm_data[i+1] & 0xFF00 >> 8); + d.push_back( pcm_data[i] & 0xFF00 >> 8); } Variant * ret = memnew( Variant(d) ); return ret; From e6f1948b47d676dee1f76d960da4107fc2eb845a Mon Sep 17 00:00:00 2001 From: hungrymonkey Date: Mon, 2 Oct 2017 13:28:30 -0700 Subject: [PATCH 41/59] Distros such as fedora have bash as default popd is a shell builtin. Change the shell to bash to be compatible with debian base distros which link sh to dash --- modules/mumble/SCsub | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mumble/SCsub b/modules/mumble/SCsub index 14b9aaca92a3..120ea9c57307 100644 --- a/modules/mumble/SCsub +++ b/modules/mumble/SCsub @@ -245,7 +245,7 @@ build_mumlib_proto = "pushd ../../thirdparty/mumlib; mkdir build;" + \ import subprocess def subprocess_cmd(command): - process = subprocess.Popen(command,stdout=subprocess.PIPE, shell=True) + process = subprocess.Popen(command,stdout=subprocess.PIPE, shell=True, executable='/bin/bash') proc_stdout = process.communicate()[0].strip() ## build .pb.h files From 4f80b9657613eece13f6064eb8d96764ecbeeaaf Mon Sep 17 00:00:00 2001 From: hungrymonkey Date: Mon, 2 Oct 2017 13:31:31 -0700 Subject: [PATCH 42/59] added packages to build this repo --- pkgs_install | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 pkgs_install diff --git a/pkgs_install b/pkgs_install new file mode 100644 index 000000000000..223a8b63d52b --- /dev/null +++ b/pkgs_install @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +PKGS="git" + +GODOT_PKGS="build-essential scons pkg-config libx11-dev libxcursor-dev libxinerama-dev \ + libgl1-mesa-dev libglu-dev libasound2-dev libpulse-dev libfreetype6-dev libssl-dev libudev-dev \ + libxrandr-dev" + +MUMBLE_PKGS="liblog4cpp5-dev libboost-dev libprotobuf-dev protobuf-compiler" + +apt-get install -y $PKGS $GODOT_PKGS $MUMBLE_PKGS From 546cf33c322a120aecf9cf271e877d905fc2ec83 Mon Sep 17 00:00:00 2001 From: hungrymonkey Date: Mon, 2 Oct 2017 13:37:28 -0700 Subject: [PATCH 43/59] forgot to add boost_system --- pkgs_install | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs_install b/pkgs_install index 223a8b63d52b..ecc00217600a 100644 --- a/pkgs_install +++ b/pkgs_install @@ -6,6 +6,6 @@ GODOT_PKGS="build-essential scons pkg-config libx11-dev libxcursor-dev libxinera libgl1-mesa-dev libglu-dev libasound2-dev libpulse-dev libfreetype6-dev libssl-dev libudev-dev \ libxrandr-dev" -MUMBLE_PKGS="liblog4cpp5-dev libboost-dev libprotobuf-dev protobuf-compiler" +MUMBLE_PKGS="liblog4cpp5-dev libboost-dev libprotobuf-dev protobuf-compiler libboost-system-dev" apt-get install -y $PKGS $GODOT_PKGS $MUMBLE_PKGS From 9d1a30f848e5652cfff5cda3e5e3eeaae9d184d2 Mon Sep 17 00:00:00 2001 From: hungrymonkey Date: Mon, 2 Oct 2017 18:48:28 -0700 Subject: [PATCH 44/59] i am cleaning up code and added a nullptr check to make sure it does not crash --- modules/mumble/callback.cpp | 35 ++++++++++++++++++----------------- modules/mumble/callback.h | 4 ++-- modules/mumble/mumble.cpp | 28 ++++++++++++++-------------- modules/mumble/mumble.h | 4 ++-- 4 files changed, 36 insertions(+), 35 deletions(-) diff --git a/modules/mumble/callback.cpp b/modules/mumble/callback.cpp index af43e88c1d47..0e1f16e4ac47 100644 --- a/modules/mumble/callback.cpp +++ b/modules/mumble/callback.cpp @@ -20,7 +20,7 @@ void SimpleCallback::audio( int target, Variant *pcm = utils::short2byte(pcm_data, pcm_data_size); Variant::CallError err; const Variant *args[4] = {tar, sid, snum, pcm}; - Variant result = audio_handler->call_func( args, 4, err); + Variant result = _audio_handler->call_func( args, 4, err); memdelete( tar); memdelete( sid); memdelete( snum); @@ -34,20 +34,21 @@ void SimpleCallback::textMessage( std::vector channel_id, std::vector tree_id, std::string message) { - - Variant *s = utils::cpp_vec2garr(session); - Variant *c = utils::cpp_vec2garr(channel_id); - Variant *t = utils::cpp_vec2garr(tree_id); - Variant *a = memnew( Variant(actor) ); - Variant *m = memnew( Variant(String(message.c_str()))); - Variant::CallError err; - const Variant *args[5] = {a, s, c, t, m}; - Variant result = this->text_handler->call_func( args, 5, err ); - memdelete( a); - memdelete( s); - memdelete( c); - memdelete( t); - memdelete( m); + if(this->_text_handler != NULL){ + Variant *s = utils::cpp_vec2garr(session); + Variant *c = utils::cpp_vec2garr(channel_id); + Variant *t = utils::cpp_vec2garr(tree_id); + Variant *a = memnew( Variant(actor) ); + Variant *m = memnew( Variant(String(message.c_str()))); + Variant::CallError err; + const Variant *args[5] = {a, s, c, t, m}; + Variant result = this->_text_handler->call_func( args, 5, err ); + memdelete( a); + memdelete( s); + memdelete( c); + memdelete( t); + memdelete( m); + } } void SimpleCallback::version( @@ -64,8 +65,8 @@ void SimpleCallback::_bind_methods(){ ClassDB::bind_method(D_METHOD("setTextHandler", "handler"), &SimpleCallback::setTextHandler); } void SimpleCallback::setAudioHandler( Object * handler){ - this->audio_handler = (FuncRef *)handler; + this->_audio_handler = (FuncRef *)handler; } void SimpleCallback::setTextHandler( Object * handler){ - this->text_handler = (FuncRef *)handler; + this->_text_handler = (FuncRef *)handler; } diff --git a/modules/mumble/callback.h b/modules/mumble/callback.h index 67a77f17295c..ad66561c70c4 100644 --- a/modules/mumble/callback.h +++ b/modules/mumble/callback.h @@ -13,8 +13,8 @@ class SimpleCallback : public mumlib::Callback, public Reference { GDCLASS(SimpleCallback,Reference); private: - FuncRef *audio_handler; - FuncRef *text_handler; + FuncRef *_audio_handler; + FuncRef *_text_handler; protected: // bool _set(const StringName &p_name, const Variant &p_value); diff --git a/modules/mumble/mumble.cpp b/modules/mumble/mumble.cpp index ce8ae9ee2c52..693773877d94 100644 --- a/modules/mumble/mumble.cpp +++ b/modules/mumble/mumble.cpp @@ -23,24 +23,24 @@ void Mumble::engage(String host, int port, String user, String password) { std::string u = utils::gstr2cpp_str(user); std::string p = utils::gstr2cpp_str(password); while(true){ - try{ - this->mum->connect(h, port, u, p); - print_line( "Mumble: connecting to " + host ); - this->mum->run(); - }catch (mumlib::TransportException &exp) { - print_line( "Mumble: error " + utils::cpp_str2gstr(exp.what())); - print_line( "Mumble: attempting to reconnect in 5s. "); - Timer * sleep = memnew(Timer); - sleep -> set_wait_time(5.0); - sleep -> start(); - memdelete(sleep); - - } + try{ + this->_mum->connect(h, port, u, p); + print_line( "Mumble: connecting to " + host ); + this->_mum->run(); + }catch (mumlib::TransportException &exp) { + print_line( "Mumble: error " + utils::cpp_str2gstr(exp.what())); + print_line( "Mumble: attempting to reconnect in 5s. "); + Timer * sleep = memnew(Timer); + sleep -> set_wait_time(5.0); + sleep -> start(); + memdelete(sleep); + + } } } void Mumble::setCallback(Object * callback){ SimpleCallback *cb = Object::cast_to(callback); - mum = new mumlib::Mumlib(*cb,conf); + _mum = new mumlib::Mumlib(*cb); } diff --git a/modules/mumble/mumble.h b/modules/mumble/mumble.h index 679eaa231e8b..a5af2766bf19 100644 --- a/modules/mumble/mumble.h +++ b/modules/mumble/mumble.h @@ -9,8 +9,8 @@ class Mumble : public Reference { GDCLASS(Mumble,Reference); int count; private: - mumlib::MumlibConfiguration conf; - mumlib::Mumlib *mum; + mumlib::MumlibConfiguration _conf; + mumlib::Mumlib *_mum; protected: static void _bind_methods(); From ab457fa074e74e9328e80ee19072b4b5d5f3315f Mon Sep 17 00:00:00 2001 From: hungrymonkey Date: Mon, 2 Oct 2017 20:16:26 -0700 Subject: [PATCH 45/59] i have to debug the callback part where i create my own function --- modules/mumble/callback.cpp | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/modules/mumble/callback.cpp b/modules/mumble/callback.cpp index 0e1f16e4ac47..0b23d9fcb6fe 100644 --- a/modules/mumble/callback.cpp +++ b/modules/mumble/callback.cpp @@ -13,18 +13,19 @@ void SimpleCallback::audio( int target, int sequenceNumber, int16_t *pcm_data, uint32_t pcm_data_size){ - - Variant *tar = memnew( Variant(target) ); - Variant *sid = memnew( Variant(sessionId) ); - Variant *snum = memnew( Variant(sequenceNumber) ); - Variant *pcm = utils::short2byte(pcm_data, pcm_data_size); - Variant::CallError err; - const Variant *args[4] = {tar, sid, snum, pcm}; - Variant result = _audio_handler->call_func( args, 4, err); - memdelete( tar); - memdelete( sid); - memdelete( snum); - memdelete( pcm); + if(_audio_handler != NULL){ + Variant *tar = memnew( Variant(target) ); + Variant *sid = memnew( Variant(sessionId) ); + Variant *snum = memnew( Variant(sequenceNumber) ); + Variant *pcm = utils::short2byte(pcm_data, pcm_data_size); + Variant::CallError err; + const Variant *args[4] = {tar, sid, snum, pcm}; + Variant result = _audio_handler->call_func( args, 4, err); + memdelete( tar); + memdelete( sid); + memdelete( snum); + memdelete( pcm); + } } @@ -35,11 +36,12 @@ void SimpleCallback::textMessage( std::vector tree_id, std::string message) { if(this->_text_handler != NULL){ + print_line("internal message: " + String(message.c_str()) ); Variant *s = utils::cpp_vec2garr(session); Variant *c = utils::cpp_vec2garr(channel_id); Variant *t = utils::cpp_vec2garr(tree_id); Variant *a = memnew( Variant(actor) ); - Variant *m = memnew( Variant(String(message.c_str()))); + Variant *m = memnew( Variant()); Variant::CallError err; const Variant *args[5] = {a, s, c, t, m}; Variant result = this->_text_handler->call_func( args, 5, err ); From 1a8a8d3378c998e5acdd0cd1a89cac0cbe19699f Mon Sep 17 00:00:00 2001 From: hungrymonkey Date: Mon, 2 Oct 2017 20:21:45 -0700 Subject: [PATCH 46/59] i have to figure out how to use funcref properly --- modules/mumble/callback.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mumble/callback.cpp b/modules/mumble/callback.cpp index 0b23d9fcb6fe..5f232bb2acc0 100644 --- a/modules/mumble/callback.cpp +++ b/modules/mumble/callback.cpp @@ -41,7 +41,7 @@ void SimpleCallback::textMessage( Variant *c = utils::cpp_vec2garr(channel_id); Variant *t = utils::cpp_vec2garr(tree_id); Variant *a = memnew( Variant(actor) ); - Variant *m = memnew( Variant()); + Variant *m = memnew( Variant(String(message.c_str()))); Variant::CallError err; const Variant *args[5] = {a, s, c, t, m}; Variant result = this->_text_handler->call_func( args, 5, err ); From 880001fd44dc095309f6d5bdf5b23adb82f88bf8 Mon Sep 17 00:00:00 2001 From: hungrymonkey Date: Tue, 3 Oct 2017 08:04:15 -0700 Subject: [PATCH 47/59] added some stuff that does nto work. WOrking on ref --- modules/mumble/callback.cpp | 4 ++-- modules/mumble/mumble.cpp | 4 ++++ modules/mumble/mumble.h | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/modules/mumble/callback.cpp b/modules/mumble/callback.cpp index 5f232bb2acc0..8eb431c124cc 100644 --- a/modules/mumble/callback.cpp +++ b/modules/mumble/callback.cpp @@ -67,8 +67,8 @@ void SimpleCallback::_bind_methods(){ ClassDB::bind_method(D_METHOD("setTextHandler", "handler"), &SimpleCallback::setTextHandler); } void SimpleCallback::setAudioHandler( Object * handler){ - this->_audio_handler = (FuncRef *)handler; + this->_audio_handler = Object::cast_to(handler); } void SimpleCallback::setTextHandler( Object * handler){ - this->_text_handler = (FuncRef *)handler; + this->_text_handler = Object::cast_to(handler); } diff --git a/modules/mumble/mumble.cpp b/modules/mumble/mumble.cpp index 693773877d94..bd8b47333d55 100644 --- a/modules/mumble/mumble.cpp +++ b/modules/mumble/mumble.cpp @@ -17,6 +17,7 @@ void Mumble::_bind_methods() { ClassDB::bind_method(D_METHOD("engage", "host", "port", "user", "password"), &Mumble::engage); ClassDB::bind_method(D_METHOD("setCallback", "callback"), &Mumble::setCallback); + ClassDB::bind_method(D_METHOD("sendText", "text"), &Mumble::sendText); } void Mumble::engage(String host, int port, String user, String password) { std::string h = utils::gstr2cpp_str(host); @@ -42,6 +43,9 @@ void Mumble::setCallback(Object * callback){ SimpleCallback *cb = Object::cast_to(callback); _mum = new mumlib::Mumlib(*cb); } +void Mumble::sendText(String text){ + _mum -> sendTextMessage( utils::gstr2cpp_str(text) ); +} Mumble::Mumble() { diff --git a/modules/mumble/mumble.h b/modules/mumble/mumble.h index a5af2766bf19..cf9061005641 100644 --- a/modules/mumble/mumble.h +++ b/modules/mumble/mumble.h @@ -20,8 +20,8 @@ class Mumble : public Reference { void reset(); int get_total() const; void engage(String host, int port, String user, String password); + void sendText(String s); void setCallback( Object * o ); - Mumble(); }; From 3f42aa7979ee487095adb2f2a9810702bd18c38b Mon Sep 17 00:00:00 2001 From: hungrymonkey Date: Tue, 3 Oct 2017 14:38:27 -0700 Subject: [PATCH 48/59] still crashes --- modules/mumble/callback.cpp | 29 +++++++++++------------------ modules/mumble/utils.cpp | 14 +++++++++++--- modules/mumble/utils.h | 1 + 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/modules/mumble/callback.cpp b/modules/mumble/callback.cpp index 8eb431c124cc..17b4b0ae31d8 100644 --- a/modules/mumble/callback.cpp +++ b/modules/mumble/callback.cpp @@ -14,16 +14,13 @@ void SimpleCallback::audio( int target, int16_t *pcm_data, uint32_t pcm_data_size){ if(_audio_handler != NULL){ - Variant *tar = memnew( Variant(target) ); - Variant *sid = memnew( Variant(sessionId) ); - Variant *snum = memnew( Variant(sequenceNumber) ); + Variant tar = memnew( Variant(target) ); + Variant sid = memnew( Variant(sessionId) ); + Variant snum = memnew( Variant(sequenceNumber) ); Variant *pcm = utils::short2byte(pcm_data, pcm_data_size); Variant::CallError err; - const Variant *args[4] = {tar, sid, snum, pcm}; + const Variant *args[4] = {&tar, &sid, &snum, pcm}; Variant result = _audio_handler->call_func( args, 4, err); - memdelete( tar); - memdelete( sid); - memdelete( snum); memdelete( pcm); } } @@ -37,19 +34,15 @@ void SimpleCallback::textMessage( std::string message) { if(this->_text_handler != NULL){ print_line("internal message: " + String(message.c_str()) ); - Variant *s = utils::cpp_vec2garr(session); - Variant *c = utils::cpp_vec2garr(channel_id); - Variant *t = utils::cpp_vec2garr(tree_id); - Variant *a = memnew( Variant(actor) ); - Variant *m = memnew( Variant(String(message.c_str()))); + print_line( session.size() + ":" +channel_id.size() ); + Variant s = utils::cpp_uint32vec2Variant(session); + Variant c = utils::cpp_uint32vec2Variant(channel_id); + Variant t = utils::cpp_uint32vec2Variant(tree_id); + Variant a = Variant(actor); + Variant m = Variant(String(message.c_str())); Variant::CallError err; - const Variant *args[5] = {a, s, c, t, m}; + const Variant *args[5] = {&a, &s, &c, &t, &m}; Variant result = this->_text_handler->call_func( args, 5, err ); - memdelete( a); - memdelete( s); - memdelete( c); - memdelete( t); - memdelete( m); } } diff --git a/modules/mumble/utils.cpp b/modules/mumble/utils.cpp index e91820af287a..0401848a2907 100644 --- a/modules/mumble/utils.cpp +++ b/modules/mumble/utils.cpp @@ -1,5 +1,6 @@ #include "utils.h" #include "variant.h" +#include "vector.h" @@ -11,14 +12,21 @@ std::string utils::gstr2cpp_str(String s){ String utils::cpp_str2gstr(std::string s){ return String(s.c_str()); } - +Variant utils::cpp_uint32vec2Variant( const std::vector &v ){ + Vector ret; + ret.resize(v.size()); + for( auto it = v.begin(); it != v.end(); it++){ + ret.push_back(Variant( (uint64_t)*it)); + } + return ret; +} Variant *utils::cpp_vec2garr( const std::vector &v ){ Array a; - a.resize(v.size()); + a.resize(v.size()); for( auto it = v.begin(); it != v.end(); it++){ a.push_back(Variant( (signed int)*it)); } - Variant * ret = memnew( Variant(a) ); + Variant * ret = memnew( Variant(a) ); return ret; } Variant *utils::short2byte( const int16_t * pcm_data, uint32_t size ){ diff --git a/modules/mumble/utils.h b/modules/mumble/utils.h index 794798055a3f..1c497fe5e82f 100644 --- a/modules/mumble/utils.h +++ b/modules/mumble/utils.h @@ -6,6 +6,7 @@ namespace utils{ std::string gstr2cpp_str(String s); String cpp_str2gstr(std::string s); + Variant cpp_uint32vec2Variant( const std::vector &v ); Variant *cpp_vec2garr( const std::vector &v ); Variant *short2byte( const int16_t * pcm_data, uint32_t size); } From 477fdfa41ee6711e8e8671fd73e18677cfdf9489 Mon Sep 17 00:00:00 2001 From: hungrymonkey Date: Wed, 4 Oct 2017 08:34:43 -0700 Subject: [PATCH 49/59] commit current nonworking code --- modules/mumble/callback.cpp | 20 ++++++++++++-------- modules/mumble/callback.h | 10 +++++----- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/modules/mumble/callback.cpp b/modules/mumble/callback.cpp index 17b4b0ae31d8..b187e1438d3b 100644 --- a/modules/mumble/callback.cpp +++ b/modules/mumble/callback.cpp @@ -4,6 +4,7 @@ #include "print_string.h" SimpleCallback::SimpleCallback(){ + } SimpleCallback::~SimpleCallback(){ } @@ -14,9 +15,9 @@ void SimpleCallback::audio( int target, int16_t *pcm_data, uint32_t pcm_data_size){ if(_audio_handler != NULL){ - Variant tar = memnew( Variant(target) ); - Variant sid = memnew( Variant(sessionId) ); - Variant snum = memnew( Variant(sequenceNumber) ); + Variant tar = Variant(target); + Variant sid = Variant(sessionId); + Variant snum = Variant(sequenceNumber); Variant *pcm = utils::short2byte(pcm_data, pcm_data_size); Variant::CallError err; const Variant *args[4] = {&tar, &sid, &snum, pcm}; @@ -53,15 +54,18 @@ void SimpleCallback::version( std::string release, std::string os, std::string os_version){ - print_line("processing os: " + String(os.c_str()) ); } void SimpleCallback::_bind_methods(){ ClassDB::bind_method(D_METHOD("setAudioHandler", "handler"), &SimpleCallback::setAudioHandler); ClassDB::bind_method(D_METHOD("setTextHandler", "handler"), &SimpleCallback::setTextHandler); } -void SimpleCallback::setAudioHandler( Object * handler){ - this->_audio_handler = Object::cast_to(handler); +void SimpleCallback::setAudioHandler( Ref handler){ + this->_audio_handler = handler; } -void SimpleCallback::setTextHandler( Object * handler){ - this->_text_handler = Object::cast_to(handler); +void SimpleCallback::setTextHandler( Ref handler){ + print_line("cb type :" + handler->get_class()); + print_line("is null :" + (this->_text_handler.is_null() == true) ? "True" : "False" ); + this->_text_handler.unref(); + this->_text_handler = handler.get_ref_ptr(); + //this-> _text_handler = memnew(FuncRef); } diff --git a/modules/mumble/callback.h b/modules/mumble/callback.h index ad66561c70c4..2b01aa3d16a8 100644 --- a/modules/mumble/callback.h +++ b/modules/mumble/callback.h @@ -13,8 +13,8 @@ class SimpleCallback : public mumlib::Callback, public Reference { GDCLASS(SimpleCallback,Reference); private: - FuncRef *_audio_handler; - FuncRef *_text_handler; + Ref _audio_handler; + Ref _text_handler; protected: // bool _set(const StringName &p_name, const Variant &p_value); @@ -27,9 +27,9 @@ class SimpleCallback : public mumlib::Callback, public Reference { SimpleCallback(); ~SimpleCallback(); - void setAudioHandler( Object * handle); - void setTextHandler( Object * handle); - + void setAudioHandler( Ref handler); + void setTextHandler(Ref handler); + virtual void audio(int target, int sessionId, int sequenceNumber, From 815bbc7eb49c22bfce35f540b23290eee7ab5b24 Mon Sep 17 00:00:00 2001 From: hungrymonkey Date: Wed, 4 Oct 2017 13:03:27 -0700 Subject: [PATCH 50/59] texting works --- modules/mumble/callback.cpp | 31 +++++++--------- modules/mumble/callback.h | 71 ++++++++++++++++++++++--------------- modules/mumble/mumble.cpp | 3 +- 3 files changed, 57 insertions(+), 48 deletions(-) diff --git a/modules/mumble/callback.cpp b/modules/mumble/callback.cpp index b187e1438d3b..2035a2e7fcd4 100644 --- a/modules/mumble/callback.cpp +++ b/modules/mumble/callback.cpp @@ -3,38 +3,37 @@ #include "variant.h" #include "print_string.h" -SimpleCallback::SimpleCallback(){ - +SimpleCallback::SimpleCallback() : _callback(*this) { } +SimpleCallback::~SimpleCallback() { } +mumlib::Callback *SimpleCallback::get_callback(){ + return &_callback; } -SimpleCallback::~SimpleCallback(){ -} - -void SimpleCallback::audio( int target, +void SimpleCallback::MyCallBack::audio( int target, int sessionId, int sequenceNumber, int16_t *pcm_data, uint32_t pcm_data_size){ - if(_audio_handler != NULL){ + if(!_cb._audio_handler.is_null()){ Variant tar = Variant(target); Variant sid = Variant(sessionId); Variant snum = Variant(sequenceNumber); Variant *pcm = utils::short2byte(pcm_data, pcm_data_size); Variant::CallError err; const Variant *args[4] = {&tar, &sid, &snum, pcm}; - Variant result = _audio_handler->call_func( args, 4, err); + Variant result = _cb._audio_handler->call_func( args, 4, err); memdelete( pcm); } } -void SimpleCallback::textMessage( +void SimpleCallback::MyCallBack::textMessage( uint32_t actor, std::vector session, std::vector channel_id, std::vector tree_id, std::string message) { - if(this->_text_handler != NULL){ - print_line("internal message: " + String(message.c_str()) ); + if(!_cb._text_handler.is_null()){ + print_line("internal message: " + String(message.c_str()) ); print_line( session.size() + ":" +channel_id.size() ); Variant s = utils::cpp_uint32vec2Variant(session); Variant c = utils::cpp_uint32vec2Variant(channel_id); @@ -43,11 +42,11 @@ void SimpleCallback::textMessage( Variant m = Variant(String(message.c_str())); Variant::CallError err; const Variant *args[5] = {&a, &s, &c, &t, &m}; - Variant result = this->_text_handler->call_func( args, 5, err ); + Variant result = _cb._text_handler->call_func( args, 5, err ); } } -void SimpleCallback::version( +void SimpleCallback::MyCallBack::version( uint16_t major, uint8_t minor, uint8_t patch, @@ -63,9 +62,5 @@ void SimpleCallback::setAudioHandler( Ref handler){ this->_audio_handler = handler; } void SimpleCallback::setTextHandler( Ref handler){ - print_line("cb type :" + handler->get_class()); - print_line("is null :" + (this->_text_handler.is_null() == true) ? "True" : "False" ); - this->_text_handler.unref(); - this->_text_handler = handler.get_ref_ptr(); - //this-> _text_handler = memnew(FuncRef); + this->_text_handler = handler; } diff --git a/modules/mumble/callback.h b/modules/mumble/callback.h index 2b01aa3d16a8..f29ff7385466 100644 --- a/modules/mumble/callback.h +++ b/modules/mumble/callback.h @@ -9,47 +9,60 @@ #include #include -class SimpleCallback : public mumlib::Callback, public Reference { +class SimpleCallback : public Reference { GDCLASS(SimpleCallback,Reference); -private: - Ref _audio_handler; - Ref _text_handler; protected: // bool _set(const StringName &p_name, const Variant &p_value); // bool _get(const StringName &p_name, Variant &r_ret) const; // void _get_property_list(List *p_list) const; static void _bind_methods(); + +private: + Ref _audio_handler; + Ref _text_handler; + + class MyCallBack : public mumlib::Callback{ + protected: + static void _bind_methods(); -public: + public: + MyCallBack( SimpleCallback &o ): _cb(o){ + }; + virtual void audio(int target, + int sessionId, + int sequenceNumber, + int16_t *pcm_data, + uint32_t pcm_data_size) ; - SimpleCallback(); - ~SimpleCallback(); + virtual void textMessage( + uint32_t actor, + std::vector session, + std::vector channel_id, + std::vector tree_id, + std::string message); - void setAudioHandler( Ref handler); + virtual void version( + uint16_t major, + uint8_t minor, + uint8_t patch, + std::string release, + std::string os, + std::string os_version); + private: + SimpleCallback &_cb; + }; + MyCallBack _callback; +public: + SimpleCallback(); + ~SimpleCallback(); + mumlib::Callback * get_callback(); + + void setAudioHandler(Ref handler); void setTextHandler(Ref handler); - - virtual void audio(int target, - int sessionId, - int sequenceNumber, - int16_t *pcm_data, - uint32_t pcm_data_size) ; - - virtual void textMessage( - uint32_t actor, - std::vector session, - std::vector channel_id, - std::vector tree_id, - std::string message); - - virtual void version( - uint16_t major, - uint8_t minor, - uint8_t patch, - std::string release, - std::string os, - std::string os_version); + + }; diff --git a/modules/mumble/mumble.cpp b/modules/mumble/mumble.cpp index bd8b47333d55..be5a8c902afa 100644 --- a/modules/mumble/mumble.cpp +++ b/modules/mumble/mumble.cpp @@ -10,6 +10,7 @@ #include "scene/main/timer.h" + void Mumble::_bind_methods() { ClassDB::bind_method(D_METHOD("add", "value"), &Mumble::add); ClassDB::bind_method(D_METHOD("reset"), &Mumble::reset); @@ -41,7 +42,7 @@ void Mumble::engage(String host, int port, String user, String password) { } void Mumble::setCallback(Object * callback){ SimpleCallback *cb = Object::cast_to(callback); - _mum = new mumlib::Mumlib(*cb); + _mum = new mumlib::Mumlib(*(cb->get_callback())); } void Mumble::sendText(String text){ _mum -> sendTextMessage( utils::gstr2cpp_str(text) ); From b0ca503dbfc79e383f969ae00d3b26dc830b4809 Mon Sep 17 00:00:00 2001 From: hungrymonkey Date: Wed, 4 Oct 2017 13:36:17 -0700 Subject: [PATCH 51/59] texting work on a few servers --- modules/mumble/callback.cpp | 1 + modules/mumble/callback.h | 1 + modules/mumble/mumble.cpp | 2 ++ modules/mumble/mumble.h | 3 ++- 4 files changed, 6 insertions(+), 1 deletion(-) diff --git a/modules/mumble/callback.cpp b/modules/mumble/callback.cpp index 2035a2e7fcd4..f4618ab6f853 100644 --- a/modules/mumble/callback.cpp +++ b/modules/mumble/callback.cpp @@ -57,6 +57,7 @@ void SimpleCallback::MyCallBack::version( void SimpleCallback::_bind_methods(){ ClassDB::bind_method(D_METHOD("setAudioHandler", "handler"), &SimpleCallback::setAudioHandler); ClassDB::bind_method(D_METHOD("setTextHandler", "handler"), &SimpleCallback::setTextHandler); + } void SimpleCallback::setAudioHandler( Ref handler){ this->_audio_handler = handler; diff --git a/modules/mumble/callback.h b/modules/mumble/callback.h index f29ff7385466..86a0b5d2c832 100644 --- a/modules/mumble/callback.h +++ b/modules/mumble/callback.h @@ -61,6 +61,7 @@ class SimpleCallback : public Reference { void setAudioHandler(Ref handler); void setTextHandler(Ref handler); + void sendText(String message); diff --git a/modules/mumble/mumble.cpp b/modules/mumble/mumble.cpp index be5a8c902afa..99889856a956 100644 --- a/modules/mumble/mumble.cpp +++ b/modules/mumble/mumble.cpp @@ -40,11 +40,13 @@ void Mumble::engage(String host, int port, String user, String password) { } } } + void Mumble::setCallback(Object * callback){ SimpleCallback *cb = Object::cast_to(callback); _mum = new mumlib::Mumlib(*(cb->get_callback())); } void Mumble::sendText(String text){ + print_line("i am sending this message: " + text); _mum -> sendTextMessage( utils::gstr2cpp_str(text) ); } diff --git a/modules/mumble/mumble.h b/modules/mumble/mumble.h index cf9061005641..f01100ba412e 100644 --- a/modules/mumble/mumble.h +++ b/modules/mumble/mumble.h @@ -20,8 +20,9 @@ class Mumble : public Reference { void reset(); int get_total() const; void engage(String host, int port, String user, String password); - void sendText(String s); void setCallback( Object * o ); + void sendText(String message); + Mumble(); }; From 15a4b7f85d2175cb8f36c01094c152a7e713d2a9 Mon Sep 17 00:00:00 2001 From: hungrymonkey Date: Wed, 4 Oct 2017 15:53:45 -0700 Subject: [PATCH 52/59] change a few things --- modules/mumble/callback.cpp | 4 ++-- modules/mumble/callback.h | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/modules/mumble/callback.cpp b/modules/mumble/callback.cpp index f4618ab6f853..26ded0becc3c 100644 --- a/modules/mumble/callback.cpp +++ b/modules/mumble/callback.cpp @@ -52,8 +52,8 @@ void SimpleCallback::MyCallBack::version( uint8_t patch, std::string release, std::string os, - std::string os_version){ -} + std::string os_version){ } + void SimpleCallback::_bind_methods(){ ClassDB::bind_method(D_METHOD("setAudioHandler", "handler"), &SimpleCallback::setAudioHandler); ClassDB::bind_method(D_METHOD("setTextHandler", "handler"), &SimpleCallback::setTextHandler); diff --git a/modules/mumble/callback.h b/modules/mumble/callback.h index 86a0b5d2c832..f29ff7385466 100644 --- a/modules/mumble/callback.h +++ b/modules/mumble/callback.h @@ -61,7 +61,6 @@ class SimpleCallback : public Reference { void setAudioHandler(Ref handler); void setTextHandler(Ref handler); - void sendText(String message); From 23e90e98fa2e39f00493f0819d5d8ebfaec863ae Mon Sep 17 00:00:00 2001 From: hungrymonkey Date: Wed, 4 Oct 2017 23:01:05 -0700 Subject: [PATCH 53/59] i have to test audio send and listen --- modules/mumble/SCsub | 2 ++ modules/mumble/callback.cpp | 18 ++++++++++-------- modules/mumble/callback.h | 2 +- modules/mumble/mumble.cpp | 27 +++++++++++++++++++++++---- modules/mumble/mumble.h | 3 ++- modules/mumble/utils.cpp | 16 ++++++++++++++++ modules/mumble/utils.h | 12 +++++++----- 7 files changed, 61 insertions(+), 19 deletions(-) diff --git a/modules/mumble/SCsub b/modules/mumble/SCsub index 120ea9c57307..5d9df14e80bc 100644 --- a/modules/mumble/SCsub +++ b/modules/mumble/SCsub @@ -217,6 +217,8 @@ sources = [ "callback.cpp" "utils.cpp" ] + + thirdparty_dir = "#thirdparty" third_party_includes = [ diff --git a/modules/mumble/callback.cpp b/modules/mumble/callback.cpp index 26ded0becc3c..06d3dfcf3c1a 100644 --- a/modules/mumble/callback.cpp +++ b/modules/mumble/callback.cpp @@ -2,6 +2,7 @@ #include "utils.h" #include "variant.h" #include "print_string.h" +#include "scene/resources/audio_stream_sample.h" SimpleCallback::SimpleCallback() : _callback(*this) { } SimpleCallback::~SimpleCallback() { } @@ -14,14 +15,14 @@ void SimpleCallback::MyCallBack::audio( int target, int16_t *pcm_data, uint32_t pcm_data_size){ if(!_cb._audio_handler.is_null()){ - Variant tar = Variant(target); - Variant sid = Variant(sessionId); - Variant snum = Variant(sequenceNumber); - Variant *pcm = utils::short2byte(pcm_data, pcm_data_size); + Variant tar(target); + Variant sid(sessionId); + Variant snum(sequenceNumber); + AudioStreamSample sam = utils::pcm2Sample(pcm_data, pcm_data_size); + Variant pcm(&sam); Variant::CallError err; - const Variant *args[4] = {&tar, &sid, &snum, pcm}; + const Variant *args[4] = {&tar, &sid, &snum, &pcm}; Variant result = _cb._audio_handler->call_func( args, 4, err); - memdelete( pcm); } } @@ -38,8 +39,8 @@ void SimpleCallback::MyCallBack::textMessage( Variant s = utils::cpp_uint32vec2Variant(session); Variant c = utils::cpp_uint32vec2Variant(channel_id); Variant t = utils::cpp_uint32vec2Variant(tree_id); - Variant a = Variant(actor); - Variant m = Variant(String(message.c_str())); + Variant a(actor); + Variant m(String(message.c_str())); Variant::CallError err; const Variant *args[5] = {&a, &s, &c, &t, &m}; Variant result = _cb._text_handler->call_func( args, 5, err ); @@ -59,6 +60,7 @@ void SimpleCallback::_bind_methods(){ ClassDB::bind_method(D_METHOD("setTextHandler", "handler"), &SimpleCallback::setTextHandler); } + void SimpleCallback::setAudioHandler( Ref handler){ this->_audio_handler = handler; } diff --git a/modules/mumble/callback.h b/modules/mumble/callback.h index f29ff7385466..b4e76ff24bc0 100644 --- a/modules/mumble/callback.h +++ b/modules/mumble/callback.h @@ -8,6 +8,7 @@ #include #include #include +#include "scene/resources/audio_stream_sample.h" class SimpleCallback : public Reference { GDCLASS(SimpleCallback,Reference); @@ -63,7 +64,6 @@ class SimpleCallback : public Reference { void setTextHandler(Ref handler); - }; #endif diff --git a/modules/mumble/mumble.cpp b/modules/mumble/mumble.cpp index 99889856a956..54be755e5d7f 100644 --- a/modules/mumble/mumble.cpp +++ b/modules/mumble/mumble.cpp @@ -16,9 +16,11 @@ void Mumble::_bind_methods() { ClassDB::bind_method(D_METHOD("reset"), &Mumble::reset); ClassDB::bind_method(D_METHOD("get_total"), &Mumble::get_total); - ClassDB::bind_method(D_METHOD("engage", "host", "port", "user", "password"), &Mumble::engage); - ClassDB::bind_method(D_METHOD("setCallback", "callback"), &Mumble::setCallback); - ClassDB::bind_method(D_METHOD("sendText", "text"), &Mumble::sendText); + ClassDB::bind_method(D_METHOD("engage", "host", "port", "user", "password"), &Mumble::engage); + ClassDB::bind_method(D_METHOD("setCallback", "callback"), &Mumble::setCallback); + ClassDB::bind_method(D_METHOD("sendText", "text"), &Mumble::sendText); + ClassDB::bind_method(D_METHOD("sendAudio", "sample"), &Mumble::sendAudio); + } void Mumble::engage(String host, int port, String user, String password) { std::string h = utils::gstr2cpp_str(host); @@ -49,7 +51,24 @@ void Mumble::sendText(String text){ print_line("i am sending this message: " + text); _mum -> sendTextMessage( utils::gstr2cpp_str(text) ); } - +void Mumble::sendAudio(Ref sample){ + int16_t * pcm = NULL; + PoolByteArray data = sample->get_data(); + switch(sample->get_format()){ + case AudioStreamSample::FORMAT_16_BITS: + pcm = new int16_t[data.size()/2]; + for(int i = 0; i > data.size()/2; i++){ + pcm[i] = data[2*i] | (data[2*i+1] << 8); + } + + break; + default: + return; + } + _mum->sendAudioData(pcm, data.size()/2); + delete pcm; + +} Mumble::Mumble() { count=0; diff --git a/modules/mumble/mumble.h b/modules/mumble/mumble.h index f01100ba412e..4d03d962358f 100644 --- a/modules/mumble/mumble.h +++ b/modules/mumble/mumble.h @@ -4,6 +4,7 @@ #include "reference.h" #include +#include "scene/resources/audio_stream_sample.h" class Mumble : public Reference { GDCLASS(Mumble,Reference); @@ -22,7 +23,7 @@ class Mumble : public Reference { void engage(String host, int port, String user, String password); void setCallback( Object * o ); void sendText(String message); - + void sendAudio(Ref sample); Mumble(); }; diff --git a/modules/mumble/utils.cpp b/modules/mumble/utils.cpp index 0401848a2907..aae042402ba6 100644 --- a/modules/mumble/utils.cpp +++ b/modules/mumble/utils.cpp @@ -41,3 +41,19 @@ Variant *utils::short2byte( const int16_t * pcm_data, uint32_t size ){ } + +AudioStreamSample utils::pcm2Sample( const int16_t * pcm_data, uint32_t size){ + PoolByteArray d; + d.resize(size * 2); + for( int i=0; i > size; i++){ + d.push_back( pcm_data[i] & 0x00FF ); + d.push_back( (pcm_data[i] & 0xFF00) >> 8); + } + AudioStreamSample sam; + sam.set_data(d); + sam.set_format(AudioStreamSample::FORMAT_16_BITS); + sam.set_loop_mode(AudioStreamSample::LOOP_DISABLED); + sam.set_loop_begin(0); + sam.set_loop_end(size * 2); + return sam; +} diff --git a/modules/mumble/utils.h b/modules/mumble/utils.h index 1c497fe5e82f..b442287bef6f 100644 --- a/modules/mumble/utils.h +++ b/modules/mumble/utils.h @@ -2,11 +2,13 @@ #include "array.h" #include #include +#include "scene/resources/audio_stream_sample.h" namespace utils{ - std::string gstr2cpp_str(String s); - String cpp_str2gstr(std::string s); - Variant cpp_uint32vec2Variant( const std::vector &v ); - Variant *cpp_vec2garr( const std::vector &v ); - Variant *short2byte( const int16_t * pcm_data, uint32_t size); + std::string gstr2cpp_str(String s); + String cpp_str2gstr(std::string s); + Variant cpp_uint32vec2Variant( const std::vector &v ); + Variant *cpp_vec2garr( const std::vector &v ); + Variant *short2byte( const int16_t * pcm_data, uint32_t size); + AudioStreamSample pcm2Sample( const int16_t * pcm_data, uint32_t size); } From 21677c5e9431018c7621dc597d3bce783b0ee783 Mon Sep 17 00:00:00 2001 From: hungrymonkey Date: Thu, 5 Oct 2017 14:30:21 -0700 Subject: [PATCH 54/59] clean up code and it still crashes on voice --- modules/mumble/callback.cpp | 10 +++++----- modules/mumble/mumble.cpp | 39 ++++++++++++++++++++++--------------- modules/mumble/mumble.h | 2 +- modules/mumble/utils.cpp | 36 +++++++--------------------------- modules/mumble/utils.h | 4 +--- 5 files changed, 37 insertions(+), 54 deletions(-) diff --git a/modules/mumble/callback.cpp b/modules/mumble/callback.cpp index 06d3dfcf3c1a..88ba2b23ba8d 100644 --- a/modules/mumble/callback.cpp +++ b/modules/mumble/callback.cpp @@ -15,14 +15,14 @@ void SimpleCallback::MyCallBack::audio( int target, int16_t *pcm_data, uint32_t pcm_data_size){ if(!_cb._audio_handler.is_null()){ - Variant tar(target); + // Variant tar(target); Variant sid(sessionId); Variant snum(sequenceNumber); - AudioStreamSample sam = utils::pcm2Sample(pcm_data, pcm_data_size); - Variant pcm(&sam); + Ref sam = Ref(utils::pcm2Sample(pcm_data, pcm_data_size)); + Variant pcm(sam); Variant::CallError err; - const Variant *args[4] = {&tar, &sid, &snum, &pcm}; - Variant result = _cb._audio_handler->call_func( args, 4, err); + const Variant *args[3] = { &sid, &snum, &pcm}; + Variant result = _cb._audio_handler->call_func( args, 3, err); } } diff --git a/modules/mumble/mumble.cpp b/modules/mumble/mumble.cpp index 54be755e5d7f..5bc6e9ecb374 100644 --- a/modules/mumble/mumble.cpp +++ b/modules/mumble/mumble.cpp @@ -8,6 +8,7 @@ #include #include #include "scene/main/timer.h" +#include @@ -45,28 +46,34 @@ void Mumble::engage(String host, int port, String user, String password) { void Mumble::setCallback(Object * callback){ SimpleCallback *cb = Object::cast_to(callback); - _mum = new mumlib::Mumlib(*(cb->get_callback())); + _mum = new mumlib::Mumlib(*(cb->get_callback()),_conf); } -void Mumble::sendText(String text){ +void Mumble::sendText(const String text){ print_line("i am sending this message: " + text); _mum -> sendTextMessage( utils::gstr2cpp_str(text) ); } void Mumble::sendAudio(Ref sample){ - int16_t * pcm = NULL; - PoolByteArray data = sample->get_data(); - switch(sample->get_format()){ - case AudioStreamSample::FORMAT_16_BITS: - pcm = new int16_t[data.size()/2]; - for(int i = 0; i > data.size()/2; i++){ - pcm[i] = data[2*i] | (data[2*i+1] << 8); - } - - break; - default: - return; + + const PoolByteArray data = sample->get_data(); + + int32_t packet_size = 0; + int16_t pcm[5000]; //https://github.com/slomkowski/mumlib/blob/master/src/mumlib.cpp look at lib source + print_line("pcm_data" + itos(sample->get_format()) +" size :" + itos((int64_t)data.size())); + + if(data.size() > 0){ + switch(sample->get_format()){ + case AudioStreamSample::FORMAT_16_BITS: + + packet_size = data.size()/2; + for(int i = 0; i > packet_size; i++){ + pcm[i] = data[2*i] | (data[2*i+1] << 8); + } + break; + default: + return; + } + _mum->sendAudioData(pcm, packet_size); } - _mum->sendAudioData(pcm, data.size()/2); - delete pcm; } diff --git a/modules/mumble/mumble.h b/modules/mumble/mumble.h index 4d03d962358f..f6a8e14e62c9 100644 --- a/modules/mumble/mumble.h +++ b/modules/mumble/mumble.h @@ -22,7 +22,7 @@ class Mumble : public Reference { int get_total() const; void engage(String host, int port, String user, String password); void setCallback( Object * o ); - void sendText(String message); + void sendText(const String message); void sendAudio(Ref sample); Mumble(); }; diff --git a/modules/mumble/utils.cpp b/modules/mumble/utils.cpp index aae042402ba6..8d437789e877 100644 --- a/modules/mumble/utils.cpp +++ b/modules/mumble/utils.cpp @@ -20,40 +20,18 @@ Variant utils::cpp_uint32vec2Variant( const std::vector &v ){ } return ret; } -Variant *utils::cpp_vec2garr( const std::vector &v ){ - Array a; - a.resize(v.size()); - for( auto it = v.begin(); it != v.end(); it++){ - a.push_back(Variant( (signed int)*it)); - } - Variant * ret = memnew( Variant(a) ); - return ret; -} -Variant *utils::short2byte( const int16_t * pcm_data, uint32_t size ){ - PoolByteArray d; - d.resize(size * 2); - for( int i=0; i > size; i++){ - d.push_back( pcm_data[i] & 0x00FF ); - d.push_back( pcm_data[i] & 0xFF00 >> 8); - } - Variant * ret = memnew( Variant(d) ); - return ret; - -} -AudioStreamSample utils::pcm2Sample( const int16_t * pcm_data, uint32_t size){ +AudioStreamSample *utils::pcm2Sample( const int16_t * pcm_data, uint32_t size){ PoolByteArray d; d.resize(size * 2); for( int i=0; i > size; i++){ - d.push_back( pcm_data[i] & 0x00FF ); - d.push_back( (pcm_data[i] & 0xFF00) >> 8); + d.set( i*2 , pcm_data[i] & 0x00FF ); + d.set( i*2+1 , (pcm_data[i] & 0xFF00) >> 8 ); } - AudioStreamSample sam; - sam.set_data(d); - sam.set_format(AudioStreamSample::FORMAT_16_BITS); - sam.set_loop_mode(AudioStreamSample::LOOP_DISABLED); - sam.set_loop_begin(0); - sam.set_loop_end(size * 2); + AudioStreamSample *sam = memnew(AudioStreamSample); + sam->set_data(d); + sam->set_format(AudioStreamSample::FORMAT_16_BITS); + sam->set_loop_mode(AudioStreamSample::LOOP_DISABLED); return sam; } diff --git a/modules/mumble/utils.h b/modules/mumble/utils.h index b442287bef6f..e3d87f532d06 100644 --- a/modules/mumble/utils.h +++ b/modules/mumble/utils.h @@ -8,7 +8,5 @@ namespace utils{ std::string gstr2cpp_str(String s); String cpp_str2gstr(std::string s); Variant cpp_uint32vec2Variant( const std::vector &v ); - Variant *cpp_vec2garr( const std::vector &v ); - Variant *short2byte( const int16_t * pcm_data, uint32_t size); - AudioStreamSample pcm2Sample( const int16_t * pcm_data, uint32_t size); + AudioStreamSample *pcm2Sample( const int16_t * pcm_data, uint32_t size); } From 4560c99c4d081069632addadb5aa36fa3081c266 Mon Sep 17 00:00:00 2001 From: hungrymonkey Date: Thu, 5 Oct 2017 17:18:20 -0700 Subject: [PATCH 55/59] messup the common for loop --- modules/mumble/callback.cpp | 1 - modules/mumble/mumble.cpp | 10 ++++------ modules/mumble/utils.cpp | 6 +++--- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/modules/mumble/callback.cpp b/modules/mumble/callback.cpp index 88ba2b23ba8d..1817e03a974a 100644 --- a/modules/mumble/callback.cpp +++ b/modules/mumble/callback.cpp @@ -35,7 +35,6 @@ void SimpleCallback::MyCallBack::textMessage( std::string message) { if(!_cb._text_handler.is_null()){ print_line("internal message: " + String(message.c_str()) ); - print_line( session.size() + ":" +channel_id.size() ); Variant s = utils::cpp_uint32vec2Variant(session); Variant c = utils::cpp_uint32vec2Variant(channel_id); Variant t = utils::cpp_uint32vec2Variant(tree_id); diff --git a/modules/mumble/mumble.cpp b/modules/mumble/mumble.cpp index 5bc6e9ecb374..eb82d21322c3 100644 --- a/modules/mumble/mumble.cpp +++ b/modules/mumble/mumble.cpp @@ -8,7 +8,6 @@ #include #include #include "scene/main/timer.h" -#include @@ -57,16 +56,15 @@ void Mumble::sendAudio(Ref sample){ const PoolByteArray data = sample->get_data(); int32_t packet_size = 0; - int16_t pcm[5000]; //https://github.com/slomkowski/mumlib/blob/master/src/mumlib.cpp look at lib source - print_line("pcm_data" + itos(sample->get_format()) +" size :" + itos((int64_t)data.size())); - + print_line("pcm_data" + itos(sample->get_format()) +" size :" + itos((int64_t)data.size())); + int16_t pcm[4096]; if(data.size() > 0){ switch(sample->get_format()){ case AudioStreamSample::FORMAT_16_BITS: packet_size = data.size()/2; - for(int i = 0; i > packet_size; i++){ - pcm[i] = data[2*i] | (data[2*i+1] << 8); + for(int i = 0; i < packet_size; i++){ + pcm[i] = (int16_t)(data[2*i] | (data[2*i+1] << 8)); } break; default: diff --git a/modules/mumble/utils.cpp b/modules/mumble/utils.cpp index 8d437789e877..98a201872000 100644 --- a/modules/mumble/utils.cpp +++ b/modules/mumble/utils.cpp @@ -15,8 +15,8 @@ String utils::cpp_str2gstr(std::string s){ Variant utils::cpp_uint32vec2Variant( const std::vector &v ){ Vector ret; ret.resize(v.size()); - for( auto it = v.begin(); it != v.end(); it++){ - ret.push_back(Variant( (uint64_t)*it)); + for( int i = 0; i < v.size(); i++){ + ret[i] = (Variant( (uint64_t)v[i])); } return ret; } @@ -25,7 +25,7 @@ Variant utils::cpp_uint32vec2Variant( const std::vector &v ){ AudioStreamSample *utils::pcm2Sample( const int16_t * pcm_data, uint32_t size){ PoolByteArray d; d.resize(size * 2); - for( int i=0; i > size; i++){ + for( int i=0; i < size; i++){ d.set( i*2 , pcm_data[i] & 0x00FF ); d.set( i*2+1 , (pcm_data[i] & 0xFF00) >> 8 ); } From 604da65481474e0f3e54b046d7fb615c964a3771 Mon Sep 17 00:00:00 2001 From: hungrymonkey Date: Thu, 5 Oct 2017 19:17:44 -0700 Subject: [PATCH 56/59] fix some small issues and added print statements, I will remove it when the bug is fixed. I might need to ask upstream on why set_data does not seem to the same output --- modules/mumble/mumble.cpp | 9 +++++++-- modules/mumble/utils.cpp | 17 ++++++++++++----- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/modules/mumble/mumble.cpp b/modules/mumble/mumble.cpp index eb82d21322c3..3ed9ed237c5f 100644 --- a/modules/mumble/mumble.cpp +++ b/modules/mumble/mumble.cpp @@ -56,16 +56,21 @@ void Mumble::sendAudio(Ref sample){ const PoolByteArray data = sample->get_data(); int32_t packet_size = 0; + int16_t pcm[5000]; print_line("pcm_data" + itos(sample->get_format()) +" size :" + itos((int64_t)data.size())); - int16_t pcm[4096]; + print_line( "sendaudio: pcm value at 500: " + itos(data[1000])+ " " + itos(data[1001])); if(data.size() > 0){ switch(sample->get_format()){ case AudioStreamSample::FORMAT_16_BITS: packet_size = data.size()/2; for(int i = 0; i < packet_size; i++){ - pcm[i] = (int16_t)(data[2*i] | (data[2*i+1] << 8)); + uint16_t low = (uint16_t) data[2*i]; + uint16_t hi = (uint16_t) data[2*i+1]; + pcm[i] = ( low | ( hi << 8)); } + print_line( "pcm value at 500: " + itos(pcm[500])); + break; default: return; diff --git a/modules/mumble/utils.cpp b/modules/mumble/utils.cpp index 98a201872000..bf30ee0d0f7e 100644 --- a/modules/mumble/utils.cpp +++ b/modules/mumble/utils.cpp @@ -25,13 +25,20 @@ Variant utils::cpp_uint32vec2Variant( const std::vector &v ){ AudioStreamSample *utils::pcm2Sample( const int16_t * pcm_data, uint32_t size){ PoolByteArray d; d.resize(size * 2); - for( int i=0; i < size; i++){ - d.set( i*2 , pcm_data[i] & 0x00FF ); - d.set( i*2+1 , (pcm_data[i] & 0xFF00) >> 8 ); - } AudioStreamSample *sam = memnew(AudioStreamSample); - sam->set_data(d); sam->set_format(AudioStreamSample::FORMAT_16_BITS); sam->set_loop_mode(AudioStreamSample::LOOP_DISABLED); + for( int i=0; i < size; i++){ + uint16_t sh = (uint16_t) pcm_data[i]; + d.set( i*2 , (uint8_t) (sh & 0x00FF) ); + d.set( i*2+1 , (uint8_t) ((sh >> 8) & 0x00FF )); + } + print_line( "utils: pcm value at 500: " + itos(pcm_data[500])); + print_line( "utils: pcm value at 700: " + itos(pcm_data[700])); + print_line( "utils: pcm value at 500: " + itos(d[1000])+ " " + itos(d[1001])); + print_line( "before audiostreamsample-set_data: pcm value at 700: " + itos(d[1400])+ " " + itos(d[1401])); + + sam->set_data(d); + print_line( "after audiostreamsample-set_data: pcm value at 500: " + itos(sam->get_data()[1000])+ " " + itos(sam->get_data()[1001])); return sam; } From cfa13bc6cdb79b958539567284e3478187c8c52a Mon Sep 17 00:00:00 2001 From: hungrymonkey Date: Thu, 5 Oct 2017 23:45:49 -0700 Subject: [PATCH 57/59] fix the data corruption but it did not fix the crashing --- modules/mumble/callback.cpp | 5 +++-- modules/mumble/mumble.cpp | 17 ++++++++++++++++- modules/mumble/mumble.h | 4 +++- modules/mumble/utils.cpp | 14 ++++++++++++++ modules/mumble/utils.h | 2 ++ 5 files changed, 38 insertions(+), 4 deletions(-) diff --git a/modules/mumble/callback.cpp b/modules/mumble/callback.cpp index 1817e03a974a..c9a4bd17a17c 100644 --- a/modules/mumble/callback.cpp +++ b/modules/mumble/callback.cpp @@ -18,8 +18,9 @@ void SimpleCallback::MyCallBack::audio( int target, // Variant tar(target); Variant sid(sessionId); Variant snum(sequenceNumber); - Ref sam = Ref(utils::pcm2Sample(pcm_data, pcm_data_size)); - Variant pcm(sam); + //Ref sam = Ref(utils::pcm2Sample(pcm_data, pcm_data_size)); + //Variant pcm(sam); + Variant pcm(utils::pcm2ByteArray(pcm_data,pcm_data_size)); Variant::CallError err; const Variant *args[3] = { &sid, &snum, &pcm}; Variant result = _cb._audio_handler->call_func( args, 3, err); diff --git a/modules/mumble/mumble.cpp b/modules/mumble/mumble.cpp index 3ed9ed237c5f..0e2f88bd0040 100644 --- a/modules/mumble/mumble.cpp +++ b/modules/mumble/mumble.cpp @@ -51,6 +51,21 @@ void Mumble::sendText(const String text){ print_line("i am sending this message: " + text); _mum -> sendTextMessage( utils::gstr2cpp_str(text) ); } +void Mumble::sendAudio(PoolByteArray sample){ + uint32_t pcm_len = sample.size()/2; + int16_t pcm[5000]; + if( pcm_len > 0){ + for(int i = 0; i < pcm_len; i++){ + uint16_t low = (uint16_t) sample[2*i]; + uint16_t hi = (uint16_t) sample[2*i+1]; + pcm[i] = ( low | ( hi << 8)); + } + print_line( "sendaudio: pcm value at 500: " + itos(sample[1000])+ " " + itos(sample[1001])); + + _mum->sendAudioData(pcm, pcm_len); + } +} +/* void Mumble::sendAudio(Ref sample){ const PoolByteArray data = sample->get_data(); @@ -79,7 +94,7 @@ void Mumble::sendAudio(Ref sample){ } } - +*/ Mumble::Mumble() { count=0; } diff --git a/modules/mumble/mumble.h b/modules/mumble/mumble.h index f6a8e14e62c9..6ed6b2c9ff72 100644 --- a/modules/mumble/mumble.h +++ b/modules/mumble/mumble.h @@ -5,6 +5,7 @@ #include "reference.h" #include #include "scene/resources/audio_stream_sample.h" +#include "variant.h" class Mumble : public Reference { GDCLASS(Mumble,Reference); @@ -23,7 +24,8 @@ class Mumble : public Reference { void engage(String host, int port, String user, String password); void setCallback( Object * o ); void sendText(const String message); - void sendAudio(Ref sample); + //void sendAudio(Ref sample); + void sendAudio(PoolByteArray sample); Mumble(); }; diff --git a/modules/mumble/utils.cpp b/modules/mumble/utils.cpp index bf30ee0d0f7e..480d075ee40d 100644 --- a/modules/mumble/utils.cpp +++ b/modules/mumble/utils.cpp @@ -21,7 +21,21 @@ Variant utils::cpp_uint32vec2Variant( const std::vector &v ){ return ret; } +PoolByteArray utils::pcm2ByteArray( const int16_t * pcm_data, uint32_t size){ + PoolByteArray d; + d.resize(size * 2); + + for( int i=0; i < size; i++){ + uint16_t sh = (uint16_t) pcm_data[i]; + d.set( i*2 , (uint8_t) (sh & 0x00FF) ); + d.set( i*2+1 , (uint8_t) ((sh >> 8) & 0x00FF )); + } + print_line( "utils: pcm value at 500: " + itos(pcm_data[500])); + print_line( "utils: pcm value at 500: " + itos(d[1000])+ " " + itos(d[1001])); + + return d; +} AudioStreamSample *utils::pcm2Sample( const int16_t * pcm_data, uint32_t size){ PoolByteArray d; d.resize(size * 2); diff --git a/modules/mumble/utils.h b/modules/mumble/utils.h index e3d87f532d06..8a3b86e5420d 100644 --- a/modules/mumble/utils.h +++ b/modules/mumble/utils.h @@ -3,10 +3,12 @@ #include #include #include "scene/resources/audio_stream_sample.h" +#include "variant.h" namespace utils{ std::string gstr2cpp_str(String s); String cpp_str2gstr(std::string s); Variant cpp_uint32vec2Variant( const std::vector &v ); + PoolByteArray pcm2ByteArray( const int16_t * pcm_data, uint32_t size); AudioStreamSample *pcm2Sample( const int16_t * pcm_data, uint32_t size); } From e467d0afe853101c28eac2d85604975c92f3610c Mon Sep 17 00:00:00 2001 From: hungrymonkey Date: Sat, 7 Oct 2017 21:44:46 -0700 Subject: [PATCH 58/59] change Mumble to be tracked by godot --- modules/mumble/callback.cpp | 19 +++--- modules/mumble/mumble.cpp | 83 ++++++++++++++----------- modules/mumble/mumble.h | 23 +++++-- modules/mumble/utils.cpp | 8 +-- scene/resources/audio_stream_sample.cpp | 3 +- 5 files changed, 80 insertions(+), 56 deletions(-) diff --git a/modules/mumble/callback.cpp b/modules/mumble/callback.cpp index c9a4bd17a17c..1c3fa80a43e7 100644 --- a/modules/mumble/callback.cpp +++ b/modules/mumble/callback.cpp @@ -15,15 +15,16 @@ void SimpleCallback::MyCallBack::audio( int target, int16_t *pcm_data, uint32_t pcm_data_size){ if(!_cb._audio_handler.is_null()){ - // Variant tar(target); - Variant sid(sessionId); - Variant snum(sequenceNumber); - //Ref sam = Ref(utils::pcm2Sample(pcm_data, pcm_data_size)); - //Variant pcm(sam); - Variant pcm(utils::pcm2ByteArray(pcm_data,pcm_data_size)); - Variant::CallError err; - const Variant *args[3] = { &sid, &snum, &pcm}; - Variant result = _cb._audio_handler->call_func( args, 3, err); + // Variant tar(target); + Variant sid(sessionId); + Variant snum(sequenceNumber); + Ref sam = Ref(utils::pcm2Sample(pcm_data, pcm_data_size)); + Variant pcm(sam); + print_line("sample is class : " + sam->get_class()); + // Variant pcm(utils::pcm2ByteArray(pcm_data,pcm_data_size)); + Variant::CallError err; + const Variant *args[3] = { &sid, &snum, &pcm}; + Variant result = _cb._audio_handler->call_func( args, 3, err); } } diff --git a/modules/mumble/mumble.cpp b/modules/mumble/mumble.cpp index 0e2f88bd0040..0b2796c0974a 100644 --- a/modules/mumble/mumble.cpp +++ b/modules/mumble/mumble.cpp @@ -9,28 +9,17 @@ #include #include "scene/main/timer.h" - - -void Mumble::_bind_methods() { - ClassDB::bind_method(D_METHOD("add", "value"), &Mumble::add); - ClassDB::bind_method(D_METHOD("reset"), &Mumble::reset); - ClassDB::bind_method(D_METHOD("get_total"), &Mumble::get_total); - - ClassDB::bind_method(D_METHOD("engage", "host", "port", "user", "password"), &Mumble::engage); - ClassDB::bind_method(D_METHOD("setCallback", "callback"), &Mumble::setCallback); - ClassDB::bind_method(D_METHOD("sendText", "text"), &Mumble::sendText); - ClassDB::bind_method(D_METHOD("sendAudio", "sample"), &Mumble::sendAudio); - +Mumble::_PrivateMumble::_PrivateMumble( mumlib::Callback & c) : _mum(c) { } -void Mumble::engage(String host, int port, String user, String password) { +void Mumble::_PrivateMumble::engage(String host, int port, String user, String password){ std::string h = utils::gstr2cpp_str(host); std::string u = utils::gstr2cpp_str(user); std::string p = utils::gstr2cpp_str(password); while(true){ try{ - this->_mum->connect(h, port, u, p); + this->_mum.connect(h, port, u, p); print_line( "Mumble: connecting to " + host ); - this->_mum->run(); + this->_mum.run(); }catch (mumlib::TransportException &exp) { print_line( "Mumble: error " + utils::cpp_str2gstr(exp.what())); print_line( "Mumble: attempting to reconnect in 5s. "); @@ -43,14 +32,45 @@ void Mumble::engage(String host, int port, String user, String password) { } } -void Mumble::setCallback(Object * callback){ - SimpleCallback *cb = Object::cast_to(callback); - _mum = new mumlib::Mumlib(*(cb->get_callback()),_conf); +void Mumble::_PrivateMumble::sendText(const String text){ + print_line("i am sending this message: " + text); + _mum.sendTextMessage( utils::gstr2cpp_str(text) ); +} + +void Mumble::_PrivateMumble::send16bAudio(const PoolByteArray & sample){ + uint32_t pcm_len = sample.size()/2; + int16_t pcm[50000]; + for(int i = 0; i < pcm_len; i++){ + uint16_t low = (uint16_t) sample[2*i]; + uint16_t hi = (uint16_t) sample[2*i+1]; + pcm[i] = ( low | ( hi << 8)); + } + _mum.sendAudioData(pcm, pcm_len); +} + +void Mumble::_bind_methods() { + ClassDB::bind_method(D_METHOD("add", "value"), &Mumble::add); + ClassDB::bind_method(D_METHOD("reset"), &Mumble::reset); + ClassDB::bind_method(D_METHOD("get_total"), &Mumble::get_total); + + ClassDB::bind_method(D_METHOD("engage", "host", "port", "user", "password"), &Mumble::engage); + ClassDB::bind_method(D_METHOD("setCallback", "callback"), &Mumble::setCallback); + ClassDB::bind_method(D_METHOD("sendText", "text"), &Mumble::sendText); + ClassDB::bind_method(D_METHOD("sendAudio", "sample"), &Mumble::sendAudio); + +} +void Mumble::engage(String host, int port, String user, String password) { + _pMumble -> engage( host, port, user, password); +} + +void Mumble::setCallback( Ref cb){ + + _pMumble = Ref<_PrivateMumble>(memnew(_PrivateMumble(*(cb->get_callback())))); } void Mumble::sendText(const String text){ - print_line("i am sending this message: " + text); - _mum -> sendTextMessage( utils::gstr2cpp_str(text) ); + _pMumble -> sendText( text ); } +/* void Mumble::sendAudio(PoolByteArray sample){ uint32_t pcm_len = sample.size()/2; int16_t pcm[5000]; @@ -65,36 +85,25 @@ void Mumble::sendAudio(PoolByteArray sample){ _mum->sendAudioData(pcm, pcm_len); } } -/* +*/ void Mumble::sendAudio(Ref sample){ const PoolByteArray data = sample->get_data(); - int32_t packet_size = 0; - int16_t pcm[5000]; - print_line("pcm_data" + itos(sample->get_format()) +" size :" + itos((int64_t)data.size())); - print_line( "sendaudio: pcm value at 500: " + itos(data[1000])+ " " + itos(data[1001])); + if(data.size() > 0){ switch(sample->get_format()){ case AudioStreamSample::FORMAT_16_BITS: - - packet_size = data.size()/2; - for(int i = 0; i < packet_size; i++){ - uint16_t low = (uint16_t) data[2*i]; - uint16_t hi = (uint16_t) data[2*i+1]; - pcm[i] = ( low | ( hi << 8)); - } - print_line( "pcm value at 500: " + itos(pcm[500])); - - break; + _pMumble->send16bAudio(data); default: return; } - _mum->sendAudioData(pcm, packet_size); } } -*/ + + + Mumble::Mumble() { count=0; } diff --git a/modules/mumble/mumble.h b/modules/mumble/mumble.h index 6ed6b2c9ff72..1527072d9a23 100644 --- a/modules/mumble/mumble.h +++ b/modules/mumble/mumble.h @@ -6,13 +6,25 @@ #include #include "scene/resources/audio_stream_sample.h" #include "variant.h" +#include "callback.h" class Mumble : public Reference { GDCLASS(Mumble,Reference); int count; private: - mumlib::MumlibConfiguration _conf; - mumlib::Mumlib *_mum; + + + class _PrivateMumble: public Reference { + GDCLASS(_PrivateMumble,Reference); + private: + mumlib::Mumlib _mum; + public: + _PrivateMumble(mumlib::Callback & c); + void engage(String host, int port, String user, String password); + void sendText(const String text); + void send16bAudio(const PoolByteArray & arr); + }; + Ref<_PrivateMumble> _pMumble; protected: static void _bind_methods(); @@ -22,11 +34,12 @@ class Mumble : public Reference { void reset(); int get_total() const; void engage(String host, int port, String user, String password); - void setCallback( Object * o ); + void setCallback( Ref c ); void sendText(const String message); - //void sendAudio(Ref sample); - void sendAudio(PoolByteArray sample); + void sendAudio(Ref sample); +// void sendAudio(PoolByteArray sample); Mumble(); +// ~Mumble(); }; #endif diff --git a/modules/mumble/utils.cpp b/modules/mumble/utils.cpp index 480d075ee40d..16e9daf4aa32 100644 --- a/modules/mumble/utils.cpp +++ b/modules/mumble/utils.cpp @@ -27,8 +27,8 @@ PoolByteArray utils::pcm2ByteArray( const int16_t * pcm_data, uint32_t size){ for( int i=0; i < size; i++){ uint16_t sh = (uint16_t) pcm_data[i]; - d.set( i*2 , (uint8_t) (sh & 0x00FF) ); - d.set( i*2+1 , (uint8_t) ((sh >> 8) & 0x00FF )); + d.set( i*2, (uint8_t) (sh & 0xFF) ); + d.set( i*2+1, (uint8_t) (sh >> 8)); } print_line( "utils: pcm value at 500: " + itos(pcm_data[500])); @@ -44,8 +44,8 @@ AudioStreamSample *utils::pcm2Sample( const int16_t * pcm_data, uint32_t size){ sam->set_loop_mode(AudioStreamSample::LOOP_DISABLED); for( int i=0; i < size; i++){ uint16_t sh = (uint16_t) pcm_data[i]; - d.set( i*2 , (uint8_t) (sh & 0x00FF) ); - d.set( i*2+1 , (uint8_t) ((sh >> 8) & 0x00FF )); + d.set( i*2 , (uint8_t) (sh & 0xFF) ); + d.set( i*2+1 , (uint8_t) (sh >> 8)); } print_line( "utils: pcm value at 500: " + itos(pcm_data[500])); print_line( "utils: pcm value at 700: " + itos(pcm_data[700])); diff --git a/scene/resources/audio_stream_sample.cpp b/scene/resources/audio_stream_sample.cpp index 1fd84a860e17..fdc3b79db652 100644 --- a/scene/resources/audio_stream_sample.cpp +++ b/scene/resources/audio_stream_sample.cpp @@ -486,7 +486,8 @@ PoolVector AudioStreamSample::get_data() const { { PoolVector::Write w = pv.write(); - copymem(w.ptr(), data, data_bytes); + uint8_t *dataptr = (uint8_t *)data; + copymem(w.ptr(), dataptr + DATA_PAD, data_bytes); } } From 2d2b0a01fbf4abd07e5e1daf952ac79ad0198a29 Mon Sep 17 00:00:00 2001 From: hungrymonkey Date: Sun, 8 Oct 2017 15:29:19 -0700 Subject: [PATCH 59/59] delete print_line and unused functions --- modules/mumble/callback.cpp | 5 +---- modules/mumble/mumble.cpp | 16 ---------------- modules/mumble/utils.cpp | 20 +------------------- modules/mumble/utils.h | 1 - 4 files changed, 2 insertions(+), 40 deletions(-) diff --git a/modules/mumble/callback.cpp b/modules/mumble/callback.cpp index 1c3fa80a43e7..e9c7fa8bf3f1 100644 --- a/modules/mumble/callback.cpp +++ b/modules/mumble/callback.cpp @@ -15,13 +15,11 @@ void SimpleCallback::MyCallBack::audio( int target, int16_t *pcm_data, uint32_t pcm_data_size){ if(!_cb._audio_handler.is_null()){ - // Variant tar(target); Variant sid(sessionId); Variant snum(sequenceNumber); Ref sam = Ref(utils::pcm2Sample(pcm_data, pcm_data_size)); Variant pcm(sam); - print_line("sample is class : " + sam->get_class()); - // Variant pcm(utils::pcm2ByteArray(pcm_data,pcm_data_size)); + Variant::CallError err; const Variant *args[3] = { &sid, &snum, &pcm}; Variant result = _cb._audio_handler->call_func( args, 3, err); @@ -36,7 +34,6 @@ void SimpleCallback::MyCallBack::textMessage( std::vector tree_id, std::string message) { if(!_cb._text_handler.is_null()){ - print_line("internal message: " + String(message.c_str()) ); Variant s = utils::cpp_uint32vec2Variant(session); Variant c = utils::cpp_uint32vec2Variant(channel_id); Variant t = utils::cpp_uint32vec2Variant(tree_id); diff --git a/modules/mumble/mumble.cpp b/modules/mumble/mumble.cpp index 0b2796c0974a..109e6444645c 100644 --- a/modules/mumble/mumble.cpp +++ b/modules/mumble/mumble.cpp @@ -33,7 +33,6 @@ void Mumble::_PrivateMumble::engage(String host, int port, String user, String p } void Mumble::_PrivateMumble::sendText(const String text){ - print_line("i am sending this message: " + text); _mum.sendTextMessage( utils::gstr2cpp_str(text) ); } @@ -70,22 +69,7 @@ void Mumble::setCallback( Ref cb){ void Mumble::sendText(const String text){ _pMumble -> sendText( text ); } -/* -void Mumble::sendAudio(PoolByteArray sample){ - uint32_t pcm_len = sample.size()/2; - int16_t pcm[5000]; - if( pcm_len > 0){ - for(int i = 0; i < pcm_len; i++){ - uint16_t low = (uint16_t) sample[2*i]; - uint16_t hi = (uint16_t) sample[2*i+1]; - pcm[i] = ( low | ( hi << 8)); - } - print_line( "sendaudio: pcm value at 500: " + itos(sample[1000])+ " " + itos(sample[1001])); - _mum->sendAudioData(pcm, pcm_len); - } -} -*/ void Mumble::sendAudio(Ref sample){ const PoolByteArray data = sample->get_data(); diff --git a/modules/mumble/utils.cpp b/modules/mumble/utils.cpp index 16e9daf4aa32..05b055e15001 100644 --- a/modules/mumble/utils.cpp +++ b/modules/mumble/utils.cpp @@ -21,21 +21,7 @@ Variant utils::cpp_uint32vec2Variant( const std::vector &v ){ return ret; } -PoolByteArray utils::pcm2ByteArray( const int16_t * pcm_data, uint32_t size){ - PoolByteArray d; - d.resize(size * 2); - - for( int i=0; i < size; i++){ - uint16_t sh = (uint16_t) pcm_data[i]; - d.set( i*2, (uint8_t) (sh & 0xFF) ); - d.set( i*2+1, (uint8_t) (sh >> 8)); - } - print_line( "utils: pcm value at 500: " + itos(pcm_data[500])); - - print_line( "utils: pcm value at 500: " + itos(d[1000])+ " " + itos(d[1001])); - return d; -} AudioStreamSample *utils::pcm2Sample( const int16_t * pcm_data, uint32_t size){ PoolByteArray d; d.resize(size * 2); @@ -47,12 +33,8 @@ AudioStreamSample *utils::pcm2Sample( const int16_t * pcm_data, uint32_t size){ d.set( i*2 , (uint8_t) (sh & 0xFF) ); d.set( i*2+1 , (uint8_t) (sh >> 8)); } - print_line( "utils: pcm value at 500: " + itos(pcm_data[500])); - print_line( "utils: pcm value at 700: " + itos(pcm_data[700])); - print_line( "utils: pcm value at 500: " + itos(d[1000])+ " " + itos(d[1001])); - print_line( "before audiostreamsample-set_data: pcm value at 700: " + itos(d[1400])+ " " + itos(d[1401])); + sam->set_data(d); - print_line( "after audiostreamsample-set_data: pcm value at 500: " + itos(sam->get_data()[1000])+ " " + itos(sam->get_data()[1001])); return sam; } diff --git a/modules/mumble/utils.h b/modules/mumble/utils.h index 8a3b86e5420d..6626a4337c2c 100644 --- a/modules/mumble/utils.h +++ b/modules/mumble/utils.h @@ -9,6 +9,5 @@ namespace utils{ std::string gstr2cpp_str(String s); String cpp_str2gstr(std::string s); Variant cpp_uint32vec2Variant( const std::vector &v ); - PoolByteArray pcm2ByteArray( const int16_t * pcm_data, uint32_t size); AudioStreamSample *pcm2Sample( const int16_t * pcm_data, uint32_t size); }