diff --git a/include/mumlib.hpp b/include/mumlib.hpp index 96b2165..cab8e31 100644 --- a/include/mumlib.hpp +++ b/include/mumlib.hpp @@ -65,9 +65,9 @@ namespace mumlib { int getChannelId(); - vector getListUser(); + vector getListAllUser(); - vector getListChannel(); + vector getListAllChannel(); void sendAudioData(int16_t *pcmData, int pcmLength); @@ -79,9 +79,9 @@ namespace mumlib { void joinChannel(std::string channelName); - void sendVoiceTarget(int targetId, int channelId); + void sendVoiceTarget(mumlib::VoiceTargetType type, int targetId, int id); - void sendVoiceTarget(int targetId, std::string channelName); + bool sendVoiceTarget(mumlib::VoiceTargetType type, int targetId, std::string name); void sendUserState(mumlib::UserState state, bool val); @@ -90,6 +90,8 @@ namespace mumlib { private: _Mumlib_Private *impl; - int getListChannelIdBy(std::string channelName); + int getChannelIdBy(std::string channelName); + + int getUserIdBy(std::string userName); }; } diff --git a/include/mumlib/enums.hpp b/include/mumlib/enums.hpp index ea189f9..740d83b 100644 --- a/include/mumlib/enums.hpp +++ b/include/mumlib/enums.hpp @@ -55,4 +55,9 @@ namespace mumlib { PRIORITY_SPEAKER, RECORDING }; + + enum class VoiceTargetType { + CHANNEL, + USER + }; } \ No newline at end of file diff --git a/src/Audio.cpp b/src/Audio.cpp index 2a0eac2..60277df 100644 --- a/src/Audio.cpp +++ b/src/Audio.cpp @@ -76,6 +76,16 @@ std::pair mumlib::Audio::decodeOpusPayload(uint8_t *inputBuffer, % inputLength % dataPointer % opusDataLength).str()); } + // Issue #3 (Users speaking simultaneously) + // https://mf4.xiph.org/jenkins/view/opus/job/opus/ws/doc/html/group__opus__decoder.html + // Opus is a stateful codec with overlapping blocks and as a result Opus packets are not coded independently of each other. + // Packets must be passed into the decoder serially and in the correct order for a correct decode. + // Lost packets can be replaced with loss concealment by calling the decoder with a null pointer and zero length for the missing packet. + // A single codec state may only be accessed from a single thread at a time and any required locking must be performed by the caller. + // Separate streams must be decoded with separate decoder states and can be decoded in parallel unless the library was compiled with NONTHREADSAFE_PSEUDOSTACK defined. + + int frame = opus_packet_get_nb_frames(&inputBuffer[dataPointer], opusDataLength); + int samples = frame * opus_packet_get_samples_per_frame(&inputBuffer[dataPointer], sampleRate); int outputSize = opus_decode(opusDecoder, reinterpret_cast(&inputBuffer[dataPointer]), opusDataLength, @@ -133,7 +143,7 @@ int mumlib::Audio::encodeAudioPacket(int target, int16_t *inputPcmBuffer, int in memcpy(outputBuffer, &header[0], header.size()); memcpy(outputBuffer + header.size(), tmpOpusBuffer, (size_t) outputSize); - int incrementNumber = 100 * inputLength / this->sampleRate; + int incrementNumber = 100 * inputLength / sampleRate; outgoingSequenceNumber += incrementNumber; diff --git a/src/CryptState.cpp b/src/CryptState.cpp index 55ca26d..e1763c3 100644 --- a/src/CryptState.cpp +++ b/src/CryptState.cpp @@ -191,34 +191,13 @@ bool mumlib::CryptState::decrypt(const unsigned char *source, unsigned char *dst return true; } -#if defined(__LP64__) - #define BLOCKSIZE 2 #define SHIFTBITS 63 typedef uint64_t subblock; -#ifdef __x86_64__ -static inline uint64_t SWAP64(register uint64_t __in) { register uint64_t __out; __asm__("bswap %q0" : "=r"(__out) : "0"(__in)); return __out; } -#else -#define SWAP64(x) ((static_cast(x) << 56) | \ - ((static_cast(x) << 40) & 0xff000000000000ULL) | \ - ((static_cast(x) << 24) & 0xff0000000000ULL) | \ - ((static_cast(x) << 8) & 0xff00000000ULL) | \ - ((static_cast(x) >> 8) & 0xff000000ULL) | \ - ((static_cast(x) >> 24) & 0xff0000ULL) | \ - ((static_cast(x) >> 40) & 0xff00ULL) | \ - ((static_cast(x) >> 56))) -#endif -// #define SWAP64(x) (__builtin_bswap64(x)) +#define SWAP64(x) (__builtin_bswap64(x)) #define SWAPPED(x) SWAP64(x) -#else -#define BLOCKSIZE 4 -#define SHIFTBITS 31 -typedef uint32_t subblock; -#define SWAPPED(x) htonl(x) -#endif - typedef subblock keyblock[BLOCKSIZE]; static void inline XOR(subblock *dst, const subblock *a, const subblock *b) { diff --git a/src/mumlib.cpp b/src/mumlib.cpp index ff3c76b..c8101b5 100644 --- a/src/mumlib.cpp +++ b/src/mumlib.cpp @@ -65,6 +65,8 @@ namespace mumlib { auto incomingAudioPacket = audio.decodeIncomingAudioPacket(buffer, length); if (type == AudioPacketType::OPUS) { + // todo: multiple users speaking simultaneously (Issue #3) + // something weird while decoding the opus payload int16_t pcmData[5000]; auto status = audio.decodeOpusPayload(incomingAudioPacket.audioPayload, incomingAudioPacket.audioPayloadLength, @@ -127,6 +129,11 @@ namespace mumlib { case MessageType::CHANNELREMOVE: { MumbleProto::ChannelRemove channelRemove; channelRemove.ParseFromArray(buffer, length); + + if(isListChannelContains(channelRemove.channel_id())) { + listChannelRemovedBy(channelRemove.channel_id()); + } + callback.channelRemove(channelRemove.channel_id()); } break; @@ -381,6 +388,12 @@ namespace mumlib { return true; return false; } + + void listChannelRemovedBy(int channelId) { + for(int i = 0; i < listMumbleChannel.size(); i++) + if(listMumbleChannel[i].channelId == channelId) + listMumbleChannel.erase(listMumbleChannel.begin() + i); + } }; Mumlib::Mumlib(Callback &callback) { @@ -413,11 +426,11 @@ namespace mumlib { return impl->channelId; } - vector Mumlib::getListUser() { + vector Mumlib::getListAllUser() { return impl->listMumbleUser; } - vector Mumlib::getListChannel() { + vector Mumlib::getListAllChannel() { return impl->listMumbleChannel; } @@ -468,23 +481,48 @@ namespace mumlib { } void Mumlib::joinChannel(string name) { - int channelId = Mumlib::getListChannelIdBy(name); - Mumlib::joinChannel(channelId); + int channelId = Mumlib::getChannelIdBy(name); + if(!channelId < 0) // when channel has not been registered / create + Mumlib::joinChannel(channelId); } - void Mumlib::sendVoiceTarget(int targetId, int channelId) { + void Mumlib::sendVoiceTarget(VoiceTargetType type, int targetId, int id) { MumbleProto::VoiceTarget voiceTarget; MumbleProto::VoiceTarget_Target voiceTargetTarget; - voiceTargetTarget.set_channel_id(channelId); - voiceTargetTarget.set_children(true); + switch(type) { + case VoiceTargetType::CHANNEL: { + voiceTargetTarget.set_channel_id(id); + voiceTargetTarget.set_children(true); + } + break; + case VoiceTargetType::USER: { + voiceTargetTarget.add_session(id); + } + break; + default: + return; + } voiceTarget.set_id(targetId); voiceTarget.add_targets()->CopyFrom(voiceTargetTarget); impl->transport.sendControlMessage(MessageType::VOICETARGET, voiceTarget); } - void Mumlib::sendVoiceTarget(int targetId, string channelName) { - int channelId = Mumlib::getListChannelIdBy(channelName); - Mumlib::sendVoiceTarget(targetId, channelId); + bool Mumlib::sendVoiceTarget(VoiceTargetType type, int targetId, string name) { + int id = -1; + switch(type) { + case VoiceTargetType::CHANNEL: + id = getChannelIdBy(name); + break; + case VoiceTargetType::USER: + id = getUserIdBy(name); + break; + default: + break; + } + if(id < 0) + return false; + sendVoiceTarget(type, targetId, id); + return true; } void Mumlib::sendUserState(mumlib::UserState field, bool val) { @@ -551,12 +589,21 @@ namespace mumlib { impl->transport.sendControlMessage(MessageType::USERSTATE, userState); } - int Mumlib::getListChannelIdBy(string name) { + int Mumlib::getChannelIdBy(string name) { vector listMumbleChannel = impl->listMumbleChannel; - int channelId = impl->channelId; + int channelId = -1; for(int i = 0; i < listMumbleChannel.size(); i++) if(listMumbleChannel[i].name == name) channelId = listMumbleChannel[i].channelId; return channelId; } + + int Mumlib::getUserIdBy(string name) { + vector listMumbleUser = impl->listMumbleUser; + int sessionId = -1; + for(int i = 0; i < listMumbleUser.size(); i++) + if(listMumbleUser[i].name == name) + sessionId = listMumbleUser[i].sessionId; + return sessionId; + } }