diff --git a/include/mumlib.hpp b/include/mumlib.hpp index ef84744..af979a0 100644 --- a/include/mumlib.hpp +++ b/include/mumlib.hpp @@ -11,6 +11,7 @@ namespace mumlib { constexpr int DEFAULT_OPUS_ENCODER_BITRATE = 16000; + constexpr int DEFAULT_OPUS_SAMPLE_RATE = 48000; using namespace std; using namespace boost::asio; @@ -22,6 +23,7 @@ namespace mumlib { struct MumlibConfiguration { int opusEncoderBitrate = DEFAULT_OPUS_ENCODER_BITRATE; + int opusSampleRate = DEFAULT_OPUS_SAMPLE_RATE; // additional fields will be added in the future }; @@ -30,7 +32,7 @@ namespace mumlib { class Mumlib : boost::noncopyable { public: - Mumlib(Callback &callback); + explicit Mumlib(Callback &callback); Mumlib(Callback &callback, io_service &ioService); @@ -44,10 +46,14 @@ namespace mumlib { void disconnect(); + void reconnect(); + void run(); ConnectionState getConnectionState(); + int getChannelId(); + void sendAudioData(int16_t *pcmData, int pcmLength); void sendAudioDataTarget(int targetId, int16_t *pcmData, int pcmLength); diff --git a/include/mumlib/Audio.hpp b/include/mumlib/Audio.hpp index d98f41a..df3ed11 100644 --- a/include/mumlib/Audio.hpp +++ b/include/mumlib/Audio.hpp @@ -2,19 +2,17 @@ #include "Transport.hpp" -#include +#include #include namespace mumlib { - constexpr int SAMPLE_RATE = 48000; - class MumlibException; class AudioException : public MumlibException { public: - AudioException(string message) : MumlibException(message) { } + explicit AudioException(string message) : MumlibException(message) { } }; struct IncomingAudioPacket { @@ -27,8 +25,8 @@ namespace mumlib { }; class Audio : boost::noncopyable { - public: - Audio(int opusEncoderBitrate = DEFAULT_OPUS_ENCODER_BITRATE); + public: + Audio(int opusSampleRate, int opusEncoderBitrate); virtual ~Audio(); @@ -59,6 +57,7 @@ namespace mumlib { OpusEncoder *opusEncoder; int64_t outgoingSequenceNumber; + int sampleRate; std::chrono::time_point lastEncodedAudioPacketTimestamp; }; diff --git a/include/mumlib/Callback.hpp b/include/mumlib/Callback.hpp index a11b7b4..3e3ac4c 100644 --- a/include/mumlib/Callback.hpp +++ b/include/mumlib/Callback.hpp @@ -153,7 +153,7 @@ namespace mumlib { ~BasicCallback(); - virtual void version( + void version( uint16_t major, uint8_t minor, uint8_t patch, @@ -161,29 +161,29 @@ namespace mumlib { string os, string os_version) override; - virtual void audio( + void audio( int target, int sessionId, int sequenceNumber, int16_t *pcm_data, uint32_t pcm_data_size) override; - virtual void unsupportedAudio( + void unsupportedAudio( int target, int sessionId, int sequenceNumber, uint8_t *encoded_audio_data, uint32_t encoded_audio_data_size) override; - virtual void serverSync( + void serverSync( string welcome_text, int32_t session, int32_t max_bandwidth, int64_t permissions) override; - virtual void channelRemove(uint32_t channel_id) override; + void channelRemove(uint32_t channel_id) override; - virtual void channelState( + void channelState( string name, int32_t channel_id, int32_t parent, @@ -194,13 +194,13 @@ namespace mumlib { bool temporary, int32_t position) override; - virtual void userRemove( + void userRemove( uint32_t session, int32_t actor, string reason, bool ban) override; - virtual void userState( + void userState( int32_t session, int32_t actor, string name, @@ -215,7 +215,7 @@ namespace mumlib { int32_t priority_speaker, int32_t recording) override; - virtual void banList( + void banList( const uint8_t *ip_data, uint32_t ip_data_size, uint32_t mask, @@ -225,14 +225,14 @@ namespace mumlib { string start, int32_t duration) override; - virtual void textMessage( + void textMessage( uint32_t actor, std::vector session, std::vector channel_id, std::vector tree_id, string message) override; - virtual void permissionDenied( + void permissionDenied( int32_t permission, int32_t channel_id, int32_t session, @@ -240,48 +240,48 @@ namespace mumlib { int32_t deny_type, string name) override; - virtual void queryUsers( + void queryUsers( uint32_t n_ids, uint32_t *ids, uint32_t n_names, string *names) override; - virtual void contextActionModify( + void contextActionModify( string action, string text, uint32_t m_context, uint32_t operation) override; - virtual void contextAction( + void contextAction( int32_t session, int32_t channel_id, string action) override; - virtual void userList( + void userList( uint32_t user_id, string name, string last_seen, int32_t last_channel) override; - virtual void permissionQuery( + void permissionQuery( int32_t channel_id, uint32_t permissions, int32_t flush) override; - virtual void codecVersion( + void codecVersion( int32_t alpha, int32_t beta, uint32_t prefer_alpha, int32_t opus) override; - virtual void serverConfig( + void serverConfig( uint32_t max_bandwidth, string welcome_text, uint32_t allow_html, uint32_t message_length, uint32_t image_message_length) override; - virtual void suggestConfig( + void suggestConfig( uint32_t version, uint32_t positional, uint32_t push_to_talk) override; diff --git a/include/mumlib/Transport.hpp b/include/mumlib/Transport.hpp index ccf94a7..f200dca 100644 --- a/include/mumlib/Transport.hpp +++ b/include/mumlib/Transport.hpp @@ -14,6 +14,7 @@ #include #include +#include namespace mumlib { @@ -30,7 +31,7 @@ namespace mumlib { class TransportException : public MumlibException { public: - TransportException(string message) : MumlibException(message) { } + TransportException(string message) : MumlibException(std::move(message)) { } }; class Transport : boost::noncopyable { @@ -49,6 +50,8 @@ namespace mumlib { void disconnect(); + void reconnect(); + ConnectionState getConnectionState() { return state; } diff --git a/include/mumlib/VarInt.hpp b/include/mumlib/VarInt.hpp index 451c61e..5ebacce 100644 --- a/include/mumlib/VarInt.hpp +++ b/include/mumlib/VarInt.hpp @@ -29,6 +29,6 @@ namespace mumlib { private: const int64_t value; - int64_t parseVariant(uint8_t *buffer); + long parseVariant(const uint8_t *buffer); }; } \ No newline at end of file diff --git a/src/Audio.cpp b/src/Audio.cpp index 3ce7594..384942d 100644 --- a/src/Audio.cpp +++ b/src/Audio.cpp @@ -4,20 +4,21 @@ static boost::posix_time::seconds RESET_SEQUENCE_NUMBER_INTERVAL(5); -mumlib::Audio::Audio(int opusEncoderBitrate) +mumlib::Audio::Audio(int opusSampleRate, int opusEncoderBitrate) : logger(log4cpp::Category::getInstance("mumlib.Audio")), opusDecoder(nullptr), opusEncoder(nullptr), outgoingSequenceNumber(0) { int error; + this->sampleRate = opusSampleRate; - opusDecoder = opus_decoder_create(SAMPLE_RATE, 1, &error); + opusDecoder = opus_decoder_create(opusSampleRate, 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); + opusEncoder = opus_encoder_create(opusSampleRate, 1, OPUS_APPLICATION_VOIP, &error); if (error != OPUS_OK) { throw AudioException((boost::format("failed to initialize OPUS encoder: %s") % opus_strerror(error)).str()); } @@ -108,7 +109,7 @@ int mumlib::Audio::encodeAudioPacket(int target, int16_t *inputPcmBuffer, int in std::vector header; - header.push_back(0x80 | target); + header.push_back(static_cast(0x80 | target)); auto sequenceNumberEnc = VarInt(outgoingSequenceNumber).getEncoded(); header.insert(header.end(), sequenceNumberEnc.begin(), sequenceNumberEnc.end()); @@ -130,15 +131,15 @@ int mumlib::Audio::encodeAudioPacket(int target, int16_t *inputPcmBuffer, int in header.insert(header.end(), outputSizeEnc.begin(), outputSizeEnc.end()); memcpy(outputBuffer, &header[0], header.size()); - memcpy(outputBuffer + header.size(), tmpOpusBuffer, outputSize); + memcpy(outputBuffer + header.size(), tmpOpusBuffer, (size_t) outputSize); - int incrementNumber = 100 * inputLength / SAMPLE_RATE; + int incrementNumber = 100 * inputLength / this->sampleRate; outgoingSequenceNumber += incrementNumber; lastEncodedAudioPacketTimestamp = std::chrono::system_clock::now(); - return outputSize + header.size(); + return static_cast(outputSize + header.size()); } void mumlib::Audio::resetEncoder() { @@ -152,7 +153,7 @@ void mumlib::Audio::resetEncoder() { } mumlib::IncomingAudioPacket mumlib::Audio::decodeIncomingAudioPacket(uint8_t *inputBuffer, int inputBufferLength) { - mumlib::IncomingAudioPacket incomingAudioPacket; + mumlib::IncomingAudioPacket incomingAudioPacket{}; incomingAudioPacket.type = static_cast((inputBuffer[0] & 0xE0) >> 5); incomingAudioPacket.target = inputBuffer[0] & 0x1F; diff --git a/src/Callback.cpp b/src/Callback.cpp index ea8fb80..5bc69e3 100644 --- a/src/Callback.cpp +++ b/src/Callback.cpp @@ -35,7 +35,7 @@ void mumlib::BasicCallback::version( os_version.c_str()); } -void mumlib::BasicCallback::audio( +void BasicCallback::audio( int target, int sessionId, int sequenceNumber, diff --git a/src/Transport.cpp b/src/Transport.cpp index f134512..e016f50 100644 --- a/src/Transport.cpp +++ b/src/Transport.cpp @@ -3,6 +3,7 @@ #include "Mumble.pb.h" #include +#include using namespace std; @@ -32,15 +33,15 @@ mumlib::Transport::Transport( bool noUdp) : logger(log4cpp::Category::getInstance("mumlib.Transport")), ioService(ioService), - processMessageFunction(processMessageFunc), - processEncodedAudioPacketFunction(processEncodedAudioPacketFunction), + processMessageFunction(std::move(processMessageFunc)), + processEncodedAudioPacketFunction(std::move(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)) { + asyncBufferPool(static_cast(max(MAX_UDP_LENGTH, MAX_TCP_LENGTH))) { sslIncomingBuffer = new uint8_t[MAX_TCP_LENGTH]; @@ -118,6 +119,15 @@ void mumlib::Transport::disconnect() { } } +void mumlib::Transport::reconnect() { + boost::system::error_code errorCode; + + udpSocket.close(errorCode); + if (errorCode) { + logger.warn("SSL socket close return an error: %s.", errorCode.message().c_str()); + } +} + void mumlib::Transport::sendVersion() { MumbleProto::Version version; @@ -185,10 +195,10 @@ void mumlib::Transport::doReceiveUdp() { } uint8_t plainBuffer[1024]; - const int plainBufferLength = bytesTransferred - 4; + const int plainBufferLength = static_cast(bytesTransferred - 4); bool success = cryptState.decrypt( - udpIncomingBuffer, plainBuffer, bytesTransferred); + udpIncomingBuffer, plainBuffer, static_cast(bytesTransferred)); if (not success) { throwTransportException("UDP packet decryption failed"); @@ -263,12 +273,12 @@ void mumlib::Transport::sendUdpAsync(uint8_t *buff, int length) { auto *encryptedMsgBuff = asyncBufferPool.malloc(); const int encryptedMsgLength = length + 4; - cryptState.encrypt(buff, reinterpret_cast(encryptedMsgBuff), length); + cryptState.encrypt(buff, reinterpret_cast(encryptedMsgBuff), static_cast(length)); logger.debug("Sending %d B of data UDP asynchronously.", encryptedMsgLength); udpSocket.async_send_to( - boost::asio::buffer(encryptedMsgBuff, length + 4), + boost::asio::buffer(encryptedMsgBuff, static_cast(length + 4)), udpReceiverEndpoint, [this, encryptedMsgBuff](const boost::system::error_code &ec, size_t bytesTransferred) { asyncBufferPool.free(encryptedMsgBuff); @@ -318,7 +328,7 @@ void mumlib::Transport::doReceiveSsl() { processMessageInternal( static_cast(messageType), &sslIncomingBuffer[6], - bytesTransferred - 6); + static_cast(bytesTransferred - 6)); doReceiveSsl(); } else { @@ -438,10 +448,10 @@ void mumlib::Transport::sendUdpPing() { vector message; message.push_back(0x20); - auto timestampVarint = VarInt(time(nullptr)).getEncoded(); + auto timestampVarint = VarInt(static_cast(time(nullptr))).getEncoded(); message.insert(message.end(), timestampVarint.begin(), timestampVarint.end()); - sendUdpAsync(&message[0], message.size()); + sendUdpAsync(&message[0], static_cast(message.size())); } void mumlib::Transport::sendSsl(uint8_t *buff, int length) { @@ -453,7 +463,7 @@ void mumlib::Transport::sendSsl(uint8_t *buff, int length) { logger.debug("Sending %d bytes of data.", length); try { - write(sslSocket, boost::asio::buffer(buff, length)); + write(sslSocket, boost::asio::buffer(buff, static_cast(length))); } catch (boost::system::system_error &err) { throwTransportException(std::string("SSL send failed: ") + err.what()); } @@ -467,13 +477,13 @@ void mumlib::Transport::sendSslAsync(uint8_t *buff, int length) { auto *asyncBuff = asyncBufferPool.malloc(); - memcpy(asyncBuff, buff, length); + memcpy(asyncBuff, buff, static_cast(length)); logger.debug("Sending %d B of data asynchronously.", length); async_write( sslSocket, - boost::asio::buffer(asyncBuff, length), + boost::asio::buffer(asyncBuff, static_cast(length)), [this, asyncBuff](const boost::system::error_code &ec, size_t bytesTransferred) { asyncBufferPool.free(asyncBuff); logger.debug("Sent %d B.", bytesTransferred); @@ -499,7 +509,7 @@ void mumlib::Transport::sendControlMessagePrivate(MessageType type, google::prot const uint16_t type_network = htons(static_cast(type)); const int size = message.ByteSize(); - const uint32_t size_network = htonl(size); + const uint32_t size_network = htonl((uint32_t) size); const int length = sizeof(type_network) + sizeof(size_network) + size; @@ -517,7 +527,7 @@ void mumlib::Transport::sendControlMessagePrivate(MessageType type, google::prot void mumlib::Transport::throwTransportException(string message) { state = ConnectionState::FAILED; - throw TransportException(message); + throw TransportException(std::move(message)); } void mumlib::Transport::sendEncodedAudioPacket(uint8_t *buffer, int length) { @@ -534,7 +544,7 @@ void mumlib::Transport::sendEncodedAudioPacket(uint8_t *buffer, int length) { const uint16_t netUdptunnelType = htons(static_cast(MessageType::UDPTUNNEL)); - const uint32_t netLength = htonl(length); + const uint32_t netLength = htonl(static_cast(length)); const int packet = sizeof(netUdptunnelType) + sizeof(netLength) + length; @@ -542,14 +552,14 @@ void mumlib::Transport::sendEncodedAudioPacket(uint8_t *buffer, int length) { memcpy(packetBuff, &netUdptunnelType, sizeof(netUdptunnelType)); memcpy(packetBuff + sizeof(netUdptunnelType), &netLength, sizeof(netLength)); - memcpy(packetBuff + sizeof(netUdptunnelType) + sizeof(netLength), buffer, length); + memcpy(packetBuff + sizeof(netUdptunnelType) + sizeof(netLength), buffer, static_cast(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); + auto type = static_cast((buff[0] & 0xE0) >> 5); switch (type) { case AudioPacketType::CELT_Alpha: case AudioPacketType::Speex: diff --git a/src/VarInt.cpp b/src/VarInt.cpp index 2eeebf8..bd489da 100644 --- a/src/VarInt.cpp +++ b/src/VarInt.cpp @@ -12,7 +12,7 @@ mumlib::VarInt::VarInt(std::vector encoded) : value(parseVariant(&encod * 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 mumlib::VarInt::parseVariant(const uint8_t *buffer) { int64_t v = buffer[0]; if ((v & 0x80) == 0x00) { return (v & 0x7F); @@ -36,6 +36,7 @@ int64_t mumlib::VarInt::parseVariant(uint8_t *buffer) { return (v & 0x1F) << 16 | buffer[1] << 8 | buffer[2]; } + throw VarIntException("invalid varint"); } @@ -46,7 +47,7 @@ std::vector mumlib::VarInt::getEncoded() const { if ((i & 0x8000000000000000LL) && (~i < 0x100000000LL)) { i = ~i; if (i <= 0x3) { - encoded.push_back(0xFC | i); + encoded.push_back(static_cast(0xFC | i)); return encoded; } else { encoded.push_back(0xF8); @@ -54,29 +55,29 @@ std::vector mumlib::VarInt::getEncoded() const { } if (i < 0x80) { - encoded.push_back(i); + encoded.push_back(static_cast(i)); } else if (i < 0x4000) { - encoded.push_back(0x80 | (i >> 8)); - encoded.push_back(i & 0xFF); + encoded.push_back(static_cast(0x80 | (i >> 8))); + encoded.push_back(static_cast(i & 0xFF)); } else if (i < 0x200000) { - encoded.push_back(0xC0 | (i >> 16)); - encoded.push_back((i >> 8) & 0xFF); - encoded.push_back(i & 0xFF); + encoded.push_back(static_cast(0xC0 | (i >> 16))); + encoded.push_back(static_cast((i >> 8) & 0xFF)); + encoded.push_back(static_cast(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); + encoded.push_back(static_cast(0xE0 | (i >> 24))); + encoded.push_back(static_cast((i >> 16) & 0xFF)); + encoded.push_back(static_cast((i >> 8) & 0xFF)); + encoded.push_back(static_cast(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); + encoded.push_back(static_cast((i >> 56) & 0xFF)); + encoded.push_back(static_cast((i >> 48) & 0xFF)); + encoded.push_back(static_cast((i >> 40) & 0xFF)); + encoded.push_back(static_cast((i >> 32) & 0xFF)); + encoded.push_back(static_cast((i >> 24) & 0xFF)); + encoded.push_back(static_cast((i >> 16) & 0xFF)); + encoded.push_back(static_cast((i >> 8) & 0xFF)); + encoded.push_back(static_cast(i & 0xFF)); } return encoded; diff --git a/src/mumlib.cpp b/src/mumlib.cpp index 16e5c4b..6f7038f 100644 --- a/src/mumlib.cpp +++ b/src/mumlib.cpp @@ -43,7 +43,8 @@ namespace mumlib { 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(configuration.opusSampleRate, configuration.opusEncoderBitrate) { audio.setOpusEncoderBitrate(configuration.opusEncoderBitrate); } @@ -363,6 +364,10 @@ namespace mumlib { return impl->transport.getConnectionState(); } + int Mumlib::getChannelId() { + return impl->channelId; + } + void Mumlib::connect(string host, int port, string user, string password) { impl->transport.connect(host, port, user, password); } @@ -376,6 +381,15 @@ namespace mumlib { } } + void Mumlib::reconnect() { + if (not impl->externalIoService) { + impl->ioService.reset(); + } + if (impl->transport.getConnectionState() != ConnectionState::NOT_CONNECTED) { + impl->transport.disconnect(); + } + } + void Mumlib::run() { if (impl->externalIoService) { throw MumlibException("can't call run() when using external io_service");