From e166bae1ea1f73409cf43713c7fffb6156cb0ad3 Mon Sep 17 00:00:00 2001 From: Dmytro Bogovych Date: Thu, 3 Sep 2026 10:03:42 +0300 Subject: [PATCH] - clang format + naming improved --- src/engine/agent/Agent_AudioManager.cpp | 16 +- src/engine/agent/Agent_AudioManager.h | 33 +- src/engine/agent/Agent_Impl.cpp | 293 +- src/engine/agent/Agent_Impl.h | 85 +- src/engine/agent/Agent_Interface.cpp | 21 +- src/engine/agent/Agent_Interface.h | 12 +- src/engine/audio/Audio_Android.cpp | 750 ++-- src/engine/audio/Audio_Android.h | 185 +- src/engine/audio/Audio_AndroidOboe.cpp | 343 +- src/engine/audio/Audio_AndroidOboe.h | 133 +- src/engine/audio/Audio_CoreAudio.cpp | 899 ++-- src/engine/audio/Audio_CoreAudio.h | 199 +- src/engine/audio/Audio_DataWindow.cpp | 19 +- src/engine/audio/Audio_DataWindow.h | 42 +- src/engine/audio/Audio_DevicePair.cpp | 328 +- src/engine/audio/Audio_DevicePair.h | 72 +- src/engine/audio/Audio_DirectSound.cpp | 301 +- src/engine/audio/Audio_DirectSound.h | 158 +- src/engine/audio/Audio_Helper.cpp | 143 +- src/engine/audio/Audio_Helper.h | 62 +- src/engine/audio/Audio_Interface.cpp | 58 +- src/engine/audio/Audio_Interface.h | 88 +- src/engine/audio/Audio_Mixer.cpp | 457 +-- src/engine/audio/Audio_Mixer.h | 69 +- src/engine/audio/Audio_Null.cpp | 49 +- src/engine/audio/Audio_Null.h | 62 +- src/engine/audio/Audio_Player.cpp | 179 +- src/engine/audio/Audio_Player.h | 65 +- src/engine/audio/Audio_Quality.cpp | 248 +- src/engine/audio/Audio_Quality.h | 69 +- src/engine/audio/Audio_Resampler.cpp | 79 +- src/engine/audio/Audio_Resampler.h | 149 +- src/engine/audio/Audio_WavFile.cpp | 58 +- src/engine/audio/Audio_WavFile.h | 80 +- src/engine/audio/Audio_Wmme.cpp | 693 ++-- src/engine/audio/Audio_Wmme.h | 168 +- src/engine/audio/Audio_iOS.cpp | 1 - src/engine/audio/Audio_iOS.h | 46 +- src/engine/endpoint/EP_Account.cpp | 194 +- src/engine/endpoint/EP_Account.h | 69 +- src/engine/endpoint/EP_AudioProvider.cpp | 74 +- src/engine/endpoint/EP_AudioProvider.h | 149 +- src/engine/endpoint/EP_DataProvider.cpp | 52 +- src/engine/endpoint/EP_DataProvider.h | 38 +- src/engine/endpoint/EP_Engine.cpp | 607 ++- src/engine/endpoint/EP_Engine.h | 275 +- src/engine/endpoint/EP_NetworkQueue.cpp | 23 +- src/engine/endpoint/EP_NetworkQueue.h | 34 +- src/engine/endpoint/EP_Observer.cpp | 25 +- src/engine/endpoint/EP_Observer.h | 26 +- src/engine/endpoint/EP_ReliableTunnel.cpp | 287 +- src/engine/endpoint/EP_ReliableTunnel.h | 173 +- src/engine/endpoint/EP_Session.cpp | 224 +- src/engine/endpoint/EP_Session.h | 516 ++- src/engine/engine_config.h | 32 +- src/engine/helper/HL_AsyncCommand.cpp | 10 +- src/engine/helper/HL_AsyncCommand.h | 8 +- src/engine/helper/HL_Base64.h | 430 +- src/engine/helper/HL_ByteBuffer.h | 8 +- src/engine/helper/HL_Calculator.h | 947 ++--- src/engine/helper/HL_CrashRpt.cpp | 165 +- src/engine/helper/HL_CrashRpt.h | 39 +- src/engine/helper/HL_CsvReader.cpp | 27 +- src/engine/helper/HL_CsvReader.h | 12 +- src/engine/helper/HL_Exception.h | 74 +- src/engine/helper/HL_File.cpp | 22 +- src/engine/helper/HL_File.h | 12 +- src/engine/helper/HL_HepSupport.cpp | 81 +- src/engine/helper/HL_HepSupport.h | 58 +- src/engine/helper/HL_IuUP.cpp | 1975 ++++----- src/engine/helper/HL_IuUP.h | 47 +- src/engine/helper/HL_Log.cpp | 1 - src/engine/helper/HL_Log.h | 8 +- src/engine/helper/HL_NetworkFrame.cpp | 53 +- src/engine/helper/HL_NetworkFrame.h | 99 +- src/engine/helper/HL_NetworkSocket.cpp | 49 +- src/engine/helper/HL_NetworkSocket.h | 40 +- src/engine/helper/HL_Optional.hpp | 1382 ++++--- src/engine/helper/HL_OsVersion.cpp | 122 +- src/engine/helper/HL_OsVersion.h | 18 +- src/engine/helper/HL_Pointer.cpp | 56 +- src/engine/helper/HL_Pointer.h | 18 +- src/engine/helper/HL_PoolAllocator.h | 627 +-- src/engine/helper/HL_Process.cpp | 342 +- src/engine/helper/HL_Process.h | 12 +- src/engine/helper/HL_Rtp.cpp | 127 +- src/engine/helper/HL_Rtp.h | 73 +- src/engine/helper/HL_Singletone.h | 9 +- src/engine/helper/HL_SocketHeap.cpp | 55 +- src/engine/helper/HL_SocketHeap.h | 73 +- src/engine/helper/HL_Statistics.h | 41 +- src/engine/helper/HL_StreamState.h | 15 +- src/engine/helper/HL_String.cpp | 118 +- src/engine/helper/HL_String.h | 63 +- src/engine/helper/HL_Sync.cpp | 84 +- src/engine/helper/HL_Sync.h | 62 +- src/engine/helper/HL_ThreadPool.cpp | 6 +- src/engine/helper/HL_ThreadPool.h | 20 +- src/engine/helper/HL_Time.cpp | 9 +- src/engine/helper/HL_Time.h | 10 +- src/engine/helper/HL_Types.h | 108 +- src/engine/helper/HL_Usb.cpp | 117 +- src/engine/helper/HL_Usb.h | 36 +- src/engine/helper/HL_Uuid.cpp | 12 +- src/engine/helper/HL_Uuid.h | 2 +- src/engine/helper/HL_VariantMap.cpp | 149 +- src/engine/helper/HL_VariantMap.h | 121 +- src/engine/helper/HL_Xcap.cpp | 82 +- src/engine/media/MT_AmrCodec.cpp | 257 +- src/engine/media/MT_AmrCodec.h | 112 +- src/engine/media/MT_AudioCodec.cpp | 521 ++- src/engine/media/MT_AudioCodec.h | 244 +- src/engine/media/MT_AudioReceiver.cpp | 263 +- src/engine/media/MT_AudioReceiver.h | 265 +- src/engine/media/MT_AudioStream.cpp | 122 +- src/engine/media/MT_AudioStream.h | 98 +- src/engine/media/MT_Box.cpp | 132 +- src/engine/media/MT_Box.h | 40 +- src/engine/media/MT_CngHelper.cpp | 177 +- src/engine/media/MT_CngHelper.h | 22 +- src/engine/media/MT_Codec.cpp | 7 +- src/engine/media/MT_Codec.h | 64 +- src/engine/media/MT_CodecList.cpp | 167 +- src/engine/media/MT_CodecList.h | 108 +- src/engine/media/MT_Dtmf.cpp | 598 ++- src/engine/media/MT_Dtmf.h | 35 +- src/engine/media/MT_EvsCodec.cpp | 292 +- src/engine/media/MT_EvsCodec.h | 39 +- src/engine/media/MT_NativeRtpSender.cpp | 20 +- src/engine/media/MT_NativeRtpSender.h | 30 +- src/engine/media/MT_SingleAudioStream.cpp | 30 +- src/engine/media/MT_SingleAudioStream.h | 4 +- src/engine/media/MT_SrtpHelper.cpp | 149 +- src/engine/media/MT_SrtpHelper.h | 65 +- src/engine/media/MT_Statistics.cpp | 245 +- src/engine/media/MT_Statistics.h | 106 +- src/engine/media/MT_Stream.cpp | 91 +- src/engine/media/MT_Stream.h | 97 +- src/engine/media/MT_WebRtc.cpp | 48 +- src/engine/media/MT_WebRtc.h | 26 +- src/libs/ice/ICEAction.h | 41 +- src/libs/ice/ICEAddress.cpp | 1138 +++--- src/libs/ice/ICEAddress.h | 85 +- src/libs/ice/ICEAuthTransaction.cpp | 335 +- src/libs/ice/ICEAuthTransaction.h | 69 +- src/libs/ice/ICEBinding.cpp | 665 ++- src/libs/ice/ICEBinding.h | 159 +- src/libs/ice/ICEBox.cpp | 36 +- src/libs/ice/ICEBox.h | 293 +- src/libs/ice/ICEBoxImpl.cpp | 436 +- src/libs/ice/ICEBoxImpl.h | 143 +- src/libs/ice/ICEByteBuffer.cpp | 119 +- src/libs/ice/ICEByteBuffer.h | 217 +- src/libs/ice/ICECRC32.cpp | 64 +- src/libs/ice/ICECRC32.h | 32 +- src/libs/ice/ICECandidate.cpp | 213 +- src/libs/ice/ICECandidate.h | 106 +- src/libs/ice/ICECandidatePair.cpp | 189 +- src/libs/ice/ICECandidatePair.h | 136 +- src/libs/ice/ICECheckList.cpp | 562 ++- src/libs/ice/ICECheckList.h | 103 +- src/libs/ice/ICEError.cpp | 58 +- src/libs/ice/ICEError.h | 40 +- src/libs/ice/ICEEvent.h | 58 +- src/libs/ice/ICEHMAC.cpp | 82 +- src/libs/ice/ICEHMAC.h | 47 +- src/libs/ice/ICEIosSupport.h | 6 +- src/libs/ice/ICEIosSupport.mm | 344 +- src/libs/ice/ICELog.cpp | 192 +- src/libs/ice/ICELog.h | 137 +- src/libs/ice/ICEMD5.cpp | 17 +- src/libs/ice/ICEMD5.h | 2 +- src/libs/ice/ICENetworkHelper.cpp | 656 ++- src/libs/ice/ICENetworkHelper.h | 78 +- src/libs/ice/ICEPacketTimer.cpp | 82 +- src/libs/ice/ICEPacketTimer.h | 42 +- src/libs/ice/ICEPlatform.cpp | 18 +- src/libs/ice/ICEPlatform.h | 64 +- src/libs/ice/ICERelaying.cpp | 407 +- src/libs/ice/ICERelaying.h | 162 +- src/libs/ice/ICEReliableTransport.cpp | 618 ++- src/libs/ice/ICEReliableTransport.h | 170 +- src/libs/ice/ICESHA1.cpp | 14 +- src/libs/ice/ICESession.cpp | 1072 +++-- src/libs/ice/ICESession.h | 250 +- src/libs/ice/ICESocket.h | 20 +- src/libs/ice/ICEStream.cpp | 4531 +++++++++++---------- src/libs/ice/ICEStream.h | 374 +- src/libs/ice/ICEStunAttributes.cpp | 854 ++-- src/libs/ice/ICEStunAttributes.h | 603 +-- src/libs/ice/ICEStunConfig.cpp | 15 +- src/libs/ice/ICEStunConfig.h | 84 +- src/libs/ice/ICEStunMessage.cpp | 1191 +++--- src/libs/ice/ICEStunMessage.h | 272 +- src/libs/ice/ICEStunTransaction.cpp | 470 +-- src/libs/ice/ICEStunTransaction.h | 296 +- src/libs/ice/ICESync.cpp | 63 +- src/libs/ice/ICESync.h | 34 +- src/libs/ice/ICETime.cpp | 221 +- src/libs/ice/ICETime.h | 104 +- src/libs/ice/ICETransactionList.cpp | 379 +- src/libs/ice/ICETransactionList.h | 61 +- src/libs/ice/ICETypes.h | 2 +- test/rtp_decode/main.cpp | 191 +- 204 files changed, 20621 insertions(+), 21019 deletions(-) diff --git a/src/engine/agent/Agent_AudioManager.cpp b/src/engine/agent/Agent_AudioManager.cpp index e2c41774..1b0b1562 100644 --- a/src/engine/agent/Agent_AudioManager.cpp +++ b/src/engine/agent/Agent_AudioManager.cpp @@ -9,14 +9,13 @@ #include "HL_String.h" #if defined(TARGET_ANDROID) -# include "../engine/audio/Audio_Android.h" +#include "../engine/audio/Audio_Android.h" #endif #define LOG_SUBSYSTEM "audio" -AudioManager::AudioManager() - :mTerminal(nullptr), mAudioMonitoring(nullptr) +AudioManager::AudioManager() : mTerminal(nullptr), mAudioMonitoring(nullptr) { mPlayer.setDelegate(this); } @@ -92,7 +91,7 @@ void AudioManager::start(int usageId) if (!mAudioOutput) { - Audio::Enumerator *enumerator = Audio::Enumerator::make(usageId == atNull); + Audio::Enumerator* enumerator = Audio::Enumerator::make(usageId == atNull); enumerator->open(Audio::mySpeaker); int outputIndex = enumerator->indexOfDefaultDevice(); @@ -102,8 +101,7 @@ void AudioManager::start(int usageId) if (outputIndex >= enumerator->count()) outputIndex = 0; - mAudioOutput = Audio::POutputDevice( - Audio::OutputDevice::make(enumerator->idAt(outputIndex))); + mAudioOutput = Audio::POutputDevice(Audio::OutputDevice::make(enumerator->idAt(outputIndex))); } else mAudioOutput = Audio::POutputDevice(new Audio::NullOutputDevice()); @@ -139,7 +137,7 @@ void AudioManager::stop(int usageId) { LOCK_MANAGER; - ICELogInfo( << "Stop main audio with usage id " << usageId); + ICELogInfo(<< "Stop main audio with usage id " << usageId); if (mTerminal) { if (mTerminal->audio()) @@ -196,9 +194,7 @@ void AudioManager::stopPlayFile(int usageId) mPlayer.release(usageId); } -void AudioManager::onFilePlayed(Audio::Player::PlaylistItem& item) -{ -} +void AudioManager::onFilePlayed(Audio::Player::PlaylistItem& item) {} void AudioManager::process() { diff --git a/src/engine/agent/Agent_AudioManager.h b/src/engine/agent/Agent_AudioManager.h index d0d05682..122a3acd 100644 --- a/src/engine/agent/Agent_AudioManager.h +++ b/src/engine/agent/Agent_AudioManager.h @@ -11,7 +11,6 @@ #include "../engine/media/MT_Box.h" - enum { AudioPrefix_Ring = 1, @@ -31,7 +30,7 @@ enum #define AudioSessionCoeff 64 -class AudioManager: public Audio::Player::EndOfAudioDelegate +class AudioManager : public Audio::Player::EndOfAudioDelegate { public: AudioManager(); @@ -40,24 +39,24 @@ public: // static AudioManager& instance(); // Enforces to close audio devices. Used to shutdown AudioManager on exit from application - void close(); + void close(); // Terminal and settings must be available for AudioManager - void setTerminal(MT::Terminal* terminal); - MT::Terminal* terminal(); + void setTerminal(MT::Terminal* terminal); + MT::Terminal* terminal(); - void setAudioMonitoring(Audio::DataConnection* monitoring); + void setAudioMonitoring(Audio::DataConnection* monitoring); Audio::DataConnection* audioMonitoring(); // Start/stop methods relies on usage counter; only first start and last stop opens/closes devices actually - void start(int usageId); - void stop(int usageId); + void start(int usageId); + void stop(int usageId); // Inject a custom input device. Must be called before start(): when set, // start() skips construction of the default platform microphone. Pass an // empty pointer to clear the override. - void setAudioInput(Audio::PInputDevice input); - void setAudioOutput(Audio::POutputDevice output); + void setAudioInput(Audio::PInputDevice input); + void setAudioOutput(Audio::POutputDevice output); enum AudioTarget { @@ -82,14 +81,14 @@ public: void process(); protected: - Audio::PInputDevice mAudioInput; - Audio::POutputDevice mAudioOutput; - Audio::Player mPlayer; - MT::Terminal* mTerminal; + Audio::PInputDevice mAudioInput; + Audio::POutputDevice mAudioOutput; + Audio::Player mPlayer; + MT::Terminal* mTerminal; Audio::DataConnection* mAudioMonitoring; - std::map UsageMap; - UsageCounter mUsage; - std::mutex mGuard; + std::map UsageMap; + UsageCounter mUsage; + std::mutex mGuard; }; #endif diff --git a/src/engine/agent/Agent_Impl.cpp b/src/engine/agent/Agent_Impl.cpp index 99040991..0cda77f3 100644 --- a/src/engine/agent/Agent_Impl.cpp +++ b/src/engine/agent/Agent_Impl.cpp @@ -21,8 +21,7 @@ const std::string Status_NoAudioManager = "no audio manager"; #define LOG_SUBSYSTEM "agent" -AgentImpl::AgentImpl() - :mShutdown(false), mEventListChangeCondVar() +AgentImpl::AgentImpl() : mShutdown(false), mEventListChangeCondVar() { #if defined(TARGET_ANDROID) || defined(TARGET_WIN) ice::GLogger.useDebugWindow(true); @@ -84,76 +83,59 @@ std::string AgentImpl::command(const std::string& command) } if (cmd == "config") processConfig(d, answer); + else if (cmd == "start") + processStart(d, answer); + else if (cmd == "stop") + processStop(d, answer); + else if (cmd == "account_create") + processCreateAccount(d, answer); + else if (cmd == "account_start") + processStartAccount(d, answer); + else if (cmd == "account_setuserinfo") + processSetUserInfoToAccount(d, answer); + else if (cmd == "session_create") + { + // For Bugsnag test + // int* v = nullptr; + // *v = 0; + processCreateSession(d, answer); + } + else if (cmd == "session_start") + processStartSession(d, answer); + else if (cmd == "session_stop") + processStopSession(d, answer); + else if (cmd == "session_accept") + processAcceptSession(d, answer); + else if (cmd == "session_destroy") + processDestroySession(d, answer); + else if (cmd == "session_use_stream") + processUseStreamForSession(d, answer); + else if (cmd == "wait_for_event") + processWaitForEvent(d, answer); + else if (cmd == "session_get_media_stats") + processGetMediaStats(d, answer); + else if (cmd == "agent_network_changed") + processNetworkChanged(d, answer); + else if (cmd == "agent_add_root_cert") + processAddRootCert(d, answer); + else if (cmd == "detach_log") + { + GLogger.closeFile(); + answer["status"] = Status_Ok; + } + else if (cmd == "attach_log") + { + GLogger.openFile(); + answer["status"] = Status_Ok; + } + else if (cmd == "log_message") + processLogMessage(d, answer); else - if (cmd == "start") - processStart(d, answer); - else - if (cmd == "stop") - processStop(d, answer); - else - if (cmd == "account_create") - processCreateAccount(d, answer); - else - if (cmd == "account_start") - processStartAccount(d, answer); - else - if (cmd == "account_setuserinfo") - processSetUserInfoToAccount(d, answer); - else - if (cmd == "session_create") { - // For Bugsnag test - // int* v = nullptr; - // *v = 0; - processCreateSession(d, answer); - } - else - if (cmd == "session_start") - processStartSession(d, answer); - else - if (cmd == "session_stop") - processStopSession(d, answer); - else - if (cmd == "session_accept") - processAcceptSession(d, answer); - else - if (cmd == "session_destroy") - processDestroySession(d, answer); - else - if (cmd == "session_use_stream") - processUseStreamForSession(d, answer); - else - if (cmd == "wait_for_event") - processWaitForEvent(d, answer); - else - if (cmd == "session_get_media_stats") - processGetMediaStats(d, answer); - else - if (cmd == "agent_network_changed") - processNetworkChanged(d, answer); - else - if (cmd == "agent_add_root_cert") - processAddRootCert(d, answer); - else - if (cmd == "detach_log") - { - GLogger.closeFile(); - answer["status"] = Status_Ok; - } - else - if (cmd == "attach_log") - { - GLogger.openFile(); - answer["status"] = Status_Ok; - } - else - if (cmd == "log_message") - processLogMessage(d, answer); - else - { - answer["status"] = Status_NoCommand; - } + { + answer["status"] = Status_NoCommand; + } } - catch(std::exception& e) + catch (std::exception& e) { answer["status"] = e.what(); } @@ -172,17 +154,20 @@ std::string AgentImpl::read() return ""; } -void AgentImpl::processConfig(JsonCpp::Value &d, JsonCpp::Value &answer) +void AgentImpl::processConfig(JsonCpp::Value& d, JsonCpp::Value& answer) { std::unique_lock l(mAgentMutex); - std::string transport = d["transport"].asString(); - config()[CONFIG_TRANSPORT] = (transport == "any") ? TransportType_Any : (transport == "udp" ? TransportType_Udp : (transport == "tcp" ? TransportType_Tcp : TransportType_Tls)); + std::string transport = d["transport"].asString(); + config()[CONFIG_TRANSPORT] = + (transport == "any") + ? TransportType_Any + : (transport == "udp" ? TransportType_Udp : (transport == "tcp" ? TransportType_Tcp : TransportType_Tls)); config()[CONFIG_IPV4] = d["ipv4"].asBool(); config()[CONFIG_IPV6] = d["ipv6"].asBool(); // Log file - std::string logfile = d["logfile"].asString(); + std::string logfile = d["logfile"].asString(); ice::Logger& logger = ice::GLogger; logger.useFile(logfile.empty() ? nullptr : logfile.c_str()); @@ -199,7 +184,7 @@ void AgentImpl::processConfig(JsonCpp::Value &d, JsonCpp::Value &answer) answer["status"] = Status_Ok; } -void AgentImpl::processStart(JsonCpp::Value& request, JsonCpp::Value &answer) +void AgentImpl::processStart(JsonCpp::Value& request, JsonCpp::Value& answer) { std::unique_lock l(mAgentMutex); if (mThread) @@ -220,9 +205,9 @@ void AgentImpl::processStart(JsonCpp::Value& request, JsonCpp::Value &answer) mTerminal = std::make_shared(settings); // Enable/disable codecs - PVariantMap priorityConfig = std::make_shared(); + PVariantMap priorityConfig = std::make_shared(); MT::CodecList& cl = mTerminal->codeclist(); - for (int i=0; iat(i) = i; config()[CONFIG_CODEC_PRIORITY] = priorityConfig; @@ -250,10 +235,10 @@ void AgentImpl::processStop(JsonCpp::Value& /*request*/, JsonCpp::Value& answer) answer["status"] = Status_Ok; } -void AgentImpl::processCreateAccount(JsonCpp::Value &d, JsonCpp::Value& answer) +void AgentImpl::processCreateAccount(JsonCpp::Value& d, JsonCpp::Value& answer) { std::unique_lock l(mAgentMutex); - PVariantMap c = std::make_shared(); + PVariantMap c = std::make_shared(); (*c)[CONFIG_USERNAME] = d["username"].asString(); (*c)[CONFIG_PASSWORD] = d["password"].asString(); @@ -276,7 +261,7 @@ void AgentImpl::processStartAccount(JsonCpp::Value& request, JsonCpp::Value& ans { std::unique_lock l(mAgentMutex); // Locate account in map - auto accountIter = mAccountMap.find(request["account_id"].asInt()); + auto accountIter = mAccountMap.find(request["account_id"].asInt()); if (accountIter != mAccountMap.end()) { accountIter->second->start(); @@ -286,17 +271,17 @@ void AgentImpl::processStartAccount(JsonCpp::Value& request, JsonCpp::Value& ans answer["status"] = Status_AccountNotFound; } -void AgentImpl::processSetUserInfoToAccount(JsonCpp::Value &request, JsonCpp::Value &answer) +void AgentImpl::processSetUserInfoToAccount(JsonCpp::Value& request, JsonCpp::Value& answer) { std::unique_lock l(mAgentMutex); // Locate account in map - auto accountIter = mAccountMap.find(request["account_id"].asInt()); + auto accountIter = mAccountMap.find(request["account_id"].asInt()); if (accountIter != mAccountMap.end()) { - Account::UserInfo info; - JsonCpp::Value& arg = request["userinfo"]; + Account::UserInfo info; + JsonCpp::Value& arg = request["userinfo"]; std::vector keys = arg.getMemberNames(); - for (const std::string& k: keys) + for (const std::string& k : keys) info[k] = arg[k].asString(); accountIter->second->setUserInfo(info); @@ -306,10 +291,10 @@ void AgentImpl::processSetUserInfoToAccount(JsonCpp::Value &request, JsonCpp::Va answer["status"] = Status_AccountNotFound; } -void AgentImpl::processCreateSession(JsonCpp::Value &request, JsonCpp::Value &answer) +void AgentImpl::processCreateSession(JsonCpp::Value& request, JsonCpp::Value& answer) { std::unique_lock l(mAgentMutex); - auto accountIter = mAccountMap.find(request["account_id"].asInt()); + auto accountIter = mAccountMap.find(request["account_id"].asInt()); if (accountIter != mAccountMap.end()) { PSession session = createSession(accountIter->second); @@ -345,9 +330,10 @@ void AgentImpl::processStartSession(JsonCpp::Value& request, JsonCpp::Value& ans if (sessionIter != mSessionMap.end()) { // Ensure audio provider is here - PSession session = sessionIter->second; + PSession session = sessionIter->second; PDataProvider audioProvider = std::make_shared(*this, *mTerminal); - audioProvider->setState(audioProvider->state() | static_cast(StreamState::Grabbing) | static_cast(StreamState::Playing)); + audioProvider->setState(audioProvider->state() | static_cast(StreamState::Grabbing) | + static_cast(StreamState::Playing)); /*#if defined(USE_AQUA_LIBRARY) std::string path_faults = request["path_faults"].asString(); @@ -372,7 +358,8 @@ void AgentImpl::processStartSession(JsonCpp::Value& request, JsonCpp::Value& ans { "specp", "32"} }; - // std::string config = "-avlp on -smtnrm on -decor off -mprio off -npnt auto -voip off -enorm off -g711 on -spfrcor off -grad off -tmc on -miter 1 -trim a 10 -output json"; + // std::string config = "-avlp on -smtnrm on -decor off -mprio off -npnt auto -voip off -enorm off -g711 on +-spfrcor off -grad off -tmc on -miter 1 -trim a 10 -output json"; // if (temp_path.size()) // config += " -fau " + temp_path; @@ -392,10 +379,10 @@ void AgentImpl::processStartSession(JsonCpp::Value& request, JsonCpp::Value& ans // TODO: support SRTP via StreamState::Srtp option in audio provider state // Get user headers - Session::UserHeaders info; - JsonCpp::Value& arg = request["userinfo"]; + Session::UserHeaders info; + JsonCpp::Value& arg = request["userinfo"]; std::vector keys = arg.getMemberNames(); - for (const std::string& k: keys) + for (const std::string& k : keys) info[k] = arg[k].asString(); session->setUserHeaders(info); @@ -413,7 +400,7 @@ void AgentImpl::processStopSession(JsonCpp::Value& request, JsonCpp::Value& answ { std::unique_lock l(mAgentMutex); - auto sessionIter = mSessionMap.find(request["session_id"].asInt()); + auto sessionIter = mSessionMap.find(request["session_id"].asInt()); if (sessionIter != mSessionMap.end()) { PSession session = sessionIter->second; @@ -427,7 +414,7 @@ void AgentImpl::processStopSession(JsonCpp::Value& request, JsonCpp::Value& answ void AgentImpl::processAcceptSession(JsonCpp::Value& request, JsonCpp::Value& answer) { std::unique_lock l(mAgentMutex); - auto sessionIter = mSessionMap.find(request["session_id"].asInt()); + auto sessionIter = mSessionMap.find(request["session_id"].asInt()); if (sessionIter != mSessionMap.end()) { if (!mAudioManager) @@ -445,13 +432,13 @@ void AgentImpl::processAcceptSession(JsonCpp::Value& request, JsonCpp::Value& an mAudioManager->start(mUseNativeAudio ? AudioManager::atReceiver : AudioManager::atNull); // Accept session on SIP level - PSession session = sessionIter->second; + PSession session = sessionIter->second; // Get user headers - Session::UserHeaders info; - JsonCpp::Value& arg = request["userinfo"]; + Session::UserHeaders info; + JsonCpp::Value& arg = request["userinfo"]; std::vector keys = arg.getMemberNames(); - for (const std::string& k: keys) + for (const std::string& k : keys) info[k] = arg[k].asString(); session->setUserHeaders(info); @@ -469,17 +456,17 @@ void AgentImpl::processDestroySession(JsonCpp::Value& request, JsonCpp::Value& a { std::unique_lock l(mAgentMutex); - int sessionId = request["session_id"].asInt(); - auto sessionIter = mSessionMap.find(sessionId); + int sessionId = request["session_id"].asInt(); + auto sessionIter = mSessionMap.find(sessionId); if (sessionIter != mSessionMap.end()) mSessionMap.erase(sessionIter); - //#if defined(USE_AQUA_LIBRARY) - // closeAqua(sessionId); - //#endif + // #if defined(USE_AQUA_LIBRARY) + // closeAqua(sessionId); + // #endif answer["status"] = Status_Ok; } -void AgentImpl::processWaitForEvent(JsonCpp::Value &request, JsonCpp::Value &answer) +void AgentImpl::processWaitForEvent(JsonCpp::Value& request, JsonCpp::Value& answer) { // Deliberately does NOT take mAgentMutex: events are produced by the worker // thread inside process(), which needs mAgentMutex. Holding it here would @@ -506,14 +493,13 @@ void AgentImpl::processWaitForEvent(JsonCpp::Value &request, JsonCpp::Value &ans void AgentImpl::processGetMediaStats(JsonCpp::Value& request, JsonCpp::Value& answer) { std::unique_lock l(mAgentMutex); - int sessionId = request["session_id"].asInt(); - SessionMap::iterator sessionIter = mSessionMap.find(sessionId); + int sessionId = request["session_id"].asInt(); + SessionMap::iterator sessionIter = mSessionMap.find(sessionId); if (sessionIter != mSessionMap.end()) { - PSession session = sessionIter->second; + PSession session = sessionIter->second; VariantMap result; - session->getSessionInfo(Session::InfoOptions::Detailed, - result); + session->getSessionInfo(Session::InfoOptions::Detailed, result); if (result.exists(SessionInfo_AudioCodec)) answer["codec"] = result[SessionInfo_AudioCodec].asStdString(); @@ -560,17 +546,19 @@ void AgentImpl::processNetworkChanged(JsonCpp::Value& /*request*/, JsonCpp::Valu const std::string BeginCertificate = "-----BEGIN CERTIFICATE-----"; const std::string EndCertificate = "-----END CERTIFICATE-----"; -void AgentImpl::processAddRootCert(JsonCpp::Value& request, JsonCpp::Value& answer) +void AgentImpl::processAddRootCert(JsonCpp::Value& request, JsonCpp::Value& answer) { std::unique_lock l(mAgentMutex); - std::string pem = request["cert"].asString(); + std::string pem = request["cert"].asString(); - std::string::size_type pb = 0, pe = 0; - while (pb != std::string::npos && pe != std::string::npos) { + std::string::size_type pb = 0, pe = 0; + while (pb != std::string::npos && pe != std::string::npos) + { pb = pem.find(BeginCertificate, pb); pe = pem.find(EndCertificate, pe); - if (pb != std::string::npos && pe != std::string::npos && pe > pb) { + if (pb != std::string::npos && pe != std::string::npos && pe > pb) + { std::string cert = pem.substr(pb, pe - pb + EndCertificate.size()); addRootCert(ByteBuffer(cert.c_str(), cert.size())); @@ -581,9 +569,9 @@ void AgentImpl::processAddRootCert(JsonCpp::Value& request, JsonCpp::Value& answ answer["status"] = Status_Ok; } -void AgentImpl::processLogMessage(JsonCpp::Value &request, JsonCpp::Value &answer) +void AgentImpl::processLogMessage(JsonCpp::Value& request, JsonCpp::Value& answer) { - int level = request["level"].asInt(); + int level = request["level"].asInt(); std::string message = request["message"].asString(); ICELog(static_cast(level), "App", << message); @@ -600,7 +588,8 @@ void AgentImpl::stopAgentAndThread() stop(); } catch (...) - {} + { + } // Stop worker thread if (mThread) @@ -634,19 +623,19 @@ void AgentImpl::stopAgentAndThread() void AgentImpl::processUseStreamForSession(JsonCpp::Value& request, JsonCpp::Value& answer) { std::unique_lock l(mAgentMutex); - SessionMap::iterator sessionIter = mSessionMap.find(request["session_id"].asInt()); + SessionMap::iterator sessionIter = mSessionMap.find(request["session_id"].asInt()); if (sessionIter != mSessionMap.end()) { // Extract ptr to session - PSession session = sessionIter->second; + PSession session = sessionIter->second; // Parse command - std::string actionText = request["media_action"].asString(), - directionText = request["media_direction"].asString(); + std::string actionText = request["media_action"].asString(), + directionText = request["media_direction"].asString(); - MT::Stream::MediaDirection direction = directionText == "incoming" ? MT::Stream::MediaDirection::Incoming - : MT::Stream::MediaDirection::Outgoing; - std::string path = request["path"].asString(); + MT::Stream::MediaDirection direction = + directionText == "incoming" ? MT::Stream::MediaDirection::Incoming : MT::Stream::MediaDirection::Outgoing; + std::string path = request["path"].asString(); // Try to open file AudioProvider* prov = session->findProviderForActiveAudio(); @@ -672,42 +661,41 @@ void AgentImpl::processUseStreamForSession(JsonCpp::Value& request, JsonCpp::Val } } } - else - if (actionText == "write") + else if (actionText == "write") + { + if (path.empty()) { - if (path.empty()) - { - // Turn off recording from the stream - prov->writeFile(Audio::PWavFileWriter(), direction); - answer["status"] = Status_Ok; - } - else - { - Audio::PWavFileWriter writer = std::make_shared(); - if (!writer->open(strx::makeTstring(path), AUDIO_SAMPLERATE, AUDIO_CHANNELS)) - answer["status"] = Status_FailedToOpenFile; - else - { - prov->writeFile(writer, direction); - answer["status"] = Status_Ok; - } - } + // Turn off recording from the stream + prov->writeFile(Audio::PWavFileWriter(), direction); + answer["status"] = Status_Ok; } else - if (actionText == "mirror") + { + Audio::PWavFileWriter writer = std::make_shared(); + if (!writer->open(strx::makeTstring(path), AUDIO_SAMPLERATE, AUDIO_CHANNELS)) + answer["status"] = Status_FailedToOpenFile; + else { - prov->setupMirror(request["enable"].asBool()); + prov->writeFile(writer, direction); answer["status"] = Status_Ok; } - else - answer["status"] = Status_NoCommand; + } + } + else if (actionText == "mirror") + { + prov->setupMirror(request["enable"].asBool()); + answer["status"] = Status_Ok; + } + else + answer["status"] = Status_NoCommand; } else answer["status"] = Status_NoMediaAction; } } -void AgentImpl::onMedia(const void* data, int length, MT::Stream::MediaDirection direction, void* context, void* userTag) +void AgentImpl::onMedia(const void* data, int length, MT::Stream::MediaDirection direction, void* context, + void* userTag) { /*switch (direction) { @@ -718,7 +706,9 @@ void AgentImpl::onMedia(const void* data, int length, MT::Stream::MediaDirection // Called on new incoming session; providers shoukld -#define EVENT_WITH_NAME(X) JsonCpp::Value v; v["event_name"] = X; +#define EVENT_WITH_NAME(X) \ + JsonCpp::Value v; \ + v["event_name"] = X; PDataProvider AgentImpl::onProviderNeeded(const std::string& name) { @@ -856,8 +846,7 @@ void AgentImpl::onCheckFinished(PSession s, const char* description) } // Called when log message must be recorded -void AgentImpl::onLog(const char* /*msg*/) -{} +void AgentImpl::onLog(const char* /*msg*/) {} // Called when problem with SIP connection(s) detected void AgentImpl::onSipConnectionFailed() diff --git a/src/engine/agent/Agent_Impl.h b/src/engine/agent/Agent_Impl.h index 5fc4a782..031c3e2d 100644 --- a/src/engine/agent/Agent_Impl.h +++ b/src/engine/agent/Agent_Impl.h @@ -16,72 +16,72 @@ #include -class AgentImpl: public UserAgent, public MT::Stream::MediaObserver +class AgentImpl : public UserAgent, public MT::Stream::MediaObserver { protected: - std::recursive_mutex mAgentMutex; - std::mutex mEventListMutex; - std::condition_variable mEventListChangeCondVar; - std::vector mEventList; - bool mUseNativeAudio = false; + std::recursive_mutex mAgentMutex; + std::mutex mEventListMutex; + std::condition_variable mEventListChangeCondVar; + std::vector mEventList; + bool mUseNativeAudio = false; typedef std::map AccountMap; - AccountMap mAccountMap; + AccountMap mAccountMap; typedef std::map SessionMap; - SessionMap mSessionMap; + SessionMap mSessionMap; - std::shared_ptr mThread; - std::atomic mShutdown; - std::shared_ptr mTerminal; - std::shared_ptr mAudioManager; - Audio::DataConnection* mAudioMonitoring = nullptr; + std::shared_ptr mThread; + std::atomic mShutdown; + std::shared_ptr mTerminal; + std::shared_ptr mAudioManager; + Audio::DataConnection* mAudioMonitoring = nullptr; - void run(); - void addEvent(const JsonCpp::Value& v); - void processConfig(JsonCpp::Value& request, JsonCpp::Value& answer); - void processStart(JsonCpp::Value& request, JsonCpp::Value& answer); - void processStop(JsonCpp::Value& request, JsonCpp::Value& answer); - void processCreateAccount(JsonCpp::Value& request, JsonCpp::Value& answer); - void processStartAccount(JsonCpp::Value& request, JsonCpp::Value& answer); - void processSetUserInfoToAccount(JsonCpp::Value& request, JsonCpp::Value& answer); - void processCreateSession(JsonCpp::Value& request, JsonCpp::Value& answer); - void processStartSession(JsonCpp::Value& request, JsonCpp::Value& answer); - void processStopSession(JsonCpp::Value& request, JsonCpp::Value& answer); - void processAcceptSession(JsonCpp::Value& request, JsonCpp::Value& answer); - void processDestroySession(JsonCpp::Value& request, JsonCpp::Value& answer); - void processWaitForEvent(JsonCpp::Value& request, JsonCpp::Value& answer); - void processGetMediaStats(JsonCpp::Value& request, JsonCpp::Value& answer); - void processUseStreamForSession(JsonCpp::Value& request, JsonCpp::Value& answer); - void processNetworkChanged(JsonCpp::Value& request, JsonCpp::Value& answer); - void processAddRootCert(JsonCpp::Value& request, JsonCpp::Value& answer); - void processLogMessage(JsonCpp::Value& request, JsonCpp::Value& answer); - void stopAgentAndThread(); + void run(); + void addEvent(const JsonCpp::Value& v); + void processConfig(JsonCpp::Value& request, JsonCpp::Value& answer); + void processStart(JsonCpp::Value& request, JsonCpp::Value& answer); + void processStop(JsonCpp::Value& request, JsonCpp::Value& answer); + void processCreateAccount(JsonCpp::Value& request, JsonCpp::Value& answer); + void processStartAccount(JsonCpp::Value& request, JsonCpp::Value& answer); + void processSetUserInfoToAccount(JsonCpp::Value& request, JsonCpp::Value& answer); + void processCreateSession(JsonCpp::Value& request, JsonCpp::Value& answer); + void processStartSession(JsonCpp::Value& request, JsonCpp::Value& answer); + void processStopSession(JsonCpp::Value& request, JsonCpp::Value& answer); + void processAcceptSession(JsonCpp::Value& request, JsonCpp::Value& answer); + void processDestroySession(JsonCpp::Value& request, JsonCpp::Value& answer); + void processWaitForEvent(JsonCpp::Value& request, JsonCpp::Value& answer); + void processGetMediaStats(JsonCpp::Value& request, JsonCpp::Value& answer); + void processUseStreamForSession(JsonCpp::Value& request, JsonCpp::Value& answer); + void processNetworkChanged(JsonCpp::Value& request, JsonCpp::Value& answer); + void processAddRootCert(JsonCpp::Value& request, JsonCpp::Value& answer); + void processLogMessage(JsonCpp::Value& request, JsonCpp::Value& answer); + void stopAgentAndThread(); public: AgentImpl(); ~AgentImpl(); - std::string command(const std::string& command); - bool waitForData(int milliseconds); - std::string read(); + std::string command(const std::string& command); + bool waitForData(int milliseconds); + std::string read(); // Get access to internal audio manager. Value can be nullptr. const std::shared_ptr& audioManager() const; - void setAudioMonitoring(Audio::DataConnection* monitoring); - Audio::DataConnection* monitoring() const; + void setAudioMonitoring(Audio::DataConnection* monitoring); + Audio::DataConnection* monitoring() const; // UserAgent overrides // Called on new incoming session; providers shoukld - PDataProvider onProviderNeeded(const std::string& name) override; + PDataProvider onProviderNeeded(const std::string& name) override; // Called on new session offer - void onNewSession(PSession s) override; + void onNewSession(PSession s) override; // Called when session is terminated - void onSessionTerminated(PSession s, int responsecode, int reason) override; + void onSessionTerminated(PSession s, int responsecode, int reason) override; // Called when session is established ok i.e. after all ICE signalling is finished // Conntype is type of establish event - EV_SIP or EV_ICE @@ -123,7 +123,8 @@ public: void onSipConnectionFailed() override; // Called on incoming & outgoing audio for voice sessions - void onMedia(const void* data, int length, MT::Stream::MediaDirection direction, void* context, void* userTag) override; + void onMedia(const void* data, int length, MT::Stream::MediaDirection direction, void* context, + void* userTag) override; }; #endif diff --git a/src/engine/agent/Agent_Interface.cpp b/src/engine/agent/Agent_Interface.cpp index 18e5bc57..448b47e9 100644 --- a/src/engine/agent/Agent_Interface.cpp +++ b/src/engine/agent/Agent_Interface.cpp @@ -1,27 +1,16 @@ #include "Agent_Interface.h" #include "Agent_Impl.h" -Agent::Agent() - :mContext(new AgentImpl()); +Agent::Agent() : mContext(new AgentImpl()); { - } -Agent::~Agent() -{ +Agent::~Agent() {} -} - -void Agent::write(const std::string& command) -{ - -} +void Agent::write(const std::string& command) {} bool Agent::waitForData(int milliseconds) { - return false; + return false; } -std::string Agent::read() -{ - -} +std::string Agent::read() {} diff --git a/src/engine/agent/Agent_Interface.h b/src/engine/agent/Agent_Interface.h index 1790de70..ba2d64ba 100644 --- a/src/engine/agent/Agent_Interface.h +++ b/src/engine/agent/Agent_Interface.h @@ -6,14 +6,14 @@ class Agent { protected: - void* mContext; + void* mContext; public: - Agent(); - ~Agent(); - void write(const std::string& command); - bool waitForData(int milliseconds); - std::string read(); + Agent(); + ~Agent(); + void write(const std::string& command); + bool waitForData(int milliseconds); + std::string read(); }; #endif diff --git a/src/engine/audio/Audio_Android.cpp b/src/engine/audio/Audio_Android.cpp index 0fc5411d..6c8bd783 100644 --- a/src/engine/audio/Audio_Android.cpp +++ b/src/engine/audio/Audio_Android.cpp @@ -14,586 +14,580 @@ using namespace Audio; // -------------------- AndroidEnumerator ----------------------------- -AndroidEnumerator::AndroidEnumerator() -{} +AndroidEnumerator::AndroidEnumerator() {} -AndroidEnumerator::~AndroidEnumerator() -{} +AndroidEnumerator::~AndroidEnumerator() {} int AndroidEnumerator::indexOfDefaultDevice() { - return 0; + return 0; } int AndroidEnumerator::count() { - return 1; + return 1; } int AndroidEnumerator::idAt(int index) { - return 0; + return 0; } std::string AndroidEnumerator::nameAt(int index) { - return "Audio"; + return "Audio"; } -void AndroidEnumerator::open(int direction) -{} +void AndroidEnumerator::open(int direction) {} -void AndroidEnumerator::close() -{} +void AndroidEnumerator::close() {} // ----------------------- -OpenSLEngine::OpenSLEngine() -{} +OpenSLEngine::OpenSLEngine() {} -OpenSLEngine::~OpenSLEngine() -{} +OpenSLEngine::~OpenSLEngine() {} void OpenSLEngine::open() { - std::unique_lock l(mMutex); - if (++mUsageCounter == 1) - internalOpen(); - + std::unique_lock l(mMutex); + if (++mUsageCounter == 1) + internalOpen(); } void OpenSLEngine::close() { - std::unique_lock l(mMutex); - if (mUsageCounter == 0) - return; + std::unique_lock l(mMutex); + if (mUsageCounter == 0) + return; - if (--mUsageCounter == 0) - internalClose(); + if (--mUsageCounter == 0) + internalClose(); } -#define CHECK_OPENSLES_ERROR if (resultCode != SL_RESULT_SUCCESS) throw Exception(ERR_OPENSLES, (int)resultCode) +#define CHECK_OPENSLES_ERROR \ + if (resultCode != SL_RESULT_SUCCESS) \ + throw Exception(ERR_OPENSLES, (int)resultCode) void OpenSLEngine::internalOpen() { - SLresult resultCode; + SLresult resultCode; - // Instantiate OpenSL ES engine object - resultCode = slCreateEngine(&mEngineObject, 0, nullptr, 0, nullptr, nullptr); - CHECK_OPENSLES_ERROR; + // Instantiate OpenSL ES engine object + resultCode = slCreateEngine(&mEngineObject, 0, nullptr, 0, nullptr, nullptr); + CHECK_OPENSLES_ERROR; - // Bring it online (realize) - resultCode = (*mEngineObject)->Realize(mEngineObject, SL_BOOLEAN_FALSE); - CHECK_OPENSLES_ERROR; + // Bring it online (realize) + resultCode = (*mEngineObject)->Realize(mEngineObject, SL_BOOLEAN_FALSE); + CHECK_OPENSLES_ERROR; - // Get interface finally - resultCode = (*mEngineObject)->GetInterface(mEngineObject, SL_IID_ENGINE, &mEngineInterface); - CHECK_OPENSLES_ERROR; + // Get interface finally + resultCode = (*mEngineObject)->GetInterface(mEngineObject, SL_IID_ENGINE, &mEngineInterface); + CHECK_OPENSLES_ERROR; - ICELogInfo(<< "OpenSL engine object created."); + ICELogInfo(<< "OpenSL engine object created."); } void OpenSLEngine::internalClose() { - if (mEngineObject != nullptr) - { - ICELogInfo(<< "Destroy OpenSL engine object."); + if (mEngineObject != nullptr) + { + ICELogInfo(<< "Destroy OpenSL engine object."); - (*mEngineObject)->Destroy(mEngineObject); - mEngineObject = nullptr; - mEngineInterface = nullptr; - } + (*mEngineObject)->Destroy(mEngineObject); + mEngineObject = nullptr; + mEngineInterface = nullptr; + } } SLEngineItf OpenSLEngine::getNativeEngine() const { - return mEngineInterface; + return mEngineInterface; } static OpenSLEngine OpenSLEngineInstance; -OpenSLEngine& OpenSLEngine::instance() +OpenSLEngine& OpenSLEngine::instance() { - return OpenSLEngineInstance; + return OpenSLEngineInstance; } // --------------- Input implementation ---------------- -AndroidInputDevice::AndroidInputDevice(int devId) -{} +AndroidInputDevice::AndroidInputDevice(int devId) {} -AndroidInputDevice::~AndroidInputDevice() -{} +AndroidInputDevice::~AndroidInputDevice() {} static int RateToProbe[12][2] = { - { SL_SAMPLINGRATE_16, 16000 }, - { SL_SAMPLINGRATE_8, 8000 }, - { SL_SAMPLINGRATE_32, 32000 }, - { SL_SAMPLINGRATE_44_1, 44100 }, - { SL_SAMPLINGRATE_11_025, 10025 }, - { SL_SAMPLINGRATE_22_05, 22050 }, - { SL_SAMPLINGRATE_24, 24000 }, - { SL_SAMPLINGRATE_48, 48000 }, - { SL_SAMPLINGRATE_64, 64000 }, - { SL_SAMPLINGRATE_88_2, 88200 }, - { SL_SAMPLINGRATE_96, 96000 }, - { SL_SAMPLINGRATE_192, 192000} }; + {SL_SAMPLINGRATE_16, 16000}, {SL_SAMPLINGRATE_8, 8000}, {SL_SAMPLINGRATE_32, 32000}, + {SL_SAMPLINGRATE_44_1, 44100}, {SL_SAMPLINGRATE_11_025, 10025}, {SL_SAMPLINGRATE_22_05, 22050}, + {SL_SAMPLINGRATE_24, 24000}, {SL_SAMPLINGRATE_48, 48000}, {SL_SAMPLINGRATE_64, 64000}, + {SL_SAMPLINGRATE_88_2, 88200}, {SL_SAMPLINGRATE_96, 96000}, {SL_SAMPLINGRATE_192, 192000}}; bool AndroidInputDevice::open() { - if (active()) - return true; + if (active()) + return true; - OpenSLEngine::instance().open(); + OpenSLEngine::instance().open(); - // Probe few sampling rates - bool opened = false; - for (int rateIndex = 0; rateIndex < 12 && !opened; rateIndex++) - { - try + // Probe few sampling rates + bool opened = false; + for (int rateIndex = 0; rateIndex < 12 && !opened; rateIndex++) { - internalOpen(RateToProbe[rateIndex][0], RateToProbe[rateIndex][1]); - mDeviceRate = RateToProbe[rateIndex][1]; - ICELogInfo(<< "Input Opened with rate " << mDeviceRate << " and rate index " << rateIndex); - opened = mDeviceRate != 0; - if (!opened) - internalClose(); + try + { + internalOpen(RateToProbe[rateIndex][0], RateToProbe[rateIndex][1]); + mDeviceRate = RateToProbe[rateIndex][1]; + ICELogInfo(<< "Input Opened with rate " << mDeviceRate << " and rate index " << rateIndex); + opened = mDeviceRate != 0; + if (!opened) + internalClose(); + } + catch (...) + { + opened = false; + internalClose(); + } } - catch(...) - { - opened = false; - internalClose(); - } - } - mActive = opened; + mActive = opened; - return opened; + return opened; } void AndroidInputDevice::close() { - // There is no check for active() value because close() can be called to cleanup after bad open() call. - internalClose(); - OpenSLEngine::instance().close(); - mActive = false; + // There is no check for active() value because close() can be called to cleanup after bad open() call. + internalClose(); + OpenSLEngine::instance().close(); + mActive = false; } Format AndroidInputDevice::getFormat() { - return Format(mDeviceRate, 1); + return Format(mDeviceRate, 1); } bool AndroidInputDevice::active() const { - return mActive; + return mActive; } bool AndroidInputDevice::fakeMode() { - return false; + return false; } -void AndroidInputDevice::setFakeMode(bool fakemode) -{} +void AndroidInputDevice::setFakeMode(bool fakemode) {} -int AndroidInputDevice::readBuffer(void* buffer) +int AndroidInputDevice::readBuffer(void* buffer) { - std::unique_lock l(mMutex); - while (mSdkRateCache.filled() < AUDIO_MIC_BUFFER_SIZE) - { - mDataCondVar.wait(l); - } + std::unique_lock l(mMutex); + while (mSdkRateCache.filled() < AUDIO_MIC_BUFFER_SIZE) + { + mDataCondVar.wait(l); + } - return mSdkRateCache.read(buffer, AUDIO_MIC_BUFFER_SIZE); + return mSdkRateCache.read(buffer, AUDIO_MIC_BUFFER_SIZE); } -#define CHECK_SL_INTERFACE(INTF, ERR) {if (!INTF) throw Exception(ERR_OPENSLES, ERR); if (!(*INTF)) throw Exception(ERR_OPENSLES, ERR);} +#define CHECK_SL_INTERFACE(INTF, ERR) \ + { \ + if (!INTF) \ + throw Exception(ERR_OPENSLES, ERR); \ + if (!(*INTF)) \ + throw Exception(ERR_OPENSLES, ERR); \ + } void AndroidInputDevice::internalOpen(int rateCode, int rate) { - SLresult resultCode = 0; - SLuint32 nrOfChannels = 1; + SLresult resultCode = 0; + SLuint32 nrOfChannels = 1; - // Prepare audio source - SLDataLocator_IODevice devDescription = { SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT, SL_DEFAULTDEVICEID_AUDIOINPUT, NULL}; - SLDataSource audioSource = { &devDescription, NULL }; + // Prepare audio source + SLDataLocator_IODevice devDescription = {SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT, + SL_DEFAULTDEVICEID_AUDIOINPUT, NULL}; + SLDataSource audioSource = {&devDescription, NULL}; - // Source flags - SLuint32 speakersFlags = nrOfChannels > 1 ? (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT) : SL_SPEAKER_FRONT_CENTER; + // Source flags + SLuint32 speakersFlags = + nrOfChannels > 1 ? (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT) : SL_SPEAKER_FRONT_CENTER; - // Buffer queue - SLDataLocator_AndroidSimpleBufferQueue queueDescription = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2 }; + // Buffer queue + SLDataLocator_AndroidSimpleBufferQueue queueDescription = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2}; - // Audio format - SLDataFormat_PCM formatDescription = { SL_DATAFORMAT_PCM, nrOfChannels, (SLuint32)rateCode, SL_PCMSAMPLEFORMAT_FIXED_16, - SL_PCMSAMPLEFORMAT_FIXED_16, (SLuint32)speakersFlags, SL_BYTEORDER_LITTLEENDIAN }; + // Audio format + SLDataFormat_PCM formatDescription = {SL_DATAFORMAT_PCM, nrOfChannels, + (SLuint32)rateCode, SL_PCMSAMPLEFORMAT_FIXED_16, + SL_PCMSAMPLEFORMAT_FIXED_16, (SLuint32)speakersFlags, + SL_BYTEORDER_LITTLEENDIAN}; - SLDataSink audioSink = { &queueDescription, &formatDescription }; + SLDataSink audioSink = {&queueDescription, &formatDescription}; - // Create recorder - // Do not forget about RECORD_AUDIO permission - const SLInterfaceID interfacesList[2] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION }; - const SLboolean interfacesRequirements[2] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE }; + // Create recorder + // Do not forget about RECORD_AUDIO permission + const SLInterfaceID interfacesList[2] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION}; + const SLboolean interfacesRequirements[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; - // Get access to OpenSL engine - SLEngineItf engine_interface = OpenSLEngine::instance().getNativeEngine(); - CHECK_SL_INTERFACE(engine_interface, -1); + // Get access to OpenSL engine + SLEngineItf engine_interface = OpenSLEngine::instance().getNativeEngine(); + CHECK_SL_INTERFACE(engine_interface, -1); - resultCode = (*engine_interface)->CreateAudioRecorder( - OpenSLEngine::instance().getNativeEngine(), - &mRecorderObject, &audioSource, &audioSink, 2, interfacesList, interfacesRequirements); - CHECK_OPENSLES_ERROR; - CHECK_SL_INTERFACE(mRecorderObject, -2); + resultCode = (*engine_interface) + ->CreateAudioRecorder(OpenSLEngine::instance().getNativeEngine(), &mRecorderObject, &audioSource, + &audioSink, 2, interfacesList, interfacesRequirements); + CHECK_OPENSLES_ERROR; + CHECK_SL_INTERFACE(mRecorderObject, -2); - // Obtain stream type - resultCode = (*mRecorderObject)->GetInterface(mRecorderObject, SL_IID_ANDROIDCONFIGURATION, &mAndroidCfg); - CHECK_OPENSLES_ERROR; + // Obtain stream type + resultCode = (*mRecorderObject)->GetInterface(mRecorderObject, SL_IID_ANDROIDCONFIGURATION, &mAndroidCfg); + CHECK_OPENSLES_ERROR; - // Now audio recorder goes to real world - resultCode = (*mRecorderObject)->Realize(mRecorderObject, SL_BOOLEAN_FALSE); - CHECK_OPENSLES_ERROR; + // Now audio recorder goes to real world + resultCode = (*mRecorderObject)->Realize(mRecorderObject, SL_BOOLEAN_FALSE); + CHECK_OPENSLES_ERROR; - // Get recorder interface - resultCode = (*mRecorderObject)->GetInterface(mRecorderObject, SL_IID_RECORD, &mRecorderInterface); - CHECK_OPENSLES_ERROR; - CHECK_SL_INTERFACE(mRecorderInterface, -3); + // Get recorder interface + resultCode = (*mRecorderObject)->GetInterface(mRecorderObject, SL_IID_RECORD, &mRecorderInterface); + CHECK_OPENSLES_ERROR; + CHECK_SL_INTERFACE(mRecorderInterface, -3); - // Now buffer queue interface... - resultCode = (*mRecorderObject)->GetInterface(mRecorderObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &mRecorderBufferInterface); - CHECK_OPENSLES_ERROR; - CHECK_SL_INTERFACE(mRecorderBufferInterface, -4); + // Now buffer queue interface... + resultCode = + (*mRecorderObject)->GetInterface(mRecorderObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &mRecorderBufferInterface); + CHECK_OPENSLES_ERROR; + CHECK_SL_INTERFACE(mRecorderBufferInterface, -4); - // Resampler is needed to provide SDK's rate - mResampler = std::make_shared(); - mResampler->start(nrOfChannels, rate, AUDIO_SAMPLERATE); + // Resampler is needed to provide SDK's rate + mResampler = std::make_shared(); + mResampler->start(nrOfChannels, rate, AUDIO_SAMPLERATE); - // Allocate recorder buffer size - mBufferSize = (AUDIO_MIC_BUFFER_LENGTH / 10) * (rate / 100) * 2; - mRecorderBuffer.setCapacity(mBufferSize * AUDIO_MIC_BUFFER_COUNT); - mRecorderBufferIndex = 0; + // Allocate recorder buffer size + mBufferSize = (AUDIO_MIC_BUFFER_LENGTH / 10) * (rate / 100) * 2; + mRecorderBuffer.setCapacity(mBufferSize * AUDIO_MIC_BUFFER_COUNT); + mRecorderBufferIndex = 0; - // Setup data consuming callback - resultCode = (*mRecorderBufferInterface)->RegisterCallback(mRecorderBufferInterface, DeviceCallback, (void*)this); - CHECK_OPENSLES_ERROR; + // Setup data consuming callback + resultCode = (*mRecorderBufferInterface)->RegisterCallback(mRecorderBufferInterface, DeviceCallback, (void*)this); + CHECK_OPENSLES_ERROR; - // Setup buffers - for (int i=0; iEnqueue(mRecorderBufferInterface, mRecorderBuffer.data() + i * mBufferSize, mBufferSize); + // Setup buffers + for (int i = 0; i < AUDIO_MIC_BUFFER_COUNT; i++) + (*mRecorderBufferInterface) + ->Enqueue(mRecorderBufferInterface, mRecorderBuffer.data() + i * mBufferSize, mBufferSize); - // Start finally - resultCode = (*mRecorderInterface)->SetRecordState(mRecorderInterface, SL_RECORDSTATE_RECORDING); - CHECK_OPENSLES_ERROR; + // Start finally + resultCode = (*mRecorderInterface)->SetRecordState(mRecorderInterface, SL_RECORDSTATE_RECORDING); + CHECK_OPENSLES_ERROR; } void AndroidInputDevice::internalClose() { - if (!mRecorderObject) - return; + if (!mRecorderObject) + return; - if (*mRecorderObject) - { - if (active()) + if (*mRecorderObject) { - // Stop recording - (*mRecorderInterface)->SetRecordState(mRecorderInterface, SL_RECORDSTATE_STOPPED); + if (active()) + { + // Stop recording + (*mRecorderInterface)->SetRecordState(mRecorderInterface, SL_RECORDSTATE_STOPPED); - // Wait until recording will not stop really - SLuint32 state = SL_RECORDSTATE_STOPPED; - do - { - (*mRecorderInterface)->GetRecordState(mRecorderInterface, &state); - SyncHelper::delay(1); - } - while (state == SL_RECORDSTATE_RECORDING); + // Wait until recording will not stop really + SLuint32 state = SL_RECORDSTATE_STOPPED; + do + { + (*mRecorderInterface)->GetRecordState(mRecorderInterface, &state); + SyncHelper::delay(1); + } while (state == SL_RECORDSTATE_RECORDING); + } + (*mRecorderObject)->Destroy(mRecorderObject); } - (*mRecorderObject)->Destroy(mRecorderObject); - } - mRecorderObject = nullptr; - mRecorderInterface = nullptr; - mRecorderBufferInterface = nullptr; - mAndroidCfg = nullptr; + mRecorderObject = nullptr; + mRecorderInterface = nullptr; + mRecorderBufferInterface = nullptr; + mAndroidCfg = nullptr; } void AndroidInputDevice::handleCallback(SLAndroidSimpleBufferQueueItf bq) { - std::unique_lock l(mMutex); + std::unique_lock l(mMutex); - // Send data to AudioPair - if (mConnection) - mConnection->onMicData(getFormat(), mRecorderBuffer.data() + mRecorderBufferIndex * mBufferSize, mBufferSize); - /* - // Send audio to cache with native sample rate - mDeviceRateCache.add(mRecorderBuffer.data() + mRecorderBufferIndex * mBufferSize, mBufferSize); - - // Check if there is enough data (10 ms) to send - int tenMsSize = (int)Format(mDeviceRate, 1).sizeFromTime(10); - while (mDeviceRateCache.filled() >= tenMsSize) - { - char* resampled = (char*)alloca(Format().sizeFromTime(10)); - int processed = 0; - int outlen = mResampler->processBuffer(mDeviceRateCache.data(), tenMsSize, processed, resampled, Format().sizeFromTime(10)); - if (outlen > 0) - mSdkRateCache.add(resampled, (int)Format().sizeFromTime(10)); - mDeviceRateCache.erase(tenMsSize); - } - - // Tell about data - while (mSdkRateCache.filled() >= AUDIO_MIC_BUFFER_SIZE) - { + // Send data to AudioPair if (mConnection) - mConnection->onMicData(Format(), mSdkRateCache.data(), AUDIO_MIC_BUFFER_SIZE); - mSdkRateCache.erase(AUDIO_MIC_BUFFER_SIZE); - } - */ - // Re-enqueue used buffer - (*mRecorderBufferInterface)->Enqueue(mRecorderBufferInterface, mRecorderBuffer.data() + mRecorderBufferIndex * mBufferSize, mBufferSize); - mRecorderBufferIndex++; - mRecorderBufferIndex %= AUDIO_MIC_BUFFER_COUNT; + mConnection->onMicData(getFormat(), mRecorderBuffer.data() + mRecorderBufferIndex * mBufferSize, mBufferSize); + /* + // Send audio to cache with native sample rate + mDeviceRateCache.add(mRecorderBuffer.data() + mRecorderBufferIndex * mBufferSize, mBufferSize); + + // Check if there is enough data (10 ms) to send + int tenMsSize = (int)Format(mDeviceRate, 1).sizeFromTime(10); + while (mDeviceRateCache.filled() >= tenMsSize) + { + char* resampled = (char*)alloca(Format().sizeFromTime(10)); + int processed = 0; + int outlen = mResampler->processBuffer(mDeviceRateCache.data(), tenMsSize, processed, resampled, + Format().sizeFromTime(10)); if (outlen > 0) mSdkRateCache.add(resampled, (int)Format().sizeFromTime(10)); + mDeviceRateCache.erase(tenMsSize); + } + + // Tell about data + while (mSdkRateCache.filled() >= AUDIO_MIC_BUFFER_SIZE) + { + if (mConnection) + mConnection->onMicData(Format(), mSdkRateCache.data(), AUDIO_MIC_BUFFER_SIZE); + mSdkRateCache.erase(AUDIO_MIC_BUFFER_SIZE); + } + */ + // Re-enqueue used buffer + (*mRecorderBufferInterface) + ->Enqueue(mRecorderBufferInterface, mRecorderBuffer.data() + mRecorderBufferIndex * mBufferSize, mBufferSize); + mRecorderBufferIndex++; + mRecorderBufferIndex %= AUDIO_MIC_BUFFER_COUNT; } -void AndroidInputDevice::DeviceCallback(SLAndroidSimpleBufferQueueItf bq, void *context) +void AndroidInputDevice::DeviceCallback(SLAndroidSimpleBufferQueueItf bq, void* context) { - try - { - if (context) - reinterpret_cast(context)->handleCallback(bq); - } - catch(...) - {} + try + { + if (context) + reinterpret_cast(context)->handleCallback(bq); + } + catch (...) + { + } } // ------------ AndroidOutputDevice ----------------- AndroidOutputDevice::AndroidOutputDevice(int devId) { - ICELogDebug(<< "Creating AndroidOutputDevice. This is: " << strx::toHex(this)); + ICELogDebug(<< "Creating AndroidOutputDevice. This is: " << strx::toHex(this)); } AndroidOutputDevice::~AndroidOutputDevice() { - ICELogDebug(<< "Deleting AndroidOutputDevice."); - close(); + ICELogDebug(<< "Deleting AndroidOutputDevice."); + close(); } bool AndroidOutputDevice::open() { - std::unique_lock l(mMutex); - bool opened = false; - for (int rateIndex = 0; rateIndex < 12 && !opened; rateIndex++) - { - try + std::unique_lock l(mMutex); + bool opened = false; + for (int rateIndex = 0; rateIndex < 12 && !opened; rateIndex++) { - internalOpen(RateToProbe[rateIndex][0], RateToProbe[rateIndex][1], true); - opened = true; - mDeviceRate = RateToProbe[rateIndex][1]; - ICELogCritical(<< "Output opened with rate " << mDeviceRate << " and index " << rateIndex); + try + { + internalOpen(RateToProbe[rateIndex][0], RateToProbe[rateIndex][1], true); + opened = true; + mDeviceRate = RateToProbe[rateIndex][1]; + ICELogCritical(<< "Output opened with rate " << mDeviceRate << " and index " << rateIndex); + } + catch (...) + { + opened = false; + } } - catch(...) - { - opened = false; - } - } - if (opened) - ICELogInfo(<< "Speaker opened on rate " << mDeviceRate); + if (opened) + ICELogInfo(<< "Speaker opened on rate " << mDeviceRate); - return opened; + return opened; } void AndroidOutputDevice::close() { - std::unique_lock l(mMutex); - internalClose(); + std::unique_lock l(mMutex); + internalClose(); } Format AndroidOutputDevice::getFormat() { - return Format(mDeviceRate, 1); + return Format(mDeviceRate, 1); } bool AndroidOutputDevice::fakeMode() { - return false; + return false; } -void AndroidOutputDevice::setFakeMode(bool fakemode) -{ -} +void AndroidOutputDevice::setFakeMode(bool fakemode) {} void AndroidOutputDevice::internalOpen(int rateId, int rate, bool voice) { - mInShutdown = false; + mInShutdown = false; - SLresult resultCode; - SLuint32 channels = 1; + SLresult resultCode; + SLuint32 channels = 1; - // Configure audio source - SLDataLocator_AndroidSimpleBufferQueue queue_desc = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2 }; + // Configure audio source + SLDataLocator_AndroidSimpleBufferQueue queue_desc = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2}; - const SLInterfaceID interfacesList[] = { SL_IID_VOLUME }; - const SLboolean interfaceRequirements[] = { SL_BOOLEAN_FALSE }; - resultCode = (*OpenSLEngine::instance().getNativeEngine())->CreateOutputMix( - OpenSLEngine::instance().getNativeEngine(), &mMixer, 1, interfacesList, - interfaceRequirements); - CHECK_OPENSLES_ERROR; + const SLInterfaceID interfacesList[] = {SL_IID_VOLUME}; + const SLboolean interfaceRequirements[] = {SL_BOOLEAN_FALSE}; + resultCode = (*OpenSLEngine::instance().getNativeEngine()) + ->CreateOutputMix(OpenSLEngine::instance().getNativeEngine(), &mMixer, 1, interfacesList, + interfaceRequirements); + CHECK_OPENSLES_ERROR; - // Bring mixer online - resultCode = (*mMixer)->Realize(mMixer, SL_BOOLEAN_FALSE); - CHECK_OPENSLES_ERROR; + // Bring mixer online + resultCode = (*mMixer)->Realize(mMixer, SL_BOOLEAN_FALSE); + CHECK_OPENSLES_ERROR; - // Prepare mixer configuration - SLuint32 speakers = - channels > 1 ? (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT) : SL_SPEAKER_FRONT_CENTER; + // Prepare mixer configuration + SLuint32 speakers = channels > 1 ? (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT) : SL_SPEAKER_FRONT_CENTER; - // Describe audio format - SLDataFormat_PCM pcm_format = {SL_DATAFORMAT_PCM, channels, (SLuint32) rateId, - SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16, - speakers, SL_BYTEORDER_LITTLEENDIAN}; + // Describe audio format + SLDataFormat_PCM pcm_format = { + SL_DATAFORMAT_PCM, channels, (SLuint32)rateId, SL_PCMSAMPLEFORMAT_FIXED_16, + SL_PCMSAMPLEFORMAT_FIXED_16, speakers, SL_BYTEORDER_LITTLEENDIAN}; - // Describe audio source - buffers + audio format - SLDataSource audio_source = { &queue_desc, &pcm_format }; + // Describe audio source - buffers + audio format + SLDataSource audio_source = {&queue_desc, &pcm_format}; - // Describe audio sink - SLDataLocator_OutputMix mixer_desc = { SL_DATALOCATOR_OUTPUTMIX, mMixer }; - SLDataSink audio_sink = { &mixer_desc, NULL }; + // Describe audio sink + SLDataLocator_OutputMix mixer_desc = {SL_DATALOCATOR_OUTPUTMIX, mMixer}; + SLDataSink audio_sink = {&mixer_desc, NULL}; - // Create player instance - const SLInterfaceID playerInterfaces[] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE, - SL_IID_VOLUME, - SL_IID_ANDROIDCONFIGURATION }; - const SLboolean playerInterfacesReqs[] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE }; + // Create player instance + const SLInterfaceID playerInterfaces[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_VOLUME, + SL_IID_ANDROIDCONFIGURATION}; + const SLboolean playerInterfacesReqs[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; - resultCode = (*OpenSLEngine::instance().getNativeEngine())->CreateAudioPlayer( - OpenSLEngine::instance().getNativeEngine(), &mPlayer, - &audio_source, &audio_sink, 3, playerInterfaces, playerInterfacesReqs); - CHECK_OPENSLES_ERROR; + resultCode = (*OpenSLEngine::instance().getNativeEngine()) + ->CreateAudioPlayer(OpenSLEngine::instance().getNativeEngine(), &mPlayer, &audio_source, + &audio_sink, 3, playerInterfaces, playerInterfacesReqs); + CHECK_OPENSLES_ERROR; - // Get android config interface - resultCode = (*mPlayer)->GetInterface(mPlayer, SL_IID_ANDROIDCONFIGURATION, &mAndroidConfig); + // Get android config interface + resultCode = (*mPlayer)->GetInterface(mPlayer, SL_IID_ANDROIDCONFIGURATION, &mAndroidConfig); - if (resultCode == SL_RESULT_SUCCESS) - { - SLint32 streamType = voice ? SL_ANDROID_STREAM_VOICE : SL_ANDROID_STREAM_MEDIA; - resultCode = (*mAndroidConfig)->SetConfiguration(mAndroidConfig, SL_ANDROID_KEY_STREAM_TYPE, - &streamType, sizeof(SLint32)); - if (resultCode != SL_RESULT_SUCCESS) - ICELogCritical(<< "Failed to set audio destination with error " << (unsigned)resultCode); - } - else - ICELogCritical(<< "Failed to obtain android cfg audio interface with error " << (unsigned)resultCode); + if (resultCode == SL_RESULT_SUCCESS) + { + SLint32 streamType = voice ? SL_ANDROID_STREAM_VOICE : SL_ANDROID_STREAM_MEDIA; + resultCode = (*mAndroidConfig) + ->SetConfiguration(mAndroidConfig, SL_ANDROID_KEY_STREAM_TYPE, &streamType, sizeof(SLint32)); + if (resultCode != SL_RESULT_SUCCESS) + ICELogCritical(<< "Failed to set audio destination with error " << (unsigned)resultCode); + } + else + ICELogCritical(<< "Failed to obtain android cfg audio interface with error " << (unsigned)resultCode); - // Bring player online - resultCode = (*mPlayer)->Realize(mPlayer, SL_BOOLEAN_FALSE); - CHECK_OPENSLES_ERROR; + // Bring player online + resultCode = (*mPlayer)->Realize(mPlayer, SL_BOOLEAN_FALSE); + CHECK_OPENSLES_ERROR; - // Obtain player control - resultCode = (*mPlayer)->GetInterface(mPlayer, SL_IID_PLAY, &mPlayerControl); - CHECK_OPENSLES_ERROR; + // Obtain player control + resultCode = (*mPlayer)->GetInterface(mPlayer, SL_IID_PLAY, &mPlayerControl); + CHECK_OPENSLES_ERROR; - // Get the buffer queue interface - resultCode = (*mPlayer)->GetInterface(mPlayer, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, - &mBufferQueue); - CHECK_OPENSLES_ERROR; + // Get the buffer queue interface + resultCode = (*mPlayer)->GetInterface(mPlayer, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &mBufferQueue); + CHECK_OPENSLES_ERROR; - // Setup callback - resultCode = (*mBufferQueue)->RegisterCallback(mBufferQueue, DeviceCallback, this); - CHECK_OPENSLES_ERROR; + // Setup callback + resultCode = (*mBufferQueue)->RegisterCallback(mBufferQueue, DeviceCallback, this); + CHECK_OPENSLES_ERROR; - // Enqueue buffers - mBufferSize = (int)Format(rate, channels).sizeFromTime(AUDIO_SPK_BUFFER_LENGTH); - mPlayBuffer.setCapacity(AUDIO_SPK_BUFFER_COUNT * mBufferSize); + // Enqueue buffers + mBufferSize = (int)Format(rate, channels).sizeFromTime(AUDIO_SPK_BUFFER_LENGTH); + mPlayBuffer.setCapacity(AUDIO_SPK_BUFFER_COUNT * mBufferSize); - mBufferIndex = 0; - for (int i = 0; i < AUDIO_SPK_BUFFER_COUNT; i++) - (*mBufferQueue)->Enqueue(mBufferQueue, mPlayBuffer.data() + i * mBufferSize, - (SLuint32)mBufferSize); + mBufferIndex = 0; + for (int i = 0; i < AUDIO_SPK_BUFFER_COUNT; i++) + (*mBufferQueue)->Enqueue(mBufferQueue, mPlayBuffer.data() + i * mBufferSize, (SLuint32)mBufferSize); - // Set the player's state to playing - resultCode = (*mPlayerControl)->SetPlayState(mPlayerControl, SL_PLAYSTATE_PLAYING); - CHECK_OPENSLES_ERROR; + // Set the player's state to playing + resultCode = (*mPlayerControl)->SetPlayState(mPlayerControl, SL_PLAYSTATE_PLAYING); + CHECK_OPENSLES_ERROR; - ICELogInfo(<< "Android audio output is opened and playing."); + ICELogInfo(<< "Android audio output is opened and playing."); } void AndroidOutputDevice::internalClose() { - if (mPlayer) - { - if (*mPlayer) + if (mPlayer) { - mInShutdown = true; - ICELogInfo(<< "Stop player"); - if (mPlayerControl) { - if (*mPlayerControl) { - SLuint32 state = SL_PLAYSTATE_PLAYING; - (*mPlayerControl)->SetPlayState(mPlayerControl, SL_PLAYSTATE_STOPPED); + if (*mPlayer) + { + mInShutdown = true; + ICELogInfo(<< "Stop player"); + if (mPlayerControl) + { + if (*mPlayerControl) + { + SLuint32 state = SL_PLAYSTATE_PLAYING; + (*mPlayerControl)->SetPlayState(mPlayerControl, SL_PLAYSTATE_STOPPED); - while (state != SL_PLAYSTATE_STOPPED) { - (*mPlayerControl)->GetPlayState(mPlayerControl, &state); - SyncHelper::delay(1); - } + while (state != SL_PLAYSTATE_STOPPED) + { + (*mPlayerControl)->GetPlayState(mPlayerControl, &state); + SyncHelper::delay(1); + } + } + } + + // Clear buffer queue + ICELogInfo(<< "Clear player buffer queue"); + (*mBufferQueue)->Clear(mBufferQueue); + + ICELogInfo(<< "Destroy player object"); + // Destroy player object + (*mPlayer)->Destroy(mPlayer); + + ICELogInfo(<< "Android audio output closed."); + + mPlayer = nullptr; + mPlayerControl = nullptr; + mBufferQueue = nullptr; + mEffect = nullptr; + mAndroidConfig = nullptr; } - } - - // Clear buffer queue - ICELogInfo(<< "Clear player buffer queue"); - (*mBufferQueue)->Clear(mBufferQueue); - - ICELogInfo(<< "Destroy player object"); - // Destroy player object - (*mPlayer)->Destroy(mPlayer); - - ICELogInfo(<< "Android audio output closed."); - - mPlayer = nullptr; - mPlayerControl = nullptr; - mBufferQueue = nullptr; - mEffect = nullptr; - mAndroidConfig = nullptr; } - } - if (mMixer) - { - if (*mMixer) - (*mMixer)->Destroy(mMixer); - mMixer = nullptr; - } + if (mMixer) + { + if (*mMixer) + (*mMixer)->Destroy(mMixer); + mMixer = nullptr; + } } void AndroidOutputDevice::handleCallback(SLAndroidSimpleBufferQueueItf bq) { - if (mInShutdown) - return; - /*{ - char silence[mBufferSize]; memset(silence, 0, mBufferSize); - (*mBufferQueue)->Enqueue(mBufferQueue, silence, mBufferSize); - return; - }*/ + if (mInShutdown) + return; + /*{ + char silence[mBufferSize]; memset(silence, 0, mBufferSize); + (*mBufferQueue)->Enqueue(mBufferQueue, silence, mBufferSize); + return; + }*/ - // Ask producer about data - char* buffer = mPlayBuffer.mutableData() + mBufferIndex * mBufferSize; - if (mConnection) - { - Format f = getFormat(); - if (f.mRate != 0) - mConnection->onSpkData(f, buffer, mBufferSize); - } - (*mBufferQueue)->Enqueue(mBufferQueue, buffer, (SLuint32)mBufferSize); + // Ask producer about data + char* buffer = mPlayBuffer.mutableData() + mBufferIndex * mBufferSize; + if (mConnection) + { + Format f = getFormat(); + if (f.mRate != 0) + mConnection->onSpkData(f, buffer, mBufferSize); + } + (*mBufferQueue)->Enqueue(mBufferQueue, buffer, (SLuint32)mBufferSize); - mBufferIndex++; - mBufferIndex %= AUDIO_SPK_BUFFER_COUNT; + mBufferIndex++; + mBufferIndex %= AUDIO_SPK_BUFFER_COUNT; } void AndroidOutputDevice::DeviceCallback(SLAndroidSimpleBufferQueueItf bq, void* context) { - if (!context) - return; + if (!context) + return; - try - { - reinterpret_cast(context)->handleCallback(bq); - } - catch(...) - {} + try + { + reinterpret_cast(context)->handleCallback(bq); + } + catch (...) + { + } } #endif // TARGET_ANDROID diff --git a/src/engine/audio/Audio_Android.h b/src/engine/audio/Audio_Android.h index f1543efb..d394fd38 100644 --- a/src/engine/audio/Audio_Android.h +++ b/src/engine/audio/Audio_Android.h @@ -25,121 +25,120 @@ namespace Audio { - class AndroidEnumerator: public Enumerator - { - public: - AndroidEnumerator(); - ~AndroidEnumerator(); +class AndroidEnumerator : public Enumerator +{ +public: + AndroidEnumerator(); + ~AndroidEnumerator(); - void open(int direction); - void close(); + void open(int direction); + void close(); - int count(); - std::string nameAt(int index); - int idAt(int index); - int indexOfDefaultDevice(); + int count(); + std::string nameAt(int index); + int idAt(int index); + int indexOfDefaultDevice(); - protected: - }; +protected: +}; - class AndroidInputDevice: public InputDevice - { - public: - AndroidInputDevice(int devId); - ~AndroidInputDevice(); +class AndroidInputDevice : public InputDevice +{ +public: + AndroidInputDevice(int devId); + ~AndroidInputDevice(); - bool open(); - void close(); - Format getFormat(); + bool open(); + void close(); + Format getFormat(); - bool fakeMode(); - void setFakeMode(bool fakemode); - int readBuffer(void* buffer); - bool active() const; + bool fakeMode(); + void setFakeMode(bool fakemode); + int readBuffer(void* buffer); + bool active() const; - protected: - bool mActive = false; - SLObjectItf mRecorderObject = nullptr; - SLRecordItf mRecorderInterface = nullptr; - SLAndroidSimpleBufferQueueItf mRecorderBufferInterface = nullptr; - SLAndroidConfigurationItf mAndroidCfg = nullptr; +protected: + bool mActive = false; + SLObjectItf mRecorderObject = nullptr; + SLRecordItf mRecorderInterface = nullptr; + SLAndroidSimpleBufferQueueItf mRecorderBufferInterface = nullptr; + SLAndroidConfigurationItf mAndroidCfg = nullptr; - PResampler mResampler; - DataWindow mDeviceRateCache, mSdkRateCache; - int mDeviceRate; // Actual rate of opened recorder - int mBufferSize; // Size of buffer used for recording (at native sample rate) - DataWindow mRecorderBuffer; - std::condition_variable mDataCondVar; - int mRecorderBufferIndex; - std::mutex mMutex; + PResampler mResampler; + DataWindow mDeviceRateCache, mSdkRateCache; + int mDeviceRate; // Actual rate of opened recorder + int mBufferSize; // Size of buffer used for recording (at native sample rate) + DataWindow mRecorderBuffer; + std::condition_variable mDataCondVar; + int mRecorderBufferIndex; + std::mutex mMutex; - void internalOpen(int rateCode, int rate); - void internalClose(); - void handleCallback(SLAndroidSimpleBufferQueueItf bq); - static void DeviceCallback(SLAndroidSimpleBufferQueueItf bq, void* context); - }; + void internalOpen(int rateCode, int rate); + void internalClose(); + void handleCallback(SLAndroidSimpleBufferQueueItf bq); + static void DeviceCallback(SLAndroidSimpleBufferQueueItf bq, void* context); +}; - class AndroidOutputDevice: public OutputDevice - { - public: - AndroidOutputDevice(int devId); - ~AndroidOutputDevice(); +class AndroidOutputDevice : public OutputDevice +{ +public: + AndroidOutputDevice(int devId); + ~AndroidOutputDevice(); - bool open(); - void close(); - Format getFormat(); + bool open(); + void close(); + Format getFormat(); - bool fakeMode(); - void setFakeMode(bool fakemode); + bool fakeMode(); + void setFakeMode(bool fakemode); - protected: - std::mutex mMutex; - int mDeviceRate = 0; - SLObjectItf mMixer = nullptr; - SLObjectItf mPlayer = nullptr; - SLPlayItf mPlayerControl = nullptr; - SLAndroidSimpleBufferQueueItf mBufferQueue = nullptr; - SLAndroidConfigurationItf mAndroidConfig = nullptr; - SLEffectSendItf mEffect = nullptr; +protected: + std::mutex mMutex; + int mDeviceRate = 0; + SLObjectItf mMixer = nullptr; + SLObjectItf mPlayer = nullptr; + SLPlayItf mPlayerControl = nullptr; + SLAndroidSimpleBufferQueueItf mBufferQueue = nullptr; + SLAndroidConfigurationItf mAndroidConfig = nullptr; + SLEffectSendItf mEffect = nullptr; - DataWindow mPlayBuffer; - int mBufferIndex = 0, mBufferSize = 0; - bool mInShutdown = false; + DataWindow mPlayBuffer; + int mBufferIndex = 0, mBufferSize = 0; + bool mInShutdown = false; - void internalOpen(int rateId, int rate, bool voice); - void internalClose(); + void internalOpen(int rateId, int rate, bool voice); + void internalClose(); - void handleCallback(SLAndroidSimpleBufferQueueItf bq); - static void DeviceCallback(SLAndroidSimpleBufferQueueItf bq, void* context); + void handleCallback(SLAndroidSimpleBufferQueueItf bq); + static void DeviceCallback(SLAndroidSimpleBufferQueueItf bq, void* context); +}; - }; +class OpenSLEngine : public OsEngine +{ +public: + OpenSLEngine(); + ~OpenSLEngine(); - class OpenSLEngine: public OsEngine - { - public: - OpenSLEngine(); - ~OpenSLEngine(); + // open() / close() methods are based on usage counting. + // It means every close() call must be matched by corresponding open() call. + // True audio engine close will happen only on last close() call. + void open() override; + void close() override; - // open() / close() methods are based on usage counting. - // It means every close() call must be matched by corresponding open() call. - // True audio engine close will happen only on last close() call. - void open() override; - void close() override; + SLEngineItf getNativeEngine() const; - SLEngineItf getNativeEngine() const; + static OpenSLEngine& instance(); - static OpenSLEngine& instance(); +protected: + std::mutex mMutex; + int mUsageCounter = 0; + SLObjectItf mEngineObject = nullptr; + SLEngineItf mEngineInterface = nullptr; - protected: - std::mutex mMutex; - int mUsageCounter = 0; - SLObjectItf mEngineObject = nullptr; - SLEngineItf mEngineInterface = nullptr; - - void internalOpen(); - void internalClose(); - }; -} + void internalOpen(); + void internalClose(); +}; +} // namespace Audio #endif // TARGET_ANDROID diff --git a/src/engine/audio/Audio_AndroidOboe.cpp b/src/engine/audio/Audio_AndroidOboe.cpp index e34f7ba8..80cdc6fa 100644 --- a/src/engine/audio/Audio_AndroidOboe.cpp +++ b/src/engine/audio/Audio_AndroidOboe.cpp @@ -18,284 +18,279 @@ using namespace Audio; // -------------------- AndroidEnumerator ----------------------------- -AndroidEnumerator::AndroidEnumerator() -{} +AndroidEnumerator::AndroidEnumerator() {} -AndroidEnumerator::~AndroidEnumerator() -{} +AndroidEnumerator::~AndroidEnumerator() {} int AndroidEnumerator::indexOfDefaultDevice() { - return 0; + return 0; } int AndroidEnumerator::count() { - return 1; + return 1; } int AndroidEnumerator::idAt(int index) { - return 0; + return 0; } std::string AndroidEnumerator::nameAt(int index) { - return "Audio"; + return "Audio"; } -void AndroidEnumerator::open(int direction) -{} +void AndroidEnumerator::open(int direction) {} -void AndroidEnumerator::close() -{} +void AndroidEnumerator::close() {} // --------------- Input implementation ---------------- -AndroidInputDevice::AndroidInputDevice(int devId) -{} +AndroidInputDevice::AndroidInputDevice(int devId) {} AndroidInputDevice::~AndroidInputDevice() { - close(); + close(); } bool AndroidInputDevice::open() { - if (active()) - return true; + if (active()) + return true; - oboe::AudioStreamBuilder builder; - builder.setDirection(oboe::Direction::Input); - builder.setPerformanceMode(oboe::PerformanceMode::LowLatency); - builder.setSharingMode(oboe::SharingMode::Exclusive); - builder.setFormat(oboe::AudioFormat::I16); - builder.setChannelCount(oboe::ChannelCount::Mono); - builder.setCallback(this); - oboe::Result rescode = builder.openStream(&mRecordingStream); - if (rescode != oboe::Result::OK) - return false; + oboe::AudioStreamBuilder builder; + builder.setDirection(oboe::Direction::Input); + builder.setPerformanceMode(oboe::PerformanceMode::LowLatency); + builder.setSharingMode(oboe::SharingMode::Exclusive); + builder.setFormat(oboe::AudioFormat::I16); + builder.setChannelCount(oboe::ChannelCount::Mono); + builder.setCallback(this); + oboe::Result rescode = builder.openStream(&mRecordingStream); + if (rescode != oboe::Result::OK) + return false; - mDeviceRate = mRecordingStream->getSampleRate(); - ICELogInfo(<< "Input Opened with rate " << mDeviceRate); - mActive = true; + mDeviceRate = mRecordingStream->getSampleRate(); + ICELogInfo(<< "Input Opened with rate " << mDeviceRate); + mActive = true; - rescode = mRecordingStream->requestStart(); - if (rescode != oboe::Result::OK) - { - close(); - mActive = false; - } - return mActive; + rescode = mRecordingStream->requestStart(); + if (rescode != oboe::Result::OK) + { + close(); + mActive = false; + } + return mActive; } void AndroidInputDevice::close() { - // There is no check for active() value because close() can be called to cleanup after bad open() call. - if (mRecordingStream != nullptr) - { - mRecordingStream->close(); - delete mRecordingStream; mRecordingStream = nullptr; - } - mActive = false; + // There is no check for active() value because close() can be called to cleanup after bad open() call. + if (mRecordingStream != nullptr) + { + mRecordingStream->close(); + delete mRecordingStream; + mRecordingStream = nullptr; + } + mActive = false; } -oboe::DataCallbackResult -AndroidInputDevice::onAudioReady(oboe::AudioStream *audioStream, void *audioData, int32_t numFrames) +oboe::DataCallbackResult AndroidInputDevice::onAudioReady(oboe::AudioStream* audioStream, void* audioData, + int32_t numFrames) { - std::unique_lock l(mMutex); + std::unique_lock l(mMutex); - // Send data to AudioPair - if (mConnection) - mConnection->onMicData(getFormat(), audioData, numFrames); + // Send data to AudioPair + if (mConnection) + mConnection->onMicData(getFormat(), audioData, numFrames); - return oboe::DataCallbackResult::Continue; + return oboe::DataCallbackResult::Continue; } Format AndroidInputDevice::getFormat() { - return Format(mDeviceRate, 1); + return Format(mDeviceRate, 1); } bool AndroidInputDevice::active() const { - return mActive; + return mActive; } bool AndroidInputDevice::fakeMode() { - return false; + return false; } -void AndroidInputDevice::setFakeMode(bool fakemode) -{} +void AndroidInputDevice::setFakeMode(bool fakemode) {} -int AndroidInputDevice::readBuffer(void* buffer) +int AndroidInputDevice::readBuffer(void* buffer) { - throw std::runtime_error("AndroidInputDevice::readBuffer() is not implemented."); + throw std::runtime_error("AndroidInputDevice::readBuffer() is not implemented."); } // ------------ AndroidOutputDevice ----------------- AndroidOutputDevice::AndroidOutputDevice(int devId) { - ICELogDebug(<< "Creating AndroidOutputDevice. This is: " << strx::toHex(this)); + ICELogDebug(<< "Creating AndroidOutputDevice. This is: " << strx::toHex(this)); } AndroidOutputDevice::~AndroidOutputDevice() { - ICELogDebug(<< "Deleting AndroidOutputDevice."); - // Mark shutdown before closing so a disconnect callback racing with teardown - // does not resurrect the stream via onErrorAfterClose()'s restart. - mInShutdown = true; - close(); + ICELogDebug(<< "Deleting AndroidOutputDevice."); + // Mark shutdown before closing so a disconnect callback racing with teardown + // does not resurrect the stream via onErrorAfterClose()'s restart. + mInShutdown = true; + close(); } bool AndroidOutputDevice::open() { - std::unique_lock l(mMutex); + std::unique_lock l(mMutex); - if (mActive) - return true; + if (mActive) + return true; - mInShutdown = false; - mRequestedFrames = 0; - mStartTime = 0.0; - mEndTime = 0.0; + mInShutdown = false; + mRequestedFrames = 0; + mStartTime = 0.0; + mEndTime = 0.0; - oboe::AudioStreamBuilder builder; - builder.setDirection(oboe::Direction::Output); - builder.setPerformanceMode(oboe::PerformanceMode::LowLatency); - builder.setSharingMode(oboe::SharingMode::Exclusive); - builder.setFormat(oboe::AudioFormat::I16); - builder.setChannelCount(oboe::ChannelCount::Mono); - // Route through the platform voice-call path: correct device selection/volume - // and platform voice tuning for a softphone. - builder.setUsage(oboe::Usage::VoiceCommunication); - builder.setContentType(oboe::ContentType::Speech); - // builder.setDataCallback(this); - builder.setCallback(this); - //builder.setErrorCallback(this) + oboe::AudioStreamBuilder builder; + builder.setDirection(oboe::Direction::Output); + builder.setPerformanceMode(oboe::PerformanceMode::LowLatency); + builder.setSharingMode(oboe::SharingMode::Exclusive); + builder.setFormat(oboe::AudioFormat::I16); + builder.setChannelCount(oboe::ChannelCount::Mono); + // Route through the platform voice-call path: correct device selection/volume + // and platform voice tuning for a softphone. + builder.setUsage(oboe::Usage::VoiceCommunication); + builder.setContentType(oboe::ContentType::Speech); + // builder.setDataCallback(this); + builder.setCallback(this); + // builder.setErrorCallback(this) - oboe::Result rescode = builder.openStream(&mPlayingStream); - if (rescode != oboe::Result::OK) - return false; + oboe::Result rescode = builder.openStream(&mPlayingStream); + if (rescode != oboe::Result::OK) + return false; - mDeviceRate = mPlayingStream->getSampleRate(); - ICELogInfo(<< "Output opened with rate " << mDeviceRate); - mActive = true; + mDeviceRate = mPlayingStream->getSampleRate(); + ICELogInfo(<< "Output opened with rate " << mDeviceRate); + mActive = true; - rescode = mPlayingStream->requestStart(); - if (rescode != oboe::Result::OK) - { - close(); - mActive = false; - return mActive; - } + rescode = mPlayingStream->requestStart(); + if (rescode != oboe::Result::OK) + { + close(); + mActive = false; + return mActive; + } - // Latch the burst size and start from a two-burst buffer. onAudioReady() grows - // this on XRuns (up to a cap) so we keep low latency when the device can sustain - // it and trade a little latency for glitch-free playback when it can't. - mBurstFrames = mPlayingStream->getFramesPerBurst(); - mXRunLast = 0; - mHeartbeatLast = 0.0f; - if (mBurstFrames > 0) - mPlayingStream->setBufferSizeInFrames(mBurstFrames * 2); + // Latch the burst size and start from a two-burst buffer. onAudioReady() grows + // this on XRuns (up to a cap) so we keep low latency when the device can sustain + // it and trade a little latency for glitch-free playback when it can't. + mBurstFrames = mPlayingStream->getFramesPerBurst(); + mXRunLast = 0; + mHeartbeatLast = 0.0f; + if (mBurstFrames > 0) + mPlayingStream->setBufferSizeInFrames(mBurstFrames * 2); - return mActive; + return mActive; } void AndroidOutputDevice::close() { - std::unique_lock l(mMutex); - if (!mActive) - return; + std::unique_lock l(mMutex); + if (!mActive) + return; - if (mPlayingStream != nullptr) - { - mPlayingStream->close(); - delete mPlayingStream; mPlayingStream = nullptr; - } - mEndTime = now_ms(); - mActive = false; + if (mPlayingStream != nullptr) + { + mPlayingStream->close(); + delete mPlayingStream; + mPlayingStream = nullptr; + } + mEndTime = now_ms(); + mActive = false; - ICELogInfo(<< "For time " << mEndTime - mStartTime << " ms was requested " - << float(mRequestedFrames) / getFormat().mRate * 1000 << " ms"); + ICELogInfo(<< "For time " << mEndTime - mStartTime << " ms was requested " + << float(mRequestedFrames) / getFormat().mRate * 1000 << " ms"); } Format AndroidOutputDevice::getFormat() { - return {mDeviceRate, 1}; + return {mDeviceRate, 1}; } bool AndroidOutputDevice::fakeMode() { - return false; + return false; } -void AndroidOutputDevice::setFakeMode(bool /*fakemode*/) +void AndroidOutputDevice::setFakeMode(bool /*fakemode*/) {} + +oboe::DataCallbackResult AndroidOutputDevice::onAudioReady(oboe::AudioStream* audioStream, void* audioData, + int32_t numFrames) { -} + if (mInShutdown) + return oboe::DataCallbackResult::Stop; -oboe::DataCallbackResult AndroidOutputDevice::onAudioReady(oboe::AudioStream *audioStream, void *audioData, int32_t numFrames) -{ - if (mInShutdown) - return oboe::DataCallbackResult::Stop; + if (mStartTime == 0.0) + mStartTime = now_ms(); - if (mStartTime == 0.0) - mStartTime = now_ms(); - - // Ask producer about data - memset(audioData, 0, numFrames * 2); - if (mConnection) - { - Format f = getFormat(); - if (f.mRate != 0) - mConnection->onSpkData(f, audioData, numFrames * 2); - } - mRequestedFrames += numFrames; - - // Adaptive buffer sizing: on new XRuns (device-side underruns, i.e. we missed a - // callback deadline), grow the buffer one burst at a time up to a cap. Both calls - // are documented as safe from within the data callback. - auto xrun = audioStream->getXRunCount(); - if (xrun && xrun.value() > mXRunLast) - { - mXRunLast = xrun.value(); - if (mBurstFrames > 0) + // Ask producer about data + memset(audioData, 0, numFrames * 2); + if (mConnection) { - int32_t cap = mBurstFrames * 8; - int32_t cur = audioStream->getBufferSizeInFrames(); - int32_t next = std::min(cur + mBurstFrames, cap); - if (next > cur) - audioStream->setBufferSizeInFrames(next); + Format f = getFormat(); + if (f.mRate != 0) + mConnection->onSpkData(f, audioData, numFrames * 2); } - } + mRequestedFrames += numFrames; - // Device-side heartbeat (Step 0): surfaces XRuns/buffer growth so device glitches - // can be told apart from network/jitter impairments. - float t = now_ms(); - if (mHeartbeatLast == 0.0f) - mHeartbeatLast = t; - else if (t - mHeartbeatLast >= 5000.0f) - { - ICELogInfo(<< "[spk-heartbeat] xruns=" << mXRunLast - << " bufFrames=" << audioStream->getBufferSizeInFrames() - << " burst=" << mBurstFrames - << " rate=" << mDeviceRate); - mHeartbeatLast = t; - } + // Adaptive buffer sizing: on new XRuns (device-side underruns, i.e. we missed a + // callback deadline), grow the buffer one burst at a time up to a cap. Both calls + // are documented as safe from within the data callback. + auto xrun = audioStream->getXRunCount(); + if (xrun && xrun.value() > mXRunLast) + { + mXRunLast = xrun.value(); + if (mBurstFrames > 0) + { + int32_t cap = mBurstFrames * 8; + int32_t cur = audioStream->getBufferSizeInFrames(); + int32_t next = std::min(cur + mBurstFrames, cap); + if (next > cur) + audioStream->setBufferSizeInFrames(next); + } + } - return oboe::DataCallbackResult::Continue; + // Device-side heartbeat (Step 0): surfaces XRuns/buffer growth so device glitches + // can be told apart from network/jitter impairments. + float t = now_ms(); + if (mHeartbeatLast == 0.0f) + mHeartbeatLast = t; + else if (t - mHeartbeatLast >= 5000.0f) + { + ICELogInfo(<< "[spk-heartbeat] xruns=" << mXRunLast << " bufFrames=" << audioStream->getBufferSizeInFrames() + << " burst=" << mBurstFrames << " rate=" << mDeviceRate); + mHeartbeatLast = t; + } + + return oboe::DataCallbackResult::Continue; } // Disconnect recovery: on a route change (headset/BT plug/unplug) AAudio tears the // stream down and calls this on its own thread after the stream is closed. Rebuild // on the new default route so audio doesn't silently die mid-call. // See https://github.com/google/oboe/blob/master/docs/notes/disconnect.md -void AndroidOutputDevice::onErrorAfterClose(oboe::AudioStream *stream, oboe::Result result) { - if (result == oboe::Result::ErrorDisconnected && !mInShutdown) { - ICELogInfo(<< "Output stream disconnected; restarting on the new route"); - // close() and open() each take mMutex internally; this callback holds none. - close(); - open(); - } +void AndroidOutputDevice::onErrorAfterClose(oboe::AudioStream* stream, oboe::Result result) +{ + if (result == oboe::Result::ErrorDisconnected && !mInShutdown) + { + ICELogInfo(<< "Output stream disconnected; restarting on the new route"); + // close() and open() each take mMutex internally; this callback holds none. + close(); + open(); + } } #endif // TARGET_ANDROID diff --git a/src/engine/audio/Audio_AndroidOboe.h b/src/engine/audio/Audio_AndroidOboe.h index 078ad792..46b67f1a 100644 --- a/src/engine/audio/Audio_AndroidOboe.h +++ b/src/engine/audio/Audio_AndroidOboe.h @@ -25,89 +25,88 @@ namespace Audio { - class AndroidEnumerator: public Enumerator - { - public: - AndroidEnumerator(); - ~AndroidEnumerator(); +class AndroidEnumerator : public Enumerator +{ +public: + AndroidEnumerator(); + ~AndroidEnumerator(); - void open(int direction); - void close(); + void open(int direction); + void close(); - int count(); - std::string nameAt(int index); - int idAt(int index); - int indexOfDefaultDevice(); + int count(); + std::string nameAt(int index); + int idAt(int index); + int indexOfDefaultDevice(); - protected: - }; +protected: +}; - class AndroidInputDevice: public InputDevice, public oboe::AudioStreamCallback - { - public: - AndroidInputDevice(int devId); - ~AndroidInputDevice(); +class AndroidInputDevice : public InputDevice, public oboe::AudioStreamCallback +{ +public: + AndroidInputDevice(int devId); + ~AndroidInputDevice(); - bool open(); - void close(); - Format getFormat(); + bool open(); + void close(); + Format getFormat(); - bool fakeMode(); - void setFakeMode(bool fakemode); - int readBuffer(void* buffer); - bool active() const; + bool fakeMode(); + void setFakeMode(bool fakemode); + int readBuffer(void* buffer); + bool active() const; - oboe::DataCallbackResult - onAudioReady(oboe::AudioStream *audioStream, void *audioData, int32_t numFrames); + oboe::DataCallbackResult onAudioReady(oboe::AudioStream* audioStream, void* audioData, int32_t numFrames); - protected: - bool mActive = false; - oboe::AudioStream* mRecordingStream = nullptr; - PResampler mResampler; - DataWindow mDeviceRateCache, mSdkRateCache; - int mDeviceRate; // Actual rate of opened recorder - int mBufferSize; // Size of buffer used for recording (at native sample rate) - DataWindow mRecorderBuffer; - std::condition_variable mDataCondVar; - int mRecorderBufferIndex; - std::mutex mMutex; - }; +protected: + bool mActive = false; + oboe::AudioStream* mRecordingStream = nullptr; + PResampler mResampler; + DataWindow mDeviceRateCache, mSdkRateCache; + int mDeviceRate; // Actual rate of opened recorder + int mBufferSize; // Size of buffer used for recording (at native sample rate) + DataWindow mRecorderBuffer; + std::condition_variable mDataCondVar; + int mRecorderBufferIndex; + std::mutex mMutex; +}; -class AndroidOutputDevice: public OutputDevice, public oboe::AudioStreamCallback - { - public: - AndroidOutputDevice(int devId); - ~AndroidOutputDevice(); +class AndroidOutputDevice : public OutputDevice, public oboe::AudioStreamCallback +{ +public: + AndroidOutputDevice(int devId); + ~AndroidOutputDevice(); - bool open(); - void close(); - Format getFormat(); + bool open(); + void close(); + Format getFormat(); - bool fakeMode(); - void setFakeMode(bool fakemode); + bool fakeMode(); + void setFakeMode(bool fakemode); - oboe::DataCallbackResult onAudioReady(oboe::AudioStream *audioStream, void *audioData, int32_t numFrames); - void onErrorAfterClose(oboe::AudioStream *stream, oboe::Result result); + oboe::DataCallbackResult onAudioReady(oboe::AudioStream* audioStream, void* audioData, int32_t numFrames); + void onErrorAfterClose(oboe::AudioStream* stream, oboe::Result result); - protected: - std::mutex mMutex; - int mDeviceRate = 0; - oboe::AudioStream* mPlayingStream = nullptr; - DataWindow mPlayBuffer; - int mBufferIndex = 0, mBufferSize = 0; - bool mInShutdown = false; - bool mActive = false; +protected: + std::mutex mMutex; + int mDeviceRate = 0; + oboe::AudioStream* mPlayingStream = nullptr; + DataWindow mPlayBuffer; + int mBufferIndex = 0, mBufferSize = 0; + bool mInShutdown = false; + bool mActive = false; - // Adaptive buffer sizing + device-side diagnostics (Step 0 / #5). - int32_t mBurstFrames = 0; // frames per burst, latched at open() - int32_t mXRunLast = 0; // last observed cumulative XRun count - float mHeartbeatLast = 0.0f; // now_ms() of last device heartbeat log + // Adaptive buffer sizing + device-side diagnostics (Step 0 / #5). + int32_t mBurstFrames = 0; // frames per burst, latched at open() + int32_t mXRunLast = 0; // last observed cumulative XRun count + float mHeartbeatLast = 0.0f; // now_ms() of last device heartbeat log - // Statistics - float mRequestedFrames = 0.0, mStartTime = 0.0, mEndTime = 0.0; - }; -} + // Statistics + float mRequestedFrames = 0.0, mStartTime = 0.0, mEndTime = 0.0; +}; +} // namespace Audio #endif // TARGET_ANDROID diff --git a/src/engine/audio/Audio_CoreAudio.cpp b/src/engine/audio/Audio_CoreAudio.cpp index dfad4c5a..20cc2775 100644 --- a/src/engine/audio/Audio_CoreAudio.cpp +++ b/src/engine/audio/Audio_CoreAudio.cpp @@ -7,7 +7,7 @@ #include "Audio_CoreAudio.h" #include "../Helper/HL_Log.h" -//#include +// #include #include #include @@ -23,12 +23,11 @@ enum static inline short Float32ToInt16(Float32 v) { - //assert (v <= 1.0); + // assert (v <= 1.0); int r = int(v * 32768); if (r >= 32768) return (short)32767; - else - if (r < -32768) + else if (r < -32768) return (short)-32768; else return (short)r; @@ -43,7 +42,7 @@ static inline Float32 Int16ToFloat32(short v) static inline Float32 StereoToMono(bool interleaved, Float32* buffer, int samples, int index, int channels) { Float32 sum = 0; - for (int i = 0; i(inRefCon); - if (!d) - return noErr; + MacDevice* d = reinterpret_cast(inRefCon); + if (!d) + return noErr; - if (!ioData->mNumberBuffers) - return noErr; + if (!ioData->mNumberBuffers) + return noErr; - // Here deinterleaving is expected; it means coreaudio will request multiple buffers - one buffer for one channel - // So only single buffer is filled from MacDevice; other are copies - AudioBuffer& ab = ioData->mBuffers[0]; - if (ab.mNumberChannels == 1) - { - ICELogMedia(<< "CoreAudio output callback for mono " << (int)ab.mDataByteSize << - " bytes"); - memset(ab.mData, 0, ab.mDataByteSize); - d->provideAudioToSpeaker(ab.mNumberChannels, ab.mData, ab.mDataByteSize); - - for (int i=1; imNumberBuffers; i++) - memcpy(ioData->mBuffers[i].mData, ab.mData, ab.mDataByteSize); - } - else - { - ICELogMedia(<< "CoreAudio output callback for stereo " << (int)ab.mDataByteSize << - " bytes") - // Iterate requested buffers - for (unsigned i=0; imNumberBuffers; i++) + // Here deinterleaving is expected; it means coreaudio will request multiple buffers - one buffer for one channel + // So only single buffer is filled from MacDevice; other are copies + AudioBuffer& ab = ioData->mBuffers[0]; + if (ab.mNumberChannels == 1) { - unsigned channels = ioData->mBuffers[i].mNumberChannels; - short* dataPtr = (short*)ioData->mBuffers[i].mData; - unsigned dataSize = ioData->mBuffers[i].mDataByteSize; + ICELogMedia(<< "CoreAudio output callback for mono " << (int)ab.mDataByteSize << " bytes"); + memset(ab.mData, 0, ab.mDataByteSize); + d->provideAudioToSpeaker(ab.mNumberChannels, ab.mData, ab.mDataByteSize); - // Preset with silence - memset(dataPtr, 0, dataSize); - - // Find how much PCM16 samples are required to fill the requested space - d->provideAudioToSpeaker(channels, dataPtr, dataSize); + for (int i = 1; i < ioData->mNumberBuffers; i++) + memcpy(ioData->mBuffers[i].mData, ab.mData, ab.mDataByteSize); } - } + else + { + ICELogMedia(<< "CoreAudio output callback for stereo " << (int)ab.mDataByteSize << " bytes") + // Iterate requested buffers + for (unsigned i = 0; i < ioData->mNumberBuffers; i++) + { + unsigned channels = ioData->mBuffers[i].mNumberChannels; + short* dataPtr = (short*)ioData->mBuffers[i].mData; + unsigned dataSize = ioData->mBuffers[i].mDataByteSize; - return noErr; + // Preset with silence + memset(dataPtr, 0, dataSize); + + // Find how much PCM16 samples are required to fill the requested space + d->provideAudioToSpeaker(channels, dataPtr, dataSize); + } + } + + return noErr; } static char GlobalInputBuffer[AUDIO_MIC_BUFFER_COUNT * AUDIO_MIC_BUFFER_SIZE]; -OSStatus MacDevice::inputCallback(void *inRefCon, - AudioUnitRenderActionFlags *ioActionFlags, - const AudioTimeStamp *inTimeStamp, - UInt32 inBusNumber, - UInt32 inNumberFrames, - AudioBufferList *ioData) +OSStatus MacDevice::inputCallback(void* inRefCon, AudioUnitRenderActionFlags* ioActionFlags, + const AudioTimeStamp* inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, + AudioBufferList* ioData) { - //ICELogDebug(<< "CoreAudio input callback"); + // ICELogDebug(<< "CoreAudio input callback"); MacDevice* d = reinterpret_cast(inRefCon); if (!d) return 0; - OSStatus ostatus; + OSStatus ostatus; AudioBuffer& b = d->mInputBufferList->mBuffers[0]; - //b.mDataByteSize = 65536; + // b.mDataByteSize = 65536; b.mNumberChannels = d->mStreamFormat.mChannelsPerFrame; b.mData = NULL; b.mDataByteSize = inNumberFrames * d->mStreamFormat.mChannelsPerFrame; // Render the unit to get input data - ostatus = AudioUnitRender(d->mAudioUnit.getHandle(), - ioActionFlags, - inTimeStamp, - inBusNumber, - inNumberFrames, - d->mInputBufferList); + ostatus = AudioUnitRender(d->mAudioUnit.getHandle(), ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, + d->mInputBufferList); if (ostatus != noErr) { - ICELogError(<< "Cannot render input audio data, error " << int(ostatus)); + ICELogError(<< "Cannot render input audio data, error " << int(ostatus)); } else { - d->obtainAudioFromMic(b.mNumberChannels, b.mData, b.mDataByteSize); + d->obtainAudioFromMic(b.mNumberChannels, b.mData, b.mDataByteSize); } return noErr; } #ifdef TARGET_IOS -void MacDevice::propListener(void *inClientData, - AudioSessionPropertyID inID, - UInt32 inDataSize, - const void * inData) +void MacDevice::propListener(void* inClientData, AudioSessionPropertyID inID, UInt32 inDataSize, const void* inData) { - MacDevice* d = reinterpret_cast(inClientData); + MacDevice* d = reinterpret_cast(inClientData); CFDictionaryRef routeDictionary; - CFNumberRef reason; - SInt32 reasonVal; + CFNumberRef reason; + SInt32 reasonVal; if (!d || inID != kAudioSessionProperty_AudioRouteChange) return; @@ -388,16 +348,15 @@ void MacDevice::propListener(void *inClientData, } // Audio route changed. Nothing to do in this implementation. - } -void MacDevice::interruptionListener(void *inClientData, UInt32 inInterruption) +void MacDevice::interruptionListener(void* inClientData, UInt32 inInterruption) { MacDevice* d = reinterpret_cast(inClientData); if (inInterruption == kAudioSessionEndInterruption) { - UInt32 audioCategory; + UInt32 audioCategory; OSStatus ostatus; /* Make sure that your application can receive remote control @@ -409,19 +368,16 @@ void MacDevice::interruptionListener(void *inClientData, UInt32 inInterruption) */ /* Make sure we set the correct audio category before restarting */ audioCategory = kAudioSessionCategory_PlayAndRecord; - ostatus = AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, - sizeof(audioCategory), - &audioCategory); + ostatus = AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(audioCategory), &audioCategory); if (ostatus != kAudioSessionNoError) { - ICELogError(<<"Cannot set the audio session category, error " << ostatus); + ICELogError(<< "Cannot set the audio session category, error " << ostatus); } // Start stream d->startStream(); } - else - if (inInterruption == kAudioSessionBeginInterruption) + else if (inInterruption == kAudioSessionBeginInterruption) { d->stopStream(); } @@ -429,211 +385,210 @@ void MacDevice::interruptionListener(void *inClientData, UInt32 inInterruption) #endif MacDevice::MacDevice(int devId) -:mDeviceId(devId), mCapture(false), mRender(false), mActive(false), - mConnection(nullptr), mUsageCount(0) + : mDeviceId(devId), mCapture(false), mRender(false), mActive(false), mConnection(nullptr), mUsageCount(0) { - mInputBuffer.setCapacity(AUDIO_MIC_BUFFER_COUNT * AUDIO_MIC_BUFFER_SIZE); - mOutputBuffer.setCapacity(AUDIO_SPK_BUFFER_SIZE); + mInputBuffer.setCapacity(AUDIO_MIC_BUFFER_COUNT * AUDIO_MIC_BUFFER_SIZE); + mOutputBuffer.setCapacity(AUDIO_SPK_BUFFER_SIZE); } -MacDevice::~MacDevice() -{ -} +MacDevice::~MacDevice() {} DataConnection* MacDevice::connection() { - return mConnection; + return mConnection; } -void MacDevice::setConnection(DataConnection *c) +void MacDevice::setConnection(DataConnection* c) { - mConnection = c; + mConnection = c; } -void MacDevice::provideAudioToSpeaker(int channels, void *buffer, int length) +void MacDevice::provideAudioToSpeaker(int channels, void* buffer, int length) { - if (!mConnection) + if (!mConnection) + return; + + mConnection->onSpkData(getFormat(), buffer, length); return; - - mConnection->onSpkData(getFormat(), buffer, length); - return; } -void MacDevice::obtainAudioFromMic(int channels, const void *buffer, int length) +void MacDevice::obtainAudioFromMic(int channels, const void* buffer, int length) { - if (!mConnection) - return; + if (!mConnection) + return; - // Put audio into internal buffer and see if there are ready AUDIO_BUFFER_SIZE chunks - mConnection->onMicData(getFormat(), buffer, length); - return; + // Put audio into internal buffer and see if there are ready AUDIO_BUFFER_SIZE chunks + mConnection->onMicData(getFormat(), buffer, length); + return; } bool MacDevice::open() { - Lock l(mGuard); - mUsageCount++; - if (mUsageCount == 1) - { - if (!createUnit(true)) + Lock l(mGuard); + mUsageCount++; + if (mUsageCount == 1) { - ICELogError(<< "Unable to create&adjust AudioUnit"); - return false; - // TODO - enable stub for iOS + if (!createUnit(true)) + { + ICELogError(<< "Unable to create&adjust AudioUnit"); + return false; + // TODO - enable stub for iOS + } + startStream(); } - startStream(); - } - return true; + return true; } void MacDevice::close() { - Lock l(mGuard); - if (mUsageCount == 1) - { - stopStream(); - destroyUnit(); - } - if (mUsageCount > 0) - mUsageCount--; + Lock l(mGuard); + if (mUsageCount == 1) + { + stopStream(); + destroyUnit(); + } + if (mUsageCount > 0) + mUsageCount--; } void MacDevice::setRender(bool render) { - mRender = render; + mRender = render; } void MacDevice::setCapture(bool capture) { - mCapture = capture; + mCapture = capture; } int MacDevice::getId() { - return this->mDeviceId; + return this->mDeviceId; } Format MacDevice::getFormat() { - Format result; - result.mChannels = mStreamFormat.mChannelsPerFrame; - result.mRate = mStreamFormat.mSampleRate; - return result; + Format result; + result.mChannels = mStreamFormat.mChannelsPerFrame; + result.mRate = mStreamFormat.mSampleRate; + return result; } void MacDevice::setupStreamFormat() { - mStreamFormat.mSampleRate = AUDIO_SAMPLERATE; - mStreamFormat.mFormatID = kAudioFormatLinearPCM; - mStreamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked; - mStreamFormat.mBitsPerChannel = AUDIO_SAMPLE_WIDTH; - mStreamFormat.mChannelsPerFrame = AUDIO_CHANNELS; - mStreamFormat.mBytesPerFrame = mStreamFormat.mChannelsPerFrame * mStreamFormat.mBitsPerChannel >> 3; - mStreamFormat.mFramesPerPacket = 1; - mStreamFormat.mBytesPerPacket = mStreamFormat.mFramesPerPacket * mStreamFormat.mBytesPerFrame; + mStreamFormat.mSampleRate = AUDIO_SAMPLERATE; + mStreamFormat.mFormatID = kAudioFormatLinearPCM; + mStreamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked; + mStreamFormat.mBitsPerChannel = AUDIO_SAMPLE_WIDTH; + mStreamFormat.mChannelsPerFrame = AUDIO_CHANNELS; + mStreamFormat.mBytesPerFrame = mStreamFormat.mChannelsPerFrame * mStreamFormat.mBitsPerChannel >> 3; + mStreamFormat.mFramesPerPacket = 1; + mStreamFormat.mBytesPerPacket = mStreamFormat.mFramesPerPacket * mStreamFormat.mBytesPerFrame; } bool MacDevice::createUnit(bool voice) { - OSStatus ostatus; + OSStatus ostatus; - mAudioUnit.open(voice); + mAudioUnit.open(voice); - //if (mCapture != mAudioUnit.getEnabled(kAudioUnitScope_Input, Bus_Microphone)) + // if (mCapture != mAudioUnit.getEnabled(kAudioUnitScope_Input, Bus_Microphone)) mAudioUnit.setEnabled(mCapture, kAudioUnitScope_Input, Bus_Microphone); - //mAudioUnit.setEnabled(mCapture, kAudioUnitScope_Output, Bus_Microphone); + // mAudioUnit.setEnabled(mCapture, kAudioUnitScope_Output, Bus_Microphone); - //if (mRender != mAudioUnit.getEnabled(kAudioUnitScope_Output, Bus_Speaker)) + // if (mRender != mAudioUnit.getEnabled(kAudioUnitScope_Output, Bus_Speaker)) mAudioUnit.setEnabled(mRender, kAudioUnitScope_Output, Bus_Speaker); - //mAudioUnit.setEnabled(mRender, kAudioUnitScope_Input, Bus_Speaker); + // mAudioUnit.setEnabled(mRender, kAudioUnitScope_Input, Bus_Speaker); #ifdef TARGET_OSX - // Open device + // Open device - if (mCapture) - mAudioUnit.makeCurrent(mDeviceId, kAudioUnitScope_Global, Bus_Microphone); + if (mCapture) + mAudioUnit.makeCurrent(mDeviceId, kAudioUnitScope_Global, Bus_Microphone); - if (mRender) - mAudioUnit.makeCurrent(mDeviceId, kAudioUnitScope_Global, Bus_Speaker); + if (mRender) + mAudioUnit.makeCurrent(mDeviceId, kAudioUnitScope_Global, Bus_Speaker); #endif - setupStreamFormat(); + setupStreamFormat(); - if (mCapture) - { - mCaptureInputFormat = mAudioUnit.getFormat(kAudioUnitScope_Input, Bus_Microphone); - mCaptureOutputFormat = mAudioUnit.getFormat(kAudioUnitScope_Output, Bus_Microphone); - mStreamFormat.mSampleRate = mCaptureInputFormat.mSampleRate; - if (mCaptureOutputFormat.mFormatFlags & kAudioFormatFlagIsNonInterleaved) - ICELogDebug(<< "Input device produces noninterleaved data"); + if (mCapture) + { + mCaptureInputFormat = mAudioUnit.getFormat(kAudioUnitScope_Input, Bus_Microphone); + mCaptureOutputFormat = mAudioUnit.getFormat(kAudioUnitScope_Output, Bus_Microphone); + mStreamFormat.mSampleRate = mCaptureInputFormat.mSampleRate; + if (mCaptureOutputFormat.mFormatFlags & kAudioFormatFlagIsNonInterleaved) + ICELogDebug(<< "Input device produces noninterleaved data"); - mAudioUnit.setFormat(mStreamFormat, kAudioUnitScope_Output, Bus_Microphone); - // Start resampler - mCaptureResampler.start(mStreamFormat.mChannelsPerFrame, mStreamFormat.mSampleRate, AUDIO_SAMPLERATE); - } + mAudioUnit.setFormat(mStreamFormat, kAudioUnitScope_Output, Bus_Microphone); + // Start resampler + mCaptureResampler.start(mStreamFormat.mChannelsPerFrame, mStreamFormat.mSampleRate, AUDIO_SAMPLERATE); + } - if (mRender) - { - // Init resample - mRenderOutputFormat = mAudioUnit.getFormat(kAudioUnitScope_Output, Bus_Speaker); - mRenderInputFormat = mAudioUnit.getFormat(kAudioUnitScope_Input, Bus_Speaker); - mAudioUnit.setFormat(mStreamFormat, kAudioUnitScope_Input, Bus_Speaker); - // Start resample - mRenderResampler.start(mStreamFormat.mChannelsPerFrame, AUDIO_SAMPLERATE, mStreamFormat.mSampleRate); + if (mRender) + { + // Init resample + mRenderOutputFormat = mAudioUnit.getFormat(kAudioUnitScope_Output, Bus_Speaker); + mRenderInputFormat = mAudioUnit.getFormat(kAudioUnitScope_Input, Bus_Speaker); + mAudioUnit.setFormat(mStreamFormat, kAudioUnitScope_Input, Bus_Speaker); + // Start resample + mRenderResampler.start(mStreamFormat.mChannelsPerFrame, AUDIO_SAMPLERATE, mStreamFormat.mSampleRate); - // Set current render format - it is format required by unit from application; scope is Input and bus is 0 (speaker) - //mAudioUnit.setFormat(mRenderInputFormat, kAudioUnitScope_Input, Bus_Speaker); + // Set current render format - it is format required by unit from application; scope is Input and bus is 0 + // (speaker) + // mAudioUnit.setFormat(mRenderInputFormat, kAudioUnitScope_Input, Bus_Speaker); - // Configure callback - AURenderCallbackStruct cb; - cb.inputProc = outputCallback; - cb.inputProcRefCon = this; - mAudioUnit.setCallback(cb, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, Bus_Speaker); - } + // Configure callback + AURenderCallbackStruct cb; + cb.inputProc = outputCallback; + cb.inputProcRefCon = this; + mAudioUnit.setCallback(cb, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, Bus_Speaker); + } - if (mCapture) - { - AURenderCallbackStruct cb; - cb.inputProc = inputCallback; - cb.inputProcRefCon = this; - mAudioUnit.setCallback(cb, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, Bus_Microphone); //!!! + if (mCapture) + { + AURenderCallbackStruct cb; + cb.inputProc = inputCallback; + cb.inputProcRefCon = this; + mAudioUnit.setCallback(cb, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, + Bus_Microphone); //!!! #ifdef TARGET_OSX - AudioBuffer *ab; - UInt32 size, bufsize; + AudioBuffer* ab; + UInt32 size, bufsize; - mAudioUnit.setBufferFrameSizeInMilliseconds(COREAUDIO_BUFFER_TIME); + mAudioUnit.setBufferFrameSizeInMilliseconds(COREAUDIO_BUFFER_TIME); - // Get device's buffer frame size - bufsize = mAudioUnit.getBufferFrameSize(); - mInputBufferList = (AudioBufferList*)malloc(sizeof(AudioBufferList) + sizeof(AudioBuffer)); - if (!mInputBufferList) - { - ICELogError(<< "No memory for buffer list"); - return false; - } - mInputBufferList->mNumberBuffers = 1; - ab = &mInputBufferList->mBuffers[0]; - ab->mNumberChannels = mStreamFormat.mChannelsPerFrame; - ab->mDataByteSize = 0;//bufsize * ab->mNumberChannels * mCaptureOutputFormat.mBitsPerChannel / 8 * 8; - ab->mData = NULL;//malloc(ab->mDataByteSize); - if (!ab->mData) - { - //ICELogError(<< "No memory for capture buffer"); - } + // Get device's buffer frame size + bufsize = mAudioUnit.getBufferFrameSize(); + mInputBufferList = (AudioBufferList*)malloc(sizeof(AudioBufferList) + sizeof(AudioBuffer)); + if (!mInputBufferList) + { + ICELogError(<< "No memory for buffer list"); + return false; + } + mInputBufferList->mNumberBuffers = 1; + ab = &mInputBufferList->mBuffers[0]; + ab->mNumberChannels = mStreamFormat.mChannelsPerFrame; + ab->mDataByteSize = 0; // bufsize * ab->mNumberChannels * mCaptureOutputFormat.mBitsPerChannel / 8 * 8; + ab->mData = NULL; // malloc(ab->mDataByteSize); + if (!ab->mData) + { + // ICELogError(<< "No memory for capture buffer"); + } #endif #ifdef TARGET_IOS - /* We will let AudioUnitRender() to allocate the buffer - * for us later - */ - mInputBufferList = (AudioBufferList*)malloc(sizeof(AudioBufferList) + sizeof(AudioBuffer)); - if (!mInputBufferList) - { - ICELogError(<< "No memory for buffer list"); - return false; - } - mInputBufferList->mNumberBuffers = 1; - mInputBufferList->mBuffers[0].mNumberChannels = 2; + /* We will let AudioUnitRender() to allocate the buffer + * for us later + */ + mInputBufferList = (AudioBufferList*)malloc(sizeof(AudioBufferList) + sizeof(AudioBuffer)); + if (!mInputBufferList) + { + ICELogError(<< "No memory for buffer list"); + return false; + } + mInputBufferList->mNumberBuffers = 1; + mInputBufferList->mBuffers[0].mNumberChannels = 2; #endif } @@ -644,59 +599,60 @@ bool MacDevice::createUnit(bool voice) void MacDevice::destroyUnit() { - mAudioUnit.close(); - mCaptureResampler.stop(); - mRenderResampler.stop(); + mAudioUnit.close(); + mCaptureResampler.stop(); + mRenderResampler.stop(); } void MacDevice::startStream() { - if (mActive) - return; + if (mActive) + return; #ifdef TARGET_IOS - if (iosVersion() > 4) - { - UInt32 sessionMode = kAudioSessionMode_VoiceChat; - AudioSessionSetProperty(kAudioSessionProperty_Mode, sizeof(sessionMode), &sessionMode); - } + if (iosVersion() > 4) + { + UInt32 sessionMode = kAudioSessionMode_VoiceChat; + AudioSessionSetProperty(kAudioSessionProperty_Mode, sizeof(sessionMode), &sessionMode); + } // Share audio chain - //UInt32 allowMixing = YES; - //AudioSessionSetProperty (kAudioSessionProperty_OverrideCategoryMixWithOthers, sizeof (allowMixing), &allowMixing); + // UInt32 allowMixing = YES; + // AudioSessionSetProperty (kAudioSessionProperty_OverrideCategoryMixWithOthers, sizeof (allowMixing), + // &allowMixing); // Activate audio chain AudioSessionSetActive(true); #endif - OSStatus ostatus; - if (mAudioUnit.getHandle()) - { - ostatus = AudioOutputUnitStart(mAudioUnit.getHandle()); - if (ostatus != noErr) + OSStatus ostatus; + if (mAudioUnit.getHandle()) { - ICELogError(<< "Failed to start audio unit, error " << int(ostatus)); - return; + ostatus = AudioOutputUnitStart(mAudioUnit.getHandle()); + if (ostatus != noErr) + { + ICELogError(<< "Failed to start audio unit, error " << int(ostatus)); + return; + } } - } - mActive = true; + mActive = true; } void MacDevice::stopStream() { - if (!mActive || !mAudioUnit.getHandle()) + if (!mActive || !mAudioUnit.getHandle()) return; - OSStatus ostatus; - ostatus = AudioOutputUnitStop(mAudioUnit.getHandle()); - if (ostatus != noErr) - { - ICELogError(<< "Failed to stop audio unit, error " << int(ostatus)); - } + OSStatus ostatus; + ostatus = AudioOutputUnitStop(mAudioUnit.getHandle()); + if (ostatus != noErr) + { + ICELogError(<< "Failed to stop audio unit, error " << int(ostatus)); + } #ifdef TARGET_IOS - AudioSessionSetActive(false); + AudioSessionSetActive(false); #endif - mActive = false; + mActive = false; } bool MacDevice::createResampleUnit(AudioStreamBasicDescription format) @@ -707,127 +663,112 @@ bool MacDevice::createResampleUnit(AudioStreamBasicDescription format) class MacDeviceList { public: - MacDeviceList(); - ~MacDeviceList(); - PMacDevice findDevice(int devId); + MacDeviceList(); + ~MacDeviceList(); + PMacDevice findDevice(int devId); - static MacDeviceList& instance(); + static MacDeviceList& instance(); protected: - Mutex mGuard; - std::vector mDeviceList; - static MacDeviceList* mInstance; + Mutex mGuard; + std::vector mDeviceList; + static MacDeviceList* mInstance; }; MacDeviceList* MacDeviceList::mInstance = NULL; -MacDeviceList::MacDeviceList() -{ +MacDeviceList::MacDeviceList() {} -} - -MacDeviceList::~MacDeviceList() -{ - -} +MacDeviceList::~MacDeviceList() {} MacDeviceList& MacDeviceList::instance() { - if (!mInstance) - mInstance = new MacDeviceList(); - return *mInstance; + if (!mInstance) + mInstance = new MacDeviceList(); + return *mInstance; } PMacDevice MacDeviceList::findDevice(int devId) { - Lock l(mGuard); - for (unsigned i=0; igetId() == devId) return d; - } + } - PMacDevice d(new MacDevice(devId)); - mDeviceList.push_back(d); - return d; + PMacDevice d(new MacDevice(devId)); + mDeviceList.push_back(d); + return d; } // Share list of opened devices -MacInputDevice::MacInputDevice(int devId) - :InputDevice() +MacInputDevice::MacInputDevice(int devId) : InputDevice() { - // Look for MacDevice - mDevice = MacDeviceList::instance().findDevice(devId); - mDevice->setCapture(true); - mDevice->setConnection(mConnection); + // Look for MacDevice + mDevice = MacDeviceList::instance().findDevice(devId); + mDevice->setCapture(true); + mDevice->setConnection(mConnection); } MacInputDevice::~MacInputDevice() { - mDevice.reset(); + mDevice.reset(); } bool MacInputDevice::open() { - mDevice->setConnection(mConnection); - return mDevice->open(); + mDevice->setConnection(mConnection); + return mDevice->open(); } void MacInputDevice::close() { - mDevice->close(); + mDevice->close(); } Format MacInputDevice::getFormat() { - return mDevice->getFormat(); + return mDevice->getFormat(); } -MacOutputDevice::MacOutputDevice(int devId) - :OutputDevice() +MacOutputDevice::MacOutputDevice(int devId) : OutputDevice() { - // Look for MacDevice - mDevice = MacDeviceList::instance().findDevice(devId); - mDevice->setRender(true); - mDevice->setConnection(mConnection); + // Look for MacDevice + mDevice = MacDeviceList::instance().findDevice(devId); + mDevice->setRender(true); + mDevice->setConnection(mConnection); } MacOutputDevice::~MacOutputDevice() { - mDevice.reset(); + mDevice.reset(); } bool MacOutputDevice::open() { - mDevice->setConnection(mConnection); - return mDevice->open(); + mDevice->setConnection(mConnection); + return mDevice->open(); } void MacOutputDevice::close() { - mDevice->close(); + mDevice->close(); } Format MacOutputDevice::getFormat() { - return mDevice->getFormat(); + return mDevice->getFormat(); } -MacEnumerator::MacEnumerator() - :mDefaultInput(0), mDefaultOutput(0) -{ +MacEnumerator::MacEnumerator() : mDefaultInput(0), mDefaultOutput(0) {} -} - -MacEnumerator::~MacEnumerator() -{ - -} +MacEnumerator::~MacEnumerator() {} void MacEnumerator::open(int direction) { - mDirection = direction; + mDirection = direction; #ifdef TARGET_OSX mDefaultInput = 0; @@ -835,30 +776,29 @@ void MacEnumerator::open(int direction) mDeviceList.clear(); AudioObjectPropertyAddress addr; - OSStatus osstatus; - UInt32 devSize, size; + OSStatus osstatus; + UInt32 devSize, size; // Get audio list size addr.mSelector = kAudioHardwarePropertyDevices; addr.mScope = kAudioObjectPropertyScopeGlobal; addr.mElement = kAudioObjectPropertyElementMaster; - osstatus = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &addr, - 0, NULL, &devSize); + osstatus = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &addr, 0, NULL, &devSize); if (osstatus != noErr) { devSize = 0; return; } - UInt32 devCount = devSize / sizeof(AudioDeviceID); + UInt32 devCount = devSize / sizeof(AudioDeviceID); std::vector deviceIds; deviceIds.resize(devCount); // Get actual list - osstatus = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, - 0, NULL, &devSize, (void *)&deviceIds.front()); + osstatus = + AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0, NULL, &devSize, (void*)&deviceIds.front()); if (osstatus != noErr) return; - for (unsigned i=0; i::iterator r = std::find_if(mDeviceList.begin(), mDeviceList.end(), - [devId] (const DeviceInfo& di) { return di.mId == devId;}); - if (r != mDeviceList.end()) - mDefaultInput = r - mDeviceList.begin(); - } + if (osstatus == noErr) + { + std::vector::iterator r = std::find_if( + mDeviceList.begin(), mDeviceList.end(), [devId](const DeviceInfo& di) { return di.mId == devId; }); + if (r != mDeviceList.end()) + mDefaultInput = r - mDeviceList.begin(); + } } /* Find default audio output device */ if (direction == mySpeaker) { - addr.mSelector = kAudioHardwarePropertyDefaultOutputDevice; - osstatus = AudioObjectGetPropertyData(kAudioObjectSystemObject, - &addr, 0, NULL, - &size, (void *)&devId); - if (osstatus == noErr) - { - std::vector::iterator r = std::find_if(mDeviceList.begin(), mDeviceList.end(), - [devId](const DeviceInfo& di) { return di.mId == devId;}); - if (r != mDeviceList.end()) - mDefaultOutput = r - mDeviceList.begin(); - } + addr.mSelector = kAudioHardwarePropertyDefaultOutputDevice; + osstatus = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0, NULL, &size, (void*)&devId); + if (osstatus == noErr) + { + std::vector::iterator r = std::find_if( + mDeviceList.begin(), mDeviceList.end(), [devId](const DeviceInfo& di) { return di.mId == devId; }); + if (r != mDeviceList.end()) + mDefaultOutput = r - mDeviceList.begin(); + } } #endif } -void MacEnumerator::getInfo(DeviceInfo &di) +void MacEnumerator::getInfo(DeviceInfo& di) { - UInt32 size; - OSStatus osstatus; + UInt32 size; + OSStatus osstatus; // Name AudioObjectPropertyAddress addr; @@ -930,7 +867,7 @@ void MacEnumerator::getInfo(DeviceInfo &di) addr.mElement = kAudioObjectPropertyElementMaster; char name[256]; size = sizeof(name); - AudioObjectGetPropertyData(di.mId, &addr, 0, NULL, &size, (void *)name); + AudioObjectGetPropertyData(di.mId, &addr, 0, NULL, &size, (void*)name); di.mName = name; // Get the number of input channels @@ -984,7 +921,8 @@ void MacEnumerator::getInfo(DeviceInfo &di) di.mOutputCount += buf->mBuffers[idx].mNumberChannels; } } - free(buf); buf = NULL; + free(buf); + buf = NULL; } /* Get default sample rate */ @@ -992,7 +930,7 @@ void MacEnumerator::getInfo(DeviceInfo &di) addr.mScope = kAudioObjectPropertyScopeGlobal; size = sizeof(Float64); Float64 sampleRate; - osstatus = AudioObjectGetPropertyData (di.mId, &addr, 0, NULL, &size, &sampleRate); + osstatus = AudioObjectGetPropertyData(di.mId, &addr, 0, NULL, &size, &sampleRate); if (osstatus == noErr) di.mDefaultRate = int(sampleRate); @@ -1009,12 +947,9 @@ void MacEnumerator::getInfo(DeviceInfo &di) } } -void MacEnumerator::close() -{ +void MacEnumerator::close() {} -} - -int MacEnumerator::count() +int MacEnumerator::count() { return mDeviceList.size(); } @@ -1026,7 +961,7 @@ std::tstring MacEnumerator::nameAt(int index) int MacEnumerator::idAt(int index) { - return mDeviceList[index].mId; + return mDeviceList[index].mId; } int MacEnumerator::indexOfDefaultDevice() diff --git a/src/engine/audio/Audio_CoreAudio.h b/src/engine/audio/Audio_CoreAudio.h index 792b98a0..abf6befc 100644 --- a/src/engine/audio/Audio_CoreAudio.h +++ b/src/engine/audio/Audio_CoreAudio.h @@ -25,69 +25,71 @@ namespace Audio { -class AudioException: public Exception +class AudioException : public Exception { public: - AudioException(int code, OSStatus subcode) - :Exception(code, int(subcode)) - {} + AudioException(int code, OSStatus subcode) : Exception(code, int(subcode)) {} }; -//#ifndef AudioDeviceID -//# define AudioDeviceID unsigned -//#endif -class MacEnumerator: public Enumerator +// #ifndef AudioDeviceID +// # define AudioDeviceID unsigned +// #endif +class MacEnumerator : public Enumerator { public: - MacEnumerator(); - ~MacEnumerator(); + MacEnumerator(); + ~MacEnumerator(); - void open(int direction); - void close(); + void open(int direction); + void close(); - int count(); - std::tstring nameAt(int index); - int idAt(int index); - int indexOfDefaultDevice(); + int count(); + std::tstring nameAt(int index); + int idAt(int index); + int indexOfDefaultDevice(); protected: - struct DeviceInfo - { - AudioDeviceID mId; - std::string mName; - bool mCanChangeOutputVolume; - bool mCanChangeInputVolume; - int mInputCount, mOutputCount; - int mDefaultRate; - DeviceInfo(): mId(0), mCanChangeOutputVolume(false), mCanChangeInputVolume(false), mInputCount(0), mOutputCount(0), mDefaultRate(16000) {} - }; - std::vector mDeviceList; - unsigned mDefaultInput, mDefaultOutput; - int mDirection; - void getInfo(DeviceInfo& di); + struct DeviceInfo + { + AudioDeviceID mId; + std::string mName; + bool mCanChangeOutputVolume; + bool mCanChangeInputVolume; + int mInputCount, mOutputCount; + int mDefaultRate; + DeviceInfo() + : mId(0), mCanChangeOutputVolume(false), mCanChangeInputVolume(false), mInputCount(0), mOutputCount(0), + mDefaultRate(16000) + { + } + }; + std::vector mDeviceList; + unsigned mDefaultInput, mDefaultOutput; + int mDirection; + void getInfo(DeviceInfo& di); }; class CoreAudioUnit { public: - CoreAudioUnit(); - ~CoreAudioUnit(); + CoreAudioUnit(); + ~CoreAudioUnit(); - void open(bool voice); - void close(); - AudioStreamBasicDescription getFormat(int scope, int bus); - void setFormat(AudioStreamBasicDescription& format, int scope, int bus); - bool getEnabled(int scope, int bus); - void setEnabled(bool enabled, int scope, int bus); - void makeCurrent(AudioDeviceID deviceId, int scope, int bus); - void setCallback(AURenderCallbackStruct cb, int callbackType, int scope, int bus); - void setBufferFrameSizeInMilliseconds(int ms); - int getBufferFrameSize(); - void initialize(); - AudioUnit getHandle(); + void open(bool voice); + void close(); + AudioStreamBasicDescription getFormat(int scope, int bus); + void setFormat(AudioStreamBasicDescription& format, int scope, int bus); + bool getEnabled(int scope, int bus); + void setEnabled(bool enabled, int scope, int bus); + void makeCurrent(AudioDeviceID deviceId, int scope, int bus); + void setCallback(AURenderCallbackStruct cb, int callbackType, int scope, int bus); + void setBufferFrameSizeInMilliseconds(int ms); + int getBufferFrameSize(); + void initialize(); + AudioUnit getHandle(); protected: - AudioUnit mUnit; + AudioUnit mUnit; }; class MacDevice @@ -96,101 +98,92 @@ public: MacDevice(int devId); ~MacDevice(); - bool open(); - void close(); - void setRender(bool render); - void setCapture(bool capture); - int getId(); - Format getFormat(); + bool open(); + void close(); + void setRender(bool render); + void setCapture(bool capture); + int getId(); + Format getFormat(); DataConnection* connection(); - void setConnection(DataConnection* c); - void provideAudioToSpeaker(int channels, void* buffer, int length); - void obtainAudioFromMic(int channels, const void* buffer, int length); + void setConnection(DataConnection* c); + void provideAudioToSpeaker(int channels, void* buffer, int length); + void obtainAudioFromMic(int channels, const void* buffer, int length); protected: - AudioDeviceID mDeviceId; - bool mCapture, mRender; - bool mActive; - int mUsageCount; - Mutex mGuard; + AudioDeviceID mDeviceId; + bool mCapture, mRender; + bool mActive; + int mUsageCount; + Mutex mGuard; - CoreAudioUnit mAudioUnit; - AudioComponent mComponent; - AudioStreamBasicDescription mCaptureInputFormat, mCaptureOutputFormat, mRenderInputFormat, mRenderOutputFormat, mStreamFormat; + CoreAudioUnit mAudioUnit; + AudioComponent mComponent; + AudioStreamBasicDescription mCaptureInputFormat, mCaptureOutputFormat, mRenderInputFormat, mRenderOutputFormat, + mStreamFormat; AudioBufferList* mInputBufferList; - DataConnection* mConnection; - SpeexResampler mCaptureResampler, mRenderResampler; - ByteBuffer mTail; - DataWindow mInputBuffer, mOutputBuffer; - bool createUnit(bool voice); - void destroyUnit(); - void startStream(); - void stopStream(); - void setupStreamFormat(); - bool createResampleUnit(AudioStreamBasicDescription format); + DataConnection* mConnection; + SpeexResampler mCaptureResampler, mRenderResampler; + ByteBuffer mTail; + DataWindow mInputBuffer, mOutputBuffer; + bool createUnit(bool voice); + void destroyUnit(); + void startStream(); + void stopStream(); + void setupStreamFormat(); + bool createResampleUnit(AudioStreamBasicDescription format); - static OSStatus outputCallback( void *inRefCon, - AudioUnitRenderActionFlags *ioActionFlags, - const AudioTimeStamp *inTimeStamp, - UInt32 inBusNumber, - UInt32 inNumberFrames, - AudioBufferList *ioData ); + static OSStatus outputCallback(void* inRefCon, AudioUnitRenderActionFlags* ioActionFlags, + const AudioTimeStamp* inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, + AudioBufferList* ioData); - static OSStatus inputCallback(void *inRefCon, - AudioUnitRenderActionFlags *ioActionFlags, - const AudioTimeStamp *inTimeStamp, - UInt32 inBusNumber, - UInt32 inNumberFrames, - AudioBufferList *ioData); + static OSStatus inputCallback(void* inRefCon, AudioUnitRenderActionFlags* ioActionFlags, + const AudioTimeStamp* inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, + AudioBufferList* ioData); #ifdef TARGET_IOS - static void propListener(void *inClientData, - AudioSessionPropertyID inID, - UInt32 inDataSize, - const void * inData); - static void interruptionListener(void *inClientData, UInt32 inInterruption); + static void propListener(void* inClientData, AudioSessionPropertyID inID, UInt32 inDataSize, const void* inData); + static void interruptionListener(void* inClientData, UInt32 inInterruption); #endif - }; typedef std::shared_ptr PMacDevice; -class MacInputDevice: public InputDevice +class MacInputDevice : public InputDevice { public: MacInputDevice(int devId); ~MacInputDevice(); - bool open(); - void close(); + bool open(); + void close(); Format getFormat(); - bool fakeMode(); - void setFakeMode(bool fakemode); - int readBuffer(void* buffer); + bool fakeMode(); + void setFakeMode(bool fakemode); + int readBuffer(void* buffer); + protected: PMacDevice mDevice; - }; -class MacOutputDevice: public OutputDevice +class MacOutputDevice : public OutputDevice { public: MacOutputDevice(int devId); ~MacOutputDevice(); - bool open(); - void close(); + bool open(); + void close(); Format getFormat(); - bool fakeMode(); - void setFakeMode(bool fakemode); + bool fakeMode(); + void setFakeMode(bool fakemode); protected: PMacDevice mDevice; }; -} +} // namespace Audio #endif // TARGET_OSX diff --git a/src/engine/audio/Audio_DataWindow.cpp b/src/engine/audio/Audio_DataWindow.cpp index 5c725c6a..06dc0f2c 100644 --- a/src/engine/audio/Audio_DataWindow.cpp +++ b/src/engine/audio/Audio_DataWindow.cpp @@ -8,8 +8,7 @@ using namespace Audio; -DataWindow::DataWindow() -{} +DataWindow::DataWindow() {} DataWindow::~DataWindow() { @@ -28,8 +27,8 @@ void DataWindow::setCapacity(size_t capacity) if (capacity <= mCapacity) return; - size_t tail = capacity - mCapacity; - char* buffer = mData; + size_t tail = capacity - mCapacity; + char* buffer = mData; mData = (char*)realloc(mData, capacity); if (!mData) { @@ -145,7 +144,7 @@ size_t DataWindow::read(void* buffer, size_t length) if (buffer) memcpy(buffer, mData, length); if (length < mFilled) - memmove(mData, mData+length, mFilled - length); + memmove(mData, mData + length, mFilled - length); mFilled -= length; } return length; @@ -181,7 +180,7 @@ void DataWindow::zero(size_t length) size_t DataWindow::moveTo(DataWindow& dst, size_t size) { - Lock l(mMutex); + Lock l(mMutex); size_t avail = std::min(size, (size_t)filled()); if (avail != 0) @@ -195,18 +194,18 @@ size_t DataWindow::moveTo(DataWindow& dst, size_t size) std::chrono::milliseconds DataWindow::getTimeLength(const Audio::Format& fmt) const { Lock l(mMutex); - return std::chrono::milliseconds(mFilled / sizeof(short) / fmt.channels() / (fmt.rate()/ 1000)); + return std::chrono::milliseconds(mFilled / sizeof(short) / fmt.channels() / (fmt.rate() / 1000)); } void DataWindow::makeStereoFromMono(DataWindow& dst, DataWindow& src) { Lock lockDst(dst.mMutex), lockSrc(src.mMutex); - dst.setCapacity(src.filled()*2); + dst.setCapacity(src.filled() * 2); short* input = (short*)src.mutableData(); short* output = (short*)dst.mutableData(); - for (int i=0; iconnection() == this) - mInput->setConnection(nullptr); - mInput.reset(); - } + if (mInput) + { + if (mInput->connection() == this) + mInput->setConnection(nullptr); + mInput.reset(); + } - if (mOutput) - { - if (mOutput->connection() == this) - mOutput->setConnection(nullptr); - mOutput.reset(); - } + if (mOutput) + { + if (mOutput->connection() == this) + mOutput->setConnection(nullptr); + mOutput.reset(); + } } DevicePair& DevicePair::setAec(bool aec) { - mAec = aec; - return *this; + mAec = aec; + return *this; } bool DevicePair::aec() { - return mAec; + return mAec; } DevicePair& DevicePair::setAgc(bool agc) { - mAgc = agc; - return *this; + mAgc = agc; + return *this; } bool DevicePair::agc() { - return mAgc; + return mAgc; } VariantMap* DevicePair::config() { - return mConfig; + return mConfig; } DevicePair& DevicePair::setConfig(VariantMap* config) { - mConfig = config; - return *this; + mConfig = config; + return *this; } PInputDevice DevicePair::input() { - return mInput; + return mInput; } DevicePair& DevicePair::setInput(PInputDevice input) { - if (mInput == input) + if (mInput == input) + return *this; + + mInput = input; + mInput->setConnection(this); + if (mDelegate) + mDelegate->deviceChanged(this); + return *this; - - mInput = input; - mInput->setConnection(this); - if (mDelegate) - mDelegate->deviceChanged(this); - - return *this; } POutputDevice DevicePair::output() { - return mOutput; + return mOutput; } DevicePair& DevicePair::setOutput(POutputDevice output) { - if (output == mOutput) + if (output == mOutput) + return *this; + + mOutput = output; + mOutput->setConnection(this); + if (mDelegate) + mDelegate->deviceChanged(this); + return *this; - - mOutput = output; - mOutput->setConnection(this); - if (mDelegate) - mDelegate->deviceChanged(this); - - return *this; } bool DevicePair::start() { - bool result = false; - if (mInput) - result = mInput->open(); - if (mOutput && result) - result &= mOutput->open(); + bool result = false; + if (mInput) + result = mInput->open(); + if (mOutput && result) + result &= mOutput->open(); - return result; + return result; } void DevicePair::stop() { - if (mInput) - mInput->close(); - if (mOutput) - mOutput->close(); + if (mInput) + mInput->close(); + if (mOutput) + mOutput->close(); } DevicePair& DevicePair::setDelegate(Delegate* dc) { - mDelegate = dc; - return *this; + mDelegate = dc; + return *this; } DevicePair::Delegate* DevicePair::delegate() { - return mDelegate; + return mDelegate; } DevicePair& DevicePair::setMonitoring(DataConnection* monitoring) { - mMonitoring = monitoring; - return *this; + mMonitoring = monitoring; + return *this; } DataConnection* DevicePair::monitoring() { - return mMonitoring; + return mMonitoring; } Player& DevicePair::player() { - return mPlayer; + return mPlayer; } void DevicePair::onMicData(const Format& f, const void* buffer, int length) { #ifdef DUMP_NATIVEINPUT - if (!mNativeInputDump) - { - mNativeInputDump = std::make_shared(); - mNativeInputDump->open("nativeinput.wav", f.mRate, f.mChannels); - } - if (mNativeInputDump) - mNativeInputDump->write(buffer, length); + if (!mNativeInputDump) + { + mNativeInputDump = std::make_shared(); + mNativeInputDump->open("nativeinput.wav", f.mRate, f.mChannels); + } + if (mNativeInputDump) + mNativeInputDump->write(buffer, length); #endif - // send the data to internal queue - it can hold data which were not processed by resampler in last call - mInputResampingData.add(buffer, length); + // send the data to internal queue - it can hold data which were not processed by resampler in last call + mInputResampingData.add(buffer, length); - // split processing by blocks - int blocks = mInputResampingData.filled() / (int)f.sizeFromTime(AUDIO_MIC_BUFFER_LENGTH); + // split processing by blocks + int blocks = mInputResampingData.filled() / (int)f.sizeFromTime(AUDIO_MIC_BUFFER_LENGTH); - for (int blockIndex = 0; blockIndex < blocks; blockIndex++) - { + for (int blockIndex = 0; blockIndex < blocks; blockIndex++) + { + size_t wasProcessed = 0; - size_t wasProcessed = 0; + size_t wasProduced = mMicResampler.resample(f.mRate, // Source rate + mInputResampingData.data(), // Source data + (int)f.sizeFromTime(AUDIO_MIC_BUFFER_LENGTH), // Source size + wasProcessed, + AUDIO_SAMPLERATE, // Dest rate + mInputBuffer.mutableData() + mInputBuffer.filled(), + mInputBuffer.capacity() - mInputBuffer.filled()); - size_t wasProduced = mMicResampler.resample(f.mRate, // Source rate - mInputResampingData.data(), // Source data - (int)f.sizeFromTime(AUDIO_MIC_BUFFER_LENGTH), // Source size - wasProcessed, - AUDIO_SAMPLERATE, // Dest rate - mInputBuffer.mutableData() + mInputBuffer.filled(), - mInputBuffer.capacity() - mInputBuffer.filled()); - - mInputBuffer.setFilled(mInputBuffer.filled() + wasProduced); - mInputResampingData.erase((int)f.sizeFromTime(AUDIO_MIC_BUFFER_LENGTH)); - processMicData(Format(), mInputBuffer.mutableData(), (int)Format().sizeFromTime(AUDIO_MIC_BUFFER_LENGTH)); - - mInputBuffer.erase((int)Format().sizeFromTime(AUDIO_MIC_BUFFER_LENGTH)); - } + mInputBuffer.setFilled(mInputBuffer.filled() + wasProduced); + mInputResampingData.erase((int)f.sizeFromTime(AUDIO_MIC_BUFFER_LENGTH)); + processMicData(Format(), mInputBuffer.mutableData(), (int)Format().sizeFromTime(AUDIO_MIC_BUFFER_LENGTH)); + mInputBuffer.erase((int)Format().sizeFromTime(AUDIO_MIC_BUFFER_LENGTH)); + } } void DevicePair::onSpkData(const Format& f, void* buffer, int length) { - //ICELogMedia(<< "Audio::DevicePair::onSpkData() begin"); + // ICELogMedia(<< "Audio::DevicePair::onSpkData() begin"); #ifdef DUMP_NATIVEOUTPUT - if (!mNativeOutputDump) - { - mNativeOutputDump = std::make_shared(); - mNativeOutputDump->open("nativeoutput.wav", f.mRate, f.mChannels); - } -#endif -#ifdef CONSOLE_LOGGING - printf("Speaker requests %d\n", length); -#endif - - Format nativeFormat = mOutput->getFormat(); - // See how much bytes are needed yet - mOutputNativeData can contain some data already - int required = length - mOutputNativeData.filled(); - if (required > 0) - { - - // Find how much blocks must be received from RTP/decoder side - int nativeBufferSize = (int)nativeFormat.sizeFromTime(AUDIO_SPK_BUFFER_LENGTH); - int blocks = required / nativeBufferSize; - if (required % nativeBufferSize) - blocks++; - - // Now request data from terminal or whetever delegate is - for (int blockIndex = 0; blockIndex < blocks; blockIndex++) + if (!mNativeOutputDump) { - memset(mOutput10msBuffer.mutableData(), 0, (size_t)mOutput10msBuffer.capacity()); - - // Ask audio data on main AUDIO_SAMPLERATE frequency - if (mDelegate) - mDelegate->onSpkData(Format(), mOutput10msBuffer.mutableData(), mOutput10msBuffer.capacity()); - - // Replace received data with custom file or data playing - mPlayer.onSpkData(Format(), mOutput10msBuffer.mutableData(), mOutput10msBuffer.capacity()); - - // Save it to process with AEC - if (mAec) - mAecSpkBuffer.add(mOutput10msBuffer.data(), mOutput10msBuffer.capacity()); - - // Resample these 10 milliseconds it to native format - size_t wasProcessed = 0; - size_t wasProduced = mSpkResampler.resample(Format().mRate, - mOutput10msBuffer.data(), - mOutput10msBuffer.capacity(), - wasProcessed, f.mRate, - mOutputNativeData.mutableData() + mOutputNativeData.filled(), - mOutputNativeData.capacity() - mOutputNativeData.filled()); - mOutputNativeData.setFilled(mOutputNativeData.filled() + wasProduced); -#ifdef CONSOLE_LOGGING - printf("Resampled %d to %d\n", wasProcessed, wasProduced); -#endif + mNativeOutputDump = std::make_shared(); + mNativeOutputDump->open("nativeoutput.wav", f.mRate, f.mChannels); } - } - - // assert(mOutputNativeData.filled() >= length); -#ifdef DUMP_NATIVEOUTPUT - if (mNativeOutputDump) - mNativeOutputDump->write(mOutputNativeData.data(), length); +#endif +#ifdef CONSOLE_LOGGING + printf("Speaker requests %d\n", length); #endif - mOutputNativeData.read(buffer, length); + Format nativeFormat = mOutput->getFormat(); + // See how much bytes are needed yet - mOutputNativeData can contain some data already + int required = length - mOutputNativeData.filled(); + if (required > 0) + { + // Find how much blocks must be received from RTP/decoder side + int nativeBufferSize = (int)nativeFormat.sizeFromTime(AUDIO_SPK_BUFFER_LENGTH); + int blocks = required / nativeBufferSize; + if (required % nativeBufferSize) + blocks++; - // Send data to monitoring if needed - if (mMonitoring) - mMonitoring->onSpkData(f, buffer, length); + // Now request data from terminal or whetever delegate is + for (int blockIndex = 0; blockIndex < blocks; blockIndex++) + { + memset(mOutput10msBuffer.mutableData(), 0, (size_t)mOutput10msBuffer.capacity()); - #define AEC_FRAME_SIZE (AUDIO_CHANNELS * (AUDIO_SAMPLERATE / 1000) * AEC_FRAME_TIME * sizeof(short)) + // Ask audio data on main AUDIO_SAMPLERATE frequency + if (mDelegate) + mDelegate->onSpkData(Format(), mOutput10msBuffer.mutableData(), mOutput10msBuffer.capacity()); - // AEC filter wants frames. - if (mAec) - { - int nrOfFrames = mAecSpkBuffer.filled() / AEC_FRAME_SIZE; - for (int frameIndex=0; frameIndex < nrOfFrames; frameIndex++) - mAecFilter.toSpeaker(mAecSpkBuffer.mutableData() + AEC_FRAME_SIZE * frameIndex); - mAecSpkBuffer.erase(nrOfFrames * AEC_FRAME_SIZE); - } + // Replace received data with custom file or data playing + mPlayer.onSpkData(Format(), mOutput10msBuffer.mutableData(), mOutput10msBuffer.capacity()); + + // Save it to process with AEC + if (mAec) + mAecSpkBuffer.add(mOutput10msBuffer.data(), mOutput10msBuffer.capacity()); + + // Resample these 10 milliseconds it to native format + size_t wasProcessed = 0; + size_t wasProduced = mSpkResampler.resample(Format().mRate, mOutput10msBuffer.data(), + mOutput10msBuffer.capacity(), wasProcessed, f.mRate, + mOutputNativeData.mutableData() + mOutputNativeData.filled(), + mOutputNativeData.capacity() - mOutputNativeData.filled()); + mOutputNativeData.setFilled(mOutputNativeData.filled() + wasProduced); +#ifdef CONSOLE_LOGGING + printf("Resampled %d to %d\n", wasProcessed, wasProduced); +#endif + } + } + + // assert(mOutputNativeData.filled() >= length); +#ifdef DUMP_NATIVEOUTPUT + if (mNativeOutputDump) + mNativeOutputDump->write(mOutputNativeData.data(), length); +#endif + + mOutputNativeData.read(buffer, length); + + // Send data to monitoring if needed + if (mMonitoring) + mMonitoring->onSpkData(f, buffer, length); + +#define AEC_FRAME_SIZE (AUDIO_CHANNELS * (AUDIO_SAMPLERATE / 1000) * AEC_FRAME_TIME * sizeof(short)) + + // AEC filter wants frames. + if (mAec) + { + int nrOfFrames = mAecSpkBuffer.filled() / AEC_FRAME_SIZE; + for (int frameIndex = 0; frameIndex < nrOfFrames; frameIndex++) + mAecFilter.toSpeaker(mAecSpkBuffer.mutableData() + AEC_FRAME_SIZE * frameIndex); + mAecSpkBuffer.erase(nrOfFrames * AEC_FRAME_SIZE); + } } void DevicePair::processMicData(const Format& f, void* buffer, int length) { - if (mAgc) - mAgcFilter.process(buffer, length); + if (mAgc) + mAgcFilter.process(buffer, length); - if (mAec) - mAecFilter.fromMic(buffer); + if (mAec) + mAecFilter.fromMic(buffer); - if (mDelegate) - mDelegate->onMicData(f, buffer, length); + if (mDelegate) + mDelegate->onMicData(f, buffer, length); } diff --git a/src/engine/audio/Audio_DevicePair.h b/src/engine/audio/Audio_DevicePair.h index a15a7bb9..ab763c80 100644 --- a/src/engine/audio/Audio_DevicePair.h +++ b/src/engine/audio/Audio_DevicePair.h @@ -11,59 +11,59 @@ #include "Audio_Resampler.h" #include "Audio_DataWindow.h" -//#define DUMP_NATIVEOUTPUT -//#define DUMP_NATIVEINPUT +// #define DUMP_NATIVEOUTPUT +// #define DUMP_NATIVEINPUT namespace Audio { - class DevicePair: protected DataConnection - { - public: - class Delegate: public DataConnection +class DevicePair : protected DataConnection +{ +public: + class Delegate : public DataConnection { public: - virtual void deviceChanged(DevicePair* dpair) = 0; + virtual void deviceChanged(DevicePair* dpair) = 0; }; DevicePair(); virtual ~DevicePair(); - DevicePair& setAec(bool aec); - bool aec(); - DevicePair& setAgc(bool agc); - bool agc(); + DevicePair& setAec(bool aec); + bool aec(); + DevicePair& setAgc(bool agc); + bool agc(); - VariantMap* config(); - DevicePair& setConfig(VariantMap* config); + VariantMap* config(); + DevicePair& setConfig(VariantMap* config); - PInputDevice input(); - DevicePair& setInput(PInputDevice input); + PInputDevice input(); + DevicePair& setInput(PInputDevice input); - POutputDevice output(); - DevicePair& setOutput(POutputDevice output); + POutputDevice output(); + DevicePair& setOutput(POutputDevice output); - bool start(); - void stop(); + bool start(); + void stop(); - DevicePair& setDelegate(Delegate* dc); - Delegate* delegate(); + DevicePair& setDelegate(Delegate* dc); + Delegate* delegate(); - DevicePair& setMonitoring(DataConnection* monitoring); + DevicePair& setMonitoring(DataConnection* monitoring); DataConnection* monitoring(); - Player& player(); + Player& player(); - protected: - VariantMap* mConfig; - PInputDevice mInput; - POutputDevice mOutput; - Delegate* mDelegate; - bool mAec; - bool mAgc; - AgcFilter mAgcFilter; - AecFilter mAecFilter; - Player mPlayer; +protected: + VariantMap* mConfig; + PInputDevice mInput; + POutputDevice mOutput; + Delegate* mDelegate; + bool mAec; + bool mAgc; + AgcFilter mAgcFilter; + AecFilter mAecFilter; + Player mPlayer; UniversalResampler mMicResampler, mSpkResampler; DataWindow mInputBuffer, mOutputBuffer, mAecSpkBuffer, mInputResampingData, mOutputNativeData, mOutput10msBuffer; DataConnection* mMonitoring; @@ -77,9 +77,9 @@ namespace Audio void onMicData(const Format& f, const void* buffer, int length); void onSpkData(const Format& f, void* buffer, int length); void processMicData(const Format& f, void* buffer, int length); - }; +}; - typedef std::shared_ptr PDevicePair; -} +typedef std::shared_ptr PDevicePair; +} // namespace Audio #endif diff --git a/src/engine/audio/Audio_DirectSound.cpp b/src/engine/audio/Audio_DirectSound.cpp index 5fc88b89..7bddd70f 100644 --- a/src/engine/audio/Audio_DirectSound.cpp +++ b/src/engine/audio/Audio_DirectSound.cpp @@ -19,7 +19,7 @@ #define DRVM_MAPPER_CONSOLEVOICECOM_GET (0x2000 + 23) #define DRVM_MAPPER_PREFERRED_GET (0x2000 + 21) -#define DRV_QUERYFUNCTIONINSTANCEID (DRV_RESERVED + 17) +#define DRV_QUERYFUNCTIONINSTANCEID (DRV_RESERVED + 17) #define DRV_QUERYFUNCTIONINSTANCEIDSIZE (DRV_RESERVED + 18) #define LOG_SUBSYSTEM "audio" @@ -39,32 +39,29 @@ public: { HINSTANCE mInstance; - HRESULT (WINAPI *DirectSoundCreate8)(LPGUID, LPDIRECTSOUND8 *, LPUNKNOWN); - HRESULT (WINAPI *DirectSoundEnumerateW)(LPDSENUMCALLBACKW, LPVOID); - HRESULT (WINAPI *DirectSoundEnumerateA)(LPDSENUMCALLBACKA, LPVOID); + HRESULT(WINAPI* DirectSoundCreate8)(LPGUID, LPDIRECTSOUND8*, LPUNKNOWN); + HRESULT(WINAPI* DirectSoundEnumerateW)(LPDSENUMCALLBACKW, LPVOID); + HRESULT(WINAPI* DirectSoundEnumerateA)(LPDSENUMCALLBACKA, LPVOID); - HRESULT (WINAPI *DirectSoundCaptureCreate8)(LPGUID, LPDIRECTSOUNDCAPTURE8* , LPUNKNOWN); - HRESULT (WINAPI *DirectSoundCaptureEnumerateW)(LPDSENUMCALLBACKW, LPVOID); - HRESULT (WINAPI *DirectSoundCaptureEnumerateA)(LPDSENUMCALLBACKA, LPVOID); - HRESULT (WINAPI *GetDeviceID)(LPCGUID src, LPGUID dst); + HRESULT(WINAPI* DirectSoundCaptureCreate8)(LPGUID, LPDIRECTSOUNDCAPTURE8*, LPUNKNOWN); + HRESULT(WINAPI* DirectSoundCaptureEnumerateW)(LPDSENUMCALLBACKW, LPVOID); + HRESULT(WINAPI* DirectSoundCaptureEnumerateA)(LPDSENUMCALLBACKA, LPVOID); + HRESULT(WINAPI* GetDeviceID)(LPCGUID src, LPGUID dst); } mRoutines; protected: LPDIRECTSOUND mDirectSound; - Mutex mGuard; + Mutex mGuard; unsigned int mRefCount; }; DSoundInit gDSoundInit; -DSoundInit::DSoundInit() - :mRefCount(0) -{ -} +DSoundInit::DSoundInit() : mRefCount(0) {} DSoundInit::~DSoundInit() { - //Unload(); + // Unload(); } void DSoundInit::load() @@ -77,16 +74,21 @@ void DSoundInit::load() hr = ::CoInitialize(NULL); - //load the DirectSound DLL + // load the DirectSound DLL mRoutines.mInstance = ::LoadLibraryW(L"dsound.dll"); if (!mRoutines.mInstance) throw std::logic_error("Cannot load dsound.dll"); - mRoutines.DirectSoundCaptureCreate8 = (HRESULT (WINAPI *)(LPGUID, LPDIRECTSOUNDCAPTURE8 *, LPUNKNOWN))::GetProcAddress(mRoutines.mInstance, "DirectSoundCaptureCreate8"); - mRoutines.DirectSoundCaptureEnumerateW = (HRESULT (WINAPI *)(LPDSENUMCALLBACKW, LPVOID))::GetProcAddress(mRoutines.mInstance, "DirectSoundCaptureEnumerateW"); - mRoutines.DirectSoundCreate8 = (HRESULT (WINAPI *)(LPGUID, LPDIRECTSOUND8 *, LPUNKNOWN))::GetProcAddress(mRoutines.mInstance, "DirectSoundCreate8"); - mRoutines.DirectSoundEnumerateW = (HRESULT (WINAPI *)(LPDSENUMCALLBACKW, LPVOID))::GetProcAddress(mRoutines.mInstance, "DirectSoundEnumerateW"); - mRoutines.GetDeviceID = (HRESULT (WINAPI*) (LPCGUID, LPGUID)) GetProcAddress(mRoutines.mInstance, "GetDeviceID"); + mRoutines.DirectSoundCaptureCreate8 = + (HRESULT(WINAPI*)(LPGUID, LPDIRECTSOUNDCAPTURE8*, LPUNKNOWN))::GetProcAddress(mRoutines.mInstance, + "DirectSoundCaptureCreate8"); + mRoutines.DirectSoundCaptureEnumerateW = (HRESULT(WINAPI*)(LPDSENUMCALLBACKW, LPVOID))::GetProcAddress( + mRoutines.mInstance, "DirectSoundCaptureEnumerateW"); + mRoutines.DirectSoundCreate8 = (HRESULT(WINAPI*)(LPGUID, LPDIRECTSOUND8*, LPUNKNOWN))::GetProcAddress( + mRoutines.mInstance, "DirectSoundCreate8"); + mRoutines.DirectSoundEnumerateW = + (HRESULT(WINAPI*)(LPDSENUMCALLBACKW, LPVOID))::GetProcAddress(mRoutines.mInstance, "DirectSoundEnumerateW"); + mRoutines.GetDeviceID = (HRESULT(WINAPI*)(LPCGUID, LPGUID))GetProcAddress(mRoutines.mInstance, "GetDeviceID"); } } @@ -106,10 +108,7 @@ void DSoundInit::unload() } // --------------- VistaEnumerator --------------------- -VistaEnumerator::VistaEnumerator() - :mCollection(NULL), mDefaultDevice(NULL), mEnumerator(NULL), mDirection(eCapture) -{ -} +VistaEnumerator::VistaEnumerator() : mCollection(NULL), mDefaultDevice(NULL), mEnumerator(NULL), mDirection(eCapture) {} VistaEnumerator::~VistaEnumerator() { @@ -119,14 +118,12 @@ VistaEnumerator::~VistaEnumerator() void VistaEnumerator::open(int direction) { const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator); - const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator); + const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator); mDirection = (direction == myMicrophone) ? eCapture : eRender; - HRESULT hr = CoCreateInstance( - CLSID_MMDeviceEnumerator, NULL, - CLSCTX_ALL, IID_IMMDeviceEnumerator, - (void**)&mEnumerator); + HRESULT hr = + CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void**)&mEnumerator); if (!mEnumerator) return; @@ -152,7 +149,7 @@ void VistaEnumerator::close() if (mDefaultDevice) { - //mDefaultDevice->Release(); + // mDefaultDevice->Release(); mDefaultDevice = NULL; } @@ -162,7 +159,7 @@ void VistaEnumerator::close() mEnumerator = NULL; } } - catch(...) + catch (...) { } } @@ -175,9 +172,9 @@ IMMDevice* VistaEnumerator::mapIndexToInterface(int index) if (index == -1) return mDefaultDevice; - size_t idSize = 0; - MMRESULT mmres = 0; - WCHAR* id = NULL; + size_t idSize = 0; + MMRESULT mmres = 0; + WCHAR* id = NULL; if (mDirection == eCapture) { mmres = waveInMessage((HWAVEIN)index, DRV_QUERYFUNCTIONINSTANCEIDSIZE, (DWORD_PTR)&idSize, NULL); @@ -185,7 +182,7 @@ IMMDevice* VistaEnumerator::mapIndexToInterface(int index) if (mmres != MMSYSERR_NOERROR) return NULL; - id = (WCHAR*)_alloca(idSize*sizeof(WCHAR)); + id = (WCHAR*)_alloca(idSize * sizeof(WCHAR)); mmres = waveInMessage((HWAVEIN)index, DRV_QUERYFUNCTIONINSTANCEID, (DWORD_PTR)id, idSize); } else @@ -195,7 +192,7 @@ IMMDevice* VistaEnumerator::mapIndexToInterface(int index) if (mmres != MMSYSERR_NOERROR) return NULL; - id = (WCHAR*)_alloca(idSize*sizeof(WCHAR)); + id = (WCHAR*)_alloca(idSize * sizeof(WCHAR)); mmres = waveOutMessage((HWAVEOUT)index, DRV_QUERYFUNCTIONINSTANCEID, (DWORD_PTR)id, idSize); } @@ -213,7 +210,7 @@ void VistaEnumerator::enumerate() mNameList.clear(); int res = (int)count(); - for (int i=0; iSetNotificationPositions(AUDIO_MIC_BUFFER_COUNT, mEventArray)); DSoundHelper::checkComResult(mBuffer->Start(DSCBSTART_LOOPING)); dscb->Release(); - setSimulate( false ); + setSimulate(false); } bool DSoundInputDevice::open() @@ -452,7 +450,7 @@ bool DSoundInputDevice::open() void DSoundInputDevice::closeDevice() { - ICELogInfo(<<"Close DirectSound audio input"); + ICELogInfo(<< "Close DirectSound audio input"); Lock l(mGuard); #ifdef AUDIO_DUMPINPUT @@ -505,7 +503,7 @@ bool DSoundInputDevice::tryReadBuffer(void* buffer) // Ensure device exists if (!mDevice) { - setSimulate( true ); + setSimulate(true); return false; } @@ -524,9 +522,10 @@ bool DSoundInputDevice::tryReadBuffer(void* buffer) try { - if (::WaitForSingleObject(mEventArray[mNextBuffer].hEventNotify, AUDIO_MIC_BUFFER_COUNT * AUDIO_MIC_BUFFER_LENGTH * 4) != WAIT_OBJECT_0) + if (::WaitForSingleObject(mEventArray[mNextBuffer].hEventNotify, + AUDIO_MIC_BUFFER_COUNT * AUDIO_MIC_BUFFER_LENGTH * 4) != WAIT_OBJECT_0) { - setSimulate( true ); + setSimulate(true); return false; } @@ -534,7 +533,7 @@ bool DSoundInputDevice::tryReadBuffer(void* buffer) if (::WaitForMultipleObjects(AUDIO_MIC_BUFFER_COUNT, mEventSignals, TRUE, 0) != WAIT_TIMEOUT) { // Possible overflow. Consider current buffer resulting. Reset ALL events. - for (int i = 0; iLock(mReadOffset, AUDIO_MIC_BUFFER_SIZE, &ptr1, &len1, &ptr2, &len2, 0)); // Copy&Enqueue captured data to mQueue @@ -574,9 +574,9 @@ bool DSoundInputDevice::tryReadBuffer(void* buffer) return true; } - catch(...) + catch (...) { - setSimulate( true ); + setSimulate(true); } return false; } @@ -585,9 +585,8 @@ void DSoundInputDevice::setSimulate(bool s) { if (!mSimulate && s) mNullAudio.start(); - else - if (mSimulate && !s) - mNullAudio.stop(); + else if (mSimulate && !s) + mNullAudio.stop(); mSimulate = s; } @@ -599,7 +598,7 @@ Format DSoundInputDevice::getFormat() int DSoundInputDevice::readBuffer(void* buffer) { - //Lock lock(mGuard); + // Lock lock(mGuard); if (mRefCount <= 0 || isSimulate()) return 0; @@ -642,10 +641,8 @@ void DSoundInputDevice::threadProc(void* arg) DSoundOutputDevice::DSoundOutputDevice(GUID deviceId) - :mDevice(NULL), mPrimaryBuffer(NULL), mBuffer(NULL), - mWriteOffset(0), mPlayedSamples(0), mTotalPlayed(0), mTail(0), - mThreadHandle(0), mSimulate(false), mGUID(deviceId), - mNullAudio(AUDIO_SPK_BUFFER_LENGTH, AUDIO_SPK_BUFFER_COUNT) + : mDevice(NULL), mPrimaryBuffer(NULL), mBuffer(NULL), mWriteOffset(0), mPlayedSamples(0), mTotalPlayed(0), mTail(0), + mThreadHandle(0), mSimulate(false), mGUID(deviceId), mNullAudio(AUDIO_SPK_BUFFER_LENGTH, AUDIO_SPK_BUFFER_COUNT) { gDSoundInit.load(); mShutdownSignal = ::CreateEvent(NULL, FALSE, FALSE, NULL); @@ -700,7 +697,7 @@ void DSoundOutputDevice::openDevice() ICELogInfo(<< "Open DirectSound audio output"); if (IsEqualGUID(mGUID, GUID_NULL)) { - setSimulate( true ); + setSimulate(true); return; } @@ -729,10 +726,10 @@ void DSoundOutputDevice::openDevice() dsbd.dwSize = sizeof(DSBUFFERDESC); dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER; dsbd.dwBufferBytes = 0; - dsbd.lpwfxFormat = NULL;//&wfx; + dsbd.lpwfxFormat = NULL; //&wfx; dsbd.guid3DAlgorithm = DS3DALG_DEFAULT; - DSoundHelper::checkComResult(mDevice->CreateSoundBuffer(&dsbd, &mPrimaryBuffer, NULL )); + DSoundHelper::checkComResult(mDevice->CreateSoundBuffer(&dsbd, &mPrimaryBuffer, NULL)); DSBCAPS caps; caps.dwSize = sizeof(caps); caps.dwFlags = 0; @@ -751,14 +748,16 @@ void DSoundOutputDevice::openDevice() DSoundHelper::checkComResult(mDevice->CreateSoundBuffer(&dsbd, &mBuffer, NULL)); // Fill the buffer with silence - LPVOID ptr1 = NULL, ptr2 = NULL; DWORD len1 = 0, len2 = 0; - DSoundHelper::checkComResult(mBuffer->Lock(0, AUDIO_SPK_BUFFER_SIZE * AUDIO_SPK_BUFFER_COUNT, &ptr1, &len1, &ptr2, &len2, 0)); + LPVOID ptr1 = NULL, ptr2 = NULL; + DWORD len1 = 0, len2 = 0; + DSoundHelper::checkComResult( + mBuffer->Lock(0, AUDIO_SPK_BUFFER_SIZE * AUDIO_SPK_BUFFER_COUNT, &ptr1, &len1, &ptr2, &len2, 0)); if (len1 && ptr1) memset(ptr1, 0, len1); if (len2 && ptr2) memset(ptr2, 0, len2); DSoundHelper::checkComResult(mBuffer->Unlock(ptr1, len1, ptr2, len2)); - DSoundHelper::checkComResult(mBuffer->Play(0,0,DSBPLAY_LOOPING)); + DSoundHelper::checkComResult(mBuffer->Play(0, 0, DSBPLAY_LOOPING)); mBuffer->GetCurrentPosition(NULL, &mWriteCursor); } @@ -804,8 +803,9 @@ bool DSoundOutputDevice::getMediaFrame() if (mConnection) mConnection->onSpkData(getFormat(), mMediaFrame, sizeof mMediaFrame); } - catch(...) - {} + catch (...) + { + } return true; } @@ -833,7 +833,8 @@ bool DSoundOutputDevice::process() offset %= mBufferSize; // See what we can write - LPVOID ptr1 = NULL, ptr2 = NULL; DWORD len1 = 0, len2 = 0; + LPVOID ptr1 = NULL, ptr2 = NULL; + DWORD len1 = 0, len2 = 0; DSoundHelper::checkComResult(mBuffer->Lock(offset, AUDIO_SPK_BUFFER_SIZE, &ptr1, &len1, &ptr2, &len2, 0)); assert(ptr2 == NULL); @@ -858,10 +859,10 @@ void DSoundOutputDevice::threadProc(void* arg) DSoundOutputDevice* impl = (DSoundOutputDevice*)arg; impl->openDevice(); - DWORD waitResult = 0; - HANDLE waitArray[2] = {impl->mBufferSignal, impl->mShutdownSignal}; + DWORD waitResult = 0; + HANDLE waitArray[2] = {impl->mBufferSignal, impl->mShutdownSignal}; unsigned exitCount = 0; - bool exitSignal = false; + bool exitSignal = false; while (true) { // Poll for shutdown signal @@ -884,12 +885,12 @@ void DSoundOutputDevice::threadProc(void* arg) impl->restoreBuffer(); impl->process(); } - catch(const Exception& e) + catch (const Exception& e) { ICELogError(<< "DirectSound output failed with code = " << e.code() << ", subcode = " << e.subcode()); impl->setSimulate(true); } - catch(...) + catch (...) { ICELogError(<< "DirectSound output failed due to unexpected exception."); impl->setSimulate(true); @@ -925,62 +926,61 @@ bool DSoundOutputDevice::closing() return false; } -typedef WINUSERAPI HRESULT (WINAPI *LPFNDLLGETCLASSOBJECT) (const CLSID &, const IID &, void **); +typedef WINUSERAPI HRESULT(WINAPI* LPFNDLLGETCLASSOBJECT)(const CLSID&, const IID&, void**); -HRESULT DirectSoundPrivateCreate (OUT LPKSPROPERTYSET * ppKsPropertySet) -{ - HMODULE hLibDsound = NULL; - LPFNDLLGETCLASSOBJECT pfnDllGetClassObject = NULL; - LPCLASSFACTORY pClassFactory = NULL; - LPKSPROPERTYSET pKsPropertySet = NULL; - HRESULT hr = DS_OK; +HRESULT DirectSoundPrivateCreate(OUT LPKSPROPERTYSET* ppKsPropertySet) +{ + HMODULE hLibDsound = NULL; + LPFNDLLGETCLASSOBJECT pfnDllGetClassObject = NULL; + LPCLASSFACTORY pClassFactory = NULL; + LPKSPROPERTYSET pKsPropertySet = NULL; + HRESULT hr = DS_OK; // Load dsound.dll hLibDsound = LoadLibrary(TEXT("dsound.dll")); - if(!hLibDsound) + if (!hLibDsound) { hr = DSERR_GENERIC; } // Find DllGetClassObject - if(SUCCEEDED(hr)) + if (SUCCEEDED(hr)) { - pfnDllGetClassObject = - (LPFNDLLGETCLASSOBJECT)GetProcAddress ( hLibDsound, "DllGetClassObject" ); + pfnDllGetClassObject = (LPFNDLLGETCLASSOBJECT)GetProcAddress(hLibDsound, "DllGetClassObject"); - if(!pfnDllGetClassObject) + if (!pfnDllGetClassObject) { hr = DSERR_GENERIC; } } // Create a class factory object - if(SUCCEEDED(hr)) + if (SUCCEEDED(hr)) { - hr = pfnDllGetClassObject (CLSID_DirectSoundPrivate, IID_IClassFactory, (LPVOID *)&pClassFactory ); + hr = pfnDllGetClassObject(CLSID_DirectSoundPrivate, IID_IClassFactory, (LPVOID*)&pClassFactory); } // Create the DirectSoundPrivate object and query for an IKsPropertySet // interface - if(SUCCEEDED(hr)) + if (SUCCEEDED(hr)) { - hr = pClassFactory->CreateInstance ( NULL, IID_IKsPropertySet, (LPVOID *)&pKsPropertySet ); + hr = pClassFactory->CreateInstance(NULL, IID_IKsPropertySet, (LPVOID*)&pKsPropertySet); } // Release the class factory - if(pClassFactory) + if (pClassFactory) { pClassFactory->Release(); } // Handle final success or failure - if(SUCCEEDED(hr)) + if (SUCCEEDED(hr)) { *ppKsPropertySet = pKsPropertySet; } - else if(pKsPropertySet) + else if (pKsPropertySet) { pKsPropertySet->Release(); } @@ -988,56 +988,45 @@ HRESULT DirectSoundPrivateCreate (OUT LPKSPROPERTYSET * ppKsPropertySet) FreeLibrary(hLibDsound); return hr; -} +} -BOOL GetInfoFromDSoundGUID( GUID i_sGUID, int &dwWaveID) -{ - LPKSPROPERTYSET pKsPropertySet = NULL; - HRESULT hr; - BOOL retval = FALSE; +BOOL GetInfoFromDSoundGUID(GUID i_sGUID, int& dwWaveID) +{ + LPKSPROPERTYSET pKsPropertySet = NULL; + HRESULT hr; + BOOL retval = FALSE; PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA psDirectSoundDeviceDescription = NULL; - DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA sDirectSoundDeviceDescription; + DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA sDirectSoundDeviceDescription; - memset(&sDirectSoundDeviceDescription,0,sizeof(sDirectSoundDeviceDescription)); - hr = DirectSoundPrivateCreate( &pKsPropertySet ); - if(SUCCEEDED(hr)) + memset(&sDirectSoundDeviceDescription, 0, sizeof(sDirectSoundDeviceDescription)); + hr = DirectSoundPrivateCreate(&pKsPropertySet); + if (SUCCEEDED(hr)) { ULONG ulBytesReturned = 0; sDirectSoundDeviceDescription.DeviceId = i_sGUID; // On the first call the final size is unknown so pass the size of the struct in order to receive // "Type" and "DataFlow" values, ulBytesReturned will be populated with bytes required for struct+strings. - hr = pKsPropertySet->Get(DSPROPSETID_DirectSoundDevice, - DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION, - NULL, - 0, - &sDirectSoundDeviceDescription, - sizeof(sDirectSoundDeviceDescription), - &ulBytesReturned - ); + hr = pKsPropertySet->Get(DSPROPSETID_DirectSoundDevice, DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION, NULL, 0, + &sDirectSoundDeviceDescription, sizeof(sDirectSoundDeviceDescription), + &ulBytesReturned); if (ulBytesReturned) { // On the first call it notifies us of the required amount of memory in order to receive the strings. // Allocate the required memory, the strings will be pointed to the memory space directly after the struct. - psDirectSoundDeviceDescription = (PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA)new BYTE[ulBytesReturned]; + psDirectSoundDeviceDescription = (PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA) new BYTE[ulBytesReturned]; *psDirectSoundDeviceDescription = sDirectSoundDeviceDescription; - hr = pKsPropertySet->Get(DSPROPSETID_DirectSoundDevice, - DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION, - NULL, - 0, - psDirectSoundDeviceDescription, - ulBytesReturned, - &ulBytesReturned - ); + hr = pKsPropertySet->Get(DSPROPSETID_DirectSoundDevice, DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION, NULL, 0, + psDirectSoundDeviceDescription, ulBytesReturned, &ulBytesReturned); - dwWaveID = psDirectSoundDeviceDescription->WaveDeviceId; + dwWaveID = psDirectSoundDeviceDescription->WaveDeviceId; /*Description = psDirectSoundDeviceDescription->Description; Module = psDirectSoundDeviceDescription->Module; Interface = psDirectSoundDeviceDescription->Interface;*/ - delete [] psDirectSoundDeviceDescription; + delete[] psDirectSoundDeviceDescription; retval = TRUE; } @@ -1045,24 +1034,18 @@ BOOL GetInfoFromDSoundGUID( GUID i_sGUID, int &dwWaveID) } return retval; -} +} struct EnumResult { - int mDeviceId; + int mDeviceId; GUID mGuid; }; -BOOL CALLBACK DSEnumCallback( - LPGUID lpGuid, - LPCTSTR lpcstrDescription, - LPCTSTR lpcstrModule, - LPVOID lpContext - ) +BOOL CALLBACK DSEnumCallback(LPGUID lpGuid, LPCTSTR lpcstrDescription, LPCTSTR lpcstrModule, LPVOID lpContext) { if (lpGuid) { - int devId = -1; GetInfoFromDSoundGUID(*lpGuid, devId); EnumResult* er = (EnumResult*)lpContext; diff --git a/src/engine/audio/Audio_DirectSound.h b/src/engine/audio/Audio_DirectSound.h index 34e0c775..be9120c2 100644 --- a/src/engine/audio/Audio_DirectSound.h +++ b/src/engine/audio/Audio_DirectSound.h @@ -22,7 +22,7 @@ #include #include #if defined(_MSC_VER) -# include +#include #endif #include #include @@ -31,48 +31,48 @@ namespace Audio { -class VistaEnumerator: public Enumerator +class VistaEnumerator : public Enumerator { public: VistaEnumerator(); ~VistaEnumerator(); - void open(int direction); - void close(); + void open(int direction); + void close(); - int count(); + int count(); std::tstring nameAt(int index); - int idAt(int index); - int indexOfDefaultDevice(); + int idAt(int index); + int indexOfDefaultDevice(); protected: - IMMDeviceCollection* mCollection; - IMMDevice* mDefaultDevice; - IMMDeviceEnumerator* mEnumerator; - EDataFlow mDirection; - std::vector mNameList; + IMMDeviceCollection* mCollection; + IMMDevice* mDefaultDevice; + IMMDeviceEnumerator* mEnumerator; + EDataFlow mDirection; + std::vector mNameList; - void enumerate(); - IMMDevice* mapIndexToInterface(int index); + void enumerate(); + IMMDevice* mapIndexToInterface(int index); }; -class XpEnumerator: public Enumerator +class XpEnumerator : public Enumerator { public: XpEnumerator(); ~XpEnumerator(); - void open(int direction); - void close(); + void open(int direction); + void close(); - int count(); + int count(); std::tstring nameAt(int index); - int idAt(int index); - int indexOfDefaultDevice(); + int idAt(int index); + int indexOfDefaultDevice(); protected: std::vector mNameList; - int mDirection; + int mDirection; }; class DSoundHelper @@ -83,32 +83,32 @@ public: }; #if !defined(_MSC_VER) -typedef struct IDirectSoundNotify8 *LPDIRECTSOUNDNOTIFY8; +typedef struct IDirectSoundNotify8* LPDIRECTSOUNDNOTIFY8; #endif -class DSoundInputDevice: public InputDevice +class DSoundInputDevice : public InputDevice { public: DSoundInputDevice(GUID deviceId); ~DSoundInputDevice(); - - void enableDenoiser(bool enable); - bool open(); - void close(); - - bool isSimulate() const; - void setSimulate(bool s); - - int readBuffer(void* buffer); + + void enableDenoiser(bool enable); + bool open(); + void close(); + + bool isSimulate() const; + void setSimulate(bool s); + + int readBuffer(void* buffer); Format getFormat(); protected: - Mutex mGuard; /// Mutex to protect this instance. - LPDIRECTSOUNDCAPTURE8 mDevice; - LPDIRECTSOUNDCAPTUREBUFFER8 mBuffer; - LPDIRECTSOUNDNOTIFY8 mNotifications; - DSBPOSITIONNOTIFY mEventArray[AUDIO_MIC_BUFFER_COUNT]; - HANDLE mEventSignals[AUDIO_MIC_BUFFER_COUNT]; // Helper array to make WaitForMultipleObjects in loop + Mutex mGuard; /// Mutex to protect this instance. + LPDIRECTSOUNDCAPTURE8 mDevice; + LPDIRECTSOUNDCAPTUREBUFFER8 mBuffer; + LPDIRECTSOUNDNOTIFY8 mNotifications; + DSBPOSITIONNOTIFY mEventArray[AUDIO_MIC_BUFFER_COUNT]; + HANDLE mEventSignals[AUDIO_MIC_BUFFER_COUNT]; // Helper array to make WaitForMultipleObjects in loop int mBufferIndex; int mNextBuffer; @@ -116,7 +116,7 @@ protected: HANDLE mThreadHandle; HANDLE mShutdownSignal; - volatile bool mSimulate; /// Marks if simulate mode is active. + volatile bool mSimulate; /// Marks if simulate mode is active. int mRefCount; ByteBuffer mQueue; unsigned mReadOffset; @@ -129,59 +129,59 @@ protected: WavFileWriter mDump; #endif - bool tryReadBuffer(void* buffer); - void openDevice(); - void closeDevice(); + bool tryReadBuffer(void* buffer); + void openDevice(); + void closeDevice(); static void threadProc(void* arg); }; -class DSoundOutputDevice: public OutputDevice +class DSoundOutputDevice : public OutputDevice { public: DSoundOutputDevice(GUID deviceId); ~DSoundOutputDevice(); - - bool open(); - void close(); - unsigned playedTime() const; - bool isSimulate() const; - void setSimulate(bool s); - bool closing(); - Format getFormat(); + bool open(); + void close(); + + unsigned playedTime() const; + bool isSimulate() const; + void setSimulate(bool s); + bool closing(); + Format getFormat(); protected: - Mutex mGuard; /// Mutex to protect this instance - int mDeviceID; - LPDIRECTSOUND8 mDevice; - LPDIRECTSOUNDBUFFER mPrimaryBuffer; - LPDIRECTSOUNDBUFFER mBuffer; - GUID mGUID; - unsigned mWriteOffset; - unsigned mPlayedSamples; - unsigned mSentBytes; - DWORD mPlayCursor; // Measured in bytes - unsigned mBufferSize; - unsigned mTotalPlayed; // Measured in bytes - unsigned mTail; // Measured in bytes - HANDLE mShutdownSignal; - HANDLE mBufferSignal; - HANDLE mThreadHandle; - bool mSimulate; - StubTimer mNullAudio; - DWORD mWriteCursor; - char mMediaFrame[AUDIO_SPK_BUFFER_SIZE]; - unsigned mRefCount; + Mutex mGuard; /// Mutex to protect this instance + int mDeviceID; + LPDIRECTSOUND8 mDevice; + LPDIRECTSOUNDBUFFER mPrimaryBuffer; + LPDIRECTSOUNDBUFFER mBuffer; + GUID mGUID; + unsigned mWriteOffset; + unsigned mPlayedSamples; + unsigned mSentBytes; + DWORD mPlayCursor; // Measured in bytes + unsigned mBufferSize; + unsigned mTotalPlayed; // Measured in bytes + unsigned mTail; // Measured in bytes + HANDLE mShutdownSignal; + HANDLE mBufferSignal; + HANDLE mThreadHandle; + bool mSimulate; + StubTimer mNullAudio; + DWORD mWriteCursor; + char mMediaFrame[AUDIO_SPK_BUFFER_SIZE]; + unsigned mRefCount; - void openDevice(); - void closeDevice(); - void restoreBuffer(); - bool process(); - bool getMediaFrame(); + void openDevice(); + void closeDevice(); + void restoreBuffer(); + bool process(); + bool getMediaFrame(); - static void threadProc(void* arg); + static void threadProc(void* arg); }; -} +} // namespace Audio #endif diff --git a/src/engine/audio/Audio_Helper.cpp b/src/engine/audio/Audio_Helper.cpp index 99fd0f75..79ae85fa 100644 --- a/src/engine/audio/Audio_Helper.cpp +++ b/src/engine/audio/Audio_Helper.cpp @@ -4,7 +4,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifdef TARGET_WIN -# include +#include #endif #include @@ -17,93 +17,92 @@ using namespace Audio; TimeSource::TimeSource(int quantTime, int nrOfQuants) { #ifdef TARGET_WIN - mCounter.QuadPart = 0; + mCounter.QuadPart = 0; #endif #if defined(TARGET_OSX) || defined(TARGET_IOS) - mach_timebase_info(&mTimebase); - mRatio = ((double)mTimebase.numer / (double)mTimebase.denom) / 1000000; + mach_timebase_info(&mTimebase); + mRatio = ((double)mTimebase.numer / (double)mTimebase.denom) / 1000000; #endif - mQuantTime = quantTime; - mDepthTime = quantTime * nrOfQuants; - mTailTime = 0; + mQuantTime = quantTime; + mDepthTime = quantTime * nrOfQuants; + mTailTime = 0; } void TimeSource::start() { #ifdef TARGET_WIN - if (!QueryPerformanceFrequency(&mFreq)) - throw Exception(ERR_QPC, GetLastError()); - if (!QueryPerformanceCounter(&mCounter)) - throw Exception(ERR_QPC, GetLastError()); + if (!QueryPerformanceFrequency(&mFreq)) + throw Exception(ERR_QPC, GetLastError()); + if (!QueryPerformanceCounter(&mCounter)) + throw Exception(ERR_QPC, GetLastError()); #endif } -void TimeSource::stop() -{ -} +void TimeSource::stop() {} unsigned TimeSource::time() { #ifdef TARGET_WIN LARGE_INTEGER c; - if (!QueryPerformanceCounter(&c)) - throw Exception(ERR_QPC, GetLastError()); - - //find the f - double f = (double)mFreq.QuadPart / 1000.0; - - //find the difference - unsigned __int64 diff = c.QuadPart - mCounter.QuadPart; + if (!QueryPerformanceCounter(&c)) + throw Exception(ERR_QPC, GetLastError()); - mCounter.QuadPart = c.QuadPart; - - diff = (unsigned __int64)((double)diff / f + 0.5); //get ms - diff += mTailTime; + // find the f + double f = (double)mFreq.QuadPart / 1000.0; - if (diff > mDepthTime) - { - mTailTime = 0; - return mDepthTime; - } - else - { - mTailTime = (unsigned )(diff % (unsigned __int64)mQuantTime); - unsigned int t = (unsigned )(diff / (unsigned __int64)mQuantTime); - return t * mQuantTime; - } + // find the difference + unsigned __int64 diff = c.QuadPart - mCounter.QuadPart; + + mCounter.QuadPart = c.QuadPart; + + diff = (unsigned __int64)((double)diff / f + 0.5); // get ms + diff += mTailTime; + + if (diff > mDepthTime) + { + mTailTime = 0; + return mDepthTime; + } + else + { + mTailTime = (unsigned)(diff % (unsigned __int64)mQuantTime); + unsigned int t = (unsigned)(diff / (unsigned __int64)mQuantTime); + return t * mQuantTime; + } #endif #if defined(TARGET_OSX) || defined(TARGET_IOS) - uint64_t t = mach_absolute_time(); - uint64_t c = uint64_t((double)t * mRatio + 0.5); + uint64_t t = mach_absolute_time(); + uint64_t c = uint64_t((double)t * mRatio + 0.5); - uint64_t diff = c - this->mTime + mTailTime; - mTime = c; - if (diff > mDepthTime) - { - mTailTime = 0; - return mDepthTime; - } - else - { - mTailTime = diff % mQuantTime; - uint64_t t = diff / mQuantTime; - return t * mQuantTime; - } + uint64_t diff = c - this->mTime + mTailTime; + mTime = c; + if (diff > mDepthTime) + { + mTailTime = 0; + return mDepthTime; + } + else + { + mTailTime = diff % mQuantTime; + uint64_t t = diff / mQuantTime; + return t * mQuantTime; + } #endif #if defined(TARGET_LINUX) - assert(0); + assert(0); #endif #if defined(TARGET_ANDROID) - assert(0); + assert(0); #endif - return 0; + return 0; } // --- StubTimer --- StubTimer::StubTimer(int bufferTime, int bufferCount) -:mBufferTime(bufferTime), mBufferCount(bufferCount), mTimeSource(bufferTime, bufferCount), mActive(false), mCurrentTime(0) + : mBufferTime(bufferTime), mBufferCount(bufferCount), mTimeSource(bufferTime, bufferCount), mActive(false), + mCurrentTime(0) { #ifdef TARGET_WIN mStubSignal = ::CreateEvent(NULL, FALSE, FALSE, NULL); @@ -113,38 +112,38 @@ StubTimer::StubTimer(int bufferTime, int bufferCount) StubTimer::~StubTimer() { #ifdef TARGET_WIN - ::CloseHandle(mStubSignal); + ::CloseHandle(mStubSignal); #endif } void StubTimer::start() { - mTimeSource.start(); - mCurrentTime = mTimeSource.time(); - mActive = true; + mTimeSource.start(); + mCurrentTime = mTimeSource.time(); + mActive = true; } void StubTimer::stop() { - mTimeSource.stop(); - mActive = false; + mTimeSource.stop(); + mActive = false; } void StubTimer::waitForBuffer() { - if (!mActive) - start(); + if (!mActive) + start(); - unsigned t = mTimeSource.time(); - - while (!t) - { + unsigned t = mTimeSource.time(); + + while (!t) + { #ifdef TARGET_WIN - ::WaitForSingleObject(mStubSignal, mBufferTime); + ::WaitForSingleObject(mStubSignal, mBufferTime); #endif #if defined(TARGET_OSX) || defined(TARGET_IOS) - usleep(100); + usleep(100); #endif - t = mTimeSource.time(); - } + t = mTimeSource.time(); + } } diff --git a/src/engine/audio/Audio_Helper.h b/src/engine/audio/Audio_Helper.h index 0a74de10..c31f96a4 100644 --- a/src/engine/audio/Audio_Helper.h +++ b/src/engine/audio/Audio_Helper.h @@ -10,15 +10,15 @@ #include #include #if defined(_MSC_VER) -# include +#include #endif #endif #if defined(TARGET_OSX) || defined(TARGET_IOS) -# include -# include -# include -# include +#include +#include +#include +#include #endif #include @@ -27,52 +27,52 @@ namespace Audio { - class TimeSource - { - protected: +class TimeSource +{ +protected: #ifdef TARGET_WIN - LARGE_INTEGER mCounter; /// Current value from QPC. - LARGE_INTEGER mFreq; /// Current frequency from QPC. + LARGE_INTEGER mCounter; /// Current value from QPC. + LARGE_INTEGER mFreq; /// Current frequency from QPC. #endif #if defined(TARGET_OSX) || defined(TARGET_IOS) - uint64_t mTime; + uint64_t mTime; struct mach_timebase_info mTimebase; - double mRatio; + double mRatio; #endif - unsigned mQuantTime; /// Used time quants length in milliseconds. - unsigned mDepthTime; /// Number of available time quants. - unsigned mTailTime; /// Not-accounted milliseconds. + unsigned mQuantTime; /// Used time quants length in milliseconds. + unsigned mDepthTime; /// Number of available time quants. + unsigned mTailTime; /// Not-accounted milliseconds. - public: +public: TimeSource(int quantTime, int nrOfQuants); ~TimeSource() = default; - void start(); - void stop(); + void start(); + void stop(); unsigned time(); - }; +}; - class StubTimer - { - public: +class StubTimer +{ +public: StubTimer(int bufferTime, int bufferCount); ~StubTimer(); void start(); void stop(); void waitForBuffer(); - protected: - unsigned mBufferTime; - unsigned mBufferCount; - unsigned mCurrentTime; - TimeSource mTimeSource; +protected: + unsigned mBufferTime; + unsigned mBufferCount; + unsigned mCurrentTime; + TimeSource mTimeSource; #ifdef TARGET_WIN - HANDLE mStubSignal; + HANDLE mStubSignal; #endif - bool mActive; - }; -} + bool mActive; +}; +} // namespace Audio #endif diff --git a/src/engine/audio/Audio_Interface.cpp b/src/engine/audio/Audio_Interface.cpp index 3d0abf72..5beab687 100644 --- a/src/engine/audio/Audio_Interface.cpp +++ b/src/engine/audio/Audio_Interface.cpp @@ -7,16 +7,16 @@ #include "../helper/HL_OsVersion.h" #if !defined(USE_NULL_AUDIO) -# ifdef TARGET_WIN -# include "Audio_Wmme.h" -# include "Audio_DirectSound.h" -# endif -# ifdef TARGET_OSX -# include "Audio_CoreAudio.h" -# endif -# ifdef TARGET_ANDROID -# include "Audio_Android.h" -# endif +#ifdef TARGET_WIN +#include "Audio_Wmme.h" +#include "Audio_DirectSound.h" +#endif +#ifdef TARGET_OSX +#include "Audio_CoreAudio.h" +#endif +#ifdef TARGET_ANDROID +#include "Audio_Android.h" +#endif #endif #include "Audio_Helper.h" @@ -24,14 +24,9 @@ using namespace Audio; -Device::Device() - :mConnection(nullptr) -{ -} +Device::Device() : mConnection(nullptr) {} -Device::~Device() -{ -} +Device::~Device() {} void Device::setConnection(DataConnection* connection) @@ -44,13 +39,9 @@ DataConnection* Device::connection() return mConnection; } -InputDevice::InputDevice() -{ -} +InputDevice::InputDevice() {} -InputDevice::~InputDevice() -{ -} +InputDevice::~InputDevice() {} InputDevice* InputDevice::make(int devId) { @@ -71,13 +62,9 @@ InputDevice* InputDevice::make(int devId) return nullptr; } -OutputDevice::OutputDevice() -{ -} +OutputDevice::OutputDevice() {} -OutputDevice::~OutputDevice() -{ -} +OutputDevice::~OutputDevice() {} OutputDevice* OutputDevice::make(int devId) { @@ -85,7 +72,7 @@ OutputDevice* OutputDevice::make(int devId) return new NullOutputDevice(); #else #if defined(TARGET_WIN) - //return new WmmeOutputDevice(index); + // return new WmmeOutputDevice(index); return new DSoundOutputDevice(DSoundHelper::deviceId2Guid(devId, false)); #endif #ifdef TARGET_OSX @@ -100,13 +87,9 @@ OutputDevice* OutputDevice::make(int devId) // --- Enumerator --- -Enumerator::Enumerator() -{ -} +Enumerator::Enumerator() {} -Enumerator::~Enumerator() -{ -} +Enumerator::~Enumerator() {} int Enumerator::nameToIndex(const std::tstring& name) { @@ -119,7 +102,6 @@ int Enumerator::nameToIndex(const std::tstring& name) Enumerator* Enumerator::make(bool useNull) { - if (useNull) return new NullEnumerator(); #ifndef USE_NULL_AUDIO @@ -147,7 +129,7 @@ OsEngine* OsEngine::instance() #ifdef TARGET_ANDROID return nullptr; // As we use Oboe library for now - //return &OpenSLEngine::instance(); + // return &OpenSLEngine::instance(); #endif return nullptr; diff --git a/src/engine/audio/Audio_Interface.h b/src/engine/audio/Audio_Interface.h index e08f763d..3bed9780 100644 --- a/src/engine/audio/Audio_Interface.h +++ b/src/engine/audio/Audio_Interface.h @@ -27,34 +27,18 @@ struct Format int mRate; int mChannels; - Format() - :mRate(AUDIO_SAMPLERATE), mChannels(AUDIO_CHANNELS) - {} + Format() : mRate(AUDIO_SAMPLERATE), mChannels(AUDIO_CHANNELS) {} - Format(int rate, int channels) - :mRate(rate), mChannels(channels) - {} + Format(int rate, int channels) : mRate(rate), mChannels(channels) {} - size_t samplesFromSize(size_t length) const - { - return length / 2 / mChannels; - } + size_t samplesFromSize(size_t length) const { return length / 2 / mChannels; } // Returns milliseconds - float timeFromSize(size_t length) const - { - return float(samplesFromSize(length) / (mRate / 1000.0)); - } + float timeFromSize(size_t length) const { return float(samplesFromSize(length) / (mRate / 1000.0)); } - float sizeFromTime(size_t milliseconds) const - { - return float((milliseconds * mRate) / 500.0 * mChannels); - } + float sizeFromTime(size_t milliseconds) const { return float((milliseconds * mRate) / 500.0 * mChannels); } - size_t sizeFromTime(std::chrono::milliseconds ms) const - { - return sizeFromTime(ms.count()); - } + size_t sizeFromTime(std::chrono::milliseconds ms) const { return sizeFromTime(ms.count()); } std::string toString() { @@ -63,26 +47,13 @@ struct Format return std::string(buffer); } - bool operator == (const Format& rhs) const - { - return mRate == rhs.mRate && mChannels == rhs.mChannels; - } + bool operator==(const Format& rhs) const { return mRate == rhs.mRate && mChannels == rhs.mChannels; } - bool operator != (const Format& rhs) const - { - return mRate != rhs.mRate || mChannels != rhs.mChannels; - } + bool operator!=(const Format& rhs) const { return mRate != rhs.mRate || mChannels != rhs.mChannels; } - int rate() const - { - return mRate; - } - - int channels() const - { - return mChannels; - } + int rate() const { return mRate; } + int channels() const { return mChannels; } }; class DataConnection @@ -99,28 +70,29 @@ public: Device(); virtual ~Device(); - void setConnection(DataConnection* connection); + void setConnection(DataConnection* connection); DataConnection* connection(); - virtual bool open() = 0; - virtual void close() = 0; - virtual Format getFormat() = 0; + virtual bool open() = 0; + virtual void close() = 0; + virtual Format getFormat() = 0; + protected: DataConnection* mConnection; }; -class InputDevice: public Device +class InputDevice : public Device { public: InputDevice(); virtual ~InputDevice(); - + static InputDevice* make(int devId); }; typedef std::shared_ptr PInputDevice; -class OutputDevice: public Device +class OutputDevice : public Device { public: OutputDevice(); @@ -135,27 +107,27 @@ class Enumerator public: Enumerator(); virtual ~Enumerator(); - int nameToIndex(const std::tstring& name); + int nameToIndex(const std::tstring& name); - virtual void open(int direction) = 0; - virtual void close() = 0; - - virtual int count() = 0; + virtual void open(int direction) = 0; + virtual void close() = 0; + + virtual int count() = 0; virtual std::tstring nameAt(int index) = 0; - virtual int idAt(int index) = 0; - virtual int indexOfDefaultDevice() = 0; - - static Enumerator* make(bool useNull = false); + virtual int idAt(int index) = 0; + virtual int indexOfDefaultDevice() = 0; + + static Enumerator* make(bool useNull = false); }; class OsEngine { public: - virtual void open() = 0; - virtual void close() = 0; + virtual void open() = 0; + virtual void close() = 0; static OsEngine* instance(); }; -}; +}; // namespace Audio #endif diff --git a/src/engine/audio/Audio_Mixer.cpp b/src/engine/audio/Audio_Mixer.cpp index fdd89626..84e40289 100644 --- a/src/engine/audio/Audio_Mixer.cpp +++ b/src/engine/audio/Audio_Mixer.cpp @@ -17,341 +17,334 @@ using namespace Audio; Mixer::Stream::Stream() { - mResampler8.start(AUDIO_CHANNELS, 8000, AUDIO_SAMPLERATE); - mResampler16.start(AUDIO_CHANNELS, 16000, AUDIO_SAMPLERATE); - mResampler32.start(AUDIO_CHANNELS, 32000, AUDIO_SAMPLERATE); - mResampler48.start(AUDIO_CHANNELS, 48000, AUDIO_SAMPLERATE); - mActive = false; - mContext = nullptr; - mSSRC = 0; - mFadeOutCounter = 0; - mData.setCapacity(AUDIO_SPK_BUFFER_SIZE * AUDIO_SPK_BUFFER_COUNT); + mResampler8.start(AUDIO_CHANNELS, 8000, AUDIO_SAMPLERATE); + mResampler16.start(AUDIO_CHANNELS, 16000, AUDIO_SAMPLERATE); + mResampler32.start(AUDIO_CHANNELS, 32000, AUDIO_SAMPLERATE); + mResampler48.start(AUDIO_CHANNELS, 48000, AUDIO_SAMPLERATE); + mActive = false; + mContext = nullptr; + mSSRC = 0; + mFadeOutCounter = 0; + mData.setCapacity(AUDIO_SPK_BUFFER_SIZE * AUDIO_SPK_BUFFER_COUNT); } -Mixer::Stream::~Stream() -{ -} +Mixer::Stream::~Stream() {} void Mixer::Stream::setSsrc(unsigned ssrc) { - mSSRC = ssrc; + mSSRC = ssrc; } unsigned Mixer::Stream::ssrc() { - return mSSRC; + return mSSRC; } void Mixer::Stream::setContext(void* context) { - mContext = context; + mContext = context; } void* Mixer::Stream::context() { - return mContext; + return mContext; } DataWindow& Mixer::Stream::data() { - return mData; + return mData; } bool Mixer::Stream::active() { - return mActive; + return mActive; } void Mixer::Stream::setActive(bool active) { - mActive = active; + mActive = active; } void Mixer::Stream::addPcm(int rate, const void* input, int length) { - // Resample to internal sample rate - size_t outputSize = size_t(0.5 + length * ((float)AUDIO_SAMPLERATE / rate)); - if (mTempBuffer.size() < outputSize) - mTempBuffer.resize(outputSize); - - Resampler* resampler = (rate == 8000) ? &mResampler8 : ((rate == 16000) ? &mResampler16 : ((rate == 32000) ? &mResampler32 : &mResampler48)); - size_t inputProcessed = 0; - resampler->processBuffer(input, length, inputProcessed, mTempBuffer.mutableData(), outputSize); - // inputProcessed result value is ignored here - rate will be 8/16/32/48k, inputProcessed is equal to length + // Resample to internal sample rate + size_t outputSize = size_t(0.5 + length * ((float)AUDIO_SAMPLERATE / rate)); + if (mTempBuffer.size() < outputSize) + mTempBuffer.resize(outputSize); - // Queue data - mData.add(mTempBuffer.data(), outputSize); + Resampler* resampler = (rate == 8000) + ? &mResampler8 + : ((rate == 16000) ? &mResampler16 : ((rate == 32000) ? &mResampler32 : &mResampler48)); + size_t inputProcessed = 0; + resampler->processBuffer(input, length, inputProcessed, mTempBuffer.mutableData(), outputSize); + // inputProcessed result value is ignored here - rate will be 8/16/32/48k, inputProcessed is equal to length + + // Queue data + mData.add(mTempBuffer.data(), outputSize); } Mixer::Mixer() { - mActiveCounter = 0; - mOutput.setCapacity(32768); + mActiveCounter = 0; + mOutput.setCapacity(32768); } -Mixer::~Mixer() -{ -} +Mixer::~Mixer() {} void Mixer::unregisterChannel(void* channel) { - Lock l(mMutex); - for (int i=0; iactive()) + // Allocate new channel + Lock l(mMutex); + Stream* channel; + for (int i = 0; i < AUDIO_MIX_CHANNEL_COUNT; i++) { - channel->setSsrc(ssrc); - channel->setContext(context); - channel->data().clear(); - mActiveCounter++; - channel->setActive(true); - return channel; + channel = &mChannelList[i]; + if (!channel->active()) + { + channel->setSsrc(ssrc); + channel->setContext(context); + channel->data().clear(); + mActiveCounter++; + channel->setActive(true); + return channel; + } } - } - return NULL; + return NULL; } -void Mixer::addPcm(void* context, unsigned ssrc, - const void* inputData, int inputLength, - int inputRate, bool fadeOut) +void Mixer::addPcm(void* context, unsigned ssrc, const void* inputData, int inputLength, int inputRate, bool fadeOut) { - assert(inputRate == 8000 || inputRate == 16000 || inputRate == 32000); + assert(inputRate == 8000 || inputRate == 16000 || inputRate == 32000); - Lock l(mMutex); - int i; + Lock l(mMutex); + int i; - // Locate a channel - Stream* channel = NULL; - - for (i=0; iaddPcm(inputRate, inputData, inputLength); + { + channel = allocateChannel(context, ssrc); + if (!channel) + throw Exception(ERR_MIXER_OVERFLOW); + } + + channel->addPcm(inputRate, inputData, inputLength); } void Mixer::addPcm(void* context, unsigned ssrc, Audio::DataWindow& w, int rate, bool fadeOut) { - assert(rate == 8000 || rate == 16000 || rate == 32000 || rate == 48000); + assert(rate == 8000 || rate == 16000 || rate == 32000 || rate == 48000); - Lock l(mMutex); - int i; + Lock l(mMutex); + int i; - // Locate a channel - Stream* channel = NULL; - - for (i=0; iaddPcm(rate, w.data(), w.filled()); - //ICELogSpecial(<<"Mixer stream " << int(this) << " has " << w.filled() << " bytes"); + { + channel = allocateChannel(context, ssrc); + if (!channel) + throw Exception(ERR_MIXER_OVERFLOW); + } + + channel->addPcm(rate, w.data(), w.filled()); + // ICELogSpecial(<<"Mixer stream " << int(this) << " has " << w.filled() << " bytes"); } void Mixer::mix() { - Lock l(mMutex); + Lock l(mMutex); - // Current sample - int sample = 0; + // Current sample + int sample = 0; - // Counter of processed active channels - int processed = 0; + // Counter of processed active channels + int processed = 0; - // Samples & sources counters - unsigned sampleCounter = 0, sourceCounter; + // Samples & sources counters + unsigned sampleCounter = 0, sourceCounter; - short outputBuffer[512]; - unsigned outputCounter = 0; + short outputBuffer[512]; + unsigned outputCounter = 0; - // Build active channel map - Stream* channelList[AUDIO_MIX_CHANNEL_COUNT]; - int activeCounter = 0; - for (int i=0; i filled2 ? filled1 : filled2; - - // Find how much samples can be mixed - int filled = mOutput.filled() / 2; - - int maxsize = mOutput.capacity() / 2; - if (maxsize - filled < available) - available = maxsize - filled; - - short sample = 0; - for (int i=0; i i ? audio1.data().shortAt(i) : 0; - short sample2 = filled2 > i ? audio2.data().shortAt(i) : 0; - sample = (abs(sample1) > abs(sample2)) ? sample1 : sample2; - - mOutput.add(sample); - } - audio1.data().erase(available*2); - audio2.data().erase(available*2); - } - else - { - do + // No active channels - nothing to mix - exit + if (!activeCounter) { - sample = 0; - sourceCounter = 0; - processed = 0; - for (int i=0; i (int)sampleCounter * 2) + // Optimized versions for 1& 2 active channels + if (activeCounter == 1) + { + // Copy much samples as we have + Stream& audio = *channelList[0]; + + // Copy the decoded data + mOutput.add(audio.data().data(), audio.data().filled()); + + // Erase copied audio samples + audio.data().erase(audio.data().filled()); + // ICELogSpecial(<<"Length of mixer stream " << audio.data().filled()); + } + else if (activeCounter == 2) + { + Stream& audio1 = *channelList[0]; + Stream& audio2 = *channelList[1]; + int filled1 = audio1.data().filled() / 2, filled2 = audio2.data().filled() / 2; + int available = filled1 > filled2 ? filled1 : filled2; + + // Find how much samples can be mixed + int filled = mOutput.filled() / 2; + + int maxsize = mOutput.capacity() / 2; + if (maxsize - filled < available) + available = maxsize - filled; + + short sample = 0; + for (int i = 0; i < available; i++) { - short currentSample = audio.data().shortAt(sampleCounter); - if (abs(currentSample) > abs(sample)) - sample = currentSample; - sourceCounter++; + short sample1 = filled1 > i ? audio1.data().shortAt(i) : 0; + short sample2 = filled2 > i ? audio2.data().shortAt(i) : 0; + sample = (abs(sample1) > abs(sample2)) ? sample1 : sample2; + + mOutput.add(sample); } - } - - if (sourceCounter) - { - outputBuffer[outputCounter++] = (short)sample; - sampleCounter++; - } - - // Check if time to flash output buffer - if ((!sourceCounter || outputCounter == 512) && outputCounter) - { - mOutput.add(outputBuffer, outputCounter * 2); - outputCounter = 0; - } + audio1.data().erase(available * 2); + audio2.data().erase(available * 2); } - while (sourceCounter); - - processed = 0; - for (int i=0; i (int)sampleCounter * 2) + { + short currentSample = audio.data().shortAt(sampleCounter); + if (abs(currentSample) > abs(sample)) + sample = currentSample; + sourceCounter++; + } + } + + if (sourceCounter) + { + outputBuffer[outputCounter++] = (short)sample; + sampleCounter++; + } + + // Check if time to flash output buffer + if ((!sourceCounter || outputCounter == 512) && outputCounter) + { + mOutput.add(outputBuffer, outputCounter * 2); + outputCounter = 0; + } + } while (sourceCounter); + + processed = 0; + for (int i = 0; i < activeCounter; i++) + { + Stream& audio = *channelList[i]; + audio.data().erase(sampleCounter * 2); + } } - } } int Mixer::getPcm(void* outputData, int outputLength) { - Lock l(mMutex); + Lock l(mMutex); - if (mOutput.filled() < outputLength) - mix(); + if (mOutput.filled() < outputLength) + mix(); - //ICELogSpecial(<<"Mixer has " << mOutput.filled() << " available bytes"); - memset(outputData, 0, outputLength); - return mOutput.read(outputData, outputLength); + // ICELogSpecial(<<"Mixer has " << mOutput.filled() << " available bytes"); + memset(outputData, 0, outputLength); + return mOutput.read(outputData, outputLength); } int Mixer::mixAndGetPcm(Audio::DataWindow& output) { - Lock l(mMutex); + Lock l(mMutex); - // Mix - mix(); + // Mix + mix(); - size_t avail = mOutput.filled(); - if (!avail) - { - output.setFilled(0); - return 0; - } + size_t avail = mOutput.filled(); + if (!avail) + { + output.setFilled(0); + return 0; + } - // Make sure output has enough space (setCapacity only ever grows the window) - if (output.capacity() < avail) - output.setCapacity(avail); + // Make sure output has enough space (setCapacity only ever grows the window) + if (output.capacity() < avail) + output.setCapacity(avail); - // Read mixed data to output and publish the real byte count - size_t got = mOutput.read(output.mutableData(), avail); - output.setFilled(got); - return static_cast(got); + // Read mixed data to output and publish the real byte count + size_t got = mOutput.read(output.mutableData(), avail); + output.setFilled(got); + return static_cast(got); } int Mixer::available() { - return mOutput.filled(); + return mOutput.filled(); } - diff --git a/src/engine/audio/Audio_Mixer.h b/src/engine/audio/Audio_Mixer.h index a43a39fb..ef74f0a2 100644 --- a/src/engine/audio/Audio_Mixer.h +++ b/src/engine/audio/Audio_Mixer.h @@ -14,59 +14,56 @@ #include #include -namespace Audio +namespace Audio { - class Mixer - { - protected: +class Mixer +{ +protected: class Stream { protected: - DataWindow mData; - Resampler mResampler8, - mResampler16, - mResampler32, - mResampler48; - bool mActive; - void* mContext; - unsigned mSSRC; - unsigned mFadeOutCounter; - ByteBuffer mTempBuffer; + DataWindow mData; + Resampler mResampler8, mResampler16, mResampler32, mResampler48; + bool mActive; + void* mContext; + unsigned mSSRC; + unsigned mFadeOutCounter; + ByteBuffer mTempBuffer; public: - Stream(); - ~Stream(); + Stream(); + ~Stream(); - void setSsrc(unsigned ssrc); - unsigned ssrc(); - void setContext(void* context); - void* context(); - DataWindow& data(); - bool active(); - void setActive(bool active); - void addPcm(int rate, const void* input, int length); + void setSsrc(unsigned ssrc); + unsigned ssrc(); + void setContext(void* context); + void* context(); + DataWindow& data(); + bool active(); + void setActive(bool active); + void addPcm(int rate, const void* input, int length); }; - - Stream mChannelList[AUDIO_MIX_CHANNEL_COUNT]; - Mutex mMutex; - DataWindow mOutput; - std::atomic_int mActiveCounter; - void mix(); - Stream* allocateChannel(void* context, unsigned ssrc); + Stream mChannelList[AUDIO_MIX_CHANNEL_COUNT]; + Mutex mMutex; + DataWindow mOutput; + std::atomic_int mActiveCounter; - public: + void mix(); + Stream* allocateChannel(void* context, unsigned ssrc); + +public: Mixer(); ~Mixer(); - + void unregisterChannel(void* context); void clear(void* context, unsigned ssrc); void addPcm(void* context, unsigned ssrc, const void* inputData, int inputLength, int inputRate, bool fadeOut); void addPcm(void* context, unsigned ssrc, Audio::DataWindow& w, int rate, bool fadeOut); int getPcm(void* outputData, int outputLength); int mixAndGetPcm(Audio::DataWindow& output); - int available(); - }; -} //end of namespace + int available(); +}; +} // namespace Audio #endif diff --git a/src/engine/audio/Audio_Null.cpp b/src/engine/audio/Audio_Null.cpp index c29bf6d8..61d97824 100644 --- a/src/engine/audio/Audio_Null.cpp +++ b/src/engine/audio/Audio_Null.cpp @@ -7,8 +7,8 @@ using namespace Audio; using namespace std::chrono_literals; -NullTimer::NullTimer(std::chrono::milliseconds interval, Delegate *delegate, const char* name) - :mShutdown(false), mDelegate(delegate), mInterval(interval), mThreadName(name) +NullTimer::NullTimer(std::chrono::milliseconds interval, Delegate* delegate, const char* name) + : mShutdown(false), mDelegate(delegate), mInterval(interval), mThreadName(name) { start(); } @@ -49,15 +49,13 @@ void NullTimer::run() // Sleep for mInterval - mTail milliseconds std::this_thread::sleep_for(mInterval - mTail); - mTail = mTail + std::chrono::duration_cast(std::chrono::system_clock::now() - timestamp); + mTail = + mTail + std::chrono::duration_cast(std::chrono::system_clock::now() - timestamp); } } // --------------------- NullInputDevice ------------------------- -NullInputDevice::NullInputDevice() - :mBuffer(nullptr) -{ -} +NullInputDevice::NullInputDevice() : mBuffer(nullptr) {} NullInputDevice::~NullInputDevice() { @@ -69,7 +67,8 @@ bool NullInputDevice::open() ICELogInfo(<< "Starting NullInputDevice for " << AUDIO_MIC_BUFFER_LENGTH << "ms buffers"); mBuffer = malloc(AUDIO_MIC_BUFFER_SIZE); memset(mBuffer, 0, AUDIO_MIC_BUFFER_SIZE); - mTimeCounter = 0; mDataCounter = 0; + mTimeCounter = 0; + mDataCounter = 0; // Creation of timer starts it also. So first onTimerSignal can come even before open() returns. mTimer = std::make_shared(std::chrono::milliseconds(AUDIO_MIC_BUFFER_LENGTH), this, "null_mic"); @@ -85,7 +84,7 @@ void NullInputDevice::internalClose() free(mBuffer); mBuffer = nullptr; } - ICELogInfo( << "Pseudocaptured " << mTimeCounter << " milliseconds , " << mDataCounter << " bytes."); + ICELogInfo(<< "Pseudocaptured " << mTimeCounter << " milliseconds , " << mDataCounter << " bytes."); } void NullInputDevice::close() @@ -95,7 +94,7 @@ void NullInputDevice::close() Format NullInputDevice::getFormat() { - assert (Format().sizeFromTime(AUDIO_MIC_BUFFER_LENGTH) == AUDIO_MIC_BUFFER_SIZE); + assert(Format().sizeFromTime(AUDIO_MIC_BUFFER_LENGTH) == AUDIO_MIC_BUFFER_SIZE); return {}; // Return library-define default format } @@ -109,10 +108,7 @@ void NullInputDevice::onTimerSignal(NullTimer& timer) } // --------------------- NullOutputDevice -------------------------- -NullOutputDevice::NullOutputDevice() - :mBuffer(nullptr) -{ -} +NullOutputDevice::NullOutputDevice() : mBuffer(nullptr) {} NullOutputDevice::~NullOutputDevice() { @@ -122,7 +118,8 @@ NullOutputDevice::~NullOutputDevice() bool NullOutputDevice::open() { - mTimeCounter = 0; mDataCounter = 0; + mTimeCounter = 0; + mDataCounter = 0; mBuffer = malloc(AUDIO_SPK_BUFFER_SIZE); // Creation of timer starts it also. So first onSpkData() can come before open() returns even. mTimer = std::make_shared(std::chrono::milliseconds(AUDIO_SPK_BUFFER_LENGTH), this, "null_spk"); @@ -132,7 +129,8 @@ bool NullOutputDevice::open() void NullOutputDevice::internalClose() { mTimer.reset(); - free(mBuffer); mBuffer = nullptr; + free(mBuffer); + mBuffer = nullptr; ICELogInfo(<< "Pseudoplayed " << mTimeCounter << " milliseconds, " << mDataCounter << " bytes."); } @@ -143,11 +141,11 @@ void NullOutputDevice::close() Format NullOutputDevice::getFormat() { - assert (Format().sizeFromTime(AUDIO_SPK_BUFFER_LENGTH) == AUDIO_SPK_BUFFER_SIZE); + assert(Format().sizeFromTime(AUDIO_SPK_BUFFER_LENGTH) == AUDIO_SPK_BUFFER_SIZE); return Format(); } -void NullOutputDevice::onTimerSignal(NullTimer &timer) +void NullOutputDevice::onTimerSignal(NullTimer& timer) { mTimeCounter += AUDIO_SPK_BUFFER_LENGTH; mDataCounter += AUDIO_SPK_BUFFER_SIZE; @@ -156,19 +154,15 @@ void NullOutputDevice::onTimerSignal(NullTimer &timer) } // ---------------------- NullEnumerator -------------------------- -NullEnumerator::NullEnumerator() -{} +NullEnumerator::NullEnumerator() {} -NullEnumerator::~NullEnumerator() -{} +NullEnumerator::~NullEnumerator() {} -void NullEnumerator::open(int direction) -{} +void NullEnumerator::open(int direction) {} -void NullEnumerator::close() -{} +void NullEnumerator::close() {} -int NullEnumerator::count() +int NullEnumerator::count() { return 1; } @@ -191,4 +185,3 @@ int NullEnumerator::indexOfDefaultDevice() { return 0; } - diff --git a/src/engine/audio/Audio_Null.h b/src/engine/audio/Audio_Null.h index b3bbd42e..6eb90854 100644 --- a/src/engine/audio/Audio_Null.h +++ b/src/engine/audio/Audio_Null.h @@ -17,75 +17,77 @@ public: }; protected: - std::thread mWorkerThread; - std::atomic_bool mShutdown = {false}; - Delegate* mDelegate = nullptr; - std::chrono::milliseconds mInterval; // Interval - wanted number of milliseconds - std::chrono::microseconds mTail; // Number of milliseconds that can be sent immediately to sink - std::string mThreadName; + std::thread mWorkerThread; + std::atomic_bool mShutdown = {false}; + Delegate* mDelegate = nullptr; + std::chrono::milliseconds mInterval; // Interval - wanted number of milliseconds + std::chrono::microseconds mTail; // Number of milliseconds that can be sent immediately to sink + std::string mThreadName; + + void start(); + void stop(); + void run(); - void start(); - void stop(); - void run(); public: /* Interval is in milliseconds. */ NullTimer(std::chrono::milliseconds interval, Delegate* delegate, const char* name = nullptr); ~NullTimer(); }; -class NullInputDevice: public InputDevice, public NullTimer::Delegate +class NullInputDevice : public InputDevice, public NullTimer::Delegate { protected: - void* mBuffer = nullptr; + void* mBuffer = nullptr; std::shared_ptr mTimer; - int64_t mTimeCounter = 0, mDataCounter = 0; - void internalClose(); + int64_t mTimeCounter = 0, mDataCounter = 0; + void internalClose(); public: NullInputDevice(); virtual ~NullInputDevice(); - bool open() override; - void close() override; + bool open() override; + void close() override; Format getFormat() override; - void onTimerSignal(NullTimer& timer) override; + void onTimerSignal(NullTimer& timer) override; }; -class NullOutputDevice: public OutputDevice, public NullTimer::Delegate +class NullOutputDevice : public OutputDevice, public NullTimer::Delegate { protected: std::shared_ptr mTimer; - void* mBuffer = nullptr; - int64_t mDataCounter = 0, mTimeCounter = 0; + void* mBuffer = nullptr; + int64_t mDataCounter = 0, mTimeCounter = 0; + + void internalClose(); - void internalClose(); public: NullOutputDevice(); virtual ~NullOutputDevice(); - bool open() override; - void close() override; + bool open() override; + void close() override; Format getFormat() override; - void onTimerSignal(NullTimer& timer) override; + void onTimerSignal(NullTimer& timer) override; }; -class NullEnumerator: public Enumerator +class NullEnumerator : public Enumerator { public: NullEnumerator(); ~NullEnumerator(); - void open(int direction) override; - void close() override; + void open(int direction) override; + void close() override; - int count() override; + int count() override; std::tstring nameAt(int index) override; - int idAt(int index) override; - int indexOfDefaultDevice() override; + int idAt(int index) override; + int indexOfDefaultDevice() override; }; -} +} // namespace Audio #endif diff --git a/src/engine/audio/Audio_Player.cpp b/src/engine/audio/Audio_Player.cpp index 7ad14ef0..5e459a1b 100644 --- a/src/engine/audio/Audio_Player.cpp +++ b/src/engine/audio/Audio_Player.cpp @@ -11,161 +11,156 @@ using namespace Audio; // -------------- Player ----------- -Player::Player() -:mDelegate(nullptr), mPlayedTime(0) -{ -} +Player::Player() : mDelegate(nullptr), mPlayedTime(0) {} -Player::~Player() -{ -} +Player::~Player() {} void Player::setDelegate(EndOfAudioDelegate* d) { - mDelegate = d; + mDelegate = d; } Player::EndOfAudioDelegate* Player::getDelegate() const { - return mDelegate; + return mDelegate; } void Player::setOutput(POutputDevice output) { - mOutput = output; - if (mOutput) - mOutput->setConnection(this); + mOutput = output; + if (mOutput) + mOutput->setConnection(this); } POutputDevice Player::getOutput() const { - return mOutput; + return mOutput; } void Player::onMicData(const Format& f, const void* buffer, int length) { - // Do nothing here - this data sink is not used in player + // Do nothing here - this data sink is not used in player } #define BYTES_PER_MILLISECOND (AUDIO_SAMPLERATE / 1000 * 2 * AUDIO_CHANNELS) void Player::onSpkData(const Format& f, void* buffer, int length) { - Lock l(mGuard); + Lock l(mGuard); - // Fill buffer by zero if player owns dedicated device - if (mOutput) - memset(buffer, 0, length); + // Fill buffer by zero if player owns dedicated device + if (mOutput) + memset(buffer, 0, length); - // See if there is item in playlist - int produced = 0; - while (mPlaylist.size() && produced < length) - { - PlaylistItem& item = mPlaylist.front(); - // Check for timelength - if (item.mTimelength > 0 && item.mTimelength < mPlayedTime) + // See if there is item in playlist + int produced = 0; + while (mPlaylist.size() && produced < length) { - onFilePlayed(); - continue; - } + PlaylistItem& item = mPlaylist.front(); + // Check for timelength + if (item.mTimelength > 0 && item.mTimelength < mPlayedTime) + { + onFilePlayed(); + continue; + } - int wasread = item.mFile->read((char*)buffer+produced, length-produced); - mPlayedTime += float(wasread) / BYTES_PER_MILLISECOND; - produced += wasread; - if (wasread < length-produced) - { - if (item.mLoop) - { - item.mFile->rewind(); - wasread = item.mFile->read((char*)buffer+produced, (length - produced)); + int wasread = item.mFile->read((char*)buffer + produced, length - produced); mPlayedTime += float(wasread) / BYTES_PER_MILLISECOND; produced += wasread; - } - else - onFilePlayed(); + if (wasread < length - produced) + { + if (item.mLoop) + { + item.mFile->rewind(); + wasread = item.mFile->read((char*)buffer + produced, (length - produced)); + mPlayedTime += float(wasread) / BYTES_PER_MILLISECOND; + produced += wasread; + } + else + onFilePlayed(); + } } - } } void Player::onFilePlayed() { - // Save usage id to release later from main loop - mFinishedUsages.push_back(mPlaylist.front().mUsageId); - - // Send event - if (mDelegate) - mDelegate->onFilePlayed(mPlaylist.front()); - - // Remove played item & reset played time - mPlaylist.pop_front(); - mPlayedTime = 0; + // Save usage id to release later from main loop + mFinishedUsages.push_back(mPlaylist.front().mUsageId); + + // Send event + if (mDelegate) + mDelegate->onFilePlayed(mPlaylist.front()); + + // Remove played item & reset played time + mPlaylist.pop_front(); + mPlayedTime = 0; } void Player::obtain(int usage) { - Lock l(mGuard); - auto usageIter = mUsage.find(usage); - if (usageIter == mUsage.end()) - mUsage[usage] = 1; - else - usageIter->second = usageIter->second + 1; + Lock l(mGuard); + auto usageIter = mUsage.find(usage); + if (usageIter == mUsage.end()) + mUsage[usage] = 1; + else + usageIter->second = usageIter->second + 1; - if (mUsage.size() == 1 && mOutput) - mOutput->open(); + if (mUsage.size() == 1 && mOutput) + mOutput->open(); } void Player::release(int usage) { - Lock l(mGuard); - UsageMap::iterator usageIter = mUsage.find(usage); - if (usageIter == mUsage.end()) - return; + Lock l(mGuard); + UsageMap::iterator usageIter = mUsage.find(usage); + if (usageIter == mUsage.end()) + return; - usageIter->second = usageIter->second - 1; - if (!usageIter->second) - mUsage.erase(usageIter); + usageIter->second = usageIter->second - 1; + if (!usageIter->second) + mUsage.erase(usageIter); - for (unsigned i=0; iclose(); + if (mUsage.empty() && mOutput) + mOutput->close(); } int Player::releasePlayed() { - Lock l(mGuard); - int result = mFinishedUsages.size(); - while (!mFinishedUsages.empty()) - { - release(mFinishedUsages.front()); - mFinishedUsages.erase(mFinishedUsages.begin()); - } - return result; + Lock l(mGuard); + int result = mFinishedUsages.size(); + while (!mFinishedUsages.empty()) + { + release(mFinishedUsages.front()); + mFinishedUsages.erase(mFinishedUsages.begin()); + } + return result; } void Player::add(int usageId, PWavFileReader file, bool loop, int timelength) { - Lock l(mGuard); - PlaylistItem item; - item.mFile = file; - item.mLoop = loop; - item.mTimelength = timelength; - item.mUsageId = usageId; - mPlaylist.push_back(item); + Lock l(mGuard); + PlaylistItem item; + item.mFile = file; + item.mLoop = loop; + item.mTimelength = timelength; + item.mUsageId = usageId; + mPlaylist.push_back(item); - obtain(usageId); + obtain(usageId); } void Player::clear() { - Lock l(mGuard); - while (mPlaylist.size()) - onFilePlayed(); + Lock l(mGuard); + while (mPlaylist.size()) + onFilePlayed(); } void Player::retrieveUsageIds(std::vector& ids) { - ids.assign(mFinishedUsages.begin(), mFinishedUsages.end()); - mFinishedUsages.clear(); + ids.assign(mFinishedUsages.begin(), mFinishedUsages.end()); + mFinishedUsages.clear(); } diff --git a/src/engine/audio/Audio_Player.h b/src/engine/audio/Audio_Player.h index 82656d8c..64adb69c 100644 --- a/src/engine/audio/Audio_Player.h +++ b/src/engine/audio/Audio_Player.h @@ -16,56 +16,57 @@ namespace Audio { - class Player: public DataConnection - { - friend class DevicePair; - public: +class Player : public DataConnection +{ + friend class DevicePair; + +public: struct PlaylistItem { - PWavFileReader mFile; - bool mLoop; - int mTimelength; - int mUsageId; + PWavFileReader mFile; + bool mLoop; + int mTimelength; + int mUsageId; }; typedef std::deque Playlist; class EndOfAudioDelegate { public: - virtual void onFilePlayed(PlaylistItem& item) = 0; + virtual void onFilePlayed(PlaylistItem& item) = 0; }; - protected: +protected: typedef std::map UsageMap; - Audio::POutputDevice mOutput; - UsageMap mUsage; // References map - std::vector mFinishedUsages; // Finished plays + Audio::POutputDevice mOutput; + UsageMap mUsage; // References map + std::vector mFinishedUsages; // Finished plays - Mutex mGuard; - Playlist mPlaylist; - float mPlayedTime; - EndOfAudioDelegate* mDelegate; + Mutex mGuard; + Playlist mPlaylist; + float mPlayedTime; + EndOfAudioDelegate* mDelegate; - void onMicData(const Format& f, const void* buffer, int length); - void onSpkData(const Format& f, void* buffer, int length); - void onFilePlayed(); - void obtain(int usageId); + void onMicData(const Format& f, const void* buffer, int length); + void onSpkData(const Format& f, void* buffer, int length); + void onFilePlayed(); + void obtain(int usageId); - public: +public: Player(); ~Player(); - void setDelegate(EndOfAudioDelegate* d); + void setDelegate(EndOfAudioDelegate* d); EndOfAudioDelegate* getDelegate() const; - void setOutput(POutputDevice output); - POutputDevice getOutput() const; + void setOutput(POutputDevice output); + POutputDevice getOutput() const; - void add(int usageId, PWavFileReader file, bool loop, int timelength); - void release(int usageId); - void clear(); - int releasePlayed(); - void retrieveUsageIds(std::vector& ids); - }; -} + void add(int usageId, PWavFileReader file, bool loop, int timelength); + void release(int usageId); + void clear(); + int releasePlayed(); + void retrieveUsageIds(std::vector& ids); +}; +} // namespace Audio #endif diff --git a/src/engine/audio/Audio_Quality.cpp b/src/engine/audio/Audio_Quality.cpp index 5a019b4f..2066b2d3 100644 --- a/src/engine/audio/Audio_Quality.cpp +++ b/src/engine/audio/Audio_Quality.cpp @@ -10,7 +10,7 @@ #include "speex/speex_preprocess.h" #ifdef WIN32 -# include +#include #endif #include #include @@ -18,221 +18,217 @@ using namespace Audio; #ifndef SHRT_MAX -# define SHRT_MAX 32767 /* maximum (signed) short value */ +#define SHRT_MAX 32767 /* maximum (signed) short value */ #endif AgcFilter::AgcFilter(int channels) { - static const float DefaultLevel = 0.8f; + static const float DefaultLevel = 0.8f; - for (int i=0; i 1.0f) - level = 1.0f; - else - if (level < 0.5f) - level = 0.5f; + for (int i = 0; i < channels; i++) + { + Channel c; + float level = DefaultLevel; + c.mSampleMax = 1; + c.mCounter = 0; + c.mIgain = 65536; + if (level > 1.0f) + level = 1.0f; + else if (level < 0.5f) + level = 0.5f; - c.mIpeak = (int)(SHRT_MAX * level * 65536); + c.mIpeak = (int)(SHRT_MAX * level * 65536); - c.mSilenceCounter = 0; - mChannelList.push_back(c); - } + c.mSilenceCounter = 0; + mChannelList.push_back(c); + } } -AgcFilter::~AgcFilter() -{ -} +AgcFilter::~AgcFilter() {} -void AgcFilter::process(void *pcm, int length) +void AgcFilter::process(void* pcm, int length) { - for (size_t i=0; i (int)channel.mSampleMax) + for (i = 0; i < nrOfSamples; i++) { - /* update the max */ - channel.mSampleMax = (unsigned int)sample; - } - channel.mCounter ++; + long gain_new; + int sample; + int sampleIndex = mChannelList.size() * i + channelIndex; + Channel& channel = mChannelList[channelIndex]; - /* Will we get an overflow with the current gain factor? */ - if (((sample * channel.mIgain) >> 16) > channel.mIpeak) - { - /* Yes: Calculate new gain. */ - channel.mIgain = ((channel.mIpeak / channel.mSampleMax) * 62259) >> 16; - channel.mSilenceCounter = 0; - pcm[sampleIndex] = (short) ((pcm[sampleIndex] * channel.mIgain) >> 16); - continue; - } + /* get the abs of buffer[i] */ + sample = pcm[sampleIndex]; + sample = (sample < 0 ? -(sample) : sample); - /* Calculate new gain factor 10x per second */ - if (channel.mCounter >= AUDIO_SAMPLERATE / 10) - { - if (channel.mSampleMax > AUDIO_SAMPLERATE / 10) /* speaking? */ - { - gain_new = ((channel.mIpeak / channel.mSampleMax) * 62259) >> 16; - - if (channel.mSilenceCounter > 40) /* pause -> speaking */ - channel.mIgain += (gain_new - channel.mIgain) >> 2; - else - channel.mIgain += (gain_new - channel.mIgain) / 20; + if (sample > (int)channel.mSampleMax) + { + /* update the max */ + channel.mSampleMax = (unsigned int)sample; + } + channel.mCounter++; - channel.mSilenceCounter = 0; - } - else /* silence */ - { - channel.mSilenceCounter++; - /* silence > 2 seconds: reduce gain */ - if ((channel.mIgain > 65536) && (channel.mSilenceCounter >= 20)) - channel.mIgain = (channel.mIgain * 62259) >> 16; - } - - channel.mCounter = 0; - channel.mSampleMax = 1; + /* Will we get an overflow with the current gain factor? */ + if (((sample * channel.mIgain) >> 16) > channel.mIpeak) + { + /* Yes: Calculate new gain. */ + channel.mIgain = ((channel.mIpeak / channel.mSampleMax) * 62259) >> 16; + channel.mSilenceCounter = 0; + pcm[sampleIndex] = (short)((pcm[sampleIndex] * channel.mIgain) >> 16); + continue; + } + + /* Calculate new gain factor 10x per second */ + if (channel.mCounter >= AUDIO_SAMPLERATE / 10) + { + if (channel.mSampleMax > AUDIO_SAMPLERATE / 10) /* speaking? */ + { + gain_new = ((channel.mIpeak / channel.mSampleMax) * 62259) >> 16; + + if (channel.mSilenceCounter > 40) /* pause -> speaking */ + channel.mIgain += (gain_new - channel.mIgain) >> 2; + else + channel.mIgain += (gain_new - channel.mIgain) / 20; + + channel.mSilenceCounter = 0; + } + else /* silence */ + { + channel.mSilenceCounter++; + /* silence > 2 seconds: reduce gain */ + if ((channel.mIgain > 65536) && (channel.mSilenceCounter >= 20)) + channel.mIgain = (channel.mIgain * 62259) >> 16; + } + + channel.mCounter = 0; + channel.mSampleMax = 1; + } + pcm[sampleIndex] = (short)((pcm[sampleIndex] * channel.mIgain) >> 16); } - pcm[sampleIndex] = (short) ((pcm[sampleIndex] * channel.mIgain) >> 16); - } } // --- AecFilter --- #ifdef USE_SPEEX_AEC -# include "speex/speex_echo.h" +#include "speex/speex_echo.h" #include "Audio_Interface.h" #if !defined(TARGET_WIN) -# include +#include #endif #endif #ifdef USE_WEBRTC_AEC -# include "aec/echo_cancellation.h" +#include "aec/echo_cancellation.h" #endif - + #ifdef USE_WEBRTC_AEC static void CheckWRACode(unsigned errorcode) { - if (errorcode) - throw Exception(ERR_WEBRTC, errorcode); + if (errorcode) + throw Exception(ERR_WEBRTC, errorcode); } #endif -AecFilter::AecFilter(int tailTime, int frameTime, int rate) -:mCtx(nullptr), mFrameTime(frameTime), mRate(rate) +AecFilter::AecFilter(int tailTime, int frameTime, int rate) : mCtx(nullptr), mFrameTime(frameTime), mRate(rate) { #ifdef USE_SPEEX_AEC - if (AUDIO_CHANNELS == 2) - mCtx = speex_echo_state_init_mc(frameTime * (mRate / 1000), tailTime * (mRate / 1000), AUDIO_CHANNELS, AUDIO_CHANNELS ); - else - mCtx = speex_echo_state_init(frameTime * (mRate / 1000), tailTime * (mRate / 1000)); - int tmp = rate; - speex_echo_ctl((SpeexEchoState*)mCtx, SPEEX_ECHO_SET_SAMPLING_RATE, &tmp); + if (AUDIO_CHANNELS == 2) + mCtx = speex_echo_state_init_mc(frameTime * (mRate / 1000), tailTime * (mRate / 1000), AUDIO_CHANNELS, + AUDIO_CHANNELS); + else + mCtx = speex_echo_state_init(frameTime * (mRate / 1000), tailTime * (mRate / 1000)); + int tmp = rate; + speex_echo_ctl((SpeexEchoState*)mCtx, SPEEX_ECHO_SET_SAMPLING_RATE, &tmp); #endif #ifdef USE_WEBRTC_AEC - CheckWRACode(WebRtcAec_Create(&mCtx)); - CheckWRACode(WebRtcAec_Init(mCtx, rate, rate)); + CheckWRACode(WebRtcAec_Create(&mCtx)); + CheckWRACode(WebRtcAec_Init(mCtx, rate, rate)); #endif } AecFilter::~AecFilter() { #ifdef USE_SPEEX_AEC - if (mCtx) - { - //speex_echo_state_destroy((SpeexEchoState*)mCtx); - mCtx = nullptr; - } + if (mCtx) + { + // speex_echo_state_destroy((SpeexEchoState*)mCtx); + mCtx = nullptr; + } #endif #ifdef USE_WEBRTC_AEC - CheckWRACode(WebRtcAec_Free(mCtx)); - mCtx = NULL; + CheckWRACode(WebRtcAec_Free(mCtx)); + mCtx = NULL; #endif } -void AecFilter::fromMic(void *data) +void AecFilter::fromMic(void* data) { #ifdef USE_SPEEX_AEC - short* output = (short*)alloca(Format().sizeFromTime(AUDIO_MIC_BUFFER_LENGTH)); - speex_echo_capture((SpeexEchoState*)mCtx, (short*)data, (short*)output); - memmove(data, output, AUDIO_MIC_BUFFER_SIZE); + short* output = (short*)alloca(Format().sizeFromTime(AUDIO_MIC_BUFFER_LENGTH)); + speex_echo_capture((SpeexEchoState*)mCtx, (short*)data, (short*)output); + memmove(data, output, AUDIO_MIC_BUFFER_SIZE); #endif #ifdef USE_WEBRTC_AEC short* inputframe = (short*)ALLOCA(framesize); - memcpy(inputframe, (char*)data+framesize*i, framesize); - CheckWRACode(WebRtcAec_Process(mCtx, (short*)inputframe, NULL, (short*)data+framesize/2*i, NULL, mFrameTime * mRate / 1000, 0,0)); + memcpy(inputframe, (char*)data + framesize * i, framesize); + CheckWRACode(WebRtcAec_Process(mCtx, (short*)inputframe, NULL, (short*)data + framesize / 2 * i, NULL, + mFrameTime * mRate / 1000, 0, 0)); #endif } -void AecFilter::toSpeaker(void *data) +void AecFilter::toSpeaker(void* data) { #ifdef USE_SPEEX_AEC - speex_echo_playback((SpeexEchoState*)mCtx, (short*)data); + speex_echo_playback((SpeexEchoState*)mCtx, (short*)data); #endif #ifdef USE_WEBRTC_AEC - CheckWRACode(WebRtcAec_BufferFarend(mCtx, (short*)data, length / 2 / AUDIO_CHANNELS)); + CheckWRACode(WebRtcAec_BufferFarend(mCtx, (short*)data, length / 2 / AUDIO_CHANNELS)); #endif } int AecFilter::frametime() { - return mFrameTime; + return mFrameTime; } -DenoiseFilter::DenoiseFilter(int rate) -:mRate(rate) +DenoiseFilter::DenoiseFilter(int rate) : mRate(rate) { - mCtx = speex_preprocess_state_init(mRate/100, mRate); + mCtx = speex_preprocess_state_init(mRate / 100, mRate); } DenoiseFilter::~DenoiseFilter() { - if (mCtx) - speex_preprocess_state_destroy((SpeexPreprocessState*)mCtx); + if (mCtx) + speex_preprocess_state_destroy((SpeexPreprocessState*)mCtx); } void DenoiseFilter::fromMic(void* data, int timelength) { - assert(timelength % 10 == 0); - - // Process by 10-ms blocks - spx_int16_t* in = (spx_int16_t*)data; - - for (int blockIndex=0; blockIndex mChannelList; - void processChannel(short* pcm, int nrOfSamples, int channelIndex); - public: + void processChannel(short* pcm, int nrOfSamples, int channelIndex); + +public: AgcFilter(int channels); ~AgcFilter(); - - void process(void* pcm, int length); - }; - class AecFilter - { - public: + void process(void* pcm, int length); +}; + +class AecFilter +{ +public: AecFilter(int tailTime, int frameTime, int rate); ~AecFilter(); // These methods accept input block with timelength "frameTime" used in constructor. void toSpeaker(void* data); void fromMic(void* data); - int frametime(); - - protected: - void* mCtx; /// The echo canceller context's pointer. - Mutex mGuard; /// Mutex to protect this instance. - int mFrameTime; /// Duration of single audio frame (in milliseconds) - int mRate; - }; + int frametime(); - class DenoiseFilter - { - public: +protected: + void* mCtx; /// The echo canceller context's pointer. + Mutex mGuard; /// Mutex to protect this instance. + int mFrameTime; /// Duration of single audio frame (in milliseconds) + int mRate; +}; + +class DenoiseFilter +{ +public: DenoiseFilter(int rate); ~DenoiseFilter(); void fromMic(void* data, int timelength); - int rate(); + int rate(); - protected: - Mutex mGuard; /// Mutex to protect this instance. - void* mCtx; /// The denoiser context pointer. - int mRate; /// Duration of single audio frame (in milliseconds) - }; +protected: + Mutex mGuard; /// Mutex to protect this instance. + void* mCtx; /// The denoiser context pointer. + int mRate; /// Duration of single audio frame (in milliseconds) +}; -} +} // namespace Audio #endif diff --git a/src/engine/audio/Audio_Resampler.cpp b/src/engine/audio/Audio_Resampler.cpp index c9769f18..2e9cca84 100644 --- a/src/engine/audio/Audio_Resampler.cpp +++ b/src/engine/audio/Audio_Resampler.cpp @@ -17,8 +17,7 @@ namespace Audio { -SpeexResampler::SpeexResampler() -{} +SpeexResampler::SpeexResampler() {} void SpeexResampler::start(int channels, int sourceRate, int destRate) { @@ -35,8 +34,8 @@ void SpeexResampler::start(int channels, int sourceRate, int destRate) if (sourceRate != destRate) { // Defer context creation until first request - //mContext = speex_resampler_init(channels, sourceRate, destRate, AUDIO_RESAMPLER_QUALITY, &mErrorCode); - //assert(mContext != NULL); + // mContext = speex_resampler_init(channels, sourceRate, destRate, AUDIO_RESAMPLER_QUALITY, &mErrorCode); + // assert(mContext != NULL); } } @@ -59,8 +58,8 @@ SpeexResampler::~SpeexResampler() stop(); } -size_t SpeexResampler::processBuffer(const void* src, size_t sourceLength, size_t& sourceProcessed, - void* dest, size_t destCapacity) +size_t SpeexResampler::processBuffer(const void* src, size_t sourceLength, size_t& sourceProcessed, void* dest, + size_t destCapacity) { assert(mSourceRate != 0 && mDestRate != 0); @@ -77,8 +76,7 @@ size_t SpeexResampler::processBuffer(const void* src, size_t sourceLength, size_ if (!mContext) { - mContext = speex_resampler_init(mChannels, mSourceRate, mDestRate, - AUDIO_RESAMPLER_QUALITY, &mErrorCode); + mContext = speex_resampler_init(mChannels, mSourceRate, mDestRate, AUDIO_RESAMPLER_QUALITY, &mErrorCode); if (!mContext) return 0; } @@ -103,11 +101,9 @@ size_t SpeexResampler::processBuffer(const void* src, size_t sourceLength, size_ unsigned inLen = sourceLength / (sizeof(short) * mChannels); outLen /= sizeof(short) * mChannels; assert(mContext != NULL); - spx_uint32_t in_len = static_cast(inLen), - out_len = static_cast(outLen); + spx_uint32_t in_len = static_cast(inLen), out_len = static_cast(outLen); - int speexCode = speex_resampler_process_interleaved_int((SpeexResamplerState *)mContext, - (spx_int16_t*)src, &in_len, + int speexCode = speex_resampler_process_interleaved_int((SpeexResamplerState*)mContext, (spx_int16_t*)src, &in_len, (spx_int16_t*)dest, &out_len); assert(speexCode == RESAMPLER_ERR_SUCCESS); @@ -147,27 +143,27 @@ size_t SpeexResampler::getSize() const } // -------------------------- ChannelConverter -------------------- -int ChannelConverter::stereoToMono(const void *source, int sourceLength, void *dest, int destLength) +int ChannelConverter::stereoToMono(const void* source, int sourceLength, void* dest, int destLength) { assert(destLength == sourceLength / 2); const short* input = (const short*)source; - short* output = (short*)dest; - for (int sampleIndex = 0; sampleIndex < destLength/2; sampleIndex++) + short* output = (short*)dest; + for (int sampleIndex = 0; sampleIndex < destLength / 2; sampleIndex++) { - output[sampleIndex] = (input[sampleIndex*2] + input[sampleIndex*2+1]) >> 1; + output[sampleIndex] = (input[sampleIndex * 2] + input[sampleIndex * 2 + 1]) >> 1; } return sourceLength / 2; } -int ChannelConverter::monoToStereo(const void *source, int sourceLength, void *dest, int destLength) +int ChannelConverter::monoToStereo(const void* source, int sourceLength, void* dest, int destLength) { - assert (destLength == sourceLength * 2); + assert(destLength == sourceLength * 2); const short* input = (const short*)source; - short* output = (short*)dest; + short* output = (short*)dest; // Convert starting from the end of buffer to allow inplace conversion - for (int sampleIndex = sourceLength/2 - 1; sampleIndex >= 0; sampleIndex--) + for (int sampleIndex = sourceLength / 2 - 1; sampleIndex >= 0; sampleIndex--) { - output[2*sampleIndex] = output[2*sampleIndex+1] = input[sampleIndex]; + output[2 * sampleIndex] = output[2 * sampleIndex + 1] = input[sampleIndex]; } return sourceLength * 2; } @@ -184,13 +180,14 @@ Resampler48kTo16k::~Resampler48kTo16k() WebRtcSpl_ResetResample48khzTo16khz(&mContext); } -int Resampler48kTo16k::process(const void *source, int sourceLen, void *dest, int destLen) +int Resampler48kTo16k::process(const void* source, int sourceLen, void* dest, int destLen) { - const short* input = (const short*)source; int inputLen = sourceLen / 2; - short* output = (short*)dest; //int outputCapacity = destLen / 2; + const short* input = (const short*)source; + int inputLen = sourceLen / 2; + short* output = (short*)dest; // int outputCapacity = destLen / 2; assert(inputLen % 480 == 0); int frames = inputLen / 480; - for (int i=0; i(); @@ -289,4 +278,4 @@ PResampler UniversalResampler::findResampler(int sourceRate, int destRate) return r; } -} // end of namespace +} // namespace Audio diff --git a/src/engine/audio/Audio_Resampler.h b/src/engine/audio/Audio_Resampler.h index 494a3842..e7b7e589 100644 --- a/src/engine/audio/Audio_Resampler.h +++ b/src/engine/audio/Audio_Resampler.h @@ -7,100 +7,99 @@ #define __AUDIO_RESAMPLER_H #ifdef USE_WEBRTC_RESAMPLER -# include "signal_processing_library/signal_processing_library.h" +#include "signal_processing_library/signal_processing_library.h" #endif #include #include #include -namespace Audio +namespace Audio { - class SpeexResampler - { - public: - SpeexResampler(); - ~SpeexResampler(); +class SpeexResampler +{ +public: + SpeexResampler(); + ~SpeexResampler(); - void start(int channels, int sourceRate, int destRate); - void stop(); - bool isOpened() const; + void start(int channels, int sourceRate, int destRate); + void stop(); + bool isOpened() const; - size_t processBuffer(const void* source, size_t sourceLength, size_t& sourceProcessed, - void* dest, size_t destCapacity); - int sourceRate() const; - int destRate() const; - size_t getDestLength(size_t sourceLen) const; - size_t getSourceLength(size_t destLen) const; + size_t processBuffer(const void* source, size_t sourceLength, size_t& sourceProcessed, void* dest, + size_t destCapacity); + int sourceRate() const; + int destRate() const; + size_t getDestLength(size_t sourceLen) const; + size_t getSourceLength(size_t destLen) const; - // Returns instance + speex encoder size in bytes - size_t getSize() const; + // Returns instance + speex encoder size in bytes + size_t getSize() const; - protected: - void* mContext = nullptr; - int mErrorCode = 0; - int mSourceRate = 0, - mDestRate = 0, - mChannels = 0; - short mLastSample = 0; - }; +protected: + void* mContext = nullptr; + int mErrorCode = 0; + int mSourceRate = 0, mDestRate = 0, mChannels = 0; + short mLastSample = 0; +}; - typedef SpeexResampler Resampler; - typedef std::shared_ptr PResampler; +typedef SpeexResampler Resampler; +typedef std::shared_ptr PResampler; - class ChannelConverter - { - public: - static int stereoToMono(const void* source, int sourceLength, void* dest, int destLength); - static int monoToStereo(const void* source, int sourceLength, void* dest, int destLength); - }; +class ChannelConverter +{ +public: + static int stereoToMono(const void* source, int sourceLength, void* dest, int destLength); + static int monoToStereo(const void* source, int sourceLength, void* dest, int destLength); +}; - // Operates with AUDIO_CHANNELS number of channels - class UniversalResampler - { - public: - UniversalResampler(); - ~UniversalResampler(); +// Operates with AUDIO_CHANNELS number of channels +class UniversalResampler +{ +public: + UniversalResampler(); + ~UniversalResampler(); - size_t resample(int sourceRate, const void* sourceBuffer, size_t sourceLength, size_t& sourceProcessed, - int destRate, void* destBuffer, size_t destCapacity); - size_t getDestLength(int sourceRate, int destRate, size_t sourceLength); - size_t getSourceLength(int sourceRate, int destRate, size_t destLength); + size_t resample(int sourceRate, const void* sourceBuffer, size_t sourceLength, size_t& sourceProcessed, + int destRate, void* destBuffer, size_t destCapacity); + size_t getDestLength(int sourceRate, int destRate, size_t sourceLength); + size_t getSourceLength(int sourceRate, int destRate, size_t destLength); - protected: - typedef std::pair RatePair; - typedef std::map ResamplerMap; - ResamplerMap mResamplerMap; - PResampler findResampler(int sourceRate, int destRate); +protected: + typedef std::pair RatePair; + typedef std::map ResamplerMap; + ResamplerMap mResamplerMap; + PResampler findResampler(int sourceRate, int destRate); - void preload(); - }; + void preload(); +}; - #ifdef USE_WEBRTC_RESAMPLER - // n*10 milliseconds buffers required! - class Resampler48kTo16k - { - public: - Resampler48kTo16k(); - ~Resampler48kTo16k(); - int process(const void* source, int sourceLen, void* dest, int destLen); - protected: - WebRtc_Word32 mTemp[496]; - WebRtcSpl_State48khzTo16khz mContext; - }; +#ifdef USE_WEBRTC_RESAMPLER +// n*10 milliseconds buffers required! +class Resampler48kTo16k +{ +public: + Resampler48kTo16k(); + ~Resampler48kTo16k(); + int process(const void* source, int sourceLen, void* dest, int destLen); - class Resampler16kto48k - { - public: - Resampler16kto48k(); - ~Resampler16kto48k(); - int process(const void* source, int sourceLen, void* dest, int destLen); +protected: + WebRtc_Word32 mTemp[496]; + WebRtcSpl_State48khzTo16khz mContext; +}; - protected: - WebRtc_Word32 mTemp[336]; - WebRtcSpl_State16khzTo48khz mContext; - }; - #endif -} // end of namespace +class Resampler16kto48k +{ +public: + Resampler16kto48k(); + ~Resampler16kto48k(); + int process(const void* source, int sourceLen, void* dest, int destLen); + +protected: + WebRtc_Word32 mTemp[336]; + WebRtcSpl_State16khzTo48khz mContext; +}; +#endif +} // namespace Audio #endif diff --git a/src/engine/audio/Audio_WavFile.cpp b/src/engine/audio/Audio_WavFile.cpp index 1609dc59..901ac060 100644 --- a/src/engine/audio/Audio_WavFile.cpp +++ b/src/engine/audio/Audio_WavFile.cpp @@ -13,13 +13,14 @@ #include #ifndef WORD -# define WORD unsigned short +#define WORD unsigned short #endif #ifndef DWORD -# define DWORD unsigned int +#define DWORD unsigned int #endif -typedef struct { +typedef struct +{ WORD wFormatTag; WORD nChannels; DWORD nSamplesPerSec; @@ -27,8 +28,7 @@ typedef struct { WORD nBlockAlign; WORD wBitsPerSample; WORD cbSize; -} -WaveFormatEx; +} WaveFormatEx; #define WAVE_FORMAT_PCM 1 @@ -39,17 +39,14 @@ WaveFormatEx; using namespace Audio; // ---------------------- WavFileReader ------------------------- -WavFileReader::WavFileReader() - :mSamplerate(0), mLastError(0), mChannels(0), mBits(0), mDataLength(0) +WavFileReader::WavFileReader() : mSamplerate(0), mLastError(0), mChannels(0), mBits(0), mDataLength(0) { mDataOffset = 0; } -WavFileReader::~WavFileReader() -{ -} +WavFileReader::~WavFileReader() {} -#define THROW_READERROR throw Exception(ERR_WAVFILE_FAILED); +#define THROW_READERROR throw Exception(ERR_WAVFILE_FAILED); std::string WavFileReader::readChunk() { @@ -57,7 +54,7 @@ std::string WavFileReader::readChunk() readBuffer(name, 4); std::string result = name; - uint32_t size = 0; + uint32_t size = 0; readBuffer(&size, 4); if (result == "data") @@ -69,7 +66,7 @@ std::string WavFileReader::readChunk() return result; } -void WavFileReader::readBuffer(void* buffer, size_t sz) +void WavFileReader::readBuffer(void* buffer, size_t sz) { auto p = mInput->tellg(); mInput->read(reinterpret_cast(buffer), sz); @@ -122,12 +119,12 @@ bool WavFileReader::open(const std::filesystem::path& p) uint32_t fmtSize = 0; readBuffer(&fmtSize, sizeof(fmtSize)); - auto fmtStart = mInput->tellg(); + auto fmtStart = mInput->tellg(); - uint16_t formattag = 0; + uint16_t formattag = 0; readBuffer(&formattag, sizeof(formattag)); - if (formattag != 1/*WAVE_FORMAT_PCM*/) + if (formattag != 1 /*WAVE_FORMAT_PCM*/) THROW_READERROR; mChannels = 0; @@ -168,7 +165,7 @@ bool WavFileReader::open(const std::filesystem::path& p) mDataOffset = mInput->tellg(); mResampler.start(AUDIO_CHANNELS, mSamplerate, AUDIO_SAMPLERATE); } - catch(...) + catch (...) { mInput.reset(); mLastError = static_cast(-1); @@ -211,8 +208,8 @@ size_t WavFileReader::read(short* buffer, size_t samples) // Get number of samples that must be read from source file size_t requiredBytes = mResampler.getSourceLength(samples) * mChannels * mBits / 8; - bool useHeap = requiredBytes > sizeof mTempBuffer; - void* temp; + bool useHeap = requiredBytes > sizeof mTempBuffer; + void* temp; if (useHeap) temp = malloc(requiredBytes); else @@ -223,19 +220,18 @@ size_t WavFileReader::read(short* buffer, size_t samples) // Find required size of input buffer if (mDataLength) { - auto filePosition = mInput->tellg(); + auto filePosition = mInput->tellg(); // Check how much data we can read std::streamoff dataEnd = std::streamoff(mDataLength) + mDataOffset; - size_t fileAvailable = filePosition < dataEnd ? size_t(dataEnd - filePosition) : 0; + size_t fileAvailable = filePosition < dataEnd ? size_t(dataEnd - filePosition) : 0; requiredBytes = fileAvailable < requiredBytes ? fileAvailable : requiredBytes; } size_t readBytes = tryReadBuffer(temp, requiredBytes); size_t processedBytes = 0; - size_t result = mResampler.processBuffer(temp, readBytes, processedBytes, - buffer, samples * 2 * AUDIO_CHANNELS); + size_t result = mResampler.processBuffer(temp, readBytes, processedBytes, buffer, samples * 2 * AUDIO_CHANNELS); if (useHeap) free(temp); @@ -256,11 +252,11 @@ size_t WavFileReader::readRaw(short* buffer, size_t samples) // Find required size of input buffer if (mDataLength) { - auto filePosition = mInput->tellg(); + auto filePosition = mInput->tellg(); // Check how much data we can read std::streamoff dataEnd = std::streamoff(mDataLength) + mDataOffset; - size_t fileAvailable = filePosition < dataEnd ? size_t(dataEnd - filePosition) : 0; + size_t fileAvailable = filePosition < dataEnd ? size_t(dataEnd - filePosition) : 0; requiredBytes = fileAvailable < requiredBytes ? fileAvailable : requiredBytes; } @@ -302,11 +298,9 @@ unsigned WavFileReader::lastError() const // ------------------------- WavFileWriter ------------------------- #define LOG_SUBSYTEM "WavFileWriter" -#define BITS_PER_CHANNEL 16 +#define BITS_PER_CHANNEL 16 -WavFileWriter::WavFileWriter() - :mLengthOffset(0), mSamplerate(AUDIO_SAMPLERATE), mChannels(1), mWritten(0) -{} +WavFileWriter::WavFileWriter() : mLengthOffset(0), mSamplerate(AUDIO_SAMPLERATE), mChannels(1), mWritten(0) {} WavFileWriter::~WavFileWriter() { @@ -358,7 +352,8 @@ bool WavFileWriter::open(const std::filesystem::path& p, int samplerate, int cha writeBuffer(wavefmt, 8); // Set the format description - uint32_t dwFmtSize = 16; /*= 16L*/; + uint32_t dwFmtSize = 16; /*= 16L*/ + ; writeBuffer(&dwFmtSize, sizeof(dwFmtSize)); WaveFormatEx format; @@ -384,7 +379,7 @@ bool WavFileWriter::open(const std::filesystem::path& p, int samplerate, int cha writeBuffer(data, 4); mPath = p; - mWritten = 0; + mWritten = 0; mLengthOffset = mOutput->tellp(); writeBuffer(&mWritten, sizeof mWritten); @@ -435,4 +430,3 @@ std::filesystem::path WavFileWriter::path() const LOCK; return mPath; } - diff --git a/src/engine/audio/Audio_WavFile.h b/src/engine/audio/Audio_WavFile.h index 4d342241..f5fe158a 100644 --- a/src/engine/audio/Audio_WavFile.h +++ b/src/engine/audio/Audio_WavFile.h @@ -22,45 +22,45 @@ namespace Audio class WavFileReader { protected: - uint16_t mChannels = 0; - uint16_t mBits = 0; - int mSamplerate = 0; - std::filesystem::path mPath; - mutable std::recursive_mutex mFileMtx; - size_t mDataOffset = 0; - size_t mDataLength = 0; - Resampler mResampler; - unsigned mLastError = 0; - std::unique_ptr mInput; - uint8_t mTempBuffer[16384]; + uint16_t mChannels = 0; + uint16_t mBits = 0; + int mSamplerate = 0; + std::filesystem::path mPath; + mutable std::recursive_mutex mFileMtx; + size_t mDataOffset = 0; + size_t mDataLength = 0; + Resampler mResampler; + unsigned mLastError = 0; + std::unique_ptr mInput; + uint8_t mTempBuffer[16384]; - std::string readChunk(); - void readBuffer(void* buffer, size_t sz); // This raises an exception if sz bytes are not read - size_t tryReadBuffer(void* buffer, size_t sz); // This doesn't raise an exception + std::string readChunk(); + void readBuffer(void* buffer, size_t sz); // This raises an exception if sz bytes are not read + size_t tryReadBuffer(void* buffer, size_t sz); // This doesn't raise an exception public: WavFileReader(); ~WavFileReader(); - bool open(const std::filesystem::path& p); - void close(); - bool isOpened(); - void rewind(); - int samplerate() const; - int channels() const; + bool open(const std::filesystem::path& p); + void close(); + bool isOpened(); + void rewind(); + int samplerate() const; + int channels() const; // This method returns number of read bytes - size_t read(void* buffer, size_t bytes); - size_t readRaw(void* buffer, size_t bytes); + size_t read(void* buffer, size_t bytes); + size_t readRaw(void* buffer, size_t bytes); // This method returns number of read samples - size_t read(short* buffer, size_t samples); - size_t readRaw(short* buffer, size_t samples); + size_t read(short* buffer, size_t samples); + size_t readRaw(short* buffer, size_t samples); std::filesystem::path path() const; - size_t size() const; + size_t size() const; - unsigned lastError() const; + unsigned lastError() const; }; typedef std::shared_ptr PWavFileReader; @@ -68,29 +68,29 @@ typedef std::shared_ptr PWavFileReader; class WavFileWriter { protected: - std::unique_ptr mOutput; /// Handle of audio file. - std::filesystem::path mPath; /// Path to requested audio file. - mutable std::recursive_mutex mFileMtx; /// Mutex to protect this instance. - size_t mWritten = 0; /// Amount of written data (in bytes) - size_t mLengthOffset = 0; /// Position of length field. - int mSamplerate = 0, - mChannels = 0; + std::unique_ptr mOutput; /// Handle of audio file. + std::filesystem::path mPath; /// Path to requested audio file. + mutable std::recursive_mutex mFileMtx; /// Mutex to protect this instance. + size_t mWritten = 0; /// Amount of written data (in bytes) + size_t mLengthOffset = 0; /// Position of length field. + int mSamplerate = 0, mChannels = 0; + + void checkWriteResult(int result); + void writeBuffer(const void* buffer, size_t sz); - void checkWriteResult(int result); - void writeBuffer(const void* buffer, size_t sz); public: WavFileWriter(); ~WavFileWriter(); - bool open(const std::filesystem::path& p, int samplerate, int channels); - void close(); - bool isOpened() const; - size_t write(const void* buffer, size_t bytes); + bool open(const std::filesystem::path& p, int samplerate, int channels); + void close(); + bool isOpened() const; + size_t write(const void* buffer, size_t bytes); std::filesystem::path path() const; }; typedef std::shared_ptr PWavFileWriter; -} +} // namespace Audio #endif diff --git a/src/engine/audio/Audio_Wmme.cpp b/src/engine/audio/Audio_Wmme.cpp index f463f815..98e4450c 100644 --- a/src/engine/audio/Audio_Wmme.cpp +++ b/src/engine/audio/Audio_Wmme.cpp @@ -15,541 +15,540 @@ using namespace Audio; WmmeInputDevice::Buffer::Buffer() { - // Do not use WAVEHDR allocated on stack! - mHeaderHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, sizeof WAVEHDR); - if (!mHeaderHandle) - throw Exception(ERR_WMME_FAILED, GetLastError()); - mHeader = (WAVEHDR*)GlobalLock(mHeaderHandle); + // Do not use WAVEHDR allocated on stack! + mHeaderHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, sizeof WAVEHDR); + if (!mHeaderHandle) + throw Exception(ERR_WMME_FAILED, GetLastError()); + mHeader = (WAVEHDR*)GlobalLock(mHeaderHandle); - mDataHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, AUDIO_MIC_BUFFER_SIZE); - if (!mDataHandle) - throw Exception(ERR_WMME_FAILED, GetLastError()); - mData = GlobalLock(mDataHandle); - - memset(mHeader, 0, sizeof *mHeader); - mHeader->dwBufferLength = AUDIO_MIC_BUFFER_SIZE; - mHeader->dwFlags = 0; - mHeader->lpData = (LPSTR)mData; + mDataHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, AUDIO_MIC_BUFFER_SIZE); + if (!mDataHandle) + throw Exception(ERR_WMME_FAILED, GetLastError()); + mData = GlobalLock(mDataHandle); + + memset(mHeader, 0, sizeof *mHeader); + mHeader->dwBufferLength = AUDIO_MIC_BUFFER_SIZE; + mHeader->dwFlags = 0; + mHeader->lpData = (LPSTR)mData; } WmmeInputDevice::Buffer::~Buffer() { - if (mDataHandle) - { - GlobalUnlock(mDataHandle); - GlobalFree(mDataHandle); - } - if (mHeaderHandle) - { - GlobalUnlock(mHeaderHandle); - GlobalFree(mHeaderHandle); - } - + if (mDataHandle) + { + GlobalUnlock(mDataHandle); + GlobalFree(mDataHandle); + } + if (mHeaderHandle) + { + GlobalUnlock(mHeaderHandle); + GlobalFree(mHeaderHandle); + } } bool WmmeInputDevice::Buffer::prepare(HWAVEIN device) { - MMRESULT resCode = MMSYSERR_NOERROR; - mHeader->dwFlags = 0; - mHeader->dwBufferLength = AUDIO_MIC_BUFFER_SIZE; - mHeader->lpData = (LPSTR)mData; + MMRESULT resCode = MMSYSERR_NOERROR; + mHeader->dwFlags = 0; + mHeader->dwBufferLength = AUDIO_MIC_BUFFER_SIZE; + mHeader->lpData = (LPSTR)mData; - resCode = waveInPrepareHeader(device, mHeader, sizeof *mHeader); - //if (resCode != MMSYSERR_NOERROR) - // LogCritical("Audio", << "Failed to prepare source header. Error code " << resCode << "."); + resCode = waveInPrepareHeader(device, mHeader, sizeof *mHeader); + // if (resCode != MMSYSERR_NOERROR) + // LogCritical("Audio", << "Failed to prepare source header. Error code " << resCode << "."); - return resCode == MMSYSERR_NOERROR; + return resCode == MMSYSERR_NOERROR; } bool WmmeInputDevice::Buffer::unprepare(HWAVEIN device) { - if (mHeader->dwFlags & WHDR_PREPARED) - { - MMRESULT resCode = waveInUnprepareHeader(device, mHeader, sizeof *mHeader); - //if (resCode != MMSYSERR_NOERROR) - // LogCritical("Audio", << "Failed to unprepare source header. Error code " << resCode << "."); - return resCode == MMSYSERR_NOERROR; - } - return true; + if (mHeader->dwFlags & WHDR_PREPARED) + { + MMRESULT resCode = waveInUnprepareHeader(device, mHeader, sizeof *mHeader); + // if (resCode != MMSYSERR_NOERROR) + // LogCritical("Audio", << "Failed to unprepare source header. Error code " << resCode << "."); + return resCode == MMSYSERR_NOERROR; + } + return true; } bool WmmeInputDevice::Buffer::isFinished() { - return (mHeader->dwFlags & WHDR_DONE) != 0; + return (mHeader->dwFlags & WHDR_DONE) != 0; } bool WmmeInputDevice::Buffer::addToDevice(HWAVEIN device) { - MMRESULT resCode = waveInAddBuffer(device, mHeader, sizeof(*mHeader)); - //if (resCode != MMSYSERR_NOERROR) - // LogCritical("Audio", << "Failed to add buffer to source audio device. Error code is " << resCode << "."); - return resCode == MMSYSERR_NOERROR; + MMRESULT resCode = waveInAddBuffer(device, mHeader, sizeof(*mHeader)); + // if (resCode != MMSYSERR_NOERROR) + // LogCritical("Audio", << "Failed to add buffer to source audio device. Error code is " << resCode << "."); + return resCode == MMSYSERR_NOERROR; } void* WmmeInputDevice::Buffer::data() { - return mData; + return mData; } WmmeInputDevice::WmmeInputDevice(int deviceId) -:mDevHandle(NULL), mDoneSignal(INVALID_HANDLE_VALUE), mFakeMode(false), -mBufferIndex(0), mDeviceIndex(deviceId), mThreadHandle(0) + : mDevHandle(NULL), mDoneSignal(INVALID_HANDLE_VALUE), mFakeMode(false), mBufferIndex(0), mDeviceIndex(deviceId), + mThreadHandle(0) { - mDoneSignal = ::CreateEvent(NULL, FALSE, FALSE, NULL); - mShutdownSignal = ::CreateEvent(NULL, FALSE, FALSE, NULL); - mRefCount = 0; + mDoneSignal = ::CreateEvent(NULL, FALSE, FALSE, NULL); + mShutdownSignal = ::CreateEvent(NULL, FALSE, FALSE, NULL); + mRefCount = 0; } WmmeInputDevice::~WmmeInputDevice() { - close(); - ::CloseHandle(mDoneSignal); - ::CloseHandle(mShutdownSignal); + close(); + ::CloseHandle(mDoneSignal); + ::CloseHandle(mShutdownSignal); } bool WmmeInputDevice::fakeMode() { - return mFakeMode; + return mFakeMode; } -void CALLBACK WmmeInputDevice::callbackProc(HWAVEIN hwi, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) +void CALLBACK WmmeInputDevice::callbackProc(HWAVEIN hwi, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, + DWORD_PTR dwParam2) { - WmmeInputDevice* impl; - switch(uMsg) - { - case WIM_DATA: - impl = (WmmeInputDevice*)dwInstance; - SetEvent(impl->mDoneSignal); - break; + WmmeInputDevice* impl; + switch (uMsg) + { + case WIM_DATA: + impl = (WmmeInputDevice*)dwInstance; + SetEvent(impl->mDoneSignal); + break; - case WIM_CLOSE: - break; + case WIM_CLOSE: + break; - case WIM_OPEN: - break; - } + case WIM_OPEN: + break; + } } void WmmeInputDevice::openDevice() { - // Build WAVEFORMATEX structure - WAVEFORMATEX wfx; - memset(&wfx, 0, sizeof(wfx)); + // Build WAVEFORMATEX structure + WAVEFORMATEX wfx; + memset(&wfx, 0, sizeof(wfx)); - wfx.wFormatTag = WAVE_FORMAT_PCM; - wfx.nChannels = AUDIO_CHANNELS; - wfx.nSamplesPerSec = AUDIO_SAMPLERATE; - wfx.wBitsPerSample = 16; - wfx.cbSize = 0; - wfx.nBlockAlign = wfx.wBitsPerSample * wfx.nChannels / 8; - wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec; - - // Open wavein - - MMRESULT mmres = waveInOpen(&mDevHandle, mDeviceIndex, &wfx, (DWORD_PTR)callbackProc, (DWORD_PTR)this, CALLBACK_FUNCTION); - if (mmres != MMSYSERR_NOERROR) - { - mFakeMode = true; - return; - } - else - mFakeMode = false; + wfx.wFormatTag = WAVE_FORMAT_PCM; + wfx.nChannels = AUDIO_CHANNELS; + wfx.nSamplesPerSec = AUDIO_SAMPLERATE; + wfx.wBitsPerSample = 16; + wfx.cbSize = 0; + wfx.nBlockAlign = wfx.wBitsPerSample * wfx.nChannels / 8; + wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec; - // Create the buffers for running - mBufferIndex = 0; - for (int i=0; i 1) + Lock lock(mGuard); + + mRefCount++; + if (mRefCount > 1) + return true; + + mThreadHandle = (HANDLE)_beginthread(&threadProc, 0, this); return true; - - mThreadHandle = (HANDLE)_beginthread(&threadProc, 0, this); - return true; } void WmmeInputDevice::closeDevice() { - // Stop device - if (mDevHandle) - { - MMRESULT mmres = MMSYSERR_NOERROR; - waveInReset(mDevHandle); - waveInStop(mDevHandle); - } - - // Close buffers - for (int i=0; iopenDevice(); - void* buffer = _alloca(AUDIO_MIC_BUFFER_SIZE); + WmmeInputDevice* impl = (WmmeInputDevice*)arg; + impl->openDevice(); + void* buffer = _alloca(AUDIO_MIC_BUFFER_SIZE); - DWORD waitResult = 0; - HANDLE waitArray[2] = {impl->mDoneSignal, impl->mShutdownSignal}; - DWORD wr; - do - { - wr = ::WaitForMultipleObjects(2, waitArray, FALSE, INFINITE); - - if (wr == WAIT_OBJECT_0) + DWORD waitResult = 0; + HANDLE waitArray[2] = {impl->mDoneSignal, impl->mShutdownSignal}; + DWORD wr; + do { - impl->readBuffer(buffer); - if (impl->connection()) - impl->connection()->onMicData(Format(), buffer, AUDIO_MIC_BUFFER_SIZE); - } - } while (wr == WAIT_OBJECT_0); + wr = ::WaitForMultipleObjects(2, waitArray, FALSE, INFINITE); - impl->closeDevice(); + if (wr == WAIT_OBJECT_0) + { + impl->readBuffer(buffer); + if (impl->connection()) + impl->connection()->onMicData(Format(), buffer, AUDIO_MIC_BUFFER_SIZE); + } + } while (wr == WAIT_OBJECT_0); + + impl->closeDevice(); } // --- WmmeOutputDevice --- -WmmeOutputDevice::Buffer::Buffer() -:mHeaderHandle(NULL), mDataHandle(NULL), mData(NULL), mHeader(NULL) +WmmeOutputDevice::Buffer::Buffer() : mHeaderHandle(NULL), mDataHandle(NULL), mData(NULL), mHeader(NULL) { - mHeaderHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, AUDIO_SPK_BUFFER_SIZE); - if (!mHeaderHandle) - throw Exception(ERR_NOMEM); + mHeaderHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, AUDIO_SPK_BUFFER_SIZE); + if (!mHeaderHandle) + throw Exception(ERR_NOMEM); - mDataHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, AUDIO_SPK_BUFFER_SIZE); - if (!mDataHandle) - throw Exception(ERR_NOMEM); + mDataHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, AUDIO_SPK_BUFFER_SIZE); + if (!mDataHandle) + throw Exception(ERR_NOMEM); - mHeader = (WAVEHDR*)GlobalLock(mHeaderHandle); - mData = GlobalLock(mDataHandle); - memset(mHeader, 0, sizeof *mHeader); - mHeader->dwBufferLength = AUDIO_SPK_BUFFER_SIZE; - mHeader->lpData = (LPSTR)mData; + mHeader = (WAVEHDR*)GlobalLock(mHeaderHandle); + mData = GlobalLock(mDataHandle); + memset(mHeader, 0, sizeof *mHeader); + mHeader->dwBufferLength = AUDIO_SPK_BUFFER_SIZE; + mHeader->lpData = (LPSTR)mData; } WmmeOutputDevice::Buffer::~Buffer() { - if (mHeaderHandle) - { - GlobalUnlock(mHeaderHandle); - GlobalFree(mHeaderHandle); - } - if (mDataHandle) - { - GlobalUnlock(mDataHandle); - GlobalFree(mDataHandle); - } + if (mHeaderHandle) + { + GlobalUnlock(mHeaderHandle); + GlobalFree(mHeaderHandle); + } + if (mDataHandle) + { + GlobalUnlock(mDataHandle); + GlobalFree(mDataHandle); + } } bool WmmeOutputDevice::Buffer::prepare(HWAVEOUT device) { - MMRESULT result; - result = ::waveOutPrepareHeader(device, mHeader, sizeof *mHeader); - return result == MMSYSERR_NOERROR; + MMRESULT result; + result = ::waveOutPrepareHeader(device, mHeader, sizeof *mHeader); + return result == MMSYSERR_NOERROR; } bool WmmeOutputDevice::Buffer::unprepare(HWAVEOUT device) { - MMRESULT result; - result = ::waveOutUnprepareHeader(device, mHeader, sizeof *mHeader); - return result == MMSYSERR_NOERROR; + MMRESULT result; + result = ::waveOutUnprepareHeader(device, mHeader, sizeof *mHeader); + return result == MMSYSERR_NOERROR; } bool WmmeOutputDevice::Buffer::write(HWAVEOUT device) { - MMRESULT result; - result = ::waveOutWrite(device, mHeader, sizeof *mHeader); - return result == MMSYSERR_NOERROR; + MMRESULT result; + result = ::waveOutWrite(device, mHeader, sizeof *mHeader); + return result == MMSYSERR_NOERROR; } WmmeOutputDevice::WmmeOutputDevice(int index) -:mDevice(NULL), mDeviceIndex(index), mPlayedTime(0), mPlayedCount(0), mBufferIndex(0), mThreadHandle(NULL), -mFailed(false), mShutdownMarker(false) + : mDevice(NULL), mDeviceIndex(index), mPlayedTime(0), mPlayedCount(0), mBufferIndex(0), mThreadHandle(NULL), + mFailed(false), mShutdownMarker(false) { - mDoneSignal = ::CreateEvent(NULL, FALSE, FALSE, NULL); - mShutdownSignal = ::CreateEvent(NULL, FALSE, FALSE, NULL); + mDoneSignal = ::CreateEvent(NULL, FALSE, FALSE, NULL); + mShutdownSignal = ::CreateEvent(NULL, FALSE, FALSE, NULL); } WmmeOutputDevice::~WmmeOutputDevice() { - close(); + close(); - // Destroy used signals - CloseHandle(mDoneSignal); CloseHandle(mShutdownSignal); + // Destroy used signals + CloseHandle(mDoneSignal); + CloseHandle(mShutdownSignal); } bool WmmeOutputDevice::open() { - // Start thread - mThreadHandle = (HANDLE)_beginthread(&threadProc, 0, this); - return true; + // Start thread + mThreadHandle = (HANDLE)_beginthread(&threadProc, 0, this); + return true; } void WmmeOutputDevice::close() { - // Tell the thread to exit - SetEvent(mShutdownSignal); - mShutdownMarker = true; + // Tell the thread to exit + SetEvent(mShutdownSignal); + mShutdownMarker = true; - // Wait for thread - if (mThreadHandle) - WaitForSingleObject(mThreadHandle, INFINITE); - mThreadHandle = 0; + // Wait for thread + if (mThreadHandle) + WaitForSingleObject(mThreadHandle, INFINITE); + mThreadHandle = 0; } void WmmeOutputDevice::openDevice() { - mClosing = false; - MMRESULT mmres = 0; - WAVEFORMATEX wfx; - memset(&wfx, 0, sizeof(wfx)); - wfx.wFormatTag = 0x0001; - wfx.nChannels = AUDIO_CHANNELS; - wfx.nSamplesPerSec = AUDIO_SAMPLERATE; - wfx.wBitsPerSample = 16; - wfx.cbSize = 0; - wfx.nBlockAlign = wfx.wBitsPerSample * wfx.nChannels / 8; - wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec; + mClosing = false; + MMRESULT mmres = 0; + WAVEFORMATEX wfx; + memset(&wfx, 0, sizeof(wfx)); + wfx.wFormatTag = 0x0001; + wfx.nChannels = AUDIO_CHANNELS; + wfx.nSamplesPerSec = AUDIO_SAMPLERATE; + wfx.wBitsPerSample = 16; + wfx.cbSize = 0; + wfx.nBlockAlign = wfx.wBitsPerSample * wfx.nChannels / 8; + wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec; - mmres = waveOutOpen(&mDevice, mDeviceIndex, &wfx, (DWORD_PTR)&callbackProc, (DWORD_PTR)this, CALLBACK_FUNCTION); - if (mmres != MMSYSERR_NOERROR) - throw Exception(ERR_WMME_FAILED, mmres); + mmres = waveOutOpen(&mDevice, mDeviceIndex, &wfx, (DWORD_PTR)&callbackProc, (DWORD_PTR)this, CALLBACK_FUNCTION); + if (mmres != MMSYSERR_NOERROR) + throw Exception(ERR_WMME_FAILED, mmres); - // Prebuffer silence - for (unsigned i=0; idwFlags & WHDR_DONE || - !mBufferList[i].mHeader->dwFlags; - if (finished) + Lock l(mGuard); + bool result = true; + for (unsigned i = 0; i < AUDIO_SPK_BUFFER_COUNT && result; i++) { -/* if (mBufferList[i].mHeader->dwFlags & WHDR_PREPARED) - mBufferList[i].Unprepare(mDevice); */ + bool finished = mBufferList[i].mHeader->dwFlags & WHDR_DONE || !mBufferList[i].mHeader->dwFlags; + if (finished) + { + /* if (mBufferList[i].mHeader->dwFlags & WHDR_PREPARED) + mBufferList[i].Unprepare(mDevice); */ + } + result &= finished; } - result &= finished; - } - return result; + return result; } void WmmeOutputDevice::threadProc(void* arg) { - WmmeOutputDevice* impl = (WmmeOutputDevice*)arg; - impl->openDevice(); + WmmeOutputDevice* impl = (WmmeOutputDevice*)arg; + impl->openDevice(); - DWORD waitResult = 0; - HANDLE waitArray[2] = {impl->mDoneSignal, impl->mShutdownSignal}; - unsigned index, i; - unsigned exitCount = 0; - bool exitSignal = false; - do - { - // Poll for exit signal - if (!exitSignal) - exitSignal = impl->mShutdownMarker; - - // Wait for played buffer - WaitForSingleObject(impl->mDoneSignal, 500); - - // Iterate buffers to find played - for (i=0; imDoneSignal, impl->mShutdownSignal}; + unsigned index, i; + unsigned exitCount = 0; + bool exitSignal = false; + do { - index = (impl->mBufferIndex + i) % AUDIO_SPK_BUFFER_COUNT; - Buffer& buffer = impl->mBufferList[index]; - if (!(buffer.mHeader->dwFlags & WHDR_DONE)) - break; - - buffer.unprepare(impl->mDevice); - if (!exitSignal) - { - bool useAEC = true; - if (impl->connection()) - impl->connection()->onSpkData(Format(), buffer.mData, AUDIO_SPK_BUFFER_SIZE); - else - memset(buffer.mData, 0, AUDIO_SPK_BUFFER_SIZE); - - buffer.prepare(impl->mDevice); - buffer.write(impl->mDevice); - } - else - exitCount++; - } - impl->mBufferIndex = (impl->mBufferIndex + i) % AUDIO_SPK_BUFFER_COUNT; - } - while (!exitSignal || exitCount < AUDIO_SPK_BUFFER_COUNT); - impl->closeDevice(); + // Poll for exit signal + if (!exitSignal) + exitSignal = impl->mShutdownMarker; + + // Wait for played buffer + WaitForSingleObject(impl->mDoneSignal, 500); + + // Iterate buffers to find played + for (i = 0; i < AUDIO_SPK_BUFFER_COUNT; i++) + { + index = (impl->mBufferIndex + i) % AUDIO_SPK_BUFFER_COUNT; + Buffer& buffer = impl->mBufferList[index]; + if (!(buffer.mHeader->dwFlags & WHDR_DONE)) + break; + + buffer.unprepare(impl->mDevice); + if (!exitSignal) + { + bool useAEC = true; + if (impl->connection()) + impl->connection()->onSpkData(Format(), buffer.mData, AUDIO_SPK_BUFFER_SIZE); + else + memset(buffer.mData, 0, AUDIO_SPK_BUFFER_SIZE); + + buffer.prepare(impl->mDevice); + buffer.write(impl->mDevice); + } + else + exitCount++; + } + impl->mBufferIndex = (impl->mBufferIndex + i) % AUDIO_SPK_BUFFER_COUNT; + } while (!exitSignal || exitCount < AUDIO_SPK_BUFFER_COUNT); + impl->closeDevice(); } HWAVEOUT WmmeOutputDevice::handle() { - return mDevice; + return mDevice; } unsigned WmmeOutputDevice::playedTime() { - if (!mDevice) - return 0; - unsigned result = 0; + if (!mDevice) + return 0; + unsigned result = 0; - MMTIME mmt; - memset(&mmt, 0, sizeof(mmt)); - mmt.wType = TIME_SAMPLES; - MMRESULT rescode = waveOutGetPosition(mDevice, &mmt, sizeof(mmt)); - if (rescode != MMSYSERR_NOERROR || mmt.wType != TIME_SAMPLES) - closeDevice(); - else - { - if (mmt.u.ms < mPlayedTime) - result = 0; + MMTIME mmt; + memset(&mmt, 0, sizeof(mmt)); + mmt.wType = TIME_SAMPLES; + MMRESULT rescode = waveOutGetPosition(mDevice, &mmt, sizeof(mmt)); + if (rescode != MMSYSERR_NOERROR || mmt.wType != TIME_SAMPLES) + closeDevice(); else { - result = mmt.u.ms - mPlayedTime; - mPlayedTime = mmt.u.ms - result % 8; + if (mmt.u.ms < mPlayedTime) + result = 0; + else + { + result = mmt.u.ms - mPlayedTime; + mPlayedTime = mmt.u.ms - result % 8; + } } - } - return result / 8; + return result / 8; } void WmmeOutputDevice::setFakeMode(bool fakemode) { - closeDevice(); + closeDevice(); } bool WmmeOutputDevice::fakeMode() { - return mFailed; + return mFailed; } bool WmmeOutputDevice::closing() { - return mClosing; + return mClosing; } -void CALLBACK WmmeOutputDevice::callbackProc(HWAVEOUT hwo, UINT msg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) +void CALLBACK WmmeOutputDevice::callbackProc(HWAVEOUT hwo, UINT msg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, + DWORD_PTR dwParam2) { - WmmeOutputDevice* impl; + WmmeOutputDevice* impl; - if (msg == WOM_DONE) - { - impl = (WmmeOutputDevice*)dwInstance; - InterlockedIncrement(&impl->mPlayedCount); - SetEvent(impl->mDoneSignal); - } + if (msg == WOM_DONE) + { + impl = (WmmeOutputDevice*)dwInstance; + InterlockedIncrement(&impl->mPlayedCount); + SetEvent(impl->mDoneSignal); + } } #endif diff --git a/src/engine/audio/Audio_Wmme.h b/src/engine/audio/Audio_Wmme.h index ba65f3bc..5304855d 100644 --- a/src/engine/audio/Audio_Wmme.h +++ b/src/engine/audio/Audio_Wmme.h @@ -30,118 +30,118 @@ namespace Audio { - class WmmeInputDevice: public InputDevice - { - public: +class WmmeInputDevice : public InputDevice +{ +public: WmmeInputDevice(int index); ~WmmeInputDevice(); - - bool open(); - void close(); - - bool fakeMode(); - void setFakeMode(bool fakeMode); - - int readBuffer(void* buffer); + + bool open(); + void close(); + + bool fakeMode(); + void setFakeMode(bool fakeMode); + + int readBuffer(void* buffer); HWAVEIN handle(); - protected: +protected: class Buffer { public: - Buffer(); - ~Buffer(); - bool prepare(HWAVEIN device); - bool unprepare(HWAVEIN device); - bool isFinished(); - bool addToDevice(HWAVEIN device); - void* data(); + Buffer(); + ~Buffer(); + bool prepare(HWAVEIN device); + bool unprepare(HWAVEIN device); + bool isFinished(); + bool addToDevice(HWAVEIN device); + void* data(); protected: - HGLOBAL mDataHandle; - void* mData; - HGLOBAL mHeaderHandle; - WAVEHDR* mHeader; + HGLOBAL mDataHandle; + void* mData; + HGLOBAL mHeaderHandle; + WAVEHDR* mHeader; }; - Mutex mGuard; /// Mutex to protect this instance. - HWAVEIN mDevHandle; /// Handle of opened capture device. - HANDLE mThreadHandle; - HANDLE mShutdownSignal; - HANDLE mDoneSignal; /// Event handle to signal about finished capture. - Buffer mBufferList[AUDIO_MIC_BUFFER_COUNT]; - unsigned mBufferIndex; - int mDeviceIndex; /// Index of capture device. - volatile bool mFakeMode; /// Marks if fake mode is active. - int mRefCount; + Mutex mGuard; /// Mutex to protect this instance. + HWAVEIN mDevHandle; /// Handle of opened capture device. + HANDLE mThreadHandle; + HANDLE mShutdownSignal; + HANDLE mDoneSignal; /// Event handle to signal about finished capture. + Buffer mBufferList[AUDIO_MIC_BUFFER_COUNT]; + unsigned mBufferIndex; + int mDeviceIndex; /// Index of capture device. + volatile bool mFakeMode; /// Marks if fake mode is active. + int mRefCount; - bool tryReadBuffer(void* buffer); - void openDevice(); - void closeDevice(); + bool tryReadBuffer(void* buffer); + void openDevice(); + void closeDevice(); - static void CALLBACK callbackProc(HWAVEIN hwi, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2); - static void threadProc(void* arg); - }; + static void CALLBACK callbackProc(HWAVEIN hwi, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, + DWORD_PTR dwParam2); + static void threadProc(void* arg); +}; - class WmmeOutputDevice: public OutputDevice - { - public: +class WmmeOutputDevice : public OutputDevice +{ +public: WmmeOutputDevice(int index); ~WmmeOutputDevice(); - - bool open(); - void close(); - HWAVEOUT handle(); - unsigned playedTime(); - void setFakeMode(bool fakemode); - bool fakeMode(); - bool closing(); + bool open(); + void close(); - protected: + HWAVEOUT handle(); + unsigned playedTime(); + void setFakeMode(bool fakemode); + bool fakeMode(); + bool closing(); + +protected: class Buffer { - friend class WmmeOutputDevice; + friend class WmmeOutputDevice; + public: - Buffer(); - ~Buffer(); - bool prepare(HWAVEOUT device); - bool unprepare(HWAVEOUT device); - bool write(HWAVEOUT device); + Buffer(); + ~Buffer(); + bool prepare(HWAVEOUT device); + bool unprepare(HWAVEOUT device); + bool write(HWAVEOUT device); + protected: - WAVEHDR* mHeader; - void* mData; - HGLOBAL mHeaderHandle; - HGLOBAL mDataHandle; + WAVEHDR* mHeader; + void* mData; + HGLOBAL mHeaderHandle; + HGLOBAL mDataHandle; }; - Mutex mGuard; /// Mutex to protect this instance - int mDeviceIndex; - HWAVEOUT mDevice; /// Handle of opened audio device - Buffer mBufferList[AUDIO_SPK_BUFFER_COUNT]; - unsigned mPlayedTime; /// Amount of played time in milliseconds - bool mClosing; - HANDLE mDoneSignal, - mShutdownSignal, - mThreadHandle; - volatile bool mShutdownMarker; - - volatile LONG mPlayedCount; - unsigned mBufferIndex; - bool mFailed; + Mutex mGuard; /// Mutex to protect this instance + int mDeviceIndex; + HWAVEOUT mDevice; /// Handle of opened audio device + Buffer mBufferList[AUDIO_SPK_BUFFER_COUNT]; + unsigned mPlayedTime; /// Amount of played time in milliseconds + bool mClosing; + HANDLE mDoneSignal, mShutdownSignal, mThreadHandle; + volatile bool mShutdownMarker; - void openDevice(); - void closeDevice(); - bool areBuffersFinished(); + volatile LONG mPlayedCount; + unsigned mBufferIndex; + bool mFailed; - static void CALLBACK callbackProc(HWAVEOUT hwo, UINT msg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2); - static void threadProc(void* arg); - }; + void openDevice(); + void closeDevice(); + bool areBuffersFinished(); + + static void CALLBACK callbackProc(HWAVEOUT hwo, UINT msg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, + DWORD_PTR dwParam2); + static void threadProc(void* arg); +}; - - -} +} // namespace Audio #endif diff --git a/src/engine/audio/Audio_iOS.cpp b/src/engine/audio/Audio_iOS.cpp index be5bb9bc..96f6812a 100644 --- a/src/engine/audio/Audio_iOS.cpp +++ b/src/engine/audio/Audio_iOS.cpp @@ -1,2 +1 @@ #include "Audio_iOS.h" - diff --git a/src/engine/audio/Audio_iOS.h b/src/engine/audio/Audio_iOS.h index 87d346c9..ecae08ce 100644 --- a/src/engine/audio/Audio_iOS.h +++ b/src/engine/audio/Audio_iOS.h @@ -1,38 +1,36 @@ #ifndef __AUDIO_IOS #define __AUDIO_IOS -class IosInputDevice: public InputDevice +class IosInputDevice : public InputDevice { protected: - public: - IosInputDevice(); - ~IosInputDevice(); - - - - void open(); - void close(); + IosInputDevice(); + ~IosInputDevice(); + + + void open(); + void close(); }; -class IosOutputDevice: public OutputDevice +class IosOutputDevice : public OutputDevice { protected: public: - IosOutputDevice(); - ~IosOutputDevice(); - enum - { - Receiver, - Speaker, - Bluetooth - }; - - int route(); - void setRoute(int route); - - void open(); - void close(); + IosOutputDevice(); + ~IosOutputDevice(); + enum + { + Receiver, + Speaker, + Bluetooth + }; + + int route(); + void setRoute(int route); + + void open(); + void close(); }; #endif \ No newline at end of file diff --git a/src/engine/endpoint/EP_Account.cpp b/src/engine/endpoint/EP_Account.cpp index eb916f4a..44dfcbd7 100644 --- a/src/engine/endpoint/EP_Account.cpp +++ b/src/engine/endpoint/EP_Account.cpp @@ -15,49 +15,46 @@ #define CONFIG(X) mConfig->at(X) #define CONFIG_EXISTS(X) mConfig->exists(X) -//#define MODIFY_VIA_BEHIND_NAT +// #define MODIFY_VIA_BEHIND_NAT // NAT decorator -class NATDecorator: public resip::MessageDecorator +class NATDecorator : public resip::MessageDecorator { protected: - UserAgent& mUserAgent; + UserAgent& mUserAgent; resip::SipMessage mMessage; - resip::Data mViaHost; - unsigned short mViaPort; + resip::Data mViaHost; + unsigned short mViaPort; - resip::Data mContactsHost; - resip::Data mContactsScheme; - unsigned short mContactsPort; + resip::Data mContactsHost; + resip::Data mContactsScheme; + unsigned short mContactsPort; public: NATDecorator(UserAgent& endpoint); virtual ~NATDecorator(); - virtual void decorateMessage(resip::SipMessage &msg, const resip::Tuple &source, const resip::Tuple &destination, const resip::Data& sigcompId); - virtual void rollbackMessage(resip::SipMessage& msg); + virtual void decorateMessage(resip::SipMessage& msg, const resip::Tuple& source, const resip::Tuple& destination, + const resip::Data& sigcompId); + virtual void rollbackMessage(resip::SipMessage& msg); virtual MessageDecorator* clone() const; }; -NATDecorator::NATDecorator(UserAgent& ua) - :mUserAgent(ua), mViaPort(0), mContactsPort(0) -{ -} +NATDecorator::NATDecorator(UserAgent& ua) : mUserAgent(ua), mViaPort(0), mContactsPort(0) {} -NATDecorator::~NATDecorator() -{ -} +NATDecorator::~NATDecorator() {} -void NATDecorator::decorateMessage(resip::SipMessage &msg, const resip::Tuple &source, const resip::Tuple &destination, const resip::Data& sigcompId) +void NATDecorator::decorateMessage(resip::SipMessage& msg, const resip::Tuple& source, const resip::Tuple& destination, + const resip::Data& sigcompId) { // Make a copy to allow rollback mMessage = msg; std::stringstream dump; mMessage.encode(dump); - //ICELogDebug(<< "Decorating message: \n" << dump.str()); + // ICELogDebug(<< "Decorating message: \n" << dump.str()); // Check From: header and find the account resip::NameAddr from; @@ -101,11 +98,11 @@ void NATDecorator::decorateMessage(resip::SipMessage &msg, const resip::Tuple &s uri.port() = account->mExternalAddress.port(); if (account->mConfig->at(CONFIG_SIPS).asBool()) { - //uri.scheme() = "sips"; - //uri.param(resip::p_transport) = "tls"; + // uri.scheme() = "sips"; + // uri.param(resip::p_transport) = "tls"; } - //uri.scheme() = account->mConfig->at(CONFIG_SIPS).asBool() ? "sips" : "sip"; + // uri.scheme() = account->mConfig->at(CONFIG_SIPS).asBool() ? "sips" : "sip"; } } } @@ -114,7 +111,7 @@ void NATDecorator::rollbackMessage(resip::SipMessage& msg) { // Check From: header and find the account resip::NameAddr from = msg.header(resip::h_From); - PAccount account = mUserAgent.getAccount(from); + PAccount account = mUserAgent.getAccount(from); if (!account) return; @@ -141,7 +138,7 @@ void NATDecorator::rollbackMessage(resip::SipMessage& msg) { uri.host() = mContactsHost; uri.port() = mContactsPort; - //uri.scheme() = mContactsScheme; + // uri.scheme() = mContactsScheme; } } } @@ -153,19 +150,16 @@ resip::MessageDecorator* NATDecorator::clone() const } Account::Account(PVariantMap config, UserAgent& agent) - :mAgent(agent), mId(0), mConfig(config), mRegistrationState(RegistrationState::None), - mRegistration(NULL) + : mAgent(agent), mId(0), mConfig(config), mRegistrationState(RegistrationState::None), mRegistration(NULL) { mProfile = std::make_shared(agent.mProfile); mId = Account::generateId(); setup(*config); } -Account::~Account() -{ -} +Account::~Account() {} -void Account::setup(VariantMap &config) +void Account::setup(VariantMap& config) { // Credentials @@ -176,8 +170,8 @@ void Account::setup(VariantMap &config) mProfile->setDigestCredential(resip::Data(config[CONFIG_DOMAIN].asStdString()), resip::Data(config[CONFIG_USERNAME].asStdString()), resip::Data(config[CONFIG_PASSWORD].asStdString())); - ICELogInfo( << "Credentials are set to domain " << config[CONFIG_DOMAIN].asStdString() << - ", username to " << config[CONFIG_USERNAME].asStdString()); + ICELogInfo(<< "Credentials are set to domain " << config[CONFIG_DOMAIN].asStdString() << ", username to " + << config[CONFIG_USERNAME].asStdString()); // Proxy mProfile->unsetOutboundProxy(); @@ -234,7 +228,7 @@ void Account::setup(VariantMap &config) if (config[CONFIG_DOMAINPORT].asInt() != 0) from.uri().port() = config[CONFIG_DOMAINPORT].asInt(); else - from.uri().port();// = 5060; + from.uri().port(); // = 5060; from.uri().user() = resip::Data(config[CONFIG_USERNAME].asStdString()); from.uri().host() = resip::Data(config[CONFIG_DOMAIN].asStdString()); @@ -266,10 +260,12 @@ void Account::start() // Create registration mRegistration = new ResipSession(*mAgent.mDum); - auto regmessage = mAgent.mDum->makeRegistration(mProfile->getDefaultFrom(), mProfile, mConfig->at(CONFIG_REGISTERDURATION).asInt(), mRegistration); + auto regmessage = mAgent.mDum->makeRegistration(mProfile->getDefaultFrom(), mProfile, + mConfig->at(CONFIG_REGISTERDURATION).asInt(), mRegistration); for (UserInfo::const_iterator iter = mUserInfo.begin(); iter != mUserInfo.end(); iter++) - regmessage->header(resip::ExtensionHeader(iter->first.c_str())).push_back(resip::StringCategory(iter->second.c_str())); + regmessage->header(resip::ExtensionHeader(iter->first.c_str())) + .push_back(resip::StringCategory(iter->second.c_str())); mRegistrationState = RegistrationState::Registering; @@ -278,10 +274,10 @@ void Account::start() // Check if STUN IP is required bool noStunServerIp = !CONFIG_EXISTS(CONFIG_STUNSERVER_IP); - //bool hasStunServerName = !CONFIG(CONFIG_STUNSERVER_NAME).asStdString().empty(); + // bool hasStunServerName = !CONFIG(CONFIG_STUNSERVER_NAME).asStdString().empty(); if (noStunServerIp) { - ICELogInfo(<<"No STUN server name or IP is not specified. Has to resolve/discover STUN server IP."); + ICELogInfo(<< "No STUN server name or IP is not specified. Has to resolve/discover STUN server IP."); mRefreshStunServerIpTimer.start(CONFIG(CONFIG_DNS_CACHE_TIME).asInt() * 1000); mRefreshStunServerIpTimer.isTimeToSend(); queryStunServerIp(); @@ -305,11 +301,10 @@ void Account::stop() mRegistrationHandle->removeAll(); mRegistrationHandle = resip::ClientRegistrationHandle(); } - else - if (mRegistration) - { - mRegistration->end(); - } + else if (mRegistration) + { + mRegistration->end(); + } mRegistration = NULL; mRegistrationState = RegistrationState::None; } @@ -361,7 +356,8 @@ void Account::publishPresence(bool online, const std::string& content, int secon if (mPublication.isValid()) mPublication->update(&p); else - mAgent.mDum->send(mAgent.mDum->makePublication(contact(SecureScheme::TlsOnly), mProfile, p, resip::Symbols::Presence, seconds)); + mAgent.mDum->send(mAgent.mDum->makePublication(contact(SecureScheme::TlsOnly), mProfile, p, + resip::Symbols::Presence, seconds)); } void Account::stopPublish() @@ -381,14 +377,14 @@ PClientObserver Account::observe(const std::string& target, const std::string& p observer->mPeer = target; std::shared_ptr msg; - int expires = DEFAULT_SUBSCRIPTION_TIME, refresh = DEFAULT_SUBSCRIPTION_REFRESHTIME; + int expires = DEFAULT_SUBSCRIPTION_TIME, refresh = DEFAULT_SUBSCRIPTION_REFRESHTIME; if (mConfig->exists(CONFIG_SUBSCRIPTION_TIME)) expires = CONFIG(CONFIG_SUBSCRIPTION_TIME).asInt(); if (mConfig->exists(CONFIG_SUBSCRIPTION_REFRESHTIME)) refresh = CONFIG(CONFIG_SUBSCRIPTION_REFRESHTIME).asInt(); - msg = mAgent.mDum->makeSubscription(resip::NameAddr(resip::Data(target)), mProfile, - resip::Data(package), expires, refresh, observer->mSession); + msg = mAgent.mDum->makeSubscription(resip::NameAddr(resip::Data(target)), mProfile, resip::Data(package), expires, + refresh, observer->mSession); msg->header(resip::h_Accepts) = mAgent.mDum->getMasterProfile()->getSupportedMimeTypes(resip::NOTIFY); mAgent.mClientObserverMap[observer->mSessionId] = observer; @@ -406,15 +402,17 @@ int Account::sendMsg(const std::string& peer, const void* ptr, unsigned length, s->setRemoteAddress(peer); // Find MIME type - resip::Mime type; + resip::Mime type; std::string::size_type p = mime.find('/'); if (p != std::string::npos) - type = resip::Mime(resip::Data(mime.substr(0, p)), resip::Data(mime.substr(p+1))); + type = resip::Mime(resip::Data(mime.substr(0, p)), resip::Data(mime.substr(p + 1))); else type = resip::Mime(resip::Data(mime), resip::Data()); - resip::ClientPagerMessageHandle msgHandle = mAgent.mDum->makePagerMessage(resip::NameAddr(resip::Data(peer)), mProfile, s); - unique_ptr contentPtr(new resip::PlainContents(resip::Data(std::string((const char*)ptr, length)),type)); + resip::ClientPagerMessageHandle msgHandle = + mAgent.mDum->makePagerMessage(resip::NameAddr(resip::Data(peer)), mProfile, s); + unique_ptr contentPtr( + new resip::PlainContents(resip::Data(std::string((const char*)ptr, length)), type)); int result = s->sessionId(); msgHandle->page(std::move(contentPtr)); @@ -451,12 +449,13 @@ resip::NameAddr Account::contact(SecureScheme ss) void Account::queryStunServerIp() { - ICELogInfo(<<"Looking for STUN/TURN server IP"); + ICELogInfo(<< "Looking for STUN/TURN server IP"); if (!mConfig->exists(CONFIG_STUNSERVER_NAME)) { // Send request to find STUN or TURN service - std::string target = std::string(mConfig->at(CONFIG_RELAY).asBool() ? "_turn" : "_stun") + "._udp." + mConfig->at(CONFIG_DOMAIN).asStdString(); + std::string target = std::string(mConfig->at(CONFIG_RELAY).asBool() ? "_turn" : "_stun") + "._udp." + + mConfig->at(CONFIG_DOMAIN).asStdString(); // Start lookup mAgent.mStack->getDnsStub().lookup(resip::Data(target), this); @@ -475,9 +474,9 @@ void Account::queryStunServerIp() } } -void Account::prepareIceStack(Session *session, ice::AgentRole icerole) +void Account::prepareIceStack(Session* session, ice::AgentRole icerole) { - ice::ServerConfig config; + ice::ServerConfig config; ice::NetworkAddress addr; addr.setIp(mConfig->at(CONFIG_STUNSERVER_IP).asStdString()); if (mConfig->at(CONFIG_STUNSERVER_PORT).asInt()) @@ -495,8 +494,8 @@ void Account::prepareIceStack(Session *session, ice::AgentRole icerole) config.mUseIPv4 = mAgent.config()[CONFIG_IPV4].asBool(); config.mUseIPv6 = mAgent.config()[CONFIG_IPV6].asBool(); - //config.mDetectNetworkChange = true; - //config.mNetworkCheckInterval = 5000; + // config.mDetectNetworkChange = true; + // config.mNetworkCheckInterval = 5000; session->mIceStack = std::shared_ptr(ice::Stack::makeICEBox(config)); session->mIceStack->setEventHandler(session, this); @@ -509,7 +508,7 @@ void Account::process() queryStunServerIp(); } -void Account::onSuccess(resip::ClientRegistrationHandle h, const resip::SipMessage &response) +void Account::onSuccess(resip::ClientRegistrationHandle h, const resip::SipMessage& response) { // Save registration handle mRegistrationHandle = h; @@ -519,16 +518,16 @@ void Account::onSuccess(resip::ClientRegistrationHandle h, const resip::SipMessa mRegistrationHandle->setCustomHeader(resip::Data(iter->first.c_str()), resip::Data(iter->second.c_str())); // Get the Via - const resip::Via& via = response.header(resip::h_Vias).front(); + const resip::Via& via = response.header(resip::h_Vias).front(); // Get the sent host - const resip::Data& sentHost = via.sentHost();//response.header(h_Contacts).front().uri().host(); + const resip::Data& sentHost = via.sentHost(); // response.header(h_Contacts).front().uri().host(); // Get the sentPort - int sentPort = via.sentPort(); + int sentPort = via.sentPort(); const resip::Data& sourceHost = response.getSource().toData(resip::UDP); - int rport = 0; + int rport = 0; if (via.exists(resip::p_rport)) rport = via.param(resip::p_rport).port(); @@ -553,13 +552,14 @@ void Account::onSuccess(resip::ClientRegistrationHandle h, const resip::SipMessa } mUsedTransport = response.getReceivedTransportTuple().getType(); - //bool streamTransport = mUsedTransport == resip::TCP || mUsedTransport == resip::TLS; + // bool streamTransport = mUsedTransport == resip::TCP || mUsedTransport == resip::TLS; // Retry registration for stream based transport too - if ( (hostChanged || portChanged) && mRegistrationState == RegistrationState::Registering /*&& !streamTransport*/ && mConfig->at(CONFIG_EXTERNALIP).asBool()) + if ((hostChanged || portChanged) && mRegistrationState == RegistrationState::Registering /*&& !streamTransport*/ && + mConfig->at(CONFIG_EXTERNALIP).asBool()) { - //mRegistrationHandle->requestRefresh(); - // Unregister at first + // mRegistrationHandle->requestRefresh(); + // Unregister at first mRegistrationHandle->removeAll(); mRegistrationState = RegistrationState::Reregistering; return; @@ -570,12 +570,12 @@ void Account::onSuccess(resip::ClientRegistrationHandle h, const resip::SipMessa mAgent.onAccountStart(mAgent.getAccount(this)); } -void Account::onRemoved(resip::ClientRegistrationHandle h, const resip::SipMessage &response) +void Account::onRemoved(resip::ClientRegistrationHandle h, const resip::SipMessage& response) { // Check if this unregistering is a part of rport pr if (mRegistrationState == RegistrationState::Reregistering) { - //if (/*this->mUseExternalIP && */response.getSource().getType() == resip::UDP) + // if (/*this->mUseExternalIP && */response.getSource().getType() == resip::UDP) { resip::Uri hostport(contact(SecureScheme::TlsOnly).uri()); hostport.host() = resip::Data(mExternalAddress.ip()); @@ -585,19 +585,24 @@ void Account::onRemoved(resip::ClientRegistrationHandle h, const resip::SipMessa const char* transportName = nullptr; switch (mUsedTransport) { - case resip::TCP: transportName = "tcp"; break; - case resip::TLS: transportName = "tls"; break; + case resip::TCP: + transportName = "tcp"; + break; + case resip::TLS: + transportName = "tls"; + break; } hostport.param(resip::p_transport) = resip::Data(transportName); } mProfile->setOverrideHostAndPort(hostport); - //mProfile->setDefaultFrom(from); + // mProfile->setDefaultFrom(from); } mProfile->setRegId(mConfig->at(CONFIG_REGID).asInt()); auto regmessage = mAgent.mDum->makeRegistration(mProfile->getDefaultFrom(), mProfile, UA_REGISTRATION_TIME); for (UserInfo::const_iterator iter = mUserInfo.begin(); iter != mUserInfo.end(); iter++) - regmessage->header(resip::ExtensionHeader(iter->first.c_str())).push_back(resip::StringCategory(iter->second.c_str())); + regmessage->header(resip::ExtensionHeader(iter->first.c_str())) + .push_back(resip::StringCategory(iter->second.c_str())); mAgent.mDum->send(regmessage); return; @@ -625,16 +630,17 @@ void Account::onDnsResult(const resip::DNSResult& result) if (result.status == 0) { resip::Data foundAddress = result.records.front().host(); - ICELogInfo( << "Success to resolve STUN/TURN address to " << foundAddress.c_str()); + ICELogInfo(<< "Success to resolve STUN/TURN address to " << foundAddress.c_str()); mConfig->at(CONFIG_STUNSERVER_IP) = std::string(foundAddress.c_str()); - // Here the IP address of STUN/TURN server is found. If account is registered already - it means account is ready. + // Here the IP address of STUN/TURN server is found. If account is registered already - it means account is + // ready. if (mRegistrationState == RegistrationState::Registered) mAgent.onAccountStart(mAgent.getAccount(this)); } else { - ICELogError( << "Failed to resolve STUN or TURN server IP address."); + ICELogError(<< "Failed to resolve STUN or TURN server IP address."); if (mRegistrationState == RegistrationState::Registered) { int startCode = mConfig->at(CONFIG_STUNSERVER_NAME).asStdString().empty() ? 0 : 503; @@ -643,10 +649,7 @@ void Account::onDnsResult(const resip::DNSResult& result) } } -void Account::onDnsResult(const resip::DNSResult&) -{ - -} +void Account::onDnsResult(const resip::DNSResult&) {} void Account::onDnsResult(const resip::DNSResult& result) { @@ -654,14 +657,14 @@ void Account::onDnsResult(const resip::DNSResult& result) { // Find lowest priority int priority = 0x7FFFFFFF; - for (size_t i=0; i= weight) { @@ -674,15 +677,15 @@ void Account::onDnsResult(const resip::DNSResult& result) const char* host = result.records[index].target().c_str(); - ICELogInfo( << "Success to find STUN/TURN server on " << result.records[index].target().c_str() << - ":" << (int)result.records[index].port()); + ICELogInfo(<< "Success to find STUN/TURN server on " << result.records[index].target().c_str() << ":" + << (int)result.records[index].port()); if (inet_addr(host) == INADDR_NONE) { // Try to resolve domain name now mAgent.mStack->getDnsStub().lookup(result.records[index].target(), this); - //mStack->getDnsStub().lookup(result.records[index].target(), this); + // mStack->getDnsStub().lookup(result.records[index].target(), this); } else { @@ -691,27 +694,20 @@ void Account::onDnsResult(const resip::DNSResult& result) } else { - ICELogError( << "Failed to find STUN or TURN service for specified domain."); - //mAgent::shutdown(); + ICELogError(<< "Failed to find STUN or TURN service for specified domain."); + // mAgent::shutdown(); } - } -void Account::onDnsResult(const resip::DNSResult&) -{ +void Account::onDnsResult(const resip::DNSResult&) {} -} +void Account::onDnsResult(const resip::DNSResult&) {} -void Account::onDnsResult(const resip::DNSResult&) -{ - -} - -bool Account::isResponsibleFor(const resip::NameAddr &addr) +bool Account::isResponsibleFor(const resip::NameAddr& addr) { std::string user = addr.uri().user().c_str(); std::string domain = addr.uri().host().c_str(); - int p = addr.uri().port(); + int p = addr.uri().port(); if (mConfig->at(CONFIG_USERNAME).asStdString() == user && mConfig->at(CONFIG_DOMAIN).asStdString() == domain) { // Check if ports are the same or port is not specified at all @@ -724,7 +720,7 @@ bool Account::isResponsibleFor(const resip::NameAddr &addr) return false; } -void Account::setUserInfo(const UserInfo &info) +void Account::setUserInfo(const UserInfo& info) { mUserInfo = info; if (mRegistrationHandle.isValid()) @@ -740,7 +736,7 @@ Account::UserInfo Account::getUserInfo() const } std::atomic_int Account::IdGenerator; -int Account::generateId() +int Account::generateId() { return ++IdGenerator; } diff --git a/src/engine/endpoint/EP_Account.h b/src/engine/endpoint/EP_Account.h index 1055ef36..50c2c70a 100644 --- a/src/engine/endpoint/EP_Account.h +++ b/src/engine/endpoint/EP_Account.h @@ -22,10 +22,11 @@ class UserAgent; class Session; -class Account: public resip::DnsResultSink +class Account : public resip::DnsResultSink { friend class UserAgent; friend class NATDecorator; + public: Account(PVariantMap config, UserAgent& agent); ~Account(); @@ -34,7 +35,7 @@ public: void stop(); void refresh(); bool active(); - int id() const; + int id() const; enum class RegistrationState { @@ -47,69 +48,69 @@ public: RegistrationState registrationState(); /* Publishes new presence information */ - void publishPresence(bool online, const std::string& content, int seconds = 600); + void publishPresence(bool online, const std::string& content, int seconds = 600); /* Stops publishing of presence */ - void stopPublish(); + void stopPublish(); /* Starts observing on specified target / package */ - PClientObserver observe(const std::string& target, const std::string& package, void* tag); + PClientObserver observe(const std::string& target, const std::string& package, void* tag); /* Queues message to peer with specified mime type. Returns ID of message. */ - int sendMsg(const std::string& peer, const void* ptr, unsigned length, const std::string& mime, void* tag); + int sendMsg(const std::string& peer, const void* ptr, unsigned length, const std::string& mime, void* tag); /* Returns name of account - */ std::string name(); /* Updates account with configuration */ - void setup(VariantMap& config); + void setup(VariantMap& config); /* Returns corresponding resiprocate profile */ - std::shared_ptr getUserProfile() const { return mProfile; } + std::shared_ptr getUserProfile() const { return mProfile; } typedef std::map UserInfo; - void setUserInfo(const UserInfo& info); - UserInfo getUserInfo() const; + void setUserInfo(const UserInfo& info); + UserInfo getUserInfo() const; protected: - PVariantMap mConfig; + PVariantMap mConfig; // Registration - ResipSession* mRegistration; - resip::ClientRegistrationHandle mRegistrationHandle; - resip::ClientPublicationHandle mPublication; - resip::TransportType mUsedTransport; + ResipSession* mRegistration; + resip::ClientRegistrationHandle mRegistrationHandle; + resip::ClientPublicationHandle mPublication; + resip::TransportType mUsedTransport; - RegistrationState mRegistrationState; + RegistrationState mRegistrationState; - ice::NetworkAddress mExternalAddress; + ice::NetworkAddress mExternalAddress; std::shared_ptr mProfile; - UserAgent& mAgent; - bool mPresenceOnline; - std::string mPresenceContent; + UserAgent& mAgent; + bool mPresenceOnline; + std::string mPresenceContent; // Timer to refresh STUN server IP - ice::ICEScheduleTimer mRefreshStunServerIpTimer; + ice::ICEScheduleTimer mRefreshStunServerIpTimer; // Cached auth - resip::Auth mCachedAuth; + resip::Auth mCachedAuth; // Id of account - int mId; + int mId; // User info about current state - UserInfo mUserInfo; + UserInfo mUserInfo; // List of client subscriptions sent from this account - typedef std::set ClientObserverSet; - ClientObserverSet mClientObserverSet; + typedef std::set ClientObserverSet; + ClientObserverSet mClientObserverSet; - void process(); + void process(); // Method queries new stun server ip from dns (if stun server is specified as dns name) - void queryStunServerIp(); + void queryStunServerIp(); - bool isResponsibleFor(const resip::NameAddr& addr); + bool isResponsibleFor(const resip::NameAddr& addr); enum class SecureScheme { SipsAndTls, @@ -121,10 +122,10 @@ protected: resip::NameAddr contact(SecureScheme ss = SecureScheme::SipsOnly); // This method prepares configuration, creates ice stack and sets ownership to session - void prepareIceStack(Session* session, ice::AgentRole role); - void onSuccess(resip::ClientRegistrationHandle h, const resip::SipMessage& response); - void onRemoved(resip::ClientRegistrationHandle h, const resip::SipMessage& response); - void onFailure(resip::ClientRegistrationHandle, const resip::SipMessage& response); + void prepareIceStack(Session* session, ice::AgentRole role); + void onSuccess(resip::ClientRegistrationHandle h, const resip::SipMessage& response); + void onRemoved(resip::ClientRegistrationHandle h, const resip::SipMessage& response); + void onFailure(resip::ClientRegistrationHandle, const resip::SipMessage& response); #pragma region DnsResultSink implementation void onDnsResult(const resip::DNSResult&); @@ -134,7 +135,7 @@ protected: void onDnsResult(const resip::DNSResult&); #pragma endregion - static int generateId(); + static int generateId(); static std::atomic_int IdGenerator; }; diff --git a/src/engine/endpoint/EP_AudioProvider.cpp b/src/engine/endpoint/EP_AudioProvider.cpp index d8d2fd9f..ed0206e0 100644 --- a/src/engine/endpoint/EP_AudioProvider.cpp +++ b/src/engine/endpoint/EP_AudioProvider.cpp @@ -17,8 +17,7 @@ #define LOG_SUBSYSTEM "engine" AudioProvider::AudioProvider(UserAgent& agent, MT::Terminal& terminal) - :mUserAgent(agent), mTerminal(terminal), mState(0), - mRemoteTelephoneCodec(0), mRemoteNoSdp(false) + : mUserAgent(agent), mTerminal(terminal), mState(0), mRemoteTelephoneCodec(0), mRemoteNoSdp(false) { mActive = mfActive; mRemoteState = msSendRecv; @@ -26,12 +25,11 @@ AudioProvider::AudioProvider(UserAgent& agent, MT::Terminal& terminal) if (mUserAgent.config().exists(CONFIG_CODEC_PRIORITY)) mCodecPriority.setupFrom(mUserAgent.config()[CONFIG_CODEC_PRIORITY].asVMap()); mSrtpSuite = SRTP_NONE; - setStateImpl((int)StreamState::SipRecv | (int)StreamState::SipSend | (int)StreamState::Receiving | (int)StreamState::Sending); + setStateImpl((int)StreamState::SipRecv | (int)StreamState::SipSend | (int)StreamState::Receiving | + (int)StreamState::Sending); } -AudioProvider::~AudioProvider() -{ -} +AudioProvider::~AudioProvider() {} std::string AudioProvider::streamName() { @@ -47,7 +45,7 @@ std::string AudioProvider::streamProfile() } // Sets destination IP address -void AudioProvider::setDestinationAddress(const RtpPair& addr) +void AudioProvider::setDestinationAddress(const RtpPair& addr) { if (!mActiveStream) return; @@ -55,7 +53,7 @@ void AudioProvider::setDestinationAddress(const RtpPair& addr) mActiveStream->setDestination(addr); } -void AudioProvider::configureMediaObserver(MT::Stream::MediaObserver *observer, void* userTag) +void AudioProvider::configureMediaObserver(MT::Stream::MediaObserver* observer, void* userTag) { mMediaObserver = observer; mMediaObserverTag = userTag; @@ -64,20 +62,21 @@ void AudioProvider::configureMediaObserver(MT::Stream::MediaObserver *observer, } // Processes incoming data -void AudioProvider::processData(const PDatagramSocket& s, const void* dataBuffer, int dataSize, InternetAddress& source) +void AudioProvider::processData(const PDatagramSocket& s, const void* dataBuffer, int dataSize, InternetAddress& source) { if (!mActiveStream) return; if (RtpHelper::isRtpOrRtcp(dataBuffer, dataSize)) { - ICELogMedia(<<"Adding new data to stream processing"); + ICELogMedia(<< "Adding new data to stream processing"); mActiveStream->dataArrived(s, dataBuffer, dataSize, source); } } // This method is called by user agent to send ICE packet from mediasocket -void AudioProvider::sendData(const PDatagramSocket& s, InternetAddress& destination, const void* buffer, unsigned int size) +void AudioProvider::sendData(const PDatagramSocket& s, InternetAddress& destination, const void* buffer, + unsigned int size) { s->sendDatagram(destination, buffer, size); } @@ -105,7 +104,7 @@ void AudioProvider::updateSdpOffer(resip::SdpContents::Session::Medium& sdp, Sdp // Use CodecListPriority mCodecPriority adapter to work with codec priorities if (mAvailableCodecs.empty()) { - for (int i=0; i& vl = media.getValues("crypto"); - SrtpSuite ss = SRTP_NONE; - ByteBuffer key; + SrtpSuite ss = SRTP_NONE; + ByteBuffer key; for (std::list::const_iterator attrIter = vl.begin(); attrIter != vl.end(); attrIter++) { const resip::Data& attr = *attrIter; - ByteBuffer tempkey; - int tag = 1; - SrtpSuite suite = processCryptoAttribute(attr, tempkey, &tag); + ByteBuffer tempkey; + int tag = 1; + SrtpSuite suite = processCryptoAttribute(attr, tempkey, &tag); if (srtpSuiteStrength(suite) > srtpSuiteStrength(ss)) { ss = suite; @@ -316,9 +328,9 @@ std::string AudioProvider::createCryptoAttribute(SrtpSuite suite, int tag) SrtpSuite AudioProvider::processCryptoAttribute(const resip::Data& value, ByteBuffer& key, int* tag) { - int srtpTag = 0; + int srtpTag = 0; char suite[64], keyChunk[256]; - int components = sscanf(value.c_str(), "%d %63s inline: %255s", &srtpTag, suite, keyChunk); + int components = sscanf(value.c_str(), "%d %63s inline: %255s", &srtpTag, suite, keyChunk); if (components != 3) return SRTP_NONE; if (tag) @@ -343,7 +355,7 @@ void AudioProvider::findRfc2833(const resip::SdpContents::Session::Medium::Codec for (codecIter = codecs.begin(); codecIter != codecs.end(); codecIter++) { if (strcmp("TELEPHONE-EVENT", codecIter->getName().c_str()) == 0 || - strcmp("telephone-event", codecIter->getName().c_str()) == 0) + strcmp("telephone-event", codecIter->getName().c_str()) == 0) mRemoteTelephoneCodec = codecIter->payloadType(); } } @@ -367,9 +379,9 @@ void AudioProvider::setupMirror(bool enable) mActiveStream->setupMirror(enable); } -void AudioProvider::setStateImpl(unsigned int state) { +void AudioProvider::setStateImpl(unsigned int state) +{ mState = state; if (mActiveStream) mActiveStream->setState(state); - } diff --git a/src/engine/endpoint/EP_AudioProvider.h b/src/engine/endpoint/EP_AudioProvider.h index 0b31864e..e3339df3 100644 --- a/src/engine/endpoint/EP_AudioProvider.h +++ b/src/engine/endpoint/EP_AudioProvider.h @@ -18,104 +18,103 @@ class UserAgent; -class AudioProvider: public DataProvider +class AudioProvider : public DataProvider { public: + AudioProvider(UserAgent& agent, MT::Terminal& terminal); + virtual ~AudioProvider(); - AudioProvider(UserAgent& agent, MT::Terminal& terminal); - virtual ~AudioProvider(); - - // Returns provider RTP name - std::string streamName() override; - - // Returns provider RTP profile name - std::string streamProfile() override; - - // Sets destination IP address - void setDestinationAddress(const RtpPair& addr) override; + // Returns provider RTP name + std::string streamName() override; - // Processes incoming data - void processData(const PDatagramSocket& s, const void* dataBuffer, int dataSize, InternetAddress& source) override; + // Returns provider RTP profile name + std::string streamProfile() override; - // This method is called by user agent to send ICE packet from mediasocket - void sendData(const PDatagramSocket& s, InternetAddress& destination, const void* dataBuffer, unsigned int datasize) override; + // Sets destination IP address + void setDestinationAddress(const RtpPair& addr) override; - // Updates SDP offer - void updateSdpOffer(resip::SdpContents::Session::Medium& sdp, SdpDirection direction) override; + // Processes incoming data + void processData(const PDatagramSocket& s, const void* dataBuffer, int dataSize, InternetAddress& source) override; - // Called by user agent when session is deleted. - void sessionDeleted() override; + // This method is called by user agent to send ICE packet from mediasocket + void sendData(const PDatagramSocket& s, InternetAddress& destination, const void* dataBuffer, + unsigned int datasize) override; - // Called by user agent when session is terminated. - void sessionTerminated() override; + // Updates SDP offer + void updateSdpOffer(resip::SdpContents::Session::Medium& sdp, SdpDirection direction) override; - // Called by user agent when session is started. - void sessionEstablished(int conntype) override; + // Called by user agent when session is deleted. + void sessionDeleted() override; - // Called by user agent to save media socket for this provider - void setSocket(const RtpPair& p4, const RtpPair& p6) override; - - // Called by user agent to get media socket for this provider - RtpPair& socket(int family) override; + // Called by user agent when session is terminated. + void sessionTerminated() override; - // Called by user agent to process media stream description from remote peer. - // Returns true if description is processed succesfully. Otherwise method returns false. - // myAnswer sets if the answer will be sent after. - bool processSdpOffer(const resip::SdpContents::Session::Medium& media, SdpDirection sdpDirection) override; + // Called by user agent when session is started. + void sessionEstablished(int conntype) override; + + // Called by user agent to save media socket for this provider + void setSocket(const RtpPair& p4, const RtpPair& p6) override; + + // Called by user agent to get media socket for this provider + RtpPair& socket(int family) override; + + // Called by user agent to process media stream description from remote peer. + // Returns true if description is processed succesfully. Otherwise method returns false. + // myAnswer sets if the answer will be sent after. + bool processSdpOffer(const resip::SdpContents::Session::Medium& media, SdpDirection sdpDirection) override; - void setState(unsigned state) override; - unsigned state() override; - MT::Statistics getStatistics() override; - MT::PStream activeStream(); + void setState(unsigned state) override; + unsigned state() override; + MT::Statistics getStatistics() override; + MT::PStream activeStream(); - void readFile(const Audio::PWavFileReader& stream, MT::Stream::MediaDirection direction); - void writeFile(const Audio::PWavFileWriter& stream, MT::Stream::MediaDirection direction); - void setupMirror(bool enable); + void readFile(const Audio::PWavFileReader& stream, MT::Stream::MediaDirection direction); + void writeFile(const Audio::PWavFileWriter& stream, MT::Stream::MediaDirection direction); + void setupMirror(bool enable); - void configureMediaObserver(MT::Stream::MediaObserver* observer, void* userTag); - static SrtpSuite processCryptoAttribute(const resip::Data& value, ByteBuffer& key, int* tag = nullptr); + void configureMediaObserver(MT::Stream::MediaObserver* observer, void* userTag); + static SrtpSuite processCryptoAttribute(const resip::Data& value, ByteBuffer& key, int* tag = nullptr); protected: - // SDP's stream name - std::string mStreamName; - - // Socket handles to operate - RtpPair mSocket4, mSocket6; + // SDP's stream name + std::string mStreamName; - // Destination IP4/6 address - RtpPair mDestination; - - MT::PStream mActiveStream; - UserAgent& mUserAgent; - MT::Terminal& mTerminal; - MT::Statistics mBackupStats; + // Socket handles to operate + RtpPair mSocket4, mSocket6; - unsigned mState; - SrtpSuite mSrtpSuite; - int mSrtpTag = 1; // RFC 4568 tag of the negotiated crypto attribute - struct RemoteCodec - { - RemoteCodec(MT::Codec::Factory* factory, int payloadType) - :mFactory(factory), mRemotePayloadType(payloadType) - { } + // Destination IP4/6 address + RtpPair mDestination; - MT::Codec::Factory* mFactory; - int mRemotePayloadType; - }; - std::vector mAvailableCodecs; - int mRemoteTelephoneCodec; // Payload type of remote rfc2833 codec - bool mRemoteNoSdp; // Marks if we got no-sdp offer - MT::CodecListPriority mCodecPriority; - MT::Stream::MediaObserver* mMediaObserver = nullptr; - void* mMediaObserverTag = nullptr; + MT::PStream mActiveStream; + UserAgent& mUserAgent; + MT::Terminal& mTerminal; + MT::Statistics mBackupStats; - std::string createCryptoAttribute(SrtpSuite suite, int tag); - void findRfc2833(const resip::SdpContents::Session::Medium::CodecContainer& codecs); + unsigned mState; + SrtpSuite mSrtpSuite; + int mSrtpTag = 1; // RFC 4568 tag of the negotiated crypto attribute + struct RemoteCodec + { + RemoteCodec(MT::Codec::Factory* factory, int payloadType) : mFactory(factory), mRemotePayloadType(payloadType) + { + } - // Implements setState() logic. This allows to be called from constructor (it is not virtual function) - void setStateImpl(unsigned state); + MT::Codec::Factory* mFactory; + int mRemotePayloadType; + }; + std::vector mAvailableCodecs; + int mRemoteTelephoneCodec; // Payload type of remote rfc2833 codec + bool mRemoteNoSdp; // Marks if we got no-sdp offer + MT::CodecListPriority mCodecPriority; + MT::Stream::MediaObserver* mMediaObserver = nullptr; + void* mMediaObserverTag = nullptr; + std::string createCryptoAttribute(SrtpSuite suite, int tag); + void findRfc2833(const resip::SdpContents::Session::Medium::CodecContainer& codecs); + + // Implements setState() logic. This allows to be called from constructor (it is not virtual function) + void setStateImpl(unsigned state); }; #endif diff --git a/src/engine/endpoint/EP_DataProvider.cpp b/src/engine/endpoint/EP_DataProvider.cpp index 0e11fee4..e7fc2803 100644 --- a/src/engine/endpoint/EP_DataProvider.cpp +++ b/src/engine/endpoint/EP_DataProvider.cpp @@ -10,7 +10,7 @@ bool DataProvider::isSupported(const char* name) { return !strcmp(name, "audio"); - //return (!strcmp(name, "screen") || !strcmp(name, "data") || !strcmp(name, "audio") || !strcmp(name, "video")); + // return (!strcmp(name, "screen") || !strcmp(name, "data") || !strcmp(name, "audio") || !strcmp(name, "video")); } void DataProvider::pause() @@ -20,7 +20,7 @@ void DataProvider::pause() // Stop receive RTP stream if (state() & (int)StreamState::Receiving) - setState( state() & ~(int)StreamState::Receiving ); + setState(state() & ~(int)StreamState::Receiving); mActive = mfPaused; } @@ -28,10 +28,10 @@ void DataProvider::pause() void DataProvider::resume() { // Tell remote peer about resumed receiving in SDP - //setState( state() | STATE_SIPRECV ); + // setState( state() | STATE_SIPRECV ); // Start receive RTP stream - setState( state() | (int)StreamState::Receiving ); + setState(state() | (int)StreamState::Receiving); mActive = mfActive; } @@ -44,31 +44,29 @@ bool DataProvider::processSdpOffer(const resip::SdpContents::Session::Medium& me mRemoteState = msSendonly; setState(state() & ~(int)StreamState::Sending); } + else if (media.exists("recvonly")) + { + mRemoteState = msRecvonly; + setState(state() & ~(int)StreamState::Receiving); + } + else if (media.exists("inactive")) + { + mRemoteState = msInactive; + setState(state() & ~((int)StreamState::Sending | (int)StreamState::Receiving)); + } else - if (media.exists("recvonly")) + { + mRemoteState = msSendRecv; + switch (mActive) { - mRemoteState = msRecvonly; - setState(state() & ~(int)StreamState::Receiving); - } - else - if (media.exists("inactive")) - { - mRemoteState = msInactive; - setState(state() & ~((int)StreamState::Sending | (int)StreamState::Receiving) ); - } - else - { - mRemoteState = msSendRecv; - switch (mActive) - { - case mfActive: - setState(state() | (int)StreamState::Sending | (int)StreamState::Receiving); - break; + case mfActive: + setState(state() | (int)StreamState::Sending | (int)StreamState::Receiving); + break; - case mfPaused: - setState(state() | (int)StreamState::Sending ); - break; - } - } + case mfPaused: + setState(state() | (int)StreamState::Sending); + break; + } + } return true; } diff --git a/src/engine/endpoint/EP_DataProvider.h b/src/engine/endpoint/EP_DataProvider.h index 070c7d16..a00fdfb2 100644 --- a/src/engine/endpoint/EP_DataProvider.h +++ b/src/engine/endpoint/EP_DataProvider.h @@ -33,59 +33,61 @@ public: msInactive }; - static bool isSupported(const char* name); + static bool isSupported(const char* name); // Returns provider RTP name - virtual std::string streamName() = 0; + virtual std::string streamName() = 0; // Returns provider RTP profile name - virtual std::string streamProfile() = 0; + virtual std::string streamProfile() = 0; // Sets destination IP address - virtual void setDestinationAddress(const RtpPair& addr) = 0; + virtual void setDestinationAddress(const RtpPair& addr) = 0; // Processes incoming data - virtual void processData(const PDatagramSocket& s, const void* dataBuffer, int dataSize, InternetAddress& address) = 0; + virtual void processData(const PDatagramSocket& s, const void* dataBuffer, int dataSize, + InternetAddress& address) = 0; // This method is called by user agent to send ICE packet from mediasocket - virtual void sendData(const PDatagramSocket& s, InternetAddress& destination, const void* dataBuffer, unsigned int datasize) = 0; + virtual void sendData(const PDatagramSocket& s, InternetAddress& destination, const void* dataBuffer, + unsigned int datasize) = 0; // Updates SDP offer - virtual void updateSdpOffer(resip::SdpContents::Session::Medium& sdp, SdpDirection direction) = 0; + virtual void updateSdpOffer(resip::SdpContents::Session::Medium& sdp, SdpDirection direction) = 0; // Called by user agent when session is deleted. Comes after sessionTerminated(). - virtual void sessionDeleted() = 0; + virtual void sessionDeleted() = 0; // Called by user agent when session is terminated. - virtual void sessionTerminated() = 0; + virtual void sessionTerminated() = 0; // Called by user agent when session is started. - virtual void sessionEstablished(int conntype) = 0; + virtual void sessionEstablished(int conntype) = 0; // Called by user agent to save media socket for this provider - virtual void setSocket(const RtpPair& p4, const RtpPair& p6) = 0; + virtual void setSocket(const RtpPair& p4, const RtpPair& p6) = 0; // Called by user agent to get media socket for this provider virtual RtpPair& socket(int family) = 0; // Called by user agent to process media stream description from remote peer. // Returns true if description is processed succesfully. Otherwise method returns false. - virtual bool processSdpOffer(const resip::SdpContents::Session::Medium& media, SdpDirection sdpDirection) = 0; + virtual bool processSdpOffer(const resip::SdpContents::Session::Medium& media, SdpDirection sdpDirection) = 0; - virtual unsigned state() = 0; - virtual void setState(unsigned state) = 0; + virtual unsigned state() = 0; + virtual void setState(unsigned state) = 0; - virtual void pause(); - virtual void resume(); + virtual void pause(); + virtual void resume(); - virtual MT::Statistics getStatistics() = 0; + virtual MT::Statistics getStatistics() = 0; protected: MediaFlow mActive; MediaState mRemoteState; }; -typedef std::shared_ptr PDataProvider; +typedef std::shared_ptr PDataProvider; typedef std::vector DataProviderVector; #endif diff --git a/src/engine/endpoint/EP_Engine.cpp b/src/engine/endpoint/EP_Engine.cpp index c856809e..2e6dd862 100644 --- a/src/engine/endpoint/EP_Engine.cpp +++ b/src/engine/endpoint/EP_Engine.cpp @@ -30,27 +30,32 @@ #include "resip/dum/InviteSession.hxx" #if defined(TARGET_OSX) -# include "resip/stack/ssl/MacSecurity.hxx" +#include "resip/stack/ssl/MacSecurity.hxx" #endif #if defined(TARGET_WIN) -# include "resip/stack/ssl/WinSecurity.hxx" +#include "resip/stack/ssl/WinSecurity.hxx" #endif #define LOG_SUBSYSTEM "engine" #define LOCK Lock l(mGuard) -#define CAST2RESIPSESSION(x) (x.isValid() ? (x->getAppDialogSet().isValid() ? dynamic_cast(x->getAppDialogSet().get()) : NULL) : NULL) +#define CAST2RESIPSESSION(x) \ + (x.isValid() ? (x->getAppDialogSet().isValid() ? dynamic_cast(x->getAppDialogSet().get()) : NULL) \ + : NULL) -typedef resip::SdpContents::Session::Medium Medium; +typedef resip::SdpContents::Session::Medium Medium; typedef resip::SdpContents::Session::MediumContainer MediumContainer; -class TransportLogger: public resip::Transport::SipMessageLoggingHandler +class TransportLogger : public resip::Transport::SipMessageLoggingHandler { public: - void outboundMessage(const resip::Tuple &source, const resip::Tuple &destination, const resip::SipMessage &msg) override + void outboundMessage(const resip::Tuple& source, const resip::Tuple& destination, + const resip::SipMessage& msg) override { - std::ostringstream dest_buffer; dest_buffer << destination; - std::ostringstream msg_buffer; msg_buffer << msg; + std::ostringstream dest_buffer; + dest_buffer << destination; + std::ostringstream msg_buffer; + msg_buffer << msg; std::string msg_text = msg_buffer.str(); #if defined(TARGET_ANDROID) if (msg_text.size() > 512) @@ -59,7 +64,7 @@ public: msg_text = strx::prefixLines(msg_text, "<---"); auto lines = strx::split(msg_text); - for (const auto& l: lines) + for (const auto& l : lines) ICELogDebug(<< l); } else @@ -72,13 +77,18 @@ public: // Note: retransmissions store already encoded messages, so callback doesn't send SipMessage it sends // the encoded version of the SipMessage instead. If you need a SipMessage you will need to // re-parse back into a SipMessage in the callback handler. - void outboundRetransmit(const resip::Tuple &source, const resip::Tuple &destination, const resip::SendData &data) override - {} - - void inboundMessage(const resip::Tuple& source, const resip::Tuple& destination, const resip::SipMessage &msg) override + void outboundRetransmit(const resip::Tuple& source, const resip::Tuple& destination, + const resip::SendData& data) override { - std::ostringstream source_buffer; source_buffer << source; - std::ostringstream msg_buffer; msg_buffer << msg; + } + + void inboundMessage(const resip::Tuple& source, const resip::Tuple& destination, + const resip::SipMessage& msg) override + { + std::ostringstream source_buffer; + source_buffer << source; + std::ostringstream msg_buffer; + msg_buffer << msg; std::string msg_text = msg_buffer.str(); #if defined(TARGET_ANDROID) if (msg_text.size() > 512) @@ -86,7 +96,7 @@ public: ICELogDebug(<< "Received from " << source_buffer.str() << " :"); msg_text = strx::prefixLines(msg_text, "--->"); auto lines = strx::split(msg_text); - for (const auto& l: lines) + for (const auto& l : lines) ICELogDebug(<< l); } else @@ -95,7 +105,6 @@ public: ICELogDebug(<< "Received from " << source_buffer.str() << "\n" << strx::prefixLines(msg_buffer.str(), "--->")); #endif } - }; //-------------- UserAgent ----------------------- @@ -142,7 +151,7 @@ void UserAgent::start() LOCK; if (mStack) { - ICELogError(<<"Endpoint is started already."); + ICELogError(<< "Endpoint is started already."); return; } @@ -154,17 +163,22 @@ void UserAgent::start() if (mConfig.exists(CONFIG_OWN_DNS)) { - std::string line, t = mConfig[CONFIG_OWN_DNS].asStdString(); + std::string line, t = mConfig[CONFIG_OWN_DNS].asStdString(); std::stringstream ss(t); while (std::getline(ss, line)) { line = strx::trim(line); - ice::NetworkAddress addr(line.c_str(), 0); addr.setPort(80); // Fake port to make ICEAddress initialized + ice::NetworkAddress addr(line.c_str(), 0); + addr.setPort(80); // Fake port to make ICEAddress initialized switch (addr.family()) { - case AF_INET: nslist.push_back(resip::GenericIPAddress(*addr.sockaddr4())); break; - case AF_INET6: nslist.push_back(resip::GenericIPAddress(*addr.sockaddr6())); break; + case AF_INET: + nslist.push_back(resip::GenericIPAddress(*addr.sockaddr4())); + break; + case AF_INET6: + nslist.push_back(resip::GenericIPAddress(*addr.sockaddr6())); + break; } } } @@ -190,7 +204,7 @@ void UserAgent::start() resip::Data cert = resip::Data(mConfig[CONFIG_ROOTCERT].asStdString()); mStack->getSecurity()->addRootCertPEM(cert); } - catch(resip::BaseException& /*e*/) + catch (resip::BaseException& /*e*/) { ICELogError(<< "Failed to preload root certificate"); } @@ -202,8 +216,16 @@ void UserAgent::start() mTransportList.clear(); resip::InternalTransport* t; -#define ADD_TRANSPORT4(X) if ((t = dynamic_cast(mStack->addTransport(X, 0, resip::V4)))) { /*t->setTransportLogger(this);*/ mTransportList.push_back(t);} -#define ADD_TRANSPORT6(X) if ((t = dynamic_cast(mStack->addTransport(X, 0, resip::V6)))) { /*t->setTransportLogger(this);*/ mTransportList.push_back(t);} +#define ADD_TRANSPORT4(X) \ + if ((t = dynamic_cast(mStack->addTransport(X, 0, resip::V4)))) \ + { /*t->setTransportLogger(this);*/ \ + mTransportList.push_back(t); \ + } +#define ADD_TRANSPORT6(X) \ + if ((t = dynamic_cast(mStack->addTransport(X, 0, resip::V6)))) \ + { /*t->setTransportLogger(this);*/ \ + mTransportList.push_back(t); \ + } switch (mConfig[CONFIG_TRANSPORT].asInt()) { @@ -314,20 +336,20 @@ void UserAgent::shutdown() if (!mStack) return; - ICELogInfo( << "Attempt to stop endpoint."); + ICELogInfo(<< "Attempt to stop endpoint."); { LOCK; - for (auto& observerIter: mClientObserverMap) + for (auto& observerIter : mClientObserverMap) observerIter.second->stop(); - for (auto& observerIter: mServerObserverMap) + for (auto& observerIter : mServerObserverMap) observerIter.second->stop(); - for (auto& sessionIter: mSessionMap) + for (auto& sessionIter : mSessionMap) sessionIter.second->stop(); - for (auto& accountIter: mAccountSet) + for (auto& accountIter : mAccountSet) accountIter->stop(); } } @@ -342,17 +364,19 @@ void UserAgent::refresh() { LOCK; - for (auto& acc: mAccountSet) + for (auto& acc : mAccountSet) acc->refresh(); - for (auto& observer: mClientObserverMap) + for (auto& observer : mClientObserverMap) observer.second->refresh(); } void UserAgent::onDumCanBeDeleted() { - delete mDum; mDum = nullptr; - delete mStack; mStack = nullptr; + delete mDum; + mDum = nullptr; + delete mStack; + mStack = nullptr; mClientObserverMap.clear(); mServerObserverMap.clear(); @@ -371,14 +395,12 @@ void UserAgent::stop() mTransportList.clear(); // Dump statistics here - ICELogInfo(<< "Remaining " - << Session::InstanceCounter.load() << " session(s), " + ICELogInfo(<< "Remaining " << Session::InstanceCounter.load() << " session(s), " << ResipSession::InstanceCounter.load() << " resip DialogSet(s), " << resip::ClientRegistration::InstanceCounter.load() << " ClientRegistration(s)"); mDum->shutdown(this); onDumCanBeDeleted(); - } @@ -390,12 +412,12 @@ void UserAgent::process() bool connectionFailed = false; mStack->buildFdSet(fdset); - //unsigned int t1 = mStack->getTimeTillNextProcessMS(); + // unsigned int t1 = mStack->getTimeTillNextProcessMS(); int ret = fdset.selectMilliSeconds(0); if (ret >= 0) // Got any results or time to send new packets? { Lock l(mGuard); - //ICELogDebug(<< "Smth on SIP socket(s)"); + // ICELogDebug(<< "Smth on SIP socket(s)"); mStack->process(fdset); // Check if there failed connections @@ -406,7 +428,7 @@ void UserAgent::process() mTransportList[transportIndex]->resetConnectionsDeleted(); } } - + { Lock l(mGuard); while (mDum->process()) @@ -417,9 +439,10 @@ void UserAgent::process() this->onSipConnectionFailed(); } - // Erase one terminated session. The rule is : seession must not have references from resiprocate and reference count has to be 1. + // Erase one terminated session. The rule is : seession must not have references from resiprocate and reference + // count has to be 1. { - Lock l(mGuard); + Lock l(mGuard); SessionMap::iterator sessionIter; for (sessionIter = mSessionMap.begin(); sessionIter != mSessionMap.end(); ++sessionIter) { @@ -434,7 +457,7 @@ void UserAgent::process() #pragma region ICE packet generating // Iterate available sessions { - Lock l(mGuard); + Lock l(mGuard); // Find all sessions std::set idSet; @@ -456,21 +479,25 @@ void UserAgent::process() session.processQueuedOffer(); // Generate outgoing data while available - int iceStreamId = -1, iceComponentId = -1; void* iceTag = NULL; bool iceResponse; + int iceStreamId = -1, iceComponentId = -1; + void* iceTag = NULL; + bool iceResponse; ice::PByteBuffer buffer; while ((buffer = session.mIceStack->generateOutgoingData(iceResponse, iceStreamId, iceComponentId, iceTag))) { // Find corresponding data provider - for (unsigned i=0; i < session.mStreamList.size(); ++i) + for (unsigned i = 0; i < session.mStreamList.size(); ++i) { Session::Stream& stream = session.mStreamList[i]; if (stream.provider() && stream.iceInfo().mStreamId == iceStreamId) { // Send generated packet via provider's method to allow custom scheme of encryption - ICELogDebug(<<"Sending ICE packet to " << buffer->remoteAddress().toStdString() << " with " << buffer->comment()); + ICELogDebug(<< "Sending ICE packet to " << buffer->remoteAddress().toStdString() << " with " + << buffer->comment()); - RtpPair& pair = buffer->remoteAddress().family() == AF_INET6 ? stream.socket6() : stream.socket4(); + RtpPair& pair = + buffer->remoteAddress().family() == AF_INET6 ? stream.socket6() : stream.socket4(); PDatagramSocket s = iceComponentId == ICE_RTP_ID ? pair.mRtp : pair.mRtcp; if (s) stream.provider()->sendData(s, buffer->remoteAddress(), buffer->data(), buffer->size()); @@ -491,10 +518,12 @@ void UserAgent::addRootCert(const ByteBuffer& data) if (!mStack) return; resip::Data b(data.data(), data.size()); - try { + try + { mStack->getSecurity()->addRootCertPEM(b); } - catch(...) { + catch (...) + { // Ignore silently } } @@ -538,11 +567,10 @@ std::string UserAgent::formatSipAddress(const std::string& sip) { if (sip.find("sip:") == std::string::npos && sip.find("sips:") == std::string::npos) result = ""; + else if (sip[0] != '<' && sip.find('<') == std::string::npos) + result = "<" + sip + ">"; else - if (sip[0] != '<' && sip.find('<') == std::string::npos) - result = "<" + sip + ">"; - else - result = sip; + result = sip; } return result; } @@ -559,7 +587,7 @@ bool UserAgent::isSipAddressValid(const std::string& sip) s += ">"; resip::Data d(formatSipAddress(s)); - resip::Uri uri(d); + resip::Uri uri(d); result = uri.isWellFormed(); if (result) { @@ -581,9 +609,9 @@ UserAgent::SipAddress UserAgent::parseSipAddress(const std::string& sip) result.mValid = isSipAddressValid(sip); if (result.mValid) { - resip::Data d(formatSipAddress(sip)); + resip::Data d(formatSipAddress(sip)); resip::NameAddr nameaddr(d); - //resip::Uri uri(d); + // resip::Uri uri(d); if (!nameaddr.isWellFormed()) result.mValid = false; else @@ -614,7 +642,7 @@ bool UserAgent::compareSipAddresses(const std::string& sip1, const std::string& return false; resip::Data d1(formatSipAddress(sip1)), d2(formatSipAddress(sip2)); - resip::Uri uri1(d1), uri2(d2); + resip::Uri uri1(d1), uri2(d2); return uri1.getAorNoPort().uppercase() == uri2.getAorNoPort().uppercase(); } @@ -633,14 +661,9 @@ void UserAgent::onCandidateGathered(PSession s, const char* address) // Called when new connectivity check is finished -void UserAgent::onCheckFinished(PSession s, const char* description) -{ +void UserAgent::onCheckFinished(PSession s, const char* description) {} -} - -void UserAgent::onLog(const char* msg) -{ -} +void UserAgent::onLog(const char* msg) {} void UserAgent::sendOffer(Session* session) { @@ -653,10 +676,12 @@ void UserAgent::sendOffer(Session* session) if (session->mOriginVersion == 1) { // Construct INVITE session - auto msg = mDum->makeInviteSession(session->mRemotePeer, session->account()->mProfile, &sdp, session->mResipSession); + auto msg = + mDum->makeInviteSession(session->mRemotePeer, session->account()->mProfile, &sdp, session->mResipSession); // Include user headers - for (Session::UserHeaders::const_iterator iter = session->mUserHeaders.begin(); iter != session->mUserHeaders.end(); iter++) + for (Session::UserHeaders::const_iterator iter = session->mUserHeaders.begin(); + iter != session->mUserHeaders.end(); iter++) { const std::string& name = iter->first; const std::string& value = iter->second; @@ -680,8 +705,8 @@ void UserAgent::sendOffer(Session* session) void UserAgent::onSuccess(resip::ClientRegistrationHandle h, const resip::SipMessage& response) { - ICELogInfo (<< "Registration got 200 response."); - Lock l(mGuard); + ICELogInfo(<< "Registration got 200 response."); + Lock l(mGuard); // Find account by registration handle PAccount account = getAccount(response.header(resip::h_From)); @@ -692,7 +717,7 @@ void UserAgent::onSuccess(resip::ClientRegistrationHandle h, const resip::SipMes // Called when all of my bindings have been removed void UserAgent::onRemoved(resip::ClientRegistrationHandle h, const resip::SipMessage& response) { - ICELogInfo( << "Registration is removed."); + ICELogInfo(<< "Registration is removed."); Lock l(mGuard); @@ -701,20 +726,20 @@ void UserAgent::onRemoved(resip::ClientRegistrationHandle h, const resip::SipMes (*accountIter)->onRemoved(h, response); } -/// call on Retry-After failure. +/// call on Retry-After failure. /// return values: -1 = fail, 0 = retry immediately, N = retry in N seconds int UserAgent::onRequestRetry(resip::ClientRegistrationHandle h, int retrySeconds, const resip::SipMessage& response) { return -1; } -// Called if registration fails, usage will be destroyed (unless a +// Called if registration fails, usage will be destroyed (unless a // Registration retry interval is enabled in the Profile) void UserAgent::onFailure(resip::ClientRegistrationHandle h, const resip::SipMessage& response) { - ICELogInfo (<< "Registration failed with code " << response.header(resip::h_StatusLine).statusCode()); + ICELogInfo(<< "Registration failed with code " << response.header(resip::h_StatusLine).statusCode()); - Lock l(mGuard); + Lock l(mGuard); PAccount account = getAccount(response.header(resip::h_From)); if (account) account->onFailure(h, response); @@ -723,41 +748,31 @@ void UserAgent::onFailure(resip::ClientRegistrationHandle h, const resip::SipMes #pragma endregion -bool UserAgent::operator()(resip::Log::Level level, - const resip::Subsystem& subsystem, - const resip::Data& appName, - const char* file, - int line, - const resip::Data& message, - const resip::Data& messageWithHeaders, - const resip::Data& instanceName) +bool UserAgent::operator()(resip::Log::Level level, const resip::Subsystem& subsystem, const resip::Data& appName, + const char* file, int line, const resip::Data& message, + const resip::Data& messageWithHeaders, const resip::Data& instanceName) { - std::string filename = file; + std::string filename = file; std::stringstream ss; - ss << "File " << strx::extractFilename(filename).c_str() << ", line " << line << ": " << message.c_str(); + ss << "File " << strx::extractFilename(filename).c_str() << ", line " << line << ": " << message.c_str(); if (level <= resip::Log::Crit) - ICELogCritical(<< ss.str()) - else - if (level <= resip::Log::Warning) - ICELogError(<< ss.str().c_str()) - else - if (level < resip::Log::Debug) - ICELogInfo(<< ss.str().c_str()) - else - ICELogDebug(<< ss.str().c_str()) - return false; + ICELogCritical(<< ss.str()) else if (level <= resip::Log::Warning) + ICELogError(<< ss.str().c_str()) else if (level < resip::Log::Debug) + ICELogInfo(<< ss.str().c_str()) else ICELogDebug(<< ss.str().c_str()) return false; } #pragma region INVITE handler -/// called when an initial INVITE or the intial response to an outoing invite -void UserAgent::onNewSession(resip::ClientInviteSessionHandle h, resip::InviteSession::OfferAnswerType oat, const resip::SipMessage& msg) +/// called when an initial INVITE or the intial response to an outoing invite +void UserAgent::onNewSession(resip::ClientInviteSessionHandle h, resip::InviteSession::OfferAnswerType oat, + const resip::SipMessage& msg) { } -void UserAgent::onNewSession(resip::ServerInviteSessionHandle h, resip::InviteSession::OfferAnswerType oat, const resip::SipMessage& msg) +void UserAgent::onNewSession(resip::ServerInviteSessionHandle h, resip::InviteSession::OfferAnswerType oat, + const resip::SipMessage& msg) { ResipSession* rs = CAST2RESIPSESSION(h); if (!rs) @@ -783,7 +798,7 @@ void UserAgent::onNewSession(resip::ServerInviteSessionHandle h, resip::InviteSe // Save remote address s->setRemoteAddress(h->peerAddr().uri().getAor().c_str()); - ICELogInfo( << "Session " << s->sessionId() << ": incoming."); + ICELogInfo(<< "Session " << s->sessionId() << ": incoming."); h->provisional(100); @@ -793,15 +808,11 @@ void UserAgent::onNewSession(resip::ServerInviteSessionHandle h, resip::InviteSe } /// Received a failure response from UAS -void UserAgent::onFailure(resip::ClientInviteSessionHandle, const resip::SipMessage& msg) -{ -} +void UserAgent::onFailure(resip::ClientInviteSessionHandle, const resip::SipMessage& msg) {} /// called when an in-dialog provisional response is received that contains an SDP body -void UserAgent::onEarlyMedia(resip::ClientInviteSessionHandle h, const resip::SipMessage&, const resip::SdpContents&) -{ -} +void UserAgent::onEarlyMedia(resip::ClientInviteSessionHandle h, const resip::SipMessage&, const resip::SdpContents&) {} /// called when dialog enters the Early state - typically after getting 18x @@ -819,7 +830,6 @@ void UserAgent::onProvisional(resip::ClientInviteSessionHandle h, const resip::S int responseCode = msg.header(resip::h_StatusLine).statusCode(); onSessionProvisional(s, responseCode); } - } @@ -835,7 +845,7 @@ void UserAgent::onConnected(resip::ClientInviteSessionHandle h, const resip::Sip if (!s->mOfferAnswerCounter) { - ICELogInfo (<< "Session " << s->sessionId() << ": connected."); + ICELogInfo(<< "Session " << s->sessionId() << ": connected."); // Transfer user headers if (h.isValid()) @@ -843,7 +853,7 @@ void UserAgent::onConnected(resip::ClientInviteSessionHandle h, const resip::Sip onSessionEstablished(s, EV_SIP, RtpPair()); - for (unsigned i=0; imStreamList.size(); i++) + for (unsigned i = 0; i < s->mStreamList.size(); i++) { if (s->mStreamList[i].provider()) s->mStreamList[i].provider()->sessionEstablished(EV_SIP); @@ -864,7 +874,7 @@ void UserAgent::onConnected(resip::InviteSessionHandle h, const resip::SipMessag if (!s) return; - ICELogInfo (<< "Session " << s->mSessionId << ": connected."); + ICELogInfo(<< "Session " << s->mSessionId << ": connected."); // Transfer user headers if (h.isValid()) @@ -872,7 +882,7 @@ void UserAgent::onConnected(resip::InviteSessionHandle h, const resip::SipMessag onSessionEstablished(s, EV_SIP, RtpPair()); - for (unsigned i=0; imStreamList.size(); i++) + for (unsigned i = 0; i < s->mStreamList.size(); i++) { if (s->mStreamList[i].provider()) s->mStreamList[i].provider()->sessionEstablished(EV_SIP); @@ -880,7 +890,8 @@ void UserAgent::onConnected(resip::InviteSessionHandle h, const resip::SipMessag } -void UserAgent::onTerminated(resip::InviteSessionHandle h, resip::InviteSessionHandler::TerminatedReason reason, const resip::SipMessage* related) +void UserAgent::onTerminated(resip::InviteSessionHandle h, resip::InviteSessionHandler::TerminatedReason reason, + const resip::SipMessage* related) { ResipSession* rs = CAST2RESIPSESSION(h); if (!rs) @@ -889,7 +900,7 @@ void UserAgent::onTerminated(resip::InviteSessionHandle h, resip::InviteSessionH if (!s) return; - ICELogInfo( << "Session " << s->mSessionId << ": terminated."); + ICELogInfo(<< "Session " << s->mSessionId << ": terminated."); int errorcode = 0; if (related) @@ -906,24 +917,20 @@ void UserAgent::onTerminated(resip::InviteSessionHandle h, resip::InviteSessionH } /// called when a fork that was created through a 1xx never receives a 2xx -/// because another fork answered and this fork was canceled by a proxy. -void UserAgent::onForkDestroyed(resip::ClientInviteSessionHandle) -{ -} +/// because another fork answered and this fork was canceled by a proxy. +void UserAgent::onForkDestroyed(resip::ClientInviteSessionHandle) {} -/// called when a 3xx with valid targets is encountered in an early dialog +/// called when a 3xx with valid targets is encountered in an early dialog /// This is different then getting a 3xx in onTerminated, as another /// request will be attempted, so the DialogSet will not be destroyed. /// Basically an onTermintated that conveys more information. /// checking for 3xx respones in onTerminated will not work as there may /// be no valid targets. -void UserAgent::onRedirected(resip::ClientInviteSessionHandle, const resip::SipMessage& msg) -{ -} +void UserAgent::onRedirected(resip::ClientInviteSessionHandle, const resip::SipMessage& msg) {} /// Called when an SDP answer is received - has nothing to do with user -/// answering the call +/// answering the call void UserAgent::onAnswer(resip::InviteSessionHandle h, const resip::SipMessage& msg, const resip::SdpContents& sdp) { // Check if session casts ok @@ -936,7 +943,7 @@ void UserAgent::onAnswer(resip::InviteSessionHandle h, const resip::SipMessage& bool iceAvailable = true; - ICELogInfo( << "Session " << s->mSessionId << ": got answer."); + ICELogInfo(<< "Session " << s->mSessionId << ": got answer."); // Check for remote ICE credentials std::string icePwd, iceUfrag; @@ -947,7 +954,7 @@ void UserAgent::onAnswer(resip::InviteSessionHandle h, const resip::SipMessage& if (s->mStreamList.size() < sdp.session().media().size()) { - ICELogError( << "SDP answer has wrong number of streams"); + ICELogError(<< "SDP answer has wrong number of streams"); h->end(); return; } @@ -957,20 +964,20 @@ void UserAgent::onAnswer(resip::InviteSessionHandle h, const resip::SipMessage& if (sdp.session().isConnection()) remoteDefaultIP = sdp.session().connection().getAddress().c_str(); - bool mediasupported = false; + bool mediasupported = false; // Iterate SDP's streams std::list::const_iterator mediaIter; - unsigned streamIndex = 0; + unsigned streamIndex = 0; for (mediaIter = sdp.session().media().begin(), streamIndex = 0; - mediaIter != sdp.session().media().end() && streamIndex < s->mStreamList.size(); - ++mediaIter, ++streamIndex) + mediaIter != sdp.session().media().end() && streamIndex < s->mStreamList.size(); ++mediaIter, ++streamIndex) { - Session::Stream& stream = s->mStreamList[streamIndex]; - const resip::SdpContents::Session::Medium& remoteStream = *mediaIter; + Session::Stream& stream = s->mStreamList[streamIndex]; + const resip::SdpContents::Session::Medium& remoteStream = *mediaIter; // Update remote default ip if available - const std::list& streamConnections = remoteStream.getMediumConnections(); + const std::list& streamConnections = + remoteStream.getMediumConnections(); if (streamConnections.size()) remoteDefaultIP = streamConnections.front().getAddress().c_str(); @@ -984,24 +991,24 @@ void UserAgent::onAnswer(resip::InviteSessionHandle h, const resip::SipMessage& // Deactivate rejected provider if (stream.provider()) { - stream.provider()->sessionTerminated(); // close corresponding media - stream.setProvider( PDataProvider() ); // free provider - SocketHeap::instance().freeSocketPair( stream.socket4() ); // close provider's socket ip4 - SocketHeap::instance().freeSocketPair( stream.socket6() ); // close provider's socket ip6 - s->mIceStack->removeStream( stream.iceInfo().mStreamId ); // remove stream from ice stack + stream.provider()->sessionTerminated(); // close corresponding media + stream.setProvider(PDataProvider()); // free provider + SocketHeap::instance().freeSocketPair(stream.socket4()); // close provider's socket ip4 + SocketHeap::instance().freeSocketPair(stream.socket6()); // close provider's socket ip6 + s->mIceStack->removeStream(stream.iceInfo().mStreamId); // remove stream from ice stack } continue; } // Try to parse SDP with ICE stack - unsigned short remoteDefaultPort = remoteStream.port(); + unsigned short remoteDefaultPort = remoteStream.port(); // Extract remote ICE candidates vector const std::list candidateList = remoteStream.getValues("candidate"); if (candidateList.empty()) iceAvailable = false; - std::vector candidateVector; + std::vector candidateVector; std::list::const_iterator cit = candidateList.begin(); for (; cit != candidateList.end(); ++cit) candidateVector.push_back(cit->c_str()); @@ -1016,10 +1023,11 @@ void UserAgent::onAnswer(resip::InviteSessionHandle h, const resip::SipMessage& // Corresponding turn allocation will be removed in this case. try { - if (!s->mIceStack->processSdpOffer(stream.iceInfo().mStreamId, candidateVector, remoteDefaultIP, remoteDefaultPort, mConfig[CONFIG_DEFERRELAYED].asBool())) + if (!s->mIceStack->processSdpOffer(stream.iceInfo().mStreamId, candidateVector, remoteDefaultIP, + remoteDefaultPort, mConfig[CONFIG_DEFERRELAYED].asBool())) iceAvailable = false; } - catch(...) + catch (...) { iceAvailable = false; } @@ -1027,16 +1035,15 @@ void UserAgent::onAnswer(resip::InviteSessionHandle h, const resip::SipMessage& // Process media description with provider if (stream.provider()) { - if (stream.provider()->processSdpOffer( remoteStream, Sdp_Answer )) + if (stream.provider()->processSdpOffer(remoteStream, Sdp_Answer)) { - InternetAddress addr(remoteDefaultIP, remoteDefaultPort), addr2(remoteDefaultIP, remoteDefaultPort+1); + InternetAddress addr(remoteDefaultIP, remoteDefaultPort), addr2(remoteDefaultIP, remoteDefaultPort + 1); // See if remote stream has "rtcp" or "rtcp-mux" attributes if (remoteStream.exists("rtcp")) - addr2.setPort( strx::toInt(remoteStream.getValues("rtcp").front().c_str(), remoteDefaultPort+1) ); - else - if (remoteStream.exists("rtcp-mux")) - addr2.setPort( remoteDefaultPort ); + addr2.setPort(strx::toInt(remoteStream.getValues("rtcp").front().c_str(), remoteDefaultPort + 1)); + else if (remoteStream.exists("rtcp-mux")) + addr2.setPort(remoteDefaultPort); stream.provider()->setDestinationAddress(RtpPair(addr, addr2)); mediasupported = true; } @@ -1083,7 +1090,7 @@ void UserAgent::onAnswer(resip::InviteSessionHandle h, const resip::SipMessage& void UserAgent::onOffer(resip::InviteSessionHandle h, const resip::SipMessage& msg, const resip::SdpContents& sdp) { ResipSession* rs = CAST2RESIPSESSION(h); - PSession s = rs ? getUserSession(rs->mSessionId) : PSession(); + PSession s = rs ? getUserSession(rs->mSessionId) : PSession(); if (!s) { h->reject(488); @@ -1101,23 +1108,22 @@ void UserAgent::onOffer(resip::InviteSessionHandle h, const resip::SipMessage& m if (sdp.session().exists("ice-ufrag")) iceUfrag = sdp.session().getValues("ice-ufrag").front().c_str(); - //ice::Stack& ice = *s->mIceStack; + // ice::Stack& ice = *s->mIceStack; - uint64_t version = sdp.session().origin().getVersion(); + uint64_t version = sdp.session().origin().getVersion(); std::string remoteIp = sdp.session().connection().getAddress().c_str(); // Default to 200: a retransmitted offer (same origin version) keeps the session. - int code = 200; + int code = 200; if ((uint64_t)-1 == s->mRemoteOriginVersion) { code = s->processSdp(version, iceAvailable, icePwd, iceUfrag, remoteIp, sdp.session().media()); } - else - if (version == s->mRemoteOriginVersion) - { - // Timer, answer with previous SDP - //session->processTimer(); - } - if (version == s->mRemoteOriginVersion+1) + else if (version == s->mRemoteOriginVersion) + { + // Timer, answer with previous SDP + // session->processTimer(); + } + if (version == s->mRemoteOriginVersion + 1) { // Updated offer. Here we must check if ICE has to be restarted. code = s->processSdp(version, iceAvailable, icePwd, iceUfrag, remoteIp, sdp.session().media()); @@ -1149,64 +1155,43 @@ void UserAgent::onOffer(resip::InviteSessionHandle h, const resip::SipMessage& m /// called when an Invite w/out SDP is sent, or any other context which /// requires an SDP offer from the user -void UserAgent::onOfferRequired(resip::InviteSessionHandle, const resip::SipMessage& msg) -{ -} +void UserAgent::onOfferRequired(resip::InviteSessionHandle, const resip::SipMessage& msg) {} /// called if an offer in a UPDATE or re-INVITE was rejected - not real /// useful. A SipMessage is provided if one is available -void UserAgent::onOfferRejected(resip::InviteSessionHandle, const resip::SipMessage* msg) -{ -} +void UserAgent::onOfferRejected(resip::InviteSessionHandle, const resip::SipMessage* msg) {} -/// called when INFO message is received -void UserAgent::onInfo(resip::InviteSessionHandle, const resip::SipMessage& msg) -{ -} +/// called when INFO message is received +void UserAgent::onInfo(resip::InviteSessionHandle, const resip::SipMessage& msg) {} -/// called when response to INFO message is received -void UserAgent::onInfoSuccess(resip::InviteSessionHandle, const resip::SipMessage& msg) -{ -} +/// called when response to INFO message is received +void UserAgent::onInfoSuccess(resip::InviteSessionHandle, const resip::SipMessage& msg) {} -void UserAgent::onInfoFailure(resip::InviteSessionHandle, const resip::SipMessage& msg) -{ -} +void UserAgent::onInfoFailure(resip::InviteSessionHandle, const resip::SipMessage& msg) {} -/// called when MESSAGE message is received -void UserAgent::onMessage(resip::InviteSessionHandle, const resip::SipMessage& msg) -{ -} +/// called when MESSAGE message is received +void UserAgent::onMessage(resip::InviteSessionHandle, const resip::SipMessage& msg) {} -/// called when response to MESSAGE message is received -void UserAgent::onMessageSuccess(resip::InviteSessionHandle, const resip::SipMessage& msg) -{ -} +/// called when response to MESSAGE message is received +void UserAgent::onMessageSuccess(resip::InviteSessionHandle, const resip::SipMessage& msg) {} -void UserAgent::onMessageFailure(resip::InviteSessionHandle, const resip::SipMessage& msg) -{ -} +void UserAgent::onMessageFailure(resip::InviteSessionHandle, const resip::SipMessage& msg) {} /// called when an REFER message is received. The refer is accepted or /// rejected using the server subscription. If the offer is accepted, /// DialogUsageManager::makeInviteSessionFromRefer can be used to create an /// InviteSession that will send notify messages using the ServerSubscription -void UserAgent::onRefer(resip::InviteSessionHandle, resip::ServerSubscriptionHandle, const resip::SipMessage& msg) -{ -} +void UserAgent::onRefer(resip::InviteSessionHandle, resip::ServerSubscriptionHandle, const resip::SipMessage& msg) {} -void UserAgent::onReferNoSub(resip::InviteSessionHandle, const resip::SipMessage& msg) -{ -} +void UserAgent::onReferNoSub(resip::InviteSessionHandle, const resip::SipMessage& msg) {} -/// called when an REFER message receives a failure response -void UserAgent::onReferRejected(resip::InviteSessionHandle, const resip::SipMessage& msg) -{ -} +/// called when an REFER message receives a failure response +void UserAgent::onReferRejected(resip::InviteSessionHandle, const resip::SipMessage& msg) {} -/// called when an REFER message receives an accepted response -void UserAgent::onReferAccepted(resip::InviteSessionHandle, resip::ClientSubscriptionHandle, const resip::SipMessage& msg) +/// called when an REFER message receives an accepted response +void UserAgent::onReferAccepted(resip::InviteSessionHandle, resip::ClientSubscriptionHandle, + const resip::SipMessage& msg) { } @@ -1215,25 +1200,21 @@ void UserAgent::onDnsResult(const resip::DNSResult& result if (result.status == 0) { resip::Data foundAddress = result.records.front().host(); - ICELogInfo( << "Success to resolve STUN/TURN address to " << foundAddress.c_str()); + ICELogInfo(<< "Success to resolve STUN/TURN address to " << foundAddress.c_str()); mConfig[CONFIG_STUNSERVER_IP] = std::string(foundAddress.c_str()); onStart(0); } else { - ICELogError( << "Failed to resolve STUN or TURN server IP address."); + ICELogError(<< "Failed to resolve STUN or TURN server IP address."); int startCode = mConfig[CONFIG_STUNSERVER_NAME].asStdString().empty() ? 0 : 503; onStart(startCode); } } -void UserAgent::onDnsResult(const resip::DNSResult& result) -{ -} +void UserAgent::onDnsResult(const resip::DNSResult& result) {} -void UserAgent::onDnsResult(const resip::DNSResult& result) -{ -} +void UserAgent::onDnsResult(const resip::DNSResult& result) {} void UserAgent::onDnsResult(const resip::DNSResult& result) { @@ -1251,7 +1232,7 @@ void UserAgent::onDnsResult(const resip::DNSResult& resul void UserAgent::onSuccess(resip::ClientPublicationHandle h, const resip::SipMessage& status) { resip::NameAddr from = status.header(resip::h_To); - PAccount account = getAccount(from); + PAccount account = getAccount(from); if (account) account->mPublication = h; onPublicationSuccess(account); @@ -1260,7 +1241,7 @@ void UserAgent::onSuccess(resip::ClientPublicationHandle h, const resip::SipMess void UserAgent::onRemove(resip::ClientPublicationHandle, const resip::SipMessage& status) { resip::NameAddr to = status.header(resip::h_To); - PAccount account = getAccount(to); + PAccount account = getAccount(to); if (account) account->mPublication = resip::ClientPublicationHandle(); onPublicationTerminated(account, 0); @@ -1269,7 +1250,7 @@ void UserAgent::onRemove(resip::ClientPublicationHandle, const resip::SipMessage void UserAgent::onFailure(resip::ClientPublicationHandle, const resip::SipMessage& status) { resip::NameAddr to = status.header(resip::h_To); - PAccount account = getAccount(to); + PAccount account = getAccount(to); if (account) account->mPublication = resip::ClientPublicationHandle(); onPublicationTerminated(account, status.header(resip::h_StatusLine).statusCode()); @@ -1281,28 +1262,20 @@ int UserAgent::onRequestRetry(resip::ClientPublicationHandle, int retrySeconds, } +void UserAgent::onPublicationSuccess(PAccount account) {} -void UserAgent::onPublicationSuccess(PAccount account) -{ -} - -void UserAgent::onPublicationTerminated(PAccount account, int code) -{ -} +void UserAgent::onPublicationTerminated(PAccount account, int code) {} #pragma endregion #pragma region Subscriptions -void UserAgent::onClientObserverStart(PClientObserver observer) -{ -} +void UserAgent::onClientObserverStart(PClientObserver observer) {} -void UserAgent::onClientObserverStop(PClientObserver observer, int code) -{ -} +void UserAgent::onClientObserverStop(PClientObserver observer, int code) {} -void UserAgent::onPresenceUpdate(PClientObserver observer, const std::string& peer, bool online, const std::string& content) +void UserAgent::onPresenceUpdate(PClientObserver observer, const std::string& peer, bool online, + const std::string& content) { } @@ -1318,12 +1291,12 @@ void UserAgent::onNewSubscription(resip::ServerSubscriptionHandle h, const resip return; // Get the event package name - const char* event = sub.header(resip::h_Event).value().c_str(); + const char* event = sub.header(resip::h_Event).value().c_str(); // Get the remote party - const char* peer = sub.header(resip::h_From).uri().getAor().c_str(); + const char* peer = sub.header(resip::h_From).uri().getAor().c_str(); - PAccount account = getAccount(sub.header(resip::h_From)); + PAccount account = getAccount(sub.header(resip::h_From)); PServerObserver so(new ServerObserver()); so->mHandle = h; so->mPeer = peer; @@ -1351,13 +1324,9 @@ void UserAgent::onTerminated(resip::ServerSubscriptionHandle h) } } -void UserAgent::onServerObserverStart(PServerObserver observer) -{ -} +void UserAgent::onServerObserverStart(PServerObserver observer) {} -void UserAgent::onServerObserverStop(PServerObserver observer, int code) -{ -} +void UserAgent::onServerObserverStop(PServerObserver observer, int code) {} void UserAgent::onUpdate(resip::ClientSubscriptionHandle h, const resip::SipMessage& notify) { @@ -1374,13 +1343,13 @@ void UserAgent::onUpdate(resip::ClientSubscriptionHandle h, const resip::SipMess h->end(); return; } - PClientObserver observer = observerIter->second; + PClientObserver observer = observerIter->second; std::vector availableContacts; h->acceptUpdate(); // Find "from" header - resip::Uri from = notify.header(resip::h_From).uri(); + resip::Uri from = notify.header(resip::h_From).uri(); // Find content resip::Contents* contents = notify.getContents(); @@ -1390,84 +1359,83 @@ void UserAgent::onUpdate(resip::ClientSubscriptionHandle h, const resip::SipMess if (resip::Pidf* pidf = dynamic_cast(contents)) { resip::Data body = pidf->getBodyData(); - bool online = pidf->getSimpleStatus(&body); + bool online = pidf->getSimpleStatus(&body); onPresenceUpdate(observer, observer->peer(), online, std::string(body.c_str(), body.size())); } - else - if (resip::MultipartRelatedContents* mr = dynamic_cast(contents)) + else if (resip::MultipartRelatedContents* mr = dynamic_cast(contents)) + { + resip::MultipartRelatedContents::Parts& parts = mr->parts(); + for (resip::MultipartRelatedContents::Parts::const_iterator i = parts.begin(); i != parts.end(); ++i) { - resip::MultipartRelatedContents::Parts& parts = mr->parts(); - for( resip::MultipartRelatedContents::Parts::const_iterator i = parts.begin(); i != parts.end(); ++i) + resip::Contents* c = *i; + assert(c); + resip::Mime m = c->getType(); + if (resip::Rlmi* rlmi = dynamic_cast(c)) { - resip::Contents* c = *i; - assert( c ); - resip::Mime m = c->getType(); - if (resip::Rlmi* rlmi = dynamic_cast(c)) + resip::Data d = rlmi->getBodyData(); + // Workaround for XMLCursor bug + if (d.find(resip::Data("getBodyData(); - // Workaround for XMLCursor bug - if (d.find(resip::Data(" tag in rlmi"); + } + else + { + for (bool hasRecord = c.firstChild(); hasRecord; hasRecord = c.nextSibling()) { - ICELogError( << "Failed to find tag in rlmi"); - } - else - { - for (bool hasRecord = c.firstChild(); hasRecord; hasRecord = c.nextSibling()) + if (c.getTag() != "resource") { - if (c.getTag() != "resource") + ICELogError(<< "Failed to find tag in rlmi"); + } + else + { + // Check if c has + + resip::XMLCursor::AttributeMap::const_iterator attrIter = c.getAttributes().find("uri"); + if (attrIter != c.getAttributes().end()) { - ICELogError( << "Failed to find tag in rlmi"); - } - else - { - // Check if c has + // Save uri + resip::Data uri = attrIter->second; - resip::XMLCursor::AttributeMap::const_iterator attrIter = c.getAttributes().find("uri"); - if (attrIter != c.getAttributes().end()) - { - // Save uri - resip::Data uri = attrIter->second; + // Check if there is tag + bool instance = false; + for (bool hasChild = c.firstChild(); hasChild; hasChild = c.nextSibling()) + instance |= c.getTag() == "instance"; + c.parent(); - // Check if there is tag - bool instance = false; - for (bool hasChild = c.firstChild(); hasChild; hasChild = c.nextSibling()) - instance |= c.getTag() == "instance"; - c.parent(); - - // Save result - if (instance) - availableContacts.push_back( attrIter->second ); - } + // Save result + if (instance) + availableContacts.push_back(attrIter->second); } } } } - else - if (resip::Pidf* pidf = dynamic_cast(c)) - { - resip::Data body = pidf->getBodyData(); - bool online = pidf->getSimpleStatus(&body); - resip::Data entity = pidf->getEntity().getAorNoPort(); - if (entity.find("sip:") == resip::Data::npos && entity.find("sips:") == resip::Data::npos) - entity = resip::Data("sip:") + entity; - onPresenceUpdate(observer, entity.c_str(), online, std::string(body.c_str(), body.size())); + } + else if (resip::Pidf* pidf = dynamic_cast(c)) + { + resip::Data body = pidf->getBodyData(); + bool online = pidf->getSimpleStatus(&body); + resip::Data entity = pidf->getEntity().getAorNoPort(); + if (entity.find("sip:") == resip::Data::npos && entity.find("sips:") == resip::Data::npos) + entity = resip::Data("sip:") + entity; + onPresenceUpdate(observer, entity.c_str(), online, std::string(body.c_str(), body.size())); - // Drop corresponding record from availableContacts - std::vector::iterator ci = std::find(availableContacts.begin(), availableContacts.end(), entity); - if (ci != availableContacts.end()) - availableContacts.erase(ci); - } + // Drop corresponding record from availableContacts + std::vector::iterator ci = + std::find(availableContacts.begin(), availableContacts.end(), entity); + if (ci != availableContacts.end()) + availableContacts.erase(ci); } } + } } - for (unsigned i=0; isessionId(), s->remoteAddress(), s->tag()); } -void UserAgent::onFailure(resip::ClientPagerMessageHandle h, const resip::SipMessage& status, std::unique_ptr contents) +void UserAgent::onFailure(resip::ClientPagerMessageHandle h, const resip::SipMessage& status, + std::unique_ptr contents) { if (!h.isValid()) return; ResipSession* s = CAST2RESIPSESSION(h); if (!s) return; - onMessageFailed(getAccount(status.header(resip::h_From)), s->sessionId(), s->remoteAddress(), status.header(resip::h_StatusLine).statusCode(), s->tag()); + onMessageFailed(getAccount(status.header(resip::h_From)), s->sessionId(), s->remoteAddress(), + status.header(resip::h_StatusLine).statusCode(), s->tag()); } void UserAgent::onMessageArrived(resip::ServerPagerMessageHandle h, const resip::SipMessage& message) @@ -1575,8 +1539,8 @@ void UserAgent::onMessageArrived(resip::ServerPagerMessageHandle h, const resip: if (!h.isValid()) return; resip::NameAddr from = message.header(resip::h_From); - std::string peer(from.uri().getAor().c_str()); - PAccount account = getAccount(from); + std::string peer(from.uri().getAor().c_str()); + PAccount account = getAccount(from); h->send(h->accept()); resip::Contents* c = message.getContents(); if (!c) @@ -1590,20 +1554,20 @@ void UserAgent::onMessageArrived(resip::ServerPagerMessageHandle h, const resip: void UserAgent::updateInterfaceList() { - //ICEImpl::ICENetworkHelper::instance().reload(); + // ICEImpl::ICENetworkHelper::instance().reload(); } -void UserAgent::onMessageArrived(PAccount /*account*/, const std::string& /*peer*/, const void* /*ptr*/, unsigned /*length*/) +void UserAgent::onMessageArrived(PAccount /*account*/, const std::string& /*peer*/, const void* /*ptr*/, + unsigned /*length*/) { } -void UserAgent::onMessageFailed(PAccount /*account*/, int /*id*/, const std::string& /*peer*/, int /*code*/, void* /*tag*/) +void UserAgent::onMessageFailed(PAccount /*account*/, int /*id*/, const std::string& /*peer*/, int /*code*/, + void* /*tag*/) { } -void UserAgent::onMessageSent(PAccount /*account*/, int /*id*/, const std::string& /*peer*/, void* /*tag*/) -{ -} +void UserAgent::onMessageSent(PAccount /*account*/, int /*id*/, const std::string& /*peer*/, void* /*tag*/) {} VariantMap& UserAgent::config() { @@ -1616,7 +1580,7 @@ VariantMap& UserAgent::config() while (endLine != resip::Data::npos) { output.push_back(content.substr(startLine, endLine)); - + startLine = endLine + 2; endLine = content.find("\r\n", startLine); } @@ -1636,7 +1600,7 @@ VariantMap& UserAgent::config() { name = input.substr(0, p); value = input.substr(p+1, input.size() - p - 1); - + // Trim leading whitespace if (value.size()) { @@ -1649,9 +1613,9 @@ VariantMap& UserAgent::config() void UserAgent::onSipMessage(int flow, const char* msg, unsigned int length, const sockaddr* addr, unsigned int addrlen) { - std::string d(msg, length); + std::string d(msg, length); ice::NetworkAddress address(*addr, addrlen); - std::string addressText = address.toStdString(); + std::string addressText = address.toStdString(); /*switch (flow) { @@ -1678,7 +1642,8 @@ PSession UserAgent::getUserSession(int sessionId) PAccount UserAgent::getAccount(const resip::NameAddr& myAddr) { PAccount acc; - for (AccountSet::iterator accountIter = mAccountSet.begin(); accountIter != mAccountSet.end() && !acc; accountIter++) + for (AccountSet::iterator accountIter = mAccountSet.begin(); accountIter != mAccountSet.end() && !acc; + accountIter++) if ((*accountIter)->isResponsibleFor(myAddr)) acc = *accountIter; @@ -1688,7 +1653,8 @@ PAccount UserAgent::getAccount(const resip::NameAddr& myAddr) PAccount UserAgent::getAccount(Account* account) { PAccount acc; - for (AccountSet::iterator accountIter = mAccountSet.begin(); accountIter != mAccountSet.end() && !acc; accountIter++) + for (AccountSet::iterator accountIter = mAccountSet.begin(); accountIter != mAccountSet.end() && !acc; + accountIter++) if (accountIter->get() == account) acc = *accountIter; @@ -1697,7 +1663,14 @@ PAccount UserAgent::getAccount(Account* account) PAccount UserAgent::getAccount(int sessionId) { - auto profileIter = std::find_if(mAccountSet.begin(), mAccountSet.end(), [=](const AccountSet::value_type& v) {if (v->mRegistration) return v->mRegistration->sessionId() == sessionId; else return false;}); + auto profileIter = std::find_if(mAccountSet.begin(), mAccountSet.end(), + [=](const AccountSet::value_type& v) + { + if (v->mRegistration) + return v->mRegistration->sessionId() == sessionId; + else + return false; + }); return (profileIter != mAccountSet.end()) ? *profileIter : PAccount(); } diff --git a/src/engine/endpoint/EP_Engine.h b/src/engine/endpoint/EP_Engine.h index 92103971..7770fff4 100644 --- a/src/engine/endpoint/EP_Engine.h +++ b/src/engine/endpoint/EP_Engine.h @@ -70,45 +70,47 @@ enum enum { - CONFIG_IPV4 = 0, // Use IP4 - CONFIG_IPV6, // Use IP6. - CONFIG_USERNAME, // Username. String value. - CONFIG_DOMAIN, // Domain. String value. - CONFIG_PASSWORD, // Password. String value. - CONFIG_RINSTANCE, // Determines if SIP rinstance field has to be used during registration. Boolean value. - CONFIG_INSTANCE_ID, // Instance id. It is alternative option to rinstance. - CONFIG_DISPLAYNAME, // Optional user display name. String value. - CONFIG_DOMAINPORT, // Optional domain port number. Integer value. - CONFIG_REGISTERDURATION, // Wanted duration for registration. Integer value. It is MANDATORY value. - CONFIG_RPORT, // Use SIP rport field. Recommended to set it to true. Boolean value. - CONFIG_KEEPALIVETIME, // Interval between UDP keep-alive messages. Boolean value. - CONFIG_RELAY, // Sets if TURN server must be used instead of STUN. Boolean value. - CONFIG_ICETIMEOUT, // Optional timeout for ICE connectivity checks and candidate gathering. Integer value. - CONFIG_ICEUSERNAME, // Optional username for TURN server. String value. - CONFIG_ICEPASSWORD, // Optional password for TURN server. String value. - CONFIG_SIPS, // Marks if account credentials are sips: scheme. Boolean value. - CONFIG_STUNSERVER_IP, // Optional IP address of STUN/TURN server. String value. It is better to use CONFIG_STUNSERVER_NAME. - CONFIG_STUNSERVER_NAME, // Host name of STUN/TURN server. stun.xten.com for example. String value. - CONFIG_STUNSERVER_PORT, // Port number of STUN/TURN server. Integer value. - CONFIG_USERAGENT, // Name of user agent in SIP headers. String value. - CONFIG_ICEREQUIRED, // ICE MUST be present in remote peer offers and answers. Boolean value. - CONFIG_TRANSPORT, // 0 - all transports, 1 - UDP, 2 - TCP, 3 - TLS, - CONFIG_SUBSCRIPTION_TIME, // Subscription time (in seconds) + CONFIG_IPV4 = 0, // Use IP4 + CONFIG_IPV6, // Use IP6. + CONFIG_USERNAME, // Username. String value. + CONFIG_DOMAIN, // Domain. String value. + CONFIG_PASSWORD, // Password. String value. + CONFIG_RINSTANCE, // Determines if SIP rinstance field has to be used during registration. Boolean value. + CONFIG_INSTANCE_ID, // Instance id. It is alternative option to rinstance. + CONFIG_DISPLAYNAME, // Optional user display name. String value. + CONFIG_DOMAINPORT, // Optional domain port number. Integer value. + CONFIG_REGISTERDURATION, // Wanted duration for registration. Integer value. It is MANDATORY value. + CONFIG_RPORT, // Use SIP rport field. Recommended to set it to true. Boolean value. + CONFIG_KEEPALIVETIME, // Interval between UDP keep-alive messages. Boolean value. + CONFIG_RELAY, // Sets if TURN server must be used instead of STUN. Boolean value. + CONFIG_ICETIMEOUT, // Optional timeout for ICE connectivity checks and candidate gathering. Integer value. + CONFIG_ICEUSERNAME, // Optional username for TURN server. String value. + CONFIG_ICEPASSWORD, // Optional password for TURN server. String value. + CONFIG_SIPS, // Marks if account credentials are sips: scheme. Boolean value. + CONFIG_STUNSERVER_IP, // Optional IP address of STUN/TURN server. String value. It is better to use + // CONFIG_STUNSERVER_NAME. + CONFIG_STUNSERVER_NAME, // Host name of STUN/TURN server. stun.xten.com for example. String value. + CONFIG_STUNSERVER_PORT, // Port number of STUN/TURN server. Integer value. + CONFIG_USERAGENT, // Name of user agent in SIP headers. String value. + CONFIG_ICEREQUIRED, // ICE MUST be present in remote peer offers and answers. Boolean value. + CONFIG_TRANSPORT, // 0 - all transports, 1 - UDP, 2 - TCP, 3 - TLS, + CONFIG_SUBSCRIPTION_TIME, // Subscription time (in seconds) CONFIG_SUBSCRIPTION_REFRESHTIME, // Refresh interval for subscriptions - CONFIG_DNS_CACHE_TIME, // DNS cache time; default is 86400 seconds - CONFIG_PRESENCE_ID, // Tuple ID used in presence publishing; determines source device - CONFIG_ROOTCERT, // Additional root cert in PEM format; string. - CONFIG_CACHECREDENTIALS, // Attempt to cache credentials that comes in response from PBX. Use them when possible to reduce number of steps of SIP transaction - CONFIG_RTCP_ATTR, // Use "rtcp" attribute in sdp. Default value is true. - CONFIG_MULTIPLEXING, // Do rtp/rtcp multiplexing - CONFIG_DEFERRELAYED, // Defer relayed media path - CONFIG_PROXY, // Proxy host name or IP address - CONFIG_PROXYPORT, // Proxy port number - CONFIG_CODEC_PRIORITY, // Another VariantMap with codec priorities, - CONFIG_ACCOUNT, // VariantMap with account configuration - CONFIG_EXTERNALIP, // Use external/public IP in outgoing requests - CONFIG_OWN_DNS, // Use predefined DNS servers - CONFIG_REGID // reg-id value from RFC5626, + CONFIG_DNS_CACHE_TIME, // DNS cache time; default is 86400 seconds + CONFIG_PRESENCE_ID, // Tuple ID used in presence publishing; determines source device + CONFIG_ROOTCERT, // Additional root cert in PEM format; string. + CONFIG_CACHECREDENTIALS, // Attempt to cache credentials that comes in response from PBX. Use them when possible to + // reduce number of steps of SIP transaction + CONFIG_RTCP_ATTR, // Use "rtcp" attribute in sdp. Default value is true. + CONFIG_MULTIPLEXING, // Do rtp/rtcp multiplexing + CONFIG_DEFERRELAYED, // Defer relayed media path + CONFIG_PROXY, // Proxy host name or IP address + CONFIG_PROXYPORT, // Proxy port number + CONFIG_CODEC_PRIORITY, // Another VariantMap with codec priorities, + CONFIG_ACCOUNT, // VariantMap with account configuration + CONFIG_EXTERNALIP, // Use external/public IP in outgoing requests + CONFIG_OWN_DNS, // Use predefined DNS servers + CONFIG_REGID // reg-id value from RFC5626, }; // Conntype parameter for OnSessionEstablished event @@ -130,7 +132,7 @@ public: typedef std::vector SIPActionVector; // Session termination reason -enum +enum { Error, Timeout, @@ -139,35 +141,37 @@ enum RemoteBye, LocalCancel, RemoteCancel, - Rejected, //Only as UAS, UAC has distinct onFailure callback + Rejected, // Only as UAS, UAC has distinct onFailure callback Referred }; -class UserAgent: public resip::ClientRegistrationHandler, - public resip::InviteSessionHandler, - public resip::DumShutdownHandler, - public resip::ExternalLogger, +class UserAgent : public resip::ClientRegistrationHandler, + public resip::InviteSessionHandler, + public resip::DumShutdownHandler, + public resip::ExternalLogger, public resip::DnsResultSink, - public resip::ClientSubscriptionHandler, + public resip::ClientSubscriptionHandler, public resip::ServerSubscriptionHandler, - public resip::ClientPagerMessageHandler, + public resip::ClientPagerMessageHandler, public resip::ServerPagerMessageHandler, public resip::ClientPublicationHandler -//public resip::InternalTransport::TransportLogger +// public resip::InternalTransport::TransportLogger { friend class Account; friend class Session; friend class ResipSession; friend class NATDecorator; friend class WatcherQueue; + public: - /* Compares two sip addresses. Returns true if they represent the same entity - user and domain are the same. Otherwise returns false. */ - static bool compareSipAddresses(const std::string& sip1, const std::string& sip2); + /* Compares two sip addresses. Returns true if they represent the same entity - user and domain are the same. + * Otherwise returns false. */ + static bool compareSipAddresses(const std::string& sip1, const std::string& sip2); static std::string formatSipAddress(const std::string& sip); - static bool isSipAddressValid(const std::string& sip); + static bool isSipAddressValid(const std::string& sip); struct SipAddress { - bool mValid; + bool mValid; std::string mScheme; std::string mUsername; std::string mDomain; @@ -181,113 +185,118 @@ public: /* Brings user agent online. Basically it creates a signalling socket(s). This is asynchronous method. */ - void start(); + void start(); /* Shutdowns user agent. It closes all sessions, tries to unregister from server and disconnects from it. This is asynchronous method. onStop() event will be called later */ - void shutdown(); + void shutdown(); - /* Emergency stop. Please always call shutdown() before this. Kills registration, sessions & presence - everything. onStop() is called in context of this method. */ - void stop(); + /* Emergency stop. Please always call shutdown() before this. Kills registration, sessions & presence - everything. + * onStop() is called in context of this method. */ + void stop(); /* Checks if user agent is active (started). */ - bool active(); + bool active(); /* Used to refresh existing registration(s), publication, subscriptions. */ - void refresh(); + void refresh(); /* Runs sip & ice stacks. Event handlers are called in its context. */ - void process(); + void process(); /* Adds root cert in PEM format. Usable after start() call. */ - void addRootCert(const ByteBuffer& data); + void addRootCert(const ByteBuffer& data); - PAccount createAccount(PVariantMap config); - void deleteAccount(PAccount account); + PAccount createAccount(PVariantMap config); + void deleteAccount(PAccount account); /* Creates session. Returns session ID. */ - PSession createSession(PAccount account); + PSession createSession(PAccount account); // Must be called when IP interface list is changed - void updateInterfaceList(); + void updateInterfaceList(); // Called on new incoming session; providers shoukld virtual PDataProvider onProviderNeeded(const std::string& name) = 0; // Called on new session offer - virtual void onNewSession(PSession s) = 0; + virtual void onNewSession(PSession s) = 0; // Called when session is terminated - virtual void onSessionTerminated(PSession s, int responsecode, int reason) = 0; + virtual void onSessionTerminated(PSession s, int responsecode, int reason) = 0; // Called when session is established ok i.e. after all ICE signalling is finished // Conntype is type of establish event - EV_SIP or EV_ICE - virtual void onSessionEstablished(PSession s, int conntype, const RtpPair& p) = 0; + virtual void onSessionEstablished(PSession s, int conntype, const RtpPair& p) = 0; // Called when client session gets - virtual void onSessionProvisional(PSession s, int code) = 0; + virtual void onSessionProvisional(PSession s, int code) = 0; // Called when user agent started - virtual void onStart(int errorcode) = 0; + virtual void onStart(int errorcode) = 0; // Called when user agent stopped - virtual void onStop() = 0; + virtual void onStop() = 0; // Called when account registered - virtual void onAccountStart(PAccount account) = 0; + virtual void onAccountStart(PAccount account) = 0; // Called when account removed or failed (non zero error code) - virtual void onAccountStop(PAccount account, int error) = 0; + virtual void onAccountStop(PAccount account, int error) = 0; // Called when connectivity checks failed. - virtual void onConnectivityFailed(PSession s) = 0; + virtual void onConnectivityFailed(PSession s) = 0; // Called when new candidate is gathered - virtual void onCandidateGathered(PSession s, const char* address); + virtual void onCandidateGathered(PSession s, const char* address); // Called when network change detected - virtual void onNetworkChange(PSession s) = 0; + virtual void onNetworkChange(PSession s) = 0; // Called when all candidates are gathered - virtual void onGathered(PSession s); + virtual void onGathered(PSession s); // Called when new connectivity check is finished - virtual void onCheckFinished(PSession s, const char* description); + virtual void onCheckFinished(PSession s, const char* description); // Called when log message must be recorded - virtual void onLog(const char* msg); + virtual void onLog(const char* msg); // Called when problem with SIP connection(s) detected - virtual void onSipConnectionFailed() = 0; + virtual void onSipConnectionFailed() = 0; // Subscribe/publish presence methods - virtual void onPublicationSuccess(PAccount acc); - virtual void onPublicationTerminated(PAccount acc, int code); - virtual void onClientObserverStart(PClientObserver observer); - virtual void onServerObserverStart(PServerObserver observer); - virtual void onClientObserverStop(PClientObserver observer, int code); - virtual void onServerObserverStop(PServerObserver observer, int code); + virtual void onPublicationSuccess(PAccount acc); + virtual void onPublicationTerminated(PAccount acc, int code); + virtual void onClientObserverStart(PClientObserver observer); + virtual void onServerObserverStart(PServerObserver observer); + virtual void onClientObserverStop(PClientObserver observer, int code); + virtual void onServerObserverStop(PServerObserver observer, int code); - virtual void onPresenceUpdate(PClientObserver observer, const std::string& peer, bool online, const std::string& content); - virtual void onMessageArrived(PAccount account, const std::string& peer, const void* ptr, unsigned length); - virtual void onMessageFailed(PAccount account, int id, const std::string& peer, int code, void* tag); - virtual void onMessageSent(PAccount account, int id, const std::string& peer, void* tag); + virtual void onPresenceUpdate(PClientObserver observer, const std::string& peer, bool online, + const std::string& content); + virtual void onMessageArrived(PAccount account, const std::string& peer, const void* ptr, unsigned length); + virtual void onMessageFailed(PAccount account, int id, const std::string& peer, int code, void* tag); + virtual void onMessageSent(PAccount account, int id, const std::string& peer, void* tag); // Configuration methods - VariantMap& config(); + VariantMap& config(); public: - // InviteSessionHandler implementation + // InviteSessionHandler implementation #pragma region InviteSessionHandler implementation - /// called when an initial INVITE or the intial response to an outoing invite - virtual void onNewSession(resip::ClientInviteSessionHandle, resip::InviteSession::OfferAnswerType oat, const resip::SipMessage& msg) override; - virtual void onNewSession(resip::ServerInviteSessionHandle, resip::InviteSession::OfferAnswerType oat, const resip::SipMessage& msg) override; + /// called when an initial INVITE or the intial response to an outoing invite + virtual void onNewSession(resip::ClientInviteSessionHandle, resip::InviteSession::OfferAnswerType oat, + const resip::SipMessage& msg) override; + virtual void onNewSession(resip::ServerInviteSessionHandle, resip::InviteSession::OfferAnswerType oat, + const resip::SipMessage& msg) override; /// Received a failure response from UAS virtual void onFailure(resip::ClientInviteSessionHandle, const resip::SipMessage& msg) override; /// called when an in-dialog provisional response is received that contains an SDP body - virtual void onEarlyMedia(resip::ClientInviteSessionHandle, const resip::SipMessage&, const resip::SdpContents&) override; + virtual void onEarlyMedia(resip::ClientInviteSessionHandle, const resip::SipMessage&, + const resip::SdpContents&) override; /// called when dialog enters the Early state - typically after getting 18x virtual void onProvisional(resip::ClientInviteSessionHandle, const resip::SipMessage&) override; @@ -298,7 +307,8 @@ public: /// called when a dialog initiated as a UAS enters the connected state virtual void onConnected(resip::InviteSessionHandle, const resip::SipMessage& msg) override; - virtual void onTerminated(resip::InviteSessionHandle, resip::InviteSessionHandler::TerminatedReason reason, const resip::SipMessage* related=0) override; + virtual void onTerminated(resip::InviteSessionHandle, resip::InviteSessionHandler::TerminatedReason reason, + const resip::SipMessage* related = 0) override; /// called when a fork that was created through a 1xx never receives a 2xx /// because another fork answered and this fork was canceled by a proxy. @@ -345,7 +355,8 @@ public: /// rejected using the server subscription. If the offer is accepted, /// DialogUsageManager::makeInviteSessionFromRefer can be used to create an /// InviteSession that will send notify messages using the ServerSubscription - virtual void onRefer(resip::InviteSessionHandle, resip::ServerSubscriptionHandle, const resip::SipMessage& msg) override; + virtual void onRefer(resip::InviteSessionHandle, resip::ServerSubscriptionHandle, + const resip::SipMessage& msg) override; virtual void onReferNoSub(resip::InviteSessionHandle, const resip::SipMessage& msg) override; @@ -353,7 +364,8 @@ public: virtual void onReferRejected(resip::InviteSessionHandle, const resip::SipMessage& msg) override; /// called when an REFER message receives an accepted response - virtual void onReferAccepted(resip::InviteSessionHandle, resip::ClientSubscriptionHandle, const resip::SipMessage& msg) override; + virtual void onReferAccepted(resip::InviteSessionHandle, resip::ClientSubscriptionHandle, + const resip::SipMessage& msg) override; #pragma endregion // ClientRegistrationHandler implementation @@ -367,7 +379,7 @@ public: /// call on Retry-After failure. /// return values: -1 = fail, 0 = retry immediately, N = retry in N seconds - int onRequestRetry(resip::ClientRegistrationHandle, int retrySeconds, const resip::SipMessage& response) override; + int onRequestRetry(resip::ClientRegistrationHandle, int retrySeconds, const resip::SipMessage& response) override; /// Called if registration fails, usage will be destroyed (unless a /// Registration retry interval is enabled in the Profile) @@ -377,14 +389,9 @@ public: #pragma region ExternalLogger implementation /** return true to also do default logging, false to suppress default logging. */ - virtual bool operator()(resip::Log::Level level, - const resip::Subsystem& subsystem, - const resip::Data& appName, - const char* file, - int line, - const resip::Data& message, - const resip::Data& messageWithHeaders, - const resip::Data& instanceName) override; + virtual bool operator()(resip::Log::Level level, const resip::Subsystem& subsystem, const resip::Data& appName, + const char* file, int line, const resip::Data& message, + const resip::Data& messageWithHeaders, const resip::Data& instanceName) override; #pragma endregion #pragma region DnsResultSink implementation @@ -399,13 +406,13 @@ public: #pragma region TransportLogger implementation void onSipMessage(int flow, const char* msg, unsigned int length, const sockaddr* addr, unsigned int addrlen); -#pragma endregion +#pragma endregion #pragma region ClientPublicationHandler void onSuccess(resip::ClientPublicationHandle, const resip::SipMessage& status) override; void onRemove(resip::ClientPublicationHandle, const resip::SipMessage& status) override; void onFailure(resip::ClientPublicationHandle, const resip::SipMessage& status) override; - int onRequestRetry(resip::ClientPublicationHandle, int retrySeconds, const resip::SipMessage& status) override; + int onRequestRetry(resip::ClientPublicationHandle, int retrySeconds, const resip::SipMessage& status) override; #pragma endregion #pragma region SubscriptionHandler @@ -413,13 +420,13 @@ public: void onUpdatePending(resip::ClientSubscriptionHandle, const resip::SipMessage& notify, bool outOfOrder) override; void onUpdateActive(resip::ClientSubscriptionHandle, const resip::SipMessage& notify, bool outOfOrder) override; - //unknown Subscription-State value + // unknown Subscription-State value void onUpdateExtension(resip::ClientSubscriptionHandle, const resip::SipMessage& notify, bool outOfOrder) override; - int onRequestRetry(resip::ClientSubscriptionHandle, int retrySeconds, const resip::SipMessage& notify) override; + int onRequestRetry(resip::ClientSubscriptionHandle, int retrySeconds, const resip::SipMessage& notify) override; - //subscription can be ended through a notify or a failure response. + // subscription can be ended through a notify or a failure response. void onTerminated(resip::ClientSubscriptionHandle, const resip::SipMessage* msg) override; - //not sure if this has any value. + // not sure if this has any value. void onNewSubscription(resip::ClientSubscriptionHandle, const resip::SipMessage& notify) override; /// called to allow app to adorn a message. @@ -438,56 +445,58 @@ public: #pragma region PagerHandler void onSuccess(resip::ClientPagerMessageHandle, const resip::SipMessage& status) override; - void onFailure(resip::ClientPagerMessageHandle, const resip::SipMessage& status, std::unique_ptr contents) override; + void onFailure(resip::ClientPagerMessageHandle, const resip::SipMessage& status, + std::unique_ptr contents) override; void onMessageArrived(resip::ServerPagerMessageHandle, const resip::SipMessage& message) override; #pragma endregion void onDumCanBeDeleted() override; + protected: // Mutex to protect this instance - Mutex mGuard; + Mutex mGuard; // Smart pointer to resiprocate's master profile instance. The stack configuration holds here. - std::shared_ptr mProfile; + std::shared_ptr mProfile; // Resiprocate's SIP stack object pointer - resip::SipStack* mStack; + resip::SipStack* mStack; // Resiprocate's dialog usage manager object pointer - resip::DialogUsageManager* mDum; + resip::DialogUsageManager* mDum; // List of available transports. They are owned by SipStack - so there is no need to delete instances in UserAgent. std::vector mTransportList; - typedef std::map SessionMap; + typedef std::map SessionMap; // Session's map - SessionMap mSessionMap; + SessionMap mSessionMap; // Used configuration - VariantMap mConfig; + VariantMap mConfig; // Action vector - SIPActionVector mActionVector; + SIPActionVector mActionVector; typedef std::map ClientObserverMap; - ClientObserverMap mClientObserverMap; + ClientObserverMap mClientObserverMap; typedef std::map ServerObserverMap; - ServerObserverMap mServerObserverMap; + ServerObserverMap mServerObserverMap; - typedef std::set AccountSet; - AccountSet mAccountSet; + typedef std::set AccountSet; + AccountSet mAccountSet; // Constructs and sends INVITE to remote peer. Remote peer address is stored inside session object. - void sendOffer(Session* session); - void internalStopSession(Session& session); - void processWatchingList(); - bool handleMultipartRelatedNotify(const resip::SipMessage& notify); + void sendOffer(Session* session); + void internalStopSession(Session& session); + void processWatchingList(); + bool handleMultipartRelatedNotify(const resip::SipMessage& notify); - PSession getUserSession(int sessionId); - PAccount getAccount(const resip::NameAddr& myAddr); - PAccount getAccount(Account* account); - PAccount getAccount(int sessionId); + PSession getUserSession(int sessionId); + PAccount getAccount(const resip::NameAddr& myAddr); + PAccount getAccount(Account* account); + PAccount getAccount(int sessionId); }; #endif diff --git a/src/engine/endpoint/EP_NetworkQueue.cpp b/src/engine/endpoint/EP_NetworkQueue.cpp index 8b630d94..b16caacf 100644 --- a/src/engine/endpoint/EP_NetworkQueue.cpp +++ b/src/engine/endpoint/EP_NetworkQueue.cpp @@ -1,19 +1,16 @@ #include "EP_NetworkQueue.h" #include "EP_Engine.h" -WatcherQueue::WatcherQueue(UserAgent& ua) - :mActiveId(0), mAgent(ua) -{} +WatcherQueue::WatcherQueue(UserAgent& ua) : mActiveId(0), mAgent(ua) {} -WatcherQueue::~WatcherQueue() -{} +WatcherQueue::~WatcherQueue() {} int WatcherQueue::add(const std::string& peer, const std::string& package, void* tag) { ice::Lock l(mGuard); // Check if queue has similar item - for (unsigned i=0; ischeduled(); i++) + for (; i != mItemList.end() && !i->scheduled(); i++) ; if (i == mItemList.end()) return; @@ -133,7 +130,7 @@ void WatcherQueue::process() void WatcherQueue::onTerminated(int id, int code) { - ice::Lock l(mGuard); + ice::Lock l(mGuard); ItemList::iterator i = findById(id); if (i != mItemList.end()) { @@ -148,7 +145,7 @@ void WatcherQueue::onTerminated(int id, int code) void WatcherQueue::onEstablished(int id, int code) { - ice::Lock l(mGuard); + ice::Lock l(mGuard); ItemList::iterator i = findById(id); if (i != mItemList.end()) { @@ -161,7 +158,7 @@ void WatcherQueue::onEstablished(int id, int code) WatcherQueue::ItemList::iterator WatcherQueue::findById(int id) { - for (ItemList::iterator i=mItemList.begin(); i != mItemList.end(); i++) + for (ItemList::iterator i = mItemList.begin(); i != mItemList.end(); i++) if (i->mId == id) return i; return mItemList.end(); @@ -170,7 +167,7 @@ WatcherQueue::ItemList::iterator WatcherQueue::findById(int id) void WatcherQueue::clear() { ice::Lock l(mGuard); - for (ItemList::iterator i=mItemList.begin(); i != mItemList.end(); i++) + for (ItemList::iterator i = mItemList.begin(); i != mItemList.end(); i++) { if (i->mHandle.isValid()) i->mHandle->end(); diff --git a/src/engine/endpoint/EP_NetworkQueue.h b/src/engine/endpoint/EP_NetworkQueue.h index 6ebda5b5..94bdaea8 100644 --- a/src/engine/endpoint/EP_NetworkQueue.h +++ b/src/engine/endpoint/EP_NetworkQueue.h @@ -27,26 +27,26 @@ public: State_Deleting }; - resip::ClientSubscriptionHandle mHandle; // Subscription handle - ResipSession* mSession = nullptr; - State mState = State::State_None; - std::string mTarget; // Target's address - std::string mPackage; // Event package - void* mTag = nullptr; // User tag - int mId = 0; // Related session ID - it is always non-zero (zero is here for initialization only) + resip::ClientSubscriptionHandle mHandle; // Subscription handle + ResipSession* mSession = nullptr; + State mState = State::State_None; + std::string mTarget; // Target's address + std::string mPackage; // Event package + void* mTag = nullptr; // User tag + int mId = 0; // Related session ID - it is always non-zero (zero is here for initialization only) - Item() - {} + Item() {} bool scheduled() { - return mState == State_ScheduledToAdd || mState == State_ScheduledToDelete || mState == State_ScheduledToRefresh; + return mState == State_ScheduledToAdd || mState == State_ScheduledToDelete || + mState == State_ScheduledToRefresh; } }; WatcherQueue(UserAgent& agent); ~WatcherQueue(); - int add(const std::string& peer, const std::string& package, void* tag); + int add(const std::string& peer, const std::string& package, void* tag); void remove(int id); void refresh(int id); void clear(); @@ -56,13 +56,13 @@ public: protected: typedef std::vector ItemList; - ItemList mItemList; - ice::Mutex mGuard; - UserAgent& mAgent; - int mActiveId; + ItemList mItemList; + ice::Mutex mGuard; + UserAgent& mAgent; + int mActiveId; - void process(); - ItemList::iterator findById(int id); + void process(); + ItemList::iterator findById(int id); }; #endif diff --git a/src/engine/endpoint/EP_Observer.cpp b/src/engine/endpoint/EP_Observer.cpp index 2a992773..9b5c465b 100644 --- a/src/engine/endpoint/EP_Observer.cpp +++ b/src/engine/endpoint/EP_Observer.cpp @@ -9,13 +9,9 @@ #include #include -ClientObserver::ClientObserver() -{ -} +ClientObserver::ClientObserver() {} -ClientObserver::~ClientObserver() -{ -} +ClientObserver::~ClientObserver() {} void ClientObserver::refresh() { @@ -27,13 +23,12 @@ void ClientObserver::stop() { if (mHandle.isValid()) mHandle->end(); - else + else if (mSession) + { + mSession->runTerminatedEvent(ResipSession::Type_Subscription); if (mSession) - { - mSession->runTerminatedEvent(ResipSession::Type_Subscription); - if (mSession) - mSession->end(); - } + mSession->end(); + } mSession = NULL; } @@ -42,11 +37,7 @@ std::string ClientObserver::peer() return mPeer; } -ServerObserver::ServerObserver() - :mState(State_Incoming) -{ - -} +ServerObserver::ServerObserver() : mState(State_Incoming) {} ServerObserver::~ServerObserver() { diff --git a/src/engine/endpoint/EP_Observer.h b/src/engine/endpoint/EP_Observer.h index 834b4e33..4956eada 100644 --- a/src/engine/endpoint/EP_Observer.h +++ b/src/engine/endpoint/EP_Observer.h @@ -23,19 +23,20 @@ class ClientObserver { friend class Account; friend class UserAgent; + public: ClientObserver(); ~ClientObserver(); - void refresh(); - void stop(); + void refresh(); + void stop(); std::string peer(); protected: resip::ClientSubscriptionHandle mHandle; - ResipSession* mSession; - int mSessionId; - std::string mPeer; + ResipSession* mSession; + int mSessionId; + std::string mPeer; }; typedef std::shared_ptr PClientObserver; @@ -43,6 +44,7 @@ typedef std::shared_ptr PClientObserver; class ServerObserver { friend class UserAgent; + public: ServerObserver(); ~ServerObserver(); @@ -50,9 +52,9 @@ public: std::string peer() const; std::string package() const; - void accept(); - void update(std::string simpleId, bool online, std::string msg); - void stop(); + void accept(); + void update(std::string simpleId, bool online, std::string msg); + void stop(); protected: enum State @@ -61,11 +63,11 @@ protected: State_Active, State_Closed }; - State mState; + State mState; resip::ServerSubscriptionHandle mHandle; - std::string mPeer, mPackage; - resip::Uri mContact; - int mSessionId; + std::string mPeer, mPackage; + resip::Uri mContact; + int mSessionId; }; typedef std::shared_ptr PServerObserver; diff --git a/src/engine/endpoint/EP_ReliableTunnel.cpp b/src/engine/endpoint/EP_ReliableTunnel.cpp index ece90939..1abd4231 100644 --- a/src/engine/endpoint/EP_ReliableTunnel.cpp +++ b/src/engine/endpoint/EP_ReliableTunnel.cpp @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2007-2012 Dmytro Bogovych * * This program is free software; you can redistribute it and/or modify @@ -13,11 +13,11 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifdef _WIN32 -# include -# include +#include +#include #endif #include @@ -30,8 +30,8 @@ enum { - CONFIRMATION_PT = 1, - DATA_PT = 2 + CONFIRMATION_PT = 1, + DATA_PT = 2 }; #define CONFIRMATION_TIMEOUT 500 @@ -39,266 +39,267 @@ enum ReliableTunnel::ReliableTunnel(const char* streamname) { - mStack.setEncryption(this); - mStreamName = streamname; - mBandwidth = 0; - mExitSignal = ::CreateEvent(NULL, FALSE, FALSE, NULL); - mDataSignal = ::CreateEvent(NULL, FALSE, FALSE, NULL); - + mStack.setEncryption(this); + mStreamName = streamname; + mBandwidth = 0; + mExitSignal = ::CreateEvent(NULL, FALSE, FALSE, NULL); + mDataSignal = ::CreateEvent(NULL, FALSE, FALSE, NULL); } ReliableTunnel::~ReliableTunnel() { - ::CloseHandle(mDataSignal); - ::CloseHandle(mExitSignal); + ::CloseHandle(mDataSignal); + ::CloseHandle(mExitSignal); } std::string ReliableTunnel::streamName() { - return mStreamName; + return mStreamName; } std::string ReliableTunnel::streamProfile() { - return "RTP/DP"; + return "RTP/DP"; } void ReliableTunnel::setDestinationAddress(InternetAddress& addr) { - mDestination = addr; + mDestination = addr; } void ReliableTunnel::queueData(const void* bufferptr, int buffersize) { - assert(bufferptr != NULL); - assert(buffersize != 0); + assert(bufferptr != NULL); + assert(buffersize != 0); - resip::Lock l(mNewQueuedGuard); - mNewQueued.push_back(std::string((const char*)bufferptr, buffersize)); - - ::SetEvent(mDataSignal); + resip::Lock l(mNewQueuedGuard); + mNewQueued.push_back(std::string((const char*)bufferptr, buffersize)); + + ::SetEvent(mDataSignal); } // This method is called by user agent to send ICE packet from mediasocket void ReliableTunnel::sendData(InternetAddress& addr, const void* dataBuffer, unsigned int datasize) { - switch (addr.type()) - { - case AF_INET: - mSocket4.sendDatagram(addr, dataBuffer, datasize); - return; + switch (addr.type()) + { + case AF_INET: + mSocket4.sendDatagram(addr, dataBuffer, datasize); + return; - case AF_INET6: - mSocket4.sendDatagram(addr, dataBuffer, datasize); - return; - } + case AF_INET6: + mSocket4.sendDatagram(addr, dataBuffer, datasize); + return; + } } void ReliableTunnel::sessionEstablished(int conntype) { - // Start worker thread - if (conntype == EV_ICE) - run(); + // Start worker thread + if (conntype == EV_ICE) + run(); } void ReliableTunnel::sessionTerminated() { - // Stop worker thread - ::SetEvent(mExitSignal); - shutdown(); - join(); + // Stop worker thread + ::SetEvent(mExitSignal); + shutdown(); + join(); } void ReliableTunnel::updateSdpOffer(resip::SdpContents::Session::Medium& sdp) { - // Get new destination port - mDestination.setPort((unsigned short)sdp.port()); - - sdp.addCodec(resip::SdpContents::Session::Codec("rt", 104)); + // Get new destination port + mDestination.setPort((unsigned short)sdp.port()); + + sdp.addCodec(resip::SdpContents::Session::Codec("rt", 104)); } void ReliableTunnel::setSocket(DatagramSocket& socket4, DatagramSocket& socket6) { - mSocket4 = socket4; - mSocket6 = socket6; + mSocket4 = socket4; + mSocket6 = socket6; } - + DatagramSocket& ReliableTunnel::socket(int family) { - switch (family) - { - case AF_INET: - return mSocket4; + switch (family) + { + case AF_INET: + return mSocket4; - case AF_INET6: - return mSocket4; + case AF_INET6: + return mSocket4; - default: - assert(0); - } + default: + assert(0); + } } bool ReliableTunnel::processSdpOffer(const resip::SdpContents::Session::Medium& media) { - //check for default port number - mDestination.setPort(media.port()); - - return true; + // check for default port number + mDestination.setPort(media.port()); + + return true; } void ReliableTunnel::thread() { - // Construct event array - while (true) - { - HANDLE eventarray[2] = { mDataSignal, mExitSignal }; - - DWORD rescode = ::WaitForMultipleObjects(2, eventarray, FALSE, INFINITE); - if (rescode == WAIT_OBJECT_0) + // Construct event array + while (true) { - resip::Lock l(mNewQueuedGuard); - for (unsigned i = 0; imDestination, buffer, length); - } + // Check if stack has to send smth + if (mStack.hasPacketToSend()) + { + // Get data to send + char buffer[2048]; + int length = sizeof(buffer); + mStack.getPacketToSend(buffer, length); + + // Send it over UDP + sendData(this->mDestination, buffer, length); + } } void ReliableTunnel::setEncryptionKey(void* ptr, unsigned length) { #ifdef USE_OPENSSL - BF_set_key(&mCipher, length, (const unsigned char*)ptr); + BF_set_key(&mCipher, length, (const unsigned char*)ptr); #endif #ifdef USE_CRYPTOPP - mEncryptor.SetKey((unsigned char*)ptr, length); - mDecryptor.SetKey((unsigned char*)ptr, length); + mEncryptor.SetKey((unsigned char*)ptr, length); + mDecryptor.SetKey((unsigned char*)ptr, length); #endif - // Save key - mEncryptionKey = std::string((const char*)ptr, length); + // Save key + mEncryptionKey = std::string((const char*)ptr, length); } diff --git a/src/engine/endpoint/EP_ReliableTunnel.h b/src/engine/endpoint/EP_ReliableTunnel.h index 94415dd4..230c41e4 100644 --- a/src/engine/endpoint/EP_ReliableTunnel.h +++ b/src/engine/endpoint/EP_ReliableTunnel.h @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2007-2010 Dmytro Bogovych * * This program is free software; you can redistribute it and/or modify @@ -13,7 +13,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __RELIABLE_TUNNEL_H #define __RELIABLE_TUNNEL_H @@ -26,122 +26,121 @@ #include "../ICE/ICEReliableTransport.h" #ifdef USE_CRYPTOPP -# include "../Libs/CryptoPP/blowfish.h" +#include "../Libs/CryptoPP/blowfish.h" #endif #ifdef USE_OPENSSL -# include "../Libs/openssl/include/openssl/blowfish.h" +#include "../Libs/openssl/include/openssl/blowfish.h" #endif -class ReliableTunnel: public DataProvider, public resip::ThreadIf, public ICEImpl::ReliableTransport::Encryption +class ReliableTunnel : public DataProvider, public resip::ThreadIf, public ICEImpl::ReliableTransport::Encryption { public: - ReliableTunnel(const char* streamname); - virtual ~ReliableTunnel(); - - // Returns provider RTP name - virtual std::string streamName(); - - // Returns provider RTP profile name - virtual std::string streamProfile(); - - // Sets destination IP address - virtual void setDestinationAddress(InternetAddress& addr); + ReliableTunnel(const char* streamname); + virtual ~ReliableTunnel(); - // Processes incoming data - virtual void processData(const void* dataBuffer, int dataSize); + // Returns provider RTP name + virtual std::string streamName(); - // This method is called by user agent to send ICE packet from mediasocket - virtual void sendData(InternetAddress& destination, const void* dataBuffer, unsigned int datasize); + // Returns provider RTP profile name + virtual std::string streamProfile(); - // Updates SDP offer - virtual void updateSdpOffer(resip::SdpContents::Session::Medium& sdp); + // Sets destination IP address + virtual void setDestinationAddress(InternetAddress& addr); - // Called by user agent when session is terminated. - virtual void sessionTerminated(); + // Processes incoming data + virtual void processData(const void* dataBuffer, int dataSize); - // Called by user agent when session is started. - virtual void sessionEstablished(int conntype); + // This method is called by user agent to send ICE packet from mediasocket + virtual void sendData(InternetAddress& destination, const void* dataBuffer, unsigned int datasize); + + // Updates SDP offer + virtual void updateSdpOffer(resip::SdpContents::Session::Medium& sdp); + + // Called by user agent when session is terminated. + virtual void sessionTerminated(); + + // Called by user agent when session is started. + virtual void sessionEstablished(int conntype); // Called by user agent to save media socket for this provider - virtual void setSocket(DatagramSocket& socket4, DatagramSocket& socket6); - - // Called by user agent to get media socket for this provider - virtual DatagramSocket& socket(int family); + virtual void setSocket(DatagramSocket& socket4, DatagramSocket& socket6); - // Called by user agent to process media stream description from remote peer. - // Returns true if description is processed succesfully. Otherwise method returns false. - virtual bool processSdpOffer(const resip::SdpContents::Session::Medium& media); + // Called by user agent to get media socket for this provider + virtual DatagramSocket& socket(int family); - virtual void thread(); + // Called by user agent to process media stream description from remote peer. + // Returns true if description is processed succesfully. Otherwise method returns false. + virtual bool processSdpOffer(const resip::SdpContents::Session::Medium& media); - // Enqueues outgoing packet to sending queue - void queueData(const void* bufferPtr, int bufferSize); - - void setBandwidth(unsigned int bytesPerSecond); - unsigned int bandwidth(); - - // Checks if there is any received application data - bool hasData(); - - // Reads received data. If ptr is NULL - the length of available data is returned. - unsigned getData(void* ptr, unsigned capacity); + virtual void thread(); - void setEncryptionKey(void* ptr, unsigned length); + // Enqueues outgoing packet to sending queue + void queueData(const void* bufferPtr, int bufferSize); + + void setBandwidth(unsigned int bytesPerSecond); + unsigned int bandwidth(); + + // Checks if there is any received application data + bool hasData(); + + // Reads received data. If ptr is NULL - the length of available data is returned. + unsigned getData(void* ptr, unsigned capacity); + + void setEncryptionKey(void* ptr, unsigned length); protected: - // SDP's stream name - std::string mStreamName; + // SDP's stream name + std::string mStreamName; - // Transport stack - ICEImpl::ReliableTransport mStack; - - // Socket handles to operate - DatagramSocket mSocket4; - DatagramSocket mSocket6; + // Transport stack + ICEImpl::ReliableTransport mStack; - // Destination IP4/6 address - InternetAddress mDestination; - - // Win32 exit signal - HANDLE mExitSignal; - - // Win32 "new outgoing data" signal - HANDLE mDataSignal; - - // Mutex to protect queuing/sending outgoing data - resip::Mutex mOutgoingMtx; - - std::vector - mNewQueued; - resip::Mutex mNewQueuedGuard; - resip::Mutex mStackGuard; + // Socket handles to operate + DatagramSocket mSocket4; + DatagramSocket mSocket6; + + // Destination IP4/6 address + InternetAddress mDestination; + + // Win32 exit signal + HANDLE mExitSignal; + + // Win32 "new outgoing data" signal + HANDLE mDataSignal; + + // Mutex to protect queuing/sending outgoing data + resip::Mutex mOutgoingMtx; + + std::vector mNewQueued; + resip::Mutex mNewQueuedGuard; + resip::Mutex mStackGuard; + + unsigned int mBandwidth; + std::string mEncryptionKey; - unsigned int mBandwidth; - std::string mEncryptionKey; - #ifdef USE_CRYPTOPP - CryptoPP::BlowfishEncryption mEncryptor; - CryptoPP::BlowfishDecryption mDecryptor; + CryptoPP::BlowfishEncryption mEncryptor; + CryptoPP::BlowfishDecryption mDecryptor; #endif #ifdef USE_OPENSSL - BF_KEY mCipher; + BF_KEY mCipher; #endif - ICEImpl::ICEByteBuffer mIncomingData; + ICEImpl::ICEByteBuffer mIncomingData; - // Returns block size for encryption algorythm - int blockSize(); - - // Encrypts dataPtr buffer inplace. dataSize must be odd to GetBlockSize() returned value. - void encrypt(void* dataPtr, int dataSize); + // Returns block size for encryption algorythm + int blockSize(); - // Decrypts dataPtr buffer inplace. dataSize must be odd to GetBlockSize() returned value. - void decrypt(void* dataPtr, int dataSize); + // Encrypts dataPtr buffer inplace. dataSize must be odd to GetBlockSize() returned value. + void encrypt(void* dataPtr, int dataSize); - // Calculates CRC - unsigned crc(const void* dataptr, int datasize); + // Decrypts dataPtr buffer inplace. dataSize must be odd to GetBlockSize() returned value. + void decrypt(void* dataPtr, int dataSize); - void sendOutgoing(); + // Calculates CRC + unsigned crc(const void* dataptr, int datasize); + + void sendOutgoing(); }; #endif \ No newline at end of file diff --git a/src/engine/endpoint/EP_Session.cpp b/src/engine/endpoint/EP_Session.cpp index c1dfa7b0..7572470e 100644 --- a/src/engine/endpoint/EP_Session.cpp +++ b/src/engine/endpoint/EP_Session.cpp @@ -13,21 +13,18 @@ #define LOG_SUBSYSTEM "engine" -typedef resip::SdpContents::Session::Medium Medium; +typedef resip::SdpContents::Session::Medium Medium; typedef resip::SdpContents::Session::MediumContainer MediumContainer; -#define IS_MULTIPLEX() mUserAgent->mConfig[CONFIG_MULTIPLEXING].asBool() ? SocketHeap::DoMultiplexing : SocketHeap::DontMultiplexing +#define IS_MULTIPLEX() \ + mUserAgent->mConfig[CONFIG_MULTIPLEXING].asBool() ? SocketHeap::DoMultiplexing : SocketHeap::DontMultiplexing //------------ ResipSessionAppDialog ------------ #pragma region ResipSessionAppDialog -ResipSessionAppDialog::ResipSessionAppDialog(resip::HandleManager& ham) : AppDialog(ham) -{ -} +ResipSessionAppDialog::ResipSessionAppDialog(resip::HandleManager& ham) : AppDialog(ham) {} -ResipSessionAppDialog::~ResipSessionAppDialog() -{ -} +ResipSessionAppDialog::~ResipSessionAppDialog() {} #pragma endregion @@ -35,7 +32,7 @@ ResipSessionAppDialog::~ResipSessionAppDialog() std::atomic_int ResipSession::InstanceCounter; -ResipSession::ResipSession(resip::DialogUsageManager& dum) +ResipSession::ResipSession(resip::DialogUsageManager& dum) : resip::AppDialogSet(dum), mUserAgent(nullptr), mType(Type_None), mSessionId(0), mSession(0) { ResipSession::InstanceCounter++; @@ -54,7 +51,7 @@ ResipSession::~ResipSession() mSession->mResipSession = nullptr; runTerminatedEvent(Type_Auto, 0, 0); } - catch(...) + catch (...) { } @@ -94,7 +91,8 @@ void ResipSession::runTerminatedEvent(Type type, int code, int reason) case Type_Subscription: if (mSession) { - UserAgent::ClientObserverMap::iterator observerIter = mUserAgent->mClientObserverMap.find(mSession->sessionId()); + UserAgent::ClientObserverMap::iterator observerIter = + mUserAgent->mClientObserverMap.find(mSession->sessionId()); if (observerIter != mUserAgent->mClientObserverMap.end()) mUserAgent->onClientObserverStop(observerIter->second, code); } @@ -186,14 +184,9 @@ std::shared_ptr ResipSession::selectUASUserProfile(const res #pragma endregion #pragma region Session::Stream -Session::Stream::Stream() - :mRtcpAttr(false), mRtcpMuxAttr(false) -{ -} +Session::Stream::Stream() : mRtcpAttr(false), mRtcpMuxAttr(false) {} -Session::Stream::~Stream() -{ -} +Session::Stream::~Stream() {} void Session::Stream::setProvider(PDataProvider provider) { @@ -261,7 +254,7 @@ void Session::Stream::setRtcpMuxAttr(bool value) std::atomic_int Session::InstanceCounter; Session::Session(PAccount account) -{ +{ InstanceCounter++; mAccount = account; mSessionId = Session::generateId(); @@ -290,14 +283,15 @@ Session::~Session() mResipSession->setSession(NULL); clearProvidersAndSockets(); } - catch(...) - {} + catch (...) + { + } InstanceCounter--; } void Session::start(const std::string& peer) { - ICELogInfo( << "Attempt to start session to " << peer); + ICELogInfo(<< "Attempt to start session to " << peer); Lock l(mGuard); if (mResipSession) @@ -320,7 +314,7 @@ void Session::start(const std::string& peer) // Mark session as Initiator mRole = Session::Initiator; - resip::Data addrData(peer); + resip::Data addrData(peer); resip::NameAddr addr(addrData); // Save target address @@ -334,7 +328,7 @@ void Session::stop() { ICELogInfo(<< "Stopping session " << mSessionId); Lock l(mGuard); - for (unsigned i=0; isessionTerminated(); // Free socket - SocketHeap::instance().freeSocketPair( dataStream.socket4() ); - SocketHeap::instance().freeSocketPair( dataStream.socket6() ); + SocketHeap::instance().freeSocketPair(dataStream.socket4()); + SocketHeap::instance().freeSocketPair(dataStream.socket6()); // Drop the references so the destructor's cleanup does not free them again dataStream.setSocket4(RtpPair()); @@ -357,7 +351,7 @@ void Session::stop() mResipSession->runTerminatedEvent(ResipSession::Type_Call, 0, LocalBye); if (mResipSession) - mResipSession->end(); // Stop SIP session + mResipSession->end(); // Stop SIP session } void Session::accept() @@ -366,7 +360,8 @@ void Session::accept() Lock locksession(mGuard); - // If ICE candidate gathering is not finished - just mark session as accepted. It will be accepted in ICE handling code. + // If ICE candidate gathering is not finished - just mark session as accepted. It will be accepted in ICE handling + // code. mAcceptedByUser = true; if (mGatheredCandidates || mIceStack->state() == ice::IceNone) @@ -405,7 +400,7 @@ void Session::accept() void Session::reject(int code) { - ICELogInfo( << "Attempt to reject session " << mSessionId); + ICELogInfo(<< "Attempt to reject session " << mSessionId); Lock l(mGuard); @@ -449,8 +444,8 @@ void Session::getSessionInfo(Session::InfoOptions options, VariantMap& info) MT::Statistics stat; // Iterate all session providers - Stream* media = nullptr; - for (Stream& stream: mStreamList) + Stream* media = nullptr; + for (Stream& stream : mStreamList) { if (!stream.provider()) continue; @@ -473,7 +468,9 @@ void Session::getSessionInfo(Session::InfoOptions options, VariantMap& info) info[SessionInfo_SentRtp] = static_cast(stat.mSentRtp); info[SessionInfo_SentRtcp] = static_cast(stat.mSentRtcp); if (stat.mFirstRtpTime) - info[SessionInfo_Duration] = static_cast(std::chrono::duration_cast(std::chrono::steady_clock::now() - *(stat.mFirstRtpTime)).count()); + info[SessionInfo_Duration] = static_cast( + std::chrono::duration_cast(std::chrono::steady_clock::now() - *(stat.mFirstRtpTime)) + .count()); else info[SessionInfo_Duration] = 0; @@ -481,7 +478,8 @@ void Session::getSessionInfo(Session::InfoOptions options, VariantMap& info) info[SessionInfo_PacketLoss] = static_cast((stat.mPacketLoss * 1000) / stat.mReceivedRtp); if (media && mIceStack) - info[SessionInfo_AudioPeer] = mIceStack->remoteAddress(media->iceInfo().mStreamId, media->iceInfo().mComponentId.mRtp).toStdString(); + info[SessionInfo_AudioPeer] = + mIceStack->remoteAddress(media->iceInfo().mStreamId, media->iceInfo().mComponentId.mRtp).toStdString(); info[SessionInfo_Jitter] = stat.mJitter; if (stat.mRttDelay.is_initialized()) @@ -505,7 +503,8 @@ PAccount Session::account() return mAccount; } -void Session::onReceivedData(PDatagramSocket socket, InternetAddress& src, const void* receivedPtr, unsigned receivedSize) +void Session::onReceivedData(PDatagramSocket socket, InternetAddress& src, const void* receivedPtr, + unsigned receivedSize) { Lock l(mGuard); @@ -513,7 +512,7 @@ void Session::onReceivedData(PDatagramSocket socket, InternetAddress& src, const return; // Check if it STUN packet and must be processed by ICE stack - //ICELogDebug (<< "Received UDP packet from " << src.ip() << ":" << src.port()); + // ICELogDebug (<< "Received UDP packet from " << src.ip() << ":" << src.port()); ice::ByteBuffer received(receivedPtr, receivedSize); received.setRemoteAddress(src); @@ -531,7 +530,7 @@ void Session::onReceivedData(PDatagramSocket socket, InternetAddress& src, const if (received.size() >= 4) { bool turnPrefix = false; - for (unsigned i=0; iprocessIncomingData(stream, component, buffer); + /*bool processed = */ mIceStack->processIncomingData(stream, component, buffer); } } else @@ -594,20 +593,19 @@ void Session::onGathered(ice::Stack* stack, void* tag) if (mRole == Initiator) mUserAgent->sendOffer(this); - else - if (mRole == Acceptor) - { - // Mark session as gathered ICE candidates - mGatheredCandidates = true; + else if (mRole == Acceptor) + { + // Mark session as gathered ICE candidates + mGatheredCandidates = true; - // if AcceptSession was already called() on session - recall it again to make real work - if (mAcceptedByUser) - { - // Check if session is needed here - because session can be terminated already - if (mResipSession && mInviteHandle.isValid()) - accept(); - } + // if AcceptSession was already called() on session - recall it again to make real work + if (mAcceptedByUser) + { + // Check if session is needed here - because session can be terminated already + if (mResipSession && mInviteHandle.isValid()) + accept(); } + } } void Session::onSuccess(ice::Stack* stack, void* tag) @@ -616,7 +614,7 @@ void Session::onSuccess(ice::Stack* stack, void* tag) RtpPair t; - for (unsigned i=0; imStreamList.size(); i++) + for (unsigned i = 0; i < this->mStreamList.size(); i++) { PDataProvider p = mStreamList[i].provider(); if (p) @@ -638,8 +636,8 @@ void Session::onSuccess(ice::Stack* stack, void* tag) mUserAgent->onSessionEstablished(mUserAgent->getUserSession(mSessionId), EV_ICE, t); - //time to resend updated media info over SIP - //TODO: + // time to resend updated media info over SIP + // TODO: } void Session::onFailed(ice::Stack* stack, void* tag) @@ -647,17 +645,17 @@ void Session::onFailed(ice::Stack* stack, void* tag) ICELogError(<< "ICE connectivity check failed for session " << mSessionId); mUserAgent->onConnectivityFailed(mUserAgent->getUserSession(mSessionId)); - //if (mInviteHandle.isValid()) - // mInviteHandle->end(); + // if (mInviteHandle.isValid()) + // mInviteHandle->end(); } -void Session::onNetworkChange(ice::Stack *stack, void *tag) +void Session::onNetworkChange(ice::Stack* stack, void* tag) { ICELogInfo(<< "Network change detected by ICE stack for session " << mSessionId); mUserAgent->onNetworkChange(mUserAgent->getUserSession(mSessionId)); } -void Session::buildSdp(resip::SdpContents &sdp, SdpDirection sdpDirection) +void Session::buildSdp(resip::SdpContents& sdp, SdpDirection sdpDirection) { sdp.session().name() = "ICE_UA"; sdp.session().origin().user() = "user"; @@ -675,8 +673,12 @@ void Session::buildSdp(resip::SdpContents &sdp, SdpDirection sdpDirection) ice::NetworkAddress defaultAddr = mIceStack->defaultAddress(mStreamList.front().iceInfo().mStreamId, ICE_RTP_ID); // Set IP address for origin and connection - sdp.session().origin().setAddress(resip::Data(defaultAddr.ip()), defaultAddr.family() == AF_INET ? resip::SdpContents::IP4 : resip::SdpContents::IP6); - sdp.session().connection().setAddress(resip::Data(defaultAddr.ip()), defaultAddr.family() == AF_INET ? resip::SdpContents::IP4 : resip::SdpContents::IP6); + sdp.session().origin().setAddress(resip::Data(defaultAddr.ip()), defaultAddr.family() == AF_INET + ? resip::SdpContents::IP4 + : resip::SdpContents::IP6); + sdp.session().connection().setAddress(resip::Data(defaultAddr.ip()), defaultAddr.family() == AF_INET + ? resip::SdpContents::IP4 + : resip::SdpContents::IP6); // Add ICE credentials if (mIceStack->state() > ice::IceNone) @@ -686,30 +688,30 @@ void Session::buildSdp(resip::SdpContents &sdp, SdpDirection sdpDirection) } // Iterate media streams - for (unsigned i=0; idefaultAddress(mStreamList[i].iceInfo().mStreamId, ICE_RTP_ID), - rtcpPort = mIceStack->defaultAddress(mStreamList[i].iceInfo().mStreamId, ICE_RTCP_ID); + rtcpPort = mIceStack->defaultAddress(mStreamList[i].iceInfo().mStreamId, ICE_RTCP_ID); // Define media stream SDP's header - resip::SdpContents::Session::Medium media(resip::Data(provider.streamName()), rtpPort.port(), 0, resip::Data(provider.streamProfile())); + resip::SdpContents::Session::Medium media(resip::Data(provider.streamName()), rtpPort.port(), 0, + resip::Data(provider.streamProfile())); // Add "rtcp" attribute if (mUserAgent->mConfig[CONFIG_RTCP_ATTR].asBool()) { if (mUserAgent->mConfig[CONFIG_MULTIPLEXING].asBool()) rtcpPort = rtpPort; - else - if (rtcpPort.isEmpty()) + else if (rtcpPort.isEmpty()) { rtcpPort = rtpPort; - rtcpPort.setPort( rtpPort.port() + 1); + rtcpPort.setPort(rtpPort.port() + 1); } media.addAttribute("rtcp", resip::Data(rtcpPort.port())); @@ -732,7 +734,7 @@ void Session::buildSdp(resip::SdpContents &sdp, SdpDirection sdpDirection) if (mIceStack->hasComponent(ii.mStreamId, ii.mComponentId.mRtcp)) mIceStack->fillCandidateList(ii.mStreamId, ii.mComponentId.mRtcp, candidates); - for (unsigned c=0; cprovider() && (streamIter->socket4().mRtp->isValid() || streamIter->socket6().mRtp->isValid())) { - streamIter->setProvider( provider ); + streamIter->setProvider(provider); provider->setSocket(streamIter->socket4(), streamIter->socket6()); return; } } Stream s; - s.setProvider( provider ); + s.setProvider(provider); // Allocate socket for provider - s.setSocket4( SocketHeap::instance().allocSocketPair(AF_INET, this, IS_MULTIPLEX()) ); - s.setSocket6( SocketHeap::instance().allocSocketPair(AF_INET6, this, IS_MULTIPLEX()) ); + s.setSocket4(SocketHeap::instance().allocSocketPair(AF_INET, this, IS_MULTIPLEX())); + s.setSocket6(SocketHeap::instance().allocSocketPair(AF_INET6, this, IS_MULTIPLEX())); s.provider()->setSocket(s.socket4(), s.socket6()); // Create ICE stream/component @@ -797,10 +799,11 @@ void Session::addProvider(PDataProvider provider) ii.mPort4 = s.socket4().mRtp->localport(); ii.mPort6 = s.socket6().mRtp->localport(); - ii.mComponentId.mRtp = mIceStack->addComponent(ii.mStreamId, NULL, s.socket4().mRtp->localport(), - s.socket6().mRtp->localport()); + ii.mComponentId.mRtp = + mIceStack->addComponent(ii.mStreamId, NULL, s.socket4().mRtp->localport(), s.socket6().mRtp->localport()); if (!mUserAgent->mConfig[CONFIG_MULTIPLEXING].asBool()) - ii.mComponentId.mRtcp = mIceStack->addComponent(ii.mStreamId, NULL, s.socket4().mRtcp->localport(), s.socket6().mRtcp->localport()); + ii.mComponentId.mRtcp = + mIceStack->addComponent(ii.mStreamId, NULL, s.socket4().mRtcp->localport(), s.socket6().mRtcp->localport()); s.setIceInfo(ii); @@ -825,7 +828,7 @@ int Session::sessionId() } std::atomic_int Session::IdGenerator; -int Session::generateId() +int Session::generateId() { return ++IdGenerator; } @@ -857,7 +860,7 @@ void Session::setTag(void* tag) void Session::pause() { - for (unsigned i=0; isocket(AF_INET)); // Bring new socket to provider and stream - RtpPair s4 = SocketHeap::instance().allocSocketPair(AF_INET, this, IS_MULTIPLEX() ), + RtpPair s4 = SocketHeap::instance().allocSocketPair(AF_INET, this, IS_MULTIPLEX()), s6 = SocketHeap::instance().allocSocketPair(AF_INET6, this, IS_MULTIPLEX()); p->setSocket(s4, s6); @@ -912,11 +915,11 @@ void Session::refreshMediaPath() int Session::processSdp(uint64_t version, bool iceAvailable, std::string icePwd, std::string iceUfrag, std::string remoteIp, const resip::SdpContents::Session::MediumContainer& media) { - bool iceRestart = false; + bool iceRestart = false; - int mediaCompatible = 0; + int mediaCompatible = 0; MediumContainer::const_iterator mediaIter; - unsigned streamIndex = 0; + unsigned streamIndex = 0; for (mediaIter = media.begin(); mediaIter != media.end(); ++mediaIter, ++streamIndex) { // Get reference to SDP description of remote stream @@ -929,7 +932,7 @@ int Session::processSdp(uint64_t version, bool iceAvailable, std::string icePwd, // Ask about provider if needed if (!stream.provider()) - stream.setProvider( mUserAgent->onProviderNeeded(remoteStream.name().c_str()) ); + stream.setProvider(mUserAgent->onProviderNeeded(remoteStream.name().c_str())); // Check the stream validity if (!stream.provider()) @@ -938,8 +941,8 @@ int Session::processSdp(uint64_t version, bool iceAvailable, std::string icePwd, continue; // See for rtcp & rtcp-mux attribute - stream.setRtcpAttr( remoteStream.exists("rtcp") ); - stream.setRtcpMuxAttr( remoteStream.exists("rtcp-mux") ); + stream.setRtcpAttr(remoteStream.exists("rtcp")); + stream.setRtcpMuxAttr(remoteStream.exists("rtcp-mux")); // Set destination address if (!remoteStream.getConnections().empty()) @@ -951,12 +954,12 @@ int Session::processSdp(uint64_t version, bool iceAvailable, std::string icePwd, targetAddr.mRtcp.setIp(remoteIp); if (stream.rtcpMuxAttr()) - targetAddr.mRtcp.setPort( remoteStream.port() ); + targetAddr.mRtcp.setPort(remoteStream.port()); + else if (stream.rtcpAttr()) + targetAddr.mRtcp.setPort( + strx::toInt(remoteStream.getValues("rtcp").front().c_str(), remoteStream.port() + 1)); else - if (stream.rtcpAttr()) - targetAddr.mRtcp.setPort( strx::toInt(remoteStream.getValues("rtcp").front().c_str(), remoteStream.port() + 1 ) ); - else - targetAddr.mRtcp.setPort( remoteStream.port() + 1); + targetAddr.mRtcp.setPort(remoteStream.port() + 1); stream.provider()->setDestinationAddress(targetAddr); @@ -974,9 +977,9 @@ int Session::processSdp(uint64_t version, bool iceAvailable, std::string icePwd, stream.setSocket4(SocketHeap::instance().allocSocketPair(AF_INET, this, IS_MULTIPLEX())); stream.setSocket6(SocketHeap::instance().allocSocketPair(AF_INET6, this, IS_MULTIPLEX())); } - catch(...) + catch (...) { - ICELogError( << "Cannot create media socket."); + ICELogError(<< "Cannot create media socket."); return 503; } @@ -1005,13 +1008,15 @@ int Session::processSdp(uint64_t version, bool iceAvailable, std::string icePwd, // See what remote peer offers - offer only single ice component if it relies on multiplexing if (!targetAddr.multiplexed() && !mUserAgent->mConfig[CONFIG_MULTIPLEXING].asBool()) - ii.mComponentId.mRtcp = mIceStack->addComponent(ii.mStreamId, NULL, stream.socket4().mRtcp->localport(), stream.socket6().mRtcp->localport()); + ii.mComponentId.mRtcp = mIceStack->addComponent(ii.mStreamId, NULL, stream.socket4().mRtcp->localport(), + stream.socket6().mRtcp->localport()); stream.setIceInfo(ii); } if (iceAvailable) { - if (mIceStack->remotePassword(stream.iceInfo().mStreamId) != icePwd || mIceStack->remoteUfrag(stream.iceInfo().mStreamId) != iceUfrag) + if (mIceStack->remotePassword(stream.iceInfo().mStreamId) != icePwd || + mIceStack->remoteUfrag(stream.iceInfo().mStreamId) != iceUfrag) { iceRestart = true; mIceStack->setRemotePassword(icePwd, stream.iceInfo().mStreamId); @@ -1020,10 +1025,10 @@ int Session::processSdp(uint64_t version, bool iceAvailable, std::string icePwd, } // Get remote ICE candidates vector - const std::list candidateList = remoteStream.getValues("candidate"); + const std::list candidateList = remoteStream.getValues("candidate"); // Repackage information about remote candidates - std::vector candidateVector; + std::vector candidateVector; std::list::const_iterator cit = candidateList.begin(); for (; cit != candidateList.end(); ++cit) @@ -1032,9 +1037,11 @@ int Session::processSdp(uint64_t version, bool iceAvailable, std::string icePwd, if (candidateVector.empty()) iceAvailable = false; - // Ask ICE stack to process this information. This call will remove also second component if it is not defined in remote sdp. + // Ask ICE stack to process this information. This call will remove also second component if it is not defined + // in remote sdp. if (iceAvailable) - iceAvailable = mIceStack->processSdpOffer(stream.iceInfo().mStreamId, candidateVector, remoteIp, remotePort, mUserAgent->mConfig[CONFIG_DEFERRELAYED].asBool()); + iceAvailable = mIceStack->processSdpOffer(stream.iceInfo().mStreamId, candidateVector, remoteIp, remotePort, + mUserAgent->mConfig[CONFIG_DEFERRELAYED].asBool()); } // See if there are compatible media streams @@ -1081,22 +1088,22 @@ int Session::release() void Session::clearProvidersAndSockets() { - for (unsigned i=0; isessionDeleted(); - SocketHeap::instance().freeSocketPair( ds.socket4() ); - SocketHeap::instance().freeSocketPair( ds.socket6() ); + SocketHeap::instance().freeSocketPair(ds.socket4()); + SocketHeap::instance().freeSocketPair(ds.socket6()); } } } void Session::clearProviders() { - for (unsigned i=0; isetUa( mAgent ); + s->setUa(mAgent); return s; } diff --git a/src/engine/endpoint/EP_Session.h b/src/engine/endpoint/EP_Session.h index 9643dc3a..7aa5c124 100644 --- a/src/engine/endpoint/EP_Session.h +++ b/src/engine/endpoint/EP_Session.h @@ -49,365 +49,363 @@ class ResipSession; enum SessionInfo { - SessionInfo_RemoteSipAddress, // remote sip address - SessionInfo_ReceivedTraffic, // amount of received traffic in session in bytes - SessionInfo_SentTraffic, // amount of sent traffic in session in bytes - SessionInfo_PacketLoss, // lost packets counter; returns number of 1/1000 fractions (0.1%) - SessionInfo_AudioPeer, // remote peer rtp address in text - SessionInfo_AudioCodec, // selected audio codec as text - SessionInfo_DtmfInterface, // Pointer to DtmfQueue class; returned as void* - SessionInfo_IceState, - SessionInfo_NetworkMos, - SessionInfo_PvqaMos, - SessionInfo_PvqaReport, - SessionInfo_SentRtp, - SessionInfo_SentRtcp, - SessionInfo_ReceivedRtp, - SessionInfo_ReceivedRtcp, - SessionInfo_LostRtp, - SessionInfo_DroppedRtp, - SessionInfo_Duration, - SessionInfo_Jitter, - SessionInfo_Rtt, - SessionInfo_BitrateSwitchCounter, // It is for AMR codecs only - SessionInfo_RemotePeer, - SessionInfo_SSRC, - SessionInfo_CngCounter, // For AMR codecs only - SessionInfo_ReceivedRtpTraffic // amount of received RTP traffic in bytes, RTCP excluded + SessionInfo_RemoteSipAddress, // remote sip address + SessionInfo_ReceivedTraffic, // amount of received traffic in session in bytes + SessionInfo_SentTraffic, // amount of sent traffic in session in bytes + SessionInfo_PacketLoss, // lost packets counter; returns number of 1/1000 fractions (0.1%) + SessionInfo_AudioPeer, // remote peer rtp address in text + SessionInfo_AudioCodec, // selected audio codec as text + SessionInfo_DtmfInterface, // Pointer to DtmfQueue class; returned as void* + SessionInfo_IceState, + SessionInfo_NetworkMos, + SessionInfo_PvqaMos, + SessionInfo_PvqaReport, + SessionInfo_SentRtp, + SessionInfo_SentRtcp, + SessionInfo_ReceivedRtp, + SessionInfo_ReceivedRtcp, + SessionInfo_LostRtp, + SessionInfo_DroppedRtp, + SessionInfo_Duration, + SessionInfo_Jitter, + SessionInfo_Rtt, + SessionInfo_BitrateSwitchCounter, // It is for AMR codecs only + SessionInfo_RemotePeer, + SessionInfo_SSRC, + SessionInfo_CngCounter, // For AMR codecs only + SessionInfo_ReceivedRtpTraffic // amount of received RTP traffic in bytes, RTCP excluded }; -class Session : - public SocketSink, - public ice::StageHandler +class Session : public SocketSink, public ice::StageHandler { public: - class Command - { - public: - virtual void run(Session& s) = 0; - }; - - // Describes ice stream/component - struct IceInfo - { - IceInfo() - :mStreamId(-1) + class Command { - mPort4 = mPort6 = 0; - mComponentId.mRtp = mComponentId.mRtcp = -1; - } + public: + virtual void run(Session& s) = 0; + }; - RtpPair mComponentId; - int mStreamId; - unsigned short mPort4; - unsigned short mPort6; - }; + // Describes ice stream/component + struct IceInfo + { + IceInfo() : mStreamId(-1) + { + mPort4 = mPort6 = 0; + mComponentId.mRtp = mComponentId.mRtcp = -1; + } - // Describes media stream (audio/video) in session - class Stream - { - public: - Stream(); - ~Stream(); + RtpPair mComponentId; + int mStreamId; + unsigned short mPort4; + unsigned short mPort6; + }; - void setProvider(PDataProvider provider); - PDataProvider provider(); + // Describes media stream (audio/video) in session + class Stream + { + public: + Stream(); + ~Stream(); - void setSocket4(const RtpPair& socket); - RtpPair& socket4(); + void setProvider(PDataProvider provider); + PDataProvider provider(); - void setSocket6(const RtpPair& socket); - RtpPair& socket6(); + void setSocket4(const RtpPair& socket); + RtpPair& socket4(); - void setIceInfo(const IceInfo& info); - IceInfo iceInfo() const; + void setSocket6(const RtpPair& socket); + RtpPair& socket6(); - // rtcpAttr/rtcpMuxAttr signals about corresponding sip attribute in offer/answer from remote peer - bool rtcpAttr() const; - void setRtcpAttr(bool value); + void setIceInfo(const IceInfo& info); + IceInfo iceInfo() const; - bool rtcpMuxAttr() const; - void setRtcpMuxAttr(bool value); + // rtcpAttr/rtcpMuxAttr signals about corresponding sip attribute in offer/answer from remote peer + bool rtcpAttr() const; + void setRtcpAttr(bool value); - protected: - // Provider for corresponding stream - PDataProvider mProvider; + bool rtcpMuxAttr() const; + void setRtcpMuxAttr(bool value); - // Socket for stream - RtpPair mSocket4, mSocket6; + protected: + // Provider for corresponding stream + PDataProvider mProvider; - bool mRtcpAttr; - bool mRtcpMuxAttr; - IceInfo mIceInfo; - }; + // Socket for stream + RtpPair mSocket4, mSocket6; - Session(PAccount account); - virtual ~Session(); + bool mRtcpAttr; + bool mRtcpMuxAttr; + IceInfo mIceInfo; + }; - // Starts call to specified peer - void start(const std::string& peer); + Session(PAccount account); + virtual ~Session(); - // Stops call - void stop(); + // Starts call to specified peer + void start(const std::string& peer); - // Accepts call - void accept(); + // Stops call + void stop(); - // Rejects call - void reject(int code); + // Accepts call + void accept(); - enum class InfoOptions - { - Standard = 0, - Detailed = 1, - }; + // Rejects call + void reject(int code); - void getSessionInfo(InfoOptions options, VariantMap& result); + enum class InfoOptions + { + Standard = 0, + Detailed = 1, + }; - // Returns integer identifier of the session; it is unique amongst all session in application - int id() const; + void getSessionInfo(InfoOptions options, VariantMap& result); - // Returns owning account - PAccount account(); + // Returns integer identifier of the session; it is unique amongst all session in application + int id() const; - typedef std::map UserHeaders; - void setUserHeaders(const UserHeaders& headers); + // Returns owning account + PAccount account(); - // Called when new media data are available for this session - void onReceivedData(PDatagramSocket socket, InternetAddress& src, const void* receivedPtr, unsigned receivedSize); + typedef std::map UserHeaders; + void setUserHeaders(const UserHeaders& headers); - // Called when new candidate is gathered - void onCandidateGathered(ice::Stack* stack, void* tag, const char* address); + // Called when new media data are available for this session + void onReceivedData(PDatagramSocket socket, InternetAddress& src, const void* receivedPtr, unsigned receivedSize); - // Called when connectivity check is finished - void onCheckFinished(ice::Stack* stack, void* tag, const char* checkDescription); + // Called when new candidate is gathered + void onCandidateGathered(ice::Stack* stack, void* tag, const char* address); - // Called when ICE candidates are gathered - with success or timeout. - void onGathered(ice::Stack* stack, void* tag); + // Called when connectivity check is finished + void onCheckFinished(ice::Stack* stack, void* tag, const char* checkDescription); - // Called when ICE connectivity check is good at least for one of required streams - void onSuccess(ice::Stack* stack, void* tag); + // Called when ICE candidates are gathered - with success or timeout. + void onGathered(ice::Stack* stack, void* tag); - // Called when ICE connectivity check is failed for all of required streams - void onFailed(ice::Stack* stack, void* tag); + // Called when ICE connectivity check is good at least for one of required streams + void onSuccess(ice::Stack* stack, void* tag); - // Called when ICE stack detects network change during the call - void onNetworkChange(ice::Stack* stack, void* tag); + // Called when ICE connectivity check is failed for all of required streams + void onFailed(ice::Stack* stack, void* tag); - // Fills SDP according to ICE and provider's data - void buildSdp(resip::SdpContents& sdp, SdpDirection sdpDirection); + // Called when ICE stack detects network change during the call + void onNetworkChange(ice::Stack* stack, void* tag); - // Searches provider by its local port number - PDataProvider findProviderByPort(int family, unsigned short port); + // Fills SDP according to ICE and provider's data + void buildSdp(resip::SdpContents& sdp, SdpDirection sdpDirection); - // Add provider to internal list - void addProvider(PDataProvider provider); - PDataProvider providerAt(int index); - int getProviderCount(); + // Searches provider by its local port number + PDataProvider findProviderByPort(int family, unsigned short port); - void setUserAgent(UserAgent* agent); - UserAgent* userAgent(); + // Add provider to internal list + void addProvider(PDataProvider provider); + PDataProvider providerAt(int index); + int getProviderCount(); - // Pauses and resumes all providers; updates states - void pause(); - void resume(); - void refreshMediaPath(); + void setUserAgent(UserAgent* agent); + UserAgent* userAgent(); - // Processes new sdp from offer. Returns response code (200 is ok, 488 bad codec, 503 internal error). - // There are passing string objects by value; this is correct; this values will modified on the stack. - int processSdp(uint64_t version, bool iceAvailable, std::string icePwd, const std::string iceUfrag, - std::string remoteIp, const resip::SdpContents::Session::MediumContainer& media); + // Pauses and resumes all providers; updates states + void pause(); + void resume(); + void refreshMediaPath(); - // Session ID - int mSessionId; + // Processes new sdp from offer. Returns response code (200 is ok, 488 bad codec, 503 internal error). + // There are passing string objects by value; this is correct; this values will modified on the stack. + int processSdp(uint64_t version, bool iceAvailable, std::string icePwd, const std::string iceUfrag, + std::string remoteIp, const resip::SdpContents::Session::MediumContainer& media); - // Media streams collection - std::vector mStreamList; + // Session ID + int mSessionId; - // Smart pointer to ICE stack. Actually stack is created in CreateICEStack() method - std::shared_ptr mIceStack; + // Media streams collection + std::vector mStreamList; - // Pointer to owner user agent instance - UserAgent* mUserAgent; + // Smart pointer to ICE stack. Actually stack is created in CreateICEStack() method + std::shared_ptr mIceStack; - // Remote peer SIP address - resip::NameAddr mRemotePeer; + // Pointer to owner user agent instance + UserAgent* mUserAgent; - // Mutex to protect this instance - Mutex mGuard; + // Remote peer SIP address + resip::NameAddr mRemotePeer; - // SDP's origin version for sending - int mOriginVersion; - uint64_t mRemoteOriginVersion; + // Mutex to protect this instance + Mutex mGuard; - // SDP's session version - int mSessionVersion; + // SDP's origin version for sending + int mOriginVersion; + uint64_t mRemoteOriginVersion; - // Marks if this session does not need OnNewSession event - bool mAcceptedByEngine; - bool mAcceptedByUser; + // SDP's session version + int mSessionVersion; - // Invite session handle - resip::InviteSessionHandle mInviteHandle; + // Marks if this session does not need OnNewSession event + bool mAcceptedByEngine; + bool mAcceptedByUser; - // Dialog set object pointer - ResipSession* mResipSession; + // Invite session handle + resip::InviteSessionHandle mInviteHandle; - // Reference counter - int mRefCount; + // Dialog set object pointer + ResipSession* mResipSession; - enum - { - Initiator = 1, - Acceptor = 2 - }; + // Reference counter + int mRefCount; - // Specifies session role - caller (Initiator) or callee (Acceptor) - volatile int mRole; + enum + { + Initiator = 1, + Acceptor = 2 + }; - // Marks if candidates are gather already - volatile bool mGatheredCandidates; + // Specifies session role - caller (Initiator) or callee (Acceptor) + volatile int mRole; - // Marks if OnTerminated event was called already on session - volatile bool mTerminated; + // Marks if candidates are gather already + volatile bool mGatheredCandidates; - // User friend remote peer's sip address - std::string mRemoteAddress; + // Marks if OnTerminated event was called already on session + volatile bool mTerminated; - // Application specific data - void* mTag; - - // Used to count number of transistions to Connected state and avoid multiple onEstablished events. - int mOfferAnswerCounter; + // User friend remote peer's sip address + std::string mRemoteAddress; - // List of turn prefixes related to sessioj - std::vector mTurnPrefixList; + // Application specific data + void* mTag; - // True if user agent has to send offer - bool mHasToSendOffer; + // Used to count number of transistions to Connected state and avoid multiple onEstablished events. + int mOfferAnswerCounter; - // True if user agent has to enqueue offer after ice gather finished - bool mSendOfferUpdateAfterIceGather; + // List of turn prefixes related to sessioj + std::vector mTurnPrefixList; - // Related sip account - PAccount mAccount; + // True if user agent has to send offer + bool mHasToSendOffer; - // User headers for INVITE transaction - UserHeaders mUserHeaders; + // True if user agent has to enqueue offer after ice gather finished + bool mSendOfferUpdateAfterIceGather; - std::string remoteAddress() const; - void setRemoteAddress(const std::string& address); + // Related sip account + PAccount mAccount; - void* tag(); - void setTag(void* tag); - int sessionId(); - int increaseSdpVersion(); - int addRef(); - int release(); + // User headers for INVITE transaction + UserHeaders mUserHeaders; - // Deletes providers and media sockets - void clearProvidersAndSockets(); + std::string remoteAddress() const; + void setRemoteAddress(const std::string& address); - // Deletes providers - void clearProviders(); + void* tag(); + void setTag(void* tag); + int sessionId(); + int increaseSdpVersion(); + int addRef(); + int release(); - // Helper method to find audio provider for active sip stream - AudioProvider* findProviderForActiveAudio(); + // Deletes providers and media sockets + void clearProvidersAndSockets(); - void processCommandList(); - void addCommand(Command* cmd); - void enqueueOffer(); - void processQueuedOffer(); - static int generateId(); - static std::atomic_int IdGenerator; - static std::atomic_int InstanceCounter; + // Deletes providers + void clearProviders(); + + // Helper method to find audio provider for active sip stream + AudioProvider* findProviderForActiveAudio(); + + void processCommandList(); + void addCommand(Command* cmd); + void enqueueOffer(); + void processQueuedOffer(); + static int generateId(); + static std::atomic_int IdGenerator; + static std::atomic_int InstanceCounter; }; typedef std::shared_ptr PSession; ///////////////////////////////////////////////////////////////////////////////// // -// Classes that provide the mapping between Application Data and DUM +// Classes that provide the mapping between Application Data and DUM // dialogs/dialogsets -// +// // The DUM layer creates an AppDialog/AppDialogSet object for inbound/outbound // SIP Request that results in Dialog creation. -// +// ///////////////////////////////////////////////////////////////////////////////// class ResipSessionAppDialog : public resip::AppDialog { public: - ResipSessionAppDialog(resip::HandleManager& ham); - virtual ~ResipSessionAppDialog(); + ResipSessionAppDialog(resip::HandleManager& ham); + virtual ~ResipSessionAppDialog(); }; -class ResipSession: public resip::AppDialogSet +class ResipSession : public resip::AppDialogSet { -friend class UserAgent; -friend class Account; + friend class UserAgent; + friend class Account; public: - enum Type - { - Type_None, - Type_Registration, - Type_Subscription, - Type_Call, - Type_Auto - }; - static std::atomic_int InstanceCounter; + enum Type + { + Type_None, + Type_Registration, + Type_Subscription, + Type_Call, + Type_Auto + }; + static std::atomic_int InstanceCounter; - ResipSession(resip::DialogUsageManager& dum); - virtual ~ResipSession(); - virtual resip::AppDialog* createAppDialog(const resip::SipMessage& msg); - virtual std::shared_ptr selectUASUserProfile(const resip::SipMessage& msg); - - void setType(Type type); - Type type(); - - Session* session(); - void setSession(Session* session); - - UserAgent* ua(); - void setUa(UserAgent* ua); - - // Used for subscriptions/messages - int sessionId(); - - // Used for subscriptions/messages - void* tag() const; - void setTag(void* tag); + ResipSession(resip::DialogUsageManager& dum); + virtual ~ResipSession(); + virtual resip::AppDialog* createAppDialog(const resip::SipMessage& msg); + virtual std::shared_ptr selectUASUserProfile(const resip::SipMessage& msg); - // Used for subscriptions/messages - std::string remoteAddress() const; - void setRemoteAddress(std::string address); + void setType(Type type); + Type type(); - void runTerminatedEvent(Type type, int code = 0, int reason = 0); + Session* session(); + void setSession(Session* session); - void setUASProfile(const std::shared_ptr& profile); + UserAgent* ua(); + void setUa(UserAgent* ua); + + // Used for subscriptions/messages + int sessionId(); + + // Used for subscriptions/messages + void* tag() const; + void setTag(void* tag); + + // Used for subscriptions/messages + std::string remoteAddress() const; + void setRemoteAddress(std::string address); + + void runTerminatedEvent(Type type, int code = 0, int reason = 0); + + void setUASProfile(const std::shared_ptr& profile); protected: - bool mTerminated; - UserAgent* mUserAgent; - Type mType; - Session* mSession; - int mSessionId; - std::string mRemoteAddress; - void* mTag; - bool mOnWatchingStartSent; - std::shared_ptr mUASProfile; + bool mTerminated; + UserAgent* mUserAgent; + Type mType; + Session* mSession; + int mSessionId; + std::string mRemoteAddress; + void* mTag; + bool mOnWatchingStartSent; + std::shared_ptr mUASProfile; }; class ResipSessionFactory : public resip::AppDialogSetFactory { public: - ResipSessionFactory(UserAgent* agent); - virtual resip::AppDialogSet* createAppDialogSet(resip::DialogUsageManager& dum, const resip::SipMessage& msg); + ResipSessionFactory(UserAgent* agent); + virtual resip::AppDialogSet* createAppDialogSet(resip::DialogUsageManager& dum, const resip::SipMessage& msg); + protected: - UserAgent* mAgent; -}; + UserAgent* mAgent; +}; #endif diff --git a/src/engine/engine_config.h b/src/engine/engine_config.h index 9f5be0b6..c6a341e8 100644 --- a/src/engine/engine_config.h +++ b/src/engine/engine_config.h @@ -9,7 +9,7 @@ #define USE_SPEEX_AEC // TODO: test implementation with webrtc aec; be careful - it needs fixes! -//#define USE_WEBRTC_AEC +// #define USE_WEBRTC_AEC #define USER @@ -20,7 +20,7 @@ #define AUDIO_SAMPLERATE 48000 #define AUDIO_MIC_BUFFER_COUNT 16 #define AUDIO_MIC_BUFFER_LENGTH 10 -#define AUDIO_MIC_BUFFER_SIZE (AUDIO_MIC_BUFFER_LENGTH * AUDIO_SAMPLERATE / 1000 * 2 * AUDIO_CHANNELS) +#define AUDIO_MIC_BUFFER_SIZE (AUDIO_MIC_BUFFER_LENGTH * AUDIO_SAMPLERATE / 1000 * 2 * AUDIO_CHANNELS) #define AUDIO_SPK_BUFFER_COUNT 16 #define AUDIO_SPK_BUFFER_LENGTH 10 #define AUDIO_SPK_BUFFER_SIZE (AUDIO_SPK_BUFFER_LENGTH * AUDIO_SAMPLERATE / 1000 * 2 * AUDIO_CHANNELS) @@ -36,25 +36,25 @@ // Defined these two lines to get dumping of audio input/output -//#define AUDIO_DUMPINPUT -//#define AUDIO_DUMPOUTPUT +// #define AUDIO_DUMPINPUT +// #define AUDIO_DUMPOUTPUT -#define UA_REGISTRATION_TIME 3600 -#define UA_MEDIA_PORT_START 20000 -#define UA_MEDIA_PORT_FINISH 30000 -#define UA_MAX_UDP_PACKET_SIZE 576 -#define UA_PUBLICATION_ID "314" +#define UA_REGISTRATION_TIME 3600 +#define UA_MEDIA_PORT_START 20000 +#define UA_MEDIA_PORT_FINISH 30000 +#define UA_MAX_UDP_PACKET_SIZE 576 +#define UA_PUBLICATION_ID "314" #define MT_SAMPLERATE AUDIO_SAMPLERATE -#define MT_MAXAUDIOFRAME 1440 -#define MT_MAXRTPPACKET 1500 -#define MT_DTMF_END_PACKETS 3 +#define MT_MAXAUDIOFRAME 1440 +#define MT_MAXRTPPACKET 1500 +#define MT_DTMF_END_PACKETS 3 // Milliseconds before -#define RTP_BUFFER_HIGH (2000) -#define RTP_BUFFER_LOW (0) +#define RTP_BUFFER_HIGH (2000) +#define RTP_BUFFER_LOW (0) #define RTP_BUFFER_PREBUFFER (100) #define RTP_DECODED_CAPACITY 2048 @@ -107,13 +107,13 @@ #define MT_MIRROR_PREBUFFER (MT_SAMPLERATE / 10) #if defined(TARGET_OSX) || defined(TARGET_LINUX) -# define TEXT(X) X +#define TEXT(X) X #endif // In milliseconds #define MT_SEVANA_FRAME_TIME 680 // Number of samples -#define MT_MAX_DECODEBUFFER 32768 +#define MT_MAX_DECODEBUFFER 32768 #endif diff --git a/src/engine/helper/HL_AsyncCommand.cpp b/src/engine/helper/HL_AsyncCommand.cpp index 9d04e3c2..44a795e6 100644 --- a/src/engine/helper/HL_AsyncCommand.cpp +++ b/src/engine/helper/HL_AsyncCommand.cpp @@ -5,12 +5,6 @@ #include "HL_AsyncCommand.h" -AsyncCommand::AsyncCommand() -{ +AsyncCommand::AsyncCommand() {} -} - -AsyncCommand::~AsyncCommand() -{ - -} +AsyncCommand::~AsyncCommand() {} diff --git a/src/engine/helper/HL_AsyncCommand.h b/src/engine/helper/HL_AsyncCommand.h index aea6ddaf..d6132f07 100644 --- a/src/engine/helper/HL_AsyncCommand.h +++ b/src/engine/helper/HL_AsyncCommand.h @@ -9,11 +9,11 @@ class AsyncCommand { public: - AsyncCommand(); - virtual ~AsyncCommand(); + AsyncCommand(); + virtual ~AsyncCommand(); - virtual void run(void* environment) = 0; - virtual bool finished() = 0; + virtual void run(void* environment) = 0; + virtual bool finished() = 0; }; #endif // HL_ASYNCCOMMAND_H diff --git a/src/engine/helper/HL_Base64.h b/src/engine/helper/HL_Base64.h index 20e30356..f6bfd725 100644 --- a/src/engine/helper/HL_Base64.h +++ b/src/engine/helper/HL_Base64.h @@ -4,253 +4,301 @@ #include const char kBase64Alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789+/"; + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; -class Base64 { - public: - static bool Encode(const std::string &in, std::string *out) { - int i = 0, j = 0; - size_t enc_len = 0; - unsigned char a3[3]; - unsigned char a4[4]; +class Base64 +{ +public: + static bool Encode(const std::string& in, std::string* out) + { + int i = 0, j = 0; + size_t enc_len = 0; + unsigned char a3[3]; + unsigned char a4[4]; - out->resize(EncodedLength(in)); + out->resize(EncodedLength(in)); - int input_len = in.size(); - std::string::const_iterator input = in.begin(); + int input_len = in.size(); + std::string::const_iterator input = in.begin(); - while (input_len--) { - a3[i++] = *(input++); - if (i == 3) { - a3_to_a4(a4, a3); + while (input_len--) + { + a3[i++] = *(input++); + if (i == 3) + { + a3_to_a4(a4, a3); - for (i = 0; i < 4; i++) { - (*out)[enc_len++] = kBase64Alphabet[a4[i]]; + for (i = 0; i < 4; i++) + { + (*out)[enc_len++] = kBase64Alphabet[a4[i]]; + } + + i = 0; + } } - i = 0; - } - } + if (i) + { + for (j = i; j < 3; j++) + { + a3[j] = '\0'; + } - if (i) { - for (j = i; j < 3; j++) { - a3[j] = '\0'; - } + a3_to_a4(a4, a3); - a3_to_a4(a4, a3); + for (j = 0; j < i + 1; j++) + { + (*out)[enc_len++] = kBase64Alphabet[a4[j]]; + } - for (j = 0; j < i + 1; j++) { - (*out)[enc_len++] = kBase64Alphabet[a4[j]]; - } - - while ((i++ < 3)) { - (*out)[enc_len++] = '='; - } - } - - return (enc_len == out->size()); - } - - static bool Encode(const char *input, size_t input_length, char *out, size_t out_length) { - int i = 0, j = 0; - char *out_begin = out; - unsigned char a3[3]; - unsigned char a4[4]; - - size_t encoded_length = EncodedLength(input_length); - - if (out_length < encoded_length) return false; - - while (input_length--) { - a3[i++] = *input++; - if (i == 3) { - a3_to_a4(a4, a3); - - for (i = 0; i < 4; i++) { - *out++ = kBase64Alphabet[a4[i]]; + while ((i++ < 3)) + { + (*out)[enc_len++] = '='; + } } - i = 0; - } + return (enc_len == out->size()); } - if (i) { - for (j = i; j < 3; j++) { - a3[j] = '\0'; - } + static bool Encode(const char* input, size_t input_length, char* out, size_t out_length) + { + int i = 0, j = 0; + char* out_begin = out; + unsigned char a3[3]; + unsigned char a4[4]; - a3_to_a4(a4, a3); + size_t encoded_length = EncodedLength(input_length); - for (j = 0; j < i + 1; j++) { - *out++ = kBase64Alphabet[a4[j]]; - } + if (out_length < encoded_length) + return false; - while ((i++ < 3)) { - *out++ = '='; - } - } + while (input_length--) + { + a3[i++] = *input++; + if (i == 3) + { + a3_to_a4(a4, a3); - return (out == (out_begin + encoded_length)); - } + for (i = 0; i < 4; i++) + { + *out++ = kBase64Alphabet[a4[i]]; + } - static bool Decode(const std::string &in, std::string *out) { - int i = 0, j = 0; - size_t dec_len = 0; - unsigned char a3[3]; - unsigned char a4[4]; - - int input_len = in.size(); - std::string::const_iterator input = in.begin(); - - out->resize(DecodedLength(in)); - - while (input_len--) { - if (*input == '=') { - break; - } - - a4[i++] = *(input++); - if (i == 4) { - for (i = 0; i <4; i++) { - a4[i] = b64_lookup(a4[i]); + i = 0; + } } - a4_to_a3(a3,a4); + if (i) + { + for (j = i; j < 3; j++) + { + a3[j] = '\0'; + } - for (i = 0; i < 3; i++) { - (*out)[dec_len++] = a3[i]; + a3_to_a4(a4, a3); + + for (j = 0; j < i + 1; j++) + { + *out++ = kBase64Alphabet[a4[j]]; + } + + while ((i++ < 3)) + { + *out++ = '='; + } } - i = 0; - } + return (out == (out_begin + encoded_length)); } - if (i) { - for (j = i; j < 4; j++) { - a4[j] = '\0'; - } + static bool Decode(const std::string& in, std::string* out) + { + int i = 0, j = 0; + size_t dec_len = 0; + unsigned char a3[3]; + unsigned char a4[4]; - for (j = 0; j < 4; j++) { - a4[j] = b64_lookup(a4[j]); - } + int input_len = in.size(); + std::string::const_iterator input = in.begin(); - a4_to_a3(a3,a4); + out->resize(DecodedLength(in)); - for (j = 0; j < i - 1; j++) { - (*out)[dec_len++] = a3[j]; - } - } + while (input_len--) + { + if (*input == '=') + { + break; + } - return (dec_len == out->size()); - } + a4[i++] = *(input++); + if (i == 4) + { + for (i = 0; i < 4; i++) + { + a4[i] = b64_lookup(a4[i]); + } - static bool Decode(const char *input, size_t input_length, char *out, size_t out_length) { - int i = 0, j = 0; - char *out_begin = out; - unsigned char a3[3]; - unsigned char a4[4]; + a4_to_a3(a3, a4); - size_t decoded_length = DecodedLength(input, input_length); + for (i = 0; i < 3; i++) + { + (*out)[dec_len++] = a3[i]; + } - if (out_length < decoded_length) return false; - - while (input_length--) { - if (*input == '=') { - break; - } - - a4[i++] = *(input++); - if (i == 4) { - for (i = 0; i <4; i++) { - a4[i] = b64_lookup(a4[i]); + i = 0; + } } - a4_to_a3(a3,a4); + if (i) + { + for (j = i; j < 4; j++) + { + a4[j] = '\0'; + } - for (i = 0; i < 3; i++) { - *out++ = a3[i]; + for (j = 0; j < 4; j++) + { + a4[j] = b64_lookup(a4[j]); + } + + a4_to_a3(a3, a4); + + for (j = 0; j < i - 1; j++) + { + (*out)[dec_len++] = a3[j]; + } } - i = 0; - } + return (dec_len == out->size()); } - if (i) { - for (j = i; j < 4; j++) { - a4[j] = '\0'; - } + static bool Decode(const char* input, size_t input_length, char* out, size_t out_length) + { + int i = 0, j = 0; + char* out_begin = out; + unsigned char a3[3]; + unsigned char a4[4]; - for (j = 0; j < 4; j++) { - a4[j] = b64_lookup(a4[j]); - } + size_t decoded_length = DecodedLength(input, input_length); - a4_to_a3(a3,a4); + if (out_length < decoded_length) + return false; - for (j = 0; j < i - 1; j++) { - *out++ = a3[j]; - } + while (input_length--) + { + if (*input == '=') + { + break; + } + + a4[i++] = *(input++); + if (i == 4) + { + for (i = 0; i < 4; i++) + { + a4[i] = b64_lookup(a4[i]); + } + + a4_to_a3(a3, a4); + + for (i = 0; i < 3; i++) + { + *out++ = a3[i]; + } + + i = 0; + } + } + + if (i) + { + for (j = i; j < 4; j++) + { + a4[j] = '\0'; + } + + for (j = 0; j < 4; j++) + { + a4[j] = b64_lookup(a4[j]); + } + + a4_to_a3(a3, a4); + + for (j = 0; j < i - 1; j++) + { + *out++ = a3[j]; + } + } + + return (out == (out_begin + decoded_length)); } - return (out == (out_begin + decoded_length)); - } + static int DecodedLength(const char* in, size_t in_length) + { + int numEq = 0; - static int DecodedLength(const char *in, size_t in_length) { - int numEq = 0; + const char* in_end = in + in_length; + while (*--in_end == '=') + ++numEq; - const char *in_end = in + in_length; - while (*--in_end == '=') ++numEq; - - return ((6 * in_length) / 8) - numEq; - } - - static int DecodedLength(const std::string &in) { - int numEq = 0; - int n = in.size(); - - for (std::string::const_reverse_iterator it = in.rbegin(); *it == '='; ++it) { - ++numEq; + return ((6 * in_length) / 8) - numEq; } - return ((6 * n) / 8) - numEq; - } + static int DecodedLength(const std::string& in) + { + int numEq = 0; + int n = in.size(); - inline static int EncodedLength(size_t length) { - return (length + 2 - ((length + 2) % 3)) / 3 * 4; - } + for (std::string::const_reverse_iterator it = in.rbegin(); *it == '='; ++it) + { + ++numEq; + } - inline static int EncodedLength(const std::string &in) { - return EncodedLength(in.length()); - } + return ((6 * n) / 8) - numEq; + } - inline static void StripPadding(std::string *in) { - while (!in->empty() && *(in->rbegin()) == '=') in->resize(in->size() - 1); - } + inline static int EncodedLength(size_t length) { return (length + 2 - ((length + 2) % 3)) / 3 * 4; } - private: - static inline void a3_to_a4(unsigned char * a4, unsigned char * a3) { - a4[0] = (a3[0] & 0xfc) >> 2; - a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4); - a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6); - a4[3] = (a3[2] & 0x3f); - } + inline static int EncodedLength(const std::string& in) { return EncodedLength(in.length()); } - static inline void a4_to_a3(unsigned char * a3, unsigned char * a4) { - a3[0] = (a4[0] << 2) + ((a4[1] & 0x30) >> 4); - a3[1] = ((a4[1] & 0xf) << 4) + ((a4[2] & 0x3c) >> 2); - a3[2] = ((a4[2] & 0x3) << 6) + a4[3]; - } + inline static void StripPadding(std::string* in) + { + while (!in->empty() && *(in->rbegin()) == '=') + in->resize(in->size() - 1); + } - static inline unsigned char b64_lookup(unsigned char c) { - if(c >='A' && c <='Z') return c - 'A'; - if(c >='a' && c <='z') return c - 71; - if(c >='0' && c <='9') return c + 4; - if(c == '+') return 62; - if(c == '/') return 63; - return 255; - } +private: + static inline void a3_to_a4(unsigned char* a4, unsigned char* a3) + { + a4[0] = (a3[0] & 0xfc) >> 2; + a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4); + a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6); + a4[3] = (a3[2] & 0x3f); + } + + static inline void a4_to_a3(unsigned char* a3, unsigned char* a4) + { + a3[0] = (a4[0] << 2) + ((a4[1] & 0x30) >> 4); + a3[1] = ((a4[1] & 0xf) << 4) + ((a4[2] & 0x3c) >> 2); + a3[2] = ((a4[2] & 0x3) << 6) + a4[3]; + } + + static inline unsigned char b64_lookup(unsigned char c) + { + if (c >= 'A' && c <= 'Z') + return c - 'A'; + if (c >= 'a' && c <= 'z') + return c - 71; + if (c >= '0' && c <= '9') + return c + 4; + if (c == '+') + return 62; + if (c == '/') + return 63; + return 255; + } }; - #endif // HL_BASE64_H \ No newline at end of file diff --git a/src/engine/helper/HL_ByteBuffer.h b/src/engine/helper/HL_ByteBuffer.h index 94711715..23ab81b3 100644 --- a/src/engine/helper/HL_ByteBuffer.h +++ b/src/engine/helper/HL_ByteBuffer.h @@ -8,10 +8,10 @@ #include "ice/ICEByteBuffer.h" -typedef ice::ByteBuffer ByteBuffer; -typedef ice::PByteBuffer PByteBuffer; -typedef ice::BitReader BitReader; -typedef ice::BitWriter BitWriter; +typedef ice::ByteBuffer ByteBuffer; +typedef ice::PByteBuffer PByteBuffer; +typedef ice::BitReader BitReader; +typedef ice::BitWriter BitWriter; typedef ice::BufferReader BufferReader; typedef ice::BufferWriter BufferWriter; diff --git a/src/engine/helper/HL_Calculator.h b/src/engine/helper/HL_Calculator.h index 9075d2fd..a0703852 100644 --- a/src/engine/helper/HL_Calculator.h +++ b/src/engine/helper/HL_Calculator.h @@ -11,616 +11,629 @@ namespace Calc { - class Parser; - namespace Ast - { - enum class Type - { - None, - And, - Or, - Equal, - NotEqual, - Less, - LessOrEqual, - Greater, - GreatorOrEqual, - Add, - Sub, - Mul, - Div, - Number, - String, - Var - }; +class Parser; +namespace Ast +{ +enum class Type +{ + None, + And, + Or, + Equal, + NotEqual, + Less, + LessOrEqual, + Greater, + GreatorOrEqual, + Add, + Sub, + Mul, + Div, + Number, + String, + Var +}; - class Item; - typedef Item* PItem; +class Item; +typedef Item* PItem; - class Item - { +class Item +{ friend class Calc::Parser; - public: - bool isVariable() const - { - return mType == Type::Var; - } - bool isFixed() const - { - return mType == Type::Number || mType == Type::String; - } - bool isOperation() const - { - return mType >= Type::And && mType <= Type::Div; - } +public: + bool isVariable() const { return mType == Type::Var; } + bool isFixed() const { return mType == Type::Number || mType == Type::String; } - bool hasBrackets() const - { - return mHasBrackets; - } + bool isOperation() const { return mType >= Type::And && mType <= Type::Div; } - int getOperatorLevel() const - { + bool hasBrackets() const { return mHasBrackets; } + + int getOperatorLevel() const + { switch (mType) { case Type::Or: - return -2; + return -2; case Type::And: - return -1; + return -1; case Type::Equal: case Type::NotEqual: - return 0; + return 0; case Type::Less: case Type::LessOrEqual: case Type::Greater: case Type::GreatorOrEqual: - return 1; + return 1; case Type::Add: case Type::Sub: - return 2; + return 2; case Type::Mul: case Type::Div: - return 3; + return 3; default: - return 4; + return 4; } assert(0); - } + } - Type getType() const - { - return mType; - } + Type getType() const { return mType; } - std::string getName() const - { - return mName; - } + std::string getName() const { return mName; } - Variant& value() - { - return mValue; - } + Variant& value() { return mValue; } - std::vector& children() - { - return mChildren; - } + std::vector& children() { return mChildren; } - typedef std::map NameMap; + typedef std::map NameMap; - std::ostream& print(std::ostream& oss, const NameMap& nm) - { + std::ostream& print(std::ostream& oss, const NameMap& nm) + { oss << " ( "; if (isOperation()) - mChildren.front()->print(oss, nm); + mChildren.front()->print(oss, nm); oss << " "; switch (mType) { - case Type::Number: oss << mValue.asStdString(); break; - case Type::String: oss << '"' << mValue.asStdString() << '"'; break; - case Type::Var: { NameMap::const_iterator iter = nm.find(mName); oss << ((iter != nm.end()) ? iter->second : mName);} break; - case Type::Add: oss << "+"; break; - case Type::Mul: oss << "*"; break; - case Type::Div: oss << "/"; break; - case Type::Sub: oss << "-"; break; - case Type::Equal: oss << "=="; break; - case Type::NotEqual: oss << "!="; break; - case Type::Less: oss << "<"; break; - case Type::LessOrEqual: oss << "<="; break; - case Type::Greater: oss << ">"; break; - case Type::GreatorOrEqual: oss << ">="; break; - case Type::Or: oss << "or"; break; - case Type::And: oss << "and"; break; + case Type::Number: + oss << mValue.asStdString(); + break; + case Type::String: + oss << '"' << mValue.asStdString() << '"'; + break; + case Type::Var: + { + NameMap::const_iterator iter = nm.find(mName); + oss << ((iter != nm.end()) ? iter->second : mName); + } + break; + case Type::Add: + oss << "+"; + break; + case Type::Mul: + oss << "*"; + break; + case Type::Div: + oss << "/"; + break; + case Type::Sub: + oss << "-"; + break; + case Type::Equal: + oss << "=="; + break; + case Type::NotEqual: + oss << "!="; + break; + case Type::Less: + oss << "<"; + break; + case Type::LessOrEqual: + oss << "<="; + break; + case Type::Greater: + oss << ">"; + break; + case Type::GreatorOrEqual: + oss << ">="; + break; + case Type::Or: + oss << "or"; + break; + case Type::And: + oss << "and"; + break; default: - throw std::runtime_error("operator expected"); + throw std::runtime_error("operator expected"); } oss << " "; if (isOperation() && mChildren.size() == 2 && mChildren.back()) - mChildren.back()->print(oss, nm); + mChildren.back()->print(oss, nm); oss << " ) "; return oss; - } + } - typedef std::map ValueMap; + typedef std::map ValueMap; - Variant eval(const ValueMap& vm) - { + Variant eval(const ValueMap& vm) + { Variant result, left, right; if (isOperation()) { - left = mChildren.front()->eval(vm); - right = mChildren.back()->eval(vm); + left = mChildren.front()->eval(vm); + right = mChildren.back()->eval(vm); } switch (mType) { case Type::Number: - case Type::String: result = mValue; break; + case Type::String: + result = mValue; + break; - case Type::Var: { auto iter = vm.find(mName); if (iter != vm.end()) return iter->second; else throw std::runtime_error("Variable " + mName + " did not find."); } - break; + case Type::Var: + { + auto iter = vm.find(mName); + if (iter != vm.end()) + return iter->second; + else + throw std::runtime_error("Variable " + mName + " did not find."); + } + break; - case Type::Add: result = left + right; break; - case Type::Mul: result = left * right; break; - case Type::Div: result = left / right; break; - case Type::Sub: result = left - right; break; - case Type::Equal: result = left == right; break; - case Type::NotEqual: result = left != right; break; - case Type::Less: result = left < right; break; - case Type::LessOrEqual: result = left <= right; break; - case Type::Greater: result = left > right; break; - case Type::GreatorOrEqual: result = left >= right; break; - case Type::Or: result = left.asBool() || right.asBool(); break; - case Type::And: result = left.asBool() && right.asBool(); break; + case Type::Add: + result = left + right; + break; + case Type::Mul: + result = left * right; + break; + case Type::Div: + result = left / right; + break; + case Type::Sub: + result = left - right; + break; + case Type::Equal: + result = left == right; + break; + case Type::NotEqual: + result = left != right; + break; + case Type::Less: + result = left < right; + break; + case Type::LessOrEqual: + result = left <= right; + break; + case Type::Greater: + result = left > right; + break; + case Type::GreatorOrEqual: + result = left >= right; + break; + case Type::Or: + result = left.asBool() || right.asBool(); + break; + case Type::And: + result = left.asBool() && right.asBool(); + break; default: - assert(0); + assert(0); } return result; - } + } - ~Item() - { - for (auto node: mChildren) - delete node; + ~Item() + { + for (auto node : mChildren) + delete node; mChildren.clear(); - } + } - private: - Type mType = Type::None; - std::string mName; - Variant mValue; - std::vector mChildren; - bool mHasBrackets = false; - }; - } +private: + Type mType = Type::None; + std::string mName; + Variant mValue; + std::vector mChildren; + bool mHasBrackets = false; +}; +} // namespace Ast - static bool ishex(int c) - { +static bool ishex(int c) +{ if (isdigit(c)) - return true; + return true; return (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); - } +} - class Parser - { - private: +class Parser +{ +private: enum class LexemType { - None, - Hex, - Dec, - Float, - Str, - Oper, - Var, - OpenBracket, - CloseBracket + None, + Hex, + Dec, + Float, + Str, + Oper, + Var, + OpenBracket, + CloseBracket }; struct Lexem { - LexemType mType = LexemType::None; - std::string mValue; + LexemType mType = LexemType::None; + std::string mValue; - operator bool () const - { - return mType != LexemType::None; - } + operator bool() const { return mType != LexemType::None; } - std::string toString() const - { - return std::to_string((int)mType) + " : " + mValue; - } + std::string toString() const { return std::to_string((int)mType) + " : " + mValue; } }; Lexem mCurrentLexem; Lexem processNewLexem(int c) { - Lexem result; + Lexem result; - if (c == '(') - mCurrentLexem.mType = LexemType::OpenBracket; - else - if (c == ')') - mCurrentLexem.mType = LexemType::CloseBracket; - else - if (isdigit(c)) - mCurrentLexem.mType = LexemType::Dec; - else - if (isalpha(c)) - mCurrentLexem.mType = LexemType::Var; - else - if (c == '+' || c == '-' || c == '/' || c == '*' || c == '=' || c == '<' || c == '>' || c == '&' || c == '|') - mCurrentLexem.mType = LexemType::Oper; - else - if (c == '"') - mCurrentLexem.mType = LexemType::Str; - else - return Lexem(); + if (c == '(') + mCurrentLexem.mType = LexemType::OpenBracket; + else if (c == ')') + mCurrentLexem.mType = LexemType::CloseBracket; + else if (isdigit(c)) + mCurrentLexem.mType = LexemType::Dec; + else if (isalpha(c)) + mCurrentLexem.mType = LexemType::Var; + else if (c == '+' || c == '-' || c == '/' || c == '*' || c == '=' || c == '<' || c == '>' || c == '&' || + c == '|') + mCurrentLexem.mType = LexemType::Oper; + else if (c == '"') + mCurrentLexem.mType = LexemType::Str; + else + return Lexem(); - mCurrentLexem.mValue.push_back(c); + mCurrentLexem.mValue.push_back(c); - // Can we return result here already ? - if (mCurrentLexem.mType == LexemType::OpenBracket || mCurrentLexem.mType == LexemType::CloseBracket) - { - // Lexem finished - result = mCurrentLexem; - mCurrentLexem = Lexem(); - return result; - } - - if (mCurrentLexem.mType == LexemType::Oper) - { - if (mCurrentLexem.mValue == "+" || - mCurrentLexem.mValue == "-" || - mCurrentLexem.mValue == "*" || - mCurrentLexem.mValue == "/" || - mCurrentLexem.mValue == ">=" || - mCurrentLexem.mValue == "<=" || - mCurrentLexem.mValue == "==" || - mCurrentLexem.mValue == "||" || - mCurrentLexem.mValue == "&&") + // Can we return result here already ? + if (mCurrentLexem.mType == LexemType::OpenBracket || mCurrentLexem.mType == LexemType::CloseBracket) { - // Lexem finished - result = mCurrentLexem; - mCurrentLexem = Lexem(); - return result; + // Lexem finished + result = mCurrentLexem; + mCurrentLexem = Lexem(); + return result; } - } - return Lexem(); + + if (mCurrentLexem.mType == LexemType::Oper) + { + if (mCurrentLexem.mValue == "+" || mCurrentLexem.mValue == "-" || mCurrentLexem.mValue == "*" || + mCurrentLexem.mValue == "/" || mCurrentLexem.mValue == ">=" || mCurrentLexem.mValue == "<=" || + mCurrentLexem.mValue == "==" || mCurrentLexem.mValue == "||" || mCurrentLexem.mValue == "&&") + { + // Lexem finished + result = mCurrentLexem; + mCurrentLexem = Lexem(); + return result; + } + } + return Lexem(); } void checkNumericLexem() { - if (mCurrentLexem.mType != LexemType::Dec) - return; + if (mCurrentLexem.mType != LexemType::Dec) + return; - // Check if there is ".:" characters - if (mCurrentLexem.mValue.find('.') != std::string::npos) - { - // Dot is here - is it float - bool isFloat = false; - strx::toFloat(mCurrentLexem.mValue, 0.0f, &isFloat); - if (isFloat) - mCurrentLexem.mType = LexemType::Float; - else + // Check if there is ".:" characters + if (mCurrentLexem.mValue.find('.') != std::string::npos) { - // Maybe it is IP4/6 address ? - InternetAddress addr(mCurrentLexem.mValue, 8000); - if (!addr.isEmpty()) - { - mCurrentLexem.mValue = "\"" + mCurrentLexem.mValue + "\""; - mCurrentLexem.mType = LexemType::Str; - } + // Dot is here - is it float + bool isFloat = false; + strx::toFloat(mCurrentLexem.mValue, 0.0f, &isFloat); + if (isFloat) + mCurrentLexem.mType = LexemType::Float; + else + { + // Maybe it is IP4/6 address ? + InternetAddress addr(mCurrentLexem.mValue, 8000); + if (!addr.isEmpty()) + { + mCurrentLexem.mValue = "\"" + mCurrentLexem.mValue + "\""; + mCurrentLexem.mType = LexemType::Str; + } + } } - } } Lexem getLexem(std::istream& input) { - Lexem result; + Lexem result; - // Iterate while characters avaialbe from input stream & lexem is not finished - bool putback = false; - int c = input.get(); - while (!input.eof() && c && result.mType == LexemType::None) - { - switch (mCurrentLexem.mType) + // Iterate while characters avaialbe from input stream & lexem is not finished + bool putback = false; + int c = input.get(); + while (!input.eof() && c && result.mType == LexemType::None) { - case LexemType::None: - result = processNewLexem(c); - break; + switch (mCurrentLexem.mType) + { + case LexemType::None: + result = processNewLexem(c); + break; - case LexemType::Hex: - if (!ishex(c)) - { - // Finish Hex lexem - result = mCurrentLexem; - putback = true; - } - else - mCurrentLexem.mValue.push_back(c); - break; + case LexemType::Hex: + if (!ishex(c)) + { + // Finish Hex lexem + result = mCurrentLexem; + putback = true; + } + else + mCurrentLexem.mValue.push_back(c); + break; - case LexemType::Dec: - if (c == 'x' && mCurrentLexem.mValue == "0") - mCurrentLexem.mType = LexemType::Hex; - else - if (isdigit(c) || c == '.') - { - mCurrentLexem.mValue.push_back(c); - } - else - { - checkNumericLexem(); - result = mCurrentLexem; - putback = true; - } - break; + case LexemType::Dec: + if (c == 'x' && mCurrentLexem.mValue == "0") + mCurrentLexem.mType = LexemType::Hex; + else if (isdigit(c) || c == '.') + { + mCurrentLexem.mValue.push_back(c); + } + else + { + checkNumericLexem(); + result = mCurrentLexem; + putback = true; + } + break; - case LexemType::Oper: - // It must be one of two-characters operations - if (c == '<' || c == '>' || c == '=' || c == '&' || c == '|') - { - mCurrentLexem.mValue.push_back(c); - result = mCurrentLexem; - mCurrentLexem = Lexem(); - } - else - { - result = mCurrentLexem; - putback = true; - } - break; + case LexemType::Oper: + // It must be one of two-characters operations + if (c == '<' || c == '>' || c == '=' || c == '&' || c == '|') + { + mCurrentLexem.mValue.push_back(c); + result = mCurrentLexem; + mCurrentLexem = Lexem(); + } + else + { + result = mCurrentLexem; + putback = true; + } + break; - case LexemType::Var: - if (isdigit(c) || isalpha(c) || c == '.' || c == '_') - { - mCurrentLexem.mValue.push_back(c); - } - else - { - result = mCurrentLexem; - putback = true; - } - break; + case LexemType::Var: + if (isdigit(c) || isalpha(c) || c == '.' || c == '_') + { + mCurrentLexem.mValue.push_back(c); + } + else + { + result = mCurrentLexem; + putback = true; + } + break; - case LexemType::Str: - mCurrentLexem.mValue.push_back(c); - if (c == '"') - { - result = mCurrentLexem; - // String lexem is finished - mCurrentLexem.mType = LexemType::None; - putback = false; - } - break; + case LexemType::Str: + mCurrentLexem.mValue.push_back(c); + if (c == '"') + { + result = mCurrentLexem; + // String lexem is finished + mCurrentLexem.mType = LexemType::None; + putback = false; + } + break; - default: - assert(0); + default: + assert(0); + } + + if (putback) + input.putback(c); + else if (!result) + c = input.get(); } - if (putback) - input.putback(c); - else - if (!result) - c = input.get(); - } + checkNumericLexem(); - checkNumericLexem(); + // Recover partially processed lexem - maybe we finish processing at all but there is dec / float / string / + // variable + if (mCurrentLexem.mType != LexemType::None && result.mType == LexemType::None) + result = mCurrentLexem; - // Recover partially processed lexem - maybe we finish processing at all but there is dec / float / string / variable - if (mCurrentLexem.mType != LexemType::None && result.mType == LexemType::None) - result = mCurrentLexem; + // Reset current lexem + mCurrentLexem = Lexem(); - // Reset current lexem - mCurrentLexem = Lexem(); - - return result; + return result; } // Make AST node from lexem Ast::PItem makeAst(const Lexem& l) { - Ast::PItem result(new Ast::Item()); + Ast::PItem result(new Ast::Item()); - switch (l.mType) - { - case LexemType::Oper: - if (l.mValue == "-") - result->mType = Ast::Type::Sub; - else - if (l.mValue == "+") - result->mType = Ast::Type::Add; - else - if (l.mValue == "*") - result->mType = Ast::Type::Mul; - else - if (l.mValue == "/") - result->mType = Ast::Type::Div; - else - if (l.mValue == "<") - result->mType = Ast::Type::Less; - else - if (l.mValue == "<=") - result->mType = Ast::Type::LessOrEqual; - else - if (l.mValue == ">") - result->mType = Ast::Type::Greater; - else - if (l.mValue == ">=") - result->mType = Ast::Type::GreatorOrEqual; - else - if (l.mValue == "==") - result->mType = Ast::Type::Equal; - else - if (l.mValue == "!=") - result->mType = Ast::Type::NotEqual; - else - if (l.mValue == "&&") - result->mType = Ast::Type::And; - else - if (l.mValue == "||") - result->mType = Ast::Type::Or; - break; + switch (l.mType) + { + case LexemType::Oper: + if (l.mValue == "-") + result->mType = Ast::Type::Sub; + else if (l.mValue == "+") + result->mType = Ast::Type::Add; + else if (l.mValue == "*") + result->mType = Ast::Type::Mul; + else if (l.mValue == "/") + result->mType = Ast::Type::Div; + else if (l.mValue == "<") + result->mType = Ast::Type::Less; + else if (l.mValue == "<=") + result->mType = Ast::Type::LessOrEqual; + else if (l.mValue == ">") + result->mType = Ast::Type::Greater; + else if (l.mValue == ">=") + result->mType = Ast::Type::GreatorOrEqual; + else if (l.mValue == "==") + result->mType = Ast::Type::Equal; + else if (l.mValue == "!=") + result->mType = Ast::Type::NotEqual; + else if (l.mValue == "&&") + result->mType = Ast::Type::And; + else if (l.mValue == "||") + result->mType = Ast::Type::Or; + break; - case LexemType::Var: - result->mType = Ast::Type::Var; - result->mName = l.mValue; - break; + case LexemType::Var: + result->mType = Ast::Type::Var; + result->mName = l.mValue; + break; - case LexemType::Dec: - result->mType = Ast::Type::Number; - result->mValue = (int64_t)atoll(l.mValue.c_str()); - break; + case LexemType::Dec: + result->mType = Ast::Type::Number; + result->mValue = (int64_t)atoll(l.mValue.c_str()); + break; - case LexemType::Hex: - result->mType = Ast::Type::Number; - result->mValue = strx::fromHex2Int(l.mValue); - break; + case LexemType::Hex: + result->mType = Ast::Type::Number; + result->mValue = strx::fromHex2Int(l.mValue); + break; - case LexemType::Float: - result->mType = Ast::Type::Number; - result->mValue = (float)atof(l.mValue.c_str()); - break; + case LexemType::Float: + result->mType = Ast::Type::Number; + result->mValue = (float)atof(l.mValue.c_str()); + break; - case LexemType::Str: - result->mType = Ast::Type::String; - result->mValue = l.mValue.substr(1, l.mValue.size() - 2); - break; + case LexemType::Str: + result->mType = Ast::Type::String; + result->mValue = l.mValue.substr(1, l.mValue.size() - 2); + break; - default: - throw std::runtime_error("Unexpected lexem."); - } + default: + throw std::runtime_error("Unexpected lexem."); + } - return result; + return result; } Lexem mLexem; - public: + +public: Ast::PItem parseExpression(std::istream& input) { - Ast::PItem operationNode(nullptr), leftNode(nullptr), rightNode(nullptr), - currentOperation(nullptr); + Ast::PItem operationNode(nullptr), leftNode(nullptr), rightNode(nullptr), currentOperation(nullptr); - // While we have lexem - while (mLexem = getLexem(input)) - { - std::cout << "Returned lexem: " << mLexem.toString() << std::endl; - - if (!leftNode) + // While we have lexem + while (mLexem = getLexem(input)) { - // It must be first operand! - switch (mLexem.mType) - { - case LexemType::OpenBracket: - leftNode = parseExpression(input); - leftNode->mHasBrackets = true; - break; + std::cout << "Returned lexem: " << mLexem.toString() << std::endl; - case LexemType::CloseBracket: - throw std::runtime_error("Expected +/-/constant/variable here."); + if (!leftNode) + { + // It must be first operand! + switch (mLexem.mType) + { + case LexemType::OpenBracket: + leftNode = parseExpression(input); + leftNode->mHasBrackets = true; + break; - case LexemType::Dec: - case LexemType::Hex: - case LexemType::Str: - case LexemType::Var: - case LexemType::Float: - leftNode = makeAst(mLexem); - break; + case LexemType::CloseBracket: + throw std::runtime_error("Expected +/-/constant/variable here."); - default: - throw std::runtime_error("Open bracket or constant / number / string / variable expected."); - } + case LexemType::Dec: + case LexemType::Hex: + case LexemType::Str: + case LexemType::Var: + case LexemType::Float: + leftNode = makeAst(mLexem); + break; + + default: + throw std::runtime_error("Open bracket or constant / number / string / variable expected."); + } + } + else if (!operationNode) + { + // Well, there is left node already + // See operation here + switch (mLexem.mType) + { + case LexemType::Oper: + operationNode = makeAst(mLexem); + break; + + case LexemType::None: + // Finish the tree building + break; + + case LexemType::CloseBracket: + // Finish the tree building in this level + if (leftNode) + return leftNode; + break; + + default: + throw std::runtime_error("Expected operation."); + } + + // Parse rest of expression + rightNode = parseExpression(input); + + // If right part of expression is operation - make left side child of right part - to allow calculation + // in right order + if (operationNode) + { + if (rightNode->isOperation() && + rightNode->getOperatorLevel() <= operationNode->getOperatorLevel() && !rightNode->hasBrackets()) + { + // Get left child of right expression - make it our right child + operationNode->children().push_back(leftNode); + operationNode->children().push_back(rightNode->children().front()); + rightNode->children().front() = operationNode; + currentOperation = rightNode; + } + else + { + operationNode->children().push_back(leftNode); + operationNode->children().push_back(rightNode); + currentOperation = operationNode; + } + } + if (mLexem.mType == LexemType::CloseBracket) + break; // Exit from loop + } } - else - if (!operationNode) + return currentOperation ? currentOperation : leftNode; + } + +public: + Ast::PItem parse(std::istream& input) { return nullptr; } + + void testLexemParser(const std::string& test) + { + std::istringstream iss(test); + + for (Lexem l = getLexem(iss); l.mType != LexemType::None; l = getLexem(iss)) { - // Well, there is left node already - // See operation here - switch (mLexem.mType) - { - case LexemType::Oper: - operationNode = makeAst(mLexem); - break; - - case LexemType::None: - // Finish the tree building - break; - - case LexemType::CloseBracket: - // Finish the tree building in this level - if (leftNode) - return leftNode; - break; - - default: - throw std::runtime_error("Expected operation."); - } - - // Parse rest of expression - rightNode = parseExpression(input); - - // If right part of expression is operation - make left side child of right part - to allow calculation in right order - if (operationNode) - { - if (rightNode->isOperation() && rightNode->getOperatorLevel() <= operationNode->getOperatorLevel() && !rightNode->hasBrackets()) - { - // Get left child of right expression - make it our right child - operationNode->children().push_back(leftNode); - operationNode->children().push_back(rightNode->children().front()); - rightNode->children().front() = operationNode; - currentOperation = rightNode; - } - else - { - operationNode->children().push_back(leftNode); - operationNode->children().push_back(rightNode); - currentOperation = operationNode; - } - } - if (mLexem.mType == LexemType::CloseBracket) - break; // Exit from loop + std::cout << "Lexem type: " << (int)l.mType << ", value: " << l.mValue << std::endl; } - } - return currentOperation ? currentOperation : leftNode; } +}; - public: - Ast::PItem parse(std::istream& input) - { - return nullptr; - } - - void testLexemParser(const std::string& test) - { - std::istringstream iss(test); - - for (Lexem l = getLexem(iss); l.mType != LexemType::None; l = getLexem(iss)) - { - std::cout << "Lexem type: " << (int)l.mType << ", value: " << l.mValue << std::endl; - } - } - }; - - class Worker - { - public: +class Worker +{ +public: Variant eval(Ast::PItem ast); - }; -} +}; +} // namespace Calc #endif diff --git a/src/engine/helper/HL_CrashRpt.cpp b/src/engine/helper/HL_CrashRpt.cpp index 2729fb5f..82c0ff46 100644 --- a/src/engine/helper/HL_CrashRpt.cpp +++ b/src/engine/helper/HL_CrashRpt.cpp @@ -14,64 +14,65 @@ BOOL WINAPI CrashReporter::Callback(LPVOID arg) { - return TRUE; + return TRUE; } -typedef int(__stdcall *CrInstallProc)(__in PCR_INSTALL_INFOW pInfo); +typedef int(__stdcall* CrInstallProc)(__in PCR_INSTALL_INFOW pInfo); static CrInstallProc CrInstall = nullptr; -typedef int(__stdcall *CrUninstallProc)(); +typedef int(__stdcall* CrUninstallProc)(); static CrUninstallProc CrUninstall = nullptr; -typedef int(__stdcall *CrInstallIntoCurrentThreadProc)(DWORD dwFlags); +typedef int(__stdcall* CrInstallIntoCurrentThreadProc)(DWORD dwFlags); static CrInstallIntoCurrentThreadProc CrInstallIntoCurrentThread = nullptr; -typedef int(__stdcall *CrUninstallFromCurrentThreadProc)(); +typedef int(__stdcall* CrUninstallFromCurrentThreadProc)(); static CrUninstallFromCurrentThreadProc CrUninstallFromCurrentThread = nullptr; -typedef int(__stdcall *CrGetLastErrorMsgProc)(LPWSTR buffer, UINT size); +typedef int(__stdcall* CrGetLastErrorMsgProc)(LPWSTR buffer, UINT size); static CrGetLastErrorMsgProc CrGetLastErrorMsg = nullptr; -static HMODULE CrLibraryHandle = NULL; +static HMODULE CrLibraryHandle = NULL; #endif void CrashReporter::init(const std::string& appname, const std::string& version, const std::string& url) { #if defined(TARGET_WIN) #if defined(CRASHRPT_DYNAMIC) - // Check if DLL functions are here - if (CrLibraryHandle) - return; // Library is loaded already - so initialized already + // Check if DLL functions are here + if (CrLibraryHandle) + return; // Library is loaded already - so initialized already - CrLibraryHandle = ::LoadLibrary(TEXT("crashrpt.dll")); - if (!CrLibraryHandle) - return; // No logging here - initialization happens on very first stages, no chance to log anything - - CrInstall = (CrInstallProc)::GetProcAddress(CrLibraryHandle, "crInstallW"); - CrUninstall = (CrUninstallProc)::GetProcAddress(CrLibraryHandle, "crUninstall"); - CrInstallIntoCurrentThread = (CrInstallIntoCurrentThreadProc)::GetProcAddress(CrLibraryHandle, "crInstallToCurrentThread2"); - CrUninstallFromCurrentThread = (CrUninstallFromCurrentThreadProc)::GetProcAddress(CrLibraryHandle, "crUninstallFromCurrentThread"); - CrGetLastErrorMsg = (CrGetLastErrorMsgProc)::GetProcAddress(CrLibraryHandle, "crGetLastErrorMsgW"); + CrLibraryHandle = ::LoadLibrary(TEXT("crashrpt.dll")); + if (!CrLibraryHandle) + return; // No logging here - initialization happens on very first stages, no chance to log anything + + CrInstall = (CrInstallProc)::GetProcAddress(CrLibraryHandle, "crInstallW"); + CrUninstall = (CrUninstallProc)::GetProcAddress(CrLibraryHandle, "crUninstall"); + CrInstallIntoCurrentThread = + (CrInstallIntoCurrentThreadProc)::GetProcAddress(CrLibraryHandle, "crInstallToCurrentThread2"); + CrUninstallFromCurrentThread = + (CrUninstallFromCurrentThreadProc)::GetProcAddress(CrLibraryHandle, "crUninstallFromCurrentThread"); + CrGetLastErrorMsg = (CrGetLastErrorMsgProc)::GetProcAddress(CrLibraryHandle, "crGetLastErrorMsgW"); #else - CrInstall = &crInstallW; - CrUninstall = &crUninstall; - CrInstallIntoCurrentThread = &crInstallToCurrentThread2; - CrUninstallFromCurrentThread = &crUninstallFromCurrentThread; - CrGetLastErrorMsg = &crGetLastErrorMsgW; + CrInstall = &crInstallW; + CrUninstall = &crUninstall; + CrInstallIntoCurrentThread = &crInstallToCurrentThread2; + CrUninstallFromCurrentThread = &crUninstallFromCurrentThread; + CrGetLastErrorMsg = &crGetLastErrorMsgW; #endif - if (!isLoaded()) - return; + if (!isLoaded()) + return; - CR_INSTALL_INFO info; - memset(&info, 0, sizeof(CR_INSTALL_INFO)); - info.cb = sizeof(CR_INSTALL_INFO); + CR_INSTALL_INFO info; + memset(&info, 0, sizeof(CR_INSTALL_INFO)); + info.cb = sizeof(CR_INSTALL_INFO); struct { std::wstring appname, version, url; } unicode; - unicode.appname = StringHelper::makeTstring(appname), - unicode.version = StringHelper::makeTstring(version), + unicode.appname = StringHelper::makeTstring(appname), unicode.version = StringHelper::makeTstring(version), unicode.url = StringHelper::makeTstring(url); if (unicode.appname.empty()) @@ -83,111 +84,105 @@ void CrashReporter::init(const std::string& appname, const std::string& version, if (unicode.version.empty()) unicode.version = L"General version"; - info.pszAppName = unicode.appname.c_str(); - info.pszAppVersion = unicode.version.c_str(); - info.pszEmailSubject = TEXT("Crash report"); - //info.pszEmailTo = L"amegyeri@minerva-soft.com"; - //info.pszUrl = L"http://ftp.minerva-soft.com/crashlog/crashrpt.php"; - //info.pszUrl = L"http://sip.crypttalk.com/crashlog/crashrpt.php"; - info.pszUrl = unicode.url.c_str(); - info.pfnCrashCallback = Callback; - info.uPriorities[CR_HTTP] = 1; - info.uPriorities[CR_SMTP] = CR_NEGATIVE_PRIORITY; - info.uPriorities[CR_SMAPI] = CR_NEGATIVE_PRIORITY; - info.dwFlags = 0; - info.pszCrashSenderPath = TEXT("."); + info.pszAppName = unicode.appname.c_str(); + info.pszAppVersion = unicode.version.c_str(); + info.pszEmailSubject = TEXT("Crash report"); + // info.pszEmailTo = L"amegyeri@minerva-soft.com"; + // info.pszUrl = L"http://ftp.minerva-soft.com/crashlog/crashrpt.php"; + // info.pszUrl = L"http://sip.crypttalk.com/crashlog/crashrpt.php"; + info.pszUrl = unicode.url.c_str(); + info.pfnCrashCallback = Callback; + info.uPriorities[CR_HTTP] = 1; + info.uPriorities[CR_SMTP] = CR_NEGATIVE_PRIORITY; + info.uPriorities[CR_SMAPI] = CR_NEGATIVE_PRIORITY; + info.dwFlags = 0; + info.pszCrashSenderPath = TEXT("."); - int nResult = CrInstall(&info); - if (nResult) - { - wchar_t errorMsg[512] = L""; - CrGetLastErrorMsg(errorMsg, 512); - OutputDebugStringW(errorMsg); - //LogCritical("Core", << "Failed to install CrashReporter with code " << nResult << " and message " << errorMsg); - } + int nResult = CrInstall(&info); + if (nResult) + { + wchar_t errorMsg[512] = L""; + CrGetLastErrorMsg(errorMsg, 512); + OutputDebugStringW(errorMsg); + // LogCritical("Core", << "Failed to install CrashReporter with code " << nResult << " and message " << + // errorMsg); + } #endif } void CrashReporter::free() { #if defined(TARGET_WIN) - if (isLoaded()) - { - CrUninstall(); - CrInstall = nullptr; - CrUninstall = nullptr; - CrInstallIntoCurrentThread = nullptr; - CrUninstallFromCurrentThread = nullptr; - CrGetLastErrorMsg = nullptr; + if (isLoaded()) + { + CrUninstall(); + CrInstall = nullptr; + CrUninstall = nullptr; + CrInstallIntoCurrentThread = nullptr; + CrUninstallFromCurrentThread = nullptr; + CrGetLastErrorMsg = nullptr; #if defined(CRASHRPT_DYNAMIC) - ::FreeLibrary(CrLibraryHandle); CrLibraryHandle = NULL; + ::FreeLibrary(CrLibraryHandle); + CrLibraryHandle = NULL; #endif - } + } #endif } bool CrashReporter::isLoaded() { #if defined(TARGET_WIN) - return !(!CrInstall || !CrUninstall || !CrGetLastErrorMsg || - !CrInstallIntoCurrentThread || !CrUninstallFromCurrentThread); + return !(!CrInstall || !CrUninstall || !CrGetLastErrorMsg || !CrInstallIntoCurrentThread || + !CrUninstallFromCurrentThread); #else - return false; + return false; #endif } void CrashReporter::initThread() { #if defined(TARGET_WIN) - if (isLoaded()) - CrInstallIntoCurrentThread(0); + if (isLoaded()) + CrInstallIntoCurrentThread(0); #endif } void CrashReporter::freeThread() { #if defined(TARGET_WIN) - if (isLoaded()) - CrUninstallFromCurrentThread(); + if (isLoaded()) + CrUninstallFromCurrentThread(); #endif } CrashReporterThreadPoint::CrashReporterThreadPoint() { - CrashReporter::initThread(); + CrashReporter::initThread(); } CrashReporterThreadPoint::~CrashReporterThreadPoint() { - CrashReporter::freeThread(); + CrashReporter::freeThread(); } CrashReporterGuard::CrashReporterGuard() { - CrashReporter::init("generic"); + CrashReporter::init("generic"); } CrashReporterGuard::~CrashReporterGuard() { - CrashReporter::free(); + CrashReporter::free(); } #else -CrashReporterThreadPoint::CrashReporterThreadPoint() -{ -} +CrashReporterThreadPoint::CrashReporterThreadPoint() {} -CrashReporterThreadPoint::~CrashReporterThreadPoint() -{ -} +CrashReporterThreadPoint::~CrashReporterThreadPoint() {} -CrashReporterGuard::CrashReporterGuard() -{ -} +CrashReporterGuard::CrashReporterGuard() {} -CrashReporterGuard::~CrashReporterGuard() -{ -} +CrashReporterGuard::~CrashReporterGuard() {} #endif diff --git a/src/engine/helper/HL_CrashRpt.h b/src/engine/helper/HL_CrashRpt.h index 13de47b8..fcbeb2c7 100644 --- a/src/engine/helper/HL_CrashRpt.h +++ b/src/engine/helper/HL_CrashRpt.h @@ -4,8 +4,8 @@ #include #if defined(TARGET_WIN) -# include -# include +#include +#include #endif // Helper class to translate SEH exceptions to C++ - sometimes it is needed @@ -14,35 +14,36 @@ class SE_Exception { private: - unsigned int nSE; + unsigned int nSE; + public: - SE_Exception() {} - SE_Exception(unsigned int n) : nSE(n) {} - ~SE_Exception() {} - unsigned int getSeNumber() { return nSE; } + SE_Exception() {} + SE_Exception(unsigned int n) : nSE(n) {} + ~SE_Exception() {} + unsigned int getSeNumber() { return nSE; } }; extern void SEHToCpp(unsigned int, EXCEPTION_POINTERS*); // Although better way is to have _set_se_translator set - in our case we do not call it. // The cause is usage of CrashRpt libraries - it gives better control on exception reporting. -# define SET_SEH_TO_CPP +#define SET_SEH_TO_CPP //_set_se_translator(&SEHToCpp) #else -# define SET_SEH_TO_CPP +#define SET_SEH_TO_CPP #endif class CrashReporter { public: - static void init(const std::string& appname, const std::string& version = "", const std::string& url = ""); - static void free(); - static void initThread(); - static void freeThread(); - static bool isLoaded(); + static void init(const std::string& appname, const std::string& version = "", const std::string& url = ""); + static void free(); + static void initThread(); + static void freeThread(); + static bool isLoaded(); #ifdef TARGET_WIN - static BOOL WINAPI Callback(LPVOID /*lpvState*/); + static BOOL WINAPI Callback(LPVOID /*lpvState*/); #endif }; @@ -50,15 +51,15 @@ public: class CrashReporterThreadPoint { public: - CrashReporterThreadPoint(); - ~CrashReporterThreadPoint(); + CrashReporterThreadPoint(); + ~CrashReporterThreadPoint(); }; class CrashReporterGuard { public: - CrashReporterGuard(); - ~CrashReporterGuard(); + CrashReporterGuard(); + ~CrashReporterGuard(); }; #endif diff --git a/src/engine/helper/HL_CsvReader.cpp b/src/engine/helper/HL_CsvReader.cpp index 8dfded2e..a7d96fb1 100644 --- a/src/engine/helper/HL_CsvReader.cpp +++ b/src/engine/helper/HL_CsvReader.cpp @@ -2,28 +2,25 @@ #include "HL_String.h" // --------- CsvFile ---------------- -CsvReader::CsvReader(std::istream& stream) - :mInputStream(stream) -{} +CsvReader::CsvReader(std::istream& stream) : mInputStream(stream) {} -CsvReader::~CsvReader() -{} +CsvReader::~CsvReader() {} std::istream& CsvReader::stream() const { - return mInputStream; + return mInputStream; } bool CsvReader::readLine(std::vector& cells) { - cells.clear(); - std::string line; - if (!std::getline(mInputStream, line)) - return false; - strx::trim(line); - if (line.empty()) - return false; + cells.clear(); + std::string line; + if (!std::getline(mInputStream, line)) + return false; + strx::trim(line); + if (line.empty()) + return false; - strx::split(line, cells, ",;"); - return true; + strx::split(line, cells, ",;"); + return true; } diff --git a/src/engine/helper/HL_CsvReader.h b/src/engine/helper/HL_CsvReader.h index fd6f3738..0bcfc4ee 100644 --- a/src/engine/helper/HL_CsvReader.h +++ b/src/engine/helper/HL_CsvReader.h @@ -8,16 +8,16 @@ class CsvReader { public: - CsvReader(std::istream& stream); - ~CsvReader(); + CsvReader(std::istream& stream); + ~CsvReader(); - void setStream(std::istream& input); - std::istream& stream() const; + void setStream(std::istream& input); + std::istream& stream() const; - bool readLine(std::vector& cells); + bool readLine(std::vector& cells); protected: - std::istream& mInputStream; + std::istream& mInputStream; }; #endif diff --git a/src/engine/helper/HL_Exception.h b/src/engine/helper/HL_Exception.h index 532d50c7..c29435b9 100644 --- a/src/engine/helper/HL_Exception.h +++ b/src/engine/helper/HL_Exception.h @@ -13,36 +13,35 @@ #include enum { - ERR_MEDIA_SOCKET_FAILED = 1, // Failed to create media socket - ERR_CANNOT_FIND_SESSION = 2, // Cannot find session - ERR_NO_CREDENTIALS = 3, // No credentials to configure instance - ERR_BAD_VARIANT_TYPE = 4, // Bad variant type conversion - ERR_RINSTANCE = 5, - ERR_SRTP = 6, // libsrtp error - ERR_WEBRTC = 7, // webrtc error - ERR_NOMEM = 8, // no more memory - ERR_WMME_FAILED = 9, // WMME error - ERR_QPC = 10, // QueryPerformanceCounter failed - ERR_BAD_PARAM = 11, // Bad parameter - ERR_NET_FAILED = 12, // Call to OS network subsystem failed - ERR_NOT_IMPLEMENTED = 13, // Not implemented in this build - ERR_MIXER_OVERFLOW = 14, // No more available channels in audio mixer - ERR_WAVFILE_FAILED = 15, // Error with .wav file - ERR_DSOUND = 16, // DSound error - ERR_COREAUDIO = 17, // CoreAudio error - ERR_CREATEWINDOW = 18, // CreateWindow failed + ERR_MEDIA_SOCKET_FAILED = 1, // Failed to create media socket + ERR_CANNOT_FIND_SESSION = 2, // Cannot find session + ERR_NO_CREDENTIALS = 3, // No credentials to configure instance + ERR_BAD_VARIANT_TYPE = 4, // Bad variant type conversion + ERR_RINSTANCE = 5, + ERR_SRTP = 6, // libsrtp error + ERR_WEBRTC = 7, // webrtc error + ERR_NOMEM = 8, // no more memory + ERR_WMME_FAILED = 9, // WMME error + ERR_QPC = 10, // QueryPerformanceCounter failed + ERR_BAD_PARAM = 11, // Bad parameter + ERR_NET_FAILED = 12, // Call to OS network subsystem failed + ERR_NOT_IMPLEMENTED = 13, // Not implemented in this build + ERR_MIXER_OVERFLOW = 14, // No more available channels in audio mixer + ERR_WAVFILE_FAILED = 15, // Error with .wav file + ERR_DSOUND = 16, // DSound error + ERR_COREAUDIO = 17, // CoreAudio error + ERR_CREATEWINDOW = 18, // CreateWindow failed ERR_REGISTERNOTIFICATION = 19, // RegisterDeviceNotification failed - ERR_PCAP = 20, // Smth bad with libpcap - ERR_CACHE_FAILED = 21, // Failed to open cache directory - ERR_FILENOTOPEN = 22, // Cannot open the file - ERR_OPENSLES = 23 // OpenSL ES failed. Subcode has actual error code. + ERR_PCAP = 20, // Smth bad with libpcap + ERR_CACHE_FAILED = 21, // Failed to open cache directory + ERR_FILENOTOPEN = 22, // Cannot open the file + ERR_OPENSLES = 23 // OpenSL ES failed. Subcode has actual error code. }; -class Exception: public std::exception +class Exception : public std::exception { public: - Exception(int code, int subcode = 0) - :mCode(code), mSubcode(subcode) + Exception(int code, int subcode = 0) : mCode(code), mSubcode(subcode) { std::snprintf(mMessage, sizeof(mMessage), "%d-%d", code, subcode); } @@ -50,35 +49,24 @@ public: Exception(int code, const char* message) { if (message) - strncpy(mMessage, message, (sizeof mMessage) - 1 ); + strncpy(mMessage, message, (sizeof mMessage) - 1); } - Exception(const Exception& src) - :mCode(src.mCode), mSubcode(src.mSubcode) + Exception(const Exception& src) : mCode(src.mCode), mSubcode(src.mSubcode) { memcpy(mMessage, src.mMessage, sizeof mMessage); } - ~Exception() - { } + ~Exception() {} - int code() const - { - return mCode; - } + int code() const { return mCode; } - int subcode() const - { - return mSubcode; - } + int subcode() const { return mSubcode; } - const char* what() const noexcept - { - return mMessage; - } + const char* what() const noexcept { return mMessage; } protected: - int mCode = 0, mSubcode = 0; + int mCode = 0, mSubcode = 0; char mMessage[256] = {0}; }; diff --git a/src/engine/helper/HL_File.cpp b/src/engine/helper/HL_File.cpp index 226eb72c..99bc6c29 100644 --- a/src/engine/helper/HL_File.cpp +++ b/src/engine/helper/HL_File.cpp @@ -2,9 +2,9 @@ #include #if defined(TARGET_LINUX) || defined(TARGET_OSX) || defined(TARGET_ANDROID) -# include -# include -# include +#include +#include +#include #endif bool FileHelper::exists(const std::string& s) @@ -102,7 +102,8 @@ size_t FileHelper::getFreespace(const std::string& path) size_t r = static_cast(-1); #if defined(TARGET_LINUX) - struct statvfs stats; memset(&stats, 0, sizeof stats); + struct statvfs stats; + memset(&stats, 0, sizeof stats); int retcode = statvfs(path.c_str(), &stats); if (retcode == 0) @@ -111,11 +112,11 @@ size_t FileHelper::getFreespace(const std::string& path) return r; } -std::string FileHelper::expandUserHome(const std::string &path) +std::string FileHelper::expandUserHome(const std::string& path) { if (path.empty() || path[0] != '~') - return path; // No expansion needed - + return path; // No expansion needed + const char* home_dir = nullptr; #ifdef TARGET_WIN @@ -124,7 +125,8 @@ std::string FileHelper::expandUserHome(const std::string &path) { home_dir = std::getenv("HOMEDRIVE"); const char* homepath = std::getenv("HOMEPATH"); - if (home_dir && homepath) { + if (home_dir && homepath) + { std::string fullpath(home_dir); fullpath += homepath; return fullpath + path.substr(1); @@ -133,9 +135,9 @@ std::string FileHelper::expandUserHome(const std::string &path) #else home_dir = std::getenv("HOME"); #endif - + if (!home_dir) throw std::runtime_error("Unable to determine the home directory"); - + return std::string(home_dir) + path.substr(1); } diff --git a/src/engine/helper/HL_File.h b/src/engine/helper/HL_File.h index f6ffc91d..6ac669e7 100644 --- a/src/engine/helper/HL_File.h +++ b/src/engine/helper/HL_File.h @@ -6,14 +6,14 @@ class FileHelper { public: - static bool exists(const std::string& s); - static bool exists(const char* s); + static bool exists(const std::string& s); + static bool exists(const char* s); - static void remove(const std::string& s); - static void remove(const char* s); + static void remove(const std::string& s); + static void remove(const char* s); // static std::string gettempname(); - static bool isAbsolute(const std::string& s); + static bool isAbsolute(const std::string& s); static std::string getCurrentDir(); @@ -22,7 +22,7 @@ public: // Returns free space on volume for path // Works for Linux only. For other systems (size_t)-1 is returned (for errors too) - static size_t getFreespace(const std::string& path); + static size_t getFreespace(const std::string& path); static std::string expandUserHome(const std::string& path); }; diff --git a/src/engine/helper/HL_HepSupport.cpp b/src/engine/helper/HL_HepSupport.cpp index 23c33cd7..8b3b4e99 100644 --- a/src/engine/helper/HL_HepSupport.cpp +++ b/src/engine/helper/HL_HepSupport.cpp @@ -7,13 +7,13 @@ static const uint32_t HEPID2 = 0x021002; static const uint32_t HEPID3 = 0x48455033; -bool Packet::parseV3(const ByteBuffer& packet) +bool Packet::parseV3(const ByteBuffer& packet) { if (packet.size() < 30) return false; BufferReader r(packet); - char signature[4]; + char signature[4]; r.readBuffer(signature, 4); if (signature[0] != 'H' || signature[1] != 'E' || signature[2] != 'P' || signature[3] != '3') @@ -24,12 +24,12 @@ bool Packet::parseV3(const ByteBuffer& packet) l -= 6; InternetAddress sourceAddr4, destAddr4, sourceAddr6, destAddr6; - uint16_t sourcePort = 0, destPort = 0; + uint16_t sourcePort = 0, destPort = 0; while (r.count() < packet.size()) { mVendorId = (VendorId)r.readUShort(); ChunkType chunkType = (ChunkType)r.readUShort(); - int chunkLength = r.readUShort(); + int chunkLength = r.readUShort(); switch (chunkType) { @@ -102,8 +102,7 @@ bool Packet::parseV3(const ByteBuffer& packet) if (!sourceAddr4.isEmpty()) mSourceAddress = sourceAddr4; - else - if (!sourceAddr6.isEmpty()) + else if (!sourceAddr6.isEmpty()) mSourceAddress = sourceAddr6; if (!mSourceAddress.isEmpty()) @@ -111,8 +110,7 @@ bool Packet::parseV3(const ByteBuffer& packet) if (!destAddr4.isEmpty()) mDestinationAddress = destAddr4; - else - if (!destAddr6.isEmpty()) + else if (!destAddr6.isEmpty()) mDestinationAddress = destAddr6; if (!mDestinationAddress.isEmpty()) @@ -121,7 +119,7 @@ bool Packet::parseV3(const ByteBuffer& packet) return true; } -bool Packet::parseV2(const ByteBuffer &packet) +bool Packet::parseV2(const ByteBuffer& packet) { if (packet.size() < 31) return false; @@ -148,16 +146,53 @@ bool Packet::parseV2(const ByteBuffer &packet) return true; } -#define WRITE_CHUNK_UCHAR(T, V) {w.writeUShort((uint16_t)mVendorId); w.writeUShort((uint16_t)T); w.writeUShort(1); w.writeUChar((uint8_t)V);} -#define WRITE_CHUNK_USHORT(T, V) {w.writeUShort((uint16_t)mVendorId); w.writeUShort((uint16_t)T); w.writeUShort(2); w.writeUShort((uint16_t)V);} -#define WRITE_CHUNK_UINT(T, V) {w.writeUShort((uint16_t)mVendorId); w.writeUShort((uint16_t)T); w.writeUShort(4); w.writeUInt((uint32_t)V);} -#define WRITE_CHUNK_IP4(T, V) {w.writeUShort((uint16_t)mVendorId); w.writeUShort((uint16_t)T); w.writeUShort(4); w.writeIp(V);} -#define WRITE_CHUNK_IP6(T, V) {w.writeUShort((uint16_t)mVendorId); w.writeUShort((uint16_t)T); w.writeUShort(8); w.writeIp(V);} -#define WRITE_CHUNK_BUFFER(T, V) {w.writeUShort((uint16_t)mVendorId); w.writeUShort((uint16_t)T); w.writeUShort(8); w.writeBuffer(V.data(), V.size());} +#define WRITE_CHUNK_UCHAR(T, V) \ + { \ + w.writeUShort((uint16_t)mVendorId); \ + w.writeUShort((uint16_t)T); \ + w.writeUShort(1); \ + w.writeUChar((uint8_t)V); \ + } +#define WRITE_CHUNK_USHORT(T, V) \ + { \ + w.writeUShort((uint16_t)mVendorId); \ + w.writeUShort((uint16_t)T); \ + w.writeUShort(2); \ + w.writeUShort((uint16_t)V); \ + } +#define WRITE_CHUNK_UINT(T, V) \ + { \ + w.writeUShort((uint16_t)mVendorId); \ + w.writeUShort((uint16_t)T); \ + w.writeUShort(4); \ + w.writeUInt((uint32_t)V); \ + } +#define WRITE_CHUNK_IP4(T, V) \ + { \ + w.writeUShort((uint16_t)mVendorId); \ + w.writeUShort((uint16_t)T); \ + w.writeUShort(4); \ + w.writeIp(V); \ + } +#define WRITE_CHUNK_IP6(T, V) \ + { \ + w.writeUShort((uint16_t)mVendorId); \ + w.writeUShort((uint16_t)T); \ + w.writeUShort(8); \ + w.writeIp(V); \ + } +#define WRITE_CHUNK_BUFFER(T, V) \ + { \ + w.writeUShort((uint16_t)mVendorId); \ + w.writeUShort((uint16_t)T); \ + w.writeUShort(8); \ + w.writeBuffer(V.data(), V.size()); \ + } ByteBuffer Packet::buildV3() { - ByteBuffer r; r.resize(mBody.size() + 512); + ByteBuffer r; + r.resize(mBody.size() + 512); BufferWriter w(r); // Signature @@ -174,9 +209,8 @@ ByteBuffer Packet::buildV3() { if (mSourceAddress.isV4()) WRITE_CHUNK_IP4(ChunkType::IP4SourceAddress, mSourceAddress) - else - if (mSourceAddress.isV6()) - WRITE_CHUNK_IP6(ChunkType::IP6SourceAddress, mSourceAddress); + else if (mSourceAddress.isV6()) + WRITE_CHUNK_IP6(ChunkType::IP6SourceAddress, mSourceAddress); WRITE_CHUNK_USHORT(ChunkType::SourcePort, mSourceAddress.port()); } @@ -186,9 +220,8 @@ ByteBuffer Packet::buildV3() { if (mDestinationAddress.isV4()) WRITE_CHUNK_IP4(ChunkType::IP4DestinationAddress, mDestinationAddress) - else - if (mDestinationAddress.isV6()) - WRITE_CHUNK_IP6(ChunkType::IP6DestinationAddress, mDestinationAddress); + else if (mDestinationAddress.isV6()) + WRITE_CHUNK_IP6(ChunkType::IP6DestinationAddress, mDestinationAddress); WRITE_CHUNK_USHORT(ChunkType::DestinationPort, mDestinationAddress.port()); } @@ -216,7 +249,9 @@ ByteBuffer Packet::buildV3() r.resize(w.offset()); - w.rewind(); w.skip(4); w.writeUShort((uint16_t)r.size()); + w.rewind(); + w.skip(4); + w.writeUShort((uint16_t)r.size()); return r; } diff --git a/src/engine/helper/HL_HepSupport.h b/src/engine/helper/HL_HepSupport.h index 604f2c43..79a9503e 100644 --- a/src/engine/helper/HL_HepSupport.h +++ b/src/engine/helper/HL_HepSupport.h @@ -6,8 +6,8 @@ namespace HEP { - enum class ChunkType - { +enum class ChunkType +{ None = 0, IPProtocolFamily, IPProtocolID, @@ -19,17 +19,17 @@ namespace HEP DestinationPort, Timestamp, TimestampMicro, - ProtocolType, // Maps to Protocol Types below + ProtocolType, // Maps to Protocol Types below CaptureAgentID, KeepAliveTimer, AuthenticationKey, PacketPayload, CompressedPayload, InternalC - }; +}; - enum class VendorId - { +enum class VendorId +{ None, FreeSwitch, Kamailio, @@ -37,10 +37,10 @@ namespace HEP Asterisk, Homer, SipXecs - }; +}; - enum class ProtocolId - { +enum class ProtocolId +{ Reserved = 0, SIP, XMPP, @@ -54,32 +54,28 @@ namespace HEP IAX, H322, H321 - }; +}; - struct Packet - { - bool parseV3(const ByteBuffer& packet); - bool parseV2(const ByteBuffer& packet); - ByteBuffer buildV3(); +struct Packet +{ + bool parseV3(const ByteBuffer& packet); + bool parseV2(const ByteBuffer& packet); + ByteBuffer buildV3(); - uint8_t - mIpProtocolFamily, - mIpProtocolId; + uint8_t mIpProtocolFamily, mIpProtocolId; - InternetAddress - mSourceAddress, - mDestinationAddress; + InternetAddress mSourceAddress, mDestinationAddress; - timeval mTimestamp; - ProtocolId mProtocolType; - uint16_t mCaptureAgentId; - uint16_t mKeepAliveTimer; - ByteBuffer mAuthenticateKey; - ByteBuffer mBody; - VendorId mVendorId; - uint32_t mBodyOffset = 0; - }; + timeval mTimestamp; + ProtocolId mProtocolType; + uint16_t mCaptureAgentId; + uint16_t mKeepAliveTimer; + ByteBuffer mAuthenticateKey; + ByteBuffer mBody; + VendorId mVendorId; + uint32_t mBodyOffset = 0; +}; -} +} // namespace HEP #endif diff --git a/src/engine/helper/HL_IuUP.cpp b/src/engine/helper/HL_IuUP.cpp index e10cb871..f32a6d82 100644 --- a/src/engine/helper/HL_IuUP.cpp +++ b/src/engine/helper/HL_IuUP.cpp @@ -3,7 +3,7 @@ bool IuUP::TwoBytePseudoheader = false; -bool IuUP::parse(const uint8_t *packet, int size, IuUP::Frame &result) +bool IuUP::parse(const uint8_t* packet, int size, IuUP::Frame& result) { // Data-with-CRC frames carry a 4 byte header if (size < 4) @@ -36,9 +36,9 @@ bool IuUP::parse(const uint8_t *packet, int size, IuUP::Frame &result) uint16_t update_crc6_by_bytes(uint16_t crc6, uint8_t byte1, uint8_t byte2); -uint16_t update_crc10_by_bytes(uint16_t crc10, const uint8_t *data_blk_ptr, int data_blk_size); +uint16_t update_crc10_by_bytes(uint16_t crc10, const uint8_t* data_blk_ptr, int data_blk_size); -bool IuUP::parse2(const uint8_t* packet, int size, Frame& result) +bool IuUP::parse2(const uint8_t* packet, int size, Frame& result) { if (size < 2) return false; @@ -77,7 +77,7 @@ bool IuUP::parse2(const uint8_t* packet, int size, Frame& result) result.mPayload = packet + 4; result.mPayloadSize = size - 4; - uint16_t crc = update_crc10_by_bytes(0, result.mPayload, result.mPayloadSize); + uint16_t crc = update_crc10_by_bytes(0, result.mPayload, result.mPayloadSize); uint16_t secondWord = ntohs(((uint16_t*)packet)[1]); secondWord &= 0x3FF; uint8_t bytes[2]; @@ -101,1044 +101,880 @@ bool IuUP::parse2(const uint8_t* packet, int size, Frame& result) } -static const unsigned char crc6_table[] = - { - 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, - 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f, - 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, - 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, - 0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28,0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20, - 0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38,0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x30, - 0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00, - 0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18,0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10, - 0x31,0x30,0x33,0x32,0x35,0x34,0x37,0x36,0x39,0x38,0x3b,0x3a,0x3d,0x3c,0x3f,0x3e, - 0x21,0x20,0x23,0x22,0x25,0x24,0x27,0x26,0x29,0x28,0x2b,0x2a,0x2d,0x2c,0x2f,0x2e, - 0x11,0x10,0x13,0x12,0x15,0x14,0x17,0x16,0x19,0x18,0x1b,0x1a,0x1d,0x1c,0x1f,0x1e, - 0x01,0x00,0x03,0x02,0x05,0x04,0x07,0x06,0x09,0x08,0x0b,0x0a,0x0d,0x0c,0x0f,0x0e, - 0x1e,0x1f,0x1c,0x1d,0x1a,0x1b,0x18,0x19,0x16,0x17,0x14,0x15,0x12,0x13,0x10,0x11, - 0x0e,0x0f,0x0c,0x0d,0x0a,0x0b,0x08,0x09,0x06,0x07,0x04,0x05,0x02,0x03,0x00,0x01, - 0x3e,0x3f,0x3c,0x3d,0x3a,0x3b,0x38,0x39,0x36,0x37,0x34,0x35,0x32,0x33,0x30,0x31, - 0x2e,0x2f,0x2c,0x2d,0x2a,0x2b,0x28,0x29,0x26,0x27,0x24,0x25,0x22,0x23,0x20,0x21, - 0x0d,0x0c,0x0f,0x0e,0x09,0x08,0x0b,0x0a,0x05,0x04,0x07,0x06,0x01,0x00,0x03,0x02, - 0x1d,0x1c,0x1f,0x1e,0x19,0x18,0x1b,0x1a,0x15,0x14,0x17,0x16,0x11,0x10,0x13,0x12, - 0x2d,0x2c,0x2f,0x2e,0x29,0x28,0x2b,0x2a,0x25,0x24,0x27,0x26,0x21,0x20,0x23,0x22, - 0x3d,0x3c,0x3f,0x3e,0x39,0x38,0x3b,0x3a,0x35,0x34,0x37,0x36,0x31,0x30,0x33,0x32, - 0x22,0x23,0x20,0x21,0x26,0x27,0x24,0x25,0x2a,0x2b,0x28,0x29,0x2e,0x2f,0x2c,0x2d, - 0x32,0x33,0x30,0x31,0x36,0x37,0x34,0x35,0x3a,0x3b,0x38,0x39,0x3e,0x3f,0x3c,0x3d, - 0x02,0x03,0x00,0x01,0x06,0x07,0x04,0x05,0x0a,0x0b,0x08,0x09,0x0e,0x0f,0x0c,0x0d, - 0x12,0x13,0x10,0x11,0x16,0x17,0x14,0x15,0x1a,0x1b,0x18,0x19,0x1e,0x1f,0x1c,0x1d, - 0x3c,0x3d,0x3e,0x3f,0x38,0x39,0x3a,0x3b,0x34,0x35,0x36,0x37,0x30,0x31,0x32,0x33, - 0x2c,0x2d,0x2e,0x2f,0x28,0x29,0x2a,0x2b,0x24,0x25,0x26,0x27,0x20,0x21,0x22,0x23, - 0x1c,0x1d,0x1e,0x1f,0x18,0x19,0x1a,0x1b,0x14,0x15,0x16,0x17,0x10,0x11,0x12,0x13, - 0x0c,0x0d,0x0e,0x0f,0x08,0x09,0x0a,0x0b,0x04,0x05,0x06,0x07,0x00,0x01,0x02,0x03, - 0x13,0x12,0x11,0x10,0x17,0x16,0x15,0x14,0x1b,0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c, - 0x03,0x02,0x01,0x00,0x07,0x06,0x05,0x04,0x0b,0x0a,0x09,0x08,0x0f,0x0e,0x0d,0x0c, - 0x33,0x32,0x31,0x30,0x37,0x36,0x35,0x34,0x3b,0x3a,0x39,0x38,0x3f,0x3e,0x3d,0x3c, - 0x23,0x22,0x21,0x20,0x27,0x26,0x25,0x24,0x2b,0x2a,0x29,0x28,0x2f,0x2e,0x2d,0x2c, - 0x1a,0x1b,0x18,0x19,0x1e,0x1f,0x1c,0x1d,0x12,0x13,0x10,0x11,0x16,0x17,0x14,0x15, - 0x0a,0x0b,0x08,0x09,0x0e,0x0f,0x0c,0x0d,0x02,0x03,0x00,0x01,0x06,0x07,0x04,0x05, - 0x3a,0x3b,0x38,0x39,0x3e,0x3f,0x3c,0x3d,0x32,0x33,0x30,0x31,0x36,0x37,0x34,0x35, - 0x2a,0x2b,0x28,0x29,0x2e,0x2f,0x2c,0x2d,0x22,0x23,0x20,0x21,0x26,0x27,0x24,0x25, - 0x35,0x34,0x37,0x36,0x31,0x30,0x33,0x32,0x3d,0x3c,0x3f,0x3e,0x39,0x38,0x3b,0x3a, - 0x25,0x24,0x27,0x26,0x21,0x20,0x23,0x22,0x2d,0x2c,0x2f,0x2e,0x29,0x28,0x2b,0x2a, - 0x15,0x14,0x17,0x16,0x11,0x10,0x13,0x12,0x1d,0x1c,0x1f,0x1e,0x19,0x18,0x1b,0x1a, - 0x05,0x04,0x07,0x06,0x01,0x00,0x03,0x02,0x0d,0x0c,0x0f,0x0e,0x09,0x08,0x0b,0x0a, - 0x2b,0x2a,0x29,0x28,0x2f,0x2e,0x2d,0x2c,0x23,0x22,0x21,0x20,0x27,0x26,0x25,0x24, - 0x3b,0x3a,0x39,0x38,0x3f,0x3e,0x3d,0x3c,0x33,0x32,0x31,0x30,0x37,0x36,0x35,0x34, - 0x0b,0x0a,0x09,0x08,0x0f,0x0e,0x0d,0x0c,0x03,0x02,0x01,0x00,0x07,0x06,0x05,0x04, - 0x1b,0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c,0x13,0x12,0x11,0x10,0x17,0x16,0x15,0x14, - 0x04,0x05,0x06,0x07,0x00,0x01,0x02,0x03,0x0c,0x0d,0x0e,0x0f,0x08,0x09,0x0a,0x0b, - 0x14,0x15,0x16,0x17,0x10,0x11,0x12,0x13,0x1c,0x1d,0x1e,0x1f,0x18,0x19,0x1a,0x1b, - 0x24,0x25,0x26,0x27,0x20,0x21,0x22,0x23,0x2c,0x2d,0x2e,0x2f,0x28,0x29,0x2a,0x2b, - 0x34,0x35,0x36,0x37,0x30,0x31,0x32,0x33,0x3c,0x3d,0x3e,0x3f,0x38,0x39,0x3a,0x3b, - 0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10,0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18, - 0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08, - 0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x30,0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38, - 0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20,0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28, - 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37, - 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27, - 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, - 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, - 0x26,0x27,0x24,0x25,0x22,0x23,0x20,0x21,0x2e,0x2f,0x2c,0x2d,0x2a,0x2b,0x28,0x29, - 0x36,0x37,0x34,0x35,0x32,0x33,0x30,0x31,0x3e,0x3f,0x3c,0x3d,0x3a,0x3b,0x38,0x39, - 0x06,0x07,0x04,0x05,0x02,0x03,0x00,0x01,0x0e,0x0f,0x0c,0x0d,0x0a,0x0b,0x08,0x09, - 0x16,0x17,0x14,0x15,0x12,0x13,0x10,0x11,0x1e,0x1f,0x1c,0x1d,0x1a,0x1b,0x18,0x19, - 0x09,0x08,0x0b,0x0a,0x0d,0x0c,0x0f,0x0e,0x01,0x00,0x03,0x02,0x05,0x04,0x07,0x06, - 0x19,0x18,0x1b,0x1a,0x1d,0x1c,0x1f,0x1e,0x11,0x10,0x13,0x12,0x15,0x14,0x17,0x16, - 0x29,0x28,0x2b,0x2a,0x2d,0x2c,0x2f,0x2e,0x21,0x20,0x23,0x22,0x25,0x24,0x27,0x26, - 0x39,0x38,0x3b,0x3a,0x3d,0x3c,0x3f,0x3e,0x31,0x30,0x33,0x32,0x35,0x34,0x37,0x36, - 0x34,0x35,0x36,0x37,0x30,0x31,0x32,0x33,0x3c,0x3d,0x3e,0x3f,0x38,0x39,0x3a,0x3b, - 0x24,0x25,0x26,0x27,0x20,0x21,0x22,0x23,0x2c,0x2d,0x2e,0x2f,0x28,0x29,0x2a,0x2b, - 0x14,0x15,0x16,0x17,0x10,0x11,0x12,0x13,0x1c,0x1d,0x1e,0x1f,0x18,0x19,0x1a,0x1b, - 0x04,0x05,0x06,0x07,0x00,0x01,0x02,0x03,0x0c,0x0d,0x0e,0x0f,0x08,0x09,0x0a,0x0b, - 0x1b,0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c,0x13,0x12,0x11,0x10,0x17,0x16,0x15,0x14, - 0x0b,0x0a,0x09,0x08,0x0f,0x0e,0x0d,0x0c,0x03,0x02,0x01,0x00,0x07,0x06,0x05,0x04, - 0x3b,0x3a,0x39,0x38,0x3f,0x3e,0x3d,0x3c,0x33,0x32,0x31,0x30,0x37,0x36,0x35,0x34, - 0x2b,0x2a,0x29,0x28,0x2f,0x2e,0x2d,0x2c,0x23,0x22,0x21,0x20,0x27,0x26,0x25,0x24, - 0x05,0x04,0x07,0x06,0x01,0x00,0x03,0x02,0x0d,0x0c,0x0f,0x0e,0x09,0x08,0x0b,0x0a, - 0x15,0x14,0x17,0x16,0x11,0x10,0x13,0x12,0x1d,0x1c,0x1f,0x1e,0x19,0x18,0x1b,0x1a, - 0x25,0x24,0x27,0x26,0x21,0x20,0x23,0x22,0x2d,0x2c,0x2f,0x2e,0x29,0x28,0x2b,0x2a, - 0x35,0x34,0x37,0x36,0x31,0x30,0x33,0x32,0x3d,0x3c,0x3f,0x3e,0x39,0x38,0x3b,0x3a, - 0x2a,0x2b,0x28,0x29,0x2e,0x2f,0x2c,0x2d,0x22,0x23,0x20,0x21,0x26,0x27,0x24,0x25, - 0x3a,0x3b,0x38,0x39,0x3e,0x3f,0x3c,0x3d,0x32,0x33,0x30,0x31,0x36,0x37,0x34,0x35, - 0x0a,0x0b,0x08,0x09,0x0e,0x0f,0x0c,0x0d,0x02,0x03,0x00,0x01,0x06,0x07,0x04,0x05, - 0x1a,0x1b,0x18,0x19,0x1e,0x1f,0x1c,0x1d,0x12,0x13,0x10,0x11,0x16,0x17,0x14,0x15, - 0x39,0x38,0x3b,0x3a,0x3d,0x3c,0x3f,0x3e,0x31,0x30,0x33,0x32,0x35,0x34,0x37,0x36, - 0x29,0x28,0x2b,0x2a,0x2d,0x2c,0x2f,0x2e,0x21,0x20,0x23,0x22,0x25,0x24,0x27,0x26, - 0x19,0x18,0x1b,0x1a,0x1d,0x1c,0x1f,0x1e,0x11,0x10,0x13,0x12,0x15,0x14,0x17,0x16, - 0x09,0x08,0x0b,0x0a,0x0d,0x0c,0x0f,0x0e,0x01,0x00,0x03,0x02,0x05,0x04,0x07,0x06, - 0x16,0x17,0x14,0x15,0x12,0x13,0x10,0x11,0x1e,0x1f,0x1c,0x1d,0x1a,0x1b,0x18,0x19, - 0x06,0x07,0x04,0x05,0x02,0x03,0x00,0x01,0x0e,0x0f,0x0c,0x0d,0x0a,0x0b,0x08,0x09, - 0x36,0x37,0x34,0x35,0x32,0x33,0x30,0x31,0x3e,0x3f,0x3c,0x3d,0x3a,0x3b,0x38,0x39, - 0x26,0x27,0x24,0x25,0x22,0x23,0x20,0x21,0x2e,0x2f,0x2c,0x2d,0x2a,0x2b,0x28,0x29, - 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, - 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, - 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27, - 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37, - 0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20,0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28, - 0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x30,0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38, - 0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08, - 0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10,0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18, - 0x2e,0x2f,0x2c,0x2d,0x2a,0x2b,0x28,0x29,0x26,0x27,0x24,0x25,0x22,0x23,0x20,0x21, - 0x3e,0x3f,0x3c,0x3d,0x3a,0x3b,0x38,0x39,0x36,0x37,0x34,0x35,0x32,0x33,0x30,0x31, - 0x0e,0x0f,0x0c,0x0d,0x0a,0x0b,0x08,0x09,0x06,0x07,0x04,0x05,0x02,0x03,0x00,0x01, - 0x1e,0x1f,0x1c,0x1d,0x1a,0x1b,0x18,0x19,0x16,0x17,0x14,0x15,0x12,0x13,0x10,0x11, - 0x01,0x00,0x03,0x02,0x05,0x04,0x07,0x06,0x09,0x08,0x0b,0x0a,0x0d,0x0c,0x0f,0x0e, - 0x11,0x10,0x13,0x12,0x15,0x14,0x17,0x16,0x19,0x18,0x1b,0x1a,0x1d,0x1c,0x1f,0x1e, - 0x21,0x20,0x23,0x22,0x25,0x24,0x27,0x26,0x29,0x28,0x2b,0x2a,0x2d,0x2c,0x2f,0x2e, - 0x31,0x30,0x33,0x32,0x35,0x34,0x37,0x36,0x39,0x38,0x3b,0x3a,0x3d,0x3c,0x3f,0x3e, - 0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18,0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10, - 0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00, - 0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38,0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x30, - 0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28,0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20, - 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, - 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, - 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f, - 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, - 0x23,0x22,0x21,0x20,0x27,0x26,0x25,0x24,0x2b,0x2a,0x29,0x28,0x2f,0x2e,0x2d,0x2c, - 0x33,0x32,0x31,0x30,0x37,0x36,0x35,0x34,0x3b,0x3a,0x39,0x38,0x3f,0x3e,0x3d,0x3c, - 0x03,0x02,0x01,0x00,0x07,0x06,0x05,0x04,0x0b,0x0a,0x09,0x08,0x0f,0x0e,0x0d,0x0c, - 0x13,0x12,0x11,0x10,0x17,0x16,0x15,0x14,0x1b,0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c, - 0x0c,0x0d,0x0e,0x0f,0x08,0x09,0x0a,0x0b,0x04,0x05,0x06,0x07,0x00,0x01,0x02,0x03, - 0x1c,0x1d,0x1e,0x1f,0x18,0x19,0x1a,0x1b,0x14,0x15,0x16,0x17,0x10,0x11,0x12,0x13, - 0x2c,0x2d,0x2e,0x2f,0x28,0x29,0x2a,0x2b,0x24,0x25,0x26,0x27,0x20,0x21,0x22,0x23, - 0x3c,0x3d,0x3e,0x3f,0x38,0x39,0x3a,0x3b,0x34,0x35,0x36,0x37,0x30,0x31,0x32,0x33, - 0x12,0x13,0x10,0x11,0x16,0x17,0x14,0x15,0x1a,0x1b,0x18,0x19,0x1e,0x1f,0x1c,0x1d, - 0x02,0x03,0x00,0x01,0x06,0x07,0x04,0x05,0x0a,0x0b,0x08,0x09,0x0e,0x0f,0x0c,0x0d, - 0x32,0x33,0x30,0x31,0x36,0x37,0x34,0x35,0x3a,0x3b,0x38,0x39,0x3e,0x3f,0x3c,0x3d, - 0x22,0x23,0x20,0x21,0x26,0x27,0x24,0x25,0x2a,0x2b,0x28,0x29,0x2e,0x2f,0x2c,0x2d, - 0x3d,0x3c,0x3f,0x3e,0x39,0x38,0x3b,0x3a,0x35,0x34,0x37,0x36,0x31,0x30,0x33,0x32, - 0x2d,0x2c,0x2f,0x2e,0x29,0x28,0x2b,0x2a,0x25,0x24,0x27,0x26,0x21,0x20,0x23,0x22, - 0x1d,0x1c,0x1f,0x1e,0x19,0x18,0x1b,0x1a,0x15,0x14,0x17,0x16,0x11,0x10,0x13,0x12, - 0x0d,0x0c,0x0f,0x0e,0x09,0x08,0x0b,0x0a,0x05,0x04,0x07,0x06,0x01,0x00,0x03,0x02, - 0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08, - 0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10,0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18, - 0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20,0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28, - 0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x30,0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38, - 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27, - 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37, - 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, - 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, - 0x36,0x37,0x34,0x35,0x32,0x33,0x30,0x31,0x3e,0x3f,0x3c,0x3d,0x3a,0x3b,0x38,0x39, - 0x26,0x27,0x24,0x25,0x22,0x23,0x20,0x21,0x2e,0x2f,0x2c,0x2d,0x2a,0x2b,0x28,0x29, - 0x16,0x17,0x14,0x15,0x12,0x13,0x10,0x11,0x1e,0x1f,0x1c,0x1d,0x1a,0x1b,0x18,0x19, - 0x06,0x07,0x04,0x05,0x02,0x03,0x00,0x01,0x0e,0x0f,0x0c,0x0d,0x0a,0x0b,0x08,0x09, - 0x19,0x18,0x1b,0x1a,0x1d,0x1c,0x1f,0x1e,0x11,0x10,0x13,0x12,0x15,0x14,0x17,0x16, - 0x09,0x08,0x0b,0x0a,0x0d,0x0c,0x0f,0x0e,0x01,0x00,0x03,0x02,0x05,0x04,0x07,0x06, - 0x39,0x38,0x3b,0x3a,0x3d,0x3c,0x3f,0x3e,0x31,0x30,0x33,0x32,0x35,0x34,0x37,0x36, - 0x29,0x28,0x2b,0x2a,0x2d,0x2c,0x2f,0x2e,0x21,0x20,0x23,0x22,0x25,0x24,0x27,0x26, - 0x0a,0x0b,0x08,0x09,0x0e,0x0f,0x0c,0x0d,0x02,0x03,0x00,0x01,0x06,0x07,0x04,0x05, - 0x1a,0x1b,0x18,0x19,0x1e,0x1f,0x1c,0x1d,0x12,0x13,0x10,0x11,0x16,0x17,0x14,0x15, - 0x2a,0x2b,0x28,0x29,0x2e,0x2f,0x2c,0x2d,0x22,0x23,0x20,0x21,0x26,0x27,0x24,0x25, - 0x3a,0x3b,0x38,0x39,0x3e,0x3f,0x3c,0x3d,0x32,0x33,0x30,0x31,0x36,0x37,0x34,0x35, - 0x25,0x24,0x27,0x26,0x21,0x20,0x23,0x22,0x2d,0x2c,0x2f,0x2e,0x29,0x28,0x2b,0x2a, - 0x35,0x34,0x37,0x36,0x31,0x30,0x33,0x32,0x3d,0x3c,0x3f,0x3e,0x39,0x38,0x3b,0x3a, - 0x05,0x04,0x07,0x06,0x01,0x00,0x03,0x02,0x0d,0x0c,0x0f,0x0e,0x09,0x08,0x0b,0x0a, - 0x15,0x14,0x17,0x16,0x11,0x10,0x13,0x12,0x1d,0x1c,0x1f,0x1e,0x19,0x18,0x1b,0x1a, - 0x3b,0x3a,0x39,0x38,0x3f,0x3e,0x3d,0x3c,0x33,0x32,0x31,0x30,0x37,0x36,0x35,0x34, - 0x2b,0x2a,0x29,0x28,0x2f,0x2e,0x2d,0x2c,0x23,0x22,0x21,0x20,0x27,0x26,0x25,0x24, - 0x1b,0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c,0x13,0x12,0x11,0x10,0x17,0x16,0x15,0x14, - 0x0b,0x0a,0x09,0x08,0x0f,0x0e,0x0d,0x0c,0x03,0x02,0x01,0x00,0x07,0x06,0x05,0x04, - 0x14,0x15,0x16,0x17,0x10,0x11,0x12,0x13,0x1c,0x1d,0x1e,0x1f,0x18,0x19,0x1a,0x1b, - 0x04,0x05,0x06,0x07,0x00,0x01,0x02,0x03,0x0c,0x0d,0x0e,0x0f,0x08,0x09,0x0a,0x0b, - 0x34,0x35,0x36,0x37,0x30,0x31,0x32,0x33,0x3c,0x3d,0x3e,0x3f,0x38,0x39,0x3a,0x3b, - 0x24,0x25,0x26,0x27,0x20,0x21,0x22,0x23,0x2c,0x2d,0x2e,0x2f,0x28,0x29,0x2a,0x2b, - 0x1d,0x1c,0x1f,0x1e,0x19,0x18,0x1b,0x1a,0x15,0x14,0x17,0x16,0x11,0x10,0x13,0x12, - 0x0d,0x0c,0x0f,0x0e,0x09,0x08,0x0b,0x0a,0x05,0x04,0x07,0x06,0x01,0x00,0x03,0x02, - 0x3d,0x3c,0x3f,0x3e,0x39,0x38,0x3b,0x3a,0x35,0x34,0x37,0x36,0x31,0x30,0x33,0x32, - 0x2d,0x2c,0x2f,0x2e,0x29,0x28,0x2b,0x2a,0x25,0x24,0x27,0x26,0x21,0x20,0x23,0x22, - 0x32,0x33,0x30,0x31,0x36,0x37,0x34,0x35,0x3a,0x3b,0x38,0x39,0x3e,0x3f,0x3c,0x3d, - 0x22,0x23,0x20,0x21,0x26,0x27,0x24,0x25,0x2a,0x2b,0x28,0x29,0x2e,0x2f,0x2c,0x2d, - 0x12,0x13,0x10,0x11,0x16,0x17,0x14,0x15,0x1a,0x1b,0x18,0x19,0x1e,0x1f,0x1c,0x1d, - 0x02,0x03,0x00,0x01,0x06,0x07,0x04,0x05,0x0a,0x0b,0x08,0x09,0x0e,0x0f,0x0c,0x0d, - 0x2c,0x2d,0x2e,0x2f,0x28,0x29,0x2a,0x2b,0x24,0x25,0x26,0x27,0x20,0x21,0x22,0x23, - 0x3c,0x3d,0x3e,0x3f,0x38,0x39,0x3a,0x3b,0x34,0x35,0x36,0x37,0x30,0x31,0x32,0x33, - 0x0c,0x0d,0x0e,0x0f,0x08,0x09,0x0a,0x0b,0x04,0x05,0x06,0x07,0x00,0x01,0x02,0x03, - 0x1c,0x1d,0x1e,0x1f,0x18,0x19,0x1a,0x1b,0x14,0x15,0x16,0x17,0x10,0x11,0x12,0x13, - 0x03,0x02,0x01,0x00,0x07,0x06,0x05,0x04,0x0b,0x0a,0x09,0x08,0x0f,0x0e,0x0d,0x0c, - 0x13,0x12,0x11,0x10,0x17,0x16,0x15,0x14,0x1b,0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c, - 0x23,0x22,0x21,0x20,0x27,0x26,0x25,0x24,0x2b,0x2a,0x29,0x28,0x2f,0x2e,0x2d,0x2c, - 0x33,0x32,0x31,0x30,0x37,0x36,0x35,0x34,0x3b,0x3a,0x39,0x38,0x3f,0x3e,0x3d,0x3c, - 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f, - 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, - 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, - 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, - 0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38,0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x30, - 0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28,0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20, - 0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18,0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10, - 0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00, - 0x21,0x20,0x23,0x22,0x25,0x24,0x27,0x26,0x29,0x28,0x2b,0x2a,0x2d,0x2c,0x2f,0x2e, - 0x31,0x30,0x33,0x32,0x35,0x34,0x37,0x36,0x39,0x38,0x3b,0x3a,0x3d,0x3c,0x3f,0x3e, - 0x01,0x00,0x03,0x02,0x05,0x04,0x07,0x06,0x09,0x08,0x0b,0x0a,0x0d,0x0c,0x0f,0x0e, - 0x11,0x10,0x13,0x12,0x15,0x14,0x17,0x16,0x19,0x18,0x1b,0x1a,0x1d,0x1c,0x1f,0x1e, - 0x0e,0x0f,0x0c,0x0d,0x0a,0x0b,0x08,0x09,0x06,0x07,0x04,0x05,0x02,0x03,0x00,0x01, - 0x1e,0x1f,0x1c,0x1d,0x1a,0x1b,0x18,0x19,0x16,0x17,0x14,0x15,0x12,0x13,0x10,0x11, - 0x2e,0x2f,0x2c,0x2d,0x2a,0x2b,0x28,0x29,0x26,0x27,0x24,0x25,0x22,0x23,0x20,0x21, - 0x3e,0x3f,0x3c,0x3d,0x3a,0x3b,0x38,0x39,0x36,0x37,0x34,0x35,0x32,0x33,0x30,0x31, - 0x33,0x32,0x31,0x30,0x37,0x36,0x35,0x34,0x3b,0x3a,0x39,0x38,0x3f,0x3e,0x3d,0x3c, - 0x23,0x22,0x21,0x20,0x27,0x26,0x25,0x24,0x2b,0x2a,0x29,0x28,0x2f,0x2e,0x2d,0x2c, - 0x13,0x12,0x11,0x10,0x17,0x16,0x15,0x14,0x1b,0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c, - 0x03,0x02,0x01,0x00,0x07,0x06,0x05,0x04,0x0b,0x0a,0x09,0x08,0x0f,0x0e,0x0d,0x0c, - 0x1c,0x1d,0x1e,0x1f,0x18,0x19,0x1a,0x1b,0x14,0x15,0x16,0x17,0x10,0x11,0x12,0x13, - 0x0c,0x0d,0x0e,0x0f,0x08,0x09,0x0a,0x0b,0x04,0x05,0x06,0x07,0x00,0x01,0x02,0x03, - 0x3c,0x3d,0x3e,0x3f,0x38,0x39,0x3a,0x3b,0x34,0x35,0x36,0x37,0x30,0x31,0x32,0x33, - 0x2c,0x2d,0x2e,0x2f,0x28,0x29,0x2a,0x2b,0x24,0x25,0x26,0x27,0x20,0x21,0x22,0x23, - 0x02,0x03,0x00,0x01,0x06,0x07,0x04,0x05,0x0a,0x0b,0x08,0x09,0x0e,0x0f,0x0c,0x0d, - 0x12,0x13,0x10,0x11,0x16,0x17,0x14,0x15,0x1a,0x1b,0x18,0x19,0x1e,0x1f,0x1c,0x1d, - 0x22,0x23,0x20,0x21,0x26,0x27,0x24,0x25,0x2a,0x2b,0x28,0x29,0x2e,0x2f,0x2c,0x2d, - 0x32,0x33,0x30,0x31,0x36,0x37,0x34,0x35,0x3a,0x3b,0x38,0x39,0x3e,0x3f,0x3c,0x3d, - 0x2d,0x2c,0x2f,0x2e,0x29,0x28,0x2b,0x2a,0x25,0x24,0x27,0x26,0x21,0x20,0x23,0x22, - 0x3d,0x3c,0x3f,0x3e,0x39,0x38,0x3b,0x3a,0x35,0x34,0x37,0x36,0x31,0x30,0x33,0x32, - 0x0d,0x0c,0x0f,0x0e,0x09,0x08,0x0b,0x0a,0x05,0x04,0x07,0x06,0x01,0x00,0x03,0x02, - 0x1d,0x1c,0x1f,0x1e,0x19,0x18,0x1b,0x1a,0x15,0x14,0x17,0x16,0x11,0x10,0x13,0x12, - 0x3e,0x3f,0x3c,0x3d,0x3a,0x3b,0x38,0x39,0x36,0x37,0x34,0x35,0x32,0x33,0x30,0x31, - 0x2e,0x2f,0x2c,0x2d,0x2a,0x2b,0x28,0x29,0x26,0x27,0x24,0x25,0x22,0x23,0x20,0x21, - 0x1e,0x1f,0x1c,0x1d,0x1a,0x1b,0x18,0x19,0x16,0x17,0x14,0x15,0x12,0x13,0x10,0x11, - 0x0e,0x0f,0x0c,0x0d,0x0a,0x0b,0x08,0x09,0x06,0x07,0x04,0x05,0x02,0x03,0x00,0x01, - 0x11,0x10,0x13,0x12,0x15,0x14,0x17,0x16,0x19,0x18,0x1b,0x1a,0x1d,0x1c,0x1f,0x1e, - 0x01,0x00,0x03,0x02,0x05,0x04,0x07,0x06,0x09,0x08,0x0b,0x0a,0x0d,0x0c,0x0f,0x0e, - 0x31,0x30,0x33,0x32,0x35,0x34,0x37,0x36,0x39,0x38,0x3b,0x3a,0x3d,0x3c,0x3f,0x3e, - 0x21,0x20,0x23,0x22,0x25,0x24,0x27,0x26,0x29,0x28,0x2b,0x2a,0x2d,0x2c,0x2f,0x2e, - 0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00, - 0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18,0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10, - 0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28,0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20, - 0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38,0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x30, - 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, - 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, - 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, - 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f, - 0x29,0x28,0x2b,0x2a,0x2d,0x2c,0x2f,0x2e,0x21,0x20,0x23,0x22,0x25,0x24,0x27,0x26, - 0x39,0x38,0x3b,0x3a,0x3d,0x3c,0x3f,0x3e,0x31,0x30,0x33,0x32,0x35,0x34,0x37,0x36, - 0x09,0x08,0x0b,0x0a,0x0d,0x0c,0x0f,0x0e,0x01,0x00,0x03,0x02,0x05,0x04,0x07,0x06, - 0x19,0x18,0x1b,0x1a,0x1d,0x1c,0x1f,0x1e,0x11,0x10,0x13,0x12,0x15,0x14,0x17,0x16, - 0x06,0x07,0x04,0x05,0x02,0x03,0x00,0x01,0x0e,0x0f,0x0c,0x0d,0x0a,0x0b,0x08,0x09, - 0x16,0x17,0x14,0x15,0x12,0x13,0x10,0x11,0x1e,0x1f,0x1c,0x1d,0x1a,0x1b,0x18,0x19, - 0x26,0x27,0x24,0x25,0x22,0x23,0x20,0x21,0x2e,0x2f,0x2c,0x2d,0x2a,0x2b,0x28,0x29, - 0x36,0x37,0x34,0x35,0x32,0x33,0x30,0x31,0x3e,0x3f,0x3c,0x3d,0x3a,0x3b,0x38,0x39, - 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, - 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, - 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37, - 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27, - 0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x30,0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38, - 0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20,0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28, - 0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10,0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18, - 0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08, - 0x24,0x25,0x26,0x27,0x20,0x21,0x22,0x23,0x2c,0x2d,0x2e,0x2f,0x28,0x29,0x2a,0x2b, - 0x34,0x35,0x36,0x37,0x30,0x31,0x32,0x33,0x3c,0x3d,0x3e,0x3f,0x38,0x39,0x3a,0x3b, - 0x04,0x05,0x06,0x07,0x00,0x01,0x02,0x03,0x0c,0x0d,0x0e,0x0f,0x08,0x09,0x0a,0x0b, - 0x14,0x15,0x16,0x17,0x10,0x11,0x12,0x13,0x1c,0x1d,0x1e,0x1f,0x18,0x19,0x1a,0x1b, - 0x0b,0x0a,0x09,0x08,0x0f,0x0e,0x0d,0x0c,0x03,0x02,0x01,0x00,0x07,0x06,0x05,0x04, - 0x1b,0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c,0x13,0x12,0x11,0x10,0x17,0x16,0x15,0x14, - 0x2b,0x2a,0x29,0x28,0x2f,0x2e,0x2d,0x2c,0x23,0x22,0x21,0x20,0x27,0x26,0x25,0x24, - 0x3b,0x3a,0x39,0x38,0x3f,0x3e,0x3d,0x3c,0x33,0x32,0x31,0x30,0x37,0x36,0x35,0x34, - 0x15,0x14,0x17,0x16,0x11,0x10,0x13,0x12,0x1d,0x1c,0x1f,0x1e,0x19,0x18,0x1b,0x1a, - 0x05,0x04,0x07,0x06,0x01,0x00,0x03,0x02,0x0d,0x0c,0x0f,0x0e,0x09,0x08,0x0b,0x0a, - 0x35,0x34,0x37,0x36,0x31,0x30,0x33,0x32,0x3d,0x3c,0x3f,0x3e,0x39,0x38,0x3b,0x3a, - 0x25,0x24,0x27,0x26,0x21,0x20,0x23,0x22,0x2d,0x2c,0x2f,0x2e,0x29,0x28,0x2b,0x2a, - 0x3a,0x3b,0x38,0x39,0x3e,0x3f,0x3c,0x3d,0x32,0x33,0x30,0x31,0x36,0x37,0x34,0x35, - 0x2a,0x2b,0x28,0x29,0x2e,0x2f,0x2c,0x2d,0x22,0x23,0x20,0x21,0x26,0x27,0x24,0x25, - 0x1a,0x1b,0x18,0x19,0x1e,0x1f,0x1c,0x1d,0x12,0x13,0x10,0x11,0x16,0x17,0x14,0x15, - 0x0a,0x0b,0x08,0x09,0x0e,0x0f,0x0c,0x0d,0x02,0x03,0x00,0x01,0x06,0x07,0x04,0x05, - 0x0e,0x0f,0x0c,0x0d,0x0a,0x0b,0x08,0x09,0x06,0x07,0x04,0x05,0x02,0x03,0x00,0x01, - 0x1e,0x1f,0x1c,0x1d,0x1a,0x1b,0x18,0x19,0x16,0x17,0x14,0x15,0x12,0x13,0x10,0x11, - 0x2e,0x2f,0x2c,0x2d,0x2a,0x2b,0x28,0x29,0x26,0x27,0x24,0x25,0x22,0x23,0x20,0x21, - 0x3e,0x3f,0x3c,0x3d,0x3a,0x3b,0x38,0x39,0x36,0x37,0x34,0x35,0x32,0x33,0x30,0x31, - 0x21,0x20,0x23,0x22,0x25,0x24,0x27,0x26,0x29,0x28,0x2b,0x2a,0x2d,0x2c,0x2f,0x2e, - 0x31,0x30,0x33,0x32,0x35,0x34,0x37,0x36,0x39,0x38,0x3b,0x3a,0x3d,0x3c,0x3f,0x3e, - 0x01,0x00,0x03,0x02,0x05,0x04,0x07,0x06,0x09,0x08,0x0b,0x0a,0x0d,0x0c,0x0f,0x0e, - 0x11,0x10,0x13,0x12,0x15,0x14,0x17,0x16,0x19,0x18,0x1b,0x1a,0x1d,0x1c,0x1f,0x1e, - 0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38,0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x30, - 0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28,0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20, - 0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18,0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10, - 0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00, - 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f, - 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, - 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, - 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, - 0x03,0x02,0x01,0x00,0x07,0x06,0x05,0x04,0x0b,0x0a,0x09,0x08,0x0f,0x0e,0x0d,0x0c, - 0x13,0x12,0x11,0x10,0x17,0x16,0x15,0x14,0x1b,0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c, - 0x23,0x22,0x21,0x20,0x27,0x26,0x25,0x24,0x2b,0x2a,0x29,0x28,0x2f,0x2e,0x2d,0x2c, - 0x33,0x32,0x31,0x30,0x37,0x36,0x35,0x34,0x3b,0x3a,0x39,0x38,0x3f,0x3e,0x3d,0x3c, - 0x2c,0x2d,0x2e,0x2f,0x28,0x29,0x2a,0x2b,0x24,0x25,0x26,0x27,0x20,0x21,0x22,0x23, - 0x3c,0x3d,0x3e,0x3f,0x38,0x39,0x3a,0x3b,0x34,0x35,0x36,0x37,0x30,0x31,0x32,0x33, - 0x0c,0x0d,0x0e,0x0f,0x08,0x09,0x0a,0x0b,0x04,0x05,0x06,0x07,0x00,0x01,0x02,0x03, - 0x1c,0x1d,0x1e,0x1f,0x18,0x19,0x1a,0x1b,0x14,0x15,0x16,0x17,0x10,0x11,0x12,0x13, - 0x32,0x33,0x30,0x31,0x36,0x37,0x34,0x35,0x3a,0x3b,0x38,0x39,0x3e,0x3f,0x3c,0x3d, - 0x22,0x23,0x20,0x21,0x26,0x27,0x24,0x25,0x2a,0x2b,0x28,0x29,0x2e,0x2f,0x2c,0x2d, - 0x12,0x13,0x10,0x11,0x16,0x17,0x14,0x15,0x1a,0x1b,0x18,0x19,0x1e,0x1f,0x1c,0x1d, - 0x02,0x03,0x00,0x01,0x06,0x07,0x04,0x05,0x0a,0x0b,0x08,0x09,0x0e,0x0f,0x0c,0x0d, - 0x1d,0x1c,0x1f,0x1e,0x19,0x18,0x1b,0x1a,0x15,0x14,0x17,0x16,0x11,0x10,0x13,0x12, - 0x0d,0x0c,0x0f,0x0e,0x09,0x08,0x0b,0x0a,0x05,0x04,0x07,0x06,0x01,0x00,0x03,0x02, - 0x3d,0x3c,0x3f,0x3e,0x39,0x38,0x3b,0x3a,0x35,0x34,0x37,0x36,0x31,0x30,0x33,0x32, - 0x2d,0x2c,0x2f,0x2e,0x29,0x28,0x2b,0x2a,0x25,0x24,0x27,0x26,0x21,0x20,0x23,0x22, - 0x14,0x15,0x16,0x17,0x10,0x11,0x12,0x13,0x1c,0x1d,0x1e,0x1f,0x18,0x19,0x1a,0x1b, - 0x04,0x05,0x06,0x07,0x00,0x01,0x02,0x03,0x0c,0x0d,0x0e,0x0f,0x08,0x09,0x0a,0x0b, - 0x34,0x35,0x36,0x37,0x30,0x31,0x32,0x33,0x3c,0x3d,0x3e,0x3f,0x38,0x39,0x3a,0x3b, - 0x24,0x25,0x26,0x27,0x20,0x21,0x22,0x23,0x2c,0x2d,0x2e,0x2f,0x28,0x29,0x2a,0x2b, - 0x3b,0x3a,0x39,0x38,0x3f,0x3e,0x3d,0x3c,0x33,0x32,0x31,0x30,0x37,0x36,0x35,0x34, - 0x2b,0x2a,0x29,0x28,0x2f,0x2e,0x2d,0x2c,0x23,0x22,0x21,0x20,0x27,0x26,0x25,0x24, - 0x1b,0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c,0x13,0x12,0x11,0x10,0x17,0x16,0x15,0x14, - 0x0b,0x0a,0x09,0x08,0x0f,0x0e,0x0d,0x0c,0x03,0x02,0x01,0x00,0x07,0x06,0x05,0x04, - 0x25,0x24,0x27,0x26,0x21,0x20,0x23,0x22,0x2d,0x2c,0x2f,0x2e,0x29,0x28,0x2b,0x2a, - 0x35,0x34,0x37,0x36,0x31,0x30,0x33,0x32,0x3d,0x3c,0x3f,0x3e,0x39,0x38,0x3b,0x3a, - 0x05,0x04,0x07,0x06,0x01,0x00,0x03,0x02,0x0d,0x0c,0x0f,0x0e,0x09,0x08,0x0b,0x0a, - 0x15,0x14,0x17,0x16,0x11,0x10,0x13,0x12,0x1d,0x1c,0x1f,0x1e,0x19,0x18,0x1b,0x1a, - 0x0a,0x0b,0x08,0x09,0x0e,0x0f,0x0c,0x0d,0x02,0x03,0x00,0x01,0x06,0x07,0x04,0x05, - 0x1a,0x1b,0x18,0x19,0x1e,0x1f,0x1c,0x1d,0x12,0x13,0x10,0x11,0x16,0x17,0x14,0x15, - 0x2a,0x2b,0x28,0x29,0x2e,0x2f,0x2c,0x2d,0x22,0x23,0x20,0x21,0x26,0x27,0x24,0x25, - 0x3a,0x3b,0x38,0x39,0x3e,0x3f,0x3c,0x3d,0x32,0x33,0x30,0x31,0x36,0x37,0x34,0x35, - 0x19,0x18,0x1b,0x1a,0x1d,0x1c,0x1f,0x1e,0x11,0x10,0x13,0x12,0x15,0x14,0x17,0x16, - 0x09,0x08,0x0b,0x0a,0x0d,0x0c,0x0f,0x0e,0x01,0x00,0x03,0x02,0x05,0x04,0x07,0x06, - 0x39,0x38,0x3b,0x3a,0x3d,0x3c,0x3f,0x3e,0x31,0x30,0x33,0x32,0x35,0x34,0x37,0x36, - 0x29,0x28,0x2b,0x2a,0x2d,0x2c,0x2f,0x2e,0x21,0x20,0x23,0x22,0x25,0x24,0x27,0x26, - 0x36,0x37,0x34,0x35,0x32,0x33,0x30,0x31,0x3e,0x3f,0x3c,0x3d,0x3a,0x3b,0x38,0x39, - 0x26,0x27,0x24,0x25,0x22,0x23,0x20,0x21,0x2e,0x2f,0x2c,0x2d,0x2a,0x2b,0x28,0x29, - 0x16,0x17,0x14,0x15,0x12,0x13,0x10,0x11,0x1e,0x1f,0x1c,0x1d,0x1a,0x1b,0x18,0x19, - 0x06,0x07,0x04,0x05,0x02,0x03,0x00,0x01,0x0e,0x0f,0x0c,0x0d,0x0a,0x0b,0x08,0x09, - 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27, - 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37, - 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, - 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, - 0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08, - 0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10,0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18, - 0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20,0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28, - 0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x30,0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38, - 0x3a,0x3b,0x38,0x39,0x3e,0x3f,0x3c,0x3d,0x32,0x33,0x30,0x31,0x36,0x37,0x34,0x35, - 0x2a,0x2b,0x28,0x29,0x2e,0x2f,0x2c,0x2d,0x22,0x23,0x20,0x21,0x26,0x27,0x24,0x25, - 0x1a,0x1b,0x18,0x19,0x1e,0x1f,0x1c,0x1d,0x12,0x13,0x10,0x11,0x16,0x17,0x14,0x15, - 0x0a,0x0b,0x08,0x09,0x0e,0x0f,0x0c,0x0d,0x02,0x03,0x00,0x01,0x06,0x07,0x04,0x05, - 0x15,0x14,0x17,0x16,0x11,0x10,0x13,0x12,0x1d,0x1c,0x1f,0x1e,0x19,0x18,0x1b,0x1a, - 0x05,0x04,0x07,0x06,0x01,0x00,0x03,0x02,0x0d,0x0c,0x0f,0x0e,0x09,0x08,0x0b,0x0a, - 0x35,0x34,0x37,0x36,0x31,0x30,0x33,0x32,0x3d,0x3c,0x3f,0x3e,0x39,0x38,0x3b,0x3a, - 0x25,0x24,0x27,0x26,0x21,0x20,0x23,0x22,0x2d,0x2c,0x2f,0x2e,0x29,0x28,0x2b,0x2a, - 0x0b,0x0a,0x09,0x08,0x0f,0x0e,0x0d,0x0c,0x03,0x02,0x01,0x00,0x07,0x06,0x05,0x04, - 0x1b,0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c,0x13,0x12,0x11,0x10,0x17,0x16,0x15,0x14, - 0x2b,0x2a,0x29,0x28,0x2f,0x2e,0x2d,0x2c,0x23,0x22,0x21,0x20,0x27,0x26,0x25,0x24, - 0x3b,0x3a,0x39,0x38,0x3f,0x3e,0x3d,0x3c,0x33,0x32,0x31,0x30,0x37,0x36,0x35,0x34, - 0x24,0x25,0x26,0x27,0x20,0x21,0x22,0x23,0x2c,0x2d,0x2e,0x2f,0x28,0x29,0x2a,0x2b, - 0x34,0x35,0x36,0x37,0x30,0x31,0x32,0x33,0x3c,0x3d,0x3e,0x3f,0x38,0x39,0x3a,0x3b, - 0x04,0x05,0x06,0x07,0x00,0x01,0x02,0x03,0x0c,0x0d,0x0e,0x0f,0x08,0x09,0x0a,0x0b, - 0x14,0x15,0x16,0x17,0x10,0x11,0x12,0x13,0x1c,0x1d,0x1e,0x1f,0x18,0x19,0x1a,0x1b, - 0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x30,0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38, - 0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20,0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28, - 0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10,0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18, - 0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08, - 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, - 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, - 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37, - 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27, - 0x06,0x07,0x04,0x05,0x02,0x03,0x00,0x01,0x0e,0x0f,0x0c,0x0d,0x0a,0x0b,0x08,0x09, - 0x16,0x17,0x14,0x15,0x12,0x13,0x10,0x11,0x1e,0x1f,0x1c,0x1d,0x1a,0x1b,0x18,0x19, - 0x26,0x27,0x24,0x25,0x22,0x23,0x20,0x21,0x2e,0x2f,0x2c,0x2d,0x2a,0x2b,0x28,0x29, - 0x36,0x37,0x34,0x35,0x32,0x33,0x30,0x31,0x3e,0x3f,0x3c,0x3d,0x3a,0x3b,0x38,0x39, - 0x29,0x28,0x2b,0x2a,0x2d,0x2c,0x2f,0x2e,0x21,0x20,0x23,0x22,0x25,0x24,0x27,0x26, - 0x39,0x38,0x3b,0x3a,0x3d,0x3c,0x3f,0x3e,0x31,0x30,0x33,0x32,0x35,0x34,0x37,0x36, - 0x09,0x08,0x0b,0x0a,0x0d,0x0c,0x0f,0x0e,0x01,0x00,0x03,0x02,0x05,0x04,0x07,0x06, - 0x19,0x18,0x1b,0x1a,0x1d,0x1c,0x1f,0x1e,0x11,0x10,0x13,0x12,0x15,0x14,0x17,0x16, - 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, - 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, - 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, - 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f, - 0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00, - 0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18,0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10, - 0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28,0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20, - 0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38,0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x30, - 0x11,0x10,0x13,0x12,0x15,0x14,0x17,0x16,0x19,0x18,0x1b,0x1a,0x1d,0x1c,0x1f,0x1e, - 0x01,0x00,0x03,0x02,0x05,0x04,0x07,0x06,0x09,0x08,0x0b,0x0a,0x0d,0x0c,0x0f,0x0e, - 0x31,0x30,0x33,0x32,0x35,0x34,0x37,0x36,0x39,0x38,0x3b,0x3a,0x3d,0x3c,0x3f,0x3e, - 0x21,0x20,0x23,0x22,0x25,0x24,0x27,0x26,0x29,0x28,0x2b,0x2a,0x2d,0x2c,0x2f,0x2e, - 0x3e,0x3f,0x3c,0x3d,0x3a,0x3b,0x38,0x39,0x36,0x37,0x34,0x35,0x32,0x33,0x30,0x31, - 0x2e,0x2f,0x2c,0x2d,0x2a,0x2b,0x28,0x29,0x26,0x27,0x24,0x25,0x22,0x23,0x20,0x21, - 0x1e,0x1f,0x1c,0x1d,0x1a,0x1b,0x18,0x19,0x16,0x17,0x14,0x15,0x12,0x13,0x10,0x11, - 0x0e,0x0f,0x0c,0x0d,0x0a,0x0b,0x08,0x09,0x06,0x07,0x04,0x05,0x02,0x03,0x00,0x01, - 0x2d,0x2c,0x2f,0x2e,0x29,0x28,0x2b,0x2a,0x25,0x24,0x27,0x26,0x21,0x20,0x23,0x22, - 0x3d,0x3c,0x3f,0x3e,0x39,0x38,0x3b,0x3a,0x35,0x34,0x37,0x36,0x31,0x30,0x33,0x32, - 0x0d,0x0c,0x0f,0x0e,0x09,0x08,0x0b,0x0a,0x05,0x04,0x07,0x06,0x01,0x00,0x03,0x02, - 0x1d,0x1c,0x1f,0x1e,0x19,0x18,0x1b,0x1a,0x15,0x14,0x17,0x16,0x11,0x10,0x13,0x12, - 0x02,0x03,0x00,0x01,0x06,0x07,0x04,0x05,0x0a,0x0b,0x08,0x09,0x0e,0x0f,0x0c,0x0d, - 0x12,0x13,0x10,0x11,0x16,0x17,0x14,0x15,0x1a,0x1b,0x18,0x19,0x1e,0x1f,0x1c,0x1d, - 0x22,0x23,0x20,0x21,0x26,0x27,0x24,0x25,0x2a,0x2b,0x28,0x29,0x2e,0x2f,0x2c,0x2d, - 0x32,0x33,0x30,0x31,0x36,0x37,0x34,0x35,0x3a,0x3b,0x38,0x39,0x3e,0x3f,0x3c,0x3d, - 0x1c,0x1d,0x1e,0x1f,0x18,0x19,0x1a,0x1b,0x14,0x15,0x16,0x17,0x10,0x11,0x12,0x13, - 0x0c,0x0d,0x0e,0x0f,0x08,0x09,0x0a,0x0b,0x04,0x05,0x06,0x07,0x00,0x01,0x02,0x03, - 0x3c,0x3d,0x3e,0x3f,0x38,0x39,0x3a,0x3b,0x34,0x35,0x36,0x37,0x30,0x31,0x32,0x33, - 0x2c,0x2d,0x2e,0x2f,0x28,0x29,0x2a,0x2b,0x24,0x25,0x26,0x27,0x20,0x21,0x22,0x23, - 0x33,0x32,0x31,0x30,0x37,0x36,0x35,0x34,0x3b,0x3a,0x39,0x38,0x3f,0x3e,0x3d,0x3c, - 0x23,0x22,0x21,0x20,0x27,0x26,0x25,0x24,0x2b,0x2a,0x29,0x28,0x2f,0x2e,0x2d,0x2c, - 0x13,0x12,0x11,0x10,0x17,0x16,0x15,0x14,0x1b,0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c, - 0x03,0x02,0x01,0x00,0x07,0x06,0x05,0x04,0x0b,0x0a,0x09,0x08,0x0f,0x0e,0x0d,0x0c, - 0x09,0x08,0x0b,0x0a,0x0d,0x0c,0x0f,0x0e,0x01,0x00,0x03,0x02,0x05,0x04,0x07,0x06, - 0x19,0x18,0x1b,0x1a,0x1d,0x1c,0x1f,0x1e,0x11,0x10,0x13,0x12,0x15,0x14,0x17,0x16, - 0x29,0x28,0x2b,0x2a,0x2d,0x2c,0x2f,0x2e,0x21,0x20,0x23,0x22,0x25,0x24,0x27,0x26, - 0x39,0x38,0x3b,0x3a,0x3d,0x3c,0x3f,0x3e,0x31,0x30,0x33,0x32,0x35,0x34,0x37,0x36, - 0x26,0x27,0x24,0x25,0x22,0x23,0x20,0x21,0x2e,0x2f,0x2c,0x2d,0x2a,0x2b,0x28,0x29, - 0x36,0x37,0x34,0x35,0x32,0x33,0x30,0x31,0x3e,0x3f,0x3c,0x3d,0x3a,0x3b,0x38,0x39, - 0x06,0x07,0x04,0x05,0x02,0x03,0x00,0x01,0x0e,0x0f,0x0c,0x0d,0x0a,0x0b,0x08,0x09, - 0x16,0x17,0x14,0x15,0x12,0x13,0x10,0x11,0x1e,0x1f,0x1c,0x1d,0x1a,0x1b,0x18,0x19, - 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37, - 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27, - 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, - 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, - 0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10,0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18, - 0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08, - 0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x30,0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38, - 0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20,0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28, - 0x04,0x05,0x06,0x07,0x00,0x01,0x02,0x03,0x0c,0x0d,0x0e,0x0f,0x08,0x09,0x0a,0x0b, - 0x14,0x15,0x16,0x17,0x10,0x11,0x12,0x13,0x1c,0x1d,0x1e,0x1f,0x18,0x19,0x1a,0x1b, - 0x24,0x25,0x26,0x27,0x20,0x21,0x22,0x23,0x2c,0x2d,0x2e,0x2f,0x28,0x29,0x2a,0x2b, - 0x34,0x35,0x36,0x37,0x30,0x31,0x32,0x33,0x3c,0x3d,0x3e,0x3f,0x38,0x39,0x3a,0x3b, - 0x2b,0x2a,0x29,0x28,0x2f,0x2e,0x2d,0x2c,0x23,0x22,0x21,0x20,0x27,0x26,0x25,0x24, - 0x3b,0x3a,0x39,0x38,0x3f,0x3e,0x3d,0x3c,0x33,0x32,0x31,0x30,0x37,0x36,0x35,0x34, - 0x0b,0x0a,0x09,0x08,0x0f,0x0e,0x0d,0x0c,0x03,0x02,0x01,0x00,0x07,0x06,0x05,0x04, - 0x1b,0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c,0x13,0x12,0x11,0x10,0x17,0x16,0x15,0x14, - 0x35,0x34,0x37,0x36,0x31,0x30,0x33,0x32,0x3d,0x3c,0x3f,0x3e,0x39,0x38,0x3b,0x3a, - 0x25,0x24,0x27,0x26,0x21,0x20,0x23,0x22,0x2d,0x2c,0x2f,0x2e,0x29,0x28,0x2b,0x2a, - 0x15,0x14,0x17,0x16,0x11,0x10,0x13,0x12,0x1d,0x1c,0x1f,0x1e,0x19,0x18,0x1b,0x1a, - 0x05,0x04,0x07,0x06,0x01,0x00,0x03,0x02,0x0d,0x0c,0x0f,0x0e,0x09,0x08,0x0b,0x0a, - 0x1a,0x1b,0x18,0x19,0x1e,0x1f,0x1c,0x1d,0x12,0x13,0x10,0x11,0x16,0x17,0x14,0x15, - 0x0a,0x0b,0x08,0x09,0x0e,0x0f,0x0c,0x0d,0x02,0x03,0x00,0x01,0x06,0x07,0x04,0x05, - 0x3a,0x3b,0x38,0x39,0x3e,0x3f,0x3c,0x3d,0x32,0x33,0x30,0x31,0x36,0x37,0x34,0x35, - 0x2a,0x2b,0x28,0x29,0x2e,0x2f,0x2c,0x2d,0x22,0x23,0x20,0x21,0x26,0x27,0x24,0x25, - 0x13,0x12,0x11,0x10,0x17,0x16,0x15,0x14,0x1b,0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c, - 0x03,0x02,0x01,0x00,0x07,0x06,0x05,0x04,0x0b,0x0a,0x09,0x08,0x0f,0x0e,0x0d,0x0c, - 0x33,0x32,0x31,0x30,0x37,0x36,0x35,0x34,0x3b,0x3a,0x39,0x38,0x3f,0x3e,0x3d,0x3c, - 0x23,0x22,0x21,0x20,0x27,0x26,0x25,0x24,0x2b,0x2a,0x29,0x28,0x2f,0x2e,0x2d,0x2c, - 0x3c,0x3d,0x3e,0x3f,0x38,0x39,0x3a,0x3b,0x34,0x35,0x36,0x37,0x30,0x31,0x32,0x33, - 0x2c,0x2d,0x2e,0x2f,0x28,0x29,0x2a,0x2b,0x24,0x25,0x26,0x27,0x20,0x21,0x22,0x23, - 0x1c,0x1d,0x1e,0x1f,0x18,0x19,0x1a,0x1b,0x14,0x15,0x16,0x17,0x10,0x11,0x12,0x13, - 0x0c,0x0d,0x0e,0x0f,0x08,0x09,0x0a,0x0b,0x04,0x05,0x06,0x07,0x00,0x01,0x02,0x03, - 0x22,0x23,0x20,0x21,0x26,0x27,0x24,0x25,0x2a,0x2b,0x28,0x29,0x2e,0x2f,0x2c,0x2d, - 0x32,0x33,0x30,0x31,0x36,0x37,0x34,0x35,0x3a,0x3b,0x38,0x39,0x3e,0x3f,0x3c,0x3d, - 0x02,0x03,0x00,0x01,0x06,0x07,0x04,0x05,0x0a,0x0b,0x08,0x09,0x0e,0x0f,0x0c,0x0d, - 0x12,0x13,0x10,0x11,0x16,0x17,0x14,0x15,0x1a,0x1b,0x18,0x19,0x1e,0x1f,0x1c,0x1d, - 0x0d,0x0c,0x0f,0x0e,0x09,0x08,0x0b,0x0a,0x05,0x04,0x07,0x06,0x01,0x00,0x03,0x02, - 0x1d,0x1c,0x1f,0x1e,0x19,0x18,0x1b,0x1a,0x15,0x14,0x17,0x16,0x11,0x10,0x13,0x12, - 0x2d,0x2c,0x2f,0x2e,0x29,0x28,0x2b,0x2a,0x25,0x24,0x27,0x26,0x21,0x20,0x23,0x22, - 0x3d,0x3c,0x3f,0x3e,0x39,0x38,0x3b,0x3a,0x35,0x34,0x37,0x36,0x31,0x30,0x33,0x32, - 0x1e,0x1f,0x1c,0x1d,0x1a,0x1b,0x18,0x19,0x16,0x17,0x14,0x15,0x12,0x13,0x10,0x11, - 0x0e,0x0f,0x0c,0x0d,0x0a,0x0b,0x08,0x09,0x06,0x07,0x04,0x05,0x02,0x03,0x00,0x01, - 0x3e,0x3f,0x3c,0x3d,0x3a,0x3b,0x38,0x39,0x36,0x37,0x34,0x35,0x32,0x33,0x30,0x31, - 0x2e,0x2f,0x2c,0x2d,0x2a,0x2b,0x28,0x29,0x26,0x27,0x24,0x25,0x22,0x23,0x20,0x21, - 0x31,0x30,0x33,0x32,0x35,0x34,0x37,0x36,0x39,0x38,0x3b,0x3a,0x3d,0x3c,0x3f,0x3e, - 0x21,0x20,0x23,0x22,0x25,0x24,0x27,0x26,0x29,0x28,0x2b,0x2a,0x2d,0x2c,0x2f,0x2e, - 0x11,0x10,0x13,0x12,0x15,0x14,0x17,0x16,0x19,0x18,0x1b,0x1a,0x1d,0x1c,0x1f,0x1e, - 0x01,0x00,0x03,0x02,0x05,0x04,0x07,0x06,0x09,0x08,0x0b,0x0a,0x0d,0x0c,0x0f,0x0e, - 0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28,0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20, - 0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38,0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x30, - 0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00, - 0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18,0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10, - 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, - 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f, - 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, - 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, - 0x3d,0x3c,0x3f,0x3e,0x39,0x38,0x3b,0x3a,0x35,0x34,0x37,0x36,0x31,0x30,0x33,0x32, - 0x2d,0x2c,0x2f,0x2e,0x29,0x28,0x2b,0x2a,0x25,0x24,0x27,0x26,0x21,0x20,0x23,0x22, - 0x1d,0x1c,0x1f,0x1e,0x19,0x18,0x1b,0x1a,0x15,0x14,0x17,0x16,0x11,0x10,0x13,0x12, - 0x0d,0x0c,0x0f,0x0e,0x09,0x08,0x0b,0x0a,0x05,0x04,0x07,0x06,0x01,0x00,0x03,0x02, - 0x12,0x13,0x10,0x11,0x16,0x17,0x14,0x15,0x1a,0x1b,0x18,0x19,0x1e,0x1f,0x1c,0x1d, - 0x02,0x03,0x00,0x01,0x06,0x07,0x04,0x05,0x0a,0x0b,0x08,0x09,0x0e,0x0f,0x0c,0x0d, - 0x32,0x33,0x30,0x31,0x36,0x37,0x34,0x35,0x3a,0x3b,0x38,0x39,0x3e,0x3f,0x3c,0x3d, - 0x22,0x23,0x20,0x21,0x26,0x27,0x24,0x25,0x2a,0x2b,0x28,0x29,0x2e,0x2f,0x2c,0x2d, - 0x0c,0x0d,0x0e,0x0f,0x08,0x09,0x0a,0x0b,0x04,0x05,0x06,0x07,0x00,0x01,0x02,0x03, - 0x1c,0x1d,0x1e,0x1f,0x18,0x19,0x1a,0x1b,0x14,0x15,0x16,0x17,0x10,0x11,0x12,0x13, - 0x2c,0x2d,0x2e,0x2f,0x28,0x29,0x2a,0x2b,0x24,0x25,0x26,0x27,0x20,0x21,0x22,0x23, - 0x3c,0x3d,0x3e,0x3f,0x38,0x39,0x3a,0x3b,0x34,0x35,0x36,0x37,0x30,0x31,0x32,0x33, - 0x23,0x22,0x21,0x20,0x27,0x26,0x25,0x24,0x2b,0x2a,0x29,0x28,0x2f,0x2e,0x2d,0x2c, - 0x33,0x32,0x31,0x30,0x37,0x36,0x35,0x34,0x3b,0x3a,0x39,0x38,0x3f,0x3e,0x3d,0x3c, - 0x03,0x02,0x01,0x00,0x07,0x06,0x05,0x04,0x0b,0x0a,0x09,0x08,0x0f,0x0e,0x0d,0x0c, - 0x13,0x12,0x11,0x10,0x17,0x16,0x15,0x14,0x1b,0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c, - 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, - 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, - 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f, - 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, - 0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18,0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10, - 0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00, - 0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38,0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x30, - 0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28,0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20, - 0x01,0x00,0x03,0x02,0x05,0x04,0x07,0x06,0x09,0x08,0x0b,0x0a,0x0d,0x0c,0x0f,0x0e, - 0x11,0x10,0x13,0x12,0x15,0x14,0x17,0x16,0x19,0x18,0x1b,0x1a,0x1d,0x1c,0x1f,0x1e, - 0x21,0x20,0x23,0x22,0x25,0x24,0x27,0x26,0x29,0x28,0x2b,0x2a,0x2d,0x2c,0x2f,0x2e, - 0x31,0x30,0x33,0x32,0x35,0x34,0x37,0x36,0x39,0x38,0x3b,0x3a,0x3d,0x3c,0x3f,0x3e, - 0x2e,0x2f,0x2c,0x2d,0x2a,0x2b,0x28,0x29,0x26,0x27,0x24,0x25,0x22,0x23,0x20,0x21, - 0x3e,0x3f,0x3c,0x3d,0x3a,0x3b,0x38,0x39,0x36,0x37,0x34,0x35,0x32,0x33,0x30,0x31, - 0x0e,0x0f,0x0c,0x0d,0x0a,0x0b,0x08,0x09,0x06,0x07,0x04,0x05,0x02,0x03,0x00,0x01, - 0x1e,0x1f,0x1c,0x1d,0x1a,0x1b,0x18,0x19,0x16,0x17,0x14,0x15,0x12,0x13,0x10,0x11, - 0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20,0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28, - 0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x30,0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38, - 0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08, - 0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10,0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18, - 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, - 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, - 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27, - 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37, - 0x16,0x17,0x14,0x15,0x12,0x13,0x10,0x11,0x1e,0x1f,0x1c,0x1d,0x1a,0x1b,0x18,0x19, - 0x06,0x07,0x04,0x05,0x02,0x03,0x00,0x01,0x0e,0x0f,0x0c,0x0d,0x0a,0x0b,0x08,0x09, - 0x36,0x37,0x34,0x35,0x32,0x33,0x30,0x31,0x3e,0x3f,0x3c,0x3d,0x3a,0x3b,0x38,0x39, - 0x26,0x27,0x24,0x25,0x22,0x23,0x20,0x21,0x2e,0x2f,0x2c,0x2d,0x2a,0x2b,0x28,0x29, - 0x39,0x38,0x3b,0x3a,0x3d,0x3c,0x3f,0x3e,0x31,0x30,0x33,0x32,0x35,0x34,0x37,0x36, - 0x29,0x28,0x2b,0x2a,0x2d,0x2c,0x2f,0x2e,0x21,0x20,0x23,0x22,0x25,0x24,0x27,0x26, - 0x19,0x18,0x1b,0x1a,0x1d,0x1c,0x1f,0x1e,0x11,0x10,0x13,0x12,0x15,0x14,0x17,0x16, - 0x09,0x08,0x0b,0x0a,0x0d,0x0c,0x0f,0x0e,0x01,0x00,0x03,0x02,0x05,0x04,0x07,0x06, - 0x2a,0x2b,0x28,0x29,0x2e,0x2f,0x2c,0x2d,0x22,0x23,0x20,0x21,0x26,0x27,0x24,0x25, - 0x3a,0x3b,0x38,0x39,0x3e,0x3f,0x3c,0x3d,0x32,0x33,0x30,0x31,0x36,0x37,0x34,0x35, - 0x0a,0x0b,0x08,0x09,0x0e,0x0f,0x0c,0x0d,0x02,0x03,0x00,0x01,0x06,0x07,0x04,0x05, - 0x1a,0x1b,0x18,0x19,0x1e,0x1f,0x1c,0x1d,0x12,0x13,0x10,0x11,0x16,0x17,0x14,0x15, - 0x05,0x04,0x07,0x06,0x01,0x00,0x03,0x02,0x0d,0x0c,0x0f,0x0e,0x09,0x08,0x0b,0x0a, - 0x15,0x14,0x17,0x16,0x11,0x10,0x13,0x12,0x1d,0x1c,0x1f,0x1e,0x19,0x18,0x1b,0x1a, - 0x25,0x24,0x27,0x26,0x21,0x20,0x23,0x22,0x2d,0x2c,0x2f,0x2e,0x29,0x28,0x2b,0x2a, - 0x35,0x34,0x37,0x36,0x31,0x30,0x33,0x32,0x3d,0x3c,0x3f,0x3e,0x39,0x38,0x3b,0x3a, - 0x1b,0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c,0x13,0x12,0x11,0x10,0x17,0x16,0x15,0x14, - 0x0b,0x0a,0x09,0x08,0x0f,0x0e,0x0d,0x0c,0x03,0x02,0x01,0x00,0x07,0x06,0x05,0x04, - 0x3b,0x3a,0x39,0x38,0x3f,0x3e,0x3d,0x3c,0x33,0x32,0x31,0x30,0x37,0x36,0x35,0x34, - 0x2b,0x2a,0x29,0x28,0x2f,0x2e,0x2d,0x2c,0x23,0x22,0x21,0x20,0x27,0x26,0x25,0x24, - 0x34,0x35,0x36,0x37,0x30,0x31,0x32,0x33,0x3c,0x3d,0x3e,0x3f,0x38,0x39,0x3a,0x3b, - 0x24,0x25,0x26,0x27,0x20,0x21,0x22,0x23,0x2c,0x2d,0x2e,0x2f,0x28,0x29,0x2a,0x2b, - 0x14,0x15,0x16,0x17,0x10,0x11,0x12,0x13,0x1c,0x1d,0x1e,0x1f,0x18,0x19,0x1a,0x1b, - 0x04,0x05,0x06,0x07,0x00,0x01,0x02,0x03,0x0c,0x0d,0x0e,0x0f,0x08,0x09,0x0a,0x0b, - 0x1c,0x1d,0x1e,0x1f,0x18,0x19,0x1a,0x1b,0x14,0x15,0x16,0x17,0x10,0x11,0x12,0x13, - 0x0c,0x0d,0x0e,0x0f,0x08,0x09,0x0a,0x0b,0x04,0x05,0x06,0x07,0x00,0x01,0x02,0x03, - 0x3c,0x3d,0x3e,0x3f,0x38,0x39,0x3a,0x3b,0x34,0x35,0x36,0x37,0x30,0x31,0x32,0x33, - 0x2c,0x2d,0x2e,0x2f,0x28,0x29,0x2a,0x2b,0x24,0x25,0x26,0x27,0x20,0x21,0x22,0x23, - 0x33,0x32,0x31,0x30,0x37,0x36,0x35,0x34,0x3b,0x3a,0x39,0x38,0x3f,0x3e,0x3d,0x3c, - 0x23,0x22,0x21,0x20,0x27,0x26,0x25,0x24,0x2b,0x2a,0x29,0x28,0x2f,0x2e,0x2d,0x2c, - 0x13,0x12,0x11,0x10,0x17,0x16,0x15,0x14,0x1b,0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c, - 0x03,0x02,0x01,0x00,0x07,0x06,0x05,0x04,0x0b,0x0a,0x09,0x08,0x0f,0x0e,0x0d,0x0c, - 0x2d,0x2c,0x2f,0x2e,0x29,0x28,0x2b,0x2a,0x25,0x24,0x27,0x26,0x21,0x20,0x23,0x22, - 0x3d,0x3c,0x3f,0x3e,0x39,0x38,0x3b,0x3a,0x35,0x34,0x37,0x36,0x31,0x30,0x33,0x32, - 0x0d,0x0c,0x0f,0x0e,0x09,0x08,0x0b,0x0a,0x05,0x04,0x07,0x06,0x01,0x00,0x03,0x02, - 0x1d,0x1c,0x1f,0x1e,0x19,0x18,0x1b,0x1a,0x15,0x14,0x17,0x16,0x11,0x10,0x13,0x12, - 0x02,0x03,0x00,0x01,0x06,0x07,0x04,0x05,0x0a,0x0b,0x08,0x09,0x0e,0x0f,0x0c,0x0d, - 0x12,0x13,0x10,0x11,0x16,0x17,0x14,0x15,0x1a,0x1b,0x18,0x19,0x1e,0x1f,0x1c,0x1d, - 0x22,0x23,0x20,0x21,0x26,0x27,0x24,0x25,0x2a,0x2b,0x28,0x29,0x2e,0x2f,0x2c,0x2d, - 0x32,0x33,0x30,0x31,0x36,0x37,0x34,0x35,0x3a,0x3b,0x38,0x39,0x3e,0x3f,0x3c,0x3d, - 0x11,0x10,0x13,0x12,0x15,0x14,0x17,0x16,0x19,0x18,0x1b,0x1a,0x1d,0x1c,0x1f,0x1e, - 0x01,0x00,0x03,0x02,0x05,0x04,0x07,0x06,0x09,0x08,0x0b,0x0a,0x0d,0x0c,0x0f,0x0e, - 0x31,0x30,0x33,0x32,0x35,0x34,0x37,0x36,0x39,0x38,0x3b,0x3a,0x3d,0x3c,0x3f,0x3e, - 0x21,0x20,0x23,0x22,0x25,0x24,0x27,0x26,0x29,0x28,0x2b,0x2a,0x2d,0x2c,0x2f,0x2e, - 0x3e,0x3f,0x3c,0x3d,0x3a,0x3b,0x38,0x39,0x36,0x37,0x34,0x35,0x32,0x33,0x30,0x31, - 0x2e,0x2f,0x2c,0x2d,0x2a,0x2b,0x28,0x29,0x26,0x27,0x24,0x25,0x22,0x23,0x20,0x21, - 0x1e,0x1f,0x1c,0x1d,0x1a,0x1b,0x18,0x19,0x16,0x17,0x14,0x15,0x12,0x13,0x10,0x11, - 0x0e,0x0f,0x0c,0x0d,0x0a,0x0b,0x08,0x09,0x06,0x07,0x04,0x05,0x02,0x03,0x00,0x01, - 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, - 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, - 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, - 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f, - 0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00, - 0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18,0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10, - 0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28,0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20, - 0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38,0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x30, - 0x06,0x07,0x04,0x05,0x02,0x03,0x00,0x01,0x0e,0x0f,0x0c,0x0d,0x0a,0x0b,0x08,0x09, - 0x16,0x17,0x14,0x15,0x12,0x13,0x10,0x11,0x1e,0x1f,0x1c,0x1d,0x1a,0x1b,0x18,0x19, - 0x26,0x27,0x24,0x25,0x22,0x23,0x20,0x21,0x2e,0x2f,0x2c,0x2d,0x2a,0x2b,0x28,0x29, - 0x36,0x37,0x34,0x35,0x32,0x33,0x30,0x31,0x3e,0x3f,0x3c,0x3d,0x3a,0x3b,0x38,0x39, - 0x29,0x28,0x2b,0x2a,0x2d,0x2c,0x2f,0x2e,0x21,0x20,0x23,0x22,0x25,0x24,0x27,0x26, - 0x39,0x38,0x3b,0x3a,0x3d,0x3c,0x3f,0x3e,0x31,0x30,0x33,0x32,0x35,0x34,0x37,0x36, - 0x09,0x08,0x0b,0x0a,0x0d,0x0c,0x0f,0x0e,0x01,0x00,0x03,0x02,0x05,0x04,0x07,0x06, - 0x19,0x18,0x1b,0x1a,0x1d,0x1c,0x1f,0x1e,0x11,0x10,0x13,0x12,0x15,0x14,0x17,0x16, - 0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x30,0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38, - 0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20,0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28, - 0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10,0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18, - 0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08, - 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, - 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, - 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37, - 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27, - 0x0b,0x0a,0x09,0x08,0x0f,0x0e,0x0d,0x0c,0x03,0x02,0x01,0x00,0x07,0x06,0x05,0x04, - 0x1b,0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c,0x13,0x12,0x11,0x10,0x17,0x16,0x15,0x14, - 0x2b,0x2a,0x29,0x28,0x2f,0x2e,0x2d,0x2c,0x23,0x22,0x21,0x20,0x27,0x26,0x25,0x24, - 0x3b,0x3a,0x39,0x38,0x3f,0x3e,0x3d,0x3c,0x33,0x32,0x31,0x30,0x37,0x36,0x35,0x34, - 0x24,0x25,0x26,0x27,0x20,0x21,0x22,0x23,0x2c,0x2d,0x2e,0x2f,0x28,0x29,0x2a,0x2b, - 0x34,0x35,0x36,0x37,0x30,0x31,0x32,0x33,0x3c,0x3d,0x3e,0x3f,0x38,0x39,0x3a,0x3b, - 0x04,0x05,0x06,0x07,0x00,0x01,0x02,0x03,0x0c,0x0d,0x0e,0x0f,0x08,0x09,0x0a,0x0b, - 0x14,0x15,0x16,0x17,0x10,0x11,0x12,0x13,0x1c,0x1d,0x1e,0x1f,0x18,0x19,0x1a,0x1b, - 0x3a,0x3b,0x38,0x39,0x3e,0x3f,0x3c,0x3d,0x32,0x33,0x30,0x31,0x36,0x37,0x34,0x35, - 0x2a,0x2b,0x28,0x29,0x2e,0x2f,0x2c,0x2d,0x22,0x23,0x20,0x21,0x26,0x27,0x24,0x25, - 0x1a,0x1b,0x18,0x19,0x1e,0x1f,0x1c,0x1d,0x12,0x13,0x10,0x11,0x16,0x17,0x14,0x15, - 0x0a,0x0b,0x08,0x09,0x0e,0x0f,0x0c,0x0d,0x02,0x03,0x00,0x01,0x06,0x07,0x04,0x05, - 0x15,0x14,0x17,0x16,0x11,0x10,0x13,0x12,0x1d,0x1c,0x1f,0x1e,0x19,0x18,0x1b,0x1a, - 0x05,0x04,0x07,0x06,0x01,0x00,0x03,0x02,0x0d,0x0c,0x0f,0x0e,0x09,0x08,0x0b,0x0a, - 0x35,0x34,0x37,0x36,0x31,0x30,0x33,0x32,0x3d,0x3c,0x3f,0x3e,0x39,0x38,0x3b,0x3a, - 0x25,0x24,0x27,0x26,0x21,0x20,0x23,0x22,0x2d,0x2c,0x2f,0x2e,0x29,0x28,0x2b,0x2a, - 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27, - 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37, - 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, - 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, - 0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08, - 0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10,0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18, - 0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20,0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28, - 0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x30,0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38, - 0x19,0x18,0x1b,0x1a,0x1d,0x1c,0x1f,0x1e,0x11,0x10,0x13,0x12,0x15,0x14,0x17,0x16, - 0x09,0x08,0x0b,0x0a,0x0d,0x0c,0x0f,0x0e,0x01,0x00,0x03,0x02,0x05,0x04,0x07,0x06, - 0x39,0x38,0x3b,0x3a,0x3d,0x3c,0x3f,0x3e,0x31,0x30,0x33,0x32,0x35,0x34,0x37,0x36, - 0x29,0x28,0x2b,0x2a,0x2d,0x2c,0x2f,0x2e,0x21,0x20,0x23,0x22,0x25,0x24,0x27,0x26, - 0x36,0x37,0x34,0x35,0x32,0x33,0x30,0x31,0x3e,0x3f,0x3c,0x3d,0x3a,0x3b,0x38,0x39, - 0x26,0x27,0x24,0x25,0x22,0x23,0x20,0x21,0x2e,0x2f,0x2c,0x2d,0x2a,0x2b,0x28,0x29, - 0x16,0x17,0x14,0x15,0x12,0x13,0x10,0x11,0x1e,0x1f,0x1c,0x1d,0x1a,0x1b,0x18,0x19, - 0x06,0x07,0x04,0x05,0x02,0x03,0x00,0x01,0x0e,0x0f,0x0c,0x0d,0x0a,0x0b,0x08,0x09, - 0x25,0x24,0x27,0x26,0x21,0x20,0x23,0x22,0x2d,0x2c,0x2f,0x2e,0x29,0x28,0x2b,0x2a, - 0x35,0x34,0x37,0x36,0x31,0x30,0x33,0x32,0x3d,0x3c,0x3f,0x3e,0x39,0x38,0x3b,0x3a, - 0x05,0x04,0x07,0x06,0x01,0x00,0x03,0x02,0x0d,0x0c,0x0f,0x0e,0x09,0x08,0x0b,0x0a, - 0x15,0x14,0x17,0x16,0x11,0x10,0x13,0x12,0x1d,0x1c,0x1f,0x1e,0x19,0x18,0x1b,0x1a, - 0x0a,0x0b,0x08,0x09,0x0e,0x0f,0x0c,0x0d,0x02,0x03,0x00,0x01,0x06,0x07,0x04,0x05, - 0x1a,0x1b,0x18,0x19,0x1e,0x1f,0x1c,0x1d,0x12,0x13,0x10,0x11,0x16,0x17,0x14,0x15, - 0x2a,0x2b,0x28,0x29,0x2e,0x2f,0x2c,0x2d,0x22,0x23,0x20,0x21,0x26,0x27,0x24,0x25, - 0x3a,0x3b,0x38,0x39,0x3e,0x3f,0x3c,0x3d,0x32,0x33,0x30,0x31,0x36,0x37,0x34,0x35, - 0x14,0x15,0x16,0x17,0x10,0x11,0x12,0x13,0x1c,0x1d,0x1e,0x1f,0x18,0x19,0x1a,0x1b, - 0x04,0x05,0x06,0x07,0x00,0x01,0x02,0x03,0x0c,0x0d,0x0e,0x0f,0x08,0x09,0x0a,0x0b, - 0x34,0x35,0x36,0x37,0x30,0x31,0x32,0x33,0x3c,0x3d,0x3e,0x3f,0x38,0x39,0x3a,0x3b, - 0x24,0x25,0x26,0x27,0x20,0x21,0x22,0x23,0x2c,0x2d,0x2e,0x2f,0x28,0x29,0x2a,0x2b, - 0x3b,0x3a,0x39,0x38,0x3f,0x3e,0x3d,0x3c,0x33,0x32,0x31,0x30,0x37,0x36,0x35,0x34, - 0x2b,0x2a,0x29,0x28,0x2f,0x2e,0x2d,0x2c,0x23,0x22,0x21,0x20,0x27,0x26,0x25,0x24, - 0x1b,0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c,0x13,0x12,0x11,0x10,0x17,0x16,0x15,0x14, - 0x0b,0x0a,0x09,0x08,0x0f,0x0e,0x0d,0x0c,0x03,0x02,0x01,0x00,0x07,0x06,0x05,0x04, - 0x32,0x33,0x30,0x31,0x36,0x37,0x34,0x35,0x3a,0x3b,0x38,0x39,0x3e,0x3f,0x3c,0x3d, - 0x22,0x23,0x20,0x21,0x26,0x27,0x24,0x25,0x2a,0x2b,0x28,0x29,0x2e,0x2f,0x2c,0x2d, - 0x12,0x13,0x10,0x11,0x16,0x17,0x14,0x15,0x1a,0x1b,0x18,0x19,0x1e,0x1f,0x1c,0x1d, - 0x02,0x03,0x00,0x01,0x06,0x07,0x04,0x05,0x0a,0x0b,0x08,0x09,0x0e,0x0f,0x0c,0x0d, - 0x1d,0x1c,0x1f,0x1e,0x19,0x18,0x1b,0x1a,0x15,0x14,0x17,0x16,0x11,0x10,0x13,0x12, - 0x0d,0x0c,0x0f,0x0e,0x09,0x08,0x0b,0x0a,0x05,0x04,0x07,0x06,0x01,0x00,0x03,0x02, - 0x3d,0x3c,0x3f,0x3e,0x39,0x38,0x3b,0x3a,0x35,0x34,0x37,0x36,0x31,0x30,0x33,0x32, - 0x2d,0x2c,0x2f,0x2e,0x29,0x28,0x2b,0x2a,0x25,0x24,0x27,0x26,0x21,0x20,0x23,0x22, - 0x03,0x02,0x01,0x00,0x07,0x06,0x05,0x04,0x0b,0x0a,0x09,0x08,0x0f,0x0e,0x0d,0x0c, - 0x13,0x12,0x11,0x10,0x17,0x16,0x15,0x14,0x1b,0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c, - 0x23,0x22,0x21,0x20,0x27,0x26,0x25,0x24,0x2b,0x2a,0x29,0x28,0x2f,0x2e,0x2d,0x2c, - 0x33,0x32,0x31,0x30,0x37,0x36,0x35,0x34,0x3b,0x3a,0x39,0x38,0x3f,0x3e,0x3d,0x3c, - 0x2c,0x2d,0x2e,0x2f,0x28,0x29,0x2a,0x2b,0x24,0x25,0x26,0x27,0x20,0x21,0x22,0x23, - 0x3c,0x3d,0x3e,0x3f,0x38,0x39,0x3a,0x3b,0x34,0x35,0x36,0x37,0x30,0x31,0x32,0x33, - 0x0c,0x0d,0x0e,0x0f,0x08,0x09,0x0a,0x0b,0x04,0x05,0x06,0x07,0x00,0x01,0x02,0x03, - 0x1c,0x1d,0x1e,0x1f,0x18,0x19,0x1a,0x1b,0x14,0x15,0x16,0x17,0x10,0x11,0x12,0x13, - 0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38,0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x30, - 0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28,0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20, - 0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18,0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10, - 0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00, - 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f, - 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, - 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, - 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, - 0x0e,0x0f,0x0c,0x0d,0x0a,0x0b,0x08,0x09,0x06,0x07,0x04,0x05,0x02,0x03,0x00,0x01, - 0x1e,0x1f,0x1c,0x1d,0x1a,0x1b,0x18,0x19,0x16,0x17,0x14,0x15,0x12,0x13,0x10,0x11, - 0x2e,0x2f,0x2c,0x2d,0x2a,0x2b,0x28,0x29,0x26,0x27,0x24,0x25,0x22,0x23,0x20,0x21, - 0x3e,0x3f,0x3c,0x3d,0x3a,0x3b,0x38,0x39,0x36,0x37,0x34,0x35,0x32,0x33,0x30,0x31, - 0x21,0x20,0x23,0x22,0x25,0x24,0x27,0x26,0x29,0x28,0x2b,0x2a,0x2d,0x2c,0x2f,0x2e, - 0x31,0x30,0x33,0x32,0x35,0x34,0x37,0x36,0x39,0x38,0x3b,0x3a,0x3d,0x3c,0x3f,0x3e, - 0x01,0x00,0x03,0x02,0x05,0x04,0x07,0x06,0x09,0x08,0x0b,0x0a,0x0d,0x0c,0x0f,0x0e, - 0x11,0x10,0x13,0x12,0x15,0x14,0x17,0x16,0x19,0x18,0x1b,0x1a,0x1d,0x1c,0x1f,0x1e, - 0x1b,0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c,0x13,0x12,0x11,0x10,0x17,0x16,0x15,0x14, - 0x0b,0x0a,0x09,0x08,0x0f,0x0e,0x0d,0x0c,0x03,0x02,0x01,0x00,0x07,0x06,0x05,0x04, - 0x3b,0x3a,0x39,0x38,0x3f,0x3e,0x3d,0x3c,0x33,0x32,0x31,0x30,0x37,0x36,0x35,0x34, - 0x2b,0x2a,0x29,0x28,0x2f,0x2e,0x2d,0x2c,0x23,0x22,0x21,0x20,0x27,0x26,0x25,0x24, - 0x34,0x35,0x36,0x37,0x30,0x31,0x32,0x33,0x3c,0x3d,0x3e,0x3f,0x38,0x39,0x3a,0x3b, - 0x24,0x25,0x26,0x27,0x20,0x21,0x22,0x23,0x2c,0x2d,0x2e,0x2f,0x28,0x29,0x2a,0x2b, - 0x14,0x15,0x16,0x17,0x10,0x11,0x12,0x13,0x1c,0x1d,0x1e,0x1f,0x18,0x19,0x1a,0x1b, - 0x04,0x05,0x06,0x07,0x00,0x01,0x02,0x03,0x0c,0x0d,0x0e,0x0f,0x08,0x09,0x0a,0x0b, - 0x2a,0x2b,0x28,0x29,0x2e,0x2f,0x2c,0x2d,0x22,0x23,0x20,0x21,0x26,0x27,0x24,0x25, - 0x3a,0x3b,0x38,0x39,0x3e,0x3f,0x3c,0x3d,0x32,0x33,0x30,0x31,0x36,0x37,0x34,0x35, - 0x0a,0x0b,0x08,0x09,0x0e,0x0f,0x0c,0x0d,0x02,0x03,0x00,0x01,0x06,0x07,0x04,0x05, - 0x1a,0x1b,0x18,0x19,0x1e,0x1f,0x1c,0x1d,0x12,0x13,0x10,0x11,0x16,0x17,0x14,0x15, - 0x05,0x04,0x07,0x06,0x01,0x00,0x03,0x02,0x0d,0x0c,0x0f,0x0e,0x09,0x08,0x0b,0x0a, - 0x15,0x14,0x17,0x16,0x11,0x10,0x13,0x12,0x1d,0x1c,0x1f,0x1e,0x19,0x18,0x1b,0x1a, - 0x25,0x24,0x27,0x26,0x21,0x20,0x23,0x22,0x2d,0x2c,0x2f,0x2e,0x29,0x28,0x2b,0x2a, - 0x35,0x34,0x37,0x36,0x31,0x30,0x33,0x32,0x3d,0x3c,0x3f,0x3e,0x39,0x38,0x3b,0x3a, - 0x16,0x17,0x14,0x15,0x12,0x13,0x10,0x11,0x1e,0x1f,0x1c,0x1d,0x1a,0x1b,0x18,0x19, - 0x06,0x07,0x04,0x05,0x02,0x03,0x00,0x01,0x0e,0x0f,0x0c,0x0d,0x0a,0x0b,0x08,0x09, - 0x36,0x37,0x34,0x35,0x32,0x33,0x30,0x31,0x3e,0x3f,0x3c,0x3d,0x3a,0x3b,0x38,0x39, - 0x26,0x27,0x24,0x25,0x22,0x23,0x20,0x21,0x2e,0x2f,0x2c,0x2d,0x2a,0x2b,0x28,0x29, - 0x39,0x38,0x3b,0x3a,0x3d,0x3c,0x3f,0x3e,0x31,0x30,0x33,0x32,0x35,0x34,0x37,0x36, - 0x29,0x28,0x2b,0x2a,0x2d,0x2c,0x2f,0x2e,0x21,0x20,0x23,0x22,0x25,0x24,0x27,0x26, - 0x19,0x18,0x1b,0x1a,0x1d,0x1c,0x1f,0x1e,0x11,0x10,0x13,0x12,0x15,0x14,0x17,0x16, - 0x09,0x08,0x0b,0x0a,0x0d,0x0c,0x0f,0x0e,0x01,0x00,0x03,0x02,0x05,0x04,0x07,0x06, - 0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20,0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28, - 0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x30,0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38, - 0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08, - 0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10,0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18, - 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, - 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, - 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27, - 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37, - 0x01,0x00,0x03,0x02,0x05,0x04,0x07,0x06,0x09,0x08,0x0b,0x0a,0x0d,0x0c,0x0f,0x0e, - 0x11,0x10,0x13,0x12,0x15,0x14,0x17,0x16,0x19,0x18,0x1b,0x1a,0x1d,0x1c,0x1f,0x1e, - 0x21,0x20,0x23,0x22,0x25,0x24,0x27,0x26,0x29,0x28,0x2b,0x2a,0x2d,0x2c,0x2f,0x2e, - 0x31,0x30,0x33,0x32,0x35,0x34,0x37,0x36,0x39,0x38,0x3b,0x3a,0x3d,0x3c,0x3f,0x3e, - 0x2e,0x2f,0x2c,0x2d,0x2a,0x2b,0x28,0x29,0x26,0x27,0x24,0x25,0x22,0x23,0x20,0x21, - 0x3e,0x3f,0x3c,0x3d,0x3a,0x3b,0x38,0x39,0x36,0x37,0x34,0x35,0x32,0x33,0x30,0x31, - 0x0e,0x0f,0x0c,0x0d,0x0a,0x0b,0x08,0x09,0x06,0x07,0x04,0x05,0x02,0x03,0x00,0x01, - 0x1e,0x1f,0x1c,0x1d,0x1a,0x1b,0x18,0x19,0x16,0x17,0x14,0x15,0x12,0x13,0x10,0x11, - 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, - 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, - 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f, - 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, - 0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18,0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10, - 0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00, - 0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38,0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x30, - 0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28,0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20, - 0x0c,0x0d,0x0e,0x0f,0x08,0x09,0x0a,0x0b,0x04,0x05,0x06,0x07,0x00,0x01,0x02,0x03, - 0x1c,0x1d,0x1e,0x1f,0x18,0x19,0x1a,0x1b,0x14,0x15,0x16,0x17,0x10,0x11,0x12,0x13, - 0x2c,0x2d,0x2e,0x2f,0x28,0x29,0x2a,0x2b,0x24,0x25,0x26,0x27,0x20,0x21,0x22,0x23, - 0x3c,0x3d,0x3e,0x3f,0x38,0x39,0x3a,0x3b,0x34,0x35,0x36,0x37,0x30,0x31,0x32,0x33, - 0x23,0x22,0x21,0x20,0x27,0x26,0x25,0x24,0x2b,0x2a,0x29,0x28,0x2f,0x2e,0x2d,0x2c, - 0x33,0x32,0x31,0x30,0x37,0x36,0x35,0x34,0x3b,0x3a,0x39,0x38,0x3f,0x3e,0x3d,0x3c, - 0x03,0x02,0x01,0x00,0x07,0x06,0x05,0x04,0x0b,0x0a,0x09,0x08,0x0f,0x0e,0x0d,0x0c, - 0x13,0x12,0x11,0x10,0x17,0x16,0x15,0x14,0x1b,0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c, - 0x3d,0x3c,0x3f,0x3e,0x39,0x38,0x3b,0x3a,0x35,0x34,0x37,0x36,0x31,0x30,0x33,0x32, - 0x2d,0x2c,0x2f,0x2e,0x29,0x28,0x2b,0x2a,0x25,0x24,0x27,0x26,0x21,0x20,0x23,0x22, - 0x1d,0x1c,0x1f,0x1e,0x19,0x18,0x1b,0x1a,0x15,0x14,0x17,0x16,0x11,0x10,0x13,0x12, - 0x0d,0x0c,0x0f,0x0e,0x09,0x08,0x0b,0x0a,0x05,0x04,0x07,0x06,0x01,0x00,0x03,0x02, - 0x12,0x13,0x10,0x11,0x16,0x17,0x14,0x15,0x1a,0x1b,0x18,0x19,0x1e,0x1f,0x1c,0x1d, - 0x02,0x03,0x00,0x01,0x06,0x07,0x04,0x05,0x0a,0x0b,0x08,0x09,0x0e,0x0f,0x0c,0x0d, - 0x32,0x33,0x30,0x31,0x36,0x37,0x34,0x35,0x3a,0x3b,0x38,0x39,0x3e,0x3f,0x3c,0x3d, - 0x22,0x23,0x20,0x21,0x26,0x27,0x24,0x25,0x2a,0x2b,0x28,0x29,0x2e,0x2f,0x2c,0x2d, - 0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28,0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20, - 0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38,0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x30, - 0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00, - 0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18,0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10, - 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, - 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f, - 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, - 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, - 0x1e,0x1f,0x1c,0x1d,0x1a,0x1b,0x18,0x19,0x16,0x17,0x14,0x15,0x12,0x13,0x10,0x11, - 0x0e,0x0f,0x0c,0x0d,0x0a,0x0b,0x08,0x09,0x06,0x07,0x04,0x05,0x02,0x03,0x00,0x01, - 0x3e,0x3f,0x3c,0x3d,0x3a,0x3b,0x38,0x39,0x36,0x37,0x34,0x35,0x32,0x33,0x30,0x31, - 0x2e,0x2f,0x2c,0x2d,0x2a,0x2b,0x28,0x29,0x26,0x27,0x24,0x25,0x22,0x23,0x20,0x21, - 0x31,0x30,0x33,0x32,0x35,0x34,0x37,0x36,0x39,0x38,0x3b,0x3a,0x3d,0x3c,0x3f,0x3e, - 0x21,0x20,0x23,0x22,0x25,0x24,0x27,0x26,0x29,0x28,0x2b,0x2a,0x2d,0x2c,0x2f,0x2e, - 0x11,0x10,0x13,0x12,0x15,0x14,0x17,0x16,0x19,0x18,0x1b,0x1a,0x1d,0x1c,0x1f,0x1e, - 0x01,0x00,0x03,0x02,0x05,0x04,0x07,0x06,0x09,0x08,0x0b,0x0a,0x0d,0x0c,0x0f,0x0e, - 0x22,0x23,0x20,0x21,0x26,0x27,0x24,0x25,0x2a,0x2b,0x28,0x29,0x2e,0x2f,0x2c,0x2d, - 0x32,0x33,0x30,0x31,0x36,0x37,0x34,0x35,0x3a,0x3b,0x38,0x39,0x3e,0x3f,0x3c,0x3d, - 0x02,0x03,0x00,0x01,0x06,0x07,0x04,0x05,0x0a,0x0b,0x08,0x09,0x0e,0x0f,0x0c,0x0d, - 0x12,0x13,0x10,0x11,0x16,0x17,0x14,0x15,0x1a,0x1b,0x18,0x19,0x1e,0x1f,0x1c,0x1d, - 0x0d,0x0c,0x0f,0x0e,0x09,0x08,0x0b,0x0a,0x05,0x04,0x07,0x06,0x01,0x00,0x03,0x02, - 0x1d,0x1c,0x1f,0x1e,0x19,0x18,0x1b,0x1a,0x15,0x14,0x17,0x16,0x11,0x10,0x13,0x12, - 0x2d,0x2c,0x2f,0x2e,0x29,0x28,0x2b,0x2a,0x25,0x24,0x27,0x26,0x21,0x20,0x23,0x22, - 0x3d,0x3c,0x3f,0x3e,0x39,0x38,0x3b,0x3a,0x35,0x34,0x37,0x36,0x31,0x30,0x33,0x32, - 0x13,0x12,0x11,0x10,0x17,0x16,0x15,0x14,0x1b,0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c, - 0x03,0x02,0x01,0x00,0x07,0x06,0x05,0x04,0x0b,0x0a,0x09,0x08,0x0f,0x0e,0x0d,0x0c, - 0x33,0x32,0x31,0x30,0x37,0x36,0x35,0x34,0x3b,0x3a,0x39,0x38,0x3f,0x3e,0x3d,0x3c, - 0x23,0x22,0x21,0x20,0x27,0x26,0x25,0x24,0x2b,0x2a,0x29,0x28,0x2f,0x2e,0x2d,0x2c, - 0x3c,0x3d,0x3e,0x3f,0x38,0x39,0x3a,0x3b,0x34,0x35,0x36,0x37,0x30,0x31,0x32,0x33, - 0x2c,0x2d,0x2e,0x2f,0x28,0x29,0x2a,0x2b,0x24,0x25,0x26,0x27,0x20,0x21,0x22,0x23, - 0x1c,0x1d,0x1e,0x1f,0x18,0x19,0x1a,0x1b,0x14,0x15,0x16,0x17,0x10,0x11,0x12,0x13, - 0x0c,0x0d,0x0e,0x0f,0x08,0x09,0x0a,0x0b,0x04,0x05,0x06,0x07,0x00,0x01,0x02,0x03, - 0x35,0x34,0x37,0x36,0x31,0x30,0x33,0x32,0x3d,0x3c,0x3f,0x3e,0x39,0x38,0x3b,0x3a, - 0x25,0x24,0x27,0x26,0x21,0x20,0x23,0x22,0x2d,0x2c,0x2f,0x2e,0x29,0x28,0x2b,0x2a, - 0x15,0x14,0x17,0x16,0x11,0x10,0x13,0x12,0x1d,0x1c,0x1f,0x1e,0x19,0x18,0x1b,0x1a, - 0x05,0x04,0x07,0x06,0x01,0x00,0x03,0x02,0x0d,0x0c,0x0f,0x0e,0x09,0x08,0x0b,0x0a, - 0x1a,0x1b,0x18,0x19,0x1e,0x1f,0x1c,0x1d,0x12,0x13,0x10,0x11,0x16,0x17,0x14,0x15, - 0x0a,0x0b,0x08,0x09,0x0e,0x0f,0x0c,0x0d,0x02,0x03,0x00,0x01,0x06,0x07,0x04,0x05, - 0x3a,0x3b,0x38,0x39,0x3e,0x3f,0x3c,0x3d,0x32,0x33,0x30,0x31,0x36,0x37,0x34,0x35, - 0x2a,0x2b,0x28,0x29,0x2e,0x2f,0x2c,0x2d,0x22,0x23,0x20,0x21,0x26,0x27,0x24,0x25, - 0x04,0x05,0x06,0x07,0x00,0x01,0x02,0x03,0x0c,0x0d,0x0e,0x0f,0x08,0x09,0x0a,0x0b, - 0x14,0x15,0x16,0x17,0x10,0x11,0x12,0x13,0x1c,0x1d,0x1e,0x1f,0x18,0x19,0x1a,0x1b, - 0x24,0x25,0x26,0x27,0x20,0x21,0x22,0x23,0x2c,0x2d,0x2e,0x2f,0x28,0x29,0x2a,0x2b, - 0x34,0x35,0x36,0x37,0x30,0x31,0x32,0x33,0x3c,0x3d,0x3e,0x3f,0x38,0x39,0x3a,0x3b, - 0x2b,0x2a,0x29,0x28,0x2f,0x2e,0x2d,0x2c,0x23,0x22,0x21,0x20,0x27,0x26,0x25,0x24, - 0x3b,0x3a,0x39,0x38,0x3f,0x3e,0x3d,0x3c,0x33,0x32,0x31,0x30,0x37,0x36,0x35,0x34, - 0x0b,0x0a,0x09,0x08,0x0f,0x0e,0x0d,0x0c,0x03,0x02,0x01,0x00,0x07,0x06,0x05,0x04, - 0x1b,0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c,0x13,0x12,0x11,0x10,0x17,0x16,0x15,0x14, - 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37, - 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27, - 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, - 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, - 0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10,0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18, - 0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08, - 0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x30,0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38, - 0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20,0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28, - 0x09,0x08,0x0b,0x0a,0x0d,0x0c,0x0f,0x0e,0x01,0x00,0x03,0x02,0x05,0x04,0x07,0x06, - 0x19,0x18,0x1b,0x1a,0x1d,0x1c,0x1f,0x1e,0x11,0x10,0x13,0x12,0x15,0x14,0x17,0x16, - 0x29,0x28,0x2b,0x2a,0x2d,0x2c,0x2f,0x2e,0x21,0x20,0x23,0x22,0x25,0x24,0x27,0x26, - 0x39,0x38,0x3b,0x3a,0x3d,0x3c,0x3f,0x3e,0x31,0x30,0x33,0x32,0x35,0x34,0x37,0x36, - 0x26,0x27,0x24,0x25,0x22,0x23,0x20,0x21,0x2e,0x2f,0x2c,0x2d,0x2a,0x2b,0x28,0x29, - 0x36,0x37,0x34,0x35,0x32,0x33,0x30,0x31,0x3e,0x3f,0x3c,0x3d,0x3a,0x3b,0x38,0x39, - 0x06,0x07,0x04,0x05,0x02,0x03,0x00,0x01,0x0e,0x0f,0x0c,0x0d,0x0a,0x0b,0x08,0x09, - 0x16,0x17,0x14,0x15,0x12,0x13,0x10,0x11,0x1e,0x1f,0x1c,0x1d,0x1a,0x1b,0x18,0x19, - 0x12,0x13,0x10,0x11,0x16,0x17,0x14,0x15,0x1a,0x1b,0x18,0x19,0x1e,0x1f,0x1c,0x1d, - 0x02,0x03,0x00,0x01,0x06,0x07,0x04,0x05,0x0a,0x0b,0x08,0x09,0x0e,0x0f,0x0c,0x0d, - 0x32,0x33,0x30,0x31,0x36,0x37,0x34,0x35,0x3a,0x3b,0x38,0x39,0x3e,0x3f,0x3c,0x3d, - 0x22,0x23,0x20,0x21,0x26,0x27,0x24,0x25,0x2a,0x2b,0x28,0x29,0x2e,0x2f,0x2c,0x2d, - 0x3d,0x3c,0x3f,0x3e,0x39,0x38,0x3b,0x3a,0x35,0x34,0x37,0x36,0x31,0x30,0x33,0x32, - 0x2d,0x2c,0x2f,0x2e,0x29,0x28,0x2b,0x2a,0x25,0x24,0x27,0x26,0x21,0x20,0x23,0x22, - 0x1d,0x1c,0x1f,0x1e,0x19,0x18,0x1b,0x1a,0x15,0x14,0x17,0x16,0x11,0x10,0x13,0x12, - 0x0d,0x0c,0x0f,0x0e,0x09,0x08,0x0b,0x0a,0x05,0x04,0x07,0x06,0x01,0x00,0x03,0x02, - 0x23,0x22,0x21,0x20,0x27,0x26,0x25,0x24,0x2b,0x2a,0x29,0x28,0x2f,0x2e,0x2d,0x2c, - 0x33,0x32,0x31,0x30,0x37,0x36,0x35,0x34,0x3b,0x3a,0x39,0x38,0x3f,0x3e,0x3d,0x3c, - 0x03,0x02,0x01,0x00,0x07,0x06,0x05,0x04,0x0b,0x0a,0x09,0x08,0x0f,0x0e,0x0d,0x0c, - 0x13,0x12,0x11,0x10,0x17,0x16,0x15,0x14,0x1b,0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c, - 0x0c,0x0d,0x0e,0x0f,0x08,0x09,0x0a,0x0b,0x04,0x05,0x06,0x07,0x00,0x01,0x02,0x03, - 0x1c,0x1d,0x1e,0x1f,0x18,0x19,0x1a,0x1b,0x14,0x15,0x16,0x17,0x10,0x11,0x12,0x13, - 0x2c,0x2d,0x2e,0x2f,0x28,0x29,0x2a,0x2b,0x24,0x25,0x26,0x27,0x20,0x21,0x22,0x23, - 0x3c,0x3d,0x3e,0x3f,0x38,0x39,0x3a,0x3b,0x34,0x35,0x36,0x37,0x30,0x31,0x32,0x33, - 0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18,0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10, - 0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00, - 0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38,0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x30, - 0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28,0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20, - 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, - 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, - 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f, - 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, - 0x2e,0x2f,0x2c,0x2d,0x2a,0x2b,0x28,0x29,0x26,0x27,0x24,0x25,0x22,0x23,0x20,0x21, - 0x3e,0x3f,0x3c,0x3d,0x3a,0x3b,0x38,0x39,0x36,0x37,0x34,0x35,0x32,0x33,0x30,0x31, - 0x0e,0x0f,0x0c,0x0d,0x0a,0x0b,0x08,0x09,0x06,0x07,0x04,0x05,0x02,0x03,0x00,0x01, - 0x1e,0x1f,0x1c,0x1d,0x1a,0x1b,0x18,0x19,0x16,0x17,0x14,0x15,0x12,0x13,0x10,0x11, - 0x01,0x00,0x03,0x02,0x05,0x04,0x07,0x06,0x09,0x08,0x0b,0x0a,0x0d,0x0c,0x0f,0x0e, - 0x11,0x10,0x13,0x12,0x15,0x14,0x17,0x16,0x19,0x18,0x1b,0x1a,0x1d,0x1c,0x1f,0x1e, - 0x21,0x20,0x23,0x22,0x25,0x24,0x27,0x26,0x29,0x28,0x2b,0x2a,0x2d,0x2c,0x2f,0x2e, - 0x31,0x30,0x33,0x32,0x35,0x34,0x37,0x36,0x39,0x38,0x3b,0x3a,0x3d,0x3c,0x3f,0x3e, - 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, - 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, - 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27, - 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37, - 0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20,0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28, - 0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x30,0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38, - 0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08, - 0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10,0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18, - 0x39,0x38,0x3b,0x3a,0x3d,0x3c,0x3f,0x3e,0x31,0x30,0x33,0x32,0x35,0x34,0x37,0x36, - 0x29,0x28,0x2b,0x2a,0x2d,0x2c,0x2f,0x2e,0x21,0x20,0x23,0x22,0x25,0x24,0x27,0x26, - 0x19,0x18,0x1b,0x1a,0x1d,0x1c,0x1f,0x1e,0x11,0x10,0x13,0x12,0x15,0x14,0x17,0x16, - 0x09,0x08,0x0b,0x0a,0x0d,0x0c,0x0f,0x0e,0x01,0x00,0x03,0x02,0x05,0x04,0x07,0x06, - 0x16,0x17,0x14,0x15,0x12,0x13,0x10,0x11,0x1e,0x1f,0x1c,0x1d,0x1a,0x1b,0x18,0x19, - 0x06,0x07,0x04,0x05,0x02,0x03,0x00,0x01,0x0e,0x0f,0x0c,0x0d,0x0a,0x0b,0x08,0x09, - 0x36,0x37,0x34,0x35,0x32,0x33,0x30,0x31,0x3e,0x3f,0x3c,0x3d,0x3a,0x3b,0x38,0x39, - 0x26,0x27,0x24,0x25,0x22,0x23,0x20,0x21,0x2e,0x2f,0x2c,0x2d,0x2a,0x2b,0x28,0x29, - 0x05,0x04,0x07,0x06,0x01,0x00,0x03,0x02,0x0d,0x0c,0x0f,0x0e,0x09,0x08,0x0b,0x0a, - 0x15,0x14,0x17,0x16,0x11,0x10,0x13,0x12,0x1d,0x1c,0x1f,0x1e,0x19,0x18,0x1b,0x1a, - 0x25,0x24,0x27,0x26,0x21,0x20,0x23,0x22,0x2d,0x2c,0x2f,0x2e,0x29,0x28,0x2b,0x2a, - 0x35,0x34,0x37,0x36,0x31,0x30,0x33,0x32,0x3d,0x3c,0x3f,0x3e,0x39,0x38,0x3b,0x3a, - 0x2a,0x2b,0x28,0x29,0x2e,0x2f,0x2c,0x2d,0x22,0x23,0x20,0x21,0x26,0x27,0x24,0x25, - 0x3a,0x3b,0x38,0x39,0x3e,0x3f,0x3c,0x3d,0x32,0x33,0x30,0x31,0x36,0x37,0x34,0x35, - 0x0a,0x0b,0x08,0x09,0x0e,0x0f,0x0c,0x0d,0x02,0x03,0x00,0x01,0x06,0x07,0x04,0x05, - 0x1a,0x1b,0x18,0x19,0x1e,0x1f,0x1c,0x1d,0x12,0x13,0x10,0x11,0x16,0x17,0x14,0x15, - 0x34,0x35,0x36,0x37,0x30,0x31,0x32,0x33,0x3c,0x3d,0x3e,0x3f,0x38,0x39,0x3a,0x3b, - 0x24,0x25,0x26,0x27,0x20,0x21,0x22,0x23,0x2c,0x2d,0x2e,0x2f,0x28,0x29,0x2a,0x2b, - 0x14,0x15,0x16,0x17,0x10,0x11,0x12,0x13,0x1c,0x1d,0x1e,0x1f,0x18,0x19,0x1a,0x1b, - 0x04,0x05,0x06,0x07,0x00,0x01,0x02,0x03,0x0c,0x0d,0x0e,0x0f,0x08,0x09,0x0a,0x0b, - 0x1b,0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c,0x13,0x12,0x11,0x10,0x17,0x16,0x15,0x14, - 0x0b,0x0a,0x09,0x08,0x0f,0x0e,0x0d,0x0c,0x03,0x02,0x01,0x00,0x07,0x06,0x05,0x04, - 0x3b,0x3a,0x39,0x38,0x3f,0x3e,0x3d,0x3c,0x33,0x32,0x31,0x30,0x37,0x36,0x35,0x34, - 0x2b,0x2a,0x29,0x28,0x2f,0x2e,0x2d,0x2c,0x23,0x22,0x21,0x20,0x27,0x26,0x25,0x24, - 0x26,0x27,0x24,0x25,0x22,0x23,0x20,0x21,0x2e,0x2f,0x2c,0x2d,0x2a,0x2b,0x28,0x29, - 0x36,0x37,0x34,0x35,0x32,0x33,0x30,0x31,0x3e,0x3f,0x3c,0x3d,0x3a,0x3b,0x38,0x39, - 0x06,0x07,0x04,0x05,0x02,0x03,0x00,0x01,0x0e,0x0f,0x0c,0x0d,0x0a,0x0b,0x08,0x09, - 0x16,0x17,0x14,0x15,0x12,0x13,0x10,0x11,0x1e,0x1f,0x1c,0x1d,0x1a,0x1b,0x18,0x19, - 0x09,0x08,0x0b,0x0a,0x0d,0x0c,0x0f,0x0e,0x01,0x00,0x03,0x02,0x05,0x04,0x07,0x06, - 0x19,0x18,0x1b,0x1a,0x1d,0x1c,0x1f,0x1e,0x11,0x10,0x13,0x12,0x15,0x14,0x17,0x16, - 0x29,0x28,0x2b,0x2a,0x2d,0x2c,0x2f,0x2e,0x21,0x20,0x23,0x22,0x25,0x24,0x27,0x26, - 0x39,0x38,0x3b,0x3a,0x3d,0x3c,0x3f,0x3e,0x31,0x30,0x33,0x32,0x35,0x34,0x37,0x36, - 0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10,0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18, - 0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08, - 0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x30,0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38, - 0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20,0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28, - 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37, - 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27, - 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, - 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, - 0x2b,0x2a,0x29,0x28,0x2f,0x2e,0x2d,0x2c,0x23,0x22,0x21,0x20,0x27,0x26,0x25,0x24, - 0x3b,0x3a,0x39,0x38,0x3f,0x3e,0x3d,0x3c,0x33,0x32,0x31,0x30,0x37,0x36,0x35,0x34, - 0x0b,0x0a,0x09,0x08,0x0f,0x0e,0x0d,0x0c,0x03,0x02,0x01,0x00,0x07,0x06,0x05,0x04, - 0x1b,0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c,0x13,0x12,0x11,0x10,0x17,0x16,0x15,0x14, - 0x04,0x05,0x06,0x07,0x00,0x01,0x02,0x03,0x0c,0x0d,0x0e,0x0f,0x08,0x09,0x0a,0x0b, - 0x14,0x15,0x16,0x17,0x10,0x11,0x12,0x13,0x1c,0x1d,0x1e,0x1f,0x18,0x19,0x1a,0x1b, - 0x24,0x25,0x26,0x27,0x20,0x21,0x22,0x23,0x2c,0x2d,0x2e,0x2f,0x28,0x29,0x2a,0x2b, - 0x34,0x35,0x36,0x37,0x30,0x31,0x32,0x33,0x3c,0x3d,0x3e,0x3f,0x38,0x39,0x3a,0x3b, - 0x1a,0x1b,0x18,0x19,0x1e,0x1f,0x1c,0x1d,0x12,0x13,0x10,0x11,0x16,0x17,0x14,0x15, - 0x0a,0x0b,0x08,0x09,0x0e,0x0f,0x0c,0x0d,0x02,0x03,0x00,0x01,0x06,0x07,0x04,0x05, - 0x3a,0x3b,0x38,0x39,0x3e,0x3f,0x3c,0x3d,0x32,0x33,0x30,0x31,0x36,0x37,0x34,0x35, - 0x2a,0x2b,0x28,0x29,0x2e,0x2f,0x2c,0x2d,0x22,0x23,0x20,0x21,0x26,0x27,0x24,0x25, - 0x35,0x34,0x37,0x36,0x31,0x30,0x33,0x32,0x3d,0x3c,0x3f,0x3e,0x39,0x38,0x3b,0x3a, - 0x25,0x24,0x27,0x26,0x21,0x20,0x23,0x22,0x2d,0x2c,0x2f,0x2e,0x29,0x28,0x2b,0x2a, - 0x15,0x14,0x17,0x16,0x11,0x10,0x13,0x12,0x1d,0x1c,0x1f,0x1e,0x19,0x18,0x1b,0x1a, - 0x05,0x04,0x07,0x06,0x01,0x00,0x03,0x02,0x0d,0x0c,0x0f,0x0e,0x09,0x08,0x0b,0x0a, - 0x3c,0x3d,0x3e,0x3f,0x38,0x39,0x3a,0x3b,0x34,0x35,0x36,0x37,0x30,0x31,0x32,0x33, - 0x2c,0x2d,0x2e,0x2f,0x28,0x29,0x2a,0x2b,0x24,0x25,0x26,0x27,0x20,0x21,0x22,0x23, - 0x1c,0x1d,0x1e,0x1f,0x18,0x19,0x1a,0x1b,0x14,0x15,0x16,0x17,0x10,0x11,0x12,0x13, - 0x0c,0x0d,0x0e,0x0f,0x08,0x09,0x0a,0x0b,0x04,0x05,0x06,0x07,0x00,0x01,0x02,0x03, - 0x13,0x12,0x11,0x10,0x17,0x16,0x15,0x14,0x1b,0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c, - 0x03,0x02,0x01,0x00,0x07,0x06,0x05,0x04,0x0b,0x0a,0x09,0x08,0x0f,0x0e,0x0d,0x0c, - 0x33,0x32,0x31,0x30,0x37,0x36,0x35,0x34,0x3b,0x3a,0x39,0x38,0x3f,0x3e,0x3d,0x3c, - 0x23,0x22,0x21,0x20,0x27,0x26,0x25,0x24,0x2b,0x2a,0x29,0x28,0x2f,0x2e,0x2d,0x2c, - 0x0d,0x0c,0x0f,0x0e,0x09,0x08,0x0b,0x0a,0x05,0x04,0x07,0x06,0x01,0x00,0x03,0x02, - 0x1d,0x1c,0x1f,0x1e,0x19,0x18,0x1b,0x1a,0x15,0x14,0x17,0x16,0x11,0x10,0x13,0x12, - 0x2d,0x2c,0x2f,0x2e,0x29,0x28,0x2b,0x2a,0x25,0x24,0x27,0x26,0x21,0x20,0x23,0x22, - 0x3d,0x3c,0x3f,0x3e,0x39,0x38,0x3b,0x3a,0x35,0x34,0x37,0x36,0x31,0x30,0x33,0x32, - 0x22,0x23,0x20,0x21,0x26,0x27,0x24,0x25,0x2a,0x2b,0x28,0x29,0x2e,0x2f,0x2c,0x2d, - 0x32,0x33,0x30,0x31,0x36,0x37,0x34,0x35,0x3a,0x3b,0x38,0x39,0x3e,0x3f,0x3c,0x3d, - 0x02,0x03,0x00,0x01,0x06,0x07,0x04,0x05,0x0a,0x0b,0x08,0x09,0x0e,0x0f,0x0c,0x0d, - 0x12,0x13,0x10,0x11,0x16,0x17,0x14,0x15,0x1a,0x1b,0x18,0x19,0x1e,0x1f,0x1c,0x1d, - 0x31,0x30,0x33,0x32,0x35,0x34,0x37,0x36,0x39,0x38,0x3b,0x3a,0x3d,0x3c,0x3f,0x3e, - 0x21,0x20,0x23,0x22,0x25,0x24,0x27,0x26,0x29,0x28,0x2b,0x2a,0x2d,0x2c,0x2f,0x2e, - 0x11,0x10,0x13,0x12,0x15,0x14,0x17,0x16,0x19,0x18,0x1b,0x1a,0x1d,0x1c,0x1f,0x1e, - 0x01,0x00,0x03,0x02,0x05,0x04,0x07,0x06,0x09,0x08,0x0b,0x0a,0x0d,0x0c,0x0f,0x0e, - 0x1e,0x1f,0x1c,0x1d,0x1a,0x1b,0x18,0x19,0x16,0x17,0x14,0x15,0x12,0x13,0x10,0x11, - 0x0e,0x0f,0x0c,0x0d,0x0a,0x0b,0x08,0x09,0x06,0x07,0x04,0x05,0x02,0x03,0x00,0x01, - 0x3e,0x3f,0x3c,0x3d,0x3a,0x3b,0x38,0x39,0x36,0x37,0x34,0x35,0x32,0x33,0x30,0x31, - 0x2e,0x2f,0x2c,0x2d,0x2a,0x2b,0x28,0x29,0x26,0x27,0x24,0x25,0x22,0x23,0x20,0x21, - 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, - 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f, - 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, - 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, - 0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28,0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20, - 0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38,0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x30, - 0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00, - 0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18,0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10, - 0x15,0x14,0x17,0x16,0x11,0x10,0x13,0x12,0x1d,0x1c,0x1f,0x1e,0x19,0x18,0x1b,0x1a, - 0x05,0x04,0x07,0x06,0x01,0x00,0x03,0x02,0x0d,0x0c,0x0f,0x0e,0x09,0x08,0x0b,0x0a, - 0x35,0x34,0x37,0x36,0x31,0x30,0x33,0x32,0x3d,0x3c,0x3f,0x3e,0x39,0x38,0x3b,0x3a, - 0x25,0x24,0x27,0x26,0x21,0x20,0x23,0x22,0x2d,0x2c,0x2f,0x2e,0x29,0x28,0x2b,0x2a, - 0x3a,0x3b,0x38,0x39,0x3e,0x3f,0x3c,0x3d,0x32,0x33,0x30,0x31,0x36,0x37,0x34,0x35, - 0x2a,0x2b,0x28,0x29,0x2e,0x2f,0x2c,0x2d,0x22,0x23,0x20,0x21,0x26,0x27,0x24,0x25, - 0x1a,0x1b,0x18,0x19,0x1e,0x1f,0x1c,0x1d,0x12,0x13,0x10,0x11,0x16,0x17,0x14,0x15, - 0x0a,0x0b,0x08,0x09,0x0e,0x0f,0x0c,0x0d,0x02,0x03,0x00,0x01,0x06,0x07,0x04,0x05, - 0x24,0x25,0x26,0x27,0x20,0x21,0x22,0x23,0x2c,0x2d,0x2e,0x2f,0x28,0x29,0x2a,0x2b, - 0x34,0x35,0x36,0x37,0x30,0x31,0x32,0x33,0x3c,0x3d,0x3e,0x3f,0x38,0x39,0x3a,0x3b, - 0x04,0x05,0x06,0x07,0x00,0x01,0x02,0x03,0x0c,0x0d,0x0e,0x0f,0x08,0x09,0x0a,0x0b, - 0x14,0x15,0x16,0x17,0x10,0x11,0x12,0x13,0x1c,0x1d,0x1e,0x1f,0x18,0x19,0x1a,0x1b, - 0x0b,0x0a,0x09,0x08,0x0f,0x0e,0x0d,0x0c,0x03,0x02,0x01,0x00,0x07,0x06,0x05,0x04, - 0x1b,0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c,0x13,0x12,0x11,0x10,0x17,0x16,0x15,0x14, - 0x2b,0x2a,0x29,0x28,0x2f,0x2e,0x2d,0x2c,0x23,0x22,0x21,0x20,0x27,0x26,0x25,0x24, - 0x3b,0x3a,0x39,0x38,0x3f,0x3e,0x3d,0x3c,0x33,0x32,0x31,0x30,0x37,0x36,0x35,0x34, - 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, - 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, - 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37, - 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27, - 0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x30,0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38, - 0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20,0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28, - 0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10,0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18, - 0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08, - 0x29,0x28,0x2b,0x2a,0x2d,0x2c,0x2f,0x2e,0x21,0x20,0x23,0x22,0x25,0x24,0x27,0x26, - 0x39,0x38,0x3b,0x3a,0x3d,0x3c,0x3f,0x3e,0x31,0x30,0x33,0x32,0x35,0x34,0x37,0x36, - 0x09,0x08,0x0b,0x0a,0x0d,0x0c,0x0f,0x0e,0x01,0x00,0x03,0x02,0x05,0x04,0x07,0x06, - 0x19,0x18,0x1b,0x1a,0x1d,0x1c,0x1f,0x1e,0x11,0x10,0x13,0x12,0x15,0x14,0x17,0x16, - 0x06,0x07,0x04,0x05,0x02,0x03,0x00,0x01,0x0e,0x0f,0x0c,0x0d,0x0a,0x0b,0x08,0x09, - 0x16,0x17,0x14,0x15,0x12,0x13,0x10,0x11,0x1e,0x1f,0x1c,0x1d,0x1a,0x1b,0x18,0x19, - 0x26,0x27,0x24,0x25,0x22,0x23,0x20,0x21,0x2e,0x2f,0x2c,0x2d,0x2a,0x2b,0x28,0x29, - 0x36,0x37,0x34,0x35,0x32,0x33,0x30,0x31,0x3e,0x3f,0x3c,0x3d,0x3a,0x3b,0x38,0x39, - 0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00, - 0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18,0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10, - 0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28,0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20, - 0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38,0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x30, - 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, - 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, - 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, - 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f, - 0x3e,0x3f,0x3c,0x3d,0x3a,0x3b,0x38,0x39,0x36,0x37,0x34,0x35,0x32,0x33,0x30,0x31, - 0x2e,0x2f,0x2c,0x2d,0x2a,0x2b,0x28,0x29,0x26,0x27,0x24,0x25,0x22,0x23,0x20,0x21, - 0x1e,0x1f,0x1c,0x1d,0x1a,0x1b,0x18,0x19,0x16,0x17,0x14,0x15,0x12,0x13,0x10,0x11, - 0x0e,0x0f,0x0c,0x0d,0x0a,0x0b,0x08,0x09,0x06,0x07,0x04,0x05,0x02,0x03,0x00,0x01, - 0x11,0x10,0x13,0x12,0x15,0x14,0x17,0x16,0x19,0x18,0x1b,0x1a,0x1d,0x1c,0x1f,0x1e, - 0x01,0x00,0x03,0x02,0x05,0x04,0x07,0x06,0x09,0x08,0x0b,0x0a,0x0d,0x0c,0x0f,0x0e, - 0x31,0x30,0x33,0x32,0x35,0x34,0x37,0x36,0x39,0x38,0x3b,0x3a,0x3d,0x3c,0x3f,0x3e, - 0x21,0x20,0x23,0x22,0x25,0x24,0x27,0x26,0x29,0x28,0x2b,0x2a,0x2d,0x2c,0x2f,0x2e, - 0x02,0x03,0x00,0x01,0x06,0x07,0x04,0x05,0x0a,0x0b,0x08,0x09,0x0e,0x0f,0x0c,0x0d, - 0x12,0x13,0x10,0x11,0x16,0x17,0x14,0x15,0x1a,0x1b,0x18,0x19,0x1e,0x1f,0x1c,0x1d, - 0x22,0x23,0x20,0x21,0x26,0x27,0x24,0x25,0x2a,0x2b,0x28,0x29,0x2e,0x2f,0x2c,0x2d, - 0x32,0x33,0x30,0x31,0x36,0x37,0x34,0x35,0x3a,0x3b,0x38,0x39,0x3e,0x3f,0x3c,0x3d, - 0x2d,0x2c,0x2f,0x2e,0x29,0x28,0x2b,0x2a,0x25,0x24,0x27,0x26,0x21,0x20,0x23,0x22, - 0x3d,0x3c,0x3f,0x3e,0x39,0x38,0x3b,0x3a,0x35,0x34,0x37,0x36,0x31,0x30,0x33,0x32, - 0x0d,0x0c,0x0f,0x0e,0x09,0x08,0x0b,0x0a,0x05,0x04,0x07,0x06,0x01,0x00,0x03,0x02, - 0x1d,0x1c,0x1f,0x1e,0x19,0x18,0x1b,0x1a,0x15,0x14,0x17,0x16,0x11,0x10,0x13,0x12, - 0x33,0x32,0x31,0x30,0x37,0x36,0x35,0x34,0x3b,0x3a,0x39,0x38,0x3f,0x3e,0x3d,0x3c, - 0x23,0x22,0x21,0x20,0x27,0x26,0x25,0x24,0x2b,0x2a,0x29,0x28,0x2f,0x2e,0x2d,0x2c, - 0x13,0x12,0x11,0x10,0x17,0x16,0x15,0x14,0x1b,0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c, - 0x03,0x02,0x01,0x00,0x07,0x06,0x05,0x04,0x0b,0x0a,0x09,0x08,0x0f,0x0e,0x0d,0x0c, - 0x1c,0x1d,0x1e,0x1f,0x18,0x19,0x1a,0x1b,0x14,0x15,0x16,0x17,0x10,0x11,0x12,0x13, - 0x0c,0x0d,0x0e,0x0f,0x08,0x09,0x0a,0x0b,0x04,0x05,0x06,0x07,0x00,0x01,0x02,0x03, - 0x3c,0x3d,0x3e,0x3f,0x38,0x39,0x3a,0x3b,0x34,0x35,0x36,0x37,0x30,0x31,0x32,0x33, - 0x2c,0x2d,0x2e,0x2f,0x28,0x29,0x2a,0x2b,0x24,0x25,0x26,0x27,0x20,0x21,0x22,0x23, - 0x21,0x20,0x23,0x22,0x25,0x24,0x27,0x26,0x29,0x28,0x2b,0x2a,0x2d,0x2c,0x2f,0x2e, - 0x31,0x30,0x33,0x32,0x35,0x34,0x37,0x36,0x39,0x38,0x3b,0x3a,0x3d,0x3c,0x3f,0x3e, - 0x01,0x00,0x03,0x02,0x05,0x04,0x07,0x06,0x09,0x08,0x0b,0x0a,0x0d,0x0c,0x0f,0x0e, - 0x11,0x10,0x13,0x12,0x15,0x14,0x17,0x16,0x19,0x18,0x1b,0x1a,0x1d,0x1c,0x1f,0x1e, - 0x0e,0x0f,0x0c,0x0d,0x0a,0x0b,0x08,0x09,0x06,0x07,0x04,0x05,0x02,0x03,0x00,0x01, - 0x1e,0x1f,0x1c,0x1d,0x1a,0x1b,0x18,0x19,0x16,0x17,0x14,0x15,0x12,0x13,0x10,0x11, - 0x2e,0x2f,0x2c,0x2d,0x2a,0x2b,0x28,0x29,0x26,0x27,0x24,0x25,0x22,0x23,0x20,0x21, - 0x3e,0x3f,0x3c,0x3d,0x3a,0x3b,0x38,0x39,0x36,0x37,0x34,0x35,0x32,0x33,0x30,0x31, - 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f, - 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, - 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, - 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, - 0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38,0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x30, - 0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28,0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20, - 0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18,0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10, - 0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00, - 0x2c,0x2d,0x2e,0x2f,0x28,0x29,0x2a,0x2b,0x24,0x25,0x26,0x27,0x20,0x21,0x22,0x23, - 0x3c,0x3d,0x3e,0x3f,0x38,0x39,0x3a,0x3b,0x34,0x35,0x36,0x37,0x30,0x31,0x32,0x33, - 0x0c,0x0d,0x0e,0x0f,0x08,0x09,0x0a,0x0b,0x04,0x05,0x06,0x07,0x00,0x01,0x02,0x03, - 0x1c,0x1d,0x1e,0x1f,0x18,0x19,0x1a,0x1b,0x14,0x15,0x16,0x17,0x10,0x11,0x12,0x13, - 0x03,0x02,0x01,0x00,0x07,0x06,0x05,0x04,0x0b,0x0a,0x09,0x08,0x0f,0x0e,0x0d,0x0c, - 0x13,0x12,0x11,0x10,0x17,0x16,0x15,0x14,0x1b,0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c, - 0x23,0x22,0x21,0x20,0x27,0x26,0x25,0x24,0x2b,0x2a,0x29,0x28,0x2f,0x2e,0x2d,0x2c, - 0x33,0x32,0x31,0x30,0x37,0x36,0x35,0x34,0x3b,0x3a,0x39,0x38,0x3f,0x3e,0x3d,0x3c, - 0x1d,0x1c,0x1f,0x1e,0x19,0x18,0x1b,0x1a,0x15,0x14,0x17,0x16,0x11,0x10,0x13,0x12, - 0x0d,0x0c,0x0f,0x0e,0x09,0x08,0x0b,0x0a,0x05,0x04,0x07,0x06,0x01,0x00,0x03,0x02, - 0x3d,0x3c,0x3f,0x3e,0x39,0x38,0x3b,0x3a,0x35,0x34,0x37,0x36,0x31,0x30,0x33,0x32, - 0x2d,0x2c,0x2f,0x2e,0x29,0x28,0x2b,0x2a,0x25,0x24,0x27,0x26,0x21,0x20,0x23,0x22, - 0x32,0x33,0x30,0x31,0x36,0x37,0x34,0x35,0x3a,0x3b,0x38,0x39,0x3e,0x3f,0x3c,0x3d, - 0x22,0x23,0x20,0x21,0x26,0x27,0x24,0x25,0x2a,0x2b,0x28,0x29,0x2e,0x2f,0x2c,0x2d, - 0x12,0x13,0x10,0x11,0x16,0x17,0x14,0x15,0x1a,0x1b,0x18,0x19,0x1e,0x1f,0x1c,0x1d, - 0x02,0x03,0x00,0x01,0x06,0x07,0x04,0x05,0x0a,0x0b,0x08,0x09,0x0e,0x0f,0x0c,0x0d, - 0x3b,0x3a,0x39,0x38,0x3f,0x3e,0x3d,0x3c,0x33,0x32,0x31,0x30,0x37,0x36,0x35,0x34, - 0x2b,0x2a,0x29,0x28,0x2f,0x2e,0x2d,0x2c,0x23,0x22,0x21,0x20,0x27,0x26,0x25,0x24, - 0x1b,0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c,0x13,0x12,0x11,0x10,0x17,0x16,0x15,0x14, - 0x0b,0x0a,0x09,0x08,0x0f,0x0e,0x0d,0x0c,0x03,0x02,0x01,0x00,0x07,0x06,0x05,0x04, - 0x14,0x15,0x16,0x17,0x10,0x11,0x12,0x13,0x1c,0x1d,0x1e,0x1f,0x18,0x19,0x1a,0x1b, - 0x04,0x05,0x06,0x07,0x00,0x01,0x02,0x03,0x0c,0x0d,0x0e,0x0f,0x08,0x09,0x0a,0x0b, - 0x34,0x35,0x36,0x37,0x30,0x31,0x32,0x33,0x3c,0x3d,0x3e,0x3f,0x38,0x39,0x3a,0x3b, - 0x24,0x25,0x26,0x27,0x20,0x21,0x22,0x23,0x2c,0x2d,0x2e,0x2f,0x28,0x29,0x2a,0x2b, - 0x0a,0x0b,0x08,0x09,0x0e,0x0f,0x0c,0x0d,0x02,0x03,0x00,0x01,0x06,0x07,0x04,0x05, - 0x1a,0x1b,0x18,0x19,0x1e,0x1f,0x1c,0x1d,0x12,0x13,0x10,0x11,0x16,0x17,0x14,0x15, - 0x2a,0x2b,0x28,0x29,0x2e,0x2f,0x2c,0x2d,0x22,0x23,0x20,0x21,0x26,0x27,0x24,0x25, - 0x3a,0x3b,0x38,0x39,0x3e,0x3f,0x3c,0x3d,0x32,0x33,0x30,0x31,0x36,0x37,0x34,0x35, - 0x25,0x24,0x27,0x26,0x21,0x20,0x23,0x22,0x2d,0x2c,0x2f,0x2e,0x29,0x28,0x2b,0x2a, - 0x35,0x34,0x37,0x36,0x31,0x30,0x33,0x32,0x3d,0x3c,0x3f,0x3e,0x39,0x38,0x3b,0x3a, - 0x05,0x04,0x07,0x06,0x01,0x00,0x03,0x02,0x0d,0x0c,0x0f,0x0e,0x09,0x08,0x0b,0x0a, - 0x15,0x14,0x17,0x16,0x11,0x10,0x13,0x12,0x1d,0x1c,0x1f,0x1e,0x19,0x18,0x1b,0x1a, - 0x36,0x37,0x34,0x35,0x32,0x33,0x30,0x31,0x3e,0x3f,0x3c,0x3d,0x3a,0x3b,0x38,0x39, - 0x26,0x27,0x24,0x25,0x22,0x23,0x20,0x21,0x2e,0x2f,0x2c,0x2d,0x2a,0x2b,0x28,0x29, - 0x16,0x17,0x14,0x15,0x12,0x13,0x10,0x11,0x1e,0x1f,0x1c,0x1d,0x1a,0x1b,0x18,0x19, - 0x06,0x07,0x04,0x05,0x02,0x03,0x00,0x01,0x0e,0x0f,0x0c,0x0d,0x0a,0x0b,0x08,0x09, - 0x19,0x18,0x1b,0x1a,0x1d,0x1c,0x1f,0x1e,0x11,0x10,0x13,0x12,0x15,0x14,0x17,0x16, - 0x09,0x08,0x0b,0x0a,0x0d,0x0c,0x0f,0x0e,0x01,0x00,0x03,0x02,0x05,0x04,0x07,0x06, - 0x39,0x38,0x3b,0x3a,0x3d,0x3c,0x3f,0x3e,0x31,0x30,0x33,0x32,0x35,0x34,0x37,0x36, - 0x29,0x28,0x2b,0x2a,0x2d,0x2c,0x2f,0x2e,0x21,0x20,0x23,0x22,0x25,0x24,0x27,0x26, - 0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08, - 0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10,0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18, - 0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20,0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28, - 0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x30,0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38, - 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27, - 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37, - 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, - 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, +static const unsigned char crc6_table[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, + 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, + 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, + 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, + 0x23, 0x22, 0x21, 0x20, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, + 0x30, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x1f, 0x1e, + 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x31, 0x30, 0x33, 0x32, 0x35, + 0x34, 0x37, 0x36, 0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e, 0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26, + 0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e, 0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16, 0x19, 0x18, 0x1b, + 0x1a, 0x1d, 0x1c, 0x1f, 0x1e, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, 0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, + 0x0f, 0x0e, 0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19, 0x16, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11, 0x0e, + 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09, 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01, 0x3e, 0x3f, 0x3c, 0x3d, + 0x3a, 0x3b, 0x38, 0x39, 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31, 0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, + 0x29, 0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21, 0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a, 0x05, 0x04, + 0x07, 0x06, 0x01, 0x00, 0x03, 0x02, 0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a, 0x15, 0x14, 0x17, 0x16, 0x11, + 0x10, 0x13, 0x12, 0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a, 0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22, + 0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a, 0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32, 0x22, 0x23, 0x20, + 0x21, 0x26, 0x27, 0x24, 0x25, 0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d, 0x32, 0x33, 0x30, 0x31, 0x36, 0x37, + 0x34, 0x35, 0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d, 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x0a, + 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d, 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x1a, 0x1b, 0x18, 0x19, + 0x1e, 0x1f, 0x1c, 0x1d, 0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b, 0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, + 0x33, 0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b, 0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23, 0x1c, 0x1d, + 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b, 0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13, 0x0c, 0x0d, 0x0e, 0x0f, 0x08, + 0x09, 0x0a, 0x0b, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14, + 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x0b, 0x0a, 0x09, + 0x08, 0x0f, 0x0e, 0x0d, 0x0c, 0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34, 0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, + 0x3d, 0x3c, 0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24, 0x2b, 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c, 0x1a, + 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x0a, 0x0b, 0x08, 0x09, + 0x0e, 0x0f, 0x0c, 0x0d, 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, + 0x3d, 0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35, 0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d, 0x22, 0x23, + 0x20, 0x21, 0x26, 0x27, 0x24, 0x25, 0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32, 0x3d, 0x3c, 0x3f, 0x3e, 0x39, + 0x38, 0x3b, 0x3a, 0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22, 0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a, + 0x15, 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12, 0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a, 0x05, 0x04, 0x07, + 0x06, 0x01, 0x00, 0x03, 0x02, 0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a, 0x2b, 0x2a, 0x29, 0x28, 0x2f, 0x2e, + 0x2d, 0x2c, 0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24, 0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c, 0x33, + 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34, 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c, 0x03, 0x02, 0x01, 0x00, + 0x07, 0x06, 0x05, 0x04, 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c, 0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, + 0x14, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b, 0x14, 0x15, + 0x16, 0x17, 0x10, 0x11, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b, 0x24, 0x25, 0x26, 0x27, 0x20, + 0x21, 0x22, 0x23, 0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b, 0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33, + 0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x1f, 0x1e, 0x1d, + 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, + 0x09, 0x08, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x27, + 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x38, 0x39, 0x3a, 0x3b, + 0x3c, 0x3d, 0x3e, 0x3f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, + 0x2f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x10, 0x11, + 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, + 0x05, 0x06, 0x07, 0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21, 0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29, + 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31, 0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39, 0x06, 0x07, 0x04, + 0x05, 0x02, 0x03, 0x00, 0x01, 0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09, 0x16, 0x17, 0x14, 0x15, 0x12, 0x13, + 0x10, 0x11, 0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19, 0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e, 0x01, + 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, 0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e, 0x11, 0x10, 0x13, 0x12, + 0x15, 0x14, 0x17, 0x16, 0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e, 0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, + 0x26, 0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e, 0x31, 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36, 0x34, 0x35, + 0x36, 0x37, 0x30, 0x31, 0x32, 0x33, 0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b, 0x24, 0x25, 0x26, 0x27, 0x20, + 0x21, 0x22, 0x23, 0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b, 0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13, + 0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x0c, 0x0d, 0x0e, + 0x0f, 0x08, 0x09, 0x0a, 0x0b, 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c, 0x13, 0x12, 0x11, 0x10, 0x17, 0x16, + 0x15, 0x14, 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x3b, + 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c, 0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34, 0x2b, 0x2a, 0x29, 0x28, + 0x2f, 0x2e, 0x2d, 0x2c, 0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24, 0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, + 0x02, 0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a, 0x15, 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12, 0x1d, 0x1c, + 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a, 0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22, 0x2d, 0x2c, 0x2f, 0x2e, 0x29, + 0x28, 0x2b, 0x2a, 0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32, 0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a, + 0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d, 0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25, 0x3a, 0x3b, 0x38, + 0x39, 0x3e, 0x3f, 0x3c, 0x3d, 0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35, 0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, + 0x0c, 0x0d, 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x12, + 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e, 0x31, 0x30, 0x33, 0x32, + 0x35, 0x34, 0x37, 0x36, 0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e, 0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, + 0x26, 0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e, 0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16, 0x09, 0x08, + 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, 0x16, 0x17, 0x14, 0x15, 0x12, + 0x13, 0x10, 0x11, 0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19, 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01, + 0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09, 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31, 0x3e, 0x3f, 0x3c, + 0x3d, 0x3a, 0x3b, 0x38, 0x39, 0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21, 0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, + 0x28, 0x29, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x18, + 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, + 0x3f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x2f, 0x2e, + 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, + 0x3a, 0x39, 0x38, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, + 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x2e, 0x2f, 0x2c, + 0x2d, 0x2a, 0x2b, 0x28, 0x29, 0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21, 0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, + 0x38, 0x39, 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31, 0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09, 0x06, + 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01, 0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19, 0x16, 0x17, 0x14, 0x15, + 0x12, 0x13, 0x10, 0x11, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, 0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, + 0x0e, 0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16, 0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e, 0x21, 0x20, + 0x23, 0x22, 0x25, 0x24, 0x27, 0x26, 0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e, 0x31, 0x30, 0x33, 0x32, 0x35, + 0x34, 0x37, 0x36, 0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, + 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, + 0x04, 0x03, 0x02, 0x01, 0x00, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, + 0x31, 0x30, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x30, + 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, + 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24, 0x2b, 0x2a, 0x29, 0x28, 0x2f, + 0x2e, 0x2d, 0x2c, 0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34, 0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c, + 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c, 0x13, 0x12, 0x11, + 0x10, 0x17, 0x16, 0x15, 0x14, 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c, 0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, + 0x0a, 0x0b, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b, 0x14, + 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13, 0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b, 0x24, 0x25, 0x26, 0x27, + 0x20, 0x21, 0x22, 0x23, 0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b, 0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, + 0x33, 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x02, 0x03, + 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d, 0x32, 0x33, 0x30, 0x31, 0x36, + 0x37, 0x34, 0x35, 0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d, 0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25, + 0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d, 0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a, 0x35, 0x34, 0x37, + 0x36, 0x31, 0x30, 0x33, 0x32, 0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a, 0x25, 0x24, 0x27, 0x26, 0x21, 0x20, + 0x23, 0x22, 0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a, 0x15, 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12, 0x0d, + 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a, 0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02, 0x07, 0x06, 0x05, 0x04, + 0x03, 0x02, 0x01, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, + 0x10, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x2f, 0x2e, + 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, + 0x3a, 0x39, 0x38, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x08, 0x09, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, + 0x1e, 0x1f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31, 0x3e, + 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39, 0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21, 0x2e, 0x2f, 0x2c, 0x2d, + 0x2a, 0x2b, 0x28, 0x29, 0x16, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11, 0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, + 0x19, 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01, 0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09, 0x19, 0x18, + 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e, 0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16, 0x09, 0x08, 0x0b, 0x0a, 0x0d, + 0x0c, 0x0f, 0x0e, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, 0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e, + 0x31, 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36, 0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e, 0x21, 0x20, 0x23, + 0x22, 0x25, 0x24, 0x27, 0x26, 0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d, 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, + 0x04, 0x05, 0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x2a, + 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d, 0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25, 0x3a, 0x3b, 0x38, 0x39, + 0x3e, 0x3f, 0x3c, 0x3d, 0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35, 0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, + 0x22, 0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a, 0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32, 0x3d, 0x3c, + 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a, 0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02, 0x0d, 0x0c, 0x0f, 0x0e, 0x09, + 0x08, 0x0b, 0x0a, 0x15, 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12, 0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a, + 0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c, 0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34, 0x2b, 0x2a, 0x29, + 0x28, 0x2f, 0x2e, 0x2d, 0x2c, 0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24, 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, + 0x1d, 0x1c, 0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14, 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c, 0x03, + 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x1f, + 0x18, 0x19, 0x1a, 0x1b, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, + 0x0b, 0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33, 0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b, 0x24, 0x25, + 0x26, 0x27, 0x20, 0x21, 0x22, 0x23, 0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b, 0x1d, 0x1c, 0x1f, 0x1e, 0x19, + 0x18, 0x1b, 0x1a, 0x15, 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12, 0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a, + 0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02, 0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a, 0x35, 0x34, 0x37, + 0x36, 0x31, 0x30, 0x33, 0x32, 0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a, 0x25, 0x24, 0x27, 0x26, 0x21, 0x20, + 0x23, 0x22, 0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35, 0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d, 0x22, + 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25, 0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d, 0x12, 0x13, 0x10, 0x11, + 0x16, 0x17, 0x14, 0x15, 0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, + 0x05, 0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d, 0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b, 0x24, 0x25, + 0x26, 0x27, 0x20, 0x21, 0x22, 0x23, 0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b, 0x34, 0x35, 0x36, 0x37, 0x30, + 0x31, 0x32, 0x33, 0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, + 0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b, 0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13, 0x03, 0x02, 0x01, + 0x00, 0x07, 0x06, 0x05, 0x04, 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c, 0x13, 0x12, 0x11, 0x10, 0x17, 0x16, + 0x15, 0x14, 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c, 0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24, 0x2b, + 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c, 0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34, 0x3b, 0x3a, 0x39, 0x38, + 0x3f, 0x3e, 0x3d, 0x3c, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, + 0x1f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x30, 0x31, + 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x20, 0x21, 0x22, 0x23, 0x24, + 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, + 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25, + 0x24, 0x23, 0x22, 0x21, 0x20, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, + 0x11, 0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x21, + 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26, 0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e, 0x31, 0x30, 0x33, 0x32, + 0x35, 0x34, 0x37, 0x36, 0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, + 0x06, 0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e, 0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16, 0x19, 0x18, + 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e, 0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09, 0x06, 0x07, 0x04, 0x05, 0x02, + 0x03, 0x00, 0x01, 0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19, 0x16, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11, + 0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29, 0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21, 0x3e, 0x3f, 0x3c, + 0x3d, 0x3a, 0x3b, 0x38, 0x39, 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31, 0x33, 0x32, 0x31, 0x30, 0x37, 0x36, + 0x35, 0x34, 0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c, 0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24, 0x2b, + 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c, 0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14, 0x1b, 0x1a, 0x19, 0x18, + 0x1f, 0x1e, 0x1d, 0x1c, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, + 0x0c, 0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b, 0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13, 0x0c, 0x0d, + 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x3c, 0x3d, 0x3e, 0x3f, 0x38, + 0x39, 0x3a, 0x3b, 0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33, 0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b, + 0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23, 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x0a, 0x0b, 0x08, + 0x09, 0x0e, 0x0f, 0x0c, 0x0d, 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, + 0x1c, 0x1d, 0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25, 0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d, 0x32, + 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35, 0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d, 0x2d, 0x2c, 0x2f, 0x2e, + 0x29, 0x28, 0x2b, 0x2a, 0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22, 0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, + 0x3a, 0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32, 0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a, 0x05, 0x04, + 0x07, 0x06, 0x01, 0x00, 0x03, 0x02, 0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a, 0x15, 0x14, 0x17, 0x16, 0x11, + 0x10, 0x13, 0x12, 0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39, 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31, + 0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29, 0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21, 0x1e, 0x1f, 0x1c, + 0x1d, 0x1a, 0x1b, 0x18, 0x19, 0x16, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11, 0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, + 0x08, 0x09, 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01, 0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16, 0x19, + 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, 0x09, 0x08, 0x0b, 0x0a, + 0x0d, 0x0c, 0x0f, 0x0e, 0x31, 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36, 0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, + 0x3e, 0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26, 0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e, 0x0f, 0x0e, + 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, + 0x1a, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, + 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, 0x35, + 0x34, 0x33, 0x32, 0x31, 0x30, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, + 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x00, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, + 0x2e, 0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26, 0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e, 0x31, 0x30, + 0x33, 0x32, 0x35, 0x34, 0x37, 0x36, 0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e, 0x01, 0x00, 0x03, 0x02, 0x05, + 0x04, 0x07, 0x06, 0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e, 0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16, + 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01, 0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09, 0x16, 0x17, 0x14, + 0x15, 0x12, 0x13, 0x10, 0x11, 0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19, 0x26, 0x27, 0x24, 0x25, 0x22, 0x23, + 0x20, 0x21, 0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29, 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31, 0x3e, + 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x28, 0x29, + 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x37, 0x36, 0x35, 0x34, 0x33, + 0x32, 0x31, 0x30, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, + 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x1f, 0x1e, 0x1d, + 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, + 0x09, 0x08, 0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23, 0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b, 0x34, + 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33, 0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b, 0x04, 0x05, 0x06, 0x07, + 0x00, 0x01, 0x02, 0x03, 0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b, 0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, + 0x13, 0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b, 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c, 0x03, 0x02, + 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c, 0x13, 0x12, 0x11, 0x10, 0x17, + 0x16, 0x15, 0x14, 0x2b, 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c, 0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24, + 0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c, 0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34, 0x15, 0x14, 0x17, + 0x16, 0x11, 0x10, 0x13, 0x12, 0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a, 0x05, 0x04, 0x07, 0x06, 0x01, 0x00, + 0x03, 0x02, 0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a, 0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32, 0x3d, + 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a, 0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22, 0x2d, 0x2c, 0x2f, 0x2e, + 0x29, 0x28, 0x2b, 0x2a, 0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d, 0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, + 0x35, 0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d, 0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25, 0x1a, 0x1b, + 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x0a, 0x0b, 0x08, 0x09, 0x0e, + 0x0f, 0x0c, 0x0d, 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09, + 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01, 0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19, 0x16, 0x17, 0x14, + 0x15, 0x12, 0x13, 0x10, 0x11, 0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29, 0x26, 0x27, 0x24, 0x25, 0x22, 0x23, + 0x20, 0x21, 0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39, 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31, 0x21, + 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26, 0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e, 0x31, 0x30, 0x33, 0x32, + 0x35, 0x34, 0x37, 0x36, 0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, + 0x06, 0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e, 0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16, 0x19, 0x18, + 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, + 0x32, 0x31, 0x30, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, + 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e, 0x0d, + 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x3c, 0x3d, 0x3e, 0x3f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, + 0x2f, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c, 0x13, 0x12, + 0x11, 0x10, 0x17, 0x16, 0x15, 0x14, 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c, 0x23, 0x22, 0x21, 0x20, 0x27, + 0x26, 0x25, 0x24, 0x2b, 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c, 0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34, + 0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c, 0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b, 0x24, 0x25, 0x26, + 0x27, 0x20, 0x21, 0x22, 0x23, 0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b, 0x34, 0x35, 0x36, 0x37, 0x30, 0x31, + 0x32, 0x33, 0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x1c, + 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b, 0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13, 0x32, 0x33, 0x30, 0x31, + 0x36, 0x37, 0x34, 0x35, 0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d, 0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, + 0x25, 0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d, 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x1a, 0x1b, + 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x0a, 0x0b, 0x08, 0x09, 0x0e, + 0x0f, 0x0c, 0x0d, 0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a, 0x15, 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12, + 0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a, 0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02, 0x3d, 0x3c, 0x3f, + 0x3e, 0x39, 0x38, 0x3b, 0x3a, 0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32, 0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, + 0x2b, 0x2a, 0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22, 0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13, 0x1c, + 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x0c, 0x0d, 0x0e, 0x0f, + 0x08, 0x09, 0x0a, 0x0b, 0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33, 0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, + 0x3b, 0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23, 0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b, 0x3b, 0x3a, + 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c, 0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34, 0x2b, 0x2a, 0x29, 0x28, 0x2f, + 0x2e, 0x2d, 0x2c, 0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24, 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c, + 0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14, 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c, 0x03, 0x02, 0x01, + 0x00, 0x07, 0x06, 0x05, 0x04, 0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22, 0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, + 0x2b, 0x2a, 0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32, 0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a, 0x05, + 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02, 0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a, 0x15, 0x14, 0x17, 0x16, + 0x11, 0x10, 0x13, 0x12, 0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a, 0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, + 0x0d, 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x12, 0x13, + 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d, 0x22, 0x23, 0x20, 0x21, 0x26, + 0x27, 0x24, 0x25, 0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d, 0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35, + 0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e, 0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16, 0x09, 0x08, 0x0b, + 0x0a, 0x0d, 0x0c, 0x0f, 0x0e, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, 0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, + 0x3f, 0x3e, 0x31, 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36, 0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e, 0x21, + 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26, 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31, 0x3e, 0x3f, 0x3c, 0x3d, + 0x3a, 0x3b, 0x38, 0x39, 0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21, 0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, + 0x29, 0x16, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11, 0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19, 0x06, 0x07, + 0x04, 0x05, 0x02, 0x03, 0x00, 0x01, 0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09, 0x28, 0x29, 0x2a, 0x2b, 0x2c, + 0x2d, 0x2e, 0x2f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, + 0x03, 0x04, 0x05, 0x06, 0x07, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x17, + 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x27, 0x26, 0x25, 0x24, + 0x23, 0x22, 0x21, 0x20, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, + 0x30, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d, 0x32, 0x33, + 0x30, 0x31, 0x36, 0x37, 0x34, 0x35, 0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d, 0x22, 0x23, 0x20, 0x21, 0x26, + 0x27, 0x24, 0x25, 0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, + 0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d, 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x15, 0x14, 0x17, + 0x16, 0x11, 0x10, 0x13, 0x12, 0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a, 0x05, 0x04, 0x07, 0x06, 0x01, 0x00, + 0x03, 0x02, 0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a, 0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32, 0x3d, + 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a, 0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22, 0x2d, 0x2c, 0x2f, 0x2e, + 0x29, 0x28, 0x2b, 0x2a, 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, + 0x04, 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c, 0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14, 0x2b, 0x2a, + 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c, 0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24, 0x3b, 0x3a, 0x39, 0x38, 0x3f, + 0x3e, 0x3d, 0x3c, 0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34, 0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23, + 0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b, 0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33, 0x3c, 0x3d, 0x3e, + 0x3f, 0x38, 0x39, 0x3a, 0x3b, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, + 0x0a, 0x0b, 0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b, 0x37, + 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x27, 0x26, 0x25, 0x24, + 0x23, 0x22, 0x21, 0x20, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, + 0x10, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x0f, 0x0e, + 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x10, 0x11, 0x12, 0x13, 0x14, + 0x15, 0x16, 0x17, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x28, 0x29, 0x2a, + 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, + 0x00, 0x01, 0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09, 0x16, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11, 0x1e, + 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19, 0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21, 0x2e, 0x2f, 0x2c, 0x2d, + 0x2a, 0x2b, 0x28, 0x29, 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31, 0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, + 0x39, 0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e, 0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26, 0x39, 0x38, + 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e, 0x31, 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36, 0x09, 0x08, 0x0b, 0x0a, 0x0d, + 0x0c, 0x0f, 0x0e, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, 0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e, + 0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, + 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, + 0x3e, 0x3f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x0f, 0x0e, 0x0d, 0x0c, + 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, + 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, + 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, + 0x32, 0x31, 0x30, 0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16, 0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e, + 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, 0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e, 0x31, 0x30, 0x33, + 0x32, 0x35, 0x34, 0x37, 0x36, 0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e, 0x21, 0x20, 0x23, 0x22, 0x25, 0x24, + 0x27, 0x26, 0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e, 0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39, 0x36, + 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31, 0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29, 0x26, 0x27, 0x24, 0x25, + 0x22, 0x23, 0x20, 0x21, 0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19, 0x16, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, + 0x11, 0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09, 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01, 0x2d, 0x2c, + 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a, 0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22, 0x3d, 0x3c, 0x3f, 0x3e, 0x39, + 0x38, 0x3b, 0x3a, 0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32, 0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a, + 0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02, 0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a, 0x15, 0x14, 0x17, + 0x16, 0x11, 0x10, 0x13, 0x12, 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, + 0x0c, 0x0d, 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x22, + 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25, 0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d, 0x32, 0x33, 0x30, 0x31, + 0x36, 0x37, 0x34, 0x35, 0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d, 0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, + 0x1b, 0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13, 0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b, 0x04, 0x05, + 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b, 0x34, 0x35, 0x36, 0x37, 0x30, + 0x31, 0x32, 0x33, 0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b, 0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23, + 0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34, 0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c, 0x23, 0x22, 0x21, + 0x20, 0x27, 0x26, 0x25, 0x24, 0x2b, 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c, 0x13, 0x12, 0x11, 0x10, 0x17, 0x16, + 0x15, 0x14, 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x0b, + 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c, 0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e, 0x01, 0x00, 0x03, 0x02, + 0x05, 0x04, 0x07, 0x06, 0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e, 0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, + 0x16, 0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e, 0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26, 0x39, 0x38, + 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e, 0x31, 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36, 0x26, 0x27, 0x24, 0x25, 0x22, + 0x23, 0x20, 0x21, 0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29, 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31, + 0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39, 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01, 0x0e, 0x0f, 0x0c, + 0x0d, 0x0a, 0x0b, 0x08, 0x09, 0x16, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11, 0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, + 0x18, 0x19, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x28, + 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, + 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x1f, 0x1e, + 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, + 0x0a, 0x09, 0x08, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, + 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x04, 0x05, 0x06, + 0x07, 0x00, 0x01, 0x02, 0x03, 0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b, 0x14, 0x15, 0x16, 0x17, 0x10, 0x11, + 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b, 0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23, 0x2c, + 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b, 0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33, 0x3c, 0x3d, 0x3e, 0x3f, + 0x38, 0x39, 0x3a, 0x3b, 0x2b, 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c, 0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, + 0x24, 0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c, 0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34, 0x0b, 0x0a, + 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x1b, 0x1a, 0x19, 0x18, 0x1f, + 0x1e, 0x1d, 0x1c, 0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14, 0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32, + 0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a, 0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22, 0x2d, 0x2c, 0x2f, + 0x2e, 0x29, 0x28, 0x2b, 0x2a, 0x15, 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12, 0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, + 0x1b, 0x1a, 0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02, 0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a, 0x1a, + 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x0a, 0x0b, 0x08, 0x09, + 0x0e, 0x0f, 0x0c, 0x0d, 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, + 0x3d, 0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35, 0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d, 0x22, 0x23, + 0x20, 0x21, 0x26, 0x27, 0x24, 0x25, 0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14, 0x1b, 0x1a, 0x19, 0x18, 0x1f, + 0x1e, 0x1d, 0x1c, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c, + 0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34, 0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c, 0x23, 0x22, 0x21, + 0x20, 0x27, 0x26, 0x25, 0x24, 0x2b, 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c, 0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, + 0x3a, 0x3b, 0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33, 0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b, 0x24, + 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23, 0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b, 0x14, 0x15, 0x16, 0x17, + 0x10, 0x11, 0x12, 0x13, 0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, + 0x03, 0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25, 0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d, 0x32, 0x33, + 0x30, 0x31, 0x36, 0x37, 0x34, 0x35, 0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d, 0x02, 0x03, 0x00, 0x01, 0x06, + 0x07, 0x04, 0x05, 0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d, 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, + 0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a, 0x05, 0x04, 0x07, + 0x06, 0x01, 0x00, 0x03, 0x02, 0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a, 0x15, 0x14, 0x17, 0x16, 0x11, 0x10, + 0x13, 0x12, 0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a, 0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22, 0x3d, + 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a, 0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32, 0x1e, 0x1f, 0x1c, 0x1d, + 0x1a, 0x1b, 0x18, 0x19, 0x16, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11, 0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, + 0x09, 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01, 0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39, 0x36, 0x37, + 0x34, 0x35, 0x32, 0x33, 0x30, 0x31, 0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29, 0x26, 0x27, 0x24, 0x25, 0x22, + 0x23, 0x20, 0x21, 0x31, 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36, 0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e, + 0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26, 0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e, 0x11, 0x10, 0x13, + 0x12, 0x15, 0x14, 0x17, 0x16, 0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, + 0x07, 0x06, 0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, + 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, + 0x33, 0x32, 0x31, 0x30, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, + 0x00, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, + 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, + 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a, 0x35, 0x34, 0x37, 0x36, 0x31, 0x30, + 0x33, 0x32, 0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a, 0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22, 0x1d, + 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a, 0x15, 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12, 0x0d, 0x0c, 0x0f, 0x0e, + 0x09, 0x08, 0x0b, 0x0a, 0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02, 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, + 0x15, 0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x0a, 0x0b, + 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d, 0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35, 0x3a, 0x3b, 0x38, 0x39, 0x3e, + 0x3f, 0x3c, 0x3d, 0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25, 0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d, + 0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x1c, 0x1d, 0x1e, + 0x1f, 0x18, 0x19, 0x1a, 0x1b, 0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13, 0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, + 0x2a, 0x2b, 0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23, 0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b, 0x34, + 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33, 0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24, 0x2b, 0x2a, 0x29, 0x28, + 0x2f, 0x2e, 0x2d, 0x2c, 0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34, 0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, + 0x3c, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c, 0x13, 0x12, + 0x11, 0x10, 0x17, 0x16, 0x15, 0x14, 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c, 0x30, 0x31, 0x32, 0x33, 0x34, + 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, + 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, + 0x0e, 0x0f, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, + 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x3f, 0x3e, 0x3d, 0x3c, + 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, + 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, 0x09, 0x08, + 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e, 0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16, 0x19, 0x18, 0x1b, 0x1a, 0x1d, + 0x1c, 0x1f, 0x1e, 0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26, 0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e, + 0x31, 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36, 0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e, 0x2e, 0x2f, 0x2c, + 0x2d, 0x2a, 0x2b, 0x28, 0x29, 0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21, 0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, + 0x38, 0x39, 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31, 0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09, 0x06, + 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01, 0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19, 0x16, 0x17, 0x14, 0x15, + 0x12, 0x13, 0x10, 0x11, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, + 0x28, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x07, 0x06, + 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x17, 0x16, 0x15, 0x14, 0x13, + 0x12, 0x11, 0x10, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x10, 0x11, 0x12, + 0x13, 0x14, 0x15, 0x16, 0x17, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, + 0x26, 0x27, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x16, + 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11, 0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19, 0x06, 0x07, 0x04, 0x05, + 0x02, 0x03, 0x00, 0x01, 0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09, 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, + 0x31, 0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39, 0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21, 0x2e, 0x2f, + 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29, 0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e, 0x31, 0x30, 0x33, 0x32, 0x35, + 0x34, 0x37, 0x36, 0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e, 0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26, + 0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e, 0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16, 0x09, 0x08, 0x0b, + 0x0a, 0x0d, 0x0c, 0x0f, 0x0e, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, 0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, + 0x2c, 0x2d, 0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25, 0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d, 0x32, + 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35, 0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d, 0x02, 0x03, 0x00, 0x01, + 0x06, 0x07, 0x04, 0x05, 0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, + 0x15, 0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02, 0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a, 0x15, 0x14, + 0x17, 0x16, 0x11, 0x10, 0x13, 0x12, 0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a, 0x25, 0x24, 0x27, 0x26, 0x21, + 0x20, 0x23, 0x22, 0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a, 0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32, + 0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a, 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c, 0x13, 0x12, 0x11, + 0x10, 0x17, 0x16, 0x15, 0x14, 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, + 0x05, 0x04, 0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c, 0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34, 0x2b, + 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c, 0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24, 0x34, 0x35, 0x36, 0x37, + 0x30, 0x31, 0x32, 0x33, 0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b, 0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, + 0x23, 0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b, 0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13, 0x1c, 0x1d, + 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x0c, 0x0d, 0x0e, 0x0f, 0x08, + 0x09, 0x0a, 0x0b, 0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b, 0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13, + 0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x3c, 0x3d, 0x3e, + 0x3f, 0x38, 0x39, 0x3a, 0x3b, 0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33, 0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, + 0x2a, 0x2b, 0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23, 0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34, 0x3b, + 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c, 0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24, 0x2b, 0x2a, 0x29, 0x28, + 0x2f, 0x2e, 0x2d, 0x2c, 0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14, 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, + 0x1c, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c, 0x2d, 0x2c, + 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a, 0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22, 0x3d, 0x3c, 0x3f, 0x3e, 0x39, + 0x38, 0x3b, 0x3a, 0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32, 0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a, + 0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02, 0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a, 0x15, 0x14, 0x17, + 0x16, 0x11, 0x10, 0x13, 0x12, 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, + 0x0c, 0x0d, 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x22, + 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25, 0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d, 0x32, 0x33, 0x30, 0x31, + 0x36, 0x37, 0x34, 0x35, 0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d, 0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, + 0x16, 0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, 0x09, 0x08, + 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e, 0x31, 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36, 0x39, 0x38, 0x3b, 0x3a, 0x3d, + 0x3c, 0x3f, 0x3e, 0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26, 0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e, + 0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39, 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31, 0x2e, 0x2f, 0x2c, + 0x2d, 0x2a, 0x2b, 0x28, 0x29, 0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21, 0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, + 0x18, 0x19, 0x16, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11, 0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09, 0x06, + 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, + 0x3f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, + 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, + 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, + 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25, + 0x24, 0x23, 0x22, 0x21, 0x20, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, + 0x31, 0x30, 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01, 0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09, 0x16, + 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11, 0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19, 0x26, 0x27, 0x24, 0x25, + 0x22, 0x23, 0x20, 0x21, 0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29, 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, + 0x31, 0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39, 0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e, 0x21, 0x20, + 0x23, 0x22, 0x25, 0x24, 0x27, 0x26, 0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e, 0x31, 0x30, 0x33, 0x32, 0x35, + 0x34, 0x37, 0x36, 0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, + 0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e, 0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16, 0x37, 0x36, 0x35, + 0x34, 0x33, 0x32, 0x31, 0x30, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, + 0x21, 0x20, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x1f, + 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, + 0x0b, 0x0a, 0x09, 0x08, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, + 0x17, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x38, 0x39, + 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x28, 0x29, 0x2a, 0x2b, 0x2c, + 0x2d, 0x2e, 0x2f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c, + 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c, 0x13, 0x12, 0x11, + 0x10, 0x17, 0x16, 0x15, 0x14, 0x2b, 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c, 0x23, 0x22, 0x21, 0x20, 0x27, 0x26, + 0x25, 0x24, 0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c, 0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34, 0x24, + 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23, 0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b, 0x34, 0x35, 0x36, 0x37, + 0x30, 0x31, 0x32, 0x33, 0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, + 0x03, 0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b, 0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13, 0x1c, 0x1d, + 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b, 0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d, 0x32, 0x33, 0x30, 0x31, 0x36, + 0x37, 0x34, 0x35, 0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d, 0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25, + 0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x0a, 0x0b, 0x08, + 0x09, 0x0e, 0x0f, 0x0c, 0x0d, 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x15, 0x14, 0x17, 0x16, 0x11, 0x10, + 0x13, 0x12, 0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a, 0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02, 0x0d, + 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a, 0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32, 0x3d, 0x3c, 0x3f, 0x3e, + 0x39, 0x38, 0x3b, 0x3a, 0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22, 0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, + 0x2a, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x38, 0x39, + 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x08, 0x09, 0x0a, 0x0b, 0x0c, + 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x0f, 0x0e, 0x0d, + 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, + 0x19, 0x18, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x37, + 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x19, 0x18, 0x1b, 0x1a, + 0x1d, 0x1c, 0x1f, 0x1e, 0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16, 0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, + 0x0e, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, 0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e, 0x31, 0x30, + 0x33, 0x32, 0x35, 0x34, 0x37, 0x36, 0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e, 0x21, 0x20, 0x23, 0x22, 0x25, + 0x24, 0x27, 0x26, 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31, 0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39, + 0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21, 0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29, 0x16, 0x17, 0x14, + 0x15, 0x12, 0x13, 0x10, 0x11, 0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19, 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, + 0x00, 0x01, 0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09, 0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22, 0x2d, + 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a, 0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32, 0x3d, 0x3c, 0x3f, 0x3e, + 0x39, 0x38, 0x3b, 0x3a, 0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02, 0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, + 0x0a, 0x15, 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12, 0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a, 0x0a, 0x0b, + 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d, 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x1a, 0x1b, 0x18, 0x19, 0x1e, + 0x1f, 0x1c, 0x1d, 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d, + 0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25, 0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d, 0x32, 0x33, 0x30, + 0x31, 0x36, 0x37, 0x34, 0x35, 0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, + 0x1a, 0x1b, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b, 0x34, + 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33, 0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b, 0x24, 0x25, 0x26, 0x27, + 0x20, 0x21, 0x22, 0x23, 0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b, 0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, + 0x3c, 0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34, 0x2b, 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c, 0x23, 0x22, + 0x21, 0x20, 0x27, 0x26, 0x25, 0x24, 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c, 0x13, 0x12, 0x11, 0x10, 0x17, + 0x16, 0x15, 0x14, 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, + 0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35, 0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d, 0x22, 0x23, 0x20, + 0x21, 0x26, 0x27, 0x24, 0x25, 0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d, 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, + 0x14, 0x15, 0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x0a, + 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d, 0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a, 0x15, 0x14, 0x17, 0x16, + 0x11, 0x10, 0x13, 0x12, 0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a, 0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, + 0x02, 0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a, 0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32, 0x2d, 0x2c, + 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a, 0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22, 0x03, 0x02, 0x01, 0x00, 0x07, + 0x06, 0x05, 0x04, 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c, 0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14, + 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c, 0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24, 0x2b, 0x2a, 0x29, + 0x28, 0x2f, 0x2e, 0x2d, 0x2c, 0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34, 0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, + 0x3d, 0x3c, 0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b, 0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23, 0x3c, + 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b, 0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33, 0x0c, 0x0d, 0x0e, 0x0f, + 0x08, 0x09, 0x0a, 0x0b, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, + 0x1b, 0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, + 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, + 0x22, 0x21, 0x20, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, + 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x10, 0x11, 0x12, + 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, + 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09, 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, + 0x01, 0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19, 0x16, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11, 0x2e, 0x2f, + 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29, 0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21, 0x3e, 0x3f, 0x3c, 0x3d, 0x3a, + 0x3b, 0x38, 0x39, 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31, 0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26, + 0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e, 0x31, 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36, 0x39, 0x38, 0x3b, + 0x3a, 0x3d, 0x3c, 0x3f, 0x3e, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, 0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, + 0x0f, 0x0e, 0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16, 0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e, 0x1b, + 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c, 0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14, 0x0b, 0x0a, 0x09, 0x08, + 0x0f, 0x0e, 0x0d, 0x0c, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, + 0x3c, 0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34, 0x2b, 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c, 0x23, 0x22, + 0x21, 0x20, 0x27, 0x26, 0x25, 0x24, 0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33, 0x3c, 0x3d, 0x3e, 0x3f, 0x38, + 0x39, 0x3a, 0x3b, 0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23, 0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b, + 0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b, 0x04, 0x05, 0x06, + 0x07, 0x00, 0x01, 0x02, 0x03, 0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b, 0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, + 0x2c, 0x2d, 0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25, 0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d, 0x32, + 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35, 0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d, 0x02, 0x03, 0x00, 0x01, + 0x06, 0x07, 0x04, 0x05, 0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, + 0x15, 0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02, 0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a, 0x15, 0x14, + 0x17, 0x16, 0x11, 0x10, 0x13, 0x12, 0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a, 0x25, 0x24, 0x27, 0x26, 0x21, + 0x20, 0x23, 0x22, 0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a, 0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32, + 0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a, 0x16, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11, 0x1e, 0x1f, 0x1c, + 0x1d, 0x1a, 0x1b, 0x18, 0x19, 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01, 0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, + 0x08, 0x09, 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31, 0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39, 0x26, + 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21, 0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29, 0x39, 0x38, 0x3b, 0x3a, + 0x3d, 0x3c, 0x3f, 0x3e, 0x31, 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36, 0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, + 0x2e, 0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26, 0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e, 0x11, 0x10, + 0x13, 0x12, 0x15, 0x14, 0x17, 0x16, 0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e, 0x01, 0x00, 0x03, 0x02, 0x05, + 0x04, 0x07, 0x06, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, + 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x07, 0x06, 0x05, + 0x04, 0x03, 0x02, 0x01, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, + 0x11, 0x10, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, + 0x27, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x01, 0x00, + 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, 0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e, 0x11, 0x10, 0x13, 0x12, 0x15, + 0x14, 0x17, 0x16, 0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e, 0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26, + 0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e, 0x31, 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36, 0x39, 0x38, 0x3b, + 0x3a, 0x3d, 0x3c, 0x3f, 0x3e, 0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29, 0x26, 0x27, 0x24, 0x25, 0x22, 0x23, + 0x20, 0x21, 0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39, 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31, 0x0e, + 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09, 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01, 0x1e, 0x1f, 0x1c, 0x1d, + 0x1a, 0x1b, 0x18, 0x19, 0x16, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, + 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, + 0x1d, 0x1e, 0x1f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e, 0x0d, + 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, + 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, + 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b, 0x04, 0x05, 0x06, 0x07, + 0x00, 0x01, 0x02, 0x03, 0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b, 0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, + 0x13, 0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b, 0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23, 0x3c, 0x3d, + 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b, 0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33, 0x23, 0x22, 0x21, 0x20, 0x27, + 0x26, 0x25, 0x24, 0x2b, 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c, 0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34, + 0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x0b, 0x0a, 0x09, + 0x08, 0x0f, 0x0e, 0x0d, 0x0c, 0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14, 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, + 0x1d, 0x1c, 0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a, 0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32, 0x2d, + 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a, 0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22, 0x1d, 0x1c, 0x1f, 0x1e, + 0x19, 0x18, 0x1b, 0x1a, 0x15, 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12, 0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, + 0x0a, 0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02, 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x1a, 0x1b, + 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x0a, 0x0b, 0x08, 0x09, 0x0e, + 0x0f, 0x0c, 0x0d, 0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35, 0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d, + 0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25, 0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d, 0x2f, 0x2e, 0x2d, + 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, + 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, + 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, + 0x13, 0x12, 0x11, 0x10, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, + 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, + 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, + 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19, + 0x16, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11, 0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09, 0x06, 0x07, 0x04, + 0x05, 0x02, 0x03, 0x00, 0x01, 0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39, 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, + 0x30, 0x31, 0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29, 0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21, 0x31, + 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36, 0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e, 0x21, 0x20, 0x23, 0x22, + 0x25, 0x24, 0x27, 0x26, 0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e, 0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, + 0x16, 0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, 0x09, 0x08, + 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e, 0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25, 0x2a, 0x2b, 0x28, 0x29, 0x2e, + 0x2f, 0x2c, 0x2d, 0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35, 0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d, + 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d, 0x12, 0x13, 0x10, + 0x11, 0x16, 0x17, 0x14, 0x15, 0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, + 0x0b, 0x0a, 0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02, 0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a, 0x15, + 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12, 0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a, 0x25, 0x24, 0x27, 0x26, + 0x21, 0x20, 0x23, 0x22, 0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a, 0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, + 0x32, 0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14, 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c, 0x03, 0x02, + 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c, 0x33, 0x32, 0x31, 0x30, 0x37, + 0x36, 0x35, 0x34, 0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c, 0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24, + 0x2b, 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c, 0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b, 0x34, 0x35, 0x36, + 0x37, 0x30, 0x31, 0x32, 0x33, 0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b, 0x24, 0x25, 0x26, 0x27, 0x20, 0x21, + 0x22, 0x23, 0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b, 0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13, 0x0c, + 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x35, 0x34, 0x37, 0x36, + 0x31, 0x30, 0x33, 0x32, 0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a, 0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, + 0x22, 0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a, 0x15, 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12, 0x1d, 0x1c, + 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a, 0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02, 0x0d, 0x0c, 0x0f, 0x0e, 0x09, + 0x08, 0x0b, 0x0a, 0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, + 0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d, 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x3a, 0x3b, 0x38, + 0x39, 0x3e, 0x3f, 0x3c, 0x3d, 0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35, 0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, + 0x2c, 0x2d, 0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x0c, + 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b, 0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x1f, + 0x18, 0x19, 0x1a, 0x1b, 0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23, 0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, + 0x2b, 0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33, 0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b, 0x2b, 0x2a, + 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c, 0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24, 0x3b, 0x3a, 0x39, 0x38, 0x3f, + 0x3e, 0x3d, 0x3c, 0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34, 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c, + 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c, 0x13, 0x12, 0x11, + 0x10, 0x17, 0x16, 0x15, 0x14, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, + 0x36, 0x37, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x18, + 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, + 0x10, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x0f, 0x0e, + 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, + 0x3a, 0x39, 0x38, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, + 0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, 0x19, 0x18, 0x1b, + 0x1a, 0x1d, 0x1c, 0x1f, 0x1e, 0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16, 0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, + 0x2f, 0x2e, 0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26, 0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e, 0x31, + 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36, 0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21, 0x2e, 0x2f, 0x2c, 0x2d, + 0x2a, 0x2b, 0x28, 0x29, 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31, 0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, + 0x39, 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01, 0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09, 0x16, 0x17, + 0x14, 0x15, 0x12, 0x13, 0x10, 0x11, 0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19, 0x12, 0x13, 0x10, 0x11, 0x16, + 0x17, 0x14, 0x15, 0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, + 0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d, 0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35, 0x3a, 0x3b, 0x38, + 0x39, 0x3e, 0x3f, 0x3c, 0x3d, 0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25, 0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, + 0x2c, 0x2d, 0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a, 0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32, 0x2d, + 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a, 0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22, 0x1d, 0x1c, 0x1f, 0x1e, + 0x19, 0x18, 0x1b, 0x1a, 0x15, 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12, 0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, + 0x0a, 0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02, 0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24, 0x2b, 0x2a, + 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c, 0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34, 0x3b, 0x3a, 0x39, 0x38, 0x3f, + 0x3e, 0x3d, 0x3c, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c, + 0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14, 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c, 0x0c, 0x0d, 0x0e, + 0x0f, 0x08, 0x09, 0x0a, 0x0b, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, + 0x1a, 0x1b, 0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13, 0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b, 0x24, + 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23, 0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b, 0x34, 0x35, 0x36, 0x37, + 0x30, 0x31, 0x32, 0x33, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, + 0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x3f, 0x3e, + 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, + 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, + 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, + 0x1e, 0x1f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x2e, + 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29, 0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21, 0x3e, 0x3f, 0x3c, 0x3d, + 0x3a, 0x3b, 0x38, 0x39, 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31, 0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, + 0x09, 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01, 0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19, 0x16, 0x17, + 0x14, 0x15, 0x12, 0x13, 0x10, 0x11, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, 0x09, 0x08, 0x0b, 0x0a, 0x0d, + 0x0c, 0x0f, 0x0e, 0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16, 0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e, + 0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26, 0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e, 0x31, 0x30, 0x33, + 0x32, 0x35, 0x34, 0x37, 0x36, 0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, + 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, + 0x37, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x37, 0x36, + 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x07, 0x06, 0x05, 0x04, 0x03, + 0x02, 0x01, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, + 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e, 0x31, 0x30, 0x33, + 0x32, 0x35, 0x34, 0x37, 0x36, 0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e, 0x21, 0x20, 0x23, 0x22, 0x25, 0x24, + 0x27, 0x26, 0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e, 0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16, 0x09, + 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, 0x16, 0x17, 0x14, 0x15, + 0x12, 0x13, 0x10, 0x11, 0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19, 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, + 0x01, 0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09, 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31, 0x3e, 0x3f, + 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39, 0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21, 0x2e, 0x2f, 0x2c, 0x2d, 0x2a, + 0x2b, 0x28, 0x29, 0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02, 0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a, + 0x15, 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12, 0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a, 0x25, 0x24, 0x27, + 0x26, 0x21, 0x20, 0x23, 0x22, 0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a, 0x35, 0x34, 0x37, 0x36, 0x31, 0x30, + 0x33, 0x32, 0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a, 0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d, 0x22, + 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25, 0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d, 0x32, 0x33, 0x30, 0x31, + 0x36, 0x37, 0x34, 0x35, 0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d, 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, + 0x05, 0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x34, 0x35, + 0x36, 0x37, 0x30, 0x31, 0x32, 0x33, 0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b, 0x24, 0x25, 0x26, 0x27, 0x20, + 0x21, 0x22, 0x23, 0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b, 0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13, + 0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x0c, 0x0d, 0x0e, + 0x0f, 0x08, 0x09, 0x0a, 0x0b, 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c, 0x13, 0x12, 0x11, 0x10, 0x17, 0x16, + 0x15, 0x14, 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x3b, + 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c, 0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34, 0x2b, 0x2a, 0x29, 0x28, + 0x2f, 0x2e, 0x2d, 0x2c, 0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24, 0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, + 0x21, 0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29, 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31, 0x3e, 0x3f, + 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39, 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01, 0x0e, 0x0f, 0x0c, 0x0d, 0x0a, + 0x0b, 0x08, 0x09, 0x16, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11, 0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19, + 0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, 0x19, 0x18, 0x1b, + 0x1a, 0x1d, 0x1c, 0x1f, 0x1e, 0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16, 0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, + 0x2f, 0x2e, 0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26, 0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e, 0x31, + 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x1f, 0x1e, 0x1d, 0x1c, + 0x1b, 0x1a, 0x19, 0x18, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, + 0x08, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x27, 0x26, + 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x38, 0x39, 0x3a, 0x3b, 0x3c, + 0x3d, 0x3e, 0x3f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x10, 0x11, 0x12, + 0x13, 0x14, 0x15, 0x16, 0x17, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x2b, 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c, 0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24, 0x3b, + 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c, 0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34, 0x0b, 0x0a, 0x09, 0x08, + 0x0f, 0x0e, 0x0d, 0x0c, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, + 0x1c, 0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x0c, 0x0d, + 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b, 0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x1f, 0x18, + 0x19, 0x1a, 0x1b, 0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23, 0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b, + 0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33, 0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b, 0x1a, 0x1b, 0x18, + 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, + 0x0c, 0x0d, 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d, 0x32, + 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35, 0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d, 0x22, 0x23, 0x20, 0x21, + 0x26, 0x27, 0x24, 0x25, 0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32, 0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, + 0x3a, 0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22, 0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a, 0x15, 0x14, + 0x17, 0x16, 0x11, 0x10, 0x13, 0x12, 0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a, 0x05, 0x04, 0x07, 0x06, 0x01, + 0x00, 0x03, 0x02, 0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a, 0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b, + 0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33, 0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b, 0x24, 0x25, 0x26, + 0x27, 0x20, 0x21, 0x22, 0x23, 0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b, 0x14, 0x15, 0x16, 0x17, 0x10, 0x11, + 0x12, 0x13, 0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x13, + 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14, 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c, 0x03, 0x02, 0x01, 0x00, + 0x07, 0x06, 0x05, 0x04, 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c, 0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, + 0x34, 0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c, 0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24, 0x2b, 0x2a, + 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c, 0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a, 0x05, 0x04, 0x07, 0x06, 0x01, + 0x00, 0x03, 0x02, 0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a, 0x15, 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12, + 0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a, 0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22, 0x3d, 0x3c, 0x3f, + 0x3e, 0x39, 0x38, 0x3b, 0x3a, 0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32, 0x22, 0x23, 0x20, 0x21, 0x26, 0x27, + 0x24, 0x25, 0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d, 0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35, 0x3a, + 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d, 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x0a, 0x0b, 0x08, 0x09, + 0x0e, 0x0f, 0x0c, 0x0d, 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, + 0x1d, 0x31, 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36, 0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e, 0x21, 0x20, + 0x23, 0x22, 0x25, 0x24, 0x27, 0x26, 0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e, 0x11, 0x10, 0x13, 0x12, 0x15, + 0x14, 0x17, 0x16, 0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, + 0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e, 0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19, 0x16, 0x17, 0x14, + 0x15, 0x12, 0x13, 0x10, 0x11, 0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09, 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, + 0x00, 0x01, 0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39, 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31, 0x2e, + 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29, 0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21, 0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, + 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, + 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, + 0x3d, 0x3e, 0x3f, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, + 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x0f, 0x0e, 0x0d, + 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, + 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x15, 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12, 0x1d, + 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a, 0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02, 0x0d, 0x0c, 0x0f, 0x0e, + 0x09, 0x08, 0x0b, 0x0a, 0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32, 0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, + 0x3a, 0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22, 0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a, 0x3a, 0x3b, + 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d, 0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35, 0x2a, 0x2b, 0x28, 0x29, 0x2e, + 0x2f, 0x2c, 0x2d, 0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25, 0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, + 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d, 0x02, 0x03, 0x00, + 0x01, 0x06, 0x07, 0x04, 0x05, 0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23, 0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, + 0x2a, 0x2b, 0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33, 0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b, 0x04, + 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b, 0x14, 0x15, 0x16, 0x17, + 0x10, 0x11, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b, 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, + 0x0c, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c, 0x13, 0x12, + 0x11, 0x10, 0x17, 0x16, 0x15, 0x14, 0x2b, 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c, 0x23, 0x22, 0x21, 0x20, 0x27, + 0x26, 0x25, 0x24, 0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c, 0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x08, 0x09, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, + 0x3e, 0x3f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x20, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x3f, 0x3e, 0x3d, 0x3c, + 0x3b, 0x3a, 0x39, 0x38, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, + 0x28, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x07, 0x06, + 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x29, 0x28, 0x2b, 0x2a, 0x2d, + 0x2c, 0x2f, 0x2e, 0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26, 0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e, + 0x31, 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36, 0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e, 0x01, 0x00, 0x03, + 0x02, 0x05, 0x04, 0x07, 0x06, 0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e, 0x11, 0x10, 0x13, 0x12, 0x15, 0x14, + 0x17, 0x16, 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01, 0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09, 0x16, + 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11, 0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19, 0x26, 0x27, 0x24, 0x25, + 0x22, 0x23, 0x20, 0x21, 0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29, 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, + 0x31, 0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, + 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, + 0x12, 0x11, 0x10, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, + 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x20, 0x21, 0x22, + 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, + 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f, 0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39, 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, + 0x31, 0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29, 0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21, 0x1e, 0x1f, + 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19, 0x16, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11, 0x0e, 0x0f, 0x0c, 0x0d, 0x0a, + 0x0b, 0x08, 0x09, 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01, 0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16, + 0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, 0x09, 0x08, 0x0b, + 0x0a, 0x0d, 0x0c, 0x0f, 0x0e, 0x31, 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36, 0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, + 0x3f, 0x3e, 0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26, 0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e, 0x02, + 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d, 0x12, 0x13, 0x10, 0x11, + 0x16, 0x17, 0x14, 0x15, 0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, + 0x25, 0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d, 0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35, 0x3a, 0x3b, + 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d, 0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a, 0x25, 0x24, 0x27, 0x26, 0x21, + 0x20, 0x23, 0x22, 0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a, 0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32, + 0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a, 0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02, 0x1d, 0x1c, 0x1f, + 0x1e, 0x19, 0x18, 0x1b, 0x1a, 0x15, 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12, 0x33, 0x32, 0x31, 0x30, 0x37, 0x36, + 0x35, 0x34, 0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c, 0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24, 0x2b, + 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c, 0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14, 0x1b, 0x1a, 0x19, 0x18, + 0x1f, 0x1e, 0x1d, 0x1c, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, + 0x0c, 0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b, 0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13, 0x0c, 0x0d, + 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x3c, 0x3d, 0x3e, 0x3f, 0x38, + 0x39, 0x3a, 0x3b, 0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33, 0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b, + 0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23, 0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26, 0x29, 0x28, 0x2b, + 0x2a, 0x2d, 0x2c, 0x2f, 0x2e, 0x31, 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36, 0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, + 0x3f, 0x3e, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, 0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e, 0x11, + 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16, 0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e, 0x0e, 0x0f, 0x0c, 0x0d, + 0x0a, 0x0b, 0x08, 0x09, 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01, 0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, + 0x19, 0x16, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11, 0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29, 0x26, 0x27, + 0x24, 0x25, 0x22, 0x23, 0x20, 0x21, 0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39, 0x36, 0x37, 0x34, 0x35, 0x32, + 0x33, 0x30, 0x31, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x30, 0x31, 0x32, + 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, + 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, + 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, + 0x23, 0x22, 0x21, 0x20, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, + 0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x2c, 0x2d, + 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b, 0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23, 0x3c, 0x3d, 0x3e, 0x3f, 0x38, + 0x39, 0x3a, 0x3b, 0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33, 0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b, + 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b, 0x14, 0x15, 0x16, + 0x17, 0x10, 0x11, 0x12, 0x13, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, + 0x0d, 0x0c, 0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14, 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c, 0x23, + 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24, 0x2b, 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c, 0x33, 0x32, 0x31, 0x30, + 0x37, 0x36, 0x35, 0x34, 0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c, 0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, + 0x1a, 0x15, 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12, 0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a, 0x05, 0x04, + 0x07, 0x06, 0x01, 0x00, 0x03, 0x02, 0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a, 0x35, 0x34, 0x37, 0x36, 0x31, + 0x30, 0x33, 0x32, 0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a, 0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22, + 0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35, 0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d, 0x22, 0x23, 0x20, + 0x21, 0x26, 0x27, 0x24, 0x25, 0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d, 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, + 0x14, 0x15, 0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x0a, + 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d, 0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c, 0x33, 0x32, 0x31, 0x30, + 0x37, 0x36, 0x35, 0x34, 0x2b, 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c, 0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, + 0x24, 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c, 0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14, 0x0b, 0x0a, + 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x14, 0x15, 0x16, 0x17, 0x10, + 0x11, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, + 0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b, 0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33, 0x3c, 0x3d, 0x3e, + 0x3f, 0x38, 0x39, 0x3a, 0x3b, 0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23, 0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, + 0x2a, 0x2b, 0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d, 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x1a, + 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x2a, 0x2b, 0x28, 0x29, + 0x2e, 0x2f, 0x2c, 0x2d, 0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25, 0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, + 0x3d, 0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35, 0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22, 0x2d, 0x2c, + 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a, 0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32, 0x3d, 0x3c, 0x3f, 0x3e, 0x39, + 0x38, 0x3b, 0x3a, 0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02, 0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a, + 0x15, 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12, 0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a, 0x36, 0x37, 0x34, + 0x35, 0x32, 0x33, 0x30, 0x31, 0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39, 0x26, 0x27, 0x24, 0x25, 0x22, 0x23, + 0x20, 0x21, 0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29, 0x16, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11, 0x1e, + 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19, 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01, 0x0e, 0x0f, 0x0c, 0x0d, + 0x0a, 0x0b, 0x08, 0x09, 0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e, 0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, + 0x16, 0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, 0x39, 0x38, + 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e, 0x31, 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36, 0x29, 0x28, 0x2b, 0x2a, 0x2d, + 0x2c, 0x2f, 0x2e, 0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, + 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x1f, 0x1e, 0x1d, + 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, + 0x29, 0x28, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x28, + 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x38, 0x39, 0x3a, 0x3b, + 0x3c, 0x3d, 0x3e, 0x3f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, + 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x10, 0x11, + 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, }; uint16_t update_crc6_by_bytes(uint16_t crc6, uint8_t byte1, uint8_t byte2) { - int bit; - uint32_t remainder = ( byte1<<8 | byte2 ) << 6; + int bit; + uint32_t remainder = (byte1 << 8 | byte2) << 6; uint32_t polynomial = 0x6F << 15; - for (bit = 15; - bit >= 0; - --bit) + for (bit = 15; bit >= 0; --bit) { if (remainder & (0x40 << bit)) { @@ -1150,10 +986,10 @@ uint16_t update_crc6_by_bytes(uint16_t crc6, uint8_t byte1, uint8_t byte2) return (uint16_t)(remainder ^ crc6); } -uint16_t crc6_compute(const uint8_t *data_blk_ptr, int data_blk_size) +uint16_t crc6_compute(const uint8_t* data_blk_ptr, int data_blk_size) { uint16_t h; - int byteIndex; + int byteIndex; h = 0; byteIndex = 0; @@ -1169,8 +1005,7 @@ uint16_t crc6_compute(const uint8_t *data_blk_ptr, int data_blk_size) h = crc6_table[h]; byteIndex++; - } - while (byteIndex < data_blk_size); + } while (byteIndex < data_blk_size); return h; } @@ -1185,50 +1020,34 @@ uint16_t crc6_compute(const uint8_t *data_blk_ptr, int data_blk_size) * routine at run time, and with various data type cleanups. */ static const uint16_t byte_crc10_table[256] = { - 0x0000, 0x0233, 0x0255, 0x0066, 0x0299, 0x00aa, 0x00cc, 0x02ff, - 0x0301, 0x0132, 0x0154, 0x0367, 0x0198, 0x03ab, 0x03cd, 0x01fe, - 0x0031, 0x0202, 0x0264, 0x0057, 0x02a8, 0x009b, 0x00fd, 0x02ce, - 0x0330, 0x0103, 0x0165, 0x0356, 0x01a9, 0x039a, 0x03fc, 0x01cf, - 0x0062, 0x0251, 0x0237, 0x0004, 0x02fb, 0x00c8, 0x00ae, 0x029d, - 0x0363, 0x0150, 0x0136, 0x0305, 0x01fa, 0x03c9, 0x03af, 0x019c, - 0x0053, 0x0260, 0x0206, 0x0035, 0x02ca, 0x00f9, 0x009f, 0x02ac, - 0x0352, 0x0161, 0x0107, 0x0334, 0x01cb, 0x03f8, 0x039e, 0x01ad, - 0x00c4, 0x02f7, 0x0291, 0x00a2, 0x025d, 0x006e, 0x0008, 0x023b, - 0x03c5, 0x01f6, 0x0190, 0x03a3, 0x015c, 0x036f, 0x0309, 0x013a, - 0x00f5, 0x02c6, 0x02a0, 0x0093, 0x026c, 0x005f, 0x0039, 0x020a, - 0x03f4, 0x01c7, 0x01a1, 0x0392, 0x016d, 0x035e, 0x0338, 0x010b, - 0x00a6, 0x0295, 0x02f3, 0x00c0, 0x023f, 0x000c, 0x006a, 0x0259, - 0x03a7, 0x0194, 0x01f2, 0x03c1, 0x013e, 0x030d, 0x036b, 0x0158, - 0x0097, 0x02a4, 0x02c2, 0x00f1, 0x020e, 0x003d, 0x005b, 0x0268, - 0x0396, 0x01a5, 0x01c3, 0x03f0, 0x010f, 0x033c, 0x035a, 0x0169, - 0x0188, 0x03bb, 0x03dd, 0x01ee, 0x0311, 0x0122, 0x0144, 0x0377, - 0x0289, 0x00ba, 0x00dc, 0x02ef, 0x0010, 0x0223, 0x0245, 0x0076, - 0x01b9, 0x038a, 0x03ec, 0x01df, 0x0320, 0x0113, 0x0175, 0x0346, - 0x02b8, 0x008b, 0x00ed, 0x02de, 0x0021, 0x0212, 0x0274, 0x0047, - 0x01ea, 0x03d9, 0x03bf, 0x018c, 0x0373, 0x0140, 0x0126, 0x0315, - 0x02eb, 0x00d8, 0x00be, 0x028d, 0x0072, 0x0241, 0x0227, 0x0014, - 0x01db, 0x03e8, 0x038e, 0x01bd, 0x0342, 0x0171, 0x0117, 0x0324, - 0x02da, 0x00e9, 0x008f, 0x02bc, 0x0043, 0x0270, 0x0216, 0x0025, - 0x014c, 0x037f, 0x0319, 0x012a, 0x03d5, 0x01e6, 0x0180, 0x03b3, - 0x024d, 0x007e, 0x0018, 0x022b, 0x00d4, 0x02e7, 0x0281, 0x00b2, - 0x017d, 0x034e, 0x0328, 0x011b, 0x03e4, 0x01d7, 0x01b1, 0x0382, - 0x027c, 0x004f, 0x0029, 0x021a, 0x00e5, 0x02d6, 0x02b0, 0x0083, - 0x012e, 0x031d, 0x037b, 0x0148, 0x03b7, 0x0184, 0x01e2, 0x03d1, - 0x022f, 0x001c, 0x007a, 0x0249, 0x00b6, 0x0285, 0x02e3, 0x00d0, - 0x011f, 0x032c, 0x034a, 0x0179, 0x0386, 0x01b5, 0x01d3, 0x03e0, - 0x021e, 0x002d, 0x004b, 0x0278, 0x0087, 0x02b4, 0x02d2, 0x00e1 -}; + 0x0000, 0x0233, 0x0255, 0x0066, 0x0299, 0x00aa, 0x00cc, 0x02ff, 0x0301, 0x0132, 0x0154, 0x0367, 0x0198, 0x03ab, + 0x03cd, 0x01fe, 0x0031, 0x0202, 0x0264, 0x0057, 0x02a8, 0x009b, 0x00fd, 0x02ce, 0x0330, 0x0103, 0x0165, 0x0356, + 0x01a9, 0x039a, 0x03fc, 0x01cf, 0x0062, 0x0251, 0x0237, 0x0004, 0x02fb, 0x00c8, 0x00ae, 0x029d, 0x0363, 0x0150, + 0x0136, 0x0305, 0x01fa, 0x03c9, 0x03af, 0x019c, 0x0053, 0x0260, 0x0206, 0x0035, 0x02ca, 0x00f9, 0x009f, 0x02ac, + 0x0352, 0x0161, 0x0107, 0x0334, 0x01cb, 0x03f8, 0x039e, 0x01ad, 0x00c4, 0x02f7, 0x0291, 0x00a2, 0x025d, 0x006e, + 0x0008, 0x023b, 0x03c5, 0x01f6, 0x0190, 0x03a3, 0x015c, 0x036f, 0x0309, 0x013a, 0x00f5, 0x02c6, 0x02a0, 0x0093, + 0x026c, 0x005f, 0x0039, 0x020a, 0x03f4, 0x01c7, 0x01a1, 0x0392, 0x016d, 0x035e, 0x0338, 0x010b, 0x00a6, 0x0295, + 0x02f3, 0x00c0, 0x023f, 0x000c, 0x006a, 0x0259, 0x03a7, 0x0194, 0x01f2, 0x03c1, 0x013e, 0x030d, 0x036b, 0x0158, + 0x0097, 0x02a4, 0x02c2, 0x00f1, 0x020e, 0x003d, 0x005b, 0x0268, 0x0396, 0x01a5, 0x01c3, 0x03f0, 0x010f, 0x033c, + 0x035a, 0x0169, 0x0188, 0x03bb, 0x03dd, 0x01ee, 0x0311, 0x0122, 0x0144, 0x0377, 0x0289, 0x00ba, 0x00dc, 0x02ef, + 0x0010, 0x0223, 0x0245, 0x0076, 0x01b9, 0x038a, 0x03ec, 0x01df, 0x0320, 0x0113, 0x0175, 0x0346, 0x02b8, 0x008b, + 0x00ed, 0x02de, 0x0021, 0x0212, 0x0274, 0x0047, 0x01ea, 0x03d9, 0x03bf, 0x018c, 0x0373, 0x0140, 0x0126, 0x0315, + 0x02eb, 0x00d8, 0x00be, 0x028d, 0x0072, 0x0241, 0x0227, 0x0014, 0x01db, 0x03e8, 0x038e, 0x01bd, 0x0342, 0x0171, + 0x0117, 0x0324, 0x02da, 0x00e9, 0x008f, 0x02bc, 0x0043, 0x0270, 0x0216, 0x0025, 0x014c, 0x037f, 0x0319, 0x012a, + 0x03d5, 0x01e6, 0x0180, 0x03b3, 0x024d, 0x007e, 0x0018, 0x022b, 0x00d4, 0x02e7, 0x0281, 0x00b2, 0x017d, 0x034e, + 0x0328, 0x011b, 0x03e4, 0x01d7, 0x01b1, 0x0382, 0x027c, 0x004f, 0x0029, 0x021a, 0x00e5, 0x02d6, 0x02b0, 0x0083, + 0x012e, 0x031d, 0x037b, 0x0148, 0x03b7, 0x0184, 0x01e2, 0x03d1, 0x022f, 0x001c, 0x007a, 0x0249, 0x00b6, 0x0285, + 0x02e3, 0x00d0, 0x011f, 0x032c, 0x034a, 0x0179, 0x0386, 0x01b5, 0x01d3, 0x03e0, 0x021e, 0x002d, 0x004b, 0x0278, + 0x0087, 0x02b4, 0x02d2, 0x00e1}; /* Update the data block's CRC-10 remainder one byte at a time */ -uint16_t update_crc10_by_bytes(uint16_t crc10_accum, const uint8_t *data_blk_ptr, int data_blk_size) +uint16_t update_crc10_by_bytes(uint16_t crc10_accum, const uint8_t* data_blk_ptr, int data_blk_size) { /*register*/ int i; - for (i = 0; i < data_blk_size; i++) { - crc10_accum = ((crc10_accum << 8) & 0x3ff) - ^ byte_crc10_table[( crc10_accum >> 2) & 0xff] - ^ *data_blk_ptr++; + for (i = 0; i < data_blk_size; i++) + { + crc10_accum = ((crc10_accum << 8) & 0x3ff) ^ byte_crc10_table[(crc10_accum >> 2) & 0xff] ^ *data_blk_ptr++; } return crc10_accum; } - diff --git a/src/engine/helper/HL_IuUP.h b/src/engine/helper/HL_IuUP.h index 022d7e7e..d4e7da1a 100644 --- a/src/engine/helper/HL_IuUP.h +++ b/src/engine/helper/HL_IuUP.h @@ -6,34 +6,33 @@ class IuUP { public: - enum class PduType - { - DataWithCrc = 0, - DataNoCrc = 1, - ControlProc = 14 - }; + enum class PduType + { + DataWithCrc = 0, + DataNoCrc = 1, + ControlProc = 14 + }; - struct Frame - { - PduType mPduType; - uint8_t mFrameNumber; - uint8_t mFqc; - uint8_t mRfci; - uint8_t mHeaderCrc; - bool mHeaderCrcOk; - uint16_t mPayloadCrc; - bool mPayloadCrcOk; - const uint8_t* mPayload; - uint16_t mPayloadSize; - }; + struct Frame + { + PduType mPduType; + uint8_t mFrameNumber; + uint8_t mFqc; + uint8_t mRfci; + uint8_t mHeaderCrc; + bool mHeaderCrcOk; + uint16_t mPayloadCrc; + bool mPayloadCrcOk; + const uint8_t* mPayload; + uint16_t mPayloadSize; + }; - /* Default value is false */ - static bool TwoBytePseudoheader; + /* Default value is false */ + static bool TwoBytePseudoheader; - static bool parse(const uint8_t* packet, int size, Frame& result); - static bool parse2(const uint8_t* packet, int size, Frame& result); + static bool parse(const uint8_t* packet, int size, Frame& result); + static bool parse2(const uint8_t* packet, int size, Frame& result); }; #endif // HL_IUUP_H - diff --git a/src/engine/helper/HL_Log.cpp b/src/engine/helper/HL_Log.cpp index e7c7b17c..f4d74b33 100644 --- a/src/engine/helper/HL_Log.cpp +++ b/src/engine/helper/HL_Log.cpp @@ -2,4 +2,3 @@ * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - diff --git a/src/engine/helper/HL_Log.h b/src/engine/helper/HL_Log.h index d594d3bf..5b9270be 100644 --- a/src/engine/helper/HL_Log.h +++ b/src/engine/helper/HL_Log.h @@ -11,13 +11,13 @@ using ice::GLogger; using ice::LogLock; -using ice::LL_MEDIA; -using ice::LL_DEBUG; -using ice::LL_INFO; using ice::LL_CRITICAL; +using ice::LL_DEBUG; +using ice::LL_ERROR; +using ice::LL_INFO; +using ice::LL_MEDIA; using ice::LL_NONE; using ice::LL_SPECIAL; -using ice::LL_ERROR; using ice::LogLevelHelper; #endif diff --git a/src/engine/helper/HL_NetworkFrame.cpp b/src/engine/helper/HL_NetworkFrame.cpp index 8200bd46..ac078b18 100644 --- a/src/engine/helper/HL_NetworkFrame.cpp +++ b/src/engine/helper/HL_NetworkFrame.cpp @@ -3,10 +3,10 @@ #include "HL_NetworkFrame.h" #include "HL_InternetAddress.h" -#define ETHERTYPE_MPLS_UC (0x8847) -#define ETHERTYPE_MPLS_MC (0x8848) -#define ETHERTYPE_IPV6 (0x86dd) -#define ETHERTYPE_IP (0x0800) +#define ETHERTYPE_MPLS_UC (0x8847) +#define ETHERTYPE_MPLS_MC (0x8848) +#define ETHERTYPE_IPV6 (0x86dd) +#define ETHERTYPE_IP (0x0800) #define MPLS_STACK_MASK (0x00000100) #define MPLS_STACK_SHIFT (8) @@ -34,7 +34,7 @@ NetworkFrame::Payload NetworkFrame::GetUdpPayloadForRaw(const Packet& data) NetworkFrame::Payload NetworkFrame::GetUdpPayloadForEthernet(const Packet& data) { - Packet result(data); + Packet result(data); const EthernetHeader* ethernet = reinterpret_cast(data.mData); @@ -53,8 +53,7 @@ NetworkFrame::Payload NetworkFrame::GetUdpPayloadForEthernet(const Packet& data) result.mData += sizeof(VlanHeader); result.mLength -= sizeof(VlanHeader); proto = ntohs(vlan->mData); - } - while (proto == 0x8100); + } while (proto == 0x8100); } // Skip MPLS headers @@ -63,11 +62,11 @@ NetworkFrame::Payload NetworkFrame::GetUdpPayloadForEthernet(const Packet& data) case ETHERTYPE_MPLS_UC: case ETHERTYPE_MPLS_MC: // Parse MPLS here until marker "bottom of mpls stack" - for(bool bottomOfStack = false; !bottomOfStack; - bottomOfStack = ((ntohl(*(uint32_t*)(result.mData - 4)) & MPLS_STACK_MASK) >> MPLS_STACK_SHIFT) != 0) + for (bool bottomOfStack = false; !bottomOfStack; + bottomOfStack = ((ntohl(*(uint32_t*)(result.mData - 4)) & MPLS_STACK_MASK) >> MPLS_STACK_SHIFT) != 0) { result.mData += 4; - result.mLength -=4; + result.mLength -= 4; } break; @@ -156,7 +155,7 @@ NetworkFrame::Payload NetworkFrame::GetUdpPayloadForLoopback(const Packet& data) NetworkFrame::Payload NetworkFrame::GetUdpPayloadForIp4(const Packet& data) { - Packet result(data); + Packet result(data); const Ip4Header* ip4 = reinterpret_cast(data.mData); if (ip4->mProtocol != IPPROTO_UDP && ip4->mProtocol != 0) return Payload(); @@ -187,40 +186,36 @@ NetworkFrame::Payload NetworkFrame::GetUdpPayloadForIp4(const Packet& data) struct Ip6Header { #if __BYTE_ORDER == __LITTLE_ENDIAN - uint8_t traffic_class_hi:4, - version:4; - uint8_t flow_label_hi:4, - traffic_class_lo:4; - uint16_t flow_label_lo; + uint8_t traffic_class_hi : 4, version : 4; + uint8_t flow_label_hi : 4, traffic_class_lo : 4; + uint16_t flow_label_lo; #elif __BYTE_ORDER == __BIG_ENDIAN - uint8_t version:4, - traffic_class_hi:4; - uint8_t traffic_class_lo:4, - flow_label_hi:4; - uint16_t flow_label_lo; + uint8_t version : 4, traffic_class_hi : 4; + uint8_t traffic_class_lo : 4, flow_label_hi : 4; + uint16_t flow_label_lo; #else -# error "Please fix endianness defines" +#error "Please fix endianness defines" #endif - uint16_t payload_len; - uint8_t next_header; - uint8_t hop_limit; + uint16_t payload_len; + uint8_t next_header; + uint8_t hop_limit; - struct in6_addr src_ip; - struct in6_addr dst_ip; + struct in6_addr src_ip; + struct in6_addr dst_ip; }; NetworkFrame::Payload NetworkFrame::GetUdpPayloadForIp6(const Packet& data) { - Packet result(data); + Packet result(data); const Ip6Header* ip6 = reinterpret_cast(result.mData); /*if (ip6->mProtocol != IPPROTO_UDP && ip4->mProtocol != 0) return PacketData(nullptr, 0); */ result.mData += sizeof(Ip6Header); result.mLength -= sizeof(Ip6Header); - //std::cout << sizeof(Ip6Header) << std::endl; + // std::cout << sizeof(Ip6Header) << std::endl; const UdpHeader* udp = reinterpret_cast(result.mData); result.mData += sizeof(UdpHeader); diff --git a/src/engine/helper/HL_NetworkFrame.h b/src/engine/helper/HL_NetworkFrame.h index ef15eead..60fe2cb5 100644 --- a/src/engine/helper/HL_NetworkFrame.h +++ b/src/engine/helper/HL_NetworkFrame.h @@ -10,25 +10,18 @@ public: struct Packet { const uint8_t* mData; - size_t mLength; + size_t mLength; - Packet(const uint8_t* data, size_t length) - :mData(data), mLength(length) - {} + Packet(const uint8_t* data, size_t length) : mData(data), mLength(length) {} - Packet() - :mData(nullptr), mLength(0) - {} + Packet() : mData(nullptr), mLength(0) {} - bool is_empty() const - { - return mData == nullptr || mLength == 0; - } + bool is_empty() const { return mData == nullptr || mLength == 0; } }; struct Payload { - Packet data; + Packet data; InternetAddress source; InternetAddress dest; }; @@ -44,14 +37,14 @@ public: { /* Ethernet addresses are 6 bytes */ static const int AddressLength = 6; - uint8_t mEtherDHost[AddressLength]; /* Destination host address */ - uint8_t mEtherSHost[AddressLength]; /* Source host address */ - uint16_t mEtherType; /* IP? ARP? RARP? etc */ + uint8_t mEtherDHost[AddressLength]; /* Destination host address */ + uint8_t mEtherSHost[AddressLength]; /* Source host address */ + uint16_t mEtherType; /* IP? ARP? RARP? etc */ }; #if defined(TARGET_WIN) struct /*__attribute__((packed))*/ LinuxSllHeader - #else +#else struct __attribute__((packed)) LinuxSllHeader #endif { @@ -70,55 +63,48 @@ public: struct Ip4Header { - uint8_t mVhl; /* version << 4 | header length >> 2 */ - uint8_t mTos; /* type of service */ - uint16_t mLen; /* total length */ - uint16_t mId; /* identification */ - uint16_t mOffset; /* fragment offset field */ -#define IP_RF 0x8000 /* reserved fragment flag */ -#define IP_DF 0x4000 /* dont fragment flag */ -#define IP_MF 0x2000 /* more fragments flag */ -#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ - uint8_t mTtl; /* time to live */ - uint8_t mProtocol; /* protocol */ - uint16_t mChecksum; /* checksum */ - in_addr mSource, - mDestination; /* source and dest address */ + uint8_t mVhl; /* version << 4 | header length >> 2 */ + uint8_t mTos; /* type of service */ + uint16_t mLen; /* total length */ + uint16_t mId; /* identification */ + uint16_t mOffset; /* fragment offset field */ +#define IP_RF 0x8000 /* reserved fragment flag */ +#define IP_DF 0x4000 /* dont fragment flag */ +#define IP_MF 0x2000 /* more fragments flag */ +#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ + uint8_t mTtl; /* time to live */ + uint8_t mProtocol; /* protocol */ + uint16_t mChecksum; /* checksum */ + in_addr mSource, mDestination; /* source and dest address */ - int headerLength() const - { - return (mVhl & 0x0f) * 4; - } + int headerLength() const { return (mVhl & 0x0f) * 4; } - int version() const - { - return mVhl >> 4; - } + int version() const { return mVhl >> 4; } - const in_addr& source4() const { return mSource; } - const in_addr& dest4() const { return mDestination; } + const in_addr& source4() const { return mSource; } + const in_addr& dest4() const { return mDestination; } const in6_addr& source6() const { return (const in6_addr&)mSource; } - const in6_addr& dest6() const { return (const in6_addr&)mDestination; } + const in6_addr& dest6() const { return (const in6_addr&)mDestination; } }; struct UdpHeader { - uint16_t mSourcePort; /* source port */ - uint16_t mDestinationPort; - uint16_t mDatagramLength; /* datagram length */ - uint16_t mDatagramChecksum; /* datagram checksum */ + uint16_t mSourcePort; /* source port */ + uint16_t mDestinationPort; + uint16_t mDatagramLength; /* datagram length */ + uint16_t mDatagramChecksum; /* datagram checksum */ }; struct TcpHeader { - uint16_t mSourcePort; /* source port */ - uint16_t mDestinationPort; /* destination port */ - uint32_t mSeqNo; /* sequence number */ - uint32_t mAckNo; /* acknowledgement number */ - uint32_t mDataOffset; /* data offset, rsvd */ -#define TH_OFF(th) (((th)->th_offx2 & 0xf0) >> 4) - uint8_t mFlags; + uint16_t mSourcePort; /* source port */ + uint16_t mDestinationPort; /* destination port */ + uint32_t mSeqNo; /* sequence number */ + uint32_t mAckNo; /* acknowledgement number */ + uint32_t mDataOffset; /* data offset, rsvd */ +#define TH_OFF(th) (((th)->th_offx2 & 0xf0) >> 4) + uint8_t mFlags; #define TH_FIN 0x01 #define TH_SYN 0x02 #define TH_RST 0x04 @@ -127,11 +113,10 @@ public: #define TH_URG 0x20 #define TH_ECE 0x40 #define TH_CWR 0x80 -#define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR) - uint16_t mWindow; /* window */ - uint16_t mChecksum; /* checksum */ - uint16_t mUrgentPointer; /* urgent pointer */ +#define TH_FLAGS (TH_FIN | TH_SYN | TH_RST | TH_ACK | TH_URG | TH_ECE | TH_CWR) + uint16_t mWindow; /* window */ + uint16_t mChecksum; /* checksum */ + uint16_t mUrgentPointer; /* urgent pointer */ }; - }; #endif diff --git a/src/engine/helper/HL_NetworkSocket.cpp b/src/engine/helper/HL_NetworkSocket.cpp index 2d0802ce..9b32dfce 100644 --- a/src/engine/helper/HL_NetworkSocket.cpp +++ b/src/engine/helper/HL_NetworkSocket.cpp @@ -4,7 +4,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #if defined(TARGET_LINUX) || defined(TARGET_ANDROID) -# include +#include #endif #include "../engine_config.h" @@ -12,19 +12,17 @@ #include "HL_Log.h" #if defined(TARGET_OSX) || defined(TARGET_LINUX) -# include +#include #endif #if !defined(TARGET_WIN) -# include +#include #endif #include #define LOG_SUBSYSTEM "network" -DatagramSocket::DatagramSocket() - :mFamily(AF_INET), mHandle(INVALID_SOCKET), mLocalPort(0) -{} +DatagramSocket::DatagramSocket() : mFamily(AF_INET), mHandle(INVALID_SOCKET), mLocalPort(0) {} DatagramSocket::~DatagramSocket() { @@ -41,10 +39,12 @@ void DatagramSocket::open(int family) mHandle = ::socket(mFamily, SOCK_DGRAM, IPPROTO_UDP); if (mHandle != INVALID_SOCKET) { - sockaddr_in addr4; sockaddr_in6 addr6; - memset(&addr4, 0, sizeof(addr4)); memset(&addr6, 0, sizeof(addr6)); + sockaddr_in addr4; + sockaddr_in6 addr6; + memset(&addr4, 0, sizeof(addr4)); + memset(&addr6, 0, sizeof(addr6)); socklen_t l = mFamily == AF_INET ? sizeof(addr4) : sizeof(addr6); - int retcode = getsockname(mHandle, (mFamily == AF_INET ? (sockaddr*)&addr4 : (sockaddr*)&addr6), &l); + int retcode = getsockname(mHandle, (mFamily == AF_INET ? (sockaddr*)&addr4 : (sockaddr*)&addr6), &l); if (!retcode) { mLocalPort = ntohs(mFamily == AF_INET ? addr4.sin_port : addr6.sin6_port); @@ -57,27 +57,34 @@ int DatagramSocket::localport() return mLocalPort; } -void DatagramSocket::sendDatagram(InternetAddress &dest, const void *packetData, unsigned int packetSize) +void DatagramSocket::sendDatagram(InternetAddress& dest, const void* packetData, unsigned int packetSize) { if (mHandle == INVALID_SOCKET) return; - /*int sent = */::sendto(mHandle, (const char*)packetData, packetSize, 0, dest.genericsockaddr(), dest.sockaddrLen()); + /*int sent = */ ::sendto(mHandle, (const char*)packetData, packetSize, 0, dest.genericsockaddr(), + dest.sockaddrLen()); } -unsigned DatagramSocket::recvDatagram(InternetAddress &src, void *packetBuffer, unsigned packetCapacity) +unsigned DatagramSocket::recvDatagram(InternetAddress& src, void* packetBuffer, unsigned packetCapacity) { if (mHandle == INVALID_SOCKET) return 0; - sockaddr* addr = nullptr; - socklen_t addrLen = 0; - sockaddr_in addr_4 = {AF_INET, 0, {0}, {0}}; + sockaddr* addr = nullptr; + socklen_t addrLen = 0; + sockaddr_in addr_4 = {AF_INET, 0, {0}, {0}}; sockaddr_in6 addr_6 = {AF_INET6, 0, 0, {0}, 0}; switch (mFamily) { - case AF_INET: addr = (sockaddr*)&addr_4; addrLen = sizeof(addr_4); break; - case AF_INET6: addr = (sockaddr*)&addr_6; addrLen = sizeof(addr_6); break; + case AF_INET: + addr = (sockaddr*)&addr_4; + addrLen = sizeof(addr_4); + break; + case AF_INET6: + addr = (sockaddr*)&addr_6; + addrLen = sizeof(addr_6); + break; default: assert(0); } @@ -131,7 +138,7 @@ bool DatagramSocket::setBlocking(bool blocking) int flags = fcntl(mHandle, F_GETFL, 0); if (flags < 0) return false; - flags = blocking ? (flags&~O_NONBLOCK) : (flags|O_NONBLOCK); + flags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK); return (fcntl(mHandle, F_SETFL, flags) == 0) ? true : false; #endif #if defined(TARGET_ANDROID) @@ -152,9 +159,7 @@ DatagramAgreggator::DatagramAgreggator() mMaxHandle = 0; } -DatagramAgreggator::~DatagramAgreggator() -{ -} +DatagramAgreggator::~DatagramAgreggator() {} void DatagramAgreggator::addSocket(PDatagramSocket socket) { @@ -196,6 +201,6 @@ bool DatagramAgreggator::waitForData(std::chrono::milliseconds timeout) tv.tv_sec = timeout.count() / 1000; tv.tv_usec = (timeout.count() % 1000) * 1000; - int rescode = ::select(mMaxHandle+1, &mReadSet, nullptr, nullptr, &tv); + int rescode = ::select(mMaxHandle + 1, &mReadSet, nullptr, nullptr, &tv); return rescode > 0; } diff --git a/src/engine/helper/HL_NetworkSocket.h b/src/engine/helper/HL_NetworkSocket.h index 85955362..8605edcd 100644 --- a/src/engine/helper/HL_NetworkSocket.h +++ b/src/engine/helper/HL_NetworkSocket.h @@ -15,34 +15,34 @@ class NetworkSocket { public: virtual int localport() = 0; - }; class DatagramSocket { friend class SocketHeap; friend class DatagramAgreggator; + public: DatagramSocket(); virtual ~DatagramSocket(); - virtual int localport(); + virtual int localport(); - virtual void sendDatagram(InternetAddress& dest, const void* packetData, unsigned packetSize); - virtual unsigned recvDatagram(InternetAddress& src, void* packetBuffer, unsigned packetCapacity); - virtual void closeSocket(); - virtual bool isValid() const; - virtual int family() const; - virtual bool setBlocking(bool blocking); - virtual SOCKET socket() const; + virtual void sendDatagram(InternetAddress& dest, const void* packetData, unsigned packetSize); + virtual unsigned recvDatagram(InternetAddress& src, void* packetBuffer, unsigned packetCapacity); + virtual void closeSocket(); + virtual bool isValid() const; + virtual int family() const; + virtual bool setBlocking(bool blocking); + virtual SOCKET socket() const; - virtual void open(int family); + virtual void open(int family); protected: - int mFamily; + int mFamily; SOCKET mHandle; - int mLocalPort; - void internalClose(); + int mLocalPort; + void internalClose(); }; typedef std::shared_ptr PDatagramSocket; @@ -52,18 +52,18 @@ public: DatagramAgreggator(); ~DatagramAgreggator(); - void addSocket(PDatagramSocket socket); - unsigned count(); - bool hasDataAtIndex(unsigned index); + void addSocket(PDatagramSocket socket); + unsigned count(); + bool hasDataAtIndex(unsigned index); PDatagramSocket socketAt(unsigned index); - bool waitForData(std::chrono::milliseconds timeout); + bool waitForData(std::chrono::milliseconds timeout); protected: typedef std::vector SocketList; - SocketList mSocketVector; - fd_set mReadSet; - SOCKET mMaxHandle; + SocketList mSocketVector; + fd_set mReadSet; + SOCKET mMaxHandle; }; #endif diff --git a/src/engine/helper/HL_Optional.hpp b/src/engine/helper/HL_Optional.hpp index f8c1acab..35fb25aa 100644 --- a/src/engine/helper/HL_Optional.hpp +++ b/src/engine/helper/HL_Optional.hpp @@ -7,199 +7,213 @@ // The idea and interface is based on Boost.Optional library // authored by Fernando Luis Cacciola Carballal -# ifndef ___OPTIONAL_HPP___ -# define ___OPTIONAL_HPP___ +#ifndef ___OPTIONAL_HPP___ +#define ___OPTIONAL_HPP___ -# include -# include -# include -# include -# include -# include -# include +#include +#include +#include +#include +#include +#include +#include -# define TR2_OPTIONAL_REQUIRES(...) typename enable_if<__VA_ARGS__::value, bool>::type = false +#define TR2_OPTIONAL_REQUIRES(...) typename enable_if<__VA_ARGS__::value, bool>::type = false -# if defined __GNUC__ // NOTE: GNUC is also defined for Clang -# if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 8) -# define TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ -# elif (__GNUC__ > 4) -# define TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ -# endif +#if defined __GNUC__ // NOTE: GNUC is also defined for Clang +#if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 8) +#define TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ +#elif (__GNUC__ > 4) +#define TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ +#endif # -# if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 7) -# define TR2_OPTIONAL_GCC_4_7_AND_HIGHER___ -# elif (__GNUC__ > 4) -# define TR2_OPTIONAL_GCC_4_7_AND_HIGHER___ -# endif +#if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 7) +#define TR2_OPTIONAL_GCC_4_7_AND_HIGHER___ +#elif (__GNUC__ > 4) +#define TR2_OPTIONAL_GCC_4_7_AND_HIGHER___ +#endif # -# if (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) && (__GNUC_PATCHLEVEL__ >= 1) -# define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ -# elif (__GNUC__ == 4) && (__GNUC_MINOR__ >= 9) -# define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ -# elif (__GNUC__ > 4) -# define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ -# endif -# endif +#if (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) && (__GNUC_PATCHLEVEL__ >= 1) +#define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ +#elif (__GNUC__ == 4) && (__GNUC_MINOR__ >= 9) +#define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ +#elif (__GNUC__ > 4) +#define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ +#endif +#endif # -# if defined __clang_major__ -# if (__clang_major__ == 3 && __clang_minor__ >= 5) -# define TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ -# elif (__clang_major__ > 3) -# define TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ -# endif -# if defined TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ -# define TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ -# elif (__clang_major__ == 3 && __clang_minor__ == 4 && __clang_patchlevel__ >= 2) -# define TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ -# endif -# endif +#if defined __clang_major__ +#if (__clang_major__ == 3 && __clang_minor__ >= 5) +#define TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ +#elif (__clang_major__ > 3) +#define TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ +#endif +#if defined TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ +#define TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ +#elif (__clang_major__ == 3 && __clang_minor__ == 4 && __clang_patchlevel__ >= 2) +#define TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ +#endif +#endif # -# if defined _MSC_VER -# if (_MSC_VER >= 1900) -# define TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ -# endif -# endif +#if defined _MSC_VER +#if (_MSC_VER >= 1900) +#define TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ +#endif +#endif -# if defined __clang__ -# if (__clang_major__ > 2) || (__clang_major__ == 2) && (__clang_minor__ >= 9) -# define OPTIONAL_HAS_THIS_RVALUE_REFS 1 -# else -# define OPTIONAL_HAS_THIS_RVALUE_REFS 0 -# endif -# elif defined TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ -# define OPTIONAL_HAS_THIS_RVALUE_REFS 1 -# elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ -# define OPTIONAL_HAS_THIS_RVALUE_REFS 1 -# else -# define OPTIONAL_HAS_THIS_RVALUE_REFS 0 -# endif +#if defined __clang__ +#if (__clang_major__ > 2) || (__clang_major__ == 2) && (__clang_minor__ >= 9) +#define OPTIONAL_HAS_THIS_RVALUE_REFS 1 +#else +#define OPTIONAL_HAS_THIS_RVALUE_REFS 0 +#endif +#elif defined TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ +#define OPTIONAL_HAS_THIS_RVALUE_REFS 1 +#elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ +#define OPTIONAL_HAS_THIS_RVALUE_REFS 1 +#else +#define OPTIONAL_HAS_THIS_RVALUE_REFS 0 +#endif -# if defined TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ -# define OPTIONAL_HAS_CONSTEXPR_INIT_LIST 1 -# define OPTIONAL_CONSTEXPR_INIT_LIST constexpr -# else -# define OPTIONAL_HAS_CONSTEXPR_INIT_LIST 0 -# define OPTIONAL_CONSTEXPR_INIT_LIST -# endif +#if defined TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ +#define OPTIONAL_HAS_CONSTEXPR_INIT_LIST 1 +#define OPTIONAL_CONSTEXPR_INIT_LIST constexpr +#else +#define OPTIONAL_HAS_CONSTEXPR_INIT_LIST 0 +#define OPTIONAL_CONSTEXPR_INIT_LIST +#endif -# if defined TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ && (defined __cplusplus) && (__cplusplus != 201103L) -# define OPTIONAL_HAS_MOVE_ACCESSORS 1 -# else -# define OPTIONAL_HAS_MOVE_ACCESSORS 0 -# endif +#if defined TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ && (defined __cplusplus) && (__cplusplus != 201103L) +#define OPTIONAL_HAS_MOVE_ACCESSORS 1 +#else +#define OPTIONAL_HAS_MOVE_ACCESSORS 0 +#endif -# // In C++11 constexpr implies const, so we need to make non-const members also non-constexpr -# if (defined __cplusplus) && (__cplusplus == 201103L) -# define OPTIONAL_MUTABLE_CONSTEXPR -# else -# define OPTIONAL_MUTABLE_CONSTEXPR constexpr -# endif +#// In C++11 constexpr implies const, so we need to make non-const members also non-constexpr +#if (defined __cplusplus) && (__cplusplus == 201103L) +#define OPTIONAL_MUTABLE_CONSTEXPR +#else +#define OPTIONAL_MUTABLE_CONSTEXPR constexpr +#endif -namespace std{ +namespace std +{ -namespace experimental{ +namespace experimental +{ // BEGIN workaround for missing is_trivially_destructible -# if defined TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ - // leave it: it is already there -# elif defined TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ - // leave it: it is already there -# elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ - // leave it: it is already there -# elif defined TR2_OPTIONAL_DISABLE_EMULATION_OF_TYPE_TRAITS - // leave it: the user doesn't want it -# else - template - using is_trivially_destructible = std::has_trivial_destructor; -# endif +#if defined TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ +// leave it: it is already there +#elif defined TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ +// leave it: it is already there +#elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ +// leave it: it is already there +#elif defined TR2_OPTIONAL_DISABLE_EMULATION_OF_TYPE_TRAITS +// leave it: the user doesn't want it +#else +template +using is_trivially_destructible = std::has_trivial_destructor; +#endif // END workaround for missing is_trivially_destructible -# if (defined TR2_OPTIONAL_GCC_4_7_AND_HIGHER___) - // leave it; our metafunctions are already defined. -# elif defined TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ - // leave it; our metafunctions are already defined. -# elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ - // leave it: it is already there -# elif defined TR2_OPTIONAL_DISABLE_EMULATION_OF_TYPE_TRAITS - // leave it: the user doesn't want it -# else +#if (defined TR2_OPTIONAL_GCC_4_7_AND_HIGHER___) +// leave it; our metafunctions are already defined. +#elif defined TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ +// leave it; our metafunctions are already defined. +#elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ +// leave it: it is already there +#elif defined TR2_OPTIONAL_DISABLE_EMULATION_OF_TYPE_TRAITS +// leave it: the user doesn't want it +#else // workaround for missing traits in GCC and CLANG -template +template struct is_nothrow_move_constructible { - constexpr static bool value = std::is_nothrow_constructible::value; + constexpr static bool value = std::is_nothrow_constructible::value; }; -template +template struct is_assignable { - template - constexpr static bool has_assign(...) { return false; } + template + constexpr static bool has_assign(...) + { + return false; + } - template () = std::declval(), true)) > - // the comma operator is necessary for the cases where operator= returns void - constexpr static bool has_assign(bool) { return true; } + template() = std::declval(), true))> + // the comma operator is necessary for the cases where operator= returns void + constexpr static bool has_assign(bool) + { + return true; + } - constexpr static bool value = has_assign(true); + constexpr static bool value = has_assign(true); }; -template +template struct is_nothrow_move_assignable { - template - struct has_nothrow_move_assign { - constexpr static bool value = false; - }; + template + struct has_nothrow_move_assign + { + constexpr static bool value = false; + }; - template - struct has_nothrow_move_assign { - constexpr static bool value = noexcept( std::declval() = std::declval() ); - }; + template + struct has_nothrow_move_assign + { + constexpr static bool value = noexcept(std::declval() = std::declval()); + }; - constexpr static bool value = has_nothrow_move_assign::value>::value; + constexpr static bool value = has_nothrow_move_assign::value>::value; }; // end workaround -# endif - +#endif // 20.5.4, optional for object types -template class optional; +template +class optional; // 20.5.5, optional for lvalue reference types -template class optional; +template +class optional; // workaround: std utility functions aren't constexpr yet -template inline constexpr T&& constexpr_forward(typename std::remove_reference::type& t) noexcept +template +inline constexpr T&& constexpr_forward(typename std::remove_reference::type& t) noexcept { - return static_cast(t); + return static_cast(t); } -template inline constexpr T&& constexpr_forward(typename std::remove_reference::type&& t) noexcept +template +inline constexpr T&& constexpr_forward(typename std::remove_reference::type&& t) noexcept { static_assert(!std::is_lvalue_reference::value, "!!"); return static_cast(t); } -template inline constexpr typename std::remove_reference::type&& constexpr_move(T&& t) noexcept +template +inline constexpr typename std::remove_reference::type&& constexpr_move(T&& t) noexcept { return static_cast::type&&>(t); } #if defined NDEBUG -# define TR2_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) (EXPR) +#define TR2_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) (EXPR) #else -# define TR2_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) ((CHECK) ? (EXPR) : ([]{assert(!#CHECK);}(), (EXPR))) +#define TR2_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) ((CHECK) ? (EXPR) : ([] { assert(!#CHECK); }(), (EXPR))) #endif @@ -207,96 +221,116 @@ namespace detail_ { // static_addressof: a constexpr version of addressof -template +template struct has_overloaded_addressof { - template - constexpr static bool has_overload(...) { return false; } - - template ().operator&()) > - constexpr static bool has_overload(bool) { return true; } + template + constexpr static bool has_overload(...) + { + return false; + } - constexpr static bool value = has_overload(true); + template().operator&())> + constexpr static bool has_overload(bool) + { + return true; + } + + constexpr static bool value = has_overload(true); }; -template )> +template)> constexpr T* static_addressof(T& ref) { - return &ref; + return &ref; } -template )> +template)> T* static_addressof(T& ref) { - return std::addressof(ref); + return std::addressof(ref); } -// the call to convert(b) has return type A and converts b to type A iff b decltype(b) is implicitly convertible to A -template -constexpr U convert(U v) { return v; } - -} // namespace detail +// the call to convert(b) has return type A and converts b to type A iff b decltype(b) is implicitly convertible to A +template +constexpr U convert(U v) +{ + return v; +} + +} // namespace detail_ -constexpr struct trivial_init_t{} trivial_init{}; +constexpr struct trivial_init_t +{ +} trivial_init{}; // 20.5.6, In-place construction -constexpr struct in_place_t{} in_place{}; +constexpr struct in_place_t +{ +} in_place{}; // 20.5.7, Disengaged state indicator struct nullopt_t { - struct init{}; - constexpr explicit nullopt_t(init){} + struct init + { + }; + constexpr explicit nullopt_t(init) {} }; constexpr nullopt_t nullopt{nullopt_t::init()}; // 20.5.8, class bad_optional_access -class bad_optional_access : public logic_error { +class bad_optional_access : public logic_error +{ public: - explicit bad_optional_access(const string& what_arg) : logic_error{what_arg} {} - explicit bad_optional_access(const char* what_arg) : logic_error{what_arg} {} + explicit bad_optional_access(const string& what_arg) : logic_error{what_arg} {} + explicit bad_optional_access(const char* what_arg) : logic_error{what_arg} {} }; -template +template union storage_t { - unsigned char dummy_; - T value_; + unsigned char dummy_; + T value_; - constexpr storage_t( trivial_init_t ) noexcept : dummy_() {}; + constexpr storage_t(trivial_init_t) noexcept : dummy_() {}; - template - constexpr storage_t( Args&&... args ) : value_(constexpr_forward(args)...) {} + template + constexpr storage_t(Args&&... args) : value_(constexpr_forward(args)...) + { + } - ~storage_t(){} + ~storage_t() {} }; -template +template union constexpr_storage_t { unsigned char dummy_; - T value_; + T value_; - constexpr constexpr_storage_t( trivial_init_t ) noexcept : dummy_() {}; + constexpr constexpr_storage_t(trivial_init_t) noexcept : dummy_() {}; - template - constexpr constexpr_storage_t( Args&&... args ) : value_(constexpr_forward(args)...) {} + template + constexpr constexpr_storage_t(Args&&... args) : value_(constexpr_forward(args)...) + { + } ~constexpr_storage_t() = default; }; -template +template struct optional_base { - bool init_; + bool init_; storage_t storage_; constexpr optional_base() noexcept : init_(false), storage_(trivial_init) {}; @@ -305,21 +339,29 @@ struct optional_base explicit constexpr optional_base(T&& v) : init_(true), storage_(constexpr_move(v)) {} - template explicit optional_base(in_place_t, Args&&... args) - : init_(true), storage_(constexpr_forward(args)...) {} + template + explicit optional_base(in_place_t, Args&&... args) : init_(true), storage_(constexpr_forward(args)...) + { + } - template >)> + template>)> explicit optional_base(in_place_t, std::initializer_list il, Args&&... args) - : init_(true), storage_(il, std::forward(args)...) {} + : init_(true), storage_(il, std::forward(args)...) + { + } - ~optional_base() { if (init_) storage_.value_.T::~T(); } + ~optional_base() + { + if (init_) + storage_.value_.T::~T(); + } }; -template +template struct constexpr_optional_base { - bool init_; + bool init_; constexpr_storage_t storage_; constexpr constexpr_optional_base() noexcept : init_(false), storage_(trivial_init) {}; @@ -328,684 +370,752 @@ struct constexpr_optional_base explicit constexpr constexpr_optional_base(T&& v) : init_(true), storage_(constexpr_move(v)) {} - template explicit constexpr constexpr_optional_base(in_place_t, Args&&... args) - : init_(true), storage_(constexpr_forward(args)...) {} + template + explicit constexpr constexpr_optional_base(in_place_t, Args&&... args) + : init_(true), storage_(constexpr_forward(args)...) + { + } - template >)> - OPTIONAL_CONSTEXPR_INIT_LIST explicit constexpr_optional_base(in_place_t, std::initializer_list il, Args&&... args) - : init_(true), storage_(il, std::forward(args)...) {} + template>)> + OPTIONAL_CONSTEXPR_INIT_LIST explicit constexpr_optional_base(in_place_t, std::initializer_list il, + Args&&... args) + : init_(true), storage_(il, std::forward(args)...) + { + } ~constexpr_optional_base() = default; }; -template -using OptionalBase = typename std::conditional< - is_trivially_destructible::value, // if possible - constexpr_optional_base::type>, // use base with trivial destructor - optional_base::type> ->::type; +template +using OptionalBase = + typename std::conditional::value, // if possible + constexpr_optional_base::type>, // use base with trivial + // destructor + optional_base::type>>::type; - -template +template class optional : private OptionalBase { - static_assert( !std::is_same::type, nullopt_t>::value, "bad T" ); - static_assert( !std::is_same::type, in_place_t>::value, "bad T" ); - + static_assert(!std::is_same::type, nullopt_t>::value, "bad T"); + static_assert(!std::is_same::type, in_place_t>::value, "bad T"); - constexpr bool initialized() const noexcept { return OptionalBase::init_; } - typename std::remove_const::type* dataptr() { return std::addressof(OptionalBase::storage_.value_); } - constexpr const T* dataptr() const { return detail_::static_addressof(OptionalBase::storage_.value_); } - -# if OPTIONAL_HAS_THIS_RVALUE_REFS == 1 - constexpr const T& contained_val() const& { return OptionalBase::storage_.value_; } -# if OPTIONAL_HAS_MOVE_ACCESSORS == 1 - OPTIONAL_MUTABLE_CONSTEXPR T&& contained_val() && { return std::move(OptionalBase::storage_.value_); } - OPTIONAL_MUTABLE_CONSTEXPR T& contained_val() & { return OptionalBase::storage_.value_; } -# else - T& contained_val() & { return OptionalBase::storage_.value_; } - T&& contained_val() && { return std::move(OptionalBase::storage_.value_); } -# endif -# else - constexpr const T& contained_val() const { return OptionalBase::storage_.value_; } - T& contained_val() { return OptionalBase::storage_.value_; } -# endif - void clear() noexcept { - if (initialized()) dataptr()->T::~T(); - OptionalBase::init_ = false; - } - - template - void initialize(Args&&... args) noexcept(noexcept(T(std::forward(args)...))) - { - assert(!OptionalBase::init_); - ::new (static_cast(dataptr())) T(std::forward(args)...); - OptionalBase::init_ = true; - } + constexpr bool initialized() const noexcept { return OptionalBase::init_; } + typename std::remove_const::type* dataptr() { return std::addressof(OptionalBase::storage_.value_); } + constexpr const T* dataptr() const { return detail_::static_addressof(OptionalBase::storage_.value_); } - template - void initialize(std::initializer_list il, Args&&... args) noexcept(noexcept(T(il, std::forward(args)...))) - { - assert(!OptionalBase::init_); - ::new (static_cast(dataptr())) T(il, std::forward(args)...); - OptionalBase::init_ = true; - } +#if OPTIONAL_HAS_THIS_RVALUE_REFS == 1 + constexpr const T& contained_val() const& { return OptionalBase::storage_.value_; } +#if OPTIONAL_HAS_MOVE_ACCESSORS == 1 + OPTIONAL_MUTABLE_CONSTEXPR T&& contained_val() && { return std::move(OptionalBase::storage_.value_); } + OPTIONAL_MUTABLE_CONSTEXPR T& contained_val() & { return OptionalBase::storage_.value_; } +#else + T& contained_val() & { return OptionalBase::storage_.value_; } + T&& contained_val() && { return std::move(OptionalBase::storage_.value_); } +#endif +#else + constexpr const T& contained_val() const { return OptionalBase::storage_.value_; } + T& contained_val() { return OptionalBase::storage_.value_; } +#endif + + void clear() noexcept + { + if (initialized()) + dataptr()->T::~T(); + OptionalBase::init_ = false; + } + + template + void initialize(Args&&... args) noexcept(noexcept(T(std::forward(args)...))) + { + assert(!OptionalBase::init_); + ::new (static_cast(dataptr())) T(std::forward(args)...); + OptionalBase::init_ = true; + } + + template + void initialize(std::initializer_list il, Args&&... args) noexcept(noexcept(T(il, std::forward(args)...))) + { + assert(!OptionalBase::init_); + ::new (static_cast(dataptr())) T(il, std::forward(args)...); + OptionalBase::init_ = true; + } public: - typedef T value_type; + typedef T value_type; - // 20.5.5.1, constructors - constexpr optional() noexcept : OptionalBase() {}; - constexpr optional(nullopt_t) noexcept : OptionalBase() {}; + // 20.5.5.1, constructors + constexpr optional() noexcept : OptionalBase() {}; + constexpr optional(nullopt_t) noexcept : OptionalBase() {}; - optional(const optional& rhs) - : OptionalBase() - { - if (rhs.initialized()) { - ::new (static_cast(dataptr())) T(*rhs); - OptionalBase::init_ = true; + optional(const optional& rhs) : OptionalBase() + { + if (rhs.initialized()) + { + ::new (static_cast(dataptr())) T(*rhs); + OptionalBase::init_ = true; + } } - } - optional(optional&& rhs) noexcept(is_nothrow_move_constructible::value) - : OptionalBase() - { - if (rhs.initialized()) { - ::new (static_cast(dataptr())) T(std::move(*rhs)); - OptionalBase::init_ = true; + optional(optional&& rhs) noexcept(is_nothrow_move_constructible::value) : OptionalBase() + { + if (rhs.initialized()) + { + ::new (static_cast(dataptr())) T(std::move(*rhs)); + OptionalBase::init_ = true; + } } - } - constexpr optional(const T& v) : OptionalBase(v) {} + constexpr optional(const T& v) : OptionalBase(v) {} - constexpr optional(T&& v) : OptionalBase(constexpr_move(v)) {} + constexpr optional(T&& v) : OptionalBase(constexpr_move(v)) {} - template - explicit constexpr optional(in_place_t, Args&&... args) - : OptionalBase(in_place_t{}, constexpr_forward(args)...) {} + template + explicit constexpr optional(in_place_t, Args&&... args) + : OptionalBase(in_place_t{}, constexpr_forward(args)...) + { + } - template >)> - OPTIONAL_CONSTEXPR_INIT_LIST explicit optional(in_place_t, std::initializer_list il, Args&&... args) - : OptionalBase(in_place_t{}, il, constexpr_forward(args)...) {} + template>)> + OPTIONAL_CONSTEXPR_INIT_LIST explicit optional(in_place_t, std::initializer_list il, Args&&... args) + : OptionalBase(in_place_t{}, il, constexpr_forward(args)...) + { + } - // 20.5.4.2, Destructor - ~optional() = default; + // 20.5.4.2, Destructor + ~optional() = default; - // 20.5.4.3, assignment - optional& operator=(nullopt_t) noexcept - { - clear(); - return *this; - } - - optional& operator=(const optional& rhs) - { - if (initialized() == true && rhs.initialized() == false) clear(); - else if (initialized() == false && rhs.initialized() == true) initialize(*rhs); - else if (initialized() == true && rhs.initialized() == true) contained_val() = *rhs; - return *this; - } - - optional& operator=(optional&& rhs) - noexcept(is_nothrow_move_assignable::value && is_nothrow_move_constructible::value) - { - if (initialized() == true && rhs.initialized() == false) clear(); - else if (initialized() == false && rhs.initialized() == true) initialize(std::move(*rhs)); - else if (initialized() == true && rhs.initialized() == true) contained_val() = std::move(*rhs); - return *this; - } + // 20.5.4.3, assignment + optional& operator=(nullopt_t) noexcept + { + clear(); + return *this; + } - template - auto operator=(U&& v) - -> typename enable_if - < - is_same::type, T>::value, - optional& - >::type - { - if (initialized()) { contained_val() = std::forward(v); } - else { initialize(std::forward(v)); } - return *this; - } - - - template - void emplace(Args&&... args) - { - clear(); - initialize(std::forward(args)...); - } - - template - void emplace(initializer_list il, Args&&... args) - { - clear(); - initialize(il, std::forward(args)...); - } - - // 20.5.4.4, Swap - void swap(optional& rhs) noexcept(is_nothrow_move_constructible::value && noexcept(swap(declval(), declval()))) - { - if (initialized() == true && rhs.initialized() == false) { rhs.initialize(std::move(**this)); clear(); } - else if (initialized() == false && rhs.initialized() == true) { initialize(std::move(*rhs)); rhs.clear(); } - else if (initialized() == true && rhs.initialized() == true) { using std::swap; swap(**this, *rhs); } - } + optional& operator=(const optional& rhs) + { + if (initialized() == true && rhs.initialized() == false) + clear(); + else if (initialized() == false && rhs.initialized() == true) + initialize(*rhs); + else if (initialized() == true && rhs.initialized() == true) + contained_val() = *rhs; + return *this; + } - // 20.5.4.5, Observers - - explicit constexpr operator bool() const noexcept { return initialized(); } - bool is_initialized() const noexcept { return initialized(); } + optional& operator=(optional&& rhs) noexcept(is_nothrow_move_assignable::value && + is_nothrow_move_constructible::value) + { + if (initialized() == true && rhs.initialized() == false) + clear(); + else if (initialized() == false && rhs.initialized() == true) + initialize(std::move(*rhs)); + else if (initialized() == true && rhs.initialized() == true) + contained_val() = std::move(*rhs); + return *this; + } - constexpr T const* operator ->() const { - return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), dataptr()); - } - -# if OPTIONAL_HAS_MOVE_ACCESSORS == 1 + template + auto operator=(U&& v) -> typename enable_if::type, T>::value, optional&>::type + { + if (initialized()) + { + contained_val() = std::forward(v); + } + else + { + initialize(std::forward(v)); + } + return *this; + } - OPTIONAL_MUTABLE_CONSTEXPR T* operator ->() { - assert (initialized()); - return dataptr(); - } - - constexpr T const& operator *() const& { - return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), contained_val()); - } - - OPTIONAL_MUTABLE_CONSTEXPR T& operator *() & { - assert (initialized()); - return contained_val(); - } - - OPTIONAL_MUTABLE_CONSTEXPR T&& operator *() && { - assert (initialized()); - return constexpr_move(contained_val()); - } - constexpr T const& value() const& { - return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); - } - - OPTIONAL_MUTABLE_CONSTEXPR T& value() & { - return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); - } - - OPTIONAL_MUTABLE_CONSTEXPR T&& value() && { - if (!initialized()) throw bad_optional_access("bad optional access"); - return std::move(contained_val()); - } - -# else + template + void emplace(Args&&... args) + { + clear(); + initialize(std::forward(args)...); + } - T* operator ->() { - assert (initialized()); - return dataptr(); - } - - constexpr T const& operator *() const { - return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), contained_val()); - } - - T& operator *() { - assert (initialized()); - return contained_val(); - } - - constexpr T const& value() const { - return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); - } - - T& value() { - return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); - } - -# endif - -# if OPTIONAL_HAS_THIS_RVALUE_REFS == 1 + template + void emplace(initializer_list il, Args&&... args) + { + clear(); + initialize(il, std::forward(args)...); + } - template - constexpr T value_or(V&& v) const& - { - return *this ? **this : detail_::convert(constexpr_forward(v)); - } - -# if OPTIONAL_HAS_MOVE_ACCESSORS == 1 + // 20.5.4.4, Swap + void swap(optional& rhs) noexcept(is_nothrow_move_constructible::value && + noexcept(swap(declval(), declval()))) + { + if (initialized() == true && rhs.initialized() == false) + { + rhs.initialize(std::move(**this)); + clear(); + } + else if (initialized() == false && rhs.initialized() == true) + { + initialize(std::move(*rhs)); + rhs.clear(); + } + else if (initialized() == true && rhs.initialized() == true) + { + using std::swap; + swap(**this, *rhs); + } + } - template - OPTIONAL_MUTABLE_CONSTEXPR T value_or(V&& v) && - { - return *this ? constexpr_move(const_cast&>(*this).contained_val()) : detail_::convert(constexpr_forward(v)); - } + // 20.5.4.5, Observers -# else - - template - T value_or(V&& v) && - { - return *this ? constexpr_move(const_cast&>(*this).contained_val()) : detail_::convert(constexpr_forward(v)); - } - -# endif - -# else - - template - constexpr T value_or(V&& v) const - { - return *this ? **this : detail_::convert(constexpr_forward(v)); - } + explicit constexpr operator bool() const noexcept { return initialized(); } + bool is_initialized() const noexcept { return initialized(); } -# endif + constexpr T const* operator->() const { return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), dataptr()); } +#if OPTIONAL_HAS_MOVE_ACCESSORS == 1 + + OPTIONAL_MUTABLE_CONSTEXPR T* operator->() + { + assert(initialized()); + return dataptr(); + } + + constexpr T const& operator*() const& { return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), contained_val()); } + + OPTIONAL_MUTABLE_CONSTEXPR T& operator*() & + { + assert(initialized()); + return contained_val(); + } + + OPTIONAL_MUTABLE_CONSTEXPR T&& operator*() && + { + assert(initialized()); + return constexpr_move(contained_val()); + } + + constexpr T const& value() const& + { + return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); + } + + OPTIONAL_MUTABLE_CONSTEXPR T& value() & + { + return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); + } + + OPTIONAL_MUTABLE_CONSTEXPR T&& value() && + { + if (!initialized()) + throw bad_optional_access("bad optional access"); + return std::move(contained_val()); + } + +#else + + T* operator->() + { + assert(initialized()); + return dataptr(); + } + + constexpr T const& operator*() const { return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), contained_val()); } + + T& operator*() + { + assert(initialized()); + return contained_val(); + } + + constexpr T const& value() const + { + return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); + } + + T& value() + { + return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); + } + +#endif + +#if OPTIONAL_HAS_THIS_RVALUE_REFS == 1 + + template + constexpr T value_or(V&& v) const& + { + return *this ? **this : detail_::convert(constexpr_forward(v)); + } + +#if OPTIONAL_HAS_MOVE_ACCESSORS == 1 + + template + OPTIONAL_MUTABLE_CONSTEXPR T value_or(V&& v) && + { + return *this ? constexpr_move(const_cast&>(*this).contained_val()) + : detail_::convert(constexpr_forward(v)); + } + +#else + + template + T value_or(V&& v) && + { + return *this ? constexpr_move(const_cast&>(*this).contained_val()) + : detail_::convert(constexpr_forward(v)); + } + +#endif + +#else + + template + constexpr T value_or(V&& v) const + { + return *this ? **this : detail_::convert(constexpr_forward(v)); + } + +#endif }; -template +template class optional { - static_assert( !std::is_same::value, "bad T" ); - static_assert( !std::is_same::value, "bad T" ); - T* ref; - -public: + static_assert(!std::is_same::value, "bad T"); + static_assert(!std::is_same::value, "bad T"); + T* ref; - // 20.5.5.1, construction/destruction - constexpr optional() noexcept : ref(nullptr) {} - - constexpr optional(nullopt_t) noexcept : ref(nullptr) {} - - constexpr optional(T& v) noexcept : ref(detail_::static_addressof(v)) {} - - optional(T&&) = delete; - - constexpr optional(const optional& rhs) noexcept : ref(rhs.ref) {} - - explicit constexpr optional(in_place_t, T& v) noexcept : ref(detail_::static_addressof(v)) {} - - explicit optional(in_place_t, T&&) = delete; - - ~optional() = default; - - // 20.5.5.2, mutation - optional& operator=(nullopt_t) noexcept { - ref = nullptr; - return *this; - } - - // optional& operator=(const optional& rhs) noexcept { +public: + // 20.5.5.1, construction/destruction + constexpr optional() noexcept : ref(nullptr) {} + + constexpr optional(nullopt_t) noexcept : ref(nullptr) {} + + constexpr optional(T& v) noexcept : ref(detail_::static_addressof(v)) {} + + optional(T&&) = delete; + + constexpr optional(const optional& rhs) noexcept : ref(rhs.ref) {} + + explicit constexpr optional(in_place_t, T& v) noexcept : ref(detail_::static_addressof(v)) {} + + explicit optional(in_place_t, T&&) = delete; + + ~optional() = default; + + // 20.5.5.2, mutation + optional& operator=(nullopt_t) noexcept + { + ref = nullptr; + return *this; + } + + // optional& operator=(const optional& rhs) noexcept { // ref = rhs.ref; // return *this; - // } - - // optional& operator=(optional&& rhs) noexcept { + // } + + // optional& operator=(optional&& rhs) noexcept { // ref = rhs.ref; // return *this; - // } - - template - auto operator=(U&& rhs) noexcept - -> typename enable_if - < - is_same::type, optional>::value, - optional& - >::type - { - ref = rhs.ref; - return *this; - } - - template - auto operator=(U&& rhs) noexcept - -> typename enable_if - < - !is_same::type, optional>::value, - optional& - >::type - = delete; - - void emplace(T& v) noexcept { - ref = detail_::static_addressof(v); - } - - void emplace(T&&) = delete; - - - void swap(optional& rhs) noexcept - { - std::swap(ref, rhs.ref); - } - - // 20.5.5.3, observers - constexpr T* operator->() const { - return TR2_OPTIONAL_ASSERTED_EXPRESSION(ref, ref); - } - - constexpr T& operator*() const { - return TR2_OPTIONAL_ASSERTED_EXPRESSION(ref, *ref); - } - - constexpr T& value() const { - return ref ? *ref : (throw bad_optional_access("bad optional access"), *ref); - } - - explicit constexpr operator bool() const noexcept { - return ref != nullptr; - } - - template - constexpr typename decay::type value_or(V&& v) const - { - return *this ? **this : detail_::convert::type>(constexpr_forward(v)); - } + // } + + template + auto operator=(U&& rhs) noexcept -> + typename enable_if::type, optional>::value, optional&>::type + { + ref = rhs.ref; + return *this; + } + + template + auto operator=(U&& rhs) noexcept -> + typename enable_if::type, optional>::value, optional&>::type = delete; + + void emplace(T& v) noexcept { ref = detail_::static_addressof(v); } + + void emplace(T&&) = delete; + + + void swap(optional& rhs) noexcept { std::swap(ref, rhs.ref); } + + // 20.5.5.3, observers + constexpr T* operator->() const { return TR2_OPTIONAL_ASSERTED_EXPRESSION(ref, ref); } + + constexpr T& operator*() const { return TR2_OPTIONAL_ASSERTED_EXPRESSION(ref, *ref); } + + constexpr T& value() const { return ref ? *ref : (throw bad_optional_access("bad optional access"), *ref); } + + explicit constexpr operator bool() const noexcept { return ref != nullptr; } + + template + constexpr typename decay::type value_or(V&& v) const + { + return *this ? **this : detail_::convert::type>(constexpr_forward(v)); + } }; -template +template class optional { - static_assert( sizeof(T) == 0, "optional rvalue references disallowed" ); + static_assert(sizeof(T) == 0, "optional rvalue references disallowed"); }; // 20.5.8, Relational operators -template constexpr bool operator==(const optional& x, const optional& y) +template +constexpr bool operator==(const optional& x, const optional& y) { - return bool(x) != bool(y) ? false : bool(x) == false ? true : *x == *y; + return bool(x) != bool(y) ? false : bool(x) == false ? true : *x == *y; } -template constexpr bool operator!=(const optional& x, const optional& y) +template +constexpr bool operator!=(const optional& x, const optional& y) { - return !(x == y); + return !(x == y); } -template constexpr bool operator<(const optional& x, const optional& y) +template +constexpr bool operator<(const optional& x, const optional& y) { - return (!y) ? false : (!x) ? true : *x < *y; + return (!y) ? false : (!x) ? true : *x < *y; } -template constexpr bool operator>(const optional& x, const optional& y) +template +constexpr bool operator>(const optional& x, const optional& y) { - return (y < x); + return (y < x); } -template constexpr bool operator<=(const optional& x, const optional& y) +template +constexpr bool operator<=(const optional& x, const optional& y) { - return !(y < x); + return !(y < x); } -template constexpr bool operator>=(const optional& x, const optional& y) +template +constexpr bool operator>=(const optional& x, const optional& y) { - return !(x < y); + return !(x < y); } // 20.5.9, Comparison with nullopt -template constexpr bool operator==(const optional& x, nullopt_t) noexcept +template +constexpr bool operator==(const optional& x, nullopt_t) noexcept { - return (!x); + return (!x); } -template constexpr bool operator==(nullopt_t, const optional& x) noexcept +template +constexpr bool operator==(nullopt_t, const optional& x) noexcept { - return (!x); + return (!x); } -template constexpr bool operator!=(const optional& x, nullopt_t) noexcept +template +constexpr bool operator!=(const optional& x, nullopt_t) noexcept { - return bool(x); + return bool(x); } -template constexpr bool operator!=(nullopt_t, const optional& x) noexcept +template +constexpr bool operator!=(nullopt_t, const optional& x) noexcept { - return bool(x); + return bool(x); } -template constexpr bool operator<(const optional&, nullopt_t) noexcept +template +constexpr bool operator<(const optional&, nullopt_t) noexcept { - return false; + return false; } -template constexpr bool operator<(nullopt_t, const optional& x) noexcept +template +constexpr bool operator<(nullopt_t, const optional& x) noexcept { - return bool(x); + return bool(x); } -template constexpr bool operator<=(const optional& x, nullopt_t) noexcept +template +constexpr bool operator<=(const optional& x, nullopt_t) noexcept { - return (!x); + return (!x); } -template constexpr bool operator<=(nullopt_t, const optional&) noexcept +template +constexpr bool operator<=(nullopt_t, const optional&) noexcept { - return true; + return true; } -template constexpr bool operator>(const optional& x, nullopt_t) noexcept +template +constexpr bool operator>(const optional& x, nullopt_t) noexcept { - return bool(x); + return bool(x); } -template constexpr bool operator>(nullopt_t, const optional&) noexcept +template +constexpr bool operator>(nullopt_t, const optional&) noexcept { - return false; + return false; } -template constexpr bool operator>=(const optional&, nullopt_t) noexcept +template +constexpr bool operator>=(const optional&, nullopt_t) noexcept { - return true; + return true; } -template constexpr bool operator>=(nullopt_t, const optional& x) noexcept +template +constexpr bool operator>=(nullopt_t, const optional& x) noexcept { - return (!x); + return (!x); } - // 20.5.10, Comparison with T -template constexpr bool operator==(const optional& x, const T& v) +template +constexpr bool operator==(const optional& x, const T& v) { - return bool(x) ? *x == v : false; + return bool(x) ? *x == v : false; } -template constexpr bool operator==(const T& v, const optional& x) +template +constexpr bool operator==(const T& v, const optional& x) { - return bool(x) ? v == *x : false; + return bool(x) ? v == *x : false; } -template constexpr bool operator!=(const optional& x, const T& v) +template +constexpr bool operator!=(const optional& x, const T& v) { - return bool(x) ? *x != v : true; + return bool(x) ? *x != v : true; } -template constexpr bool operator!=(const T& v, const optional& x) +template +constexpr bool operator!=(const T& v, const optional& x) { - return bool(x) ? v != *x : true; + return bool(x) ? v != *x : true; } -template constexpr bool operator<(const optional& x, const T& v) +template +constexpr bool operator<(const optional& x, const T& v) { - return bool(x) ? *x < v : true; + return bool(x) ? *x < v : true; } -template constexpr bool operator>(const T& v, const optional& x) +template +constexpr bool operator>(const T& v, const optional& x) { - return bool(x) ? v > *x : true; + return bool(x) ? v > *x : true; } -template constexpr bool operator>(const optional& x, const T& v) +template +constexpr bool operator>(const optional& x, const T& v) { - return bool(x) ? *x > v : false; + return bool(x) ? *x > v : false; } -template constexpr bool operator<(const T& v, const optional& x) +template +constexpr bool operator<(const T& v, const optional& x) { - return bool(x) ? v < *x : false; + return bool(x) ? v < *x : false; } -template constexpr bool operator>=(const optional& x, const T& v) +template +constexpr bool operator>=(const optional& x, const T& v) { - return bool(x) ? *x >= v : false; + return bool(x) ? *x >= v : false; } -template constexpr bool operator<=(const T& v, const optional& x) +template +constexpr bool operator<=(const T& v, const optional& x) { - return bool(x) ? v <= *x : false; + return bool(x) ? v <= *x : false; } -template constexpr bool operator<=(const optional& x, const T& v) +template +constexpr bool operator<=(const optional& x, const T& v) { - return bool(x) ? *x <= v : true; + return bool(x) ? *x <= v : true; } -template constexpr bool operator>=(const T& v, const optional& x) +template +constexpr bool operator>=(const T& v, const optional& x) { - return bool(x) ? v >= *x : true; + return bool(x) ? v >= *x : true; } // Comparison of optional with T -template constexpr bool operator==(const optional& x, const T& v) +template +constexpr bool operator==(const optional& x, const T& v) { - return bool(x) ? *x == v : false; + return bool(x) ? *x == v : false; } -template constexpr bool operator==(const T& v, const optional& x) +template +constexpr bool operator==(const T& v, const optional& x) { - return bool(x) ? v == *x : false; + return bool(x) ? v == *x : false; } -template constexpr bool operator!=(const optional& x, const T& v) +template +constexpr bool operator!=(const optional& x, const T& v) { - return bool(x) ? *x != v : true; + return bool(x) ? *x != v : true; } -template constexpr bool operator!=(const T& v, const optional& x) +template +constexpr bool operator!=(const T& v, const optional& x) { - return bool(x) ? v != *x : true; + return bool(x) ? v != *x : true; } -template constexpr bool operator<(const optional& x, const T& v) +template +constexpr bool operator<(const optional& x, const T& v) { - return bool(x) ? *x < v : true; + return bool(x) ? *x < v : true; } -template constexpr bool operator>(const T& v, const optional& x) +template +constexpr bool operator>(const T& v, const optional& x) { - return bool(x) ? v > *x : true; + return bool(x) ? v > *x : true; } -template constexpr bool operator>(const optional& x, const T& v) +template +constexpr bool operator>(const optional& x, const T& v) { - return bool(x) ? *x > v : false; + return bool(x) ? *x > v : false; } -template constexpr bool operator<(const T& v, const optional& x) +template +constexpr bool operator<(const T& v, const optional& x) { - return bool(x) ? v < *x : false; + return bool(x) ? v < *x : false; } -template constexpr bool operator>=(const optional& x, const T& v) +template +constexpr bool operator>=(const optional& x, const T& v) { - return bool(x) ? *x >= v : false; + return bool(x) ? *x >= v : false; } -template constexpr bool operator<=(const T& v, const optional& x) +template +constexpr bool operator<=(const T& v, const optional& x) { - return bool(x) ? v <= *x : false; + return bool(x) ? v <= *x : false; } -template constexpr bool operator<=(const optional& x, const T& v) +template +constexpr bool operator<=(const optional& x, const T& v) { - return bool(x) ? *x <= v : true; + return bool(x) ? *x <= v : true; } -template constexpr bool operator>=(const T& v, const optional& x) +template +constexpr bool operator>=(const T& v, const optional& x) { - return bool(x) ? v >= *x : true; + return bool(x) ? v >= *x : true; } // Comparison of optional with T -template constexpr bool operator==(const optional& x, const T& v) +template +constexpr bool operator==(const optional& x, const T& v) { - return bool(x) ? *x == v : false; + return bool(x) ? *x == v : false; } -template constexpr bool operator==(const T& v, const optional& x) +template +constexpr bool operator==(const T& v, const optional& x) { - return bool(x) ? v == *x : false; + return bool(x) ? v == *x : false; } -template constexpr bool operator!=(const optional& x, const T& v) +template +constexpr bool operator!=(const optional& x, const T& v) { - return bool(x) ? *x != v : true; + return bool(x) ? *x != v : true; } -template constexpr bool operator!=(const T& v, const optional& x) +template +constexpr bool operator!=(const T& v, const optional& x) { - return bool(x) ? v != *x : true; + return bool(x) ? v != *x : true; } -template constexpr bool operator<(const optional& x, const T& v) +template +constexpr bool operator<(const optional& x, const T& v) { - return bool(x) ? *x < v : true; + return bool(x) ? *x < v : true; } -template constexpr bool operator>(const T& v, const optional& x) +template +constexpr bool operator>(const T& v, const optional& x) { - return bool(x) ? v > *x : true; + return bool(x) ? v > *x : true; } -template constexpr bool operator>(const optional& x, const T& v) +template +constexpr bool operator>(const optional& x, const T& v) { - return bool(x) ? *x > v : false; + return bool(x) ? *x > v : false; } -template constexpr bool operator<(const T& v, const optional& x) +template +constexpr bool operator<(const T& v, const optional& x) { - return bool(x) ? v < *x : false; + return bool(x) ? v < *x : false; } -template constexpr bool operator>=(const optional& x, const T& v) +template +constexpr bool operator>=(const optional& x, const T& v) { - return bool(x) ? *x >= v : false; + return bool(x) ? *x >= v : false; } -template constexpr bool operator<=(const T& v, const optional& x) +template +constexpr bool operator<=(const T& v, const optional& x) { - return bool(x) ? v <= *x : false; + return bool(x) ? v <= *x : false; } -template constexpr bool operator<=(const optional& x, const T& v) +template +constexpr bool operator<=(const optional& x, const T& v) { - return bool(x) ? *x <= v : true; + return bool(x) ? *x <= v : true; } -template constexpr bool operator>=(const T& v, const optional& x) +template +constexpr bool operator>=(const T& v, const optional& x) { - return bool(x) ? v >= *x : true; + return bool(x) ? v >= *x : true; } // 20.5.12, Specialized algorithms -template +template void swap(optional& x, optional& y) noexcept(noexcept(x.swap(y))) { - x.swap(y); + x.swap(y); } -template +template constexpr optional::type> make_optional(T&& v) { - return optional::type>(constexpr_forward(v)); + return optional::type>(constexpr_forward(v)); } -template +template constexpr optional make_optional(reference_wrapper v) { - return optional(v.get()); + return optional(v.get()); } @@ -1014,30 +1124,32 @@ constexpr optional make_optional(reference_wrapper v) namespace std { - template - struct hash> - { - typedef typename hash::result_type result_type; +template +struct hash> +{ + typedef typename hash::result_type result_type; typedef std::experimental::optional argument_type; - - constexpr result_type operator()(argument_type const& arg) const { - return arg ? std::hash{}(*arg) : result_type{}; + + constexpr result_type operator()(argument_type const& arg) const + { + return arg ? std::hash{}(*arg) : result_type{}; } - }; - - template - struct hash> - { - typedef typename hash::result_type result_type; +}; + +template +struct hash> +{ + typedef typename hash::result_type result_type; typedef std::experimental::optional argument_type; - - constexpr result_type operator()(argument_type const& arg) const { - return arg ? std::hash{}(*arg) : result_type{}; + + constexpr result_type operator()(argument_type const& arg) const + { + return arg ? std::hash{}(*arg) : result_type{}; } - }; -} +}; +} // namespace std -# undef TR2_OPTIONAL_REQUIRES -# undef TR2_OPTIONAL_ASSERTED_EXPRESSION +#undef TR2_OPTIONAL_REQUIRES +#undef TR2_OPTIONAL_ASSERTED_EXPRESSION -# endif //___OPTIONAL_HPP___ +#endif //___OPTIONAL_HPP___ diff --git a/src/engine/helper/HL_OsVersion.cpp b/src/engine/helper/HL_OsVersion.cpp index 32bd1ae2..2cc0847c 100644 --- a/src/engine/helper/HL_OsVersion.cpp +++ b/src/engine/helper/HL_OsVersion.cpp @@ -10,79 +10,79 @@ #include #if defined(USE_MINIDUMP) -# include +#include #endif int winVersion() { - DWORD dwVersion = 0; - DWORD dwMajorVersion = 0; - DWORD dwMinorVersion = 0; - DWORD dwBuild = 0; + DWORD dwVersion = 0; + DWORD dwMajorVersion = 0; + DWORD dwMinorVersion = 0; + DWORD dwBuild = 0; - dwVersion = GetVersion(); + dwVersion = GetVersion(); - // Get the Windows version. + // Get the Windows version. - dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion))); - dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion))); + dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion))); + dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion))); - // Get the build number. + // Get the build number. - if (dwVersion < 0x80000000) - dwBuild = (DWORD)(HIWORD(dwVersion)); - - if (dwMajorVersion == 5) - return Win_Xp; + if (dwVersion < 0x80000000) + dwBuild = (DWORD)(HIWORD(dwVersion)); - if (dwMinorVersion == 1) - return Win_Seven; - else - return Win_Vista; - } + if (dwMajorVersion == 5) + return Win_Xp; + + if (dwMinorVersion == 1) + return Win_Seven; + else + return Win_Vista; +} // ----------------- CrashMiniDump ----------------- #if defined(USE_MINIDUMP) static LONG WINAPI MyExceptionHandler(EXCEPTION_POINTERS* ExceptionInfo) { - // Open the file - HANDLE hFile = CreateFile( L"MiniDump.dmp", GENERIC_READ | GENERIC_WRITE, - 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); + // Open the file + HANDLE hFile = + CreateFile(L"MiniDump.dmp", GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if( ( hFile != NULL ) && ( hFile != INVALID_HANDLE_VALUE ) ) - { - // Create the minidump - MINIDUMP_EXCEPTION_INFORMATION mdei; + if ((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE)) + { + // Create the minidump + MINIDUMP_EXCEPTION_INFORMATION mdei; - mdei.ThreadId = GetCurrentThreadId(); - mdei.ExceptionPointers = ExceptionInfo; - mdei.ClientPointers = FALSE; + mdei.ThreadId = GetCurrentThreadId(); + mdei.ExceptionPointers = ExceptionInfo; + mdei.ClientPointers = FALSE; - MINIDUMP_TYPE mdt = MiniDumpWithFullMemory; + MINIDUMP_TYPE mdt = MiniDumpWithFullMemory; - BOOL rv = MiniDumpWriteDump( GetCurrentProcess(), GetCurrentProcessId(), - hFile, mdt, (ExceptionInfo != 0) ? &mdei : 0, 0, 0 ); + BOOL rv = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, mdt, + (ExceptionInfo != 0) ? &mdei : 0, 0, 0); - // Close the file - CloseHandle( hFile ); - } - else - { - } + // Close the file + CloseHandle(hFile); + } + else + { + } - return EXCEPTION_CONTINUE_SEARCH; + return EXCEPTION_CONTINUE_SEARCH; } static LPTOP_LEVEL_EXCEPTION_FILTER OldExceptionHandler = nullptr; -void CrashMiniDump::registerHandler() +void CrashMiniDump::registerHandler() { - OldExceptionHandler = ::SetUnhandledExceptionFilter(&MyExceptionHandler); + OldExceptionHandler = ::SetUnhandledExceptionFilter(&MyExceptionHandler); } void CrashMiniDump::unregisterHandler() { - ::SetUnhandledExceptionFilter(nullptr); + ::SetUnhandledExceptionFilter(nullptr); } #endif @@ -124,29 +124,29 @@ int _kbhit() ioctl(STDIN, FIONREAD, &bytesWaiting); return bytesWaiting;*/ static const int STDIN_FILENO = 0; - struct termios oldt, newt; - int ch; - int oldf; + struct termios oldt, newt; + int ch; + int oldf; - tcgetattr(STDIN_FILENO, &oldt); - newt = oldt; - newt.c_lflag &= ~(ICANON | ECHO); - tcsetattr(STDIN_FILENO, TCSANOW, &newt); - oldf = fcntl(STDIN_FILENO, F_GETFL, 0); - fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK); + tcgetattr(STDIN_FILENO, &oldt); + newt = oldt; + newt.c_lflag &= ~(ICANON | ECHO); + tcsetattr(STDIN_FILENO, TCSANOW, &newt); + oldf = fcntl(STDIN_FILENO, F_GETFL, 0); + fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK); - ch = getchar(); + ch = getchar(); - tcsetattr(STDIN_FILENO, TCSANOW, &oldt); - fcntl(STDIN_FILENO, F_SETFL, oldf); + tcsetattr(STDIN_FILENO, TCSANOW, &oldt); + fcntl(STDIN_FILENO, F_SETFL, oldf); - if(ch != EOF) - { - ungetc(ch, stdin); - return 1; - } + if (ch != EOF) + { + ungetc(ch, stdin); + return 1; + } - return 0; + return 0; } #endif diff --git a/src/engine/helper/HL_OsVersion.h b/src/engine/helper/HL_OsVersion.h index c5723ec0..3b9683a3 100644 --- a/src/engine/helper/HL_OsVersion.h +++ b/src/engine/helper/HL_OsVersion.h @@ -10,11 +10,11 @@ enum { - Win_Xp = 0, - Win_Vista = 1, - Win_Seven = 2, - Win_Eight = 3, - Win_Ten = 4 + Win_Xp = 0, + Win_Vista = 1, + Win_Seven = 2, + Win_Eight = 3, + Win_Ten = 4 }; extern int winVersion(); @@ -22,8 +22,8 @@ extern int winVersion(); class CrashMiniDump { public: - static void registerHandler(); - static void unregisterHandler(); + static void registerHandler(); + static void unregisterHandler(); }; extern void writeMiniDump(); @@ -41,7 +41,7 @@ int iosVersion(); #include #include #if defined(TARGET_LINUX) -//# include +// # include #endif extern int _kbhit(); @@ -49,6 +49,6 @@ extern int _kbhit(); #endif #if defined(TARGET_WIN) -# include +#include #endif #endif diff --git a/src/engine/helper/HL_Pointer.cpp b/src/engine/helper/HL_Pointer.cpp index a6d72156..4d170ec7 100644 --- a/src/engine/helper/HL_Pointer.cpp +++ b/src/engine/helper/HL_Pointer.cpp @@ -5,51 +5,49 @@ #include "HL_Pointer.h" -UsageCounter::UsageCounter() -{} +UsageCounter::UsageCounter() {} -UsageCounter::~UsageCounter() -{} +UsageCounter::~UsageCounter() {} int UsageCounter::obtain(int usageId) { - Lock l(mGuard); - UsageMap::iterator usageIter = mUsage.find(usageId); - if (usageIter != mUsage.end()) - usageIter->second = usageIter->second + 1; - else - mUsage[usageId] = 1; - - return usageCount(); + Lock l(mGuard); + UsageMap::iterator usageIter = mUsage.find(usageId); + if (usageIter != mUsage.end()) + usageIter->second = usageIter->second + 1; + else + mUsage[usageId] = 1; + + return usageCount(); } int UsageCounter::release(int usageId) { - Lock l(mGuard); - UsageMap::iterator usageIter = mUsage.find(usageId); - if (usageIter == mUsage.end()) - return usageCount(); + Lock l(mGuard); + UsageMap::iterator usageIter = mUsage.find(usageId); + if (usageIter == mUsage.end()) + return usageCount(); - usageIter->second = usageIter->second - 1; - if (!usageIter->second) - mUsage.erase(usageIter); - - return usageCount(); + usageIter->second = usageIter->second - 1; + if (!usageIter->second) + mUsage.erase(usageIter); + + return usageCount(); } int UsageCounter::usageCount() { - Lock l(mGuard); - UsageMap::const_iterator usageIter; - int result = 0; - for (usageIter = mUsage.begin(); usageIter != mUsage.end(); usageIter++) - result += usageIter->second; + Lock l(mGuard); + UsageMap::const_iterator usageIter; + int result = 0; + for (usageIter = mUsage.begin(); usageIter != mUsage.end(); usageIter++) + result += usageIter->second; - return result; + return result; } void UsageCounter::clear() { - Lock l(mGuard); - mUsage.clear(); + Lock l(mGuard); + mUsage.clear(); } diff --git a/src/engine/helper/HL_Pointer.h b/src/engine/helper/HL_Pointer.h index 5709fdb9..d8ff09fd 100644 --- a/src/engine/helper/HL_Pointer.h +++ b/src/engine/helper/HL_Pointer.h @@ -13,17 +13,17 @@ class UsageCounter { public: - UsageCounter(); - ~UsageCounter(); - int obtain(int usageId); - int release(int usageId); - int usageCount(); - void clear(); + UsageCounter(); + ~UsageCounter(); + int obtain(int usageId); + int release(int usageId); + int usageCount(); + void clear(); protected: - typedef std::map UsageMap; - UsageMap mUsage; - Mutex mGuard; + typedef std::map UsageMap; + UsageMap mUsage; + Mutex mGuard; }; #endif diff --git a/src/engine/helper/HL_PoolAllocator.h b/src/engine/helper/HL_PoolAllocator.h index 02d1c765..aecdb5be 100644 --- a/src/engine/helper/HL_PoolAllocator.h +++ b/src/engine/helper/HL_PoolAllocator.h @@ -19,354 +19,381 @@ #include #ifndef HL_RTP_POOL -# define HL_RTP_POOL 1 +#define HL_RTP_POOL 1 #endif namespace hl { #if HL_RTP_POOL - /// @class FixedBlockPool - /// A process-wide, fixed-block pool with a lock-free thread-local fast path: uniform 256-byte - /// blocks carved from 64 KB chunks, an intrusive thread-local free list, and a per-block header - /// tag so deallocate() is O(1) and lock-free for any block (and can tell pooled blocks from the - /// global-allocator fallback used for oversized requests) regardless of the freeing thread. - /// - /// CROSS-THREAD RECLAIM (2026-07-26) — fixes an unbounded capacity ratchet. A uniform block size - /// makes a block allocated on one thread safe to free on another, but "safe" is not "reclaimed". - /// With a purely thread-local free list the block joins the FREEING thread's list, so a - /// producer/consumer split strands it: vq-core allocates RTPPacket / jitter-buffer nodes on the - /// capture threads and frees them on the interval/reap side, so the capture threads' lists were - /// perpetually empty and refill() carved a fresh chunk every BlocksPerChunk allocations, forever. - /// Observed on vqmonitor (the only box with >1 capture thread): capacityBlocks() 256 -> 11.8M - /// = 2.7 GiB over 4 days at ~25 MiB/h, while activeBlocks() drained to 0 every idle interval. - /// - /// The fix is a process-wide depot of free-block batches. A thread whose free list grows past - /// ThreadCacheHighWater hands a batch down to the depot; a thread that runs dry takes a batch - /// from the depot before carving a new chunk; a thread flushes its remainder to the depot on - /// exit. The depot is touched once per BlocksPerChunk operations and the hysteresis between - /// "empty" and the high-water keeps it off the per-packet path, so the fast path stays lock-free. - /// capacityBlocks() now plateaus at the true concurrent high-water instead of ratcheting. - class FixedBlockPool - { - public: - /// Usable bytes handed back to the caller from a pooled block. Comfortably covers the - /// shared_ptr nodes we pool (control block + RTPPacket / RtpBuffer::Packet, ~90-130 bytes). - static constexpr std::size_t PayloadSize = 240; - static constexpr std::size_t BlocksPerChunk = 256; - /// Free blocks a thread keeps to itself before handing a BlocksPerChunk batch to the depot. - /// Must exceed BlocksPerChunk so a thread that churns around the boundary does not bounce - /// on the depot mutex; 2x leaves a full batch in hand after every release. - static constexpr std::size_t ThreadCacheHighWater = 2 * BlocksPerChunk; +/// @class FixedBlockPool +/// A process-wide, fixed-block pool with a lock-free thread-local fast path: uniform 256-byte +/// blocks carved from 64 KB chunks, an intrusive thread-local free list, and a per-block header +/// tag so deallocate() is O(1) and lock-free for any block (and can tell pooled blocks from the +/// global-allocator fallback used for oversized requests) regardless of the freeing thread. +/// +/// CROSS-THREAD RECLAIM (2026-07-26) — fixes an unbounded capacity ratchet. A uniform block size +/// makes a block allocated on one thread safe to free on another, but "safe" is not "reclaimed". +/// With a purely thread-local free list the block joins the FREEING thread's list, so a +/// producer/consumer split strands it: vq-core allocates RTPPacket / jitter-buffer nodes on the +/// capture threads and frees them on the interval/reap side, so the capture threads' lists were +/// perpetually empty and refill() carved a fresh chunk every BlocksPerChunk allocations, forever. +/// Observed on vqmonitor (the only box with >1 capture thread): capacityBlocks() 256 -> 11.8M +/// = 2.7 GiB over 4 days at ~25 MiB/h, while activeBlocks() drained to 0 every idle interval. +/// +/// The fix is a process-wide depot of free-block batches. A thread whose free list grows past +/// ThreadCacheHighWater hands a batch down to the depot; a thread that runs dry takes a batch +/// from the depot before carving a new chunk; a thread flushes its remainder to the depot on +/// exit. The depot is touched once per BlocksPerChunk operations and the hysteresis between +/// "empty" and the high-water keeps it off the per-packet path, so the fast path stays lock-free. +/// capacityBlocks() now plateaus at the true concurrent high-water instead of ratcheting. +class FixedBlockPool +{ +public: + /// Usable bytes handed back to the caller from a pooled block. Comfortably covers the + /// shared_ptr nodes we pool (control block + RTPPacket / RtpBuffer::Packet, ~90-130 bytes). + static constexpr std::size_t PayloadSize = 240; + static constexpr std::size_t BlocksPerChunk = 256; + /// Free blocks a thread keeps to itself before handing a BlocksPerChunk batch to the depot. + /// Must exceed BlocksPerChunk so a thread that churns around the boundary does not bounce + /// on the depot mutex; 2x leaves a full batch in hand after every release. + static constexpr std::size_t ThreadCacheHighWater = 2 * BlocksPerChunk; - static void* allocate(std::size_t size) - { - if (size > PayloadSize) - { - uint8_t* raw = static_cast(::operator new(size + HeaderSize)); - tagOf(raw) = TagGlobal; - s_activeGlobal.fetch_add(1, std::memory_order_relaxed); - return raw + HeaderSize; - } + static void* allocate(std::size_t size) + { + if (size > PayloadSize) + { + uint8_t* raw = static_cast(::operator new(size + HeaderSize)); + tagOf(raw) = TagGlobal; + s_activeGlobal.fetch_add(1, std::memory_order_relaxed); + return raw + HeaderSize; + } - ThreadCache& tc = cache(); - if (tc.head == nullptr) - { - // Reclaim from the depot before asking the OS for more memory. Only when the - // depot is dry as well has the pool genuinely outgrown its current capacity. - std::size_t taken = 0; - tc.head = depot().takeBatch(taken); - if (tc.head == nullptr) - { - tc.head = registry().refill(); - taken = BlocksPerChunk; - } - tc.count = taken; - } + ThreadCache& tc = cache(); + if (tc.head == nullptr) + { + // Reclaim from the depot before asking the OS for more memory. Only when the + // depot is dry as well has the pool genuinely outgrown its current capacity. + std::size_t taken = 0; + tc.head = depot().takeBatch(taken); + if (tc.head == nullptr) + { + tc.head = registry().refill(); + taken = BlocksPerChunk; + } + tc.count = taken; + } - uint8_t* block = static_cast(tc.head); - tc.head = nextOf(block); - --tc.count; - s_activeBlocks.fetch_add(1, std::memory_order_relaxed); - return block + HeaderSize; - } + uint8_t* block = static_cast(tc.head); + tc.head = nextOf(block); + --tc.count; + s_activeBlocks.fetch_add(1, std::memory_order_relaxed); + return block + HeaderSize; + } - static void deallocate(void* ptr) noexcept - { - if (ptr == nullptr) - return; + static void deallocate(void* ptr) noexcept + { + if (ptr == nullptr) + return; - uint8_t* block = static_cast(ptr) - HeaderSize; - if (tagOf(block) == TagPool) - { - ThreadCache& tc = cache(); - nextOf(block) = tc.head; - tc.head = block; - ++tc.count; - s_activeBlocks.fetch_sub(1, std::memory_order_relaxed); + uint8_t* block = static_cast(ptr) - HeaderSize; + if (tagOf(block) == TagPool) + { + ThreadCache& tc = cache(); + nextOf(block) = tc.head; + tc.head = block; + ++tc.count; + s_activeBlocks.fetch_sub(1, std::memory_order_relaxed); - // The one line that closes the ratchet: surplus goes back to the depot, where - // the thread that actually allocates can reach it. - if (tc.count >= ThreadCacheHighWater) - releaseBatch(tc, BlocksPerChunk); - } - else - { - ::operator delete(static_cast(block)); - s_activeGlobal.fetch_sub(1, std::memory_order_relaxed); - } - } + // The one line that closes the ratchet: surplus goes back to the depot, where + // the thread that actually allocates can reach it. + if (tc.count >= ThreadCacheHighWater) + releaseBatch(tc, BlocksPerChunk); + } + else + { + ::operator delete(static_cast(block)); + s_activeGlobal.fetch_sub(1, std::memory_order_relaxed); + } + } - /// @name Diagnostics (relaxed gauges — not synchronization) - /// @{ - /// Blocks currently handed out from the pool = pooled allocate() minus - /// pooled deallocate(). Unlike capacityBlocks() (the chunk high-water, - /// which only ever grows) this DROPS when objects are freed, so a rising - /// activeBlocks() is a genuine leak of referenced objects rather than a - /// traffic peak that merely carved extra chunks. Covers every pooled - /// shared_ptr node (allocate_shared + jitter-buffer packets). - static std::int64_t activeBlocks() noexcept - { - return s_activeBlocks.load(std::memory_order_relaxed); - } - /// Live oversized allocations that overflowed to ::operator new. - static std::int64_t activeGlobalAllocations() noexcept - { - return s_activeGlobal.load(std::memory_order_relaxed); - } - /// Total blocks ever carved (chunks x BlocksPerChunk) = high-water capacity. - /// With cross-thread reclaim this PLATEAUS once the pool has covered the - /// concurrent high-water; sustained linear growth means reclaim is not working. - static std::int64_t capacityBlocks() noexcept - { - return s_chunks.load(std::memory_order_relaxed) * static_cast(BlocksPerChunk); - } - /// Free blocks parked in the process-wide depot, i.e. reclaimed from a freeing - /// thread and available to any allocating thread. Healthy steady state is a - /// non-zero, bounded value: it is the surplus that used to be stranded. - static std::int64_t depotBlocks() noexcept - { - return s_depotBlocks.load(std::memory_order_relaxed); - } - /// Approximate live pooled payload bytes (excludes per-block header). - static std::int64_t activeBytes() noexcept - { - return activeBlocks() * static_cast(PayloadSize); - } - /// @} + /// @name Diagnostics (relaxed gauges — not synchronization) + /// @{ + /// Blocks currently handed out from the pool = pooled allocate() minus + /// pooled deallocate(). Unlike capacityBlocks() (the chunk high-water, + /// which only ever grows) this DROPS when objects are freed, so a rising + /// activeBlocks() is a genuine leak of referenced objects rather than a + /// traffic peak that merely carved extra chunks. Covers every pooled + /// shared_ptr node (allocate_shared + jitter-buffer packets). + static std::int64_t activeBlocks() noexcept { return s_activeBlocks.load(std::memory_order_relaxed); } + /// Live oversized allocations that overflowed to ::operator new. + static std::int64_t activeGlobalAllocations() noexcept { return s_activeGlobal.load(std::memory_order_relaxed); } + /// Total blocks ever carved (chunks x BlocksPerChunk) = high-water capacity. + /// With cross-thread reclaim this PLATEAUS once the pool has covered the + /// concurrent high-water; sustained linear growth means reclaim is not working. + static std::int64_t capacityBlocks() noexcept + { + return s_chunks.load(std::memory_order_relaxed) * static_cast(BlocksPerChunk); + } + /// Free blocks parked in the process-wide depot, i.e. reclaimed from a freeing + /// thread and available to any allocating thread. Healthy steady state is a + /// non-zero, bounded value: it is the surplus that used to be stranded. + static std::int64_t depotBlocks() noexcept { return s_depotBlocks.load(std::memory_order_relaxed); } + /// Approximate live pooled payload bytes (excludes per-block header). + static std::int64_t activeBytes() noexcept { return activeBlocks() * static_cast(PayloadSize); } + /// @} - private: - inline static std::atomic s_activeBlocks{0}; - inline static std::atomic s_activeGlobal{0}; - inline static std::atomic s_chunks{0}; - inline static std::atomic s_depotBlocks{0}; +private: + inline static std::atomic s_activeBlocks{0}; + inline static std::atomic s_activeGlobal{0}; + inline static std::atomic s_chunks{0}; + inline static std::atomic s_depotBlocks{0}; - static constexpr std::size_t HeaderSize = - alignof(std::max_align_t) >= sizeof(uint64_t) ? alignof(std::max_align_t) : sizeof(uint64_t); - static constexpr std::size_t BlockSize = HeaderSize + PayloadSize; + static constexpr std::size_t HeaderSize = + alignof(std::max_align_t) >= sizeof(uint64_t) ? alignof(std::max_align_t) : sizeof(uint64_t); + static constexpr std::size_t BlockSize = HeaderSize + PayloadSize; - static constexpr uint64_t TagPool = 0x504F4F4C52545008ULL; // "POOLRTP\b" - static constexpr uint64_t TagGlobal = 0x474C4F42524C0808ULL; // "GLOBRL\b\b" + static constexpr uint64_t TagPool = 0x504F4F4C52545008ULL; // "POOLRTP\b" + static constexpr uint64_t TagGlobal = 0x474C4F42524C0808ULL; // "GLOBRL\b\b" - /// A free block's payload is dead space, so the list links live there. Slot 0 chains - /// blocks within a list/batch; slots 1-2 are used only on a batch's head block, to chain - /// batches inside the depot and to carry the batch length (batches from a thread-exit - /// flush are shorter than BlocksPerChunk). - static_assert(PayloadSize >= 2 * sizeof(void*) + sizeof(std::size_t), - "pooled block payload must hold the free-list, depot and length slots"); + /// A free block's payload is dead space, so the list links live there. Slot 0 chains + /// blocks within a list/batch; slots 1-2 are used only on a batch's head block, to chain + /// batches inside the depot and to carry the batch length (batches from a thread-exit + /// flush are shorter than BlocksPerChunk). + static_assert(PayloadSize >= 2 * sizeof(void*) + sizeof(std::size_t), + "pooled block payload must hold the free-list, depot and length slots"); - static uint64_t& tagOf(void* block) noexcept - { - return *reinterpret_cast(block); - } + static uint64_t& tagOf(void* block) noexcept { return *reinterpret_cast(block); } - static void*& nextOf(void* block) noexcept - { - return *reinterpret_cast(static_cast(block) + HeaderSize); - } + static void*& nextOf(void* block) noexcept + { + return *reinterpret_cast(static_cast(block) + HeaderSize); + } - static void*& batchNextOf(void* block) noexcept - { - return *reinterpret_cast(static_cast(block) + HeaderSize + sizeof(void*)); - } + static void*& batchNextOf(void* block) noexcept + { + return *reinterpret_cast(static_cast(block) + HeaderSize + sizeof(void*)); + } - static std::size_t& batchLenOf(void* block) noexcept - { - return *reinterpret_cast(static_cast(block) + HeaderSize + 2 * sizeof(void*)); - } + static std::size_t& batchLenOf(void* block) noexcept + { + return *reinterpret_cast(static_cast(block) + HeaderSize + 2 * sizeof(void*)); + } - /// Per-thread free list. The destructor hands the remainder to the depot so a thread that - /// exits does not strand its blocks — the same ratchet as the cross-thread case, just - /// triggered once per thread instead of continuously. - struct ThreadCache - { - void* head = nullptr; - std::size_t count = 0; + /// Per-thread free list. The destructor hands the remainder to the depot so a thread that + /// exits does not strand its blocks — the same ratchet as the cross-thread case, just + /// triggered once per thread instead of continuously. + struct ThreadCache + { + void* head = nullptr; + std::size_t count = 0; - ~ThreadCache() - { - while (count > 0 && head != nullptr) - releaseBatch(*this, count); - } - }; + ~ThreadCache() + { + while (count > 0 && head != nullptr) + releaseBatch(*this, count); + } + }; - static ThreadCache& cache() noexcept - { - static thread_local ThreadCache tc; - return tc; - } + static ThreadCache& cache() noexcept + { + static thread_local ThreadCache tc; + return tc; + } - /// Detach the first `blocks` entries of the thread list and park them in the depot. - static void releaseBatch(ThreadCache& tc, std::size_t blocks) noexcept - { - if (blocks == 0 || tc.head == nullptr) - return; + /// Detach the first `blocks` entries of the thread list and park them in the depot. + static void releaseBatch(ThreadCache& tc, std::size_t blocks) noexcept + { + if (blocks == 0 || tc.head == nullptr) + return; - void* batchHead = tc.head; - void* batchTail = batchHead; - std::size_t length = 1; - for (; length < blocks && nextOf(batchTail) != nullptr; ++length) - batchTail = nextOf(batchTail); + void* batchHead = tc.head; + void* batchTail = batchHead; + std::size_t length = 1; + for (; length < blocks && nextOf(batchTail) != nullptr; ++length) + batchTail = nextOf(batchTail); - tc.head = nextOf(batchTail); - tc.count -= length; - nextOf(batchTail) = nullptr; + tc.head = nextOf(batchTail); + tc.count -= length; + nextOf(batchTail) = nullptr; - batchLenOf(batchHead) = length; - depot().giveBatch(batchHead, length); - } + batchLenOf(batchHead) = length; + depot().giveBatch(batchHead, length); + } - /// Process-wide store of reclaimed batches. Intrusive (the links live in the free blocks - /// themselves) so neither path can allocate or throw — deallocate() is noexcept. The mutex - /// is taken once per BlocksPerChunk operations, not per packet. - class Depot - { - public: - void* takeBatch(std::size_t& lengthOut) noexcept - { - std::lock_guard lock(m_Mutex); - void* batch = m_Head; - if (batch == nullptr) - { - lengthOut = 0; - return nullptr; - } - m_Head = batchNextOf(batch); - lengthOut = batchLenOf(batch); - batchNextOf(batch) = nullptr; - s_depotBlocks.fetch_sub(static_cast(lengthOut), std::memory_order_relaxed); - return batch; - } + /// Process-wide store of reclaimed batches. Intrusive (the links live in the free blocks + /// themselves) so neither path can allocate or throw — deallocate() is noexcept. The mutex + /// is taken once per BlocksPerChunk operations, not per packet. + class Depot + { + public: + void* takeBatch(std::size_t& lengthOut) noexcept + { + std::lock_guard lock(m_Mutex); + void* batch = m_Head; + if (batch == nullptr) + { + lengthOut = 0; + return nullptr; + } + m_Head = batchNextOf(batch); + lengthOut = batchLenOf(batch); + batchNextOf(batch) = nullptr; + s_depotBlocks.fetch_sub(static_cast(lengthOut), std::memory_order_relaxed); + return batch; + } - void giveBatch(void* batch, std::size_t length) noexcept - { - std::lock_guard lock(m_Mutex); - batchNextOf(batch) = m_Head; - m_Head = batch; - s_depotBlocks.fetch_add(static_cast(length), std::memory_order_relaxed); - } + void giveBatch(void* batch, std::size_t length) noexcept + { + std::lock_guard lock(m_Mutex); + batchNextOf(batch) = m_Head; + m_Head = batch; + s_depotBlocks.fetch_add(static_cast(length), std::memory_order_relaxed); + } - private: - std::mutex m_Mutex; - void* m_Head = nullptr; - }; + private: + std::mutex m_Mutex; + void* m_Head = nullptr; + }; - class ChunkRegistry - { - public: - void* refill() - { - const std::size_t chunkBytes = BlockSize * BlocksPerChunk; - uint8_t* chunk = static_cast(::operator new(chunkBytes)); - s_chunks.fetch_add(1, std::memory_order_relaxed); + class ChunkRegistry + { + public: + void* refill() + { + const std::size_t chunkBytes = BlockSize * BlocksPerChunk; + uint8_t* chunk = static_cast(::operator new(chunkBytes)); + s_chunks.fetch_add(1, std::memory_order_relaxed); - { - std::lock_guard lock(m_Mutex); - m_Chunks.push_back(chunk); - } + { + std::lock_guard lock(m_Mutex); + m_Chunks.push_back(chunk); + } - void* list = nullptr; - for (std::size_t i = 0; i < BlocksPerChunk; ++i) - { - uint8_t* block = chunk + i * BlockSize; - tagOf(block) = TagPool; - nextOf(block) = list; - list = block; - } - return list; - } + void* list = nullptr; + for (std::size_t i = 0; i < BlocksPerChunk; ++i) + { + uint8_t* block = chunk + i * BlockSize; + tagOf(block) = TagPool; + nextOf(block) = list; + list = block; + } + return list; + } - private: - std::mutex m_Mutex; - std::vector m_Chunks; - }; + private: + std::mutex m_Mutex; + std::vector m_Chunks; + }; - /// Both singletons are deliberately immortal (leaked at exit, reclaimed by the OS). - /// A thread_local ThreadCache is destroyed at thread exit — for the main thread that is - /// during static destruction — and its destructor touches the depot, so a depot with a - /// destructor could be used after being destroyed. The same applies to the chunk memory: - /// any pooled object outliving the registry would free into deleted chunks. Never - /// destroying them removes both hazards; the process is exiting either way. - static Depot& depot() noexcept - { - static Depot* instance = new Depot(); - return *instance; - } + /// Both singletons are deliberately immortal (leaked at exit, reclaimed by the OS). + /// A thread_local ThreadCache is destroyed at thread exit — for the main thread that is + /// during static destruction — and its destructor touches the depot, so a depot with a + /// destructor could be used after being destroyed. The same applies to the chunk memory: + /// any pooled object outliving the registry would free into deleted chunks. Never + /// destroying them removes both hazards; the process is exiting either way. + static Depot& depot() noexcept + { + static Depot* instance = new Depot(); + return *instance; + } - static ChunkRegistry& registry() - { - static ChunkRegistry* instance = new ChunkRegistry(); - return *instance; - } - }; -#endif // HL_RTP_POOL + static ChunkRegistry& registry() + { + static ChunkRegistry* instance = new ChunkRegistry(); + return *instance; + } +}; +#endif // HL_RTP_POOL - /// Mode-independent accessors for the pool diagnostics, so callers need not know - /// whether HL_RTP_POOL is compiled in. When pooling is disabled they return -1 - /// ("not applicable") since allocate_shared then behaves like make_shared. +/// Mode-independent accessors for the pool diagnostics, so callers need not know +/// whether HL_RTP_POOL is compiled in. When pooling is disabled they return -1 +/// ("not applicable") since allocate_shared then behaves like make_shared. #if HL_RTP_POOL - inline std::int64_t poolActiveBlocks() noexcept { return FixedBlockPool::activeBlocks(); } - inline std::int64_t poolCapacityBlocks() noexcept { return FixedBlockPool::capacityBlocks(); } - inline std::int64_t poolDepotBlocks() noexcept { return FixedBlockPool::depotBlocks(); } - inline std::int64_t poolActiveGlobal() noexcept { return FixedBlockPool::activeGlobalAllocations(); } - inline std::int64_t poolActiveBytes() noexcept { return FixedBlockPool::activeBytes(); } +inline std::int64_t poolActiveBlocks() noexcept +{ + return FixedBlockPool::activeBlocks(); +} +inline std::int64_t poolCapacityBlocks() noexcept +{ + return FixedBlockPool::capacityBlocks(); +} +inline std::int64_t poolDepotBlocks() noexcept +{ + return FixedBlockPool::depotBlocks(); +} +inline std::int64_t poolActiveGlobal() noexcept +{ + return FixedBlockPool::activeGlobalAllocations(); +} +inline std::int64_t poolActiveBytes() noexcept +{ + return FixedBlockPool::activeBytes(); +} #else - inline std::int64_t poolActiveBlocks() noexcept { return -1; } - inline std::int64_t poolCapacityBlocks() noexcept { return -1; } - inline std::int64_t poolDepotBlocks() noexcept { return -1; } - inline std::int64_t poolActiveGlobal() noexcept { return -1; } - inline std::int64_t poolActiveBytes() noexcept { return -1; } +inline std::int64_t poolActiveBlocks() noexcept +{ + return -1; +} +inline std::int64_t poolCapacityBlocks() noexcept +{ + return -1; +} +inline std::int64_t poolDepotBlocks() noexcept +{ + return -1; +} +inline std::int64_t poolActiveGlobal() noexcept +{ + return -1; +} +inline std::int64_t poolActiveBytes() noexcept +{ + return -1; +} #endif - /// @class PoolAllocator - /// A stateless, std-conforming Allocator suitable for std::allocate_shared. When HL_RTP_POOL is - /// enabled it serves single-node allocations from FixedBlockPool; otherwise (and for any request - /// that does not fit a pooled block) it delegates to the global allocator, matching make_shared. - template struct PoolAllocator - { - using value_type = T; +/// @class PoolAllocator +/// A stateless, std-conforming Allocator suitable for std::allocate_shared. When HL_RTP_POOL is +/// enabled it serves single-node allocations from FixedBlockPool; otherwise (and for any request +/// that does not fit a pooled block) it delegates to the global allocator, matching make_shared. +template +struct PoolAllocator +{ + using value_type = T; - PoolAllocator() noexcept = default; - template PoolAllocator(const PoolAllocator&) noexcept {} + PoolAllocator() noexcept = default; + template + PoolAllocator(const PoolAllocator&) noexcept + { + } - T* allocate(std::size_t n) - { + T* allocate(std::size_t n) + { #if HL_RTP_POOL - return static_cast(FixedBlockPool::allocate(n * sizeof(T))); + return static_cast(FixedBlockPool::allocate(n * sizeof(T))); #else - return static_cast(::operator new(n * sizeof(T))); + return static_cast(::operator new(n * sizeof(T))); #endif - } + } - void deallocate(T* p, std::size_t /*n*/) noexcept - { + void deallocate(T* p, std::size_t /*n*/) noexcept + { #if HL_RTP_POOL - FixedBlockPool::deallocate(p); + FixedBlockPool::deallocate(p); #else - ::operator delete(static_cast(p)); + ::operator delete(static_cast(p)); #endif - } + } - template bool operator==(const PoolAllocator&) const noexcept { return true; } - template bool operator!=(const PoolAllocator&) const noexcept { return false; } - }; -} // namespace hl + template + bool operator==(const PoolAllocator&) const noexcept + { + return true; + } + template + bool operator!=(const PoolAllocator&) const noexcept + { + return false; + } +}; +} // namespace hl diff --git a/src/engine/helper/HL_Process.cpp b/src/engine/helper/HL_Process.cpp index 31a4c9b1..5c63428b 100644 --- a/src/engine/helper/HL_Process.cpp +++ b/src/engine/helper/HL_Process.cpp @@ -4,8 +4,8 @@ #include #ifdef TARGET_WIN -# define popen _popen -# define pclose _pclose +#define popen _popen +#define pclose _pclose #endif #if defined(TARGET_WIN) @@ -19,46 +19,46 @@ int OsProcess::execSystem(const std::string& cmd) std::string OsProcess::execCommand(const std::string& cmd) { - std::string output; - HANDLE hPipeRead, hPipeWrite; + std::string output; + HANDLE hPipeRead, hPipeWrite; - SECURITY_ATTRIBUTES saAttr = { sizeof(SECURITY_ATTRIBUTES) }; - saAttr.bInheritHandle = TRUE; //Pipe handles are inherited by child process. + SECURITY_ATTRIBUTES saAttr = {sizeof(SECURITY_ATTRIBUTES)}; + saAttr.bInheritHandle = TRUE; // Pipe handles are inherited by child process. saAttr.lpSecurityDescriptor = NULL; // Create a pipe to get results from child's stdout. - if ( !CreatePipe(&hPipeRead, &hPipeWrite, &saAttr, 0) ) + if (!CreatePipe(&hPipeRead, &hPipeWrite, &saAttr, 0)) return output; - STARTUPINFOA si = { sizeof(STARTUPINFOA) }; - si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; - si.hStdOutput = hPipeWrite; - si.hStdError = hPipeWrite; - si.wShowWindow = SW_HIDE; // Prevents cmd window from flashing. Requires STARTF_USESHOWWINDOW in dwFlags. + STARTUPINFOA si = {sizeof(STARTUPINFOA)}; + si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; + si.hStdOutput = hPipeWrite; + si.hStdError = hPipeWrite; + si.wShowWindow = SW_HIDE; // Prevents cmd window from flashing. Requires STARTF_USESHOWWINDOW in dwFlags. - PROCESS_INFORMATION pi = { 0 }; + PROCESS_INFORMATION pi = {0}; - char* cmdline = (char*)_alloca(cmd.size()+1); + char* cmdline = (char*)_alloca(cmd.size() + 1); strcpy(cmdline, strx::replace(cmd, "/", "\\").c_str()); - BOOL fSuccess = CreateProcessA( nullptr, cmdline, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi); - if (! fSuccess) + BOOL fSuccess = CreateProcessA(nullptr, cmdline, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi); + if (!fSuccess) { - CloseHandle( hPipeWrite ); - CloseHandle( hPipeRead ); + CloseHandle(hPipeWrite); + CloseHandle(hPipeRead); return output; } bool bProcessEnded = false; - for (; !bProcessEnded ;) + for (; !bProcessEnded;) { // Give some timeslice (50ms), so we won't waste 100% cpu. - bProcessEnded = WaitForSingleObject( pi.hProcess, 50) == WAIT_OBJECT_0; + bProcessEnded = WaitForSingleObject(pi.hProcess, 50) == WAIT_OBJECT_0; // Even if process exited - we continue reading, if there is some data available over pipe. for (;;) { - char buf[1024]; + char buf[1024]; DWORD dwRead = 0; DWORD dwAvail = 0; @@ -75,119 +75,122 @@ std::string OsProcess::execCommand(const std::string& cmd) buf[dwRead] = 0; output += buf; } - } //for + } // for - CloseHandle( hPipeWrite ); - CloseHandle( hPipeRead ); - CloseHandle( pi.hProcess ); - CloseHandle( pi.hThread ); + CloseHandle(hPipeWrite); + CloseHandle(hPipeRead); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); return output; } -std::shared_ptr OsProcess::asyncExecCommand(const std::string& cmdline, - std::function callback, - std::function finished_callback, - bool& finish_flag) +std::shared_ptr +OsProcess::asyncExecCommand(const std::string& cmdline, std::function callback, + std::function finished_callback, bool& finish_flag) { // std::cout << cmdline << std::endl; - std::string output; - HANDLE hPipeRead, hPipeWrite; + std::string output; + HANDLE hPipeRead, hPipeWrite; - SECURITY_ATTRIBUTES saAttr = { sizeof(SECURITY_ATTRIBUTES), nullptr, FALSE }; - saAttr.bInheritHandle = TRUE; //Pipe handles are inherited by child process. + SECURITY_ATTRIBUTES saAttr = {sizeof(SECURITY_ATTRIBUTES), nullptr, FALSE}; + saAttr.bInheritHandle = TRUE; // Pipe handles are inherited by child process. saAttr.lpSecurityDescriptor = nullptr; - + // Create a pipe to get results from child's stdout. - if ( !CreatePipe(&hPipeRead, &hPipeWrite, &saAttr, 0) ) + if (!CreatePipe(&hPipeRead, &hPipeWrite, &saAttr, 0)) return std::shared_ptr(); - STARTUPINFOA si; memset(&si, 0, sizeof si); + STARTUPINFOA si; + memset(&si, 0, sizeof si); si.cb = sizeof(STARTUPINFOA); - si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; - si.hStdOutput = hPipeWrite; - si.hStdError = hPipeWrite; - si.wShowWindow = SW_HIDE; // Prevents cmd window from flashing. Requires STARTF_USESHOWWINDOW in dwFlags. + si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; + si.hStdOutput = hPipeWrite; + si.hStdError = hPipeWrite; + si.wShowWindow = SW_HIDE; // Prevents cmd window from flashing. Requires STARTF_USESHOWWINDOW in dwFlags. PROCESS_INFORMATION pi; memset(&pi, 0, sizeof pi); - char* cmdbuffer = (char*)_alloca(cmdline.size()+1); + char* cmdbuffer = (char*)_alloca(cmdline.size() + 1); strcpy(cmdbuffer, strx::replace(cmdline, "/", "\\").c_str()); - BOOL fSuccess = CreateProcessA( nullptr, cmdbuffer, nullptr, nullptr, TRUE, - CREATE_NEW_CONSOLE, nullptr, nullptr, &si, &pi); - if (! fSuccess) + BOOL fSuccess = + CreateProcessA(nullptr, cmdbuffer, nullptr, nullptr, TRUE, CREATE_NEW_CONSOLE, nullptr, nullptr, &si, &pi); + if (!fSuccess) { - CloseHandle( hPipeWrite ); - CloseHandle( hPipeRead ); + CloseHandle(hPipeWrite); + CloseHandle(hPipeRead); return std::shared_ptr(); } std::shared_ptr r = std::make_shared( - [&finish_flag, pi, callback, finished_callback, hPipeRead, hPipeWrite]() - { - char buf[4096]; memset(buf, 0, sizeof buf); - for (; !finish_flag ;) + [&finish_flag, pi, callback, finished_callback, hPipeRead, hPipeWrite]() { - // Give some timeslice (50ms), so we won't waste 100% cpu. - bool timeouted = WaitForSingleObject( pi.hProcess, 50) == WAIT_OBJECT_0; - - // Even if process exited - we continue reading, if there is some data available over pipe. - for (;;) + char buf[4096]; + memset(buf, 0, sizeof buf); + for (; !finish_flag;) { - DWORD dwRead = 0; - DWORD dwAvail = 0; + // Give some timeslice (50ms), so we won't waste 100% cpu. + bool timeouted = WaitForSingleObject(pi.hProcess, 50) == WAIT_OBJECT_0; - if (!::PeekNamedPipe(hPipeRead, nullptr, 0, nullptr, &dwAvail, nullptr)) - break; - - if (!dwAvail) // no data available, return - break; - - int filled = strlen(buf); - if (!::ReadFile(hPipeRead, buf + filled, std::min(sizeof(buf) - 1 - filled, (size_t)dwAvail), &dwRead, nullptr) || !dwRead) - // error, the child process might ended - break; - - buf[dwRead] = 0; - - // Split to lines and send to callback - const char* cr; - while ((cr = strchr(buf, '\n')) != nullptr) + // Even if process exited - we continue reading, if there is some data available over pipe. + for (;;) { - std::string line(buf, cr - buf -1); - if (callback) - callback(strx::trim(line)); - memmove(buf, cr + 1, strlen(cr+1) + 1); + DWORD dwRead = 0; + DWORD dwAvail = 0; + + if (!::PeekNamedPipe(hPipeRead, nullptr, 0, nullptr, &dwAvail, nullptr)) + break; + + if (!dwAvail) // no data available, return + break; + + int filled = strlen(buf); + if (!::ReadFile(hPipeRead, buf + filled, std::min(sizeof(buf) - 1 - filled, (size_t)dwAvail), + &dwRead, nullptr) || + !dwRead) + // error, the child process might ended + break; + + buf[dwRead] = 0; + + // Split to lines and send to callback + const char* cr; + while ((cr = strchr(buf, '\n')) != nullptr) + { + std::string line(buf, cr - buf - 1); + if (callback) + callback(strx::trim(line)); + memmove(buf, cr + 1, strlen(cr + 1) + 1); + } } + } // for + + if (buf[0]) + callback(strx::trim(std::string(buf))); + + char ctrlc = 3; + // if (finish_flag) + // ::WriteFile(hPipeWrite, &ctrlc, 1, nullptr, nullptr); + + // GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, pi.dwProcessId); + + CloseHandle(hPipeWrite); + CloseHandle(hPipeRead); + if (finish_flag) + { + // GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); + // Close underlying process + // TerminateProcess(pi.hProcess, 3); } - } //for - - if (buf[0]) - callback(strx::trim(std::string(buf))); - - char ctrlc = 3; - //if (finish_flag) - // ::WriteFile(hPipeWrite, &ctrlc, 1, nullptr, nullptr); - - // GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, pi.dwProcessId); - - CloseHandle( hPipeWrite ); - CloseHandle( hPipeRead ); - if (finish_flag) - { - //GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); - // Close underlying process - //TerminateProcess(pi.hProcess, 3); - } - CloseHandle( pi.hProcess ); - CloseHandle( pi.hThread ); - if (finished_callback) - finished_callback(std::string()); - }); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + if (finished_callback) + finished_callback(std::string()); + }); return r; } @@ -201,12 +204,12 @@ std::shared_ptr OsProcess::asyncExecCommand(const std::string& cmdl std::string OsProcess::execCommand(const std::string& cmd) { - std::string cp = cmd; + std::string cp = cmd; std::shared_ptr pipe(popen(cp.c_str(), "r"), pclose); if (!pipe) throw std::runtime_error("Failed to run."); - char buffer[1024]; + char buffer[1024]; std::string result = ""; while (!feof(pipe.get())) { @@ -229,84 +232,83 @@ int OsProcess::execSystem(const std::string& cmd) #include "helper/HL_String.h" #include "helper/HL_Sync.h" -std::shared_ptr OsProcess::asyncExecCommand(const std::string& cmdline, - std::function line_callback, - std::function finished_callback, - bool& finish_flag) +std::shared_ptr +OsProcess::asyncExecCommand(const std::string& cmdline, std::function line_callback, + std::function finished_callback, bool& finish_flag) { - std::shared_ptr t = std::make_shared([cmdline, line_callback, finished_callback, &finish_flag]() - { - ThreadHelper::setName("OsProcess::asyncExecCommand"); - std::string cp = cmdline; - FILE* pipe = popen(cp.c_str(), "r"); - if (!pipe) + std::shared_ptr t = std::make_shared( + [cmdline, line_callback, finished_callback, &finish_flag]() { - if (finished_callback) - finished_callback("Failed to open pipe"); - return; - } - - char buffer[1024]; - std::string lines; - std::string result = ""; - int fno = fileno(pipe); - - // Make it non blocking - fcntl(fno, F_SETFL, O_NONBLOCK); - - while (!feof(pipe) && !finish_flag) - { - // Wait for more data - struct pollfd pfd{ .fd = fno, .events = POLLIN }; - - while (poll(&pfd, 1, 0) == 0 && !finish_flag) - ; - - // Read data - if (finish_flag) - continue; - - int r; - do + ThreadHelper::setName("OsProcess::asyncExecCommand"); + std::string cp = cmdline; + FILE* pipe = popen(cp.c_str(), "r"); + if (!pipe) { - r = static_cast(read(fno, buffer, sizeof(buffer) - 1)); - if (r > 0) - { - buffer[r] = 0; - lines += std::string(buffer); - } + if (finished_callback) + finished_callback("Failed to open pipe"); + return; } - while (r == sizeof(buffer) - 1); - if (lines.find('\n') != std::string::npos && line_callback) + char buffer[1024]; + std::string lines; + std::string result = ""; + int fno = fileno(pipe); + + // Make it non blocking + fcntl(fno, F_SETFL, O_NONBLOCK); + + while (!feof(pipe) && !finish_flag) { - std::string::size_type p = 0; - while (p < lines.size()) + // Wait for more data + struct pollfd pfd{.fd = fno, .events = POLLIN}; + + while (poll(&pfd, 1, 0) == 0 && !finish_flag) + ; + + // Read data + if (finish_flag) + continue; + + int r; + do { - std::string::size_type d = lines.find('\n', p); - if (d != std::string::npos) + r = static_cast(read(fno, buffer, sizeof(buffer) - 1)); + if (r > 0) { - if (line_callback) - line_callback(strx::trim(lines.substr(p, d-p))); - p = d + 1; + buffer[r] = 0; + lines += std::string(buffer); } + } while (r == sizeof(buffer) - 1); + + if (lines.find('\n') != std::string::npos && line_callback) + { + std::string::size_type p = 0; + while (p < lines.size()) + { + std::string::size_type d = lines.find('\n', p); + if (d != std::string::npos) + { + if (line_callback) + line_callback(strx::trim(lines.substr(p, d - p))); + p = d + 1; + } + } + + lines.erase(0, p); } - - lines.erase(0, p); } - } - if (finish_flag) - { - // Send SIGINT to process - } - if (pipe) - pclose(pipe); + if (finish_flag) + { + // Send SIGINT to process + } + if (pipe) + pclose(pipe); - finish_flag = true; - if (finished_callback) - finished_callback(std::string()); - }); + finish_flag = true; + if (finished_callback) + finished_callback(std::string()); + }); return t; } @@ -322,7 +324,7 @@ pid_t OsProcess::findPid(const std::string& cmdline) std::string output = execCommand(oss.str()); return std::atoi(output.c_str()); } - catch(...) + catch (...) { return 0; } diff --git a/src/engine/helper/HL_Process.h b/src/engine/helper/HL_Process.h index e933198d..9ecdab80 100644 --- a/src/engine/helper/HL_Process.h +++ b/src/engine/helper/HL_Process.h @@ -10,16 +10,14 @@ class OsProcess { public: static std::string execCommand(const std::string& cmdline); - static int execSystem(const std::string& cmdline); - static std::shared_ptr asyncExecCommand(const std::string& cmdline, - std::function line_callback, - std::function finished_callback, - bool& finish_flag); + static int execSystem(const std::string& cmdline); + static std::shared_ptr + asyncExecCommand(const std::string& cmdline, std::function line_callback, + std::function finished_callback, bool& finish_flag); #if defined(TARGET_OSX) || defined(TARGET_LINUX) static pid_t findPid(const std::string& cmdline); - static void killByPid(pid_t pid); + static void killByPid(pid_t pid); #endif - }; #endif diff --git a/src/engine/helper/HL_Rtp.cpp b/src/engine/helper/HL_Rtp.cpp index a68e3d27..9b82619c 100644 --- a/src/engine/helper/HL_Rtp.cpp +++ b/src/engine/helper/HL_Rtp.cpp @@ -4,12 +4,12 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #if defined(TARGET_WIN) -# include -# include +#include +#include #endif #if defined(TARGET_LINUX) || defined(TARGET_ANDROID) || defined(TARGET_OSX) -# include +#include #endif #include "HL_Rtp.h" @@ -28,30 +28,30 @@ #define LOG_SUBSYSTEM "network" static constexpr size_t MAX_RTP_PACKET_SIZE = 65535; -static const char RTPDUMP_SHEBANG[] = "#!rtpplay1.0"; +static const char RTPDUMP_SHEBANG[] = "#!rtpplay1.0"; // RTP fixed header (little-endian bit-field layout) struct RtpHeader { - unsigned char cc:4; /* CSRC count */ - unsigned char x:1; /* header extension flag */ - unsigned char p:1; /* padding flag */ - unsigned char version:2; /* protocol version */ - unsigned char pt:7; /* payload type */ - unsigned char m:1; /* marker bit */ + unsigned char cc : 4; /* CSRC count */ + unsigned char x : 1; /* header extension flag */ + unsigned char p : 1; /* padding flag */ + unsigned char version : 2; /* protocol version */ + unsigned char pt : 7; /* payload type */ + unsigned char m : 1; /* marker bit */ unsigned short seq; /* sequence number */ - unsigned int ts; /* timestamp */ - unsigned int ssrc; /* synchronization source */ + unsigned int ts; /* timestamp */ + unsigned int ssrc; /* synchronization source */ }; struct RtcpHeader { - unsigned char rc:5; /* reception report count */ - unsigned char p:1; /* padding flag */ - unsigned char version:2; /* protocol version */ - unsigned char pt; /* payload type */ - uint16_t len; /* length */ - uint32_t ssrc; /* synchronization source */ + unsigned char rc : 5; /* reception report count */ + unsigned char p : 1; /* padding flag */ + unsigned char version : 2; /* protocol version */ + unsigned char pt; /* payload type */ + uint16_t len; /* length */ + uint32_t ssrc; /* synchronization source */ }; // --- IPv4 address helpers --- @@ -59,10 +59,8 @@ struct RtcpHeader static std::string ipToString(uint32_t ip) { // ip in host byte order → dotted-decimal - return std::to_string((ip >> 24) & 0xFF) + "." + - std::to_string((ip >> 16) & 0xFF) + "." + - std::to_string((ip >> 8) & 0xFF) + "." + - std::to_string( ip & 0xFF); + return std::to_string((ip >> 24) & 0xFF) + "." + std::to_string((ip >> 16) & 0xFF) + "." + + std::to_string((ip >> 8) & 0xFF) + "." + std::to_string(ip & 0xFF); } static uint32_t stringToIp(const std::string& s) @@ -87,7 +85,7 @@ bool RtpHelper::isRtp(const void* buffer, size_t length) return false; unsigned char pt = h->pt; - bool rtp = (pt >= 96 && pt <= 127) || (pt < 35); + bool rtp = (pt >= 96 && pt <= 127) || (pt < 35); return rtp; } @@ -130,7 +128,7 @@ int RtpHelper::findPtype(const void* buffer, size_t length) return -1; } -int RtpHelper::findPacketNo(const void *buffer, size_t length) +int RtpHelper::findPacketNo(const void* buffer, size_t length) { if (isRtp(buffer, length)) return ntohs(reinterpret_cast(buffer)->seq); @@ -144,15 +142,16 @@ int RtpHelper::findPayloadLength(const void* buffer, size_t length) return -1; const RtpHeader* h = reinterpret_cast(buffer); - const uint8_t* p = static_cast(buffer); + const uint8_t* p = static_cast(buffer); // Fixed header (12 bytes) + CSRC list (4 * CC bytes) - size_t offset = 12 + 4u * h->cc; + size_t offset = 12 + 4u * h->cc; if (offset > length) return -1; // Header extension - if (h->x) { + if (h->x) + { if (offset + 4 > length) return -1; uint16_t extWords = (static_cast(p[offset + 2]) << 8) | p[offset + 3]; @@ -164,7 +163,8 @@ int RtpHelper::findPayloadLength(const void* buffer, size_t length) size_t payloadLen = length - offset; // Padding - if (h->p && payloadLen > 0) { + if (h->p && payloadLen > 0) + { uint8_t padBytes = p[length - 1]; if (padBytes > payloadLen) return -1; @@ -186,29 +186,29 @@ std::shared_ptr RtpDump::parseRtpData(const uint8_t* data, s if (!data || len < 12 || !RtpHelper::isRtp(data, len)) return nullptr; - try { + try + { // Both are heap-allocated; RTPRawPacket takes ownership and deletes them jrtplib::RTPIPAddress senderAddress = {jrtplib::RTPIPv4Address(uint32_t(0), uint16_t(0))}; - uint8_t* dataCopy = new uint8_t[len]; + uint8_t* dataCopy = new uint8_t[len]; std::memcpy(dataCopy, data, len); jrtplib::RTPRawPacket raw(dataCopy, len, senderAddress, jrtplib::RTPTime(0), true); - auto packet = std::make_shared(raw); + auto packet = std::make_shared(raw); if (packet->GetCreationError() != 0) return nullptr; return packet; - } catch (const std::exception& e) { + } + catch (const std::exception& e) + { ICELogInfo(<< "Failed to parse RTP packet: " << e.what()); return nullptr; } } -RtpDump::RtpDump(const char* filename) - : mFilename(filename ? filename : "") -{ -} +RtpDump::RtpDump(const char* filename) : mFilename(filename ? filename : "") {} RtpDump::~RtpDump() = default; @@ -237,14 +237,19 @@ void RtpDump::load() // Parse source address from the text line size_t spacePos = textLine.find(' '); - if (spacePos != std::string::npos) { + if (spacePos != std::string::npos) + { std::string addrPart = textLine.substr(spacePos + 1); - size_t slashPos = addrPart.find('/'); - if (slashPos != std::string::npos) { + size_t slashPos = addrPart.find('/'); + if (slashPos != std::string::npos) + { mSourceIp = stringToIp(addrPart.substr(0, slashPos)); - try { + try + { mSourcePort = static_cast(std::stoi(addrPart.substr(slashPos + 1))); - } catch (...) { + } + catch (...) + { mSourcePort = 0; } } @@ -260,14 +265,14 @@ void RtpDump::load() input.read(reinterpret_cast(&buf32), 4); mStartUsec = ntohl(buf32); - input.read(reinterpret_cast(&buf32), 4); // source IP (already NBO in file) + input.read(reinterpret_cast(&buf32), 4); // source IP (already NBO in file) // The binary header stores IP in network byte order; convert to host mSourceIp = ntohl(buf32); input.read(reinterpret_cast(&buf16), 2); mSourcePort = ntohs(buf16); - input.read(reinterpret_cast(&buf16), 2); // padding — discard + input.read(reinterpret_cast(&buf16), 2); // padding — discard if (!input.good()) throw std::runtime_error("Failed to read rtpdump binary header"); @@ -275,21 +280,25 @@ void RtpDump::load() // --- 3. Packet records --- size_t packetCount = 0; - while (input.good() && input.peek() != EOF) { + while (input.good() && input.peek() != EOF) + { // Packet header: length(2) + plen(2) + offset(4) = 8 bytes uint16_t recLength, plen; uint32_t offsetMs; input.read(reinterpret_cast(&recLength), 2); - if (input.gcount() != 2) break; + if (input.gcount() != 2) + break; recLength = ntohs(recLength); input.read(reinterpret_cast(&plen), 2); - if (input.gcount() != 2) break; + if (input.gcount() != 2) + break; plen = ntohs(plen); input.read(reinterpret_cast(&offsetMs), 4); - if (input.gcount() != 4) break; + if (input.gcount() != 4) + break; offsetMs = ntohl(offsetMs); // All-zeros record signals end of file in some implementations @@ -365,9 +374,10 @@ void RtpDump::add(const void* buffer, size_t len) return; uint32_t offsetMs = 0; - auto now = std::chrono::steady_clock::now(); + auto now = std::chrono::steady_clock::now(); - if (!mRecording) { + if (!mRecording) + { mRecording = true; mRecordStart = now; @@ -376,9 +386,11 @@ void RtpDump::add(const void* buffer, size_t len) auto epoch = wallNow.time_since_epoch(); auto sec = std::chrono::duration_cast(epoch); auto usec = std::chrono::duration_cast(epoch - sec); - mStartSec = static_cast(sec.count()); + mStartSec = static_cast(sec.count()); mStartUsec = static_cast(usec.count()); - } else { + } + else + { auto elapsed = std::chrono::duration_cast(now - mRecordStart); offsetMs = static_cast(elapsed.count()); } @@ -396,8 +408,7 @@ void RtpDump::add(const void* buffer, size_t len, uint32_t offsetMs) throw std::runtime_error("Packet too large: " + std::to_string(len)); RtpData entry; - entry.mRawData.assign(static_cast(buffer), - static_cast(buffer) + len); + entry.mRawData.assign(static_cast(buffer), static_cast(buffer) + len); entry.mOffsetMs = offsetMs; entry.mPacket = parseRtpData(entry.mRawData.data(), entry.mRawData.size()); @@ -414,9 +425,8 @@ void RtpDump::flush() throw std::runtime_error("Failed to open file for writing: " + mFilename); // --- 1. Text header --- - std::string textLine = std::string(RTPDUMP_SHEBANG) + " " + - ipToString(mSourceIp) + "/" + - std::to_string(mSourcePort) + "\n"; + std::string textLine = + std::string(RTPDUMP_SHEBANG) + " " + ipToString(mSourceIp) + "/" + std::to_string(mSourcePort) + "\n"; output.write(textLine.data(), static_cast(textLine.size())); // --- 2. Binary file header (16 bytes) --- @@ -435,13 +445,14 @@ void RtpDump::flush() buf16 = htons(mSourcePort); output.write(reinterpret_cast(&buf16), 2); - buf16 = 0; // padding + buf16 = 0; // padding output.write(reinterpret_cast(&buf16), 2); // --- 3. Packet records --- size_t written = 0; - for (const auto& pkt : mPacketList) { + for (const auto& pkt : mPacketList) + { if (pkt.mRawData.empty()) continue; diff --git a/src/engine/helper/HL_Rtp.h b/src/engine/helper/HL_Rtp.h index aeb13ae3..323e66ae 100644 --- a/src/engine/helper/HL_Rtp.h +++ b/src/engine/helper/HL_Rtp.h @@ -22,12 +22,9 @@ struct RtpPair T mRtp; T mRtcp; - RtpPair() - {} + RtpPair() {} - RtpPair(const T& rtp, const T& rtcp) - :mRtp(rtp), mRtcp(rtcp) - {} + RtpPair(const T& rtp, const T& rtcp) : mRtp(rtp), mRtcp(rtcp) {} bool multiplexed() const { return mRtp == mRtcp; } }; @@ -35,14 +32,14 @@ struct RtpPair class RtpHelper { public: - static bool isRtp(const void* buffer, size_t length); - static int findPtype(const void* buffer, size_t length); - static int findPacketNo(const void *buffer, size_t length); - static bool isRtpOrRtcp(const void* buffer, size_t length); - static bool isRtcp(const void* buffer, size_t length); - static unsigned findSsrc(const void* buffer, size_t length); - static void setSsrc(void* buffer, size_t length, uint32_t ssrc); - static int findPayloadLength(const void* buffer, size_t length); + static bool isRtp(const void* buffer, size_t length); + static int findPtype(const void* buffer, size_t length); + static int findPacketNo(const void* buffer, size_t length); + static bool isRtpOrRtcp(const void* buffer, size_t length); + static bool isRtcp(const void* buffer, size_t length); + static unsigned findSsrc(const void* buffer, size_t length); + static void setSsrc(void* buffer, size_t length, uint32_t ssrc); + static int findPayloadLength(const void* buffer, size_t length); static std::chrono::microseconds toMicroseconds(const jrtplib::RTPTime& t); }; @@ -79,72 +76,72 @@ protected: struct RtpData { std::shared_ptr mPacket; - std::vector mRawData; - uint32_t mOffsetMs = 0; + std::vector mRawData; + uint32_t mOffsetMs = 0; }; - typedef std::vector PacketList; - PacketList mPacketList; - std::string mFilename; - bool mLoaded = false; + typedef std::vector PacketList; + PacketList mPacketList; + std::string mFilename; + bool mLoaded = false; // File header fields - uint32_t mSourceIp = 0; - uint16_t mSourcePort = 0; - uint32_t mStartSec = 0; - uint32_t mStartUsec = 0; + uint32_t mSourceIp = 0; + uint16_t mSourcePort = 0; + uint32_t mStartSec = 0; + uint32_t mStartUsec = 0; // Auto-compute packet offsets during recording - bool mRecording = false; + bool mRecording = false; std::chrono::steady_clock::time_point mRecordStart; - std::shared_ptr parseRtpData(const uint8_t* data, size_t len); + std::shared_ptr parseRtpData(const uint8_t* data, size_t len); public: explicit RtpDump(const char* filename); ~RtpDump(); /** Set source address for the file header (host byte order). */ - void setSource(uint32_t ip, uint16_t port); - uint32_t sourceIp() const { return mSourceIp; } - uint16_t sourcePort() const { return mSourcePort; } + void setSource(uint32_t ip, uint16_t port); + uint32_t sourceIp() const { return mSourceIp; } + uint16_t sourcePort() const { return mSourcePort; } /** * @brief Load packets from an rtpdump file * @throws std::runtime_error on file/format error */ - void load(); - bool isLoaded() const { return mLoaded; } + void load(); + bool isLoaded() const { return mLoaded; } - size_t count() const; + size_t count() const; /** * @brief Get parsed RTP packet at index * @throws std::out_of_range if index is invalid * @throws std::runtime_error if packet could not be parsed as RTP */ - jrtplib::RTPPacket& packetAt(size_t index); + jrtplib::RTPPacket& packetAt(size_t index); /** @brief Get raw packet bytes at index */ const std::vector& rawDataAt(size_t index) const; /** @brief Get packet time offset in milliseconds */ - uint32_t offsetAt(size_t index) const; + uint32_t offsetAt(size_t index) const; /** @brief Add a packet; time offset is auto-computed from first add() call */ - void add(const void* data, size_t len); + void add(const void* data, size_t len); /** @brief Add a packet with an explicit millisecond offset */ - void add(const void* data, size_t len, uint32_t offsetMs); + void add(const void* data, size_t len, uint32_t offsetMs); /** * @brief Write all packets to file in rtpdump format * @throws std::runtime_error on file error */ - void flush(); + void flush(); - void clear(); - const std::string& filename() const { return mFilename; } + void clear(); + const std::string& filename() const { return mFilename; } }; #endif diff --git a/src/engine/helper/HL_Singletone.h b/src/engine/helper/HL_Singletone.h index 9473c153..55b1670c 100644 --- a/src/engine/helper/HL_Singletone.h +++ b/src/engine/helper/HL_Singletone.h @@ -4,12 +4,13 @@ #include #include -template +template class SafeSingleton { protected: static std::atomic SharedInstance; - static std::mutex mMutex; + static std::mutex mMutex; + public: static T& instance() { @@ -50,9 +51,9 @@ public: } }; -template +template std::atomic SafeSingleton::SharedInstance; -template +template std::mutex SafeSingleton::mMutex; #endif diff --git a/src/engine/helper/HL_SocketHeap.cpp b/src/engine/helper/HL_SocketHeap.cpp index 04ff3b21..c0bc572e 100644 --- a/src/engine/helper/HL_SocketHeap.cpp +++ b/src/engine/helper/HL_SocketHeap.cpp @@ -12,7 +12,7 @@ #include #include #if !defined(TARGET_WIN) -# include // Responsible for close() call on Linux +#include // Responsible for close() call on Linux #endif #include "HL_SocketHeap.h" @@ -31,14 +31,13 @@ using namespace std::chrono_literals; // ----------------------------- SocketSink ------------------------- -SocketSink::~SocketSink() -{} +SocketSink::~SocketSink() {} // ----------------------------- SocketHeap ------------------------- SocketHeap::SocketHeap(unsigned short start, unsigned short finish) { - mStart = start; + mStart = start; mFinish = finish; } @@ -74,7 +73,7 @@ void SocketHeap::setRange(unsigned short start, unsigned short finish) mFinish = finish; } -void SocketHeap::range(unsigned short &start, unsigned short &finish) +void SocketHeap::range(unsigned short& start, unsigned short& finish) { Lock l(mGuard); @@ -82,10 +81,10 @@ void SocketHeap::range(unsigned short &start, unsigned short &finish) finish = mFinish; } -RtpPair SocketHeap::allocSocketPair(int family, SocketSink *sink, Multiplex m) +RtpPair SocketHeap::allocSocketPair(int family, SocketSink* sink, Multiplex m) { PDatagramSocket rtp, rtcp; - for (int attempt=0; (!rtp || !rtcp) && attempt < (mFinish - mStart)/2; attempt++) + for (int attempt = 0; (!rtp || !rtcp) && attempt < (mFinish - mStart) / 2; attempt++) { // Allocate RTP try @@ -96,7 +95,7 @@ RtpPair SocketHeap::allocSocketPair(int family, SocketSink *sin else rtcp = allocSocket(family, sink, rtp->localport() + 1); } - catch(...) + catch (...) { // Release a partially allocated pair before retrying - otherwise // the RTP socket from this attempt leaks into the socket map. @@ -121,14 +120,13 @@ RtpPair SocketHeap::allocSocketPair(int family, SocketSink *sin freeSocket(rtcp); throw Exception(ERR_NET_FAILED); } - ICELogInfo(<< "Allocated socket pair " << (family == AF_INET ? "AF_INET" : "AF_INET6") << " " - << rtp->socket() << ":" << rtcp->socket() - << " at ports " << rtp->localport() << ":"<< rtcp->localport()); + ICELogInfo(<< "Allocated socket pair " << (family == AF_INET ? "AF_INET" : "AF_INET6") << " " << rtp->socket() + << ":" << rtcp->socket() << " at ports " << rtp->localport() << ":" << rtcp->localport()); return RtpPair(rtp, rtcp); } -void SocketHeap::freeSocketPair(const RtpPair &p) +void SocketHeap::freeSocketPair(const RtpPair& p) { freeSocket(p.mRtp); freeSocket(p.mRtcp); @@ -136,7 +134,7 @@ void SocketHeap::freeSocketPair(const RtpPair &p) PDatagramSocket SocketHeap::allocSocket(int family, SocketSink* sink, int port) { - Lock l(mGuard); + Lock l(mGuard); SOCKET sock = ::socket(family, SOCK_DGRAM, IPPROTO_UDP); if (sock == INVALID_SOCKET) { @@ -148,13 +146,13 @@ PDatagramSocket SocketHeap::allocSocket(int family, SocketSink* sink, int port) } // Obtain port number - sockaddr_in addr; + sockaddr_in addr; sockaddr_in6 addr6; - int result = 0; - int testport; + int result = 0; + int testport; // A fixed port cannot be retried (it would loop forever if the port is // owned by another process); random ports get a bounded number of attempts. - int attemptsLeft = port ? 1 : 100; + int attemptsLeft = port ? 1 : 100; do { testport = port ? port : rand() % ((mFinish - mStart) / 2) * 2 + mStart; @@ -215,7 +213,7 @@ void SocketHeap::freeSocket(PDatagramSocket socket) void SocketHeap::processDeleted() { - Lock l(mDeleteGuard); + Lock l(mDeleteGuard); SocketVector::iterator socketIter = mDeleteVector.begin(); while (socketIter != mDeleteVector.end()) @@ -257,10 +255,11 @@ void SocketHeap::thread() } // Update socket set - for (auto& socketIter: mSocketMap) + for (auto& socketIter : mSocketMap) agreggator.addSocket(socketIter.second.mSocket); - /* for (SocketMap::iterator socketIter = mSocketMap.begin(); socketIter != mSocketMap.end(); ++socketIter) + /* for (SocketMap::iterator socketIter = mSocketMap.begin(); socketIter != mSocketMap.end(); + ++socketIter) { // Add handle to set agreggator.addSocket(socketIter->second.mSocket); @@ -278,12 +277,12 @@ void SocketHeap::thread() // Remove deleted sockets to avoid call non-existant sinks processDeleted(); - for (unsigned i=0; imHandle); @@ -291,16 +290,16 @@ void SocketHeap::thread() if (socketItemIter != mSocketMap.end()) { InternetAddress src; - unsigned received = sock->recvDatagram(src, mTempPacket, sizeof mTempPacket); + unsigned received = sock->recvDatagram(src, mTempPacket, sizeof mTempPacket); - if ( received > 0 && received <= MAX_VALID_UDPPACKET_SIZE) + if (received > 0 && received <= MAX_VALID_UDPPACKET_SIZE) socketItemIter->second.mSink->onReceivedData(sock, src, mTempPacket, received); } // There is a call to ProcessDeleted() as OnReceivedData() could delete sockets processDeleted(); } - } //of for + } // of for } } else @@ -308,12 +307,12 @@ void SocketHeap::thread() } mShutdown = false; - //#endif + // #endif } static SocketHeap GRTPSocketHeap(20002, 25100); -SocketHeap& SocketHeap::instance() +SocketHeap& SocketHeap::instance() { return GRTPSocketHeap; } diff --git a/src/engine/helper/HL_SocketHeap.h b/src/engine/helper/HL_SocketHeap.h index f7e301e3..f7f8c1c3 100644 --- a/src/engine/helper/HL_SocketHeap.h +++ b/src/engine/helper/HL_SocketHeap.h @@ -22,7 +22,8 @@ class SocketSink { public: virtual ~SocketSink(); - virtual void onReceivedData(PDatagramSocket socket, InternetAddress& src, const void* receivedPtr, unsigned receivedSize) = 0; + virtual void onReceivedData(PDatagramSocket socket, InternetAddress& src, const void* receivedPtr, + unsigned receivedSize) = 0; }; // Class allocates new UDP sockets and tracks incoming packets on them. It runs in separate thread @@ -38,76 +39,68 @@ public: SocketHeap(unsigned short start, unsigned short finish); virtual ~SocketHeap(); - static SocketHeap& instance(); + static SocketHeap& instance(); - void start(); - void stop(); + void start(); + void stop(); // Specifies ne\ port number range. The sockets will be allocated in range [start..finish] - void setRange(unsigned short start, unsigned short finish); + void setRange(unsigned short start, unsigned short finish); // Returns used port number range - void range(unsigned short& start, unsigned short& finish); + void range(unsigned short& start, unsigned short& finish); - // Attempts to allocate and return socket + allocated port number. REQUIRES pointer to data sink - it will be used to process incoming datagrams - PDatagramSocket allocSocket(int family, SocketSink* sink, int port = 0); - RtpPair allocSocketPair(int family, SocketSink* sink, Multiplex m); + // Attempts to allocate and return socket + allocated port number. REQUIRES pointer to data sink - it will be used + // to process incoming datagrams + PDatagramSocket allocSocket(int family, SocketSink* sink, int port = 0); + RtpPair allocSocketPair(int family, SocketSink* sink, Multiplex m); // Stops receiving data for specified socket and frees socket itself. - void freeSocket(PDatagramSocket socket); - void freeSocketPair(const RtpPair& p); + void freeSocket(PDatagramSocket socket); + void freeSocketPair(const RtpPair& p); // Sends data to specified address on specified socket. - void sendData(DatagramSocket& socket, InternetAddress& dest, const void* dataPtr, int dataSize); + void sendData(DatagramSocket& socket, InternetAddress& dest, const void* dataPtr, int dataSize); protected: struct SocketItem { // Local port number for socket - PDatagramSocket mSocket; + PDatagramSocket mSocket; // Data sink pointer - SocketSink* mSink; + SocketSink* mSink; - SocketItem() - :mSink(nullptr) - { } + SocketItem() : mSink(nullptr) {} - SocketItem(unsigned short portnumber, SocketSink* sink) - :mSink(sink) - { - mSocket->mLocalPort = portnumber; - } + SocketItem(unsigned short portnumber, SocketSink* sink) : mSink(sink) { mSocket->mLocalPort = portnumber; } - ~SocketItem() - { } + ~SocketItem() {} }; typedef std::map SocketMap; - typedef std::vector PortVector; + typedef std::vector PortVector; typedef std::vector SocketVector; - Mutex mGuard; - SocketMap mSocketMap; - PortVector mPortVector; - unsigned short mStart, - mFinish; - SocketVector mDeleteVector; - Mutex mDeleteGuard; + Mutex mGuard; + SocketMap mSocketMap; + PortVector mPortVector; + unsigned short mStart, mFinish; + SocketVector mDeleteVector; + Mutex mDeleteGuard; - char mTempPacket[MAX_UDPPACKET_SIZE]; + char mTempPacket[MAX_UDPPACKET_SIZE]; - std::shared_ptr mWorkerThread; + std::shared_ptr mWorkerThread; - std::thread::id mThreadId; - bool mShutdown = false; - bool isShutdown() const { return mShutdown; } + std::thread::id mThreadId; + bool mShutdown = false; + bool isShutdown() const { return mShutdown; } - void thread(); + void thread(); // Processes mDeleteVector -> updates mSocketMap, removes socket items and closes sockets specified in mDeleteVector - void processDeleted(); - + void processDeleted(); }; #endif diff --git a/src/engine/helper/HL_Statistics.h b/src/engine/helper/HL_Statistics.h index a9f29cef..4522ea21 100644 --- a/src/engine/helper/HL_Statistics.h +++ b/src/engine/helper/HL_Statistics.h @@ -5,18 +5,15 @@ template struct Average { int mCount = 0; - T mSum = 0; - T average() const + T mSum = 0; + T average() const { if (!mCount) return 0; return mSum / mCount; } - T value() const - { - return average(); - } + T value() const { return average(); } void process(T value) { @@ -28,12 +25,12 @@ struct Average template struct TestResult { - T mMin = minimum; - T mMax = maximum; + T mMin = minimum; + T mMax = maximum; Average mAverage; - T mCurrent = default_value; + T mCurrent = default_value; - void process(T value) + void process(T value) { if (mMin > value) mMin = value; @@ -43,12 +40,9 @@ struct TestResult mAverage.process(value); } - bool is_initialized() const - { - return mAverage.mCount > 0; - } + bool is_initialized() const { return mAverage.mCount > 0; } - T current() const + T current() const { if (is_initialized()) return mCurrent; @@ -56,26 +50,17 @@ struct TestResult return 0; } - T value() const - { - return current(); - } + T value() const { return current(); } - T average() const - { - return mAverage.average(); - } + T average() const { return mAverage.average(); } - TestResult& operator = (T value) + TestResult& operator=(T value) { process(value); return *this; } - operator T() - { - return mCurrent; - } + operator T() { return mCurrent; } }; diff --git a/src/engine/helper/HL_StreamState.h b/src/engine/helper/HL_StreamState.h index 906c7c09..3f3b81c5 100644 --- a/src/engine/helper/HL_StreamState.h +++ b/src/engine/helper/HL_StreamState.h @@ -10,15 +10,14 @@ enum class StreamState { - Sending = 1, // Transmitting RTP. Set this flag to allow outgoing media stream. - Receiving = 2, // Receiving RTP. Set this flag to allow receiving media stream. - Playing = 4, // Play to audio. Unmutes the audio from specified stream. - Grabbing = 8, // Capture audio. Unmutes the audio to specified stream. - Srtp = 16, // Use SRTP. Make attempt - SipSend = 32, // Declare send capability in SDP - SipRecv = 64 // Declare recv capability in SDP + Sending = 1, // Transmitting RTP. Set this flag to allow outgoing media stream. + Receiving = 2, // Receiving RTP. Set this flag to allow receiving media stream. + Playing = 4, // Play to audio. Unmutes the audio from specified stream. + Grabbing = 8, // Capture audio. Unmutes the audio to specified stream. + Srtp = 16, // Use SRTP. Make attempt + SipSend = 32, // Declare send capability in SDP + SipRecv = 64 // Declare recv capability in SDP }; - #endif diff --git a/src/engine/helper/HL_String.cpp b/src/engine/helper/HL_String.cpp index 8f50ee98..1ead3f96 100644 --- a/src/engine/helper/HL_String.cpp +++ b/src/engine/helper/HL_String.cpp @@ -11,9 +11,9 @@ #include #ifdef TARGET_WIN -# include -# include -# include +#include +#include +#include #endif std::string strx::extractFilename(const std::string& path) @@ -45,7 +45,7 @@ std::string strx::appendPath(const std::string& s1, const std::string& s2) return result + s2; } -std::string strx::makeUtf8(const std::tstring &arg) +std::string strx::makeUtf8(const std::tstring& arg) { #if defined(TARGET_WIN) int required = WideCharToMultiByte(CP_UTF8, 0, arg.c_str(), -1, NULL, 0, NULL, NULL); @@ -60,7 +60,7 @@ std::string strx::makeUtf8(const std::tstring &arg) #endif } -std::string strx::toUtf8(const std::tstring &arg) +std::string strx::toUtf8(const std::tstring& arg) { return makeUtf8(arg); } @@ -80,7 +80,7 @@ std::tstring strx::makeTstring(const std::string& arg) #endif } -int strx::toInt(const char *s, int defaultValue, bool* isOk) +int strx::toInt(const char* s, int defaultValue, bool* isOk) { int result; if (sscanf(s, "%d", &result) != 1) @@ -89,14 +89,13 @@ int strx::toInt(const char *s, int defaultValue, bool* isOk) *isOk = false; result = defaultValue; } - else - if (isOk) - *isOk = true; + else if (isOk) + *isOk = true; return result; } -uint64_t strx::toUint64(const char* s, uint64_t def, bool *isOk) +uint64_t strx::toUint64(const char* s, uint64_t def, bool* isOk) { uint64_t result = def; if (sscanf(s, "%" SCNu64, &result) != 1) @@ -105,9 +104,8 @@ uint64_t strx::toUint64(const char* s, uint64_t def, bool *isOk) *isOk = false; result = def; } - else - if (isOk) - *isOk = true; + else if (isOk) + *isOk = true; return result; } @@ -119,28 +117,29 @@ std::string strx::toHex(unsigned int value) return buffer; } -std::string strx::toHex(const void *ptr) +std::string strx::toHex(const void* ptr) { std::ostringstream oss; oss << std::fixed << std::setw(8) << std::setfill('0') << std::hex << ptr; return oss.str(); } -//must be lowercase for MD5 +// must be lowercase for MD5 static const char hexmap[] = "0123456789abcdef"; -std::string strx::toHex(const uint8_t* input, size_t inputLength) +std::string strx::toHex(const uint8_t* input, size_t inputLength) { - std::string result; result.resize(inputLength * 2); + std::string result; + result.resize(inputLength * 2); const char* p = (const char*)input; - char* r = &result[0]; - for (size_t i=0; i < inputLength; ++i) + char* r = &result[0]; + for (size_t i = 0; i < inputLength; ++i) { unsigned char temp = *p++; - int hi = (temp & 0xf0)>>4; - int low = (temp & 0xf); + int hi = (temp & 0xf0) >> 4; + int low = (temp & 0xf); *r++ = hexmap[hi]; *r++ = hexmap[low]; @@ -149,13 +148,13 @@ std::string strx::toHex(const uint8_t* input, size_t inputLength) return result; } -std::string strx::prefixLines(const std::string &source, const std::string &prefix) +std::string strx::prefixLines(const std::string& source, const std::string& prefix) { // Read source line by line std::istringstream iss(source); std::ostringstream oss; - std::string line; - while (std::getline(iss,line)) + std::string line; + while (std::getline(iss, line)) { oss << prefix << line << std::endl; } @@ -194,7 +193,7 @@ void strx::split(const std::string& src, std::vector& dst, const st } else { - std::string t = src.substr(p, f-p); + std::string t = src.substr(p, f - p); if (!t.empty()) dst.push_back(t); p = f + 1; @@ -212,7 +211,7 @@ std::vector strx::split(const std::string& src, const std::string& std::pair strx::parseHost(const std::string& host, int defaultPort) { std::pair result; - std::size_t p = host.find(':'); + std::size_t p = host.find(':'); if (p != std::string::npos) { result.first = host.substr(0, p); @@ -230,15 +229,15 @@ std::pair strx::parseAssignment(const std::string& s, { std::pair result; - std::string::size_type p = s.find('='); + std::string::size_type p = s.find('='); if (p != std::string::npos) { result.first = strx::trim(s.substr(0, p)); - result.second = strx::trim(s.substr(p+1)); + result.second = strx::trim(s.substr(p + 1)); if (trimQuotes && result.second.size() >= 2) { - if ((result.second[0] == '"' && result.second[result.second.size()-1] == '"') || - (result.second[0] == '\'' && result.second[result.second.size()-1] == '\'')) + if ((result.second[0] == '"' && result.second[result.second.size() - 1] == '"') || + (result.second[0] == '\'' && result.second[result.second.size() - 1] == '\'')) result.second = result.second.substr(1, result.second.size() - 2); } } @@ -255,10 +254,10 @@ std::string strx::intToString(int value) return buffer; } -float strx::toFloat(const std::string &s, float v, bool* isOk) +float strx::toFloat(const std::string& s, float v, bool* isOk) { float result = 0.0; - int code = sscanf(s.c_str(), "%f", &result); + int code = sscanf(s.c_str(), "%f", &result); if (code == 1) { if (isOk) @@ -274,16 +273,18 @@ float strx::toFloat(const std::string &s, float v, bool* isOk) return result; } -std::string strx::trim(const std::string &s) +std::string strx::trim(const std::string& s) { - auto wsfront = std::find_if_not(s.begin(), s.end(), [](int c) { return std::isspace(c) || c == '\r' || c == '\n'; }); - auto wsback = std::find_if_not(s.rbegin(), s.rend(), [](int c) { return std::isspace(c) || c == '\r' || c == '\n'; }).base(); - return (wsback <= wsfront ? std::string() : std::string(wsfront,wsback)); + auto wsfront = + std::find_if_not(s.begin(), s.end(), [](int c) { return std::isspace(c) || c == '\r' || c == '\n'; }); + auto wsback = + std::find_if_not(s.rbegin(), s.rend(), [](int c) { return std::isspace(c) || c == '\r' || c == '\n'; }).base(); + return (wsback <= wsfront ? std::string() : std::string(wsfront, wsback)); } std::string strx::timeToString(time_t t) { - char buffer[128] = ""; + char buffer[128] = ""; struct tm lt; #if defined(TARGET_LINUX) || defined(TARGET_OSX) || defined(TARGET_ANDROID) if (localtime_r(&t, <) == nullptr) @@ -291,16 +292,16 @@ std::string strx::timeToString(time_t t) #else lt = *localtime(&t); #endif - strftime(buffer, sizeof(buffer)-1, "%Y-%m-%d %H:%M:%S", <); + strftime(buffer, sizeof(buffer) - 1, "%Y-%m-%d %H:%M:%S", <); return buffer; } std::string strx::millisecondsToString(uint64_t t) { - return timeToString(t/1000); + return timeToString(t / 1000); } -int strx::fromHex2Int(const std::string &s) +int strx::fromHex2Int(const std::string& s) { int result = 0; int retcode = sscanf(s.c_str(), "%x", &result); @@ -328,10 +329,11 @@ static int hex2code(char s) std::string strx::fromHex2String(const std::string& s) { - std::string result; result.resize(s.size() / 2); + std::string result; + result.resize(s.size() / 2); const char* t = s.c_str(); for (size_t i = 0; i < result.size(); i++) - result[i] = static_cast((hex2code(t[i*2]) << 4) | hex2code(t[i*2+1])); + result[i] = static_cast((hex2code(t[i * 2]) << 4) | hex2code(t[i * 2 + 1])); return result; } @@ -348,9 +350,9 @@ std::string strx::replace(const std::string& s, char f, char r) std::string strx::replace(const std::string& s, const std::string& tmpl, const std::string& n) { - std::string result(s); + std::string result(s); std::string::size_type p = 0; - while ( (p = result.find(tmpl, p)) != std::string::npos) + while ((p = result.find(tmpl, p)) != std::string::npos) { result.replace(p, tmpl.size(), n); p += n.size(); @@ -366,12 +368,12 @@ std::string strx::decodeUri(const std::string& s) char ch; - int i, ii = 0; - for (i=0; i<(int)s.length(); i++) + int i, ii = 0; + for (i = 0; i < (int)s.length(); i++) { if (s[i] == '%' && i + 2 < (int)s.length()) { - if (sscanf(s.substr(i+1,2).c_str(), "%x", &ii) == 1) + if (sscanf(s.substr(i + 1, 2).c_str(), "%x", &ii) == 1) { ch = static_cast(ii); ret += ch; @@ -403,13 +405,13 @@ bool strx::endsWith(const std::string& s, const std::string& suffix) int strx::stringToDuration(const std::string& s) { if (endsWith(s, "ms")) - return std::stoi(s.substr(0, s.size()-2)); + return std::stoi(s.substr(0, s.size() - 2)); if (endsWith(s, "s")) - return std::stoi(s.substr(0, s.size()-1)) * 1000; + return std::stoi(s.substr(0, s.size() - 1)) * 1000; if (endsWith(s, "m")) - return std::stoi(s.substr(0, s.size()-1)) * 60000; + return std::stoi(s.substr(0, s.size() - 1)) * 60000; if (endsWith(s, "h")) - return std::stoi(s.substr(0, s.size()-1)) * 3600 * 1000; + return std::stoi(s.substr(0, s.size() - 1)) * 3600 * 1000; else return std::stoi(s) * 1000; } @@ -438,7 +440,7 @@ std::string strx::removeQuotes(const std::string& s) r = r.substr(1); if (r.back() == '"') - r = r.substr(0, r.size()-1); + r = r.substr(0, r.size() - 1); return r; } @@ -446,20 +448,18 @@ std::string strx::removeQuotes(const std::string& s) #if defined(TARGET_WIN) // MSVC++ lacks memmem support -const void *memmem(const void *haystack, size_t haystack_len, - const void * const needle, const size_t needle_len) +const void* memmem(const void* haystack, size_t haystack_len, const void* const needle, const size_t needle_len) { if (!haystack || !haystack_len || !needle || !needle_len) return nullptr; - for (const char *h = (const char*)haystack; - haystack_len >= needle_len; - ++h, --haystack_len) { - if (!memcmp(h, needle, needle_len)) { + for (const char* h = (const char*)haystack; haystack_len >= needle_len; ++h, --haystack_len) + { + if (!memcmp(h, needle, needle_len)) + { return h; } } return nullptr; } #endif - diff --git a/src/engine/helper/HL_String.h b/src/engine/helper/HL_String.h index 5581c7c8..56f17a72 100644 --- a/src/engine/helper/HL_String.h +++ b/src/engine/helper/HL_String.h @@ -20,32 +20,32 @@ class strx { public: - static std::string extractFilename(const std::string& path); - static std::string appendPath(const std::string& s1, const std::string& s2); + static std::string extractFilename(const std::string& path); + static std::string appendPath(const std::string& s1, const std::string& s2); - static std::string makeUtf8(const std::tstring& arg); - static std::string toUtf8(const std::tstring& arg); + static std::string makeUtf8(const std::tstring& arg); + static std::string toUtf8(const std::tstring& arg); static std::tstring makeTstring(const std::string& arg); - static int toInt(const char* s, int defaultValue, bool* isOk = nullptr); - static uint64_t toUint64(const char* s, uint64_t def, bool *isOk = nullptr); - static std::string toHex(unsigned int value); - static std::string toHex(const void* ptr); - static std::string toHex(const uint8_t* input, size_t inputLength); - static std::string intToString(int value); - static std::string prefixLines(const std::string& source, const std::string& prefix); - static std::string doubleToString(double value, int precision); - static int fromHex2Int(const std::string& s); - static std::string fromHex2String(const std::string& s); - static float toFloat(const std::string& s, float defaultValue = 0.0, bool* isOk = nullptr); + static int toInt(const char* s, int defaultValue, bool* isOk = nullptr); + static uint64_t toUint64(const char* s, uint64_t def, bool* isOk = nullptr); + static std::string toHex(unsigned int value); + static std::string toHex(const void* ptr); + static std::string toHex(const uint8_t* input, size_t inputLength); + static std::string intToString(int value); + static std::string prefixLines(const std::string& source, const std::string& prefix); + static std::string doubleToString(double value, int precision); + static int fromHex2Int(const std::string& s); + static std::string fromHex2String(const std::string& s); + static float toFloat(const std::string& s, float defaultValue = 0.0, bool* isOk = nullptr); - static const char* findSubstring(const char* buffer, const char* substring, size_t bufferLength); + static const char* findSubstring(const char* buffer, const char* substring, size_t bufferLength); - static void split(const std::string& src, std::vector& dst, const std::string& delims); + static void split(const std::string& src, std::vector& dst, const std::string& delims); static std::vector split(const std::string& src, const std::string& delims = "\n"); - template + template static std::string join(const std::vector& v, const std::string& delimiter) { std::ostringstream s; @@ -58,21 +58,21 @@ public: return s.str(); } - static std::pair parseHost(const std::string& host, int defaultPort); + static std::pair parseHost(const std::string& host, int defaultPort); static std::pair parseAssignment(const std::string& s, bool trimQuotes = true); - static std::string trim(const std::string& s); - static std::string timeToString(time_t t); - static std::string millisecondsToString(uint64_t t); - static std::string replace(const std::string& s, char f, char r); + static std::string trim(const std::string& s); + static std::string timeToString(time_t t); + static std::string millisecondsToString(uint64_t t); + static std::string replace(const std::string& s, char f, char r); static std::string replace(const std::string& s, const std::string& tmpl, const std::string& n); static std::string decodeUri(const std::string& s); - static bool startsWith(const std::string& s, const std::string& prefix); - static bool endsWith(const std::string& s, const std::string& suffix); - static int stringToDuration(const std::string& s); - - static std::string uppercase(const std::string& s); - static std::string lowercase(const std::string& s); - static std::string removeQuotes(const std::string& s); + static bool startsWith(const std::string& s, const std::string& prefix); + static bool endsWith(const std::string& s, const std::string& suffix); + static int stringToDuration(const std::string& s); + + static std::string uppercase(const std::string& s); + static std::string lowercase(const std::string& s); + static std::string removeQuotes(const std::string& s); }; class XcapHelper @@ -88,8 +88,7 @@ public: #if defined(TARGET_WIN) // MSVC++ lacks memmem support -extern const void *memmem(const void *haystack, size_t haystack_len, - const void * const needle, const size_t needle_len); +extern const void* memmem(const void* haystack, size_t haystack_len, const void* const needle, const size_t needle_len); #endif #endif diff --git a/src/engine/helper/HL_Sync.cpp b/src/engine/helper/HL_Sync.cpp index 424d831b..dd4d50d4 100644 --- a/src/engine/helper/HL_Sync.cpp +++ b/src/engine/helper/HL_Sync.cpp @@ -10,11 +10,11 @@ #include #ifdef TARGET_OSX -# include +#include #endif #ifdef TARGET_WIN -# include +#include #endif void SyncHelper::delay(unsigned int microseconds) @@ -35,7 +35,7 @@ void SyncHelper::delay(unsigned int microseconds) // ------------------- ThreadHelper ------------------- -void ThreadHelper::setName(const std::string &name) +void ThreadHelper::setName(const std::string& name) { #if defined(TARGET_LINUX) // The name will be truncated to 8 or 16 characters @@ -53,7 +53,7 @@ uint64_t ThreadHelper::getCurrentId() return static_cast(GetCurrentThreadId()); #endif -#if defined(TARGET_LINUX)||defined(TARGET_OSX) +#if defined(TARGET_LINUX) || defined(TARGET_OSX) // RPi builds want this! return (uint64_t)(pthread_self()); #endif @@ -70,13 +70,13 @@ using namespace std::chrono; static uint64_t TimestampStartPoint = duration_cast(steady_clock::now().time_since_epoch()).count(); // Seconds starting from the epoch -static time_t TimestampBase = time(nullptr); +static time_t TimestampBase = time(nullptr); // Returns number of milliseconds starting from 01 Jan 1970 GMT std::chrono::milliseconds chronox::getTimestamp() { time_point t = steady_clock::now(); - uint64_t ms = duration_cast< milliseconds >(t.time_since_epoch()).count(); + uint64_t ms = duration_cast(t.time_since_epoch()).count(); return std::chrono::milliseconds(ms - TimestampStartPoint + TimestampBase * 1000); } @@ -84,7 +84,7 @@ std::chrono::milliseconds chronox::getUptime() { time_point t = steady_clock::now(); - uint64_t ms = duration_cast< milliseconds >(t.time_since_epoch()).count(); + uint64_t ms = duration_cast(t.time_since_epoch()).count(); return std::chrono::milliseconds(ms - TimestampStartPoint); } @@ -140,21 +140,15 @@ std::chrono::milliseconds chronox::ExecutionTime::getSpentTime() const } // --------------- BufferQueue ----------------- -BufferQueue::BufferQueue() -{ +BufferQueue::BufferQueue() {} -} - -BufferQueue::~BufferQueue() -{ - -} +BufferQueue::~BufferQueue() {} void BufferQueue::push(const void* data, int bytes) { std::unique_lock l(mMutex); - PBlock b = std::make_shared(); + PBlock b = std::make_shared(); b->resize(bytes); memcpy(b->data(), data, bytes); mBlockList.push_back(b); @@ -164,8 +158,7 @@ void BufferQueue::push(const void* data, int bytes) BufferQueue::PBlock BufferQueue::pull(int milliseconds) { std::unique_lock l(mMutex); - mSignal.wait_for(l, std::chrono::milliseconds(milliseconds), - [this]() { return !mBlockList.empty(); }); + mSignal.wait_for(l, std::chrono::milliseconds(milliseconds), [this]() { return !mBlockList.empty(); }); PBlock r; if (!mBlockList.empty()) @@ -178,9 +171,7 @@ BufferQueue::PBlock BufferQueue::pull(int milliseconds) } // ----------------- Semaphore --------------------- -Semaphore::Semaphore(unsigned int count) - : m_count(count) -{} +Semaphore::Semaphore(unsigned int count) : m_count(count) {} void Semaphore::notify() { @@ -196,7 +187,8 @@ void Semaphore::wait() m_count--; } -bool Semaphore::waitFor(std::chrono::milliseconds timeout) { +bool Semaphore::waitFor(std::chrono::milliseconds timeout) +{ std::unique_lock lock(m_mtx); if (!m_cv.wait_for(lock, timeout, [this]() { return m_count > 0; })) @@ -231,7 +223,7 @@ uint64_t TimerQueue::add(std::chrono::milliseconds milliseconds, std::function lk(m_mtx); - uint64_t id = ++m_idcounter; + uint64_t id = ++m_idcounter; item.id = id; m_items.push(std::move(item)); lk.unlock(); @@ -246,19 +238,22 @@ uint64_t TimerQueue::add(std::chrono::milliseconds milliseconds, std::function lk(m_mtx); - for (auto&& item : m_items.getContainer()) { - if (item.id == id && item.handler) { + for (auto&& item : m_items.getContainer()) + { + if (item.id == id && item.handler) + { WorkItem newItem; // Zero time, so it stays at the top for immediate execution newItem.end = Clock::time_point(); - newItem.id = 0; // Means it is a canceled item + newItem.id = 0; // Means it is a canceled item // Move the handler from item to newitem. // Also, we need to manually set the handler to nullptr, since // the standard does not guarantee moving an std::function will @@ -285,8 +280,10 @@ size_t TimerQueue::cancelAll() // Setting all "end" to 0 (for immediate execution) is ok, // since it maintains the heap integrity std::unique_lock lk(m_mtx); - for (auto&& item : m_items.getContainer()) { - if (item.id) { + for (auto&& item : m_items.getContainer()) + { + if (item.id) + { item.end = Clock::time_point(); item.id = 0; } @@ -307,9 +304,12 @@ void TimerQueue::run() if (end.first) { // Timers found, so wait until it expires (or something else changes) - auto milliseconds = std::chrono::duration_cast(end.second - std::chrono::steady_clock::now()); + auto milliseconds = + std::chrono::duration_cast(end.second - std::chrono::steady_clock::now()); m_checkWork.waitFor(milliseconds); - } else { + } + else + { // No timers exist, so wait forever until something changes m_checkWork.wait(); } @@ -327,11 +327,15 @@ void TimerQueue::run() std::pair TimerQueue::calcWaitTime() { std::lock_guard lk(m_mtx); - while (m_items.size()) { - if (m_items.top().handler) { + while (m_items.size()) + { + if (m_items.top().handler) + { // Item present, so return the new wait time return std::make_pair(true, m_items.top().end); - } else { + } + else + { // Discard empty handlers (they were cancelled) m_items.pop(); } @@ -342,9 +346,11 @@ std::pair TimerQueue::calcWaitTime() return std::make_pair(false, Clock::time_point()); } -void TimerQueue::checkWork() { +void TimerQueue::checkWork() +{ std::unique_lock lk(m_mtx); - while (m_items.size() && m_items.top().end <= Clock::now()) { + while (m_items.size() && m_items.top().end <= Clock::now()) + { WorkItem item(std::move(m_items.top())); m_items.pop(); @@ -355,10 +361,12 @@ void TimerQueue::checkWork() { } } -bool TimerQueue::WorkItem::operator > (const TimerQueue::WorkItem& other) const { +bool TimerQueue::WorkItem::operator>(const TimerQueue::WorkItem& other) const +{ return end > other.end; } -std::vector& TimerQueue::Queue::getContainer() { +std::vector& TimerQueue::Queue::getContainer() +{ return this->c; } diff --git a/src/engine/helper/HL_Sync.h b/src/engine/helper/HL_Sync.h index 88b3c1d5..29a1b246 100644 --- a/src/engine/helper/HL_Sync.h +++ b/src/engine/helper/HL_Sync.h @@ -15,11 +15,11 @@ #include #if defined(TARGET_WIN) -# include -# include +#include +#include #endif -typedef std::recursive_mutex Mutex; +typedef std::recursive_mutex Mutex; typedef std::unique_lock Lock; class SyncHelper @@ -38,15 +38,15 @@ public: bool waitFor(std::chrono::milliseconds timeout); private: - std::mutex m_mtx; + std::mutex m_mtx; std::condition_variable m_cv; - unsigned int m_count; + unsigned int m_count; }; class ThreadHelper { public: - static void setName(const std::string& name); + static void setName(const std::string& name); static uint64_t getCurrentId(); }; @@ -61,21 +61,22 @@ public: // Finds time delta between 'later' and 'earlier' time points. // Handles cases when clock is wrapped. - static uint32_t getDelta(uint32_t later, uint32_t earlier); + static uint32_t getDelta(uint32_t later, uint32_t earlier); // Converts number of milliseconds starting from Epoch begin to timespec. - static timespec toTimespec(uint64_t milliseconds); - static uint64_t toTimestamp(const timeval& ts); + static timespec toTimespec(uint64_t milliseconds); + static uint64_t toTimestamp(const timeval& ts); // Returns difference between timestamps in milliseconds - static int64_t getDelta(const timespec& a, const timespec& b); - static int64_t getDelta(const timeval& a, const timeval& b); + static int64_t getDelta(const timespec& a, const timespec& b); + static int64_t getDelta(const timeval& a, const timeval& b); class ExecutionTime { public: ExecutionTime(); std::chrono::milliseconds getSpentTime() const; + protected: std::chrono::milliseconds mStart; }; @@ -88,16 +89,16 @@ public: BufferQueue(); ~BufferQueue(); - typedef std::vector Block; + typedef std::vector Block; typedef std::shared_ptr PBlock; - void push(const void* data, int bytes); - PBlock pull(int milliseconds); + void push(const void* data, int bytes); + PBlock pull(int milliseconds); protected: - std::mutex mMutex; + std::mutex mMutex; std::condition_variable mSignal; - std::deque mBlockList; + std::deque mBlockList; }; @@ -106,7 +107,7 @@ protected: // Allows execution of handlers at a specified time in the future // Guarantees: // - All handlers are executed ONCE, even if canceled (aborted parameter will -//be set to true) +// be set to true) // - If TimerQueue is destroyed, it will cancel all handlers. // - Handlers are ALWAYS executed in the Timer Queue worker thread. // - Handlers execution order is NOT guaranteed @@ -128,38 +129,37 @@ public: // 1 if the timer was cancelled. // 0 if you were too late to cancel (or the timer ID was never valid to // start with) - size_t cancel(uint64_t id); + size_t cancel(uint64_t id); //! Cancels all timers // \return // The number of timers cancelled - size_t cancelAll(); + size_t cancelAll(); private: using Clock = std::chrono::steady_clock; TimerQueue(const TimerQueue&) = delete; - TimerQueue& operator=(const TimerQueue&) = delete; + TimerQueue& operator=(const TimerQueue&) = delete; - void run(); + void run(); std::pair calcWaitTime(); - void checkWork(); - Semaphore m_checkWork; - std::thread m_th; - bool m_finish = false; - uint64_t m_idcounter = 0; + void checkWork(); + Semaphore m_checkWork; + std::thread m_th; + bool m_finish = false; + uint64_t m_idcounter = 0; struct WorkItem { - Clock::time_point end; - uint64_t id; // id==0 means it was cancelled + Clock::time_point end; + uint64_t id; // id==0 means it was cancelled std::function handler; - bool operator > (const WorkItem& other) const; + bool operator>(const WorkItem& other) const; }; std::mutex m_mtx; // Inheriting from priority_queue, so we can access the internal container - class Queue : public std::priority_queue, - std::greater> + class Queue : public std::priority_queue, std::greater> { public: std::vector& getContainer(); diff --git a/src/engine/helper/HL_ThreadPool.cpp b/src/engine/helper/HL_ThreadPool.cpp index be356dea..e8e702df 100644 --- a/src/engine/helper/HL_ThreadPool.cpp +++ b/src/engine/helper/HL_ThreadPool.cpp @@ -6,7 +6,7 @@ thread_pool::thread_pool(size_t num_of_threads, const std::string& name) if (!num_of_threads) num_of_threads = std::thread::hardware_concurrency(); - for(size_t idx = 0; idx < num_of_threads; idx++) + for (size_t idx = 0; idx < num_of_threads; idx++) this->workers.emplace_back(std::thread(&thread_pool::run_worker, this)); } @@ -45,7 +45,7 @@ thread_pool::~thread_pool() stop = true; } this->condition.notify_all(); - for(std::thread &worker: workers) + for (std::thread& worker : workers) worker.join(); } @@ -58,7 +58,7 @@ void thread_pool::run_worker() { std::unique_lock lock(this->queue_mutex); - this->condition.wait(lock, [this]{return !this->tasks.empty() || this->stop;}); + this->condition.wait(lock, [this] { return !this->tasks.empty() || this->stop; }); if (!tasks.empty()) { t = tasks.front(); diff --git a/src/engine/helper/HL_ThreadPool.h b/src/engine/helper/HL_ThreadPool.h index 92b1f9d0..f0b98ec3 100644 --- a/src/engine/helper/HL_ThreadPool.h +++ b/src/engine/helper/HL_ThreadPool.h @@ -21,26 +21,26 @@ public: thread_pool(size_t num_of_threads, const std::string& thread_name); ~thread_pool(); - void enqueue(const task& task); - void wait(std::chrono::milliseconds interval = std::chrono::milliseconds(50)); + void enqueue(const task& task); + void wait(std::chrono::milliseconds interval = std::chrono::milliseconds(50)); size_t size(); size_t threads(); private: // need to keep track of threads so we can join them - std::vector< std::thread > workers; + std::vector workers; // the task queue - std::queue< task > tasks; - + std::queue tasks; + // synchronization - std::mutex queue_mutex; - std::condition_variable condition; - std::atomic_bool stop = false; + std::mutex queue_mutex; + std::condition_variable condition; + std::atomic_bool stop = false; // thread name prefix for worker threads - std::string name; + std::string name; - void run_worker(); + void run_worker(); }; #endif diff --git a/src/engine/helper/HL_Time.cpp b/src/engine/helper/HL_Time.cpp index ac579365..d75b1b6e 100644 --- a/src/engine/helper/HL_Time.cpp +++ b/src/engine/helper/HL_Time.cpp @@ -12,7 +12,7 @@ double now_ms(void) #else struct timespec res; clock_gettime(CLOCK_MONOTONIC, &res); - return 1000.0 * res.tv_sec + (double) res.tv_nsec / 1e6; + return 1000.0 * res.tv_sec + (double)res.tv_nsec / 1e6; #endif } @@ -31,17 +31,17 @@ int compare_timespec(const timespec& lhs, const timespec& rhs) return 0; } -bool operator < (const timespec& lhs, const timespec& rhs) +bool operator<(const timespec& lhs, const timespec& rhs) { return compare_timespec(lhs, rhs) < 0; } -bool operator == (const timespec& lhs, const timespec& rhs) +bool operator==(const timespec& lhs, const timespec& rhs) { return compare_timespec(lhs, rhs) == 0; } -bool operator > (const timespec& lhs, const timespec& rhs) +bool operator>(const timespec& lhs, const timespec& rhs) { return compare_timespec(lhs, rhs) > 0; } @@ -50,4 +50,3 @@ bool is_zero(const timespec& ts) { return !ts.tv_sec && !ts.tv_nsec; } - diff --git a/src/engine/helper/HL_Time.h b/src/engine/helper/HL_Time.h index 1af72a23..58acc851 100644 --- a/src/engine/helper/HL_Time.h +++ b/src/engine/helper/HL_Time.h @@ -8,10 +8,10 @@ extern double now_ms(); // Compare the timespec. // Returns -1 if lhs < rhs, 1 if lhs > rhs, 0 if equal -extern int compare_timespec(const timespec& lhs, const timespec& rhs); -extern bool operator < (const timespec& lhs, const timespec& rhs); -extern bool operator == (const timespec& lhs, const timespec& rhs); -extern bool operator > (const timespec& lhs, const timespec& rhs); -extern bool is_zero(const timespec& ts); +extern int compare_timespec(const timespec& lhs, const timespec& rhs); +extern bool operator<(const timespec& lhs, const timespec& rhs); +extern bool operator==(const timespec& lhs, const timespec& rhs); +extern bool operator>(const timespec& lhs, const timespec& rhs); +extern bool is_zero(const timespec& ts); #endif diff --git a/src/engine/helper/HL_Types.h b/src/engine/helper/HL_Types.h index d9ceeb26..b2cb35ff 100644 --- a/src/engine/helper/HL_Types.h +++ b/src/engine/helper/HL_Types.h @@ -7,11 +7,11 @@ #define __HL_TYPES_H #ifdef WIN32 -# define tstring wstring -# define to_tstring to_wstring +#define tstring wstring +#define to_tstring to_wstring #else -# define tstring string -# define to_tstring to_string +#define tstring string +#define to_tstring to_string #endif #ifdef WIN32 @@ -22,8 +22,8 @@ enum SdpDirection { - Sdp_Answer, - Sdp_Offer + Sdp_Answer, + Sdp_Offer }; @@ -32,49 +32,61 @@ enum SdpDirection #include #include -template< - class K, class V, - class HashK = std::hash, class EqK = std::equal_to, - class HashV = std::hash, class EqV = std::equal_to -> -class BiMap { +template, class EqK = std::equal_to, class HashV = std::hash, + class EqV = std::equal_to> +class BiMap +{ public: using key_type = K; using mapped_type = V; - BiMap(const std::map& initializers) { - for (const auto& item: initializers) { + BiMap(const std::map& initializers) + { + for (const auto& item : initializers) + { insert(item.first, item.second); } } // Insert a new (key, value) pair. Returns false if either key or value already exists. - bool insert(const K& k, const V& v) { - if (contains_key(k) || contains_value(v)) return false; + bool insert(const K& k, const V& v) + { + if (contains_key(k) || contains_value(v)) + return false; auto ok = forward_.emplace(k, v); - try { + try + { auto ov = reverse_.emplace(v, k); - if (!ov.second) { // shouldn't happen given the guard above + if (!ov.second) + { // shouldn't happen given the guard above forward_.erase(k); return false; } - } catch (...) { + } + catch (...) + { forward_.erase(k); throw; } return ok.second; } - bool insert(K&& k, V&& v) { - if (contains_key(k) || contains_value(v)) return false; + bool insert(K&& k, V&& v) + { + if (contains_key(k) || contains_value(v)) + return false; auto ok = forward_.emplace(std::move(k), std::move(v)); - try { + try + { auto ov = reverse_.emplace(ok.first->second, ok.first->first); // use stored refs - if (!ov.second) { + if (!ov.second) + { forward_.erase(ok.first); return false; } - } catch (...) { + } + catch (...) + { forward_.erase(ok.first); throw; } @@ -82,10 +94,13 @@ public: } // Replace value for existing key (and update reverse map). Returns false if value is already bound elsewhere. - bool replace_by_key(const K& k, const V& new_v) { + bool replace_by_key(const K& k, const V& new_v) + { auto it = forward_.find(k); - if (it == forward_.end()) return false; - if (contains_value(new_v)) return false; + if (it == forward_.end()) + return false; + if (contains_value(new_v)) + return false; // remove old reverse, insert new reverse, then update forward reverse_.erase(it->second); reverse_.emplace(new_v, k); @@ -94,10 +109,13 @@ public: } // Replace key for existing value (and update forward map). Returns false if key is already bound elsewhere. - bool replace_by_value(const V& v, const K& new_k) { + bool replace_by_value(const V& v, const K& new_k) + { auto it = reverse_.find(v); - if (it == reverse_.end()) return false; - if (contains_key(new_k)) return false; + if (it == reverse_.end()) + return false; + if (contains_key(new_k)) + return false; forward_.erase(it->second); forward_.emplace(new_k, v); it->second = new_k; @@ -105,31 +123,37 @@ public: } // Erase by key/value. Return number erased (0 or 1). - size_t erase_key(const K& k) { + size_t erase_key(const K& k) + { auto it = forward_.find(k); - if (it == forward_.end()) return 0; + if (it == forward_.end()) + return 0; reverse_.erase(it->second); forward_.erase(it); return 1; } - size_t erase_value(const V& v) { + size_t erase_value(const V& v) + { auto it = reverse_.find(v); - if (it == reverse_.end()) return 0; + if (it == reverse_.end()) + return 0; forward_.erase(it->second); reverse_.erase(it); return 1; } // Lookup - bool contains_key(const K& k) const { return forward_.find(k) != forward_.end(); } - bool contains_value(const V& v) const { return reverse_.find(v) != reverse_.end(); } + bool contains_key(const K& k) const { return forward_.find(k) != forward_.end(); } + bool contains_value(const V& v) const { return reverse_.find(v) != reverse_.end(); } - const V* find_by_key(const K& k) const { + const V* find_by_key(const K& k) const + { auto it = forward_.find(k); return (it == forward_.end()) ? nullptr : &it->second; } - const K* find_by_value(const V& v) const { + const K* find_by_value(const V& v) const + { auto it = reverse_.find(v); return (it == reverse_.end()) ? nullptr : &it->second; } @@ -138,16 +162,18 @@ public: const V& at_key(const K& k) const { return forward_.at(k); } const K& at_value(const V& v) const { return reverse_.at(v); } - void clear() noexcept { + void clear() noexcept + { forward_.clear(); reverse_.clear(); } - bool empty() const noexcept { return forward_.empty(); } + bool empty() const noexcept { return forward_.empty(); } size_t size() const noexcept { return forward_.size(); } // Reserve buckets for performance (optional) - void reserve(size_t n) { + void reserve(size_t n) + { forward_.reserve(n); reverse_.reserve(n); } diff --git a/src/engine/helper/HL_Usb.cpp b/src/engine/helper/HL_Usb.cpp index 52ba2faa..706ca7a3 100644 --- a/src/engine/helper/HL_Usb.cpp +++ b/src/engine/helper/HL_Usb.cpp @@ -7,104 +7,101 @@ #define ADR_WINDOW_CLASS_NAME L"HIDDEN_USB_CHANGE_DELEGATE_WINDOWCLASS_%u" #define ADR_WINDOW_NAME L"HIDDEN_USB_CHANGE_DELEGATE_WINDOW_%u" -UsbChangeListener::UsbChangeListener() -:mNotifyHandle(NULL), mHiddenWindow(NULL), mDelegate(NULL) +UsbChangeListener::UsbChangeListener() : mNotifyHandle(NULL), mHiddenWindow(NULL), mDelegate(NULL) { - wsprintfW(mWindowClassName, ADR_WINDOW_CLASS_NAME, (unsigned int)rand()); + wsprintfW(mWindowClassName, ADR_WINDOW_CLASS_NAME, (unsigned int)rand()); } UsbChangeListener::~UsbChangeListener() { - stop(); + stop(); } void UsbChangeListener::setDelegate(Delegate* d) { - mDelegate = d; + mDelegate = d; } UsbChangeListener::Delegate* UsbChangeListener::getDelegate() const { - return mDelegate; + return mDelegate; } void UsbChangeListener::start() { - // Exposing Window to Mixer + // Exposing Window to Mixer WNDCLASSEXW wcx; - memset( &wcx, 0, sizeof(WNDCLASSEXW) ); + memset(&wcx, 0, sizeof(WNDCLASSEXW)); wcx.cbSize = sizeof(WNDCLASSEXW); wcx.lpszClassName = mWindowClassName; - wcx.lpfnWndProc = (WNDPROC)ADRWindowProc; + wcx.lpfnWndProc = (WNDPROC)ADRWindowProc; ::RegisterClassExW(&wcx); - wchar_t windowname[128]; - wsprintfW(windowname, ADR_WINDOW_NAME, rand()); - mHiddenWindow = CreateWindowW( mWindowClassName, - windowname, - WS_POPUP | WS_DISABLED, - 0, 0, 0, 0, - NULL, NULL, NULL, NULL ); - if (!mHiddenWindow) - throw Exception(ERR_CREATEWINDOW, GetLastError()); - if (!SetWindowLongPtr(mHiddenWindow, GWLP_USERDATA, (LONG_PTR)this)) - throw Exception(ERR_CREATEWINDOW, GetLastError()); + wchar_t windowname[128]; + wsprintfW(windowname, ADR_WINDOW_NAME, rand()); + mHiddenWindow = + CreateWindowW(mWindowClassName, windowname, WS_POPUP | WS_DISABLED, 0, 0, 0, 0, NULL, NULL, NULL, NULL); + if (!mHiddenWindow) + throw Exception(ERR_CREATEWINDOW, GetLastError()); + if (!SetWindowLongPtr(mHiddenWindow, GWLP_USERDATA, (LONG_PTR)this)) + throw Exception(ERR_CREATEWINDOW, GetLastError()); - // Adjust notification filter - memset(&mNotificationFilter, 0, sizeof(mNotificationFilter)); - - mNotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE); - mNotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; - - // Register notification - if (!RegisterDeviceNotification(mHiddenWindow, &mNotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE | DEVICE_NOTIFY_ALL_INTERFACE_CLASSES)) - throw Exception(ERR_REGISTERNOTIFICATION, GetLastError()); + // Adjust notification filter + memset(&mNotificationFilter, 0, sizeof(mNotificationFilter)); + + mNotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE); + mNotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; + + // Register notification + if (!RegisterDeviceNotification(mHiddenWindow, &mNotificationFilter, + DEVICE_NOTIFY_WINDOW_HANDLE | DEVICE_NOTIFY_ALL_INTERFACE_CLASSES)) + throw Exception(ERR_REGISTERNOTIFICATION, GetLastError()); } -LRESULT CALLBACK UsbChangeListener::ADRWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) +LRESULT CALLBACK UsbChangeListener::ADRWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { - if ( uMsg == WM_DEVICECHANGE ) - { - if (wParam == DBT_DEVICEARRIVAL || wParam == DBT_DEVICEREMOVECOMPLETE) + if (uMsg == WM_DEVICECHANGE) { - LONG_PTR l = GetWindowLongPtr(hwnd, GWLP_USERDATA); - if (l) - { - UsbChangeListener* obj = reinterpret_cast(l); - switch (wParam) + if (wParam == DBT_DEVICEARRIVAL || wParam == DBT_DEVICEREMOVECOMPLETE) { - case DBT_DEVICEARRIVAL: - obj->getDelegate()->onDeviceInsert(NULL); - break; + LONG_PTR l = GetWindowLongPtr(hwnd, GWLP_USERDATA); + if (l) + { + UsbChangeListener* obj = reinterpret_cast(l); + switch (wParam) + { + case DBT_DEVICEARRIVAL: + obj->getDelegate()->onDeviceInsert(NULL); + break; - case DBT_DEVICEREMOVECOMPLETE: - obj->getDelegate()->onDeviceRemove(NULL); - break; + case DBT_DEVICEREMOVECOMPLETE: + obj->getDelegate()->onDeviceRemove(NULL); + break; + } + } } - } } - } - return ::DefWindowProc( hwnd, uMsg, wParam, lParam); + return ::DefWindowProc(hwnd, uMsg, wParam, lParam); } void UsbChangeListener::stop() { - // Unregister - if (mNotifyHandle != NULL) - { - ::UnregisterDeviceNotification(mNotifyHandle); - mNotifyHandle = NULL; - } + // Unregister + if (mNotifyHandle != NULL) + { + ::UnregisterDeviceNotification(mNotifyHandle); + mNotifyHandle = NULL; + } - //Destroy the window - if (mHiddenWindow != NULL) - { - ::DestroyWindow(mHiddenWindow); - mHiddenWindow = NULL; + // Destroy the window + if (mHiddenWindow != NULL) + { + ::DestroyWindow(mHiddenWindow); + mHiddenWindow = NULL; - ::UnregisterClassW(mWindowClassName, NULL); - } + ::UnregisterClassW(mWindowClassName, NULL); + } } #endif diff --git a/src/engine/helper/HL_Usb.h b/src/engine/helper/HL_Usb.h index 81318601..734d4540 100644 --- a/src/engine/helper/HL_Usb.h +++ b/src/engine/helper/HL_Usb.h @@ -7,39 +7,39 @@ #include #include - class UsbChangeListener - { - public: +class UsbChangeListener +{ +public: class Delegate { public: - virtual void onDeviceInsert(const wchar_t* name) = 0; - virtual void onDeviceRemove(const wchar_t* name) = 0; + virtual void onDeviceInsert(const wchar_t* name) = 0; + virtual void onDeviceRemove(const wchar_t* name) = 0; }; - + UsbChangeListener(); ~UsbChangeListener(); - - void setDelegate(Delegate* d); + + void setDelegate(Delegate* d); Delegate* getDelegate() const; - void start(); - void stop(); + void start(); + void stop(); - protected: - HDEVNOTIFY mNotifyHandle; /// Handle to track notifications about USB insert/removal. - HWND mHiddenWindow; /// Hidden window to receive notifications - DEV_BROADCAST_DEVICEINTERFACE mNotificationFilter; /// Notifications filter - wchar_t mWindowClassName[256]; /// Hidden window class - Delegate* mDelegate; /// Event handler pointer +protected: + HDEVNOTIFY mNotifyHandle; /// Handle to track notifications about USB insert/removal. + HWND mHiddenWindow; /// Hidden window to receive notifications + DEV_BROADCAST_DEVICEINTERFACE mNotificationFilter; /// Notifications filter + wchar_t mWindowClassName[256]; /// Hidden window class + Delegate* mDelegate; /// Event handler pointer /// Hidden window procedure. /// @param hwnd Window handle /// @param uMsg Message ID /// @param wParam First param /// @param lParam Second param - static LRESULT CALLBACK ADRWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ); - }; + static LRESULT CALLBACK ADRWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +}; #endif diff --git a/src/engine/helper/HL_Uuid.cpp b/src/engine/helper/HL_Uuid.cpp index 4df81f00..cbe0eb25 100644 --- a/src/engine/helper/HL_Uuid.cpp +++ b/src/engine/helper/HL_Uuid.cpp @@ -16,7 +16,7 @@ Uuid::Uuid() Uuid Uuid::generateOne() { - Uuid result; + Uuid result; // A fully-seeded Mersenne Twister, built ONCE per thread. The previous code // re-seeded a fresh mt19937 from std::random_device on every call: filling @@ -28,19 +28,19 @@ Uuid Uuid::generateOne() static thread_local std::mt19937 generator = [] { std::random_device rd; - auto seed_data = std::array {}; + auto seed_data = std::array{}; std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); return std::mt19937(seq); }(); uuids::uuid_random_generator gen{generator}; - auto id = gen(); + auto id = gen(); memcpy(result.mUuid, id.as_bytes().data(), id.as_bytes().size_bytes()); return result; } -Uuid Uuid::parse(const std::string &s) +Uuid Uuid::parse(const std::string& s) { Uuid result; auto id = uuids::uuid::from_string(s); @@ -52,12 +52,12 @@ Uuid Uuid::parse(const std::string &s) std::string Uuid::toString() const { - auto s = std::span{(uuids::uuid::value_type*)mUuid, 16}; + auto s = std::span{(uuids::uuid::value_type*)mUuid, 16}; uuids::uuid id(s); return uuids::to_string(id); } -bool Uuid::operator < (const Uuid& right) const +bool Uuid::operator<(const Uuid& right) const { return memcmp(mUuid, right.mUuid, sizeof(mUuid)) < 0; return false; diff --git a/src/engine/helper/HL_Uuid.h b/src/engine/helper/HL_Uuid.h index c3821583..9d2944cc 100644 --- a/src/engine/helper/HL_Uuid.h +++ b/src/engine/helper/HL_Uuid.h @@ -11,7 +11,7 @@ public: static Uuid generateOne(); static Uuid parse(const std::string& s); std::string toString() const; - bool operator < (const Uuid& right) const; + bool operator<(const Uuid& right) const; protected: uint8_t mUuid[16]; diff --git a/src/engine/helper/HL_VariantMap.cpp b/src/engine/helper/HL_VariantMap.cpp index 09aaa0b0..feedb8fd 100644 --- a/src/engine/helper/HL_VariantMap.cpp +++ b/src/engine/helper/HL_VariantMap.cpp @@ -8,7 +8,7 @@ #include #if defined(TARGET_ANDROID) -# define __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS #endif #include @@ -25,35 +25,21 @@ Variant::Variant() mPointer = nullptr; } -Variant::~Variant() -{ -} +Variant::~Variant() {} -Variant::Variant(bool value) - :mType(VTYPE_BOOL), mBool(value) -{} +Variant::Variant(bool value) : mType(VTYPE_BOOL), mBool(value) {} -Variant::Variant(int value) - :mType(VTYPE_INT), mInt(value) -{} +Variant::Variant(int value) : mType(VTYPE_INT), mInt(value) {} -Variant::Variant(int64_t value) - :mType(VTYPE_INT64), mInt64(value) -{} +Variant::Variant(int64_t value) : mType(VTYPE_INT64), mInt64(value) {} -Variant::Variant(float value) - :mType(VTYPE_FLOAT), mFloat(value) -{} +Variant::Variant(float value) : mType(VTYPE_FLOAT), mFloat(value) {} -Variant::Variant(double value) - :mType(VTYPE_FLOAT), mFloat((float)value) -{} +Variant::Variant(double value) : mType(VTYPE_FLOAT), mFloat((float)value) {} -Variant::Variant(const std::string& value) - :mType(VTYPE_STRING), mString(value) -{} +Variant::Variant(const std::string& value) : mType(VTYPE_STRING), mString(value) {} -Variant& Variant::operator = (bool value) +Variant& Variant::operator=(bool value) { mType = VTYPE_BOOL; mBool = value; @@ -61,7 +47,7 @@ Variant& Variant::operator = (bool value) return *this; } -Variant& Variant::operator = (int value) +Variant& Variant::operator=(int value) { mType = VTYPE_INT; mInt = value; @@ -69,7 +55,7 @@ Variant& Variant::operator = (int value) return *this; } -Variant& Variant::operator = (int64_t value) +Variant& Variant::operator=(int64_t value) { mType = VTYPE_INT64; mInt64 = value; @@ -77,7 +63,7 @@ Variant& Variant::operator = (int64_t value) return *this; } -Variant& Variant::operator = (float value) +Variant& Variant::operator=(float value) { mType = VTYPE_FLOAT; mFloat = value; @@ -85,7 +71,7 @@ Variant& Variant::operator = (float value) return *this; } -Variant& Variant::operator = (const std::string& value) +Variant& Variant::operator=(const std::string& value) { mType = VTYPE_STRING; mString = value; @@ -93,7 +79,7 @@ Variant& Variant::operator = (const std::string& value) return *this; } -Variant& Variant::operator = (const char* value) +Variant& Variant::operator=(const char* value) { mType = VTYPE_STRING; mString = value; @@ -101,7 +87,7 @@ Variant& Variant::operator = (const char* value) return *this; } -Variant& Variant::operator = (void* value) +Variant& Variant::operator=(void* value) { mType = VTYPE_POINTER; mPointer = value; @@ -109,7 +95,7 @@ Variant& Variant::operator = (void* value) return *this; } -Variant& Variant::operator = (PVariantMap map) +Variant& Variant::operator=(PVariantMap map) { mType = VTYPE_VMAP; mVMap = map; @@ -117,94 +103,119 @@ Variant& Variant::operator = (PVariantMap map) return *this; } -Variant Variant::operator + (const Variant& rhs) +Variant Variant::operator+(const Variant& rhs) { switch (type()) { case VTYPE_BOOL: - case VTYPE_INT: return asInt() + rhs.asInt(); - case VTYPE_INT64: return asInt64() + rhs.asInt64(); - case VTYPE_FLOAT: return asFloat() + rhs.asFloat(); - case VTYPE_STRING: return asStdString() + rhs.asStdString(); + case VTYPE_INT: + return asInt() + rhs.asInt(); + case VTYPE_INT64: + return asInt64() + rhs.asInt64(); + case VTYPE_FLOAT: + return asFloat() + rhs.asFloat(); + case VTYPE_STRING: + return asStdString() + rhs.asStdString(); default: return false; } } -Variant Variant::operator - (const Variant& rhs) +Variant Variant::operator-(const Variant& rhs) { switch (type()) { case VTYPE_BOOL: case VTYPE_STRING: - case VTYPE_INT: return asInt() - rhs.asInt(); - case VTYPE_INT64: return asInt64() - rhs.asInt64(); - case VTYPE_FLOAT: return asFloat() - rhs.asFloat(); + case VTYPE_INT: + return asInt() - rhs.asInt(); + case VTYPE_INT64: + return asInt64() - rhs.asInt64(); + case VTYPE_FLOAT: + return asFloat() - rhs.asFloat(); default: return false; } } -Variant Variant::operator * (const Variant& rhs) +Variant Variant::operator*(const Variant& rhs) { switch (type()) { case VTYPE_BOOL: case VTYPE_STRING: - case VTYPE_INT: return asInt() * rhs.asInt(); - case VTYPE_INT64: return asInt64() * rhs.asInt64(); - case VTYPE_FLOAT: return asFloat() * rhs.asFloat(); + case VTYPE_INT: + return asInt() * rhs.asInt(); + case VTYPE_INT64: + return asInt64() * rhs.asInt64(); + case VTYPE_FLOAT: + return asFloat() * rhs.asFloat(); default: return false; } } -Variant Variant::operator / (const Variant& rhs) +Variant Variant::operator/(const Variant& rhs) { switch (type()) { case VTYPE_BOOL: case VTYPE_STRING: - case VTYPE_INT: return asInt() / rhs.asInt(); - case VTYPE_INT64: return asInt64() / rhs.asInt64(); - case VTYPE_FLOAT: return asFloat() / rhs.asFloat(); + case VTYPE_INT: + return asInt() / rhs.asInt(); + case VTYPE_INT64: + return asInt64() / rhs.asInt64(); + case VTYPE_FLOAT: + return asFloat() / rhs.asFloat(); default: return false; } } -bool Variant::operator < (const Variant& rhs) const +bool Variant::operator<(const Variant& rhs) const { switch (type()) { - case VTYPE_STRING: return asStdString() < rhs.asStdString(); + case VTYPE_STRING: + return asStdString() < rhs.asStdString(); case VTYPE_BOOL: - case VTYPE_INT: return asInt() < rhs.asInt(); - case VTYPE_INT64: return asInt64() < rhs.asInt64(); - case VTYPE_FLOAT: return asFloat() < rhs.asFloat(); + case VTYPE_INT: + return asInt() < rhs.asInt(); + case VTYPE_INT64: + return asInt64() < rhs.asInt64(); + case VTYPE_FLOAT: + return asFloat() < rhs.asFloat(); default: return false; } } -bool Variant::operator > (const Variant& rhs) const +bool Variant::operator>(const Variant& rhs) const { return !(*this == rhs) && !(*this < rhs); } -bool Variant::operator == (const Variant& rhs) const +bool Variant::operator==(const Variant& rhs) const { switch (type()) { - case VTYPE_STRING: return asStdString() == rhs.asStdString(); - case VTYPE_BOOL: return asBool() == rhs.asBool(); - case VTYPE_INT: return asInt() == rhs.asInt(); - case VTYPE_INT64: return asInt64() == rhs.asInt64(); - case VTYPE_FLOAT: return asFloat() == rhs.asFloat(); - case VTYPE_POINTER: return asPointer() == rhs.asPointer(); - case VTYPE_VMAP: assert(0); break; + case VTYPE_STRING: + return asStdString() == rhs.asStdString(); + case VTYPE_BOOL: + return asBool() == rhs.asBool(); + case VTYPE_INT: + return asInt() == rhs.asInt(); + case VTYPE_INT64: + return asInt64() == rhs.asInt64(); + case VTYPE_FLOAT: + return asFloat() == rhs.asFloat(); + case VTYPE_POINTER: + return asPointer() == rhs.asPointer(); + case VTYPE_VMAP: + assert(0); + break; default: return false; } @@ -212,17 +223,17 @@ bool Variant::operator == (const Variant& rhs) const return false; } -bool Variant::operator != (const Variant& rhs) const +bool Variant::operator!=(const Variant& rhs) const { return !(*this == rhs); } -bool Variant::operator <= (const Variant& rhs) const +bool Variant::operator<=(const Variant& rhs) const { return (*this < rhs) || (*this == rhs); } -bool Variant::operator >= (const Variant& rhs) const +bool Variant::operator>=(const Variant& rhs) const { return (*this > rhs) || (*this == rhs); } @@ -345,13 +356,9 @@ VariantType Variant::type() const return mType; } -VariantMap::VariantMap() -{ -} +VariantMap::VariantMap() {} -VariantMap::~VariantMap() -{ -} +VariantMap::~VariantMap() {} bool VariantMap::empty() const { @@ -368,7 +375,7 @@ bool VariantMap::exists(int itemId) const return mData.find(itemId) != mData.end(); } -Variant& VariantMap::operator [](int itemId) +Variant& VariantMap::operator[](int itemId) { return mData[itemId]; } diff --git a/src/engine/helper/HL_VariantMap.h b/src/engine/helper/HL_VariantMap.h index 706dcde2..73040416 100644 --- a/src/engine/helper/HL_VariantMap.h +++ b/src/engine/helper/HL_VariantMap.h @@ -12,13 +12,13 @@ enum VariantType { - VTYPE_BOOL, - VTYPE_INT, - VTYPE_INT64, - VTYPE_FLOAT, - VTYPE_STRING, - VTYPE_POINTER, - VTYPE_VMAP + VTYPE_BOOL, + VTYPE_INT, + VTYPE_INT64, + VTYPE_FLOAT, + VTYPE_STRING, + VTYPE_POINTER, + VTYPE_VMAP }; class VariantMap; @@ -27,74 +27,75 @@ typedef std::shared_ptr PVariantMap; class Variant { public: - Variant(); - ~Variant(); + Variant(); + ~Variant(); - Variant(bool value); - Variant(int value); - Variant(int64_t value); - Variant(float value); - Variant(double value); - Variant(const std::string& value); + Variant(bool value); + Variant(int value); + Variant(int64_t value); + Variant(float value); + Variant(double value); + Variant(const std::string& value); - Variant& operator = (bool value); - Variant& operator = (int value); - Variant& operator = (int64_t value); - Variant& operator = (float value); - Variant& operator = (const std::string& value); - Variant& operator = (const char* value); - Variant& operator = (void* value); - Variant& operator = (PVariantMap vmap); + Variant& operator=(bool value); + Variant& operator=(int value); + Variant& operator=(int64_t value); + Variant& operator=(float value); + Variant& operator=(const std::string& value); + Variant& operator=(const char* value); + Variant& operator=(void* value); + Variant& operator=(PVariantMap vmap); - Variant operator + (const Variant& rhs); - Variant operator - (const Variant& rhs); - Variant operator * (const Variant& rhs); - Variant operator / (const Variant& rhs); - bool operator < (const Variant& rhs) const; - bool operator > (const Variant& rhs) const; - bool operator == (const Variant& rhs) const; - bool operator != (const Variant& rhs) const; - bool operator <= (const Variant& rhs) const; - bool operator >= (const Variant& rhs) const; + Variant operator+(const Variant& rhs); + Variant operator-(const Variant& rhs); + Variant operator*(const Variant& rhs); + Variant operator/(const Variant& rhs); + bool operator<(const Variant& rhs) const; + bool operator>(const Variant& rhs) const; + bool operator==(const Variant& rhs) const; + bool operator!=(const Variant& rhs) const; + bool operator<=(const Variant& rhs) const; + bool operator>=(const Variant& rhs) const; - int asInt() const; - int64_t asInt64() const; - bool asBool() const; - float asFloat() const; - double asDouble() const; - std::string asStdString() const; - //const char* asString(); - void* asPointer() const; + int asInt() const; + int64_t asInt64() const; + bool asBool() const; + float asFloat() const; + double asDouble() const; + std::string asStdString() const; + // const char* asString(); + void* asPointer() const; - PVariantMap asVMap(); + PVariantMap asVMap(); - VariantType type() const; + VariantType type() const; protected: - VariantType mType; - bool mBool; - int mInt; - int64_t mInt64; - float mFloat; - std::string mString; - void* mPointer; - PVariantMap mVMap; + VariantType mType; + bool mBool; + int mInt; + int64_t mInt64; + float mFloat; + std::string mString; + void* mPointer; + PVariantMap mVMap; }; class VariantMap { public: - VariantMap(); - ~VariantMap(); - - bool empty() const; - void clear(); - bool exists(int itemId) const; + VariantMap(); + ~VariantMap(); + + bool empty() const; + void clear(); + bool exists(int itemId) const; + + Variant& operator[](int itemId); + Variant& at(int itemId); - Variant& operator[](int itemId); - Variant& at(int itemId); protected: - std::map mData; + std::map mData; }; #endif diff --git a/src/engine/helper/HL_Xcap.cpp b/src/engine/helper/HL_Xcap.cpp index 895247b8..b194065e 100644 --- a/src/engine/helper/HL_Xcap.cpp +++ b/src/engine/helper/HL_Xcap.cpp @@ -11,9 +11,9 @@ #include #ifdef TARGET_WIN -# include -# include -# include +#include +#include +#include #endif #define XML_HEADER "" @@ -21,15 +21,14 @@ std::string XcapHelper::buildBuddyList(const std::string& listName, const std::vector& buddies) { std::ostringstream result; - result << XML_HEADER << - "" << - ""; + result << XML_HEADER << "" << ""; // to test CT only! - //result << ""; - //result << ""; + // result << ""; + // result << ""; - for (unsigned i = 0; i"; } @@ -40,35 +39,20 @@ std::string XcapHelper::buildBuddyList(const std::string& listName, const std::v std::string XcapHelper::buildRules(const std::vector& buddies) { std::ostringstream result; - result << XML_HEADER << - "" << - "" << - ""; + result << XML_HEADER << "" << "" + << ""; - for (unsigned i = 0; i"; + result << ""; } - result << "" << - "" << - "" << - "allow" << - "" << - "" << - "" << - "" << - "" << - "" << - "" << - "" << - "" << - "" << - "" << - "" << - "" << - "" << - ""; + result << "" << "" << "" << "allow" + << "" << "" << "" + << "" << "" + << "" << "" + << "" << "" + << "" << "" + << "" << "" << "" << ""; return result.str(); } @@ -76,17 +60,17 @@ std::string XcapHelper::buildServices(const std::string& serviceUri, const std:: { std::ostringstream result; - result << "" << std::endl << - "" << std::endl << - "" << std::endl << - "" << listRef.c_str() << "" << std::endl << - "" << std::endl << - "presence" << std::endl << - "" << std::endl << - "" << std::endl << - ""; + result << "" << std::endl + << "" << std::endl + << "" << std::endl + << "" << listRef.c_str() << "" << std::endl + << "" << std::endl + << "presence" << std::endl + << "" << std::endl + << "" << std::endl + << ""; return result.str(); } @@ -98,11 +82,11 @@ std::string XcapHelper::normalizeSipUri(const std::string& uri) if (t.length()) { if (t[0] == '<') - t.erase(0,1); + t.erase(0, 1); if (t.length()) { - if (t[t.length()-1] == '>') - t.erase(uri.length()-1, 1); + if (t[t.length() - 1] == '>') + t.erase(uri.length() - 1, 1); } } return t; diff --git a/src/engine/media/MT_AmrCodec.cpp b/src/engine/media/MT_AmrCodec.cpp index 44e846dd..795bdb0c 100644 --- a/src/engine/media/MT_AmrCodec.cpp +++ b/src/engine/media/MT_AmrCodec.cpp @@ -11,40 +11,36 @@ using namespace MT; // Constant of AMR-NB frame lengths in bytes. -const uint8_t amrnb_framelen[9] = - {12, 13, 15, 17, 19, 20, 26, 31, 5}; +const uint8_t amrnb_framelen[9] = {12, 13, 15, 17, 19, 20, 26, 31, 5}; -const uint16_t amrnb_framelenbits[9] = - {95, 103, 118, 134, 148, 159, 204, 244, 39}; +const uint16_t amrnb_framelenbits[9] = {95, 103, 118, 134, 148, 159, 204, 244, 39}; // Constant of AMR-WB frame lengths in bytes. -const uint8_t amrwb_framelen[10] = - {17, 23, 32, 37, 40, 46, 50, 58, 60, 5 /* SID packet */}; -const uint16_t amrwb_framelenbits[10] = - {132, 177, 253, 285, 317, 365, 397, 461, 477, 40 /* SID packet */}; +const uint8_t amrwb_framelen[10] = {17, 23, 32, 37, 40, 46, 50, 58, 60, 5 /* SID packet */}; +const uint16_t amrwb_framelenbits[10] = {132, 177, 253, 285, 317, 365, 397, 461, 477, 40 /* SID packet */}; // Helper routines struct AmrPayloadInfo { - const uint8_t* mPayload = nullptr; - int mPayloadLength = 0; - bool mOctetAligned = false; - bool mInterleaving = false; - bool mWideband = false; - uint64_t mCurrentTimestamp = 0; + const uint8_t* mPayload = nullptr; + int mPayloadLength = 0; + bool mOctetAligned = false; + bool mInterleaving = false; + bool mWideband = false; + uint64_t mCurrentTimestamp = 0; }; struct AmrFrame { - uint8_t mFrameType = 0; - uint8_t mMode = 0; - bool mGoodQuality = false; - uint64_t mTimestamp = 0; + uint8_t mFrameType = 0; + uint8_t mMode = 0; + bool mGoodQuality = false; + uint64_t mTimestamp = 0; std::shared_ptr mData; - uint8_t mSTI = 0; + uint8_t mSTI = 0; }; struct AmrPayload @@ -67,7 +63,7 @@ static AmrPayload parseAmrPayload(AmrPayloadInfo& input, size_t& cngCounter) // Wrap incoming data with ByteArray to make bit dequeuing easy ByteBuffer byte_reader(input.mPayload, static_cast(input.mPayloadLength)); - BitReader bit_reader (input.mPayload, static_cast(input.mPayloadLength)); + BitReader bit_reader(input.mPayload, static_cast(input.mPayloadLength)); // In bandwidth-efficient mode, the payload header simply consists of a // 4-bit codec mode request: @@ -89,10 +85,10 @@ static AmrPayload parseAmrPayload(AmrPayloadInfo& input, size_t& cngCounter) bit_reader.readBits(8); // Silence codec mode constant (it differs for wideband and narrowband codecs) - uint8_t SID_FT = input.mWideband ? 9 : 8; + uint8_t SID_FT = input.mWideband ? 9 : 8; // Table of contents - uint8_t F, FT, Q; + uint8_t F, FT, Q; // Bits consumed by a single ToC entry: F(1) + FT(4) + Q(1), plus 2 padding // bits in octet-aligned mode. @@ -139,10 +135,9 @@ static AmrPayload parseAmrPayload(AmrPayloadInfo& input, size_t& cngCounter) input.mCurrentTimestamp += input.mWideband ? 320 : 160; if (FT == SID_FT) cngCounter++; - } - while (F != 0); + } while (F != 0); - for (size_t frameIndex=0; frameIndex < result.mFrames.size() && !result.mDiscardPacket; frameIndex++) + for (size_t frameIndex = 0; frameIndex < result.mFrames.size() && !result.mDiscardPacket; frameIndex++) { AmrFrame& f = result.mFrames[frameIndex]; @@ -150,7 +145,8 @@ static AmrPayload parseAmrPayload(AmrPayloadInfo& input, size_t& cngCounter) // 10-13 for AMR-WB, the whole packet SHOULD be discarded. This is to // avoid the loss of data synchronization in the depacketization // process, which can result in a huge degradation in speech quality. - bool discard = input.mWideband ? (f.mFrameType >= 10 && f.mFrameType <= 13) : (f.mFrameType >= 9 && f.mFrameType <= 14); + bool discard = + input.mWideband ? (f.mFrameType >= 10 && f.mFrameType <= 13) : (f.mFrameType >= 9 && f.mFrameType <= 14); if (discard) { result.mDiscardPacket = true; @@ -180,8 +176,8 @@ static AmrPayload parseAmrPayload(AmrPayloadInfo& input, size_t& cngCounter) continue; } - size_t bitsLength = input.mWideband ? amrwb_framelenbits[f.mFrameType] : amrnb_framelenbits[f.mFrameType]; - size_t byteLength = input.mWideband ? amrwb_framelen[f.mFrameType] : amrnb_framelen[f.mFrameType]; + size_t bitsLength = input.mWideband ? amrwb_framelenbits[f.mFrameType] : amrnb_framelenbits[f.mFrameType]; + size_t byteLength = input.mWideband ? amrwb_framelen[f.mFrameType] : amrnb_framelen[f.mFrameType]; if (bitsLength > 0) { @@ -206,8 +202,9 @@ static AmrPayload parseAmrPayload(AmrPayloadInfo& input, size_t& cngCounter) } else { - ICELogError(<< "Problem parsing AMR header: octet-aligned is set, available " << int(input.mPayloadLength - byteOffset) - << " bytes but requested " << (int)byteLength); + ICELogError(<< "Problem parsing AMR header: octet-aligned is set, available " + << int(input.mPayloadLength - byteOffset) << " bytes but requested " + << (int)byteLength); result.mDiscardPacket = true; continue; } @@ -223,7 +220,7 @@ static AmrPayload parseAmrPayload(AmrPayloadInfo& input, size_t& cngCounter) f.mData->mutableData()[0] = (f.mFrameType << 3) | (1 << 2); // Read bits - if (bit_reader.readBits(f.mData->mutableData() + 1, bitsLength /*+ bitsLength*/ ) < (size_t)bitsLength) + if (bit_reader.readBits(f.mData->mutableData() + 1, bitsLength /*+ bitsLength*/) < (size_t)bitsLength) f.mGoodQuality = false; } } @@ -233,11 +230,7 @@ static AmrPayload parseAmrPayload(AmrPayloadInfo& input, size_t& cngCounter) return result; } -AmrNbCodec::CodecFactory::CodecFactory(const AmrCodecConfig& config) - :mConfig(config) -{ - -} +AmrNbCodec::CodecFactory::CodecFactory(const AmrCodecConfig& config) : mConfig(config) {} const char* AmrNbCodec::CodecFactory::name() { @@ -255,10 +248,13 @@ int AmrNbCodec::CodecFactory::payloadType() } -void AmrNbCodec::CodecFactory::updateSdp(resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) -{} +void AmrNbCodec::CodecFactory::updateSdp(resip::SdpContents::Session::Medium::CodecContainer& codecs, + SdpDirection direction) +{ +} -int AmrNbCodec::CodecFactory::processSdp(const resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) +int AmrNbCodec::CodecFactory::processSdp(const resip::SdpContents::Session::Medium::CodecContainer& codecs, + SdpDirection direction) { return 0; } @@ -274,8 +270,7 @@ PCodec AmrNbCodec::CodecFactory::create() } -AmrNbCodec::AmrNbCodec(const AmrCodecConfig& config) - :mConfig(config) +AmrNbCodec::AmrNbCodec(const AmrCodecConfig& config) : mConfig(config) { // Contexts are created lazily (see ensureEncoder/ensureDecoder) - a codec // resolved only for network-MOS metadata never allocates them. @@ -310,14 +305,12 @@ AmrNbCodec::~AmrNbCodec() Codec::Info AmrNbCodec::info() { - return { - .mName = MT_AMRNB_CODECNAME, - .mSamplerate = 8000, - .mChannels = 1, - .mPcmLength = 20 * 16, - .mFrameTime = 20, - .mRtpLength = 0 - }; + return {.mName = MT_AMRNB_CODECNAME, + .mSamplerate = 8000, + .mChannels = 1, + .mPcmLength = 20 * 16, + .mFrameTime = 20, + .mRtpLength = 0}; } Codec::EncodeResult AmrNbCodec::encode(std::span input, std::span output) @@ -328,10 +321,10 @@ Codec::EncodeResult AmrNbCodec::encode(std::span input, std::span return {.mEncoded = 0}; // Declare the data input pointer - auto *dataIn = (const short *)input.data(); + auto* dataIn = (const short*)input.data(); // Declare the data output pointer - auto *dataOut = (unsigned char *)output.data(); + auto* dataOut = (unsigned char*)output.data(); // Find how much RTP frames will be generated unsigned int frames = input.size_bytes() / pcmLength(); @@ -398,7 +391,7 @@ Codec::DecodeResult AmrNbCodec::decode(std::span input, std::span if (input.size_bytes() == 0) { // PLC part unsigned char buffer[32]; - buffer[0] = (AMR_BITRATE_DTX << 3)|4; + buffer[0] = (AMR_BITRATE_DTX << 3) | 4; Decoder_Interface_Decode(mDecoderCtx, buffer, (short*)output.data(), 0); // Handle missing data return {.mDecoded = (size_t)pcmLength()}; } @@ -416,7 +409,7 @@ Codec::DecodeResult AmrNbCodec::decode(std::span input, std::span { ap = parseAmrPayload(info, mCngCounter); } - catch(...) + catch (...) { ICELogDebug(<< "Failed to decode AMR payload."); return {.mDecoded = 0}; @@ -438,7 +431,7 @@ Codec::DecodeResult AmrNbCodec::decode(std::span input, std::span ICELogError(<< "No AMR frames"); } short* dataOut = (short*)output.data(); - for (AmrFrame& frame: ap.mFrames) + for (AmrFrame& frame : ap.mFrames) { if (frame.mData) { @@ -462,10 +455,10 @@ size_t AmrNbCodec::plc(int lostFrames, std::span output) short* dataOut = (short*)output.data(); - for (int i=0; i < lostFrames; i++) + for (int i = 0; i < lostFrames; i++) { uint8_t buffer[32]; - buffer[0] = (AMR_BITRATE_DTX << 3)|4; + buffer[0] = (AMR_BITRATE_DTX << 3) | 4; Decoder_Interface_Decode(mDecoderCtx, buffer, dataOut, 0); // Handle missing data dataOut += L_FRAME; } @@ -484,9 +477,7 @@ int AmrNbCodec::getCngCounter() const } // -------- AMR WB codec -AmrWbCodec::CodecFactory::CodecFactory(const AmrCodecConfig& config) - :mConfig(config) -{} +AmrWbCodec::CodecFactory::CodecFactory(const AmrCodecConfig& config) : mConfig(config) {} const char* AmrWbCodec::CodecFactory::name() { @@ -503,10 +494,13 @@ int AmrWbCodec::CodecFactory::payloadType() return mConfig.mPayloadType; } -void AmrWbCodec::CodecFactory::updateSdp(resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) -{} +void AmrWbCodec::CodecFactory::updateSdp(resip::SdpContents::Session::Medium::CodecContainer& codecs, + SdpDirection direction) +{ +} -int AmrWbCodec::CodecFactory::processSdp(const resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) +int AmrWbCodec::CodecFactory::processSdp(const resip::SdpContents::Session::Medium::CodecContainer& codecs, + SdpDirection direction) { return 0; } @@ -523,8 +517,7 @@ PCodec AmrWbCodec::CodecFactory::create() AmrWbStatistics MT::GAmrWbStatistics; -AmrWbCodec::AmrWbCodec(const AmrCodecConfig& config) - :mConfig(config) +AmrWbCodec::AmrWbCodec(const AmrCodecConfig& config) : mConfig(config) { // Decoder context is created lazily (see ensureDecoder) - a codec resolved // only for network-MOS metadata never allocates the AMR-WB decoder state. @@ -540,7 +533,7 @@ AmrWbCodec::~AmrWbCodec() { if (mEncoderCtx) { - //E_IF_exit(mEncoderCtx); + // E_IF_exit(mEncoderCtx); mEncoderCtx = nullptr; } @@ -551,14 +544,16 @@ AmrWbCodec::~AmrWbCodec() } } -Codec::Info AmrWbCodec::info() { +Codec::Info AmrWbCodec::info() +{ return { .mName = MT_AMRWB_CODECNAME, .mSamplerate = 16000, .mChannels = 1, .mPcmLength = 20 * 16 * 2, .mFrameTime = 20, - .mRtpLength = 0 /* There is complex structure inside AMR packet which may include multilple frames with various length. */ + .mRtpLength = + 0 /* There is complex structure inside AMR packet which may include multilple frames with various length. */ }; } @@ -607,19 +602,19 @@ Codec::DecodeResult AmrWbCodec::decodeIuup(std::span input, std:: Codec::DecodeResult AmrWbCodec::decodePlain(std::span input, std::span output) { AmrPayloadInfo info; - info.mCurrentTimestamp = mCurrentDecoderTimestamp; - info.mOctetAligned = mConfig.mOctetAligned; - info.mPayload = input.data(); - info.mPayloadLength = input.size(); - info.mWideband = true; - info.mInterleaving = false; + info.mCurrentTimestamp = mCurrentDecoderTimestamp; + info.mOctetAligned = mConfig.mOctetAligned; + info.mPayload = input.data(); + info.mPayloadLength = input.size(); + info.mWideband = true; + info.mInterleaving = false; AmrPayload ap; try { ap = parseAmrPayload(info, mCngCounter); } - catch(...) + catch (...) { GAmrWbStatistics.mNonParsed++; ICELogDebug(<< "Failed to decode AMR payload"); @@ -637,7 +632,7 @@ Codec::DecodeResult AmrWbCodec::decodePlain(std::span input, std: // Find the required output capacity size_t capacity = 0; - for (AmrFrame& frame: ap.mFrames) + for (AmrFrame& frame : ap.mFrames) capacity += frame.mMode == 0xFF /* CNG */ ? pcmLength() : pcmLength(); if (output.size() < capacity) @@ -645,7 +640,7 @@ Codec::DecodeResult AmrWbCodec::decodePlain(std::span input, std: short* dataOut = (short*)output.data(); size_t dataOutSizeInBytes = 0; - for (AmrFrame& frame: ap.mFrames) + for (AmrFrame& frame : ap.mFrames) { size_t frameOutputSize = frame.mMode == 0xFF ? pcmLength() : pcmLength(); memset(dataOut, 0, frameOutputSize); @@ -709,9 +704,7 @@ int AmrWbCodec::getCngCounter() const // ------------- GSM EFR ----------------- -GsmEfrCodec::GsmEfrFactory::GsmEfrFactory(bool iuup, int ptype) - :mIuUP(iuup), mPayloadType(ptype) -{} +GsmEfrCodec::GsmEfrFactory::GsmEfrFactory(bool iuup, int ptype) : mIuUP(iuup), mPayloadType(ptype) {} const char* GsmEfrCodec::GsmEfrFactory::name() { @@ -728,10 +721,13 @@ int GsmEfrCodec::GsmEfrFactory::payloadType() return mPayloadType; } -void GsmEfrCodec::GsmEfrFactory::updateSdp(resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) -{} +void GsmEfrCodec::GsmEfrFactory::updateSdp(resip::SdpContents::Session::Medium::CodecContainer& codecs, + SdpDirection direction) +{ +} -int GsmEfrCodec::GsmEfrFactory::processSdp(const resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) +int GsmEfrCodec::GsmEfrFactory::processSdp(const resip::SdpContents::Session::Medium::CodecContainer& codecs, + SdpDirection direction) { return 0; } @@ -746,8 +742,7 @@ PCodec GsmEfrCodec::GsmEfrFactory::create() return PCodec(new GsmEfrCodec(mIuUP)); } -GsmEfrCodec::GsmEfrCodec(bool iuup) - :mIuUP(iuup) +GsmEfrCodec::GsmEfrCodec(bool iuup) : mIuUP(iuup) { mEncoderCtx = Encoder_Interface_init(1); mDecoderCtx = Decoder_Interface_init(); @@ -770,14 +765,12 @@ GsmEfrCodec::~GsmEfrCodec() Codec::Info GsmEfrCodec::info() { - return { - .mName = MT_GSMEFR_CODECNAME, - .mSamplerate = 8000, - .mChannels = 1, - .mPcmLength = 20 * 16, - .mFrameTime = 20, - .mRtpLength = 0 - }; + return {.mName = MT_GSMEFR_CODECNAME, + .mSamplerate = 8000, + .mChannels = 1, + .mPcmLength = 20 * 16, + .mFrameTime = 20, + .mRtpLength = 0}; } Codec::EncodeResult GsmEfrCodec::encode(std::span input, std::span output) @@ -786,13 +779,13 @@ Codec::EncodeResult GsmEfrCodec::encode(std::span input, std::spa return {.mEncoded = 0}; // Declare the data input pointer - const short *dataIn = (const short *)input.data(); + const short* dataIn = (const short*)input.data(); // Declare the data output pointer - unsigned char *dataOut = (unsigned char *)output.data(); + unsigned char* dataOut = (unsigned char*)output.data(); // Find how much RTP frames will be generated - unsigned int frames = input.size_bytes() / pcmLength(); + unsigned int frames = input.size_bytes() / pcmLength(); // Generate frames for (unsigned int i = 0; i < frames; i++) @@ -806,56 +799,40 @@ Codec::EncodeResult GsmEfrCodec::encode(std::span input, std::spa #define L_FRAME 160 #define AMR_BITRATE_DTX 15 -#define GSM_EFR_SAMPLES 160 -#define GSM_EFR_FRAME_LEN 31 +#define GSM_EFR_SAMPLES 160 +#define GSM_EFR_FRAME_LEN 31 -static void -msb_put_bit(uint8_t *buf, int bn, int bit) +static void msb_put_bit(uint8_t* buf, int bn, int bit) { int pos_byte = bn >> 3; - int pos_bit = 7 - (bn & 7); + int pos_bit = 7 - (bn & 7); if (bit) - buf[pos_byte] |= (1 << pos_bit); + buf[pos_byte] |= (1 << pos_bit); else buf[pos_byte] &= ~(1 << pos_bit); } -static int -msb_get_bit(const uint8_t *buf, int bn) +static int msb_get_bit(const uint8_t* buf, int bn) { int pos_byte = bn >> 3; - int pos_bit = 7 - (bn & 7); + int pos_bit = 7 - (bn & 7); return (buf[pos_byte] >> pos_bit) & 1; } const uint16_t gsm690_12_2_bitorder[244] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 23, 15, 16, 17, 18, - 19, 20, 21, 22, 24, 25, 26, 27, 28, 38, - 141, 39, 142, 40, 143, 41, 144, 42, 145, 43, - 146, 44, 147, 45, 148, 46, 149, 47, 97, 150, - 200, 48, 98, 151, 201, 49, 99, 152, 202, 86, - 136, 189, 239, 87, 137, 190, 240, 88, 138, 191, - 241, 91, 194, 92, 195, 93, 196, 94, 197, 95, - 198, 29, 30, 31, 32, 33, 34, 35, 50, 100, - 153, 203, 89, 139, 192, 242, 51, 101, 154, 204, - 55, 105, 158, 208, 90, 140, 193, 243, 59, 109, - 162, 212, 63, 113, 166, 216, 67, 117, 170, 220, - 36, 37, 54, 53, 52, 58, 57, 56, 62, 61, - 60, 66, 65, 64, 70, 69, 68, 104, 103, 102, - 108, 107, 106, 112, 111, 110, 116, 115, 114, 120, - 119, 118, 157, 156, 155, 161, 160, 159, 165, 164, - 163, 169, 168, 167, 173, 172, 171, 207, 206, 205, - 211, 210, 209, 215, 214, 213, 219, 218, 217, 223, - 222, 221, 73, 72, 71, 76, 75, 74, 79, 78, - 77, 82, 81, 80, 85, 84, 83, 123, 122, 121, - 126, 125, 124, 129, 128, 127, 132, 131, 130, 135, - 134, 133, 176, 175, 174, 179, 178, 177, 182, 181, - 180, 185, 184, 183, 188, 187, 186, 226, 225, 224, - 229, 228, 227, 232, 231, 230, 235, 234, 233, 238, - 237, 236, 96, 199, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 23, 15, 16, 17, 18, 19, 20, 21, + 22, 24, 25, 26, 27, 28, 38, 141, 39, 142, 40, 143, 41, 144, 42, 145, 43, 146, 44, 147, 45, 148, 46, + 149, 47, 97, 150, 200, 48, 98, 151, 201, 49, 99, 152, 202, 86, 136, 189, 239, 87, 137, 190, 240, 88, 138, + 191, 241, 91, 194, 92, 195, 93, 196, 94, 197, 95, 198, 29, 30, 31, 32, 33, 34, 35, 50, 100, 153, 203, + 89, 139, 192, 242, 51, 101, 154, 204, 55, 105, 158, 208, 90, 140, 193, 243, 59, 109, 162, 212, 63, 113, 166, + 216, 67, 117, 170, 220, 36, 37, 54, 53, 52, 58, 57, 56, 62, 61, 60, 66, 65, 64, 70, 69, 68, 104, + 103, 102, 108, 107, 106, 112, 111, 110, 116, 115, 114, 120, 119, 118, 157, 156, 155, 161, 160, 159, 165, 164, 163, + 169, 168, 167, 173, 172, 171, 207, 206, 205, 211, 210, 209, 215, 214, 213, 219, 218, 217, 223, 222, 221, 73, 72, + 71, 76, 75, 74, 79, 78, 77, 82, 81, 80, 85, 84, 83, 123, 122, 121, 126, 125, 124, 129, 128, 127, 132, + 131, 130, 135, 134, 133, 176, 175, 174, 179, 178, 177, 182, 181, 180, 185, 184, 183, 188, 187, 186, 226, 225, 224, + 229, 228, 227, 232, 231, 230, 235, 234, 233, 238, 237, 236, 96, 199, }; Codec::DecodeResult GsmEfrCodec::decode(std::span input, std::span output) @@ -866,17 +843,17 @@ Codec::DecodeResult GsmEfrCodec::decode(std::span input, std::spa if (input.size_bytes() == 0) { // PLC part unsigned char buffer[32]; - buffer[0] = (AMR_BITRATE_DTX << 3)|4; + buffer[0] = (AMR_BITRATE_DTX << 3) | 4; Decoder_Interface_Decode(mDecoderCtx, buffer, (short*)output.data(), 0); // Handle missing data } else { // Reorder bytes from input to dst - uint8_t dst[GSM_EFR_FRAME_LEN]; + uint8_t dst[GSM_EFR_FRAME_LEN]; const uint8_t* src = input.data(); - for (int i=0; i<(GSM_EFR_FRAME_LEN-1); i++) - dst[i] = (src[i] << 4) | (src[i+1] >> 4); - dst[GSM_EFR_FRAME_LEN-1] = src[GSM_EFR_FRAME_LEN-1] << 4; + for (int i = 0; i < (GSM_EFR_FRAME_LEN - 1); i++) + dst[i] = (src[i] << 4) | (src[i + 1] >> 4); + dst[GSM_EFR_FRAME_LEN - 1] = src[GSM_EFR_FRAME_LEN - 1] << 4; unsigned char in[GSM_EFR_FRAME_LEN + 1]; @@ -884,7 +861,7 @@ Codec::DecodeResult GsmEfrCodec::decode(std::span input, std::spa in[0] = 0x3c; /* AMR mode 7 = GSM-EFR, Quality bit is set */ in[GSM_EFR_FRAME_LEN] = 0x0; - for (int i=0; i<244; i++) + for (int i = 0; i < 244; i++) { int si = gsm690_12_2_bitorder[i]; int di = i; @@ -896,11 +873,11 @@ Codec::DecodeResult GsmEfrCodec::decode(std::span input, std::spa Decoder_Interface_Decode(mDecoderCtx, in, (short*)output.data(), 0); uint8_t* pcm = (uint8_t*)output.data(); - for (int i=0; i<160; i++) + for (int i = 0; i < 160; i++) { uint16_t w = ((uint16_t*)output.data())[i]; - pcm[(i<<1) ] = w & 0xff; - pcm[(i<<1)+1] = (w >> 8) & 0xff; + pcm[(i << 1)] = w & 0xff; + pcm[(i << 1) + 1] = (w >> 8) & 0xff; } } @@ -914,10 +891,10 @@ size_t GsmEfrCodec::plc(int lostFrames, std::span output) short* dataOut = (short*)output.data(); - for (int i=0; i < lostFrames; i++) + for (int i = 0; i < lostFrames; i++) { unsigned char buffer[32]; - buffer[0] = (AMR_BITRATE_DTX << 3)|4; + buffer[0] = (AMR_BITRATE_DTX << 3) | 4; Decoder_Interface_Decode(mDecoderCtx, buffer, dataOut, 0); // Handle missing data dataOut += L_FRAME; } diff --git a/src/engine/media/MT_AmrCodec.h b/src/engine/media/MT_AmrCodec.h index c15f4b06..f5b4ac29 100644 --- a/src/engine/media/MT_AmrCodec.h +++ b/src/engine/media/MT_AmrCodec.h @@ -8,51 +8,53 @@ #include "MT_Codec.h" #include "../helper/HL_Pointer.h" -# include "opencore-amr/amrnb/interf_enc.h" -# include "opencore-amr/amrnb/interf_dec.h" +#include "opencore-amr/amrnb/interf_enc.h" +#include "opencore-amr/amrnb/interf_dec.h" -# include "opencore-amr/amrwb/if_rom.h" -# include "opencore-amr/amrwb/dec_if.h" +#include "opencore-amr/amrwb/if_rom.h" +#include "opencore-amr/amrwb/dec_if.h" namespace MT { struct AmrCodecConfig { - bool mIuUP = false; - bool mOctetAligned = false; - int mPayloadType = -1; + bool mIuUP = false; + bool mOctetAligned = false; + int mPayloadType = -1; }; class AmrNbCodec : public Codec { protected: - void* mEncoderCtx = nullptr; - void* mDecoderCtx = nullptr; + void* mEncoderCtx = nullptr; + void* mDecoderCtx = nullptr; AmrCodecConfig mConfig; - unsigned mCurrentDecoderTimestamp = 0; - int mPreviousPacketLength = 0; - size_t mCngCounter = 0; - size_t mSwitchCounter = 0; + unsigned mCurrentDecoderTimestamp = 0; + int mPreviousPacketLength = 0; + size_t mCngCounter = 0; + size_t mSwitchCounter = 0; // opencore-amr encoder/decoder state is allocated lazily on first encode/decode. // Network-MOS-only streams resolve codec metadata (name/samplerate/frame timing) // but never decode, so they must not pay for a context they never use - at scale // this is ~a decoder state (several KB) saved per network-only stream. - void ensureEncoder(); - void ensureDecoder(); + void ensureEncoder(); + void ensureDecoder(); + public: - class CodecFactory: public Factory + class CodecFactory : public Factory { public: CodecFactory(const AmrCodecConfig& config); const char* name() override; - int samplerate() override; - int payloadType() override; + int samplerate() override; + int payloadType() override; - void updateSdp(resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) override; - int processSdp(const resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) override; - void create(CodecMap& codecs) override; + void updateSdp(resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) override; + int processSdp(const resip::SdpContents::Session::Medium::CodecContainer& codecs, + SdpDirection direction) override; + void create(CodecMap& codecs) override; PCodec create() override; @@ -63,14 +65,14 @@ public: AmrNbCodec(const AmrCodecConfig& config); ~AmrNbCodec(); - Info info() override; + Info info() override; EncodeResult encode(std::span input, std::span output) override; DecodeResult decode(std::span input, std::span output) override; - size_t plc(int lostFrames, std::span output) override; + size_t plc(int lostFrames, std::span output) override; - int getSwitchCounter() const; - int getCngCounter() const; + int getSwitchCounter() const; + int getCngCounter() const; }; struct AmrWbStatistics @@ -83,35 +85,36 @@ extern AmrWbStatistics GAmrWbStatistics; class AmrWbCodec : public Codec { protected: - void* mEncoderCtx = nullptr; - void* mDecoderCtx = nullptr; + void* mEncoderCtx = nullptr; + void* mDecoderCtx = nullptr; AmrCodecConfig mConfig; - uint64_t mCurrentDecoderTimestamp = 0; - size_t mSwitchCounter = 0; - size_t mCngCounter = 0; + uint64_t mCurrentDecoderTimestamp = 0; + size_t mSwitchCounter = 0; + size_t mCngCounter = 0; - int mPreviousPacketLength; + int mPreviousPacketLength; // Decoder state is allocated lazily on first decode/plc (see AmrNbCodec) so // network-MOS-only streams never instantiate the AMR-WB decoder. - void ensureDecoder(); + void ensureDecoder(); - DecodeResult decodeIuup(std::span input, std::span output); - DecodeResult decodePlain(std::span input, std::span output); + DecodeResult decodeIuup(std::span input, std::span output); + DecodeResult decodePlain(std::span input, std::span output); public: - class CodecFactory: public Factory + class CodecFactory : public Factory { public: CodecFactory(const AmrCodecConfig& config); const char* name() override; - int samplerate() override; - int payloadType() override; + int samplerate() override; + int payloadType() override; - void updateSdp(resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) override; - int processSdp(const resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) override; - void create(CodecMap& codecs) override; + void updateSdp(resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) override; + int processSdp(const resip::SdpContents::Session::Medium::CodecContainer& codecs, + SdpDirection direction) override; + void create(CodecMap& codecs) override; PCodec create() override; @@ -122,13 +125,13 @@ public: AmrWbCodec(const AmrCodecConfig& config); virtual ~AmrWbCodec(); - Info info() override; + Info info() override; EncodeResult encode(std::span input, std::span output) override; DecodeResult decode(std::span input, std::span output) override; size_t plc(int lostFrames, std::span output) override; - int getSwitchCounter() const; - int getCngCounter() const; + int getSwitchCounter() const; + int getCngCounter() const; }; class GsmEfrCodec : public Codec @@ -136,40 +139,41 @@ class GsmEfrCodec : public Codec protected: void* mEncoderCtx = nullptr; void* mDecoderCtx = nullptr; - bool mIuUP = false; + bool mIuUP = false; public: - class GsmEfrFactory: public Factory + class GsmEfrFactory : public Factory { public: GsmEfrFactory(bool iuup, int ptype); const char* name() override; - int samplerate() override; - int payloadType() override; + int samplerate() override; + int payloadType() override; - void updateSdp(resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) override; - int processSdp(const resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) override; - void create(CodecMap& codecs) override; + void updateSdp(resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) override; + int processSdp(const resip::SdpContents::Session::Medium::CodecContainer& codecs, + SdpDirection direction) override; + void create(CodecMap& codecs) override; PCodec create() override; + protected: bool mIuUP; - int mPayloadType; + int mPayloadType; }; GsmEfrCodec(bool iuup = false); ~GsmEfrCodec(); - Info info() override; + Info info() override; EncodeResult encode(std::span input, std::span output) override; DecodeResult decode(std::span input, std::span output) override; size_t plc(int lostFrames, std::span output) override; }; -} // End of MT namespace +} // namespace MT #endif // MT_AMRCODEC_H - diff --git a/src/engine/media/MT_AudioCodec.cpp b/src/engine/media/MT_AudioCodec.cpp index 1626fbe6..1ddc7ea1 100644 --- a/src/engine/media/MT_AudioCodec.cpp +++ b/src/engine/media/MT_AudioCodec.cpp @@ -29,7 +29,7 @@ #define LOG_SUBSYSTEM "media" #ifdef TARGET_LINUX -# define stricmp strcasecmp +#define stricmp strcasecmp #endif using namespace MT; @@ -57,10 +57,13 @@ int G729Codec::G729Factory::payloadType() return 18; } -void G729Codec::G729Factory::updateSdp(resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) -{} +void G729Codec::G729Factory::updateSdp(resip::SdpContents::Session::Medium::CodecContainer& codecs, + SdpDirection direction) +{ +} -int G729Codec::G729Factory::processSdp(const resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) +int G729Codec::G729Factory::processSdp(const resip::SdpContents::Session::Medium::CodecContainer& codecs, + SdpDirection direction) { return 0; } @@ -70,10 +73,7 @@ PCodec G729Codec::G729Factory::create() return std::make_shared(); } -G729Codec::G729Codec() - :mEncoder(nullptr), mDecoder(nullptr) -{ -} +G729Codec::G729Codec() : mEncoder(nullptr), mDecoder(nullptr) {} G729Codec::~G729Codec() { @@ -92,14 +92,12 @@ G729Codec::~G729Codec() Codec::Info G729Codec::info() { - return { - .mName = "G729", - .mSamplerate = 8000, - .mChannels = 1, - .mPcmLength = 10 * 8 * 2, - .mFrameTime = 10, - .mRtpLength = 10 - }; + return {.mName = "G729", + .mSamplerate = 8000, + .mChannels = 1, + .mPcmLength = 10 * 8 * 2, + .mFrameTime = 10, + .mRtpLength = 10}; } // static const int SamplesPerFrame = 80; @@ -115,11 +113,12 @@ Codec::EncodeResult G729Codec::encode(std::span input, std::span< size_t result = 0; if (mEncoder) { - int nrOfFrames = input.size_bytes() / 160; // 10ms frames - Word16 parm[PRM_SIZE]; // ITU's service buffer + int nrOfFrames = input.size_bytes() / 160; // 10ms frames + Word16 parm[PRM_SIZE]; // ITU's service buffer for (int frameIndex = 0; frameIndex < nrOfFrames; frameIndex++) { - Copy((int16_t*)input.data() + frameIndex * info().mPcmLength / 2, mEncoder->new_speech, info().mPcmLength / 2); + Copy((int16_t*)input.data() + frameIndex * info().mPcmLength / 2, mEncoder->new_speech, + info().mPcmLength / 2); Pre_Process(mEncoder, mEncoder->new_speech, info().mPcmLength / 2); Coder_ld8a(mEncoder, parm); Store_Params(parm, output.data() + frameIndex * info().mRtpLength); @@ -148,11 +147,12 @@ Codec::DecodeResult G729Codec::decode(std::span input, std::span< bool isSilence = (input.size_bytes() % info().mRtpLength) / 2 != 0; // Find number of frames - int nrOfFrames = input.size_bytes() / info().mRtpLength; + int nrOfFrames = input.size_bytes() / info().mRtpLength; nrOfFrames = std::min(output.size_bytes() / info().mPcmLength, (size_t)nrOfFrames); for (int frameIndex = 0; frameIndex < nrOfFrames; frameIndex++) - decodeFrame(input.data() + frameIndex * info().mRtpLength, (int16_t*)output.data() + frameIndex * info().mPcmLength); + decodeFrame(input.data() + frameIndex * info().mRtpLength, + (int16_t*)output.data() + frameIndex * info().mPcmLength); result += nrOfFrames * info().mPcmLength; @@ -168,9 +168,9 @@ Codec::DecodeResult G729Codec::decode(std::span input, std::span< void G729Codec::decodeFrame(const uint8_t* rtp, int16_t* pcm) { - Word16 i; - Word16 *synth; - Word16 parm[PRM_SIZE + 1]; + Word16 i; + Word16* synth; + Word16 parm[PRM_SIZE + 1]; Restore_Params(rtp, &parm[1]); @@ -194,7 +194,6 @@ void G729Codec::decodeFrame(const uint8_t* rtp, int16_t* pcm) for (i = 0; i < pcmLength() / 2; i++) pcm[i] = synth[i]; - } @@ -204,14 +203,13 @@ size_t G729Codec::plc(int lostFrames, std::span output) } // -------------- Opus ------------------- -#define OPUS_CODEC_NAME "OPUS" -#define OPUS_CODEC_RATE 16000 -#define OPUS_TARGET_BITRATE 64000 -#define OPUS_PACKET_LOSS 10 -#define OPUS_CODEC_COMPLEXITY 2 +#define OPUS_CODEC_NAME "OPUS" +#define OPUS_CODEC_RATE 16000 +#define OPUS_TARGET_BITRATE 64000 +#define OPUS_PACKET_LOSS 10 +#define OPUS_CODEC_COMPLEXITY 2 -OpusCodec::Params::Params() - :mUseDtx(false), mUseInbandFec(true), mStereo(true), mPtime(20) +OpusCodec::Params::Params() : mUseDtx(false), mUseInbandFec(true), mStereo(true), mPtime(20) { mExpectedPacketLoss = OPUS_PACKET_LOSS; mTargetBitrate = OPUS_TARGET_BITRATE; @@ -220,7 +218,7 @@ OpusCodec::Params::Params() resip::Data OpusCodec::Params::toString() const { std::ostringstream oss; - //oss << "ptime=" << mPTime << ";"; + // oss << "ptime=" << mPTime << ";"; if (mUseDtx) oss << "usedtx=" << (mUseDtx ? "1" : "0") << ";"; if (mUseInbandFec) @@ -229,9 +227,9 @@ resip::Data OpusCodec::Params::toString() const // Erase last semicolon if (r.size()) - r.erase(r.size()-1); + r.erase(r.size() - 1); - //oss << "stereo=" << (mStereo ? "1" : "0") << ";"; + // oss << "stereo=" << (mStereo ? "1" : "0") << ";"; return resip::Data(r); } @@ -248,7 +246,7 @@ static void splitParams(const resip::Data& s, std::list& params) { resip::Data::size_type p1 = s.find(";", p); - resip::Data param; + resip::Data param; if (p1 != resip::Data::npos) { param = s.substr(p, p1 - p); @@ -261,7 +259,7 @@ static void splitParams(const resip::Data& s, std::list& params) } - CodecParam cp; + CodecParam cp; // See if there is '=' inside resip::Data::size_type ep = param.find("="); if (ep != resip::Data::npos) @@ -277,7 +275,7 @@ static void splitParams(const resip::Data& s, std::list& params) } -void OpusCodec::Params::parse(const resip::Data ¶ms) +void OpusCodec::Params::parse(const resip::Data& params) { // There is opus codec in sdp. Be simple - use the parameters from remote peer to operate std::list parsed; @@ -288,14 +286,11 @@ void OpusCodec::Params::parse(const resip::Data ¶ms) { if (paramIter->mName == "usedtx") mUseDtx = paramIter->mValue == "1"; - else - if (paramIter->mName == "useinbandfec") + else if (paramIter->mName == "useinbandfec") mUseInbandFec = paramIter->mValue == "1"; - else - if (paramIter->mName == "stereo") + else if (paramIter->mName == "stereo") mStereo = paramIter->mValue == "1"; - else - if (paramIter->mName == "ptime") + else if (paramIter->mName == "ptime") mPtime = strx::toInt(paramIter->mValue.c_str(), 20); } } @@ -327,7 +322,8 @@ int OpusCodec::OpusFactory::payloadType() return mPType; } -void OpusCodec::OpusFactory::updateSdp(resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) +void OpusCodec::OpusFactory::updateSdp(resip::SdpContents::Session::Medium::CodecContainer& codecs, + SdpDirection direction) { // Put opus codec record resip::Codec opus(name(), payloadType(), samplerate()); @@ -339,10 +335,11 @@ void OpusCodec::OpusFactory::updateSdp(resip::SdpContents::Session::Medium::Code } #if defined(TARGET_ANDROID) -# define stricmp strcasecmp +#define stricmp strcasecmp #endif -int OpusCodec::OpusFactory::processSdp(const resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) +int OpusCodec::OpusFactory::processSdp(const resip::SdpContents::Session::Medium::CodecContainer& codecs, + SdpDirection direction) { resip::SdpContents::Session::Medium::CodecContainer::const_iterator codecIter; for (codecIter = codecs.begin(); codecIter != codecs.end(); ++codecIter) @@ -357,7 +354,8 @@ int OpusCodec::OpusFactory::processSdp(const resip::SdpContents::Session::Medium mParams.mStereo |= codecIter->encodingParameters() == "2"; // Here changes must be applied to instantiated codec - for (CodecList::iterator instanceIter = mCodecList.begin(); instanceIter != mCodecList.end(); ++instanceIter) + for (CodecList::iterator instanceIter = mCodecList.begin(); instanceIter != mCodecList.end(); + ++instanceIter) { Codec& c = **instanceIter; if ((c.channels() == (mParams.mStereo ? 2 : 1)) && resipCodec.getRate() == c.samplerate()) @@ -380,7 +378,8 @@ PCodec OpusCodec::OpusFactory::create() } OpusCodec::OpusCodec(Audio::Format fmt, int ptime) - :mEncoderCtx(nullptr), mDecoderCtx(nullptr), mChannels(fmt.channels()), mPTime(ptime), mSamplerate(fmt.rate()), mDecoderChannels(0) + : mEncoderCtx(nullptr), mDecoderCtx(nullptr), mChannels(fmt.channels()), mPTime(ptime), mSamplerate(fmt.rate()), + mDecoderChannels(0) { int status; mEncoderCtx = opus_encoder_create(mSamplerate, mChannels, OPUS_APPLICATION_VOIP, &status); @@ -389,7 +388,7 @@ OpusCodec::OpusCodec(Audio::Format fmt, int ptime) // Decoder creation is postponed until first packet arriving (because it may use different channel number } -void OpusCodec::applyParams(const Params ¶ms) +void OpusCodec::applyParams(const Params& params) { int error; if (OPUS_OK != (error = opus_encoder_ctl(mEncoderCtx, OPUS_SET_DTX(params.mUseDtx ? 1 : 0)))) @@ -398,7 +397,8 @@ void OpusCodec::applyParams(const Params ¶ms) if (OPUS_OK != (error = opus_encoder_ctl(mEncoderCtx, OPUS_SET_INBAND_FEC(params.mUseInbandFec ? 1 : 0)))) ICELogError(<< "Failed to (un)set FEC mode in Opus encoder. Error " << opus_strerror(error)); - if (OPUS_OK != (error = opus_encoder_ctl(mEncoderCtx, OPUS_SET_BITRATE(params.mTargetBitrate ? params.mTargetBitrate : OPUS_AUTO)))) + if (OPUS_OK != (error = opus_encoder_ctl( + mEncoderCtx, OPUS_SET_BITRATE(params.mTargetBitrate ? params.mTargetBitrate : OPUS_AUTO)))) ICELogError(<< "Failed to (un)set target bandwidth. Error " << opus_strerror(error)); if (OPUS_OK != (error = opus_encoder_ctl(mEncoderCtx, OPUS_SET_PACKET_LOSS_PERC(params.mExpectedPacketLoss)))) @@ -422,7 +422,8 @@ OpusCodec::~OpusCodec() } } -Codec::Info OpusCodec::info() { +Codec::Info OpusCodec::info() +{ return { .mName = OPUS_CODEC_NAME, .mSamplerate = mSamplerate, @@ -437,8 +438,8 @@ Codec::EncodeResult OpusCodec::encode(std::span input, std::span< { // opus_encode() takes the frame size in samples per channel and the output // capacity in bytes. - int written = opus_encode(mEncoderCtx, (const opus_int16*)input.data(), input.size_bytes() / (sizeof(short) * channels()), - output.data(), output.size_bytes()); + int written = opus_encode(mEncoderCtx, (const opus_int16*)input.data(), + input.size_bytes() / (sizeof(short) * channels()), output.data(), output.size_bytes()); if (written < 0) return {.mEncoded = 0}; else @@ -485,8 +486,8 @@ Codec::DecodeResult OpusCodec::decode(std::span input, std::span< if (nr_of_channels == channels()) { - int decoded = opus_decode(mDecoderCtx, input.data(), input.size_bytes(), - (opus_int16*)output.data(), nr_of_frames, 0); + int decoded = + opus_decode(mDecoderCtx, input.data(), input.size_bytes(), (opus_int16*)output.data(), nr_of_frames, 0); if (decoded < 0) { ICELogCritical(<< "opus_decode() returned " << decoded); @@ -498,8 +499,7 @@ Codec::DecodeResult OpusCodec::decode(std::span input, std::span< // Channel count differs from the negotiated one - decode to a temporary // buffer and convert. std::vector temp((size_t)nr_of_frames * nr_of_channels); - int decoded = opus_decode(mDecoderCtx, input.data(), input.size_bytes(), - temp.data(), nr_of_frames, 0); + int decoded = opus_decode(mDecoderCtx, input.data(), input.size_bytes(), temp.data(), nr_of_frames, 0); if (decoded < 0) { ICELogCritical(<< "opus_decode() returned " << decoded); @@ -539,7 +539,7 @@ size_t OpusCodec::plc(int lostPackets, std::span output) if (samples_per_packet <= 0) return total; - opus_int16* out = reinterpret_cast(output.data()); + opus_int16* out = reinterpret_cast(output.data()); std::vector temp((size_t)samples_per_packet * mDecoderChannels); for (int packet = 0; packet < lostPackets; packet++) @@ -598,8 +598,8 @@ size_t OpusCodec::fec(std::span nextPacket, std::span ou // decode_fec = 1: pull the redundant copy of the previous frame. If nextPacket // carries no LBRR for it, Opus falls back to its own concealment internally, // so the result is never worse than plc(). - int decoded = opus_decode(mDecoderCtx, nextPacket.data(), nextPacket.size_bytes(), - (opus_int16*)output.data(), samples_per_channel, 1); + int decoded = opus_decode(mDecoderCtx, nextPacket.data(), nextPacket.size_bytes(), (opus_int16*)output.data(), + samples_per_channel, 1); if (decoded <= 0) return 0; @@ -615,8 +615,7 @@ size_t OpusCodec::getNumberOfSamples(std::span payload) // -------------- ILBC ------------------- #define ILBC_CODEC_NAME "ILBC" -IlbcCodec::IlbcCodec(int packetTime) - :mPacketTime(packetTime) +IlbcCodec::IlbcCodec(int packetTime) : mPacketTime(packetTime) { WebRtcIlbcfix_EncoderCreate(&mEncoderCtx); WebRtcIlbcfix_DecoderCreate(&mDecoderCtx); @@ -632,14 +631,12 @@ IlbcCodec::~IlbcCodec() Codec::Info IlbcCodec::info() { - return { - .mName = ILBC_CODEC_NAME, - .mSamplerate = 8000, - .mChannels = 1, - .mPcmLength = mPacketTime * 8 * (int)sizeof(short), - .mFrameTime = mPacketTime, - .mRtpLength = (mPacketTime == 20) ? 38 : 50 - }; + return {.mName = ILBC_CODEC_NAME, + .mSamplerate = 8000, + .mChannels = 1, + .mPcmLength = mPacketTime * 8 * (int)sizeof(short), + .mFrameTime = mPacketTime, + .mRtpLength = (mPacketTime == 20) ? 38 : 50}; } Codec::EncodeResult IlbcCodec::encode(std::span input, std::span output) @@ -648,18 +645,18 @@ Codec::EncodeResult IlbcCodec::encode(std::span input, std::span< return {}; // Declare the data input pointer - short *dataIn = (short *)input.data(); + short* dataIn = (short*)input.data(); // Declare the data output pointer - char *dataOut = (char *)output.data(); + char* dataOut = (char*)output.data(); // Find how much RTP frames will be generated unsigned int frames = input.size_bytes() / pcmLength(); // Generate frames - for (unsigned int i=0; i input, std::span< { unsigned frames = input.size_bytes() / rtpLength(); - char* dataIn = (char*)input.data(); - short* dataOut = (short*)output.data(); + char* dataIn = (char*)input.data(); + short* dataOut = (short*)output.data(); - for (unsigned i=0; i < frames; ++i) + for (unsigned i = 0; i < frames; ++i) { WebRtc_Word16 speechType = 0; WebRtcIlbcfix_Decode(mDecoderCtx, (WebRtc_Word16*)dataIn, rtpLength(), dataOut, &speechType); @@ -692,7 +689,7 @@ size_t IlbcCodec::plc(int lostFrames, std::span output) // --- IlbcFactory --- IlbcCodec::IlbcFactory::IlbcFactory(int ptype20ms, int ptype30ms) - :mPtime(30), mPType20ms(ptype20ms), mPType30ms(ptype30ms) + : mPtime(30), mPType20ms(ptype20ms), mPType30ms(ptype30ms) { } @@ -723,7 +720,8 @@ void IlbcCodec::IlbcFactory::create(CodecMap& codecs) codecs[mPType30ms] = PCodec(create()); } -void IlbcCodec::IlbcFactory::updateSdp(resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) +void IlbcCodec::IlbcFactory::updateSdp(resip::SdpContents::Session::Medium::CodecContainer& codecs, + SdpDirection direction) { if (mPtime == 20 || direction == Sdp_Offer) { @@ -739,23 +737,23 @@ void IlbcCodec::IlbcFactory::updateSdp(resip::SdpContents::Session::Medium::Code } } -int IlbcCodec::IlbcFactory::processSdp(const resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) +int IlbcCodec::IlbcFactory::processSdp(const resip::SdpContents::Session::Medium::CodecContainer& codecs, + SdpDirection direction) { resip::SdpContents::Session::Medium::CodecContainer::const_iterator codecIter; - int pt = -1, ptime = 0; + int pt = -1, ptime = 0; for (codecIter = codecs.begin(); codecIter != codecs.end(); codecIter++) { if (stricmp(codecIter->getName().c_str(), "ilbc") == 0) { const resip::Data& p = codecIter->parameters(); - int codecPtime = 0; + int codecPtime = 0; if (p.size()) { if (strstr(p.c_str(), "mode=") == p.c_str()) sscanf(p.c_str(), "mode=%d", &codecPtime); - else - if (strstr(p.c_str(), "ptime=")) - sscanf(p.c_str(), "ptime=%d", &codecPtime); + else if (strstr(p.c_str(), "ptime=")) + sscanf(p.c_str(), "ptime=%d", &codecPtime); } if (codecPtime > ptime) @@ -763,13 +761,12 @@ int IlbcCodec::IlbcFactory::processSdp(const resip::SdpContents::Session::Medium pt = codecIter->payloadType(); ptime = codecPtime; } - else - if (!codecPtime) - { - // Suppose it is 30ms ilbc - pt = codecIter->payloadType(); - ptime = 30; - } + else if (!codecPtime) + { + // Suppose it is 30ms ilbc + pt = codecIter->payloadType(); + ptime = 30; + } } } @@ -781,48 +778,48 @@ int IlbcCodec::IlbcFactory::processSdp(const resip::SdpContents::Session::Medium // --- IsacCodec(s) --- #define ISAC_CODEC_NAME "ISAC" -IsacCodec::IsacCodec(int samplerate) - :mSamplerate(samplerate) +IsacCodec::IsacCodec(int samplerate) : mSamplerate(samplerate) { // This code initializes isac encoder to automatic mode - it will adjust its bitrate automatically. // Frame time is 60 ms WebRtcIsacfix_Create(&mEncoderCtx); WebRtcIsacfix_EncoderInit(mEncoderCtx, 0); - //WebRtcIsacfix_Control(mEncoderCtx, mSamplerate, 30); - //WebRtcIsacfix_SetEncSampRate(mEncoderCtx, mSampleRate == 16000 ? kIsacWideband : kIsacSuperWideband); + // WebRtcIsacfix_Control(mEncoderCtx, mSamplerate, 30); + // WebRtcIsacfix_SetEncSampRate(mEncoderCtx, mSampleRate == 16000 ? kIsacWideband : kIsacSuperWideband); WebRtcIsacfix_Create(&mDecoderCtx); WebRtcIsacfix_DecoderInit(mDecoderCtx); - //WebRtcIsacfix_Control(mDecoderCtx, mSamplerate, 30); - //WebRtcIsacfix_SetDecSampRate(mDecoderCtx, mSampleRate == 16000 ? kIsacWideband : kIsacSuperWideband); + // WebRtcIsacfix_Control(mDecoderCtx, mSamplerate, 30); + // WebRtcIsacfix_SetDecSampRate(mDecoderCtx, mSampleRate == 16000 ? kIsacWideband : kIsacSuperWideband); } IsacCodec::~IsacCodec() { - WebRtcIsacfix_Free(mEncoderCtx); mEncoderCtx = NULL; - WebRtcIsacfix_Free(mDecoderCtx); mDecoderCtx = NULL; + WebRtcIsacfix_Free(mEncoderCtx); + mEncoderCtx = NULL; + WebRtcIsacfix_Free(mDecoderCtx); + mDecoderCtx = NULL; } -Codec::Info IsacCodec::info() { - return { - .mName = "isac", - .mSamplerate = mSamplerate, - .mChannels = 1, - .mPcmLength = 60 * mSamplerate / 1000 * 2, - .mFrameTime = 60, - .mRtpLength = 0 - }; +Codec::Info IsacCodec::info() +{ + return {.mName = "isac", + .mSamplerate = mSamplerate, + .mChannels = 1, + .mPcmLength = 60 * mSamplerate / 1000 * 2, + .mFrameTime = 60, + .mRtpLength = 0}; } Codec::EncodeResult IsacCodec::encode(std::span input, std::span output) { - unsigned nrOfSamples = input.size_bytes() / 2; - unsigned timeLength = nrOfSamples / (mSamplerate / 1000); - int encoded = 0; - char* dataOut = (char*)output.data(); + unsigned nrOfSamples = input.size_bytes() / 2; + unsigned timeLength = nrOfSamples / (mSamplerate / 1000); + int encoded = 0; + char* dataOut = (char*)output.data(); const WebRtc_Word16* dataIn = (const WebRtc_Word16*)input.data(); // Iterate 10 milliseconds chunks - for (unsigned i=0; i 0) @@ -834,7 +831,8 @@ Codec::EncodeResult IsacCodec::encode(std::span input, std::span< Codec::DecodeResult IsacCodec::decode(std::span input, std::span output) { WebRtc_Word16 speechType = 0; - unsigned produced = WebRtcIsacfix_Decode(mDecoderCtx, (const WebRtc_UWord16*)input.data(), input.size_bytes(), (WebRtc_Word16*)output.data(), &speechType); + unsigned produced = WebRtcIsacfix_Decode(mDecoderCtx, (const WebRtc_UWord16*)input.data(), input.size_bytes(), + (WebRtc_Word16*)output.data(), &speechType); if (produced == (unsigned)-1) return {.mDecoded = 0}; @@ -845,17 +843,15 @@ size_t IsacCodec::plc(int lostFrames, std::span output) { // lostFrames are 30-milliseconds frames; but used encoding mode is 60 milliseconds. // So lostFrames * 2 - lostFrames *=2 ; - if (-1 == WebRtcIsacfix_DecodePlc(mDecoderCtx, (WebRtc_Word16*)output.data(), lostFrames )) + lostFrames *= 2; + if (-1 == WebRtcIsacfix_DecodePlc(mDecoderCtx, (WebRtc_Word16*)output.data(), lostFrames)) return 0; - return lostFrames * 30 * (samplerate()/1000 * sizeof(short)); + return lostFrames * 30 * (samplerate() / 1000 * sizeof(short)); } // --- IsacFactory16K --- -IsacCodec::IsacFactory16K::IsacFactory16K(int ptype) - :mPType(ptype) -{} +IsacCodec::IsacFactory16K::IsacFactory16K(int ptype) : mPType(ptype) {} const char* IsacCodec::IsacFactory16K::name() { @@ -878,9 +874,7 @@ PCodec IsacCodec::IsacFactory16K::create() } // --- IsacFactory32K --- -IsacCodec::IsacFactory32K::IsacFactory32K(int ptype) - :mPType(ptype) -{} +IsacCodec::IsacFactory32K::IsacFactory32K(int ptype) : mPType(ptype) {} const char* IsacCodec::IsacFactory32K::name() @@ -907,49 +901,49 @@ PCodec IsacCodec::IsacFactory32K::create() #define ULAW_CODEC_NAME "PCMU" #define ALAW_CODEC_NAME "PCMA" -G711Codec::G711Codec(int type) - :mType(type) -{} +G711Codec::G711Codec(int type) : mType(type) {} -G711Codec::~G711Codec() -{} +G711Codec::~G711Codec() {} -Codec::Info G711Codec::info() { - return { - .mName = mType == ALaw ? "PCMA" : "PCMU", - .mSamplerate = 8000, - .mChannels = 1, - .mPcmLength = 10 * 16, - .mFrameTime = 10, - .mRtpLength = 10 * 8 - }; +Codec::Info G711Codec::info() +{ + return {.mName = mType == ALaw ? "PCMA" : "PCMU", + .mSamplerate = 8000, + .mChannels = 1, + .mPcmLength = 10 * 16, + .mFrameTime = 10, + .mRtpLength = 10 * 8}; } Codec::EncodeResult G711Codec::encode(std::span input, std::span output) { int result; if (mType == ALaw) - result = WebRtcG711_EncodeA(nullptr, (WebRtc_Word16*)input.data(), input.size_bytes() / 2, (WebRtc_Word16*)output.data()); + result = WebRtcG711_EncodeA(nullptr, (WebRtc_Word16*)input.data(), input.size_bytes() / 2, + (WebRtc_Word16*)output.data()); else - result = WebRtcG711_EncodeU(nullptr, (WebRtc_Word16*)input.data(), input.size_bytes() / 2, (WebRtc_Word16*)output.data()); + result = WebRtcG711_EncodeU(nullptr, (WebRtc_Word16*)input.data(), input.size_bytes() / 2, + (WebRtc_Word16*)output.data()); if (result < 0) return {.mEncoded = 0}; - return {.mEncoded = (size_t) result}; + return {.mEncoded = (size_t)result}; } Codec::DecodeResult G711Codec::decode(std::span input, std::span output) { assert(output.size_bytes() >= input.size_bytes() * 2); - int result; + int result; WebRtc_Word16 speechType; if (mType == ALaw) - result = WebRtcG711_DecodeA(nullptr, (WebRtc_Word16*)input.data(), input.size_bytes(), (WebRtc_Word16*)output.data(), &speechType); + result = WebRtcG711_DecodeA(nullptr, (WebRtc_Word16*)input.data(), input.size_bytes(), + (WebRtc_Word16*)output.data(), &speechType); else - result = WebRtcG711_DecodeU(nullptr, (WebRtc_Word16*)input.data(), input.size_bytes(), (WebRtc_Word16*)output.data(), &speechType); + result = WebRtcG711_DecodeU(nullptr, (WebRtc_Word16*)input.data(), input.size_bytes(), + (WebRtc_Word16*)output.data(), &speechType); if (result < 0) return {.mDecoded = 0}; @@ -1000,9 +994,7 @@ PCodec G711Codec::UlawFactory::create() // ---------- GsmCodec ------------- -GsmCodec::GsmFactory::GsmFactory(Type codecType, int pt) - :mCodecType(codecType), mPayloadType(pt) -{} +GsmCodec::GsmFactory::GsmFactory(Type codecType, int pt) : mCodecType(codecType), mPayloadType(pt) {} const char* GsmCodec::GsmFactory::name() { @@ -1024,8 +1016,7 @@ PCodec GsmCodec::GsmFactory::create() return PCodec(new GsmCodec(mCodecType)); } -GsmCodec::GsmCodec(Type codecType) - :mCodecType(codecType) +GsmCodec::GsmCodec(Type codecType) : mCodecType(codecType) { mGSM = gsm_create(); if (codecType != Type::Bytes_33) @@ -1037,38 +1028,47 @@ GsmCodec::GsmCodec(Type codecType) GsmCodec::~GsmCodec() { - gsm_destroy(mGSM); mGSM = nullptr; + gsm_destroy(mGSM); + mGSM = nullptr; } -Codec::Info GsmCodec::info() { +Codec::Info GsmCodec::info() +{ int rtpLength = 0; switch (mCodecType) { - case Type::Bytes_31: rtpLength = GSM_RTPFRAME_SIZE_31; break; - case Type::Bytes_32: rtpLength = GSM_RTPFRAME_SIZE_32; break; - case Type::Bytes_33: rtpLength = GSM_RTPFRAME_SIZE_33; break; - case Type::Bytes_65: rtpLength = GSM_RTPFRAME_SIZE_32 + GSM_RTPFRAME_SIZE_33; break; - default: rtpLength = GSM_RTPFRAME_SIZE_33; + case Type::Bytes_31: + rtpLength = GSM_RTPFRAME_SIZE_31; + break; + case Type::Bytes_32: + rtpLength = GSM_RTPFRAME_SIZE_32; + break; + case Type::Bytes_33: + rtpLength = GSM_RTPFRAME_SIZE_33; + break; + case Type::Bytes_65: + rtpLength = GSM_RTPFRAME_SIZE_32 + GSM_RTPFRAME_SIZE_33; + break; + default: + rtpLength = GSM_RTPFRAME_SIZE_33; } - return { - .mName = "GSM-06.10", - .mSamplerate = 8000, - .mChannels = 1, - .mPcmLength = GSM_AUDIOFRAME_TIME * 16, - .mFrameTime = GSM_AUDIOFRAME_TIME, - .mRtpLength = rtpLength - }; + return {.mName = "GSM-06.10", + .mSamplerate = 8000, + .mChannels = 1, + .mPcmLength = GSM_AUDIOFRAME_TIME * 16, + .mFrameTime = GSM_AUDIOFRAME_TIME, + .mRtpLength = rtpLength}; } Codec::EncodeResult GsmCodec::encode(std::span input, std::span output) { - int outputBytes = 0; + int outputBytes = 0; char* outputBuffer = (char*)output.data(); for (int i = 0; i < input.size_bytes() / pcmLength(); i++) { - gsm_encode(mGSM, (gsm_signal *)input.data()+160*i, (gsm_byte*)outputBuffer); + gsm_encode(mGSM, (gsm_signal*)input.data() + 160 * i, (gsm_byte*)outputBuffer); outputBuffer += rtpLength(); outputBytes += rtpLength(); } @@ -1084,16 +1084,16 @@ Codec::DecodeResult GsmCodec::decode(std::span input, std::span output.size_bytes()) break; const gsm_byte* in = (const gsm_byte*)input.data() + frameSize * i; - gsm_signal* out = (gsm_signal*)output.data() + (pcmPerFrame / 2) * i; + gsm_signal* out = (gsm_signal*)output.data() + (pcmPerFrame / 2) * i; gsm_decode(mGSM, (gsm_byte*)in, out); if (mCodecType == Type::Bytes_65) @@ -1120,25 +1120,25 @@ G722Codec::G722Codec() { mEncoder = g722_encode_init(nullptr, 64000, 0); mDecoder = g722_decode_init(nullptr, 64000, 0); - } G722Codec::~G722Codec() { - g722_decode_release((g722_decode_state_t*)mDecoder); mDecoder = nullptr; - g722_encode_release((g722_encode_state_t*)mEncoder); mEncoder = nullptr; + g722_decode_release((g722_decode_state_t*)mDecoder); + mDecoder = nullptr; + g722_encode_release((g722_encode_state_t*)mEncoder); + mEncoder = nullptr; } -Codec::Info G722Codec::info() { +Codec::Info G722Codec::info() +{ // ToDo: double check the G722 calls - remember RFC has bug about samplerate - return { - .mName = G722_MIME_NAME, - .mSamplerate = 8000, - .mChannels = 1, - .mPcmLength = 640, - .mFrameTime = 20, - .mRtpLength = 160 - }; + return {.mName = G722_MIME_NAME, + .mSamplerate = 8000, + .mChannels = 1, + .mPcmLength = 640, + .mFrameTime = 20, + .mRtpLength = 160}; } Codec::EncodeResult G722Codec::encode(std::span input, std::span output) @@ -1146,7 +1146,8 @@ Codec::EncodeResult G722Codec::encode(std::span input, std::span< if (output.size_bytes() < input.size_bytes() / 4) return {.mEncoded = 0}; // Destination buffer not big enough - int r = g722_encode((g722_encode_state_t *)mEncoder, (unsigned char*)output.data(), ( short*)input.data(), input.size_bytes() / 2); + int r = g722_encode((g722_encode_state_t*)mEncoder, (unsigned char*)output.data(), (short*)input.data(), + input.size_bytes() / 2); if (r < 0) return {.mEncoded = 0}; @@ -1158,7 +1159,9 @@ Codec::DecodeResult G722Codec::decode(std::span input, std::span< if (output.size_bytes() < input.size_bytes() * 4) return {.mDecoded = 0}; // Destination buffer not big enough - int r = g722_decode((g722_decode_state_t *)mDecoder, (short*)output.data(), (unsigned char*)input.data(), input.size_bytes()) * 2; + int r = g722_decode((g722_decode_state_t*)mDecoder, (short*)output.data(), (unsigned char*)input.data(), + input.size_bytes()) * + 2; if (r < 0) return {.mDecoded = 0}; return {.mDecoded = (size_t)r}; @@ -1174,8 +1177,7 @@ size_t G722Codec::plc(int lostFrames, std::span output) return lostFrames * pcmLength(); } -G722Codec::G722Factory::G722Factory() -{} +G722Codec::G722Factory::G722Factory() {} const char* G722Codec::G722Factory::name() { @@ -1202,9 +1204,9 @@ PCodec G722Codec::G722Factory::create() // --------------- GsmHrCodec ------------------- // Returns false if error occured. -#define GSMHR_GOODSPEECH (0) -#define GSMHR_GOODSID (2) -#define GSMHR_NODATA (7) +#define GSMHR_GOODSPEECH (0) +#define GSMHR_GOODSID (2) +#define GSMHR_NODATA (7) static bool repackHalfRate(BitReader& br, uint16_t frame[22], bool& lastItem) { @@ -1221,12 +1223,12 @@ static bool repackHalfRate(BitReader& br, uint16_t frame[22], bool& lastItem) { case GSMHR_GOODSPEECH: case GSMHR_GOODSID: - frame[0] = br.readBits(5); // R0 + frame[0] = br.readBits(5); // R0 frame[1] = br.readBits(11); // LPC1 - frame[2] = br.readBits(9); // LPC2 - frame[3] = br.readBits(8); // LPC3 - frame[4] = br.readBits(1); // INT_LPC - frame[5] = br.readBits(2); // MODE + frame[2] = br.readBits(9); // LPC2 + frame[3] = br.readBits(8); // LPC3 + frame[4] = br.readBits(1); // INT_LPC + frame[5] = br.readBits(2); // MODE // Parse speech frame if (frame[5]) { @@ -1235,7 +1237,7 @@ static bool repackHalfRate(BitReader& br, uint16_t frame[22], bool& lastItem) frame[7] = br.readBits(9); // CODE_1 frame[8] = br.readBits(5); // GSP0_1 - frame[9] = br.readBits(4); // LAG_2 + frame[9] = br.readBits(4); // LAG_2 frame[10] = br.readBits(9); // CODE_2 frame[11] = br.readBits(5); // GSP0_2 @@ -1254,7 +1256,7 @@ static bool repackHalfRate(BitReader& br, uint16_t frame[22], bool& lastItem) frame[7] = br.readBits(7); // CODE2_1 frame[8] = br.readBits(5); // GSP0_1 - frame[9] = br.readBits(7); // CODE1_2 + frame[9] = br.readBits(7); // CODE1_2 frame[10] = br.readBits(7); // CODE2_2 frame[11] = br.readBits(5); // GSP0_2 @@ -1267,8 +1269,10 @@ static bool repackHalfRate(BitReader& br, uint16_t frame[22], bool& lastItem) frame[17] = br.readBits(5); // GSP0_4; } - frame[18] = 0; frame[19] = 0; - frame[20] = 0; frame[21] = 0; + frame[18] = 0; + frame[19] = 0; + frame[20] = 0; + frame[21] = 0; break; case GSMHR_NODATA: @@ -1292,15 +1296,14 @@ GsmHrCodec::~GsmHrCodec() mDecoder = nullptr; } -Codec::Info GsmHrCodec::info() { - return { - .mName = "GSM-HR-08", - .mSamplerate = 8000, - .mChannels = 1, - .mPcmLength = 20 * 8 * 2, - .mFrameTime = 20, - .mRtpLength = 0 - }; +Codec::Info GsmHrCodec::info() +{ + return {.mName = "GSM-HR-08", + .mSamplerate = 8000, + .mChannels = 1, + .mPcmLength = 20 * 8 * 2, + .mFrameTime = 20, + .mRtpLength = 0}; } Codec::EncodeResult GsmHrCodec::encode(std::span input, std::span output) @@ -1310,75 +1313,73 @@ Codec::EncodeResult GsmHrCodec::encode(std::span input, std::span } static const int params_unvoiced[] = { - 5, /* R0 */ - 11, /* k1Tok3 */ - 9, /* k4Tok6 */ - 8, /* k7Tok10 */ - 1, /* softInterpolation */ - 2, /* voicingDecision */ - 7, /* code1_1 */ - 7, /* code2_1 */ - 5, /* gsp0_1 */ - 7, /* code1_2 */ - 7, /* code2_2 */ - 5, /* gsp0_2 */ - 7, /* code1_3 */ - 7, /* code2_3 */ - 5, /* gsp0_3 */ - 7, /* code1_4 */ - 7, /* code2_4 */ - 5, /* gsp0_4 */ + 5, /* R0 */ + 11, /* k1Tok3 */ + 9, /* k4Tok6 */ + 8, /* k7Tok10 */ + 1, /* softInterpolation */ + 2, /* voicingDecision */ + 7, /* code1_1 */ + 7, /* code2_1 */ + 5, /* gsp0_1 */ + 7, /* code1_2 */ + 7, /* code2_2 */ + 5, /* gsp0_2 */ + 7, /* code1_3 */ + 7, /* code2_3 */ + 5, /* gsp0_3 */ + 7, /* code1_4 */ + 7, /* code2_4 */ + 5, /* gsp0_4 */ }; static const int params_voiced[] = { - 5, /* R0 */ - 11, /* k1Tok3 */ - 9, /* k4Tok6 */ - 8, /* k7Tok10 */ - 1, /* softInterpolation */ - 2, /* voicingDecision */ - 8, /* frameLag */ - 9, /* code_1 */ - 5, /* gsp0_1 */ - 4, /* deltaLag_2 */ - 9, /* code_2 */ - 5, /* gsp0_2 */ - 4, /* deltaLag_3 */ - 9, /* code_3 */ - 5, /* gsp0_3 */ - 4, /* deltaLag_4 */ - 9, /* code_4 */ - 5, /* gsp0_4 */ + 5, /* R0 */ + 11, /* k1Tok3 */ + 9, /* k4Tok6 */ + 8, /* k7Tok10 */ + 1, /* softInterpolation */ + 2, /* voicingDecision */ + 8, /* frameLag */ + 9, /* code_1 */ + 5, /* gsp0_1 */ + 4, /* deltaLag_2 */ + 9, /* code_2 */ + 5, /* gsp0_2 */ + 4, /* deltaLag_3 */ + 9, /* code_3 */ + 5, /* gsp0_3 */ + 4, /* deltaLag_4 */ + 9, /* code_4 */ + 5, /* gsp0_4 */ }; -static int -msb_get_bit(const uint8_t *buf, int bn) +static int msb_get_bit(const uint8_t* buf, int bn) { int pos_byte = bn >> 3; - int pos_bit = 7 - (bn & 7); + int pos_bit = 7 - (bn & 7); return (buf[pos_byte] >> pos_bit) & 1; } -static int -hr_ref_from_canon(uint16_t *hr_ref, const uint8_t *canon) +static int hr_ref_from_canon(uint16_t* hr_ref, const uint8_t* canon) { - int i, j, voiced; - const int *params; + int i, j, voiced; + const int* params; voiced = (msb_get_bit(canon, 34) << 1) | msb_get_bit(canon, 35); params = voiced ? ¶ms_voiced[0] : ¶ms_unvoiced[0]; - for (i=0,j=0; i<18; i++) + for (i = 0, j = 0; i < 18; i++) { uint16_t w; - int l, k; + int l, k; l = params[i]; w = 0; - for (k=0; k input, std::span uint16_t hr_ref[22]; hr_ref_from_canon(hr_ref, input.data() + 1); - hr_ref[18] = 0; /* BFI : 1 bit */ - hr_ref[19] = 0; /* UFI : 1 bit */ - hr_ref[20] = 0; /* SID : 2 bit */ - hr_ref[21] = 0; /* TAF : 1 bit */ + hr_ref[18] = 0; /* BFI : 1 bit */ + hr_ref[19] = 0; /* UFI : 1 bit */ + hr_ref[20] = 0; /* SID : 2 bit */ + hr_ref[21] = 0; /* TAF : 1 bit */ reinterpret_cast(mDecoder)->speechDecoder((int16_t*)hr_ref, (int16_t*)output.data()); return {.mDecoded = 320}; @@ -1421,9 +1422,7 @@ size_t GsmHrCodec::plc(int lostFrames, std::span output) return 0; } -GsmHrCodec::GsmHrFactory::GsmHrFactory(int ptype) - :mPtype(ptype) -{} +GsmHrCodec::GsmHrFactory::GsmHrFactory(int ptype) : mPtype(ptype) {} const char* GsmHrCodec::GsmHrFactory::name() { diff --git a/src/engine/media/MT_AudioCodec.h b/src/engine/media/MT_AudioCodec.h index 5a737b2e..9192df08 100644 --- a/src/engine/media/MT_AudioCodec.h +++ b/src/engine/media/MT_AudioCodec.h @@ -26,203 +26,199 @@ extern "C" #include "opus.h" -namespace MT +namespace MT { -class G729Codec: public Codec +class G729Codec : public Codec { protected: CodState* mEncoder = nullptr; DecState* mDecoder = nullptr; - void decodeFrame(const uint8_t* rtp, int16_t* pcm); + void decodeFrame(const uint8_t* rtp, int16_t* pcm); public: - class G729Factory: public Factory + class G729Factory : public Factory { public: const char* name() override; - int channels() override; - int samplerate() override; - int payloadType() override; + int channels() override; + int samplerate() override; + int payloadType() override; - void updateSdp(resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) override; - int processSdp(const resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) override; + void updateSdp(resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) override; + int processSdp(const resip::SdpContents::Session::Medium::CodecContainer& codecs, + SdpDirection direction) override; PCodec create() override; }; G729Codec(); ~G729Codec() override; - Info info() override; + Info info() override; - EncodeResult encode(std::span input, std::span output) override; - DecodeResult decode(std::span input, std::span output) override; - size_t plc(int lostFrames, std::span output) override; + EncodeResult encode(std::span input, std::span output) override; + DecodeResult decode(std::span input, std::span output) override; + size_t plc(int lostFrames, std::span output) override; }; -class OpusCodec: public Codec +class OpusCodec : public Codec { protected: - OpusEncoder *mEncoderCtx = nullptr; - OpusDecoder *mDecoderCtx = nullptr; - int mPTime = 0, - mSamplerate = 0, - mChannels = 0; - int mDecoderChannels = 0; + OpusEncoder* mEncoderCtx = nullptr; + OpusDecoder* mDecoderCtx = nullptr; + int mPTime = 0, mSamplerate = 0, mChannels = 0; + int mDecoderChannels = 0; public: struct Params { - bool mUseDtx = false, - mUseInbandFec = false, - mStereo = false; - int mPtime = 0, - mTargetBitrate = 0, - mExpectedPacketLoss = 0; + bool mUseDtx = false, mUseInbandFec = false, mStereo = false; + int mPtime = 0, mTargetBitrate = 0, mExpectedPacketLoss = 0; Params(); resip::Data toString() const; - void parse(const resip::Data& params); + void parse(const resip::Data& params); }; - class OpusFactory: public Factory + class OpusFactory : public Factory { protected: - int mSamplerate, mChannels, mPType; - OpusCodec::Params mParams; + int mSamplerate, mChannels, mPType; + OpusCodec::Params mParams; typedef std::vector CodecList; - CodecList mCodecList; + CodecList mCodecList; public: OpusFactory(int samplerate, int channels, int ptype); const char* name() override; - int channels() override; - int samplerate() override; - int payloadType() override; - void updateSdp(resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) override; - int processSdp(const resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) override; + int channels() override; + int samplerate() override; + int payloadType() override; + void updateSdp(resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) override; + int processSdp(const resip::SdpContents::Session::Medium::CodecContainer& codecs, + SdpDirection direction) override; PCodec create() override; }; OpusCodec(Audio::Format fmt, int ptime); ~OpusCodec(); - void applyParams(const Params& params); + void applyParams(const Params& params); - Info info() override; + Info info() override; - EncodeResult encode(std::span input, std::span output) override; - DecodeResult decode(std::span input, std::span output) override; - size_t plc(int lostFrames, std::span output) override; - size_t fec(std::span nextPacket, std::span output) override; + EncodeResult encode(std::span input, std::span output) override; + DecodeResult decode(std::span input, std::span output) override; + size_t plc(int lostFrames, std::span output) override; + size_t fec(std::span nextPacket, std::span output) override; - size_t getNumberOfSamples(std::span payload); + size_t getNumberOfSamples(std::span payload); }; -class IlbcCodec: public Codec +class IlbcCodec : public Codec { protected: - int mPacketTime = 0; /// Single frame time (20 or 30 ms) - iLBC_encinst_t* mEncoderCtx = nullptr; - iLBC_decinst_t* mDecoderCtx = nullptr; - + int mPacketTime = 0; /// Single frame time (20 or 30 ms) + iLBC_encinst_t* mEncoderCtx = nullptr; + iLBC_decinst_t* mDecoderCtx = nullptr; + public: - class IlbcFactory: public Factory + class IlbcFactory : public Factory { protected: int mPtime; int mPType20ms, mPType30ms; public: - IlbcFactory(int ptype20ms, int ptype30ms); const char* name(); - int samplerate(); - int payloadType(); - void updateSdp(resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction); - int processSdp(const resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction); - void create(CodecMap& codecs); + int samplerate(); + int payloadType(); + void updateSdp(resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction); + int processSdp(const resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction); + void create(CodecMap& codecs); PCodec create(); }; IlbcCodec(int packetTime); virtual ~IlbcCodec(); - Info info() override; + Info info() override; - EncodeResult encode(std::span input, std::span output) override; - DecodeResult decode(std::span input, std::span output) override; - size_t plc(int lostFrames, std::span output) override; + EncodeResult encode(std::span input, std::span output) override; + DecodeResult decode(std::span input, std::span output) override; + size_t plc(int lostFrames, std::span output) override; }; -class G711Codec: public Codec +class G711Codec : public Codec { public: - class AlawFactory: public Factory + class AlawFactory : public Factory { public: const char* name(); - int samplerate(); - int payloadType(); - PCodec create(); + int samplerate(); + int payloadType(); + PCodec create(); }; - class UlawFactory: public Factory + class UlawFactory : public Factory { public: const char* name(); - int samplerate(); - int payloadType(); - PCodec create(); + int samplerate(); + int payloadType(); + PCodec create(); }; enum { - ALaw = 0, /// a-law codec type - ULaw = 1 /// u-law codec type + ALaw = 0, /// a-law codec type + ULaw = 1 /// u-law codec type }; - + G711Codec(int type); ~G711Codec(); - - Info info() override; + + Info info() override; EncodeResult encode(std::span input, std::span output) override; DecodeResult decode(std::span input, std::span output) override; - size_t plc(int lostSamples, std::span output) override ; + size_t plc(int lostSamples, std::span output) override; protected: - int mType; /// Determines if it is u-law or a-law codec. Its value is ALaw or ULaw. + int mType; /// Determines if it is u-law or a-law codec. Its value is ALaw or ULaw. }; -class IsacCodec: public Codec +class IsacCodec : public Codec { protected: - int mSamplerate = 0; - ISACFIX_MainStruct* mEncoderCtx = nullptr; - ISACFIX_MainStruct* mDecoderCtx = nullptr; + int mSamplerate = 0; + ISACFIX_MainStruct* mEncoderCtx = nullptr; + ISACFIX_MainStruct* mDecoderCtx = nullptr; + public: - class IsacFactory16K: public Factory + class IsacFactory16K : public Factory { public: IsacFactory16K(int ptype); const char* name(); - int samplerate(); - int payloadType(); - PCodec create(); + int samplerate(); + int payloadType(); + PCodec create(); protected: int mPType; }; - - class IsacFactory32K: public Factory + + class IsacFactory32K : public Factory { public: IsacFactory32K(int ptype); const char* name(); - int samplerate(); - int payloadType(); - PCodec create(); + int samplerate(); + int payloadType(); + PCodec create(); protected: int mPType; @@ -230,16 +226,15 @@ public: IsacCodec(int sampleRate); ~IsacCodec(); - - Info info() override; - EncodeResult encode(std::span input, std::span output) override; - DecodeResult decode(std::span input, std::span output) override; - size_t plc(int lostFrames, std::span output) override; + Info info() override; + + EncodeResult encode(std::span input, std::span output) override; + DecodeResult decode(std::span input, std::span output) override; + size_t plc(int lostFrames, std::span output) override; }; - /// GSM MIME name #define GSM_MIME_NAME "gsm" @@ -262,10 +257,10 @@ public: /*! - * GSM codec wrapper. Based on implementation located in libgsm directory. - * @see IMediaCodec - */ -class GsmCodec: public Codec + * GSM codec wrapper. Based on implementation located in libgsm directory. + * @see IMediaCodec + */ +class GsmCodec : public Codec { public: enum class Type @@ -275,24 +270,25 @@ public: Bytes_31, Bytes_65 }; + protected: - struct gsm_state * mGSM; /// Pointer to codec context - Type mCodecType; + struct gsm_state* mGSM; /// Pointer to codec context + Type mCodecType; public: - class GsmFactory: public Factory + class GsmFactory : public Factory { protected: - int mPayloadType; + int mPayloadType; Type mCodecType; public: GsmFactory(Type codecType = Type::Bytes_33, int pt = GSM_PAYLOAD_TYPE); const char* name(); - int samplerate(); - int payloadType(); - PCodec create(); + int samplerate(); + int payloadType(); + PCodec create(); }; /*! Default constructor. Initializes codec context's pointer to NULL. */ @@ -301,11 +297,11 @@ public: /*! Destructor. */ ~GsmCodec(); - Info info() override; + Info info() override; EncodeResult encode(std::span input, std::span output) override; DecodeResult decode(std::span input, std::span output) override; - size_t plc(int lostFrames, std::span output) override; + size_t plc(int lostFrames, std::span output) override; }; /// GSM MIME name @@ -326,40 +322,40 @@ public: /// GSM bitrate (bits/sec) #define G722_BITRATE 64000 -class G722Codec: public Codec +class G722Codec : public Codec { protected: void* mEncoder; void* mDecoder; public: - class G722Factory: public Factory + class G722Factory : public Factory { public: G722Factory(); const char* name(); - int samplerate(); - int payloadType(); - PCodec create(); + int samplerate(); + int payloadType(); + PCodec create(); }; G722Codec(); ~G722Codec(); - Info info() override; + Info info() override; EncodeResult encode(std::span input, std::span output) override; DecodeResult decode(std::span input, std::span output) override; - size_t plc(int lostFrames, std::span output) override; + size_t plc(int lostFrames, std::span output) override; }; -class GsmHrCodec: public Codec +class GsmHrCodec : public Codec { protected: void* mDecoder = nullptr; public: - class GsmHrFactory: public Factory + class GsmHrFactory : public Factory { protected: int mPtype; @@ -368,20 +364,20 @@ public: GsmHrFactory(int ptype); const char* name() override; - int samplerate() override; - int payloadType() override; - PCodec create() override; + int samplerate() override; + int payloadType() override; + PCodec create() override; }; GsmHrCodec(); ~GsmHrCodec() override; - Info info() override; + Info info() override; - EncodeResult encode(std::span input, std::span output) override; - DecodeResult decode(std::span input, std::span output) override; - size_t plc(int lostFrames, std::span output) override; + EncodeResult encode(std::span input, std::span output) override; + DecodeResult decode(std::span input, std::span output) override; + size_t plc(int lostFrames, std::span output) override; }; -} +} // namespace MT #endif diff --git a/src/engine/media/MT_AudioReceiver.cpp b/src/engine/media/MT_AudioReceiver.cpp index 9796d899..6cca4480 100644 --- a/src/engine/media/MT_AudioReceiver.cpp +++ b/src/engine/media/MT_AudioReceiver.cpp @@ -16,8 +16,9 @@ #include #include -#if !defined(TARGET_ANDROID) && !defined(TARGET_OPENWRT) && !defined(TARGET_WIN) && !defined(TARGET_RPI) && defined(USE_AMR_CODEC) -# include "MT_AmrCodec.h" +#if !defined(TARGET_ANDROID) && !defined(TARGET_OPENWRT) && !defined(TARGET_WIN) && !defined(TARGET_RPI) && \ + defined(USE_AMR_CODEC) +#include "MT_AmrCodec.h" #endif #include @@ -27,9 +28,11 @@ using namespace MT; // ----------------- RtpBuffer::Packet -------------- -RtpBuffer::Packet::Packet(const std::shared_ptr& packet, std::chrono::milliseconds timelength, int samplerate) - :mRtp(packet), mTimelength(timelength), mSamplerate(samplerate) -{} +RtpBuffer::Packet::Packet(const std::shared_ptr& packet, std::chrono::milliseconds timelength, + int samplerate) + : mRtp(packet), mTimelength(timelength), mSamplerate(samplerate) +{ +} const std::shared_ptr& RtpBuffer::Packet::rtp() const { @@ -57,15 +60,13 @@ std::vector& RtpBuffer::Packet::pcm() } // ------------ RtpBuffer ---------------- -RtpBuffer::RtpBuffer(Statistics& stat) - :mStat(stat) -{ -} +RtpBuffer::RtpBuffer(Statistics& stat) : mStat(stat) {} RtpBuffer::~RtpBuffer() { if (mAddCounter) - ICELogDebug(<< "Number of add packets: " << mAddCounter << ", number of retrieved packets " << mReturnedCounter); + ICELogDebug(<< "Number of add packets: " << mAddCounter << ", number of retrieved packets " + << mReturnedCounter); } void RtpBuffer::setHigh(std::chrono::milliseconds t) @@ -109,7 +110,8 @@ bool SequenceSort(const std::shared_ptr& p1, const std::share return p1->rtp()->GetExtendedSequenceNumber() < p2->rtp()->GetExtendedSequenceNumber(); } -std::shared_ptr RtpBuffer::add(const std::shared_ptr& packet, std::chrono::milliseconds timelength, int rate) +std::shared_ptr RtpBuffer::add(const std::shared_ptr& packet, + std::chrono::milliseconds timelength, int rate) { if (!packet) return std::shared_ptr(); @@ -137,7 +139,7 @@ std::shared_ptr RtpBuffer::add(const std::shared_ptrGetExtendedSequenceNumber(); - for (auto& p: mPacketList) + for (auto& p : mPacketList) { unsigned seqno = p->rtp()->GetExtendedSequenceNumber(); @@ -196,16 +198,15 @@ void RtpBuffer::trimToHighWater(size_t maxPackets) // high-water mark (mHigh, when set) or, if maxPackets != 0, the packet-count // cap. Always keep at least one packet so loss/gap accounting has a reference. while (mPacketList.size() > 1 && - ((0ms != mHigh && total > mHigh) || - (maxPackets != 0 && mPacketList.size() > maxPackets))) + ((0ms != mHigh && total > mHigh) || (maxPackets != 0 && mPacketList.size() > maxPackets))) { - ICELogMedia( << "Dropping RTP packets from jitter buffer"); + ICELogMedia(<< "Dropping RTP packets from jitter buffer"); total -= mPacketList.front()->timelength(); // Before advancing mLastSeqno over the dropped packet, record a loss event for any // sequence-number gap on the wire between the previous packet we saw and this one. // Without this, drops silently mask real packet loss that happened between them. - auto droppingPacket = mPacketList.front(); + auto droppingPacket = mPacketList.front(); uint32_t droppingSeq = droppingPacket->rtp()->GetExtendedSequenceNumber(); if (mLastSeqno) { @@ -241,7 +242,7 @@ void RtpBuffer::trimToHighWater(size_t maxPackets) RtpBuffer::FetchResult RtpBuffer::fetch() { - Lock l(mGuard); + Lock l(mGuard); FetchResult result; @@ -268,11 +269,11 @@ RtpBuffer::FetchResult RtpBuffer::fetch() else { // Current sequence number ? - auto& packet = *mPacketList.front(); + auto& packet = *mPacketList.front(); uint32_t seqno = packet.rtp()->GetExtendedSequenceNumber(); // Gap between new packet and previous on - int gap = (int64_t)seqno - (int64_t)*mLastSeqno - 1; + int gap = (int64_t)seqno - (int64_t)*mLastSeqno - 1; if (gap > 0) { // std::cout << "Increase the packet loss for SSRC " << std::hex << mSsrc << std::endl; @@ -290,8 +291,9 @@ RtpBuffer::FetchResult RtpBuffer::fetch() .mTimestampEnd = gapEnd}); } - // ToDo: here we should decide smth - 2-packet gap shoud report Status::Gap two times at least; but current implementation gives only one. - // It is not big problem - as gap is detected when we have smth to return usually + // ToDo: here we should decide smth - 2-packet gap shoud report Status::Gap two times at least; but + // current implementation gives only one. It is not big problem - as gap is detected when we have + // smth to return usually mLastSeqno = seqno; mLastReceiveTime = packet.rtp()->GetReceiveTime(); result = {FetchResult::Status::Gap}; @@ -343,7 +345,7 @@ RtpBuffer::FetchResult RtpBuffer::fetch() std::chrono::milliseconds RtpBuffer::findTimelength() { std::chrono::milliseconds r = 0ms; - for (const auto& p: mPacketList) + for (const auto& p : mPacketList) r += p->timelength(); return r; } @@ -356,9 +358,9 @@ std::shared_ptr RtpBuffer::peekFront() const std::chrono::milliseconds RtpBuffer::bufferedTime() const { - Lock l(mGuard); + Lock l(mGuard); std::chrono::milliseconds r = 0ms; - for (const auto& p: mPacketList) + for (const auto& p : mPacketList) r += p->timelength(); return r; } @@ -374,16 +376,14 @@ int RtpBuffer::getNumberOfAddPackets() const } //-------------- Receiver --------------- -Receiver::Receiver(Statistics& stat) - :mStat(stat) -{} +Receiver::Receiver(Statistics& stat) : mStat(stat) {} -Receiver::~Receiver() -{} +Receiver::~Receiver() {} //-------------- AudioReceiver ---------------- -AudioReceiver::AudioReceiver(const CodecList::Settings& settings, MT::Statistics &stat) - :Receiver(stat), mRtpBuffer(stat), mDtmfBuffer(stat), mCodecSettings(settings), mCodecList(settings), mDtmfReceiver(stat) +AudioReceiver::AudioReceiver(const CodecList::Settings& settings, MT::Statistics& stat) + : Receiver(stat), mRtpBuffer(stat), mDtmfBuffer(stat), mCodecSettings(settings), mCodecList(settings), + mDtmfReceiver(stat) { // Init codecs mCodecList.setSettings(settings); @@ -449,7 +449,8 @@ void AudioReceiver::setCodecSettings(const CodecList::Settings& codecSettings) const bool lazy = mCodecSettings.mLazyCodecMap; mCodecSettings = codecSettings; mCodecSettings.mLazyCodecMap = lazy; - mCodecList.setSettings(mCodecSettings); // This builds factory list with proper payload types according to payload types in settings + mCodecList.setSettings( + mCodecSettings); // This builds factory list with proper payload types according to payload types in settings // Rebuild codec map from factory list mCodecList.fillCodecMap(mCodecMap); @@ -485,10 +486,7 @@ Codec* AudioReceiver::add(const std::shared_ptr& p) Codec* codec = nullptr; // Estimate time length - int time_length = 0, - samplerate = 8000, - payloadLength = p->GetPayloadLength(), - ptype = p->GetPayloadType(); + int time_length = 0, samplerate = 8000, payloadLength = p->GetPayloadLength(), ptype = p->GetPayloadType(); // ICELogMedia(<< "Adding packet No " << p->GetSequenceNumber()); @@ -522,8 +520,7 @@ Codec* AudioReceiver::add(const std::shared_ptr& p) if (!codec) time_length = 10; - else - if (!codec->rtpLength()) + else if (!codec->rtpLength()) time_length = codec->frameTime(); else time_length = lround(double(payloadLength) / codec->rtpLength() * codec->frameTime()); @@ -543,14 +540,14 @@ Codec* AudioReceiver::add(const std::shared_ptr& p) if (payloadLength >= 1 && payloadLength <= 6 && (ptype == 0 || ptype == 8)) time_length = mLastPacketTimeLength ? mLastPacketTimeLength : 20; else - // Check if packet is too short from time length side - smth strange with found codec... - if (time_length < 2) - { - // It will cause statistics to report about bad RTP packet - // I have to replay last packet payload here to avoid report about lost packet - mRtpBuffer.add(p, std::chrono::milliseconds(time_length), samplerate); - return nullptr; - } + // Check if packet is too short from time length side - smth strange with found codec... + if (time_length < 2) + { + // It will cause statistics to report about bad RTP packet + // I have to replay last packet payload here to avoid report about lost packet + mRtpBuffer.add(p, std::chrono::milliseconds(time_length), samplerate); + return nullptr; + } // Queue packet to buffer mRtpBuffer.add(p, std::chrono::milliseconds(time_length), samplerate).get(); @@ -618,7 +615,8 @@ void AudioReceiver::produceCNG(std::chrono::milliseconds length, Audio::DataWind if (options.mSkipDecode) mDecodedLength = 0; else - mDecodedLength = cng().produce(mCodec->samplerate(), tail, reinterpret_cast(mDecodedFrame.data()), false); + mDecodedLength = + cng().produce(mCodec->samplerate(), tail, reinterpret_cast(mDecodedFrame.data()), false); if (mDecodedLength) processDecoded(output, options); @@ -636,13 +634,13 @@ AudioReceiver::DecodeResult AudioReceiver::decodeGapTo(Audio::DataWindow& output { // Synthesize comfort noise. It will be done on AUDIO_SAMPLERATE rate directly to mResampledFrame buffer. // Do not forget to send this noise to analysis - mDecodedLength = cng().produce(mCodec->samplerate(), mLastPacketTimeLength, reinterpret_cast(mDecodedFrame.data()), false); + mDecodedLength = cng().produce(mCodec->samplerate(), mLastPacketTimeLength, + reinterpret_cast(mDecodedFrame.data()), false); } else decodePacketTo(output, options, mCngPacket); } - else - if (mCodec && mFrameCount && !mCodecSettings.mSkipDecode) + else if (mCodec && mFrameCount && !mCodecSettings.mSkipDecode) { // Conceal the gap into mDecodedFrame/mDecodedLength. if (options.mSkipDecode) @@ -662,8 +660,8 @@ AudioReceiver::DecodeResult AudioReceiver::decodeGapTo(Audio::DataWindow& output auto codecIter = mCodecMap.find(next->rtp()->GetPayloadType()); if (codecIter != mCodecMap.end() && codecIter->second == mCodec) { - mDecodedLength = mCodec->fec({next->rtp()->GetPayloadData(), (size_t)next->rtp()->GetPayloadLength()}, - concealBuffer); + mDecodedLength = mCodec->fec( + {next->rtp()->GetPayloadData(), (size_t)next->rtp()->GetPayloadLength()}, concealBuffer); } } @@ -675,8 +673,8 @@ AudioReceiver::DecodeResult AudioReceiver::decodeGapTo(Audio::DataWindow& output if (!mDecodedLength) { // PLC unsupported or failed - substitute one frame of silence. - size_t frameBytes = (size_t)mCodec->frameTime() * mCodec->samplerate() / 1000 - * sizeof(short) * std::max(1, mCodec->channels()); + size_t frameBytes = (size_t)mCodec->frameTime() * mCodec->samplerate() / 1000 * sizeof(short) * + std::max(1, mCodec->channels()); frameBytes = std::min(frameBytes, concealBuffer.size_bytes()); mDecodedLength = frameBytes; memset(mDecodedFrame.data(), 0, mDecodedLength); @@ -703,48 +701,51 @@ AudioReceiver::DecodeResult AudioReceiver::decodeGapTo(Audio::DataWindow& output if (mDecodedLength) { processDecoded(output, options); - return {.mStatus = DecodeResult::Status::Ok, .mSamplerate = mCodec->samplerate(), .mChannels = mCodec->channels()}; + return { + .mStatus = DecodeResult::Status::Ok, .mSamplerate = mCodec->samplerate(), .mChannels = mCodec->channels()}; } else return {.mStatus = DecodeResult::Status::Skip}; } -AudioReceiver::DecodeResult AudioReceiver::decodePacketTo(Audio::DataWindow& output, DecodeOptions options, const std::shared_ptr& packet) +AudioReceiver::DecodeResult AudioReceiver::decodePacketTo(Audio::DataWindow& output, DecodeOptions options, + const std::shared_ptr& packet) { if (!packet || !packet->rtp()) return {DecodeResult::Status::Skip}; DecodeResult result = {.mStatus = DecodeResult::Status::Skip}; - auto& rtp = *packet->rtp(); // Syntax sugar + auto& rtp = *packet->rtp(); // Syntax sugar mFailedCount = 0; - // Check if we need to emit silence - it may happen in the case if next packet has RTP timestamp much beyond the previous one; maybe DTX was active. + // Check if we need to emit silence - it may happen in the case if next packet has RTP timestamp much beyond the + // previous one; maybe DTX was active. if (mLastPacketTimestamp && mLastPacketTimeLength && mCodec) { - int units = rtp.GetTimestamp() - *mLastPacketTimestamp; - int milliseconds = units / (mCodec->samplerate() / 1000); - if (milliseconds > mLastPacketTimeLength) - { - auto silenceLength = std::chrono::milliseconds(milliseconds - mLastPacketTimeLength); - ICELogDebug(<< "Emit " << silenceLength << " silence while requested " << options.mElapsed); - silenceLength = std::min(silenceLength, options.mElapsed); - if (mCngPacket && options.mFillGapByCNG) - produceCNG(silenceLength, output, options); - else - produceSilence(silenceLength, output, options); - } - } + int units = rtp.GetTimestamp() - *mLastPacketTimestamp; + int milliseconds = units / (mCodec->samplerate() / 1000); + if (milliseconds > mLastPacketTimeLength) + { + auto silenceLength = std::chrono::milliseconds(milliseconds - mLastPacketTimeLength); + ICELogDebug(<< "Emit " << silenceLength << " silence while requested " << options.mElapsed); + silenceLength = std::min(silenceLength, options.mElapsed); + if (mCngPacket && options.mFillGapByCNG) + produceCNG(silenceLength, output, options); + else + produceSilence(silenceLength, output, options); + } + } mLastPacketTimestamp = rtp.GetTimestamp(); // Find codec by payload type - int ptype = rtp.GetPayloadType(); + int ptype = rtp.GetPayloadType(); // Look into mCodecMap if exists auto codecIter = mCodecMap.find(ptype); if (codecIter == mCodecMap.end()) - return {}; + return {}; if (!codecIter->second) codecIter->second = mCodecList.createCodecByPayloadType(ptype); @@ -756,7 +757,8 @@ AudioReceiver::DecodeResult AudioReceiver::decodePacketTo(Audio::DataWindow& out result.mSamplerate = mCodec->samplerate(); // Check if it is CNG packet - if (((ptype == 0 || ptype == 8) && rtp.GetPayloadLength() >= 1 && rtp.GetPayloadLength() <= 6) || rtp.GetPayloadType() == 13) + if (((ptype == 0 || ptype == 8) && rtp.GetPayloadLength() >= 1 && rtp.GetPayloadLength() <= 6) || + rtp.GetPayloadType() == 13) { if (options.mSkipDecode) mDecodedLength = 0; @@ -767,7 +769,8 @@ AudioReceiver::DecodeResult AudioReceiver::decodePacketTo(Audio::DataWindow& out cng().decode3389(rtp.GetPayloadData(), rtp.GetPayloadLength()); // Emit CNG mLastPacketLength milliseconds - mDecodedLength = cng().produce(mCodec->samplerate(), mLastPacketTimeLength, (short*)mDecodedFrame.data(), true); + mDecodedLength = + cng().produce(mCodec->samplerate(), mLastPacketTimeLength, (short*)mDecodedFrame.data(), true); if (mDecodedLength) processDecoded(output, options); } @@ -783,7 +786,7 @@ AudioReceiver::DecodeResult AudioReceiver::decodePacketTo(Audio::DataWindow& out size_t payload_length = rtp.GetPayloadLength(); size_t rtp_frame_length = mCodec->rtpLength(); - int tail = rtp_frame_length ? payload_length % rtp_frame_length : 0; + int tail = rtp_frame_length ? payload_length % rtp_frame_length : 0; if (!tail) { @@ -795,15 +798,17 @@ AudioReceiver::DecodeResult AudioReceiver::decodePacketTo(Audio::DataWindow& out mLastPacketTimeLength = mFrameCount * mCodec->frameTime(); // Decode - for (int i=0; irtpLength(), (size_t)frameLength}; - auto codecOutput = std::span{(uint8_t*)mDecodedFrame.data(), mDecodedFrame.size() * sizeof(int16_t)}; + auto codecInput = + std::span{rtp.GetPayloadData() + i * mCodec->rtpLength(), (size_t)frameLength}; + auto codecOutput = + std::span{(uint8_t*)mDecodedFrame.data(), mDecodedFrame.size() * sizeof(int16_t)}; auto r = mCodec->decode(codecInput, codecOutput); mDecodedLength = r.mDecoded; if (mDecodedLength > 0) @@ -832,8 +837,8 @@ AudioReceiver::DecodeResult AudioReceiver::decodePacketTo(Audio::DataWindow& out AudioReceiver::DecodeResult AudioReceiver::decodeEmptyTo(Audio::DataWindow& output, DecodeOptions options) { // There are two cases - // First is we have no ready time estimated how much audio should be emitted i.e. audio is decoded right after the next packet arrives. - // In this case we just skip the analysis - we should not be called in this situation + // First is we have no ready time estimated how much audio should be emitted i.e. audio is decoded right after the + // next packet arrives. In this case we just skip the analysis - we should not be called in this situation if (options.mElapsed == 0ms || !mCodec) return {.mStatus = DecodeResult::Status::Skip}; @@ -851,7 +856,8 @@ AudioReceiver::DecodeResult AudioReceiver::decodeEmptyTo(Audio::DataWindow& outp // the CNG decoder writes straight into its buffer. size_t bytesPerMs = (size_t)fmt.rate() / 1000 * sizeof(short) * fmt.channels(); size_t room = output.capacity() - output.filled(); - int ms = bytesPerMs ? (int)std::min(options.mElapsed.count(), (int64_t)(room / bytesPerMs)) : 0; + int ms = + bytesPerMs ? (int)std::min(options.mElapsed.count(), (int64_t)(room / bytesPerMs)) : 0; if (ms <= 0) return {.mStatus = DecodeResult::Status::Skip}; auto produced = cng().produce(fmt.rate(), ms, (short*)(output.mutableData() + output.filled()), false); @@ -918,11 +924,8 @@ void MT::AudioReceiver::logReceiveHeartbeat() size_t dropDelta = mStat.mPacketDropped - mStatDropLast; ICELogInfo(<< "[rx-heartbeat] buffered=" << mRtpBuffer.bufferedTime().count() << "ms" - << " packets=" << mRtpBuffer.getCount() - << " underruns/5s=" << mUnderrunCount - << " gaps/5s=" << mGapCount - << " loss/5s=" << lossDelta - << " dropped/5s=" << dropDelta); + << " packets=" << mRtpBuffer.getCount() << " underruns/5s=" << mUnderrunCount << " gaps/5s=" << mGapCount + << " loss/5s=" << lossDelta << " dropped/5s=" << dropDelta); mStatLogLast = t; mUnderrunCount = 0; @@ -938,7 +941,8 @@ void MT::AudioReceiver::updateDecodingTimeStatistics() else { auto t = std::chrono::steady_clock::now(); - mStat.mDecodingInterval.process(std::chrono::duration_cast(t - *mDecodeTimestamp).count()); + mStat.mDecodingInterval.process( + std::chrono::duration_cast(t - *mDecodeTimestamp).count()); mDecodeTimestamp = t; } } @@ -946,7 +950,7 @@ void MT::AudioReceiver::updateDecodingTimeStatistics() AudioReceiver::DecodeResult AudioReceiver::getAudioTo(Audio::DataWindow& output, DecodeOptions options) { // ICELogDebug(<< "getAudioTo() for " << options.mElapsed); - assert (options.mElapsed != 0ms); + assert(options.mElapsed != 0ms); // First decode on this receiver: allocate the scratch buffers. Network-MOS-only // streams never reach this point, so they never pay for them. @@ -961,7 +965,7 @@ AudioReceiver::DecodeResult AudioReceiver::getAudioTo(Audio::DataWindow& output, processDtmf(); // How much time length audio we produced here - auto produced = 0ms; + auto produced = 0ms; Audio::Format fmt; // Have we anything from the previous decode attempts ? @@ -993,9 +997,17 @@ AudioReceiver::DecodeResult AudioReceiver::getAudioTo(Audio::DataWindow& output, // Decode to mAvailable buffer switch (fr.mStatus) { - case RtpBuffer::FetchResult::Status::Gap: mGapCount++; result = decodeGapTo(mAvailable, options.decreaseElapsedBy(produced)); break; - case RtpBuffer::FetchResult::Status::NoPacket: result = decodeEmptyTo(mAvailable, options.decreaseElapsedBy(produced)); break; - case RtpBuffer::FetchResult::Status::RegularPacket: result = decodePacketTo(mAvailable, options.decreaseElapsedBy(produced), fr.mPacket); updateDecodeIntervalStatistics(); break; + case RtpBuffer::FetchResult::Status::Gap: + mGapCount++; + result = decodeGapTo(mAvailable, options.decreaseElapsedBy(produced)); + break; + case RtpBuffer::FetchResult::Status::NoPacket: + result = decodeEmptyTo(mAvailable, options.decreaseElapsedBy(produced)); + break; + case RtpBuffer::FetchResult::Status::RegularPacket: + result = decodePacketTo(mAvailable, options.decreaseElapsedBy(produced), fr.mPacket); + updateDecodeIntervalStatistics(); + break; default: assert(0); } @@ -1005,8 +1017,8 @@ AudioReceiver::DecodeResult AudioReceiver::getAudioTo(Audio::DataWindow& output, break; // No sense to continue - we have no information at all fmt = options.mResampleToMainRate ? Audio::Format(AUDIO_SAMPLERATE, 1) : mCodec->getAudioFormat(); - result.mSamplerate = fmt.rate(); - result.mChannels = fmt.channels(); + result.mSamplerate = fmt.rate(); + result.mChannels = fmt.channels(); // How much milliseconds we have in audio buffer ? auto bufferAvailable = mAvailable.getTimeLength(fmt); @@ -1026,7 +1038,8 @@ AudioReceiver::DecodeResult AudioReceiver::getAudioTo(Audio::DataWindow& output, } mProducedAudio += produced; - // ICELogDebug(<< "Requested " << options.mElapsed << ", produced " << produced << ", remains " << mAvailable.getTimeLength(fmt) << ", packets " << getRtpBuffer().getCount()); + // ICELogDebug(<< "Requested " << options.mElapsed << ", produced " << produced << ", remains " << + // mAvailable.getTimeLength(fmt) << ", packets " << getRtpBuffer().getCount()); logReceiveHeartbeat(); return result; @@ -1059,21 +1072,31 @@ void AudioReceiver::makeMonoAndResample(int rate, int channels) if (channels != AUDIO_CHANNELS) { if (channels == 1) - mConvertedLength = Audio::ChannelConverter::monoToStereo(mDecodedFrame.data(), mDecodedLength, mConvertedFrame.data(), mDecodedLength * 2); + mConvertedLength = Audio::ChannelConverter::monoToStereo(mDecodedFrame.data(), mDecodedLength, + mConvertedFrame.data(), mDecodedLength * 2); else - mDecodedLength = Audio::ChannelConverter::stereoToMono(mDecodedFrame.data(), mDecodedLength, mDecodedFrame.data(), mDecodedLength / 2); + mDecodedLength = Audio::ChannelConverter::stereoToMono(mDecodedFrame.data(), mDecodedLength, + mDecodedFrame.data(), mDecodedLength / 2); } - void* frames = mConvertedLength ? (void*)mConvertedFrame.data() : (void*)mDecodedFrame.data(); - unsigned length = mConvertedLength ? mConvertedLength : mDecodedLength; + void* frames = mConvertedLength ? (void*)mConvertedFrame.data() : (void*)mDecodedFrame.data(); + unsigned length = mConvertedLength ? mConvertedLength : mDecodedLength; Audio::Resampler* r = nullptr; switch (rate) { - case 8000: r = &mResampler8; break; - case 16000: r = &mResampler16; break; - case 32000: r = &mResampler32; break; - case 48000: r = &mResampler48; break; + case 8000: + r = &mResampler8; + break; + case 16000: + r = &mResampler16; + break; + case 32000: + r = &mResampler32; + break; + case 48000: + r = &mResampler48; + break; default: memcpy(mResampledFrame.data(), frames, length); mResampledLength = length; @@ -1081,7 +1104,8 @@ void AudioReceiver::makeMonoAndResample(int rate, int channels) } size_t processedInput = 0; - mResampledLength = r->processBuffer(frames, length, processedInput, mResampledFrame.data(), r->getDestLength(length)); + mResampledLength = + r->processBuffer(frames, length, processedInput, mResampledFrame.data(), r->getDestLength(length)); // processedInput result value is ignored - it is always equal to length as internal sample rate is 8/16/32/48K } @@ -1093,7 +1117,8 @@ Codec* AudioReceiver::findCodec(int payloadType) void AudioReceiver::updateAmrCodecStats(Codec* c) { -#if !defined(TARGET_ANDROID) && !defined(TARGET_OPENWRT) && !defined(TARGET_WIN) && !defined(TARGET_RPI) && defined(USE_AMR_CODEC) +#if !defined(TARGET_ANDROID) && !defined(TARGET_OPENWRT) && !defined(TARGET_WIN) && !defined(TARGET_RPI) && \ + defined(USE_AMR_CODEC) AmrNbCodec* nb = dynamic_cast(c); AmrWbCodec* wb = dynamic_cast(c); @@ -1102,8 +1127,7 @@ void AudioReceiver::updateAmrCodecStats(Codec* c) mStat.mBitrateSwitchCounter = nb->getSwitchCounter(); mStat.mCng = nb->getCngCounter(); } - else - if (wb != nullptr) + else if (wb != nullptr) { mStat.mBitrateSwitchCounter = wb->getSwitchCounter(); mStat.mCng = wb->getCngCounter(); @@ -1114,7 +1138,8 @@ void AudioReceiver::updateAmrCodecStats(Codec* c) int AudioReceiver::getSize() const { int result = 0; - result += sizeof(*this) + mResampler8.getSize() + mResampler16.getSize() + mResampler32.getSize() + mResampler48.getSize(); + result += sizeof(*this) + mResampler8.getSize() + mResampler16.getSize() + mResampler32.getSize() + + mResampler48.getSize(); if (mCodec) ; // ToDo: need the way to calculate size of codec instances @@ -1133,18 +1158,17 @@ AudioReceiver::MediaInfo AudioReceiver::infoFor(jrtplib::RTPPacket& p) if (codec->rtpLength() != 0) { int frameCount = static_cast(p.GetPayloadLength() / codec->rtpLength()); - if (p.GetPayloadType() == 9/*G729A silence*/ && p.GetPayloadLength() % codec->rtpLength()) + if (p.GetPayloadType() == 9 /*G729A silence*/ && p.GetPayloadLength() % codec->rtpLength()) frameCount++; packetTime = std::chrono::milliseconds(frameCount * codec->frameTime()); } - else - if (typeid(*codec) == typeid(OpusCodec)) + else if (typeid(*codec) == typeid(OpusCodec)) { OpusCodec* oc = dynamic_cast(codec); assert(oc); size_t samplesCount = oc->getNumberOfSamples({p.GetPayloadData(), p.GetPayloadLength()}); - int sampleratePerMs = codec->samplerate() / 1000; + int sampleratePerMs = codec->samplerate() / 1000; packetTime = std::chrono::milliseconds(samplesCount / sampleratePerMs); } else @@ -1161,18 +1185,15 @@ void AudioReceiver::updateDecodeIntervalStatistics() if (mLastDecodeTimestamp) { mIntervalBetweenDecode += std::chrono::duration_cast(now - *mLastDecodeTimestamp); - mDecodeCount ++; + mDecodeCount++; } mLastDecodeTimestamp = now; } // ----------------------- DtmfReceiver ------------------- -DtmfReceiver::DtmfReceiver(Statistics& stat) - :Receiver(stat) -{} +DtmfReceiver::DtmfReceiver(Statistics& stat) : Receiver(stat) {} -DtmfReceiver::~DtmfReceiver() -{} +DtmfReceiver::~DtmfReceiver() {} void DtmfReceiver::add(const std::shared_ptr& p) { @@ -1192,8 +1213,8 @@ void DtmfReceiver::add(const std::shared_ptr& p) mCallback(ev.mTone); // Queue statistics item - mStat.mDtmf2833Timeline.emplace_back(Dtmf2833Event{.mTone = ev.mTone, - .mTimestamp = RtpHelper::toMicroseconds(p->GetReceiveTime())}); + mStat.mDtmf2833Timeline.emplace_back( + Dtmf2833Event{.mTone = ev.mTone, .mTimestamp = RtpHelper::toMicroseconds(p->GetReceiveTime())}); } mEvent = ev.mTone; diff --git a/src/engine/media/MT_AudioReceiver.h b/src/engine/media/MT_AudioReceiver.h index 1156b344..ce4648b1 100644 --- a/src/engine/media/MT_AudioReceiver.h +++ b/src/engine/media/MT_AudioReceiver.h @@ -37,21 +37,21 @@ public: Packet(const std::shared_ptr& packet, std::chrono::milliseconds timelen, int samplerate); const std::shared_ptr& rtp() const; - std::chrono::milliseconds timelength() const; - int samplerate() const; + std::chrono::milliseconds timelength() const; + int samplerate() const; - const std::vector& pcm() const; - std::vector& pcm(); + const std::vector& pcm() const; + std::vector& pcm(); - const std::chrono::microseconds& timestamp() const; - std::chrono::microseconds& timestamp(); + const std::chrono::microseconds& timestamp() const; + std::chrono::microseconds& timestamp(); protected: std::shared_ptr mRtp; - std::chrono::milliseconds mTimelength = 0ms; - int mSamplerate = 0; - std::vector mPcm; - std::chrono::microseconds mTimestamp = 0us; + std::chrono::milliseconds mTimelength = 0ms; + int mSamplerate = 0; + std::vector mPcm; + std::chrono::microseconds mTimestamp = 0us; }; struct FetchResult @@ -63,16 +63,19 @@ public: NoPacket }; - Status mStatus = Status::NoPacket; + Status mStatus = Status::NoPacket; std::shared_ptr mPacket; - std::string toString() const + std::string toString() const { switch (mStatus) { - case Status::RegularPacket: return "packet"; - case Status::Gap: return "gap"; - case Status::NoPacket: return "empty"; + case Status::RegularPacket: + return "packet"; + case Status::Gap: + return "gap"; + case Status::NoPacket: + return "empty"; } } }; @@ -80,42 +83,43 @@ public: RtpBuffer(Statistics& stat); ~RtpBuffer(); - unsigned ssrc() const; - void setSsrc(unsigned ssrc); + unsigned ssrc() const; + void setSsrc(unsigned ssrc); - void setHigh(std::chrono::milliseconds t); + void setHigh(std::chrono::milliseconds t); std::chrono::milliseconds high() const; - void setLow(std::chrono::milliseconds t); + void setLow(std::chrono::milliseconds t); std::chrono::milliseconds low() const; - void setPrebuffer(std::chrono::milliseconds t); + void setPrebuffer(std::chrono::milliseconds t); std::chrono::milliseconds prebuffer() const; - int getNumberOfReturnedPackets() const; - int getNumberOfAddPackets() const; + int getNumberOfReturnedPackets() const; + int getNumberOfAddPackets() const; std::chrono::milliseconds findTimelength(); - int getCount() const; + int getCount() const; // Returns false if packet was not add - maybe too old or too new or duplicate - std::shared_ptr add(const std::shared_ptr& packet, std::chrono::milliseconds timelength, int rate); + std::shared_ptr add(const std::shared_ptr& packet, std::chrono::milliseconds timelength, + int rate); typedef std::vector> ResultList; - typedef std::shared_ptr PResultList; + typedef std::shared_ptr PResultList; - FetchResult fetch(); + FetchResult fetch(); // Return the oldest buffered packet without removing it, or nullptr when empty. // After fetch() reports a Gap the post-gap packet stays at the front, so this // lets the decoder peek at it (e.g. to pull Opus in-band FEC) before it is // fetched and decoded normally on the next call. - std::shared_ptr peekFront() const; + std::shared_ptr peekFront() const; // Thread-safe snapshot of the currently buffered audio duration. Same value as // findTimelength() but taken under the buffer lock, safe to call from the audio // thread while the network thread adds packets (used by the diagnostic heartbeat). - std::chrono::milliseconds bufferedTime() const; + std::chrono::milliseconds bufferedTime() const; // Drop oldest packets so buffered audio stays within the high-water mark, // recording packet-loss events for any sequence gaps crossed (the same @@ -127,29 +131,28 @@ public: // regardless of buffered time. The decode path (fetch()) leaves it 0 so jitter // tolerance stays governed by the time-based high-water mark; the network-only // path passes a small cap since those packets are never decoded. - void trimToHighWater(size_t maxPackets = 0); + void trimToHighWater(size_t maxPackets = 0); protected: - unsigned mSsrc = 0; - std::chrono::milliseconds mHigh = std::chrono::milliseconds(RTP_BUFFER_HIGH), - mLow = std::chrono::milliseconds(RTP_BUFFER_LOW), - mPrebuffer = std::chrono::milliseconds(RTP_BUFFER_PREBUFFER); - int mReturnedCounter = 0, - mAddCounter = 0; + unsigned mSsrc = 0; + std::chrono::milliseconds mHigh = std::chrono::milliseconds(RTP_BUFFER_HIGH), + mLow = std::chrono::milliseconds(RTP_BUFFER_LOW), + mPrebuffer = std::chrono::milliseconds(RTP_BUFFER_PREBUFFER); + int mReturnedCounter = 0, mAddCounter = 0; - mutable Mutex mGuard; + mutable Mutex mGuard; typedef std::vector> PacketList; - PacketList mPacketList; - Statistics& mStat; - bool mFirstPacketWillGo = true; - jrtplib::RTPSourceStats mRtpStats; - std::shared_ptr mFetchedPacket; - std::optional mLastSeqno; - std::optional mLastReceiveTime; + PacketList mPacketList; + Statistics& mStat; + bool mFirstPacketWillGo = true; + jrtplib::RTPSourceStats mRtpStats; + std::shared_ptr mFetchedPacket; + std::optional mLastSeqno; + std::optional mLastReceiveTime; // To calculate average interval between packet add. It is close to jitter but more useful in debugging. - float mLastAddTime = 0.0f; + float mLastAddTime = 0.0f; }; class Receiver @@ -162,11 +165,11 @@ protected: Statistics& mStat; }; -class DtmfReceiver: public Receiver +class DtmfReceiver : public Receiver { private: - char mEvent = 0; - bool mEventEnded = false; + char mEvent = 0; + bool mEventEnded = false; std::chrono::milliseconds mEventStart = 0ms; std::function mCallback; @@ -179,37 +182,35 @@ public: }; -class AudioReceiver: public Receiver +class AudioReceiver : public Receiver { public: AudioReceiver(const CodecList::Settings& codecSettings, Statistics& stat); ~AudioReceiver(); - - // Update codec settings - void setCodecSettings(const CodecList::Settings& codecSettings); - CodecList::Settings& getCodecSettings(); - // Returns false when packet is rejected as illegal. codec parameter will show codec which will be used for decoding. - // Lifetime of pointer to codec is limited by lifetime of AudioReceiver (it is container). - Codec* add(const std::shared_ptr& p); + // Update codec settings + void setCodecSettings(const CodecList::Settings& codecSettings); + CodecList::Settings& getCodecSettings(); + + // Returns false when packet is rejected as illegal. codec parameter will show codec which will be used for + // decoding. Lifetime of pointer to codec is limited by lifetime of AudioReceiver (it is container). + Codec* add(const std::shared_ptr& p); struct DecodeOptions { - bool mRealtimeProcessing = false; // Target PCAP parsing by default - bool mResampleToMainRate = true; // Resample all decoded audio to AUDIO_SAMPLERATE - bool mFillGapByCNG = false; // Use CNG information if available - bool mSkipDecode = false; // Don't do decode, just dry run - fetch packets, remove them from the jitter buffer - std::chrono::milliseconds mElapsed = 0ms; // How much milliseconds should be decoded; zero value means "decode just next packet from the buffer" + bool mRealtimeProcessing = false; // Target PCAP parsing by default + bool mResampleToMainRate = true; // Resample all decoded audio to AUDIO_SAMPLERATE + bool mFillGapByCNG = false; // Use CNG information if available + bool mSkipDecode = false; // Don't do decode, just dry run - fetch packets, remove them from the jitter buffer + std::chrono::milliseconds mElapsed = + 0ms; // How much milliseconds should be decoded; zero value means "decode just next packet from the buffer" DecodeOptions decreaseElapsedBy(std::chrono::milliseconds delta) { - return - { - .mRealtimeProcessing = mRealtimeProcessing, - .mResampleToMainRate = mResampleToMainRate, - .mFillGapByCNG = mFillGapByCNG, - .mSkipDecode = mSkipDecode, - .mElapsed = std::max(mElapsed - delta, 0ms) - }; + return {.mRealtimeProcessing = mRealtimeProcessing, + .mResampleToMainRate = mResampleToMainRate, + .mFillGapByCNG = mFillGapByCNG, + .mSkipDecode = mSkipDecode, + .mElapsed = std::max(mElapsed - delta, 0ms)}; } }; @@ -217,62 +218,65 @@ public: { enum class Status { - Ok, // Decoded ok - Skip, // Just no data - emit silence instead - BadPacket // Error happened during the decode + Ok, // Decoded ok + Skip, // Just no data - emit silence instead + BadPacket // Error happened during the decode }; - Status mStatus = Status::Ok; - int mSamplerate = 0; - int mChannels = 0; + Status mStatus = Status::Ok; + int mSamplerate = 0; + int mChannels = 0; }; DecodeResult getAudioTo(Audio::DataWindow& output, DecodeOptions options); // Looks for codec by payload type - Codec* findCodec(int payloadType); - RtpBuffer& getRtpBuffer() { return mRtpBuffer; } + Codec* findCodec(int payloadType); + RtpBuffer& getRtpBuffer() { return mRtpBuffer; } // Returns size of AudioReceiver's instance in bytes (including size of all data + codecs + etc.) - int getSize() const; + int getSize() const; struct MediaInfo { std::chrono::milliseconds mTimeLength = 0ms; - int mSamplerate = 0; + int mSamplerate = 0; }; MediaInfo infoFor(jrtplib::RTPPacket& p); - void processDtmf(); + void processDtmf(); - void updateDecodingTimeStatistics(); + void updateDecodingTimeStatistics(); protected: // Resolve (and lazily create) the codec for a payload type. Returns null when no // factory handles it. Used by add()/findCodec()/infoFor() so mLazyCodecMap works. - Codec* ensureCodec(int payloadType); + Codec* ensureCodec(int payloadType); // Lazily create the comfort-noise decoder on first use. - CngDecoder& cng(); + CngDecoder& cng(); - RtpBuffer mRtpBuffer; // RTP jitter buffer itself; here are audio packets - RtpBuffer mDtmfBuffer; // These two (mDtmfBuffer / mDtmfReceiver) are for our analyzer stack only; in normal softphone logic DTMF packets goes via SingleAudioStream::mDtmfReceiver - DtmfReceiver mDtmfReceiver; + RtpBuffer mRtpBuffer; // RTP jitter buffer itself; here are audio packets + RtpBuffer mDtmfBuffer; // These two (mDtmfBuffer / mDtmfReceiver) are for our analyzer stack only; in normal + // softphone logic DTMF packets goes via SingleAudioStream::mDtmfReceiver + DtmfReceiver mDtmfReceiver; - CodecMap mCodecMap; - PCodec mCodec; - int mFrameCount = 0; - CodecList::Settings mCodecSettings; - CodecList mCodecList; - JitterStatistics mJitterStats; - std::shared_ptr mCngPacket; + CodecMap mCodecMap; + PCodec mCodec; + int mFrameCount = 0; + CodecList::Settings mCodecSettings; + CodecList mCodecList; + JitterStatistics mJitterStats; + std::shared_ptr mCngPacket; // Lazily created on first CNG use (getAudioTo); its ctor calls WebRtcCng_CreateDec, // which is wasted for the many streams that never decode comfort noise. Access via cng(). - std::unique_ptr mCngDecoder; - size_t mDTXSamplesToEmit = 0; // How much silence (or CNG) should be emited before next RTP packet gets into the action + std::unique_ptr mCngDecoder; + size_t mDTXSamplesToEmit = + 0; // How much silence (or CNG) should be emited before next RTP packet gets into the action - // Already decoded data that can be retrieved without actual decoding - it may happen because of getAudioTo() may be limited by time interval - Audio::DataWindow mAvailable; + // Already decoded data that can be retrieved without actual decoding - it may happen because of getAudioTo() may be + // limited by time interval + Audio::DataWindow mAvailable; // Decode/convert/resample scratch buffers. These were inline arrays // (MT_MAX_DECODEBUFFER * {1,2,1} * int16_t = 256 KB total) carried by every @@ -281,75 +285,72 @@ protected: // getAudioTo() call via ensureDecodeBuffers(); non-decoding streams keep them // empty. Once allocated they are sized to full capacity and reused, so decode // behaviour is unchanged. - std::vector mDecodedFrame; // sized to MT_MAX_DECODEBUFFER - size_t mDecodedLength = 0; + std::vector mDecodedFrame; // sized to MT_MAX_DECODEBUFFER + size_t mDecodedLength = 0; // Buffer to hold data converted to stereo/mono; there is multiplier 2 as it can be stereo audio - std::vector mConvertedFrame; // sized to MT_MAX_DECODEBUFFER * 2 - size_t mConvertedLength = 0; + std::vector mConvertedFrame; // sized to MT_MAX_DECODEBUFFER * 2 + size_t mConvertedLength = 0; // Buffer to hold data resampled to AUDIO_SAMPLERATE - std::vector mResampledFrame; // sized to MT_MAX_DECODEBUFFER - size_t mResampledLength = 0; + std::vector mResampledFrame; // sized to MT_MAX_DECODEBUFFER + size_t mResampledLength = 0; // Last packet time length - int mLastPacketTimeLength = 0; - std::optional mLastPacketTimestamp; + int mLastPacketTimeLength = 0; + std::optional mLastPacketTimestamp; - int mFailedCount = 0; - Audio::Resampler mResampler8, - mResampler16, - mResampler32, - mResampler48; + int mFailedCount = 0; + Audio::Resampler mResampler8, mResampler16, mResampler32, mResampler48; - Audio::PWavFileWriter mDecodedDump; + Audio::PWavFileWriter mDecodedDump; std::optional mDecodeTimestamp; // Time last call happened to codec->decode() - float mIntervalSum = 0.0f; - int mIntervalCount = 0; + float mIntervalSum = 0.0f; + int mIntervalCount = 0; - std::chrono::milliseconds mRequestedAudio = 0ms; - std::chrono::milliseconds mProducedAudio = 0ms; + std::chrono::milliseconds mRequestedAudio = 0ms; + std::chrono::milliseconds mProducedAudio = 0ms; // Lazily allocate the decode/convert/resample scratch buffers (mDecodedFrame, // mConvertedFrame, mResampledFrame) to full capacity on the first decode. A // no-op once allocated. Called at the top of getAudioTo(); network-MOS-only // streams never reach it, so they never pay the 256 KB. - void ensureDecodeBuffers(); + void ensureDecodeBuffers(); // Zero rate will make audio mono but resampling will be skipped - void makeMonoAndResample(int rate, int channels); + void makeMonoAndResample(int rate, int channels); // Resamples, sends to analysis, writes to dump and queues to output decoded frames from mDecodedFrame - void processDecoded(Audio::DataWindow& output, DecodeOptions options); - void produceSilence(std::chrono::milliseconds length, Audio::DataWindow& output, DecodeOptions options); - void produceCNG(std::chrono::milliseconds length, Audio::DataWindow& output, DecodeOptions options); + void processDecoded(Audio::DataWindow& output, DecodeOptions options); + void produceSilence(std::chrono::milliseconds length, Audio::DataWindow& output, DecodeOptions options); + void produceCNG(std::chrono::milliseconds length, Audio::DataWindow& output, DecodeOptions options); // Calculate bitrate switch statistics for AMR codecs - void updateAmrCodecStats(Codec* c); + void updateAmrCodecStats(Codec* c); DecodeResult decodeGapTo(Audio::DataWindow& output, DecodeOptions options); - DecodeResult decodePacketTo(Audio::DataWindow& output, DecodeOptions options, const std::shared_ptr& p); + DecodeResult decodePacketTo(Audio::DataWindow& output, DecodeOptions options, + const std::shared_ptr& p); DecodeResult decodeEmptyTo(Audio::DataWindow& output, DecodeOptions options); std::optional mLastDecodeTimestamp; - std::chrono::microseconds mIntervalBetweenDecode = 0us; - size_t mDecodeCount = 0; - void updateDecodeIntervalStatistics(); + std::chrono::microseconds mIntervalBetweenDecode = 0us; + size_t mDecodeCount = 0; + void updateDecodeIntervalStatistics(); // --- Step 0 diagnostics: periodic receive-path heartbeat --- // Emits jitter-buffer fill level, starvation (underrun) count, gap/loss/drop // deltas every ~5 s so we can tell which impairment mechanism dominates a call. - float mStatLogLast = 0.0f; // now_ms() of last heartbeat; 0 = not started - size_t mUnderrunCount = 0; // silence insertions on an empty/starved buffer since last log - size_t mGapCount = 0; // gap (loss) concealment events since last log - size_t mStatLossLast = 0; // mStat.mPacketLoss at last heartbeat - size_t mStatDropLast = 0; // mStat.mPacketDropped at last heartbeat - void logReceiveHeartbeat(); - + float mStatLogLast = 0.0f; // now_ms() of last heartbeat; 0 = not started + size_t mUnderrunCount = 0; // silence insertions on an empty/starved buffer since last log + size_t mGapCount = 0; // gap (loss) concealment events since last log + size_t mStatLossLast = 0; // mStat.mPacketLoss at last heartbeat + size_t mStatDropLast = 0; // mStat.mPacketDropped at last heartbeat + void logReceiveHeartbeat(); }; -} +} // namespace MT #endif diff --git a/src/engine/media/MT_AudioStream.cpp b/src/engine/media/MT_AudioStream.cpp index 958ae89e..3c29f490 100644 --- a/src/engine/media/MT_AudioStream.cpp +++ b/src/engine/media/MT_AudioStream.cpp @@ -18,13 +18,12 @@ #define LOG_SUBSYSTEM "media" -//#define DUMP_SENDING_AUDIO +// #define DUMP_SENDING_AUDIO using namespace MT; AudioStream::AudioStream(const CodecList::Settings& settings) - :mPacketTime(0), mEncodedTime(0), mCodecSettings(settings), - mRemoteTelephoneCodec(0), mRtpSession(), mTransmittingPayloadType(-1), - mRtpSender(mStat) + : mPacketTime(0), mEncodedTime(0), mCodecSettings(settings), mRemoteTelephoneCodec(0), mRtpSession(), + mTransmittingPayloadType(-1), mRtpSender(mStat) { mOutputBuffer.setCapacity(16384); mCapturedAudio.setCapacity(16384); @@ -36,19 +35,19 @@ AudioStream::AudioStream(const CodecList::Settings& settings) // Configure transmitter jrtplib::RTPExternalTransmissionParams params(&mRtpSender, 0); - jrtplib::RTPSessionParams sessionParams; + jrtplib::RTPSessionParams sessionParams; sessionParams.SetAcceptOwnPackets(true); sessionParams.SetMaximumPacketSize(MT_MAXRTPPACKET); sessionParams.SetResolveLocalHostname(false); sessionParams.SetUsePollThread(false); - sessionParams.SetOwnTimestampUnit(1/8000.0); + sessionParams.SetOwnTimestampUnit(1 / 8000.0); mRtpSession.Create(sessionParams, ¶ms, jrtplib::RTPTransmitter::ExternalProto); mRtpDtmfSession.Create(sessionParams, ¶ms, jrtplib::RTPTransmitter::ExternalProto); // Attach srtp session to sender mRtpSender.setSrtpSession(&mSrtpSession); - //mRtpDump = new RtpDump("d:\\outgoing.rtp"); - //mRtpSender.setDumpWriter(mRtpDump); + // mRtpDump = new RtpDump("d:\\outgoing.rtp"); + // mRtpSender.setDumpWriter(mRtpDump); #if defined(DUMP_SENDING_AUDIO) mSendingDump = std::make_shared(); @@ -107,7 +106,7 @@ void AudioStream::setDestination(const RtpPair& dest) mRtpSender.setDestination(dest); } -void AudioStream::setTransmittingCodec(Codec::Factory& factory, int payloadType) +void AudioStream::setTransmittingCodec(Codec::Factory& factory, int payloadType) { ICELogInfo(<< "Selected codec " << factory.name() << "/" << factory.samplerate() << " for transmitting"); @@ -146,28 +145,38 @@ void AudioStream::addData(const void* buffer, int bytes) { Lock l(mMutex); codec = mTransmittingCodec.get(); - if (nullptr == codec) { + if (nullptr == codec) + { // ICELogDebug(<< "No transmitting codec selected."); return; } } // Resample - unsigned dstlen = unsigned(float(codec->samplerate() / float(AUDIO_SAMPLERATE)) * bytes); + unsigned dstlen = unsigned(float(codec->samplerate() / float(AUDIO_SAMPLERATE)) * bytes); Audio::Resampler* r = nullptr; switch (codec->samplerate()) { - case 8000: r = &mCaptureResampler8; break; - case 16000: r = &mCaptureResampler16; break; - case 32000: r = &mCaptureResampler32; break; - case 48000: r = &mCaptureResampler48; break; + case 8000: + r = &mCaptureResampler8; + break; + case 16000: + r = &mCaptureResampler16; + break; + case 32000: + r = &mCaptureResampler32; + break; + case 48000: + r = &mCaptureResampler48; + break; default: assert(0); } size_t processedInput = 0; dstlen = r->processBuffer(buffer, bytes, processedInput, mResampleBuffer, dstlen); - // ProcessedInput output value is ignored - because sample rate of input is always 8/16/32/48K - so all buffer is processed + // ProcessedInput output value is ignored - because sample rate of input is always 8/16/32/48K - so all buffer is + // processed // See if we need stereo <-> mono conversions unsigned stereolen = 0; @@ -181,22 +190,26 @@ void AudioStream::addData(const void* buffer, int bytes) // See if inband dtmf audio should be sent instead ByteBuffer dtmf; - if (mDtmfContext.type() == DtmfContext::Dtmf_Inband && mDtmfContext.getInband(AUDIO_MIC_BUFFER_LENGTH, codec->samplerate(), dtmf)) + if (mDtmfContext.type() == DtmfContext::Dtmf_Inband && + mDtmfContext.getInband(AUDIO_MIC_BUFFER_LENGTH, codec->samplerate(), dtmf)) mCapturedAudio.add(dtmf.data(), dtmf.size()); else mCapturedAudio.add(stereolen ? mStereoBuffer : mResampleBuffer, stereolen ? stereolen : dstlen); // See if it is time to send RFC2833 tone ByteBuffer rfc2833, stopPacket; - if (mDtmfContext.type() == DtmfContext::Dtmf_Rfc2833 && mDtmfContext.getRfc2833(AUDIO_MIC_BUFFER_LENGTH, rfc2833, stopPacket)) + if (mDtmfContext.type() == DtmfContext::Dtmf_Rfc2833 && + mDtmfContext.getRfc2833(AUDIO_MIC_BUFFER_LENGTH, rfc2833, stopPacket)) { if (rfc2833.size()) - mRtpDtmfSession.SendPacket(rfc2833.data(), rfc2833.size(), mRemoteTelephoneCodec, true, AUDIO_MIC_BUFFER_LENGTH * 8); + mRtpDtmfSession.SendPacket(rfc2833.data(), rfc2833.size(), mRemoteTelephoneCodec, true, + AUDIO_MIC_BUFFER_LENGTH * 8); if (stopPacket.size()) { - for (int i=0; i<3; i++) - mRtpDtmfSession.SendPacket(stopPacket.data(), stopPacket.size(), mRemoteTelephoneCodec, true, AUDIO_MIC_BUFFER_LENGTH * 8); + for (int i = 0; i < 3; i++) + mRtpDtmfSession.SendPacket(stopPacket.data(), stopPacket.size(), mRemoteTelephoneCodec, true, + AUDIO_MIC_BUFFER_LENGTH * 8); } } @@ -205,14 +218,15 @@ void AudioStream::addData(const void* buffer, int bytes) int packetTime = mPacketTime ? mPacketTime : codec->frameTime(); // Make stereo version if required - for (int i=0; ipcmLength(); i++) + for (int i = 0; i < mCapturedAudio.filled() / codec->pcmLength(); i++) { if (mSendingDump) mSendingDump->write((const char*)mCapturedAudio.data() + codec->pcmLength() * i, codec->pcmLength()); - auto r = codec->encode({(const uint8_t*)mCapturedAudio.data() + codec->pcmLength()*i, (size_t)codec->pcmLength()}, - {(uint8_t*)mFrameBuffer, MT_MAXAUDIOFRAME}); - + auto r = + codec->encode({(const uint8_t*)mCapturedAudio.data() + codec->pcmLength() * i, (size_t)codec->pcmLength()}, + {(uint8_t*)mFrameBuffer, MT_MAXAUDIOFRAME}); + // Counter of processed input bytes of raw pcm data from microphone processed += codec->pcmLength(); encodedTime += codec->frameTime(); @@ -224,9 +238,10 @@ void AudioStream::addData(const void* buffer, int bytes) if (packetTime <= encodedTime) { // Time to send packet - ICELogMedia(<< "Sending RTP packet pt = " << mTransmittingPayloadType << ", plength = " << (int)mEncodedAudio.size() << " to "); + ICELogMedia(<< "Sending RTP packet pt = " << mTransmittingPayloadType + << ", plength = " << (int)mEncodedAudio.size() << " to "); mRtpSession.SendPacketEx(mEncodedAudio.data(), mEncodedAudio.size(), mTransmittingPayloadType, false, - packetTime * codec->samplerate()/1000, 0, nullptr, 0); + packetTime * codec->samplerate() / 1000, 0, nullptr, 0); mEncodedAudio.clear(); encodedTime = 0; } @@ -239,14 +254,14 @@ void AudioStream::addData(const void* buffer, int bytes) void AudioStream::copyDataTo(Audio::Mixer& mixer, int needed) { // mStreamMap is also mutated from the network thread (dataArrived) - Lock l(mMutex); + Lock l(mMutex); // Local audio mixer - used to send audio to media observer - Audio::Mixer localMixer; + Audio::Mixer localMixer; Audio::DataWindow forObserver; // Iterate - for (auto& streamIter: mStreamMap) + for (auto& streamIter : mStreamMap) { Audio::DataWindow w; w.setCapacity(32768); @@ -287,7 +302,8 @@ void AudioStream::copyDataTo(Audio::Mixer& mixer, int needed) { int mixedBytes = localMixer.mixAndGetPcm(forObserver); if (mixedBytes > 0) - mMediaObserver->onMedia(forObserver.data(), mixedBytes, MT::Stream::MediaDirection::Incoming, this, mMediaObserverTag); + mMediaObserver->onMedia(forObserver.data(), mixedBytes, MT::Stream::MediaDirection::Incoming, this, + mMediaObserverTag); } } @@ -295,11 +311,12 @@ void AudioStream::dataArrived(PDatagramSocket s, const void* buffer, int length, { // Protects mStreamMap (also iterated by copyDataTo on the audio thread) // and the receive/decrypt buffers. - Lock l(mMutex); + Lock l(mMutex); - jrtplib::RTPIPv6Address addr6; - jrtplib::RTPIPv4Address addr4; - jrtplib::RTPExternalTransmissionInfo* info = dynamic_cast(mRtpSession.GetTransmissionInfo()); + jrtplib::RTPIPv6Address addr6; + jrtplib::RTPIPv4Address addr4; + jrtplib::RTPExternalTransmissionInfo* info = + dynamic_cast(mRtpSession.GetTransmissionInfo()); assert(info); // Drop RTP packets if stream is not receiving now; let RTCP go @@ -315,15 +332,16 @@ void AudioStream::dataArrived(PDatagramSocket s, const void* buffer, int length, if (mSrtpSession.active()) { - bool srtpResult; - size_t srcLength = length; size_t dstLength = sizeof mSrtpDecodeBuffer; + bool srtpResult; + size_t srcLength = length; + size_t dstLength = sizeof mSrtpDecodeBuffer; if (RtpHelper::isRtp(mReceiveBuffer, receiveLength)) srtpResult = mSrtpSession.unprotectRtp(mReceiveBuffer, srcLength, mSrtpDecodeBuffer, &dstLength); else srtpResult = mSrtpSession.unprotectRtcp(mReceiveBuffer, srcLength, mSrtpDecodeBuffer, &dstLength); if (!srtpResult) { - ICELogError(<<"Cannot decrypt SRTP packet."); + ICELogError(<< "Cannot decrypt SRTP packet."); return; } @@ -379,8 +397,9 @@ void AudioStream::dataArrived(PDatagramSocket s, const void* buffer, int length, // Find right handler for rtp stream SingleAudioStream* rtpStream = nullptr; - auto streamIter = mStreamMap.find(packet->GetSSRC()); - if (streamIter == mStreamMap.end()) { + auto streamIter = mStreamMap.find(packet->GetSSRC()); + if (streamIter == mStreamMap.end()) + { rtpStream = new SingleAudioStream(mCodecSettings, mStat); mStreamMap.insert({packet->GetSSRC(), rtpStream}); } @@ -395,14 +414,13 @@ void AudioStream::dataArrived(PDatagramSocket s, const void* buffer, int length, // without these, a skewed or buggy peer can poison mRttDelay // (and therefore the Id term in MOS). double rtt = mRtpSession.GetCurrentSourceInfo()->INF_GetRoundtripTime().GetDouble(); - if (rtt > 0 && rtt < 30.0) // reject "RTT not making any sense" (>30s) + if (rtt > 0 && rtt < 30.0) // reject "RTT not making any sense" (>30s) { // Once an average is established, cap a new sample at 3x mean // so a single outlier can't skew the running RTT. constexpr double kRttNormalizeFactor = 3.0; - const double meanRtt = mStat.mRttDelay.average(); - if (mStat.mRttDelay.is_initialized() && meanRtt > 0.0 && - rtt > meanRtt * kRttNormalizeFactor) + const double meanRtt = mStat.mRttDelay.average(); + if (mStat.mRttDelay.is_initialized() && meanRtt > 0.0 && rtt > meanRtt * kRttNormalizeFactor) { rtt = meanRtt * kRttNormalizeFactor; } @@ -438,8 +456,12 @@ void AudioStream::readFile(const Audio::PWavFileReader& stream, MediaDirection d { switch (direction) { - case MediaDirection::Outgoing: mDumpStreams.mStreamForReadingOutgoing = stream; break; - case MediaDirection::Incoming: mDumpStreams.mStreamForReadingIncoming = stream; break; + case MediaDirection::Outgoing: + mDumpStreams.mStreamForReadingOutgoing = stream; + break; + case MediaDirection::Incoming: + mDumpStreams.mStreamForReadingIncoming = stream; + break; } } @@ -447,8 +469,12 @@ void AudioStream::writeFile(const Audio::PWavFileWriter& writer, MediaDirection { switch (direction) { - case MediaDirection::Outgoing: mDumpStreams.mStreamForRecordingOutgoing = writer; break; - case MediaDirection::Incoming: mDumpStreams.mStreamForRecordingIncoming = writer; break; + case MediaDirection::Outgoing: + mDumpStreams.mStreamForRecordingOutgoing = writer; + break; + case MediaDirection::Incoming: + mDumpStreams.mStreamForRecordingIncoming = writer; + break; } } diff --git a/src/engine/media/MT_AudioStream.h b/src/engine/media/MT_AudioStream.h index 9dab698c..da05a1e1 100644 --- a/src/engine/media/MT_AudioStream.h +++ b/src/engine/media/MT_AudioStream.h @@ -26,88 +26,82 @@ namespace MT { -class AudioStream: public Stream +class AudioStream : public Stream { public: AudioStream(const CodecList::Settings& codecSettings); ~AudioStream(); - void setDestination(const RtpPair& dest) override; - //void setPacketTime(int packetTime); - - void setTransmittingCodec(Codec::Factory& factory, int payloadType) override; - PCodec transmittingCodec(); + void setDestination(const RtpPair& dest) override; + // void setPacketTime(int packetTime); + + void setTransmittingCodec(Codec::Factory& factory, int payloadType) override; + PCodec transmittingCodec(); // Called to queue data captured from microphone. // Buffer holds 16bits PCM data with AUDIO_SAMPLERATE rate and AUDIO_CHANNELS channels. - void addData(const void* buffer, int length); - + void addData(const void* buffer, int length); + // Called to get data to speaker (or mixer) - void copyDataTo(Audio::Mixer& mixer, int needed); + void copyDataTo(Audio::Mixer& mixer, int needed); // Called to process incoming rtp packet - void dataArrived(PDatagramSocket s, const void* buffer, int length, InternetAddress& source) override; - void setSocket(const RtpPair& socket) override; - void setState(unsigned state) override; - - void setTelephoneCodec(int payloadType); + void dataArrived(PDatagramSocket s, const void* buffer, int length, InternetAddress& source) override; + void setSocket(const RtpPair& socket) override; + void setState(unsigned state) override; + + void setTelephoneCodec(int payloadType); DtmfContext& queueOfDtmf(); - void readFile(const Audio::PWavFileReader& stream, MediaDirection direction) override; - void writeFile(const Audio::PWavFileWriter& writer, MediaDirection direction) override; - void setupMirror(bool enable) override; + void readFile(const Audio::PWavFileReader& stream, MediaDirection direction) override; + void writeFile(const Audio::PWavFileWriter& writer, MediaDirection direction) override; + void setupMirror(bool enable) override; - void setFinalStatisticsOutput(Statistics* stats); + void setFinalStatisticsOutput(Statistics* stats); protected: - Audio::DataWindow mCapturedAudio; // Data from microphone + Audio::DataWindow mCapturedAudio; // Data from microphone Audio::DataWindow mStereoCapturedAudio; - char mIncomingPcmBuffer[AUDIO_MIC_BUFFER_SIZE] = {0}; // Temporary buffer to allow reading from file - char mResampleBuffer[AUDIO_MIC_BUFFER_SIZE*8] = {0}; // Temporary buffer to hold data - char mStereoBuffer[AUDIO_MIC_BUFFER_SIZE*16] = {0}; // Temporary buffer to hold data converted to stereo - PCodec mTransmittingCodec; // Current encoding codec - int mTransmittingPayloadType = -1; // Payload type to mark outgoing packets - int mPacketTime = 0; // Required packet time - char mFrameBuffer[MT_MAXAUDIOFRAME]; // Temporary buffer to hold results of encoder - ByteBuffer mEncodedAudio; // Encoded frame(s) - int mEncodedTime = 0; // Time length of encoded audio - CodecList::Settings mCodecSettings; // Configuration for stream - Mutex mMutex; // Mutex - int mRemoteTelephoneCodec; // Payload for remote telephone codec - jrtplib::RTPSession mRtpSession; // Rtp session - jrtplib::RTPSession mRtpDtmfSession; // Rtp dtmf session - NativeRtpSender mRtpSender; - AudioStreamMap mStreamMap; // Map of media streams. Key is RTP's SSRC value. - Audio::DataWindow mOutputBuffer; + char mIncomingPcmBuffer[AUDIO_MIC_BUFFER_SIZE] = {0}; // Temporary buffer to allow reading from file + char mResampleBuffer[AUDIO_MIC_BUFFER_SIZE * 8] = {0}; // Temporary buffer to hold data + char mStereoBuffer[AUDIO_MIC_BUFFER_SIZE * 16] = {0}; // Temporary buffer to hold data converted to stereo + PCodec mTransmittingCodec; // Current encoding codec + int mTransmittingPayloadType = -1; // Payload type to mark outgoing packets + int mPacketTime = 0; // Required packet time + char mFrameBuffer[MT_MAXAUDIOFRAME]; // Temporary buffer to hold results of encoder + ByteBuffer mEncodedAudio; // Encoded frame(s) + int mEncodedTime = 0; // Time length of encoded audio + CodecList::Settings mCodecSettings; // Configuration for stream + Mutex mMutex; // Mutex + int mRemoteTelephoneCodec; // Payload for remote telephone codec + jrtplib::RTPSession mRtpSession; // Rtp session + jrtplib::RTPSession mRtpDtmfSession; // Rtp dtmf session + NativeRtpSender mRtpSender; + AudioStreamMap mStreamMap; // Map of media streams. Key is RTP's SSRC value. + Audio::DataWindow mOutputBuffer; #if defined(USE_RTPDUMP) RtpDump* mRtpDump = nullptr; #endif - Audio::Resampler mCaptureResampler8, - mCaptureResampler16, - mCaptureResampler32, - mCaptureResampler48; - DtmfContext mDtmfContext; - char mReceiveBuffer[MAX_VALID_UDPPACKET_SIZE] = {0}, - mSrtpDecodeBuffer[MAX_VALID_UDPPACKET_SIZE] = {0}; + Audio::Resampler mCaptureResampler8, mCaptureResampler16, mCaptureResampler32, mCaptureResampler48; + DtmfContext mDtmfContext; + char mReceiveBuffer[MAX_VALID_UDPPACKET_SIZE] = {0}, mSrtpDecodeBuffer[MAX_VALID_UDPPACKET_SIZE] = {0}; struct { - Audio::PWavFileWriter mStreamForRecordingIncoming, - mStreamForRecordingOutgoing; - Audio::PWavFileReader mStreamForReadingIncoming, - mStreamForReadingOutgoing; + Audio::PWavFileWriter mStreamForRecordingIncoming, mStreamForRecordingOutgoing; + Audio::PWavFileReader mStreamForReadingIncoming, mStreamForReadingOutgoing; } mDumpStreams; Audio::PWavFileWriter mSendingDump; - bool mMirror = false; - bool mMirrorPrebuffered = false; - Audio::DataWindow mMirrorBuffer; + bool mMirror = false; + bool mMirrorPrebuffered = false; + Audio::DataWindow mMirrorBuffer; - Statistics* mFinalStatistics = nullptr; + Statistics* mFinalStatistics = nullptr; // bool decryptSrtp(void* data, int* len); }; -}; +}; // namespace MT #endif diff --git a/src/engine/media/MT_Box.cpp b/src/engine/media/MT_Box.cpp index 6e4930af..40fb1053 100644 --- a/src/engine/media/MT_Box.cpp +++ b/src/engine/media/MT_Box.cpp @@ -16,117 +16,115 @@ using namespace MT; -Terminal::Terminal(const CodecList::Settings& settings) - :mCodecList(settings) +Terminal::Terminal(const CodecList::Settings& settings) : mCodecList(settings) { - ICELogDebug(<< "Opening Terminal instance"); + ICELogDebug(<< "Opening Terminal instance"); - // Alloc memory for captured audio - mCapturedAudio.setCapacity(AUDIO_MIC_BUFFER_COUNT * AUDIO_MIC_BUFFER_SIZE); + // Alloc memory for captured audio + mCapturedAudio.setCapacity(AUDIO_MIC_BUFFER_COUNT * AUDIO_MIC_BUFFER_SIZE); - // Init srtp library - SrtpSession::initSrtp(); + // Init srtp library + SrtpSession::initSrtp(); } Terminal::~Terminal() { - ICELogDebug(<< "Closing Terminal instance"); - mAudioPair.reset(); + ICELogDebug(<< "Closing Terminal instance"); + mAudioPair.reset(); } PStream Terminal::createStream(int type, VariantMap& /*config*/) { - PStream result; - switch (type) - { - case Stream::Audio: - result = std::make_shared(MT::CodecList::Settings::getClientSettings()); - mAudioList.add(result); - break; + PStream result; + switch (type) + { + case Stream::Audio: + result = std::make_shared(MT::CodecList::Settings::getClientSettings()); + mAudioList.add(result); + break; - case Stream::Video: - default: - throw Exception(ERR_NOT_IMPLEMENTED); - } + case Stream::Video: + default: + throw Exception(ERR_NOT_IMPLEMENTED); + } - return result; + return result; } void Terminal::freeStream(const PStream& stream) { - if (AudioStream* audio = dynamic_cast(stream.get())) - { - ICELogDebug(<< "Unregister audio stream from mixer."); - mAudioMixer.unregisterChannel(audio); + if (AudioStream* audio = dynamic_cast(stream.get())) + { + ICELogDebug(<< "Unregister audio stream from mixer."); + mAudioMixer.unregisterChannel(audio); - ICELogDebug(<< "Remove audio stream from list."); - mAudioList.remove(stream); - } + ICELogDebug(<< "Remove audio stream from list."); + mAudioList.remove(stream); + } } CodecList& Terminal::codeclist() { - return mCodecList; + return mCodecList; } Audio::PDevicePair Terminal::audio() { - return mAudioPair; + return mAudioPair; } void Terminal::setAudio(const Audio::PDevicePair& audio) { - mAudioPair = audio; - if (mAudioPair) - mAudioPair->setDelegate(this); + mAudioPair = audio; + if (mAudioPair) + mAudioPair->setDelegate(this); } -void Terminal::deviceChanged(Audio::DevicePair* dp) -{ -} +void Terminal::deviceChanged(Audio::DevicePair* dp) {} void Terminal::onMicData(const Audio::Format& f, const void* buffer, int length) { - //ICELogMedia(<< "Got " << length << " bytes from microphone"); + // ICELogMedia(<< "Got " << length << " bytes from microphone"); - // See if it is enough data to feed streams - mCapturedAudio.add(buffer, length); - if (mCapturedAudio.filled() < AUDIO_MIC_BUFFER_SIZE) - return; + // See if it is enough data to feed streams + mCapturedAudio.add(buffer, length); + if (mCapturedAudio.filled() < AUDIO_MIC_BUFFER_SIZE) + return; - StreamList sl; - mAudioList.copyTo(&sl); + StreamList sl; + mAudioList.copyTo(&sl); - // Iterate streams. See what of them requires microphone data. - for (int frameIndex=0; frameIndex < mCapturedAudio.filled() / AUDIO_MIC_BUFFER_SIZE; frameIndex++) - { - for (int i=0; i(sl.streamAt(i).get())) + // Iterate streams. See what of them requires microphone data. + for (int frameIndex = 0; frameIndex < mCapturedAudio.filled() / AUDIO_MIC_BUFFER_SIZE; frameIndex++) + { + for (int i = 0; i < sl.size(); i++) { - if (stream->state() & (int)StreamState::Sending) - stream->addData(mCapturedAudio.data(), AUDIO_MIC_BUFFER_SIZE); + if (AudioStream* stream = dynamic_cast(sl.unsafeStreamAt(i).get())) + { + if (stream->state() & (int)StreamState::Sending) + stream->addData(mCapturedAudio.data(), AUDIO_MIC_BUFFER_SIZE); + } } - } - mCapturedAudio.erase(AUDIO_MIC_BUFFER_SIZE); - } + mCapturedAudio.erase(AUDIO_MIC_BUFFER_SIZE); + } } void Terminal::onSpkData(const Audio::Format& f, void* buffer, int length) { - ICELogMedia(<< "Speaker requests " << length << " bytes"); - if (mAudioMixer.available() < length) - { - Lock l(mAudioList.getMutex()); - - for (int i=0; i(mAudioList.streamAt(i).get())) - { - //if (stream->state() & STATE_RECEIVING) - stream->copyDataTo(mAudioMixer, length - mAudioMixer.available()); - } + // Lock stream list + Lock l(mAudioList.getMutex()); + + for (size_t i = 0; i < mAudioList.size(); i++) + { + if (AudioStream* stream = dynamic_cast(mAudioList.unsafeStreamAt(i).get())) + { + // if (stream->state() & STATE_RECEIVING) + stream->copyDataTo(mAudioMixer, length - mAudioMixer.available()); + } + } } - } - mAudioMixer.getPcm(buffer, length); + mAudioMixer.getPcm(buffer, length); } diff --git a/src/engine/media/MT_Box.h b/src/engine/media/MT_Box.h index b4c33e54..10d9bd27 100644 --- a/src/engine/media/MT_Box.h +++ b/src/engine/media/MT_Box.h @@ -17,32 +17,32 @@ namespace MT { - class Terminal: public Audio::DevicePair::Delegate - { - public: +class Terminal : public Audio::DevicePair::Delegate +{ +public: Terminal(const CodecList::Settings& codecSettings); virtual ~Terminal(); - - CodecList& codeclist(); - PStream createStream(int type, VariantMap& config); - void freeStream(const PStream& s); - + CodecList& codeclist(); + + PStream createStream(int type, VariantMap& config); + void freeStream(const PStream& s); + Audio::PDevicePair audio(); - void setAudio(const Audio::PDevicePair& audio); + void setAudio(const Audio::PDevicePair& audio); - protected: - StreamList mAudioList; - std::mutex mAudioListMutex; - CodecList mCodecList; +protected: + StreamList mAudioList; + std::mutex mAudioListMutex; + CodecList mCodecList; Audio::PDevicePair mAudioPair; - Audio::Mixer mAudioMixer; - Audio::DataWindow mCapturedAudio; + Audio::Mixer mAudioMixer; + Audio::DataWindow mCapturedAudio; - void deviceChanged(Audio::DevicePair* dp); - void onMicData(const Audio::Format& f, const void* buffer, int length); - void onSpkData(const Audio::Format& f, void* buffer, int length); - }; + void deviceChanged(Audio::DevicePair* dp); + void onMicData(const Audio::Format& f, const void* buffer, int length); + void onSpkData(const Audio::Format& f, void* buffer, int length); +}; -} +} // namespace MT #endif diff --git a/src/engine/media/MT_CngHelper.cpp b/src/engine/media/MT_CngHelper.cpp index e5292732..cd1edeb7 100644 --- a/src/engine/media/MT_CngHelper.cpp +++ b/src/engine/media/MT_CngHelper.cpp @@ -15,167 +15,168 @@ typedef int __int32; namespace MT { - static int GenerateRandom(int maxvalue) - { +static int GenerateRandom(int maxvalue) +{ assert(maxvalue <= RAND_MAX); int result = rand(); result = static_cast(result / ((float)RAND_MAX / maxvalue) + 0.5); if (result > maxvalue) - result = maxvalue; + result = maxvalue; return result; - } +} - class LPFilter - { - public: +class LPFilter +{ +public: static const int NCoef = 1; static const int DCgain = 128; - __int16 ACoef[NCoef+1]; - __int16 BCoef[NCoef+1]; + __int16 ACoef[NCoef + 1]; + __int16 BCoef[NCoef + 1]; - __int32 y[NCoef+1] = {0, 0}; - __int16 x[NCoef+1] = {0, 0}; + __int32 y[NCoef + 1] = {0, 0}; + __int16 x[NCoef + 1] = {0, 0}; LPFilter() { - ACoef[0] = 16707; ACoef[1] = 16707; - BCoef[0] = 32767; BCoef[1] = -32511; + ACoef[0] = 16707; + ACoef[1] = 16707; + BCoef[0] = 32767; + BCoef[1] = -32511; } - ~LPFilter() - { - - } + ~LPFilter() {} __int16 Do(__int16 sample) { - int n; + int n; - //shift the old samples - for(n=NCoef; n>0; n--) { - x[n] = x[n-1]; - y[n] = y[n-1]; - } + // shift the old samples + for (n = NCoef; n > 0; n--) + { + x[n] = x[n - 1]; + y[n] = y[n - 1]; + } - //Calculate the new output - x[0] = sample; - y[0] = ACoef[0] * x[0]; - for(n=1; n<=NCoef; n++) - y[0] += ACoef[n] * x[n] - BCoef[n] * y[n]; + // Calculate the new output + x[0] = sample; + y[0] = ACoef[0] * x[0]; + for (n = 1; n <= NCoef; n++) + y[0] += ACoef[n] * x[n] - BCoef[n] * y[n]; - y[0] /= BCoef[0]; + y[0] /= BCoef[0]; - return y[0] / DCgain; + return y[0] / DCgain; } - }; +}; - class HPFilter - { - public: +class HPFilter +{ +public: static const int NCoef = 1; static const int DCgain = 128; - __int16 ACoef[NCoef+1]; - __int16 BCoef[NCoef+1]; + __int16 ACoef[NCoef + 1]; + __int16 BCoef[NCoef + 1]; - __int32 y[NCoef+1] = {0, 0}; - __int16 x[NCoef+1] = {0, 0}; + __int32 y[NCoef + 1] = {0, 0}; + __int16 x[NCoef + 1] = {0, 0}; HPFilter() { - ACoef[0] = 16384; ACoef[1] = -16384; - BCoef[0] = 32767; BCoef[1] = 0; + ACoef[0] = 16384; + ACoef[1] = -16384; + BCoef[0] = 32767; + BCoef[1] = 0; } - ~HPFilter() - { - - } + ~HPFilter() {} __int16 Do(__int16 sample) { - int n; + int n; - //shift the old samples - for(n=NCoef; n>0; n--) { - x[n] = x[n-1]; - y[n] = y[n-1]; - } + // shift the old samples + for (n = NCoef; n > 0; n--) + { + x[n] = x[n - 1]; + y[n] = y[n - 1]; + } - //Calculate the new output - x[0] = sample; - y[0] = ACoef[0] * x[0]; - for(n=1; n<=NCoef; n++) - y[0] += ACoef[n] * x[n] - BCoef[n] * y[n]; + // Calculate the new output + x[0] = sample; + y[0] = ACoef[0] * x[0]; + for (n = 1; n <= NCoef; n++) + y[0] += ACoef[n] * x[n] - BCoef[n] * y[n]; - y[0] /= BCoef[0]; + y[0] /= BCoef[0]; - return y[0] / DCgain; + return y[0] / DCgain; } - }; +}; - // --------------------- CngHelper ---------------------------- - int CngHelper::parse3389(const void* buf, int size, int rate, int requestLengthInMilliseconds, short* output) - { +// --------------------- CngHelper ---------------------------- +int CngHelper::parse3389(const void* buf, int size, int rate, int requestLengthInMilliseconds, short* output) +{ assert(buf); assert(output); if (!size || !requestLengthInMilliseconds) - return 0; + return 0; - int outputSize = requestLengthInMilliseconds * (rate / 1000); + int outputSize = requestLengthInMilliseconds * (rate / 1000); // Cast pointer to input data const unsigned char* dataIn = (const unsigned char*)buf; // Get noise level - unsigned char noiseLevel = *dataIn; - float linear = 1.0f / float(noiseLevel ? noiseLevel : 1); + unsigned char noiseLevel = *dataIn; + float linear = 1.0f / float(noiseLevel ? noiseLevel : 1); // Generate white noise for 16KHz sample rate - LPFilter lpf; HPFilter hpf; + LPFilter lpf; + HPFilter hpf; for (int sampleIndex = 0; sampleIndex < outputSize; sampleIndex++) { - output[sampleIndex] = GenerateRandom(NOISE_AMPL*2) - NOISE_AMPL; - output[sampleIndex] = lpf.Do(output[sampleIndex]); - output[sampleIndex] = hpf.Do(output[sampleIndex]); - output[sampleIndex] = (short)((float)output[sampleIndex] * linear); + output[sampleIndex] = GenerateRandom(NOISE_AMPL * 2) - NOISE_AMPL; + output[sampleIndex] = lpf.Do(output[sampleIndex]); + output[sampleIndex] = hpf.Do(output[sampleIndex]); + output[sampleIndex] = (short)((float)output[sampleIndex] * linear); } return outputSize * 2; - } +} - // ------------------- CngDecoder -------------------- +// ------------------- CngDecoder -------------------- - CngDecoder::CngDecoder() - { +CngDecoder::CngDecoder() +{ WebRtcCng_CreateDec(&mContext); if (mContext) - WebRtcCng_InitDec(mContext); - } + WebRtcCng_InitDec(mContext); +} - CngDecoder::~CngDecoder() - { +CngDecoder::~CngDecoder() +{ if (mContext) - WebRtcCng_FreeDec(mContext); - } + WebRtcCng_FreeDec(mContext); +} - void CngDecoder::decode3389(const void *buf, int size) - { +void CngDecoder::decode3389(const void* buf, int size) +{ if (mContext) - WebRtcCng_UpdateSid(mContext, (WebRtc_UWord8*)buf, size); - } + WebRtcCng_UpdateSid(mContext, (WebRtc_UWord8*)buf, size); +} - int CngDecoder::produce(int rate, int requestedMilliseconds, short *output, bool newPeriod) - { +int CngDecoder::produce(int rate, int requestedMilliseconds, short* output, bool newPeriod) +{ WebRtcCng_Generate(mContext, output, requestedMilliseconds * rate / 1000, newPeriod ? 1 : 0); return requestedMilliseconds * rate / 1000 * 2; - } - } + +} // namespace MT diff --git a/src/engine/media/MT_CngHelper.h b/src/engine/media/MT_CngHelper.h index 6b82934d..d48afe47 100644 --- a/src/engine/media/MT_CngHelper.h +++ b/src/engine/media/MT_CngHelper.h @@ -5,25 +5,25 @@ namespace MT { - class CngHelper - { - public: +class CngHelper +{ +public: /* Parses RTP 3389 payload and produces CNG to audio buffer. Returns size of produced audio in bytes. */ static int parse3389(const void* buf, int size, int rate, int requestLengthInMilliseconds, short* output); - }; +}; - class CngDecoder - { - protected: +class CngDecoder +{ +protected: CNG_dec_inst* mContext; - public: +public: CngDecoder(); ~CngDecoder(); void decode3389(const void* buf, int size); - int produce(int rate, int requestedMilliseconds, short* output, bool newPeriod); - }; -} + int produce(int rate, int requestedMilliseconds, short* output, bool newPeriod); +}; +} // namespace MT #endif diff --git a/src/engine/media/MT_Codec.cpp b/src/engine/media/MT_Codec.cpp index 69336264..4539454c 100644 --- a/src/engine/media/MT_Codec.cpp +++ b/src/engine/media/MT_Codec.cpp @@ -27,13 +27,14 @@ resip::Codec Codec::Factory::resipCodec() return c; } -int Codec::Factory::processSdp(const resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) +int Codec::Factory::processSdp(const resip::SdpContents::Session::Medium::CodecContainer& codecs, + SdpDirection direction) { - for (resip::SdpContents::Session::Medium::CodecContainer::const_iterator codecIter = codecs.begin(); codecIter != codecs.end(); ++codecIter) + for (resip::SdpContents::Session::Medium::CodecContainer::const_iterator codecIter = codecs.begin(); + codecIter != codecs.end(); ++codecIter) { if (resipCodec() == *codecIter) return codecIter->payloadType(); } return -1; } - diff --git a/src/engine/media/MT_Codec.h b/src/engine/media/MT_Codec.h index a0b91455..987b7d03 100644 --- a/src/engine/media/MT_Codec.h +++ b/src/engine/media/MT_Codec.h @@ -18,28 +18,29 @@ namespace MT class Codec; typedef std::shared_ptr PCodec; -class CodecMap: public std::map -{}; +class CodecMap : public std::map +{ +}; class Codec { public: - class Factory { public: virtual ~Factory() {} - virtual const char* name() = 0; - virtual int samplerate() = 0; - virtual int payloadType() = 0; - virtual PCodec create() = 0; + virtual const char* name() = 0; + virtual int samplerate() = 0; + virtual int payloadType() = 0; + virtual PCodec create() = 0; - virtual int channels(); - typedef std::map CodecMap; - virtual void create(CodecMap& codecs); + virtual int channels(); + typedef std::map CodecMap; + virtual void create(CodecMap& codecs); virtual void updateSdp(resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction); // Returns payload type from chosen codec if success. -1 is returned for negative result. - virtual int processSdp(const resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction); + virtual int processSdp(const resip::SdpContents::Session::Medium::CodecContainer& codecs, + SdpDirection direction); resip::Codec resipCodec(); }; virtual ~Codec() {} @@ -47,28 +48,26 @@ public: struct Info { std::string mName; - int mSamplerate = 0; // Hz - int mChannels = 0; - int mPcmLength = 0; // In bytes - int mFrameTime = 0; // In milliseconds - int mRtpLength = 0; // In bytes - float mTimestampUnit = 0.0f; + int mSamplerate = 0; // Hz + int mChannels = 0; + int mPcmLength = 0; // In bytes + int mFrameTime = 0; // In milliseconds + int mRtpLength = 0; // In bytes + float mTimestampUnit = 0.0f; }; // Returns information about this codec instance virtual Info info() = 0; // Helper functions to return information - they are based on info() method - int pcmLength() { return info().mPcmLength; } - int rtpLength() { return info().mRtpLength; } - int channels() { return info().mChannels; } - int samplerate() { return info().mSamplerate; } - int frameTime() { return info().mFrameTime; } - std::string name() { return info().mName; } - float timestampUnit() { return info().mTimestampUnit == 0.0f ? 1.0f / info().mSamplerate : info().mTimestampUnit; } + int pcmLength() { return info().mPcmLength; } + int rtpLength() { return info().mRtpLength; } + int channels() { return info().mChannels; } + int samplerate() { return info().mSamplerate; } + int frameTime() { return info().mFrameTime; } + std::string name() { return info().mName; } + float timestampUnit() { return info().mTimestampUnit == 0.0f ? 1.0f / info().mSamplerate : info().mTimestampUnit; } - Audio::Format getAudioFormat() { - return Audio::Format(this->info().mSamplerate, this->info().mChannels); - } + Audio::Format getAudioFormat() { return Audio::Format(this->info().mSamplerate, this->info().mChannels); } // Returns size of encoded data (RTP) in bytes struct EncodeResult @@ -80,21 +79,20 @@ public: // Returns size of decoded data (PCM signed short) in bytes struct DecodeResult { - size_t mDecoded = 0; // Number of decoded bytes - bool mIsCng = false; // Should this packet to be used as CNG ? (used for AMR codecs) + size_t mDecoded = 0; // Number of decoded bytes + bool mIsCng = false; // Should this packet to be used as CNG ? (used for AMR codecs) }; virtual DecodeResult decode(std::span input, std::span output) = 0; // Returns size of produced data (PCM signed short) in bytes - virtual size_t plc(int lostFrames, std::span output) = 0; + virtual size_t plc(int lostFrames, std::span output) = 0; // In-band forward error correction. Reconstructs the single frame lost // immediately before nextPacket, using the redundant (LBRR) copy that // nextPacket may carry. Returns the number of PCM bytes written to output, // or 0 when the codec has no in-band FEC or no redundant data was present // (in which case the caller should fall back to plc()). Default: unsupported. - virtual size_t fec(std::span nextPacket, std::span output) { return 0; } - + virtual size_t fec(std::span nextPacket, std::span output) { return 0; } }; -} +} // namespace MT #endif diff --git a/src/engine/media/MT_CodecList.cpp b/src/engine/media/MT_CodecList.cpp index 7e00a542..fd7776dd 100644 --- a/src/engine/media/MT_CodecList.cpp +++ b/src/engine/media/MT_CodecList.cpp @@ -10,13 +10,13 @@ #include "MT_AudioCodec.h" #if !defined(TARGET_ANDROID) && !defined(TARGET_OPENWRT) && !defined(TARGET_RPI) -# if defined(USE_AMR_CODEC) -# include "MT_AmrCodec.h" -# endif +#if defined(USE_AMR_CODEC) +#include "MT_AmrCodec.h" +#endif -# if defined(USE_EVS_CODEC) -# include "MT_EvsCodec.h" -# endif +#if defined(USE_EVS_CODEC) +#include "MT_EvsCodec.h" +#endif #endif #include "helper/HL_String.h" @@ -50,10 +50,10 @@ bool CodecList::Settings::contains(int ptype) const return true; if (mAmrWbPayloadType.contains(ptype)) return true; - for (const auto& s: mOpusSpec) + for (const auto& s : mOpusSpec) if (s.mPayloadType == ptype) return true; - for (const auto& s: mEvsSpec) + for (const auto& s : mEvsSpec) if (s.mPayloadType == ptype) return true; @@ -80,27 +80,27 @@ std::string CodecList::Settings::toString() const if (!mAmrWbPayloadType.empty()) { oss << "AMR WB ptype: "; - for (int ptype: mAmrWbPayloadType) + for (int ptype : mAmrWbPayloadType) oss << ptype << " "; } if (!mAmrWbOctetPayloadType.empty()) { oss << "AMR WB octet ptype: "; - for (int ptype: mAmrWbOctetPayloadType) + for (int ptype : mAmrWbOctetPayloadType) oss << ptype << " "; } if (!mAmrNbPayloadType.empty()) { oss << "AMR ptype: "; - for (int ptype: mAmrNbPayloadType) + for (int ptype : mAmrNbPayloadType) oss << ptype << " "; } if (!mAmrNbOctetPayloadType.empty()) { oss << "AMR octet ptype: "; - for (int ptype: mAmrNbOctetPayloadType) + for (int ptype : mAmrNbOctetPayloadType) oss << ptype << " "; } if (mIsac16KPayloadType != -1) @@ -127,14 +127,16 @@ std::string CodecList::Settings::toString() const if (mTelephoneEvent != -1) oss << "RFC2833 DTMF ptype: " << mTelephoneEvent; - for (auto& spec: mEvsSpec) + for (auto& spec : mEvsSpec) { - oss << "EVS ptype: " << spec.mPayloadType << ", bw: " << spec.mBandwidth << ", enc: " << (spec.mEncodingType == EvsSpec::Encoding_MIME ? "mime" : "g192") << " "; + oss << "EVS ptype: " << spec.mPayloadType << ", bw: " << spec.mBandwidth + << ", enc: " << (spec.mEncodingType == EvsSpec::Encoding_MIME ? "mime" : "g192") << " "; } - for (auto& spec: mOpusSpec) + for (auto& spec : mOpusSpec) { - oss << "OPUS ptype: " << spec.mPayloadType << ", rate: " << spec.mRate << ", channels: " << spec.mChannels << std::endl; + oss << "OPUS ptype: " << spec.mPayloadType << ", rate: " << spec.mRate << ", channels: " << spec.mChannels + << std::endl; } return oss.str(); @@ -168,7 +170,7 @@ CodecList::Settings::EvsSpec CodecList::Settings::EvsSpec::parse(const std::stri { EvsSpec result; - auto parts = strx::split(spec, "-/ ,:"); + auto parts = strx::split(spec, "-/ ,:"); if (parts.size() == 3) { // Payload type number @@ -178,8 +180,7 @@ CodecList::Settings::EvsSpec CodecList::Settings::EvsSpec::parse(const std::stri std::string& encoding_type = parts[1]; if (encoding_type == "mime") result.mEncodingType = Encoding_MIME; - else - if (encoding_type == "g192") + else if (encoding_type == "g192") result.mEncodingType = Encoding_G192; else throw std::logic_error("Bad EVS codec encoding type"); @@ -188,14 +189,11 @@ CodecList::Settings::EvsSpec CodecList::Settings::EvsSpec::parse(const std::stri std::string& bandwidth = parts.back(); if (bandwidth == "nb" || bandwidth == "NB") result.mBandwidth = Bandwidth_NB; - else - if (bandwidth == "wb" || bandwidth == "WB") + else if (bandwidth == "wb" || bandwidth == "WB") result.mBandwidth = Bandwidth_WB; - else - if (bandwidth == "swb" || bandwidth == "SWB") + else if (bandwidth == "swb" || bandwidth == "SWB") result.mBandwidth = Bandwidth_SWB; - else - if (bandwidth == "fb" || bandwidth == "FB") + else if (bandwidth == "fb" || bandwidth == "FB") result.mBandwidth = Bandwidth_FB; } @@ -204,16 +202,14 @@ CodecList::Settings::EvsSpec CodecList::Settings::EvsSpec::parse(const std::stri bool CodecList::Settings::OpusSpec::isValid() const { - return (mPayloadType >= 96 && mPayloadType <= 127 && - mRate > 0 && - mChannels > 0); + return (mPayloadType >= 96 && mPayloadType <= 127 && mRate > 0 && mChannels > 0); } -CodecList::Settings::OpusSpec CodecList::Settings::OpusSpec::parse(const std::string &spec) +CodecList::Settings::OpusSpec CodecList::Settings::OpusSpec::parse(const std::string& spec) { OpusSpec result; - auto parts = strx::split(spec, "-/ ,:"); + auto parts = strx::split(spec, "-/ ,:"); if (parts.size() == 3) { result.mPayloadType = strx::toInt(strx::trim(parts.front()).c_str(), -1); @@ -226,12 +222,12 @@ CodecList::Settings::OpusSpec CodecList::Settings::OpusSpec::parse(const std::st static int findOctetMode(const char* line) { const char* param_name = "octet-align="; - auto p = strstr(line, param_name); + auto p = strstr(line, param_name); if (!p) return 0; p += strlen(param_name); - char int_buf[8] = {0}; + char int_buf[8] = {0}; size_t int_buf_offset = 0; while (*p && isdigit(*p) && int_buf_offset < sizeof(int_buf) - 1) int_buf[int_buf_offset++] = *p++; @@ -242,48 +238,62 @@ CodecList::Settings CodecList::Settings::parseSdp(const std::list& { CodecList::Settings r; - for (auto& c: codeclist) + for (auto& c : codeclist) { std::string codec_name = strx::uppercase(c.getName().c_str()); - int samplerate = c.getRate(); - int ptype = c.payloadType(); + int samplerate = c.getRate(); + int ptype = c.payloadType(); - auto enc_params = c.encodingParameters(); // This must channels number for Opus codec - auto params = c.parameters(); + auto enc_params = c.encodingParameters(); // This must channels number for Opus codec + auto params = c.parameters(); // Dynamic payload type codecs only - ISAC / iLBC / Speex / etc. - if (codec_name == "OPUS") { + if (codec_name == "OPUS") + { // Check the parameters int channels = strx::toInt(enc_params.c_str(), 1); r.mOpusSpec.push_back({ptype, samplerate, channels}); - } else if (codec_name == "AMR-WB") { + } + else if (codec_name == "AMR-WB") + { int octet_mode = findOctetMode(params.c_str()); - if (octet_mode != -1) { + if (octet_mode != -1) + { if (octet_mode == 0) r.mAmrWbPayloadType.insert(ptype); else if (octet_mode == 1) r.mAmrWbOctetPayloadType.insert(ptype); } - } else if (codec_name == "AMR" || codec_name == "AMR-NB") { + } + else if (codec_name == "AMR" || codec_name == "AMR-NB") + { int octet_mode = findOctetMode(params.c_str()); - if (octet_mode != -1) { + if (octet_mode != -1) + { if (octet_mode == 0) r.mAmrNbPayloadType.insert(ptype); else if (octet_mode == 1) r.mAmrNbOctetPayloadType.insert(ptype); } - } else if (codec_name == "EVS") { + } + else if (codec_name == "EVS") + { r.mEvsSpec.push_back({ptype}); - } else if (codec_name == "TELEPHONE-EVENT") + } + else if (codec_name == "TELEPHONE-EVENT") r.mTelephoneEvent = ptype; } return r; } -bool CodecList::Settings::operator == (const Settings& rhs) const +bool CodecList::Settings::operator==(const Settings& rhs) const { - if (std::tie(mWrapIuUP, mSkipDecode, mIsac16KPayloadType, mIsac32KPayloadType, mIlbc20PayloadType, mIlbc30PayloadType, mGsmFrPayloadType, mGsmFrPayloadLength, mGsmEfrPayloadType, mGsmHrPayloadType, mTelephoneEvent) != - std::tie(rhs.mWrapIuUP, rhs.mSkipDecode, rhs.mIsac16KPayloadType, rhs.mIsac32KPayloadType, rhs.mIlbc20PayloadType, rhs.mIlbc30PayloadType, rhs.mGsmFrPayloadType, rhs.mGsmFrPayloadLength, rhs.mGsmEfrPayloadType, rhs.mGsmHrPayloadType, rhs.mTelephoneEvent)) + if (std::tie(mWrapIuUP, mSkipDecode, mIsac16KPayloadType, mIsac32KPayloadType, mIlbc20PayloadType, + mIlbc30PayloadType, mGsmFrPayloadType, mGsmFrPayloadLength, mGsmEfrPayloadType, mGsmHrPayloadType, + mTelephoneEvent) != std::tie(rhs.mWrapIuUP, rhs.mSkipDecode, rhs.mIsac16KPayloadType, + rhs.mIsac32KPayloadType, rhs.mIlbc20PayloadType, rhs.mIlbc30PayloadType, + rhs.mGsmFrPayloadType, rhs.mGsmFrPayloadLength, rhs.mGsmEfrPayloadType, + rhs.mGsmHrPayloadType, rhs.mTelephoneEvent)) return false; if (mAmrNbOctetPayloadType != rhs.mAmrNbOctetPayloadType) @@ -322,8 +332,7 @@ bool CodecList::Settings::operator == (const Settings& rhs) const // ---------------------------------------- -CodecList::CodecList(const Settings& settings) - :mSettings(settings) +CodecList::CodecList(const Settings& settings) : mSettings(settings) { init(mSettings); } @@ -332,7 +341,7 @@ void CodecList::init(const Settings& settings) { mFactoryList.clear(); mSettings = settings; - for (auto spec: settings.mOpusSpec) + for (auto spec : settings.mOpusSpec) { mFactoryList.push_back(std::make_shared(spec.mRate, spec.mChannels, spec.mPayloadType)); } @@ -340,25 +349,32 @@ void CodecList::init(const Settings& settings) #if !defined(TARGET_ANDROID) && !defined(TARGET_OPENWRT) && !defined(TARGET_RPI) #if defined(USE_AMR_CODEC) - for (int pt: mSettings.mAmrWbPayloadType) - mFactoryList.push_back(std::make_shared(AmrCodecConfig{mSettings.mWrapIuUP, false, pt})); - for (int pt: mSettings.mAmrWbOctetPayloadType) - mFactoryList.push_back(std::make_shared(AmrCodecConfig{mSettings.mWrapIuUP, true, pt})); + for (int pt : mSettings.mAmrWbPayloadType) + mFactoryList.push_back( + std::make_shared(AmrCodecConfig{mSettings.mWrapIuUP, false, pt})); + for (int pt : mSettings.mAmrWbOctetPayloadType) + mFactoryList.push_back( + std::make_shared(AmrCodecConfig{mSettings.mWrapIuUP, true, pt})); - for (int pt: mSettings.mAmrNbPayloadType) - mFactoryList.push_back(std::make_shared(AmrCodecConfig{mSettings.mWrapIuUP, false, pt})); - for (int pt: mSettings.mAmrNbOctetPayloadType) - mFactoryList.push_back(std::make_shared(AmrCodecConfig{mSettings.mWrapIuUP, true, pt})); + for (int pt : mSettings.mAmrNbPayloadType) + mFactoryList.push_back( + std::make_shared(AmrCodecConfig{mSettings.mWrapIuUP, false, pt})); + for (int pt : mSettings.mAmrNbOctetPayloadType) + mFactoryList.push_back( + std::make_shared(AmrCodecConfig{mSettings.mWrapIuUP, true, pt})); if (mSettings.mGsmEfrPayloadType != -1) - mFactoryList.push_back(std::make_shared(mSettings.mWrapIuUP, mSettings.mGsmEfrPayloadType)); + mFactoryList.push_back( + std::make_shared(mSettings.mWrapIuUP, mSettings.mGsmEfrPayloadType)); #endif #endif mFactoryList.push_back(std::make_shared()); mFactoryList.push_back(std::make_shared()); if (mSettings.mGsmFrPayloadType != -1) - mFactoryList.push_back(std::make_shared(mSettings.mGsmFrPayloadLength == 32 ? GsmCodec::Type::Bytes_32 : GsmCodec::Type::Bytes_33, mSettings.mGsmFrPayloadType)); + mFactoryList.push_back(std::make_shared( + mSettings.mGsmFrPayloadLength == 32 ? GsmCodec::Type::Bytes_32 : GsmCodec::Type::Bytes_33, + mSettings.mGsmFrPayloadType)); mFactoryList.push_back(std::make_shared()); mFactoryList.push_back(std::make_shared()); #ifndef TARGET_ANDROID @@ -367,7 +383,7 @@ void CodecList::init(const Settings& settings) #endif #if !defined(TARGET_ANDROID) && defined(USE_EVS_CODEC) - for (auto& spec: settings.mEvsSpec) + for (auto& spec : settings.mEvsSpec) { EVSCodec::StreamParameters evs_params; evs_params.mime = spec.mEncodingType == Settings::EvsSpec::Encoding_MIME; @@ -395,9 +411,9 @@ Codec::Factory& CodecList::codecAt(int index) const return *mFactoryList[static_cast(index)]; } -int CodecList::findCodec(const std::string &name) const +int CodecList::findCodec(const std::string& name) const { - for (int i=0; ipayloadType() == payloadType) return factory->create(); @@ -428,11 +444,9 @@ PCodec CodecList::createCodecByPayloadType(int payloadType) return {}; } -CodecListPriority::CodecListPriority() -{} +CodecListPriority::CodecListPriority() {} -CodecListPriority::~CodecListPriority() -{} +CodecListPriority::~CodecListPriority() {} bool CodecListPriority::isNegativePriority(const CodecListPriority::Item& item) { @@ -446,14 +460,14 @@ bool CodecListPriority::compare(const Item& item1, const Item& item2) void CodecListPriority::setupFrom(PVariantMap vmap) { - auto settings = CodecList::Settings::getClientSettings(); + auto settings = CodecList::Settings::getClientSettings(); CodecList cl(settings); - //mPriorityList.resize(cl.count()); - bool emptyVmap = vmap ? vmap->empty() : true; + // mPriorityList.resize(cl.count()); + bool emptyVmap = vmap ? vmap->empty() : true; if (emptyVmap) { - for (int i=0; i(mPriorityList.size()); } diff --git a/src/engine/media/MT_CodecList.h b/src/engine/media/MT_CodecList.h index 79b034cf..b31a1a5c 100644 --- a/src/engine/media/MT_CodecList.h +++ b/src/engine/media/MT_CodecList.h @@ -25,8 +25,8 @@ class CodecList public: struct Settings { - bool mWrapIuUP = false; - bool mSkipDecode = false; + bool mWrapIuUP = false; + bool mSkipDecode = false; // When set, fillCodecMap() registers the payload-type keys but leaves the codec // objects null; each codec is created on first use (add()/findCodec()/infoFor()). @@ -34,28 +34,34 @@ public: // streams use only 1-2 payload types, so eagerly creating every registered codec // (G722 enc+dec, G729, Opus, AMR, EVS, ...) per stream is pure waste. Default false // keeps the eager behaviour for all other consumers (softphone, etc.). - bool mLazyCodecMap = false; + bool mLazyCodecMap = false; // RFC2833 DTMF - int mTelephoneEvent = -1; + int mTelephoneEvent = -1; // AMR payload types - std::set mAmrWbPayloadType = { }; - std::set mAmrNbPayloadType = { }; - std::set mAmrWbOctetPayloadType = { }; - std::set mAmrNbOctetPayloadType = { }; + std::set mAmrWbPayloadType = {}; + std::set mAmrNbPayloadType = {}; + std::set mAmrWbOctetPayloadType = {}; + std::set mAmrNbOctetPayloadType = {}; - bool isAmrWb(int ptype) const { return mAmrWbOctetPayloadType.count(ptype) > 0 || mAmrWbPayloadType.count(ptype) > 0; } - bool isAmrNb(int ptype) const { return mAmrNbOctetPayloadType.count(ptype) > 0 || mAmrNbPayloadType.count(ptype) > 0; } + bool isAmrWb(int ptype) const + { + return mAmrWbOctetPayloadType.count(ptype) > 0 || mAmrWbPayloadType.count(ptype) > 0; + } + bool isAmrNb(int ptype) const + { + return mAmrNbOctetPayloadType.count(ptype) > 0 || mAmrNbPayloadType.count(ptype) > 0; + } - int mIsac16KPayloadType = -1; - int mIsac32KPayloadType = -1; - int mIlbc20PayloadType = -1; - int mIlbc30PayloadType = -1; - int mGsmFrPayloadType = -1; // GSM is codec with fixed payload type. But sometimes it has to be overwritten. - int mGsmFrPayloadLength = 33; // Expected GSM payload length - int mGsmHrPayloadType = -1; - int mGsmEfrPayloadType = -1; + int mIsac16KPayloadType = -1; + int mIsac32KPayloadType = -1; + int mIlbc20PayloadType = -1; + int mIlbc30PayloadType = -1; + int mGsmFrPayloadType = -1; // GSM is codec with fixed payload type. But sometimes it has to be overwritten. + int mGsmFrPayloadLength = 33; // Expected GSM payload length + int mGsmHrPayloadType = -1; + int mGsmEfrPayloadType = -1; struct EvsSpec { @@ -76,56 +82,60 @@ public: Encoding_G192 }; - Encoding mEncodingType = Encoding_MIME; - bool isValid() const; + Encoding mEncodingType = Encoding_MIME; + bool isValid() const; static EvsSpec parse(const std::string& spec); - bool operator == (const EvsSpec& rhs) const { return std::tie(mPayloadType, mBandwidth, mEncodingType) == std::tie(rhs.mPayloadType, rhs.mBandwidth, rhs.mEncodingType);} - bool operator != (const EvsSpec& rhs) const { return ! (operator ==) (rhs);} - + bool operator==(const EvsSpec& rhs) const + { + return std::tie(mPayloadType, mBandwidth, mEncodingType) == + std::tie(rhs.mPayloadType, rhs.mBandwidth, rhs.mEncodingType); + } + bool operator!=(const EvsSpec& rhs) const { return !(operator==)(rhs); } }; std::vector mEvsSpec; struct OpusSpec { - int mPayloadType = -1; - int mRate = -1; - int mChannels = -1; + int mPayloadType = -1; + int mRate = -1; + int mChannels = -1; OpusSpec(int ptype = -1, int rate = -1, int channels = -1) - :mPayloadType(ptype), mRate(rate), mChannels(channels) - {} + : mPayloadType(ptype), mRate(rate), mChannels(channels) + { + } bool isValid() const; - bool operator == (const OpusSpec& rhs) const { return std::tie(mPayloadType, mRate, mChannels) == std::tie(rhs.mPayloadType, rhs.mRate, rhs.mChannels);} - bool operator != (const OpusSpec& rhs) const { return ! (operator ==) (rhs);} + bool operator==(const OpusSpec& rhs) const + { + return std::tie(mPayloadType, mRate, mChannels) == std::tie(rhs.mPayloadType, rhs.mRate, rhs.mChannels); + } + bool operator!=(const OpusSpec& rhs) const { return !(operator==)(rhs); } static OpusSpec parse(const std::string& spec); }; std::vector mOpusSpec; // Payload type - bool contains(int ptype) const; + bool contains(int ptype) const; // Textual representation - used in logging - std::string toString() const; - void clear(); + std::string toString() const; + void clear(); - static Settings parseSdp(const std::list& codeclist); + static Settings parseSdp(const std::list& codeclist); - bool operator == (const Settings& rhs) const; + bool operator==(const Settings& rhs) const; - static Settings getClientSettings(); - static Settings getAnalyzerSettings(); + static Settings getClientSettings(); + static Settings getAnalyzerSettings(); }; CodecList(const Settings& settings); ~CodecList(); - void setSettings(const Settings& settings) - { - init(settings); - } + void setSettings(const Settings& settings) { init(settings); } int count() const; Codec::Factory& codecAt(int index) const; @@ -136,10 +146,10 @@ public: protected: typedef std::vector> FactoryList; - FactoryList mFactoryList; - Settings mSettings; + FactoryList mFactoryList; + Settings mSettings; - void init(const Settings& settings); + void init(const Settings& settings); }; class CodecListPriority @@ -148,8 +158,8 @@ public: CodecListPriority(); ~CodecListPriority(); - void setupFrom(PVariantMap vmap); - int count(const CodecList& cl) const; + void setupFrom(PVariantMap vmap); + int count(const CodecList& cl) const; Codec::Factory& codecAt(const CodecList& cl, int index) const; protected: @@ -160,8 +170,8 @@ protected: }; std::vector mPriorityList; - static bool isNegativePriority(const CodecListPriority::Item& item); - static bool compare(const Item& item1, const Item& item2); + static bool isNegativePriority(const CodecListPriority::Item& item); + static bool compare(const Item& item1, const Item& item2); }; -} +} // namespace MT #endif diff --git a/src/engine/media/MT_Dtmf.cpp b/src/engine/media/MT_Dtmf.cpp index 983cc244..3d0e63d9 100644 --- a/src/engine/media/MT_Dtmf.cpp +++ b/src/engine/media/MT_Dtmf.cpp @@ -8,7 +8,7 @@ #ifdef TARGET_WIN -# include +#include #endif #include #include @@ -23,16 +23,13 @@ void DtmfBuilder::buildRfc2833(const Rfc2833Event& ev, void* output) assert(ev.mTone != 0); unsigned char toneValue = 0; - if (ev.mTone >= '0' && ev.mTone <='9') + if (ev.mTone >= '0' && ev.mTone <= '9') toneValue = ev.mTone - '0'; - else - if (ev.mTone >= 'A' && ev.mTone <='D' ) + else if (ev.mTone >= 'A' && ev.mTone <= 'D') toneValue = ev.mTone - 'A' + 12; - else - if (ev.mTone == '*') + else if (ev.mTone == '*') toneValue = 10; - else - if (ev.mTone == '#') + else if (ev.mTone == '#') toneValue = 11; char* packet = (char*)output; @@ -59,14 +56,11 @@ DtmfBuilder::Rfc2833Event DtmfBuilder::parseRfc2833(std::span payload) if (b0 <= 9) r.mTone = '0' + b0; - else - if (b0 >= 12 && b0 <= 15) + else if (b0 >= 12 && b0 <= 15) r.mTone = 'A' + b0 - 12; - else - if (b0 == 10) + else if (b0 == 10) r.mTone = '*'; - else - if (b0 == 11) + else if (b0 == 11) r.mTone = '#'; // RFC 4733: byte 1 is E(1) R(1) volume(6); duration is bytes 2-3, network order @@ -81,61 +75,43 @@ DtmfBuilder::Rfc2833Event DtmfBuilder::parseRfc2833(std::span payload) #pragma region Inband DTMF support #include #ifndef TARGET_WIN -# include -# if !defined(TARGET_ANDROID) && !defined(TARGET_WIN) -//# include -# endif +#include +#if !defined(TARGET_ANDROID) && !defined(TARGET_WIN) +// # include +#endif #endif -static bool sineTabInit = false; +static bool sineTabInit = false; -static double sinetab[1 << 11]; +static double sinetab[1 << 11]; static inline double sine(unsigned int ptr) -{ - return sinetab[ptr >> (32-11)]; -} - -#define TWOPI (2.0 * 3.14159265358979323846) -#define MAXSTR 512 -#define SINEBITS 11 -#define SINELEN (1 << SINEBITS) -#define TWO32 4294967296.0 /* 2^32 */ - - -static double amptab[2] = { 8191.75, 16383.5 }; -static inline int ifix(double x) -{ - return (x >= 0.0) ? (int) (x+0.5) : (int) (x-0.5); -} - -// given frequency f, return corresponding phase increment -static inline int phinc(double f) -{ - return ifix(TWO32 * f / (double) AUDIO_SAMPLERATE); -} - -static char dtmfSymbols[16] = { - '0', - '1', - '2', - '3', - '4', - '5', - '6', - '7', - '8', - '9', - 'A', - 'B', - 'C', - 'D', - '*', - '#' -}; - -char PDTMFEncoder_DtmfChar(int i) { + return sinetab[ptr >> (32 - 11)]; +} +#define TWOPI (2.0 * 3.14159265358979323846) +#define MAXSTR 512 +#define SINEBITS 11 +#define SINELEN (1 << SINEBITS) +#define TWO32 4294967296.0 /* 2^32 */ + + +static double amptab[2] = {8191.75, 16383.5}; +static inline int ifix(double x) +{ + return (x >= 0.0) ? (int)(x + 0.5) : (int)(x - 0.5); +} + +// given frequency f, return corresponding phase increment +static inline int phinc(double f) +{ + return ifix(TWO32 * f / (double)AUDIO_SAMPLERATE); +} + +static char dtmfSymbols[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', '*', '#'}; + +char PDTMFEncoder_DtmfChar(int i) +{ if (i < 16) return dtmfSymbols[i]; else @@ -145,34 +121,36 @@ char PDTMFEncoder_DtmfChar(int i) // DTMF frequencies as per http://www.commlinx.com.au/DTMF_frequencies.htm static double dtmfFreqs[16][2] = { - { 941.0, 1336.0 }, // 0 - { 697.0, 1209.0 }, // 1 - { 697.0, 1336.0 }, // 2 - { 697.0, 1477.0 }, // 3 - { 770.0, 1209.0 }, // 4 - { 770.0, 1336.0 }, // 5 - { 770.0, 1477.0 }, // 6 - { 852.0, 1209.0 }, // 7 - { 852.0, 1336.0 }, // 8 - { 852.0, 1477.0 }, // 9 - { 697.0, 1633.0 }, // A - { 770.0, 1633.0 }, // B - { 852.0, 1633.0 }, // C - { 941.0, 1633.0 }, // D - { 941.0, 1209.0 }, // * - { 941.0, 1477.0 } // # + {941.0, 1336.0}, // 0 + {697.0, 1209.0}, // 1 + {697.0, 1336.0}, // 2 + {697.0, 1477.0}, // 3 + {770.0, 1209.0}, // 4 + {770.0, 1336.0}, // 5 + {770.0, 1477.0}, // 6 + {852.0, 1209.0}, // 7 + {852.0, 1336.0}, // 8 + {852.0, 1477.0}, // 9 + {697.0, 1633.0}, // A + {770.0, 1633.0}, // B + {852.0, 1633.0}, // C + {941.0, 1633.0}, // D + {941.0, 1209.0}, // * + {941.0, 1477.0} // # }; static Mutex LocalDtmfMutex; -void PDTMFEncoder_MakeSineTable() -{ +void PDTMFEncoder_MakeSineTable() +{ Lock lock(LocalDtmfMutex); - if (!sineTabInit) { - for (int k = 0; k < SINELEN; k++) { - double th = TWOPI * (double) k / (double) SINELEN; + if (!sineTabInit) + { + for (int k = 0; k < SINELEN; k++) + { + double th = TWOPI * (double)k / (double)SINELEN; double v = sin(th); sinetab[k] = v; } @@ -186,20 +164,20 @@ void PDTMFEncoder_AddTone(double f1, double f2, unsigned ms1, unsigned ms2, unsi PDTMFEncoder_MakeSineTable(); - int dataPtr = 0; + int dataPtr = 0; - double amp = amptab[ak]; - int phinc1 = phinc(f1), phinc2 = phinc(f2); - int ns1 = ms1 * (rate/1000); - int ns2 = ms2 * (rate/1000); + double amp = amptab[ak]; + int phinc1 = phinc(f1), phinc2 = phinc(f2); + int ns1 = ms1 * (rate / 1000); + int ns2 = ms2 * (rate / 1000); unsigned int ptr1 = 0, ptr2 = 0; ptr1 += phinc1 * ns1; ptr2 += phinc2 * ns1; - for (int n = ns1; n < ns2; n++) { - + for (int n = ns1; n < ns2; n++) + { double val = amp * (sine(ptr1) + sine(ptr2)); - int ival = ifix(val); + int ival = ifix(val); if (ival < -32768) ival = -32768; else if (ival > 32767) @@ -228,7 +206,7 @@ void PDTMFEncoder_AddTone(char _digit, unsigned startTime, unsigned finishTime, digit = 15; else - return ; + return; PDTMFEncoder_AddTone(dtmfFreqs[(int)digit][0], dtmfFreqs[(int)digit][1], startTime, finishTime, rate, result); } @@ -241,14 +219,9 @@ void DtmfBuilder::buildInband(int tone, int startTime, int finishTime, int rate, } #pragma region DtmfContext -DtmfContext::DtmfContext() - :mType(Dtmf_Rfc2833) -{ -} +DtmfContext::DtmfContext() : mType(Dtmf_Rfc2833) {} -DtmfContext::~DtmfContext() -{ -} +DtmfContext::~DtmfContext() {} void DtmfContext::setType(Type t) { @@ -316,7 +289,8 @@ bool DtmfContext::getInband(int milliseconds, int rate, ByteBuffer& output) Dtmf& d = mQueue.front(); output.resize((uint64_t)milliseconds * rate / 1000 * 2); - DtmfBuilder::buildInband(d.mTone, d.mCurrentTime, d.mCurrentTime + milliseconds, rate, (short*)output.mutableData()); + DtmfBuilder::buildInband(d.mTone, d.mCurrentTime, d.mCurrentTime + milliseconds, rate, + (short*)output.mutableData()); d.mCurrentTime += milliseconds; return true; } @@ -333,16 +307,19 @@ bool DtmfContext::getRfc2833(int milliseconds, ByteBuffer& output, ByteBuffer& s { // Emit rfc2833 packet output.resize(4); - DtmfBuilder::buildRfc2833({.mTone = (char)d.mTone, .mDuration = milliseconds, .mVolume = d.mVolume, .mEnd = false}, output.mutableData()); + DtmfBuilder::buildRfc2833( + {.mTone = (char)d.mTone, .mDuration = milliseconds, .mVolume = d.mVolume, .mEnd = false}, + output.mutableData()); d.mDuration -= milliseconds; - if(d.mDuration <= 0) + if (d.mDuration <= 0) d.mStopped = true; } - else - if (!d.mStopped) + else if (!d.mStopped) { output.resize(4); - DtmfBuilder::buildRfc2833({.mTone = (char)d.mTone, .mDuration = milliseconds, .mVolume = d.mVolume, .mEnd = false}, output.mutableData()); + DtmfBuilder::buildRfc2833( + {.mTone = (char)d.mTone, .mDuration = milliseconds, .mVolume = d.mVolume, .mEnd = false}, + output.mutableData()); } else output.clear(); @@ -350,7 +327,9 @@ bool DtmfContext::getRfc2833(int milliseconds, ByteBuffer& output, ByteBuffer& s if (d.mStopped) { stopPacket.resize(4); - DtmfBuilder::buildRfc2833({.mTone = (char)d.mTone, .mDuration = milliseconds, .mVolume = d.mVolume, .mEnd = true}, stopPacket.mutableData()); + DtmfBuilder::buildRfc2833( + {.mTone = (char)d.mTone, .mDuration = milliseconds, .mVolume = d.mVolume, .mEnd = true}, + stopPacket.mutableData()); } else stopPacket.clear(); @@ -372,27 +351,27 @@ typedef struct typedef struct { - int hit1; - int hit2; - int hit3; - int hit4; - int mhit; + int hit1; + int hit2; + int hit3; + int hit4; + int mhit; - goertzel_state_t row_out[4]; - goertzel_state_t col_out[4]; - goertzel_state_t row_out2nd[4]; - goertzel_state_t col_out2nd[4]; - goertzel_state_t fax_tone; - goertzel_state_t fax_tone2nd; - float energy; - - int current_sample; - char digits[MAX_DTMF_DIGITS + 1]; - int current_digits; - int detected_digits; - int lost_digits; - int digit_hits[16]; - int fax_hits; + goertzel_state_t row_out[4]; + goertzel_state_t col_out[4]; + goertzel_state_t row_out2nd[4]; + goertzel_state_t col_out2nd[4]; + goertzel_state_t fax_tone; + goertzel_state_t fax_tone2nd; + float energy; + + int current_sample; + char digits[MAX_DTMF_DIGITS + 1]; + int current_digits; + int detected_digits; + int lost_digits; + int digit_hits[16]; + int fax_hits; } dtmf_detect_state_t; typedef struct @@ -400,14 +379,13 @@ typedef struct float fac; } tone_detection_descriptor_t; -void zap_goertzel_update(goertzel_state_t *s, int16_t x[], int samples); -float zap_goertzel_result (goertzel_state_t *s); -void zap_dtmf_detect_init(dtmf_detect_state_t *s); -int zap_dtmf_detect(dtmf_detect_state_t *s, int16_t amp[], int samples, int isradio); -int zap_dtmf_get(dtmf_detect_state_t *s, char *buf, int max); +void zap_goertzel_update(goertzel_state_t* s, int16_t x[], int samples); +float zap_goertzel_result(goertzel_state_t* s); +void zap_dtmf_detect_init(dtmf_detect_state_t* s); +int zap_dtmf_detect(dtmf_detect_state_t* s, int16_t amp[], int samples, int isradio); +int zap_dtmf_get(dtmf_detect_state_t* s, char* buf, int max); -InbandDtmfDetector::InbandDtmfDetector() - :mState(NULL) +InbandDtmfDetector::InbandDtmfDetector() : mState(NULL) { mState = malloc(sizeof(dtmf_detect_state_t)); @@ -423,8 +401,9 @@ InbandDtmfDetector::~InbandDtmfDetector() std::string InbandDtmfDetector::streamPut(unsigned char* samples, unsigned int size) { - char buf[16]; buf[0] = 0; - if (zap_dtmf_detect((dtmf_detect_state_t*)mState, (int16_t*)samples, size/2, 0)) + char buf[16]; + buf[0] = 0; + if (zap_dtmf_detect((dtmf_detect_state_t*)mState, (int16_t*)samples, size / 2, 0)) zap_dtmf_get((dtmf_detect_state_t*)mState, buf, 15); return buf; } @@ -436,16 +415,16 @@ void InbandDtmfDetector::resetState() #ifndef TRUE -# define FALSE 0 -# define TRUE (!FALSE) +#define FALSE 0 +#define TRUE (!FALSE) #endif #ifndef M_PI -#define M_PI 3.14159265358979323846 +#define M_PI 3.14159265358979323846 #endif -//#define USE_3DNOW +// #define USE_3DNOW /* Basic DTMF specs: * @@ -459,17 +438,17 @@ void InbandDtmfDetector::resetState() * Frequency tolerance +- 1.5% will detect, +-3.5% will reject */ -#define SAMPLE_RATE 8000.0 +#define SAMPLE_RATE 8000.0 -#define DTMF_THRESHOLD 8.0e7 -#define FAX_THRESHOLD 8.0e7 -#define FAX_2ND_HARMONIC 2.0 /* 4dB */ -#define DTMF_NORMAL_TWIST 6.3 /* 8dB */ -#define DTMF_REVERSE_TWIST ((isradio) ? 4.0 : 2.5) /* 4dB normal */ -#define DTMF_RELATIVE_PEAK_ROW 6.3 /* 8dB */ -#define DTMF_RELATIVE_PEAK_COL 6.3 /* 8dB */ -#define DTMF_2ND_HARMONIC_ROW ((isradio) ? 1.7 : 2.5) /* 4dB normal */ -#define DTMF_2ND_HARMONIC_COL 63.1 /* 18dB */ +#define DTMF_THRESHOLD 8.0e7 +#define FAX_THRESHOLD 8.0e7 +#define FAX_2ND_HARMONIC 2.0 /* 4dB */ +#define DTMF_NORMAL_TWIST 6.3 /* 8dB */ +#define DTMF_REVERSE_TWIST ((isradio) ? 4.0 : 2.5) /* 4dB normal */ +#define DTMF_RELATIVE_PEAK_ROW 6.3 /* 8dB */ +#define DTMF_RELATIVE_PEAK_COL 6.3 /* 8dB */ +#define DTMF_2ND_HARMONIC_ROW ((isradio) ? 1.7 : 2.5) /* 4dB normal */ +#define DTMF_2ND_HARMONIC_COL 63.1 /* 18dB */ static tone_detection_descriptor_t dtmf_detect_row[4]; static tone_detection_descriptor_t dtmf_detect_col[4]; @@ -478,36 +457,29 @@ static tone_detection_descriptor_t dtmf_detect_col_2nd[4]; static tone_detection_descriptor_t fax_detect; static tone_detection_descriptor_t fax_detect_2nd; -static float dtmf_row[] = - { - 697.0, 770.0, 852.0, 941.0 -}; -static float dtmf_col[] = - { - 1209.0, 1336.0, 1477.0, 1633.0 -}; +static float dtmf_row[] = {697.0, 770.0, 852.0, 941.0}; +static float dtmf_col[] = {1209.0, 1336.0, 1477.0, 1633.0}; -static float fax_freq = 1100.0; +static float fax_freq = 1100.0; -static char dtmf_positions[] = "123A" "456B" "789C" "*0#D"; +static char dtmf_positions[] = "123A" + "456B" + "789C" + "*0#D"; -static void goertzel_init(goertzel_state_t *s, - tone_detection_descriptor_t *t) +static void goertzel_init(goertzel_state_t* s, tone_detection_descriptor_t* t) { - s->v2 = - s->v3 = 0.0; + s->v2 = s->v3 = 0.0; s->fac = t->fac; } /*- End of function --------------------------------------------------------*/ #if defined(USE_3DNOW) -static inline void _dtmf_goertzel_update(goertzel_state_t *s, - float x[], - int samples) +static inline void _dtmf_goertzel_update(goertzel_state_t* s, float x[], int samples) { - int n; + int n; float v; - int i; + int i; float vv[16]; vv[4] = s[0].v2; @@ -523,55 +495,54 @@ static inline void _dtmf_goertzel_update(goertzel_state_t *s, vv[14] = s[2].fac; vv[15] = s[3].fac; - //v1 = s->v2; - //s->v2 = s->v3; - //s->v3 = s->fac*s->v2 - v1 + x[0]; + // v1 = s->v2; + // s->v2 = s->v3; + // s->v3 = s->fac*s->v2 - v1 + x[0]; - __asm__ __volatile__ ( - " femms;\n" + __asm__ __volatile__(" femms;\n" - " movq 16(%%edx),%%mm2;\n" - " movq 24(%%edx),%%mm3;\n" - " movq 32(%%edx),%%mm4;\n" - " movq 40(%%edx),%%mm5;\n" - " movq 48(%%edx),%%mm6;\n" - " movq 56(%%edx),%%mm7;\n" + " movq 16(%%edx),%%mm2;\n" + " movq 24(%%edx),%%mm3;\n" + " movq 32(%%edx),%%mm4;\n" + " movq 40(%%edx),%%mm5;\n" + " movq 48(%%edx),%%mm6;\n" + " movq 56(%%edx),%%mm7;\n" - " jmp 1f;\n" - " .align 32;\n" + " jmp 1f;\n" + " .align 32;\n" - " 1: ;\n" - " prefetch (%%eax);\n" - " movq %%mm3,%%mm1;\n" - " movq %%mm2,%%mm0;\n" - " movq %%mm5,%%mm3;\n" - " movq %%mm4,%%mm2;\n" + " 1: ;\n" + " prefetch (%%eax);\n" + " movq %%mm3,%%mm1;\n" + " movq %%mm2,%%mm0;\n" + " movq %%mm5,%%mm3;\n" + " movq %%mm4,%%mm2;\n" - " pfmul %%mm7,%%mm5;\n" - " pfmul %%mm6,%%mm4;\n" - " pfsub %%mm1,%%mm5;\n" - " pfsub %%mm0,%%mm4;\n" + " pfmul %%mm7,%%mm5;\n" + " pfmul %%mm6,%%mm4;\n" + " pfsub %%mm1,%%mm5;\n" + " pfsub %%mm0,%%mm4;\n" - " movq (%%eax),%%mm0;\n" - " movq %%mm0,%%mm1;\n" - " punpckldq %%mm0,%%mm1;\n" - " add $4,%%eax;\n" - " pfadd %%mm1,%%mm5;\n" - " pfadd %%mm1,%%mm4;\n" + " movq (%%eax),%%mm0;\n" + " movq %%mm0,%%mm1;\n" + " punpckldq %%mm0,%%mm1;\n" + " add $4,%%eax;\n" + " pfadd %%mm1,%%mm5;\n" + " pfadd %%mm1,%%mm4;\n" - " dec %%ecx;\n" + " dec %%ecx;\n" - " jnz 1b;\n" + " jnz 1b;\n" - " movq %%mm2,16(%%edx);\n" - " movq %%mm3,24(%%edx);\n" - " movq %%mm4,32(%%edx);\n" - " movq %%mm5,40(%%edx);\n" + " movq %%mm2,16(%%edx);\n" + " movq %%mm3,24(%%edx);\n" + " movq %%mm4,32(%%edx);\n" + " movq %%mm5,40(%%edx);\n" - " femms;\n" - : - : "c" (samples), "a" (x), "d" (vv) - : "memory", "eax", "ecx"); + " femms;\n" + : + : "c"(samples), "a"(x), "d"(vv) + : "memory", "eax", "ecx"); s[0].v2 = vv[4]; s[1].v2 = vv[5]; @@ -585,67 +556,64 @@ static inline void _dtmf_goertzel_update(goertzel_state_t *s, #endif /*- End of function --------------------------------------------------------*/ -void zap_goertzel_update(goertzel_state_t *s, - int16_t x[], - int samples) +void zap_goertzel_update(goertzel_state_t* s, int16_t x[], int samples) { - int i; + int i; float v1; - - for (i = 0; i < samples; i++) + + for (i = 0; i < samples; i++) { v1 = s->v2; s->v2 = s->v3; - s->v3 = s->fac*s->v2 - v1 + x[i]; + s->v3 = s->fac * s->v2 - v1 + x[i]; } } /*- End of function --------------------------------------------------------*/ -float zap_goertzel_result (goertzel_state_t *s) +float zap_goertzel_result(goertzel_state_t* s) { - return s->v3*s->v3 + s->v2*s->v2 - s->v2*s->v3*s->fac; + return s->v3 * s->v3 + s->v2 * s->v2 - s->v2 * s->v3 * s->fac; } /*- End of function --------------------------------------------------------*/ -void zap_dtmf_detect_init (dtmf_detect_state_t *s) +void zap_dtmf_detect_init(dtmf_detect_state_t* s) { - int i; + int i; float theta; - s->hit1 = - s->hit2 = 0; + s->hit1 = s->hit2 = 0; - for (i = 0; i < 4; i++) + for (i = 0; i < 4; i++) { - theta = float(2.0*M_PI*(dtmf_row[i]/SAMPLE_RATE)); - dtmf_detect_row[i].fac = float(2.0*cos(theta)); + theta = float(2.0 * M_PI * (dtmf_row[i] / SAMPLE_RATE)); + dtmf_detect_row[i].fac = float(2.0 * cos(theta)); - theta = float(2.0*M_PI*(dtmf_col[i]/SAMPLE_RATE)); - dtmf_detect_col[i].fac = float(2.0*cos(theta)); + theta = float(2.0 * M_PI * (dtmf_col[i] / SAMPLE_RATE)); + dtmf_detect_col[i].fac = float(2.0 * cos(theta)); - theta = float(2.0*M_PI*(dtmf_row[i]*2.0/SAMPLE_RATE)); - dtmf_detect_row_2nd[i].fac = float(2.0*cos(theta)); + theta = float(2.0 * M_PI * (dtmf_row[i] * 2.0 / SAMPLE_RATE)); + dtmf_detect_row_2nd[i].fac = float(2.0 * cos(theta)); - theta = float(2.0*M_PI*(dtmf_col[i]*2.0/SAMPLE_RATE)); - dtmf_detect_col_2nd[i].fac = float(2.0*cos(theta)); + theta = float(2.0 * M_PI * (dtmf_col[i] * 2.0 / SAMPLE_RATE)); + dtmf_detect_col_2nd[i].fac = float(2.0 * cos(theta)); - goertzel_init (&s->row_out[i], &dtmf_detect_row[i]); - goertzel_init (&s->col_out[i], &dtmf_detect_col[i]); - goertzel_init (&s->row_out2nd[i], &dtmf_detect_row_2nd[i]); - goertzel_init (&s->col_out2nd[i], &dtmf_detect_col_2nd[i]); + goertzel_init(&s->row_out[i], &dtmf_detect_row[i]); + goertzel_init(&s->col_out[i], &dtmf_detect_col[i]); + goertzel_init(&s->row_out2nd[i], &dtmf_detect_row_2nd[i]); + goertzel_init(&s->col_out2nd[i], &dtmf_detect_col_2nd[i]); s->energy = 0.0; } /* Same for the fax dector */ - theta = float(2.0*M_PI*(fax_freq/SAMPLE_RATE)); + theta = float(2.0 * M_PI * (fax_freq / SAMPLE_RATE)); fax_detect.fac = float(2.0 * cos(theta)); - goertzel_init (&s->fax_tone, &fax_detect); + goertzel_init(&s->fax_tone, &fax_detect); /* Same for the fax dector 2nd harmonic */ - theta = float(2.0*M_PI*(fax_freq * 2.0/SAMPLE_RATE)); + theta = float(2.0 * M_PI * (fax_freq * 2.0 / SAMPLE_RATE)); fax_detect_2nd.fac = float(2.0 * cos(theta)); - goertzel_init (&s->fax_tone2nd, &fax_detect_2nd); + goertzel_init(&s->fax_tone2nd, &fax_detect_2nd); s->current_sample = 0; s->detected_digits = 0; @@ -655,28 +623,24 @@ void zap_dtmf_detect_init (dtmf_detect_state_t *s) } /*- End of function --------------------------------------------------------*/ -int zap_dtmf_detect (dtmf_detect_state_t *s, - int16_t amp[], - int samples, - int isradio) +int zap_dtmf_detect(dtmf_detect_state_t* s, int16_t amp[], int samples, int isradio) { - float row_energy[4]; float col_energy[4]; float fax_energy; float fax_energy_2nd; float famp; float v1; - int i; - int j; - int sample; - int best_row; - int best_col; - int hit; - int limit; + int i; + int j; + int sample; + int best_row; + int best_col; + int hit; + int limit; hit = 0; - for (sample = 0; sample < samples; sample = limit) + for (sample = 0; sample < samples; sample = limit) { /* 102 is optimised to meet the DTMF specs. */ if ((samples - sample) >= (102 - s->current_sample)) @@ -684,95 +648,95 @@ int zap_dtmf_detect (dtmf_detect_state_t *s, else limit = samples; #if defined(USE_3DNOW) - _dtmf_goertzel_update (s->row_out, amp + sample, limit - sample); - _dtmf_goertzel_update (s->col_out, amp + sample, limit - sample); - _dtmf_goertzel_update (s->row_out2nd, amp + sample, limit2 - sample); - _dtmf_goertzel_update (s->col_out2nd, amp + sample, limit2 - sample); + _dtmf_goertzel_update(s->row_out, amp + sample, limit - sample); + _dtmf_goertzel_update(s->col_out, amp + sample, limit - sample); + _dtmf_goertzel_update(s->row_out2nd, amp + sample, limit2 - sample); + _dtmf_goertzel_update(s->col_out2nd, amp + sample, limit2 - sample); /* XXX Need to fax detect for 3dnow too XXX */ #warning "Fax Support Broken" #else - /* The following unrolled loop takes only 35% (rough estimate) of the + /* The following unrolled loop takes only 35% (rough estimate) of the time of a rolled loop on the machine on which it was developed */ - for (j = sample; j < limit; j++) + for (j = sample; j < limit; j++) { famp = amp[j]; - s->energy += famp*famp; + s->energy += famp * famp; /* With GCC 2.95, the following unrolled code seems to take about 35% (rough estimate) as long as a neat little 0-3 loop */ v1 = s->row_out[0].v2; s->row_out[0].v2 = s->row_out[0].v3; - s->row_out[0].v3 = s->row_out[0].fac*s->row_out[0].v2 - v1 + famp; + s->row_out[0].v3 = s->row_out[0].fac * s->row_out[0].v2 - v1 + famp; v1 = s->col_out[0].v2; s->col_out[0].v2 = s->col_out[0].v3; - s->col_out[0].v3 = s->col_out[0].fac*s->col_out[0].v2 - v1 + famp; + s->col_out[0].v3 = s->col_out[0].fac * s->col_out[0].v2 - v1 + famp; v1 = s->row_out[1].v2; s->row_out[1].v2 = s->row_out[1].v3; - s->row_out[1].v3 = s->row_out[1].fac*s->row_out[1].v2 - v1 + famp; + s->row_out[1].v3 = s->row_out[1].fac * s->row_out[1].v2 - v1 + famp; v1 = s->col_out[1].v2; s->col_out[1].v2 = s->col_out[1].v3; - s->col_out[1].v3 = s->col_out[1].fac*s->col_out[1].v2 - v1 + famp; + s->col_out[1].v3 = s->col_out[1].fac * s->col_out[1].v2 - v1 + famp; v1 = s->row_out[2].v2; s->row_out[2].v2 = s->row_out[2].v3; - s->row_out[2].v3 = s->row_out[2].fac*s->row_out[2].v2 - v1 + famp; + s->row_out[2].v3 = s->row_out[2].fac * s->row_out[2].v2 - v1 + famp; v1 = s->col_out[2].v2; s->col_out[2].v2 = s->col_out[2].v3; - s->col_out[2].v3 = s->col_out[2].fac*s->col_out[2].v2 - v1 + famp; + s->col_out[2].v3 = s->col_out[2].fac * s->col_out[2].v2 - v1 + famp; v1 = s->row_out[3].v2; s->row_out[3].v2 = s->row_out[3].v3; - s->row_out[3].v3 = s->row_out[3].fac*s->row_out[3].v2 - v1 + famp; + s->row_out[3].v3 = s->row_out[3].fac * s->row_out[3].v2 - v1 + famp; v1 = s->col_out[3].v2; s->col_out[3].v2 = s->col_out[3].v3; - s->col_out[3].v3 = s->col_out[3].fac*s->col_out[3].v2 - v1 + famp; + s->col_out[3].v3 = s->col_out[3].fac * s->col_out[3].v2 - v1 + famp; v1 = s->col_out2nd[0].v2; s->col_out2nd[0].v2 = s->col_out2nd[0].v3; - s->col_out2nd[0].v3 = s->col_out2nd[0].fac*s->col_out2nd[0].v2 - v1 + famp; + s->col_out2nd[0].v3 = s->col_out2nd[0].fac * s->col_out2nd[0].v2 - v1 + famp; v1 = s->row_out2nd[0].v2; s->row_out2nd[0].v2 = s->row_out2nd[0].v3; - s->row_out2nd[0].v3 = s->row_out2nd[0].fac*s->row_out2nd[0].v2 - v1 + famp; + s->row_out2nd[0].v3 = s->row_out2nd[0].fac * s->row_out2nd[0].v2 - v1 + famp; v1 = s->col_out2nd[1].v2; s->col_out2nd[1].v2 = s->col_out2nd[1].v3; - s->col_out2nd[1].v3 = s->col_out2nd[1].fac*s->col_out2nd[1].v2 - v1 + famp; + s->col_out2nd[1].v3 = s->col_out2nd[1].fac * s->col_out2nd[1].v2 - v1 + famp; v1 = s->row_out2nd[1].v2; s->row_out2nd[1].v2 = s->row_out2nd[1].v3; - s->row_out2nd[1].v3 = s->row_out2nd[1].fac*s->row_out2nd[1].v2 - v1 + famp; + s->row_out2nd[1].v3 = s->row_out2nd[1].fac * s->row_out2nd[1].v2 - v1 + famp; v1 = s->col_out2nd[2].v2; s->col_out2nd[2].v2 = s->col_out2nd[2].v3; - s->col_out2nd[2].v3 = s->col_out2nd[2].fac*s->col_out2nd[2].v2 - v1 + famp; + s->col_out2nd[2].v3 = s->col_out2nd[2].fac * s->col_out2nd[2].v2 - v1 + famp; v1 = s->row_out2nd[2].v2; s->row_out2nd[2].v2 = s->row_out2nd[2].v3; - s->row_out2nd[2].v3 = s->row_out2nd[2].fac*s->row_out2nd[2].v2 - v1 + famp; + s->row_out2nd[2].v3 = s->row_out2nd[2].fac * s->row_out2nd[2].v2 - v1 + famp; v1 = s->col_out2nd[3].v2; s->col_out2nd[3].v2 = s->col_out2nd[3].v3; - s->col_out2nd[3].v3 = s->col_out2nd[3].fac*s->col_out2nd[3].v2 - v1 + famp; + s->col_out2nd[3].v3 = s->col_out2nd[3].fac * s->col_out2nd[3].v2 - v1 + famp; v1 = s->row_out2nd[3].v2; s->row_out2nd[3].v2 = s->row_out2nd[3].v3; - s->row_out2nd[3].v3 = s->row_out2nd[3].fac*s->row_out2nd[3].v2 - v1 + famp; + s->row_out2nd[3].v3 = s->row_out2nd[3].fac * s->row_out2nd[3].v2 - v1 + famp; /* Update fax tone */ v1 = s->fax_tone.v2; s->fax_tone.v2 = s->fax_tone.v3; - s->fax_tone.v3 = s->fax_tone.fac*s->fax_tone.v2 - v1 + famp; + s->fax_tone.v3 = s->fax_tone.fac * s->fax_tone.v2 - v1 + famp; v1 = s->fax_tone2nd.v2; s->fax_tone2nd.v2 = s->fax_tone2nd.v3; - s->fax_tone2nd.v3 = s->fax_tone2nd.fac*s->fax_tone2nd.v2 - v1 + famp; + s->fax_tone2nd.v3 = s->fax_tone2nd.fac * s->fax_tone2nd.v2 - v1 + famp; } #endif s->current_sample += (limit - sample); @@ -784,46 +748,37 @@ int zap_dtmf_detect (dtmf_detect_state_t *s, /* We are at the end of a DTMF detection block */ /* Find the peak row and the peak column */ - row_energy[0] = zap_goertzel_result (&s->row_out[0]); - col_energy[0] = zap_goertzel_result (&s->col_out[0]); + row_energy[0] = zap_goertzel_result(&s->row_out[0]); + col_energy[0] = zap_goertzel_result(&s->col_out[0]); - for (best_row = best_col = 0, i = 1; i < 4; i++) + for (best_row = best_col = 0, i = 1; i < 4; i++) { - row_energy[i] = zap_goertzel_result (&s->row_out[i]); + row_energy[i] = zap_goertzel_result(&s->row_out[i]); if (row_energy[i] > row_energy[best_row]) best_row = i; - col_energy[i] = zap_goertzel_result (&s->col_out[i]); + col_energy[i] = zap_goertzel_result(&s->col_out[i]); if (col_energy[i] > col_energy[best_col]) best_col = i; } hit = 0; /* Basic signal level test and the twist test */ - if (row_energy[best_row] >= DTMF_THRESHOLD - && - col_energy[best_col] >= DTMF_THRESHOLD - && - col_energy[best_col] < row_energy[best_row]*DTMF_REVERSE_TWIST - && - col_energy[best_col]*DTMF_NORMAL_TWIST > row_energy[best_row]) + if (row_energy[best_row] >= DTMF_THRESHOLD && col_energy[best_col] >= DTMF_THRESHOLD && + col_energy[best_col] < row_energy[best_row] * DTMF_REVERSE_TWIST && + col_energy[best_col] * DTMF_NORMAL_TWIST > row_energy[best_row]) { /* Relative peak test */ - for (i = 0; i < 4; i++) + for (i = 0; i < 4; i++) { - if ((i != best_col && col_energy[i]*DTMF_RELATIVE_PEAK_COL > col_energy[best_col]) - || - (i != best_row && row_energy[i]*DTMF_RELATIVE_PEAK_ROW > row_energy[best_row])) + if ((i != best_col && col_energy[i] * DTMF_RELATIVE_PEAK_COL > col_energy[best_col]) || + (i != best_row && row_energy[i] * DTMF_RELATIVE_PEAK_ROW > row_energy[best_row])) { break; } } /* ... and second harmonic test */ - if (i >= 4 - && - (row_energy[best_row] + col_energy[best_col]) > 42.0*s->energy - && - zap_goertzel_result (&s->col_out2nd[best_col])*DTMF_2ND_HARMONIC_COL < col_energy[best_col] - && - zap_goertzel_result (&s->row_out2nd[best_row])*DTMF_2ND_HARMONIC_ROW < row_energy[best_row]) + if (i >= 4 && (row_energy[best_row] + col_energy[best_col]) > 42.0 * s->energy && + zap_goertzel_result(&s->col_out2nd[best_col]) * DTMF_2ND_HARMONIC_COL < col_energy[best_col] && + zap_goertzel_result(&s->row_out2nd[best_row]) * DTMF_2ND_HARMONIC_ROW < row_energy[best_row]) { hit = dtmf_positions[(best_row << 2) + best_col]; /* Look for two successive similar results */ @@ -833,7 +788,7 @@ int zap_dtmf_detect (dtmf_detect_state_t *s, back to back differing digits. More importantly, it can work with nasty phones that give a very wobbly start to a digit. */ - if (hit == s->hit3 && s->hit3 != s->hit2) + if (hit == s->hit3 && s->hit3 != s->hit2) { s->mhit = hit; s->digit_hits[(best_row << 2) + best_col]++; @@ -849,10 +804,12 @@ int zap_dtmf_detect (dtmf_detect_state_t *s, } } } - } - if (!hit && (fax_energy >= FAX_THRESHOLD) && (fax_energy > s->energy * 21.0)) { + } + if (!hit && (fax_energy >= FAX_THRESHOLD) && (fax_energy > s->energy * 21.0)) + { fax_energy_2nd = zap_goertzel_result(&s->fax_tone2nd); - if (fax_energy_2nd * FAX_2ND_HARMONIC < fax_energy) { + if (fax_energy_2nd * FAX_2ND_HARMONIC < fax_energy) + { #if 0 printf("Fax energy/Second Harmonic: %f/%f\n", fax_energy, fax_energy_2nd); #endif @@ -860,8 +817,11 @@ printf("Fax energy/Second Harmonic: %f/%f\n", fax_energy, fax_energy_2nd); hit = 'f'; s->fax_hits++; } /* Don't reset fax hits counter */ - } else { - if (s->fax_hits > 5) { + } + else + { + if (s->fax_hits > 5) + { s->mhit = 'f'; s->detected_digits++; if (s->current_digits < MAX_DTMF_DIGITS) @@ -880,41 +840,37 @@ printf("Fax energy/Second Harmonic: %f/%f\n", fax_energy, fax_energy_2nd); s->hit2 = s->hit3; s->hit3 = hit; /* Reinitialise the detector for the next block */ - for (i = 0; i < 4; i++) + for (i = 0; i < 4; i++) { - goertzel_init (&s->row_out[i], &dtmf_detect_row[i]); - goertzel_init (&s->col_out[i], &dtmf_detect_col[i]); - goertzel_init (&s->row_out2nd[i], &dtmf_detect_row_2nd[i]); - goertzel_init (&s->col_out2nd[i], &dtmf_detect_col_2nd[i]); + goertzel_init(&s->row_out[i], &dtmf_detect_row[i]); + goertzel_init(&s->col_out[i], &dtmf_detect_col[i]); + goertzel_init(&s->row_out2nd[i], &dtmf_detect_row_2nd[i]); + goertzel_init(&s->col_out2nd[i], &dtmf_detect_col_2nd[i]); } - goertzel_init (&s->fax_tone, &fax_detect); - goertzel_init (&s->fax_tone2nd, &fax_detect_2nd); + goertzel_init(&s->fax_tone, &fax_detect); + goertzel_init(&s->fax_tone2nd, &fax_detect_2nd); s->energy = 0.0; s->current_sample = 0; } if ((!s->mhit) || (s->mhit != hit)) { s->mhit = 0; - return(0); + return (0); } return (hit); } /*- End of function --------------------------------------------------------*/ -int zap_dtmf_get (dtmf_detect_state_t *s, - char *buf, - int max) +int zap_dtmf_get(dtmf_detect_state_t* s, char* buf, int max) { if (max > s->current_digits) max = s->current_digits; if (max > 0) { - memcpy (buf, s->digits, max); - memmove (s->digits, s->digits + max, s->current_digits - max); + memcpy(buf, s->digits, max); + memmove(s->digits, s->digits + max, s->current_digits - max); s->current_digits -= max; } buf[max] = '\0'; - return max; + return max; } - - diff --git a/src/engine/media/MT_Dtmf.h b/src/engine/media/MT_Dtmf.h index b0732377..129b58f5 100644 --- a/src/engine/media/MT_Dtmf.h +++ b/src/engine/media/MT_Dtmf.h @@ -21,28 +21,29 @@ public: struct Rfc2833Event { char mTone = 0; - int mDuration = 0; - int mVolume = 0; + int mDuration = 0; + int mVolume = 0; bool mEnd = false; - bool isValid() const { - return mTone != 0; - } + bool isValid() const { return mTone != 0; } }; // Output should be 4 bytes length - static void buildRfc2833(const Rfc2833Event& ev, void* output); + static void buildRfc2833(const Rfc2833Event& ev, void* output); static Rfc2833Event parseRfc2833(std::span payload); // Buf receives PCM audio - static void buildInband(int tone, int startTime, int finishTime, int rate, short* buf); + static void buildInband(int tone, int startTime, int finishTime, int rate, short* buf); }; struct Dtmf { - Dtmf(): mTone(0), mDuration(0), mVolume(0), mFinishCount(3), mCurrentTime(0), mStopped(false) {} - Dtmf(int tone, int volume, int duration): mTone(tone), mVolume(volume), mDuration(duration), mFinishCount(3), mCurrentTime(0), mStopped(false) {} + Dtmf() : mTone(0), mDuration(0), mVolume(0), mFinishCount(3), mCurrentTime(0), mStopped(false) {} + Dtmf(int tone, int volume, int duration) + : mTone(tone), mVolume(volume), mDuration(duration), mFinishCount(3), mCurrentTime(0), mStopped(false) + { + } int mStopped; int mTone; @@ -80,8 +81,8 @@ public: bool getRfc2833(int milliseconds, ByteBuffer& output, ByteBuffer& stopPacket); protected: - Mutex mGuard; - Type mType; + Mutex mGuard; + Type mType; DtmfQueue mQueue; }; @@ -95,18 +96,18 @@ public: ~InbandDtmfDetector(); /*! This method receives the input PCM 16-bit data and returns found DTMF event(s) in string representation. - * @param samples Input PCM buffer pointer. - * @param size Size of input buffer in bytes - * @return Found DTMF event(s) in string representation. The returned value has variable length. - */ + * @param samples Input PCM buffer pointer. + * @param size Size of input buffer in bytes + * @return Found DTMF event(s) in string representation. The returned value has variable length. + */ std::string streamPut(unsigned char* samples, unsigned int size); - void resetState(); + void resetState(); protected: void* mState; /// DTMF detector context }; -} +} // namespace MT #endif diff --git a/src/engine/media/MT_EvsCodec.cpp b/src/engine/media/MT_EvsCodec.cpp index 658f8bf0..dc7d60a9 100644 --- a/src/engine/media/MT_EvsCodec.cpp +++ b/src/engine/media/MT_EvsCodec.cpp @@ -3,133 +3,86 @@ #include /*-------------------------------------------------------------------* -* rate2AMRWB_IOmode() -* -* lookup AMRWB IO mode -*-------------------------------------------------------------------*/ -namespace evs { -extern Word16 rate2AMRWB_IOmode( - Word32 rate /* i: bit rate */ + * rate2AMRWB_IOmode() + * + * lookup AMRWB IO mode + *-------------------------------------------------------------------*/ +namespace evs +{ +extern Word16 rate2AMRWB_IOmode(Word32 rate /* i: bit rate */ ); /*Revers Function*/ -extern Word16 AMRWB_IOmode2rate( - Word32 mode -); +extern Word16 AMRWB_IOmode2rate(Word32 mode); /*-------------------------------------------------------------------* -* rate2EVSmode() -* -* lookup EVS mode -*-------------------------------------------------------------------*/ -extern Word16 rate2EVSmode( - Word32 rate /* i: bit rate */ + * rate2EVSmode() + * + * lookup EVS mode + *-------------------------------------------------------------------*/ +extern Word16 rate2EVSmode(Word32 rate /* i: bit rate */ ); /*Revers Function*/ -extern Word16 EVSmode2rate( - Word32 mode -); +extern Word16 EVSmode2rate(Word32 mode); -#define CMR_OFF -1 -#define CMR_ON 0 -#define CMR_ONLY 1 +#define CMR_OFF -1 +#define CMR_ON 0 +#define CMR_ONLY 1 -} +} // namespace evs static const std::map> BitrateToBandwidth_Tab{ - {5900, {NB, WB}}, - {7200, {NB, WB}}, - {8000, {NB, WB}}, - {9600, {NB, WB, SWB}}, - {13200, {NB, WB, SWB}}, //if channel aware mode - WB, SWB - {16400, {NB, WB, SWB, FB}}, - {24400, {NB, WB, SWB, FB}}, - {32000, {WB, SWB, FB}}, - {48000, {WB, SWB, FB}}, - {64000, {WB, SWB, FB}}, - {96000, {WB, SWB, FB}}, - {128000, {WB, SWB, FB}} -}; + {5900, {NB, WB}}, {7200, {NB, WB}}, {8000, {NB, WB}}, {9600, {NB, WB, SWB}}, + {13200, {NB, WB, SWB}}, // if channel aware mode - WB, SWB + {16400, {NB, WB, SWB, FB}}, {24400, {NB, WB, SWB, FB}}, {32000, {WB, SWB, FB}}, {48000, {WB, SWB, FB}}, + {64000, {WB, SWB, FB}}, {96000, {WB, SWB, FB}}, {128000, {WB, SWB, FB}}}; /* Protected payload size/Fixed bitrate to EVS ()*/ static const std::map Bitrate2PayloadSize_EVSAMR_WB{ - /*{bitrate, payload size}*/ - { SID_1k75, 56}, //AMR-WB I/O SIB - {ACELP_6k60, 136}, - {ACELP_8k85, 184}, - {ACELP_12k65, 256}, - {ACELP_14k25, 288}, - {ACELP_15k85, 320}, - {ACELP_18k25, 368}, - {ACELP_19k85, 400}, - {ACELP_23k05, 464}, - {ACELP_23k85, 480} -}; + /*{bitrate, payload size}*/ + {SID_1k75, 56}, // AMR-WB I/O SIB + {ACELP_6k60, 136}, {ACELP_8k85, 184}, {ACELP_12k65, 256}, {ACELP_14k25, 288}, {ACELP_15k85, 320}, + {ACELP_18k25, 368}, {ACELP_19k85, 400}, {ACELP_23k05, 464}, {ACELP_23k85, 480}}; -static const std::map Bitrate2PayloadSize_EVS{ - /*{bitrate, payload size}*/ - {FRAME__NO_DATA, 0}, - {SID_2k40, 48}, //EVS Primary SID - {PPP_NELP_2k80, 56}, //special for full header - {ACELP_7k20, 144}, - {ACELP_8k00, 160}, - {ACELP_9k60, 192}, - {ACELP_13k20, 264}, - {ACELP_16k40, 328}, - {ACELP_24k40, 488}, - {ACELP_32k, 640}, - {ACELP_48k, 960}, - {ACELP_64k, 1280}, - {HQ_96k, 1920}, - {HQ_128k, 2560} -}; +static const std::map Bitrate2PayloadSize_EVS{ /*{bitrate, payload size}*/ + {FRAME__NO_DATA, 0}, {SID_2k40, 48}, // EVS Primary SID + {PPP_NELP_2k80, 56}, // special for full header + {ACELP_7k20, 144}, {ACELP_8k00, 160}, {ACELP_9k60, 192}, + {ACELP_13k20, 264}, {ACELP_16k40, 328}, {ACELP_24k40, 488}, + {ACELP_32k, 640}, {ACELP_48k, 960}, {ACELP_64k, 1280}, + {HQ_96k, 1920}, {HQ_128k, 2560}}; /* Protected payload size/Fixed bitrate to EVS ()*/ -static const std::map FixedPayload_EVSPrimary{ - /*{payload size , bitrate}*/ - {48, 2400}, //EVS Primary SID - {56, 2800}, //special for full header - {144, 7200}, - {160, 8000}, - {192, 9600}, - {264, 13200}, - {328, 16400}, - {488, 24400}, - {640, 32000}, - {960, 48000}, - {1280, 64000}, - {1920, 96000}, - {2560, 128000} -}; +static const std::map FixedPayload_EVSPrimary{ /*{payload size , bitrate}*/ + {48, 2400}, // EVS Primary SID + {56, 2800}, // special for full header + {144, 7200}, {160, 8000}, {192, 9600}, {264, 13200}, + {328, 16400}, {488, 24400}, {640, 32000}, {960, 48000}, + {1280, 64000}, {1920, 96000}, {2560, 128000}}; -static const std::map FixedPayload_EVSAMR_WB{ - /*{payload size , bitrate}*/ - {136, 6600}, - {184, 8850}, - {256, 12650}, - {288, 14250}, - {320, 15850}, - {368, 18250}, - {400, 19850}, - {464, 23050}, - {480, 23850} -}; +static const std::map FixedPayload_EVSAMR_WB{/*{payload size , bitrate}*/ + {136, 6600}, {184, 8850}, {256, 12650}, + {288, 14250}, {320, 15850}, {368, 18250}, + {400, 19850}, {464, 23050}, {480, 23850}}; namespace MT { -EVSCodec::EVSFactory::EVSFactory(StreamParameters& sp) : _sp(sp) -{} +EVSCodec::EVSFactory::EVSFactory(StreamParameters& sp) : _sp(sp) {} int EVSCodec::EVSFactory::samplerate() { switch (_sp.bw) { - case 0: return 8000; - case 1: return 16000; - case 2: return 32000; - case 3: return 48000; + case 0: + return 8000; + case 1: + return 16000; + case 2: + return 32000; + case 3: + return 48000; } return 0; @@ -145,12 +98,11 @@ PCodec EVSCodec::EVSFactory::create() return std::static_pointer_cast(std::make_shared(_sp)); } -EVSCodec::EVSCodec(): EVSCodec(StreamParameters()) -{} +EVSCodec::EVSCodec() : EVSCodec(StreamParameters()) {} -EVSCodec::EVSCodec(const StreamParameters &sp) +EVSCodec::EVSCodec(const StreamParameters& sp) { - EVSCodec::sp = sp; + EVSCodec::sp = sp; // Metadata only - the heavy decoder state is created lazily (ensureDecoder()). mOutputFs = outputFsFromBw(sp.bw); @@ -160,10 +112,14 @@ int EVSCodec::outputFsFromBw(int bw) { switch (bw) { - case NB: return 8000; - case WB: return 16000; - case SWB: return 32000; - case FB: return 48000; + case NB: + return 8000; + case WB: + return 16000; + case SWB: + return 32000; + case FB: + return 48000; } return 0; } @@ -184,19 +140,19 @@ EVSCodec::~EVSCodec() if (st_dec) { destroy_decoder(st_dec); - free(st_dec); st_dec = nullptr; + free(st_dec); + st_dec = nullptr; } } -Codec::Info EVSCodec::info() { - return { - .mName = MT_EVS_CODECNAME, - .mSamplerate = mOutputFs, - .mChannels = 1, - .mPcmLength = mOutputFs / 1000 * sp.ptime * 2, - .mFrameTime = sp.ptime, - .mRtpLength = 0 - }; +Codec::Info EVSCodec::info() +{ + return {.mName = MT_EVS_CODECNAME, + .mSamplerate = mOutputFs, + .mChannels = 1, + .mPcmLength = mOutputFs / 1000 * sp.ptime * 2, + .mFrameTime = sp.ptime, + .mRtpLength = 0}; } @@ -216,7 +172,7 @@ Codec::DecodeResult EVSCodec::decode(std::span input, std::span input, std::span(input.data()), input.size_bytes()); } else // Skip CMR byte - buffer = std::string(reinterpret_cast(input.data()) + 1, input.size_bytes()-1); + buffer = std::string(reinterpret_cast(input.data()) + 1, input.size_bytes() - 1); // Output buffer for 48 KHz - float data[L_FRAME48k]; - int offset = 0; + float data[L_FRAME48k]; + int offset = 0; /* Decode process */ size_t buffer_processed = 0; - while (st_dec->bitstreamformat == evs::G192 ? read_indices(st_dec, buffer.c_str(), buffer.size(), &buffer_processed, 0) : read_indices_mime(st_dec, buffer.c_str(), buffer.size(), &buffer_processed, 0)) - { - if (st_dec->codec_mode == MODE1) - { + while (st_dec->bitstreamformat == evs::G192 + ? read_indices(st_dec, buffer.c_str(), buffer.size(), &buffer_processed, 0) + : read_indices_mime(st_dec, buffer.c_str(), buffer.size(), &buffer_processed, 0)) + { + if (st_dec->codec_mode == MODE1) + { if (st_dec->Opt_AMR_WB) - { + { amr_wb_dec(st_dec, data); - } - else - { + } + else + { evs_dec(st_dec, data, evs::FRAMEMODE_NORMAL); - } - } - else - { + } + } + else + { if (!st_dec->bfi) - { + { evs_dec(st_dec, data, evs::FRAMEMODE_NORMAL); - } - else - { + } + else + { evs_dec(st_dec, data, evs::FRAMEMODE_MISSING); - } - } + } + } - /* convert 'float' output data to 'short' */ + /* convert 'float' output data to 'short' */ evs::syn_output(data, static_cast(pcmLength() / 2), reinterpret_cast(output.data()) + offset); offset += pcmLength() / 2; if (st_dec->ini_frame < MAX_FRAME_COUNTER) - { + { st_dec->ini_frame++; - } - } + } + } return {.mDecoded = (size_t)pcmLength()}; } @@ -295,42 +253,44 @@ size_t EVSCodec::plc(int lostFrames, std::span output) void EVSCodec::initDecoder(const StreamParameters& sp) { - /* set to NULL, to avoid reading of uninitialized memory in case of early abort */ + /* set to NULL, to avoid reading of uninitialized memory in case of early abort */ st_dec->cldfbAna = st_dec->cldfbBPF = st_dec->cldfbSyn = nullptr; st_dec->hFdCngDec = nullptr; - st_dec->codec_mode = 0; /* unknown before first frame */ + st_dec->codec_mode = 0; /* unknown before first frame */ st_dec->Opt_AMR_WB = 0; st_dec->Opt_VOIP = 0; st_dec->bitstreamformat = evs::G192; - st_dec->amrwb_rfc4867_flag = -1; + st_dec->amrwb_rfc4867_flag = -1; - /*Set MIME type*/ - if (sp.mime) { + /*Set MIME type*/ + if (sp.mime) + { st_dec->bitstreamformat = evs::MIME; - st_dec->amrwb_rfc4867_flag = 0; - } - /*Set Bandwidth*/ - switch (sp.bw) { - case NB : + st_dec->amrwb_rfc4867_flag = 0; + } + /*Set Bandwidth*/ + switch (sp.bw) + { + case NB: st_dec->output_Fs = 8000; - break; - case WB: + break; + case WB: st_dec->output_Fs = 16000; - break; - case SWB: + break; + case SWB: st_dec->output_Fs = 32000; - break; - case FB: + break; + case FB: st_dec->output_Fs = 48000; - break; - } + break; + } // st_enc->input_Fs = st_dec->output_Fs; //TODO: remove when func initEncoder() is added - /*------------------------------------------------------------------------------------------* - * Allocate memory for static variables - * Decoder initialization - *------------------------------------------------------------------------------------------*/ - + /*------------------------------------------------------------------------------------------* + * Allocate memory for static variables + * Decoder initialization + *------------------------------------------------------------------------------------------*/ + // TODO: add ability of reinit Decoder_state, may be need use destroy_decoder() init_decoder(st_dec); reset_indices_dec(st_dec); diff --git a/src/engine/media/MT_EvsCodec.h b/src/engine/media/MT_EvsCodec.h index fa6418b3..cea23d9d 100644 --- a/src/engine/media/MT_EvsCodec.h +++ b/src/engine/media/MT_EvsCodec.h @@ -12,7 +12,8 @@ #include "libevs/lib_com/prot.h" -namespace MT { +namespace MT +{ class EVSCodec : public Codec { @@ -20,13 +21,13 @@ public: // Emulated SDP config/media type parameters struct StreamParameters { - bool mime = false; /* encoding */ - bool fh_only = false; /* not use*/ - int CRMByte = -1/*CMR_OFF*/; /* not use*/ - int br = 0; /* not use*/ - int bw = NB; /* bandwidth */ - int ptime = 20; /* ptime */ - int ptype = -1; /* payload type */ + bool mime = false; /* encoding */ + bool fh_only = false; /* not use*/ + int CRMByte = -1 /*CMR_OFF*/; /* not use*/ + int br = 0; /* not use*/ + int bw = NB; /* bandwidth */ + int ptime = 20; /* ptime */ + int ptype = -1; /* payload type */ }; public: @@ -38,17 +39,17 @@ public: public: EVSFactory(StreamParameters& sp); const char* name() { return MT_EVS_CODECNAME; } - int samplerate(); - int payloadType(); - PCodec create(); - int channels() { return 1; } //without support stereo audio transmition + int samplerate(); + int payloadType(); + PCodec create(); + int channels() { return 1; } // without support stereo audio transmition }; EVSCodec(); EVSCodec(const StreamParameters& sp); ~EVSCodec() override; - Info info() override; + Info info() override; EncodeResult encode(std::span input, std::span output) override; DecodeResult decode(std::span input, std::span output) override; @@ -56,24 +57,24 @@ public: private: evs::Decoder_State* st_dec = nullptr; - StreamParameters sp; + StreamParameters sp; // Output sample rate, derived from the negotiated bandwidth (sp.bw) at // construction. Cached so info()/samplerate()/pcmLength() work for network-MOS // metadata without allocating the (large) EVS decoder state - see ensureDecoder. - int mOutputFs = 0; + int mOutputFs = 0; - void initDecoder(const StreamParameters& sp); + void initDecoder(const StreamParameters& sp); // Allocate + initialize the EVS decoder state lazily on first decode(). // Network-MOS-only streams resolve metadata but never decode, so they never // pay for the EVS decoder (Decoder_State + CLDFB/FD-CNG sub-allocations). - void ensureDecoder(); + void ensureDecoder(); // Maps an EVS bandwidth (NB/WB/SWB/FB) to its output sample rate in Hz. - static int outputFsFromBw(int bw); + static int outputFsFromBw(int bw); }; -} // End of namespace +} // namespace MT #endif diff --git a/src/engine/media/MT_NativeRtpSender.cpp b/src/engine/media/MT_NativeRtpSender.cpp index 54baa14d..e588654a 100644 --- a/src/engine/media/MT_NativeRtpSender.cpp +++ b/src/engine/media/MT_NativeRtpSender.cpp @@ -10,16 +10,11 @@ #define LOG_SUBSYSTEM "media" using namespace MT; -NativeRtpSender::NativeRtpSender(Statistics& stat) - :mStat(stat), mSrtpSession(nullptr) -{ -} +NativeRtpSender::NativeRtpSender(Statistics& stat) : mStat(stat), mSrtpSession(nullptr) {} -NativeRtpSender::~NativeRtpSender() -{ -} +NativeRtpSender::~NativeRtpSender() {} -bool NativeRtpSender::SendRTP(const void *data, size_t len) +bool NativeRtpSender::SendRTP(const void* data, size_t len) { if (mTarget.mRtp.isEmpty() || !mSocket.mRtp) return false; @@ -43,7 +38,7 @@ bool NativeRtpSender::SendRTP(const void *data, size_t len) } } - ICELogMedia(<< "Sending " << sendLength <<" bytes to " << mTarget.mRtp.toBriefStdString()); + ICELogMedia(<< "Sending " << sendLength << " bytes to " << mTarget.mRtp.toBriefStdString()); mSocket.mRtp->sendDatagram(mTarget.mRtp, mSendBuffer, sendLength); mStat.mSentRtp++; mStat.mSent += len; @@ -55,7 +50,7 @@ bool NativeRtpSender::SendRTP(const void *data, size_t len) } /** This member function will be called when an RTCP packet needs to be transmitted. */ -bool NativeRtpSender::SendRTCP(const void *data, size_t len) +bool NativeRtpSender::SendRTCP(const void* data, size_t len) { if (mTarget.mRtp.isEmpty() || !mSocket.mRtcp) return false; @@ -85,7 +80,7 @@ bool NativeRtpSender::SendRTCP(const void *data, size_t len) /** Used to identify if an RTPAddress instance originated from this sender (to be able to detect own packets). */ -bool NativeRtpSender::ComesFromThisSender(const jrtplib::RTPAddress *a) +bool NativeRtpSender::ComesFromThisSender(const jrtplib::RTPAddress* a) { return false; } @@ -111,7 +106,7 @@ RtpPair& NativeRtpSender::socket() } #if defined(USE_RTPDUMP) -void NativeRtpSender::setDumpWriter(RtpDump *dump) +void NativeRtpSender::setDumpWriter(RtpDump* dump) { mDumpWriter = dump; } @@ -131,4 +126,3 @@ SrtpSession* NativeRtpSender::srtpSession() { return mSrtpSession; } - diff --git a/src/engine/media/MT_NativeRtpSender.h b/src/engine/media/MT_NativeRtpSender.h index e0e7a201..32c99dc1 100644 --- a/src/engine/media/MT_NativeRtpSender.h +++ b/src/engine/media/MT_NativeRtpSender.h @@ -18,44 +18,44 @@ namespace MT { -class NativeRtpSender: public jrtplib::RTPExternalSender +class NativeRtpSender : public jrtplib::RTPExternalSender { public: NativeRtpSender(Statistics& stat); ~NativeRtpSender(); - + /** This member function will be called when RTP data needs to be transmitted. */ - bool SendRTP(const void *data, size_t len); + bool SendRTP(const void* data, size_t len); /** This member function will be called when an RTCP packet needs to be transmitted. */ - bool SendRTCP(const void *data, size_t len); + bool SendRTCP(const void* data, size_t len); /** Used to identify if an RTPAddress instance originated from this sender (to be able to detect own packets). */ - bool ComesFromThisSender(const jrtplib::RTPAddress *a); - - void setDestination(RtpPair destination); - RtpPair destination(); + bool ComesFromThisSender(const jrtplib::RTPAddress* a); - void setSocket(const RtpPair& socket); + void setDestination(RtpPair destination); + RtpPair destination(); + + void setSocket(const RtpPair& socket); RtpPair& socket(); - + #if defined(USE_RTPDUMP) - void setDumpWriter(RtpDump* dump); + void setDumpWriter(RtpDump* dump); RtpDump* dumpWriter(); #endif - void setSrtpSession(SrtpSession* srtp); + void setSrtpSession(SrtpSession* srtp); SrtpSession* srtpSession(); protected: RtpPair mSocket; RtpPair mTarget; - Statistics& mStat; + Statistics& mStat; #if defined(USE_RTPDUMP) RtpDump* mDumpWriter = nullptr; #endif SrtpSession* mSrtpSession; - char mSendBuffer[MAX_VALID_UDPPACKET_SIZE]; + char mSendBuffer[MAX_VALID_UDPPACKET_SIZE]; }; -} +} // namespace MT #endif diff --git a/src/engine/media/MT_SingleAudioStream.cpp b/src/engine/media/MT_SingleAudioStream.cpp index 8dac1ee6..35fa4421 100644 --- a/src/engine/media/MT_SingleAudioStream.cpp +++ b/src/engine/media/MT_SingleAudioStream.cpp @@ -5,7 +5,7 @@ #include "MT_SingleAudioStream.h" #include "MT_CodecList.h" -//#include "resip/stack/SdpContents.hxx" +// #include "resip/stack/SdpContents.hxx" #include "../engine/helper/HL_Log.h" #define LOG_SUBSYSTEM "media" @@ -13,12 +13,11 @@ using namespace MT; SingleAudioStream::SingleAudioStream(const CodecList::Settings& codecSettings, Statistics& stat) - :mReceiver(codecSettings, stat), - mDtmfReceiver(stat) -{} + : mReceiver(codecSettings, stat), mDtmfReceiver(stat) +{ +} -SingleAudioStream::~SingleAudioStream() -{} +SingleAudioStream::~SingleAudioStream() {} void SingleAudioStream::process(const std::shared_ptr& packet) { @@ -35,27 +34,26 @@ void SingleAudioStream::copyPcmTo(Audio::DataWindow& output, int needed) while (output.filled() < needed) { // Number of bytes to fill on this step - auto requested = needed - output.filled(); + auto requested = needed - output.filled(); // requested is in bytes: 16-bit samples at AUDIO_SAMPLERATE/AUDIO_CHANNELS constexpr int bytesPerMs = AUDIO_SAMPLERATE / 1000 * sizeof(int16_t) * AUDIO_CHANNELS; - auto options = AudioReceiver::DecodeOptions{ - .mRealtimeProcessing = true, - .mResampleToMainRate = true, - .mSkipDecode = false, - .mElapsed = std::chrono::milliseconds(requested / bytesPerMs) - }; + auto options = AudioReceiver::DecodeOptions{.mRealtimeProcessing = true, + .mResampleToMainRate = true, + .mSkipDecode = false, + .mElapsed = std::chrono::milliseconds(requested / bytesPerMs)}; // Try to get the data from receiver / decoder - if (options.mElapsed != 0ms) { + if (options.mElapsed != 0ms) + { if (mReceiver.getAudioTo(output, options).mStatus != AudioReceiver::DecodeResult::Status::Ok) break; - } else + } + else break; } // if (output.filled() < needed) // ICELogError(<< "Not enough data for speaker's mixer"); } - diff --git a/src/engine/media/MT_SingleAudioStream.h b/src/engine/media/MT_SingleAudioStream.h index 7c468819..c284a104 100644 --- a/src/engine/media/MT_SingleAudioStream.h +++ b/src/engine/media/MT_SingleAudioStream.h @@ -22,10 +22,10 @@ public: void copyPcmTo(Audio::DataWindow& output, int needed); protected: - DtmfReceiver mDtmfReceiver; + DtmfReceiver mDtmfReceiver; AudioReceiver mReceiver; }; typedef std::map AudioStreamMap; -} +} // namespace MT #endif diff --git a/src/engine/media/MT_SrtpHelper.cpp b/src/engine/media/MT_SrtpHelper.cpp index e971f7ee..8fedb29c 100644 --- a/src/engine/media/MT_SrtpHelper.cpp +++ b/src/engine/media/MT_SrtpHelper.cpp @@ -14,25 +14,24 @@ struct SrtpSuiteAndName { - SrtpSuite mSuite; + SrtpSuite mSuite; std::string mName, mAltName; }; -std::vector SrtpSuiteList { - { SRTP_AES_256_AUTH_80, "AES_CM_256_HMAC_SHA1_80", "AES_256_CM_HMAC_SHA1_80" }, - { SRTP_AES_128_AUTH_80, "AES_CM_128_HMAC_SHA1_80", "AES_128_CM_HMAC_SHA1_80" }, - { SRTP_AES_192_AUTH_80, "AES_CM_192_HMAC_SHA1_80", "AES_192_CM_HMAC_SHA1_80" }, - { SRTP_AES_256_AUTH_32, "AES_CM_256_HMAC_SHA1_32", "AES_256_CM_HMAC_SHA1_32" }, - { SRTP_AES_192_AUTH_32, "AES_CM_192_HMAC_SHA1_32", "AES_192_CM_HMAC_SHA1_32" }, - { SRTP_AES_128_AUTH_32, "AES_CM_128_HMAC_SHA1_32", "AES_128_CM_HMAC_SHA1_32" }, - { SRTP_AES_128_AUTH_NULL, "AES_CM_128_NULL_AUTH", "AES_128_CM_NULL_AUTH"}, - { SRTP_AED_AES_256_GCM, "AEAD_AES_256_GCM"}, - { SRTP_AED_AES_128_GCM, "AEAD_AES_128_GCM"} -}; +std::vector SrtpSuiteList{ + {SRTP_AES_256_AUTH_80, "AES_CM_256_HMAC_SHA1_80", "AES_256_CM_HMAC_SHA1_80"}, + {SRTP_AES_128_AUTH_80, "AES_CM_128_HMAC_SHA1_80", "AES_128_CM_HMAC_SHA1_80"}, + {SRTP_AES_192_AUTH_80, "AES_CM_192_HMAC_SHA1_80", "AES_192_CM_HMAC_SHA1_80"}, + {SRTP_AES_256_AUTH_32, "AES_CM_256_HMAC_SHA1_32", "AES_256_CM_HMAC_SHA1_32"}, + {SRTP_AES_192_AUTH_32, "AES_CM_192_HMAC_SHA1_32", "AES_192_CM_HMAC_SHA1_32"}, + {SRTP_AES_128_AUTH_32, "AES_CM_128_HMAC_SHA1_32", "AES_128_CM_HMAC_SHA1_32"}, + {SRTP_AES_128_AUTH_NULL, "AES_CM_128_NULL_AUTH", "AES_128_CM_NULL_AUTH"}, + {SRTP_AED_AES_256_GCM, "AEAD_AES_256_GCM"}, + {SRTP_AED_AES_128_GCM, "AEAD_AES_128_GCM"}}; -extern SrtpSuite toSrtpSuite(const std::string_view& s) +extern SrtpSuite toSrtpSuite(const std::string_view& s) { - for (const auto& suite: SrtpSuiteList) + for (const auto& suite : SrtpSuiteList) if (s == suite.mName || s == suite.mAltName) return suite.mSuite; @@ -41,7 +40,7 @@ extern SrtpSuite toSrtpSuite(const std::string_view& s) extern std::string_view toString(SrtpSuite suite) { - for (const auto& item: SrtpSuiteList) + for (const auto& item : SrtpSuiteList) if (item.mSuite == suite) return item.mName; @@ -52,36 +51,65 @@ extern int srtpSuiteStrength(SrtpSuite suite) { switch (suite) { - case SRTP_NONE: return 0; - case SRTP_AES_128_AUTH_NULL: return 1; // no authentication - weakest - case SRTP_AES_128_AUTH_32: return 2; - case SRTP_AES_192_AUTH_32: return 3; - case SRTP_AES_256_AUTH_32: return 4; - case SRTP_AES_128_AUTH_80: return 5; - case SRTP_AES_192_AUTH_80: return 6; - case SRTP_AES_256_AUTH_80: return 7; - case SRTP_AED_AES_128_GCM: return 8; - case SRTP_AED_AES_256_GCM: return 9; + case SRTP_NONE: + return 0; + case SRTP_AES_128_AUTH_NULL: + return 1; // no authentication - weakest + case SRTP_AES_128_AUTH_32: + return 2; + case SRTP_AES_192_AUTH_32: + return 3; + case SRTP_AES_256_AUTH_32: + return 4; + case SRTP_AES_128_AUTH_80: + return 5; + case SRTP_AES_192_AUTH_80: + return 6; + case SRTP_AES_256_AUTH_80: + return 7; + case SRTP_AED_AES_128_GCM: + return 8; + case SRTP_AED_AES_256_GCM: + return 9; } return 0; } -typedef void (*set_srtp_policy_function) (srtp_crypto_policy_t*); +typedef void (*set_srtp_policy_function)(srtp_crypto_policy_t*); set_srtp_policy_function findPolicyFunction(SrtpSuite suite) { switch (suite) { - case SRTP_AES_128_AUTH_80: return &srtp_crypto_policy_set_rtp_default; break; - case SRTP_AES_192_AUTH_80: return &srtp_crypto_policy_set_aes_cm_192_hmac_sha1_80; break; - case SRTP_AES_256_AUTH_80: return &srtp_crypto_policy_set_aes_cm_256_hmac_sha1_80; break; - case SRTP_AES_128_AUTH_32: return &srtp_crypto_policy_set_aes_cm_128_hmac_sha1_32; break; - case SRTP_AES_192_AUTH_32: return &srtp_crypto_policy_set_aes_cm_192_hmac_sha1_32; break; - case SRTP_AES_256_AUTH_32: return &srtp_crypto_policy_set_aes_cm_256_hmac_sha1_32; break; - case SRTP_AES_128_AUTH_NULL: return &srtp_crypto_policy_set_aes_cm_128_null_auth; break; - case SRTP_AED_AES_256_GCM: return &srtp_crypto_policy_set_aes_gcm_256_16_auth; break; - case SRTP_AED_AES_128_GCM: return &srtp_crypto_policy_set_aes_gcm_128_16_auth; break; - case SRTP_NONE: return nullptr; + case SRTP_AES_128_AUTH_80: + return &srtp_crypto_policy_set_rtp_default; + break; + case SRTP_AES_192_AUTH_80: + return &srtp_crypto_policy_set_aes_cm_192_hmac_sha1_80; + break; + case SRTP_AES_256_AUTH_80: + return &srtp_crypto_policy_set_aes_cm_256_hmac_sha1_80; + break; + case SRTP_AES_128_AUTH_32: + return &srtp_crypto_policy_set_aes_cm_128_hmac_sha1_32; + break; + case SRTP_AES_192_AUTH_32: + return &srtp_crypto_policy_set_aes_cm_192_hmac_sha1_32; + break; + case SRTP_AES_256_AUTH_32: + return &srtp_crypto_policy_set_aes_cm_256_hmac_sha1_32; + break; + case SRTP_AES_128_AUTH_NULL: + return &srtp_crypto_policy_set_aes_cm_128_null_auth; + break; + case SRTP_AED_AES_256_GCM: + return &srtp_crypto_policy_set_aes_gcm_256_16_auth; + break; + case SRTP_AED_AES_128_GCM: + return &srtp_crypto_policy_set_aes_gcm_128_16_auth; + break; + case SRTP_NONE: + return nullptr; } return nullptr; @@ -100,36 +128,37 @@ static void configureSrtpStream(SrtpStream& s, uint16_t ssrc, SrtpSuite suite) func(&s.second.rtcp); } -SrtpSession::SrtpSession() - :mInboundSession(nullptr), mOutboundSession(nullptr) +SrtpSession::SrtpSession() : mInboundSession(nullptr), mOutboundSession(nullptr) { mSuite = SRTP_NONE; memset(&mInboundPolicy, 0, sizeof mInboundPolicy); - mInboundPolicy.ssrc.type = ssrc_specific; + mInboundPolicy.ssrc.type = ssrc_specific; memset(&mOutboundPolicy, 0, sizeof mOutboundPolicy); mOutboundPolicy.ssrc.type = ssrc_specific; // Generate outgoing keys for all ciphers - auto putKey = [this](SrtpSuite suite, size_t length){ + auto putKey = [this](SrtpSuite suite, size_t length) + { assert(suite > SRTP_NONE && suite <= SRTP_LAST); auto key = std::make_shared(); key->resize(length); RAND_bytes(key->mutableData(), key->size()); mOutgoingKey[suite].first = key; }; - putKey(SRTP_AES_128_AUTH_80, 30); putKey(SRTP_AES_128_AUTH_32, 30); - putKey(SRTP_AES_192_AUTH_80, 38); putKey(SRTP_AES_192_AUTH_32, 38); - putKey(SRTP_AES_256_AUTH_80, 46); putKey(SRTP_AES_256_AUTH_32, 46); + putKey(SRTP_AES_128_AUTH_80, 30); + putKey(SRTP_AES_128_AUTH_32, 30); + putKey(SRTP_AES_192_AUTH_80, 38); + putKey(SRTP_AES_192_AUTH_32, 38); + putKey(SRTP_AES_256_AUTH_80, 46); + putKey(SRTP_AES_256_AUTH_32, 46); putKey(SRTP_AES_128_AUTH_NULL, 30); // NULL auth still encrypts - it needs a key+salt putKey(SRTP_AED_AES_128_GCM, 28); putKey(SRTP_AED_AES_256_GCM, 44); } -SrtpSession::~SrtpSession() -{ -} +SrtpSession::~SrtpSession() {} /*void SrtpSession::addSsrc(unsigned ssrc, SsrcDirection d) { @@ -191,7 +220,7 @@ void SrtpSession::open(ByteBuffer& incomingKey, SrtpSuite suite) mOutboundPolicy.key = (unsigned char*)mOutgoingKey[int(suite)].first->mutableData(); mOutboundPolicy.ssrc.type = ssrc_any_outbound; - mInboundPolicy.key = (unsigned char*)mIncomingKey.first->mutableData(); + mInboundPolicy.key = (unsigned char*)mIncomingKey.first->mutableData(); mInboundPolicy.ssrc.type = ssrc_any_inbound; // Create SRTP session @@ -244,9 +273,7 @@ bool SrtpSession::protectRtp(void* buffer, int* length) if (mOutboundSession) { size_t srtp_len = MAX_VALID_UDPPACKET_SIZE; - auto code = srtp_protect(mOutboundSession, - (const uint8_t*)buffer, (size_t)*length, - (uint8_t*)buffer, &srtp_len, + auto code = srtp_protect(mOutboundSession, (const uint8_t*)buffer, (size_t)*length, (uint8_t*)buffer, &srtp_len, 0 /* mki_index, non-used */); *length = srtp_len; return code == 0; @@ -257,16 +284,14 @@ bool SrtpSession::protectRtp(void* buffer, int* length) bool SrtpSession::protectRtcp(void* buffer, int* length) { - //addSsrc(RtpHelper::findSsrc(buffer, *length), sdOutgoing); + // addSsrc(RtpHelper::findSsrc(buffer, *length), sdOutgoing); Lock l(mGuard); if (mOutboundSession) { size_t srtp_len = MAX_VALID_UDPPACKET_SIZE; - auto code = srtp_protect_rtcp(mOutboundSession, - (const uint8_t*)buffer, (size_t)*length, - (uint8_t*)buffer, &srtp_len, - 0 /* mki_index, non-used */); + auto code = srtp_protect_rtcp(mOutboundSession, (const uint8_t*)buffer, (size_t)*length, (uint8_t*)buffer, + &srtp_len, 0 /* mki_index, non-used */); *length = srtp_len; return code == 0; } @@ -276,14 +301,12 @@ bool SrtpSession::protectRtcp(void* buffer, int* length) bool SrtpSession::unprotectRtp(const void* src, size_t srcLength, void* dst, size_t* dstLength) { - //addSsrc(RtpHelper::findSsrc(buffer, *length), sdIncoming); + // addSsrc(RtpHelper::findSsrc(buffer, *length), sdIncoming); Lock l(mGuard); if (mInboundSession) { - auto code = srtp_unprotect(mInboundSession, - (const uint8_t*)src, srcLength, - (uint8_t*)dst, dstLength); + auto code = srtp_unprotect(mInboundSession, (const uint8_t*)src, srcLength, (uint8_t*)dst, dstLength); return code == 0; } else @@ -292,14 +315,12 @@ bool SrtpSession::unprotectRtp(const void* src, size_t srcLength, void* dst, siz bool SrtpSession::unprotectRtcp(const void* src, size_t srcLength, void* dst, size_t* dstLength) { - //addSsrc(RtpHelper::findSsrc(buffer, *length), sdIncoming); + // addSsrc(RtpHelper::findSsrc(buffer, *length), sdIncoming); Lock l(mGuard); if (mInboundSession) { - auto code = srtp_unprotect_rtcp(mInboundSession, - (const uint8_t*)src, srcLength, - (uint8_t*)dst, dstLength); + auto code = srtp_unprotect_rtcp(mInboundSession, (const uint8_t*)src, srcLength, (uint8_t*)dst, dstLength); return code == 0; } else @@ -307,7 +328,7 @@ bool SrtpSession::unprotectRtcp(const void* src, size_t srcLength, void* dst, si } static bool GSrtpInitialized = false; -void SrtpSession::initSrtp() +void SrtpSession::initSrtp() { if (GSrtpInitialized) return; diff --git a/src/engine/media/MT_SrtpHelper.h b/src/engine/media/MT_SrtpHelper.h index 0fe5fe33..0102a0d7 100644 --- a/src/engine/media/MT_SrtpHelper.h +++ b/src/engine/media/MT_SrtpHelper.h @@ -20,28 +20,28 @@ enum SrtpSuite { - SRTP_NONE = 0, - SRTP_AES_128_AUTH_80 = 1, - SRTP_AES_256_AUTH_80 = 2, - SRTP_AES_192_AUTH_80 = 3, - SRTP_AES_128_AUTH_32 = 4, - SRTP_AES_256_AUTH_32 = 5, - SRTP_AES_192_AUTH_32 = 6, - SRTP_AES_128_AUTH_NULL = 7, - SRTP_AED_AES_256_GCM = 8, - SRTP_AED_AES_128_GCM = 9, + SRTP_NONE = 0, + SRTP_AES_128_AUTH_80 = 1, + SRTP_AES_256_AUTH_80 = 2, + SRTP_AES_192_AUTH_80 = 3, + SRTP_AES_128_AUTH_32 = 4, + SRTP_AES_256_AUTH_32 = 5, + SRTP_AES_192_AUTH_32 = 6, + SRTP_AES_128_AUTH_NULL = 7, + SRTP_AED_AES_256_GCM = 8, + SRTP_AED_AES_128_GCM = 9, SRTP_LAST = SRTP_AED_AES_128_GCM }; -extern SrtpSuite toSrtpSuite(const std::string_view& s); -extern std::string_view toString(SrtpSuite suite); +extern SrtpSuite toSrtpSuite(const std::string_view& s); +extern std::string_view toString(SrtpSuite suite); // Relative cryptographic strength used to pick a suite from an SDP offer. // Bigger is stronger. The raw enum values do NOT follow strength order. -extern int srtpSuiteStrength(SrtpSuite suite); +extern int srtpSuiteStrength(SrtpSuite suite); typedef std::pair SrtpKeySalt; -typedef std::pair SrtpStream; +typedef std::pair SrtpStream; class SrtpSession { @@ -54,37 +54,36 @@ public: sdIncoming, sdOutgoing }; - SrtpKeySalt& outgoingKey(SrtpSuite suite); + SrtpKeySalt& outgoingKey(SrtpSuite suite); - void open(ByteBuffer& incomingKey, SrtpSuite suite); - void close(); - bool active(); + void open(ByteBuffer& incomingKey, SrtpSuite suite); + void close(); + bool active(); /* bufferPtr is RTP packet data i.e. header + payload. Buffer must be big enough to hold encrypted data. */ - bool protectRtp(void* buffer, int* length); - bool protectRtcp(void* buffer, int* length); - bool unprotectRtp(const void* src, size_t srcLength, void* dst, size_t* dstLength); - bool unprotectRtcp(const void* src, size_t srcLength, void* dst, size_t* dstLength); + bool protectRtp(void* buffer, int* length); + bool protectRtcp(void* buffer, int* length); + bool unprotectRtp(const void* src, size_t srcLength, void* dst, size_t* dstLength); + bool unprotectRtcp(const void* src, size_t srcLength, void* dst, size_t* dstLength); - static void initSrtp(); + static void initSrtp(); + protected: - srtp_t mInboundSession, - mOutboundSession; + srtp_t mInboundSession, mOutboundSession; // Outgoing keys are indexed by the SrtpSuite enum value directly; // index 0 (SRTP_NONE) is unused. - SrtpKeySalt mIncomingKey, - mOutgoingKey[SRTP_LAST + 1]; - srtp_policy_t mInboundPolicy; - srtp_policy_t mOutboundPolicy; - SrtpSuite mSuite; + SrtpKeySalt mIncomingKey, mOutgoingKey[SRTP_LAST + 1]; + srtp_policy_t mInboundPolicy; + srtp_policy_t mOutboundPolicy; + SrtpSuite mSuite; typedef std::map SrtpStreamMap; - SrtpStreamMap mIncomingMap, mOutgoingMap; - Mutex mGuard; + SrtpStreamMap mIncomingMap, mOutgoingMap; + Mutex mGuard; - void addSsrc(unsigned ssrc, SsrcDirection d); + void addSsrc(unsigned ssrc, SsrcDirection d); }; #endif diff --git a/src/engine/media/MT_Statistics.cpp b/src/engine/media/MT_Statistics.cpp index c12379ce..80bcbf24 100644 --- a/src/engine/media/MT_Statistics.cpp +++ b/src/engine/media/MT_Statistics.cpp @@ -14,50 +14,56 @@ namespace // Per-codec impairment parameters (Ie, Bpl) from ITU-T G.113 / G.107. // clockRate == 0 means "any". -struct MosCodecEntry { const char* mName; unsigned mClockRate; double mIe; double mBpl; }; +struct MosCodecEntry +{ + const char* mName; + unsigned mClockRate; + double mIe; + double mBpl; +}; constexpr MosCodecEntry kMosCodecTable[] = { - { "PCMU", 8000, 0.0, 25.0 }, - { "PCMA", 8000, 0.0, 25.0 }, - { "G722", 8000, 13.0, 21.0 }, - { "G7221", 16000, 13.0, 21.0 }, - { "G7221", 32000, 13.0, 21.0 }, - { "G729", 8000, 11.0, 19.0 }, - { "G729A", 8000, 11.0, 19.0 }, - { "G729AB", 8000, 11.0, 19.0 }, - { "G723", 8000, 15.0, 16.0 }, - { "iLBC", 8000, 11.0, 18.0 }, - { "GSM", 8000, 20.0, 10.0 }, - { "AMR", 8000, 5.0, 10.0 }, - { "AMR-WB", 16000, 7.0, 10.0 }, - { "speex", 8000, 15.0, 20.0 }, - { "speex", 16000, 10.0, 20.0 }, - { "speex", 32000, 10.0, 20.0 }, - { "opus", 48000, 5.0, 25.0 }, + {"PCMU", 8000, 0.0, 25.0}, + {"PCMA", 8000, 0.0, 25.0}, + {"G722", 8000, 13.0, 21.0}, + {"G7221", 16000, 13.0, 21.0}, + {"G7221", 32000, 13.0, 21.0}, + {"G729", 8000, 11.0, 19.0}, + {"G729A", 8000, 11.0, 19.0}, + {"G729AB", 8000, 11.0, 19.0}, + {"G723", 8000, 15.0, 16.0}, + {"iLBC", 8000, 11.0, 18.0}, + {"GSM", 8000, 20.0, 10.0}, + {"AMR", 8000, 5.0, 10.0}, + {"AMR-WB", 16000, 7.0, 10.0}, + {"speex", 8000, 15.0, 20.0}, + {"speex", 16000, 10.0, 20.0}, + {"speex", 32000, 10.0, 20.0}, + {"opus", 48000, 5.0, 25.0}, // EVS — no published G.113 value. Using AMR-WB-family Bpl with a // conservative Ie that matches typical commercial VQM tools for EVS // Primary ~13.2 kbps WB. - { "EVS", 16000, 5.0, 10.0 }, + {"EVS", 16000, 5.0, 10.0}, }; -constexpr double kMosDefaultIe = 0.0; +constexpr double kMosDefaultIe = 0.0; constexpr double kMosDefaultBpl = 25.0; -bool iequals(const std::string& a, const char* b) +bool iequals(const std::string& a, const char* b) { const size_t n = std::strlen(b); - if (a.size() != n) return false; + if (a.size() != n) + return false; for (size_t i = 0; i < n; ++i) - if (std::tolower(static_cast(a[i])) != - std::tolower(static_cast(b[i]))) + if (std::tolower(static_cast(a[i])) != std::tolower(static_cast(b[i]))) return false; return true; } void resolveMosCodecParams(const std::string& codecName, double& ie, double& bpl) { - ie = kMosDefaultIe; + ie = kMosDefaultIe; bpl = kMosDefaultBpl; if (codecName.empty()) return; @@ -67,10 +73,10 @@ void resolveMosCodecParams(const std::string& codecName, double& ie, double& bpl if (iequals(lookup, "GSM-06.10")) lookup = "GSM"; - for (const auto& e: kMosCodecTable) + for (const auto& e : kMosCodecTable) if (iequals(lookup, e.mName)) { - ie = e.mIe; + ie = e.mIe; bpl = e.mBpl; return; } @@ -88,19 +94,19 @@ void JitterStatistics::process(jrtplib::RTPPacket* packet, int rate) // entirely (the previous behaviour) under-reports it. // 2. Ignore the first few in-sequence samples while transit time // settles after call setup. - constexpr uint32_t kIgnoreFirstPackets = 5; + constexpr uint32_t kIgnoreFirstPackets = 5; - const uint32_t timestamp = packet->GetTimestamp(); - const uint32_t extSeqno = packet->GetExtendedSequenceNumber(); + const uint32_t timestamp = packet->GetTimestamp(); + const uint32_t extSeqno = packet->GetExtendedSequenceNumber(); const jrtplib::RTPTime receiveTime = packet->GetReceiveTime(); // First packet: just stash state. if (!mLastJitter) { - mReceiveTime = receiveTime; + mReceiveTime = receiveTime; mReceiveTimestamp = timestamp; - mLastExtSeqno = extSeqno; - mLastJitter = 0.0; + mLastExtSeqno = extSeqno; + mLastJitter = 0.0; mPacketsProcessed = 1; return; } @@ -116,9 +122,9 @@ void JitterStatistics::process(jrtplib::RTPPacket* packet, int rate) // happened, restarting from the latest known good packet. if (mLastExtSeqno && extSeqno > mLastExtSeqno.value()) { - mReceiveTime = receiveTime; + mReceiveTime = receiveTime; mReceiveTimestamp = timestamp; - mLastExtSeqno = extSeqno; + mLastExtSeqno = extSeqno; } return; } @@ -133,15 +139,14 @@ void JitterStatistics::process(jrtplib::RTPPacket* packet, int rate) // Wrap-safe signed delta on the 32-bit RTP timestamp: // transit = arrival - rtp_ts; d = transit - prev_transit (signed 32-bit). const int32_t timestampDelta = static_cast(timestamp - mReceiveTimestamp); - const int64_t receiveDelta = - static_cast(receiveTime.GetDouble() * rate) - - static_cast(mReceiveTime.GetDouble() * rate); + const int64_t receiveDelta = + static_cast(receiveTime.GetDouble() * rate) - static_cast(mReceiveTime.GetDouble() * rate); const int64_t delta = receiveDelta - timestampDelta; // Save state for the next pair regardless of warmup. - mReceiveTime = receiveTime; + mReceiveTime = receiveTime; mReceiveTimestamp = timestamp; - mLastExtSeqno = extSeqno; + mLastExtSeqno = extSeqno; ++mPacketsProcessed; // Skip the first N in-sequence samples while transit time settles. @@ -153,8 +158,7 @@ void JitterStatistics::process(jrtplib::RTPPacket* packet, int rate) mMaxDelta = deltaSec; // J = J + (|D| - J) / 16 - mLastJitter = mLastJitter.value() + - (std::fabs(static_cast(delta)) - mLastJitter.value()) / 16.0; + mLastJitter = mLastJitter.value() + (std::fabs(static_cast(delta)) - mLastJitter.value()) / 16.0; mJitter.process(mLastJitter.value() / static_cast(rate)); } @@ -163,16 +167,14 @@ void JitterStatistics::process(jrtplib::RTPPacket* packet, int rate) // ---------------------------- Statistics ------------------------------------ -Statistics::Statistics() -{} +Statistics::Statistics() {} -Statistics::~Statistics() -{} +Statistics::~Statistics() {} void Statistics::calculateBurstr(double* burstr, double* lossr) const { int lost = 0; // Total packet lost - for (const auto& item: mPacketLossTimeline) + for (const auto& item : mPacketLossTimeline) lost += item.mGap; int bursts = mPacketLossTimeline.size(); // number of events @@ -221,32 +223,31 @@ double Statistics::calculateMos() const return 0.0; // Loss percent is computed as lost / (lost + received). - const uint64_t expected = static_cast(mReceivedRtp) + - static_cast(mPacketLoss); - const double Ppl = expected > 0 - ? static_cast(mPacketLoss) * 100.0 / static_cast(expected) - : 0.0; + const uint64_t expected = static_cast(mReceivedRtp) + static_cast(mPacketLoss); + const double Ppl = expected > 0 ? static_cast(mPacketLoss) * 100.0 / static_cast(expected) : 0.0; - double Ie = kMosDefaultIe, Bpl = kMosDefaultBpl; + double Ie = kMosDefaultIe, Bpl = kMosDefaultBpl; resolveMosCodecParams(mCodecName, Ie, Bpl); if (Bpl <= 0.0) Bpl = 1.0; // mRttDelay and mJitter are stored in seconds. jb_delay is unknown at // this layer, so it is treated as zero. - const double rttMs = static_cast(mRttDelay.average()) * 1000.0; + const double rttMs = static_cast(mRttDelay.average()) * 1000.0; const double jitterMs = static_cast(mJitter) * 1000.0; - const double d = rttMs / 2.0 + jitterMs; + const double d = rttMs / 2.0 + jitterMs; - double Id = 0.024 * d; + double Id = 0.024 * d; if (d > 177.3) Id += 0.11 * (d - 177.3); const double Ie_eff = Ie + (95.0 - Ie) * Ppl / (Ppl + Bpl); - double R = 93.2 - Id - Ie_eff; - if (R < 0.0) R = 0.0; - if (R > 100.0) R = 100.0; + double R = 93.2 - Id - Ie_eff; + if (R < 0.0) + R = 0.0; + if (R > 100.0) + R = 100.0; double mos; if (R == 0.0) @@ -254,27 +255,28 @@ double Statistics::calculateMos() const else mos = 1.0 + 0.035 * R + 7e-6 * R * (R - 60.0) * (100.0 - R); - if (mos < 1.0) mos = 1.0; + if (mos < 1.0) + mos = 1.0; return mos; } -Statistics& Statistics::operator += (const Statistics& src) +Statistics& Statistics::operator+=(const Statistics& src) { - mReceived += src.mReceived; - mSent += src.mSent; + mReceived += src.mReceived; + mSent += src.mSent; mReceivedRtpBytes += src.mReceivedRtpBytes; - mReceivedRtp += src.mReceivedRtp; - mSentRtp += src.mSentRtp; - mReceivedRtcp += src.mReceivedRtcp; - mSentRtcp += src.mSentRtcp; - mDuplicatedRtp += src.mDuplicatedRtp; - mOldRtp += src.mOldRtp; - mPacketLoss += src.mPacketLoss; - mPacketDropped += src.mPacketDropped; - mAudioTime += src.mAudioTime; + mReceivedRtp += src.mReceivedRtp; + mSentRtp += src.mSentRtp; + mReceivedRtcp += src.mReceivedRtcp; + mSentRtcp += src.mSentRtcp; + mDuplicatedRtp += src.mDuplicatedRtp; + mOldRtp += src.mOldRtp; + mPacketLoss += src.mPacketLoss; + mPacketDropped += src.mPacketDropped; + mAudioTime += src.mAudioTime; - for (auto codecStat: src.mCodecCount) + for (auto codecStat : src.mCodecCount) { if (mCodecCount.find(codecStat.first) == mCodecCount.end()) mCodecCount[codecStat.first] = codecStat.second; @@ -282,10 +284,10 @@ Statistics& Statistics::operator += (const Statistics& src) mCodecCount[codecStat.first] += codecStat.second; } - mJitter = src.mJitter; - mRttDelay = src.mRttDelay; - mDecodingInterval = src.mDecodingInterval; - mDecodeRequested = src.mDecodeRequested; + mJitter = src.mJitter; + mRttDelay = src.mRttDelay; + mDecodingInterval = src.mDecodingInterval; + mDecodeRequested = src.mDecodeRequested; if (!src.mCodecName.empty()) mCodecName = src.mCodecName; @@ -299,60 +301,59 @@ Statistics& Statistics::operator += (const Statistics& src) mFirstRtpTime = src.mFirstRtpTime; } } - else - if (src.mFirstRtpTime) + else if (src.mFirstRtpTime) mFirstRtpTime = src.mFirstRtpTime; - mBitrateSwitchCounter += src.mBitrateSwitchCounter; - mRemotePeer = src.mRemotePeer; - mSsrc = src.mSsrc; + mBitrateSwitchCounter += src.mBitrateSwitchCounter; + mRemotePeer = src.mRemotePeer; + mSsrc = src.mSsrc; - for (const auto& [addr, counts]: src.mPerDestination) + for (const auto& [addr, counts] : src.mPerDestination) { auto& dst = mPerDestination[addr]; - dst.mSentRtp += counts.mSentRtp; - dst.mSentRtcp += counts.mSentRtcp; - dst.mSentBytes += counts.mSentBytes; - dst.mReceivedRtp += counts.mReceivedRtp; - dst.mReceivedRtcp += counts.mReceivedRtcp; + dst.mSentRtp += counts.mSentRtp; + dst.mSentRtcp += counts.mSentRtcp; + dst.mSentBytes += counts.mSentBytes; + dst.mReceivedRtp += counts.mReceivedRtp; + dst.mReceivedRtcp += counts.mReceivedRtcp; dst.mReceivedBytes += counts.mReceivedBytes; } return *this; } -Statistics& Statistics::operator -= (const Statistics& src) +Statistics& Statistics::operator-=(const Statistics& src) { - mReceived -= src.mReceived; - mSent -= src.mSent; - mReceivedRtpBytes -= src.mReceivedRtpBytes; - mReceivedRtp -= src.mReceivedRtp; - mIllegalRtp -= src.mIllegalRtp; - mSentRtp -= src.mSentRtp; - mReceivedRtcp -= src.mReceivedRtcp; - mSentRtcp -= src.mSentRtcp; - mDuplicatedRtp -= src.mDuplicatedRtp; - mOldRtp -= src.mOldRtp; - mPacketLoss -= src.mPacketLoss; - mPacketDropped -= src.mPacketDropped; - mAudioTime -= src.mAudioTime; + mReceived -= src.mReceived; + mSent -= src.mSent; + mReceivedRtpBytes -= src.mReceivedRtpBytes; + mReceivedRtp -= src.mReceivedRtp; + mIllegalRtp -= src.mIllegalRtp; + mSentRtp -= src.mSentRtp; + mReceivedRtcp -= src.mReceivedRtcp; + mSentRtcp -= src.mSentRtcp; + mDuplicatedRtp -= src.mDuplicatedRtp; + mOldRtp -= src.mOldRtp; + mPacketLoss -= src.mPacketLoss; + mPacketDropped -= src.mPacketDropped; + mAudioTime -= src.mAudioTime; - for (auto codecStat: src.mCodecCount) + for (auto codecStat : src.mCodecCount) { if (mCodecCount.find(codecStat.first) != mCodecCount.end()) mCodecCount[codecStat.first] -= codecStat.second; } - for (const auto& [addr, counts]: src.mPerDestination) + for (const auto& [addr, counts] : src.mPerDestination) { auto it = mPerDestination.find(addr); if (it == mPerDestination.end()) continue; - it->second.mSentRtp -= counts.mSentRtp; - it->second.mSentRtcp -= counts.mSentRtcp; - it->second.mSentBytes -= counts.mSentBytes; - it->second.mReceivedRtp -= counts.mReceivedRtp; - it->second.mReceivedRtcp -= counts.mReceivedRtcp; + it->second.mSentRtp -= counts.mSentRtp; + it->second.mSentRtcp -= counts.mSentRtcp; + it->second.mSentBytes -= counts.mSentBytes; + it->second.mReceivedRtp -= counts.mReceivedRtp; + it->second.mReceivedRtcp -= counts.mReceivedRtcp; it->second.mReceivedBytes -= counts.mReceivedBytes; } @@ -363,25 +364,17 @@ Statistics& Statistics::operator -= (const Statistics& src) std::string Statistics::toString() const { std::ostringstream oss; - oss << "Received: " << mReceivedRtp - << ", received bytes: " << mReceivedRtpBytes - << ", avg rtp size: " << (mReceivedRtp ? mReceivedRtpBytes / mReceivedRtp : 0) - << ", lost: " << mPacketLoss - << ", dropped: " << mPacketDropped - << ", sent: " << mSentRtp - << ", decoding interval: " << mDecodingInterval.average() - << ", decode requested: " << mDecodeRequested.average() - << ", packet interval: " << mPacketInterval.average(); + oss << "Received: " << mReceivedRtp << ", received bytes: " << mReceivedRtpBytes + << ", avg rtp size: " << (mReceivedRtp ? mReceivedRtpBytes / mReceivedRtp : 0) << ", lost: " << mPacketLoss + << ", dropped: " << mPacketDropped << ", sent: " << mSentRtp + << ", decoding interval: " << mDecodingInterval.average() + << ", decode requested: " << mDecodeRequested.average() << ", packet interval: " << mPacketInterval.average(); - for (const auto& [addr, counts]: mPerDestination) + for (const auto& [addr, counts] : mPerDestination) { - oss << "; peer " << addr.toBriefStdString() - << " sent rtp=" << counts.mSentRtp - << "/rtcp=" << counts.mSentRtcp - << "/bytes=" << counts.mSentBytes - << ", received rtp=" << counts.mReceivedRtp - << "/rtcp=" << counts.mReceivedRtcp - << "/bytes=" << counts.mReceivedBytes; + oss << "; peer " << addr.toBriefStdString() << " sent rtp=" << counts.mSentRtp << "/rtcp=" << counts.mSentRtcp + << "/bytes=" << counts.mSentBytes << ", received rtp=" << counts.mReceivedRtp + << "/rtcp=" << counts.mReceivedRtcp << "/bytes=" << counts.mReceivedBytes; } return oss.str(); diff --git a/src/engine/media/MT_Statistics.h b/src/engine/media/MT_Statistics.h index 358a964c..d95f19ba 100644 --- a/src/engine/media/MT_Statistics.h +++ b/src/engine/media/MT_Statistics.h @@ -28,13 +28,13 @@ struct StreamStats class JitterStatistics { public: - void process(jrtplib::RTPPacket* packet, int samplerate); - TestResult get() const { return mJitter; } - float getMaxDelta() const { return mMaxDelta; } + void process(jrtplib::RTPPacket* packet, int samplerate); + TestResult get() const { return mJitter; } + float getMaxDelta() const { return mMaxDelta; } protected: // Jitter calculation - jrtplib::RTPTime mReceiveTime = jrtplib::RTPTime(0,0); + jrtplib::RTPTime mReceiveTime = jrtplib::RTPTime(0, 0); // Last timestamp from packet in units uint32_t mReceiveTimestamp = 0; @@ -60,16 +60,14 @@ protected: struct PacketLossEvent { // This is extended sequence numbers (not the raw uint16_t seqno) - uint32_t mStartSeqno = 0, - mEndSeqno = 0; - int mGap = 0; - std::chrono::microseconds mTimestampStart = 0us, - mTimestampEnd = 0us; + uint32_t mStartSeqno = 0, mEndSeqno = 0; + int mGap = 0; + std::chrono::microseconds mTimestampStart = 0us, mTimestampEnd = 0us; }; struct Dtmf2833Event { - char mTone; + char mTone; std::chrono::microseconds mTimestamp; }; @@ -78,75 +76,75 @@ struct Dtmf2833Event // for diagnosing ICE candidate switches or symmetric-RTP issues. struct DestinationStats { - size_t mSentRtp = 0; - size_t mSentRtcp = 0; - size_t mSentBytes = 0; - size_t mReceivedRtp = 0; - size_t mReceivedRtcp = 0; + size_t mSentRtp = 0; + size_t mSentRtcp = 0; + size_t mSentBytes = 0; + size_t mReceivedRtp = 0; + size_t mReceivedRtcp = 0; size_t mReceivedBytes = 0; }; class Statistics { public: - size_t mReceived = 0, // Received traffic in bytes - mSent = 0, // Sent traffic in bytes - // Received RTP traffic in bytes. Unlike mReceived this excludes - // RTCP, so mReceivedRtpBytes / mReceivedRtp is the true average - // on-the-wire RTP packet size (UDP payload: RTP header + payload - // + SRTP auth tag; IP/UDP headers are not counted). - mReceivedRtpBytes = 0, - mReceivedRtp = 0, // Number of received rtp packets - mSentRtp = 0, // Number of sent rtp packets - mReceivedRtcp = 0, // Number of received rtcp packets - mSentRtcp = 0, // Number of sent rtcp packets - mDuplicatedRtp = 0, // Number of received duplicated rtp packets - mOldRtp = 0, // Number of late rtp packets - mPacketLoss = 0, // Number of lost packets - mPacketDropped = 0, // Number of dropped packets (due to time unsync when playing)б - mIllegalRtp = 0; // Number of rtp packets with bad payload type + size_t mReceived = 0, // Received traffic in bytes + mSent = 0, // Sent traffic in bytes + // Received RTP traffic in bytes. Unlike mReceived this excludes + // RTCP, so mReceivedRtpBytes / mReceivedRtp is the true average + // on-the-wire RTP packet size (UDP payload: RTP header + payload + // + SRTP auth tag; IP/UDP headers are not counted). + mReceivedRtpBytes = 0, + mReceivedRtp = 0, // Number of received rtp packets + mSentRtp = 0, // Number of sent rtp packets + mReceivedRtcp = 0, // Number of received rtcp packets + mSentRtcp = 0, // Number of sent rtcp packets + mDuplicatedRtp = 0, // Number of received duplicated rtp packets + mOldRtp = 0, // Number of late rtp packets + mPacketLoss = 0, // Number of lost packets + mPacketDropped = 0, // Number of dropped packets (due to time unsync when playing)б + mIllegalRtp = 0; // Number of rtp packets with bad payload type // Per-remote-address breakdown of the totals above. Keyed by the remote // RTP/RTCP socket address (NAT-mapped, after ICE selection). std::map mPerDestination; - TestResult mDecodingInterval, // Average interval on call to packet decode - mDecodeRequested, // Average amount of requested audio frames to play - mPacketInterval; // Average interval between packet adding to jitter buffer + TestResult mDecodingInterval, // Average interval on call to packet decode + mDecodeRequested, // Average amount of requested audio frames to play + mPacketInterval; // Average interval between packet adding to jitter buffer - std::map mLoss; // Every item is number of loss of corresping length - std::chrono::milliseconds mAudioTime = 0ms; // Decoded/found time in milliseconds - size_t mDecodedSize = 0; // Number of decoded bytes - uint32_t mSsrc = 0; // Last known SSRC ID in a RTP stream - ice::NetworkAddress mRemotePeer; // Last known remote RTP address + std::map mLoss; // Every item is number of loss of corresping length + std::chrono::milliseconds mAudioTime = 0ms; // Decoded/found time in milliseconds + size_t mDecodedSize = 0; // Number of decoded bytes + uint32_t mSsrc = 0; // Last known SSRC ID in a RTP stream + ice::NetworkAddress mRemotePeer; // Last known remote RTP address // AMR codec bitrate switch counter - int mBitrateSwitchCounter = 0; - int mCng = 0; - std::string mCodecName; - float mJitter = 0.0f; // Jitter - TestResult mRttDelay; // RTT delay + int mBitrateSwitchCounter = 0; + int mCng = 0; + std::string mCodecName; + float mJitter = 0.0f; // Jitter + TestResult mRttDelay; // RTT delay // Timestamp when first RTP packet has arrived - std::optional mFirstRtpTime; + std::optional mFirstRtpTime; - std::map mCodecCount; // Stats on used codecs + std::map mCodecCount; // Stats on used codecs - std::vector mPacketLossTimeline; // Packet loss timeline - std::vector mDtmf2833Timeline; + std::vector mPacketLossTimeline; // Packet loss timeline + std::vector mDtmf2833Timeline; // It is to calculate network MOS - void calculateBurstr(double* burstr, double* loss) const; - double calculateMos() const; + void calculateBurstr(double* burstr, double* loss) const; + double calculateMos() const; Statistics(); ~Statistics(); - void reset(); + void reset(); - Statistics& operator += (const Statistics& src); - Statistics& operator -= (const Statistics& src); + Statistics& operator+=(const Statistics& src); + Statistics& operator-=(const Statistics& src); - float mNetworkMos = 0.0f; + float mNetworkMos = 0.0f; std::string toString() const; }; diff --git a/src/engine/media/MT_Stream.cpp b/src/engine/media/MT_Stream.cpp index a5008470..6750c87b 100644 --- a/src/engine/media/MT_Stream.cpp +++ b/src/engine/media/MT_Stream.cpp @@ -13,118 +13,119 @@ using namespace MT; - -Stream::Stream() -:mState(0) -{ -} +Stream::Stream() : mState(0) {} Stream::~Stream() { - ICELogInfo(<< mStat.toString()); + ICELogInfo(<< mStat.toString()); } void Stream::setDestination(const RtpPair& dest) { - ICELogInfo(<< "Set RTP destination to " << dest.mRtp.toStdString()); - mDestination = dest; + ICELogInfo(<< "Set RTP destination to " << dest.mRtp.toStdString()); + mDestination = dest; - mStat.mRemotePeer = dest.mRtp; + mStat.mRemotePeer = dest.mRtp; } - + void Stream::setState(unsigned state) { - mState = state; + mState = state; } unsigned Stream::state() { - return mState; + return mState; } void Stream::setSocket(const RtpPair& socket) { - mSocket = socket; + mSocket = socket; } RtpPair& Stream::socket() { - return mSocket; + return mSocket; } Statistics& Stream::statistics() { - return mStat; + return mStat; } SrtpSession& Stream::srtp() { - return mSrtpSession; + return mSrtpSession; } -void Stream::configureMediaObserver(MediaObserver *observer, void* userTag) +void Stream::configureMediaObserver(MediaObserver* observer, void* userTag) { - mMediaObserver = observer; - mMediaObserverTag = userTag; + mMediaObserver = observer; + mMediaObserverTag = userTag; } -StreamList::StreamList() -{ -} +StreamList::StreamList() {} StreamList::~StreamList() { - clear(); + clear(); } void StreamList::add(const PStream& s) { - Lock l(mMutex); - mStreamVector.push_back(s); + Lock l(mMutex); + mStreamVector.push_back(s); } void StreamList::remove(const PStream& s) { - Lock l(mMutex); + Lock l(mMutex); - StreamVector::iterator streamIter = std::find(mStreamVector.begin(), mStreamVector.end(), s); - if (streamIter != mStreamVector.end()) - mStreamVector.erase(streamIter); + StreamVector::iterator streamIter = std::find(mStreamVector.begin(), mStreamVector.end(), s); + if (streamIter != mStreamVector.end()) + mStreamVector.erase(streamIter); } void StreamList::clear() { - Lock l(mMutex); - mStreamVector.clear(); + Lock l(mMutex); + mStreamVector.clear(); } -bool StreamList::has(const PStream& s) +bool StreamList::has(const PStream& s) const { - Lock l(mMutex); - return std::find(mStreamVector.begin(), mStreamVector.end(), s) != mStreamVector.end(); + Lock l(mMutex); + return std::find(mStreamVector.begin(), mStreamVector.end(), s) != mStreamVector.end(); } -int StreamList::size() +size_t StreamList::size() const { - Lock l(mMutex); - return mStreamVector.size(); + Lock l(mMutex); + return mStreamVector.size(); } -PStream StreamList::streamAt(int index) +const PStream StreamList::unsafeStreamAt(size_t index) const { - return mStreamVector[index]; + // It requires outside lock ! + return mStreamVector[index]; +} + +PStream StreamList::unsafeStreamAt(size_t index) +{ + // It requires outside lock ! + return mStreamVector[index]; } void StreamList::copyTo(StreamList* sl) { - Lock l(mMutex); - Lock l2(sl->mMutex); - StreamVector::iterator streamIter = mStreamVector.begin(); - for(;streamIter != mStreamVector.end(); ++streamIter) - sl->add(*streamIter); + Lock l(mMutex); + Lock l2(sl->mMutex); + StreamVector::iterator streamIter = mStreamVector.begin(); + for (; streamIter != mStreamVector.end(); ++streamIter) + sl->add(*streamIter); } Mutex& StreamList::getMutex() { - return mMutex; + return mMutex; } diff --git a/src/engine/media/MT_Stream.h b/src/engine/media/MT_Stream.h index 9be3f9ea..1e5c0618 100644 --- a/src/engine/media/MT_Stream.h +++ b/src/engine/media/MT_Stream.h @@ -25,86 +25,87 @@ using std::experimental::optional; namespace MT { - class Stream - { - public: +class Stream +{ +public: enum Type { - Audio = 1, - Video = 2 + Audio = 1, + Video = 2 }; - + enum class MediaDirection { - Incoming, - Outgoing + Incoming, + Outgoing }; class MediaObserver { public: - virtual void onMedia(const void* buffer, int length, MT::Stream::MediaDirection direction, - void* context, void* userTag) = 0; + virtual void onMedia(const void* buffer, int length, MT::Stream::MediaDirection direction, void* context, + void* userTag) = 0; }; Stream(); virtual ~Stream(); - virtual void setDestination(const RtpPair& dest); + virtual void setDestination(const RtpPair& dest); - virtual void setTransmittingCodec(Codec::Factory& factory, int payloadType) = 0; - virtual void dataArrived(PDatagramSocket s, const void* buffer, int length, InternetAddress& source) = 0; + virtual void setTransmittingCodec(Codec::Factory& factory, int payloadType) = 0; + virtual void dataArrived(PDatagramSocket s, const void* buffer, int length, InternetAddress& source) = 0; - virtual void readFile(const Audio::PWavFileReader& reader, MediaDirection direction) = 0; - virtual void writeFile(const Audio::PWavFileWriter& writer, MediaDirection direction) = 0; - virtual void setupMirror(bool enable) = 0; + virtual void readFile(const Audio::PWavFileReader& reader, MediaDirection direction) = 0; + virtual void writeFile(const Audio::PWavFileWriter& writer, MediaDirection direction) = 0; + virtual void setupMirror(bool enable) = 0; - virtual void setState(unsigned state); + virtual void setState(unsigned state); virtual unsigned state(); - - virtual void setSocket(const RtpPair& socket); + + virtual void setSocket(const RtpPair& socket); virtual RtpPair& socket(); - Statistics& statistics(); - SrtpSession& srtp(); - void configureMediaObserver(MediaObserver* observer, void* userTag); + Statistics& statistics(); + SrtpSession& srtp(); + void configureMediaObserver(MediaObserver* observer, void* userTag); - protected: - unsigned mState; +protected: + unsigned mState; RtpPair mDestination; RtpPair mSocket; - Statistics mStat; - SrtpSession mSrtpSession; - MediaObserver* mMediaObserver = nullptr; - void* mMediaObserverTag = nullptr; - }; + Statistics mStat; + SrtpSession mSrtpSession; + MediaObserver* mMediaObserver = nullptr; + void* mMediaObserverTag = nullptr; +}; - typedef std::shared_ptr PStream; +typedef std::shared_ptr PStream; - class StreamList - { - public: +class StreamList +{ +public: StreamList(); ~StreamList(); - void add(const PStream& s); - void remove(const PStream& s); - void clear(); - bool has(const PStream& s); - - int size(); - PStream streamAt(int index); - - void copyTo(StreamList* sl); + void add(const PStream& s); + void remove(const PStream& s); + void clear(); + bool has(const PStream& s) const; - Mutex& getMutex(); - protected: + size_t size() const; + const PStream unsafeStreamAt(size_t index) const; + PStream unsafeStreamAt(size_t index); + + void copyTo(StreamList* sl); + Mutex& getMutex(); + +protected: typedef std::vector StreamVector; - StreamVector mStreamVector; - Mutex mMutex; - }; -} + StreamVector mStreamVector; + mutable Mutex mMutex; +}; +} // namespace MT #endif diff --git a/src/engine/media/MT_WebRtc.cpp b/src/engine/media/MT_WebRtc.cpp index b14b99d2..0672e4d8 100644 --- a/src/engine/media/MT_WebRtc.cpp +++ b/src/engine/media/MT_WebRtc.cpp @@ -11,60 +11,56 @@ static void checkResultCode(unsigned short code) { - if (code) - throw Exception(ERR_WEBRTC, code); + if (code) + throw Exception(ERR_WEBRTC, code); } -Vad::Vad(int sampleRate) -:mSampleRate(sampleRate), mContext(NULL) +Vad::Vad(int sampleRate) : mSampleRate(sampleRate), mContext(NULL) { - checkResultCode(WebRtcVad_Create(&mContext)); + checkResultCode(WebRtcVad_Create(&mContext)); } Vad::~Vad() { - if (mContext) - WebRtcVad_Free(mContext); + if (mContext) + WebRtcVad_Free(mContext); } bool Vad::isSilence(short* samplePtr, int nrOfSamples) { - short resultCode = WebRtcVad_Process(mContext, mSampleRate, samplePtr, nrOfSamples); - return !resultCode; + short resultCode = WebRtcVad_Process(mContext, mSampleRate, samplePtr, nrOfSamples); + return !resultCode; } // -- Cng --- -Cng::Cng() -:mEncoder(NULL), mDecoder(NULL) +Cng::Cng() : mEncoder(NULL), mDecoder(NULL) { - checkResultCode(WebRtcCng_CreateEnc(&mEncoder)); - checkResultCode(WebRtcCng_CreateDec(&mDecoder)); + checkResultCode(WebRtcCng_CreateEnc(&mEncoder)); + checkResultCode(WebRtcCng_CreateDec(&mDecoder)); } Cng::~Cng() { - if (mEncoder) - WebRtcCng_FreeEnc(mEncoder); - if (mDecoder) - WebRtcCng_FreeDec(mDecoder); + if (mEncoder) + WebRtcCng_FreeEnc(mEncoder); + if (mDecoder) + WebRtcCng_FreeDec(mDecoder); } -void Cng::updateSid(unsigned char *sidPacket, int sidLength) +void Cng::updateSid(unsigned char* sidPacket, int sidLength) { - WebRtcCng_UpdateSid(mDecoder, sidPacket, sidLength); + WebRtcCng_UpdateSid(mDecoder, sidPacket, sidLength); } void Cng::generateSid(short* samples, int nrOfSamples, unsigned char* sidPacket, int* sidLength) { - WebRtc_Word16 produced = 0; - checkResultCode(WebRtcCng_Encode(mEncoder, (WebRtc_Word16*)samples, nrOfSamples, sidPacket, &produced, 1/*TRUE*/)); - - *sidLength = (int)produced; + WebRtc_Word16 produced = 0; + checkResultCode(WebRtcCng_Encode(mEncoder, (WebRtc_Word16*)samples, nrOfSamples, sidPacket, &produced, 1 /*TRUE*/)); + + *sidLength = (int)produced; } void Cng::generateNoise(short* buffer, int nrOfSamples) { - checkResultCode(WebRtcCng_Generate(mDecoder, buffer, nrOfSamples, 1 /*Reset CNG history*/)); + checkResultCode(WebRtcCng_Generate(mDecoder, buffer, nrOfSamples, 1 /*Reset CNG history*/)); } - - diff --git a/src/engine/media/MT_WebRtc.h b/src/engine/media/MT_WebRtc.h index ff525ccd..cb2bd7c5 100644 --- a/src/engine/media/MT_WebRtc.h +++ b/src/engine/media/MT_WebRtc.h @@ -16,31 +16,31 @@ class Vad { public: - Vad(int sampleRate); - ~Vad(); + Vad(int sampleRate); + ~Vad(); - bool isSilence(short* samplePtr, int sampleCount); + bool isSilence(short* samplePtr, int sampleCount); protected: - int mSampleRate; - bool mEnabled; - VadInst* mContext; + int mSampleRate; + bool mEnabled; + VadInst* mContext; }; // Comfort noise helper. It is tiny wrapper for webrtc functionality. class Cng { public: - Cng(); - ~Cng(); + Cng(); + ~Cng(); - void updateSid(unsigned char *sidPacket, int sidLength); - void generateSid(short* samples, int nrOfSamples, unsigned char* sidPacket, int* sidLength); - void generateNoise(short* buffer, int nrOfSamples); + void updateSid(unsigned char* sidPacket, int sidLength); + void generateSid(short* samples, int nrOfSamples, unsigned char* sidPacket, int* sidLength); + void generateNoise(short* buffer, int nrOfSamples); protected: - CNG_enc_inst* mEncoder; - CNG_dec_inst* mDecoder; + CNG_enc_inst* mEncoder; + CNG_dec_inst* mDecoder; }; #endif diff --git a/src/libs/ice/ICEAction.h b/src/libs/ice/ICEAction.h index 2e170fda..efd199c1 100644 --- a/src/libs/ice/ICEAction.h +++ b/src/libs/ice/ICEAction.h @@ -11,32 +11,27 @@ namespace ice { - class Transaction; - struct Stream; - class Logger; - struct StackConfig; +class Transaction; +struct Stream; +class Logger; +struct StackConfig; - class Action - { - protected: - Stream& mStream; +class Action +{ +protected: + Stream& mStream; StackConfig& mConfig; - public: - Action(Stream& stream, StackConfig& config) - :mStream(stream), mConfig(config) - { - } - - virtual ~Action() - { - } - - virtual void finished(Transaction& transaction) = 0; - }; - - typedef std::shared_ptr PAction; +public: + Action(Stream& stream, StackConfig& config) : mStream(stream), mConfig(config) {} -} + virtual ~Action() {} + + virtual void finished(Transaction& transaction) = 0; +}; + +typedef std::shared_ptr PAction; + +} // namespace ice #endif diff --git a/src/libs/ice/ICEAddress.cpp b/src/libs/ice/ICEAddress.cpp index 975f0eb3..9f6ebd9c 100644 --- a/src/libs/ice/ICEAddress.cpp +++ b/src/libs/ice/ICEAddress.cpp @@ -5,11 +5,11 @@ #if defined(__MINGW32__) -# include +#include -# define WINVER WindowsVista -# define _WIN32_WINDOWS WindowsVista -# define _WIN32_WINNT WindowsVista +#define WINVER WindowsVista +#define _WIN32_WINDOWS WindowsVista +#define _WIN32_WINNT WindowsVista #endif #include "ICEPlatform.h" @@ -19,28 +19,28 @@ #include #if defined(TARGET_WIN) -# include -# include -# include +#include +#include +#include #else -# include +#include -# if /*defined(TARGET_LINUX) || */ defined(TARGET_ANDROID) -# include -# endif +#if /*defined(TARGET_LINUX) || */ defined(TARGET_ANDROID) +#include +#endif #endif -std::ostream& operator << (std::ostream& s, const ice::NetworkAddress& addr) +std::ostream& operator<<(std::ostream& s, const ice::NetworkAddress& addr) { - s << addr.toStdString().c_str(); - return s; + s << addr.toStdString().c_str(); + return s; } #ifdef TARGET_WIN -std::wostream& operator << (std::wostream& s, const ice::NetworkAddress& addr) +std::wostream& operator<<(std::wostream& s, const ice::NetworkAddress& addr) { - s << addr.toStdWString(); - return s; + s << addr.toStdWString(); + return s; } #endif @@ -48,337 +48,326 @@ using namespace ice; NetworkAddress NetworkAddress::LoopbackAddress4("127.0.0.1", 1000); #ifdef TARGET_WIN -static in_addr6 la6 = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1 }; +static in_addr6 la6 = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}; #else -static in6_addr la6 = { { { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1 } } }; +static in6_addr la6 = {{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}}; #endif NetworkAddress NetworkAddress::LoopbackAddress6(la6, 1000); NetworkAddress NetworkAddress::parse(const std::string& s) { - NetworkAddress result; - result.mInitialized = !s.empty(); - if (result.mInitialized) - { - // Relayed or not - result.mRelayed = s.find("relayed ") != std::string::npos; - std::string::size_type ip4Pos = s.find("IPv4"), ip6Pos = s.find("IPv6"); - - if (ip4Pos == std::string::npos && ip6Pos == std::string::npos) + NetworkAddress result; + result.mInitialized = !s.empty(); + if (result.mInitialized) { - // Parse usual IP[:port] pair - std::string::size_type cp = s.find_last_of(':'); - if (cp == std::string::npos) - result.setIp(cp); - else - { - result.setIp(s.substr(0, cp)); - result.setPort(atoi(s.substr(cp + 1).c_str())); - } - } - else - { - // Family - result.mAddr4.sin_family = ip4Pos != std::string::npos ? AF_INET : AF_INET6; + // Relayed or not + result.mRelayed = s.find("relayed ") != std::string::npos; + std::string::size_type ip4Pos = s.find("IPv4"), ip6Pos = s.find("IPv6"); - // IP:port - std::string::size_type familyPos = ip4Pos != std::string::npos ? ip4Pos : ip6Pos; - std::string addr = s.substr(familyPos + 5); + if (ip4Pos == std::string::npos && ip6Pos == std::string::npos) + { + // Parse usual IP[:port] pair + std::string::size_type cp = s.find_last_of(':'); + if (cp == std::string::npos) + result.setIp(cp); + else + { + result.setIp(s.substr(0, cp)); + result.setPort(atoi(s.substr(cp + 1).c_str())); + } + } + else + { + // Family + result.mAddr4.sin_family = ip4Pos != std::string::npos ? AF_INET : AF_INET6; - // Find IP substring and port - std::string::size_type colonPos = addr.find_last_of(':'); - if (colonPos != std::string::npos) - { - int port = atoi(addr.substr(colonPos+1).c_str()); - result.setPort(port); - result.setIp(addr.substr(0, colonPos)); - } + // IP:port + std::string::size_type familyPos = ip4Pos != std::string::npos ? ip4Pos : ip6Pos; + std::string addr = s.substr(familyPos + 5); + + // Find IP substring and port + std::string::size_type colonPos = addr.find_last_of(':'); + if (colonPos != std::string::npos) + { + int port = atoi(addr.substr(colonPos + 1).c_str()); + result.setPort(port); + result.setIp(addr.substr(0, colonPos)); + } + } } - } - return result; + return result; } // NetworkAddress NetworkAddress::LoopbackAddress6("0:0:0:0:0:0:0:1", 1000); -NetworkAddress::NetworkAddress() - :mInitialized(false), mRelayed(false) +NetworkAddress::NetworkAddress() : mInitialized(false), mRelayed(false) { - memset(&mAddr6, 0, sizeof(mAddr6)); - mAddr4.sin_family = AF_INET; + memset(&mAddr6, 0, sizeof(mAddr6)); + mAddr4.sin_family = AF_INET; } -NetworkAddress::NetworkAddress(int stunType) - :mInitialized(false), mRelayed(false) +NetworkAddress::NetworkAddress(int stunType) : mInitialized(false), mRelayed(false) { - memset(&mAddr6, 0, sizeof(mAddr6)); - setStunType(stunType); + memset(&mAddr6, 0, sizeof(mAddr6)); + setStunType(stunType); } -NetworkAddress::NetworkAddress(const in6_addr& addr6, unsigned short port) - :mInitialized(true), mRelayed(false) +NetworkAddress::NetworkAddress(const in6_addr& addr6, unsigned short port) : mInitialized(true), mRelayed(false) { - memset(&mAddr6, 0, sizeof(mAddr6)); - mAddr4.sin_family = AF_INET6; - mAddr6.sin6_addr = addr6; - mAddr6.sin6_port = htons(port); + memset(&mAddr6, 0, sizeof(mAddr6)); + mAddr4.sin_family = AF_INET6; + mAddr6.sin6_addr = addr6; + mAddr6.sin6_port = htons(port); } -NetworkAddress::NetworkAddress(const in_addr& addr4, unsigned short port) - :mInitialized(true), mRelayed(false) +NetworkAddress::NetworkAddress(const in_addr& addr4, unsigned short port) : mInitialized(true), mRelayed(false) { - memset(&mAddr6, 0, sizeof(mAddr6)); - mAddr4.sin_family = AF_INET; - mAddr4.sin_addr = addr4; - mAddr4.sin_port = htons(port); + memset(&mAddr6, 0, sizeof(mAddr6)); + mAddr4.sin_family = AF_INET; + mAddr4.sin_addr = addr4; + mAddr4.sin_port = htons(port); } unsigned char NetworkAddress::stunType() const { - assert(mInitialized); - switch (mAddr4.sin_family) - { - case AF_INET: - return 1; + assert(mInitialized); + switch (mAddr4.sin_family) + { + case AF_INET: + return 1; - case AF_INET6: - return 2; + case AF_INET6: + return 2; - default: - assert(0); - } - return -1; + default: + assert(0); + } + return -1; } void NetworkAddress::setStunType(unsigned char st) { - switch (st) - { - case 1: - mAddr4.sin_family = AF_INET; - break; + switch (st) + { + case 1: + mAddr4.sin_family = AF_INET; + break; - case 2: - mAddr6.sin6_family = AF_INET6; - break; + case 2: + mAddr6.sin6_family = AF_INET6; + break; - default: - assert(0); - } + default: + assert(0); + } } -NetworkAddress::NetworkAddress(const std::string& ip, unsigned short port) - :mInitialized(true), mRelayed(false) +NetworkAddress::NetworkAddress(const std::string& ip, unsigned short port) : mInitialized(true), mRelayed(false) { - memset(&mAddr6, 0, sizeof(mAddr6)); - setIp(ip); - if (mAddr4.sin_family == AF_INET || mAddr4.sin_family == AF_INET6) - setPort(port); -} - -NetworkAddress::NetworkAddress(const char *ip, unsigned short port) - :mInitialized(true), mRelayed(false) -{ - memset(&mAddr6, 0, sizeof(mAddr6)); - setIp(ip); - if (mAddr4.sin_family == AF_INET || mAddr4.sin_family == AF_INET6) - setPort(port); -} - -NetworkAddress::NetworkAddress(uint32_t ip_4, uint16_t port) - :mInitialized(true), mRelayed(false) -{ - memset(&mAddr6, 0, sizeof(mAddr6)); - mAddr4.sin_family = AF_INET; - mAddr4.sin_addr.s_addr = ip_4; - mAddr4.sin_port = port; -} - -NetworkAddress::NetworkAddress(const uint8_t* ip_6, uint16_t port) - :mInitialized(true), mRelayed(false) -{ - memset(&mAddr6, 0, sizeof(mAddr6)); - mAddr6.sin6_family = AF_INET6; - memmove(&mAddr6.sin6_addr, ip_6, sizeof(mAddr6.sin6_addr)); - mAddr6.sin6_port = port; -} - -NetworkAddress::NetworkAddress(const sockaddr& addr, size_t addrLen) - :mInitialized(true), mRelayed(false) -{ - switch (addr.sa_family) - { - case AF_INET6: memset(&mAddr6, 0, sizeof(mAddr6)); - memcpy(&mAddr6, &addr, addrLen); - break; - - case AF_INET: - memset(&mAddr4, 0, sizeof(mAddr4)); - memcpy(&mAddr4, &addr, addrLen); - break; - } + setIp(ip); + if (mAddr4.sin_family == AF_INET || mAddr4.sin_family == AF_INET6) + setPort(port); } -NetworkAddress::NetworkAddress(const NetworkAddress& src) - :mInitialized(src.mInitialized), mRelayed(src.mRelayed) +NetworkAddress::NetworkAddress(const char* ip, unsigned short port) : mInitialized(true), mRelayed(false) { - memset(&mAddr6, 0, sizeof(mAddr6)); - if (src.mAddr4.sin_family == AF_INET) - memcpy(&mAddr4, &src.mAddr4, sizeof mAddr4); - else - memcpy(&mAddr6, &src.mAddr6, sizeof mAddr6); + memset(&mAddr6, 0, sizeof(mAddr6)); + setIp(ip); + if (mAddr4.sin_family == AF_INET || mAddr4.sin_family == AF_INET6) + setPort(port); +} + +NetworkAddress::NetworkAddress(uint32_t ip_4, uint16_t port) : mInitialized(true), mRelayed(false) +{ + memset(&mAddr6, 0, sizeof(mAddr6)); + mAddr4.sin_family = AF_INET; + mAddr4.sin_addr.s_addr = ip_4; + mAddr4.sin_port = port; +} + +NetworkAddress::NetworkAddress(const uint8_t* ip_6, uint16_t port) : mInitialized(true), mRelayed(false) +{ + memset(&mAddr6, 0, sizeof(mAddr6)); + mAddr6.sin6_family = AF_INET6; + memmove(&mAddr6.sin6_addr, ip_6, sizeof(mAddr6.sin6_addr)); + mAddr6.sin6_port = port; +} + +NetworkAddress::NetworkAddress(const sockaddr& addr, size_t addrLen) : mInitialized(true), mRelayed(false) +{ + switch (addr.sa_family) + { + case AF_INET6: + memset(&mAddr6, 0, sizeof(mAddr6)); + memcpy(&mAddr6, &addr, addrLen); + break; + + case AF_INET: + memset(&mAddr4, 0, sizeof(mAddr4)); + memcpy(&mAddr4, &addr, addrLen); + break; + } +} + +NetworkAddress::NetworkAddress(const NetworkAddress& src) : mInitialized(src.mInitialized), mRelayed(src.mRelayed) +{ + memset(&mAddr6, 0, sizeof(mAddr6)); + if (src.mAddr4.sin_family == AF_INET) + memcpy(&mAddr4, &src.mAddr4, sizeof mAddr4); + else + memcpy(&mAddr6, &src.mAddr6, sizeof mAddr6); } int NetworkAddress::family() const { - assert(mInitialized == true); - - return this->mAddr4.sin_family; + assert(mInitialized == true); + + return this->mAddr4.sin_family; } sockaddr* NetworkAddress::genericsockaddr() const { - assert(mInitialized == true); - switch (mAddr4.sin_family) - { - case AF_INET: - return (sockaddr*)&mAddr4; + assert(mInitialized == true); + switch (mAddr4.sin_family) + { + case AF_INET: + return (sockaddr*)&mAddr4; - case AF_INET6: - return (sockaddr*)&mAddr6; + case AF_INET6: + return (sockaddr*)&mAddr6; - default: - assert(0); - } - return NULL; + default: + assert(0); + } + return NULL; } unsigned NetworkAddress::sockaddrLen() const { - assert(mInitialized == true); - switch (mAddr4.sin_family) - { - case AF_INET: - return sizeof(mAddr4); + assert(mInitialized == true); + switch (mAddr4.sin_family) + { + case AF_INET: + return sizeof(mAddr4); - case AF_INET6: - return sizeof(mAddr6); + case AF_INET6: + return sizeof(mAddr6); - default: - assert(0); - } - return 0; + default: + assert(0); + } + return 0; } sockaddr_in* NetworkAddress::sockaddr4() const { - assert(mInitialized == true); - switch (mAddr4.sin_family) - { - case AF_INET: - return (sockaddr_in*)&mAddr4; + assert(mInitialized == true); + switch (mAddr4.sin_family) + { + case AF_INET: + return (sockaddr_in*)&mAddr4; - default: - assert(0); - } - return NULL; + default: + assert(0); + } + return NULL; } sockaddr_in6* NetworkAddress::sockaddr6() const { - assert(mInitialized == true); - switch (mAddr4.sin_family) - { - case AF_INET6: - return (sockaddr_in6*)&mAddr6; + assert(mInitialized == true); + switch (mAddr4.sin_family) + { + case AF_INET6: + return (sockaddr_in6*)&mAddr6; - default: - assert(0); - } - return NULL; + default: + assert(0); + } + return NULL; } void NetworkAddress::setIp(NetworkAddress ipOnly) { - // Setup family - mAddr4.sin_family = ipOnly.genericsockaddr()->sa_family; + // Setup family + mAddr4.sin_family = ipOnly.genericsockaddr()->sa_family; - // Copy address chunk only - switch (ipOnly.family()) - { - case AF_INET: - memcpy(&mAddr4.sin_addr, &ipOnly.sockaddr4()->sin_addr, 4); - break; + // Copy address chunk only + switch (ipOnly.family()) + { + case AF_INET: + memcpy(&mAddr4.sin_addr, &ipOnly.sockaddr4()->sin_addr, 4); + break; - case AF_INET6: - memcpy(&mAddr6.sin6_addr, &ipOnly.sockaddr6()->sin6_addr, 16); - break; + case AF_INET6: + memcpy(&mAddr6.sin6_addr, &ipOnly.sockaddr6()->sin6_addr, 16); + break; - default: - assert(0); - } + default: + assert(0); + } } void NetworkAddress::setIp(const std::string& ip) { #ifdef TARGET_WIN - int addrSize = sizeof(mAddr6); + int addrSize = sizeof(mAddr6); #endif - - if (inet_addr(ip.c_str()) != INADDR_NONE) - { - mAddr4.sin_family = AF_INET; - mAddr4.sin_addr.s_addr = inet_addr(ip.c_str()); - if (mAddr4.sin_port) - mInitialized = true; - } - else - { - mAddr6.sin6_family = AF_INET6; -#ifdef TARGET_WIN - if (WSAStringToAddressA((char*)ip.c_str(), AF_INET6, NULL, (sockaddr*)&mAddr6, &addrSize) != 0) -#else - std::string ip2; - if (ip.find('[') == 0 && ip.find(']') == ip.length()-1) - ip2 = ip.substr(1, ip.length()-2); - else - ip2 = ip; - if (!inet_pton(AF_INET6, ip2.c_str(), &mAddr6.sin6_addr)) -#endif + if (inet_addr(ip.c_str()) != INADDR_NONE) { - mInitialized = false; - return; + mAddr4.sin_family = AF_INET; + mAddr4.sin_addr.s_addr = inet_addr(ip.c_str()); + if (mAddr4.sin_port) + mInitialized = true; } - - mAddr6.sin6_family = AF_INET6; - if (mAddr6.sin6_port) - mInitialized = true; - } + else + { + mAddr6.sin6_family = AF_INET6; +#ifdef TARGET_WIN + if (WSAStringToAddressA((char*)ip.c_str(), AF_INET6, NULL, (sockaddr*)&mAddr6, &addrSize) != 0) +#else + std::string ip2; + if (ip.find('[') == 0 && ip.find(']') == ip.length() - 1) + ip2 = ip.substr(1, ip.length() - 2); + else + ip2 = ip; + if (!inet_pton(AF_INET6, ip2.c_str(), &mAddr6.sin6_addr)) +#endif + { + mInitialized = false; + return; + } + + mAddr6.sin6_family = AF_INET6; + if (mAddr6.sin6_port) + mInitialized = true; + } } void NetworkAddress::setIp(unsigned long ip) { - mAddr4.sin_family = AF_INET; - mAddr4.sin_addr.s_addr = ip; + mAddr4.sin_family = AF_INET; + mAddr4.sin_addr.s_addr = ip; - if (mAddr4.sin_port) - mInitialized = true; + if (mAddr4.sin_port) + mInitialized = true; } void NetworkAddress::setIp(const in_addr& ip) { - //memset(&mAddr4, 0, sizeof mAddr4); - mAddr4.sin_family = AF_INET; - mAddr4.sin_addr = ip; + // memset(&mAddr4, 0, sizeof mAddr4); + mAddr4.sin_family = AF_INET; + mAddr4.sin_addr = ip; } void NetworkAddress::setIp(const in6_addr& ip) { - mAddr6.sin6_family = AF_INET6; - mAddr6.sin6_addr = ip; + mAddr6.sin6_family = AF_INET6; + mAddr6.sin6_addr = ip; } // 10.0.0.0 - 10.255.255.255 // 172.16.0.0 - 172.31.255.255 @@ -386,436 +375,433 @@ void NetworkAddress::setIp(const in6_addr& ip) bool NetworkAddress::isSameLAN(const NetworkAddress& a1, const NetworkAddress& a2) { - if (a1.family() != a2.family()) - return false; - if (a1.family() == AF_INET) - { - sockaddr_in* s1 = a1.sockaddr4(); - sockaddr_in* s2 = a2.sockaddr4(); + if (a1.family() != a2.family()) + return false; + if (a1.family() == AF_INET) + { + sockaddr_in* s1 = a1.sockaddr4(); + sockaddr_in* s2 = a2.sockaddr4(); #ifdef TARGET_WIN - unsigned b1_0 = (s1->sin_addr.S_un.S_addr >> 0) & 0xFF; - unsigned b1_1 = (s1->sin_addr.S_un.S_addr >> 8) & 0xFF; - unsigned b2_0 = (s2->sin_addr.S_un.S_addr >> 0) & 0xFF; - unsigned b2_1 = (s2->sin_addr.S_un.S_addr >> 8) & 0xFF; + unsigned b1_0 = (s1->sin_addr.S_un.S_addr >> 0) & 0xFF; + unsigned b1_1 = (s1->sin_addr.S_un.S_addr >> 8) & 0xFF; + unsigned b2_0 = (s2->sin_addr.S_un.S_addr >> 0) & 0xFF; + unsigned b2_1 = (s2->sin_addr.S_un.S_addr >> 8) & 0xFF; #else - unsigned b1_0 = (s1->sin_addr.s_addr >> 0) & 0xFF; - unsigned b1_1 = (s1->sin_addr.s_addr >> 8) & 0xFF; - unsigned b2_0 = (s2->sin_addr.s_addr >> 0) & 0xFF; - unsigned b2_1 = (s2->sin_addr.s_addr >> 8) & 0xFF; + unsigned b1_0 = (s1->sin_addr.s_addr >> 0) & 0xFF; + unsigned b1_1 = (s1->sin_addr.s_addr >> 8) & 0xFF; + unsigned b2_0 = (s2->sin_addr.s_addr >> 0) & 0xFF; + unsigned b2_1 = (s2->sin_addr.s_addr >> 8) & 0xFF; - if (b1_0 == b2_0 && b1_0 == 192 && - b1_1 == b2_1 && b1_1 == 168) - return true; + if (b1_0 == b2_0 && b1_0 == 192 && b1_1 == b2_1 && b1_1 == 168) + return true; - if (b1_0 == b2_0 && b1_0 == 10) - return true; + if (b1_0 == b2_0 && b1_0 == 10) + return true; - if (b1_0 == b2_0 && b1_0 == 172 && - b1_1 == b2_1 && (b1_1 < 32)) - return true; + if (b1_0 == b2_0 && b1_0 == 172 && b1_1 == b2_1 && (b1_1 < 32)) + return true; #endif - } - return false; + } + return false; } void NetworkAddress::setPort(unsigned short port) { - switch(mAddr4.sin_family) - { - case AF_INET: - mAddr4.sin_port = htons(port); - mInitialized = true; - break; + switch (mAddr4.sin_family) + { + case AF_INET: + mAddr4.sin_port = htons(port); + mInitialized = true; + break; - case AF_INET6: - mAddr6.sin6_port = htons(port); - mInitialized = true; - break; + case AF_INET6: + mAddr6.sin6_port = htons(port); + mInitialized = true; + break; - default: - assert(0); - } + default: + assert(0); + } } std::string NetworkAddress::ip() const { - assert(mInitialized == true); + assert(mInitialized == true); - char resultbuf[159], ip6[161]; resultbuf[0] = 0; + char resultbuf[159], ip6[161]; + resultbuf[0] = 0; #ifdef TARGET_WIN - DWORD resultsize = sizeof(resultbuf); + DWORD resultsize = sizeof(resultbuf); #endif - switch (mAddr4.sin_family) - { - case AF_INET: - return inet_ntoa(mAddr4.sin_addr); + switch (mAddr4.sin_family) + { + case AF_INET: + return inet_ntoa(mAddr4.sin_addr); - case AF_INET6: + case AF_INET6: #if defined(TARGET_WIN) - InetNtopA(AF_INET6, (PVOID)&mAddr6.sin6_addr, resultbuf, sizeof(resultbuf)); + InetNtopA(AF_INET6, (PVOID)&mAddr6.sin6_addr, resultbuf, sizeof(resultbuf)); #else - inet_ntop(AF_INET6, &mAddr6.sin6_addr, resultbuf, sizeof(resultbuf)); + inet_ntop(AF_INET6, &mAddr6.sin6_addr, resultbuf, sizeof(resultbuf)); #endif - sprintf(ip6, "[%s]", resultbuf); - return ip6; + sprintf(ip6, "[%s]", resultbuf); + return ip6; - default: + default: + return ""; + } return ""; - } - return ""; } unsigned char* NetworkAddress::ipBytes() const { - switch (family()) - { - case AF_INET: + switch (family()) + { + case AF_INET: #ifdef TARGET_WIN - return (unsigned char*)&mAddr4.sin_addr.S_un.S_un_b; + return (unsigned char*)&mAddr4.sin_addr.S_un.S_un_b; #else - return (unsigned char*)&mAddr4.sin_addr.s_addr; + return (unsigned char*)&mAddr4.sin_addr.s_addr; #endif - case AF_INET6: + case AF_INET6: #ifdef TARGET_WIN - return (unsigned char*)mAddr6.sin6_addr.u.Byte; + return (unsigned char*)mAddr6.sin6_addr.u.Byte; #elif defined(TARGET_OSX) || defined(TARGET_IOS) - return (unsigned char*)&mAddr6.sin6_addr.__u6_addr.__u6_addr8; + return (unsigned char*)&mAddr6.sin6_addr.__u6_addr.__u6_addr8; #elif defined(TARGET_OPENWRT) || defined(TARGET_MUSL) - return (unsigned char*)&mAddr6.sin6_addr.__in6_union.__s6_addr; + return (unsigned char*)&mAddr6.sin6_addr.__in6_union.__s6_addr; #elif defined(TARGET_LINUX) - return (unsigned char*)&mAddr6.sin6_addr.__in6_u.__u6_addr8; + return (unsigned char*)&mAddr6.sin6_addr.__in6_u.__u6_addr8; #elif defined(TARGET_ANDROID) - return (unsigned char*)&mAddr6.sin6_addr.in6_u.u6_addr8; + return (unsigned char*)&mAddr6.sin6_addr.in6_u.u6_addr8; #endif - } - assert(0); - return nullptr; // to avoid compiler warning + } + assert(0); + return nullptr; // to avoid compiler warning } unsigned short NetworkAddress::port() const { - assert(mInitialized == true); + assert(mInitialized == true); - return ntohs(mAddr4.sin_port); + return ntohs(mAddr4.sin_port); } std::string NetworkAddress::toStdString() const { - if (!mInitialized) - return ""; + if (!mInitialized) + return ""; - char temp[128]; - sprintf(temp, "%s%s %s:%u", mRelayed ? "relayed " : "", this->mAddr4.sin_family == AF_INET ? "IPv4" : "IPv6", ip().c_str(), (unsigned int)port()); - - return temp; + char temp[128]; + sprintf(temp, "%s%s %s:%u", mRelayed ? "relayed " : "", this->mAddr4.sin_family == AF_INET ? "IPv4" : "IPv6", + ip().c_str(), (unsigned int)port()); + + return temp; } std::string NetworkAddress::toBriefStdString() const { - if (!mInitialized) - return ""; + if (!mInitialized) + return ""; - char temp[128]; - sprintf(temp, "%s:%u", ip().c_str(), (unsigned int)port()); + char temp[128]; + sprintf(temp, "%s:%u", ip().c_str(), (unsigned int)port()); - return temp; + return temp; } #ifdef WIN32 std::wstring NetworkAddress::toStdWString() const { - if (!mInitialized) - return L""; + if (!mInitialized) + return L""; - wchar_t temp[128]; - swprintf(temp, L"%s%s %S:%u", mRelayed ? L"relayed " : L"", this->mAddr4.sin_family == AF_INET ? L"IPv4" : L"IPv6", ip().c_str(), (unsigned int)port()); + wchar_t temp[128]; + swprintf(temp, L"%s%s %S:%u", mRelayed ? L"relayed " : L"", this->mAddr4.sin_family == AF_INET ? L"IPv4" : L"IPv6", + ip().c_str(), (unsigned int)port()); - return temp; + return temp; } #endif -static const unsigned char localhost6[] = -{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; +static const unsigned char localhost6[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}; -bool NetworkAddress::isLoopback() const +bool NetworkAddress::isLoopback() const { - switch (mAddr4.sin_family) - { - case AF_INET: - return (mAddr4.sin_addr.s_addr == htonl(INADDR_LOOPBACK)); + switch (mAddr4.sin_family) + { + case AF_INET: + return (mAddr4.sin_addr.s_addr == htonl(INADDR_LOOPBACK)); - case AF_INET6: - return memcmp(localhost6, &mAddr6.sin6_addr, sizeof mAddr6.sin6_addr) == 0; + case AF_INET6: + return memcmp(localhost6, &mAddr6.sin6_addr, sizeof mAddr6.sin6_addr) == 0; - default: - assert(0); - } - return false; + default: + assert(0); + } + return false; } bool NetworkAddress::isIp(const std::string& str) { - if (inet_addr(str.c_str()) != INADDR_NONE) - return true; - const char* address = str.c_str(); - std::string temp; - if (str.find('[') == 0 && str.find(']') == str.length()-1) - { - temp = str.substr(1, str.length()-2); - address = temp.c_str(); - } - sockaddr_in6 addr6; - addr6.sin6_family = AF_INET6; + if (inet_addr(str.c_str()) != INADDR_NONE) + return true; + const char* address = str.c_str(); + std::string temp; + if (str.find('[') == 0 && str.find(']') == str.length() - 1) + { + temp = str.substr(1, str.length() - 2); + address = temp.c_str(); + } + sockaddr_in6 addr6; + addr6.sin6_family = AF_INET6; #ifdef _WIN32 - int addrSize = sizeof(addr6); - if (WSAStringToAddressA((char*)address, AF_INET6, NULL, (sockaddr*)&addr6, &addrSize) != 0) + int addrSize = sizeof(addr6); + if (WSAStringToAddressA((char*)address, AF_INET6, NULL, (sockaddr*)&addr6, &addrSize) != 0) #else - if (!inet_pton(AF_INET6, address, &addr6)) + if (!inet_pton(AF_INET6, address, &addr6)) #endif - return false; - return true; + return false; + return true; } bool NetworkAddress::isLAN() const { - assert(mInitialized); - - switch (mAddr4.sin_family) - { - case AF_INET: - { - unsigned char b1 = mAddr4.sin_addr.s_addr & 0xFF; - unsigned char b2 = (mAddr4.sin_addr.s_addr >> 8) & 0xFF; - if (b1 == 192 && b2 == 168) - return true; - if (b1 == 10) - return true; - if (b1 == 172 && (b2 >= 16 && b2 <= 31)) - return true; - - // Link local addresses are not routable so report them here - if (b1 == 169 && b2 == 254) - return true; - - return false; - - } - - case AF_INET6: - return false; - - default: - assert(0); - } - return false; -} - -bool NetworkAddress::isLinkLocal() const -{ - assert(mInitialized); - - switch (mAddr4.sin_family) - { - case AF_INET: - { - unsigned char b1 = mAddr4.sin_addr.s_addr & 0xFF; - unsigned char b2 = (mAddr4.sin_addr.s_addr >> 8) & 0xFF; - - // Link local addresses are not routable so report them here - if (b1 == 169 && b2 == 254) - return true; - - //if (b1 == 100 && (b2 >= 64 && b2 <= 127)) - // return true; - - return false; - - } - - case AF_INET6: -#ifdef WIN32 - return (mAddr6.sin6_addr.u.Byte[0] == 0xFE && mAddr6.sin6_addr.u.Byte[1] == 0x80); -#else - return IN6_IS_ADDR_LINKLOCAL(&mAddr6.sin6_addr); -#endif - default: - assert(0); - } - return false; -} - -void NetworkAddress::clear() -{ - memset(&mAddr6, 0, sizeof(mAddr6)); - mInitialized = false; -} - -bool NetworkAddress::isEmpty() const -{ - return !mInitialized; -} - -bool NetworkAddress::isZero() const -{ - if (!mInitialized) - return false; - switch (mAddr4.sin_family) - { - case AF_INET: - return mAddr4.sin_addr.s_addr == 0; - - case AF_INET6: -#ifdef WIN32 - return !mAddr6.sin6_addr.u.Word[0] && !mAddr6.sin6_addr.u.Word[1] && - !mAddr6.sin6_addr.u.Word[2] && !mAddr6.sin6_addr.u.Word[3] && - !mAddr6.sin6_addr.u.Word[4] && !mAddr6.sin6_addr.u.Word[5] && - !mAddr6.sin6_addr.u.Word[6] && !mAddr6.sin6_addr.u.Word[7]; -#else - return IN6_IS_ADDR_UNSPECIFIED(&mAddr6.sin6_addr); -#endif - } - return false; -} - -bool NetworkAddress::isV4() const -{ - return family() == AF_INET; -} - -bool NetworkAddress::isV6() const -{ - return family() == AF_INET6; -} - -bool NetworkAddress::operator == (const NetworkAddress& rhs) const -{ - return NetworkAddress::isSame(*this, rhs); -} - -bool NetworkAddress::operator != (const NetworkAddress& rhs) const -{ - return !NetworkAddress::isSame(*this, rhs); -} - -bool NetworkAddress::operator < (const NetworkAddress& rhs) const -{ - if (family() != rhs.family()) - return family() < rhs.family(); - - if (port() != rhs.port()) - return port() < rhs.port(); - - switch (family()) - { - case AF_INET: - return memcmp(sockaddr4(), rhs.sockaddr4(), sizeof(sockaddr_in)) < 0; - - case AF_INET6: - return memcmp(sockaddr6(), rhs.sockaddr6(), sizeof(sockaddr_in6)) < 0; - } - - return false; -} - -bool NetworkAddress::operator > (const NetworkAddress& rhs) const -{ - if (family() != rhs.family()) - return family() > rhs.family(); - - if (port() != rhs.port()) - return port() > rhs.port(); - - switch (family()) - { - case AF_INET: - return memcmp(sockaddr4(), rhs.sockaddr4(), sizeof(sockaddr_in)) > 0; - - case AF_INET6: - return memcmp(sockaddr6(), rhs.sockaddr6(), sizeof(sockaddr_in6)) > 0; - } - - return false; -} - -bool NetworkAddress::isPublic() const -{ - return !isLAN() && !isLinkLocal() && !isLoopback() && !isEmpty(); -} - -void NetworkAddress::setRelayed(bool relayed) -{ - mRelayed = relayed; -} -bool NetworkAddress::relayed() const -{ - return mRelayed; -} - -bool NetworkAddress::hasHost(const std::vector& hosts) -{ - for (unsigned i=0; i> 8) & 0xFF; + if (b1 == 192 && b2 == 168) + return true; + if (b1 == 10) + return true; + if (b1 == 172 && (b2 >= 16 && b2 <= 31)) + return true; + + // Link local addresses are not routable so report them here + if (b1 == 169 && b2 == 254) + return true; + + return false; + } case AF_INET6: - if (!memcmp(&mAddr6.sin6_addr, &a.mAddr6.sin6_addr, sizeof(mAddr6.sin6_addr))) - return true; - break; + return false; + + default: + assert(0); } - } - return false; + return false; +} + +bool NetworkAddress::isLinkLocal() const +{ + assert(mInitialized); + + switch (mAddr4.sin_family) + { + case AF_INET: + { + unsigned char b1 = mAddr4.sin_addr.s_addr & 0xFF; + unsigned char b2 = (mAddr4.sin_addr.s_addr >> 8) & 0xFF; + + // Link local addresses are not routable so report them here + if (b1 == 169 && b2 == 254) + return true; + + // if (b1 == 100 && (b2 >= 64 && b2 <= 127)) + // return true; + + return false; + } + + case AF_INET6: +#ifdef WIN32 + return (mAddr6.sin6_addr.u.Byte[0] == 0xFE && mAddr6.sin6_addr.u.Byte[1] == 0x80); +#else + return IN6_IS_ADDR_LINKLOCAL(&mAddr6.sin6_addr); +#endif + default: + assert(0); + } + return false; +} + +void NetworkAddress::clear() +{ + memset(&mAddr6, 0, sizeof(mAddr6)); + mInitialized = false; +} + +bool NetworkAddress::isEmpty() const +{ + return !mInitialized; +} + +bool NetworkAddress::isZero() const +{ + if (!mInitialized) + return false; + switch (mAddr4.sin_family) + { + case AF_INET: + return mAddr4.sin_addr.s_addr == 0; + + case AF_INET6: +#ifdef WIN32 + return !mAddr6.sin6_addr.u.Word[0] && !mAddr6.sin6_addr.u.Word[1] && !mAddr6.sin6_addr.u.Word[2] && + !mAddr6.sin6_addr.u.Word[3] && !mAddr6.sin6_addr.u.Word[4] && !mAddr6.sin6_addr.u.Word[5] && + !mAddr6.sin6_addr.u.Word[6] && !mAddr6.sin6_addr.u.Word[7]; +#else + return IN6_IS_ADDR_UNSPECIFIED(&mAddr6.sin6_addr); +#endif + } + return false; +} + +bool NetworkAddress::isV4() const +{ + return family() == AF_INET; +} + +bool NetworkAddress::isV6() const +{ + return family() == AF_INET6; +} + +bool NetworkAddress::operator==(const NetworkAddress& rhs) const +{ + return NetworkAddress::isSame(*this, rhs); +} + +bool NetworkAddress::operator!=(const NetworkAddress& rhs) const +{ + return !NetworkAddress::isSame(*this, rhs); +} + +bool NetworkAddress::operator<(const NetworkAddress& rhs) const +{ + if (family() != rhs.family()) + return family() < rhs.family(); + + if (port() != rhs.port()) + return port() < rhs.port(); + + switch (family()) + { + case AF_INET: + return memcmp(sockaddr4(), rhs.sockaddr4(), sizeof(sockaddr_in)) < 0; + + case AF_INET6: + return memcmp(sockaddr6(), rhs.sockaddr6(), sizeof(sockaddr_in6)) < 0; + } + + return false; +} + +bool NetworkAddress::operator>(const NetworkAddress& rhs) const +{ + if (family() != rhs.family()) + return family() > rhs.family(); + + if (port() != rhs.port()) + return port() > rhs.port(); + + switch (family()) + { + case AF_INET: + return memcmp(sockaddr4(), rhs.sockaddr4(), sizeof(sockaddr_in)) > 0; + + case AF_INET6: + return memcmp(sockaddr6(), rhs.sockaddr6(), sizeof(sockaddr_in6)) > 0; + } + + return false; +} + +bool NetworkAddress::isPublic() const +{ + return !isLAN() && !isLinkLocal() && !isLoopback() && !isEmpty(); +} + +void NetworkAddress::setRelayed(bool relayed) +{ + mRelayed = relayed; +} +bool NetworkAddress::relayed() const +{ + return mRelayed; +} + +bool NetworkAddress::hasHost(const std::vector& hosts) +{ + for (unsigned i = 0; i < hosts.size(); i++) + { + const NetworkAddress& a = hosts[i]; + if (mAddr4.sin_family != a.mAddr4.sin_family) + continue; + + switch (mAddr4.sin_family) + { + case AF_INET: + if (!memcmp(&mAddr4.sin_addr, &a.mAddr4.sin_addr, sizeof(mAddr4.sin_addr))) + return true; + break; + + case AF_INET6: + if (!memcmp(&mAddr6.sin6_addr, &a.mAddr6.sin6_addr, sizeof(mAddr6.sin6_addr))) + return true; + break; + } + } + return false; } bool NetworkAddress::isSameHost(const NetworkAddress& a1, const NetworkAddress& a2) { - return (a1.ip() == a2.ip()); + return (a1.ip() == a2.ip()); } bool NetworkAddress::isSame(const NetworkAddress& a1, const NetworkAddress& a2) { - if (!a1.mInitialized || !a2.mInitialized) - return false; - - // Compare address families - if (a1.mAddr4.sin_family != a2.mAddr4.sin_family) - return false; + if (!a1.mInitialized || !a2.mInitialized) + return false; - if (a1.mRelayed != a2.mRelayed) + // Compare address families + if (a1.mAddr4.sin_family != a2.mAddr4.sin_family) + return false; + + if (a1.mRelayed != a2.mRelayed) + return false; + + switch (a1.mAddr4.sin_family) + { + case AF_INET: + return a1.mAddr4.sin_addr.s_addr == a2.mAddr4.sin_addr.s_addr && a1.mAddr4.sin_port == a2.mAddr4.sin_port; + + case AF_INET6: + return memcmp(&a1.mAddr6.sin6_addr, &a2.mAddr6.sin6_addr, sizeof(a1.mAddr6.sin6_addr)) == 0 && + a1.mAddr6.sin6_port == a2.mAddr6.sin6_port; + + default: + assert(0); + } return false; - - switch (a1.mAddr4.sin_family) - { - case AF_INET: - return a1.mAddr4.sin_addr.s_addr == a2.mAddr4.sin_addr.s_addr && a1.mAddr4.sin_port == a2.mAddr4.sin_port; - - case AF_INET6: - return memcmp(&a1.mAddr6.sin6_addr, &a2.mAddr6.sin6_addr, sizeof(a1.mAddr6.sin6_addr)) == 0 && - a1.mAddr6.sin6_port == a2.mAddr6.sin6_port; - - default: - assert(0); - } - return false; } -NetworkAddress& NetworkAddress::operator = (const NetworkAddress& src) +NetworkAddress& NetworkAddress::operator=(const NetworkAddress& src) { - this->mInitialized = src.mInitialized; - this->mRelayed = src.mRelayed; - this->mAddr6 = src.mAddr6; + this->mInitialized = src.mInitialized; + this->mRelayed = src.mRelayed; + this->mAddr6 = src.mAddr6; - return *this; + return *this; } diff --git a/src/libs/ice/ICEAddress.h b/src/libs/ice/ICEAddress.h index a2813c65..a04e56d4 100644 --- a/src/libs/ice/ICEAddress.h +++ b/src/libs/ice/ICEAddress.h @@ -13,13 +13,13 @@ namespace ice { - class NetworkAddress - { - public: +class NetworkAddress +{ +public: static NetworkAddress LoopbackAddress4; static NetworkAddress LoopbackAddress6; - static bool isSameLAN(const NetworkAddress& a1, const NetworkAddress& a2); - static bool isIp(const std::string& str); + static bool isSameLAN(const NetworkAddress& a1, const NetworkAddress& a2); + static bool isIp(const std::string& str); static NetworkAddress parse(const std::string& s); NetworkAddress(); @@ -40,30 +40,30 @@ namespace ice ~NetworkAddress() = default; // Returns AF_INET or AF_INET6 - int family() const; + int family() const; - unsigned char stunType() const; - void setStunType(unsigned char st); + unsigned char stunType() const; + void setStunType(unsigned char st); - sockaddr* genericsockaddr() const; - sockaddr_in* sockaddr4() const; - sockaddr_in6* sockaddr6() const; - unsigned sockaddrLen() const; - void setIp(const std::string& ip); - void setIp(unsigned long ip); - void setIp(const in_addr& ip); - void setIp(const in6_addr& ip); - void setIp(NetworkAddress ipOnly); + sockaddr* genericsockaddr() const; + sockaddr_in* sockaddr4() const; + sockaddr_in6* sockaddr6() const; + unsigned sockaddrLen() const; + void setIp(const std::string& ip); + void setIp(unsigned long ip); + void setIp(const in_addr& ip); + void setIp(const in6_addr& ip); + void setIp(NetworkAddress ipOnly); - void setPort(unsigned short port); - std::string ip() const; - unsigned char* ipBytes() const; - - unsigned short port() const; - std::string toStdString() const; - std::string toBriefStdString() const; + void setPort(unsigned short port); + std::string ip() const; + unsigned char* ipBytes() const; + + unsigned short port() const; + std::string toStdString() const; + std::string toBriefStdString() const; #ifdef WIN32 - std::wstring toStdWString() const; + std::wstring toStdWString() const; #endif bool isLoopback() const; bool isLAN() const; @@ -80,31 +80,32 @@ namespace ice bool relayed() const; bool hasHost(const std::vector& hosts); - static bool isSameHost(const NetworkAddress& a1, const NetworkAddress& a2); - - static bool isSame(const NetworkAddress& a1, const NetworkAddress& a2); + static bool isSameHost(const NetworkAddress& a1, const NetworkAddress& a2); - NetworkAddress& operator = (const NetworkAddress& src); + static bool isSame(const NetworkAddress& a1, const NetworkAddress& a2); - bool operator == (const NetworkAddress& rhs) const; - bool operator != (const NetworkAddress& rhs) const; - bool operator < (const NetworkAddress& rhs) const; - bool operator > (const NetworkAddress& rhs) const; - protected: + NetworkAddress& operator=(const NetworkAddress& src); + + bool operator==(const NetworkAddress& rhs) const; + bool operator!=(const NetworkAddress& rhs) const; + bool operator<(const NetworkAddress& rhs) const; + bool operator>(const NetworkAddress& rhs) const; + +protected: union { - sockaddr_in6 mAddr6; - sockaddr_in mAddr4; + sockaddr_in6 mAddr6; + sockaddr_in mAddr4; }; - bool mRelayed; - bool mInitialized; - }; + bool mRelayed; + bool mInitialized; +}; -} +} // namespace ice -std::ostream& operator << (std::ostream& s, const ice::NetworkAddress& addr); +std::ostream& operator<<(std::ostream& s, const ice::NetworkAddress& addr); #ifdef WIN32 -std::wostream& operator << (std::wostream& s, const ice::NetworkAddress& addr); +std::wostream& operator<<(std::wostream& s, const ice::NetworkAddress& addr); #endif #endif diff --git a/src/libs/ice/ICEAuthTransaction.cpp b/src/libs/ice/ICEAuthTransaction.cpp index a6c84e96..271c86ec 100644 --- a/src/libs/ice/ICEAuthTransaction.cpp +++ b/src/libs/ice/ICEAuthTransaction.cpp @@ -13,239 +13,238 @@ using namespace ice; #define LOG_SUBSYSTEM "ice" AuthTransaction::AuthTransaction() -:Transaction(), mActive(false), mComposed(false), mConformsToKeepaliveSchedule(true), -mCredentialsEncoded(false), mErrorCode(0) + : Transaction(), mActive(false), mComposed(false), mConformsToKeepaliveSchedule(true), mCredentialsEncoded(false), + mErrorCode(0) { } -AuthTransaction::~AuthTransaction() -{ -} +AuthTransaction::~AuthTransaction() {} void AuthTransaction::init() { - mConformsToKeepaliveSchedule = false; - if (mRealm.size() && mNonce.size()) - buildAuthenticatedMsg(); - else - { - auto msg = std::make_shared(); - msg->setTransactionId(mTransactionID); - setInitialRequest(*msg); - mComposed = false; - mOutgoingMsgQueue.push_back(msg); - } + mConformsToKeepaliveSchedule = false; + if (mRealm.size() && mNonce.size()) + buildAuthenticatedMsg(); + else + { + auto msg = std::make_shared(); + msg->setTransactionId(mTransactionID); + setInitialRequest(*msg); + mComposed = false; + mOutgoingMsgQueue.push_back(msg); + } } void AuthTransaction::buildAuthenticatedMsg() { - // Setup key for MessageIntegrity - std::string key = mUsername + ":" + mRealm + ":" + mPassword; - md5Bin(key.c_str(), key.size(), mKey); + // Setup key for MessageIntegrity + std::string key = mUsername + ":" + mRealm + ":" + mPassword; + md5Bin(key.c_str(), key.size(), mKey); - // Create new authenticated message - auto newMsg = std::make_shared(); + // Create new authenticated message + auto newMsg = std::make_shared(); - // Optional - generate new transaction ID - // mTransactionID = StunMessage::TransactionID::GenerateNew(); + // Optional - generate new transaction ID + // mTransactionID = StunMessage::TransactionID::GenerateNew(); - newMsg->setTransactionId( mTransactionID ); + newMsg->setTransactionId(mTransactionID); - // Add USERNAME - newMsg->usernameAttr().setValue( mUsername ); - newMsg->realmAttr().setValue( mRealm ); - newMsg->nonceAttr().setValue( mNonce ); + // Add USERNAME + newMsg->usernameAttr().setValue(mUsername); + newMsg->realmAttr().setValue(mRealm); + newMsg->nonceAttr().setValue(mNonce); - // Adjust message - setAuthenticatedRequest( *newMsg ); + // Adjust message + setAuthenticatedRequest(*newMsg); - // Ensure MessageIntegrity exists - newMsg->messageIntegrityAttr().setValue( NULL ); + // Ensure MessageIntegrity exists + newMsg->messageIntegrityAttr().setValue(NULL); - // Enqueue msg - mComposed = false; + // Enqueue msg + mComposed = false; - mOutgoingMsgQueue.clear(); - mOutgoingMsgQueue.push_back( newMsg ); + mOutgoingMsgQueue.clear(); + mOutgoingMsgQueue.push_back(newMsg); } bool AuthTransaction::processData(StunMessage& msg, NetworkAddress& address) { - if (msg.transactionId() != mTransactionID) - return false; - - // Check for 401 error code - if (msg.hasAttribute(StunAttribute::ErrorCode)) - { - ErrorCode& ec = msg.errorCodeAttr(); - - // Get realm value - it must be long term credentials - if (ec.errorCode() == 401 && (!mCredentialsEncoded || !mLongTerm)) - { - if (!msg.hasAttribute(StunAttribute::Realm) || !msg.hasAttribute(StunAttribute::Nonce)) + if (msg.transactionId() != mTransactionID) return false; - - Realm& realm = msg.realmAttr(); - - // Extract realm and nonce - mRealm = realm.value(); - mNonce = msg.nonceAttr().value(); - - // Change transaction id - if (mLongTerm) - { - mCredentialsEncoded = true; - generateId(); - } - ICELogDebug(<< "Server requested long term credentials for realm " << mRealm); - buildAuthenticatedMsg(); - } - else - if (ec.errorCode() == 438 && (msg.hasAttribute(StunAttribute::Realm) || msg.hasAttribute(StunAttribute::Nonce))) - { - if (msg.hasAttribute(StunAttribute::Realm)) - mRealm = msg.realmAttr().value(); - if (msg.hasAttribute(StunAttribute::Nonce)) - mNonce = msg.nonceAttr().value(); - - ICELogDebug(<< "Returned error 438, using new nonce"); - if (msg.hasAttribute(StunAttribute::Realm) && msg.hasAttribute(StunAttribute::Nonce)) - { - if (mLongTerm) - { - mCredentialsEncoded = true; - generateId(); - } - } - buildAuthenticatedMsg(); - } - else - { - mErrorCode = ec.errorCode(); - mErrorResponse = ec.errorPhrase(); - mState = Transaction::Failed; - processError(); - - ICELogError(<<"Stack ID " << mStackID << ". Got error code " << mErrorCode << " for STUN transaction. Error message: " << ec.errorPhrase()); - } - } - else - if (msg.messageClass() == StunMessage::ErrorClass) - { - mErrorCode = 0; - mState = Transaction::Failed; - processError(); - ICELogError(<<"Stack ID " << mStackID << ". Got ErrorClass response."); - } - else - { - ICELogDebug(<< "Process STUN success message"); - processSuccessMessage(msg, address); - mState = Transaction::Success; - } - return true; + // Check for 401 error code + if (msg.hasAttribute(StunAttribute::ErrorCode)) + { + ErrorCode& ec = msg.errorCodeAttr(); + + // Get realm value - it must be long term credentials + if (ec.errorCode() == 401 && (!mCredentialsEncoded || !mLongTerm)) + { + if (!msg.hasAttribute(StunAttribute::Realm) || !msg.hasAttribute(StunAttribute::Nonce)) + return false; + + Realm& realm = msg.realmAttr(); + + // Extract realm and nonce + mRealm = realm.value(); + mNonce = msg.nonceAttr().value(); + + // Change transaction id + if (mLongTerm) + { + mCredentialsEncoded = true; + generateId(); + } + ICELogDebug(<< "Server requested long term credentials for realm " << mRealm); + buildAuthenticatedMsg(); + } + else if (ec.errorCode() == 438 && + (msg.hasAttribute(StunAttribute::Realm) || msg.hasAttribute(StunAttribute::Nonce))) + { + if (msg.hasAttribute(StunAttribute::Realm)) + mRealm = msg.realmAttr().value(); + if (msg.hasAttribute(StunAttribute::Nonce)) + mNonce = msg.nonceAttr().value(); + + ICELogDebug(<< "Returned error 438, using new nonce"); + if (msg.hasAttribute(StunAttribute::Realm) && msg.hasAttribute(StunAttribute::Nonce)) + { + if (mLongTerm) + { + mCredentialsEncoded = true; + generateId(); + } + } + buildAuthenticatedMsg(); + } + else + { + mErrorCode = ec.errorCode(); + mErrorResponse = ec.errorPhrase(); + mState = Transaction::Failed; + processError(); + + ICELogError(<< "Stack ID " << mStackID << ". Got error code " << mErrorCode + << " for STUN transaction. Error message: " << ec.errorPhrase()); + } + } + else if (msg.messageClass() == StunMessage::ErrorClass) + { + mErrorCode = 0; + mState = Transaction::Failed; + processError(); + ICELogError(<< "Stack ID " << mStackID << ". Got ErrorClass response."); + } + else + { + ICELogDebug(<< "Process STUN success message"); + processSuccessMessage(msg, address); + mState = Transaction::Success; + } + + return true; } ByteBuffer* AuthTransaction::generateData(bool force) { - if (!mActive) - { - init(); - mActive = true; - } - - if (!mComposed) - { - // Restart retransmission timer as new message will be built - mRTOTimer.stop(); - mRTOTimer.start(); - - // Get message from outgoing queue - if (!mOutgoingMsgQueue.empty()) + if (!mActive) { - // Clear buffer for raw data - mOutgoingData.clear(); - - // Encode next message - StunMessage& msg = *mOutgoingMsgQueue.front(); - - //ICELogDebug(<< "Stack ID " << mStackID << ". Build message " << msg.GetTransactionID().ToString() << " from transaction " << this->GetComment()); - - if (mShortTerm) - msg.buildPacket(mOutgoingData, mPassword); - else - msg.buildPacket(mOutgoingData, std::string((char*)mKey, 16)); - - // Remove encoded message from msg queue - mOutgoingMsgQueue.pop_front(); + init(); + mActive = true; } - else - ICELogDebug(<< "No outgoing message in queue"); - - mComposed = true; - } - return Transaction::generateData(force); + if (!mComposed) + { + // Restart retransmission timer as new message will be built + mRTOTimer.stop(); + mRTOTimer.start(); + + // Get message from outgoing queue + if (!mOutgoingMsgQueue.empty()) + { + // Clear buffer for raw data + mOutgoingData.clear(); + + // Encode next message + StunMessage& msg = *mOutgoingMsgQueue.front(); + + // ICELogDebug(<< "Stack ID " << mStackID << ". Build message " << msg.GetTransactionID().ToString() << " + // from transaction " << this->GetComment()); + + if (mShortTerm) + msg.buildPacket(mOutgoingData, mPassword); + else + msg.buildPacket(mOutgoingData, std::string((char*)mKey, 16)); + + // Remove encoded message from msg queue + mOutgoingMsgQueue.pop_front(); + } + else + ICELogDebug(<< "No outgoing message in queue"); + + mComposed = true; + } + + return Transaction::generateData(force); } int AuthTransaction::errorCode() { - return mErrorCode; + return mErrorCode; } std::string AuthTransaction::errorResponse() { - return mErrorResponse; + return mErrorResponse; } void AuthTransaction::restart() { - // Clear outgoing data - mOutgoingData.clear(); - mOutgoingMsgQueue.clear(); + // Clear outgoing data + mOutgoingData.clear(); + mOutgoingMsgQueue.clear(); - mState = Transaction::Running; + mState = Transaction::Running; - // Mark "message is not built yet" - mComposed = false; + // Mark "message is not built yet" + mComposed = false; - // Mark "first request is not sent yet" - mActive = false; + // Mark "first request is not sent yet" + mActive = false; - // Reset retransmission timer - mRTOTimer.stop(); - mRTOTimer.start(); - mCredentialsEncoded = false; - mConformsToKeepaliveSchedule = true; + // Reset retransmission timer + mRTOTimer.stop(); + mRTOTimer.start(); + mCredentialsEncoded = false; + mConformsToKeepaliveSchedule = true; } bool AuthTransaction::hasToRunNow() { - bool result = Transaction::hasToRunNow(); - if (!result && keepalive()) - { - result |= mState == /*TransactionState::*/Running && !mConformsToKeepaliveSchedule; - } - return result; + bool result = Transaction::hasToRunNow(); + if (!result && keepalive()) + { + result |= mState == /*TransactionState::*/ Running && !mConformsToKeepaliveSchedule; + } + return result; } std::string AuthTransaction::realm() const { - return mRealm; + return mRealm; } void AuthTransaction::setRealm(std::string realm) { - mRealm = realm; + mRealm = realm; } std::string AuthTransaction::nonce() const { - return mNonce; + return mNonce; } void AuthTransaction::setNonce(std::string nonce) { - mNonce = nonce; + mNonce = nonce; } diff --git a/src/libs/ice/ICEAuthTransaction.h b/src/libs/ice/ICEAuthTransaction.h index 6c43258d..1a073853 100644 --- a/src/libs/ice/ICEAuthTransaction.h +++ b/src/libs/ice/ICEAuthTransaction.h @@ -10,51 +10,52 @@ #include "ICEPlatform.h" #include "ICEStunTransaction.h" -namespace ice { +namespace ice +{ -class AuthTransaction: public Transaction +class AuthTransaction : public Transaction { public: - AuthTransaction(); - virtual ~AuthTransaction(); - - // Creates initial request, calls SetInitialRequest. This method is called once from GenerateData. - void init(); + AuthTransaction(); + virtual ~AuthTransaction(); - virtual void setInitialRequest(StunMessage& msg) = 0; - virtual void setAuthenticatedRequest(StunMessage& msg) = 0; - virtual void processSuccessMessage(StunMessage& msg, NetworkAddress& sourceAddress) = 0; - virtual void processError() {} - - virtual bool processData(StunMessage& msg, NetworkAddress& address); - virtual ByteBuffer* generateData(bool force = false); + // Creates initial request, calls SetInitialRequest. This method is called once from GenerateData. + void init(); - int errorCode(); - std::string errorResponse(); - virtual void restart(); - virtual bool hasToRunNow(); + virtual void setInitialRequest(StunMessage& msg) = 0; + virtual void setAuthenticatedRequest(StunMessage& msg) = 0; + virtual void processSuccessMessage(StunMessage& msg, NetworkAddress& sourceAddress) = 0; + virtual void processError() {} - std::string realm() const; - void setRealm(std::string realm); + virtual bool processData(StunMessage& msg, NetworkAddress& address); + virtual ByteBuffer* generateData(bool force = false); - std::string nonce() const; - void setNonce(std::string nonce); + int errorCode(); + std::string errorResponse(); + virtual void restart(); + virtual bool hasToRunNow(); + + std::string realm() const; + void setRealm(std::string realm); + + std::string nonce() const; + void setNonce(std::string nonce); protected: - bool mActive; - bool mComposed; - int mErrorCode; - std::string mErrorResponse; - std::deque > mOutgoingMsgQueue; - unsigned char mKey[16] = {0}; - bool mConformsToKeepaliveSchedule; - std::string mRealm; - std::string mNonce; - bool mCredentialsEncoded; + bool mActive; + bool mComposed; + int mErrorCode; + std::string mErrorResponse; + std::deque> mOutgoingMsgQueue; + unsigned char mKey[16] = {0}; + bool mConformsToKeepaliveSchedule; + std::string mRealm; + std::string mNonce; + bool mCredentialsEncoded; - void buildAuthenticatedMsg(); + void buildAuthenticatedMsg(); }; -} // end of namespace +} // namespace ice #endif diff --git a/src/libs/ice/ICEBinding.cpp b/src/libs/ice/ICEBinding.cpp index c84a12cb..ab495d7f 100644 --- a/src/libs/ice/ICEBinding.cpp +++ b/src/libs/ice/ICEBinding.cpp @@ -16,505 +16,488 @@ using namespace ice; ConnectivityCheck::ConnectivityCheck() { - setComment("ConnectivityCheck"); - mErrorCode = 0; + setComment("ConnectivityCheck"); + mErrorCode = 0; } -ConnectivityCheck::~ConnectivityCheck() -{ -} +ConnectivityCheck::~ConnectivityCheck() {} ByteBuffer* ConnectivityCheck::generateData(bool force) { - if (!mComposed) - { - StunMessage msg; - msg.setMessageClass(StunMessage::RequestClass); - msg.setMessageType(StunMessage::Binding); - msg.setTransactionId(mTransactionID); - - if (mUseCandidate) - msg.setAttribute(new ICEUseCandidate()); - - // Use message integrity attribute - mMessageIntegrity = true; + if (!mComposed) + { + StunMessage msg; + msg.setMessageClass(StunMessage::RequestClass); + msg.setMessageType(StunMessage::Binding); + msg.setTransactionId(mTransactionID); - // Use fingerprint attribute - mFingerprint = true; + if (mUseCandidate) + msg.setAttribute(new ICEUseCandidate()); - if (mEnablePriority) - msg.icePriorityAttr().setPriority(mPriority); + // Use message integrity attribute + mMessageIntegrity = true; - // Copy comment to message object - msg.setComment(mComment); + // Use fingerprint attribute + mFingerprint = true; - enqueueMessage(msg); + if (mEnablePriority) + msg.icePriorityAttr().setPriority(mPriority); - mComposed = true; - } + // Copy comment to message object + msg.setComment(mComment); - return Transaction::generateData(force); + enqueueMessage(msg); + + mComposed = true; + } + + return Transaction::generateData(force); } void ConnectivityCheck::confirmTransaction(NetworkAddress& mapped) { - // Save resolved address&ip - mMappedAddress = mapped; + // Save resolved address&ip + mMappedAddress = mapped; - // Mark transaction as succeeded - mState = Transaction::Success; - - // Save source IP and port - mResponseAddress = mapped; + // Mark transaction as succeeded + mState = Transaction::Success; + + // Save source IP and port + mResponseAddress = mapped; } bool ConnectivityCheck::processData(StunMessage& msg, NetworkAddress& address) { #ifdef ICE_TEST_VERYAGGRESSIVE - return false; + return false; #endif - // Check if it is response - if (msg.messageClass() != StunMessage::ErrorClass && - msg.messageClass() != StunMessage::SuccessClass) - return false; - - if (msg.transactionId() != mTransactionID) - return false; - - // Validate againgst password used to encrypt - if (!msg.validatePacket(mPassword)) - return false; + // Check if it is response + if (msg.messageClass() != StunMessage::ErrorClass && msg.messageClass() != StunMessage::SuccessClass) + return false; - // Check for ErrorCode attribute - if (msg.hasAttribute(StunAttribute::ErrorCode)) - { - ErrorCode& ec = dynamic_cast(msg.attribute(StunAttribute::ErrorCode)); - - //save error code and response - mErrorCode = ec.errorCode(); - mErrorResponse = ec.errorPhrase(); - - //mark transaction as failed - mState = Transaction::Failed; + if (msg.transactionId() != mTransactionID) + return false; + + // Validate againgst password used to encrypt + if (!msg.validatePacket(mPassword)) + return false; + + // Check for ErrorCode attribute + if (msg.hasAttribute(StunAttribute::ErrorCode)) + { + ErrorCode& ec = dynamic_cast(msg.attribute(StunAttribute::ErrorCode)); + + // save error code and response + mErrorCode = ec.errorCode(); + mErrorResponse = ec.errorPhrase(); + + // mark transaction as failed + mState = Transaction::Failed; + + return true; + } + + // check if received empty ErrorClass response for poor servers + if (msg.messageClass() == StunMessage::ErrorClass) + { + // mark transaction as failed + mState = Transaction::Failed; + + return true; + } + + // check for mapped address attribute + if (msg.hasAttribute(StunAttribute::MappedAddress)) + { + // Save resolved address&ip + mMappedAddress = msg.mappedAddressAttr().address(); + + // Mark transaction as succeeded + mState = Transaction::Success; + + // Save source IP and port + mResponseAddress = address; + } + + // check for xor'ed mapped address attribute + if (msg.hasAttribute(StunAttribute::XorMappedAddress)) + { + // Save resolved IP and port + mMappedAddress = msg.xorMappedAddressAttr().address(); + + // Mark transaction as succeeded + mState = Transaction::Success; + + // Save source IP and port + mResponseAddress = address; + } return true; - } - - //check if received empty ErrorClass response for poor servers - if (msg.messageClass() == StunMessage::ErrorClass) - { - //mark transaction as failed - mState = Transaction::Failed; - - return true; - } - - //check for mapped address attribute - if (msg.hasAttribute(StunAttribute::MappedAddress)) - { - // Save resolved address&ip - mMappedAddress = msg.mappedAddressAttr().address(); - - // Mark transaction as succeeded - mState = Transaction::Success; - - // Save source IP and port - mResponseAddress = address; - } - - //check for xor'ed mapped address attribute - if (msg.hasAttribute(StunAttribute::XorMappedAddress)) - { - // Save resolved IP and port - mMappedAddress = msg.xorMappedAddressAttr().address(); - - // Mark transaction as succeeded - mState = Transaction::Success; - - // Save source IP and port - mResponseAddress = address; - } - - return true; } NetworkAddress& ConnectivityCheck::mappedAddress() { - return mMappedAddress; + return mMappedAddress; } NetworkAddress& ConnectivityCheck::responseAddress() { - return mResponseAddress; + return mResponseAddress; } void ConnectivityCheck::addUseCandidate() { - mUseCandidate = true; + mUseCandidate = true; } int ConnectivityCheck::errorCode() { - return mErrorCode; + return mErrorCode; } int ConnectivityCheck::resultError() { - return mErrorCode; + return mErrorCode; } NetworkAddress& ConnectivityCheck::resultSource() { - return mResponseAddress; + return mResponseAddress; } Transaction::State ConnectivityCheck::resultState() { - return state(); + return state(); } NetworkAddress& ConnectivityCheck::resultLocal() { - return mMappedAddress; + return mMappedAddress; } void ConnectivityCheck::useCandidate() { - addUseCandidate(); + addUseCandidate(); } unsigned ConnectivityCheck::resultPriority() { - return priorityValue(); + return priorityValue(); } //---------------------------- ClientBindingTransaction ---------------------------- -ClientBinding::ClientBinding() -:Transaction(), mErrorCode(0), mUseCandidate(false) +ClientBinding::ClientBinding() : Transaction(), mErrorCode(0), mUseCandidate(false) { - setComment("ClientBinding"); + setComment("ClientBinding"); } -ClientBinding::~ClientBinding() -{ -} - +ClientBinding::~ClientBinding() {} + int ClientBinding::errorCode() { - return mErrorCode; + return mErrorCode; } std::string ClientBinding::errorResponse() { - return mErrorResponse; + return mErrorResponse; } NetworkAddress& ClientBinding::mappedAddress() { - return mMappedAddress; + return mMappedAddress; } NetworkAddress& ClientBinding::responseAddress() { - return mResponseAddress; + return mResponseAddress; } bool ClientBinding::processData(StunMessage& msg, NetworkAddress& address) { - // Check if it is response - if (msg.messageClass() != StunMessage::ErrorClass && - msg.messageClass() != StunMessage::SuccessClass) - return false; - - if (msg.transactionId() != this->mTransactionID) - return false; - - // Check for ErrorCode attribute - if (msg.hasAttribute(StunAttribute::ErrorCode)) - { - // Save error code and response - mErrorCode = msg.errorCodeAttr().errorCode(); - mErrorResponse = msg.errorCodeAttr().errorPhrase(); - - // Mark transaction as failed - mState = Transaction::Failed; + // Check if it is response + if (msg.messageClass() != StunMessage::ErrorClass && msg.messageClass() != StunMessage::SuccessClass) + return false; + + if (msg.transactionId() != this->mTransactionID) + return false; + + // Check for ErrorCode attribute + if (msg.hasAttribute(StunAttribute::ErrorCode)) + { + // Save error code and response + mErrorCode = msg.errorCodeAttr().errorCode(); + mErrorResponse = msg.errorCodeAttr().errorPhrase(); + + // Mark transaction as failed + mState = Transaction::Failed; + + return true; + } + + // Check if received empty ErrorClass response for poor servers + if (msg.messageClass() == StunMessage::ErrorClass) + { + // Mark transaction as failed + mState = Transaction::Failed; + + return true; + } + + // Check for mapped address attribute + if (msg.hasAttribute(StunAttribute::MappedAddress)) + { + // Save resolved address&ip + mMappedAddress = msg.mappedAddressAttr().address(); + + // mMark transaction as succeeded + mState = Transaction::Success; + + // Save source IP and port + mResponseAddress = address; + } + + // check for xor'ed mapped address attribute + if (msg.hasAttribute(StunAttribute::XorMappedAddress)) + { + // Save resolved IP and port + mMappedAddress = msg.xorMappedAddressAttr().address(); + + // Mark transaction as succeeded + mState = Transaction::Success; + + // Save source IP and port + mResponseAddress = address; + } return true; - } - - // Check if received empty ErrorClass response for poor servers - if (msg.messageClass() == StunMessage::ErrorClass) - { - // Mark transaction as failed - mState = Transaction::Failed; - - return true; - } - - // Check for mapped address attribute - if (msg.hasAttribute(StunAttribute::MappedAddress)) - { - // Save resolved address&ip - mMappedAddress = msg.mappedAddressAttr().address(); - - // mMark transaction as succeeded - mState = Transaction::Success; - - // Save source IP and port - mResponseAddress = address; - } - - //check for xor'ed mapped address attribute - if (msg.hasAttribute(StunAttribute::XorMappedAddress)) - { - // Save resolved IP and port - mMappedAddress = msg.xorMappedAddressAttr().address(); - - // Mark transaction as succeeded - mState = Transaction::Success; - - // Save source IP and port - mResponseAddress = address; - } - - return true; } ByteBuffer* ClientBinding::generateData(bool force) { - if (!mComposed) - { - StunMessage msg; - msg.setMessageType(ice::StunMessage::Binding); - msg.setMessageClass(ice::StunMessage::RequestClass); - msg.setTransactionId(mTransactionID); - - if (mUseCandidate) - msg.setAttribute(new ICEUseCandidate()); + if (!mComposed) + { + StunMessage msg; + msg.setMessageType(ice::StunMessage::Binding); + msg.setMessageClass(ice::StunMessage::RequestClass); + msg.setTransactionId(mTransactionID); - // Copy comment to message object - msg.setComment(mComment); + if (mUseCandidate) + msg.setAttribute(new ICEUseCandidate()); - enqueueMessage(msg); - - mComposed = true; - } + // Copy comment to message object + msg.setComment(mComment); - return Transaction::generateData(force); + enqueueMessage(msg); + + mComposed = true; + } + + return Transaction::generateData(force); } void ClientBinding::addUseCandidate() { - mUseCandidate = true; + mUseCandidate = true; } - + //------------------------------ ServerBindingTransaction --------------------------- ServerBinding::ServerBinding() { - setComment("ServerBinding"); + setComment("ServerBinding"); - mGenerate400 = false; - mGenerate487 = false; - mRole = 0; + mGenerate400 = false; + mGenerate487 = false; + mRole = 0; } -ServerBinding::~ServerBinding() -{ -} +ServerBinding::~ServerBinding() {} void ServerBinding::setLocalTieBreaker(std::string tieBreaker) { - mLocalTieBreaker = tieBreaker; + mLocalTieBreaker = tieBreaker; } bool ServerBinding::processData(StunMessage& msg, NetworkAddress& address) { - if (msg.messageType() != StunMessage::Binding || msg.messageClass() != StunMessage::RequestClass) - return false; - ICELogDebug(<< "Received Binding request from " << address.toStdString().c_str()); - - // Save visible address - mSourceAddress = address; - - // Save transaction ID - mTransactionID = msg.transactionId(); - - // Save Priority value - if (msg.hasAttribute(StunAttribute::ICEPriority)) - { - mEnablePriority = true; - mPriority = msg.icePriorityAttr().priority(); - } + if (msg.messageType() != StunMessage::Binding || msg.messageClass() != StunMessage::RequestClass) + return false; + ICELogDebug(<< "Received Binding request from " << address.toStdString().c_str()); - // Save UseCandidate flag - mUseCandidate = msg.hasAttribute(StunAttribute::ICEUseCandidate); + // Save visible address + mSourceAddress = address; - // Check if auth credentials are needed - mGenerate400 = false; //do not send 400 response by default - mGenerate487 = false; - - if (!msg.hasAttribute(StunAttribute::Username) || !msg.hasAttribute(StunAttribute::MessageIntegrity)) - { - ICELogError(<< "There is no Username or MessageIntegrity attributes in Binding required. Error 400 will be generated."); - // Send 400 error - mGenerate400 = true; + // Save transaction ID + mTransactionID = msg.transactionId(); + + // Save Priority value + if (msg.hasAttribute(StunAttribute::ICEPriority)) + { + mEnablePriority = true; + mPriority = msg.icePriorityAttr().priority(); + } + + // Save UseCandidate flag + mUseCandidate = msg.hasAttribute(StunAttribute::ICEUseCandidate); + + // Check if auth credentials are needed + mGenerate400 = false; // do not send 400 response by default + mGenerate487 = false; + + if (!msg.hasAttribute(StunAttribute::Username) || !msg.hasAttribute(StunAttribute::MessageIntegrity)) + { + ICELogError( + << "There is no Username or MessageIntegrity attributes in Binding required. Error 400 will be generated."); + // Send 400 error + mGenerate400 = true; + + return true; + } + + // Check for role + if (msg.hasAttribute(StunAttribute::ControlledAttr)) + { + mRemoteTieBreaker = msg.iceControlledAttr().tieBreaker(); + mRole = 1; // Session::Controlled; + } + else if (msg.hasAttribute(StunAttribute::ControllingAttr)) + { + mRemoteTieBreaker = msg.iceControllingAttr().tieBreaker(); + mRole = 2; // Session::Controlling; + } return true; - } - - // Check for role - if (msg.hasAttribute(StunAttribute::ControlledAttr)) - { - mRemoteTieBreaker = msg.iceControlledAttr().tieBreaker(); - mRole = 1; // Session::Controlled; - } - else - if (msg.hasAttribute(StunAttribute::ControllingAttr)) - { - mRemoteTieBreaker = msg.iceControllingAttr().tieBreaker(); - mRole = 2;// Session::Controlling; - } - - return true; } ByteBuffer* ServerBinding::generateData(bool force) { - // Restart timer - mRTOTimer.stop(); - mRTOTimer.start(); - - // See if remote password / username are set - if (mPassword.empty() || mUsername.empty()) - return NULL; + // Restart timer + mRTOTimer.stop(); + mRTOTimer.start(); - StunMessage msg; - - // Set transaction ID the same as processed incoming message - msg.setTransactionId(mTransactionID); - msg.setMessageType(StunMessage::Binding); - - if (mGenerate400) - { - // Generate bad request error - msg.setMessageClass(StunMessage::ErrorClass); - - msg.errorCodeAttr().setErrorCode(400); - msg.errorCodeAttr().setErrorPhrase("Bad request"); - } - else - if (mGenerate487) - { - // Generate 487 error - msg.setMessageClass(StunMessage::ErrorClass); - msg.errorCodeAttr().setErrorCode(487); - msg.errorCodeAttr().setErrorPhrase("Role conflict"); - } - else - { - msg.setMessageClass(StunMessage::SuccessClass); - - msg.mappedAddressAttr().address() = mSourceAddress; - msg.xorMappedAddressAttr().address() = mSourceAddress; - } + // See if remote password / username are set + if (mPassword.empty() || mUsername.empty()) + return NULL; - // Build message - - // Clear outgoing buffer - mOutgoingData.clear(); - - // Check if message should be secured by message integrity - //std::string password; - if (!mGenerate400 && !mGenerate487) - { - // Do not create username attribute here - response does not need it - // msg.usernameAttr().setValue(mUsername); - - //ICELogMedia(<< "Using password " << mPassword); + StunMessage msg; - // Add message integrity attribute - msg.setAttribute(new MessageIntegrity()); - - if (mFingerprint) - msg.setAttribute(new Fingerprint()); - - // Add ICE-CONTROLLED attribute if needed - if (mEnableControlled) - msg.iceControlledAttr().setTieBreaker(mLocalTieBreaker); + // Set transaction ID the same as processed incoming message + msg.setTransactionId(mTransactionID); + msg.setMessageType(StunMessage::Binding); - // Add ICE-CONTROLLING attribute if needed - if (mEnableControlling) - msg.iceControllingAttr().setTieBreaker(mLocalTieBreaker); + if (mGenerate400) + { + // Generate bad request error + msg.setMessageClass(StunMessage::ErrorClass); - // Add ICE-PRIORITY attribute if needed - if (mEnablePriority) - msg.icePriorityAttr().setPriority(mPriority); - } + msg.errorCodeAttr().setErrorCode(400); + msg.errorCodeAttr().setErrorPhrase("Bad request"); + } + else if (mGenerate487) + { + // Generate 487 error + msg.setMessageClass(StunMessage::ErrorClass); + msg.errorCodeAttr().setErrorCode(487); + msg.errorCodeAttr().setErrorPhrase("Role conflict"); + } + else + { + msg.setMessageClass(StunMessage::SuccessClass); - // Build packet - msg.buildPacket(mOutgoingData, mPassword); - - // Copy comment - msg.setComment(mComment); + msg.mappedAddressAttr().address() = mSourceAddress; + msg.xorMappedAddressAttr().address() = mSourceAddress; + } - mComposed = true; - - return new ByteBuffer(mOutgoingData); + // Build message + + // Clear outgoing buffer + mOutgoingData.clear(); + + // Check if message should be secured by message integrity + // std::string password; + if (!mGenerate400 && !mGenerate487) + { + // Do not create username attribute here - response does not need it + // msg.usernameAttr().setValue(mUsername); + + // ICELogMedia(<< "Using password " << mPassword); + + // Add message integrity attribute + msg.setAttribute(new MessageIntegrity()); + + if (mFingerprint) + msg.setAttribute(new Fingerprint()); + + // Add ICE-CONTROLLED attribute if needed + if (mEnableControlled) + msg.iceControlledAttr().setTieBreaker(mLocalTieBreaker); + + // Add ICE-CONTROLLING attribute if needed + if (mEnableControlling) + msg.iceControllingAttr().setTieBreaker(mLocalTieBreaker); + + // Add ICE-PRIORITY attribute if needed + if (mEnablePriority) + msg.icePriorityAttr().setPriority(mPriority); + } + + // Build packet + msg.buildPacket(mOutgoingData, mPassword); + + // Copy comment + msg.setComment(mComment); + + mComposed = true; + + return new ByteBuffer(mOutgoingData); } bool ServerBinding::hasUseCandidate() { - return mUseCandidate; + return mUseCandidate; } bool ServerBinding::gotRequest() { - return !mGenerate400 && !mGenerate487; + return !mGenerate400 && !mGenerate487; } int ServerBinding::role() { - return mRole; + return mRole; } void ServerBinding::generate487() { - mGenerate487 = true; + mGenerate487 = true; } std::string ServerBinding::remoteTieBreaker() { - return mRemoteTieBreaker; + return mRemoteTieBreaker; } -void ServerBinding::restart() -{ -} +void ServerBinding::restart() {} //-------------------- BindingIndication --------------- -BindingIndication::BindingIndication(unsigned int interval) -:mInterval(interval) +BindingIndication::BindingIndication(unsigned int interval) : mInterval(interval) { - setComment("BindingIndication"); + setComment("BindingIndication"); } -BindingIndication::~BindingIndication() -{ -} +BindingIndication::~BindingIndication() {} bool BindingIndication::processData(StunMessage& msg, NetworkAddress& address) { - return (msg.messageClass() == StunMessage::IndicationClass && - msg.messageType() == StunMessage::Binding); + return (msg.messageClass() == StunMessage::IndicationClass && msg.messageType() == StunMessage::Binding); } ByteBuffer* BindingIndication::generateData(bool force) { - if (!mComposed) - { - StunMessage msg; - msg.setMessageClass(StunMessage::IndicationClass); - msg.setMessageType(StunMessage::Binding); - msg.setTransactionId(mTransactionID); - msg.setComment(mComment); - enqueueMessage(msg); - mComposed = true; - } + if (!mComposed) + { + StunMessage msg; + msg.setMessageClass(StunMessage::IndicationClass); + msg.setMessageType(StunMessage::Binding); + msg.setTransactionId(mTransactionID); + msg.setComment(mComment); + enqueueMessage(msg); + mComposed = true; + } - return Transaction::generateData(force); + return Transaction::generateData(force); } - diff --git a/src/libs/ice/ICEBinding.h b/src/libs/ice/ICEBinding.h index 5ea7272b..c9e4981d 100644 --- a/src/libs/ice/ICEBinding.h +++ b/src/libs/ice/ICEBinding.h @@ -12,120 +12,121 @@ namespace ice { - class CheckResult - { - public: +class CheckResult +{ +public: virtual Transaction::State resultState() = 0; - virtual int resultError() = 0; - virtual NetworkAddress& resultSource() = 0; - virtual NetworkAddress& resultLocal() = 0; - virtual void useCandidate() = 0; - virtual unsigned resultPriority() = 0; - }; + virtual int resultError() = 0; + virtual NetworkAddress& resultSource() = 0; + virtual NetworkAddress& resultLocal() = 0; + virtual void useCandidate() = 0; + virtual unsigned resultPriority() = 0; +}; - class ConnectivityCheck: public Transaction, public CheckResult - { - public: +class ConnectivityCheck : public Transaction, public CheckResult +{ +public: ConnectivityCheck(); virtual ~ConnectivityCheck(); - ByteBuffer* generateData(bool force = false); + ByteBuffer* generateData(bool force = false); bool processData(StunMessage& msg, NetworkAddress& sourceAddress); - NetworkAddress& mappedAddress(); //returns result from succesful transaction - NetworkAddress& responseAddress(); //returns responses source address + NetworkAddress& mappedAddress(); // returns result from succesful transaction + NetworkAddress& responseAddress(); // returns responses source address int errorCode(); void addUseCandidate(); void confirmTransaction(NetworkAddress& mapped); // CheckResult interface - int resultError(); + int resultError(); NetworkAddress& resultSource(); NetworkAddress& resultLocal(); - State resultState(); - void useCandidate(); - unsigned resultPriority(); - protected: - NetworkAddress mResponseAddress; - NetworkAddress mMappedAddress; - bool mUseCandidate; - int mErrorCode; - std::string mErrorResponse; - }; + State resultState(); + void useCandidate(); + unsigned resultPriority(); - class ClientBinding: public Transaction - { - public: +protected: + NetworkAddress mResponseAddress; + NetworkAddress mMappedAddress; + bool mUseCandidate; + int mErrorCode; + std::string mErrorResponse; +}; + +class ClientBinding : public Transaction +{ +public: ClientBinding(); virtual ~ClientBinding(); - - int errorCode(); //returns error code from failed transaction - std::string errorResponse(); //returns error msg from failed transaction - NetworkAddress& mappedAddress(); //returns result from succesful transaction - NetworkAddress& responseAddress(); //returns responses source address - - bool processData(StunMessage& msg, NetworkAddress& address); - ByteBuffer* generateData(bool force = false); - void addUseCandidate(); - protected: - int mErrorCode; - NetworkAddress mMappedAddress; - std::string mErrorResponse; - NetworkAddress mResponseAddress; - bool mUseCandidate; - }; + int errorCode(); // returns error code from failed transaction + std::string errorResponse(); // returns error msg from failed transaction + NetworkAddress& mappedAddress(); // returns result from succesful transaction + NetworkAddress& responseAddress(); // returns responses source address - class ServerBinding: public Transaction - { - public: + bool processData(StunMessage& msg, NetworkAddress& address); + ByteBuffer* generateData(bool force = false); + void addUseCandidate(); + +protected: + int mErrorCode; + NetworkAddress mMappedAddress; + std::string mErrorResponse; + NetworkAddress mResponseAddress; + bool mUseCandidate; +}; + +class ServerBinding : public Transaction +{ +public: ServerBinding(); virtual ~ServerBinding(); - void setLocalTieBreaker(std::string tieBreaker); + void setLocalTieBreaker(std::string tieBreaker); + + bool processData(StunMessage& msg, NetworkAddress& address); + ByteBuffer* generateData(bool force = false); + void restart(); - bool processData(StunMessage& msg, NetworkAddress& address); - ByteBuffer* generateData(bool force = false); - void restart(); - // Checks if incoming request has UseCandidate attribute - bool hasUseCandidate(); - + bool hasUseCandidate(); + // Checks if processed StunMessage was authenticated ok - bool gotRequest(); - + bool gotRequest(); + // Gets the role from processed message. It can be Controlled or Controlling or None. - int role(); - + int role(); + // Instructs transaction to response with 487 code - void generate487(); - + void generate487(); + // Returns received tie breaker - std::string remoteTieBreaker(); + std::string remoteTieBreaker(); - protected: - NetworkAddress mSourceAddress; - bool mUseCandidate; - bool mGenerate400; - bool mGenerate487; - int mRole; - std::string mLocalTieBreaker; - std::string mRemoteTieBreaker; - }; +protected: + NetworkAddress mSourceAddress; + bool mUseCandidate; + bool mGenerate400; + bool mGenerate487; + int mRole; + std::string mLocalTieBreaker; + std::string mRemoteTieBreaker; +}; - class BindingIndication: public Transaction - { - public: +class BindingIndication : public Transaction +{ +public: BindingIndication(unsigned int interval); virtual ~BindingIndication(); - bool processData(StunMessage& msg, NetworkAddress& address); - ByteBuffer* generateData(bool force = false); + bool processData(StunMessage& msg, NetworkAddress& address); + ByteBuffer* generateData(bool force = false); - protected: +protected: unsigned mTimestamp; unsigned mInterval; - }; -} +}; +} // namespace ice #endif \ No newline at end of file diff --git a/src/libs/ice/ICEBox.cpp b/src/libs/ice/ICEBox.cpp index 1da3cda6..ef6343d4 100644 --- a/src/libs/ice/ICEBox.cpp +++ b/src/libs/ice/ICEBox.cpp @@ -9,52 +9,48 @@ using namespace ice; -Stack::~Stack() -{ -} +Stack::~Stack() {} -void Stack::initialize() -{ -} +void Stack::initialize() {} void Stack::finalize() { - ; + ; } Stack* Stack::makeICEBox(const ServerConfig& config) { - return new StackImpl(config); + return new StackImpl(config); } bool Stack::isDataIndication(ByteBuffer& source, ByteBuffer* plain) { - return Session::isDataIndication(source, plain); + return Session::isDataIndication(source, plain); } bool Stack::isStun(ByteBuffer& source) { - return Session::isStun(source); + return Session::isStun(source); } bool Stack::isRtp(ByteBuffer& data) { - return Session::isRtp(data); + return Session::isRtp(data); } bool Stack::isChannelData(ByteBuffer& data, TurnPrefix prefix) { - return Session::isChannelData(data, prefix); + return Session::isChannelData(data, prefix); } ByteBuffer Stack::makeChannelData(TurnPrefix prefix, const void* data, unsigned datasize) { - ByteBuffer result; - result.resize(4 + datasize); - BufferWriter writer(result); - writer.writeUShort(prefix); - writer.writeUShort(datasize); - writer.writeBuffer(data, datasize); - - return result; + ByteBuffer result; + result.resize(4 + datasize); + BufferWriter writer(result); + writer.writeUShort(prefix); + writer.writeUShort(datasize); + writer.writeBuffer(data, datasize); + + return result; } diff --git a/src/libs/ice/ICEBox.h b/src/libs/ice/ICEBox.h index 4b37710a..a9d465d7 100644 --- a/src/libs/ice/ICEBox.h +++ b/src/libs/ice/ICEBox.h @@ -21,91 +21,90 @@ #define ICE_RTP_ID 1 #define ICE_RTCP_ID 2 -namespace ice +namespace ice { - // Structure to describe used STUN/TURN configuration - struct ServerConfig - { +// Structure to describe used STUN/TURN configuration +struct ServerConfig +{ std::vector mServerList4, mServerList6; // List of STUN/TURN servers for IPv4 and IPv6 protocols - bool mUseIPv4; // Marks if IPv4 should be used when gathering candidates - bool mUseIPv6; // Marks if IPv6 should be used when gathering candidates - std::string mHost; // Target host to get default IP interface; usually it is public IP address - bool mRelay; // Marks if TURN is to be used instead STUN - unsigned int mTimeout; // Timeout value in milliseconds - unsigned int mPeriod; // Transmission interval - std::string mUsername; // User name for TURN server [optional] - std::string mPassword; // Password for TURN server [optional] - - ServerConfig() - :mUseIPv4(true), mUseIPv6(true), mRelay(false), mTimeout(ICE_TIMEOUT), mPeriod(ICE_CHECK_INTERVAL) - { - } + bool mUseIPv4; // Marks if IPv4 should be used when gathering candidates + bool mUseIPv6; // Marks if IPv6 should be used when gathering candidates + std::string mHost; // Target host to get default IP interface; usually it is public IP address + bool mRelay; // Marks if TURN is to be used instead STUN + unsigned int mTimeout; // Timeout value in milliseconds + unsigned int mPeriod; // Transmission interval + std::string mUsername; // User name for TURN server [optional] + std::string mPassword; // Password for TURN server [optional] - ~ServerConfig() - {} - }; - - enum IceState - { - IceNone = 0, // Stack non active now - IceGathering = 1, // Stack gathering candidates now - IceGathered = 2, // Stack gathered candidates - IceChecking = 3, // Stack runs connectivity checks now - IceCheckSuccess = 4, // Connectivity checks were successful - IceFailed = 5, // Connectivity checks or gathering failed - IceTimeout = 6 // Timeout - }; - - - enum AgentRole - { + ServerConfig() : mUseIPv4(true), mUseIPv6(true), mRelay(false), mTimeout(ICE_TIMEOUT), mPeriod(ICE_CHECK_INTERVAL) + { + } + + ~ServerConfig() {} +}; + +enum IceState +{ + IceNone = 0, // Stack non active now + IceGathering = 1, // Stack gathering candidates now + IceGathered = 2, // Stack gathered candidates + IceChecking = 3, // Stack runs connectivity checks now + IceCheckSuccess = 4, // Connectivity checks were successful + IceFailed = 5, // Connectivity checks or gathering failed + IceTimeout = 6 // Timeout +}; + + +enum AgentRole +{ RoleControlled = 1, RoleControlling = 2 - }; +}; - // ICE stack - class Stack - { - public: - static void initialize(); - static void finalize(); +// ICE stack +class Stack +{ +public: + static void initialize(); + static void finalize(); + + static Stack* makeICEBox(const ServerConfig& config); - static Stack* makeICEBox(const ServerConfig& config); - // Service methods to check incoming packets - static bool isDataIndication(ByteBuffer& source, ByteBuffer* plain); - static bool isStun(ByteBuffer& source); - static bool isRtp(ByteBuffer& data); - static bool isChannelData(ByteBuffer& data, TurnPrefix prefix); + static bool isDataIndication(ByteBuffer& source, ByteBuffer* plain); + static bool isStun(ByteBuffer& source); + static bool isRtp(ByteBuffer& data); + static bool isChannelData(ByteBuffer& data, TurnPrefix prefix); - static ByteBuffer makeChannelData(TurnPrefix prefix, const void* data, unsigned datasize); + static ByteBuffer makeChannelData(TurnPrefix prefix, const void* data, unsigned datasize); /*! Sets ICE event handler pointer in stack. * @param handler Pointer to ICE event handler instance. * @param tag Custom user tag. */ - virtual void setEventHandler(StageHandler* handler, void* tag) = 0; - + virtual void setEventHandler(StageHandler* handler, void* tag) = 0; + /*! Adds new stream to ICE stack object. * @return ID of created stream. */ - virtual int addStream() = 0; + virtual int addStream() = 0; + + /*! Adds new component (socket) to media stream. + * @param portNumber specifies used local port number for the socket. + * @returns component ID. This ID is unique only for specified stream. Two components in different streams can have + * the same */ + virtual int addComponent(int streamID, void* tag, unsigned short port4, unsigned short port6) = 0; - /*! Adds new component (socket) to media stream. - * @param portNumber specifies used local port number for the socket. - * @returns component ID. This ID is unique only for specified stream. Two components in different streams can have the same */ - virtual int addComponent(int streamID, void* tag, unsigned short port4, unsigned short port6) = 0; - /*! Removes media stream from ICE stack object. */ - virtual void removeStream(int streamID) = 0; - - virtual bool hasStream(int streamId) = 0; - virtual bool hasComponent(int streamId, int componentId) = 0; - virtual void setComponentPort(int streamId, int componentId, unsigned short port4, unsigned short port6) = 0; + virtual void removeStream(int streamID) = 0; + + virtual bool hasStream(int streamId) = 0; + virtual bool hasComponent(int streamId, int componentId) = 0; + virtual void setComponentPort(int streamId, int componentId, unsigned short port4, unsigned short port6) = 0; + + virtual void setRole(AgentRole role) = 0; + virtual AgentRole role() = 0; - virtual void setRole(AgentRole role) = 0; - virtual AgentRole role() = 0; - /*! Processes incoming data. * @param streamID ICE stream ID * @param componentID ICE component ID @@ -114,39 +113,40 @@ namespace ice * @param sourceBuffer pointer to incoming data buffer * @param sourceSize size of incoming data (in bytes) */ - virtual bool processIncomingData(int stream, int component, ByteBuffer& incomingData) = 0; - - /*! Generates outgoing data for sending. + virtual bool processIncomingData(int stream, int component, ByteBuffer& incomingData) = 0; + + /*! Generates outgoing data for sending. * @param response marks if the returned packet is response packet to remote peer's request * @param streamID ICE stream ID * @param componentID ICE component ID * @param destIP Character buffer to write destination IP address in textual form * @param destPort Destination port number. - * @param dataBuffer Pointer to output buffer. It must be big enough to include at least 1500 bytes - it is biggest UDP datagram in this library. + * @param dataBuffer Pointer to output buffer. It must be big enough to include at least 1500 bytes - it is biggest + * UDP datagram in this library. */ virtual PByteBuffer generateOutgoingData(bool& response, int& stream, int& component, void*& tag) = 0; - + /*! Searches stream&component IDs by used local port and socket family. */ - virtual bool findStreamAndComponent(int family, unsigned short port, int* stream, int* component) = 0; + virtual bool findStreamAndComponent(int family, unsigned short port, int* stream, int* component) = 0; /*! Starts to gather local candidates. */ - virtual void gatherCandidates() = 0; - - /*! Starts ICE connectivity checks. */ - virtual void checkConnectivity() = 0; + virtual void gatherCandidates() = 0; + + /*! Starts ICE connectivity checks. */ + virtual void checkConnectivity() = 0; /*! Checks if gathering is finished. */ - virtual IceState state() = 0; - - /*! Creates common part of SDP. It includes ice-full attribute and ufrag/pwd pair. + virtual IceState state() = 0; + + /*! Creates common part of SDP. It includes ice-full attribute and ufrag/pwd pair. * @param common Common part of SDP. */ - virtual void createSdp(std::vector& common) = 0; - + virtual void createSdp(std::vector& common) = 0; + /*! Returns default address for specified stream/component ID. * @param ip Default IP address. * @param port Default port number. */ virtual NetworkAddress defaultAddress(int streamID, int componentID) = 0; - + /*! Returns candidate list for specified stream/component ID. * @param streamID Stream ID. * @param componentID Component ID. @@ -157,95 +157,98 @@ namespace ice * @param streamIndex ICE stream index. * @param candidateList Input vector of strings - it holds candidate list. * @param defaultIP Default IP for component ID 0. - * @param defaultPort Default port number for component ID 0. + * @param defaultPort Default port number for component ID 0. * @return Returns true if processing(parsing) was ok, otherwise method returns false. */ - virtual bool processSdpOffer(int streamIndex, std::vector& candidateList, - const std::string& defaultIP, unsigned short defaultPort, bool deleteRelayed) = 0; - + virtual bool processSdpOffer(int streamIndex, std::vector& candidateList, const std::string& defaultIP, + unsigned short defaultPort, bool deleteRelayed) = 0; + virtual NetworkAddress getRemoteRelayedCandidate(int stream, int component) = 0; virtual NetworkAddress getRemoteReflexiveCandidate(int stream, int component) = 0; - + /*! Notifies stack about ICE password of remote peer. * @param pwd ICE password. */ - virtual void setRemotePassword(const std::string& pwd, int streamId = -1) = 0; - virtual std::string remotePassword(int streamId = -1) const = 0; + virtual void setRemotePassword(const std::string& pwd, int streamId = -1) = 0; + virtual std::string remotePassword(int streamId = -1) const = 0; /*! Notifies stack about ICE ufrag of remote peer. * @param ufrag ICE ufrag credential. */ - virtual void setRemoteUfrag(const std::string& ufrag, int streamId = -1) = 0; - virtual std::string remoteUfrag(int streamId = -1) const = 0; + virtual void setRemoteUfrag(const std::string& ufrag, int streamId = -1) = 0; + virtual std::string remoteUfrag(int streamId = -1) const = 0; /*! Returns local ICE password. * @return ICE password. */ - virtual std::string localPassword() const = 0; - + virtual std::string localPassword() const = 0; + /*! Returns local ICE ufrag. * @return ICE ufrag credential. */ - virtual std::string localUfrag() const = 0; + virtual std::string localUfrag() const = 0; - /*! Checks if the specified value is ICE session's TURN prefix value. - * @return Returns true if parameter is TURN prefix value, false otherwise. */ - virtual bool hasTurnPrefix(unsigned short prefix) = 0; - - /*! Gets the discovered during connectivity checks remote party's address. - * @return Remote party's address */ - virtual NetworkAddress remoteAddress(int stream, int component) = 0; + /*! Checks if the specified value is ICE session's TURN prefix value. + * @return Returns true if parameter is TURN prefix value, false otherwise. */ + virtual bool hasTurnPrefix(unsigned short prefix) = 0; + + /*! Gets the discovered during connectivity checks remote party's address. + * @return Remote party's address */ + virtual NetworkAddress remoteAddress(int stream, int component) = 0; virtual NetworkAddress localAddress(int stream, int component) = 0; - - /*! Seeks for conclude pair. - */ - virtual bool findConcludePair(int stream, Candidate& local, Candidate& remote) = 0; - /*! Checks if remote candidate list contains specified address. - * @return True if address is found in remote candidate list, false otherwise. */ - virtual bool candidateListContains(int stream, const std::string& remoteIP, unsigned short remotePort) = 0; - + /*! Seeks for conclude pair. + */ + virtual bool findConcludePair(int stream, Candidate& local, Candidate& remote) = 0; + + /*! Checks if remote candidate list contains specified address. + * @return True if address is found in remote candidate list, false otherwise. */ + virtual bool candidateListContains(int stream, const std::string& remoteIP, unsigned short remotePort) = 0; + // Dumps current state of stack to output - virtual void dump(std::ostream& output) = 0; + virtual void dump(std::ostream& output) = 0; // Returns if ICE session must be restarted after new offer. - virtual bool mustRestart() = 0; - - // Clears all connectivity checks and reset state of session to None. It does not delete streams and components. - virtual void clear() = 0; - - // Prepares stack to restart - clears remote candidate list, cancels existing connectivity checks, resets turn allocation counter - virtual void clearForRestart(bool localNetworkChanged) = 0; - - // Stops all connectivity & gathering checks. - virtual void stopChecks() = 0; - - // Refreshes local password and ufrag values. Useful when connectivity checks must be restarted. - virtual void refreshPwdUfrag() = 0; - - // Binds channel and return channel prefix - virtual TurnPrefix bindChannel(int stream, int component, const NetworkAddress& target, ChannelBoundCallback* cb) = 0; - virtual bool isChannelBindingFailed(int stream, int component, TurnPrefix prefix) = 0; + virtual bool mustRestart() = 0; - virtual void installPermissions(int stream, int component, const NetworkAddress& address, InstallPermissionsCallback* cb) = 0; + // Clears all connectivity checks and reset state of session to None. It does not delete streams and components. + virtual void clear() = 0; + + // Prepares stack to restart - clears remote candidate list, cancels existing connectivity checks, resets turn + // allocation counter + virtual void clearForRestart(bool localNetworkChanged) = 0; + + // Stops all connectivity & gathering checks. + virtual void stopChecks() = 0; + + // Refreshes local password and ufrag values. Useful when connectivity checks must be restarted. + virtual void refreshPwdUfrag() = 0; + + // Binds channel and return channel prefix + virtual TurnPrefix bindChannel(int stream, int component, const NetworkAddress& target, + ChannelBoundCallback* cb) = 0; + virtual bool isChannelBindingFailed(int stream, int component, TurnPrefix prefix) = 0; + + virtual void installPermissions(int stream, int component, const NetworkAddress& address, + InstallPermissionsCallback* cb) = 0; // Starts freeing of TURN allocations - virtual void freeAllocation(int stream, int component, DeleteAllocationCallback* cb) = 0; - - // Checks if there are active allocations on TURN server - virtual bool hasAllocations() = 0; - - // Checks if any of stream has set error code and return it - virtual int errorCode() = 0; - - // Returns the list of candidates from remote peer - virtual std::vector* remoteCandidates(int stream) = 0; - - // Returns chosen stun server address during last candidate gathering - virtual NetworkAddress activeStunServer(int stream) const = 0; + virtual void freeAllocation(int stream, int component, DeleteAllocationCallback* cb) = 0; - virtual void setup(const ServerConfig& config) = 0; - virtual bool isRelayHost(const NetworkAddress& remote) = 0; - virtual bool isRelayAddress(const NetworkAddress& remote) = 0; + // Checks if there are active allocations on TURN server + virtual bool hasAllocations() = 0; + + // Checks if any of stream has set error code and return it + virtual int errorCode() = 0; + + // Returns the list of candidates from remote peer + virtual std::vector* remoteCandidates(int stream) = 0; + + // Returns chosen stun server address during last candidate gathering + virtual NetworkAddress activeStunServer(int stream) const = 0; + + virtual void setup(const ServerConfig& config) = 0; + virtual bool isRelayHost(const NetworkAddress& remote) = 0; + virtual bool isRelayAddress(const NetworkAddress& remote) = 0; virtual ~Stack(); - }; +}; -} //end of namespace +} // namespace ice #endif diff --git a/src/libs/ice/ICEBoxImpl.cpp b/src/libs/ice/ICEBoxImpl.cpp index 689c1705..eb383a13 100644 --- a/src/libs/ice/ICEBoxImpl.cpp +++ b/src/libs/ice/ICEBoxImpl.cpp @@ -13,434 +13,442 @@ using namespace ice; StackImpl::StackImpl(const ServerConfig& config) -:mConfig(config), mEventHandler(NULL), mEventTag(NULL), mTimeout(false), mActionTimestamp(0) + : mConfig(config), mEventHandler(NULL), mEventTag(NULL), mTimeout(false), mActionTimestamp(0) { - setup(config); + setup(config); } -StackImpl::~StackImpl() -{ -} +StackImpl::~StackImpl() {} void StackImpl::setEventHandler(StageHandler* handler, void* tag) { - mEventHandler = handler; - mEventTag = tag; + mEventHandler = handler; + mEventTag = tag; } int StackImpl::addStream() { - return mSession.addStream(); + return mSession.addStream(); } int StackImpl::addComponent(int streamID, void* tag, unsigned short port4, unsigned short port6) { - return mSession.addComponent(streamID, tag, port4, port6); + return mSession.addComponent(streamID, tag, port4, port6); } void StackImpl::removeStream(int streamID) { - mSession.removeStream(streamID); + mSession.removeStream(streamID); } bool StackImpl::findStreamAndComponent(int family, unsigned short port, int* stream, int* component) { - return mSession.findStreamAndComponent(family, port, stream, component); + return mSession.findStreamAndComponent(family, port, stream, component); } bool StackImpl::hasStream(int streamId) { - return mSession.hasStream(streamId); + return mSession.hasStream(streamId); } bool StackImpl::hasComponent(int streamId, int componentId) { - return mSession.hasComponent(streamId, componentId); + return mSession.hasComponent(streamId, componentId); } void StackImpl::setComponentPort(int streamId, int componentId, unsigned short port4, unsigned short port6) { - mSession.setComponentPort(streamId, componentId, port4, port6); + mSession.setComponentPort(streamId, componentId, port4, port6); } void StackImpl::setRole(AgentRole role) { - mSession.setRole(role); + mSession.setRole(role); } AgentRole StackImpl::role() { - return mSession.role(); + return mSession.role(); } bool StackImpl::processIncomingData(int stream, int component, ByteBuffer& incomingData) { #if defined(ICE_EMULATE_SYMMETRIC_NAT) //&& (TARGET_IPHONE_SIMULATOR) - if (!isRelayHost(incomingData.remoteAddress())) - { - ICELogDebug(<<"Discard packet as symmetric NAT is emulating now"); - return false; - } -#endif - - if (incomingData.remoteAddress().isEmpty()) - { - ICELogDebug(<< "Incoming packet; remote address is unknown"); - incomingData.setRemoteAddress(NetworkAddress::LoopbackAddress4); - } - else - { - ICELogDebug(<< "Incoming packet from " << incomingData.remoteAddress().toStdString()); - } - // Save previous ICE stack state - int icestate = state(); - - incomingData.setComponent(component); - bool result = mSession.processData(incomingData, stream, component); - - // Run handlers - if (result && mEventHandler) - { - int newicestate = state(); - if (icestate < IceCheckSuccess && newicestate >= IceCheckSuccess) + if (!isRelayHost(incomingData.remoteAddress())) { - // Connectivity check finished - if (newicestate == IceCheckSuccess) - mEventHandler->onSuccess(this, mEventTag); - else - mEventHandler->onFailed(this, mEventTag); + ICELogDebug(<< "Discard packet as symmetric NAT is emulating now"); + return false; + } +#endif + + if (incomingData.remoteAddress().isEmpty()) + { + ICELogDebug(<< "Incoming packet; remote address is unknown"); + incomingData.setRemoteAddress(NetworkAddress::LoopbackAddress4); } else - if (icestate < IceGathered && newicestate >= IceGathered) { - // Candidates are gathered - mEventHandler->onGathered(this, mEventTag); + ICELogDebug(<< "Incoming packet from " << incomingData.remoteAddress().toStdString()); } - } + // Save previous ICE stack state + int icestate = state(); - return result; + incomingData.setComponent(component); + bool result = mSession.processData(incomingData, stream, component); + + // Run handlers + if (result && mEventHandler) + { + int newicestate = state(); + if (icestate < IceCheckSuccess && newicestate >= IceCheckSuccess) + { + // Connectivity check finished + if (newicestate == IceCheckSuccess) + mEventHandler->onSuccess(this, mEventTag); + else + mEventHandler->onFailed(this, mEventTag); + } + else if (icestate < IceGathered && newicestate >= IceGathered) + { + // Candidates are gathered + mEventHandler->onGathered(this, mEventTag); + } + } + + return result; } PByteBuffer StackImpl::generateOutgoingData(bool& response, int& stream, int& component, void*& tag) { - // Get current timestamp - unsigned timestamp = ICETimeHelper::timestamp(); + // Get current timestamp + unsigned timestamp = ICETimeHelper::timestamp(); - // Find amount of spent time - unsigned spent = ICETimeHelper::findDelta(mActionTimestamp, timestamp); - - // Check for timeout - if (mConfig.mTimeout && spent > mConfig.mTimeout) - { - ice::RunningState sessionState = mSession.state(); + // Find amount of spent time + unsigned spent = ICETimeHelper::findDelta(mActionTimestamp, timestamp); - bool timeout = sessionState == ice::ConnCheck || sessionState == ice::CandidateGathering; - - if (!mTimeout && timeout) + // Check for timeout + if (mConfig.mTimeout && spent > mConfig.mTimeout) { - // Mark stack as timeouted - mTimeout = true; - ICELogInfo(<< "Timeout detected."); - - if (sessionState == ice::CandidateGathering) - mSession.cancelAllocations(); - - // Find default address amongst host candidates - mSession.chooseDefaults(); + ice::RunningState sessionState = mSession.state(); - if (mEventHandler) - { - if (sessionState == ice::ConnCheck) + bool timeout = sessionState == ice::ConnCheck || sessionState == ice::CandidateGathering; + + if (!mTimeout && timeout) { - // Session should not be cleared here - the CT uses direct path for connectivity checks and relayed if checks are failed. Relayed allocations will not be refreshed in such case - mEventHandler->onFailed(this, this->mEventTag); + // Mark stack as timeouted + mTimeout = true; + ICELogInfo(<< "Timeout detected."); + + if (sessionState == ice::CandidateGathering) + mSession.cancelAllocations(); + + // Find default address amongst host candidates + mSession.chooseDefaults(); + + if (mEventHandler) + { + if (sessionState == ice::ConnCheck) + { + // Session should not be cleared here - the CT uses direct path for connectivity checks and relayed + // if checks are failed. Relayed allocations will not be refreshed in such case + mEventHandler->onFailed(this, this->mEventTag); + } + else + mEventHandler->onGathered(this, this->mEventTag); + } + } + + if (timeout) + { + // Check if keepalive transactions are scheduled + if (!mSession.hasAllocations()) + return PByteBuffer(); } - else - mEventHandler->onGathered(this, this->mEventTag); - } } - if (timeout) - { - // Check if keepalive transactions are scheduled - if (!mSession.hasAllocations()) - return PByteBuffer(); - } - } + // No timeout, proceed... + PByteBuffer result = mSession.getDataToSend(response, stream, component, tag); + if (result) + ICELogInfo(<< "Sending: " << result->comment() << " to " << result->remoteAddress().toStdString() + << ". Data: \r\n" + << result->hexstring()); - // No timeout, proceed... - PByteBuffer result = mSession.getDataToSend(response, stream, component, tag); - if (result) - ICELogInfo(<< "Sending: " << result->comment() << " to " << result->remoteAddress().toStdString() << ". Data: \r\n" << result->hexstring()); - - return result; + return result; } void StackImpl::gatherCandidates() { - mActionTimestamp = ICETimeHelper::timestamp(); - mSession.gatherCandidates(); + mActionTimestamp = ICETimeHelper::timestamp(); + mSession.gatherCandidates(); - // If there is no STUN server set or IP6 only interfaces - the candidate gathering can finish without network I/O - if (mSession.state() == CreatingSDP && mEventHandler) - mEventHandler->onGathered(this, mEventTag); + // If there is no STUN server set or IP6 only interfaces - the candidate gathering can finish without network I/O + if (mSession.state() == CreatingSDP && mEventHandler) + mEventHandler->onGathered(this, mEventTag); } void StackImpl::checkConnectivity() { - // Connectivity check can work if candidate gathering timeout-ed yet - it relies on host candidates only in this case - // So timeout flag is reset - mTimeout = false; - mActionTimestamp = ICETimeHelper::timestamp(); - mSession.checkConnectivity(); + // Connectivity check can work if candidate gathering timeout-ed yet - it relies on host candidates only in this + // case So timeout flag is reset + mTimeout = false; + mActionTimestamp = ICETimeHelper::timestamp(); + mSession.checkConnectivity(); } void StackImpl::stopChecks() { - mTimeout = false; - mActionTimestamp = 0; - mSession.stopChecks(); + mTimeout = false; + mActionTimestamp = 0; + mSession.stopChecks(); } -IceState StackImpl::state() +IceState StackImpl::state() { - if (mTimeout) - return IceTimeout; + if (mTimeout) + return IceTimeout; - switch (mSession.state()) - { - case ice::None: return IceNone; - case ice::CandidateGathering: return IceGathering; - case ice::CreatingSDP: return IceGathered; - case ice::ConnCheck: return IceChecking; - case ice::Failed: return IceFailed; - case ice::Success: return IceCheckSuccess; - default: - break; - } - - assert(0); - return IceNone; // to avoid compiler warning + switch (mSession.state()) + { + case ice::None: + return IceNone; + case ice::CandidateGathering: + return IceGathering; + case ice::CreatingSDP: + return IceGathered; + case ice::ConnCheck: + return IceChecking; + case ice::Failed: + return IceFailed; + case ice::Success: + return IceCheckSuccess; + default: + break; + } + + assert(0); + return IceNone; // to avoid compiler warning } void StackImpl::createSdp(std::vector& commonPart) { - mSession.createSdp(commonPart); + mSession.createSdp(commonPart); } NetworkAddress StackImpl::defaultAddress(int stream, int component) { - return mSession.defaultAddress(stream, component); + return mSession.defaultAddress(stream, component); } void StackImpl::fillCandidateList(int streamID, int componentID, std::vector& candidateList) { - mSession.fillCandidateList(streamID, componentID, candidateList); + mSession.fillCandidateList(streamID, componentID, candidateList); } -bool StackImpl::processSdpOffer(int streamIndex, std::vector& candidateList, - const std::string& defaultIP, unsigned short defaultPort, bool deleteRelayed) +bool StackImpl::processSdpOffer(int streamIndex, std::vector& candidateList, const std::string& defaultIP, + unsigned short defaultPort, bool deleteRelayed) { - return mSession.processSdpOffer(streamIndex, candidateList, defaultIP, defaultPort, deleteRelayed); + return mSession.processSdpOffer(streamIndex, candidateList, defaultIP, defaultPort, deleteRelayed); } NetworkAddress StackImpl::getRemoteRelayedCandidate(int stream, int component) { - return mSession.getRemoteRelayedCandidate(stream, component); + return mSession.getRemoteRelayedCandidate(stream, component); } NetworkAddress StackImpl::getRemoteReflexiveCandidate(int stream, int component) { - return mSession.getRemoteReflexiveCandidate(stream, component); + return mSession.getRemoteReflexiveCandidate(stream, component); } void StackImpl::setRemotePassword(const std::string& pwd, int streamId) { - mSession.setRemotePassword(pwd, streamId); + mSession.setRemotePassword(pwd, streamId); } std::string StackImpl::remotePassword(int streamId) const { - return mSession.remotePassword(streamId); + return mSession.remotePassword(streamId); } void StackImpl::setRemoteUfrag(const std::string& ufrag, int streamId) { - mSession.setRemoteUfrag(ufrag, streamId); + mSession.setRemoteUfrag(ufrag, streamId); } std::string StackImpl::remoteUfrag(int streamId) const { - return mSession.remoteUfrag(streamId); + return mSession.remoteUfrag(streamId); } std::string StackImpl::localPassword() const { - return mSession.mLocalPwd; + return mSession.mLocalPwd; } std::string StackImpl::localUfrag() const { - return mSession.mLocalUfrag; + return mSession.mLocalUfrag; } -bool StackImpl::hasTurnPrefix(unsigned short prefix) +bool StackImpl::hasTurnPrefix(unsigned short prefix) { - return mSession.hasTurnPrefix((TurnPrefix)prefix); + return mSession.hasTurnPrefix((TurnPrefix)prefix); } NetworkAddress StackImpl::remoteAddress(int stream, int component) { - return mSession.remoteAddress(stream, component); + return mSession.remoteAddress(stream, component); } NetworkAddress StackImpl::localAddress(int stream, int component) { - return mSession.localAddress(stream, component); + return mSession.localAddress(stream, component); } bool StackImpl::findConcludePair(int stream, Candidate& local, Candidate& remote) { - // Find nominated pair in stream - return mSession.findConcludePair(stream, local, remote); + // Find nominated pair in stream + return mSession.findConcludePair(stream, local, remote); } bool StackImpl::candidateListContains(int stream, const std::string& remoteIP, unsigned short remotePort) { - return mSession.mStreamMap[stream]->candidateListContains(remoteIP, remotePort); + return mSession.mStreamMap[stream]->candidateListContains(remoteIP, remotePort); } void StackImpl::dump(std::ostream& output) { - mSession.dump(output); + mSession.dump(output); } bool StackImpl::mustRestart() { - return mSession.mustRestart(); + return mSession.mustRestart(); } void StackImpl::clear() { - mSession.clear(); - mActionTimestamp = 0; - mTimeout = false; + mSession.clear(); + mActionTimestamp = 0; + mTimeout = false; } void StackImpl::clearForRestart(bool localNetworkChanged) { - mSession.clearForRestart(localNetworkChanged); - mActionTimestamp = 0; - mTimeout = false; + mSession.clearForRestart(localNetworkChanged); + mActionTimestamp = 0; + mTimeout = false; } void StackImpl::refreshPwdUfrag() { - mSession.refreshPwdUfrag(); + mSession.refreshPwdUfrag(); } -TurnPrefix StackImpl::bindChannel(int stream, int component, const ice::NetworkAddress &target, ChannelBoundCallback* cb) +TurnPrefix StackImpl::bindChannel(int stream, int component, const ice::NetworkAddress& target, + ChannelBoundCallback* cb) { - return mSession.bindChannel(stream, component, target, cb); + return mSession.bindChannel(stream, component, target, cb); } bool StackImpl::isChannelBindingFailed(int stream, int component, TurnPrefix prefix) { - return mSession.isChannelBindingFailed(stream, component, prefix); + return mSession.isChannelBindingFailed(stream, component, prefix); } -void StackImpl::installPermissions(int stream, int component, const NetworkAddress &address, InstallPermissionsCallback* cb) +void StackImpl::installPermissions(int stream, int component, const NetworkAddress& address, + InstallPermissionsCallback* cb) { - mSession.installPermissions(stream, component, address, cb); + mSession.installPermissions(stream, component, address, cb); } void StackImpl::freeAllocation(int stream, int component, DeleteAllocationCallback* cb) { - mSession.freeAllocation(stream, component, cb); + mSession.freeAllocation(stream, component, cb); } bool StackImpl::hasAllocations() { - return mSession.hasAllocations(); + return mSession.hasAllocations(); } int StackImpl::errorCode() { - return mSession.errorCode(); + return mSession.errorCode(); } std::vector* StackImpl::remoteCandidates(int stream) { - return mSession.remoteCandidates(stream); + return mSession.remoteCandidates(stream); } NetworkAddress StackImpl::activeStunServer(int stream) const { - return mSession.activeStunServer(stream); + return mSession.activeStunServer(stream); } void StackImpl::setup(const ServerConfig& config) { - mConfig = config; - mSession.mConfig.mServerList4 = config.mServerList4; - mSession.mConfig.mServerList6 = config.mServerList6; - - // Set initial STUN/TURN server IP for case if there will no gathering candidates & selecting fastest server. - if (mSession.mConfig.mServerList4.size()) - mSession.mConfig.mServerAddr4 = mSession.mConfig.mServerList4.front(); - if (mSession.mConfig.mServerList6.size()) - mSession.mConfig.mServerAddr6 = mSession.mConfig.mServerList6.front(); - mSession.mConfig.mUseIPv4 = config.mUseIPv4; - mSession.mConfig.mUseIPv6 = config.mUseIPv6; + mConfig = config; + mSession.mConfig.mServerList4 = config.mServerList4; + mSession.mConfig.mServerList6 = config.mServerList6; - if (mConfig.mRelay) - { - mSession.mConfig.mTurnPassword = config.mPassword; - mSession.mConfig.mTurnUsername = config.mUsername; + // Set initial STUN/TURN server IP for case if there will no gathering candidates & selecting fastest server. + if (mSession.mConfig.mServerList4.size()) + mSession.mConfig.mServerAddr4 = mSession.mConfig.mServerList4.front(); + if (mSession.mConfig.mServerList6.size()) + mSession.mConfig.mServerAddr6 = mSession.mConfig.mServerList6.front(); + mSession.mConfig.mUseIPv4 = config.mUseIPv4; + mSession.mConfig.mUseIPv6 = config.mUseIPv6; - mSession.mConfig.mUseTURN = true; - mSession.mConfig.mUseSTUN = false; - } - else - { - mSession.mConfig.mUseTURN = false; - mSession.mConfig.mUseSTUN = true; - } - mSession.mConfig.mTimeout = config.mTimeout; + if (mConfig.mRelay) + { + mSession.mConfig.mTurnPassword = config.mPassword; + mSession.mConfig.mTurnUsername = config.mUsername; - mSession.setup(mSession.mConfig); + mSession.mConfig.mUseTURN = true; + mSession.mConfig.mUseSTUN = false; + } + else + { + mSession.mConfig.mUseTURN = false; + mSession.mConfig.mUseSTUN = true; + } + mSession.mConfig.mTimeout = config.mTimeout; + + mSession.setup(mSession.mConfig); } bool StackImpl::isRelayHost(const NetworkAddress& remote) { - for (unsigned i=0; i& commonPart) override; - NetworkAddress defaultAddress(int streamID, int componentID) override; - void fillCandidateList(int streamID, int componentID, std::vector& candidateList) override; + IceState state() override; - bool processSdpOffer(int streamIndex, std::vector& candidateList, - const std::string& defaultIP, unsigned short defaultPort, bool deleteRelayed) override; - NetworkAddress getRemoteRelayedCandidate(int stream, int component) override; - NetworkAddress getRemoteReflexiveCandidate(int stream, int component) override; + void createSdp(std::vector& commonPart) override; + NetworkAddress defaultAddress(int streamID, int componentID) override; + void fillCandidateList(int streamID, int componentID, std::vector& candidateList) override; - void setRemotePassword(const std::string& pwd, int streamId = -1) override; - std::string remotePassword(int streamId = -1) const override; - void setRemoteUfrag(const std::string& ufrag, int streamId = -1) override; - std::string remoteUfrag(int streamId = -1) const override; + bool processSdpOffer(int streamIndex, std::vector& candidateList, const std::string& defaultIP, + unsigned short defaultPort, bool deleteRelayed) override; + NetworkAddress getRemoteRelayedCandidate(int stream, int component) override; + NetworkAddress getRemoteReflexiveCandidate(int stream, int component) override; - std::string localPassword() const override; - std::string localUfrag() const override; - bool hasTurnPrefix(unsigned short prefix) override; - NetworkAddress remoteAddress(int stream, int component) override; - NetworkAddress localAddress(int stream, int component) override; - bool findConcludePair(int stream, Candidate& local, Candidate& remote) override; - bool candidateListContains(int stream, const std::string& remoteIP, unsigned short remotePort) override; - void dump(std::ostream& output) override; - bool mustRestart() override; - void clear() override; - void clearForRestart(bool localNetworkChanged) override; - void refreshPwdUfrag() override; + void setRemotePassword(const std::string& pwd, int streamId = -1) override; + std::string remotePassword(int streamId = -1) const override; + void setRemoteUfrag(const std::string& ufrag, int streamId = -1) override; + std::string remoteUfrag(int streamId = -1) const override; + + std::string localPassword() const override; + std::string localUfrag() const override; + bool hasTurnPrefix(unsigned short prefix) override; + NetworkAddress remoteAddress(int stream, int component) override; + NetworkAddress localAddress(int stream, int component) override; + bool findConcludePair(int stream, Candidate& local, Candidate& remote) override; + bool candidateListContains(int stream, const std::string& remoteIP, unsigned short remotePort) override; + void dump(std::ostream& output) override; + bool mustRestart() override; + void clear() override; + void clearForRestart(bool localNetworkChanged) override; + void refreshPwdUfrag() override; // Channel binding - TurnPrefix bindChannel(int stream, int component, const NetworkAddress& target, ChannelBoundCallback* cb) override; - bool isChannelBindingFailed(int stream, int component, TurnPrefix prefix) override; + TurnPrefix bindChannel(int stream, int component, const NetworkAddress& target, ChannelBoundCallback* cb) override; + bool isChannelBindingFailed(int stream, int component, TurnPrefix prefix) override; // Permissions - void installPermissions(int stream, int component, const NetworkAddress& address, InstallPermissionsCallback* cb) override; + void installPermissions(int stream, int component, const NetworkAddress& address, + InstallPermissionsCallback* cb) override; // Allocations - void freeAllocation(int stream, int component, DeleteAllocationCallback* cb) override; - bool hasAllocations() override; + void freeAllocation(int stream, int component, DeleteAllocationCallback* cb) override; + bool hasAllocations() override; - int errorCode() override; - std::vector* - remoteCandidates(int stream) override; - NetworkAddress activeStunServer(int stream) const override; - void setup(const ServerConfig& config) override; - bool isRelayHost(const NetworkAddress& remote) override; - bool isRelayAddress(const NetworkAddress& remote) override; - }; -} //end of namespace + int errorCode() override; + std::vector* remoteCandidates(int stream) override; + NetworkAddress activeStunServer(int stream) const override; + void setup(const ServerConfig& config) override; + bool isRelayHost(const NetworkAddress& remote) override; + bool isRelayAddress(const NetworkAddress& remote) override; +}; +} // namespace ice #endif diff --git a/src/libs/ice/ICEByteBuffer.cpp b/src/libs/ice/ICEByteBuffer.cpp index 679a54ba..05aee159 100644 --- a/src/libs/ice/ICEByteBuffer.cpp +++ b/src/libs/ice/ICEByteBuffer.cpp @@ -23,16 +23,15 @@ ByteBuffer::ByteBuffer(size_t initialCapacity) } ByteBuffer::ByteBuffer(const ByteBuffer& src) - :mData(src.mData), mComponent(src.mComponent), mTag(nullptr), - mRelayed(src.mRelayed), mCopyBehavior(src.mCopyBehavior), - mDataPtr(src.mDataPtr), mDataSize(src.mDataSize) + : mData(src.mData), mComponent(src.mComponent), mTag(nullptr), mRelayed(src.mRelayed), + mCopyBehavior(src.mCopyBehavior), mDataPtr(src.mDataPtr), mDataSize(src.mDataSize) { if (mCopyBehavior == CopyBehavior::CopyMemory && mData.size()) mDataPtr = &mData[0]; } ByteBuffer::ByteBuffer(const void* packetPtr, size_t packetSize, CopyBehavior behavior) - :mComponent(-1), mTag(nullptr), mRelayed(false), mCopyBehavior(behavior), mDataPtr(nullptr), mDataSize(packetSize) + : mComponent(-1), mTag(nullptr), mRelayed(false), mCopyBehavior(behavior), mDataPtr(nullptr), mDataSize(packetSize) { switch (behavior) { @@ -53,7 +52,8 @@ ByteBuffer::ByteBuffer(const void* packetPtr, size_t packetSize, CopyBehavior be ByteBuffer::ByteBuffer(const std::span& packet, CopyBehavior behavior) : ByteBuffer(packet.data(), packet.size(), behavior) -{} +{ +} ByteBuffer::~ByteBuffer() { @@ -61,7 +61,7 @@ ByteBuffer::~ByteBuffer() memset(mDataPtr, 0, mDataSize); } -ByteBuffer& ByteBuffer::operator = (const ByteBuffer& src) +ByteBuffer& ByteBuffer::operator=(const ByteBuffer& src) { mRelayed = src.mRelayed; mComment = src.mComment; @@ -92,7 +92,7 @@ void ByteBuffer::clear() mDataPtr = nullptr; } -size_t ByteBuffer::size() const +size_t ByteBuffer::size() const { return mDataSize; } @@ -145,8 +145,8 @@ std::string ByteBuffer::toHex(const void* bytes, size_t len) { char value[3]; sprintf(value, "%02X", (unsigned char)((const unsigned char*)bytes)[index]); - result[index*2] = value[0]; - result[index*2+1] = value[1]; + result[index * 2] = value[0]; + result[index * 2 + 1] = value[1]; } return result; } @@ -168,7 +168,7 @@ void ByteBuffer::insertTurnPrefix(unsigned short prefix) syncPointer(); } -int ByteBuffer::component() +int ByteBuffer::component() { return mComponent; } @@ -180,7 +180,7 @@ void ByteBuffer::setComponent(int component) void ByteBuffer::truncate(size_t newsize) { - assert (mCopyBehavior == CopyBehavior::CopyMemory); + assert(mCopyBehavior == CopyBehavior::CopyMemory); mData.erase(mData.begin() + newsize, mData.end()); syncPointer(); @@ -188,7 +188,7 @@ void ByteBuffer::truncate(size_t newsize) void ByteBuffer::erase(size_t p, size_t l) { - assert (mCopyBehavior == CopyBehavior::CopyMemory); + assert(mCopyBehavior == CopyBehavior::CopyMemory); mData.erase(mData.begin() + p, mData.begin() + p + l); syncPointer(); @@ -196,7 +196,7 @@ void ByteBuffer::erase(size_t p, size_t l) void ByteBuffer::resize(size_t newsize) { - assert (mCopyBehavior == CopyBehavior::CopyMemory); + assert(mCopyBehavior == CopyBehavior::CopyMemory); std::vector::size_type sz = mData.size(); mData.resize(newsize); @@ -206,9 +206,9 @@ void ByteBuffer::resize(size_t newsize) syncPointer(); } -void ByteBuffer::appendBuffer(const void *data, size_t size) +void ByteBuffer::appendBuffer(const void* data, size_t size) { - assert (mCopyBehavior == CopyBehavior::CopyMemory); + assert(mCopyBehavior == CopyBehavior::CopyMemory); size_t len = mData.size(); mData.resize(len + size); @@ -221,7 +221,7 @@ void* ByteBuffer::tag() return mTag; } -void ByteBuffer::setTag(void* tag) +void ByteBuffer::setTag(void* tag) { mTag = tag; } @@ -263,14 +263,14 @@ uint8_t& ByteBuffer::operator[](int index) } // ----------------- BitReader ------------------- -BitReader::BitReader(const ByteBuffer &buffer) - :mStream(buffer.data()), mStreamLen(buffer.size()), mStreamOffset(0), mCurrentBit(0) +BitReader::BitReader(const ByteBuffer& buffer) + : mStream(buffer.data()), mStreamLen(buffer.size()), mStreamOffset(0), mCurrentBit(0) { init(); } -BitReader::BitReader(const void *input, size_t bytes) - :mStream(reinterpret_cast(input)), mStreamLen(bytes), mStreamOffset(0), mCurrentBit(0) +BitReader::BitReader(const void* input, size_t bytes) + : mStream(reinterpret_cast(input)), mStreamLen(bytes), mStreamOffset(0), mCurrentBit(0) { init(); } @@ -278,7 +278,7 @@ BitReader::BitReader(const void *input, size_t bytes) void BitReader::init() { mStreamOffset = mStreamLen << 3; - mCurrentPosition = 0;//mStreamOffset - 1; + mCurrentPosition = 0; // mStreamOffset - 1; mCurrentBit = 0; } @@ -289,10 +289,10 @@ uint8_t BitReader::readBit() if (mCurrentPosition < mStreamOffset) { // Read single BIT - size_t currentByte = mCurrentPosition >> 3; + size_t currentByte = mCurrentPosition >> 3; uint8_t currentBit = (uint8_t)(mCurrentPosition % 8); value = ((uint8_t)(mStream[currentByte] << currentBit) >> 7); - mCurrentPosition = std::max((size_t)0, std::min(mStreamOffset-1, mCurrentPosition+1)); + mCurrentPosition = std::max((size_t)0, std::min(mStreamOffset - 1, mCurrentPosition + 1)); } return value; @@ -300,23 +300,23 @@ uint8_t BitReader::readBit() uint32_t BitReader::readBits(size_t nrOfBits) { - assert (nrOfBits <= 32); + assert(nrOfBits <= 32); - uint32_t result = 0; + uint32_t result = 0; BitWriter bw(&result); - for (int i=0; i(nrOfBits); i++) + for (int i = 0; i < static_cast(nrOfBits); i++) bw.writeBit(readBit()); return result; } -size_t BitReader::readBits(void *output, size_t nrOfBits) +size_t BitReader::readBits(void* output, size_t nrOfBits) { // Check how much bits available nrOfBits = std::min(nrOfBits, mStreamOffset - mCurrentPosition); BitWriter bw(output); - for (int i=0; i(nrOfBits); i++) + for (int i = 0; i < static_cast(nrOfBits); i++) bw.writeBit(readBit()); return nrOfBits; @@ -333,14 +333,13 @@ size_t BitReader::position() const } // ----------------- BitWriter ------------------- -BitWriter::BitWriter(ByteBuffer &buffer) - :mStream(buffer.mutableData()), mStreamLen(0), mStreamOffset(0), mCurrentBit(0) +BitWriter::BitWriter(ByteBuffer& buffer) + : mStream(buffer.mutableData()), mStreamLen(0), mStreamOffset(0), mCurrentBit(0) { init(); } -BitWriter::BitWriter(void *output) - :mStream((uint8_t*)output), mStreamLen(0), mStreamOffset(0), mCurrentBit(0) +BitWriter::BitWriter(void* output) : mStream((uint8_t*)output), mStreamLen(0), mStreamOffset(0), mCurrentBit(0) { init(); } @@ -348,7 +347,7 @@ BitWriter::BitWriter(void *output) void BitWriter::init() { mStreamOffset = mStreamLen << 3; - mCurrentPosition = 0;//mStreamOffset - 1; + mCurrentPosition = 0; // mStreamOffset - 1; mCurrentBit = 0; } @@ -362,12 +361,12 @@ BitWriter& BitWriter::writeBit(int bit) // Write new zero byte to the end of stream mCurrentBit = 0; mStreamLen++; - mStream[mStreamLen-1] = 0; + mStream[mStreamLen - 1] = 0; } // Write single BIT - mStream[mStreamLen-1] <<= 1; - mStream[mStreamLen-1] |= bit; + mStream[mStreamLen - 1] <<= 1; + mStream[mStreamLen - 1] |= bit; mStreamOffset++; mCurrentPosition = mStreamOffset - 1; mCurrentBit++; @@ -381,13 +380,12 @@ size_t BitWriter::count() const } // ----------------- BufferReader ---------------- -BufferReader::BufferReader(const ByteBuffer &buffer) - :mData(buffer.data()), mSize(buffer.size()), mIndex(0) -{} +BufferReader::BufferReader(const ByteBuffer& buffer) : mData(buffer.data()), mSize(buffer.size()), mIndex(0) {} -BufferReader::BufferReader(const void *input, size_t bytes) - :mData(reinterpret_cast(input)), mSize(bytes), mIndex(0) -{} +BufferReader::BufferReader(const void* input, size_t bytes) + : mData(reinterpret_cast(input)), mSize(bytes), mIndex(0) +{ +} uint32_t BufferReader::readUInt() @@ -442,17 +440,16 @@ NetworkAddress BufferReader::readIp(int family) return NetworkAddress(reinterpret_cast(addr), sizeof(addr)); } - else - if (family == AF_INET6) - { - sockaddr_in6 addr; - memset(&addr, 0, sizeof(addr)); - addr.sin6_family = AF_INET6; - addr.sin6_port = 0; - readBuffer(&addr.sin6_addr, 16); + else if (family == AF_INET6) + { + sockaddr_in6 addr; + memset(&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + addr.sin6_port = 0; + readBuffer(&addr.sin6_addr, 16); - return NetworkAddress(reinterpret_cast(addr), sizeof(addr)); - } + return NetworkAddress(reinterpret_cast(addr), sizeof(addr)); + } return NetworkAddress(); } @@ -497,13 +494,15 @@ size_t BufferReader::count() const } // -------------- BufferWriter ---------------------- -BufferWriter::BufferWriter(ByteBuffer &buffer, size_t startOffset) - :mBuffer(&buffer), mData(buffer.mutableData() + startOffset), mBase(startOffset), mIndex(0), mCapacity(0) -{} +BufferWriter::BufferWriter(ByteBuffer& buffer, size_t startOffset) + : mBuffer(&buffer), mData(buffer.mutableData() + startOffset), mBase(startOffset), mIndex(0), mCapacity(0) +{ +} -BufferWriter::BufferWriter(void *output, size_t capacity) - :mBuffer(nullptr), mData(reinterpret_cast(output)), mBase(0), mIndex(0), mCapacity(capacity) -{} +BufferWriter::BufferWriter(void* output, size_t capacity) + : mBuffer(nullptr), mData(reinterpret_cast(output)), mBase(0), mIndex(0), mCapacity(capacity) +{ +} void BufferWriter::writeUInt(uint32_t value) @@ -530,11 +529,11 @@ void BufferWriter::writeIp(const NetworkAddress& ip) { switch (ip.stunType()) { - case 1/*IPv4*/: + case 1 /*IPv4*/: writeBuffer(&ip.sockaddr4()->sin_addr, 4); break; - case 2/*IPv6*/: + case 2 /*IPv6*/: writeBuffer(&ip.sockaddr6()->sin6_addr, 16); break; diff --git a/src/libs/ice/ICEByteBuffer.h b/src/libs/ice/ICEByteBuffer.h index 90801cad..7814aa3c 100644 --- a/src/libs/ice/ICEByteBuffer.h +++ b/src/libs/ice/ICEByteBuffer.h @@ -16,15 +16,15 @@ #include "ICETypes.h" #include "ICEAddress.h" -namespace ice +namespace ice { - class ByteBuffer - { - public: +class ByteBuffer +{ +public: enum class CopyBehavior { - CopyMemory, - UseExternal + CopyMemory, + UseExternal }; ByteBuffer(); @@ -34,165 +34,166 @@ namespace ice ByteBuffer(const std::span& packet, CopyBehavior behavior = CopyBehavior::CopyMemory); ~ByteBuffer(); - - ByteBuffer& operator = (const ByteBuffer& src); - - void clear(); - size_t size() const; - const uint8_t* data() const; - uint8_t* mutableData(); + ByteBuffer& operator=(const ByteBuffer& src); + + void clear(); + + size_t size() const; + const uint8_t* data() const; + uint8_t* mutableData(); std::span span(); - NetworkAddress& remoteAddress(); - void setRemoteAddress(const NetworkAddress& addr); - int component(); - void setComponent(int component); - void setComment(std::string comment); - std::string comment(); - std::string hexstring(); + NetworkAddress& remoteAddress(); + void setRemoteAddress(const NetworkAddress& addr); + int component(); + void setComponent(int component); + void setComment(std::string comment); + std::string comment(); + std::string hexstring(); - static std::string toHex(const void* bytes, size_t len); + static std::string toHex(const void* bytes, size_t len); - void reserve(size_t capacity); - void insertTurnPrefix(unsigned short prefix); - void truncate(size_t newsize); - void erase(size_t p, size_t l); - void resize(size_t newsize); - void appendBuffer(const void* data, size_t size); - void* tag(); - void setTag(void* tag); - void trim(); - bool relayed(); - void setRelayed(bool value); - void syncPointer(); + void reserve(size_t capacity); + void insertTurnPrefix(unsigned short prefix); + void truncate(size_t newsize); + void erase(size_t p, size_t l); + void resize(size_t newsize); + void appendBuffer(const void* data, size_t size); + void* tag(); + void setTag(void* tag); + void trim(); + bool relayed(); + void setRelayed(bool value); + void syncPointer(); - uint8_t operator[](int index) const; - uint8_t& operator[](int index); + uint8_t operator[](int index) const; + uint8_t& operator[](int index); - protected: - std::vector mData; // Internal storage - uint8_t* mDataPtr; // Pointer to internal storage or external data - size_t mDataSize; // Used only for mCopyBehavior == UseExternal - NetworkAddress mRemoteAddress; // Associates buffer with IP address - int mComponent; // Associates buffer with component ID - std::string mComment; // Comment's for this buffer - useful in debugging - void* mTag; // User tag - bool mRelayed; // Marks if buffer was received via relay - CopyBehavior mCopyBehavior; // Determines if buffer manages internal or external data +protected: + std::vector mData; // Internal storage + uint8_t* mDataPtr; // Pointer to internal storage or external data + size_t mDataSize; // Used only for mCopyBehavior == UseExternal + NetworkAddress mRemoteAddress; // Associates buffer with IP address + int mComponent; // Associates buffer with component ID + std::string mComment; // Comment's for this buffer - useful in debugging + void* mTag; // User tag + bool mRelayed; // Marks if buffer was received via relay + CopyBehavior mCopyBehavior; // Determines if buffer manages internal or external data - void initEmpty(); - int bitsInBuffer(uint8_t bufferMask); - }; + void initEmpty(); + int bitsInBuffer(uint8_t bufferMask); +}; - typedef std::shared_ptr PByteBuffer; +typedef std::shared_ptr PByteBuffer; - class BitReader - { - protected: +class BitReader +{ +protected: const uint8_t* mStream; - size_t mStreamLen; - size_t mStreamOffset; - size_t mCurrentPosition; - size_t mCurrentBit; + size_t mStreamLen; + size_t mStreamOffset; + size_t mCurrentPosition; + size_t mCurrentBit; - void init(); + void init(); - public: +public: BitReader(const void* input, size_t bytes); BitReader(const ByteBuffer& buffer); ~BitReader() = default; - uint8_t readBit(); + uint8_t readBit(); uint32_t readBits(size_t nrOfBits); - size_t readBits(void* output, size_t nrOfBits); + size_t readBits(void* output, size_t nrOfBits); - size_t count() const; - size_t position() const; - }; + size_t count() const; + size_t position() const; +}; - class BitWriter - { - protected: +class BitWriter +{ +protected: uint8_t* mStream; - size_t mStreamLen; - size_t mStreamOffset; - size_t mCurrentPosition; - size_t mCurrentBit; + size_t mStreamLen; + size_t mStreamOffset; + size_t mCurrentPosition; + size_t mCurrentBit; - void init(); - public: + void init(); + +public: BitWriter(void* output); BitWriter(ByteBuffer& buffer); ~BitWriter() = default; // Bit must be 0 or 1 BitWriter& writeBit(int bit); - size_t count() const; - }; + size_t count() const; +}; - class BufferReader - { - protected: +class BufferReader +{ +protected: const uint8_t* mData; - size_t mSize; - size_t mIndex; + size_t mSize; + size_t mIndex; - public: +public: BufferReader(const void* input, size_t bytes); BufferReader(const ByteBuffer& buffer); // This methods reads uint32_t from stream and converts network byte order to host byte order. - uint32_t readUInt(); + uint32_t readUInt(); // This method reads uint32_t from stream. No conversion between byte orders. - uint32_t readNativeUInt(); + uint32_t readNativeUInt(); // This method reads uint16_t from stream and converts network byte order to host byte order. - uint16_t readUShort(); + uint16_t readUShort(); // This method reads uint16_t. No conversion between byte orders. - uint16_t readNativeUShort(); - uint8_t readUChar(); + uint16_t readNativeUShort(); + uint8_t readUChar(); // Reads in_addr or in6_addr from stream and wraps it to NetworkAddress - NetworkAddress readIp(int family); + NetworkAddress readIp(int family); // Reads to plain memory buffer - size_t readBuffer(void* dataPtr, size_t dataSize); + size_t readBuffer(void* dataPtr, size_t dataSize); // Read directly to byte buffer. New data will be appended to byte buffer - size_t readBuffer(ByteBuffer& bb, size_t dataSize); + size_t readBuffer(ByteBuffer& bb, size_t dataSize); - size_t count() const; - }; + size_t count() const; +}; - class BufferWriter - { - protected: - ByteBuffer* mBuffer; // Non-null => growable: writes resize this buffer to fit - uint8_t* mData; // Cached write pointer (refreshed on growth in growable mode) - size_t mBase; // Start offset within mBuffer (growable mode) - size_t mIndex; // Bytes written since mBase - size_t mCapacity; // Usable capacity from mData (raw/bounded mode) +class BufferWriter +{ +protected: + ByteBuffer* mBuffer; // Non-null => growable: writes resize this buffer to fit + uint8_t* mData; // Cached write pointer (refreshed on growth in growable mode) + size_t mBase; // Start offset within mBuffer (growable mode) + size_t mIndex; // Bytes written since mBase + size_t mCapacity; // Usable capacity from mData (raw/bounded mode) - public: +public: // Bounded writer over caller-owned memory. Writes past 'capacity' are refused. BufferWriter(void* output, size_t capacity); // Growable writer: the backing buffer is resized as needed so writes never overflow. BufferWriter(ByteBuffer& buffer, size_t startOffset = 0); - void writeUInt(uint32_t value); - void writeUShort(uint16_t value); - void writeUChar(uint8_t value); - void writeIp(const NetworkAddress& ip); - void writeBuffer(const void* dataPtr, size_t dataSize); - void rewind(); - void skip(int count); + void writeUInt(uint32_t value); + void writeUShort(uint16_t value); + void writeUChar(uint8_t value); + void writeIp(const NetworkAddress& ip); + void writeBuffer(const void* dataPtr, size_t dataSize); + void rewind(); + void skip(int count); size_t offset() const; - }; -} +}; +} // namespace ice #endif diff --git a/src/libs/ice/ICECRC32.cpp b/src/libs/ice/ICECRC32.cpp index 0524554a..6946379e 100644 --- a/src/libs/ice/ICECRC32.cpp +++ b/src/libs/ice/ICECRC32.cpp @@ -27,20 +27,20 @@ CRC32::CRC32(void) void CRC32::initialize(void) { - //0x04C11DB7 is the official polynomial used by PKZip, WinZip and Ethernet. + // 0x04C11DB7 is the official polynomial used by PKZip, WinZip and Ethernet. unsigned long ulPolynomial = 0x04C11DB7; - //memset(&this->ulTable, 0, sizeof(this->ulTable)); + // memset(&this->ulTable, 0, sizeof(this->ulTable)); // 256 values representing ASCII character codes. - for(int iCodes = 0; iCodes <= 0xFF; iCodes++) + for (int iCodes = 0; iCodes <= 0xFF; iCodes++) { this->ulTable[iCodes] = this->reflect(iCodes, 8) << 24; - for(int iPos = 0; iPos < 8; iPos++) + for (int iPos = 0; iPos < 8; iPos++) { - this->ulTable[iCodes] = (this->ulTable[iCodes] << 1) - ^ ((this->ulTable[iCodes] & (1 << 31)) ? ulPolynomial : 0); + this->ulTable[iCodes] = + (this->ulTable[iCodes] << 1) ^ ((this->ulTable[iCodes] & (1 << 31)) ? ulPolynomial : 0); } this->ulTable[iCodes] = this->reflect(this->ulTable[iCodes], 32); @@ -58,9 +58,9 @@ unsigned long CRC32::reflect(unsigned long ulReflect, const char cChar) unsigned long ulValue = 0; // Swap bit 0 for bit 7, bit 1 For bit 6, etc.... - for(int iPos = 1; iPos < (cChar + 1); iPos++) + for (int iPos = 1; iPos < (cChar + 1); iPos++) { - if(ulReflect & 1) + if (ulReflect & 1) { ulValue |= (1 << (cChar - iPos)); } @@ -77,15 +77,15 @@ unsigned long CRC32::reflect(unsigned long ulReflect, const char cChar) Note: For Example usage example, see FileCRC(). */ -void CRC32::partialCrc(unsigned long *ulCRC, const unsigned char *sData, unsigned long ulDataLength) +void CRC32::partialCrc(unsigned long* ulCRC, const unsigned char* sData, unsigned long ulDataLength) { - while(ulDataLength--) + while (ulDataLength--) { - //If your compiler complains about the following line, try changing each - // occurrence of *ulCRC with "((unsigned long)*ulCRC)" or "*(unsigned long *)ulCRC". + // If your compiler complains about the following line, try changing each + // occurrence of *ulCRC with "((unsigned long)*ulCRC)" or "*(unsigned long *)ulCRC". - *(unsigned long *)ulCRC = - ((*(unsigned long *)ulCRC) >> 8) ^ this->ulTable[((*(unsigned long *)ulCRC) & 0xFF) ^ *sData++]; + *(unsigned long*)ulCRC = + ((*(unsigned long*)ulCRC) >> 8) ^ this->ulTable[((*(unsigned long*)ulCRC) & 0xFF) ^ *sData++]; } } @@ -94,11 +94,11 @@ void CRC32::partialCrc(unsigned long *ulCRC, const unsigned char *sData, unsigne Returns the calculated CRC32 (through ulOutCRC) for the given string. */ -void CRC32::fullCrc(const unsigned char *sData, unsigned long ulDataLength, unsigned long *ulOutCRC) +void CRC32::fullCrc(const unsigned char* sData, unsigned long ulDataLength, unsigned long* ulOutCRC) { - *(unsigned long *)ulOutCRC = 0xffffffff; //Initilaize the CRC. + *(unsigned long*)ulOutCRC = 0xffffffff; // Initilaize the CRC. this->partialCrc(ulOutCRC, sData, ulDataLength); - *(unsigned long *)ulOutCRC ^= 0xffffffff; //Finalize the CRC. + *(unsigned long*)ulOutCRC ^= 0xffffffff; // Finalize the CRC. } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -106,11 +106,11 @@ void CRC32::fullCrc(const unsigned char *sData, unsigned long ulDataLength, unsi Returns the calculated CRC23 for the given string. */ -unsigned long CRC32::fullCrc(const unsigned char *sData, unsigned long ulDataLength) +unsigned long CRC32::fullCrc(const unsigned char* sData, unsigned long ulDataLength) { - unsigned long ulCRC = 0xffffffff; //Initilaize the CRC. + unsigned long ulCRC = 0xffffffff; // Initilaize the CRC. this->partialCrc(&ulCRC, sData, ulDataLength); - return(ulCRC ^ 0xffffffff); //Finalize the CRC and return. + return (ulCRC ^ 0xffffffff); // Finalize the CRC and return. } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -121,26 +121,26 @@ unsigned long CRC32::fullCrc(const unsigned char *sData, unsigned long ulDataLen it has been provided for performance purposes only. */ -bool CRC32::fileCrc(const char *sFileName, unsigned long *ulOutCRC, unsigned long ulBufferSize) +bool CRC32::fileCrc(const char* sFileName, unsigned long* ulOutCRC, unsigned long ulBufferSize) { - *(unsigned long *)ulOutCRC = 0xffffffff; //Initilaize the CRC. + *(unsigned long*)ulOutCRC = 0xffffffff; // Initilaize the CRC. - FILE *fSource = NULL; - unsigned char *sBuf = NULL; - int iBytesRead = 0; + FILE* fSource = NULL; + unsigned char* sBuf = NULL; + int iBytesRead = 0; - if((fSource = fopen(sFileName, "rb")) == NULL) + if ((fSource = fopen(sFileName, "rb")) == NULL) { - return false; //Failed to open file for read access. + return false; // Failed to open file for read access. } - if(!(sBuf = (unsigned char *)malloc(ulBufferSize))) //Allocate memory for file buffering. + if (!(sBuf = (unsigned char*)malloc(ulBufferSize))) // Allocate memory for file buffering. { fclose(fSource); - return false; //Out of memory. + return false; // Out of memory. } - while((iBytesRead = fread(sBuf, sizeof(char), ulBufferSize, fSource))) + while ((iBytesRead = fread(sBuf, sizeof(char), ulBufferSize, fSource))) { this->partialCrc(ulOutCRC, sBuf, iBytesRead); } @@ -148,7 +148,7 @@ bool CRC32::fileCrc(const char *sFileName, unsigned long *ulOutCRC, unsigned lon free(sBuf); fclose(fSource); - *(unsigned long *)ulOutCRC ^= 0xffffffff; //Finalize the CRC. + *(unsigned long*)ulOutCRC ^= 0xffffffff; // Finalize the CRC. return true; } @@ -161,7 +161,7 @@ bool CRC32::fileCrc(const char *sFileName, unsigned long *ulOutCRC, unsigned lon it has been provided for performance purposes only. */ -bool CRC32::fileCrc(const char *sFileName, unsigned long *ulOutCRC) +bool CRC32::fileCrc(const char* sFileName, unsigned long* ulOutCRC) { return this->fileCrc(sFileName, ulOutCRC, 1048576); } diff --git a/src/libs/ice/ICECRC32.h b/src/libs/ice/ICECRC32.h index 3d2b91d6..4bb21ee9 100644 --- a/src/libs/ice/ICECRC32.h +++ b/src/libs/ice/ICECRC32.h @@ -7,26 +7,26 @@ #define __ICE_CRC32_H namespace ice { - class CRC32 - { - public: - CRC32(void); - ~CRC32(void) = default; +class CRC32 +{ +public: + CRC32(void); + ~CRC32(void) = default; - void initialize(void); + void initialize(void); - bool fileCrc(const char *sFileName, unsigned long *ulOutCRC); - bool fileCrc(const char *sFileName, unsigned long *ulOutCRC, unsigned long ulBufferSize); + bool fileCrc(const char* sFileName, unsigned long* ulOutCRC); + bool fileCrc(const char* sFileName, unsigned long* ulOutCRC, unsigned long ulBufferSize); - unsigned long fullCrc(const unsigned char *sData, unsigned long ulDataLength); - void fullCrc(const unsigned char *sData, unsigned long ulLength, unsigned long *ulOutCRC); + unsigned long fullCrc(const unsigned char* sData, unsigned long ulDataLength); + void fullCrc(const unsigned char* sData, unsigned long ulLength, unsigned long* ulOutCRC); - void partialCrc(unsigned long *ulCRC, const unsigned char *sData, unsigned long ulDataLength); + void partialCrc(unsigned long* ulCRC, const unsigned char* sData, unsigned long ulDataLength); - private: - unsigned long reflect(unsigned long ulReflect, const char cChar); - unsigned long ulTable[256]; // CRC lookup table array. - }; -} +private: + unsigned long reflect(unsigned long ulReflect, const char cChar); + unsigned long ulTable[256]; // CRC lookup table array. +}; +} // namespace ice #endif diff --git a/src/libs/ice/ICECandidate.cpp b/src/libs/ice/ICECandidate.cpp index 272ba453..3988fbf8 100644 --- a/src/libs/ice/ICECandidate.cpp +++ b/src/libs/ice/ICECandidate.cpp @@ -15,174 +15,173 @@ using namespace ice; void Candidate::setLocalAndExternalAddresses(std::string& ip, unsigned short portNumber) { - mLocalAddr.setIp(ip); - mLocalAddr.setPort(portNumber); - mExternalAddr.setIp(ip); - mExternalAddr.setPort(portNumber); + mLocalAddr.setIp(ip); + mLocalAddr.setPort(portNumber); + mExternalAddr.setIp(ip); + mExternalAddr.setPort(portNumber); } void Candidate::setLocalAndExternalAddresses(NetworkAddress& addr) { - mLocalAddr = addr; - mExternalAddr = addr; + mLocalAddr = addr; + mExternalAddr = addr; } -void Candidate::setLocalAndExternalAddresses(NetworkAddress &addr, unsigned short altPort) +void Candidate::setLocalAndExternalAddresses(NetworkAddress& addr, unsigned short altPort) { - mLocalAddr = addr; - mExternalAddr = addr; - mLocalAddr.setPort(altPort); - mExternalAddr.setPort(altPort); + mLocalAddr = addr; + mExternalAddr = addr; + mLocalAddr.setPort(altPort); + mExternalAddr.setPort(altPort); } void Candidate::computePriority(int* typepreflist) { - mPriority = (typepreflist[mType] << 24) + (mInterfacePriority << 8) + (256 - mComponentId); + mPriority = (typepreflist[mType] << 24) + (mInterfacePriority << 8) + (256 - mComponentId); } void Candidate::computeFoundation() { - sprintf(mFoundation, "%u", unsigned((mType << 24) + inet_addr(mLocalAddr.ip().c_str()))); + sprintf(mFoundation, "%u", unsigned((mType << 24) + inet_addr(mLocalAddr.ip().c_str()))); } const char* Candidate::type() { - switch (mType) - { - case Candidate::Host: - return "host"; + switch (mType) + { + case Candidate::Host: + return "host"; - case Candidate::ServerReflexive: - return "srflx"; + case Candidate::ServerReflexive: + return "srflx"; - case Candidate::ServerRelayed: - return "relay"; + case Candidate::ServerRelayed: + return "relay"; - case Candidate::PeerReflexive: - return "prflx"; + case Candidate::PeerReflexive: + return "prflx"; - default: - ICELogError(<< "Bad candidate type, reverted to Host."); - return "host"; - } + default: + ICELogError(<< "Bad candidate type, reverted to Host."); + return "host"; + } } std::string Candidate::createSdp() { - char buffer[512]; - - unsigned port = (unsigned)mExternalAddr.port(); + char buffer[512]; + + unsigned port = (unsigned)mExternalAddr.port(); #define SDP_CANDIDATE_FORMAT "%s %u %s %u %s %u typ %s" - sprintf(buffer, SDP_CANDIDATE_FORMAT, strlen(mFoundation) ? mFoundation : "16777000" , mComponentId, "UDP", mPriority, mExternalAddr.ip().c_str(), port, type()); - - if (mType != Candidate::Host) - { - char relattr[64]; - sprintf(relattr, " raddr %s rport %u", mLocalAddr.ip().c_str(), (unsigned int)mLocalAddr.port()); - strcat(buffer, relattr); - } - - return buffer; + sprintf(buffer, SDP_CANDIDATE_FORMAT, strlen(mFoundation) ? mFoundation : "16777000", mComponentId, "UDP", + mPriority, mExternalAddr.ip().c_str(), port, type()); + + if (mType != Candidate::Host) + { + char relattr[64]; + sprintf(relattr, " raddr %s rport %u", mLocalAddr.ip().c_str(), (unsigned int)mLocalAddr.port()); + strcat(buffer, relattr); + } + + return buffer; } Candidate Candidate::parseSdp(const char* sdp) { - Candidate result(Candidate::Host); + Candidate result(Candidate::Host); - char protocol[32], externalIP[128], candtype[32], raddr[64]; - unsigned int remoteport = 0; - - unsigned int externalPort = 0; - - // Look for "typ" string - const char* formatstring; - if (strstr(sdp, "typ")) - formatstring = "%s %u %s %u %s %u typ %s raddr %s rport %u"; - else - formatstring = "%s %u %s %u %s %u %s raddr %s rport %u"; - int wasread = sscanf(sdp, formatstring, &result.mFoundation, &result.mComponentId, protocol, - &result.mPriority, externalIP, &externalPort, candtype, raddr, &remoteport); + char protocol[32], externalIP[128], candtype[32], raddr[64]; + unsigned int remoteport = 0; - if (wasread >= 7) - { - // Save external address - result.mExternalAddr.setIp( externalIP ); - result.mExternalAddr.setPort( externalPort ); - - result.mLocalAddr = result.mExternalAddr; + unsigned int externalPort = 0; - // Check the protocol (UDP4/6 is supported only) + // Look for "typ" string + const char* formatstring; + if (strstr(sdp, "typ")) + formatstring = "%s %u %s %u %s %u typ %s raddr %s rport %u"; + else + formatstring = "%s %u %s %u %s %u %s raddr %s rport %u"; + int wasread = sscanf(sdp, formatstring, &result.mFoundation, &result.mComponentId, protocol, &result.mPriority, + externalIP, &externalPort, candtype, raddr, &remoteport); + + if (wasread >= 7) + { + // Save external address + result.mExternalAddr.setIp(externalIP); + result.mExternalAddr.setPort(externalPort); + + result.mLocalAddr = result.mExternalAddr; + + // Check the protocol (UDP4/6 is supported only) #ifdef _WIN32 - _strupr(protocol); _strupr(candtype); + _strupr(protocol); + _strupr(candtype); #else - strupr(protocol); strupr(candtype); + strupr(protocol); + strupr(candtype); #endif - if (strcmp(protocol, "UDP") != 0) - throw Exception(UDP_SUPPORTED_ONLY); + if (strcmp(protocol, "UDP") != 0) + throw Exception(UDP_SUPPORTED_ONLY); - // Save candidate type - result.mType = typeFromString(candtype); - } + // Save candidate type + result.mType = typeFromString(candtype); + } - return result; + return result; } -Candidate::Type Candidate::typeFromString(const char* candtype) +Candidate::Type Candidate::typeFromString(const char* candtype) { - if (!strcmp(candtype, "HOST")) - return Candidate::Host; - else - if (!strcmp(candtype, "SRFLX")) - return Candidate::ServerReflexive; - else - if (!strcmp(candtype, "PRFLX")) - return Candidate::PeerReflexive; - else - if (!strcmp(candtype, "RELAY")) - return Candidate::ServerRelayed; - else - { - ICELogError(<< "Bad candidate type in parser. Reverted to Host"); - return Candidate::Host; - } + if (!strcmp(candtype, "HOST")) + return Candidate::Host; + else if (!strcmp(candtype, "SRFLX")) + return Candidate::ServerReflexive; + else if (!strcmp(candtype, "PRFLX")) + return Candidate::PeerReflexive; + else if (!strcmp(candtype, "RELAY")) + return Candidate::ServerRelayed; + else + { + ICELogError(<< "Bad candidate type in parser. Reverted to Host"); + return Candidate::Host; + } } bool Candidate::equal(Candidate& cand1, Candidate& cand2) { - if (cand1.mType != cand2.mType) - return false; - switch (cand1.mType) - { - case Candidate::Host: - return (cand1.mLocalAddr == cand2.mLocalAddr); + if (cand1.mType != cand2.mType) + return false; + switch (cand1.mType) + { + case Candidate::Host: + return (cand1.mLocalAddr == cand2.mLocalAddr); - case Candidate::ServerReflexive: - case Candidate::PeerReflexive: - case Candidate::ServerRelayed: - return (cand1.mExternalAddr == cand2.mExternalAddr); - - } - - ICELogError(<< "Bad candidate type, comparing as Host"); - return cand1.mLocalAddr == cand2.mLocalAddr; + case Candidate::ServerReflexive: + case Candidate::PeerReflexive: + case Candidate::ServerRelayed: + return (cand1.mExternalAddr == cand2.mExternalAddr); + } + + ICELogError(<< "Bad candidate type, comparing as Host"); + return cand1.mLocalAddr == cand2.mLocalAddr; } -bool Candidate::operator == (const Candidate& rhs) const +bool Candidate::operator==(const Candidate& rhs) const { - bool relayed1 = mType == ServerRelayed, relayed2 = rhs.mType == ServerRelayed; + bool relayed1 = mType == ServerRelayed, relayed2 = rhs.mType == ServerRelayed; - return relayed1 == relayed2 && mLocalAddr == rhs.mLocalAddr && mExternalAddr == rhs.mExternalAddr; + return relayed1 == relayed2 && mLocalAddr == rhs.mLocalAddr && mExternalAddr == rhs.mExternalAddr; } void Candidate::dump(std::ostream& output) { - output << Logger::TabPrefix<< Logger::TabPrefix << createSdp().c_str() << std::endl; + output << Logger::TabPrefix << Logger::TabPrefix << createSdp().c_str() << std::endl; } int Candidate::component() { - return mComponentId; + return mComponentId; } diff --git a/src/libs/ice/ICECandidate.h b/src/libs/ice/ICECandidate.h index d763031f..23630392 100644 --- a/src/libs/ice/ICECandidate.h +++ b/src/libs/ice/ICECandidate.h @@ -11,52 +11,50 @@ #include -namespace ice +namespace ice +{ +struct Candidate { - struct Candidate - { enum Type { - Host = 0, - ServerReflexive = 1, - PeerReflexive = 2, - ServerRelayed = 3 + Host = 0, + ServerReflexive = 1, + PeerReflexive = 2, + ServerRelayed = 3 }; - + // Type of candidate - host, server reflexive/relayes or peer reflexive - Type mType; - + Type mType; + // External address - NetworkAddress mExternalAddr; + NetworkAddress mExternalAddr; // The component ID in ICE session - int mComponentId; + int mComponentId; // Mark the gathered candidate - bool mReady; - + bool mReady; + // Mark the failed candidate - gathering is failed - bool mFailed; - + bool mFailed; + // The candidate priority - unsigned int mPriority; - + unsigned int mPriority; + // Candidate's foundation - char mFoundation[33]; - + char mFoundation[33]; + // Interface priority - unsigned int mInterfacePriority; + unsigned int mInterfacePriority; // Local used address - NetworkAddress mLocalAddr; + NetworkAddress mLocalAddr; - Candidate() - :mType(Host), mComponentId(0), mReady(false), mFailed(false), mPriority(0), - mInterfacePriority(0) + Candidate() : mType(Host), mComponentId(0), mReady(false), mFailed(false), mPriority(0), mInterfacePriority(0) { - memset(mFoundation, 0, sizeof mFoundation); + memset(mFoundation, 0, sizeof mFoundation); } - + /* Constructor. * @param _type Type of candidate - host, reflexive or relayed. * @param componentID ID of component where candidate is used. @@ -65,48 +63,46 @@ namespace ice * @param interfacePriority Priority of specified interface. * @param startTimeout Start time for STUN/TURN checks. */ Candidate(Type _type) - : mType(_type), mComponentId(0), mReady(false), mFailed(false), mPriority(0), - mInterfacePriority(0) + : mType(_type), mComponentId(0), mReady(false), mFailed(false), mPriority(0), mInterfacePriority(0) { - // Check if type is "host" - the candidate is ready in this case - if (_type == Host) - mReady = true; - memset(mFoundation, 0, sizeof mFoundation); + // Check if type is "host" - the candidate is ready in this case + if (_type == Host) + mReady = true; + memset(mFoundation, 0, sizeof mFoundation); } - - ~Candidate() - {} - + + ~Candidate() {} + // Sets local and external address simultaneously - void setLocalAndExternalAddresses(std::string& ip, unsigned short portNumber); - void setLocalAndExternalAddresses(NetworkAddress& addr); - void setLocalAndExternalAddresses(NetworkAddress &addr, unsigned short altPort); + void setLocalAndExternalAddresses(std::string& ip, unsigned short portNumber); + void setLocalAndExternalAddresses(NetworkAddress& addr); + void setLocalAndExternalAddresses(NetworkAddress& addr, unsigned short altPort); // Returns type of candidate as string - 'host', 'reflexive' or 'relayed' - const char* type(); - + const char* type(); + // Computes priority value basing on members and type priority list - void computePriority(int* typepreflist); - + void computePriority(int* typepreflist); + // Updates foundation value depending on members - void computeFoundation(); - + void computeFoundation(); + // Returns SDP line for this candidate - std::string createSdp(); + std::string createSdp(); // Creates ICECandidate instance based on SDP line - static Candidate parseSdp(const char* sdp); + static Candidate parseSdp(const char* sdp); // Returns candidate type basing on string type representation - static Type typeFromString(const char* candtype); + static Type typeFromString(const char* candtype); // Compares if two candidates are equal - static bool equal(Candidate& cand1, Candidate& cand2); - - bool operator == (const Candidate& rhs) const; - void dump(std::ostream& output); - int component(); - }; + static bool equal(Candidate& cand1, Candidate& cand2); + bool operator==(const Candidate& rhs) const; + void dump(std::ostream& output); + int component(); }; + +}; // namespace ice #endif diff --git a/src/libs/ice/ICECandidatePair.cpp b/src/libs/ice/ICECandidatePair.cpp index 033b81ae..ab856695 100644 --- a/src/libs/ice/ICECandidatePair.cpp +++ b/src/libs/ice/ICECandidatePair.cpp @@ -13,211 +13,220 @@ using namespace ice; #define LOG_SUBSYSTEM "ice" CandidatePair::CandidatePair() -:mPriority(0), mState(CandidatePair::Frozen), mControlledIndex(0), mControllingIndex(1), -mNomination(Nomination_None), mRole(Regular), mTransaction(NULL) + : mPriority(0), mState(CandidatePair::Frozen), mControlledIndex(0), mControllingIndex(1), + mNomination(Nomination_None), mRole(Regular), mTransaction(NULL) { - memset(mFoundation, 0, sizeof mFoundation); + memset(mFoundation, 0, sizeof mFoundation); } CandidatePair::CandidatePair(const CandidatePair& src) -:mPriority(src.mPriority), mState(src.mState), mControlledIndex(src.mControlledIndex), -mControllingIndex(src.mControllingIndex), mNomination(src.mNomination), -mRole(src.mRole), mTransaction(src.mTransaction) + : mPriority(src.mPriority), mState(src.mState), mControlledIndex(src.mControlledIndex), + mControllingIndex(src.mControllingIndex), mNomination(src.mNomination), mRole(src.mRole), + mTransaction(src.mTransaction) { - mCandidate[0] = src.mCandidate[0]; - mCandidate[1] = src.mCandidate[1]; - memcpy(mFoundation, src.mFoundation, sizeof mFoundation); + mCandidate[0] = src.mCandidate[0]; + mCandidate[1] = src.mCandidate[1]; + memcpy(mFoundation, src.mFoundation, sizeof mFoundation); } -CandidatePair& CandidatePair::operator = (const CandidatePair& src) +CandidatePair& CandidatePair::operator=(const CandidatePair& src) { - mPriority = src.mPriority; - mState = src.mState; - memcpy(mFoundation, src.mFoundation, sizeof mFoundation); - mControlledIndex = src.mControlledIndex; - mControllingIndex = src.mControllingIndex; - mNomination = src.mNomination; - mTransaction = src.mTransaction; - mRole = src.mRole; - mCandidate[0] = src.mCandidate[0]; - mCandidate[1] = src.mCandidate[1]; - return *this; + mPriority = src.mPriority; + mState = src.mState; + memcpy(mFoundation, src.mFoundation, sizeof mFoundation); + mControlledIndex = src.mControlledIndex; + mControllingIndex = src.mControllingIndex; + mNomination = src.mNomination; + mTransaction = src.mTransaction; + mRole = src.mRole; + mCandidate[0] = src.mCandidate[0]; + mCandidate[1] = src.mCandidate[1]; + return *this; } -CandidatePair::~CandidatePair() -{ -} +CandidatePair::~CandidatePair() {} const char* CandidatePair::stateToString(State s) { - switch (s) - { - case Waiting: return "Waiting"; - case InProgress: return "InProgress"; - case Succeeded: return "Succeeded"; - case Failed: return "Failed"; - case Frozen: return "Frozen"; - } - return "UNEXPECTED"; + switch (s) + { + case Waiting: + return "Waiting"; + case InProgress: + return "InProgress"; + case Succeeded: + return "Succeeded"; + case Failed: + return "Failed"; + case Frozen: + return "Frozen"; + } + return "UNEXPECTED"; } const char* CandidatePair::nominationToString(ice::CandidatePair::Nomination n) { - switch (n) - { - case Nomination_None: return "nomination:none"; - case Nomination_Started: return "nomination:started"; - case Nomination_Finished: return "nomination:finished"; - } - return "nomination:bad"; + switch (n) + { + case Nomination_None: + return "nomination:none"; + case Nomination_Started: + return "nomination:started"; + case Nomination_Finished: + return "nomination:finished"; + } + return "nomination:bad"; } void CandidatePair::updatePriority() { - unsigned int G = mCandidate[mControllingIndex].mPriority; - unsigned int D = mCandidate[mControlledIndex].mPriority; - // As RFC says... - mPriority = 0xFFFFFFFF * MINVALUE(G, D) + 2*MAXVALUE(G,D) + ((G>D)?1:0); - - // ICELogDebug(<< "G=" << G << ", D=" << D << ", priority=" << mPriority); + unsigned int G = mCandidate[mControllingIndex].mPriority; + unsigned int D = mCandidate[mControlledIndex].mPriority; + // As RFC says... + mPriority = 0xFFFFFFFF * MINVALUE(G, D) + 2 * MAXVALUE(G, D) + ((G > D) ? 1 : 0); + + // ICELogDebug(<< "G=" << G << ", D=" << D << ", priority=" << mPriority); } void CandidatePair::updateFoundation() { - // Get a combination of controlling and controlled foundations - strcpy(mFoundation, mCandidate[mControlledIndex].mFoundation); - strcat(mFoundation, mCandidate[mControlledIndex].mFoundation); + // Get a combination of controlling and controlled foundations + strcpy(mFoundation, mCandidate[mControlledIndex].mFoundation); + strcat(mFoundation, mCandidate[mControlledIndex].mFoundation); } -bool CandidatePair::operator == (const CandidatePair& rhs) const +bool CandidatePair::operator==(const CandidatePair& rhs) const { - return this->mCandidate[0] == rhs.mCandidate[0] && this->mCandidate[1] == rhs.mCandidate[1]; + return this->mCandidate[0] == rhs.mCandidate[0] && this->mCandidate[1] == rhs.mCandidate[1]; } const char* CandidatePair::roleToString(Role r) { - switch (r) - { - case Regular: return "regular"; - case Triggered: return "triggered"; - case Valid: return "valid"; - case None: return "none"; - } - return "UNEXPECTED"; + switch (r) + { + case Regular: + return "regular"; + case Triggered: + return "triggered"; + case Valid: + return "valid"; + case None: + return "none"; + } + return "UNEXPECTED"; } std::string CandidatePair::toStdString() { - char result[256]; - - sprintf(result, "(%s%s) %s %s -> %s %s ", roleToString(mRole), nominationToString(mNomination), - mCandidate[0].type(), mCandidate[0].mLocalAddr.toStdString().c_str(), mCandidate[1].type(), - mCandidate[1].mExternalAddr.toStdString().c_str()); + char result[256]; - return result; + sprintf(result, "(%s%s) %s %s -> %s %s ", roleToString(mRole), nominationToString(mNomination), + mCandidate[0].type(), mCandidate[0].mLocalAddr.toStdString().c_str(), mCandidate[1].type(), + mCandidate[1].mExternalAddr.toStdString().c_str()); + + return result; } bool CandidatePair::isLanOnly() const { - return first().mLocalAddr.isLAN() && - second().mExternalAddr.isLAN(); + return first().mLocalAddr.isLAN() && second().mExternalAddr.isLAN(); } CandidatePair::Role CandidatePair::role() const { - return mRole; + return mRole; }; void CandidatePair::setRole(Role role) { - mRole = role; + mRole = role; } CandidatePair::Nomination CandidatePair::nomination() const { - return mNomination; + return mNomination; } void CandidatePair::setNomination(ice::CandidatePair::Nomination n) { - mNomination = n; + mNomination = n; } const char* CandidatePair::foundation() const { - return mFoundation; + return mFoundation; }; void CandidatePair::setFoundation(const char* foundation) { - strcpy(mFoundation, foundation); + strcpy(mFoundation, foundation); } CandidatePair::State CandidatePair::state() const { - return mState; + return mState; } void CandidatePair::setState(CandidatePair::State state) { - mState = state; + mState = state; } int64_t CandidatePair::priority() const { - return mPriority; + return mPriority; } void CandidatePair::setPriority(int64_t priority) { - mPriority = priority; + mPriority = priority; } Candidate& CandidatePair::first() { - return mCandidate[0]; + return mCandidate[0]; } const Candidate& CandidatePair::first() const { - return mCandidate[0]; + return mCandidate[0]; } Candidate& CandidatePair::second() { - return mCandidate[1]; + return mCandidate[1]; } const Candidate& CandidatePair::second() const { - return mCandidate[1]; + return mCandidate[1]; } unsigned CandidatePair::controlledIndex() { - return mControlledIndex; + return mControlledIndex; } -void CandidatePair::setControlledIndex(unsigned index) +void CandidatePair::setControlledIndex(unsigned index) { - mControlledIndex = index; + mControlledIndex = index; } unsigned CandidatePair::controllingIndex() { - return mControllingIndex; + return mControllingIndex; } -void CandidatePair::setControllingIndex(unsigned index) +void CandidatePair::setControllingIndex(unsigned index) { - mControllingIndex = index; + mControllingIndex = index; } -void* CandidatePair::transaction() +void* CandidatePair::transaction() { - return mTransaction; + return mTransaction; } void CandidatePair::setTransaction(void* t) { - mTransaction = t; + mTransaction = t; } diff --git a/src/libs/ice/ICECandidatePair.h b/src/libs/ice/ICECandidatePair.h index 0d1845d1..f435143a 100644 --- a/src/libs/ice/ICECandidatePair.h +++ b/src/libs/ice/ICECandidatePair.h @@ -12,101 +12,101 @@ namespace ice { - class CandidatePair - { - public: +class CandidatePair +{ +public: /// Possible pair states enum State { - Waiting = 0, - InProgress, - Succeeded, - Failed, - Frozen + Waiting = 0, + InProgress, + Succeeded, + Failed, + Frozen }; - + enum Role { - None = 0, - Regular = 1, - Triggered = 2, - Valid = 3 + None = 0, + Regular = 1, + Triggered = 2, + Valid = 3 }; - + enum Nomination { - Nomination_None, - Nomination_Started, - Nomination_Finished + Nomination_None, + Nomination_Started, + Nomination_Finished }; - + static const char* stateToString(State s); - static const char* nominationToString(Nomination n); - - - protected: + static const char* nominationToString(Nomination n); + + +protected: /// Local and remote candidates. First (zero index) is local candidate, second (index one) is remote candidate - Candidate mCandidate[2]; - + Candidate mCandidate[2]; + /// Pair's priority, computed in UpdatePriority() method - int64_t mPriority; - + int64_t mPriority; + /// Pair's state - State mState; - + State mState; + /// Index of controlled candidate in mCandidate array - int mControlledIndex; - + int mControlledIndex; + /// Index of controlling candidate in mCandidate array - int mControllingIndex; - + int mControllingIndex; + /// Combination of controlled and controlling candidates foundations, computed in UpdateFoundation() method. - char mFoundation[65]; - + char mFoundation[65]; + /// Marks nominated pair - Nomination mNomination; - + Nomination mNomination; + /// Mark pair role - regular, triggered, valid, nominated - Role mRole; - void* mTransaction; + Role mRole; + void* mTransaction; - static const char* roleToString(Role r); + static const char* roleToString(Role r); - public: +public: CandidatePair(); CandidatePair(const CandidatePair& src); ~CandidatePair(); - Candidate& first(); + Candidate& first(); const Candidate& first() const; - Candidate& second(); + Candidate& second(); const Candidate& second() const; - int64_t priority() const; - void setPriority(int64_t priority); - State state() const; - void setState(State state); - const char* foundation() const; - void setFoundation(const char* foundation); - Role role() const; - void setRole(Role role); - Nomination nomination() const; - void setNomination(Nomination n); - unsigned controlledIndex(); - void setControlledIndex(unsigned index); - unsigned controllingIndex(); - void setControllingIndex(unsigned index); - void updatePriority(); - void updateFoundation(); - std::string toStdString(); - bool isLanOnly() const; + int64_t priority() const; + void setPriority(int64_t priority); + State state() const; + void setState(State state); + const char* foundation() const; + void setFoundation(const char* foundation); + Role role() const; + void setRole(Role role); + Nomination nomination() const; + void setNomination(Nomination n); + unsigned controlledIndex(); + void setControlledIndex(unsigned index); + unsigned controllingIndex(); + void setControllingIndex(unsigned index); + void updatePriority(); + void updateFoundation(); + std::string toStdString(); + bool isLanOnly() const; - void* transaction(); - void setTransaction(void* t); - CandidatePair& operator = (const CandidatePair& rhs); - bool operator == (const CandidatePair& rhs) const; - }; - - typedef std::shared_ptr PCandidatePair; -} + void* transaction(); + void setTransaction(void* t); + CandidatePair& operator=(const CandidatePair& rhs); + bool operator==(const CandidatePair& rhs) const; +}; + +typedef std::shared_ptr PCandidatePair; +} // namespace ice #endif diff --git a/src/libs/ice/ICECheckList.cpp b/src/libs/ice/ICECheckList.cpp index 68dbee00..49436a84 100644 --- a/src/libs/ice/ICECheckList.cpp +++ b/src/libs/ice/ICECheckList.cpp @@ -17,419 +17,407 @@ using namespace ice; const char* CheckList::stateToString(int state) { - switch (state) - { - case Running: return "Running"; - case Completed: return "Completed"; - case Failed: return "Failed"; - } - return "Undefined"; -} -CheckList::CheckList() -:mState(CheckList::Running) -{ + switch (state) + { + case Running: + return "Running"; + case Completed: + return "Completed"; + case Failed: + return "Failed"; + } + return "Undefined"; } +CheckList::CheckList() : mState(CheckList::Running) {} CheckList::State CheckList::state() { - return mState; + return mState; } void CheckList::setState(CheckList::State state) { - mState = state; + mState = state; } CheckList::PairList& CheckList::pairlist() { - return mPairList; + return mPairList; } static bool ComparePairByPriority(const PCandidatePair& pair1, const PCandidatePair& pair2) { - return pair1->priority() > pair2->priority(); + return pair1->priority() > pair2->priority(); } void CheckList::pruneDuplicates() { - // Remove duplicates - for (PairList::iterator pairIter = mPairList.begin(); pairIter != mPairList.end(); pairIter++) - { - PCandidatePair& pair = *pairIter; - - // Get the iterator to next element - PairList::iterator nextPairIter = pairIter; std::advance(nextPairIter, 1); - - // Iterate next elements to find duplicates - while (nextPairIter != mPairList.end()) + // Remove duplicates + for (PairList::iterator pairIter = mPairList.begin(); pairIter != mPairList.end(); pairIter++) { - PCandidatePair& nextPair = *nextPairIter; - - bool sameType = pair->first().mLocalAddr.family() == nextPair->second().mLocalAddr.family(); - bool sameAddress = pair->second().mExternalAddr == nextPair->second().mExternalAddr; - bool relayed1 = pair->first().mType == Candidate::ServerRelayed; - bool relayed2 = nextPair->first().mType == Candidate::ServerRelayed; - bool sameRelayed = relayed1 == relayed2; -#ifdef ICE_SMART_PRUNE_CHECKLIST - if (sameType && sameAddress && sameRelayed) -#else - if (equalCandidates && sameAddress && sameRelayed) -#endif - nextPairIter = mPairList.erase(nextPairIter); - else - nextPairIter++; - } - } + PCandidatePair& pair = *pairIter; + // Get the iterator to next element + PairList::iterator nextPairIter = pairIter; + std::advance(nextPairIter, 1); + + // Iterate next elements to find duplicates + while (nextPairIter != mPairList.end()) + { + PCandidatePair& nextPair = *nextPairIter; + + bool sameType = pair->first().mLocalAddr.family() == nextPair->second().mLocalAddr.family(); + bool sameAddress = pair->second().mExternalAddr == nextPair->second().mExternalAddr; + bool relayed1 = pair->first().mType == Candidate::ServerRelayed; + bool relayed2 = nextPair->first().mType == Candidate::ServerRelayed; + bool sameRelayed = relayed1 == relayed2; +#ifdef ICE_SMART_PRUNE_CHECKLIST + if (sameType && sameAddress && sameRelayed) +#else + if (equalCandidates && sameAddress && sameRelayed) +#endif + nextPairIter = mPairList.erase(nextPairIter); + else + nextPairIter++; + } + } } void CheckList::prune(int /*checkLimit*/) { - // Sort list by priority - std::sort(mPairList.begin(), mPairList.end(), ComparePairByPriority); + // Sort list by priority + std::sort(mPairList.begin(), mPairList.end(), ComparePairByPriority); - // Replace server reflexive candidates with bases - for (unsigned ci=0; cifirst().mType == Candidate::ServerReflexive) - pair->first().mType = Candidate::Host; - } - - /* -#ifdef _WIN32 - Win32Preprocess(); -#endif - */ + // Replace server reflexive candidates with bases + for (unsigned ci = 0; ci < mPairList.size(); ci++) + { + PCandidatePair& pair = mPairList[ci]; + if (pair->first().mType == Candidate::ServerReflexive) + pair->first().mType = Candidate::Host; + } - pruneDuplicates(); - - // Erase all relayed checks to LAN candidates - PairList::iterator pairIter = mPairList.begin(); - while (pairIter != mPairList.end()) - { - PCandidatePair& pair = *pairIter; - if (pair->first().mType == Candidate::ServerRelayed && !pair->second().mExternalAddr.isPublic()) - pairIter = mPairList.erase(pairIter); - else - pairIter++; - } + /* + #ifdef _WIN32 + Win32Preprocess(); + #endif + */ + + pruneDuplicates(); + + // Erase all relayed checks to LAN candidates + PairList::iterator pairIter = mPairList.begin(); + while (pairIter != mPairList.end()) + { + PCandidatePair& pair = *pairIter; + if (pair->first().mType == Candidate::ServerRelayed && !pair->second().mExternalAddr.isPublic()) + pairIter = mPairList.erase(pairIter); + else + pairIter++; + } #ifndef ICE_LOOPBACK_SUPPORT - pairIter = mPairList.begin(); - while (pairIter != mPairList.end()) - { - PCandidatePair& pair = *pairIter; - if (pair->second().mExternalAddr.isLoopback()) - pairIter = mPairList.erase(pairIter); - else - pairIter++; - } + pairIter = mPairList.begin(); + while (pairIter != mPairList.end()) + { + PCandidatePair& pair = *pairIter; + if (pair->second().mExternalAddr.isLoopback()) + pairIter = mPairList.erase(pairIter); + else + pairIter++; + } #endif #ifdef ICE_SKIP_LINKLOCAL - pairIter = mPairList.begin(); - while (pairIter != mPairList.end()) - { - PCandidatePair& pair = *pairIter; - if (pair->second().mExternalAddr.isLinkLocal()) - pairIter = mPairList.erase(pairIter); - else - pairIter++; - } + pairIter = mPairList.begin(); + while (pairIter != mPairList.end()) + { + PCandidatePair& pair = *pairIter; + if (pair->second().mExternalAddr.isLinkLocal()) + pairIter = mPairList.erase(pairIter); + else + pairIter++; + } #endif - pruneDuplicates(); - + pruneDuplicates(); + #ifdef ICE_POSTPONE_RELAYEDCHECKS - postponeRelayed(); + postponeRelayed(); #endif - // Put all LAN checks before other. - // Therefore it should be priorities sorting should be enough. - // But in answer's SDP remote peer can put external IP to the top of the list - // It can cause its promote to the top of list of connectivity checks - std::sort(mPairList.begin(), mPairList.end(), [](const PCandidatePair& p1, const PCandidatePair& p2) -> bool - { - return p1->isLanOnly() && !p2->isLanOnly(); - }); + // Put all LAN checks before other. + // Therefore it should be priorities sorting should be enough. + // But in answer's SDP remote peer can put external IP to the top of the list + // It can cause its promote to the top of list of connectivity checks + std::sort(mPairList.begin(), mPairList.end(), [](const PCandidatePair& p1, const PCandidatePair& p2) -> bool + { return p1->isLanOnly() && !p2->isLanOnly(); }); - // Cut all checks that are behind the limit - if (mPairList.size() > ICE_CONNCHECK_LIMIT) - { - ICELogDebug(<<"Cut extra connection checks. The total number of checks should not exceed " << ICE_CONNCHECK_LIMIT); - PairList::iterator bcIter = mPairList.begin(); - std::advance(bcIter, ICE_CONNCHECK_LIMIT); - mPairList.erase(bcIter, mPairList.end()); - } + // Cut all checks that are behind the limit + if (mPairList.size() > ICE_CONNCHECK_LIMIT) + { + ICELogDebug(<< "Cut extra connection checks. The total number of checks should not exceed " + << ICE_CONNCHECK_LIMIT); + PairList::iterator bcIter = mPairList.begin(); + std::advance(bcIter, ICE_CONNCHECK_LIMIT); + mPairList.erase(bcIter, mPairList.end()); + } } void CheckList::win32Preprocess() { - for (unsigned i=0; itoStdString()); - - if (pair->first().mType == Candidate::Host) + for (unsigned i = 0; i < mPairList.size(); i++) { - // Get best source interface for remote candidate - NetworkAddress bestInterface = NetworkHelper::instance().sourceInterface(pair->second().mExternalAddr); - - // Replace IP address to found - if (!bestInterface.isEmpty()) - pair->first().mLocalAddr.setIp(bestInterface.ip()); - else - ICELogDebug(<<"Failed to find source interface for remote candidate"); + PCandidatePair& pair = mPairList[i]; + ICELogDebug(<< "Win32Preprocess pair " << pair->toStdString()); + + if (pair->first().mType == Candidate::Host) + { + // Get best source interface for remote candidate + NetworkAddress bestInterface = NetworkHelper::instance().sourceInterface(pair->second().mExternalAddr); + + // Replace IP address to found + if (!bestInterface.isEmpty()) + pair->first().mLocalAddr.setIp(bestInterface.ip()); + else + ICELogDebug(<< "Failed to find source interface for remote candidate"); + } } - } } PCandidatePair CheckList::findEqualPair(CandidatePair& _pair, ComparisionType ct) { - for (PCandidatePair& p: mPairList) - { - if (p->role() != CandidatePair::None) + for (PCandidatePair& p : mPairList) { - switch (ct) - { - case CT_TreatHostAsUniform: - if (p->first().mType == Candidate::Host && _pair.first().mType == Candidate::Host && p->second() == _pair.second()) - return p; - if (p->first().mLocalAddr == _pair.first().mLocalAddr && p->first().mType == Candidate::Host && p->second() == _pair.second() && _pair.first().mType != Candidate::ServerRelayed) - return p; - if (_pair == *p) - return p; - - break; + if (p->role() != CandidatePair::None) + { + switch (ct) + { + case CT_TreatHostAsUniform: + if (p->first().mType == Candidate::Host && _pair.first().mType == Candidate::Host && + p->second() == _pair.second()) + return p; + if (p->first().mLocalAddr == _pair.first().mLocalAddr && p->first().mType == Candidate::Host && + p->second() == _pair.second() && _pair.first().mType != Candidate::ServerRelayed) + return p; + if (_pair == *p) + return p; - case CT_Strict: - if (_pair == *p) - return p; - break; - } + break; + + case CT_Strict: + if (_pair == *p) + return p; + break; + } + } } - } - return PCandidatePair(); + return PCandidatePair(); } unsigned CheckList::add(CandidatePair& p) { - mPairList.push_back(std::make_shared(p)); - - // Sort list by priority - std::sort(mPairList.begin(), mPairList.end(), ComparePairByPriority); - - return (unsigned)mPairList.size(); + mPairList.push_back(std::make_shared(p)); + + // Sort list by priority + std::sort(mPairList.begin(), mPairList.end(), ComparePairByPriority); + + return (unsigned)mPairList.size(); } unsigned CheckList::count() { - return (unsigned)mPairList.size(); + return (unsigned)mPairList.size(); } std::string CheckList::toStdString() { - std::string dump = ""; - for (size_t i=0; itoStdString(); - dump += "\n"; - } + std::string dump = ""; + for (size_t i = 0; i < mPairList.size(); i++) + { + dump += mPairList[i]->toStdString(); + dump += "\n"; + } - return dump; + return dump; } -PCandidatePair& CheckList::operator[] (size_t index) +PCandidatePair& CheckList::operator[](size_t index) { - return mPairList[index]; + return mPairList[index]; } PCandidatePair CheckList::findNominatedPair(int component) { - for (PCandidatePair& p: mPairList) - { - if (p->first().component() == component && - p->role() != CandidatePair::None && - p->nomination() == CandidatePair::Nomination_Finished) - return p; - } - return PCandidatePair(); + for (PCandidatePair& p : mPairList) + { + if (p->first().component() == component && p->role() != CandidatePair::None && + p->nomination() == CandidatePair::Nomination_Finished) + return p; + } + return PCandidatePair(); } PCandidatePair CheckList::findValidPair(int component) { - for (PCandidatePair& p: mPairList) - { - if (p->first().component() == component && - p->role() == CandidatePair::Valid) - return p; - } - return PCandidatePair(); + for (PCandidatePair& p : mPairList) + { + if (p->first().component() == component && p->role() == CandidatePair::Valid) + return p; + } + return PCandidatePair(); } PCandidatePair CheckList::findBestValidPair(int componentId) { - PairList found; - std::copy_if(mPairList.begin(), mPairList.end(), std::back_inserter(found), - [componentId](const PCandidatePair& p) -> bool - { - return (p->first().component() == componentId && - p->role() == CandidatePair::Valid && - p->first().mExternalAddr.isLAN() && - p->second().mExternalAddr.isLAN()); - }); + PairList found; + std::copy_if(mPairList.begin(), mPairList.end(), std::back_inserter(found), + [componentId](const PCandidatePair& p) -> bool + { + return (p->first().component() == componentId && p->role() == CandidatePair::Valid && + p->first().mExternalAddr.isLAN() && p->second().mExternalAddr.isLAN()); + }); - if (found.size()) - return found.front(); + if (found.size()) + return found.front(); - return findValidPair(componentId); + return findValidPair(componentId); } PCandidatePair CheckList::findHighestNominatedPair(int component) { #ifdef ICE_POSTPONE_RELAYEDCHECKS - PairList found; - for (PCandidatePair& p: mPairList) - { - if (p->first().component() == component && - p->role() != CandidatePair::None && - p->nomination() == CandidatePair::Nomination_Finished && - p->first().mType != Candidate::ServerRelayed && - p->second().mType != Candidate::ServerRelayed) - found.push_back( p ); - } - - if (found.size()) - { - PCandidatePair& f0 = found.front(); - for (PCandidatePair& p: mPairList) - if (p == f0) - return p; - } -#endif - int64_t priority = -1; - PCandidatePair result; - - std::ostringstream oss; - oss << "Looking for highest nominated pair in list:"; - for (PCandidatePair& p: mPairList) - { - oss << "\n " << p->toStdString().c_str() << ", priority " << p->priority(); - - if (p->first().component() == component && - p->role() != CandidatePair::None && - p->nomination() == CandidatePair::Nomination_Finished && - p->priority() > priority ) + PairList found; + for (PCandidatePair& p : mPairList) { - result = p; - priority = p->priority(); + if (p->first().component() == component && p->role() != CandidatePair::None && + p->nomination() == CandidatePair::Nomination_Finished && p->first().mType != Candidate::ServerRelayed && + p->second().mType != Candidate::ServerRelayed) + found.push_back(p); } - } - // ICELogDebug( << oss.str() ); + if (found.size()) + { + PCandidatePair& f0 = found.front(); + for (PCandidatePair& p : mPairList) + if (p == f0) + return p; + } +#endif + int64_t priority = -1; + PCandidatePair result; - if (result) - { - ICELogDebug(<< "Result is " << result->toStdString()); - } - else - { - // ICELogDebug(<< "No nominated pair"); - } - return result; + std::ostringstream oss; + oss << "Looking for highest nominated pair in list:"; + for (PCandidatePair& p : mPairList) + { + oss << "\n " << p->toStdString().c_str() << ", priority " << p->priority(); + + if (p->first().component() == component && p->role() != CandidatePair::None && + p->nomination() == CandidatePair::Nomination_Finished && p->priority() > priority) + { + result = p; + priority = p->priority(); + } + } + + // ICELogDebug( << oss.str() ); + + if (result) + { + ICELogDebug(<< "Result is " << result->toStdString()); + } + else + { + // ICELogDebug(<< "No nominated pair"); + } + return result; } void CheckList::removePairs(CandidatePair::State state, int component) { - for (unsigned i=0; ifirst().component() == component && - p->role() != CandidatePair::None && - p->nomination() == CandidatePair::Nomination_Finished && - p->priority() < priority ) + for (PCandidatePair& p : mPairList) { - result = p; - priority = p->priority(); + if (p->first().component() == component && p->role() != CandidatePair::None && + p->nomination() == CandidatePair::Nomination_Finished && p->priority() < priority) + { + result = p; + priority = p->priority(); + } } - } - return result; + return result; } void CheckList::updatePairPriorities() { - for (unsigned i=0; iupdatePriority(); + for (unsigned i = 0; i < mPairList.size(); i++) + mPairList[i]->updatePriority(); } void CheckList::clear() { - mState = Running; - mPairList.clear(); + mState = Running; + mPairList.clear(); } void CheckList::dump(std::ostream& output) { - output << Logger::TabPrefix << Logger::TabPrefix << "State: " << CheckList::stateToString(mState) << std::endl; - for (unsigned i=0; irole() != CandidatePair::None) - output << Logger::TabPrefix << Logger::TabPrefix << mPairList[i]->toStdString().c_str() << std::endl; + output << Logger::TabPrefix << Logger::TabPrefix << "State: " << CheckList::stateToString(mState) << std::endl; + for (unsigned i = 0; i < mPairList.size(); i++) + if (mPairList[i]->role() != CandidatePair::None) + output << Logger::TabPrefix << Logger::TabPrefix << mPairList[i]->toStdString().c_str() << std::endl; } unsigned CheckList::countOfValidPairs() { - unsigned result = 0; - for (unsigned i=0; irole() >= CandidatePair::Valid) - result++; - return result; + unsigned result = 0; + for (unsigned i = 0; i < mPairList.size(); i++) + if (mPairList[i]->role() >= CandidatePair::Valid) + result++; + return result; } void CheckList::postponeRelayed() { - PairList relayed, relayedTarget; + PairList relayed, relayedTarget; - PairList::iterator pairIter = mPairList.begin(); - while ( pairIter != mPairList.end() ) - { - PCandidatePair& p = *pairIter; - if (p->first().mType == Candidate::ServerRelayed) + PairList::iterator pairIter = mPairList.begin(); + while (pairIter != mPairList.end()) { - relayed.push_back(p); - pairIter = mPairList.erase( pairIter ); + PCandidatePair& p = *pairIter; + if (p->first().mType == Candidate::ServerRelayed) + { + relayed.push_back(p); + pairIter = mPairList.erase(pairIter); + } + else if (p->second().mType == Candidate::ServerRelayed) + { + relayedTarget.push_back(p); + pairIter = mPairList.erase(pairIter); + } + else + pairIter++; } - else - if (p->second().mType == Candidate::ServerRelayed) - { - relayedTarget.push_back(p); - pairIter = mPairList.erase( pairIter ); - } - else - pairIter++; - } - - for (pairIter = relayedTarget.begin(); pairIter != relayedTarget.end(); pairIter++) - mPairList.push_back(*pairIter); - - for (pairIter = relayed.begin(); pairIter != relayed.end(); pairIter++) - mPairList.push_back(*pairIter); + + for (pairIter = relayedTarget.begin(); pairIter != relayedTarget.end(); pairIter++) + mPairList.push_back(*pairIter); + + for (pairIter = relayed.begin(); pairIter != relayed.end(); pairIter++) + mPairList.push_back(*pairIter); } diff --git a/src/libs/ice/ICECheckList.h b/src/libs/ice/ICECheckList.h index 21181c4d..a49a840b 100644 --- a/src/libs/ice/ICECheckList.h +++ b/src/libs/ice/ICECheckList.h @@ -12,90 +12,91 @@ namespace ice { - class CheckList - { - public: +class CheckList +{ +public: enum State { - Running = 0, - Completed, - Failed + Running = 0, + Completed, + Failed }; - static const char* stateToString(int state); + static const char* stateToString(int state); typedef std::vector PairList; - - protected: + +protected: /// Check list state - State mState; - + State mState; + /// Vector of pairs PairList mPairList; - - void pruneDuplicates(); - void postponeRelayed(); - public: - CheckList(); - - State state(); - void setState(State state); + void pruneDuplicates(); + void postponeRelayed(); + +public: + CheckList(); + + State state(); + void setState(State state); PairList& pairlist(); /// Sorts check list, prunes from duplicate pairs and cuts to checkLimit number of elements. - void prune(int checkLimit); - + void prune(int checkLimit); + /// Replaces local host candidates IP addresses with best source interface. - void win32Preprocess(); - - /// Finds&returns smart pointer to pair + void win32Preprocess(); + + /// Finds&returns smart pointer to pair enum ComparisionType { - CT_TreatHostAsUniform, - CT_Strict + CT_TreatHostAsUniform, + CT_Strict }; - PCandidatePair findEqualPair(CandidatePair& p, ComparisionType ct); - - /// Add&sort - unsigned add(CandidatePair& p); - + PCandidatePair findEqualPair(CandidatePair& p, ComparisionType ct); + + /// Add&sort + unsigned add(CandidatePair& p); + /// Returns number of pairs in list - unsigned count(); - + unsigned count(); + /// Returns items of list - //ICECandidatePair operator[] (size_t index) const; - PCandidatePair& operator[] (size_t index); + // ICECandidatePair operator[] (size_t index) const; + PCandidatePair& operator[](size_t index); /// Dumps check list to string - std::string toStdString(); - + std::string toStdString(); + /// Updates state of list based on items state - void updateState(); + void updateState(); /// Find first nominated pair for specified component ID - PCandidatePair findNominatedPair(int componentID); + PCandidatePair findNominatedPair(int componentID); /// Finds valid pair for specified component ID. It is used for valid lists only. - PCandidatePair findValidPair(int componentID); + PCandidatePair findValidPair(int componentID); - /// Finds best valid pair for specified component ID. 'Best' means to prefer 1) LAN addresses 2) reflexive addresses 3)relayed addresses is low priority - PCandidatePair findBestValidPair(int componentId); + /// Finds best valid pair for specified component ID. 'Best' means to prefer 1) LAN addresses 2) reflexive addresses + /// 3)relayed addresses is low priority + PCandidatePair findBestValidPair(int componentId); /// Finds nominated pair with highest priority and specified component ID - PCandidatePair findHighestNominatedPair(int componentID); + PCandidatePair findHighestNominatedPair(int componentID); /// Finds nominated pair with highest priority and specified component ID - PCandidatePair findLowestNominatedPair(int componentID); + PCandidatePair findLowestNominatedPair(int componentID); /// Removes from list pairs with specified state and component ID. - void removePairs(CandidatePair::State state, int componentID); + void removePairs(CandidatePair::State state, int componentID); /// Recomputes pair priorities - void updatePairPriorities(); + void updatePairPriorities(); - void clear(); - void dump(std::ostream& output); - unsigned countOfValidPairs(); - }; + void clear(); + void dump(std::ostream& output); + unsigned countOfValidPairs(); +}; -} +} // namespace ice #endif diff --git a/src/libs/ice/ICEError.cpp b/src/libs/ice/ICEError.cpp index 13bf8af6..d9f83130 100644 --- a/src/libs/ice/ICEError.cpp +++ b/src/libs/ice/ICEError.cpp @@ -9,76 +9,66 @@ using namespace ice; std::string ErrorInfo::errorMsg(int errorCode) { - switch (errorCode) - { - case 403: return "(Forbidden): The request was valid, but cannot be performed due \ + switch (errorCode) + { + case 403: + return "(Forbidden): The request was valid, but cannot be performed due \ to administrative or similar restrictions."; - case 437: return "(Allocation Mismatch): A request was received by the server that \ + case 437: + return "(Allocation Mismatch): A request was received by the server that \ requires an allocation to be in place, but there is none, or a \ request was received which requires no allocation, but there is \ one."; - case 441: return "(Wrong Credentials): The credentials in the (non-Allocate) \ + case 441: + return "(Wrong Credentials): The credentials in the (non-Allocate) \ request, though otherwise acceptable to the server, do not match \ those used to create the allocation."; - case 442: return "(Unsupported Transport Protocol): The Allocate request asked the \ + case 442: + return "(Unsupported Transport Protocol): The Allocate request asked the \ server to use a transport protocol between the server and the peer \ that the server does not support. NOTE: This does NOT refer to \ the transport protocol used in the 5-tuple."; - case 486: return "(Allocation Quota Reached): No more allocations using this \ + case 486: + return "(Allocation Quota Reached): No more allocations using this \ username can be created at the present time."; - case 508: return "(Insufficient Capacity): The server is unable to carry out the \ + case 508: + return "(Insufficient Capacity): The server is unable to carry out the \ request due to some capacity limit being reached. In an Allocate \ response, this could be due to the server having no more relayed \ transport addresses available right now, or having none with the \ requested properties, or the one that corresponds to the specified \ reservation token is not available."; - } - - return "Unknown error."; + } + return "Unknown error."; } -Exception::Exception(int errorCode, std::string errorMsg) -:mErrorCode(errorCode), mSubcode(0), mErrorMsg(errorMsg) -{ -} +Exception::Exception(int errorCode, std::string errorMsg) : mErrorCode(errorCode), mSubcode(0), mErrorMsg(errorMsg) {} -Exception::Exception(int code) - :mErrorCode(code), mSubcode(0) -{ -} +Exception::Exception(int code) : mErrorCode(code), mSubcode(0) {} -Exception::Exception(int code, int subcode) - :mErrorCode(code), mSubcode(subcode) -{ +Exception::Exception(int code, int subcode) : mErrorCode(code), mSubcode(subcode) {} -} +Exception::Exception(const Exception& src) : mErrorCode(src.mErrorCode), mErrorMsg(src.mErrorMsg), mSubcode(0) {} -Exception::Exception(const Exception& src) -:mErrorCode(src.mErrorCode), mErrorMsg(src.mErrorMsg), mSubcode(0) -{ -} - -Exception::~Exception() -{ -} +Exception::~Exception() {} int Exception::code() { - return mErrorCode; + return mErrorCode; } int Exception::subcode() { - return mSubcode; + return mSubcode; } std::string Exception::message() { - return mErrorMsg; + return mErrorMsg; } diff --git a/src/libs/ice/ICEError.h b/src/libs/ice/ICEError.h index d2c008e3..50328530 100644 --- a/src/libs/ice/ICEError.h +++ b/src/libs/ice/ICEError.h @@ -11,15 +11,14 @@ namespace ice { - class ErrorInfo - { - public: +class ErrorInfo +{ +public: static std::string errorMsg(int errorCode); +}; - }; - - enum - { +enum +{ GETIFADDRS_FAILED = 1, WRONG_CANDIDATE_TYPE, UDP_SUPPORTED_ONLY, @@ -29,12 +28,11 @@ namespace ice CANNOT_FIND_ATTRIBUTE, UNKNOWN_ATTRIBUTE, WRONG_IP_ADDRESS - }; - - class Exception - { - public: +}; +class Exception +{ +public: Exception(int code, std::string msg); Exception(int code); Exception(int code, int subcode); @@ -42,16 +40,16 @@ namespace ice Exception(const Exception& src); ~Exception(); - int code(); - int subcode(); - std::string message(); + int code(); + int subcode(); + std::string message(); - protected: - int mErrorCode; - int mSubcode; - std::string mErrorMsg; - }; +protected: + int mErrorCode; + int mSubcode; + std::string mErrorMsg; +}; -} +} // namespace ice #endif diff --git a/src/libs/ice/ICEEvent.h b/src/libs/ice/ICEEvent.h index 1c69c58d..b145ec5d 100644 --- a/src/libs/ice/ICEEvent.h +++ b/src/libs/ice/ICEEvent.h @@ -8,11 +8,11 @@ namespace ice { - class Stack; - - class StageHandler - { - public: +class Stack; + +class StageHandler +{ +public: // Fires when candidates are gathered virtual void onGathered(Stack* stack, void* tag) = 0; @@ -21,42 +21,42 @@ namespace ice // Fires when connectivity checks failed (timeout usually) virtual void onFailed(Stack* stack, void* tag) = 0; - }; +}; - class ChannelBoundCallback - { - public: +class ChannelBoundCallback +{ +public: virtual ~ChannelBoundCallback() {} virtual void onChannelBound(int /*stream*/, int /*component*/, int /*error*/) {} - }; - - class InstallPermissionsCallback - { - public: +}; + +class InstallPermissionsCallback +{ +public: virtual ~InstallPermissionsCallback() {} virtual void onPermissionsInstalled(int /*stream*/, int /*component*/, int /*error*/) {} - }; +}; - class DeletePermissionsCallback - { - public: +class DeletePermissionsCallback +{ +public: virtual ~DeletePermissionsCallback() {} virtual void onPermissionsDeleted(int /*stream*/, int /*component*/, int /*error*/) {} - }; +}; - class DeleteAllocationCallback - { - public: +class DeleteAllocationCallback +{ +public: virtual ~DeleteAllocationCallback() {} virtual void onAllocationDeleted(int /*stream*/, int /*component*/, int /*error*/) {} - }; - - class RefreshAllocationCallback - { - public: +}; + +class RefreshAllocationCallback +{ +public: virtual ~RefreshAllocationCallback(); virtual void onAllocationRefreshed(int /*stream*/, int /*component*/, int /*error*/) {} - }; -} +}; +} // namespace ice #endif diff --git a/src/libs/ice/ICEHMAC.cpp b/src/libs/ice/ICEHMAC.cpp index acffaea1..16e0d800 100644 --- a/src/libs/ice/ICEHMAC.cpp +++ b/src/libs/ice/ICEHMAC.cpp @@ -9,57 +9,57 @@ #include "ICEHMAC.h" #include "ICESHA1.h" -void ICEHMAC::GetDigest(unsigned char *text, int text_len, unsigned char *key, int key_len, unsigned char *digest) +void ICEHMAC::GetDigest(unsigned char* text, int text_len, unsigned char* key, int key_len, unsigned char* digest) { - memset(SHA1_Key, 0, SHA1_BLOCK_SIZE); + memset(SHA1_Key, 0, SHA1_BLOCK_SIZE); - /* repeated 64 times for values in ipad and opad */ - memset(m_ipad, 0x36, sizeof(m_ipad)); - memset(m_opad, 0x5c, sizeof(m_opad)); + /* repeated 64 times for values in ipad and opad */ + memset(m_ipad, 0x36, sizeof(m_ipad)); + memset(m_opad, 0x5c, sizeof(m_opad)); - /* STEP 1 */ - if (key_len > SHA1_DIGEST_LENGTH) - { - ICESHA1::Reset(); - ICESHA1::Update((UINT_8 *)key, key_len); - ICESHA1::Final(); + /* STEP 1 */ + if (key_len > SHA1_DIGEST_LENGTH) + { + ICESHA1::Reset(); + ICESHA1::Update((UINT_8*)key, key_len); + ICESHA1::Final(); - ICESHA1::GetHash((UINT_8 *)SHA1_Key); - } - else - memcpy(SHA1_Key, key, key_len); + ICESHA1::GetHash((UINT_8*)SHA1_Key); + } + else + memcpy(SHA1_Key, key, key_len); - /* STEP 2 */ - for (int i=0; i + by Chien-Chung, Chung (Jim Chung) */ #ifndef __ICE_HMAC_H @@ -8,42 +8,41 @@ #include "ICESHA1.h" -class ICEHMAC: public ICESHA1 +class ICEHMAC : public ICESHA1 { private: - unsigned char m_ipad[64]; - unsigned char m_opad[64]; + unsigned char m_ipad[64]; + unsigned char m_opad[64]; - unsigned char * szReport ; - unsigned char * SHA1_Key ; - unsigned char * AppendBuf1 ; - unsigned char * AppendBuf2 ; + unsigned char* szReport; + unsigned char* SHA1_Key; + unsigned char* AppendBuf1; + unsigned char* AppendBuf2; public: - enum { - SHA1_DIGEST_LENGTH = 20, - SHA1_BLOCK_SIZE = 64, - HMAC_BUF_LEN = 4096 - } ; + enum + { + SHA1_DIGEST_LENGTH = 20, + SHA1_BLOCK_SIZE = 64, + HMAC_BUF_LEN = 4096 + }; - ICEHMAC() - :szReport(new unsigned char[HMAC_BUF_LEN]), - AppendBuf1(new unsigned char[HMAC_BUF_LEN]), - AppendBuf2(new unsigned char[HMAC_BUF_LEN]), - SHA1_Key(new unsigned char[HMAC_BUF_LEN]) - { + ICEHMAC() + : szReport(new unsigned char[HMAC_BUF_LEN]), AppendBuf1(new unsigned char[HMAC_BUF_LEN]), + AppendBuf2(new unsigned char[HMAC_BUF_LEN]), SHA1_Key(new unsigned char[HMAC_BUF_LEN]) + { } ~ICEHMAC() { - delete[] szReport ; - delete[] AppendBuf1 ; - delete[] AppendBuf2 ; - delete[] SHA1_Key ; + delete[] szReport; + delete[] AppendBuf1; + delete[] AppendBuf2; + delete[] SHA1_Key; } - void GetDigest(unsigned char *text, int text_len, unsigned char* key, int key_len, unsigned char *digest); + void GetDigest(unsigned char* text, int text_len, unsigned char* key, int key_len, unsigned char* digest); }; diff --git a/src/libs/ice/ICEIosSupport.h b/src/libs/ice/ICEIosSupport.h index 3616674d..f76a8204 100644 --- a/src/libs/ice/ICEIosSupport.h +++ b/src/libs/ice/ICEIosSupport.h @@ -11,8 +11,8 @@ namespace ice { - int getIosIp(int networkType, int family, char* adress); - int fillIosInterfaceList(int family, int networkType, std::vector& output); -} +int getIosIp(int networkType, int family, char* adress); +int fillIosInterfaceList(int family, int networkType, std::vector& output); +} // namespace ice #endif \ No newline at end of file diff --git a/src/libs/ice/ICEIosSupport.mm b/src/libs/ice/ICEIosSupport.mm index a87fc9c1..db4738e6 100644 --- a/src/libs/ice/ICEIosSupport.mm +++ b/src/libs/ice/ICEIosSupport.mm @@ -22,203 +22,207 @@ namespace ice { - typedef enum { +typedef enum +{ ConnectionTypeUnknown, ConnectionTypeNone, ConnectionType3G, ConnectionTypeWiFi - } ConnectionType; - - - ConnectionType FindConnectionType(int family) - { - SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, family == AF_INET ? "8.8.8.8" : "2001:4860:4860::8888"); +} ConnectionType; + + +ConnectionType FindConnectionType(int family) +{ + SCNetworkReachabilityRef reachability = + SCNetworkReachabilityCreateWithName(NULL, family == AF_INET ? "8.8.8.8" : "2001:4860:4860::8888"); SCNetworkReachabilityFlags flags; - BOOL success = SCNetworkReachabilityGetFlags(reachability, &flags); + BOOL success = SCNetworkReachabilityGetFlags(reachability, &flags); CFRelease(reachability); - if (!success) { - return ConnectionTypeUnknown; + if (!success) + { + return ConnectionTypeUnknown; } BOOL isReachable = ((flags & kSCNetworkReachabilityFlagsReachable) != 0); BOOL needsConnection = ((flags & kSCNetworkReachabilityFlagsConnectionRequired) != 0); BOOL isNetworkReachable = (isReachable && !needsConnection); - - if (!isNetworkReachable) { - return ConnectionTypeNone; - } else if ((flags & kSCNetworkReachabilityFlagsIsWWAN) != 0) { - return ConnectionType3G; - } else { - return ConnectionTypeWiFi; + + if (!isNetworkReachable) + { + return ConnectionTypeNone; } - } - + else if ((flags & kSCNetworkReachabilityFlagsIsWWAN) != 0) + { + return ConnectionType3G; + } + else + { + return ConnectionTypeWiFi; + } +} + int fillIosInterfaceList(int family, int networkType, std::vector& output) { - if (networkType == NetworkHelper::NetworkType_None) - { - switch (FindConnectionType(family)) + if (networkType == NetworkHelper::NetworkType_None) { - case ConnectionTypeNone: - return 0; - - case ConnectionType3G: - networkType = NetworkHelper::NetworkType_3G; - break; - - case ConnectionTypeWiFi: - networkType = NetworkHelper::NetworkType_WiFi; - break; - - default: - break; - } - } - - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - - struct ifaddrs *interfaces = NULL; - struct ifaddrs *temp_addr = NULL; - - // retrieve the current interfaces - returns 0 on success - if(!getifaddrs(&interfaces)) - { - // Loop through linked list of interfaces - for (temp_addr = interfaces; temp_addr != NULL; temp_addr = temp_addr->ifa_next) - { - sa_family_t sa_type = temp_addr->ifa_addr->sa_family; - - if (sa_type == family) - { - NSString* name = [NSString stringWithUTF8String: temp_addr->ifa_name]; - - if (networkType != NetworkHelper::NetworkType_None) + switch (FindConnectionType(family)) { - bool wifi = [name rangeOfString: @"en"].location == 0; - bool cell = [name rangeOfString: @"pdp_ip"].location == 0; - /*bool vpn = [name rangeOfString: @"tun"].location == 0 || [name rangeOfString: @"tap"].location == 0;*/ - - switch (networkType) - { - case NetworkHelper::NetworkType_3G: - if (wifi) // Skip wifi addresses here. Use cell and vpn addresses here. - continue; - break; - - case NetworkHelper::NetworkType_WiFi: - if (cell) // Skip cell addresses here. Use other addresses - wifi and vpn. - continue; - break; - - default: - break; - } + case ConnectionTypeNone: + return 0; + + case ConnectionType3G: + networkType = NetworkHelper::NetworkType_3G; + break; + + case ConnectionTypeWiFi: + networkType = NetworkHelper::NetworkType_WiFi; + break; + + default: + break; } - - ice::NetworkAddress addr; - if (sa_type == AF_INET6) - addr = ice::NetworkAddress(((sockaddr_in6*)temp_addr->ifa_addr)->sin6_addr, 1000); - else - addr = ice::NetworkAddress(((sockaddr_in*)temp_addr->ifa_addr)->sin_addr, 1000); - - //ICELogDebug(<< "Found: " << addr.toStdString()); - - if (!addr.isLoopback() && !addr.isLinkLocal()) - output.push_back(addr); - } - } - // Free memory - freeifaddrs(interfaces); - } - - [pool release]; - return 0; + + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + struct ifaddrs* interfaces = NULL; + struct ifaddrs* temp_addr = NULL; + + // retrieve the current interfaces - returns 0 on success + if (!getifaddrs(&interfaces)) + { + // Loop through linked list of interfaces + for (temp_addr = interfaces; temp_addr != NULL; temp_addr = temp_addr->ifa_next) + { + sa_family_t sa_type = temp_addr->ifa_addr->sa_family; + + if (sa_type == family) + { + NSString* name = [NSString stringWithUTF8String:temp_addr->ifa_name]; + + if (networkType != NetworkHelper::NetworkType_None) + { + bool wifi = [name rangeOfString:@"en"].location == 0; + bool cell = [name rangeOfString:@"pdp_ip"].location == 0; + /*bool vpn = [name rangeOfString: @"tun"].location == 0 || [name rangeOfString: @"tap"].location == + * 0;*/ + + switch (networkType) + { + case NetworkHelper::NetworkType_3G: + if (wifi) // Skip wifi addresses here. Use cell and vpn addresses here. + continue; + break; + + case NetworkHelper::NetworkType_WiFi: + if (cell) // Skip cell addresses here. Use other addresses - wifi and vpn. + continue; + break; + + default: + break; + } + } + + ice::NetworkAddress addr; + if (sa_type == AF_INET6) + addr = ice::NetworkAddress(((sockaddr_in6*)temp_addr->ifa_addr)->sin6_addr, 1000); + else + addr = ice::NetworkAddress(((sockaddr_in*)temp_addr->ifa_addr)->sin_addr, 1000); + + // ICELogDebug(<< "Found: " << addr.toStdString()); + + if (!addr.isLoopback() && !addr.isLinkLocal()) + output.push_back(addr); + } + } + // Free memory + freeifaddrs(interfaces); + } + + [pool release]; + return 0; } int getIosIp(int networkType, int family, char* address) { - assert(address); - - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - - struct ifaddrs *interfaces = NULL; - struct ifaddrs *temp_addr = NULL; - NSString *wifiAddress = nil; - NSString *cellAddress = nil; - - // retrieve the current interfaces - returns 0 on success - if(!getifaddrs(&interfaces)) - { - // Loop through linked list of interfaces - temp_addr = interfaces; - while(temp_addr != NULL) + assert(address); + + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + struct ifaddrs* interfaces = NULL; + struct ifaddrs* temp_addr = NULL; + NSString* wifiAddress = nil; + NSString* cellAddress = nil; + + // retrieve the current interfaces - returns 0 on success + if (!getifaddrs(&interfaces)) { - sa_family_t sa_type = temp_addr->ifa_addr->sa_family; - - if (sa_type == family) - { - NSString* name = [NSString stringWithUTF8String: temp_addr->ifa_name]; - char buffer[128]; - if (sa_type == AF_INET6) - inet_ntop(AF_INET6, &((sockaddr_in6*)temp_addr->ifa_addr)->sin6_addr, buffer, sizeof(buffer)); - else - inet_ntop(AF_INET, &((sockaddr_in*)temp_addr->ifa_addr)->sin_addr, buffer, sizeof(buffer)); + // Loop through linked list of interfaces + temp_addr = interfaces; + while (temp_addr != NULL) + { + sa_family_t sa_type = temp_addr->ifa_addr->sa_family; - NSString* addr = [NSString stringWithUTF8String: buffer]; - - if([name rangeOfString: @"en"].location == 0) - { - // Interface is the wifi connection on the iPhone - wifiAddress = addr; + if (sa_type == family) + { + NSString* name = [NSString stringWithUTF8String:temp_addr->ifa_name]; + char buffer[128]; + if (sa_type == AF_INET6) + inet_ntop(AF_INET6, &((sockaddr_in6*)temp_addr->ifa_addr)->sin6_addr, buffer, sizeof(buffer)); + else + inet_ntop(AF_INET, &((sockaddr_in*)temp_addr->ifa_addr)->sin_addr, buffer, sizeof(buffer)); + + NSString* addr = [NSString stringWithUTF8String:buffer]; + + if ([name rangeOfString:@"en"].location == 0) + { + // Interface is the wifi connection on the iPhone + wifiAddress = addr; + } + else if ([name isEqualToString:@"pdp_ip0"]) + { + // Interface is the cell connection on the iPhone + cellAddress = addr; + } + else if ([name rangeOfString:@"tun"].location == 0 || [name rangeOfString:@"tap"].location == 0) + { + wifiAddress = addr; + } + } + temp_addr = temp_addr->ifa_next; } - else - if([name isEqualToString: @"pdp_ip0"]) - { - // Interface is the cell connection on the iPhone - cellAddress = addr; - } - else - if ([name rangeOfString: @"tun"].location == 0 || [name rangeOfString: @"tap"].location == 0) - { - wifiAddress = addr; - } - } - temp_addr = temp_addr->ifa_next; + // Free memory + freeifaddrs(interfaces); } - // Free memory - freeifaddrs(interfaces); - } - - NSString* currentAddr = nil; - switch (networkType) - { + + NSString* currentAddr = nil; + switch (networkType) + { case ice::NetworkHelper::NetworkType_None: - currentAddr = wifiAddress ? wifiAddress : cellAddress; - break; - + currentAddr = wifiAddress ? wifiAddress : cellAddress; + break; + case ice::NetworkHelper::NetworkType_WiFi: - currentAddr = wifiAddress; - break; - + currentAddr = wifiAddress; + break; + case ice::NetworkHelper::NetworkType_3G: - currentAddr = cellAddress; - break; - } - - if (currentAddr) - strcpy(address, [currentAddr UTF8String]); - else - if (wifiAddress) - strcpy(address, [wifiAddress UTF8String]); - else - if (cellAddress) - strcpy(address, [cellAddress UTF8String]); - else - strcpy(address, "127.0.0.1"); - - [pool release]; - - return 0; + currentAddr = cellAddress; + break; + } + + if (currentAddr) + strcpy(address, [currentAddr UTF8String]); + else if (wifiAddress) + strcpy(address, [wifiAddress UTF8String]); + else if (cellAddress) + strcpy(address, [cellAddress UTF8String]); + else + strcpy(address, "127.0.0.1"); + + [pool release]; + + return 0; } -} +} // namespace ice diff --git a/src/libs/ice/ICELog.cpp b/src/libs/ice/ICELog.cpp index f450dee7..adf81c09 100644 --- a/src/libs/ice/ICELog.cpp +++ b/src/libs/ice/ICELog.cpp @@ -13,7 +13,7 @@ #include #include #if defined(__ANDROID_API__) -# include +#include #endif using namespace ice; @@ -23,7 +23,7 @@ using namespace ice; #include #include -#define KEEP_SIZE (128 * 1024) // 128 KB = 131,072 bytes +#define KEEP_SIZE (128 * 1024) // 128 KB = 131,072 bytes /** * Truncates a file to its last 128 KB of content. @@ -37,20 +37,24 @@ using namespace ice; * - Uses binary mode to avoid newline translation issues * - Preserves file existence but NOT original inode/permissions (reopens in write mode) */ -int truncate_file_to_last_128k(const char *filename) { - if (!filename || *filename == '\0') { +int truncate_file_to_last_128k(const char* filename) +{ + if (!filename || *filename == '\0') + { errno = EINVAL; return -1; } // Step 1: Open file for reading (binary mode for exact byte handling) - FILE *fp = fopen(filename, "rb"); - if (!fp) { - return -1; // errno set by fopen + FILE* fp = fopen(filename, "rb"); + if (!fp) + { + return -1; // errno set by fopen } // Step 2: Get file size - if (fseek(fp, 0, SEEK_END) != 0) { + if (fseek(fp, 0, SEEK_END) != 0) + { int err = errno; fclose(fp); errno = err; @@ -58,7 +62,8 @@ int truncate_file_to_last_128k(const char *filename) { } long size = ftell(fp); - if (size < 0) { + if (size < 0) + { int err = errno; fclose(fp); errno = err; @@ -66,14 +71,16 @@ int truncate_file_to_last_128k(const char *filename) { } // Step 3: Nothing to do if file is small enough - if (size <= KEEP_SIZE) { + if (size <= KEEP_SIZE) + { fclose(fp); return 0; } // Step 4: Position at start of region to keep (last 128 KB) long start_pos = size - KEEP_SIZE; - if (fseek(fp, start_pos, SEEK_SET) != 0) { + if (fseek(fp, start_pos, SEEK_SET) != 0) + { int err = errno; fclose(fp); errno = err; @@ -81,18 +88,20 @@ int truncate_file_to_last_128k(const char *filename) { } // Step 5: Read the last 128 KB into buffer - char *buffer = (char*)malloc(KEEP_SIZE); - if (!buffer) { + char* buffer = (char*)malloc(KEEP_SIZE); + if (!buffer) + { fclose(fp); errno = ENOMEM; return -1; } size_t read_bytes = fread(buffer, 1, KEEP_SIZE, fp); - int read_err = ferror(fp); + int read_err = ferror(fp); fclose(fp); - if (read_bytes != KEEP_SIZE || read_err) { + if (read_bytes != KEEP_SIZE || read_err) + { free(buffer); errno = read_err ? ferror(fp) : EIO; return -1; @@ -100,18 +109,20 @@ int truncate_file_to_last_128k(const char *filename) { // Step 6: Reopen file in write mode (truncates existing content) fp = fopen(filename, "wb"); - if (!fp) { + if (!fp) + { free(buffer); - return -1; // errno set by fopen + return -1; // errno set by fopen } // Step 7: Write preserved content back to file size_t written = fwrite(buffer, 1, KEEP_SIZE, fp); - int write_err = ferror(fp); + int write_err = ferror(fp); fclose(fp); free(buffer); - if (written != KEEP_SIZE || write_err) { + if (written != KEEP_SIZE || write_err) + { errno = write_err ? ferror(fp) : EIO; return -1; } @@ -123,26 +134,19 @@ LogLevel LogLevelHelper::parse(const std::string& t) { if (t == "none") return LL_NONE; - else - if (t == "debug") + else if (t == "debug") return LL_DEBUG; - else - if (t == "critical") - return LL_CRITICAL; - else - if (t == "info") + else if (t == "critical") + return LL_CRITICAL; + else if (t == "info") return LL_INFO; - else - if (t == "media") + else if (t == "media") return LL_MEDIA; - else - if (t == "error") + else if (t == "error") return LL_ERROR; - else - if (t == "special") + else if (t == "special") return LL_SPECIAL; - else - if (t == "media") + else if (t == "media") return LL_MEDIA; throw std::runtime_error("Bad log param string value."); @@ -152,13 +156,20 @@ std::string LogLevelHelper::toString(LogLevel level) { switch (level) { - case LL_NONE: return "none"; - case LL_CRITICAL: return "critical"; - case LL_DEBUG: return "debug"; - case LL_ERROR: return "error"; - case LL_INFO: return "info"; - case LL_MEDIA: return "media"; - case LL_SPECIAL: return "special"; + case LL_NONE: + return "none"; + case LL_CRITICAL: + return "critical"; + case LL_DEBUG: + return "debug"; + case LL_ERROR: + return "error"; + case LL_INFO: + return "info"; + case LL_MEDIA: + return "media"; + case LL_SPECIAL: + return "special"; } throw std::runtime_error("Bad log param value."); @@ -167,8 +178,7 @@ std::string LogLevelHelper::toString(LogLevel level) ice::Logger ice::GLogger; const char* ice::Logger::TabPrefix = " "; -Logger::Logger() - :mStream(nullptr) +Logger::Logger() : mStream(nullptr) { mFile = nullptr; mUseDebugWindow = false; @@ -178,7 +188,7 @@ Logger::Logger() Logger::~Logger() { - //LogGuard l(mGuard); + // LogGuard l(mGuard); if (mFile) { fclose(mFile); @@ -186,16 +196,14 @@ Logger::~Logger() } } -void -Logger::useDebugWindow(bool enable) +void Logger::useDebugWindow(bool enable) { LogGuard l(mGuard); mUseDebugWindow = enable; } -void -Logger::useFile(const char* filepath) +void Logger::useFile(const char* filepath) { LogGuard l(mGuard); @@ -221,12 +229,12 @@ Logger::useFile(const char* filepath) } } -const std::string& Logger::getLogPath() const { +const std::string& Logger::getLogPath() const +{ return mLogPath; } -void -Logger::useNull() +void Logger::useNull() { LogGuard l(mGuard); @@ -262,20 +270,23 @@ void Logger::openFile() useFile(mLogPath.c_str()); } -std::string Logger::getLastContent(size_t bytes) { - LogGuard l(mGuard); +std::string Logger::getLastContent(size_t bytes) +{ + LogGuard l(mGuard); std::string r; - bool fileOpenNeeded = false; + bool fileOpenNeeded = false; if (mFile) { - fclose(mFile); mFile = nullptr; + fclose(mFile); + mFile = nullptr; fileOpenNeeded = true; } mFile = fopen(mLogPath.c_str(), "rt"); - if (mFile) { + if (mFile) + { fseek(mFile, 0, SEEK_END); auto size = ftell(mFile); @@ -284,7 +295,7 @@ std::string Logger::getLastContent(size_t bytes) { else fseek(mFile, size - (long)bytes, SEEK_SET); - auto contentPos = ftell(mFile); + auto contentPos = ftell(mFile); size_t contentLength = size - contentPos; if (bytes < contentLength) contentLength = bytes; @@ -293,7 +304,8 @@ std::string Logger::getLastContent(size_t bytes) { auto readCount = fread(r.data(), 1, contentLength, mFile); if (readCount >= 0) r.resize(readCount); - fclose(mFile); mFile = nullptr; + fclose(mFile); + mFile = nullptr; } if (fileOpenNeeded) @@ -333,7 +345,7 @@ void Logger::beginLine(LogLevel level, const char* filename, int linenumber, con const char* filenamestart = strrchr(filename, '\\'); #else const char* filenamestart = strrchr(filename, '/'); -#endif +#endif if (!filenamestart) filenamestart = filename; else @@ -344,32 +356,37 @@ void Logger::beginLine(LogLevel level, const char* filename, int linenumber, con mSubsystem = subsystem; } -void -Logger::endLine() +void Logger::endLine() { mStream->flush(); - std::ostringstream result; - std::chrono::milliseconds unix_timestamp_ms = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()); - time_t unix_timestamp = unix_timestamp_ms.count() / 1000; + std::ostringstream result; + std::chrono::milliseconds unix_timestamp_ms = + std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()); + time_t unix_timestamp = unix_timestamp_ms.count() / 1000; struct tm current_time = *gmtime(&unix_timestamp); - char time_buffer[128]; strftime(time_buffer, sizeof(time_buffer), "%H:%M:%S", ¤t_time); + char time_buffer[128]; + strftime(time_buffer, sizeof(time_buffer), "%H:%M:%S", ¤t_time); - result << time_buffer << ":" << (unix_timestamp_ms.count() % 1000 ) << "\t" << " | " << std::setw(8) << ThreadInfo::currentThread() << " | " - << std::setw(40) << mFilename.c_str() << " | " << std::setw(4) << mLine << " | " << std::setw(12) << mSubsystem.c_str() << " | " - << mStream->str().c_str(); + result << time_buffer << ":" << (unix_timestamp_ms.count() % 1000) << "\t" << " | " << std::setw(8) + << ThreadInfo::currentThread() << " | " << std::setw(40) << mFilename.c_str() << " | " << std::setw(4) + << mLine << " | " << std::setw(12) << mSubsystem.c_str() << " | " << mStream->str().c_str(); std::string t = result.str(); - if (mUseDebugWindow) { + if (mUseDebugWindow) + { #ifdef TARGET_WIN OutputDebugStringA(t.c_str()); #elif defined(TARGET_ANDROID) - if (t.size() > 512) { + if (t.size() > 512) + { std::string cut = t; cut.erase(480); // Erase tail of string cut += "\r\n... [cut]"; __android_log_print(ANDROID_LOG_INFO, "VoipAgent", "%s", cut.c_str()); - } else { + } + else + { __android_log_print(ANDROID_LOG_INFO, "VoipAgent", "%s", t.c_str()); } #else @@ -384,11 +401,11 @@ Logger::endLine() if (mDelegate) mDelegate->onIceLog(mMsgLevel, mFilename, mLine, mSubsystem, mStream->str()); - delete mStream; mStream = nullptr; + delete mStream; + mStream = nullptr; } -Logger& -Logger::operator << (const char* data) +Logger& Logger::operator<<(const char* data) { *mStream << data; @@ -403,67 +420,58 @@ Logger::operator << (const wchar_t* data) return *this; }*/ -Logger& -Logger::operator << (const int data) +Logger& Logger::operator<<(const int data) { *mStream << data; return *this; } -Logger& -Logger::operator << (const float data) +Logger& Logger::operator<<(const float data) { *mStream << data; return *this; } -Logger& -Logger::operator<<(const int64_t data) +Logger& Logger::operator<<(const int64_t data) { *mStream << data; return *this; } -Logger& -Logger::operator<<(const unsigned int data) +Logger& Logger::operator<<(const unsigned int data) { *mStream << data; return *this; } -Logger& -Logger::operator<<(const uint64_t data) +Logger& Logger::operator<<(const uint64_t data) { *mStream << data; return *this; } -Logger& -Logger::operator << (const std::string& data) +Logger& Logger::operator<<(const std::string& data) { *mStream << data.c_str(); return *this; } -Logger& -Logger::operator << (const std::string_view& data) +Logger& Logger::operator<<(const std::string_view& data) { *mStream << data; return *this; } -Logger& -Logger::operator << (const std::filesystem::path& p) +Logger& Logger::operator<<(const std::filesystem::path& p) { *mStream << p; return *this; } -Logger& -Logger::operator << (const std::chrono::milliseconds t) +Logger& Logger::operator<<(const std::chrono::milliseconds t) { *mStream << t.count() << "ms"; return *this; diff --git a/src/libs/ice/ICELog.h b/src/libs/ice/ICELog.h index d2159820..510ccb70 100644 --- a/src/libs/ice/ICELog.h +++ b/src/libs/ice/ICELog.h @@ -11,8 +11,8 @@ #include #ifdef _WIN32 -# include -# include +#include +#include #endif #include "ICEPlatform.h" @@ -38,7 +38,7 @@ enum LogLevel class LogLevelHelper { public: - static LogLevel parse(const std::string& t); + static LogLevel parse(const std::string& t); static std::string toString(LogLevel level); }; @@ -46,17 +46,18 @@ class LogHandler { public: virtual ~LogHandler() {} - virtual void onIceLog(LogLevel level, const std::string& filename, int line, const std::string& subsystem, const std::string& msg) = 0; + virtual void onIceLog(LogLevel level, const std::string& filename, int line, const std::string& subsystem, + const std::string& msg) = 0; }; #ifdef _WIN32 class LogGuard { public: - LogGuard() { ::InitializeCriticalSection(&mCS); } - ~LogGuard() { ::DeleteCriticalSection(&mCS); } - void Lock() { ::EnterCriticalSection(&mCS); } - void Unlock() { ::LeaveCriticalSection(&mCS); } + LogGuard() { ::InitializeCriticalSection(&mCS); } + ~LogGuard() { ::DeleteCriticalSection(&mCS); } + void Lock() { ::EnterCriticalSection(&mCS); } + void Unlock() { ::LeaveCriticalSection(&mCS); } protected: CRITICAL_SECTION mCS; @@ -65,8 +66,8 @@ protected: class LogLock { public: - LogLock(LogGuard& g) :mGuard(g) { mGuard.Lock(); } - ~LogLock() { mGuard.Unlock(); } + LogLock(LogGuard& g) : mGuard(g) { mGuard.Lock(); } + ~LogLock() { mGuard.Unlock(); } protected: LogGuard& mGuard; @@ -75,10 +76,10 @@ protected: class LogGuard { public: - LogGuard() { ::pthread_mutex_init(&mMutex, NULL); } - ~LogGuard() { ::pthread_mutex_destroy(&mMutex); } - void Lock() { ::pthread_mutex_lock(&mMutex); } - void Unlock() { ::pthread_mutex_unlock(&mMutex); } + LogGuard() { ::pthread_mutex_init(&mMutex, NULL); } + ~LogGuard() { ::pthread_mutex_destroy(&mMutex); } + void Lock() { ::pthread_mutex_lock(&mMutex); } + void Unlock() { ::pthread_mutex_unlock(&mMutex); } protected: pthread_mutex_t mMutex; @@ -87,8 +88,8 @@ protected: class LogLock { public: - LogLock(LogGuard& g) :mGuard(g) { mGuard.Lock(); } - ~LogLock() { mGuard.Unlock(); } + LogLock(LogGuard& g) : mGuard(g) { mGuard.Lock(); } + ~LogLock() { mGuard.Unlock(); } protected: LogGuard& mGuard; @@ -103,36 +104,36 @@ public: Logger(); ~Logger(); - - void useDebugWindow(bool enable); - void useFile(const char* filepath); - void useDelegate(LogHandler* delegate_); - void useNull(); - void closeFile(); - void openFile(); - std::string getLastContent(size_t bytes); + void useDebugWindow(bool enable); + void useFile(const char* filepath); + void useDelegate(LogHandler* delegate_); + void useNull(); + void closeFile(); + void openFile(); + + std::string getLastContent(size_t bytes); const std::string& getLogPath() const; - LogGuard& mutex(); - LogLevel level(); - void setLevel(LogLevel level); - void beginLine(LogLevel level, const char* filename, int linenumber, const char* subsystem); - void endLine(); + LogGuard& mutex(); + LogLevel level(); + void setLevel(LogLevel level); + void beginLine(LogLevel level, const char* filename, int linenumber, const char* subsystem); + void endLine(); - Logger& operator << (const char* data); - Logger& operator << (const wchar_t* data); - Logger& operator << (const int data); - Logger& operator << (const float data); - Logger& operator << (const std::string& data); - Logger& operator << (const std::string_view& data); - Logger& operator << (const int64_t data); - Logger& operator << (const unsigned int data); - Logger& operator << (const uint64_t data); - Logger& operator << (const std::filesystem::path& p); - Logger& operator << (const std::chrono::milliseconds t); + Logger& operator<<(const char* data); + Logger& operator<<(const wchar_t* data); + Logger& operator<<(const int data); + Logger& operator<<(const float data); + Logger& operator<<(const std::string& data); + Logger& operator<<(const std::string_view& data); + Logger& operator<<(const int64_t data); + Logger& operator<<(const unsigned int data); + Logger& operator<<(const uint64_t data); + Logger& operator<<(const std::filesystem::path& p); + Logger& operator<<(const std::chrono::milliseconds t); template - Logger& operator << (const T data) + Logger& operator<<(const T data) { *mStream << data; return *this; @@ -147,7 +148,7 @@ protected: LogHandler* mDelegate; LogLevel mLevel; std::ostringstream* mStream; - + LogLevel mMsgLevel; std::string mFilename; int mLine; @@ -158,24 +159,26 @@ protected: extern Logger GLogger; -#define ICELog(level_, subsystem_, args_)\ -{do\ -{\ - if (ice::GLogger.level() >= level_)\ -{\ - ice::LogLock log_lock(ice::GLogger.mutex());\ - ice::GLogger.beginLine(level_, __FILE__, __LINE__, subsystem_);\ - ice::GLogger args_;\ - ice::GLogger.endLine();\ -}\ -} while (false);} +#define ICELog(level_, subsystem_, args_) \ + { \ + do \ + { \ + if (ice::GLogger.level() >= level_) \ + { \ + ice::LogLock log_lock(ice::GLogger.mutex()); \ + ice::GLogger.beginLine(level_, __FILE__, __LINE__, subsystem_); \ + ice::GLogger args_; \ + ice::GLogger.endLine(); \ + } \ + } while (false); \ + } -#define ICELogCritical(args_) ICELog(ice::LL_CRITICAL, LOG_SUBSYSTEM, args_) -#define ICELogInfo(args_) ICELog(ice::LL_INFO, LOG_SUBSYSTEM, args_) -#define ICELogDebug(args_) ICELog(ice::LL_DEBUG, LOG_SUBSYSTEM, args_) -#define ICELogMedia(args_) ICELog(ice::LL_MEDIA, LOG_SUBSYSTEM, args_) -#define ICELogError(args_) ICELog(ice::LL_ERROR, LOG_SUBSYSTEM, args_) -#define ICELogSpecial(args_) ICELog(ice::LL_SPECIAL, LOG_SUBSYSTEM, args_) +#define ICELogCritical(args_) ICELog(ice::LL_CRITICAL, LOG_SUBSYSTEM, args_) +#define ICELogInfo(args_) ICELog(ice::LL_INFO, LOG_SUBSYSTEM, args_) +#define ICELogDebug(args_) ICELog(ice::LL_DEBUG, LOG_SUBSYSTEM, args_) +#define ICELogMedia(args_) ICELog(ice::LL_MEDIA, LOG_SUBSYSTEM, args_) +#define ICELogError(args_) ICELog(ice::LL_ERROR, LOG_SUBSYSTEM, args_) +#define ICELogSpecial(args_) ICELog(ice::LL_SPECIAL, LOG_SUBSYSTEM, args_) /* #define ICELogCritical2(args_) ICELog(LogLevel_Critical, LogSubsystem.c_str(), args_) @@ -186,13 +189,13 @@ extern Logger GLogger; #define ICELogSpecial2(args_) ICELog(LogLevel_Special, LogSubsystem.c_str(), args_) */ -#define DEFINE_LOGGING(subsystem) \ - static std::string LogSubsystem = subsystem; \ - static ice::LogLevel LogLevel_Critical = LL_CRITICAL; \ - static ice::LogLevel LogLevel_Info = LL_INFO; \ - static ice::LogLevel LogLevel_Debug = LL_DEBUG; \ - static ice::LogLevel LogLevel_Media = LL_MEDIA; \ - static ice::LogLevel LogLevel_Error = LL_ERROR; \ +#define DEFINE_LOGGING(subsystem) \ + static std::string LogSubsystem = subsystem; \ + static ice::LogLevel LogLevel_Critical = LL_CRITICAL; \ + static ice::LogLevel LogLevel_Info = LL_INFO; \ + static ice::LogLevel LogLevel_Debug = LL_DEBUG; \ + static ice::LogLevel LogLevel_Media = LL_MEDIA; \ + static ice::LogLevel LogLevel_Error = LL_ERROR; \ static ice::LogLevel LogLevel_Special = LL_SPECIAL @@ -203,6 +206,6 @@ extern Logger GLogger; #define ICELogMedia(args_) */ -} //end of namespace +} // namespace ice #endif diff --git a/src/libs/ice/ICEMD5.cpp b/src/libs/ice/ICEMD5.cpp index a77a4c0e..a0032eef 100644 --- a/src/libs/ice/ICEMD5.cpp +++ b/src/libs/ice/ICEMD5.cpp @@ -14,21 +14,21 @@ using namespace CryptoPP; void ice::md5Bin(const void* inputData, size_t inputSize, void* digest) { - Weak::MD5 md5; - md5.Update((const byte*)inputData, inputSize); + Weak::MD5 md5; + md5.Update((const byte*)inputData, inputSize); - md5.Final((byte*)digest); + md5.Final((byte*)digest); } #elif defined(USE_OPENSSL) -# include +#include void ice::md5Bin(const void* inputData, size_t inputSize, void* digest) { - MD5_CTX md5; - MD5_Init(&md5); - MD5_Update(&md5, (void*)inputData, inputSize); - MD5_Final((unsigned char*)digest, &md5); + MD5_CTX md5; + MD5_Init(&md5); + MD5_Update(&md5, (void*)inputData, inputSize); + MD5_Final((unsigned char*)digest, &md5); } #else @@ -44,4 +44,3 @@ void ice::md5Bin(const void* inputData, size_t inputSize, void* digest) memcpy(digest, ctx.digest, sizeof(ctx.digest)); } #endif - diff --git a/src/libs/ice/ICEMD5.h b/src/libs/ice/ICEMD5.h index 5704161a..f0a39a6d 100644 --- a/src/libs/ice/ICEMD5.h +++ b/src/libs/ice/ICEMD5.h @@ -10,6 +10,6 @@ namespace ice { - extern void md5Bin(const void* inputData, size_t inputSize, void* digest ); +extern void md5Bin(const void* inputData, size_t inputSize, void* digest); } #endif \ No newline at end of file diff --git a/src/libs/ice/ICENetworkHelper.cpp b/src/libs/ice/ICENetworkHelper.cpp index b8b67f48..45b9566a 100644 --- a/src/libs/ice/ICENetworkHelper.cpp +++ b/src/libs/ice/ICENetworkHelper.cpp @@ -13,26 +13,26 @@ #include #ifdef TARGET_WIN -# include -# if defined(WINDOWS_RT) -# include "ICEWinRtSupport.h" -# endif +#include +#if defined(WINDOWS_RT) +#include "ICEWinRtSupport.h" +#endif #elif defined(TARGET_IOS) -# include "ICEIosSupport.h" +#include "ICEIosSupport.h" #else -# include -# if defined(TARGET_ANDROID) || defined(TARGET_LINUX) -# include -# include -# if defined(TARGET_ANDROID) -# if __ANDROID_API__ < 24 -# include "android-ifaddrs/android-ifaddrs.h" -//# error not supported for ANDROID_API < 24 -# else -# include -# endif -# endif -# endif +#include +#if defined(TARGET_ANDROID) || defined(TARGET_LINUX) +#include +#include +#if defined(TARGET_ANDROID) +#if __ANDROID_API__ < 24 +#include "android-ifaddrs/android-ifaddrs.h" +// # error not supported for ANDROID_API < 24 +#else +#include +#endif +#endif +#endif #endif #include "ICEError.h" @@ -44,176 +44,172 @@ using namespace ice; class IPHlpApi { public: - HMODULE mHandle; - DWORD (WINAPI *pGetBestInterfaceEx) (struct sockaddr* pDestAddr, PDWORD pdwBestIfIndex); - DWORD (WINAPI *pGetBestInterface) (IPAddr dwDestAddr, PDWORD pdwBestIfIndex); - ULONG (WINAPI *pGetAdaptersAddresses) (ULONG Family, ULONG Flags, PVOID Reserved, PIP_ADAPTER_ADDRESSES AdapterAddresses, PULONG SizePointer); + HMODULE mHandle; + DWORD(WINAPI* pGetBestInterfaceEx)(struct sockaddr* pDestAddr, PDWORD pdwBestIfIndex); + DWORD(WINAPI* pGetBestInterface)(IPAddr dwDestAddr, PDWORD pdwBestIfIndex); + ULONG(WINAPI* pGetAdaptersAddresses)(ULONG Family, ULONG Flags, PVOID Reserved, + PIP_ADAPTER_ADDRESSES AdapterAddresses, PULONG SizePointer); - void ResolveProc(const char* name, FARPROC& proc) - { - proc = GetProcAddress(mHandle, name); - } + void ResolveProc(const char* name, FARPROC& proc) { proc = GetProcAddress(mHandle, name); } public: - IPHlpApi() - { - pGetBestInterfaceEx = NULL; - pGetBestInterface = NULL; - pGetAdaptersAddresses = NULL; - mHandle = ::LoadLibraryW(L"iphlpapi.dll"); - if (mHandle) + IPHlpApi() { - ResolveProc("GetBestInterfaceEx", (FARPROC&)pGetBestInterfaceEx); - ResolveProc("GetBestInterface", (FARPROC&)pGetBestInterface); - ResolveProc("GetAdaptersAddresses", (FARPROC&)pGetAdaptersAddresses); + pGetBestInterfaceEx = NULL; + pGetBestInterface = NULL; + pGetAdaptersAddresses = NULL; + mHandle = ::LoadLibraryW(L"iphlpapi.dll"); + if (mHandle) + { + ResolveProc("GetBestInterfaceEx", (FARPROC&)pGetBestInterfaceEx); + ResolveProc("GetBestInterface", (FARPROC&)pGetBestInterface); + ResolveProc("GetAdaptersAddresses", (FARPROC&)pGetAdaptersAddresses); + } } - } - - ~IPHlpApi() - { - if (mHandle) - FreeLibrary(mHandle); - } + ~IPHlpApi() + { + if (mHandle) + FreeLibrary(mHandle); + } }; IPHlpApi IPHelper; #endif NetworkHelper::NetworkHelper() { - reload(NetworkType_None); + reload(NetworkType_None); } -NetworkHelper::~NetworkHelper() -{ -} +NetworkHelper::~NetworkHelper() {} void NetworkHelper::reload(int networkType) { - Lock l(mInstanceGuard); - - // Get list of interfaces + Lock l(mInstanceGuard); + + // Get list of interfaces #if defined(TARGET_WIN) && !defined(WINDOWS_RT) - mInterfaceList.clear(); - mIP2IndexList.clear(); + mInterfaceList.clear(); + mIP2IndexList.clear(); - DWORD dwRet, dwSize; - DWORD flags = GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER; - IP_ADAPTER_ADDRESSES* ipAdapters = NULL; - dwRet = IPHelper.pGetAdaptersAddresses(AF_INET, flags, NULL, NULL, &dwSize); - if (dwRet == ERROR_BUFFER_OVERFLOW) - { - ipAdapters = (IP_ADAPTER_ADDRESSES*)malloc(dwSize); - if (!ipAdapters) - return; - - dwRet = IPHelper.pGetAdaptersAddresses(AF_INET, flags, NULL, ipAdapters, &dwSize); - if (dwRet != ERROR_SUCCESS) + DWORD dwRet, dwSize; + DWORD flags = + GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER; + IP_ADAPTER_ADDRESSES* ipAdapters = NULL; + dwRet = IPHelper.pGetAdaptersAddresses(AF_INET, flags, NULL, NULL, &dwSize); + if (dwRet == ERROR_BUFFER_OVERFLOW) { - free(ipAdapters); - throw Exception(CANNOT_FIND_INTERFACES); + ipAdapters = (IP_ADAPTER_ADDRESSES*)malloc(dwSize); + if (!ipAdapters) + return; + + dwRet = IPHelper.pGetAdaptersAddresses(AF_INET, flags, NULL, ipAdapters, &dwSize); + if (dwRet != ERROR_SUCCESS) + { + free(ipAdapters); + throw Exception(CANNOT_FIND_INTERFACES); + } + processAdaptersList(ipAdapters); + free(ipAdapters); } - processAdaptersList(ipAdapters); - free(ipAdapters); - } #ifdef ICE_IPV6SUPPORT - dwRet = IPHelper.pGetAdaptersAddresses(AF_INET6, flags, NULL, NULL, &dwSize); - if (dwRet == ERROR_BUFFER_OVERFLOW) - { - ipAdapters = (IP_ADAPTER_ADDRESSES*)malloc(dwSize); - if (!ipAdapters) - return; - - dwRet = IPHelper.pGetAdaptersAddresses(AF_INET6, flags, NULL, ipAdapters, &dwSize); - if (dwRet != ERROR_SUCCESS) + dwRet = IPHelper.pGetAdaptersAddresses(AF_INET6, flags, NULL, NULL, &dwSize); + if (dwRet == ERROR_BUFFER_OVERFLOW) { - free(ipAdapters); - throw NetworkAddress(CANNOT_FIND_INTERFACES); + ipAdapters = (IP_ADAPTER_ADDRESSES*)malloc(dwSize); + if (!ipAdapters) + return; + + dwRet = IPHelper.pGetAdaptersAddresses(AF_INET6, flags, NULL, ipAdapters, &dwSize); + if (dwRet != ERROR_SUCCESS) + { + free(ipAdapters); + throw NetworkAddress(CANNOT_FIND_INTERFACES); + } + processAdaptersList(ipAdapters); + free(ipAdapters); } - processAdaptersList(ipAdapters); - free(ipAdapters); - } #endif - for (unsigned i=0; iifa_addr == nullptr) - { - current = current->ifa_next; - continue; - } - - //char ipbuffer[64]; - NetworkAddress addr; - addr.setPort(1000); // Set fake address to keep NetworkAddress initialized - bool handleIt = true; - switch(current->ifa_addr->sa_family) - { - case AF_INET: - // just for debug - // printf("%s", inet_ntoa(reinterpret_cast(current->ifa_addr)->sin_addr)); - addr.setIp(reinterpret_cast(current->ifa_addr)->sin_addr); + bool handleIt = true; + NetworkAddress ip = mIP2IndexList[i].mIP; #ifndef ICE_LOOPBACK_SUPPORT - handleIt = !addr.isLoopback(); + handleIt = !ip.isLoopback(); #endif #ifdef ICE_SKIP_LINKLOCAL - handleIt &= !addr.isLinkLocal(); + handleIt &= !ip.isLinkLocal(); #endif if (handleIt) - mIPList.push_back(addr); - break; + mInterfaceList.push_back(ip); + } +#else + mIPList.clear(); +#if TARGET_OS_IPHONE + ICELogDebug(<< "Obtaining IPv4 interfaces."); + fillIosInterfaceList(AF_INET, networkType, mIPList); + ICELogDebug(<< "Obtaining IPv6 interfaces."); + fillIosInterfaceList(AF_INET6, networkType, mIPList); + for (auto& addr : mIPList) + ICELogDebug(<< " " << addr.toStdString()); +#elif defined(WINDOWS_RT) + fillUwpInterfaceList(AF_INET, networkType, mIPList); + fillUwpInterfaceList(AF_INET6, networkType, mIPList); +#else + // https://github.com/golang/go/issues/40569 + struct ifaddrs* il = nullptr; + if (getifaddrs(&il)) + throw Exception(GETIFADDRS_FAILED, errno); + if (il) + { + struct ifaddrs* current = il; + while (current) + { + // getifaddrs() may return entries with a null ifa_addr (interfaces with + // no assigned address, point-to-point/tunnel interfaces, link-layer + // entries, ...). Dereferencing it would crash, so skip such entries. + if (current->ifa_addr == nullptr) + { + current = current->ifa_next; + continue; + } + + // char ipbuffer[64]; + NetworkAddress addr; + addr.setPort(1000); // Set fake address to keep NetworkAddress initialized + bool handleIt = true; + switch (current->ifa_addr->sa_family) + { + case AF_INET: + // just for debug + // printf("%s", inet_ntoa(reinterpret_cast(current->ifa_addr)->sin_addr)); + addr.setIp(reinterpret_cast(current->ifa_addr)->sin_addr); +#ifndef ICE_LOOPBACK_SUPPORT + handleIt = !addr.isLoopback(); +#endif +#ifdef ICE_SKIP_LINKLOCAL + handleIt &= !addr.isLinkLocal(); +#endif + if (handleIt) + mIPList.push_back(addr); + break; #ifdef ICE_IPV6SUPPORT - case AF_INET6: - addr.setIp(reinterpret_cast(current->ifa_addr)->sin6_addr); + case AF_INET6: + addr.setIp(reinterpret_cast(current->ifa_addr)->sin6_addr); #ifndef ICE_LOOPBACK_SUPPORT - if (!addr.isLoopback()) + if (!addr.isLoopback()) #endif - mIPList.push_back(addr); - break; + mIPList.push_back(addr); + break; #endif - } - current = current->ifa_next; + } + current = current->ifa_next; + } + freeifaddrs(il); } - freeifaddrs(il); - } #endif #endif } @@ -221,286 +217,280 @@ void NetworkHelper::reload(int networkType) #if defined(TARGET_WIN) && !defined(WINDOWS_RT) void NetworkHelper::processAdaptersList(IP_ADAPTER_ADDRESSES* addresses) { - IP_ADAPTER_ADDRESSES *AI; - int i; - for (i = 0, AI = addresses; AI != NULL; AI = AI->Next, i++) - { - for (PIP_ADAPTER_UNICAST_ADDRESS unicast = AI->FirstUnicastAddress; unicast; unicast = unicast->Next) + IP_ADAPTER_ADDRESSES* AI; + int i; + for (i = 0, AI = addresses; AI != NULL; AI = AI->Next, i++) { + for (PIP_ADAPTER_UNICAST_ADDRESS unicast = AI->FirstUnicastAddress; unicast; unicast = unicast->Next) + { #ifdef ICE_IPV6SUPPORT - if (unicast->Address.lpSockaddr->sa_family != AF_INET && unicast->Address.lpSockaddr->sa_family != AF_INET6) - continue; + if (unicast->Address.lpSockaddr->sa_family != AF_INET && unicast->Address.lpSockaddr->sa_family != AF_INET6) + continue; #else - if (unicast->Address.lpSockaddr->sa_family != AF_INET) - continue; + if (unicast->Address.lpSockaddr->sa_family != AF_INET) + continue; #endif - IP2Index rec; - rec.mIP = NetworkAddress(*unicast->Address.lpSockaddr, unicast->Address.iSockaddrLength); - rec.mIndex = AI->IfIndex; - mIP2IndexList.push_back(rec); + IP2Index rec; + rec.mIP = NetworkAddress(*unicast->Address.lpSockaddr, unicast->Address.iSockaddrLength); + rec.mIndex = AI->IfIndex; + mIP2IndexList.push_back(rec); + } } - } } #endif Mutex& NetworkHelper::guard() { - return mInstanceGuard; + return mInstanceGuard; } std::vector& NetworkHelper::interfaceList() { #if defined(TARGET_WIN) && !defined(WINDOWS_RT) - return mInterfaceList; + return mInterfaceList; #else - return mIPList; + return mIPList; #endif } - NetworkAddress NetworkHelper::sourceInterface(const NetworkAddress& remoteIP) { - //Lock l(mInstanceGuard); - - if (remoteIP.isLoopback()) - return remoteIP.family() == AF_INET ? NetworkAddress::LoopbackAddress4 : NetworkAddress::LoopbackAddress6; + // Lock l(mInstanceGuard); + + if (remoteIP.isLoopback()) + return remoteIP.family() == AF_INET ? NetworkAddress::LoopbackAddress4 : NetworkAddress::LoopbackAddress6; #if defined(TARGET_WIN) && !defined(WINDOWS_RT) - if (IPHelper.pGetBestInterfaceEx) - { - DWORD index = 0; - DWORD rescode = IPHelper.pGetBestInterfaceEx(remoteIP.genericsockaddr(), &index); - if (rescode == NO_ERROR) - return ipInterfaceByIndex(index); - } - else - if (IPHelper.pGetBestInterface) - { - DWORD index = 0; - DWORD rescode = IPHelper.pGetBestInterface(remoteIP.sockaddr4()->sin_addr.S_un.S_addr, &index); - if (rescode == NO_ERROR) - return ipInterfaceByIndex(index); - } - #ifdef ICE_LOOPBACK_SUPPORT - return NetworkAddress::LoopbackAddress4; - #else - return remoteIP; - #endif + if (IPHelper.pGetBestInterfaceEx) + { + DWORD index = 0; + DWORD rescode = IPHelper.pGetBestInterfaceEx(remoteIP.genericsockaddr(), &index); + if (rescode == NO_ERROR) + return ipInterfaceByIndex(index); + } + else if (IPHelper.pGetBestInterface) + { + DWORD index = 0; + DWORD rescode = IPHelper.pGetBestInterface(remoteIP.sockaddr4()->sin_addr.S_un.S_addr, &index); + if (rescode == NO_ERROR) + return ipInterfaceByIndex(index); + } +#ifdef ICE_LOOPBACK_SUPPORT + return NetworkAddress::LoopbackAddress4; +#else + return remoteIP; +#endif #elif defined(WINDOWS_RT) - std::vector& il = interfaceList(); - if (il.size()) - return il.front(); - else - return NetworkAddress(); + std::vector& il = interfaceList(); + if (il.size()) + return il.front(); + else + return NetworkAddress(); #else - if (remoteIP.isLoopback()) - return remoteIP; + if (remoteIP.isLoopback()) + return remoteIP; -/*#if defined(TARGET_OS_IPHONE) || defined(TARGET_IPHONE_SIMULATOR) - // There is only one interface - return it - std::vector& il = interfaceList(); - if (il.size()) - { - if (!il.front().isZero()) - return il.front(); - } - -#endif*/ - - // Here magic goes. - // 1) Check if remoteIP is IP4 or IP6 - // 2) Check if it is LAN or loopback or internet address - // 3) For LAN address - try to find interface from the same network - // For Loopback address - return loopback address - // For internet address - find default interface - - //printf("remote ip %s\n", remoteIP.GetIP().c_str()); - if (remoteIP.isLAN()) - { - for (unsigned i=0; i& il = interfaceList(); + if (il.size()) { - addrLen = sizeof(ipv4); - if (::getsockname(s, (sockaddr*)&ipv4, &addrLen) != -1) - result = NetworkAddress((sockaddr&)ipv4, addrLen); + if (!il.front().isZero()) + return il.front(); } - ::close(s); - } - break; -#ifdef ICE_IPV6SUPPORT - case AF_INET6: - s = ::socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); - if (s != INVALID_SOCKET) + #endif*/ + + // Here magic goes. + // 1) Check if remoteIP is IP4 or IP6 + // 2) Check if it is LAN or loopback or internet address + // 3) For LAN address - try to find interface from the same network + // For Loopback address - return loopback address + // For internet address - find default interface + + // printf("remote ip %s\n", remoteIP.GetIP().c_str()); + if (remoteIP.isLAN()) { - rescode = ::connect(s, remoteIP.genericsockaddr(), remoteIP.sockaddrLen()); - if (rescode != -1) - { - addrLen = sizeof(ipv6); - if (::getsockname(s, (sockaddr*)&ipv6, &addrLen) != -1) - result = NetworkAddress((sockaddr&)ipv6, addrLen); - } - ::close(s); + for (unsigned i = 0; i < mIPList.size(); i++) + { + // printf("local ip %s\n", mIPList[i].GetIP().c_str()); + if (NetworkAddress::isSameLAN(mIPList[i], remoteIP)) + return mIPList[i]; + } } - break; +#ifdef ICE_LOOPBACK_SUPPORT + NetworkAddress result = + remoteIP.type() == AF_INET ? NetworkAddress::LoopbackAddress4 : NetworkAddress::LoopbackAddress6; +#else + NetworkAddress result = remoteIP; #endif - default: + // Find default interface - this operation costs, so the result must be cached + SOCKET s = INVALID_SOCKET; + int rescode = 0; + sockaddr_in ipv4; +#ifdef ICE_IPV6SUPPORT + sockaddr_in6 ipv6; +#endif + socklen_t addrLen = 0; + switch (remoteIP.family()) + { + case AF_INET: + s = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (s != INVALID_SOCKET) + { + rescode = ::connect(s, remoteIP.genericsockaddr(), remoteIP.sockaddrLen()); + if (rescode != -1) + { + addrLen = sizeof(ipv4); + if (::getsockname(s, (sockaddr*)&ipv4, &addrLen) != -1) + result = NetworkAddress((sockaddr&)ipv4, addrLen); + } + ::close(s); + } + break; - assert(0); - } - - if (result.isEmpty()) - { - // Get first available interface - for (unsigned i=0; i #ifdef _WIN32 -# include -# include +#include +#include #else -# include +#include #endif -namespace ice +namespace ice { - class NetworkHelper - { - public: +class NetworkHelper +{ +public: NetworkHelper(); ~NetworkHelper(); - + enum { - NetworkType_None, - NetworkType_WiFi, - NetworkType_3G + NetworkType_None, + NetworkType_WiFi, + NetworkType_3G }; - - Mutex& guard(); - + + Mutex& guard(); + /* Returns list of IP4 interfaces installed in system. */ std::vector& interfaceList(); - - bool hasIPv4() const; - bool hasIPv6() const; - + + bool hasIPv4() const; + bool hasIPv6() const; + /* Finds source interface for specified remote address. */ - NetworkAddress sourceInterface(const NetworkAddress& remoteIP); + NetworkAddress sourceInterface(const NetworkAddress& remoteIP); - void reload(int networkType); + void reload(int networkType); - static NetworkHelper& instance(); - static void destroyInstance(); - - static void NetworkToHost(const in6_addr& addr6, uint32_t* output); - static void HostToNetwork(const uint32_t* input, in6_addr& output); - - protected: + static NetworkHelper& instance(); + static void destroyInstance(); + + static void NetworkToHost(const in6_addr& addr6, uint32_t* output); + static void HostToNetwork(const uint32_t* input, in6_addr& output); + +protected: #ifdef _WIN32 struct IP2Index { - NetworkAddress mIP; - DWORD mIndex; + NetworkAddress mIP; + DWORD mIndex; }; - std::vector mIP2IndexList; - std::vector mInterfaceList; + std::vector mIP2IndexList; + std::vector mInterfaceList; - void processAdaptersList(IP_ADAPTER_ADDRESSES* addresses); - NetworkAddress ipInterfaceByIndex(int index); + void processAdaptersList(IP_ADAPTER_ADDRESSES* addresses); + NetworkAddress ipInterfaceByIndex(int index); #else - std::vector mIPList; + std::vector mIPList; #endif - static NetworkHelper* mInstance; - static Mutex mGuard; - Mutex mInstanceGuard; - }; - + static NetworkHelper* mInstance; + static Mutex mGuard; + Mutex mInstanceGuard; }; +}; // namespace ice + #endif diff --git a/src/libs/ice/ICEPacketTimer.cpp b/src/libs/ice/ICEPacketTimer.cpp index 980be02c..f7629b6a 100644 --- a/src/libs/ice/ICEPacketTimer.cpp +++ b/src/libs/ice/ICEPacketTimer.cpp @@ -10,81 +10,81 @@ using namespace ice; PacketScheduler::PacketScheduler() { - mTimestamp = 0; - mAttemptCounter = 0; - mInitialRTO = 100; - mLastRTO = 100; + mTimestamp = 0; + mAttemptCounter = 0; + mInitialRTO = 100; + mLastRTO = 100; } void PacketScheduler::setInitialRTO(int value) { - mInitialRTO = value; + mInitialRTO = value; } -int PacketScheduler::initialRTO() +int PacketScheduler::initialRTO() { - return mInitialRTO; + return mInitialRTO; } void PacketScheduler::start() { - mLastRTO = mInitialRTO; - mAttemptCounter = 0; - mTimestamp = 0;//ICETimeHelper::timestamp(); + mLastRTO = mInitialRTO; + mAttemptCounter = 0; + mTimestamp = 0; // ICETimeHelper::timestamp(); } void PacketScheduler::stop() { - ; + ; } bool PacketScheduler::isTimeToRetransmit() { - if (!mTimestamp) - { - mTimestamp = ICETimeHelper::timestamp(); - return true; - } + if (!mTimestamp) + { + mTimestamp = ICETimeHelper::timestamp(); + return true; + } - unsigned currentTime = ICETimeHelper::timestamp(); - unsigned delta = ICETimeHelper::findDelta(mTimestamp, currentTime); - - return delta >= mLastRTO; + unsigned currentTime = ICETimeHelper::timestamp(); + unsigned delta = ICETimeHelper::findDelta(mTimestamp, currentTime); + + return delta >= mLastRTO; } - + /// Instructs timer that attempt made void PacketScheduler::attemptMade() { - // Increase attempt counter - mAttemptCounter++; + // Increase attempt counter + mAttemptCounter++; - // Save new timestamp - mTimestamp = ICETimeHelper::timestamp(); - - // Increase mLastRTO -#ifndef ICE_SIMPLE_SCHEDULE - mLastRTO *= 2; + // Save new timestamp + mTimestamp = ICETimeHelper::timestamp(); + + // Increase mLastRTO +#ifndef ICE_SIMPLE_SCHEDULE + mLastRTO *= 2; #endif } /// Checks if attempt limit reached bool PacketScheduler::isAttemptLimitReached() { - return mAttemptCounter >= ICE_TRANSACTION_RTO_LIMIT; + return mAttemptCounter >= ICE_TRANSACTION_RTO_LIMIT; } - + /// Checks if timeout happens bool PacketScheduler::isTimeout() { - // Are attempts to send finished? - if (!isAttemptLimitReached()) - return false; - - // Get current time - unsigned int currentTime = ICETimeHelper::timestamp(); - - // Get difference between current time and last send attempt - unsigned int delta = ICETimeHelper::findDelta(mTimestamp, currentTime); + // Are attempts to send finished? + if (!isAttemptLimitReached()) + return false; - return delta > mLastRTO * 16; + // Get current time + unsigned int currentTime = ICETimeHelper::timestamp(); + + // Get difference between current time and last send attempt + unsigned int delta = ICETimeHelper::findDelta(mTimestamp, currentTime); + + return delta > mLastRTO * 16; } diff --git a/src/libs/ice/ICEPacketTimer.h b/src/libs/ice/ICEPacketTimer.h index 5c2d67eb..b71e7446 100644 --- a/src/libs/ice/ICEPacketTimer.h +++ b/src/libs/ice/ICEPacketTimer.h @@ -6,38 +6,38 @@ #ifndef __ICE_PACKET_TIMER_H #define __ICE_PACKET_TIMER_H -namespace ice +namespace ice { class PacketScheduler { public: - PacketScheduler(); - ~PacketScheduler() = default; + PacketScheduler(); + ~PacketScheduler() = default; - void setInitialRTO(int value); - int initialRTO(); + void setInitialRTO(int value); + int initialRTO(); - void start(); - void stop(); - bool isTimeToRetransmit(); - - /// Instructs timer that attempt made - void attemptMade(); + void start(); + void stop(); + bool isTimeToRetransmit(); - /// Checks if attempt limit reached - bool isAttemptLimitReached(); - - /// Checks if timeout happens - bool isTimeout(); + /// Instructs timer that attempt made + void attemptMade(); + + /// Checks if attempt limit reached + bool isAttemptLimitReached(); + + /// Checks if timeout happens + bool isTimeout(); protected: - unsigned int mTimestamp; - unsigned int mAttemptCounter; - unsigned int mInitialRTO; - unsigned int mLastRTO; + unsigned int mTimestamp; + unsigned int mAttemptCounter; + unsigned int mInitialRTO; + unsigned int mLastRTO; }; -} //end of namespace +} // namespace ice #endif diff --git a/src/libs/ice/ICEPlatform.cpp b/src/libs/ice/ICEPlatform.cpp index 7f885c3f..ac1d2ffc 100644 --- a/src/libs/ice/ICEPlatform.cpp +++ b/src/libs/ice/ICEPlatform.cpp @@ -9,14 +9,14 @@ #include char* strupr(char* buffer) { - char* result = buffer; - - while (*buffer) - { - *buffer = toupper(*buffer); - buffer++; - } - - return result; + char* result = buffer; + + while (*buffer) + { + *buffer = toupper(*buffer); + buffer++; + } + + return result; } #endif diff --git a/src/libs/ice/ICEPlatform.h b/src/libs/ice/ICEPlatform.h index c4757c73..8acdf482 100644 --- a/src/libs/ice/ICEPlatform.h +++ b/src/libs/ice/ICEPlatform.h @@ -10,28 +10,28 @@ enum AddressFamily { - IPv4 = 1, - IPv6 = 2 + IPv4 = 1, + IPv6 = 2 }; #ifdef _WIN32 -# include -# include -# include -# include -# define MINVALUE(X,Y) (((X)<(Y)) ? (X) : (Y)) -# define MAXVALUE(X,Y) (((X)>(Y)) ? (X) : (Y)) +#include +#include +#include +#include +#define MINVALUE(X, Y) (((X) < (Y)) ? (X) : (Y)) +#define MAXVALUE(X, Y) (((X) > (Y)) ? (X) : (Y)) #else -# include -# include -# include -# include -# include -# include -# include -# include -# define MINVALUE(X,Y) (((X)<(Y)) ? (X) : (Y)) -# define MAXVALUE(X,Y) (((X)>(Y)) ? (X) : (Y)) +#include +#include +#include +#include +#include +#include +#include +#include +#define MINVALUE(X, Y) (((X) < (Y)) ? (X) : (Y)) +#define MAXVALUE(X, Y) (((X) > (Y)) ? (X) : (Y)) #ifndef SOCKET typedef int SOCKET; @@ -40,7 +40,7 @@ typedef int SOCKET; extern char* strupr(char*); #ifndef INVALID_SOCKET -# define INVALID_SOCKET -1 +#define INVALID_SOCKET -1 #endif #endif @@ -50,13 +50,13 @@ typedef unsigned short TurnPrefix; // Limit of candidates per SIP offer/answer -#define ICE_CANDIDATE_LIMIT 64 +#define ICE_CANDIDATE_LIMIT 64 // Limit of connection checks -#define ICE_CONNCHECK_LIMIT 100 +#define ICE_CONNCHECK_LIMIT 100 // Connection checks timer interval (in milliseconds) -#define ICE_SCHEDULE_TIMER_INTERVAL 5 +#define ICE_SCHEDULE_TIMER_INTERVAL 5 #define ICE_PERMISSIONS_REFRESH_INTERVAL 240 @@ -69,24 +69,24 @@ typedef unsigned short TurnPrefix; #define ICE_SKIP_LINKLOCAL #define ICE_SKIP_RELAYED_CHECKS -//#define ICE_IPV6_SUPPORT -//#define ICE_LOOPBACK_SUPPORT +// #define ICE_IPV6_SUPPORT +// #define ICE_LOOPBACK_SUPPORT -//#define ICE_DISABLE_KEEP +// #define ICE_DISABLE_KEEP // Makes check list shorter. Most checks are triggered in this case. #define ICE_SMART_PRUNE_CHECKLIST // Simulates symmetric NAT behavior - stack rejects all data coming not from specified STUN/TURN servers. -//#define ICE_EMULATE_SYMMETRIC_NAT +// #define ICE_EMULATE_SYMMETRIC_NAT -// Publishes more reflexive candidates than was gathered. +// Publishes more reflexive candidates than was gathered. // The virtual candidates will have port number +1 +2 +3 ... +ICE_VIRTUAL_CANDIDATES -// +// #define ICE_VIRTUAL_CANDIDATES (0) // Use simple model to schedule connectivity checks -//#define ICE_SIMPLE_SCHEDULE +// #define ICE_SIMPLE_SCHEDULE // Limit of packet retransmission during ice checks #define ICE_TRANSACTION_RTO_LIMIT (10) @@ -98,10 +98,10 @@ typedef unsigned short TurnPrefix; // #define ICE_VERYAGGRESSIVE // Define to emulate network problem -//#define ICE_TEST_VERYAGGRESSIVE +// #define ICE_TEST_VERYAGGRESSIVE -// Use this define to avoid gathering reflexive/relayed candidates for public IP address -//#define ICE_REST_ON_PUBLICIP +// Use this define to avoid gathering reflexive/relayed candidates for public IP address +// #define ICE_REST_ON_PUBLICIP // #define ICE_DONT_CANCEL_CHECKS_ON_SUCCESS diff --git a/src/libs/ice/ICERelaying.cpp b/src/libs/ice/ICERelaying.cpp index ac5b8c5a..45277a74 100644 --- a/src/libs/ice/ICERelaying.cpp +++ b/src/libs/ice/ICERelaying.cpp @@ -18,402 +18,389 @@ using namespace ice; // ------------------ ClientAllocate ----------------- ClientAllocate::ClientAllocate(unsigned int lifetime) -:AuthTransaction(), mLifetime(lifetime), mWireFamily(AF_INET), mAllocFamily(AF_INET) + : AuthTransaction(), mLifetime(lifetime), mWireFamily(AF_INET), mAllocFamily(AF_INET) { - assert(lifetime > 60 || !lifetime); - setComment("ClientAllocate"); - addLongTermCredentials(true); + assert(lifetime > 60 || !lifetime); + setComment("ClientAllocate"); + addLongTermCredentials(true); } -ClientAllocate::~ClientAllocate() -{ -} +ClientAllocate::~ClientAllocate() {} NetworkAddress& ClientAllocate::relayedAddress() { - return mRelayedAddr; + return mRelayedAddr; } NetworkAddress& ClientAllocate::reflexiveAddress() { - return mReflexiveAddr; + return mReflexiveAddr; } NetworkAddress& ClientAllocate::responseAddress() { - return mResponseAddr; + return mResponseAddr; } void ClientAllocate::setInitialRequest(StunMessage& msg) { - if (keepalive()) - { - // Build refresh request - msg.setMessageType(ice::StunMessage::Refresh); - msg.setMessageClass(StunMessage::RequestClass); - } - else - { - // Build allocate request - msg.setMessageClass(StunMessage::RequestClass); - msg.setMessageType(StunMessage::Allocate); - - // Add UDP transport attribute (RequestedTransport is UDP by default) - msg.setAttribute(new RequestedTransport()); + if (keepalive()) + { + // Build refresh request + msg.setMessageType(ice::StunMessage::Refresh); + msg.setMessageClass(StunMessage::RequestClass); + } + else + { + // Build allocate request + msg.setMessageClass(StunMessage::RequestClass); + msg.setMessageType(StunMessage::Allocate); - // Add request family attribute - if (mAllocFamily != mWireFamily) - msg.setAttribute(new RequestedAddressFamily(mAllocFamily == AF_INET ? IPv4 : IPv6)); - } + // Add UDP transport attribute (RequestedTransport is UDP by default) + msg.setAttribute(new RequestedTransport()); + + // Add request family attribute + if (mAllocFamily != mWireFamily) + msg.setAttribute(new RequestedAddressFamily(mAllocFamily == AF_INET ? IPv4 : IPv6)); + } } void ClientAllocate::setAuthenticatedRequest(StunMessage& msg) { - if (keepalive()) - { - // Build refresh request - msg.setMessageType(ice::StunMessage::Refresh); - msg.setMessageClass(StunMessage::RequestClass); - msg.lifetimeAttr().setLifetime(mLifetime); - } - else - { - msg.setMessageClass(StunMessage::RequestClass); - msg.setMessageType(StunMessage::Allocate); + if (keepalive()) + { + // Build refresh request + msg.setMessageType(ice::StunMessage::Refresh); + msg.setMessageClass(StunMessage::RequestClass); + msg.lifetimeAttr().setLifetime(mLifetime); + } + else + { + msg.setMessageClass(StunMessage::RequestClass); + msg.setMessageType(StunMessage::Allocate); - // Add UDP transport attribute - msg.setAttribute(new RequestedTransport()); + // Add UDP transport attribute + msg.setAttribute(new RequestedTransport()); - // Add LIFETIME - msg.lifetimeAttr().setLifetime(mLifetime); + // Add LIFETIME + msg.lifetimeAttr().setLifetime(mLifetime); - // Add request family attribute - if (mAllocFamily != mWireFamily) - msg.setAttribute(new RequestedAddressFamily(mAllocFamily == AF_INET ? IPv4 : IPv6)); - } + // Add request family attribute + if (mAllocFamily != mWireFamily) + msg.setAttribute(new RequestedAddressFamily(mAllocFamily == AF_INET ? IPv4 : IPv6)); + } } void ClientAllocate::processSuccessMessage(StunMessage& msg, NetworkAddress& sourceAddress) { - if (msg.hasAttribute(StunAttribute::XorMappedAddress)) - mReflexiveAddr = msg.xorMappedAddressAttr().address(); + if (msg.hasAttribute(StunAttribute::XorMappedAddress)) + mReflexiveAddr = msg.xorMappedAddressAttr().address(); - if (msg.hasAttribute(StunAttribute::XorRelayedAddress)) - mRelayedAddr = msg.xorRelayedAddressAttr().address(); + if (msg.hasAttribute(StunAttribute::XorRelayedAddress)) + mRelayedAddr = msg.xorRelayedAddressAttr().address(); - if (msg.hasAttribute(StunAttribute::Lifetime)) - mLifetime = msg.lifetimeAttr().lifetime(); + if (msg.hasAttribute(StunAttribute::Lifetime)) + mLifetime = msg.lifetimeAttr().lifetime(); - mResponseAddr = sourceAddress; - ICELogDebug(<< "Allocated for " << (int)mLifetime << " seconds."); + mResponseAddr = sourceAddress; + ICELogDebug(<< "Allocated for " << (int)mLifetime << " seconds."); } int ClientAllocate::lifetime() { - return mLifetime; + return mLifetime; } void ClientAllocate::setWireFamily(int family) { - mWireFamily = family; + mWireFamily = family; } int ClientAllocate::getWireFamily() const { - return mWireFamily; + return mWireFamily; } void ClientAllocate::setAllocFamily(int family) { - mAllocFamily = family; + mAllocFamily = family; } int ClientAllocate::getAllocFamily() const { - return mAllocFamily; + return mAllocFamily; } //------------------- ClientRefresh ------------------------------- ClientRefresh::ClientRefresh(unsigned int lifetime, Stream* stream, ClientAllocate* allocate) -:AuthTransaction(), mLifetime(lifetime), mStream(stream) + : AuthTransaction(), mLifetime(lifetime), mStream(stream) { - assert(stream); - setComment("ClientRefresh"); - addLongTermCredentials(true); - - // Copy data from Allocate transaction - if (allocate) - { - setDestination( allocate->destination() ); - setPassword( stream->mConfig.mTurnPassword ); - setUsername( stream->mConfig.mTurnUsername ); - setComponent( allocate->component() ); + assert(stream); + setComment("ClientRefresh"); + addLongTermCredentials(true); + + // Copy data from Allocate transaction + if (allocate) + { + setDestination(allocate->destination()); + setPassword(stream->mConfig.mTurnPassword); + setUsername(stream->mConfig.mTurnUsername); + setComponent(allocate->component()); #ifdef ICE_CACHE_REALM_NONCE - setRealm( allocate->realm() ); - setNonce( allocate->nonce() ); + setRealm(allocate->realm()); + setNonce(allocate->nonce()); #endif - mRelayed = allocate->relayedAddress(); - mReflexive = allocate->reflexiveAddress(); - } + mRelayed = allocate->relayedAddress(); + mReflexive = allocate->reflexiveAddress(); + } } -ClientRefresh::~ClientRefresh() -{ -} - +ClientRefresh::~ClientRefresh() {} + void ClientRefresh::setInitialRequest(StunMessage& msg) { - ICELogDebug(<< "Prepare to run ClientRefresh on TURN server with lifetime " << mLifetime); - msg.setMessageType(ice::StunMessage::Refresh); - msg.setMessageClass(ice::StunMessage::RequestClass); + ICELogDebug(<< "Prepare to run ClientRefresh on TURN server with lifetime " << mLifetime); + msg.setMessageType(ice::StunMessage::Refresh); + msg.setMessageClass(ice::StunMessage::RequestClass); } void ClientRefresh::setAuthenticatedRequest(StunMessage& msg) { - msg.setMessageType(StunMessage::Refresh); - msg.setMessageClass(StunMessage::RequestClass); - msg.lifetimeAttr().setLifetime(mLifetime); + msg.setMessageType(StunMessage::Refresh); + msg.setMessageClass(StunMessage::RequestClass); + msg.lifetimeAttr().setLifetime(mLifetime); } void ClientRefresh::processSuccessMessage(StunMessage& /*msg*/, NetworkAddress& /*sourceAddress*/) { - if (mLifetime) - { - ICELogDebug(<< "TURN allocation refreshed for " << (int)mLifetime << " seconds."); - } - else - { - if (mStream) + if (mLifetime) { - if (mStream->mTurnAllocated > 0) - mStream->mTurnAllocated--; + ICELogDebug(<< "TURN allocation refreshed for " << (int)mLifetime << " seconds."); + } + else + { + if (mStream) + { + if (mStream->mTurnAllocated > 0) + mStream->mTurnAllocated--; + } + ICELogDebug(<< "TURN allocation is deleted."); } - ICELogDebug(<< "TURN allocation is deleted."); - } } void ClientRefresh::processError() { - if (mStream) - { - if (!mLifetime) + if (mStream) { - if (mStream->mTurnAllocated > 0) - mStream->mTurnAllocated--; - ICELogError(<< "TURN allocation is not deleted due to error " << errorCode() << " " << errorResponse()); + if (!mLifetime) + { + if (mStream->mTurnAllocated > 0) + mStream->mTurnAllocated--; + ICELogError(<< "TURN allocation is not deleted due to error " << errorCode() << " " << errorResponse()); + } + else + ICELogError(<< "ClientRefresh failed due to error " << errorCode() << " " << errorResponse()); } - else - ICELogError(<< "ClientRefresh failed due to error " << errorCode() << " " << errorResponse()); - } } NetworkAddress ClientRefresh::relayedAddress() { - return mRelayed; + return mRelayed; } NetworkAddress ClientRefresh::reflexiveAddress() { - return mReflexive; + return mReflexive; } //------------------- ClientChannelBind ---------------------------- static TurnPrefix GPrefix = 0; -static Mutex GPrefixGuard; +static Mutex GPrefixGuard; static TurnPrefix obtainNewPrefix() { - Lock l(GPrefixGuard); - - // Generate initial value if needed - if (!GPrefix) - GPrefix = (rand() % (0x7FFE - 0x4000)) + 0x4000; - - // Avoid logical overflow - if (GPrefix == 0x7FFE) - GPrefix = 0x4000; + Lock l(GPrefixGuard); - return ++GPrefix; + // Generate initial value if needed + if (!GPrefix) + GPrefix = (rand() % (0x7FFE - 0x4000)) + 0x4000; + + // Avoid logical overflow + if (GPrefix == 0x7FFE) + GPrefix = 0x4000; + + return ++GPrefix; } -ClientChannelBind::ClientChannelBind(const NetworkAddress& address) -:AuthTransaction(), mPeerAddress(address) +ClientChannelBind::ClientChannelBind(const NetworkAddress& address) : AuthTransaction(), mPeerAddress(address) { - setComment( "ClientChannelBind" ); - // Compute prefix - mChannelPrefix = obtainNewPrefix(); - ICELogInfo(<< "Channel prefix for TURN channel bind is " << mChannelPrefix); - addLongTermCredentials(true); + setComment("ClientChannelBind"); + // Compute prefix + mChannelPrefix = obtainNewPrefix(); + ICELogInfo(<< "Channel prefix for TURN channel bind is " << mChannelPrefix); + addLongTermCredentials(true); } -ClientChannelBind::~ClientChannelBind() -{ -} +ClientChannelBind::~ClientChannelBind() {} void ClientChannelBind::setInitialRequest(StunMessage& msg) { - msg.setMessageClass(StunMessage::RequestClass); - msg.setMessageType(StunMessage::ChannelBind); - - msg.channelNumberAttr().setChannelNumber(mChannelPrefix); - msg.xorPeerAddressAttr().address() = mPeerAddress; + msg.setMessageClass(StunMessage::RequestClass); + msg.setMessageType(StunMessage::ChannelBind); + + msg.channelNumberAttr().setChannelNumber(mChannelPrefix); + msg.xorPeerAddressAttr().address() = mPeerAddress; } void ClientChannelBind::setAuthenticatedRequest(StunMessage& msg) { - setInitialRequest(msg); + setInitialRequest(msg); } unsigned short ClientChannelBind::channelPrefix() { - return mChannelPrefix; + return mChannelPrefix; } bool ClientChannelBind::processData(StunMessage& msg, NetworkAddress& address) { - return AuthTransaction::processData(msg, address); + return AuthTransaction::processData(msg, address); } void ClientChannelBind::processSuccessMessage(StunMessage& msg, NetworkAddress& sourceAddress) { - ICELogDebug(<< mPeerAddress.toStdString() << " is bound to " << mChannelPrefix); - // Make this transaction keepalive - setKeepalive( true ); - setType( KeepAlive ); - setInterval( ICE_PERMISSIONS_REFRESH_INTERVAL ); - setTimestamp( ICETimeHelper::timestamp() ); + ICELogDebug(<< mPeerAddress.toStdString() << " is bound to " << mChannelPrefix); + // Make this transaction keepalive + setKeepalive(true); + setType(KeepAlive); + setInterval(ICE_PERMISSIONS_REFRESH_INTERVAL); + setTimestamp(ICETimeHelper::timestamp()); } void ClientChannelBind::processError() { - ICELogCritical(<< "Failed to bind channel with error " << errorCode()); + ICELogCritical(<< "Failed to bind channel with error " << errorCode()); } NetworkAddress ClientChannelBind::peerAddress() { - return mPeerAddress; + return mPeerAddress; } //----------------- ClientCreatePermission ------------------------ -ClientCreatePermission::ClientCreatePermission() -:AuthTransaction() +ClientCreatePermission::ClientCreatePermission() : AuthTransaction() { - setComment("ClientCreatePermission"); - addLongTermCredentials(true); + setComment("ClientCreatePermission"); + addLongTermCredentials(true); } ClientCreatePermission::~ClientCreatePermission() { - ; + ; } void ClientCreatePermission::addIpAddress(const NetworkAddress& ip) { - // Skip loopback / empty / LAN / IPv6 addresses addresses - if (!ip.isLoopback() && !ip.isEmpty() && !ip.isLAN() && ip.family() == AF_INET) - { - for (unsigned i=0; iaddress() = mIPAddressList[i]; - msg.addAttribute(xpa); - } + msg.setMessageClass(StunMessage::RequestClass); + msg.setMessageType(StunMessage::CreatePermission); + + for (unsigned i = 0; i < mIPAddressList.size(); i++) + { + XorPeerAddress* xpa = new XorPeerAddress(); + xpa->address() = mIPAddressList[i]; + msg.addAttribute(xpa); + } } -void -ClientCreatePermission::setAuthenticatedRequest(StunMessage& msg) +void ClientCreatePermission::setAuthenticatedRequest(StunMessage& msg) { - setInitialRequest(msg); + setInitialRequest(msg); } ClientCreatePermission::IpList& ClientCreatePermission::ipList() { - return mIPAddressList; + return mIPAddressList; } // ------------------ SendIndication ---------------------------------- -SendIndication::SendIndication() -{ -} +SendIndication::SendIndication() {} + +SendIndication::~SendIndication() {} -SendIndication::~SendIndication() -{ -} - void SendIndication::setTarget(NetworkAddress& addr) { - mTarget = addr; + mTarget = addr; } NetworkAddress& SendIndication::target() { - return mTarget; + return mTarget; } void SendIndication::setPlainData(ByteBuffer& plain) { - mPlainData = plain; + mPlainData = plain; } ByteBuffer& SendIndication::plainData() { - return mPlainData; + return mPlainData; } ByteBuffer* SendIndication::buildPacket() { - StunMessage m; - m.setMessageClass(StunMessage::IndicationClass); - m.setMessageType(StunMessage::Send); + StunMessage m; + m.setMessageClass(StunMessage::IndicationClass); + m.setMessageType(StunMessage::Send); - XorPeerAddress* xpa = new XorPeerAddress(); - xpa->address() = mTarget; + XorPeerAddress* xpa = new XorPeerAddress(); + xpa->address() = mTarget; - DataAttribute* da = new DataAttribute(); - da->setData(mPlainData); + DataAttribute* da = new DataAttribute(); + da->setData(mPlainData); - m.setAttribute(xpa); - m.setAttribute(da); + m.setAttribute(xpa); + m.setAttribute(da); - ByteBuffer* result = new ByteBuffer(); - m.buildPacket(*result, ""); - - return result; + ByteBuffer* result = new ByteBuffer(); + m.buildPacket(*result, ""); + + return result; } ByteBuffer* SendIndication::buildPacket(NetworkAddress& target, ByteBuffer& data, NetworkAddress& relay, int component) { - SendIndication si; - si.setTarget( target ); - si.setPlainData( data ); - - ByteBuffer* result = si.buildPacket(); - result->setComponent( component ); - result->setRemoteAddress( relay ); + SendIndication si; + si.setTarget(target); + si.setPlainData(data); - return result; + ByteBuffer* result = si.buildPacket(); + result->setComponent(component); + result->setRemoteAddress(relay); + + return result; } diff --git a/src/libs/ice/ICERelaying.h b/src/libs/ice/ICERelaying.h index 061b2018..e5afc7af 100644 --- a/src/libs/ice/ICERelaying.h +++ b/src/libs/ice/ICERelaying.h @@ -13,124 +13,124 @@ namespace ice { - const int ChannelBindTimeout = 10 * 60 * 1000; - const int PermissionTimeout = 5 * 60 * 1000; +const int ChannelBindTimeout = 10 * 60 * 1000; +const int PermissionTimeout = 5 * 60 * 1000; - // This class encapsulates TURN Allocate transaction - // Usage: create instance, set password and login, generate data. - // pass incoming data while GetState() != StunTransaction::Failed or Success - - class ClientAllocate: public AuthTransaction - { - public: +// This class encapsulates TURN Allocate transaction +// Usage: create instance, set password and login, generate data. +// pass incoming data while GetState() != StunTransaction::Failed or Success + +class ClientAllocate : public AuthTransaction +{ +public: ClientAllocate(unsigned int lifetime); virtual ~ClientAllocate(); - - NetworkAddress& relayedAddress(); - NetworkAddress& reflexiveAddress(); - NetworkAddress& responseAddress(); + + NetworkAddress& relayedAddress(); + NetworkAddress& reflexiveAddress(); + NetworkAddress& responseAddress(); int lifetime(); void setWireFamily(int family); int getWireFamily() const; void setAllocFamily(int family); int getAllocFamily() const; - + virtual void setInitialRequest(StunMessage& msg); virtual void setAuthenticatedRequest(StunMessage& msg); virtual void processSuccessMessage(StunMessage& msg, NetworkAddress& sourceAddress); - - protected: - NetworkAddress mRelayedAddr; - NetworkAddress mReflexiveAddr; - NetworkAddress mResponseAddr; - unsigned int mLifetime; - int mWireFamily; - int mAllocFamily; - }; - class ClientChannelBind: public AuthTransaction - { - public: +protected: + NetworkAddress mRelayedAddr; + NetworkAddress mReflexiveAddr; + NetworkAddress mResponseAddr; + unsigned int mLifetime; + int mWireFamily; + int mAllocFamily; +}; + +class ClientChannelBind : public AuthTransaction +{ +public: ClientChannelBind(const NetworkAddress& peerAddress); virtual ~ClientChannelBind(); /*Channel prefix must be 0x4000 through 0x7FFF: These values are the allowed channel numbers (16,383 possible values) */ - unsigned short channelPrefix(); - - void setInitialRequest(StunMessage& msg); - void setAuthenticatedRequest(StunMessage& msg); - void processSuccessMessage(StunMessage& msg, NetworkAddress& sourceAddress); - bool processData(StunMessage& msg, NetworkAddress& address); - void processError(); + unsigned short channelPrefix(); + + void setInitialRequest(StunMessage& msg); + void setAuthenticatedRequest(StunMessage& msg); + void processSuccessMessage(StunMessage& msg, NetworkAddress& sourceAddress); + bool processData(StunMessage& msg, NetworkAddress& address); + void processError(); NetworkAddress peerAddress(); - protected: - unsigned short mChannelPrefix; - NetworkAddress mPeerAddress; - }; +protected: + unsigned short mChannelPrefix; + NetworkAddress mPeerAddress; +}; - class ClientCreatePermission: public AuthTransaction - { - public: +class ClientCreatePermission : public AuthTransaction +{ +public: typedef std::vector IpList; ClientCreatePermission(); virtual ~ClientCreatePermission(); - - void addIpAddress(const NetworkAddress& ip); - virtual void setInitialRequest(StunMessage& msg); - virtual void setAuthenticatedRequest(StunMessage& msg); - virtual void processSuccessMessage(StunMessage& msg, NetworkAddress& sourceAddress); + void addIpAddress(const NetworkAddress& ip); - IpList& ipList(); + virtual void setInitialRequest(StunMessage& msg); + virtual void setAuthenticatedRequest(StunMessage& msg); + virtual void processSuccessMessage(StunMessage& msg, NetworkAddress& sourceAddress); - protected: + IpList& ipList(); + +protected: IpList mIPAddressList; - }; - - struct Stream; - class ClientRefresh: public AuthTransaction - { - public: +}; + +struct Stream; +class ClientRefresh : public AuthTransaction +{ +public: ClientRefresh(unsigned int lifetime, Stream* stream, ClientAllocate* allocate = NULL); virtual ~ClientRefresh(); - - virtual void setInitialRequest(StunMessage& msg); - virtual void setAuthenticatedRequest(StunMessage& msg); - virtual void processSuccessMessage(StunMessage& msg, NetworkAddress& sourceAddress); - virtual void processError(); - unsigned int lifetime() { return mLifetime; } - NetworkAddress relayedAddress(); - NetworkAddress reflexiveAddress(); - - protected: - unsigned int mLifetime; - Stream* mStream; - NetworkAddress mRelayed, mReflexive; - }; - - class SendIndication - { - public: + + virtual void setInitialRequest(StunMessage& msg); + virtual void setAuthenticatedRequest(StunMessage& msg); + virtual void processSuccessMessage(StunMessage& msg, NetworkAddress& sourceAddress); + virtual void processError(); + unsigned int lifetime() { return mLifetime; } + NetworkAddress relayedAddress(); + NetworkAddress reflexiveAddress(); + +protected: + unsigned int mLifetime; + Stream* mStream; + NetworkAddress mRelayed, mReflexive; +}; + +class SendIndication +{ +public: SendIndication(); ~SendIndication(); - - void setTarget(NetworkAddress& addr); - NetworkAddress& target(); - void setPlainData(ByteBuffer& plain); - ByteBuffer& plainData(); - ByteBuffer* buildPacket(); + void setTarget(NetworkAddress& addr); + NetworkAddress& target(); + void setPlainData(ByteBuffer& plain); + ByteBuffer& plainData(); + + ByteBuffer* buildPacket(); static ByteBuffer* buildPacket(NetworkAddress& target, ByteBuffer& data, NetworkAddress& relay, int component); - protected: +protected: NetworkAddress mTarget; - ByteBuffer mPlainData; - }; + ByteBuffer mPlainData; +}; -} +} // namespace ice #endif \ No newline at end of file diff --git a/src/libs/ice/ICEReliableTransport.cpp b/src/libs/ice/ICEReliableTransport.cpp index 752e6ef0..8e4fc47a 100644 --- a/src/libs/ice/ICEReliableTransport.cpp +++ b/src/libs/ice/ICEReliableTransport.cpp @@ -11,436 +11,418 @@ using namespace ICEImpl; //------------------- ReliableTransport::Packet -------------------------- ReliableTransport::Packet::Packet() { - mType = AppData; - mSeqno = 0; - mAppSeqno = 0; + mType = AppData; + mSeqno = 0; + mAppSeqno = 0; } -ReliableTransport::Packet::~Packet() +ReliableTransport::Packet::~Packet() {} + +bool ReliableTransport::Packet::parse(const void* dataptr, int datasize, Encryption* encryption) { + assert(encryption != NULL); + assert(dataptr != NULL); + assert(datasize != 0); + + // 1) Check if packet has mEncryption->GetBlockSize() bytes boundary + if (datasize % encryption->blockSize()) + return false; + + // 2) Save data + mData.enqueueBuffer(dataptr, datasize); + + // 2) Decrypt it using mEncryption provider + encryption->decrypt(mData.mutableData(), mData.size()); + + // 3) Check CRC from first 4 bytes (it is for little endian only) + unsigned crc = mData.dequeueUInt(); + if (crc != encryption->crc(mData.data(), mData.size())) + return false; + + // 4) Check next byte for signature + unsigned char signature = mData.dequeueUChar(); + if (signature != RTSignature) + return false; + + // 5) Next 2 bits are type of packet - AppData, Confirmation, Request or Ack + unsigned short ts = mData.dequeueUShort(); + + mType = (Packet::Type)((ts & 0xC000) >> 14); + + // 6) Next 14 bits are real size of packet + unsigned short realsize = ts & 0x3FFF; + + // 7) Seqno + mSeqno = mData.dequeueUShort(); + + // 7) Check if we deal with AppData + if (mType == AppData) + mAppSeqno = mData.dequeueUShort(); + + // 8) Truncate app data to real size + mData.truncate(realsize); + return true; } -bool -ReliableTransport::Packet::parse(const void* dataptr, int datasize, Encryption* encryption) +void ReliableTransport::Packet::build(const void* dataptr, int datasize, Encryption* encryption) { - assert(encryption != NULL); - assert(dataptr != NULL); - assert(datasize != 0); + assert(encryption && dataptr && datasize); - // 1) Check if packet has mEncryption->GetBlockSize() bytes boundary - if (datasize % encryption->blockSize()) - return false; - - // 2) Save data - mData.enqueueBuffer(dataptr, datasize); + mData.clear(); - // 2) Decrypt it using mEncryption provider - encryption->decrypt(mData.mutableData(), mData.size()); + // Reserve place for CRC + mData.enqueueUInt(0); - // 3) Check CRC from first 4 bytes (it is for little endian only) - unsigned crc = mData.dequeueUInt(); - if (crc != encryption->crc(mData.data(), mData.size())) - return false; + // Signature + mData.enqueueUChar(RTSignature); - // 4) Check next byte for signature - unsigned char signature = mData.dequeueUChar(); - if (signature != RTSignature) - return false; + // Real size and type of packet + unsigned short ts = (unsigned short)datasize; + ts |= mType << 14; - // 5) Next 2 bits are type of packet - AppData, Confirmation, Request or Ack - unsigned short ts = mData.dequeueUShort(); - - mType = (Packet::Type)((ts & 0xC000) >> 14); - - // 6) Next 14 bits are real size of packet - unsigned short realsize = ts & 0x3FFF; + // Enqueue real size and type of packet + mData.enqueueUShort(ts); - // 7) Seqno - mSeqno = mData.dequeueUShort(); + // Enqueue sequence number + mData.enqueueUShort(mSeqno); - // 7) Check if we deal with AppData - if (mType == AppData) - mAppSeqno = mData.dequeueUShort(); - - // 8) Truncate app data to real size - mData.truncate(realsize); - return true; -} + // Enqueue application sequence number if needed + if (mType == Packet::AppData) + mData.enqueueUShort(mAppSeqno); -void -ReliableTransport::Packet::build(const void* dataptr, int datasize, Encryption* encryption) -{ - assert(encryption && dataptr && datasize); + // Enqueue payload data + mData.enqueueBuffer(dataptr, datasize); - mData.clear(); + // Padding with zero bytes + int tail = mData.size() % encryption->blockSize(); + if (tail) + { + for (int i = 0; i < encryption->blockSize() - tail; i++) + mData.enqueueUChar(0); + } - // Reserve place for CRC - mData.enqueueUInt(0); - - // Signature - mData.enqueueUChar(RTSignature); + // Get CRC on packet + unsigned crc = encryption->crc((const char*)mData.data() + 4, mData.size() - 4); - // Real size and type of packet - unsigned short ts = (unsigned short)datasize; - ts |= mType << 14; + crc = htonl(crc); // It is here as corresponding DequeueUInt does ntohl + memcpy(mData.mutableData(), &crc, 4); - // Enqueue real size and type of packet - mData.enqueueUShort(ts); - - // Enqueue sequence number - mData.enqueueUShort(mSeqno); - - // Enqueue application sequence number if needed - if (mType == Packet::AppData) - mData.enqueueUShort(mAppSeqno); - - // Enqueue payload data - mData.enqueueBuffer(dataptr, datasize); - - // Padding with zero bytes - int tail = mData.size() % encryption->blockSize(); - if (tail) - { - for (int i=0; i < encryption->blockSize() - tail; i++) - mData.enqueueUChar(0); - } - - // Get CRC on packet - unsigned crc = encryption->crc((const char*)mData.data() + 4, mData.size() - 4); - - crc = htonl(crc); //It is here as corresponding DequeueUInt does ntohl - memcpy(mData.mutableData(), &crc, 4); - - // Encrypt - encryption->encrypt(mData.mutableData(), mData.size()); + // Encrypt + encryption->encrypt(mData.mutableData(), mData.size()); } void ReliableTransport::Packet::setType(Type packetType) { - mType = packetType; + mType = packetType; } -ReliableTransport::Packet::Type ReliableTransport::Packet::type() +ReliableTransport::Packet::Type ReliableTransport::Packet::type() { - return mType; + return mType; } void ReliableTransport::Packet::setSeqno(unsigned short seqno) { - mSeqno = seqno; + mSeqno = seqno; } unsigned short ReliableTransport::Packet::seqno() { - return mSeqno; + return mSeqno; } void ReliableTransport::Packet::setAppSeqno(unsigned short seqno) { - mAppSeqno = seqno; + mAppSeqno = seqno; } unsigned short ReliableTransport::Packet::appSeqno() { - return mAppSeqno; + return mAppSeqno; } ICEByteBuffer& ReliableTransport::Packet::data() { - return mData; + return mData; } //-------------------- ReliableTransport -------------------- ReliableTransport::ReliableTransport() { - mEncryption = NULL; - mSeqno = 0; + mEncryption = NULL; + mSeqno = 0; } -ReliableTransport::~ReliableTransport() -{ -} +ReliableTransport::~ReliableTransport() {} void ReliableTransport::setMaxDatagram(int size) { - mMaxDatagramSize = size; + mMaxDatagramSize = size; } int ReliableTransport::maxDatagram() { - return mMaxDatagramSize; + return mMaxDatagramSize; } bool ReliableTransport::processIncoming(const void* dataptr, int datasize) { - Packet* p = new Packet(); - if (p->parse(dataptr, datasize, mEncryption)) - { - switch (p->type()) + Packet* p = new Packet(); + if (p->parse(dataptr, datasize, mEncryption)) { - case Packet::AppData: - processAppData(p); - break; + switch (p->type()) + { + case Packet::AppData: + processAppData(p); + break; - case Packet::Confirmation: - processConfirmation(p); - break; + case Packet::Confirmation: + processConfirmation(p); + break; - case Packet::Ack: - processAck(p); - break; + case Packet::Ack: + processAck(p); + break; - case Packet::Request: - processRequest(p); - break; + case Packet::Request: + processRequest(p); + break; + } + + return true; } - - return true; - } - else - { + else + { + delete p; + return false; + } +} + +void ReliableTransport::queueOutgoing(const void* dataPtr, int dataSize) +{ + // Split enqueued data to datagrams using mMaxDatagramSize value. + // Do not forget about service bytes - seqno, appseqno, CRC, signature... + int payloadsize = this->mMaxDatagramSize - (2 /*CRC*/ + 1 /* signature */ + 2 /* type and size */); + + // Find packet count + int packetcount = dataSize / payloadsize; + if (dataSize % payloadsize) + packetcount++; + + // Case input pointer + const char* dataIn = (const char*)dataPtr; + + // Split data to packets + for (int i = 0; i < packetcount; i++) + { + Packet* p = new Packet(); + p->setSeqno(mSeqno++); + p->setAppSeqno(i); + if (i == packetcount - 1 && dataSize % payloadsize) + p->build(dataIn + i * payloadsize, dataSize % payloadsize, mEncryption); + else + p->build(dataIn + i * payloadsize, payloadsize, mEncryption); + + mOutgoingData.push_back(p); + } +} + +void ReliableTransport::processAck(Packet* p) +{ + // Ack received for confirmation + int count = p->data().dequeueUShort(); + for (int i = 0; i < count; i++) + { + // Extract Confirmation packet seqno + int seqno = p->data().dequeueUShort(); + + // Find corresponding confirmation packet and remove it + removePacket(seqno); + } + delete p; - return false; - } } -void -ReliableTransport::queueOutgoing(const void *dataPtr, int dataSize) +void ReliableTransport::processConfirmation(Packet* p) { - // Split enqueued data to datagrams using mMaxDatagramSize value. - // Do not forget about service bytes - seqno, appseqno, CRC, signature... - int payloadsize = this->mMaxDatagramSize - (2 /*CRC*/ + 1 /* signature */ + 2 /* type and size */); - - // Find packet count - int packetcount = dataSize / payloadsize; - if (dataSize % payloadsize) - packetcount++; - - // Case input pointer - const char* dataIn = (const char*)dataPtr; - - // Split data to packets - for (int i=0; isetSeqno(mSeqno++); - p->setAppSeqno(i); - if (i == packetcount-1 && dataSize % payloadsize) - p->build(dataIn + i * payloadsize, dataSize % payloadsize, mEncryption); - else - p->build(dataIn + i * payloadsize, payloadsize, mEncryption); - - mOutgoingData.push_back(p); - } -} - -void -ReliableTransport::processAck(Packet* p) -{ - // Ack received for confirmation - int count = p->data().dequeueUShort(); - for (int i=0; idata().dequeueUShort(); - - // Find corresponding confirmation packet and remove it - removePacket(seqno); - } - - delete p; -} - -void -ReliableTransport::processConfirmation(Packet* p) -{ - int count = p->data().dequeueUShort(); - for (int i=0; idata().dequeueUShort(); - - // Find corresponding AppData packet and remove it - removePacket(seqno); - } - - // Create Ack packet - mOutgoingData.push_back(makeAckPacket(p->seqno())); - - delete p; -} - -void -ReliableTransport::processRequest(Packet* p) -{ - int count = p->data().dequeueUShort(); - for (int i=0; idata().dequeueUShort(); - - // Find specified by seqno packet and move to top of list - prioritizePacket(seqno); - } - - delete p; -} - -void -ReliableTransport::processAppData(Packet* p) -{ - // 1) Add seqno to confirmation list - mConfirmationData.push_back(p->seqno()); - - // 2) Check if confirmation list if big enough to transmit confirmation packet - if (mConfirmationData.size() >= (unsigned)MaxConfirmationQueue) - { - mOutgoingData.push_back(makeConfirmationPacket(mConfirmationData)); - mConfirmationData.clear(); - } - - // 3) Move packet to mIncomingAppData with optional packet assembling - mIncomingAppData.push_back(p); -} - -void -ReliableTransport::removePacket(Packet::Seqno seqno) -{ - PacketList::iterator pit = mOutgoingData.begin(); - while (pit != mOutgoingData.end()) - { - Packet* p = *pit; - - if (p->seqno() == seqno) + int count = p->data().dequeueUShort(); + for (int i = 0; i < count; i++) { - pit = mOutgoingData.erase(pit); - delete p; + // Extract AppData packet seqno + int seqno = p->data().dequeueUShort(); + + // Find corresponding AppData packet and remove it + removePacket(seqno); } - else - pit++; - } + + // Create Ack packet + mOutgoingData.push_back(makeAckPacket(p->seqno())); + + delete p; } -void -ReliableTransport::prioritizePacket(Packet::Seqno seqno) +void ReliableTransport::processRequest(Packet* p) { - PacketList::iterator pit = mOutgoingData.begin(); - while (pit != mOutgoingData.end()) - { - Packet* p = *pit; - - if (p->seqno() == seqno) + int count = p->data().dequeueUShort(); + for (int i = 0; i < count; i++) { - // Remove pointer from old index - pit = mOutgoingData.erase(pit); + // Extract AppData packet seqno + int seqno = p->data().dequeueUShort(); - // Insert at beginning of queue - mOutgoingData.insert(mOutgoingData.begin(), p); - - // Exit from loop - break; + // Find specified by seqno packet and move to top of list + prioritizePacket(seqno); } - else - pit++; - } + + delete p; } -ReliableTransport::Packet* -ReliableTransport::makeAckPacket(Packet::Seqno seqno) +void ReliableTransport::processAppData(Packet* p) { - // Create packet - Packet* p = new Packet(); - - // Set type - p->setType(Packet::Ack); - - // Convert seqno number to network byte order - unsigned short value = htons(seqno); + // 1) Add seqno to confirmation list + mConfirmationData.push_back(p->seqno()); - // Build packet - p->build(&value, sizeof(value), mEncryption); + // 2) Check if confirmation list if big enough to transmit confirmation packet + if (mConfirmationData.size() >= (unsigned)MaxConfirmationQueue) + { + mOutgoingData.push_back(makeConfirmationPacket(mConfirmationData)); + mConfirmationData.clear(); + } - // Return packet - return p; + // 3) Move packet to mIncomingAppData with optional packet assembling + mIncomingAppData.push_back(p); } -ReliableTransport::Packet* -ReliableTransport::makeConfirmationPacket(std::vector seqnovector) +void ReliableTransport::removePacket(Packet::Seqno seqno) { - // Convert seqno values to network byte order - std::vector value; - for (unsigned i=0; isetType(Packet::Ack); - - // Build packet - p->build(&value[0], value.size() * sizeof(Packet::Seqno), mEncryption); - - // Return packet - return p; + if (p->seqno() == seqno) + { + pit = mOutgoingData.erase(pit); + delete p; + } + else + pit++; + } } - -bool -ReliableTransport::hasAppData() +void ReliableTransport::prioritizePacket(Packet::Seqno seqno) { - return !mIncomingAppData.empty(); + PacketList::iterator pit = mOutgoingData.begin(); + while (pit != mOutgoingData.end()) + { + Packet* p = *pit; + + if (p->seqno() == seqno) + { + // Remove pointer from old index + pit = mOutgoingData.erase(pit); + + // Insert at beginning of queue + mOutgoingData.insert(mOutgoingData.begin(), p); + + // Exit from loop + break; + } + else + pit++; + } +} + +ReliableTransport::Packet* ReliableTransport::makeAckPacket(Packet::Seqno seqno) +{ + // Create packet + Packet* p = new Packet(); + + // Set type + p->setType(Packet::Ack); + + // Convert seqno number to network byte order + unsigned short value = htons(seqno); + + // Build packet + p->build(&value, sizeof(value), mEncryption); + + // Return packet + return p; +} + +ReliableTransport::Packet* ReliableTransport::makeConfirmationPacket(std::vector seqnovector) +{ + // Convert seqno values to network byte order + std::vector value; + for (unsigned i = 0; i < seqnovector.size(); i++) + value.push_back(htons(seqnovector[i])); + + // Create packet + Packet* p = new Packet(); + + // Set type + p->setType(Packet::Ack); + + // Build packet + p->build(&value[0], value.size() * sizeof(Packet::Seqno), mEncryption); + + // Return packet + return p; +} + + +bool ReliableTransport::hasAppData() +{ + return !mIncomingAppData.empty(); } unsigned ReliableTransport::appData(void* ptr) { - if (mIncomingAppData.empty()) - return 0; - - Packet& p = *mIncomingAppData.front(); - unsigned length = p.data().size(); - if (!ptr) + if (mIncomingAppData.empty()) + return 0; + + Packet& p = *mIncomingAppData.front(); + unsigned length = p.data().size(); + if (!ptr) + return length; + + memcpy(ptr, p.data().data(), length); + mIncomingAppData.erase(mIncomingAppData.begin()); return length; - - memcpy(ptr, p.data().data(), length); - mIncomingAppData.erase(mIncomingAppData.begin()); - return length; } -bool -ReliableTransport::hasPacketToSend() +bool ReliableTransport::hasPacketToSend() { - return !mOutgoingData.empty(); + return !mOutgoingData.empty(); } -void -ReliableTransport::getPacketToSend(void* outputptr, int& outputsize) +void ReliableTransport::getPacketToSend(void* outputptr, int& outputsize) { - if (mOutgoingData.empty()) - { - outputsize = 0; - } - else - { - if (!outputptr) + if (mOutgoingData.empty()) { - outputsize = mOutgoingData.front()->data().size(); + outputsize = 0; } else { - Packet& p = *mOutgoingData.front(); + if (!outputptr) + { + outputsize = mOutgoingData.front()->data().size(); + } + else + { + Packet& p = *mOutgoingData.front(); - unsigned tocopy = MINVALUE((int)outputsize, (int)p.data().size()); - memcpy(outputptr, p.data().data(), p.data().size()); - outputsize = tocopy; + unsigned tocopy = MINVALUE((int)outputsize, (int)p.data().size()); + memcpy(outputptr, p.data().data(), p.data().size()); + outputsize = tocopy; - mOutgoingData.erase(mOutgoingData.begin()); + mOutgoingData.erase(mOutgoingData.begin()); + } } - } } -void ReliableTransport::setEncryption(ICEImpl::ReliableTransport::Encryption *encryption) +void ReliableTransport::setEncryption(ICEImpl::ReliableTransport::Encryption* encryption) { - mEncryption = encryption; + mEncryption = encryption; } diff --git a/src/libs/ice/ICEReliableTransport.h b/src/libs/ice/ICEReliableTransport.h index bd1fdbf0..f558196b 100644 --- a/src/libs/ice/ICEReliableTransport.h +++ b/src/libs/ice/ICEReliableTransport.h @@ -13,28 +13,29 @@ #include "ICEByteBuffer.h" -namespace ICEImpl { +namespace ICEImpl +{ - // ReliableTransport is protocol stack to provide reliable transport over UDP protocol. It remains packet based protocol, not stream. - // But it guarantees integrity and order of packets. - class ReliableTransport - { - public: +// ReliableTransport is protocol stack to provide reliable transport over UDP protocol. It remains packet based +// protocol, not stream. But it guarantees integrity and order of packets. +class ReliableTransport +{ +public: // ReliableTransport encryption interface class Encryption { public: - // Returns block size for encryption algorythm - virtual int blockSize() = 0; - - // Encrypts dataPtr buffer inplace. dataSize must be odd to GetBlockSize() returned value. - virtual void encrypt(void* dataPtr, int dataSize) = 0; + // Returns block size for encryption algorythm + virtual int blockSize() = 0; - // Decrypts dataPtr buffer inplace. dataSize must be odd to GetBlockSize() returned value. - virtual void decrypt(void* dataPtr, int dataSize) = 0; + // Encrypts dataPtr buffer inplace. dataSize must be odd to GetBlockSize() returned value. + virtual void encrypt(void* dataPtr, int dataSize) = 0; - // Calculates CRC - virtual unsigned crc(const void* dataptr, int datasize) = 0; + // Decrypts dataPtr buffer inplace. dataSize must be odd to GetBlockSize() returned value. + virtual void decrypt(void* dataPtr, int dataSize) = 0; + + // Calculates CRC + virtual unsigned crc(const void* dataptr, int datasize) = 0; }; // Signature byte value @@ -45,124 +46,123 @@ namespace ICEImpl { ReliableTransport(); ~ReliableTransport(); - + // Sets maximal datagram size. This value must be odd to Encryption::GetBlockSize() returned value. - void setMaxDatagram(int size); - + void setMaxDatagram(int size); + // Returns maximal datagram size - int maxDatagram(); + int maxDatagram(); // Sets encryption interface - void setEncryption(Encryption* encryption); - + void setEncryption(Encryption* encryption); + // Returns current encryption interface. Default is NULL. Encryption* encryption(); - + // Process incoming UDP packet. Returns true if packet is recognized. Otherwise it returns false. - bool processIncoming(const void* dataPtr, int dataSize); - + bool processIncoming(const void* dataPtr, int dataSize); + // Enqueue outgoing packet - void queueOutgoing(const void* dataPtr, int dataSize); - + void queueOutgoing(const void* dataPtr, int dataSize); + // Checks if there are incoming application data - bool hasAppData(); + bool hasAppData(); // Returns incoming application data. ptr may be NULL - in this case method will return packet size. - unsigned appData(void* ptr); - + unsigned appData(void* ptr); + // Checks if there are raw packet(s) to send - bool hasPacketToSend(); + bool hasPacketToSend(); // Returns raw packet data to send. - void getPacketToSend(void* outputPtr, int& outputSize); + void getPacketToSend(void* outputPtr, int& outputSize); - protected: - +protected: class Packet { public: - enum Type - { - Request = 0, - Confirmation = 1, - Ack = 2, - AppData = 3 - }; - - typedef unsigned short Seqno; - typedef unsigned short AppSeqno; - - Packet(); - ~Packet(); + enum Type + { + Request = 0, + Confirmation = 1, + Ack = 2, + AppData = 3 + }; - bool parse(const void* dataptr, int datasize, Encryption* encryption); - void build(const void* dataptr, int datasize, Encryption* encryption); - void setType(Type packetType); - Type type(); - void setSeqno(Seqno seqno); - Seqno seqno(); - void setAppSeqno(AppSeqno seqno); - AppSeqno appSeqno(); - ByteBuffer& data(); + typedef unsigned short Seqno; + typedef unsigned short AppSeqno; + + Packet(); + ~Packet(); + + bool parse(const void* dataptr, int datasize, Encryption* encryption); + void build(const void* dataptr, int datasize, Encryption* encryption); + void setType(Type packetType); + Type type(); + void setSeqno(Seqno seqno); + Seqno seqno(); + void setAppSeqno(AppSeqno seqno); + AppSeqno appSeqno(); + ByteBuffer& data(); protected: - Type mType; - Seqno mSeqno; - AppSeqno mAppSeqno; - ByteBuffer mData; + Type mType; + Seqno mSeqno; + AppSeqno mAppSeqno; + ByteBuffer mData; }; - + // List of UDP packets typedef std::vector PacketList; // Incoming UDP packets - PacketList mIncomingData; + PacketList mIncomingData; // Outgoing UDP packets - PacketList mOutgoingData; - + PacketList mOutgoingData; + // Used encryption provider - Encryption* mEncryption; - + Encryption* mEncryption; + // Maximal datagram size - int mMaxDatagramSize; - + int mMaxDatagramSize; + // Vector of packet numbers to confirm - std::vector mConfirmationData; - + std::vector mConfirmationData; + // Vector of packet numbers to ack - std::vector mAckData; - + std::vector mAckData; + // Incoming decrypted application data packets - PacketList mIncomingAppData; + PacketList mIncomingAppData; // Seqno generator - Packet::Seqno mSeqno; + Packet::Seqno mSeqno; // Process incoming Ack packets - void processAck(Packet* p); - + void processAck(Packet* p); + // Process confirmation packets - void processConfirmation(Packet* p); - + void processConfirmation(Packet* p); + // Process requests packets - void processRequest(Packet* p); + void processRequest(Packet* p); // Process app. data - void processAppData(Packet* p); + void processAppData(Packet* p); // Remove packet from outgoing queue - void removePacket(Packet::Seqno seqno); + void removePacket(Packet::Seqno seqno); // Prioritizes packet with specified seqno - void prioritizePacket(Packet::Seqno seqno); - + void prioritizePacket(Packet::Seqno seqno); + // Creates Ack packet for specified seqno index - Packet* makeAckPacket(Packet::Seqno seqno); + Packet* makeAckPacket(Packet::Seqno seqno); // Creates Confirm packet for specified seqno indexes - Packet* makeConfirmationPacket(std::vector seqnovector); - }; + Packet* makeConfirmationPacket(std::vector seqnovector); +}; } // end of namespace ICEImpl #endif diff --git a/src/libs/ice/ICESHA1.cpp b/src/libs/ice/ICESHA1.cpp index b112f434..dbb78426 100644 --- a/src/libs/ice/ICESHA1.cpp +++ b/src/libs/ice/ICESHA1.cpp @@ -12,10 +12,10 @@ void hmacSha1Digest(const void* inputData, size_t inputSize, void* outputData, const void* key, size_t keySize) { - CryptoPP::HMAC mac((const byte*)key, keySize); - - mac.Update((const byte*)inputData, inputSize); - mac.Final((byte*)outputData); + CryptoPP::HMAC mac((const byte*)key, keySize); + + mac.Update((const byte*)inputData, inputSize); + mac.Final((byte*)outputData); } #elif defined(USE_OPENSSL) @@ -24,8 +24,8 @@ void hmacSha1Digest(const void* inputData, size_t inputSize, void* outputData, c void hmacSha1Digest(const void* inputData, size_t inputSize, void* outputData, const void* key, size_t keySize) { - unsigned outputSize = 0; - HMAC(EVP_sha1(), key, keySize, (const unsigned char*)inputData, inputSize, (unsigned char*)outputData, &outputSize); + unsigned outputSize = 0; + HMAC(EVP_sha1(), key, keySize, (const unsigned char*)inputData, inputSize, (unsigned char*)outputData, &outputSize); } #else @@ -33,6 +33,6 @@ void hmacSha1Digest(const void* inputData, size_t inputSize, void* outputData, c #include "hmac_sha1_impl.h" void hmacSha1Digest(const void* inputData, size_t inputSize, void* outputData, const void* key, size_t keySize) { - hmac_sha1((const uint8_t*)key, keySize, (const uint8_t*)inputData, inputSize, (uint8_t*)outputData); + hmac_sha1((const uint8_t*)key, keySize, (const uint8_t*)inputData, inputSize, (uint8_t*)outputData); } #endif diff --git a/src/libs/ice/ICESession.cpp b/src/libs/ice/ICESession.cpp index 595f021e..c3aee377 100644 --- a/src/libs/ice/ICESession.cpp +++ b/src/libs/ice/ICESession.cpp @@ -33,860 +33,854 @@ using namespace ice; Session::Session() { - //No activity yet - mState = None; - - //start interval for STUN messages - mStartInterval = 20; + // No activity yet + mState = None; - mLocalPortNumber = 0; - refreshPwdUfrag(); - - //default role is Controlled - mRole = RoleControlled; - - mTieBreaker = " "; - for (size_t i=0; i<8; i++) - mTieBreaker[i] = rand() & 0xFF; + // start interval for STUN messages + mStartInterval = 20; - mFoundationGenerator = 0xFFFFFFFF; - mMustRestart = false; + mLocalPortNumber = 0; + refreshPwdUfrag(); + + // default role is Controlled + mRole = RoleControlled; + + mTieBreaker = " "; + for (size_t i = 0; i < 8; i++) + mTieBreaker[i] = rand() & 0xFF; + + mFoundationGenerator = 0xFFFFFFFF; + mMustRestart = false; } -Session::~Session() -{ -} +Session::~Session() {} void Session::setup(StackConfig& config) { - if (!config.mUseSTUN && !config.mUseTURN) - throw std::logic_error("ICE is configured to not use STUN and not use TURN."); - if (config.mUseSTUN && config.mUseTURN) - throw std::logic_error("ICE is configured to use both STUN and TURN."); + if (!config.mUseSTUN && !config.mUseTURN) + throw std::logic_error("ICE is configured to not use STUN and not use TURN."); + if (config.mUseSTUN && config.mUseTURN) + throw std::logic_error("ICE is configured to use both STUN and TURN."); - // Save the configuration - mConfig = config; + // Save the configuration + mConfig = config; - std::map::iterator streamIter; - for (streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); ++streamIter) - streamIter->second->setConfig(config); + std::map::iterator streamIter; + for (streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); ++streamIter) + streamIter->second->setConfig(config); } int Session::addStream() { - Lock lock(mGuard); + Lock lock(mGuard); - ICEStreamPtr s(new Stream()); - s->setAgentRole(mRole); - s->setConfig(mConfig); - s->mTieBreaker = mTieBreaker; - s->setLocalPwd(mLocalPwd); - s->setLocalUfrag(mLocalUfrag); - s->mId = mStreamMap.size(); - mStreamMap[s->mId] = s; + ICEStreamPtr s(new Stream()); + s->setAgentRole(mRole); + s->setConfig(mConfig); + s->mTieBreaker = mTieBreaker; + s->setLocalPwd(mLocalPwd); + s->setLocalUfrag(mLocalUfrag); + s->mId = mStreamMap.size(); + mStreamMap[s->mId] = s; - ICELogInfo(<< "New stream " << s->mId << " is add."); + ICELogInfo(<< "New stream " << s->mId << " is add."); - return s->mId; + return s->mId; } int Session::addComponent(int streamID, void* tag, unsigned short port4, unsigned short port6) { - Lock lock(mGuard); + Lock lock(mGuard); - if (mStreamMap.find(streamID) == mStreamMap.end()) - { - ICELogError(<< "Cannot find stream " << streamID << " to add new component."); - return -1; - } + if (mStreamMap.find(streamID) == mStreamMap.end()) + { + ICELogError(<< "Cannot find stream " << streamID << " to add new component."); + return -1; + } - // Get reference to stream - Stream& stream = *mStreamMap[streamID]; - - // Assign new ID to component - int componentID = stream.addComponent(tag, port4, port6); + // Get reference to stream + Stream& stream = *mStreamMap[streamID]; - ICELogInfo( << "New component " << componentID << " is add to stream " << streamID << "."); + // Assign new ID to component + int componentID = stream.addComponent(tag, port4, port6); - return componentID; + ICELogInfo(<< "New component " << componentID << " is add to stream " << streamID << "."); + + return componentID; } void Session::removeStream(int streamID) { - Lock lock(mGuard); + Lock lock(mGuard); - std::map::iterator streamIter = mStreamMap.find(streamID); - if (streamIter != mStreamMap.end()) - mStreamMap.erase(streamIter); + std::map::iterator streamIter = mStreamMap.find(streamID); + if (streamIter != mStreamMap.end()) + mStreamMap.erase(streamIter); } bool Session::findStreamAndComponent(int family, unsigned short port, int* stream, int* component) { - Lock lock(mGuard); + Lock lock(mGuard); - // Iterate streams - ICEStreamMap::iterator sit; - for (sit = mStreamMap.begin(); sit != mStreamMap.end(); ++sit) - { - if (sit->second->hasPortNumber(family, port, component)) + // Iterate streams + ICEStreamMap::iterator sit; + for (sit = mStreamMap.begin(); sit != mStreamMap.end(); ++sit) { - *stream = sit->first; - return true; + if (sit->second->hasPortNumber(family, port, component)) + { + *stream = sit->first; + return true; + } } - } - return false; + return false; } bool Session::hasStream(int streamId) { - Lock l(mGuard); - return mStreamMap.find(streamId) != mStreamMap.end(); + Lock l(mGuard); + return mStreamMap.find(streamId) != mStreamMap.end(); } bool Session::hasComponent(int streamId, int componentId) { - Lock l(mGuard); - ICEStreamMap::const_iterator streamIter = mStreamMap.find(streamId); - if (streamIter == mStreamMap.end()) - return false; - if (!streamIter->second) - return false; + Lock l(mGuard); + ICEStreamMap::const_iterator streamIter = mStreamMap.find(streamId); + if (streamIter == mStreamMap.end()) + return false; + if (!streamIter->second) + return false; - return streamIter->second->mComponentMap.find(componentId) != streamIter->second->mComponentMap.end(); + return streamIter->second->mComponentMap.find(componentId) != streamIter->second->mComponentMap.end(); } void Session::setComponentPort(int streamId, int componentId, unsigned short port4, unsigned short port6) { - Lock l(mGuard); - if (hasComponent(streamId, componentId)) - { - mStreamMap[streamId]->mComponentMap[componentId].mPort4 = port4; - mStreamMap[streamId]->mComponentMap[componentId].mPort6 = port6; - } + Lock l(mGuard); + if (hasComponent(streamId, componentId)) + { + mStreamMap[streamId]->mComponentMap[componentId].mPort4 = port4; + mStreamMap[streamId]->mComponentMap[componentId].mPort6 = port6; + } } void Session::gatherCandidates() { - //protect instance - Lock lock(mGuard); + // protect instance + Lock lock(mGuard); - //parse the STUN/TURN server IP address - //mConfig.mSTUNServerAddr.GetSockaddr((sockaddr&)mSTUNServerAddr); - //mConfig.mTURNServerAddr.GetSockaddr((sockaddr&)mTURNServerAddr); + // parse the STUN/TURN server IP address + // mConfig.mSTUNServerAddr.GetSockaddr((sockaddr&)mSTUNServerAddr); + // mConfig.mTURNServerAddr.GetSockaddr((sockaddr&)mTURNServerAddr); - //as RFC says... - //if (mConfig.mUseTURN) - // mSTUNServerAddr = mTURNServerAddr; + // as RFC says... + // if (mConfig.mUseTURN) + // mSTUNServerAddr = mTURNServerAddr; - // Define the list of used IP interfaces - std::vector hostip; - - // Get list of IP interfaces - // std::vector& ipList = NetworkHelper::Instance().GetInterfaceList(); + // Define the list of used IP interfaces + std::vector hostip; - // Iterate all streams and instructs them to gather candidates - std::map::iterator streamIter; - int finished = 0; - for (streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); ++streamIter) - { - streamIter->second->gatherCandidates(); - if (streamIter->second->mState > CandidateGathering) - finished++; - } - - // Set session state as "candidate gathering" or "creating sdp" - depending on stream state - if ((size_t)finished == mStreamMap.size()) - mState = CreatingSDP; - else - mState = CandidateGathering; + // Get list of IP interfaces + // std::vector& ipList = NetworkHelper::Instance().GetInterfaceList(); + + // Iterate all streams and instructs them to gather candidates + std::map::iterator streamIter; + int finished = 0; + for (streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); ++streamIter) + { + streamIter->second->gatherCandidates(); + if (streamIter->second->mState > CandidateGathering) + finished++; + } + + // Set session state as "candidate gathering" or "creating sdp" - depending on stream state + if ((size_t)finished == mStreamMap.size()) + mState = CreatingSDP; + else + mState = CandidateGathering; } - bool Session::processData(ByteBuffer& buffer, int streamID, int component) { - Lock lock(mGuard); + Lock lock(mGuard); - // Attempt to parse - StunMessage msg; - if (!msg.parsePacket(buffer)) - return false; - - ICELogDebug( << "Received STUN packet from " << buffer.remoteAddress().toStdString().c_str() << ". Data: " << buffer.hexstring()); - - // Old&new states - int oldstate = None, newstate = None; + // Attempt to parse + StunMessage msg; + if (!msg.parsePacket(buffer)) + return false; - // Find stream responsible for this buffer - if (mStreamMap.find(streamID) == mStreamMap.end()) - return false; - - // Get pointer to stream - ICEStreamPtr streamPtr = mStreamMap[streamID]; - if (!streamPtr) - return false; - - Stream& stream = *streamPtr; - oldstate = stream.mState; - /*bool result = */stream.processData(msg, buffer, component); - newstate = stream.mState; + ICELogDebug(<< "Received STUN packet from " << buffer.remoteAddress().toStdString().c_str() + << ". Data: " << buffer.hexstring()); - if (newstate != oldstate) - { - // State is changed. Maybe full session state is changed too? - int failedcount = 0, successcount = 0; - - switch (newstate) + // Old&new states + int oldstate = None, newstate = None; + + // Find stream responsible for this buffer + if (mStreamMap.find(streamID) == mStreamMap.end()) + return false; + + // Get pointer to stream + ICEStreamPtr streamPtr = mStreamMap[streamID]; + if (!streamPtr) + return false; + + Stream& stream = *streamPtr; + oldstate = stream.mState; + /*bool result = */ stream.processData(msg, buffer, component); + newstate = stream.mState; + + if (newstate != oldstate) { - case CreatingSDP: + // State is changed. Maybe full session state is changed too? + int failedcount = 0, successcount = 0; - // Check if all streams gathered candidates or failed - for (ICEStreamMap::iterator si=mStreamMap.begin(); si != mStreamMap.end(); ++si) - { - if (!si->second) - continue; - - Stream& stream = *si->second; - if (stream.mState == CreatingSDP) - successcount++; - else - if (stream.mState == Failed) - failedcount++; - } + switch (newstate) + { + case CreatingSDP: - if (failedcount == (int)mStreamMap.size()) - mState = Failed; - else - mState = CreatingSDP; + // Check if all streams gathered candidates or failed + for (ICEStreamMap::iterator si = mStreamMap.begin(); si != mStreamMap.end(); ++si) + { + if (!si->second) + continue; - break; + Stream& stream = *si->second; + if (stream.mState == CreatingSDP) + successcount++; + else if (stream.mState == Failed) + failedcount++; + } - case Success: - case Failed: - // Check if all streams a success or failed - for (ICEStreamMap::iterator si=mStreamMap.begin(); si != mStreamMap.end(); ++si) - { - if (!si->second) - continue; - - Stream& stream = *si->second; - if (stream.mState == Success) - successcount++; - else - if (stream.mState == Failed) - failedcount++; - } + if (failedcount == (int)mStreamMap.size()) + mState = Failed; + else + mState = CreatingSDP; - if (failedcount == (int)mStreamMap.size()) - mState = Failed; - else - mState = Success; + break; - break; + case Success: + case Failed: + // Check if all streams a success or failed + for (ICEStreamMap::iterator si = mStreamMap.begin(); si != mStreamMap.end(); ++si) + { + if (!si->second) + continue; + Stream& stream = *si->second; + if (stream.mState == Success) + successcount++; + else if (stream.mState == Failed) + failedcount++; + } + + if (failedcount == (int)mStreamMap.size()) + mState = Failed; + else + mState = Success; + + break; + } } - } - return true; + return true; } -PByteBuffer Session::getDataToSend(bool& response, int& stream, int& component, void*&tag) +PByteBuffer Session::getDataToSend(bool& response, int& stream, int& component, void*& tag) { - // Protect instance - Lock lock(mGuard); - - PByteBuffer result; + // Protect instance + Lock lock(mGuard); - // Iterate streams to update their states (maybe timeout occured since last call of getDataToSend()) - ICEStreamMap::iterator streamIter; - for (streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); ++streamIter) - if (streamIter->second) - streamIter->second->isTimeout(); - - for (streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); ++streamIter) - { - if (streamIter->second) - result = streamIter->second->getDataToSend(response, component, tag); - if (result) + PByteBuffer result; + + // Iterate streams to update their states (maybe timeout occured since last call of getDataToSend()) + ICEStreamMap::iterator streamIter; + for (streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); ++streamIter) + if (streamIter->second) + streamIter->second->isTimeout(); + + for (streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); ++streamIter) { - stream = streamIter->first; - return result; + if (streamIter->second) + result = streamIter->second->getDataToSend(response, component, tag); + if (result) + { + stream = streamIter->first; + return result; + } } - } - return result; + return result; } bool Session::active() { - //protect instance - Lock lock(mGuard); - - return (mState != None); + // protect instance + Lock lock(mGuard); + + return (mState != None); } void Session::createSdp(std::vector& common) { - common.push_back("a=ice-full"); - common.push_back("a=ice-pwd:" + localPwd()); - common.push_back("a=ice-ufrag:" + localUfrag()); + common.push_back("a=ice-full"); + common.push_back("a=ice-pwd:" + localPwd()); + common.push_back("a=ice-ufrag:" + localUfrag()); } -void Session::createSdp(int streamID, std::vector& defaultIP, - std::vector& defaultPort, std::vector& candidateList) +void Session::createSdp(int streamID, std::vector& defaultIP, std::vector& defaultPort, + std::vector& candidateList) { - ICEStreamMap::iterator streamIter = mStreamMap.find(streamID); - if (streamIter != mStreamMap.end()) - streamIter->second->createOfferSdp(defaultIP, defaultPort, candidateList); + ICEStreamMap::iterator streamIter = mStreamMap.find(streamID); + if (streamIter != mStreamMap.end()) + streamIter->second->createOfferSdp(defaultIP, defaultPort, candidateList); } - -bool Session::findCandidate(std::vector&cv, Candidate::Type _type, - const std::string& baseIP, int componentID, Candidate& result) + +bool Session::findCandidate(std::vector& cv, Candidate::Type _type, const std::string& baseIP, + int componentID, Candidate& result) { - for (unsigned int i=0; isecond; - if (s) + mMustRestart |= pwd != mRemotePwd; + mRemotePwd = pwd; + for (ICEStreamMap::iterator streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); streamIter++) { - if (streamId == -1 || streamIter->first == streamId) - s->setRemotePwd(pwd); + ICEStreamPtr s = streamIter->second; + if (s) + { + if (streamId == -1 || streamIter->first == streamId) + s->setRemotePwd(pwd); + } } - } - } std::string Session::remotePassword(int streamId) const { - if (streamId == -1) - return mRemotePwd; - ICEStreamMap::const_iterator streamIter = mStreamMap.find(streamId); - if (streamIter == mStreamMap.end()) - return std::string(); - if (!streamIter->second) - return std::string(); - - return streamIter->second->mRemotePwd; + if (streamId == -1) + return mRemotePwd; + ICEStreamMap::const_iterator streamIter = mStreamMap.find(streamId); + if (streamIter == mStreamMap.end()) + return std::string(); + if (!streamIter->second) + return std::string(); + + return streamIter->second->mRemotePwd; } void Session::setRemoteUfrag(const std::string& ufrag, int streamId) { - mMustRestart |= ufrag != mRemoteUfrag; - mRemoteUfrag = ufrag; + mMustRestart |= ufrag != mRemoteUfrag; + mRemoteUfrag = ufrag; - // Set it to streams - for (ICEStreamMap::iterator streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); streamIter++) - { - ICEStreamPtr s = streamIter->second; - if (s) + // Set it to streams + for (ICEStreamMap::iterator streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); streamIter++) { - if (streamId == -1 || streamIter->first == streamId) - s->setRemoteUfrag(ufrag); + ICEStreamPtr s = streamIter->second; + if (s) + { + if (streamId == -1 || streamIter->first == streamId) + s->setRemoteUfrag(ufrag); + } } - } } std::string Session::remoteUfrag(int streamId) const { - if (streamId == -1) - return mRemoteUfrag; - ICEStreamMap::const_iterator streamIter = mStreamMap.find(streamId); - if (streamIter == mStreamMap.end()) - return std::string(); - if (!streamIter->second) - return std::string(); + if (streamId == -1) + return mRemoteUfrag; + ICEStreamMap::const_iterator streamIter = mStreamMap.find(streamId); + if (streamIter == mStreamMap.end()) + return std::string(); + if (!streamIter->second) + return std::string(); - return streamIter->second->mRemoteUfrag; + return streamIter->second->mRemoteUfrag; } -bool Session::processSdpOffer(int streamIndex, std::vector& candidateList, - const std::string& defaultIP, unsigned short defaultPort, bool deleteRelayed) +bool Session::processSdpOffer(int streamIndex, std::vector& candidateList, const std::string& defaultIP, + unsigned short defaultPort, bool deleteRelayed) { - ICEStreamMap::iterator streamIter = mStreamMap.find(streamIndex); - if (streamIter != mStreamMap.end()) - return streamIter->second->processSdpOffer(candidateList, defaultIP, defaultPort, deleteRelayed); - - return false; + ICEStreamMap::iterator streamIter = mStreamMap.find(streamIndex); + if (streamIter != mStreamMap.end()) + return streamIter->second->processSdpOffer(candidateList, defaultIP, defaultPort, deleteRelayed); + + return false; } NetworkAddress Session::getRemoteRelayedCandidate(int stream, int component) { - ICEStreamMap::iterator streamIter = mStreamMap.find(stream); - if (streamIter != mStreamMap.end()) - return streamIter->second->remoteRelayedAddress(component); - - return NetworkAddress(); + ICEStreamMap::iterator streamIter = mStreamMap.find(stream); + if (streamIter != mStreamMap.end()) + return streamIter->second->remoteRelayedAddress(component); + + return NetworkAddress(); } NetworkAddress Session::getRemoteReflexiveCandidate(int stream, int component) { - ICEStreamMap::iterator streamIter = mStreamMap.find(stream); - if (streamIter != mStreamMap.end()) - return streamIter->second->remoteReflexiveAddress(component); - - return NetworkAddress(); + ICEStreamMap::iterator streamIter = mStreamMap.find(stream); + if (streamIter != mStreamMap.end()) + return streamIter->second->remoteReflexiveAddress(component); + + return NetworkAddress(); } NetworkAddress Session::defaultAddress(int streamID, int componentID) { - ICEStreamMap::iterator streamIter = mStreamMap.find(streamID); - if (streamIter != mStreamMap.end()) - return streamIter->second->defaultAddress(componentID); - return NetworkAddress(); + ICEStreamMap::iterator streamIter = mStreamMap.find(streamID); + if (streamIter != mStreamMap.end()) + return streamIter->second->defaultAddress(componentID); + return NetworkAddress(); } void Session::fillCandidateList(int streamID, int componentID, std::vector& candidateList) { - ICEStreamMap::iterator streamIter = mStreamMap.find(streamID); - if (streamIter != mStreamMap.end()) - streamIter->second->candidateList(componentID, candidateList); + ICEStreamMap::iterator streamIter = mStreamMap.find(streamID); + if (streamIter != mStreamMap.end()) + streamIter->second->candidateList(componentID, candidateList); } void Session::checkConnectivity() { - ICELogInfo( << "Starting connectivity checks."); + ICELogInfo(<< "Starting connectivity checks."); - // Check current session state to ensure is did not run connectivity checks already - if (mState == ConnCheck || mState == Success) - return; - - // Make current state "connection checking now" - mState = ConnCheck; - - std::map::iterator streamIter; - for (streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); streamIter++) - { - streamIter->second->setRemotePwd(mRemotePwd); - streamIter->second->setRemoteUfrag(mRemoteUfrag); - streamIter->second->startChecks(); - } + // Check current session state to ensure is did not run connectivity checks already + if (mState == ConnCheck || mState == Success) + return; - // Set session state to "connection checks" - mState = ConnCheck; + // Make current state "connection checking now" + mState = ConnCheck; - /* - Checks are generated only by full implementations. Lite - implementations MUST skip the steps described in this section. + std::map::iterator streamIter; + for (streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); streamIter++) + { + streamIter->second->setRemotePwd(mRemotePwd); + streamIter->second->setRemoteUfrag(mRemoteUfrag); + streamIter->second->startChecks(); + } - An agent performs ordinary checks and triggered checks. The - generation of both checks is governed by a timer which fires - periodically for each media stream. The agent maintains a FIFO - queue, called the triggered check queue, which contains candidate - pairs for which checks are to be sent at the next available + // Set session state to "connection checks" + mState = ConnCheck; - opportunity. When the timer fires, the agent removes the top pair - from triggered check queue, performs a connectivity check on that - pair, and sets the state of the candidate pair to In-Progress. If - there are no pairs in the triggered check queue, an ordinary check is - sent. + /* + Checks are generated only by full implementations. Lite + implementations MUST skip the steps described in this section. - Once the agent has computed the check lists as described in - Section 5.7, it sets a timer for each active check list. The timer - fires every Ta*N seconds, where N is the number of active check lists - (initially, there is only one active check list). Implementations - MAY set the timer to fire less frequently than this. Implementations - SHOULD take care to spread out these timers so that they do not fire - at the same time for each media stream. Ta and the retransmit timer - RTO are computed as described in Section 16. Multiplying by N allows - this aggregate check throughput to be split between all active check - lists. The first timer fires immediately, so that the agent performs - a connectivity check the moment the offer/answer exchange has been - done, followed by the next check Ta seconds later (since there is - only one active check list). + An agent performs ordinary checks and triggered checks. The + generation of both checks is governed by a timer which fires + periodically for each media stream. The agent maintains a FIFO + queue, called the triggered check queue, which contains candidate + pairs for which checks are to be sent at the next available - When the timer fires, and there is no triggered check to be sent, the - agent MUST choose an ordinary check as follows: + opportunity. When the timer fires, the agent removes the top pair + from triggered check queue, performs a connectivity check on that + pair, and sets the state of the candidate pair to In-Progress. If + there are no pairs in the triggered check queue, an ordinary check is + sent. - o Find the highest priority pair in that check list that is in the - Waiting state. + Once the agent has computed the check lists as described in + Section 5.7, it sets a timer for each active check list. The timer + fires every Ta*N seconds, where N is the number of active check lists + (initially, there is only one active check list). Implementations + MAY set the timer to fire less frequently than this. Implementations + SHOULD take care to spread out these timers so that they do not fire + at the same time for each media stream. Ta and the retransmit timer + RTO are computed as described in Section 16. Multiplying by N allows + this aggregate check throughput to be split between all active check + lists. The first timer fires immediately, so that the agent performs + a connectivity check the moment the offer/answer exchange has been + done, followed by the next check Ta seconds later (since there is + only one active check list). - o If there is such a pair: + When the timer fires, and there is no triggered check to be sent, the + agent MUST choose an ordinary check as follows: - * Send a STUN check from the local candidate of that pair to the - remote candidate of that pair. The procedures for forming the - STUN request for this purpose are described in Section 7.1.1. + o Find the highest priority pair in that check list that is in the + Waiting state. - * Set the state of the candidate pair to In-Progress. + o If there is such a pair: - o If there is no such pair: + * Send a STUN check from the local candidate of that pair to the + remote candidate of that pair. The procedures for forming the + STUN request for this purpose are described in Section 7.1.1. - * Find the highest priority pair in that check list that is in - the Frozen state. + * Set the state of the candidate pair to In-Progress. - * If there is such a pair: + o If there is no such pair: - + Unfreeze the pair. + * Find the highest priority pair in that check list that is in + the Frozen state. - + Perform a check for that pair, causing its state to - transition to In-Progress. + * If there is such a pair: - * If there is no such pair: + + Unfreeze the pair. - + Terminate the timer for that check list. + + Perform a check for that pair, causing its state to + transition to In-Progress. - To compute the message integrity for the check, the agent uses the - remote username fragment and password learned from the SDP from its - peer. The local username fragment is known directly by the agent for - its own candidate. - */ + * If there is no such pair: + + Terminate the timer for that check list. + + To compute the message integrity for the check, the agent uses the + remote username fragment and password learned from the SDP from its + peer. The local username fragment is known directly by the agent for + its own candidate. + */ } void Session::setRole(AgentRole role) { - mRole = role; + mRole = role; - std::map::iterator streamIter; - for (streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); ++streamIter) - streamIter->second->setAgentRole(role); + std::map::iterator streamIter; + for (streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); ++streamIter) + streamIter->second->setAgentRole(role); } AgentRole Session::role() { - return mRole; + return mRole; } void Session::clear() { - refreshPwdUfrag(); - mState = None; - std::map::iterator streamIter; - for (streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); ++streamIter) - streamIter->second->clear(); - mTurnPrefixMap.clear(); + refreshPwdUfrag(); + mState = None; + std::map::iterator streamIter; + for (streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); ++streamIter) + streamIter->second->clear(); + mTurnPrefixMap.clear(); } void Session::clearForRestart(bool localNetworkChanged) { - refreshPwdUfrag(); - mState = ice::None; - ICEStreamMap::iterator streamIter; - for (streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); ++streamIter) - streamIter->second->clearForRestart(localNetworkChanged); + refreshPwdUfrag(); + mState = ice::None; + ICEStreamMap::iterator streamIter; + for (streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); ++streamIter) + streamIter->second->clearForRestart(localNetworkChanged); } void Session::stopChecks() { - ICELogInfo(<< "Stop connectivity checks"); + ICELogInfo(<< "Stop connectivity checks"); - ICEStreamMap::iterator streamIter; - for (streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); ++streamIter) - streamIter->second->stopChecks(); - - if (mState < Failed) - mState = Failed; + ICEStreamMap::iterator streamIter; + for (streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); ++streamIter) + streamIter->second->stopChecks(); + + if (mState < Failed) + mState = Failed; } void Session::cancelAllocations() { - for (auto stream: mStreamMap) - stream.second->cancelAllocations(); + for (auto stream : mStreamMap) + stream.second->cancelAllocations(); } bool Session::finished() { - return (mState == Failed || mState == Success); + return (mState == Failed || mState == Success); } NetworkAddress Session::remoteAddress(int streamID, int componentID) { - ICEStreamMap::iterator streamIter = mStreamMap.find(streamID); - if (streamIter != mStreamMap.end()) - return streamIter->second->remoteAddress(componentID); - - return NetworkAddress(); + ICEStreamMap::iterator streamIter = mStreamMap.find(streamID); + if (streamIter != mStreamMap.end()) + return streamIter->second->remoteAddress(componentID); + + return NetworkAddress(); } NetworkAddress Session::localAddress(int streamID, int componentID) { - ICEStreamMap::iterator streamIter = mStreamMap.find(streamID); - if (streamIter != mStreamMap.end()) - return streamIter->second->localAddress(componentID); - - return NetworkAddress(); + ICEStreamMap::iterator streamIter = mStreamMap.find(streamID); + if (streamIter != mStreamMap.end()) + return streamIter->second->localAddress(componentID); + + return NetworkAddress(); } NetworkAddress Session::reflexiveAddress(int streamID, int componentID) { - Lock l(mGuard); - ICEStreamMap::iterator streamIter = mStreamMap.find(streamID); - if (streamIter != mStreamMap.end()) - return streamIter->second->reflexiveAddress(componentID); - - return NetworkAddress(); + Lock l(mGuard); + ICEStreamMap::iterator streamIter = mStreamMap.find(streamID); + if (streamIter != mStreamMap.end()) + return streamIter->second->reflexiveAddress(componentID); + + return NetworkAddress(); } - + NetworkAddress Session::relayedAddress(int streamID, int componentID) { - Lock l(mGuard); - ICEStreamMap::iterator streamIter = mStreamMap.find(streamID); - if (streamIter != mStreamMap.end()) - return streamIter->second->relayedAddress(componentID); - - return NetworkAddress(); + Lock l(mGuard); + ICEStreamMap::iterator streamIter = mStreamMap.find(streamID); + if (streamIter != mStreamMap.end()) + return streamIter->second->relayedAddress(componentID); + + return NetworkAddress(); } bool Session::hasTurnPrefix(TurnPrefix prefix) { - Lock l(mGuard); - TurnPrefixMap::iterator mit = mTurnPrefixMap.find(prefix); - return mit != mTurnPrefixMap.end(); + Lock l(mGuard); + TurnPrefixMap::iterator mit = mTurnPrefixMap.find(prefix); + return mit != mTurnPrefixMap.end(); } void Session::chooseDefaults() { - Lock l(mGuard); + Lock l(mGuard); - ICEStreamMap::iterator streamIter; - for (streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); ++streamIter) - streamIter->second->Handle_CD(); + ICEStreamMap::iterator streamIter; + for (streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); ++streamIter) + streamIter->second->Handle_CD(); } void Session::dump(std::ostream& output) { - Lock l(mGuard); + Lock l(mGuard); - ICEStreamMap::iterator streamIter; - for (streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); ++streamIter) - streamIter->second->dump(output); + ICEStreamMap::iterator streamIter; + for (streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); ++streamIter) + streamIter->second->dump(output); } bool Session::findConcludePair(int stream, Candidate& local, Candidate& remote) { - Lock l(mGuard); + Lock l(mGuard); - ICEStreamMap::iterator streamIter = mStreamMap.find(stream); - if (streamIter != mStreamMap.end()) - return streamIter->second->findConcludePair(local, remote); - return false; + ICEStreamMap::iterator streamIter = mStreamMap.find(stream); + if (streamIter != mStreamMap.end()) + return streamIter->second->findConcludePair(local, remote); + return false; } bool Session::mustRestart() const { - return mMustRestart; + return mMustRestart; } void Session::refreshPwdUfrag() { - mLocalPwd = Session::createPassword(); - mLocalUfrag = Session::createUfrag(); + mLocalPwd = Session::createPassword(); + mLocalUfrag = Session::createUfrag(); - // Update all streams - for (ICEStreamMap::iterator streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); ++streamIter) - { - if (streamIter->second) + // Update all streams + for (ICEStreamMap::iterator streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); ++streamIter) { - streamIter->second->setLocalPwd(mLocalPwd); - streamIter->second->setLocalUfrag(mLocalUfrag); + if (streamIter->second) + { + streamIter->second->setLocalPwd(mLocalPwd); + streamIter->second->setLocalUfrag(mLocalUfrag); + } } - } } void Session::freeAllocation(int stream, int component, DeleteAllocationCallback* cb) { - Lock l(mGuard); - - ICEStreamMap::iterator streamIter = mStreamMap.find(stream); - if (streamIter != mStreamMap.end()) - streamIter->second->freeAllocation(component, cb); + Lock l(mGuard); + + ICEStreamMap::iterator streamIter = mStreamMap.find(stream); + if (streamIter != mStreamMap.end()) + streamIter->second->freeAllocation(component, cb); } bool Session::hasAllocations() { - int allocated = 0; - Lock l(mGuard); - - ICEStreamMap::iterator streamIter = mStreamMap.begin(); - for (;streamIter != mStreamMap.end(); ++streamIter) - if (streamIter->second) - allocated += streamIter->second->mTurnAllocated; - - return allocated > 0; + int allocated = 0; + Lock l(mGuard); + + ICEStreamMap::iterator streamIter = mStreamMap.begin(); + for (; streamIter != mStreamMap.end(); ++streamIter) + if (streamIter->second) + allocated += streamIter->second->mTurnAllocated; + + return allocated > 0; } bool Session::isDataIndication(ByteBuffer& source, ByteBuffer* plain) { - StunMessage msg; - if (!msg.parsePacket(source)) - return false; - - if (msg.hasAttribute(StunAttribute::Data) && msg.hasAttribute(StunAttribute::XorPeerAddress)) - { - // It is Data indication packet - DataAttribute& d = dynamic_cast(msg.attribute(StunAttribute::Data)); - XorPeerAddress& xpa = dynamic_cast(msg.attribute(StunAttribute::XorPeerAddress)); - - if (plain) + StunMessage msg; + if (!msg.parsePacket(source)) + return false; + + if (msg.hasAttribute(StunAttribute::Data) && msg.hasAttribute(StunAttribute::XorPeerAddress)) { - *plain = d.data(); - NetworkAddress remoteAddress = xpa.address(); - remoteAddress.setRelayed(true); - plain->setRemoteAddress(remoteAddress); - plain->setRelayed(true); + // It is Data indication packet + DataAttribute& d = dynamic_cast(msg.attribute(StunAttribute::Data)); + XorPeerAddress& xpa = dynamic_cast(msg.attribute(StunAttribute::XorPeerAddress)); + + if (plain) + { + *plain = d.data(); + NetworkAddress remoteAddress = xpa.address(); + remoteAddress.setRelayed(true); + plain->setRemoteAddress(remoteAddress); + plain->setRelayed(true); + } + return true; } - return true; - } - else - return false; + else + return false; } bool Session::isStun(const ByteBuffer& source) { - if (source.size() < 8) - return false; + if (source.size() < 8) + return false; - const unsigned* magic = (const unsigned*)source.data(); - return (ntohl(magic[1]) == 0x2112A442); + const unsigned* magic = (const unsigned*)source.data(); + return (ntohl(magic[1]) == 0x2112A442); } int Session::errorCode() { - Lock l(mGuard); - ICEStreamMap::const_iterator streamIter = mStreamMap.begin(); - for (;streamIter != mStreamMap.end(); ++streamIter) - if (streamIter->second->mState == /*RunningState::*/Failed) - return streamIter->second->mErrorCode; - return 0; + Lock l(mGuard); + ICEStreamMap::const_iterator streamIter = mStreamMap.begin(); + for (; streamIter != mStreamMap.end(); ++streamIter) + if (streamIter->second->mState == /*RunningState::*/ Failed) + return streamIter->second->mErrorCode; + return 0; } TurnPrefix Session::bindChannel(int stream, int component, const NetworkAddress& target, ChannelBoundCallback* cb) { - Lock l(mGuard); - ICELogInfo(<< "Bind channel " << stream << "/" << component << " to " << target.toStdString()); + Lock l(mGuard); + ICELogInfo(<< "Bind channel " << stream << "/" << component << " to " << target.toStdString()); - ICEStreamMap::iterator streamIter = mStreamMap.find(stream); - if (streamIter != mStreamMap.end()) - return streamIter->second->bindChannel(target, component, cb); - - return 0; // Channel numbers are in range [0x4000...0x7FFF] + ICEStreamMap::iterator streamIter = mStreamMap.find(stream); + if (streamIter != mStreamMap.end()) + return streamIter->second->bindChannel(target, component, cb); + + return 0; // Channel numbers are in range [0x4000...0x7FFF] } bool Session::isChannelBindingFailed(int stream, int component, TurnPrefix prefix) { - Lock l(mGuard); - ICEStreamMap::iterator streamIter = mStreamMap.begin(); - if (streamIter != mStreamMap.end()) - if (streamIter->second) - return streamIter->second->isChannelBindingFailed(component, prefix); + Lock l(mGuard); + ICEStreamMap::iterator streamIter = mStreamMap.begin(); + if (streamIter != mStreamMap.end()) + if (streamIter->second) + return streamIter->second->isChannelBindingFailed(component, prefix); - return false; + return false; } -void Session::installPermissions(int stream, int component, const NetworkAddress &address, InstallPermissionsCallback* cb) +void Session::installPermissions(int stream, int component, const NetworkAddress& address, + InstallPermissionsCallback* cb) { - Lock l(mGuard); - ICELogInfo(<< "Install permissions " << stream << "/" << component << " for " << address.toStdString()); + Lock l(mGuard); + ICELogInfo(<< "Install permissions " << stream << "/" << component << " for " << address.toStdString()); - ICEStreamMap::iterator streamIter = mStreamMap.begin(); - if (streamIter != mStreamMap.end()) - streamIter->second->installPermissions(component, address, cb); + ICEStreamMap::iterator streamIter = mStreamMap.begin(); + if (streamIter != mStreamMap.end()) + streamIter->second->installPermissions(component, address, cb); } bool Session::isRtp(ByteBuffer& source) { - if (!source.size()) - return false; - unsigned char b = *(const unsigned char*)source.data(); - return (b & 0xC0) == 0x80; + if (!source.size()) + return false; + unsigned char b = *(const unsigned char*)source.data(); + return (b & 0xC0) == 0x80; } bool Session::isChannelData(ByteBuffer& source, TurnPrefix prefix) { - if (source.size() < 4) - return false; + if (source.size() < 4) + return false; - if (!prefix) - { - unsigned char b = *(const unsigned char*)source.data(); - return (b & 0xC0) == 0x40; - } - else - { - unsigned short pp = ntohs(*(const unsigned short*)source.data()); - return pp == prefix; - } + if (!prefix) + { + unsigned char b = *(const unsigned char*)source.data(); + return (b & 0xC0) == 0x40; + } + else + { + unsigned short pp = ntohs(*(const unsigned short*)source.data()); + return pp == prefix; + } } Stream::CandidateVector* Session::remoteCandidates(int stream) { - ICEStreamMap::iterator iter = mStreamMap.find(stream); - if (iter != mStreamMap.end()) - return &iter->second->mRemoteCandidate; - else - return NULL; + ICEStreamMap::iterator iter = mStreamMap.find(stream); + if (iter != mStreamMap.end()) + return &iter->second->mRemoteCandidate; + else + return NULL; } NetworkAddress Session::activeStunServer(int stream) const { - ICEStreamMap::const_iterator iter = mStreamMap.find(stream); - if (iter != mStreamMap.end()) - return iter->second->mConfig.mServerAddr4; - else - return NetworkAddress(); + ICEStreamMap::const_iterator iter = mStreamMap.find(stream); + if (iter != mStreamMap.end()) + return iter->second->mConfig.mServerAddr4; + else + return NetworkAddress(); } diff --git a/src/libs/ice/ICESession.h b/src/libs/ice/ICESession.h index cccaf5b8..f9e172bf 100644 --- a/src/libs/ice/ICESession.h +++ b/src/libs/ice/ICESession.h @@ -22,199 +22,199 @@ namespace ice { - // ICE session context - struct Session - { - public: - Mutex mGuard; // Mutex to protect this instance +// ICE session context +struct Session +{ +public: + Mutex mGuard; // Mutex to protect this instance typedef std::map ICEStreamMap; - ICEStreamMap mStreamMap; // Streams - RunningState mState; // State of session - StackConfig mConfig; // Configuration - - size_t mStartInterval; /// Start interval - unsigned short mLocalPortNumber; /// Local port number - std::string mLocalPwd, - mLocalUfrag, - mRemotePwd, - mRemoteUfrag; - - NetworkAddress mRemoteDefaultAddr; /// Remote default address - AgentRole mRole; /// Marks if agent is Controlled or Controlling - std::string mTieBreaker; /// Tie breaker - unsigned int mFoundationGenerator; /// Foundation value generator. Used when foundation of remote candidate is not available. - bool mCanTransmit; /// Marks if transmission can start - bool mMustReInvite; /// Must reINVITE - TurnPrefixMap mTurnPrefixMap; /// Map of established relays - bool mMustRestart; /// Marks if session has to restart - + ICEStreamMap mStreamMap; // Streams + RunningState mState; // State of session + StackConfig mConfig; // Configuration + + size_t mStartInterval; /// Start interval + unsigned short mLocalPortNumber; /// Local port number + std::string mLocalPwd, mLocalUfrag, mRemotePwd, mRemoteUfrag; + + NetworkAddress mRemoteDefaultAddr; /// Remote default address + AgentRole mRole; /// Marks if agent is Controlled or Controlling + std::string mTieBreaker; /// Tie breaker + unsigned int + mFoundationGenerator; /// Foundation value generator. Used when foundation of remote candidate is not available. + bool mCanTransmit; /// Marks if transmission can start + bool mMustReInvite; /// Must reINVITE + TurnPrefixMap mTurnPrefixMap; /// Map of established relays + bool mMustRestart; /// Marks if session has to restart + /*! Default constructor. */ Session(); - + /*! Destructor. */ ~Session(); /*! Adjusts session to work with specified component number and specified local port number. */ - void setup(StackConfig& config); + void setup(StackConfig& config); /*! Checks if ICE session is started. */ - bool active(); + bool active(); /*! Initiates candidate gathering. Setup() must be called before. */ - void gatherCandidates(); - + void gatherCandidates(); + /*! Processing incoming data. * @return True if data were processed, false otherwise (too old response or not STUN data at all). */ - bool processData(ByteBuffer& buffer, int stream, int component); - - /*! Checks if there is any data to send. - * @return True if more data to send are available, false if all available data are returned in current call. */ - PByteBuffer getDataToSend(bool& response, int& stream, int& component, void*&tag); - + bool processData(ByteBuffer& buffer, int stream, int component); - /*! Handles incoming data in gathering candidate stage. + /*! Checks if there is any data to send. + * @return True if more data to send are available, false if all available data are returned in current call. */ + PByteBuffer getDataToSend(bool& response, int& stream, int& component, void*& tag); + + + /*! Handles incoming data in gathering candidate stage. * @return True if data was handled, false otherwise (too old response or not STUN data at all. */ - bool Handle_CG_In(StunMessage& msg, NetworkAddress& address); - + bool Handle_CG_In(StunMessage& msg, NetworkAddress& address); + /*! Handle eliminate redudand stage. */ - void Handle_ER(); - + void Handle_ER(); + // Compute foundations - void Handle_CF(); - + void Handle_CF(); + // Starting keep alive timers - void Handle_SKA(); + void Handle_SKA(); // Prioritize candidates - void Handle_PC(); - + void Handle_PC(); + // Choosing default candidate - void chooseDefaults(); + void chooseDefaults(); // Creation of common SDP strings - void createSdp(std::vector& common); - + void createSdp(std::vector& common); + // Creation of component SDP strings - void createSdp(int streamID, std::vector& defaultIP, - std::vector& defaultPort, std::vector& candidateList); + void createSdp(int streamID, std::vector& defaultIP, std::vector& defaultPort, + std::vector& candidateList); - bool findCandidate(std::vector&cv, Candidate::Type _type, - const std::string& baseIP, int componentID, Candidate& result); + bool findCandidate(std::vector& cv, Candidate::Type _type, const std::string& baseIP, int componentID, + Candidate& result); - RunningState state(); - - std::string localUfrag(); - std::string localPwd(); - - /*! Process ICE offer text. It does not mean SIP offer. No, this method applies to initial ICE candidate list and other information in both SIP offer and answer packets. */ - bool processSdpOffer(int streamIndex, std::vector& candidateList, - const std::string& defaultIP, unsigned short defaultPort, bool deleteRelayed); - NetworkAddress getRemoteRelayedCandidate(int stream, int component); - NetworkAddress getRemoteReflexiveCandidate(int stream, int component); + RunningState state(); - NetworkAddress defaultAddress(int streamID, int componentID); - void fillCandidateList(int streamID, int componentID, std::vector& candidateList); + std::string localUfrag(); + std::string localPwd(); + + /*! Process ICE offer text. It does not mean SIP offer. No, this method applies to initial ICE candidate list and + * other information in both SIP offer and answer packets. */ + bool processSdpOffer(int streamIndex, std::vector& candidateList, const std::string& defaultIP, + unsigned short defaultPort, bool deleteRelayed); + NetworkAddress getRemoteRelayedCandidate(int stream, int component); + NetworkAddress getRemoteReflexiveCandidate(int stream, int component); + + NetworkAddress defaultAddress(int streamID, int componentID); + void fillCandidateList(int streamID, int componentID, std::vector& candidateList); /*! Seeks in candidate list for candidate with specified IP and port. */ - bool candidateListContains(std::string remoteIP, unsigned short remotePort); - + bool candidateListContains(std::string remoteIP, unsigned short remotePort); + /*! Marks agent as Controlled or Controlling role. */ - void setRole(AgentRole role); - + void setRole(AgentRole role); + /*! Gets current role. */ - AgentRole role(); + AgentRole role(); /*! Binds channel to prefix */ - TurnPrefix bindChannel(int stream, int component, const NetworkAddress& target, ChannelBoundCallback* cb); - bool isChannelBindingFailed(int stream, int component, TurnPrefix prefix); + TurnPrefix bindChannel(int stream, int component, const NetworkAddress& target, ChannelBoundCallback* cb); + bool isChannelBindingFailed(int stream, int component, TurnPrefix prefix); - void installPermissions(int stream, int component, const NetworkAddress &address, InstallPermissionsCallback* cb); + void installPermissions(int stream, int component, const NetworkAddress& address, InstallPermissionsCallback* cb); /*! Enqueues CreatePermisssion transaction with zero lifetime - it removes permission. */ - void deletePermission(int stream, int component, DeletePermissionsCallback* cb); - + void deletePermission(int stream, int component, DeletePermissionsCallback* cb); + // Enqueues ClientAllocate with zero lifetime - void freeAllocation(int stream, int component, DeleteAllocationCallback* cb); - + void freeAllocation(int stream, int component, DeleteAllocationCallback* cb); + // Returns if there were any TURN allocations from this stack - bool hasAllocations(); - - static bool isDataIndication(ByteBuffer& source, ByteBuffer* plain); - static bool isStun(const ByteBuffer& source); - static bool isRtp(ByteBuffer& source); - static bool isChannelData(ByteBuffer& source, TurnPrefix prefix); + bool hasAllocations(); + + static bool isDataIndication(ByteBuffer& source, ByteBuffer* plain); + static bool isStun(const ByteBuffer& source); + static bool isRtp(ByteBuffer& source); + static bool isChannelData(ByteBuffer& source, TurnPrefix prefix); /*! Starts connectivity checks. */ - void checkConnectivity(); - - // Clears state of session and streams; does not delete streams or components. Stops all connectivity checks. Candidates must be gathered again. - void clear(); - - void clearForRestart(bool localNetworkChanged); - + void checkConnectivity(); + + // Clears state of session and streams; does not delete streams or components. Stops all connectivity checks. + // Candidates must be gathered again. + void clear(); + + void clearForRestart(bool localNetworkChanged); + // Returns true if state of session is Success or Failed - bool finished(); - + bool finished(); + // Stop connectivity checks and gathering requests. - void stopChecks(); - + void stopChecks(); + // Cancel allocation requests. Called when timeout is detected and allocation should be cancelled. // Allocation transaction and session can have different timeout values - so this method is neccessary - void cancelAllocations(); - + void cancelAllocations(); + /*! Returns concluding addresses . */ - NetworkAddress remoteAddress(int streamID, int componentID); - NetworkAddress localAddress(int streamID, int componentID); - + NetworkAddress remoteAddress(int streamID, int componentID); + NetworkAddress localAddress(int streamID, int componentID); + /*! Searches for local server reflexive candidate with specified component ID and returns its external address. */ - NetworkAddress reflexiveAddress(int streamID, int componentID); - + NetworkAddress reflexiveAddress(int streamID, int componentID); + /*! Searches for local server relayed candidate with specified component ID and returns its external address. */ - NetworkAddress relayedAddress(int streamID, int componentID); + NetworkAddress relayedAddress(int streamID, int componentID); /*! Checks if argument is used TURN prefix in one of the TURN bound channels. */ - bool hasTurnPrefix(TurnPrefix prefix); + bool hasTurnPrefix(TurnPrefix prefix); /*! Adds stream to session. Returns stream index. */ - int addStream(); + int addStream(); /*! Adds component to stream. * @param streamIndex Stream index. * @param tag Tag associated with component. * @return Created component record index. */ - int addComponent(int streamID, void *tag, unsigned short port4, unsigned short port6); + int addComponent(int streamID, void* tag, unsigned short port4, unsigned short port6); /* Removes stream with specified ID. All stream's components are removed too. */ - void removeStream(int streamID); + void removeStream(int streamID); /* Searches the stream&component ID basing on socket family (AF_INET or AF_INET6) and local port number. */ - bool findStreamAndComponent(int family, unsigned short port, int* stream, int* component); + bool findStreamAndComponent(int family, unsigned short port, int* stream, int* component); - bool hasStream(int streamId); - bool hasComponent(int streamId, int componentId); - void setComponentPort(int streamId, int componentId, unsigned short port4, unsigned short port6); + bool hasStream(int streamId); + bool hasComponent(int streamId, int componentId); + void setComponentPort(int streamId, int componentId, unsigned short port4, unsigned short port6); /*! Generates new ICE ufrag string. */ - static std::string createUfrag(); - + static std::string createUfrag(); + /*! Generates new ICE pwd string. */ - static std::string createPassword(); + static std::string createPassword(); - void setRemotePassword(const std::string& pwd, int streamId = -1); - std::string remotePassword(int streamId = -1) const; - void setRemoteUfrag(const std::string& ufrag, int streamId = -1); - std::string remoteUfrag(int streamId = -1) const; - - void refreshPwdUfrag(); + void setRemotePassword(const std::string& pwd, int streamId = -1); + std::string remotePassword(int streamId = -1) const; + void setRemoteUfrag(const std::string& ufrag, int streamId = -1); + std::string remoteUfrag(int streamId = -1) const; - void dump(std::ostream& output); - bool mustRestart() const; - bool findConcludePair(int stream, Candidate& local, Candidate& remote); - int errorCode(); + void refreshPwdUfrag(); + + void dump(std::ostream& output); + bool mustRestart() const; + bool findConcludePair(int stream, Candidate& local, Candidate& remote); + int errorCode(); Stream::CandidateVector* remoteCandidates(int stream); - NetworkAddress activeStunServer(int stream) const; - }; + NetworkAddress activeStunServer(int stream) const; }; +}; // namespace ice #endif diff --git a/src/libs/ice/ICESocket.h b/src/libs/ice/ICESocket.h index bc8447ff..40464b27 100644 --- a/src/libs/ice/ICESocket.h +++ b/src/libs/ice/ICESocket.h @@ -10,23 +10,21 @@ #include "ICETypes.h" #include -namespace ice { +namespace ice +{ struct ICESocket { - std::string mHostIP; - unsigned short mPort; - SOCKET mHandle; - unsigned int mPriority; + std::string mHostIP; + unsigned short mPort; + SOCKET mHandle; + unsigned int mPriority; - ICESocket() - :mPort(0), mHandle(INVALID_SOCKET), mPriority(0) - {} + ICESocket() : mPort(0), mHandle(INVALID_SOCKET), mPriority(0) {} - ~ICESocket() - {} + ~ICESocket() {} }; -}; +}; // namespace ice #endif diff --git a/src/libs/ice/ICEStream.cpp b/src/libs/ice/ICEStream.cpp index 33139c81..e6a2334d 100644 --- a/src/libs/ice/ICEStream.cpp +++ b/src/libs/ice/ICEStream.cpp @@ -22,2863 +22,2868 @@ using namespace ice; const char* ice::RunningStateToString(RunningState state) { - switch(state) - { - case None: return "None"; - case CandidateGathering: return "CandidateGathering"; - case EliminateRedudand: return "EliminateRedudand"; - case ComputingFoundations: return "ComputingFoundations"; - case StartingKeepAlives: return "StartingKeepAlives"; - case PrioritizingCandidates: return "PrioritizingCandidates"; - case ChoosingDefault: return "ChoosingDefault"; - case CreatingSDP: return "CreatingSDP"; - case ConnCheck: return "ConnCheck"; - case Failed: return "Failed"; - case Success: return "Success"; - } - return "Undefined"; + switch (state) + { + case None: + return "None"; + case CandidateGathering: + return "CandidateGathering"; + case EliminateRedudand: + return "EliminateRedudand"; + case ComputingFoundations: + return "ComputingFoundations"; + case StartingKeepAlives: + return "StartingKeepAlives"; + case PrioritizingCandidates: + return "PrioritizingCandidates"; + case ChoosingDefault: + return "ChoosingDefault"; + case CreatingSDP: + return "CreatingSDP"; + case ConnCheck: + return "ConnCheck"; + case Failed: + return "Failed"; + case Success: + return "Success"; + } + return "Undefined"; } // This class is intended to bring client binding results with candidates -class BindingAction: public Action +class BindingAction : public Action { public: - BindingAction(Stream& stream, StackConfig& config) - :Action(stream, config) - { - } + BindingAction(Stream& stream, StackConfig& config) : Action(stream, config) {} - virtual void finished(Transaction& st) - { - // Declare possible keepalive binding transaction - ClientBinding* kaBinding = NULL; - - // Cast finished transaction to ClientBinding - ClientBinding& cb = dynamic_cast(st); - - // Iterate local candidate to update values - for (unsigned i=0; i(st); + + // Iterate local candidate to update values + for (unsigned i = 0; i < mStream.mLocalCandidate.size(); i++) + { + Candidate& c = mStream.mLocalCandidate[i]; + if (c.mType == Candidate::ServerReflexive && c.mComponentId == st.component()) + { + // Update candidate state + c.mFailed = cb.state() == Transaction::Failed; + c.mReady = true; + if (!c.mFailed) + c.mExternalAddr = cb.mappedAddress(); + } + } + + if (cb.state() == Transaction::Success) + { + ICELogInfo(<< "Stack ID " << st.stackId() << ". Gathered reflexive address " + << cb.mappedAddress().toStdString()); + + // Delete other parallel gathering requests to avoid races + mStream.removeGatherRequests(st.component(), cb.failoverId(), &st); + + // Set working address + mStream.mConfig.mServerAddr4 = st.destination(); - // Set working address - mStream.mConfig.mServerAddr4 = st.destination(); - #ifdef ICE_ENABLE_KEEPALIVE - // Create keepalive transaction (it is usual Binding) - kaBinding = new ClientBinding(); - kaBinding->setStackId(mStream.mStackId); + // Create keepalive transaction (it is usual Binding) + kaBinding = new ClientBinding(); + kaBinding->setStackId(mStream.mStackId); - // Set destination address - kaBinding->setDestination(cb.transportType() == IPv4 ? mConfig.mServerAddr4 : mConfig.mServerAddr6); - - // Set source component port number - kaBinding->setComponent(st.component()); - kaBinding->setKeepalive(true); - kaBinding->setInterval(mConfig.mKeepAliveInterval); - mStream.mActiveChecks.addRegular(kaBinding); + // Set destination address + kaBinding->setDestination(cb.transportType() == IPv4 ? mConfig.mServerAddr4 : mConfig.mServerAddr6); + + // Set source component port number + kaBinding->setComponent(st.component()); + kaBinding->setKeepalive(true); + kaBinding->setInterval(mConfig.mKeepAliveInterval); + mStream.mActiveChecks.addRegular(kaBinding); #endif + } + else + { + ICELogCritical(<< "Stack ID " << st.stackId() << ". Failed to gather reflexive candidate."); + mStream.mErrorCode = cb.errorCode(); + } } - else - { - ICELogCritical( << "Stack ID " << st.stackId() << ". Failed to gather reflexive candidate."); - mStream.mErrorCode = cb.errorCode(); - } - } }; -class RelayingAction: public Action +class RelayingAction : public Action { protected: - bool mAutoreleaseAllocation; - + bool mAutoreleaseAllocation; + public: - RelayingAction(Stream& stream, StackConfig& config) - :Action(stream, config), mAutoreleaseAllocation(false) - { - } + RelayingAction(Stream& stream, StackConfig& config) : Action(stream, config), mAutoreleaseAllocation(false) {} - void autoreleaseAllocation() - { - mAutoreleaseAllocation = true; - } - - virtual void finished(Transaction& transaction) - { - ClientAllocate& ca = dynamic_cast(transaction); - - // Increase counter of finished Allocate requests - mStream.mFailoverRequestsFinished++; - ICELogDebug(<< "Increase failover gathering finished requests counter to " << mStream.mFailoverRequestsFinished); - - // Check if this Allocation must be freed ASAP - if (mAutoreleaseAllocation) + void autoreleaseAllocation() { mAutoreleaseAllocation = true; } + + virtual void finished(Transaction& transaction) { - if (ca.state() == Transaction::Success) - { - ICELogInfo(<< "Has to free this allocation as it is not needed due to failover scheme"); - // Increase counter of turn allocation for stream. It will be decreased again in ClientRefresh::processSuccessMessage - mStream.mTurnAllocated++; - - // Send deallocation message - ClientRefresh* allocation = new ClientRefresh(0, &mStream, &ca); - allocation->setKeepalive(false); - allocation->setDestination(ca.destination()); - mStream.mActiveChecks.addRegular(allocation); - } - return; - } - - // Save latest credentials from server - if (ca.realm().size() && ca.nonce().size()) - { - mStream.mCachedRealm = ca.realm(); - mStream.mCachedNonce = ca.nonce(); - } - - // Update local candidates - for (unsigned i=0; i(transaction); + + // Increase counter of finished Allocate requests + mStream.mFailoverRequestsFinished++; + ICELogDebug(<< "Increase failover gathering finished requests counter to " + << mStream.mFailoverRequestsFinished); + + // Check if this Allocation must be freed ASAP + if (mAutoreleaseAllocation) { - if (c.mType == Candidate::ServerReflexive) - c.mExternalAddr = ca.reflexiveAddress(); - else - if (c.mType == Candidate::ServerRelayed) - c.mExternalAddr = ca.relayedAddress(); - } - } - } + if (ca.state() == Transaction::Success) + { + ICELogInfo(<< "Has to free this allocation as it is not needed due to failover scheme"); + // Increase counter of turn allocation for stream. It will be decreased again in + // ClientRefresh::processSuccessMessage + mStream.mTurnAllocated++; - if (ca.state() == Transaction::Success) - { - ICELogInfo( << "Stack ID " << transaction.stackId() << ". Gathered reflexive address " << ca.reflexiveAddress().toStdString() << " and relayed address " << ca.relayedAddress().toStdString()); - - // Remove other parallel requests sent to be failover - mStream.removeGatherRequests(transaction.component(), transaction.failoverId(), &transaction); - - // Set working address - mStream.mConfig.mServerAddr4 = transaction.destination(); - - // Create keepalive transaction (cast lifetime parameter to milliseconds) -#ifdef ICE_ENABLE_KEEPALIVE - ClientRefresh* cf = new ClientRefresh( ca.lifetime(), &mStream, &ca ); - // Set 5 seconds interval to avoid NAT problems - cf->setInterval(5); - //cf->setInterval( ca.lifetime() / 2); - cf->setKeepalive( true ); - cf->setType( Transaction::KeepAlive ); - cf->setDestination(ca.destination()); - - // Defer transaction run to interval() value - cf->setTimestamp( ICETimeHelper::timestamp() ); - - // Increase counter of TURN allocations - mStream.mTurnAllocated++; - - // Associate Refresh transaction with retransmission timer - mStream.mActiveChecks.addRegular(cf); -#endif - } - else - { - ICELogCritical( << "Stack ID " << transaction.stackId() << ". Failed to gather reflexive/relayed addresses."); - bool ressurected = false; - // Check if single server is used and error code is 437 - in this case attempt to recover old Allocation will be made - if (mStream.mConfig.mServerList4.size() < 2 && ca.errorCode() == 437) - { - if (true == (ressurected = mStream.ressurectAllocation(transaction.component()))) - { - // Increase counter of TURN allocations - mStream.mTurnAllocated++; - - ICELogCritical(<< "Stack ID " << transaction.stackId() << ". Ressurected old Refresh transaction. Error will not be raized."); - } - } - - if (!ressurected) - mStream.mErrorCode = ca.errorCode(); - - // There is no any further processing here - result of transaction will be handled later - } - } -}; - -class CheckPairAction: public Action -{ - friend struct Stream; -public: - CheckPairAction(Stream& stream, StackConfig& config, PCandidatePair& p) - :Action(stream, config), mPair(p), mNomination(false), mAgentRole(stream.mAgentRole) - { - } - - virtual ~CheckPairAction() - { - } - - virtual void finished(Transaction& transaction) - { - CheckResult& cr = dynamic_cast(transaction); - - //ConnectivityCheck& cb = dynamic_cast(transaction); - - bool success = false; - if (cr.resultState() == Transaction::Failed) - { - // Handle role conflict - if (cr.resultError() == 487) - { - // Change session role - if (mAgentRole == RoleControlling) - mStream.mAgentRole = RoleControlled; - else - mStream.mAgentRole = RoleControlling; - - transaction.restart(); - return; - } - } - else - success = true; - - // A check is considered to be a success if all of the following are - // true: - //- the STUN transaction generated a success response - success &= cr.resultState() == Transaction::Success; - - if (success && mNomination && - mPair->nomination() != CandidatePair::Nomination_Finished) - { - ICELogInfo(<< "Received response for nominated request"); - - // Add keep-alive check - mStream.addKeepAliveCheck(*mPair); - - // Nomination is finished for this pair - mPair->setNomination(CandidatePair::Nomination_Finished); - - // Ensure RTCP component is unfrozen - mStream.unfreeze(mPair->foundation()); - - // Maybe processing for component is finished? - mStream.checkNominated(); - - return; - } - - // Reset transaction tag for checked pair - mPair->setTransaction(NULL); - - ICELogInfo ( << "Stack ID " << transaction.stackId() << ". Check " << mPair->toStdString() << " is " << (success ? "ok" : "failed") << "."); - - //- the source IP address and port of the response equals the - // destination IP address and port that the Binding Request was sent - // to - if (success) - success &= (cr.resultSource() == mPair->second().mExternalAddr); - - //- the destination IP address and port of the response match the - // source IP address and port that the Binding Request was sent from - mPair->setState(success ? CandidatePair::Succeeded : CandidatePair::Failed); - - if (success) - { - std::string foundation = mPair->foundation(); - mStream.dumpLocalCandidateList(); - unsigned li = mStream.findLocalCandidate( cr.resultLocal() ); - ICELogDebug( << "Looking for " << cr.resultLocal().toStdString() << " in local candidate list. Result index is " << int(li) ); - if ( li == NoIndex ) - { - // Add peer reflexive candidate - ICELogInfo(<< "Add peer reflexive candidate " << cr.resultLocal().toStdString()); - - // Its type is equal to peer reflexive. - Candidate cand(Candidate::PeerReflexive); - cand.mExternalAddr = cr.resultLocal(); - - // Its base is set equal to the local candidate of the candidate pair from which the STUN check was sent. - cand.mLocalAddr = mPair->first().mLocalAddr; - - // Its priority is set equal to the value of the PRIORITY attribute in the Binding Request. - cand.mPriority = cr.resultPriority(); - - // Its foundation is selected as described in Section 4.1.1. - cand.computeFoundation(); - - // This peer reflexive candidate is then added to the list of local - // candidates for the media stream - mStream.mLocalCandidate.push_back(cand); - - // The agent constructs a candidate pair whose local candidate equals - // the mapped address of the response, and whose remote candidate equals - // the destination address to which the request was sent. - CandidatePair _pair; - - // Use created local peer reflexive candidate - _pair.first() = cand; - - // Create new remote candidate - Candidate& newRemoteCand = _pair.second(); - newRemoteCand.mLocalAddr = cr.resultSource(); - newRemoteCand.mExternalAddr = cr.resultSource(); - newRemoteCand.mPriority = cr.resultPriority(); - newRemoteCand.computeFoundation(); - - _pair.updateFoundation(); - _pair.updatePriority(); - _pair.setRole(CandidatePair::Valid); - mStream.checkList().add(_pair); - - // Ensure reference to original ICECandidatePair is valid yet - ICELogInfo( << "Stack ID " << transaction.stackId() << ". Created peer reflexive candidate and corresponding pair " << _pair.toStdString() << " in valid list."); - } - else - { - ICELogInfo( << "Stack ID " << transaction.stackId() << ". Pair " << mPair->toStdString() <<" is add to valid list."); - mPair->setRole(CandidatePair::Valid); // And this pair is valid now - } - - // Now - unfreeze all pairs from the same queue and same foundation - mStream.unfreeze(foundation.c_str()); - mPair->setTransaction(&transaction); - - // Start regular nomination - if (mStream.mAgentRole == RoleControlling && !mNomination) - { - Component& component = mStream.mComponentMap[transaction.component()]; - - // If remote address is not LAN - maybe it should be delayed to give chance - // to finish LAN -> LAN checks before. - // ICE_NOMINATION_WAIT_INTERVAL is responsible for this - if (!mPair->second().mExternalAddr.isLAN() && ICE_NOMINATION_WAIT_INTERVAL != 0 && mStream.mState != Success) - { - // Check if - if (!component.mNominationWaitIntervalStartTime) - { - component.mNominationWaitIntervalStartTime = ICETimeHelper::timestamp(); + // Send deallocation message + ClientRefresh* allocation = new ClientRefresh(0, &mStream, &ca); + allocation->setKeepalive(false); + allocation->setDestination(ca.destination()); + mStream.mActiveChecks.addRegular(allocation); + } return; - } - else - { - unsigned currentTime = ICETimeHelper::timestamp(); - if (ICETimeHelper::findDelta(component.mNominationWaitIntervalStartTime, currentTime) >= ICE_NOMINATION_WAIT_INTERVAL) - mNomination = true; // Start nomination - } + } + + // Save latest credentials from server + if (ca.realm().size() && ca.nonce().size()) + { + mStream.mCachedRealm = ca.realm(); + mStream.mCachedNonce = ca.nonce(); + } + + // Update local candidates + for (unsigned i = 0; i < mStream.mLocalCandidate.size(); i++) + { + Candidate& c = mStream.mLocalCandidate[i]; + + // Avoid updating of successful candidates to failed state + if (c.mComponentId == ca.component() && (!c.mReady || c.mFailed)) + { + c.mReady = true; + c.mFailed = ca.state() == Transaction::Failed; + if (!c.mFailed) + { + if (c.mType == Candidate::ServerReflexive) + c.mExternalAddr = ca.reflexiveAddress(); + else if (c.mType == Candidate::ServerRelayed) + c.mExternalAddr = ca.relayedAddress(); + } + } + } + + if (ca.state() == Transaction::Success) + { + ICELogInfo(<< "Stack ID " << transaction.stackId() << ". Gathered reflexive address " + << ca.reflexiveAddress().toStdString() << " and relayed address " + << ca.relayedAddress().toStdString()); + + // Remove other parallel requests sent to be failover + mStream.removeGatherRequests(transaction.component(), transaction.failoverId(), &transaction); + + // Set working address + mStream.mConfig.mServerAddr4 = transaction.destination(); + + // Create keepalive transaction (cast lifetime parameter to milliseconds) +#ifdef ICE_ENABLE_KEEPALIVE + ClientRefresh* cf = new ClientRefresh(ca.lifetime(), &mStream, &ca); + // Set 5 seconds interval to avoid NAT problems + cf->setInterval(5); + // cf->setInterval( ca.lifetime() / 2); + cf->setKeepalive(true); + cf->setType(Transaction::KeepAlive); + cf->setDestination(ca.destination()); + + // Defer transaction run to interval() value + cf->setTimestamp(ICETimeHelper::timestamp()); + + // Increase counter of TURN allocations + mStream.mTurnAllocated++; + + // Associate Refresh transaction with retransmission timer + mStream.mActiveChecks.addRegular(cf); +#endif } else - mNomination = true; - - if (mNomination && mStream.mState != Success) { - component.mNominationWaitIntervalStartTime = 0; // Stop nomination interval timer - mStream.nominatePair(mPair); + ICELogCritical(<< "Stack ID " << transaction.stackId() + << ". Failed to gather reflexive/relayed addresses."); + bool ressurected = false; + // Check if single server is used and error code is 437 - in this case attempt to recover old Allocation + // will be made + if (mStream.mConfig.mServerList4.size() < 2 && ca.errorCode() == 437) + { + if (true == (ressurected = mStream.ressurectAllocation(transaction.component()))) + { + // Increase counter of TURN allocations + mStream.mTurnAllocated++; + + ICELogCritical(<< "Stack ID " << transaction.stackId() + << ". Ressurected old Refresh transaction. Error will not be raized."); + } + } + + if (!ressurected) + mStream.mErrorCode = ca.errorCode(); + + // There is no any further processing here - result of transaction will be handled later } - } } - else - mPair->setState(CandidatePair::Failed); - } +}; - PCandidatePair& getPair() - { - return mPair; - } +class CheckPairAction : public Action +{ + friend struct Stream; - void setNomination(bool value) - { - mNomination = value; - } +public: + CheckPairAction(Stream& stream, StackConfig& config, PCandidatePair& p) + : Action(stream, config), mPair(p), mNomination(false), mAgentRole(stream.mAgentRole) + { + } - bool nomination() const - { - return mNomination; - } + virtual ~CheckPairAction() {} + + virtual void finished(Transaction& transaction) + { + CheckResult& cr = dynamic_cast(transaction); + + // ConnectivityCheck& cb = dynamic_cast(transaction); + + bool success = false; + if (cr.resultState() == Transaction::Failed) + { + // Handle role conflict + if (cr.resultError() == 487) + { + // Change session role + if (mAgentRole == RoleControlling) + mStream.mAgentRole = RoleControlled; + else + mStream.mAgentRole = RoleControlling; + + transaction.restart(); + return; + } + } + else + success = true; + + // A check is considered to be a success if all of the following are + // true: + //- the STUN transaction generated a success response + success &= cr.resultState() == Transaction::Success; + + if (success && mNomination && mPair->nomination() != CandidatePair::Nomination_Finished) + { + ICELogInfo(<< "Received response for nominated request"); + + // Add keep-alive check + mStream.addKeepAliveCheck(*mPair); + + // Nomination is finished for this pair + mPair->setNomination(CandidatePair::Nomination_Finished); + + // Ensure RTCP component is unfrozen + mStream.unfreeze(mPair->foundation()); + + // Maybe processing for component is finished? + mStream.checkNominated(); + + return; + } + + // Reset transaction tag for checked pair + mPair->setTransaction(NULL); + + ICELogInfo(<< "Stack ID " << transaction.stackId() << ". Check " << mPair->toStdString() << " is " + << (success ? "ok" : "failed") << "."); + + //- the source IP address and port of the response equals the + // destination IP address and port that the Binding Request was sent + // to + if (success) + success &= (cr.resultSource() == mPair->second().mExternalAddr); + + //- the destination IP address and port of the response match the + // source IP address and port that the Binding Request was sent from + mPair->setState(success ? CandidatePair::Succeeded : CandidatePair::Failed); + + if (success) + { + std::string foundation = mPair->foundation(); + mStream.dumpLocalCandidateList(); + unsigned li = mStream.findLocalCandidate(cr.resultLocal()); + ICELogDebug(<< "Looking for " << cr.resultLocal().toStdString() + << " in local candidate list. Result index is " << int(li)); + if (li == NoIndex) + { + // Add peer reflexive candidate + ICELogInfo(<< "Add peer reflexive candidate " << cr.resultLocal().toStdString()); + + // Its type is equal to peer reflexive. + Candidate cand(Candidate::PeerReflexive); + cand.mExternalAddr = cr.resultLocal(); + + // Its base is set equal to the local candidate of the candidate pair from which the STUN check was + // sent. + cand.mLocalAddr = mPair->first().mLocalAddr; + + // Its priority is set equal to the value of the PRIORITY attribute in the Binding Request. + cand.mPriority = cr.resultPriority(); + + // Its foundation is selected as described in Section 4.1.1. + cand.computeFoundation(); + + // This peer reflexive candidate is then added to the list of local + // candidates for the media stream + mStream.mLocalCandidate.push_back(cand); + + // The agent constructs a candidate pair whose local candidate equals + // the mapped address of the response, and whose remote candidate equals + // the destination address to which the request was sent. + CandidatePair _pair; + + // Use created local peer reflexive candidate + _pair.first() = cand; + + // Create new remote candidate + Candidate& newRemoteCand = _pair.second(); + newRemoteCand.mLocalAddr = cr.resultSource(); + newRemoteCand.mExternalAddr = cr.resultSource(); + newRemoteCand.mPriority = cr.resultPriority(); + newRemoteCand.computeFoundation(); + + _pair.updateFoundation(); + _pair.updatePriority(); + _pair.setRole(CandidatePair::Valid); + mStream.checkList().add(_pair); + + // Ensure reference to original ICECandidatePair is valid yet + ICELogInfo(<< "Stack ID " << transaction.stackId() + << ". Created peer reflexive candidate and corresponding pair " << _pair.toStdString() + << " in valid list."); + } + else + { + ICELogInfo(<< "Stack ID " << transaction.stackId() << ". Pair " << mPair->toStdString() + << " is add to valid list."); + mPair->setRole(CandidatePair::Valid); // And this pair is valid now + } + + // Now - unfreeze all pairs from the same queue and same foundation + mStream.unfreeze(foundation.c_str()); + mPair->setTransaction(&transaction); + + // Start regular nomination + if (mStream.mAgentRole == RoleControlling && !mNomination) + { + Component& component = mStream.mComponentMap[transaction.component()]; + + // If remote address is not LAN - maybe it should be delayed to give chance + // to finish LAN -> LAN checks before. + // ICE_NOMINATION_WAIT_INTERVAL is responsible for this + if (!mPair->second().mExternalAddr.isLAN() && ICE_NOMINATION_WAIT_INTERVAL != 0 && + mStream.mState != Success) + { + // Check if + if (!component.mNominationWaitIntervalStartTime) + { + component.mNominationWaitIntervalStartTime = ICETimeHelper::timestamp(); + return; + } + else + { + unsigned currentTime = ICETimeHelper::timestamp(); + if (ICETimeHelper::findDelta(component.mNominationWaitIntervalStartTime, currentTime) >= + ICE_NOMINATION_WAIT_INTERVAL) + mNomination = true; // Start nomination + } + } + else + mNomination = true; + + if (mNomination && mStream.mState != Success) + { + component.mNominationWaitIntervalStartTime = 0; // Stop nomination interval timer + mStream.nominatePair(mPair); + } + } + } + else + mPair->setState(CandidatePair::Failed); + } + + PCandidatePair& getPair() { return mPair; } + + void setNomination(bool value) { mNomination = value; } + + bool nomination() const { return mNomination; } protected: - PCandidatePair mPair; /// Pair - bool mNomination; /// Nomination request flag - int mAgentRole; + PCandidatePair mPair; /// Pair + bool mNomination; /// Nomination request flag + int mAgentRole; }; - -//This class is intended to bring client binding results with candidates -class ICEInstallPermissionsAction: public Action +// This class is intended to bring client binding results with candidates +class ICEInstallPermissionsAction : public Action { protected: - InstallPermissionsCallback* mCallback; + InstallPermissionsCallback* mCallback; public: - ICEInstallPermissionsAction(Stream& stream, StackConfig& config, InstallPermissionsCallback* cb) - :Action(stream, config), mCallback(cb) - { - } - - ~ICEInstallPermissionsAction() - { - delete mCallback; - } - - virtual void finished(Transaction& st) - { - ClientCreatePermission& ccp = dynamic_cast(st); - int code = 0; - - if (st.state() == Transaction::Success) + ICEInstallPermissionsAction(Stream& stream, StackConfig& config, InstallPermissionsCallback* cb) + : Action(stream, config), mCallback(cb) { - ClientCreatePermission::IpList al = ccp.ipList(); - std::string iptext; - for (unsigned i=0; i(st); - code = auth.errorCode() ? auth.errorCode() : -1; + ClientCreatePermission& ccp = dynamic_cast(st); + int code = 0; + + if (st.state() == Transaction::Success) + { + ClientCreatePermission::IpList al = ccp.ipList(); + std::string iptext; + for (unsigned i = 0; i < al.size(); i++) + iptext += al[i].ip() + " "; + ICELogInfo(<< "TURN client permissions are installed for: " << iptext); + } + else + { + ICELogCritical(<< "Failed to install TURN client permissions."); + AuthTransaction& auth = dynamic_cast(st); + code = auth.errorCode() ? auth.errorCode() : -1; + } + if (mCallback) + mCallback->onPermissionsInstalled(mStream.mId, st.component(), code); } - if (mCallback) - mCallback->onPermissionsInstalled(mStream.mId, st.component(), code); - } }; static long GStackID = 0; Stream::Stream() { - mErrorCode = 0; - mState = None; - mFoundationGenerator = 0xFFFFFFFF; - mAgentRole = RoleControlling; - mDefaultIPChanged = false; - mCanTransmit = false; - - mStackId = Atomic::increment(&GStackID); - mTurnAllocated = 0; - mFailoverRequestsFinished = 0; - mFailoverIdGenerator = 0; + mErrorCode = 0; + mState = None; + mFoundationGenerator = 0xFFFFFFFF; + mAgentRole = RoleControlling; + mDefaultIPChanged = false; + mCanTransmit = false; + + mStackId = Atomic::increment(&GStackID); + mTurnAllocated = 0; + mFailoverRequestsFinished = 0; + mFailoverIdGenerator = 0; } -Stream::~Stream() -{ -} +Stream::~Stream() {} void Stream::setConfig(StackConfig& config) { - mCachedNonce.clear(); - mCachedRealm.clear(); - mConfig = config; + mCachedNonce.clear(); + mCachedRealm.clear(); + mConfig = config; } int Stream::addComponent(void* tag, unsigned short port4, unsigned short port6) { - int componentID = mComponentMap.size() + 1; + int componentID = mComponentMap.size() + 1; - Component& c = mComponentMap[componentID]; - c.mTag = tag; - c.mPort4 = port4; - c.mPort6 = port6; + Component& c = mComponentMap[componentID]; + c.mTag = tag; + c.mPort4 = port4; + c.mPort6 = port6; - return componentID; + return componentID; } void Stream::setAgentRole(AgentRole role) { - mAgentRole = role; + mAgentRole = role; } void Stream::setLocalPwd(const std::string& pwd) { - mLocalPwd = pwd; + mLocalPwd = pwd; } - + void Stream::setLocalUfrag(const std::string& ufrag) { - mLocalUfrag = ufrag; + mLocalUfrag = ufrag; } void Stream::setRemotePwd(const std::string& pwd) { - mRemotePwd = pwd; + mRemotePwd = pwd; } - + void Stream::setRemoteUfrag(const std::string& ufrag) { - mRemoteUfrag = ufrag; + mRemoteUfrag = ufrag; } void Stream::setTieBreaker(const std::string& tieBreaker) { - mTieBreaker = tieBreaker; + mTieBreaker = tieBreaker; } void Stream::gatherCandidates() { - ICELogInfo (<<"Stack ID " << mStackId << ". Attempt to gather candidates. Use IPv4 = " << mConfig.mUseIPv4 << ", IPv6 = " << mConfig.mUseIPv6); - mState = CandidateGathering; - mErrorCode = 0; - mFailoverRequestsFinished = 0; - mLocalCandidate.clear(); - mDefaultCandidate.clear(); - - // Get list of available IP interfaces - Lock l(NetworkHelper::instance().guard()); - std::vector& interfaceList = NetworkHelper::instance().interfaceList(); - for (auto& addr: interfaceList) - ICELogDebug(<< " " << addr.toStdString()); - - // See if there is public IP address - // Iterate components - - int numberOfActions = 0; - - ComponentMap::iterator componentIter; - for (componentIter = mComponentMap.begin(); componentIter != mComponentMap.end(); ++componentIter) - { - ICELogDebug(<< "Checking ICE component " << componentIter->first); - BindingAction* bindingAction = nullptr; - RelayingAction *relayingAction = nullptr, /**getIp6Action = nullptr,*/ *getIp4Action = nullptr; + ICELogInfo(<< "Stack ID " << mStackId << ". Attempt to gather candidates. Use IPv4 = " << mConfig.mUseIPv4 + << ", IPv6 = " << mConfig.mUseIPv6); + mState = CandidateGathering; + mErrorCode = 0; + mFailoverRequestsFinished = 0; + mLocalCandidate.clear(); + mDefaultCandidate.clear(); - // Clear binding results as new allocation will exists anyway - removeBindingResult(componentIter->first); + // Get list of available IP interfaces + Lock l(NetworkHelper::instance().guard()); + std::vector& interfaceList = NetworkHelper::instance().interfaceList(); + for (auto& addr : interfaceList) + ICELogDebug(<< " " << addr.toStdString()); - // Iterate available IP interfaces i.e. local IP addresses - for (unsigned interfaceIndex = 0; interfaceIndex < interfaceList.size(); interfaceIndex++) + // See if there is public IP address + // Iterate components + + int numberOfActions = 0; + + ComponentMap::iterator componentIter; + for (componentIter = mComponentMap.begin(); componentIter != mComponentMap.end(); ++componentIter) { - NetworkAddress& ipInterface = interfaceList[interfaceIndex]; - if (ipInterface.isLoopback() || ipInterface.isLinkLocal() || ipInterface.isZero()) - continue; - - ICELogInfo(<< "Checking interface " << ipInterface.toStdString()); - - // Find local port number for this - int port = ipInterface.family() == AF_INET ? componentIter->second.mPort4 : - componentIter->second.mPort6; + ICELogDebug(<< "Checking ICE component " << componentIter->first); + BindingAction* bindingAction = nullptr; + RelayingAction *relayingAction = nullptr, /**getIp6Action = nullptr,*/ *getIp4Action = nullptr; - // Define host candidate - Candidate host(Candidate::Host); - if ((ipInterface.family() == AF_INET && mConfig.mUseIPv4) || - (ipInterface.family() == AF_INET6 && mConfig.mUseIPv6)) - { - host.setLocalAndExternalAddresses(ipInterface, - ipInterface.family() == AF_INET6 ? componentIter->second.mPort6 : componentIter->second.mPort4); - host.mComponentId = componentIter->first; - host.mInterfacePriority = 0; - // Gathering of host candidate is finished - host.mReady = true; // Gathering finished - host.mFailed = false; // With success + // Clear binding results as new allocation will exists anyway + removeBindingResult(componentIter->first); - mLocalCandidate.push_back(host); - } + // Iterate available IP interfaces i.e. local IP addresses + for (unsigned interfaceIndex = 0; interfaceIndex < interfaceList.size(); interfaceIndex++) + { + NetworkAddress& ipInterface = interfaceList[interfaceIndex]; + if (ipInterface.isLoopback() || ipInterface.isLinkLocal() || ipInterface.isZero()) + continue; - // Check if IPv4 reflexive address is needed. - // It can be gathered with IPv4 relaying request also - bool needReflexiveAddr = mConfig.mUseIPv4 && mConfig.mServerList4.size() > 0; - - // Check if IPv4 relayed address is needed - bool needRelayingAddr = - mConfig.mUseIPv4 && mConfig.mServerList4.size() > 0 && mConfig.mUseTURN; + ICELogInfo(<< "Checking interface " << ipInterface.toStdString()); - // Check if 6-to-4 relaying is required - bool needIPv6ToIPv4 = !mConfig.mUseIPv4 && mConfig.mUseIPv6 && - !mConfig.mServerAddr6.isEmpty() && !mConfig.mServerAddr6.isZero() && mConfig.mUseProtocolRelay; + // Find local port number for this + int port = ipInterface.family() == AF_INET ? componentIter->second.mPort4 : componentIter->second.mPort6; - // Check if 4-to-6 relaying is required - /*bool needIPv4ToIPv6 = mConfig.mUseIPv4 && mConfig.mUseIPv6 && - mConfig.mServerList4.size() > 0 && mConfig.mUseProtocolRelay; - */ + // Define host candidate + Candidate host(Candidate::Host); + if ((ipInterface.family() == AF_INET && mConfig.mUseIPv4) || + (ipInterface.family() == AF_INET6 && mConfig.mUseIPv6)) + { + host.setLocalAndExternalAddresses(ipInterface, ipInterface.family() == AF_INET6 + ? componentIter->second.mPort6 + : componentIter->second.mPort4); + host.mComponentId = componentIter->first; + host.mInterfacePriority = 0; + // Gathering of host candidate is finished + host.mReady = true; // Gathering finished + host.mFailed = false; // With success - // Prepare candidate instances. - Candidate reflexive(Candidate::ServerReflexive); - Candidate relayed(Candidate::ServerRelayed); - - // Save initial local&external IP and port number - relayed.setLocalAndExternalAddresses( ipInterface, port ); - reflexive.setLocalAndExternalAddresses( ipInterface, port ); - - // Assign component ID - relayed.mComponentId = reflexive.mComponentId = componentIter->first; + mLocalCandidate.push_back(host); + } - // Put interface priority as zero - there is no configuration option for it yet - relayed.mInterfacePriority = reflexive.mInterfacePriority = 0; - - bool restOnPublic = false; + // Check if IPv4 reflexive address is needed. + // It can be gathered with IPv4 relaying request also + bool needReflexiveAddr = mConfig.mUseIPv4 && mConfig.mServerList4.size() > 0; + + // Check if IPv4 relayed address is needed + bool needRelayingAddr = mConfig.mUseIPv4 && mConfig.mServerList4.size() > 0 && mConfig.mUseTURN; + + // Check if 6-to-4 relaying is required + bool needIPv6ToIPv4 = !mConfig.mUseIPv4 && mConfig.mUseIPv6 && !mConfig.mServerAddr6.isEmpty() && + !mConfig.mServerAddr6.isZero() && mConfig.mUseProtocolRelay; + + // Check if 4-to-6 relaying is required + /*bool needIPv4ToIPv6 = mConfig.mUseIPv4 && mConfig.mUseIPv6 && + mConfig.mServerList4.size() > 0 && mConfig.mUseProtocolRelay; + */ + + // Prepare candidate instances. + Candidate reflexive(Candidate::ServerReflexive); + Candidate relayed(Candidate::ServerRelayed); + + // Save initial local&external IP and port number + relayed.setLocalAndExternalAddresses(ipInterface, port); + reflexive.setLocalAndExternalAddresses(ipInterface, port); + + // Assign component ID + relayed.mComponentId = reflexive.mComponentId = componentIter->first; + + // Put interface priority as zero - there is no configuration option for it yet + relayed.mInterfacePriority = reflexive.mInterfacePriority = 0; + + bool restOnPublic = false; #ifdef ICE_REST_ON_PUBLICIP - if ( ipInterface.isPublic() && ipInterface.type() == AF_INET ) - restOnPublic = true; + if (ipInterface.isPublic() && ipInterface.type() == AF_INET) + restOnPublic = true; #endif - // See if there we need reflexive candidate yet - if (mConfig.mUseSTUN && !restOnPublic && !bindingAction && - needReflexiveAddr && ipInterface.family() == AF_INET) - { - ICELogInfo(<< "Request reflexive address"); - // Add candidate to list - mLocalCandidate.push_back(reflexive); - - // Bind transaction to candidate - if (!bindingAction) - bindingAction = new BindingAction(*this, mConfig); - } + // See if there we need reflexive candidate yet + if (mConfig.mUseSTUN && !restOnPublic && !bindingAction && needReflexiveAddr && + ipInterface.family() == AF_INET) + { + ICELogInfo(<< "Request reflexive address"); + // Add candidate to list + mLocalCandidate.push_back(reflexive); - if (mConfig.mUseTURN && !restOnPublic && !relayingAction && needRelayingAddr) - { - ICELogInfo(<< "Request relayed address"); - // Add relayed candidate to list - mLocalCandidate.push_back(relayed); - - // Add reflexive candidate to list - mLocalCandidate.push_back(reflexive); + // Bind transaction to candidate + if (!bindingAction) + bindingAction = new BindingAction(*this, mConfig); + } - // Bind allocation to reflexive candidate - if (!relayingAction) - relayingAction = new RelayingAction(*this, mConfig); - } + if (mConfig.mUseTURN && !restOnPublic && !relayingAction && needRelayingAddr) + { + ICELogInfo(<< "Request relayed address"); + // Add relayed candidate to list + mLocalCandidate.push_back(relayed); - if (!getIp4Action && needIPv6ToIPv4 && ipInterface.family() == AF_INET6) - { - ICELogInfo(<< "Requesting IPv6 to IPv4 relay."); - Candidate c(Candidate::ServerRelayed); - c.setLocalAndExternalAddresses(ipInterface, port); - c.mInterfacePriority = 0; - c.mComponentId = componentIter->first; - mLocalCandidate.push_back(relayed); - getIp4Action = new RelayingAction(*this, mConfig); - } - - /* - if (!getIp6Action && needIPv4ToIPv6 && ipInterface.type() == AF_INET) - { - ICELogInfo(<< "Requesting IPv4 to IPv6 relay."); - Candidate c(Candidate::ServerRelayed); - c.setLocalAndExternalAddresses(ipInterface, port); - c.mInterfacePriority = 0; - c.mComponentId = componentIter->first; - mLocalCandidate.push_back(relayed); - getIp6Action = new RelayingAction(*this, mConfig); - } - */ + // Add reflexive candidate to list + mLocalCandidate.push_back(reflexive); + + // Bind allocation to reflexive candidate + if (!relayingAction) + relayingAction = new RelayingAction(*this, mConfig); + } + + if (!getIp4Action && needIPv6ToIPv4 && ipInterface.family() == AF_INET6) + { + ICELogInfo(<< "Requesting IPv6 to IPv4 relay."); + Candidate c(Candidate::ServerRelayed); + c.setLocalAndExternalAddresses(ipInterface, port); + c.mInterfacePriority = 0; + c.mComponentId = componentIter->first; + mLocalCandidate.push_back(relayed); + getIp4Action = new RelayingAction(*this, mConfig); + } + + /* + if (!getIp6Action && needIPv4ToIPv6 && ipInterface.type() == AF_INET) + { + ICELogInfo(<< "Requesting IPv4 to IPv6 relay."); + Candidate c(Candidate::ServerRelayed); + c.setLocalAndExternalAddresses(ipInterface, port); + c.mInterfacePriority = 0; + c.mComponentId = componentIter->first; + mLocalCandidate.push_back(relayed); + getIp6Action = new RelayingAction(*this, mConfig); + } + */ + } + + if (bindingAction) + { + bind(mConfig.mServerAddr4, PAction(bindingAction), false /*it is gathering!*/, componentIter->first, + mConfig.mServerList4.empty() ? FailoverOff : FailoverOn); + numberOfActions++; + } + if (relayingAction) + { + ICELogDebug(<< "Request relayed candidate IPv4 <-> IPv4."); + AllocateOptions options; + options.mActionOnFinish = PAction(relayingAction); + options.mComponent = componentIter->first; + options.mFailoverOption = mConfig.mServerList4.empty() ? FailoverOff : FailoverOn; + options.mServerAddress = mConfig.mServerAddr4; + allocate(options); + numberOfActions++; + } + + if (getIp4Action) + { + ICELogDebug(<< "Request relayed candidate IPv6 <-> IPv4."); + AllocateOptions options; + options.mActionOnFinish = PAction(getIp4Action); + options.mComponent = componentIter->first; + options.mFailoverOption = mConfig.mServerList6.empty() ? FailoverOff : FailoverOn; + options.mServerAddress = mConfig.mServerAddr6; + options.mWireFamily = AF_INET6; + options.mAllocFamily = AF_INET; + // Ask TURN server to allocation IPv4 address via IPv6 address + allocate(options); + numberOfActions++; + } + + // SDK does not use IPv4 to IPv6 relaying for now. Reverse direction has to be used instead. + /* + if (getIp6Action) + { + AllocateOptions options; + options.mActionOnFinish = PAction(getIp6Action); + options.mComponent = componentIter->first; + options.mAllocFamily = AF_INET6; + options.mWireFamily = AF_INET; + options.mServerAddress = mConfig.mServerAddr4; + options.mFailoverOption = mConfig.mServerList4.empty() ? FailoverOff : FailoverOn; + // Ask TURN server to allocate IPv6 address via IPv4 socket + allocate(options); + numberOfActions++; + }*/ } - if (bindingAction) + if (!numberOfActions) { - bind(mConfig.mServerAddr4, PAction(bindingAction), false/*it is gathering!*/, componentIter->first, mConfig.mServerList4.empty() ? FailoverOff : FailoverOn); - numberOfActions++; + mState = EliminateRedudand; + processStateChain(); } - if (relayingAction) - { - ICELogDebug(<< "Request relayed candidate IPv4 <-> IPv4."); - AllocateOptions options; - options.mActionOnFinish = PAction(relayingAction); - options.mComponent = componentIter->first; - options.mFailoverOption = mConfig.mServerList4.empty() ? FailoverOff : FailoverOn; - options.mServerAddress = mConfig.mServerAddr4; - allocate(options); - numberOfActions++; - } - - if (getIp4Action) - { - ICELogDebug(<< "Request relayed candidate IPv6 <-> IPv4."); - AllocateOptions options; - options.mActionOnFinish = PAction(getIp4Action); - options.mComponent = componentIter->first; - options.mFailoverOption = mConfig.mServerList6.empty() ? FailoverOff : FailoverOn; - options.mServerAddress = mConfig.mServerAddr6; - options.mWireFamily = AF_INET6; - options.mAllocFamily = AF_INET; - // Ask TURN server to allocation IPv4 address via IPv6 address - allocate(options); - numberOfActions++; - } - - // SDK does not use IPv4 to IPv6 relaying for now. Reverse direction has to be used instead. - /* - if (getIp6Action) - { - AllocateOptions options; - options.mActionOnFinish = PAction(getIp6Action); - options.mComponent = componentIter->first; - options.mAllocFamily = AF_INET6; - options.mWireFamily = AF_INET; - options.mServerAddress = mConfig.mServerAddr4; - options.mFailoverOption = mConfig.mServerList4.empty() ? FailoverOff : FailoverOn; - // Ask TURN server to allocate IPv6 address via IPv4 socket - allocate(options); - numberOfActions++; - }*/ - - } - - if (!numberOfActions) - { - mState = EliminateRedudand; - processStateChain(); - } } CheckList& Stream::checkList() { - return mCheckList; + return mCheckList; } void Stream::allocate(const AllocateOptions& options) { - assert(options.mComponent != -1); - - if (options.mFailoverOption == FailoverOn) - { - // If failover scheme is required - spread requests to few servers - std::vector& servers = options.mWireFamily == AF_INET ? mConfig.mServerList4 : mConfig.mServerList6; - int failoverId = ++mFailoverIdGenerator; - for (std::vector::iterator addrIter = servers.begin(); addrIter != servers.end(); addrIter++) - { - AllocateOptions options2(options); - options2.mServerAddress = *addrIter; - options2.mFailoverId = failoverId; - options2.mFailoverOption = FailoverOff; - allocate(options2); - } - } - else - { - ClientAllocate* allocation = new ClientAllocate(mConfig.mTurnLifetime); - allocation->setStackId(mStackId); - allocation->setWireFamily(options.mWireFamily); - allocation->setAllocFamily(options.mAllocFamily); - allocation->setDestination(options.mServerAddress); - allocation->setComponent(options.mComponent); - allocation->setFailoverId(options.mFailoverId); - - // Use auth for TURN server - allocation->setPassword(mConfig.mTurnPassword); - allocation->setUsername(mConfig.mTurnUsername); + assert(options.mComponent != -1); - // Associate it with action - allocation->setAction(options.mActionOnFinish); - - mActiveChecks.addRegular(allocation); - } + if (options.mFailoverOption == FailoverOn) + { + // If failover scheme is required - spread requests to few servers + std::vector& servers = + options.mWireFamily == AF_INET ? mConfig.mServerList4 : mConfig.mServerList6; + int failoverId = ++mFailoverIdGenerator; + for (std::vector::iterator addrIter = servers.begin(); addrIter != servers.end(); addrIter++) + { + AllocateOptions options2(options); + options2.mServerAddress = *addrIter; + options2.mFailoverId = failoverId; + options2.mFailoverOption = FailoverOff; + allocate(options2); + } + } + else + { + ClientAllocate* allocation = new ClientAllocate(mConfig.mTurnLifetime); + allocation->setStackId(mStackId); + allocation->setWireFamily(options.mWireFamily); + allocation->setAllocFamily(options.mAllocFamily); + allocation->setDestination(options.mServerAddress); + allocation->setComponent(options.mComponent); + allocation->setFailoverId(options.mFailoverId); + + // Use auth for TURN server + allocation->setPassword(mConfig.mTurnPassword); + allocation->setUsername(mConfig.mTurnUsername); + + // Associate it with action + allocation->setAction(options.mActionOnFinish); + + mActiveChecks.addRegular(allocation); + } } void Stream::bind(const NetworkAddress& dest, PAction action, bool /*auth*/, int component, Failover f) { - assert(component != -1); - - if (f == FailoverOn) - { - for (std::vector::iterator addrIter = mConfig.mServerList4.begin(); addrIter != mConfig.mServerList4.end(); addrIter++) + assert(component != -1); + + if (f == FailoverOn) { - bind(*addrIter, action, false, component, FailoverOff); + for (std::vector::iterator addrIter = mConfig.mServerList4.begin(); + addrIter != mConfig.mServerList4.end(); addrIter++) + { + bind(*addrIter, action, false, component, FailoverOff); + } } - } - else - { - ClientBinding* binding = new ClientBinding(); - binding->setStackId(mStackId); - binding->setDestination(dest); - binding->setComponent(component); + else + { + ClientBinding* binding = new ClientBinding(); + binding->setStackId(mStackId); + binding->setDestination(dest); + binding->setComponent(component); - // Associate it with action - binding->setAction(action); + // Associate it with action + binding->setAction(action); - mActiveChecks.addRegular(binding); - } + mActiveChecks.addRegular(binding); + } } bool Stream::hasPortNumber(int family, unsigned short portNumber, int* component) { - ComponentMap::iterator componentIterator; - for (componentIterator = mComponentMap.begin(); componentIterator != mComponentMap.end(); ++componentIterator) - { - if ((family == AF_INET && componentIterator->second.mPort4 == portNumber) || - (family == AF_INET6 && componentIterator->second.mPort6 == portNumber)) + ComponentMap::iterator componentIterator; + for (componentIterator = mComponentMap.begin(); componentIterator != mComponentMap.end(); ++componentIterator) { - if (component) - *component = componentIterator->first; - return true; - } - } - - return false; + if ((family == AF_INET && componentIterator->second.mPort4 == portNumber) || + (family == AF_INET6 && componentIterator->second.mPort6 == portNumber)) + { + if (component) + *component = componentIterator->first; + return true; + } + } + + return false; } -unsigned Stream::findRemoteCandidate(const NetworkAddress& addr, int componentID) +unsigned Stream::findRemoteCandidate(const NetworkAddress& addr, int componentID) { - for (size_t i=0; i(p.transaction()))) - { - ICELogInfo(<< "Transaction for pair " << p.toStdString() << " is cancelled"); - mActiveChecks.erase((Transaction*)p.transaction()); - } + if (mActiveChecks.exists(reinterpret_cast(p.transaction()))) + { + ICELogInfo(<< "Transaction for pair " << p.toStdString() << " is cancelled"); + mActiveChecks.erase((Transaction*)p.transaction()); + } } -class EraseBindingAndRelaying: public TransactionCondition +class EraseBindingAndRelaying : public TransactionCondition { public: - bool check(Transaction* t) const - { - ClientRefresh* c = dynamic_cast(t); - if (c) + bool check(Transaction* t) const { - if (!c->lifetime()) + ClientRefresh* c = dynamic_cast(t); + if (c) + { + if (!c->lifetime()) + return false; + } + + if ((Transaction::Binding | Transaction::Relaying) & t->type()) + return true; + return false; } - - if ((Transaction::Binding | Transaction::Relaying) & t->type()) - return true; - - return false; - } }; -class KeepDeallocationRequest: public TransactionCondition +class KeepDeallocationRequest : public TransactionCondition { public: - bool check(Transaction* t) const - { - ClientRefresh* c = dynamic_cast(t); - if (c) + bool check(Transaction* t) const { - if (!c->lifetime()) - return false; + ClientRefresh* c = dynamic_cast(t); + if (c) + { + if (!c->lifetime()) + return false; + } + return true; } - return true; - } }; void Stream::cancelAllocations() { - mActiveChecks.erase(KeepDeallocationRequest()); + mActiveChecks.erase(KeepDeallocationRequest()); } void Stream::handleBindingRequest(ServerBinding& binding, ByteBuffer& buffer, int component) { - if (mComponentMap.find(component) == mComponentMap.end()) - return; + if (mComponentMap.find(component) == mComponentMap.end()) + return; - // If the source transport address of the request does not match any - // existing remote candidates, it represents a new peer reflexive remote - // candidate. This candidate is constructed as follows: - unsigned candidateIndex = findRemoteCandidate(buffer.remoteAddress(), component); - if (candidateIndex == NoIndex) - { - ICELogInfo(<< "Stack ID " << mStackId << ". Remote candidate with address " << buffer.remoteAddress().toStdString() << " is not found so creating peer reflexive candidate."); - - // Construct candidate - Candidate newRemoteCand(Candidate::PeerReflexive); - - // Set priority from request's priority attribute - newRemoteCand.mPriority = binding.priorityValue(); - - // Set address - newRemoteCand.setLocalAndExternalAddresses(buffer.remoteAddress()); - - // The foundation of the candidate is set to an arbitrary value, - // different from the foundation for all other remote candidates. If - // any subsequent offer/answer exchanges contain this peer reflexive - // candidate in the SDP, it will signal the actual foundation for the - // candidate. - sprintf(newRemoteCand.mFoundation, "%u", --mFoundationGenerator); - - // The component ID of this candidate is set to the component ID for - // the local candidate to which the request was sent. - newRemoteCand.mComponentId = component; - - // This candidate is added to the list of remote candidates. However, - // the agent does not pair this candidate with any local candidates. - mRemoteCandidate.push_back(newRemoteCand); - - candidateIndex = (unsigned)mRemoteCandidate.size()-1; - } - - // Next, the agent constructs a pair whose local candidate is equal to - // the transport address on which the STUN request was received, and a - // remote candidate equal to the source transport address where the - // request came from (which may be peer-reflexive remote candidate that - // was just learned). - CandidatePair _pair; - - // Find local transport address (IP) - NetworkAddress interfaceIP; - if (buffer.relayed()) - { - // Find relayed ip:port for given component - for (unsigned i=0; isetNomination(CandidatePair::Nomination_Finished); - - ICELogInfo(<< "Stack ID " << mStackId << ". Pair " << existingPair->toStdString() - << " already exists in check list. Its state is " - << CandidatePair::stateToString(existingPair->state())); - - if (mConfig.mTreatRequestAsConfirmation) + // Find local transport address (IP) + NetworkAddress interfaceIP; + if (buffer.relayed()) { - if (existingPair->transaction()) - { - ConnectivityCheck* cc = dynamic_cast((Transaction*)existingPair->transaction()); - if (cc) + // Find relayed ip:port for given component + for (unsigned i = 0; i < mLocalCandidate.size(); i++) + if (mLocalCandidate[i].mType == Candidate::ServerRelayed && + mLocalCandidate[i].component() == buffer.component()) + interfaceIP = mLocalCandidate[i].mExternalAddr; + } + + // If looking for relayed candidate failed or it is not relayed candidate at all - just find source interface for + // peer address + if (interfaceIP.isEmpty()) + { + interfaceIP = NetworkHelper::instance().sourceInterface(buffer.remoteAddress()); + + // Find local port number + switch (buffer.remoteAddress().family()) { - if (!cc->removed()) - cc->confirmTransaction(buffer.remoteAddress()); + case AF_INET: + interfaceIP.setPort(mComponentMap[buffer.component()].mPort4); + break; + + case AF_INET6: + interfaceIP.setPort(mComponentMap[buffer.component()].mPort6); + break; } - } } - // There can be one of several outcomes: - // If the state of that pair is Waiting or Frozen, a check for - // that pair is enqueued into the triggered check queue if not - // already present. - switch (existingPair->state()) + // And try to find local candidate with such address - addrToFind + unsigned existingLocalCandIndex = findLocalCandidate(interfaceIP); + + // There MUST be such candidate! + if (existingLocalCandIndex == NoIndex) { - case CandidatePair::Frozen: - case CandidatePair::Waiting: - existingPair->setRole(CandidatePair::Triggered); - existingPair->setState(CandidatePair::Waiting); - break; - - case CandidatePair::InProgress: - // If the state of that pair is In-Progress, the agent cancels the - // in-progress transaction. Cancellation means that the agent - // will not retransmit the request, will not treat the lack of - // response to be a failure, but will wait the duration of the - // transaction timeout for a response. In addition, the agent - // MUST create a new connectivity check for that pair - // (representing a new STUN Binding Request transaction) by - // enqueuing the pair in the triggered check queue. The state of - // the pair is then changed to Waiting. - if (existingPair->role() == CandidatePair::Regular) - { - cancelCheck(*existingPair); - existingPair->setState(CandidatePair::Waiting); - existingPair->setRole(CandidatePair::Triggered); - - // Re-run new check in prioritized list - Transaction* t = createCheckRequest(existingPair); - if (buffer.relayed()) - { - t->setComment("Check from " + existingPair->first().mExternalAddr.toStdString() + - " to " + existingPair->second().mExternalAddr.toStdString()); - t->setRelayed(true); - } - existingPair->setTransaction(t); - mActiveChecks.addPrioritized(t); - } - break; - - case CandidatePair::Failed: - // If the state of the pair is Failed, it is changed to Waiting - // and the agent MUST create a new connectivity check for that - // pair (representing a new STUN Binding Request transaction), by - // enqueuing the pair in the triggered check queue. - existingPair->setState(CandidatePair::Waiting); - existingPair->setRole(CandidatePair::Triggered); - break; - - case CandidatePair::Succeeded: - //existingPair.setNominated(); - break; + unsigned short port = interfaceIP.port(); + std::string ip = interfaceIP.ip(); + ICELogCritical(<< "Failed to find local candidate for " << ip << ":" << port << ". Ignoring binding request"); + return; } - } - else - { - // If the pair is not already on the check list: - // The pair is inserted into the check list based on its priority - // Its state is set to Waiting - _pair.setState(CandidatePair::Waiting); - _pair.setRole(CandidatePair::Triggered); - ICELogInfo(<< "Stack ID " << mStackId << ". Adding pair " << _pair.toStdString() << " to triggered check list"); - mCheckList.add(_pair); - ICELogInfo(<< "Resulting check list is \r\n" << mCheckList.toStdString()); - } + // Construct pair + _pair.first() = mLocalCandidate[existingLocalCandIndex]; + _pair.second() = mRemoteCandidate[candidateIndex]; + + // Since both candidates are known to the agent, it + // can obtain their priorities and compute the candidate pair priority. + _pair.updateFoundation(); + _pair.updatePriority(); + + ICELogInfo(<< "Stack ID " << mStackId << ". Constructed candidate pair " << _pair.toStdString()); + + if (mAgentRole == RoleControlled && binding.hasUseCandidate()) + { + _pair.setNomination(CandidatePair::Nomination_Finished); + ICELogInfo(<< "Stack ID " << mStackId << ". Pair " << _pair.toStdString() + << " nominated as received incoming Binding request with UseCandidate attribute."); + } + + // This pair is then looked up in the check list. + PCandidatePair existingPair = mCheckList.findEqualPair(_pair, CheckList::CT_TreatHostAsUniform); + + if (existingPair) + { + // Nominate new pair if the similar pair was nominated before + if (_pair.nomination() == CandidatePair::Nomination_Finished) + existingPair->setNomination(CandidatePair::Nomination_Finished); + + ICELogInfo(<< "Stack ID " << mStackId << ". Pair " << existingPair->toStdString() + << " already exists in check list. Its state is " + << CandidatePair::stateToString(existingPair->state())); + + if (mConfig.mTreatRequestAsConfirmation) + { + if (existingPair->transaction()) + { + ConnectivityCheck* cc = dynamic_cast((Transaction*)existingPair->transaction()); + if (cc) + { + if (!cc->removed()) + cc->confirmTransaction(buffer.remoteAddress()); + } + } + } + + // There can be one of several outcomes: + // If the state of that pair is Waiting or Frozen, a check for + // that pair is enqueued into the triggered check queue if not + // already present. + switch (existingPair->state()) + { + case CandidatePair::Frozen: + case CandidatePair::Waiting: + existingPair->setRole(CandidatePair::Triggered); + existingPair->setState(CandidatePair::Waiting); + break; + + case CandidatePair::InProgress: + // If the state of that pair is In-Progress, the agent cancels the + // in-progress transaction. Cancellation means that the agent + // will not retransmit the request, will not treat the lack of + // response to be a failure, but will wait the duration of the + // transaction timeout for a response. In addition, the agent + // MUST create a new connectivity check for that pair + // (representing a new STUN Binding Request transaction) by + // enqueuing the pair in the triggered check queue. The state of + // the pair is then changed to Waiting. + if (existingPair->role() == CandidatePair::Regular) + { + cancelCheck(*existingPair); + existingPair->setState(CandidatePair::Waiting); + existingPair->setRole(CandidatePair::Triggered); + + // Re-run new check in prioritized list + Transaction* t = createCheckRequest(existingPair); + if (buffer.relayed()) + { + t->setComment("Check from " + existingPair->first().mExternalAddr.toStdString() + " to " + + existingPair->second().mExternalAddr.toStdString()); + t->setRelayed(true); + } + existingPair->setTransaction(t); + mActiveChecks.addPrioritized(t); + } + break; + + case CandidatePair::Failed: + // If the state of the pair is Failed, it is changed to Waiting + // and the agent MUST create a new connectivity check for that + // pair (representing a new STUN Binding Request transaction), by + // enqueuing the pair in the triggered check queue. + existingPair->setState(CandidatePair::Waiting); + existingPair->setRole(CandidatePair::Triggered); + break; + + case CandidatePair::Succeeded: + // existingPair.setNominated(); + break; + } + } + else + { + // If the pair is not already on the check list: + // The pair is inserted into the check list based on its priority + + // Its state is set to Waiting + _pair.setState(CandidatePair::Waiting); + _pair.setRole(CandidatePair::Triggered); + ICELogInfo(<< "Stack ID " << mStackId << ". Adding pair " << _pair.toStdString() << " to triggered check list"); + mCheckList.add(_pair); + ICELogInfo(<< "Resulting check list is \r\n" << mCheckList.toStdString()); + } } bool Stream::processData(StunMessage& msg, ByteBuffer& buffer, int component) { - bool result = true; - - // Depending on the state call the handler - if (mState < CreatingSDP) - { - result = handleCgIn(msg, buffer.remoteAddress()); - if (result) - processStateChain(); + bool result = true; + + // Depending on the state call the handler + if (mState < CreatingSDP) + { + result = handleCgIn(msg, buffer.remoteAddress()); + if (result) + processStateChain(); + return result; + } + else if (mState >= ConnCheck) + { + if (handleConnChecksIn(msg, buffer.remoteAddress())) + { + ICELogDebug(<< "Found response for transaction from " << buffer.remoteAddress().toStdString()); + checkNominated(); + return true; + } + } + else if (handleConnChecksIn(msg, buffer.remoteAddress())) + return true; + + + // Check if source address&request belongs to TURN server - so it is relayed candidate in action + if (buffer.remoteAddress() == mConfig.mServerAddr4) + { + if (buffer.size() < 4) + return false; + + TurnPrefix prefix = *reinterpret_cast(buffer.data()); + + // For requests being received on a relayed candidate, the source + // transport address used for STUN processing (namely, generation of the + // XOR-MAPPED-ADDRESS attribute) is the transport address as seen by the + // TURN server. That source transport address will be present in the + // REMOTE-ADDRESS attribute of a Data Indication message, if the Binding + // Request was delivered through a Data Indication (a TURN server + // delivers packets encapsulated in a Data Indication when no active + // destination is set). If the Binding Request was not encapsulated in + // a Data Indication, that source address is equal to the current active + // destination for the TURN session. + + // check channel binding prefix + if (mTurnPrefixMap.find(prefix) != mTurnPrefixMap.end()) + { + NetworkAddress& sourceAddr = mTurnPrefixMap[prefix]; + buffer.setRemoteAddress(sourceAddr); + buffer.erase(0, 4); + buffer.setRelayed(true); + } + } + + handleIncomingRequest(msg, buffer, component); + + if (mCheckList.state() == CheckList::Failed) + mState = Failed; + else + checkNominated(); + return result; - } - else - if (mState >= ConnCheck) - { - if (handleConnChecksIn(msg, buffer.remoteAddress())) - { - ICELogDebug(<< "Found response for transaction from " << buffer.remoteAddress().toStdString()); - checkNominated(); - return true; - } - } - else - if (handleConnChecksIn(msg, buffer.remoteAddress())) - return true; - - - // Check if source address&request belongs to TURN server - so it is relayed candidate in action - if (buffer.remoteAddress() == mConfig.mServerAddr4) - { - if (buffer.size() < 4) - return false; - - TurnPrefix prefix = *reinterpret_cast(buffer.data()); - - // For requests being received on a relayed candidate, the source - // transport address used for STUN processing (namely, generation of the - // XOR-MAPPED-ADDRESS attribute) is the transport address as seen by the - // TURN server. That source transport address will be present in the - // REMOTE-ADDRESS attribute of a Data Indication message, if the Binding - // Request was delivered through a Data Indication (a TURN server - // delivers packets encapsulated in a Data Indication when no active - // destination is set). If the Binding Request was not encapsulated in - // a Data Indication, that source address is equal to the current active - // destination for the TURN session. - - //check channel binding prefix - if (mTurnPrefixMap.find(prefix) != mTurnPrefixMap.end()) - { - NetworkAddress& sourceAddr = mTurnPrefixMap[prefix]; - buffer.setRemoteAddress(sourceAddr); - buffer.erase(0, 4); - buffer.setRelayed(true); - } - } - - handleIncomingRequest(msg, buffer, component); - - if (mCheckList.state() == CheckList::Failed) - mState = Failed; - else - checkNominated(); - - return result; } bool Stream::handleCgIn(StunMessage& msg, NetworkAddress& address) { - if (!mActiveChecks.processIncoming(msg, address)) - return false; - if (mLocalCandidate.empty()) - return true; - - // Check if failover and relaying is used - if (mConfig.mUseTURN && !mConfig.mServerList4.empty()) - { - int successCounter = 0, failedCounter = 0; - for (size_t i=0; i= mLocalCandidate.size()) + if (!mActiveChecks.processIncoming(msg, address)) + return false; + if (mLocalCandidate.empty()) + return true; + + // Check if failover and relaying is used + if (mConfig.mUseTURN && !mConfig.mServerList4.empty()) { - // Shift to next state - ICELogInfo(<< "All candidates succeeded, shift to EliminateRedudand"); - mState = EliminateRedudand; + int successCounter = 0, failedCounter = 0; + for (size_t i = 0; i < mLocalCandidate.size(); i++) + if (mLocalCandidate[i].mReady) + { + if (mLocalCandidate[i].mFailed) + failedCounter++; + else + successCounter++; + } + ICELogDebug(<< "Succeed " << successCounter << " candidates, failed " << failedCounter << " candidates from " + << (int)mLocalCandidate.size()); + if ((size_t)successCounter >= mLocalCandidate.size()) + { + // Shift to next state + ICELogInfo(<< "All candidates succeeded, shift to EliminateRedudand"); + mState = EliminateRedudand; + } + else + { + // See if all gathering requests are performed. + if ((size_t)mFailoverRequestsFinished == mConfig.mServerList4.size() * mComponentMap.size()) + { + ICELogInfo(<< "All failover gathering requests finished, shift to Failed"); + mState = Failed; + } + } } else { - // See if all gathering requests are performed. - if ((size_t)mFailoverRequestsFinished == mConfig.mServerList4.size() * mComponentMap.size()) - { - ICELogInfo(<< "All failover gathering requests finished, shift to Failed"); - mState = Failed; - } + // Look if all gathering checks are finished + bool finished = true; + + for (size_t i = 0; i < mLocalCandidate.size() && finished; i++) + if (false == mLocalCandidate[i].mReady) + finished &= false; + + // NOTE! Checking for timeout is made in other place! + if (finished && mState != /*RunningState::*/ Failed) + mState = EliminateRedudand; } - } - else - { - // Look if all gathering checks are finished - bool finished = true; - - for (size_t i=0; i c2.mExternalAddr.port()) return true; - else - if (c1.mExternalAddr.port() < c2.mExternalAddr.port()) - return false; - - if (c1.mExternalAddr.ip() > c2.mExternalAddr.ip()) - return true; - else - return false; } -bool RedudandCand( const ice::Candidate& c1, const ice::Candidate& c2) + +bool FailedCand(const ice::Candidate& value) { - return c1.mExternalAddr == c2.mExternalAddr; + return value.mFailed; +} + +bool GreaterCand(const ice::Candidate& c1, const ice::Candidate& c2) +{ + if (c1.mExternalAddr.port() > c2.mExternalAddr.port()) + return true; + else if (c1.mExternalAddr.port() < c2.mExternalAddr.port()) + return false; + + if (c1.mExternalAddr.ip() > c2.mExternalAddr.ip()) + return true; + else + return false; +} + +bool RedudandCand(const ice::Candidate& c1, const ice::Candidate& c2) +{ + return c1.mExternalAddr == c2.mExternalAddr; } void Stream::Handle_ER() { - // Remove failed candidates (without STUN/TURN responses) - mLocalCandidate.erase(std::remove_if(mLocalCandidate.begin(), mLocalCandidate.end(), - FailedCand), mLocalCandidate.end()); + // Remove failed candidates (without STUN/TURN responses) + mLocalCandidate.erase(std::remove_if(mLocalCandidate.begin(), mLocalCandidate.end(), FailedCand), + mLocalCandidate.end()); - // Sort candidates by priority - unsigned int cand_per_component = unsigned(( mLocalCandidate.size() ) / mComponentMap.size()); - for (unsigned int i=0; icomputeFoundation(); + for (cit = mLocalCandidate.begin(); cit != mLocalCandidate.end(); ++cit) + cit->computeFoundation(); - mState = StartingKeepAlives; + mState = StartingKeepAlives; } void Stream::Handle_SKA() { #ifdef ICE_ENABLE_KEEPALIVE - //TODO: replace successful transactions to keep alive state + // TODO: replace successful transactions to keep alive state #endif - - mState = PrioritizingCandidates; + + mState = PrioritizingCandidates; } bool PriorityGreater(const Candidate& c1, const Candidate& c2) { - return c1.mPriority > c2.mPriority; + return c1.mPriority > c2.mPriority; } void Stream::Handle_PC() { - for (size_t i = 0; i < mLocalCandidate.size(); ++i) - mLocalCandidate[i].computePriority(mConfig.mTypePreferenceList); - - // Find the candidates range for each component ID - ComponentMap::iterator componentIter = mComponentMap.begin(); - for (; componentIter != mComponentMap.end(); componentIter++) - { - // Find range start - size_t minIndex = 0xFFFFFFFF, maxIndex = 0; - - for (CandidateVector::size_type i = 0; i < mLocalCandidate.size(); i++) - { - if (mLocalCandidate[i].mComponentId == (int)componentIter->first) - { - // Wow, we have found first candidate with the specified componentID - minIndex = i; + for (size_t i = 0; i < mLocalCandidate.size(); ++i) + mLocalCandidate[i].computePriority(mConfig.mTypePreferenceList); - break; - } + // Find the candidates range for each component ID + ComponentMap::iterator componentIter = mComponentMap.begin(); + for (; componentIter != mComponentMap.end(); componentIter++) + { + // Find range start + size_t minIndex = 0xFFFFFFFF, maxIndex = 0; + + for (CandidateVector::size_type i = 0; i < mLocalCandidate.size(); i++) + { + if (mLocalCandidate[i].mComponentId == (int)componentIter->first) + { + // Wow, we have found first candidate with the specified componentID + minIndex = i; + + break; + } + } + + // Find range max + for (int i = (int)mLocalCandidate.size() - 1; i >= 0; i--) + { + if (mLocalCandidate[i].mComponentId == componentIter->first) + { + // Wow, we have found first candidate with the specified componentID + maxIndex = i; + + break; + } + } + + if (minIndex == 0xFFFFFFFF) + return; + + CandidateVector::iterator bit = mLocalCandidate.begin() + minIndex; + CandidateVector::iterator fit; + if (maxIndex == mLocalCandidate.size() - 1) + fit = mLocalCandidate.end(); + else + fit = mLocalCandidate.begin() + maxIndex + 1; + + std::sort(bit, fit, PriorityGreater); } - // Find range max - for (int i = (int)mLocalCandidate.size()-1; i >=0; i--) - { - if (mLocalCandidate[i].mComponentId == componentIter->first) - { - // Wow, we have found first candidate with the specified componentID - maxIndex = i; - - break; - } - } - - if (minIndex == 0xFFFFFFFF) - return; - - CandidateVector::iterator bit = mLocalCandidate.begin() + minIndex; - CandidateVector::iterator fit; - if (maxIndex == mLocalCandidate.size()-1) - fit = mLocalCandidate.end(); - else - fit = mLocalCandidate.begin() + maxIndex + 1; - - std::sort(bit, fit, PriorityGreater); - } - - mState = ChoosingDefault; + mState = ChoosingDefault; } void Stream::Handle_CD() { - mDefaultCandidate.clear(); - ComponentMap::iterator componentIter = mComponentMap.begin(); - for (; componentIter != mComponentMap.end(); componentIter++) - mDefaultCandidate[componentIter->first] = findDefaultCandidate(componentIter->first); - - if (mDefaultCandidate.empty()) - throw std::logic_error("Cannot find default candidate."); + mDefaultCandidate.clear(); + ComponentMap::iterator componentIter = mComponentMap.begin(); + for (; componentIter != mComponentMap.end(); componentIter++) + mDefaultCandidate[componentIter->first] = findDefaultCandidate(componentIter->first); - mState = CreatingSDP; + if (mDefaultCandidate.empty()) + throw std::logic_error("Cannot find default candidate."); + + mState = CreatingSDP; } Candidate Stream::findDefaultCandidate(int componentID) { - // Extract all candidates for specified component to separate vector - CandidateVector candidateList; - for (size_t i=0; isetComment("Response for connectivity check request."); - - // Set destination address - // If request has come via relayed candidate - send it back using SendIndication - if (buffer.relayed()) - { - ByteBuffer* si = SendIndication::buildPacket( buffer.remoteAddress(), *responseBuffer, mConfig.mServerAddr4, buffer.component() ); - delete responseBuffer; responseBuffer = si; - responseBuffer->setComment( "SI for CC response to " + buffer.remoteAddress().toStdString() ); - } - else - responseBuffer->setRemoteAddress( buffer.remoteAddress() ); - - // Set component port number - responseBuffer->setComponent(buffer.component()); + // Check if packet has message integrity with local password + if (!msg.validatePacket(mLocalPwd)) + return; - // Send response immediately - mResponseQueue.push_back(responseBuffer); - } + // Is binding processed ok? + if (binding.gotRequest()) + { + // Is role conflict detected? it happens on user agent level - not streams or components + if (binding.role() == mAgentRole && binding.role()) + { + bool errorGenerated = handleRoleConflict(binding); + if (errorGenerated) + return; + } + else + { + ICELogInfo(<< "Stack ID " << mStackId << ". Got a binding request from " + << buffer.remoteAddress().toStdString() << "."); + + handleBindingRequest(binding, buffer, component); + } // of Generate 400 + + // Create response packet + ByteBuffer* responseBuffer = binding.generateData(true); + + // If there is a response packet + if (responseBuffer) + { + // Set comment + responseBuffer->setComment("Response for connectivity check request."); + + // Set destination address + // If request has come via relayed candidate - send it back using SendIndication + if (buffer.relayed()) + { + ByteBuffer* si = SendIndication::buildPacket(buffer.remoteAddress(), *responseBuffer, + mConfig.mServerAddr4, buffer.component()); + delete responseBuffer; + responseBuffer = si; + responseBuffer->setComment("SI for CC response to " + buffer.remoteAddress().toStdString()); + } + else + responseBuffer->setRemoteAddress(buffer.remoteAddress()); + + // Set component port number + responseBuffer->setComponent(buffer.component()); + + // Send response immediately + mResponseQueue.push_back(responseBuffer); + } + } } - } } void Stream::checkNominated(int component) { - // If there are no nominated pairs in the valid list for a media - // stream and the state of the check list is Running, ICE processing - // continues. - if (mCheckList.state() != CheckList::Running) - return; + // If there are no nominated pairs in the valid list for a media + // stream and the state of the check list is Running, ICE processing + // continues. + if (mCheckList.state() != CheckList::Running) + return; - // Attempt to find nominated pair - unsigned i; - for (i=0; inomination() != CandidatePair::Nomination_Finished || mCheckList[i]->state() != CandidatePair::Succeeded); i++) - ; - - if (i == mCheckList.count()) - return; + // Attempt to find nominated pair + unsigned i; + for (i = 0; i < mCheckList.count() && (mCheckList[i]->nomination() != CandidatePair::Nomination_Finished || + mCheckList[i]->state() != CandidatePair::Succeeded); + i++) + ; - // If there is at least one nominated pair in the valid list for a - // media stream and the state of the check list is Running: + if (i == mCheckList.count()) + return; + + // If there is at least one nominated pair in the valid list for a + // media stream and the state of the check list is Running: + + // The agent MUST remove all Waiting and Frozen pairs in the check + // list and triggered check queue for the same component as the + // nominated pairs for that media stream + mCheckList.removePairs(CandidatePair::Frozen, component); + mCheckList.removePairs(CandidatePair::Waiting, component); - // The agent MUST remove all Waiting and Frozen pairs in the check - // list and triggered check queue for the same component as the - // nominated pairs for that media stream - mCheckList.removePairs(CandidatePair::Frozen, component); - mCheckList.removePairs(CandidatePair::Waiting, component); - #ifndef ICE_DONT_CANCEL_CHECKS_ON_SUCCESS - // If an In-Progress pair in the check list is for the same - // component as a nominated pair, the agent SHOULD cease - // retransmissions for its check if its pair priority is lower - // than the lowest priority nominated pair for that component. - PCandidatePair lowestPair = mCheckList.findLowestNominatedPair(component); - if (lowestPair) - { - int64_t lowestPriority = lowestPair->priority(); - - for (unsigned i=0; ipriority(); + + for (unsigned i = 0; i < mCheckList.count(); i++) + { + CandidatePair& pair = *mCheckList[i]; + if (((pair.state() == CandidatePair::InProgress && pair.priority() < lowestPriority) || + pair.nomination() != CandidatePair::Nomination_Finished) && + pair.first().component() == component) + cancelCheck(pair); + } } - } #endif } void Stream::checkNominated() { - if (mState == Success) - return; - - // Check if there is running nomination waiting interval timer - if (ICE_NOMINATION_WAIT_INTERVAL) - { - for (auto componentIter = mComponentMap.begin(); componentIter != mComponentMap.end(); ++componentIter) + if (mState == Success) + return; + + // Check if there is running nomination waiting interval timer + if (ICE_NOMINATION_WAIT_INTERVAL) { - if (componentIter->second.mNominationWaitIntervalStartTime && mAgentRole == RoleControlling) - { - PCandidatePair validPair = mCheckList.findBestValidPair(componentIter->first); - if (validPair) + for (auto componentIter = mComponentMap.begin(); componentIter != mComponentMap.end(); ++componentIter) { - unsigned currentTime = ICETimeHelper::timestamp(); - if (ICETimeHelper::findDelta(componentIter->second.mNominationWaitIntervalStartTime, currentTime) >= ICE_NOMINATION_WAIT_INTERVAL) - nominatePair(validPair); + if (componentIter->second.mNominationWaitIntervalStartTime && mAgentRole == RoleControlling) + { + PCandidatePair validPair = mCheckList.findBestValidPair(componentIter->first); + if (validPair) + { + unsigned currentTime = ICETimeHelper::timestamp(); + if (ICETimeHelper::findDelta(componentIter->second.mNominationWaitIntervalStartTime, currentTime) >= + ICE_NOMINATION_WAIT_INTERVAL) + nominatePair(validPair); + } + } } - } } - } - - if (mNominationWaitStartTime && mCheckList.countOfValidPairs() && mAgentRole == RoleControlling) - { - unsigned currentTime = ICETimeHelper::timestamp(); - if (ICETimeHelper::findDelta(mNominationWaitStartTime, currentTime) >= ICE_NOMINATION_WAIT_INTERVAL) + + if (mNominationWaitStartTime && mCheckList.countOfValidPairs() && mAgentRole == RoleControlling) { - // Iterate components - for (auto componentIter = mComponentMap.begin(); componentIter != mComponentMap.end(); ++componentIter) - { - PCandidatePair validPair = mCheckList.findBestValidPair(componentIter->first); - if (validPair) - nominatePair(validPair); - } + unsigned currentTime = ICETimeHelper::timestamp(); + if (ICETimeHelper::findDelta(mNominationWaitStartTime, currentTime) >= ICE_NOMINATION_WAIT_INTERVAL) + { + // Iterate components + for (auto componentIter = mComponentMap.begin(); componentIter != mComponentMap.end(); ++componentIter) + { + PCandidatePair validPair = mCheckList.findBestValidPair(componentIter->first); + if (validPair) + nominatePair(validPair); + } + } } - } - // Process all components - ComponentMap::iterator componentIter = mComponentMap.begin(); - for (; componentIter != mComponentMap.end(); componentIter++) - checkNominated(componentIter->first); + // Process all components + ComponentMap::iterator componentIter = mComponentMap.begin(); + for (; componentIter != mComponentMap.end(); componentIter++) + checkNominated(componentIter->first); - // Once there is at least one nominated pair in the valid list for - // every component of at least one media stream and the state of the - // check list is Running: + // Once there is at least one nominated pair in the valid list for + // every component of at least one media stream and the state of the + // check list is Running: - // The agent MUST change the state of processing for its check - // list for that media stream to Completed. + // The agent MUST change the state of processing for its check + // list for that media stream to Completed. - bool found = true; - componentIter = mComponentMap.begin(); - for (; componentIter != mComponentMap.end(); componentIter++) - found &= mCheckList.findNominatedPair(componentIter->first).get() != nullptr; - - if (found && mCheckList.state() == CheckList::Running) - { - mCheckList.setState(CheckList::Completed); - - // Create vector of default - std::map defaultCandList; + bool found = true; componentIter = mComponentMap.begin(); for (; componentIter != mComponentMap.end(); componentIter++) - { - int componentId = componentIter->first; - PCandidatePair highestPair = mCheckList.findHighestNominatedPair(componentId); - if (highestPair) - { - defaultCandList[componentId] = Candidate(highestPair->first()); - - // Compare with existing default IP list - if (!Candidate::equal(defaultCandList[componentId], mDefaultCandidate[componentId])) - mDefaultIPChanged = true; - } - } - - mDefaultCandidate = defaultCandList; - mCanTransmit = true; - } - - // Once the state of each check list is Completed: - //ICELogDebug(<< "Stack ID " << mStackID << ". Check list state is " << mCheckList.stateToString(mCheckList.state())); - if (mCheckList.state() == CheckList::Completed) - { - // The agent sets the state of ICE processing overall to - // completed. - if (mState != Success && mState > CandidateGathering) - { - ICELogCritical( << "Stack ID " << mStackId << ". Check list is completed, so session is succeeded."); - mState = Success; - } - } - else - if (mCheckList.state() == CheckList::Failed) - { - // If the state of the check list is Failed, ICE has not been able to - // complete for this media stream. The correct behavior depends on - // the state of the check lists for other media streams: - - // If all check lists are Failed, ICE processing overall is - // considered to be in the Failed state, and the agent SHOULD - // consider the session a failure, SHOULD NOT restart ICE, and the - // controlling agent SHOULD terminate the entire session. - if (mState != Failed && mState > CandidateGathering) - { - ICELogCritical(<< "Stack ID " << mStackId << ". Check list is failed, so session is failed too."); - mState = Failed; - } - clearChecks(); - //TODO: - //If at least one of the check lists for other media streams is - //Completed, the controlling agent SHOULD remove the failed media - //stream from the session in its updated offer. + found &= mCheckList.findNominatedPair(componentIter->first).get() != nullptr; - //If none of the check lists for other media streams are - //Completed, but at least one is Running, the agent SHOULD let - //ICE continue. - } + if (found && mCheckList.state() == CheckList::Running) + { + mCheckList.setState(CheckList::Completed); + + // Create vector of default + std::map defaultCandList; + componentIter = mComponentMap.begin(); + for (; componentIter != mComponentMap.end(); componentIter++) + { + int componentId = componentIter->first; + PCandidatePair highestPair = mCheckList.findHighestNominatedPair(componentId); + if (highestPair) + { + defaultCandList[componentId] = Candidate(highestPair->first()); + + // Compare with existing default IP list + if (!Candidate::equal(defaultCandList[componentId], mDefaultCandidate[componentId])) + mDefaultIPChanged = true; + } + } + + mDefaultCandidate = defaultCandList; + mCanTransmit = true; + } + + // Once the state of each check list is Completed: + // ICELogDebug(<< "Stack ID " << mStackID << ". Check list state is " << + // mCheckList.stateToString(mCheckList.state())); + if (mCheckList.state() == CheckList::Completed) + { + // The agent sets the state of ICE processing overall to + // completed. + if (mState != Success && mState > CandidateGathering) + { + ICELogCritical(<< "Stack ID " << mStackId << ". Check list is completed, so session is succeeded."); + mState = Success; + } + } + else if (mCheckList.state() == CheckList::Failed) + { + // If the state of the check list is Failed, ICE has not been able to + // complete for this media stream. The correct behavior depends on + // the state of the check lists for other media streams: + + // If all check lists are Failed, ICE processing overall is + // considered to be in the Failed state, and the agent SHOULD + // consider the session a failure, SHOULD NOT restart ICE, and the + // controlling agent SHOULD terminate the entire session. + if (mState != Failed && mState > CandidateGathering) + { + ICELogCritical(<< "Stack ID " << mStackId << ". Check list is failed, so session is failed too."); + mState = Failed; + } + clearChecks(); + // TODO: + // If at least one of the check lists for other media streams is + // Completed, the controlling agent SHOULD remove the failed media + // stream from the session in its updated offer. + + // If none of the check lists for other media streams are + // Completed, but at least one is Running, the agent SHOULD let + // ICE continue. + } } bool Stream::handleRoleConflict(ServerBinding& binding) { - ICELogCritical( << "Stack ID " << mStackId << ". Detected role conflict. Local role is " << - (mAgentRole == RoleControlled ? "Controlled" : "Controlling") << ", remote role is " << - (binding.role() == RoleControlled ? "Controlled" : "Controlling") << "."); - - // Compare tie breakers - int compareResult = memcmp(mTieBreaker.c_str(), binding.remoteTieBreaker().c_str(), 8); + ICELogCritical(<< "Stack ID " << mStackId << ". Detected role conflict. Local role is " + << (mAgentRole == RoleControlled ? "Controlled" : "Controlling") << ", remote role is " + << (binding.role() == RoleControlled ? "Controlled" : "Controlling") << "."); - if (mAgentRole == RoleControlling) - { - // So remove - if (compareResult >= 0) + // Compare tie breakers + int compareResult = memcmp(mTieBreaker.c_str(), binding.remoteTieBreaker().c_str(), 8); + + if (mAgentRole == RoleControlling) { - // Queue 487 error to remote peer - binding.generate487(); - return true; + // So remove + if (compareResult >= 0) + { + // Queue 487 error to remote peer + binding.generate487(); + return true; + } + else + mAgentRole = RoleControlled; } else - mAgentRole = RoleControlled; - } - else - { - if (compareResult < 0) { - // Enqueue 487 error to remote peer - binding.generate487(); - return true; + if (compareResult < 0) + { + // Enqueue 487 error to remote peer + binding.generate487(); + return true; + } + else + mAgentRole = RoleControlling; } - else - mAgentRole = RoleControlling; - } - // Recompute pair priorities for all stream's queues and triggered check queue - mCheckList.updatePairPriorities(); + // Recompute pair priorities for all stream's queues and triggered check queue + mCheckList.updatePairPriorities(); - return false; + return false; } -void Stream::createOfferSdp(std::vector& defaultIP, std::vector& defaultPort, - std::vector& candidateList) +void Stream::createOfferSdp(std::vector& defaultIP, std::vector& defaultPort, + std::vector& candidateList) { - // Iterator all components - ComponentMap::iterator componentIter = mComponentMap.begin(); - for (; componentIter != mComponentMap.end(); componentIter++) - { - // Find default IP for this component - defaultIP.push_back(mDefaultCandidate[componentIter->first].mExternalAddr.ip()); - defaultPort.push_back(mDefaultCandidate[componentIter->first].mExternalAddr.port()); - - for (unsigned candidateCounter=0; candidateCounterfirst) - { - candidateList.push_back(cand.createSdp()); -#ifdef ICE_VIRTUAL_CANDIDATES - if (cand.mType == Candidate::ServerReflexive || cand.mType == Candidate::PeerReflexive) + // Find default IP for this component + defaultIP.push_back(mDefaultCandidate[componentIter->first].mExternalAddr.ip()); + defaultPort.push_back(mDefaultCandidate[componentIter->first].mExternalAddr.port()); + + for (unsigned candidateCounter = 0; candidateCounter < mLocalCandidate.size(); candidateCounter++) { - for (int i=0; ifirst) + { + candidateList.push_back(cand.createSdp()); +#ifdef ICE_VIRTUAL_CANDIDATES + if (cand.mType == Candidate::ServerReflexive || cand.mType == Candidate::PeerReflexive) + { + for (int i = 0; i < ICE_VIRTUAL_CANDIDATES; i++) + { + Candidate v = cand; + v.mExternalAddr.setPort(v.mExternalAddr.port() + i + 1); + candidateList.push_back(v.createSdp()); + } + } #endif - } + } + } } - } } NetworkAddress Stream::defaultAddress(int componentID) { - if ((int)mDefaultCandidate.size() >= componentID) - return mDefaultCandidate[componentID].mExternalAddr; + if ((int)mDefaultCandidate.size() >= componentID) + return mDefaultCandidate[componentID].mExternalAddr; - if (mComponentMap.find(componentID) != mComponentMap.end()) - { - NetworkAddress result = NetworkHelper::instance().sourceInterface(NetworkAddress(mConfig.mTargetIP, 1)); - result.setPort(mComponentMap[componentID].mPort4); - return result; - } - return NetworkAddress(); + if (mComponentMap.find(componentID) != mComponentMap.end()) + { + NetworkAddress result = NetworkHelper::instance().sourceInterface(NetworkAddress(mConfig.mTargetIP, 1)); + result.setPort(mComponentMap[componentID].mPort4); + return result; + } + return NetworkAddress(); } void Stream::candidateList(int componentID, std::vector& candidateList) { - for (unsigned i=0; icomponent(); - tag = mComponentMap[component].mTag; - - return result; + if (!result) + return PByteBuffer(); + + component = result->component(); + tag = mComponentMap[component].mTag; + + return result; } Transaction* Stream::runCheckList(CandidatePair::Role r, CandidatePair::State state) { - Transaction* result = NULL; - for (unsigned i=0; irole() != r || p->transaction()) - continue; - - if (p->state() == state) + Transaction* result = NULL; + for (unsigned i = 0; i < mCheckList.count() && !result; i++) { - ICELogInfo(<<"Creating check request for " << p->toStdString()); + // Extract reference to candidate pair + PCandidatePair& p = mCheckList[i]; - // Create binding request - result = createCheckRequest(p); - - // Mark candidate pair as InProgress - p->setTransaction(result); - p->setState(CandidatePair::InProgress); + if (p->role() != r || p->transaction()) + continue; + + if (p->state() == state) + { + ICELogInfo(<< "Creating check request for " << p->toStdString()); + + // Create binding request + result = createCheckRequest(p); + + // Mark candidate pair as InProgress + p->setTransaction(result); + p->setState(CandidatePair::InProgress); + } } - } - return result; + return result; } ByteBuffer* Stream::handleConnChecksOut() { - // Update stream state - checkNominated(); - - // Loop while we have time to send packets - if (mScheduleTimer.isTimeToSend()) - { - // Declare pointer to created check request - Transaction* request = NULL; - - // Check for triggered request - //ICELogInfo(<<"Create checks for triggered waiting pairs for list " << std::endl << mCheckList.toStdString()); - request = runCheckList(CandidatePair::Triggered, CandidatePair::Waiting); - if (request) - mActiveChecks.addPrioritized(request); - else + // Update stream state + checkNominated(); + + // Loop while we have time to send packets + if (mScheduleTimer.isTimeToSend()) { - request = runCheckList(CandidatePair::Regular, CandidatePair::Waiting); - if (request) - mActiveChecks.addRegular(request); - else - { - // Find Frozen check with highest priority and lowest componentID in check list - request = runCheckList(CandidatePair::Regular, CandidatePair::Frozen); + // Declare pointer to created check request + Transaction* request = NULL; + + // Check for triggered request + // ICELogInfo(<<"Create checks for triggered waiting pairs for list " << std::endl << mCheckList.toStdString()); + request = runCheckList(CandidatePair::Triggered, CandidatePair::Waiting); if (request) - mActiveChecks.addRegular(request); - } + mActiveChecks.addPrioritized(request); + else + { + request = runCheckList(CandidatePair::Regular, CandidatePair::Waiting); + if (request) + mActiveChecks.addRegular(request); + else + { + // Find Frozen check with highest priority and lowest componentID in check list + request = runCheckList(CandidatePair::Regular, CandidatePair::Frozen); + if (request) + mActiveChecks.addRegular(request); + } + } } - } - - // ICELogDebug(<< "Looking for transaction to send"); - // Loop while active transaction is not found - Transaction* t; int attemptCounter = 0; - do - { - attemptCounter++; - t = mActiveChecks.getNextTransaction(); + // ICELogDebug(<< "Looking for transaction to send"); + // Loop while active transaction is not found + Transaction* t; + int attemptCounter = 0; + do + { + attemptCounter++; + t = mActiveChecks.getNextTransaction(); + if (!t) + continue; + // This code forces keepalive transaction to its intervals + if (!t->hasToRunNow()) + t = NULL; + } while (!t && attemptCounter < mActiveChecks.count()); + if (!t) - continue; - // This code forces keepalive transaction to its intervals - if (!t->hasToRunNow()) - t = NULL; - } - while (!t && attemptCounter < mActiveChecks.count()); - - if (!t) - return NULL; - - ByteBuffer* buffer = t->generateData(); - if (!buffer) - return NULL; + return NULL; - // Self test - /*StunMessage msg; - msg.parsePacket(*buffer); - std::ostringstream oss; - msg.dump(oss); - ICELogDebug(<< "Self test result: " << oss.str()); - */ - ICELogInfo(<< "Generating packet for " << (t->relayed() ? "relayed " : "") << t->comment() << " to " << t->destination().toStdString()); - if (t->relayed()) - { - ByteBuffer* si = SendIndication::buildPacket(t->destination(), *buffer, mConfig.mServerAddr4, t->component()); - si->setComment("Relayed: " + buffer->comment()); - delete buffer; buffer = si; - } + ByteBuffer* buffer = t->generateData(); + if (!buffer) + return NULL; - assert(!buffer->remoteAddress().isEmpty()); - return buffer; + // Self test + /*StunMessage msg; + msg.parsePacket(*buffer); + std::ostringstream oss; + msg.dump(oss); + ICELogDebug(<< "Self test result: " << oss.str()); + */ + ICELogInfo(<< "Generating packet for " << (t->relayed() ? "relayed " : "") << t->comment() << " to " + << t->destination().toStdString()); + if (t->relayed()) + { + ByteBuffer* si = SendIndication::buildPacket(t->destination(), *buffer, mConfig.mServerAddr4, t->component()); + si->setComment("Relayed: " + buffer->comment()); + delete buffer; + buffer = si; + } + + assert(!buffer->remoteAddress().isEmpty()); + return buffer; } Transaction* Stream::createCheckRequest(PCandidatePair& p) { - // Get reference to checked pair + // Get reference to checked pair - // Create transaction - depending on candidates it can be regular ConnectivityCheck or RelayedConnectivityCheck - ConnectivityCheck* cc = new ConnectivityCheck(); + // Create transaction - depending on candidates it can be regular ConnectivityCheck or RelayedConnectivityCheck + ConnectivityCheck* cc = new ConnectivityCheck(); - cc->setRelayed( p->first().mType == Candidate::ServerRelayed ); - cc->setStackId( mStackId ); - cc->setComponent( p->first().mComponentId ); + cc->setRelayed(p->first().mType == Candidate::ServerRelayed); + cc->setStackId(mStackId); + cc->setComponent(p->first().mComponentId); - // Add PRIORITY attribute - unsigned int peerReflexivePriority = 0xFFFFFF * mConfig.mTypePreferenceList[Candidate::PeerReflexive] + - (p->first().mInterfacePriority << 8) + (256 - p->first().mComponentId); + // Add PRIORITY attribute + unsigned int peerReflexivePriority = 0xFFFFFF * mConfig.mTypePreferenceList[Candidate::PeerReflexive] + + (p->first().mInterfacePriority << 8) + (256 - p->first().mComponentId); - cc->addPriority( peerReflexivePriority ); - - cc->addFingerprint( true ); - cc->setDestination( p->second().mExternalAddr ); - cc->setComment( p->toStdString() ); - - // Add CONTROLLED or CONTROLLING attribute - switch (mAgentRole) - { - case RoleControlled: - cc->addControlledRole(mTieBreaker); - break; + cc->addPriority(peerReflexivePriority); - case RoleControlling: - cc->addControllingRole(mTieBreaker); - break; - - default: - assert(0); - } - - // Enable short term credentials - cc->addShortTermCredentials(true); - - // Set right username and password - cc->setUsername(mRemoteUfrag + ":" + mLocalUfrag); - cc->setPassword(mRemotePwd); - - // Add action - cc->setAction(PAction(new CheckPairAction(*this, mConfig, p))); - - // Do not forget about aggressive nomination - if (mConfig.mAggressiveNomination) - cc->addUseCandidate(); + cc->addFingerprint(true); + cc->setDestination(p->second().mExternalAddr); + cc->setComment(p->toStdString()); - ICELogInfo( << "Stack ID " << mStackId << ". Created " << (cc->relayed() ? "RCC" : "CC") << " for " << p->toStdString() << " and destination " << cc->destination().toStdString() << "."); + // Add CONTROLLED or CONTROLLING attribute + switch (mAgentRole) + { + case RoleControlled: + cc->addControlledRole(mTieBreaker); + break; - return cc; + case RoleControlling: + cc->addControllingRole(mTieBreaker); + break; + + default: + assert(0); + } + + // Enable short term credentials + cc->addShortTermCredentials(true); + + // Set right username and password + cc->setUsername(mRemoteUfrag + ":" + mLocalUfrag); + cc->setPassword(mRemotePwd); + + // Add action + cc->setAction(PAction(new CheckPairAction(*this, mConfig, p))); + + // Do not forget about aggressive nomination + if (mConfig.mAggressiveNomination) + cc->addUseCandidate(); + + ICELogInfo(<< "Stack ID " << mStackId << ". Created " << (cc->relayed() ? "RCC" : "CC") << " for " + << p->toStdString() << " and destination " << cc->destination().toStdString() << "."); + + return cc; } TurnPrefix Stream::findTurnPrefixByAddress(NetworkAddress& peerAddress) { - TurnPrefixMap::iterator tpit = mTurnPrefixMap.begin(); - for (; tpit != mTurnPrefixMap.end(); ++tpit) - { - NetworkAddress& addr = tpit->second; - if (addr == peerAddress) - return tpit->first; - } + TurnPrefixMap::iterator tpit = mTurnPrefixMap.begin(); + for (; tpit != mTurnPrefixMap.end(); ++tpit) + { + NetworkAddress& addr = tpit->second; + if (addr == peerAddress) + return tpit->first; + } - return 0; + return 0; } -class KeepAliveCheckCondition: public TransactionCondition +class KeepAliveCheckCondition : public TransactionCondition { protected: - NetworkAddress mTarget; - int mComponentId; - + NetworkAddress mTarget; + int mComponentId; + public: - KeepAliveCheckCondition(const NetworkAddress& address, int componentId) - :mTarget(address), mComponentId(componentId) - { - - } - - bool check(Transaction* t) const - { - BindingIndication* bi = dynamic_cast(t); - if (!bi) - return false; - if (!bi->keepalive()) - return false; - - return (t->component() == mComponentId && t->destination() == mTarget); - } + KeepAliveCheckCondition(const NetworkAddress& address, int componentId) + : mTarget(address), mComponentId(componentId) + { + } + + bool check(Transaction* t) const + { + BindingIndication* bi = dynamic_cast(t); + if (!bi) + return false; + if (!bi->keepalive()) + return false; + + return (t->component() == mComponentId && t->destination() == mTarget); + } }; void Stream::addKeepAliveCheck(CandidatePair& _pair) { #ifdef ICE_ENABLE_KEEPALIVE - // Ensure it is new keepalive check - if (mActiveChecks.exists(KeepAliveCheckCondition(_pair.second().mExternalAddr, _pair.first().mComponentId))) - return; - - // Create binding indication transaction - BindingIndication* bi = new BindingIndication(mConfig.mKeepAliveInterval); - bi->setStackId(mStackId); - bi->setKeepalive(true); - bi->setInterval(mConfig.mKeepAliveInterval); - - // Restart transaction on finish - //bi->setUserObject(new CandidatePair(_pair)); + // Ensure it is new keepalive check + if (mActiveChecks.exists(KeepAliveCheckCondition(_pair.second().mExternalAddr, _pair.first().mComponentId))) + return; - // Do not forget to comment transaction - bi->setComment("Keepalive check for " + _pair.toStdString()); - - // Set destination - bi->setDestination(_pair.second().mExternalAddr); - - // Set component port - bi->setComponent(_pair.first().mComponentId); + // Create binding indication transaction + BindingIndication* bi = new BindingIndication(mConfig.mKeepAliveInterval); + bi->setStackId(mStackId); + bi->setKeepalive(true); + bi->setInterval(mConfig.mKeepAliveInterval); - // Put transaction to container - mActiveChecks.addRegular(bi); + // Restart transaction on finish + // bi->setUserObject(new CandidatePair(_pair)); + + // Do not forget to comment transaction + bi->setComment("Keepalive check for " + _pair.toStdString()); + + // Set destination + bi->setDestination(_pair.second().mExternalAddr); + + // Set component port + bi->setComponent(_pair.first().mComponentId); + + // Put transaction to container + mActiveChecks.addRegular(bi); #endif } -bool Stream::processSdpOffer( std::vector& candidateList, std::string defaultIP, unsigned short defaultPort, bool deleteRelayed) +bool Stream::processSdpOffer(std::vector& candidateList, std::string defaultIP, unsigned short defaultPort, + bool deleteRelayed) { - if (candidateList.empty()) - { - // Anyway we may need TURN permissions installed - if (mState >= CreatingSDP && mConfig.mUseTURN) + if (candidateList.empty()) { - ICELogDebug(<< "Installing permissions for default address " << defaultIP << ":" << defaultPort); - installPermissions(-1, NetworkAddress(defaultIP, defaultPort)); + // Anyway we may need TURN permissions installed + if (mState >= CreatingSDP && mConfig.mUseTURN) + { + ICELogDebug(<< "Installing permissions for default address " << defaultIP << ":" << defaultPort); + installPermissions(-1, NetworkAddress(defaultIP, defaultPort)); + } + return false; } - return false; - } - // Save remote candidate list - std::set availComponents; + // Save remote candidate list + std::set availComponents; - for (size_t i=0; ifirst) != availComponents.end()) - validComponentMap[componentIter->first] = componentIter->second; - else - { - // Do not deallocate turn candidate here - side effect can be bad - } - } - mComponentMap = validComponentMap; + Candidate cand = Candidate::parseSdp(candidateList[i].c_str()); - // Ensure there is at least one component - if (mComponentMap.empty()) - { - ICELogCritical(<< "SDP offer is not valid; it has no components"); - return false; - } - - // Check if candidate list includes default IP:pair - bool result = candidateListContains(defaultIP, defaultPort); + if (availComponents.find(cand.mComponentId) == availComponents.end()) + availComponents.insert(cand.mComponentId); - // Delete relayed candidates if needed - if (deleteRelayed) - { - mRemoteRelayedCandidate.clear(); - CandidateVector::iterator candIter = mRemoteCandidate.begin(); - while (candIter != mRemoteCandidate.end()) - { - if (candIter->mType == Candidate::ServerRelayed) - { - mRemoteRelayedCandidate.push_back(*candIter); - candIter = mRemoteCandidate.erase(candIter); - } - else - candIter++; + unsigned existingIndex = findRemoteCandidate(cand.mExternalAddr, cand.mComponentId); + if (existingIndex != NoIndex) + { + ICELogInfo(<< "Stack ID " << mStackId << ". Remote candidate " << cand.mExternalAddr.toStdString() + << " is found already, so just update priority value."); + mRemoteCandidate[existingIndex].mPriority = cand.mPriority; + } + else + { + ICELogInfo(<< "Stack ID " << mStackId << ". Remote candidate " << cand.mExternalAddr.toStdString() + << " is add."); + mRemoteCandidate.push_back(cand); + } } - } - return result; + // Update number of components according to sdp + ComponentMap validComponentMap; + + ComponentMap::iterator componentIter = mComponentMap.begin(); + for (; componentIter != mComponentMap.end(); componentIter++) + { + if (availComponents.find(componentIter->first) != availComponents.end()) + validComponentMap[componentIter->first] = componentIter->second; + else + { + // Do not deallocate turn candidate here - side effect can be bad + } + } + mComponentMap = validComponentMap; + + // Ensure there is at least one component + if (mComponentMap.empty()) + { + ICELogCritical(<< "SDP offer is not valid; it has no components"); + return false; + } + + // Check if candidate list includes default IP:pair + bool result = candidateListContains(defaultIP, defaultPort); + + // Delete relayed candidates if needed + if (deleteRelayed) + { + mRemoteRelayedCandidate.clear(); + CandidateVector::iterator candIter = mRemoteCandidate.begin(); + while (candIter != mRemoteCandidate.end()) + { + if (candIter->mType == Candidate::ServerRelayed) + { + mRemoteRelayedCandidate.push_back(*candIter); + candIter = mRemoteCandidate.erase(candIter); + } + else + candIter++; + } + } + + return result; } bool Stream::candidateListContains(const std::string& remoteIP, unsigned short remotePort) { - NetworkAddress remote; - remote.setIp(remoteIP.c_str()); - remote.setPort(remotePort); + NetworkAddress remote; + remote.setIp(remoteIP.c_str()); + remote.setPort(remotePort); - for (size_t i=0; ifirst || !local.mReady ) - continue; + // Pair local candidates with remote candidates + for (unsigned localIndex = 0; localIndex < mLocalCandidate.size() && localIndex < ICE_CANDIDATE_LIMIT; + localIndex++) + { + Candidate& local = mLocalCandidate[localIndex]; + if (local.mComponentId != (int)componentIter->first || !local.mReady) + continue; - for (unsigned remoteIndex=0; remoteIndex(t); - if (c) - return false; - ClientChannelBind* ccb = dynamic_cast(t); - if (ccb) - return false; - ClientCreatePermission* ccp = dynamic_cast(t); - if (ccp) - return false; - - // Send indication is not listed here; it is sent directly without transaction list proxy. - return true; - } + bool check(Transaction* t) const + { + ClientRefresh* c = dynamic_cast(t); + if (c) + return false; + ClientChannelBind* ccb = dynamic_cast(t); + if (ccb) + return false; + ClientCreatePermission* ccp = dynamic_cast(t); + if (ccp) + return false; + + // Send indication is not listed here; it is sent directly without transaction list proxy. + return true; + } }; void Stream::stopChecks() { - // Clear generated check list - mCheckList.clear(); - - // Delete corresponding transactions - mActiveChecks.erase(DeleteChecksAndGathers()); - - // Avoid responding to remote peer's transactions - if (mState < Failed) - mState = Failed; -} + // Clear generated check list + mCheckList.clear(); + // Delete corresponding transactions + mActiveChecks.erase(DeleteChecksAndGathers()); + + // Avoid responding to remote peer's transactions + if (mState < Failed) + mState = Failed; +} void Stream::clear() { - ICELogDebug(<< "Clear ICE stream"); - mState = None; - - // Clear connectivity checks list - mCheckList.clear(); - - // Delete all transactions except possible deallocation requests - mActiveChecks.erase(KeepDeallocationRequest()); - - // Remote candidates are not needed anymore - mRemoteCandidate.clear(); - mRemoteRelayedCandidate.clear(); - mDefaultCandidate.clear(); - mComponentLimit.clear(); - mTurnPrefixMap.clear(); - mScheduleTimer.stop(); - mTurnAllocated = 0; - mDefaultIPChanged = false; - for (ComponentMap::iterator componentIter = mComponentMap.begin(); componentIter != mComponentMap.end(); componentIter++) - componentIter->second.mNominationWaitIntervalStartTime = 0; - mNominationWaitStartTime = 0; - mFailoverRequestsFinished = 0; + ICELogDebug(<< "Clear ICE stream"); + mState = None; + + // Clear connectivity checks list + mCheckList.clear(); + + // Delete all transactions except possible deallocation requests + mActiveChecks.erase(KeepDeallocationRequest()); + + // Remote candidates are not needed anymore + mRemoteCandidate.clear(); + mRemoteRelayedCandidate.clear(); + mDefaultCandidate.clear(); + mComponentLimit.clear(); + mTurnPrefixMap.clear(); + mScheduleTimer.stop(); + mTurnAllocated = 0; + mDefaultIPChanged = false; + for (ComponentMap::iterator componentIter = mComponentMap.begin(); componentIter != mComponentMap.end(); + componentIter++) + componentIter->second.mNominationWaitIntervalStartTime = 0; + mNominationWaitStartTime = 0; + mFailoverRequestsFinished = 0; } -class DeleteConnChecks: public TransactionCondition +class DeleteConnChecks : public TransactionCondition { public: - bool check(Transaction* t) const - { - return (dynamic_cast(t) != NULL); - } + bool check(Transaction* t) const { return (dynamic_cast(t) != NULL); } }; -class DeleteChannelBindingRequests: public TransactionCondition +class DeleteChannelBindingRequests : public TransactionCondition { public: - bool check(Transaction* t) const - { - return (dynamic_cast(t) != NULL); - } + bool check(Transaction* t) const { return (dynamic_cast(t) != NULL); } }; -class DeleteClientRefreshes: public TransactionCondition +class DeleteClientRefreshes : public TransactionCondition { public: - bool check(Transaction* t) const - { - return (dynamic_cast(t) != NULL); - } + bool check(Transaction* t) const { return (dynamic_cast(t) != NULL); } }; -class DeleteCreatePermissions: public TransactionCondition +class DeleteCreatePermissions : public TransactionCondition { public: - bool check(Transaction* t) const - { - return (dynamic_cast(t) != NULL); - } + bool check(Transaction* t) const { return (dynamic_cast(t) != NULL); } }; -class DeleteClientBindings: public TransactionCondition +class DeleteClientBindings : public TransactionCondition { public: - bool check(Transaction* t) const - { - return dynamic_cast(t) != NULL; - } + bool check(Transaction* t) const { return dynamic_cast(t) != NULL; } }; -class DeleteClientAllocations: public TransactionCondition +class DeleteClientAllocations : public TransactionCondition { public: - bool check(Transaction* t) const - { - return dynamic_cast(t) != NULL; - } + bool check(Transaction* t) const { return dynamic_cast(t) != NULL; } }; void Stream::clearForRestart(bool localNetworkChanged) { - ICELogDebug(<< "Clear ice stream before restart"); - mState = None; - mCheckList.clear(); - mRemoteCandidate.clear(); - mRemoteRelayedCandidate.clear(); - mTurnAllocated = 0; - - // Here deleting transactions common for remote or local peer changing networks - - // Existing connectivity checks must be removed - there is no sense in result from them - mActiveChecks.erase(DeleteConnChecks()); + ICELogDebug(<< "Clear ice stream before restart"); + mState = None; + mCheckList.clear(); + mRemoteCandidate.clear(); + mRemoteRelayedCandidate.clear(); + mTurnAllocated = 0; - // Existing channel binding requests are useless now - new ones should be sent - with new IP:port (when remote peer changes) or after creation new socket(s) (when local peer changes) - mActiveChecks.erase(DeleteChannelBindingRequests()); - - // And there is no sense in old TURN permissions - mActiveChecks.erase(DeleteCreatePermissions()); - - if (localNetworkChanged) - { - // No sense to refresh current TURN allocation - old socket is lost, there is no way to send from the same ip:port pair exactly - mActiveChecks.erase(DeleteClientRefreshes()); - - // Maybe new candidates were gathering when network changed - so remove old ClientBinding requests - mActiveChecks.erase(DeleteClientBindings()); - - // The same about TURN allocations - delete allocation requests. - mActiveChecks.erase(DeleteClientAllocations()); - } + // Here deleting transactions common for remote or local peer changing networks + + // Existing connectivity checks must be removed - there is no sense in result from them + mActiveChecks.erase(DeleteConnChecks()); + + // Existing channel binding requests are useless now - new ones should be sent - with new IP:port (when remote peer + // changes) or after creation new socket(s) (when local peer changes) + mActiveChecks.erase(DeleteChannelBindingRequests()); + + // And there is no sense in old TURN permissions + mActiveChecks.erase(DeleteCreatePermissions()); + + if (localNetworkChanged) + { + // No sense to refresh current TURN allocation - old socket is lost, there is no way to send from the same + // ip:port pair exactly + mActiveChecks.erase(DeleteClientRefreshes()); + + // Maybe new candidates were gathering when network changed - so remove old ClientBinding requests + mActiveChecks.erase(DeleteClientBindings()); + + // The same about TURN allocations - delete allocation requests. + mActiveChecks.erase(DeleteClientAllocations()); + } } void Stream::restart() { - mErrorCode = 0; - if (mState > CreatingSDP) - mState = ConnCheck; - else - mState = None; - - mCheckList.clear(); + mErrorCode = 0; + if (mState > CreatingSDP) + mState = ConnCheck; + else + mState = None; + + mCheckList.clear(); } NetworkAddress Stream::remoteAddress(int componentID) { - NetworkAddress result; - PCandidatePair highestPair = mCheckList.findHighestNominatedPair(componentID); - if (highestPair) - { - result = highestPair->second().mExternalAddr; - result.setRelayed(highestPair->first().mType == Candidate::ServerRelayed); - } + NetworkAddress result; + PCandidatePair highestPair = mCheckList.findHighestNominatedPair(componentID); + if (highestPair) + { + result = highestPair->second().mExternalAddr; + result.setRelayed(highestPair->first().mType == Candidate::ServerRelayed); + } - return result; + return result; } NetworkAddress Stream::localAddress(int component) { - PCandidatePair highestPair = mCheckList.findHighestNominatedPair(component); - if (highestPair) - return highestPair->first().mExternalAddr; - else - return NetworkAddress(); + PCandidatePair highestPair = mCheckList.findHighestNominatedPair(component); + if (highestPair) + return highestPair->first().mExternalAddr; + else + return NetworkAddress(); } -class FreeAllocationAction: public Action +class FreeAllocationAction : public Action { protected: - DeleteAllocationCallback* mCallback; + DeleteAllocationCallback* mCallback; + public: - FreeAllocationAction(Stream& stream, StackConfig& config, DeleteAllocationCallback* cb) - :Action(stream, config), mCallback(cb) - { + FreeAllocationAction(Stream& stream, StackConfig& config, DeleteAllocationCallback* cb) + : Action(stream, config), mCallback(cb) + { + } + ~FreeAllocationAction() { delete mCallback; } - } - ~FreeAllocationAction() - { - delete mCallback; - } + void finished(Transaction& transaction) + { + AuthTransaction& auth = dynamic_cast(transaction); + int code = auth.state() == Transaction::Failed ? (auth.errorCode() ? auth.errorCode() : -1) : 0; - void finished(Transaction& transaction) - { - AuthTransaction& auth = dynamic_cast(transaction); - int code = auth.state() == Transaction::Failed ? (auth.errorCode() ? auth.errorCode() : -1) : 0; - - if (mCallback) - mCallback->onAllocationDeleted(mStream.mId, transaction.component(), code); - } + if (mCallback) + mCallback->onAllocationDeleted(mStream.mId, transaction.component(), code); + } }; void Stream::freeAllocation(int component, DeleteAllocationCallback* cb) { - // Clear bindings - removeBindingResult(component); + // Clear bindings + removeBindingResult(component); - if (component == -1) - { - ComponentMap::iterator compIter; - for (compIter = mComponentMap.begin(); compIter != mComponentMap.end(); ++compIter) - freeAllocation(compIter->first, cb); - } - else - { - ClientRefresh* allocation = new ClientRefresh(0, this); - allocation->setStackId( mStackId ); - allocation->setDestination( (mConfig.mServerAddr4.isZero() || mConfig.mServerAddr4.isEmpty()) ? mConfig.mServerAddr6 : mConfig.mServerAddr4); - allocation->setPassword( mConfig.mTurnPassword ); - allocation->setUsername( mConfig.mTurnUsername ); - allocation->setComponent( component ); - allocation->setKeepalive( false ); + if (component == -1) + { + ComponentMap::iterator compIter; + for (compIter = mComponentMap.begin(); compIter != mComponentMap.end(); ++compIter) + freeAllocation(compIter->first, cb); + } + else + { + ClientRefresh* allocation = new ClientRefresh(0, this); + allocation->setStackId(mStackId); + allocation->setDestination((mConfig.mServerAddr4.isZero() || mConfig.mServerAddr4.isEmpty()) + ? mConfig.mServerAddr6 + : mConfig.mServerAddr4); + allocation->setPassword(mConfig.mTurnPassword); + allocation->setUsername(mConfig.mTurnUsername); + allocation->setComponent(component); + allocation->setKeepalive(false); #ifdef ICE_CACHE_REALM_NONCE - allocation->setRealm( mCachedRealm ); - allocation->setNonce( mCachedNonce ); + allocation->setRealm(mCachedRealm); + allocation->setNonce(mCachedNonce); #endif - // Associate it with action - allocation->setAction(PAction(new FreeAllocationAction(*this, mConfig, cb))); + // Associate it with action + allocation->setAction(PAction(new FreeAllocationAction(*this, mConfig, cb))); - mActiveChecks.addRegular(allocation); - } + mActiveChecks.addRegular(allocation); + } } -class ChannelBindResultAction: public Action +class ChannelBindResultAction : public Action { protected: - ChannelBoundCallback* mCallback; + ChannelBoundCallback* mCallback; public: - ChannelBindResultAction(Stream& stream, StackConfig& config, ChannelBoundCallback* cb) - :Action(stream, config), mCallback(cb) - {} + ChannelBindResultAction(Stream& stream, StackConfig& config, ChannelBoundCallback* cb) + : Action(stream, config), mCallback(cb) + { + } - ~ChannelBindResultAction() - { - delete mCallback; - } + ~ChannelBindResultAction() { delete mCallback; } - void finished(Transaction& transaction) - { - ClientChannelBind& cb = dynamic_cast(transaction); - Stream::BoundChannel channel; - channel.mComponentId = cb.component(); - channel.mPrefix = cb.channelPrefix(); - channel.mPeerAddress = cb.peerAddress(); - channel.mResultCode = 0; - - if (cb.state() == Transaction::Failed) - channel.mResultCode = cb.errorCode() ? cb.errorCode() : -1; - - ICELogDebug(<< "Saving TURN channel binding result " << channel.mPrefix << " to " << channel.mPeerAddress.toStdString()); - mStream.mBoundChannelList.push_back(channel); - if (mCallback) - mCallback->onChannelBound(mStream.mId, cb.component(), channel.mResultCode); - } + void finished(Transaction& transaction) + { + ClientChannelBind& cb = dynamic_cast(transaction); + Stream::BoundChannel channel; + channel.mComponentId = cb.component(); + channel.mPrefix = cb.channelPrefix(); + channel.mPeerAddress = cb.peerAddress(); + channel.mResultCode = 0; + + if (cb.state() == Transaction::Failed) + channel.mResultCode = cb.errorCode() ? cb.errorCode() : -1; + + ICELogDebug(<< "Saving TURN channel binding result " << channel.mPrefix << " to " + << channel.mPeerAddress.toStdString()); + mStream.mBoundChannelList.push_back(channel); + if (mCallback) + mCallback->onChannelBound(mStream.mId, cb.component(), channel.mResultCode); + } }; TurnPrefix Stream::bindChannel(const NetworkAddress& peerAddress, int component, ChannelBoundCallback* cb) { - ICELogInfo(<< "Bind TURN channel for " << peerAddress.toStdString() << " for component " << component); - - // Check if the request binding is done already - BoundChannelList::iterator channelIter = mBoundChannelList.begin(); - for (;channelIter != mBoundChannelList.end(); ++channelIter) - { - if (channelIter->mComponentId == component && channelIter->mPeerAddress == peerAddress) + ICELogInfo(<< "Bind TURN channel for " << peerAddress.toStdString() << " for component " << component); + + // Check if the request binding is done already + BoundChannelList::iterator channelIter = mBoundChannelList.begin(); + for (; channelIter != mBoundChannelList.end(); ++channelIter) { - if (!channelIter->mResultCode) - { - ICELogInfo(<< "Already bound to prefix " << channelIter->mPrefix); - return channelIter->mPrefix; - } + if (channelIter->mComponentId == component && channelIter->mPeerAddress == peerAddress) + { + if (!channelIter->mResultCode) + { + ICELogInfo(<< "Already bound to prefix " << channelIter->mPrefix); + return channelIter->mPrefix; + } + } } - } - - ChannelBindResultAction* action = new ChannelBindResultAction(*this, mConfig, cb); - // Create transaction - ClientChannelBind* ccb = new ClientChannelBind( peerAddress ); - ccb->setStackId( mStackId ); + ChannelBindResultAction* action = new ChannelBindResultAction(*this, mConfig, cb); - ccb->setUsername( mConfig.mTurnUsername ); - ccb->setPassword( mConfig.mTurnPassword ); - ccb->setDestination( mConfig.mUseIPv6 && !mConfig.mUseIPv4 ? mConfig.mServerAddr6 : mConfig.mServerAddr4 ); - ccb->setComponent( component ); + // Create transaction + ClientChannelBind* ccb = new ClientChannelBind(peerAddress); + ccb->setStackId(mStackId); + + ccb->setUsername(mConfig.mTurnUsername); + ccb->setPassword(mConfig.mTurnPassword); + ccb->setDestination(mConfig.mUseIPv6 && !mConfig.mUseIPv4 ? mConfig.mServerAddr6 : mConfig.mServerAddr4); + ccb->setComponent(component); #ifdef ICE_CACHE_REALM_NONCE - ccb->setRealm( mCachedRealm ); - ccb->setNonce( mCachedNonce ); + ccb->setRealm(mCachedRealm); + ccb->setNonce(mCachedNonce); #endif - ccb->setAction(PAction(action)); - mActiveChecks.addRegular(ccb); + ccb->setAction(PAction(action)); + mActiveChecks.addRegular(ccb); - return ccb->channelPrefix(); + return ccb->channelPrefix(); } bool Stream::isChannelBindingFailed(int component, TurnPrefix prefix) { - BoundChannelList::iterator channelIter = mBoundChannelList.begin(); - for (; channelIter != mBoundChannelList.end(); ++channelIter) - if (channelIter->mComponentId == component && channelIter->mPrefix == prefix) - return channelIter->mResultCode != 0; - - return false; + BoundChannelList::iterator channelIter = mBoundChannelList.begin(); + for (; channelIter != mBoundChannelList.end(); ++channelIter) + if (channelIter->mComponentId == component && channelIter->mPrefix == prefix) + return channelIter->mResultCode != 0; + + return false; } void Stream::removeBindingResult(int component) { - // Clear related channel bindings - Stream::BoundChannelList::iterator channelIter = mBoundChannelList.begin(); - while (channelIter != mBoundChannelList.end()) - { - if (channelIter->mComponentId == component) + // Clear related channel bindings + Stream::BoundChannelList::iterator channelIter = mBoundChannelList.begin(); + while (channelIter != mBoundChannelList.end()) { - ICELogDebug(<< "Clearing TURN channel binding " << channelIter->mPrefix << " for " << channelIter->mPeerAddress.toStdString()); - channelIter = mBoundChannelList.erase(channelIter); + if (channelIter->mComponentId == component) + { + ICELogDebug(<< "Clearing TURN channel binding " << channelIter->mPrefix << " for " + << channelIter->mPeerAddress.toStdString()); + channelIter = mBoundChannelList.erase(channelIter); + } + else + channelIter++; } - else - channelIter++; - } } NetworkAddress Stream::reflexiveAddress(int componentID) { - for (size_t i=0; ifirst && component != -1) - continue; - - ClientCreatePermission* ccp = new ClientCreatePermission(); - - ccp->setComment( "CreatePermissions request" ); - ccp->setStackId( mStackId ); - ccp->setDestination( (mConfig.mServerAddr4.isEmpty() || mConfig.mServerAddr4.isZero()) ? mConfig.mServerAddr6 : mConfig.mServerAddr4 ); - ccp->setUsername( mConfig.mTurnUsername ); - ccp->setPassword( mConfig.mTurnPassword ); - -#ifdef ICE_CACHE_REALM_NONCE - ccp->setRealm( mCachedRealm ); - ccp->setNonce( mCachedNonce ); -#endif - ccp->setAction( PAction(new ICEInstallPermissionsAction(*this, mConfig, cb)) ); - - // Get remote candidates for given component - if (addr.isEmpty()) + // Iterate all components + int requestCounter = 0; + for (ComponentMap::iterator cmip = mComponentMap.begin(); cmip != mComponentMap.end(); ++cmip) { - for (auto candIter = mRemoteCandidate.begin(); candIter != mRemoteCandidate.end(); candIter++) - if (candIter->mComponentId == cmip->first && candIter->mExternalAddr.isPublic()) - ccp->addIpAddress(candIter->mExternalAddr); - for (auto candIter = mRemoteRelayedCandidate.begin(); candIter != mRemoteRelayedCandidate.end(); candIter++) - if (candIter->mComponentId == cmip->first) - ccp->addIpAddress(candIter->mExternalAddr); + // Check if component is found + if (component != cmip->first && component != -1) + continue; + + ClientCreatePermission* ccp = new ClientCreatePermission(); + + ccp->setComment("CreatePermissions request"); + ccp->setStackId(mStackId); + ccp->setDestination((mConfig.mServerAddr4.isEmpty() || mConfig.mServerAddr4.isZero()) ? mConfig.mServerAddr6 + : mConfig.mServerAddr4); + ccp->setUsername(mConfig.mTurnUsername); + ccp->setPassword(mConfig.mTurnPassword); + +#ifdef ICE_CACHE_REALM_NONCE + ccp->setRealm(mCachedRealm); + ccp->setNonce(mCachedNonce); +#endif + ccp->setAction(PAction(new ICEInstallPermissionsAction(*this, mConfig, cb))); + + // Get remote candidates for given component + if (addr.isEmpty()) + { + for (auto candIter = mRemoteCandidate.begin(); candIter != mRemoteCandidate.end(); candIter++) + if (candIter->mComponentId == cmip->first && candIter->mExternalAddr.isPublic()) + ccp->addIpAddress(candIter->mExternalAddr); + for (auto candIter = mRemoteRelayedCandidate.begin(); candIter != mRemoteRelayedCandidate.end(); candIter++) + if (candIter->mComponentId == cmip->first) + ccp->addIpAddress(candIter->mExternalAddr); + } + else + ccp->addIpAddress(addr); + ccp->setComponent(cmip->first); + + // Enqueue transaction + mActiveChecks.addPrioritized(ccp); + requestCounter++; } - else - ccp->addIpAddress(addr); - ccp->setComponent(cmip->first); - - // Enqueue transaction - mActiveChecks.addPrioritized(ccp); - requestCounter++; - } - ICELogDebug(<< "Created " << requestCounter << " CreatePermission requests"); + ICELogDebug(<< "Created " << requestCounter << " CreatePermission requests"); } void Stream::dump(std::ostream& output) { - output << Logger::TabPrefix << "State: " << RunningStateToString(mState) << std::endl; - output << Logger::TabPrefix << "Local candidates: " << std::endl; - for (unsigned i=0; ifirst(); - remote = validPair->second(); - return true; + PCandidatePair validPair = mCheckList.findBestValidPair(local.mComponentId); + if (!validPair) + return false; + local = validPair->first(); + remote = validPair->second(); + return true; } int Stream::findComponentIdByPort(unsigned short port, int family) { - ComponentMap::iterator it = mComponentMap.begin(); - for (;it != mComponentMap.end();it++) - if (family == AF_INET) - { - if (it->second.mPort4 == port) - return it->first; - } - else - { - if (it->second.mPort6 == port) - return it->first; - } + ComponentMap::iterator it = mComponentMap.begin(); + for (; it != mComponentMap.end(); it++) + if (family == AF_INET) + { + if (it->second.mPort4 == port) + return it->first; + } + else + { + if (it->second.mPort6 == port) + return it->first; + } - return -1; + return -1; } void Stream::clearChecks() { - switch (mState) - { - case Success: - mCheckList.clear(); - mActiveChecks.erase(EraseBindingAndRelaying()); - break; + switch (mState) + { + case Success: + mCheckList.clear(); + mActiveChecks.erase(EraseBindingAndRelaying()); + break; - case Failed: - mCheckList.clear(); - mActiveChecks.erase(KeepDeallocationRequest()); - break; - - default: - break; - } + case Failed: + mCheckList.clear(); + mActiveChecks.erase(KeepDeallocationRequest()); + break; + + default: + break; + } } void Stream::dumpLocalCandidateList() { - std::ostringstream oss; - oss << "Local candidate list:" << std::endl; - for (unsigned i=0; iremoved()) - return false; - if (!t->action()) - return false; - if (t == mValidTransaction) - return false; - if (t->component() != mComponent) - return false; - if (t->failoverId() != mFailoverId) - return false; - - // Special case for Allocate - RelayingAction* relayingAction = dynamic_cast(t->action().get()); - bool binding = dynamic_cast(t->action().get()) != NULL; - - if (relayingAction) - relayingAction->autoreleaseAllocation(); - - return binding; - } + GatheringCondition(int component, int failoverId, Transaction* valid) + : mComponent(component), mFailoverId(failoverId), mValidTransaction(valid) + { + } + + bool check(Transaction* t) const + { + if (!t) + return false; + if (t->removed()) + return false; + if (!t->action()) + return false; + if (t == mValidTransaction) + return false; + if (t->component() != mComponent) + return false; + if (t->failoverId() != mFailoverId) + return false; + + // Special case for Allocate + RelayingAction* relayingAction = dynamic_cast(t->action().get()); + bool binding = dynamic_cast(t->action().get()) != NULL; + + if (relayingAction) + relayingAction->autoreleaseAllocation(); + + return binding; + } }; void Stream::removeGatherRequests(int component, int failoverId, Transaction* validOne) { - mActiveChecks.erase(GatheringCondition(component, failoverId, validOne)); + mActiveChecks.erase(GatheringCondition(component, failoverId, validOne)); } -void Stream::nominatePair(PCandidatePair &p) +void Stream::nominatePair(PCandidatePair& p) { - // Check if pair is already nominated - if (p->nomination() != p->Nomination_None) - return; - - if (!p->transaction()) - { - // It can be newly created candidate pair - PCandidatePair equalPair = mCheckList.findEqualPair(*p, CheckList::CT_Strict); - if (equalPair) - createCheckRequest(equalPair); - } - - Transaction* t = reinterpret_cast(p->transaction()); - if (!t) - { - ICELogCritical(<< "Logical error in nomination procedure."); - return; - } - - CheckResult* cr = dynamic_cast(t); + // Check if pair is already nominated + if (p->nomination() != p->Nomination_None) + return; - p->setNomination(CandidatePair::Nomination_Started); - - // Restart binding transaction - t->restart(); - - - // "upgrade" binding transaction to include USE-CANDIDATE attribute - cr->useCandidate(); - - // Push log records - t->setComment("Nominated request for " + p->toStdString()); - ICELogInfo (<< "Stack ID " << t->stackId() << ". Generated nominated candidate request for pair " << p->toStdString()); - - // Prioritize restarted transaction - mActiveChecks.prioritize(t); - - // Mark transaction's action as nomination - CheckPairAction* cp = dynamic_cast(t->action().get()); - if (cp) - cp->setNomination(true); + if (!p->transaction()) + { + // It can be newly created candidate pair + PCandidatePair equalPair = mCheckList.findEqualPair(*p, CheckList::CT_Strict); + if (equalPair) + createCheckRequest(equalPair); + } + + Transaction* t = reinterpret_cast(p->transaction()); + if (!t) + { + ICELogCritical(<< "Logical error in nomination procedure."); + return; + } + + CheckResult* cr = dynamic_cast(t); + + p->setNomination(CandidatePair::Nomination_Started); + + // Restart binding transaction + t->restart(); + + + // "upgrade" binding transaction to include USE-CANDIDATE attribute + cr->useCandidate(); + + // Push log records + t->setComment("Nominated request for " + p->toStdString()); + ICELogInfo(<< "Stack ID " << t->stackId() << ". Generated nominated candidate request for pair " + << p->toStdString()); + + // Prioritize restarted transaction + mActiveChecks.prioritize(t); + + // Mark transaction's action as nomination + CheckPairAction* cp = dynamic_cast(t->action().get()); + if (cp) + cp->setNomination(true); } -class OldAllocationCondition: public TransactionCondition +class OldAllocationCondition : public TransactionCondition { protected: - int mComponent; + int mComponent; + public: - OldAllocationCondition(int component) - :mComponent(component) - {} - - bool check(Transaction* t) const - { - if (!t->removed()) - return false; - ClientRefresh* cf = dynamic_cast(t); - if (!cf) - return false; - return true; - } + OldAllocationCondition(int component) : mComponent(component) {} + + bool check(Transaction* t) const + { + if (!t->removed()) + return false; + ClientRefresh* cf = dynamic_cast(t); + if (!cf) + return false; + return true; + } }; bool Stream::ressurectAllocation(int component) { - std::vector allocations; - mActiveChecks.copyMatching(OldAllocationCondition(component), allocations); - if (allocations.empty()) - return false; - // Find most recent allocation - unsigned current = ICETimeHelper::timestamp(); - unsigned delta = 0xFFFFFFFF; - Transaction* chosen = NULL; - for (size_t index=0; indextimestamp() < delta) + std::vector allocations; + mActiveChecks.copyMatching(OldAllocationCondition(component), allocations); + if (allocations.empty()) + return false; + // Find most recent allocation + unsigned current = ICETimeHelper::timestamp(); + unsigned delta = 0xFFFFFFFF; + Transaction* chosen = NULL; + for (size_t index = 0; index < allocations.size(); index++) { - chosen = t; - delta = current - t->timestamp(); + Transaction* t = allocations[index]; + if (current - t->timestamp() < delta) + { + chosen = t; + delta = current - t->timestamp(); + } } - } - - if (!chosen) - return false; - - ClientRefresh* cf = dynamic_cast(chosen); - if (!cf) - return false; // Just extra check - cf->setRemoved(false); - - // Update local candidates - for (unsigned i=0; i(chosen); + if (!cf) + return false; // Just extra check + cf->setRemoved(false); + + // Update local candidates + for (unsigned i = 0; i < mLocalCandidate.size(); i++) { - c.mReady = true; - c.mFailed = false; - if (c.mType == Candidate::ServerReflexive) - c.mExternalAddr = cf->reflexiveAddress(); - else - if (c.mType == Candidate::ServerRelayed) - c.mExternalAddr = cf->relayedAddress(); + Candidate& c = mLocalCandidate[i]; + + // Avoid updating of successful candidates to failed state + if (c.mComponentId == component) + { + c.mReady = true; + c.mFailed = false; + if (c.mType == Candidate::ServerReflexive) + c.mExternalAddr = cf->reflexiveAddress(); + else if (c.mType == Candidate::ServerRelayed) + c.mExternalAddr = cf->relayedAddress(); + } } - } - return true; + return true; } diff --git a/src/libs/ice/ICEStream.h b/src/libs/ice/ICEStream.h index 8b64caa5..f489980e 100644 --- a/src/libs/ice/ICEStream.h +++ b/src/libs/ice/ICEStream.h @@ -22,15 +22,15 @@ namespace ice { - enum Failover - { +enum Failover +{ FailoverOn = 1, FailoverOff = 2 - }; +}; - // Session state - enum RunningState - { +// Session state +enum RunningState +{ None = 0, CandidateGathering, EliminateRedudand, @@ -42,294 +42,293 @@ namespace ice ConnCheck, Failed, Success - }; +}; - extern const char* RunningStateToString(RunningState state); +extern const char* RunningStateToString(RunningState state); - // Smart pointer to ICE stream type - typedef std::shared_ptr ICEStreamPtr; - - - // Map of used channel TURN prefixes as key and corresponding address as value - typedef std::map TurnPrefixMap; +// Smart pointer to ICE stream type +typedef std::shared_ptr ICEStreamPtr; - struct Component - { - void* mTag; + +// Map of used channel TURN prefixes as key and corresponding address as value +typedef std::map TurnPrefixMap; + +struct Component +{ + void* mTag; unsigned short mPort4; unsigned short mPort6; - unsigned mNominationWaitIntervalStartTime; - Component() - :mTag(NULL), mPort4(0), mPort6(0), mNominationWaitIntervalStartTime(0) - {} + unsigned mNominationWaitIntervalStartTime; + Component() : mTag(NULL), mPort4(0), mPort6(0), mNominationWaitIntervalStartTime(0) {} ~Component() = default; - }; +}; - typedef std::map ComponentMap; +typedef std::map ComponentMap; - // Represents single ICE stream with single or multiple components (sockets) - struct Stream - { +// Represents single ICE stream with single or multiple components (sockets) +struct Stream +{ // Stream id - int mId; + int mId; // Stack ID. Used for debugging purposes. - int mStackId; + int mStackId; // Map of component ID -> user tag - ComponentMap mComponentMap; + ComponentMap mComponentMap; // List of local candidates and list of remote candidates typedef std::vector CandidateVector; - CandidateVector mLocalCandidate, mRemoteCandidate, mRemoteRelayedCandidate; + CandidateVector mLocalCandidate, mRemoteCandidate, mRemoteRelayedCandidate; // Check list - CheckList mCheckList; - + CheckList mCheckList; + // Logger - Logger* mLogger; + Logger* mLogger; // Foundation generator value to provide foundation value for peer reflexive candidates - unsigned int mFoundationGenerator; + unsigned int mFoundationGenerator; - // Active STUN transactions. This vector includes connectivity check transactions and gather candidates transactions. - // Keepalive transactions are stored in mKeepAliveList - TransactionList mActiveChecks; + // Active STUN transactions. This vector includes connectivity check transactions and gather candidates + // transactions. Keepalive transactions are stored in mKeepAliveList + TransactionList mActiveChecks; // ICE agent role - AgentRole mAgentRole; + AgentRole mAgentRole; // Map of established relay channels - TurnPrefixMap mTurnPrefixMap; - + TurnPrefixMap mTurnPrefixMap; + // Current state of media stream - RunningState mState; - + RunningState mState; + // Used configuration - StackConfig mConfig; - + StackConfig mConfig; + // Helper vector used to prioritize candidates - std::vector mComponentLimit; + std::vector mComponentLimit; // Default candidate list - one per each component - std::map mDefaultCandidate; - + std::map mDefaultCandidate; + // Local password/ufrag - std::string mLocalPwd; - std::string mLocalUfrag; + std::string mLocalPwd; + std::string mLocalUfrag; // Remote password/ufrag - std::string mRemotePwd; - std::string mRemoteUfrag; + std::string mRemotePwd; + std::string mRemoteUfrag; // Marks if selected during connectivity checks default IP list differs from used to generate offer - bool mDefaultIPChanged; - + bool mDefaultIPChanged; + // Marks if checks was ok for this stream and each component has valid nominated pair - bool mCanTransmit; - - std::vector mResponseQueue; + bool mCanTransmit; + + std::vector mResponseQueue; // Tie breaker - std::string mTieBreaker; + std::string mTieBreaker; // Timer to schedule connection checks (CC) - ICEScheduleTimer mScheduleTimer; + ICEScheduleTimer mScheduleTimer; // Counter of TURN allocations - int mTurnAllocated; - + int mTurnAllocated; + // Last error code during gathering/checks - int mErrorCode; + int mErrorCode; // Cached realm and nonce for used TURN server - std::string mCachedRealm, mCachedNonce; - + std::string mCachedRealm, mCachedNonce; + // Timestamp of nomination waiting timer. Used to accumulate valid pairs and chose the "best" of them. - unsigned mNominationWaitStartTime; - + unsigned mNominationWaitStartTime; + // Number of finished failover gathering requests - int mFailoverRequestsFinished; - + int mFailoverRequestsFinished; + // Failover ID generator. Failover transactions which share the same goal share the same ID. - int mFailoverIdGenerator; - + int mFailoverIdGenerator; + struct BoundChannel { - int mComponentId; - TurnPrefix mPrefix; - NetworkAddress mPeerAddress; - int mResultCode; + int mComponentId; + TurnPrefix mPrefix; + NetworkAddress mPeerAddress; + int mResultCode; }; typedef std::vector BoundChannelList; - BoundChannelList mBoundChannelList; - + BoundChannelList mBoundChannelList; + // Create Allocate transaction and associate with passed action struct AllocateOptions { - NetworkAddress mServerAddress; - PAction mActionOnFinish; - int mComponent = 0; - Failover mFailoverOption = FailoverOn; - int mWireFamily = AF_INET; - int mAllocFamily = AF_INET; - int mFailoverId = 0; + NetworkAddress mServerAddress; + PAction mActionOnFinish; + int mComponent = 0; + Failover mFailoverOption = FailoverOn; + int mWireFamily = AF_INET; + int mAllocFamily = AF_INET; + int mFailoverId = 0; }; - void allocate(const AllocateOptions& options); - + void allocate(const AllocateOptions& options); + // Create Bind transaction and associate with passed action - void bind(const NetworkAddress& addr, PAction action, bool auth, int component, Failover failover); - + void bind(const NetworkAddress& addr, PAction action, bool auth, int component, Failover failover); + // Searches for local candidate with specified address - unsigned findLocalCandidate(const NetworkAddress& addr); - + unsigned findLocalCandidate(const NetworkAddress& addr); + // Cancels found transaction. - void cancelCheck(CandidatePair& p); - + void cancelCheck(CandidatePair& p); + // Cancels allocations - void cancelAllocations(); - + void cancelAllocations(); + // Searches for remote candidate with specified remote address and corresponding to local port number - unsigned findRemoteCandidate(const NetworkAddress& addr, int componentID); + unsigned findRemoteCandidate(const NetworkAddress& addr, int componentID); // Process incoming binding request - void handleBindingRequest(ServerBinding& binding, ByteBuffer& buffer, int component); + void handleBindingRequest(ServerBinding& binding, ByteBuffer& buffer, int component); + + // Handles incoming data in gathering candidate stage. + bool handleCgIn(StunMessage& msg, NetworkAddress& address); - // Handles incoming data in gathering candidate stage. - bool handleCgIn(StunMessage& msg, NetworkAddress& address); - // Handle eliminate redudand stage - void Handle_ER(); - + void Handle_ER(); + // Compute foundations - void Handle_CF(); - + void Handle_CF(); + // Starting keep alive timers - void Handle_SKA(); + void Handle_SKA(); // Prioritize candidates - void Handle_PC(); - + void Handle_PC(); + // Choosing default candidate - void Handle_CD(); - + void Handle_CD(); + // Handles keepalive messages - //bool handleKeepAlivesIn(StunMessage& msg, NetworkAddress& address); + // bool handleKeepAlivesIn(StunMessage& msg, NetworkAddress& address); // Handles incoming messages in connectivity checks stage // This method uses Handle_KA_In to perform keepalive handling - bool handleConnChecksIn(StunMessage& msg, NetworkAddress& address); + bool handleConnChecksIn(StunMessage& msg, NetworkAddress& address); // Handle incoming Bind request - void handleIncomingRequest(StunMessage& msg, ByteBuffer& buffer, int component); + void handleIncomingRequest(StunMessage& msg, ByteBuffer& buffer, int component); // Chooses default candidate for specified component ID Candidate findDefaultCandidate(int componentID); - //Performs 8.1.2. Updating States - void checkNominated(int componentID); - void checkNominated(); - bool handleRoleConflict(ServerBinding& binding); - - //Checks active transactions (keepalive and ordinary) for timeouts - void isTimeout(); + // Performs 8.1.2. Updating States + void checkNominated(int componentID); + void checkNominated(); + bool handleRoleConflict(ServerBinding& binding); + + // Checks active transactions (keepalive and ordinary) for timeouts + void isTimeout(); // Checks for next byte buffer for sending ByteBuffer* handleConnChecksOut(); - - // Creates connectivity check request for specified pair. - Transaction* createCheckRequest(PCandidatePair& p); - // Checks for TURN channel prefix by specified peer's address. + // Creates connectivity check request for specified pair. + Transaction* createCheckRequest(PCandidatePair& p); + + // Checks for TURN channel prefix by specified peer's address. // Returns zero prefix if it is not found. - TurnPrefix findTurnPrefixByAddress(NetworkAddress& peerAddress); + TurnPrefix findTurnPrefixByAddress(NetworkAddress& peerAddress); // Create candidate pair in check list. - void createCheckList(); - + void createCheckList(); + // Starts connectivity checks - calls Create_CheckList to create check list + starts retransmission timer - void startChecks(); + void startChecks(); // Stops connectivity checks and gathering requests - void stopChecks(); - - // Initiates ChannelBind transaction to TURN server. - TurnPrefix bindChannel(const NetworkAddress& peerAddress, int component, ChannelBoundCallback* cb = NULL); - bool isChannelBindingFailed(int component, TurnPrefix prefix); - void removeBindingResult(int component); - - // Attempts to free allocation. - void freeAllocation(int component, DeleteAllocationCallback* cb = NULL); + void stopChecks(); - // Searches for local server reflexive candidate with specified component ID and returns its external address. - NetworkAddress reflexiveAddress(int componentID); + // Initiates ChannelBind transaction to TURN server. + TurnPrefix bindChannel(const NetworkAddress& peerAddress, int component, ChannelBoundCallback* cb = NULL); + bool isChannelBindingFailed(int component, TurnPrefix prefix); + void removeBindingResult(int component); + + // Attempts to free allocation. + void freeAllocation(int component, DeleteAllocationCallback* cb = NULL); + + // Searches for local server reflexive candidate with specified component ID and returns its external address. + NetworkAddress reflexiveAddress(int componentID); /*! Searches for local server relayed candidate with specified component ID and returns its external address. */ - NetworkAddress relayedAddress(int componentID); - + NetworkAddress relayedAddress(int componentID); + // Searches for remote server relayed candidate with specified component - NetworkAddress remoteRelayedAddress(int component); + NetworkAddress remoteRelayedAddress(int component); // Searches for remote server reflexive candidate with specified component - NetworkAddress remoteReflexiveAddress(int component); - - + NetworkAddress remoteReflexiveAddress(int component); + + Stream(); ~Stream(); - + // Sets config - void setConfig(StackConfig& config); + void setConfig(StackConfig& config); // Sets ICE agent role - Controlled or Controlling - void setAgentRole(AgentRole role); + void setAgentRole(AgentRole role); // Sets local password - void setLocalPwd(const std::string& pwd); - + void setLocalPwd(const std::string& pwd); + // Sets local ufrag - void setLocalUfrag(const std::string& ufrag); - + void setLocalUfrag(const std::string& ufrag); + // Sets remote password - void setRemotePwd(const std::string& pwd); - + void setRemotePwd(const std::string& pwd); + // Sets remote ufrag - void setRemoteUfrag(const std::string& ufrag); + void setRemoteUfrag(const std::string& ufrag); // Sets tie breaker - void setTieBreaker(const std::string& tieBreaker); + void setTieBreaker(const std::string& tieBreaker); // Adds new component to stream - int addComponent(void* tag, unsigned short port4, unsigned short port6); + int addComponent(void* tag, unsigned short port4, unsigned short port6); // Gathers candidates for stream - void gatherCandidates(); - + void gatherCandidates(); + // Returns reference to check list - CheckList& checkList(); + CheckList& checkList(); // Check is stream owns specified port number - bool hasPortNumber(int family, unsigned short portNumber, int* component = NULL); + bool hasPortNumber(int family, unsigned short portNumber, int* component = NULL); // Processes incoming data - bool processData(StunMessage& msg, ByteBuffer& buffer, int component); + bool processData(StunMessage& msg, ByteBuffer& buffer, int component); + + void createOfferSdp(std::vector& defaultIP, std::vector& defaultPort, + std::vector& candidateList); - void createOfferSdp(std::vector& defaultIP, std::vector& defaultPort, - std::vector& candidateList); - NetworkAddress defaultAddress(int componentID); - void candidateList(int componentID, std::vector& candidateList); + void candidateList(int componentID, std::vector& candidateList); - PByteBuffer getDataToSend(bool& response, int& component, void*&tag); + PByteBuffer getDataToSend(bool& response, int& component, void*& tag); // Constructs new keepalive transaction and adds to mKeepAlives - void addKeepAliveCheck(CandidatePair& p); - - // Processes SDP offer, adding remote candidates from it - bool processSdpOffer(std::vector& candidateList, std::string defaultIP, unsigned short defaultPort, bool deleteRelayed); + void addKeepAliveCheck(CandidatePair& p); - // Checks if remote candidate list contains specified address + // Processes SDP offer, adding remote candidates from it + bool processSdpOffer(std::vector& candidateList, std::string defaultIP, unsigned short defaultPort, + bool deleteRelayed); + + // Checks if remote candidate list contains specified address bool candidateListContains(const std::string& remoteIP, unsigned short remotePort); - + // Restarts stream's connectivity checks void restart(); @@ -338,28 +337,29 @@ namespace ice // Deletes existing connectivity checks and resets turn allocation counters void clearForRestart(bool localNetworkChanged); - + // Returns resolved address of remote party identified by its componmentID NetworkAddress remoteAddress(int component); NetworkAddress localAddress(int component); - void installPermissions(int component = -1, const NetworkAddress& addr = NetworkAddress(), InstallPermissionsCallback* cb = NULL); - void dump(std::ostream& output); - bool findConcludePair(Candidate& local, Candidate& remote); - int findComponentIdByPort(unsigned short port, int family); - Transaction* runCheckList(CandidatePair::Role role, CandidatePair::State state); - void deleteTransactionAt(unsigned index); - void clearChecks(); - - void dumpLocalCandidateList(); - void processStateChain(); - + void installPermissions(int component = -1, const NetworkAddress& addr = NetworkAddress(), + InstallPermissionsCallback* cb = NULL); + void dump(std::ostream& output); + bool findConcludePair(Candidate& local, Candidate& remote); + int findComponentIdByPort(unsigned short port, int family); + Transaction* runCheckList(CandidatePair::Role role, CandidatePair::State state); + void deleteTransactionAt(unsigned index); + void clearChecks(); + + void dumpLocalCandidateList(); + void processStateChain(); + // Disables (removes) active transactions responsible for gathering candidates - binding & allocating - void removeGatherRequests(int component, int failoverId, Transaction* validOne); - void unfreeze(const char* foundation); - void nominatePair(PCandidatePair& p); - bool ressurectAllocation(int component); - }; -} + void removeGatherRequests(int component, int failoverId, Transaction* validOne); + void unfreeze(const char* foundation); + void nominatePair(PCandidatePair& p); + bool ressurectAllocation(int component); +}; +} // namespace ice #endif diff --git a/src/libs/ice/ICEStunAttributes.cpp b/src/libs/ice/ICEStunAttributes.cpp index cc5d1017..52add98b 100644 --- a/src/libs/ice/ICEStunAttributes.cpp +++ b/src/libs/ice/ICEStunAttributes.cpp @@ -12,947 +12,881 @@ using namespace ice; - // --- MappedAddress --- -MappedAddress::MappedAddress() -{ -} +MappedAddress::MappedAddress() {} -MappedAddress::~MappedAddress() -{ -} +MappedAddress::~MappedAddress() {} int MappedAddress::type() const { - return StunAttribute::MappedAddress; + return StunAttribute::MappedAddress; } NetworkAddress& MappedAddress::address() { - return mAddress; + return mAddress; } void MappedAddress::buildPacket(BufferWriter& writer) { - writer.writeUChar(0); - writer.writeUChar(mAddress.stunType()); - writer.writeUShort(mAddress.port()); - - switch (mAddress.stunType()) - { - case IPv4: - writer.writeBuffer(&mAddress.sockaddr4()->sin_addr, 4); - break; + writer.writeUChar(0); + writer.writeUChar(mAddress.stunType()); + writer.writeUShort(mAddress.port()); - case IPv6: - writer.writeBuffer(&mAddress.sockaddr6()->sin6_addr, 16); - break; + switch (mAddress.stunType()) + { + case IPv4: + writer.writeBuffer(&mAddress.sockaddr4()->sin_addr, 4); + break; - default: - assert(0); - } + case IPv6: + writer.writeBuffer(&mAddress.sockaddr6()->sin6_addr, 16); + break; + + default: + assert(0); + } } bool MappedAddress::parsePacket(BufferReader& reader) { - // Dequeue zero byte and ignore it - /*uint8_t zeroByte = */reader.readUChar(); + // Dequeue zero byte and ignore it + /*uint8_t zeroByte = */ reader.readUChar(); - // Dequeue family - mAddress.setStunType(reader.readUChar()); + // Dequeue family + mAddress.setStunType(reader.readUChar()); - // Dequeue port - mAddress.setPort(reader.readUShort()); - - // Deqeueue IP - mAddress.setIp(reader.readIp(mAddress.stunType() == IPv4 ? AF_INET : AF_INET6)); - - return true; + // Dequeue port + mAddress.setPort(reader.readUShort()); + + // Deqeueue IP + mAddress.setIp(reader.readIp(mAddress.stunType() == IPv4 ? AF_INET : AF_INET6)); + + return true; } void MappedAddress::dump(std::ostream& output) { - output << "MappedAddress " << mAddress.toStdString(); + output << "MappedAddress " << mAddress.toStdString(); } //----------- XorMappedAddress --------------- -XorMappedAddress::XorMappedAddress() -{} +XorMappedAddress::XorMappedAddress() {} -XorMappedAddress::~XorMappedAddress() -{} +XorMappedAddress::~XorMappedAddress() {} int XorMappedAddress::type() const { - return StunAttribute::XorMappedAddress; + return StunAttribute::XorMappedAddress; } void XorMappedAddress::buildPacket(BufferWriter& writer) { - // Queue zero byte - writer.writeUChar(0); - - // Queue family - writer.writeUChar(mAddress.stunType()); + // Queue zero byte + writer.writeUChar(0); - // Xor&queue port - uint16_t port = mAddress.port() ^ 0x2112; - writer.writeUShort(port); + // Queue family + writer.writeUChar(mAddress.stunType()); - // Xor&queue ip - unsigned int ip4 = 0; - uint32_t ip6[4]; - switch (mAddress.stunType()) - { - case IPv4: - ip4 = mAddress.sockaddr4()->sin_addr.s_addr; //this gets ip in network byte order - ip4 = ntohl(ip4); // get host byte order - ip4 ^= 0x2112A442; - writer.writeUInt(ip4); // It will convert again to network byte order - break; + // Xor&queue port + uint16_t port = mAddress.port() ^ 0x2112; + writer.writeUShort(port); - case IPv6: - // Get copy of address in network byte order - memcpy(&ip6, &mAddress.sockaddr6()->sin6_addr, 16); - - for (int i=0; i<3; i++) - ip6[i] ^= htonl(0x2112A442); - - writer.writeBuffer(ip6, 16); - break; - } + // Xor&queue ip + unsigned int ip4 = 0; + uint32_t ip6[4]; + switch (mAddress.stunType()) + { + case IPv4: + ip4 = mAddress.sockaddr4()->sin_addr.s_addr; // this gets ip in network byte order + ip4 = ntohl(ip4); // get host byte order + ip4 ^= 0x2112A442; + writer.writeUInt(ip4); // It will convert again to network byte order + break; + case IPv6: + // Get copy of address in network byte order + memcpy(&ip6, &mAddress.sockaddr6()->sin6_addr, 16); + + for (int i = 0; i < 3; i++) + ip6[i] ^= htonl(0x2112A442); + + writer.writeBuffer(ip6, 16); + break; + } } bool XorMappedAddress::parsePacket(BufferReader& reader) { - // Dequeue zero byte and ignore it - reader.readUChar(); + // Dequeue zero byte and ignore it + reader.readUChar(); - // Dequeue family - mAddress.setStunType(reader.readUChar()); + // Dequeue family + mAddress.setStunType(reader.readUChar()); - // Dequeue port - mAddress.setPort(reader.readUShort() ^ 0x2112); + // Dequeue port + mAddress.setPort(reader.readUShort() ^ 0x2112); - // Deqeueue IP - unsigned int ip4; - union - { - uint32_t ip6[4]; - in6_addr addr6; - } v6; - - switch (mAddress.stunType()) - { - case IPv4: - ip4 = htonl(reader.readUInt() ^ 0x2112A442); - mAddress.setIp(ip4); - break; + // Deqeueue IP + unsigned int ip4; + union + { + uint32_t ip6[4]; + in6_addr addr6; + } v6; - case IPv6: - reader.readBuffer(v6.ip6, 16); - // XOR buffer - for (int i=0; i<3; i++) - v6.ip6[i] ^= htonl(0x2112A442); - mAddress.setIp(v6.addr6); - break; + switch (mAddress.stunType()) + { + case IPv4: + ip4 = htonl(reader.readUInt() ^ 0x2112A442); + mAddress.setIp(ip4); + break; - default: - assert(0); - } + case IPv6: + reader.readBuffer(v6.ip6, 16); + // XOR buffer + for (int i = 0; i < 3; i++) + v6.ip6[i] ^= htonl(0x2112A442); + mAddress.setIp(v6.addr6); + break; - return true; + default: + assert(0); + } + + return true; } -void XorMappedAddress::dump(std::ostream &output) +void XorMappedAddress::dump(std::ostream& output) { - output << "XorMappedAddress " << mAddress.toStdString(); + output << "XorMappedAddress " << mAddress.toStdString(); } //------------ StringAttr ----------------------- -StringAttr::StringAttr() -{ -} -StringAttr::~StringAttr() -{ -} +StringAttr::StringAttr() {} +StringAttr::~StringAttr() {} int StringAttr::type() const { - return StunAttribute::UnknownAttributes; + return StunAttribute::UnknownAttributes; } std::string StringAttr::value() const { - return mValue; + return mValue; } void StringAttr::setValue(const std::string& value) { - mValue = value; + mValue = value; } void StringAttr::buildPacket(BufferWriter& writer) { - if (!mValue.empty()) - writer.writeBuffer(mValue.c_str(), mValue.length()); + if (!mValue.empty()) + writer.writeBuffer(mValue.c_str(), mValue.length()); } bool StringAttr::parsePacket(BufferReader& reader) { - char temp[1024]; memset(temp, 0, sizeof temp); - reader.readBuffer(temp, sizeof temp); - mValue = temp; + char temp[1024]; + memset(temp, 0, sizeof temp); + reader.readBuffer(temp, sizeof temp); + mValue = temp; - return true; + return true; } void StringAttr::dump(std::ostream& output) { - output << "StringAttr " << mValue; + output << "StringAttr " << mValue; } //----------- Username --------------------------------- -Username::Username() -{} +Username::Username() {} -Username::~Username() -{} +Username::~Username() {} int Username::type() const { - return StunAttribute::Username; + return StunAttribute::Username; } -void Username::dump(std::ostream &output) +void Username::dump(std::ostream& output) { - output << "Username " << value(); + output << "Username " << value(); } //----------- MessageIntegrity ------------------------- MessageIntegrity::MessageIntegrity() { - memset(mValue, 0, sizeof(mValue)); -} -MessageIntegrity::~MessageIntegrity() -{ + memset(mValue, 0, sizeof(mValue)); } +MessageIntegrity::~MessageIntegrity() {} int MessageIntegrity::type() const { - return StunAttribute::MessageIntegrity; + return StunAttribute::MessageIntegrity; } void MessageIntegrity::setValue(const void* data) { - if (data) - memcpy(mValue, data, 20); + if (data) + memcpy(mValue, data, 20); } const void* MessageIntegrity::value() const { - return mValue; + return mValue; } void MessageIntegrity::buildPacket(BufferWriter& stream) { - stream.writeBuffer(mValue, 20); + stream.writeBuffer(mValue, 20); } bool MessageIntegrity::parsePacket(BufferReader& stream) { - try - { - stream.readBuffer(mValue, 20); - } - catch(...) - { - return false; - } + try + { + stream.readBuffer(mValue, 20); + } + catch (...) + { + return false; + } - return true; + return true; } -void MessageIntegrity::dump(std::ostream &output) +void MessageIntegrity::dump(std::ostream& output) { - ByteBuffer buffer(mValue, 20); - output << "MessageIntegrity " << buffer.hexstring(); + ByteBuffer buffer(mValue, 20); + output << "MessageIntegrity " << buffer.hexstring(); } //--------------- Fingerprint ---------------- Fingerprint::Fingerprint() { - mCRC32 = 0; + mCRC32 = 0; } -Fingerprint::~Fingerprint() -{ -} +Fingerprint::~Fingerprint() {} int Fingerprint::type() const { - return StunAttribute::Fingerprint; + return StunAttribute::Fingerprint; } void Fingerprint::setCrc32(unsigned int crc) { - mCRC32 = crc; + mCRC32 = crc; } unsigned int Fingerprint::crc32() const { - return mCRC32; + return mCRC32; } void Fingerprint::buildPacket(BufferWriter& stream) { - stream.writeUInt(mCRC32); + stream.writeUInt(mCRC32); } bool Fingerprint::parsePacket(BufferReader& stream) { - try - { - mCRC32 = stream.readUInt(); - } - catch(...) - { - return false; - } - - return true; + try + { + mCRC32 = stream.readUInt(); + } + catch (...) + { + return false; + } + + return true; } -void Fingerprint::dump(std::ostream &output) +void Fingerprint::dump(std::ostream& output) { - output << "Fingerprint " << mCRC32; + output << "Fingerprint " << mCRC32; } //---------------- ErrorCode --------------- ErrorCode::ErrorCode() { - mErrorCode = 0; + mErrorCode = 0; } -ErrorCode::~ErrorCode() -{ -} +ErrorCode::~ErrorCode() {} int ErrorCode::type() const { - return StunAttribute::ErrorCode; + return StunAttribute::ErrorCode; } void ErrorCode::setErrorCode(int errorCode) { - mErrorCode = errorCode; + mErrorCode = errorCode; } -int ErrorCode::errorCode() const +int ErrorCode::errorCode() const { - return mErrorCode; + return mErrorCode; } void ErrorCode::setErrorPhrase(const std::string& phrase) { - mErrorPhrase = phrase; + mErrorPhrase = phrase; } std::string ErrorCode::errorPhrase() const { - return mErrorPhrase; + return mErrorPhrase; } void ErrorCode::buildPacket(BufferWriter& stream) { - stream.writeUShort(0); - - uint8_t b = 0; - // Get hundreds digit - int digit = mErrorCode / 100; - b = (digit & 4 ? 1 : 0) << 2; - b |= (digit & 2 ? 1 : 0) << 1; - b |= (digit & 1 ? 1 : 0); - stream.writeUChar(b); - - stream.writeUChar(mErrorCode % 100); + stream.writeUShort(0); - if (!mErrorPhrase.empty()) - stream.writeBuffer(mErrorPhrase.c_str(), mErrorPhrase.length()); + uint8_t b = 0; + // Get hundreds digit + int digit = mErrorCode / 100; + b = (digit & 4 ? 1 : 0) << 2; + b |= (digit & 2 ? 1 : 0) << 1; + b |= (digit & 1 ? 1 : 0); + stream.writeUChar(b); + + stream.writeUChar(mErrorCode % 100); + + if (!mErrorPhrase.empty()) + stream.writeBuffer(mErrorPhrase.c_str(), mErrorPhrase.length()); } bool ErrorCode::parsePacket(BufferReader& stream) { - try - { - stream.readUShort(); - unsigned char _class = stream.readUChar(); - unsigned char _number = stream.readUChar(); + try + { + stream.readUShort(); + unsigned char _class = stream.readUChar(); + unsigned char _number = stream.readUChar(); - mErrorCode = _class * 100 + _number; - char temp[1024]; memset(temp, 0, sizeof temp); - stream.readBuffer(temp, sizeof temp); - mErrorPhrase = std::string(temp); - } - catch(...) - { - return false; - } + mErrorCode = _class * 100 + _number; + char temp[1024]; + memset(temp, 0, sizeof temp); + stream.readBuffer(temp, sizeof temp); + mErrorPhrase = std::string(temp); + } + catch (...) + { + return false; + } - return true; + return true; } -void ErrorCode::dump(std::ostream &output) +void ErrorCode::dump(std::ostream& output) { - output << "ErrorCode " << mErrorCode << " " << mErrorPhrase; + output << "ErrorCode " << mErrorCode << " " << mErrorPhrase; } //----------------- Realm ------------------------ -Realm::Realm() -{} +Realm::Realm() {} -Realm::~Realm() -{} +Realm::~Realm() {} int Realm::type() const { - return StunAttribute::Realm; + return StunAttribute::Realm; } -void Realm::dump(std::ostream &output) +void Realm::dump(std::ostream& output) { - output << "Realm " << value(); + output << "Realm " << value(); } //----------------- Nonce ------------------------ -Nonce::Nonce() -{} +Nonce::Nonce() {} -Nonce::~Nonce() -{} +Nonce::~Nonce() {} int Nonce::type() const { - return StunAttribute::Nonce; + return StunAttribute::Nonce; } -void Nonce::dump(std::ostream &output) +void Nonce::dump(std::ostream& output) { - output << "Nonce " << value(); + output << "Nonce " << value(); } //----------------- Server ----------------------- -Server::Server() -{} +Server::Server() {} -Server::~Server() -{} +Server::~Server() {} int Server::type() const { - return StunAttribute::Server; + return StunAttribute::Server; } -void Server::dump(std::ostream &output) +void Server::dump(std::ostream& output) { - output << "Server " << value(); + output << "Server " << value(); } //----------------- AlternateServer -------------- -AlternateServer::AlternateServer() -{} +AlternateServer::AlternateServer() {} -AlternateServer::~AlternateServer() -{} +AlternateServer::~AlternateServer() {} int AlternateServer::type() const { - return StunAttribute::AlternateServer; + return StunAttribute::AlternateServer; } -void AlternateServer::dump(std::ostream &output) +void AlternateServer::dump(std::ostream& output) { - output << "AlternateServer " << address().toStdString(); + output << "AlternateServer " << address().toStdString(); } //----------------- UnknownAttributes ------------ -UnknownAttributes::UnknownAttributes() -{ -} +UnknownAttributes::UnknownAttributes() {} -UnknownAttributes::~UnknownAttributes() -{ -} +UnknownAttributes::~UnknownAttributes() {} int UnknownAttributes::type() const { - return StunAttribute::UnknownAttributes; + return StunAttribute::UnknownAttributes; } void UnknownAttributes::buildPacket(BufferWriter& stream) { - char zeroBytes[8]; memset(zeroBytes, 0, sizeof(zeroBytes)); - stream.writeBuffer(zeroBytes, sizeof(zeroBytes)); + char zeroBytes[8]; + memset(zeroBytes, 0, sizeof(zeroBytes)); + stream.writeBuffer(zeroBytes, sizeof(zeroBytes)); } bool UnknownAttributes::parsePacket(BufferReader& stream) { - try - { - char zeroBytes[8]; memset(zeroBytes, 0, sizeof(zeroBytes)); - stream.readBuffer(zeroBytes, sizeof(zeroBytes)); - } - catch(...) - { - return false; - } - - return true; + try + { + char zeroBytes[8]; + memset(zeroBytes, 0, sizeof(zeroBytes)); + stream.readBuffer(zeroBytes, sizeof(zeroBytes)); + } + catch (...) + { + return false; + } + + return true; } -void UnknownAttributes::dump(std::ostream &output) +void UnknownAttributes::dump(std::ostream& output) { - output << "UnknownAttributes"; + output << "UnknownAttributes"; } //---------------- ChannelNumber ---------------- -ChannelNumber::ChannelNumber() -:mChannelNumber(0) -{ -} +ChannelNumber::ChannelNumber() : mChannelNumber(0) {} -ChannelNumber::~ChannelNumber() -{ -} +ChannelNumber::~ChannelNumber() {} int ChannelNumber::type() const { - return StunAttribute::ChannelNumber; + return StunAttribute::ChannelNumber; } void ChannelNumber::setChannelNumber(unsigned short value) { - mChannelNumber = value; + mChannelNumber = value; } unsigned short ChannelNumber::channelNumber() const { - return mChannelNumber; + return mChannelNumber; } -void ChannelNumber::buildPacket(BufferWriter& stream) +void ChannelNumber::buildPacket(BufferWriter& stream) { - stream.writeUShort(mChannelNumber); - stream.writeUChar(0); - stream.writeUChar(0); + stream.writeUShort(mChannelNumber); + stream.writeUChar(0); + stream.writeUChar(0); } -bool ChannelNumber::parsePacket(BufferReader& stream) +bool ChannelNumber::parsePacket(BufferReader& stream) { - try - { - mChannelNumber = stream.readUShort(); - stream.readUChar(); - stream.readUChar(); - } - catch(...) - { - return false; - } + try + { + mChannelNumber = stream.readUShort(); + stream.readUChar(); + stream.readUChar(); + } + catch (...) + { + return false; + } - return true; + return true; } -void ChannelNumber::dump(std::ostream &output) +void ChannelNumber::dump(std::ostream& output) { - output << "ChannelNumber " << mChannelNumber; + output << "ChannelNumber " << mChannelNumber; } //--------------------------------- Lifetime ----------------------- -Lifetime::Lifetime() -:mLifetime(0) -{ -} +Lifetime::Lifetime() : mLifetime(0) {} -Lifetime::~Lifetime() -{ -} +Lifetime::~Lifetime() {} int Lifetime::type() const { - return StunAttribute::Lifetime; + return StunAttribute::Lifetime; } void Lifetime::setLifetime(unsigned int value) { - mLifetime = value; + mLifetime = value; } unsigned int Lifetime::lifetime() const { - return mLifetime; + return mLifetime; } void Lifetime::buildPacket(BufferWriter& stream) { - stream.writeUInt(mLifetime); + stream.writeUInt(mLifetime); } bool Lifetime::parsePacket(BufferReader& stream) { - try - { - mLifetime = stream.readUInt(); - } - catch(...) - { - return false; - } + try + { + mLifetime = stream.readUInt(); + } + catch (...) + { + return false; + } - return true; + return true; } -void Lifetime::dump(std::ostream &output) +void Lifetime::dump(std::ostream& output) { - output << "Lifetime " << mLifetime; + output << "Lifetime " << mLifetime; } //----------------------- DataAttribute ---------------------- -DataAttribute::DataAttribute() -{ -} +DataAttribute::DataAttribute() {} -DataAttribute::~DataAttribute() -{ -} +DataAttribute::~DataAttribute() {} int DataAttribute::type() const { - return StunAttribute::Data; + return StunAttribute::Data; } -void DataAttribute::setData(ByteBuffer& buffer) +void DataAttribute::setData(ByteBuffer& buffer) { - mData = buffer; + mData = buffer; } ByteBuffer DataAttribute::data() const { - return mData; + return mData; } -void DataAttribute::buildPacket(BufferWriter& stream) +void DataAttribute::buildPacket(BufferWriter& stream) { - stream.writeBuffer(mData.data(), mData.size()); + stream.writeBuffer(mData.data(), mData.size()); } -bool DataAttribute::parsePacket(BufferReader& stream) +bool DataAttribute::parsePacket(BufferReader& stream) { - mData.resize(1024); - mData.resize(stream.readBuffer(mData.mutableData(), mData.size())); - return true; + mData.resize(1024); + mData.resize(stream.readBuffer(mData.mutableData(), mData.size())); + return true; } -void DataAttribute::dump(std::ostream &output) +void DataAttribute::dump(std::ostream& output) { - output << "DataAttribute " << mData.hexstring(); + output << "DataAttribute " << mData.hexstring(); } //---------------------- XorRelayedTransport ------------------------- -XorRelayedAddress::XorRelayedAddress() -{} +XorRelayedAddress::XorRelayedAddress() {} -XorRelayedAddress::~XorRelayedAddress() -{} +XorRelayedAddress::~XorRelayedAddress() {} int XorRelayedAddress::type() const { - return StunAttribute::XorRelayedAddress; + return StunAttribute::XorRelayedAddress; } -void XorRelayedAddress::dump(std::ostream &output) +void XorRelayedAddress::dump(std::ostream& output) { - output << "XorRelayedAddress " << address().toStdString(); + output << "XorRelayedAddress " << address().toStdString(); } //---------------------- RequestedTransport --------------------------- -RequestedTransport::RequestedTransport() -:mRequestedTransport(UDP) -{ -} +RequestedTransport::RequestedTransport() : mRequestedTransport(UDP) {} -RequestedTransport::~RequestedTransport() -{ -} +RequestedTransport::~RequestedTransport() {} int RequestedTransport::type() const { - return StunAttribute::RequestedTransport; + return StunAttribute::RequestedTransport; } void RequestedTransport::setRequestedTransport(RequestedTransport::TransportType value) { - mRequestedTransport = value; + mRequestedTransport = value; } unsigned char RequestedTransport::requestedTransport() const { - return mRequestedTransport; + return mRequestedTransport; } -void RequestedTransport::buildPacket(BufferWriter& stream) +void RequestedTransport::buildPacket(BufferWriter& stream) { - stream.writeUChar(mRequestedTransport); - stream.writeUChar(0); - stream.writeUChar(0); - stream.writeUChar(0); + stream.writeUChar(mRequestedTransport); + stream.writeUChar(0); + stream.writeUChar(0); + stream.writeUChar(0); } bool RequestedTransport::parsePacket(BufferReader& stream) { - try - { - mRequestedTransport = stream.readUChar(); - stream.readUChar(); - stream.readUChar(); - stream.readUChar(); - } - catch(...) - { - return false; - } + try + { + mRequestedTransport = stream.readUChar(); + stream.readUChar(); + stream.readUChar(); + stream.readUChar(); + } + catch (...) + { + return false; + } - return true; + return true; } -void RequestedTransport::dump(std::ostream &output) +void RequestedTransport::dump(std::ostream& output) { - output << "RequestedTransport " << mRequestedTransport; + output << "RequestedTransport " << mRequestedTransport; } //--------------------------------- Controlled ----------------------- -ControlledAttr::ControlledAttr() -{ -} +ControlledAttr::ControlledAttr() {} -ControlledAttr::~ControlledAttr() -{ -} +ControlledAttr::~ControlledAttr() {} int ControlledAttr::type() const { - return StunAttribute::ControlledAttr; + return StunAttribute::ControlledAttr; } std::string ControlledAttr::tieBreaker() const { - return std::string((const char*)mTieBreaker, 8); + return std::string((const char*)mTieBreaker, 8); } void ControlledAttr::setTieBreaker(const std::string& tieBreaker) { - assert(tieBreaker.length() == 8); + assert(tieBreaker.length() == 8); - memcpy(mTieBreaker, tieBreaker.c_str(), 8); + memcpy(mTieBreaker, tieBreaker.c_str(), 8); } void ControlledAttr::buildPacket(BufferWriter& stream) { - stream.writeBuffer(mTieBreaker, 8); + stream.writeBuffer(mTieBreaker, 8); } bool ControlledAttr::parsePacket(BufferReader& stream) { - try - { - stream.readBuffer(mTieBreaker, 8); - } - catch(...) - { - return false; - } + try + { + stream.readBuffer(mTieBreaker, 8); + } + catch (...) + { + return false; + } - return true; + return true; } -void ControlledAttr::dump(std::ostream &output) +void ControlledAttr::dump(std::ostream& output) { - ByteBuffer b(mTieBreaker, 8); - output << "ControlledAttr " << b.hexstring(); + ByteBuffer b(mTieBreaker, 8); + output << "ControlledAttr " << b.hexstring(); } //------------------- ControllingAttr -------------- ControllingAttr::ControllingAttr() { - memset(mTieBreaker, 0, sizeof(mTieBreaker)); + memset(mTieBreaker, 0, sizeof(mTieBreaker)); } -ControllingAttr::~ControllingAttr() -{ -} +ControllingAttr::~ControllingAttr() {} int ControllingAttr::type() const { - return StunAttribute::ControllingAttr; + return StunAttribute::ControllingAttr; } -std::string ControllingAttr::tieBreaker() const +std::string ControllingAttr::tieBreaker() const { - return std::string((const char*)mTieBreaker, 8); + return std::string((const char*)mTieBreaker, 8); } void ControllingAttr::setTieBreaker(const std::string& tieBreaker) { - memcpy(mTieBreaker, tieBreaker.c_str(), 8); + memcpy(mTieBreaker, tieBreaker.c_str(), 8); } void ControllingAttr::buildPacket(BufferWriter& stream) { - stream.writeBuffer(mTieBreaker, 8); + stream.writeBuffer(mTieBreaker, 8); } bool ControllingAttr::parsePacket(BufferReader& stream) { - try - { - stream.readBuffer(mTieBreaker, 8); - } - catch(...) - { - return false; - } + try + { + stream.readBuffer(mTieBreaker, 8); + } + catch (...) + { + return false; + } - return true; + return true; } -void ControllingAttr::dump(std::ostream &output) +void ControllingAttr::dump(std::ostream& output) { - ByteBuffer b(mTieBreaker, 8); - output << "ControllingAttr " << b.hexstring(); + ByteBuffer b(mTieBreaker, 8); + output << "ControllingAttr " << b.hexstring(); } //----------- ICEPriority --------------- ICEPriority::ICEPriority() { - mPriority = 0; + mPriority = 0; } -ICEPriority::~ICEPriority() -{ -} +ICEPriority::~ICEPriority() {} int ICEPriority::type() const { - return StunAttribute::ICEPriority; + return StunAttribute::ICEPriority; } unsigned int ICEPriority::priority() const { - return mPriority; + return mPriority; } void ICEPriority::setPriority(unsigned int priority) { - mPriority = priority; + mPriority = priority; } void ICEPriority::buildPacket(BufferWriter& stream) { - stream.writeUInt(mPriority); + stream.writeUInt(mPriority); } bool ICEPriority::parsePacket(BufferReader& stream) { - try - { - mPriority = stream.readUInt(); - } - catch(...) - { - return false; - } + try + { + mPriority = stream.readUInt(); + } + catch (...) + { + return false; + } - return true; + return true; } -void ICEPriority::dump(std::ostream &output) +void ICEPriority::dump(std::ostream& output) { - output << "ICEPriority " << mPriority; + output << "ICEPriority " << mPriority; } //------------------ USE-CANDIDATE ----------------------- -ICEUseCandidate::ICEUseCandidate() -{ -} +ICEUseCandidate::ICEUseCandidate() {} -ICEUseCandidate::~ICEUseCandidate() -{ -} +ICEUseCandidate::~ICEUseCandidate() {} int ICEUseCandidate::type() const { - return StunAttribute::ICEUseCandidate; + return StunAttribute::ICEUseCandidate; } -void ICEUseCandidate::buildPacket(BufferWriter& /*buffer*/) -{ -} +void ICEUseCandidate::buildPacket(BufferWriter& /*buffer*/) {} bool ICEUseCandidate::parsePacket(BufferReader& /*buffer*/) { - return true; + return true; } -void ICEUseCandidate::dump(std::ostream &output) +void ICEUseCandidate::dump(std::ostream& output) { - output << "ICEUseCandidate"; + output << "ICEUseCandidate"; } // ------------- REQUESTED-ADDRESS-FAMILY ------------- -RequestedAddressFamily::RequestedAddressFamily() -:mAddressFamily(IPv4) -{} +RequestedAddressFamily::RequestedAddressFamily() : mAddressFamily(IPv4) {} -RequestedAddressFamily::RequestedAddressFamily(AddressFamily family) - :mAddressFamily(family) -{} +RequestedAddressFamily::RequestedAddressFamily(AddressFamily family) : mAddressFamily(family) {} -RequestedAddressFamily::~RequestedAddressFamily() -{} +RequestedAddressFamily::~RequestedAddressFamily() {} int RequestedAddressFamily::type() const { - return StunAttribute::RequestedAddressFamily; + return StunAttribute::RequestedAddressFamily; } AddressFamily RequestedAddressFamily::family() const { - return mAddressFamily; + return mAddressFamily; } void RequestedAddressFamily::buildPacket(BufferWriter& stream) { - stream.writeUChar(mAddressFamily); - stream.writeUChar(0); stream.writeUChar(0); stream.writeUChar(0); + stream.writeUChar(mAddressFamily); + stream.writeUChar(0); + stream.writeUChar(0); + stream.writeUChar(0); } bool RequestedAddressFamily::parsePacket(BufferReader& stream) { - try - { - mAddressFamily = (AddressFamily)stream.readUChar(); - } - catch(...) - { - return false; - } - return true; + try + { + mAddressFamily = (AddressFamily)stream.readUChar(); + } + catch (...) + { + return false; + } + return true; } -void RequestedAddressFamily::dump(std::ostream &output) +void RequestedAddressFamily::dump(std::ostream& output) { - output << "RequestedAddressFamily " << (mAddressFamily == IPv4 ? "IPv4" : "IPv6"); + output << "RequestedAddressFamily " << (mAddressFamily == IPv4 ? "IPv4" : "IPv6"); } diff --git a/src/libs/ice/ICEStunAttributes.h b/src/libs/ice/ICEStunAttributes.h index e363ae2b..706882ab 100644 --- a/src/libs/ice/ICEStunAttributes.h +++ b/src/libs/ice/ICEStunAttributes.h @@ -11,353 +11,358 @@ namespace ice { - class MappedAddress: public StunAttribute - { - public: +class MappedAddress : public StunAttribute +{ +public: MappedAddress(); virtual ~MappedAddress(); - virtual int type() const override; - NetworkAddress& address(); - virtual void buildPacket(BufferWriter& buffer) override; - virtual bool parsePacket(BufferReader& buffer) override; - virtual void dump(std::ostream& output) override; + virtual int type() const override; + NetworkAddress& address(); + virtual void buildPacket(BufferWriter& buffer) override; + virtual bool parsePacket(BufferReader& buffer) override; + virtual void dump(std::ostream& output) override; - protected: - NetworkAddress mAddress; - }; +protected: + NetworkAddress mAddress; +}; - class XorMappedAddress: public MappedAddress - { - public: +class XorMappedAddress : public MappedAddress +{ +public: XorMappedAddress(); virtual ~XorMappedAddress(); virtual int type() const override; - - virtual void buildPacket(BufferWriter& writer) override; - virtual bool parsePacket(BufferReader& reader) override; - virtual void dump(std::ostream& output) override; - }; - - class StringAttr: public StunAttribute - { - public: + + virtual void buildPacket(BufferWriter& writer) override; + virtual bool parsePacket(BufferReader& reader) override; + virtual void dump(std::ostream& output) override; +}; + +class StringAttr : public StunAttribute +{ +public: StringAttr(); virtual ~StringAttr(); - virtual int type() const override; - std::string value() const; - void setValue(const std::string& value); + virtual int type() const override; + std::string value() const; + void setValue(const std::string& value); - virtual void buildPacket(BufferWriter& writer) override; - virtual bool parsePacket(BufferReader& reader) override; - virtual void dump(std::ostream& output) override; + virtual void buildPacket(BufferWriter& writer) override; + virtual bool parsePacket(BufferReader& reader) override; + virtual void dump(std::ostream& output) override; - protected: +protected: std::string mValue; - }; - - class Username: public StringAttr - { - public: +}; + +class Username : public StringAttr +{ +public: Username(); ~Username(); - int type() const; + int type() const; void dump(std::ostream& output); - }; +}; - class MessageIntegrity: public StunAttribute - { - public: +class MessageIntegrity : public StunAttribute +{ +public: MessageIntegrity(); ~MessageIntegrity(); - int type() const override; - void setValue(const void* data); - const void* value() const; - - void buildPacket(BufferWriter& stream) override; - bool parsePacket(BufferReader& stream) override; - void dump(std::ostream& output) override; + int type() const override; + void setValue(const void* data); + const void* value() const; - protected: + void buildPacket(BufferWriter& stream) override; + bool parsePacket(BufferReader& stream) override; + void dump(std::ostream& output) override; + +protected: unsigned char mValue[20]; - }; +}; - class Fingerprint: public StunAttribute - { - public: +class Fingerprint : public StunAttribute +{ +public: Fingerprint(); ~Fingerprint(); - int type() const override; - void setCrc32(unsigned int crc); - unsigned int crc32() const; + int type() const override; + void setCrc32(unsigned int crc); + unsigned int crc32() const; - void buildPacket(BufferWriter& stream) override; - bool parsePacket(BufferReader& stream) override; - void dump(std::ostream& output) override; + void buildPacket(BufferWriter& stream) override; + bool parsePacket(BufferReader& stream) override; + void dump(std::ostream& output) override; - protected: - unsigned int mCRC32; - }; +protected: + unsigned int mCRC32; +}; - class ErrorCode: public StunAttribute - { - public: +class ErrorCode : public StunAttribute +{ +public: ErrorCode(); ~ErrorCode(); - virtual int type() const override; - void setErrorCode(int errorCode); - int errorCode() const; + virtual int type() const override; + void setErrorCode(int errorCode); + int errorCode() const; - void setErrorPhrase(const std::string& phrase); - std::string errorPhrase() const; - - void buildPacket(BufferWriter& stream) override; - bool parsePacket(BufferReader& stream) override; - void dump(std::ostream& output) override; + void setErrorPhrase(const std::string& phrase); + std::string errorPhrase() const; - protected: - int mErrorCode; - std::string mErrorPhrase; - }; + void buildPacket(BufferWriter& stream) override; + bool parsePacket(BufferReader& stream) override; + void dump(std::ostream& output) override; - class Realm: public StringAttr - { - public: +protected: + int mErrorCode; + std::string mErrorPhrase; +}; + +class Realm : public StringAttr +{ +public: Realm(); ~Realm(); - int type() const override; + int type() const override; void dump(std::ostream& output) override; - }; +}; - class Nonce: public StringAttr - { - public: +class Nonce : public StringAttr +{ +public: Nonce(); ~Nonce(); - - int type() const override; - void dump(std::ostream& output) override; - }; - class UnknownAttributes: public StunAttribute - { - public: + int type() const override; + void dump(std::ostream& output) override; +}; + +class UnknownAttributes : public StunAttribute +{ +public: UnknownAttributes(); ~UnknownAttributes(); - int type() const override; - void buildPacket(BufferWriter& stream) override; - bool parsePacket(BufferReader& stream) override; - void dump(std::ostream& output) override; - }; - - class Server: public StringAttr - { - public: - Server(); - ~Server(); - int type() const override; - void dump(std::ostream& output) override; - }; - - class AlternateServer: public MappedAddress - { - public: - AlternateServer(); - ~AlternateServer(); - int type() const override; - void dump(std::ostream& output) override; - }; - - - class ChannelNumber: public StunAttribute - { - public: - ChannelNumber(); - ~ChannelNumber(); - - int type() const override; - void setChannelNumber(unsigned short value); - unsigned short channelNumber() const; - - void buildPacket(BufferWriter& stream) override; - bool parsePacket(BufferReader& stream) override; - void dump(std::ostream& output) override; - protected: - unsigned short mChannelNumber; - }; - - class Lifetime: public StunAttribute - { - public: - Lifetime(); - ~Lifetime(); - - int type() const override; - void setLifetime(unsigned int value); - unsigned int lifetime() const; - - void buildPacket(BufferWriter& writer) override; - bool parsePacket(BufferReader& reader) override; - void dump(std::ostream& output) override; - protected: - unsigned int mLifetime; - }; - - class XorPeerAddress: public XorMappedAddress - { - public: - int type() const override - { - return StunAttribute::XorPeerAddress; - } - }; - - class DataAttribute: public StunAttribute - { - public: - DataAttribute(); - virtual ~DataAttribute(); - - int type() const override; - void setData(ByteBuffer& buffer); - ByteBuffer data() const; - - void buildPacket(BufferWriter& stream) override; - bool parsePacket(BufferReader& stream) override; - void dump(std::ostream &output) override; - - protected: - ByteBuffer mData; - }; - - class XorRelayedAddress: public XorMappedAddress - { - public: - XorRelayedAddress(); - ~XorRelayedAddress(); - int type() const override; - void dump(std::ostream& output) override; - }; - - class RequestedTransport: public StunAttribute - { - public: - RequestedTransport(); - virtual ~RequestedTransport(); - - enum TransportType - { - UDP = 17 - }; - - int type() const override; - void setRequestedTransport(TransportType value); - unsigned char requestedTransport() const; - - void buildPacket(BufferWriter& stream) override; - bool parsePacket(BufferReader& stream) override; - void dump(std::ostream& output) override; - protected: - unsigned char mRequestedTransport; //always 17! - }; - - class ReservedToken: public StunAttribute - { - public: - ReservedToken(); - ~ReservedToken(); - - int type() const override; - void setToken(const std::string& token); - std::string token() const; - - void buildPacket(BufferWriter& buffer) override; - bool parsePacket(BufferReader& buffer) override; - void dump(std::ostream& output) override; - protected: - std::string mToken; - }; - - class ControlledAttr: public StunAttribute - { - public: - ControlledAttr(); - ~ControlledAttr(); - - int type() const override; - - std::string tieBreaker() const; - void setTieBreaker(const std::string& tieBreaker); - void buildPacket(BufferWriter& stream) override; - bool parsePacket(BufferReader& stream) override; - void dump(std::ostream& output) override; - protected: - unsigned char mTieBreaker[8]; - }; - - class ControllingAttr: public StunAttribute - { - public: - ControllingAttr(); - ~ControllingAttr(); - - int type() const override; - std::string tieBreaker() const; - void setTieBreaker(const std::string& tieBreaker); - - void buildPacket(BufferWriter& stream) override; - bool parsePacket(BufferReader& stream) override; - void dump(std::ostream& output) override; - protected: - unsigned char mTieBreaker[8]; - }; - - class ICEPriority: public StunAttribute - { - public: - ICEPriority(); - ~ICEPriority(); - - int type() const override; - unsigned int priority() const; - void setPriority(unsigned int priority); - void buildPacket(BufferWriter& stream) override; - bool parsePacket(BufferReader& stream) override; - void dump(std::ostream& output) override; - protected: - unsigned int mPriority; - }; - - class ICEUseCandidate: public StunAttribute - { - public: - ICEUseCandidate(); - virtual ~ICEUseCandidate(); - int type() const override; - void buildPacket(BufferWriter& stream) override; - bool parsePacket(BufferReader& stream) override; - void dump(std::ostream& output) override; - }; - - class RequestedAddressFamily: public StunAttribute - { - public: - RequestedAddressFamily(); - RequestedAddressFamily(AddressFamily family); - ~RequestedAddressFamily(); - - int type() const override; - AddressFamily family() const; + int type() const override; void buildPacket(BufferWriter& stream) override; bool parsePacket(BufferReader& stream) override; void dump(std::ostream& output) override; - protected: +}; + +class Server : public StringAttr +{ +public: + Server(); + ~Server(); + int type() const override; + void dump(std::ostream& output) override; +}; + +class AlternateServer : public MappedAddress +{ +public: + AlternateServer(); + ~AlternateServer(); + int type() const override; + void dump(std::ostream& output) override; +}; + + +class ChannelNumber : public StunAttribute +{ +public: + ChannelNumber(); + ~ChannelNumber(); + + int type() const override; + void setChannelNumber(unsigned short value); + unsigned short channelNumber() const; + + void buildPacket(BufferWriter& stream) override; + bool parsePacket(BufferReader& stream) override; + void dump(std::ostream& output) override; + +protected: + unsigned short mChannelNumber; +}; + +class Lifetime : public StunAttribute +{ +public: + Lifetime(); + ~Lifetime(); + + int type() const override; + void setLifetime(unsigned int value); + unsigned int lifetime() const; + + void buildPacket(BufferWriter& writer) override; + bool parsePacket(BufferReader& reader) override; + void dump(std::ostream& output) override; + +protected: + unsigned int mLifetime; +}; + +class XorPeerAddress : public XorMappedAddress +{ +public: + int type() const override { return StunAttribute::XorPeerAddress; } +}; + +class DataAttribute : public StunAttribute +{ +public: + DataAttribute(); + virtual ~DataAttribute(); + + int type() const override; + void setData(ByteBuffer& buffer); + ByteBuffer data() const; + + void buildPacket(BufferWriter& stream) override; + bool parsePacket(BufferReader& stream) override; + void dump(std::ostream& output) override; + +protected: + ByteBuffer mData; +}; + +class XorRelayedAddress : public XorMappedAddress +{ +public: + XorRelayedAddress(); + ~XorRelayedAddress(); + int type() const override; + void dump(std::ostream& output) override; +}; + +class RequestedTransport : public StunAttribute +{ +public: + RequestedTransport(); + virtual ~RequestedTransport(); + + enum TransportType + { + UDP = 17 + }; + + int type() const override; + void setRequestedTransport(TransportType value); + unsigned char requestedTransport() const; + + void buildPacket(BufferWriter& stream) override; + bool parsePacket(BufferReader& stream) override; + void dump(std::ostream& output) override; + +protected: + unsigned char mRequestedTransport; // always 17! +}; + +class ReservedToken : public StunAttribute +{ +public: + ReservedToken(); + ~ReservedToken(); + + int type() const override; + void setToken(const std::string& token); + std::string token() const; + + void buildPacket(BufferWriter& buffer) override; + bool parsePacket(BufferReader& buffer) override; + void dump(std::ostream& output) override; + +protected: + std::string mToken; +}; + +class ControlledAttr : public StunAttribute +{ +public: + ControlledAttr(); + ~ControlledAttr(); + + int type() const override; + + std::string tieBreaker() const; + void setTieBreaker(const std::string& tieBreaker); + void buildPacket(BufferWriter& stream) override; + bool parsePacket(BufferReader& stream) override; + void dump(std::ostream& output) override; + +protected: + unsigned char mTieBreaker[8]; +}; + +class ControllingAttr : public StunAttribute +{ +public: + ControllingAttr(); + ~ControllingAttr(); + + int type() const override; + std::string tieBreaker() const; + void setTieBreaker(const std::string& tieBreaker); + + void buildPacket(BufferWriter& stream) override; + bool parsePacket(BufferReader& stream) override; + void dump(std::ostream& output) override; + +protected: + unsigned char mTieBreaker[8]; +}; + +class ICEPriority : public StunAttribute +{ +public: + ICEPriority(); + ~ICEPriority(); + + int type() const override; + unsigned int priority() const; + void setPriority(unsigned int priority); + void buildPacket(BufferWriter& stream) override; + bool parsePacket(BufferReader& stream) override; + void dump(std::ostream& output) override; + +protected: + unsigned int mPriority; +}; + +class ICEUseCandidate : public StunAttribute +{ +public: + ICEUseCandidate(); + virtual ~ICEUseCandidate(); + int type() const override; + void buildPacket(BufferWriter& stream) override; + bool parsePacket(BufferReader& stream) override; + void dump(std::ostream& output) override; +}; + +class RequestedAddressFamily : public StunAttribute +{ +public: + RequestedAddressFamily(); + RequestedAddressFamily(AddressFamily family); + ~RequestedAddressFamily(); + + int type() const override; + AddressFamily family() const; + void buildPacket(BufferWriter& stream) override; + bool parsePacket(BufferReader& stream) override; + void dump(std::ostream& output) override; + +protected: AddressFamily mAddressFamily; - }; -} +}; +} // namespace ice #endif diff --git a/src/libs/ice/ICEStunConfig.cpp b/src/libs/ice/ICEStunConfig.cpp index 29190e14..1e89f9b7 100644 --- a/src/libs/ice/ICEStunConfig.cpp +++ b/src/libs/ice/ICEStunConfig.cpp @@ -10,14 +10,14 @@ using namespace ice; std::string StackConfig::mDefaultIpTarget = ICE_FALLBACK_IP_ADDR; StackConfig::StackConfig() -:mUseTURN(false), mTimeout(DEFAULT_STUN_FINISH_TIMEOUT), mPeriod(DEFAULT_STUN_RETRANSMIT_TIMEOUT), -mUseSTUN(true), mUseIPv4(true), mUseIPv6(true) + : mUseTURN(false), mTimeout(DEFAULT_STUN_FINISH_TIMEOUT), mPeriod(DEFAULT_STUN_RETRANSMIT_TIMEOUT), mUseSTUN(true), + mUseIPv4(true), mUseIPv6(true) { #ifdef ICE_AGGRESSIVE mAggressiveNomination = true; mTreatRequestAsConfirmation = false; #endif - + #ifdef ICE_VERYAGGRESSIVE mAggressiveNomination = true; mTreatRequestAsConfirmation = true; @@ -27,10 +27,10 @@ mUseSTUN(true), mUseIPv4(true), mUseIPv6(true) #endif mInitialRTO = 100; mKeepAliveInterval = 5000; - mServerAddr4.setPort( 3478 ); - mServerAddr6.setPort( 3478 ); + mServerAddr4.setPort(3478); + mServerAddr6.setPort(3478); mTurnLifetime = 300; - mUseProtocolRelay = true;// false; + mUseProtocolRelay = true; // false; #ifdef TEST_RELAYING mTypePreferenceList[Candidate::Host] = 0; @@ -46,5 +46,4 @@ mUseSTUN(true), mUseIPv4(true), mUseIPv6(true) mTargetIP = mDefaultIpTarget; } -StackConfig::~StackConfig() -{} +StackConfig::~StackConfig() {} diff --git a/src/libs/ice/ICEStunConfig.h b/src/libs/ice/ICEStunConfig.h index a5873328..a52f84de 100644 --- a/src/libs/ice/ICEStunConfig.h +++ b/src/libs/ice/ICEStunConfig.h @@ -13,74 +13,72 @@ #include #include -namespace ice { - +namespace ice +{ + #define DEFAULT_STUN_RETRANSMIT_TIMEOUT 790000 -#define DEFAULT_STUN_FINISH_TIMEOUT 790000 -#define ICE_FALLBACK_IP_ADDR "8.8.8.8" +#define DEFAULT_STUN_FINISH_TIMEOUT 790000 +#define ICE_FALLBACK_IP_ADDR "8.8.8.8" // #define TEST_RELAYING - struct StackConfig - { +struct StackConfig +{ // The IP of STUN server - std::vector mServerList4, - mServerList6; - NetworkAddress mServerAddr4, - mServerAddr6; - + std::vector mServerList4, mServerList6; + NetworkAddress mServerAddr4, mServerAddr6; + // Use IPv4 when gathering candidates - bool mUseIPv4; + bool mUseIPv4; // Use IPv6 when gathering candidates - bool mUseIPv6; + bool mUseIPv6; // Should we use relying (TURN)? - bool mUseTURN; - + bool mUseTURN; + // Should we use IPv4 <--> IPv6 bypassing via relaying ? - bool mUseProtocolRelay; + bool mUseProtocolRelay; // The timeout for STUN transaction - unsigned int mTimeout; - + unsigned int mTimeout; + // The RTO - unsigned int mPeriod; - + unsigned int mPeriod; + // Marks if STUN use is disalbed - bool mUseSTUN; - + bool mUseSTUN; + // Sets the possible peer IP for ICE session - std::string mTargetIP; - + std::string mTargetIP; + // The type preference list for ICE session - int mTypePreferenceList[4]; - + int mTypePreferenceList[4]; + // The initial RTO value - int mInitialRTO; - + int mInitialRTO; + // Interval for keepalive checks - int mKeepAliveInterval; - - std::string mTurnUsername, - mTurnPassword; - + int mKeepAliveInterval; + + std::string mTurnUsername, mTurnPassword; + // TURN lifetime - int mTurnLifetime; + int mTurnLifetime; // Enable/disable aggressive nomination - bool mAggressiveNomination; + bool mAggressiveNomination; + + // Treats requests as confirmation for connectivity checks sent in reverse direction if the corresponding pair + // already exists It violates RFC. It can be needed in poor networks. + bool mTreatRequestAsConfirmation; - // Treats requests as confirmation for connectivity checks sent in reverse direction if the corresponding pair already exists - // It violates RFC. It can be needed in poor networks. - bool mTreatRequestAsConfirmation; - // Default IP target if mTargetIP is not set - static std::string mDefaultIpTarget; - + static std::string mDefaultIpTarget; + StackConfig(); ~StackConfig(); - }; - }; +}; // namespace ice + #endif diff --git a/src/libs/ice/ICEStunMessage.cpp b/src/libs/ice/ICEStunMessage.cpp index 3d627455..6465ea06 100644 --- a/src/libs/ice/ICEStunMessage.cpp +++ b/src/libs/ice/ICEStunMessage.cpp @@ -17,9 +17,9 @@ #include #ifndef _WIN32 -# include -# include -# include +#include +#include +#include #endif #define STUN_HEADER_SIZE 20 @@ -28,828 +28,829 @@ using namespace ice; -bool StunMessage::TransactionID::operator == (const StunMessage::TransactionID& rhs) +bool StunMessage::TransactionID::operator==(const StunMessage::TransactionID& rhs) { - return memcmp(mValue, rhs.mValue, 12) == 0; + return memcmp(mValue, rhs.mValue, 12) == 0; } -bool StunMessage::TransactionID::operator != (const TransactionID& rhs) +bool StunMessage::TransactionID::operator!=(const TransactionID& rhs) { - return memcmp(mValue, rhs.mValue, 12) != 0; + return memcmp(mValue, rhs.mValue, 12) != 0; } StunMessage::TransactionID::TransactionID() { - for (int i=0; i<12; i++) - mValue[i] = rand() & 0xFF; + for (int i = 0; i < 12; i++) + mValue[i] = rand() & 0xFF; - //memset(mValue, 0, 12); + // memset(mValue, 0, 12); } std::string StunMessage::TransactionID::toStdString() { - char hex[3]; - std::string result; - for (size_t i=0; i<12; i++) - { - sprintf(hex, "%2x", mValue[i]); - result += hex; - } - - return result; + char hex[3]; + std::string result; + for (size_t i = 0; i < 12; i++) + { + sprintf(hex, "%2x", mValue[i]); + result += hex; + } + + return result; } StunMessage::TransactionID StunMessage::TransactionID::generateNew() { - TransactionID result; - for (size_t i=0; i<12; i++) - result.mValue[i] = (unsigned char)rand(); + TransactionID result; + for (size_t i = 0; i < 12; i++) + result.mValue[i] = (unsigned char)rand(); - return result; + return result; } //--------------------------- StunAttribute ---------------------- StunAttribute::StunAttribute() { - mLength = 0; - mType = 0; - mDataOffset = 0; + mLength = 0; + mType = 0; + mDataOffset = 0; } -StunAttribute::~StunAttribute() -{ -} +StunAttribute::~StunAttribute() {} void StunAttribute::setDataOffset(size_t offset) { - mDataOffset = offset; + mDataOffset = offset; } size_t StunAttribute::dataOffset() const { - return mDataOffset; + return mDataOffset; } //---------------------------- StunMessage ----------------------- -StunMessage::StunMessage() -:mMagicCookie(0x2112A442) -{ - -} +StunMessage::StunMessage() : mMagicCookie(0x2112A442) {} StunMessage::~StunMessage() { - // Iterate map to delete all attributes - for (AttributeMap::iterator ait=mAttrMap.begin(); ait != mAttrMap.end(); ++ait) - delete ait->second; + // Iterate map to delete all attributes + for (AttributeMap::iterator ait = mAttrMap.begin(); ait != mAttrMap.end(); ++ait) + delete ait->second; } std::string StunMessage::comment() { - return mComment; + return mComment; } void StunMessage::setComment(std::string comment) { - mComment = comment; + mComment = comment; } void StunMessage::setMessageType(Type type) { - mType = type; + mType = type; } StunMessage::Type StunMessage::messageType() { - return mType; + return mType; } - + void StunMessage::setMessageClass(Class value) { - mClass = value; + mClass = value; } StunMessage::Class StunMessage::messageClass() { - return mClass; + return mClass; } unsigned int StunMessage::magicCookie() { - return mMagicCookie; + return mMagicCookie; } bool StunMessage::isMagicCookieValid() { - return mMagicCookie == 0x2112A442; + return mMagicCookie == 0x2112A442; } - + void StunMessage::setTransactionId(TransactionID id) { - mTransactionID = id; + mTransactionID = id; } StunMessage::TransactionID StunMessage::transactionId() { - return mTransactionID; + return mTransactionID; } static void EmbedAttrBuffer(StunAttribute& attr, BufferWriter& writer) { - ByteBuffer attrBuffer; attrBuffer.resize(512); - BufferWriter attrWriter(attrBuffer); - attr.buildPacket(attrWriter); - attrBuffer.resize(attrWriter.offset()); + ByteBuffer attrBuffer; + attrBuffer.resize(512); + BufferWriter attrWriter(attrBuffer); + attr.buildPacket(attrWriter); + attrBuffer.resize(attrWriter.offset()); - // Enqueue attribute type - writer.writeUShort(attr.type()); - - // Enqueue length - writer.writeUShort((uint16_t)attrBuffer.size()); - - // Save data offset in generated buffer - attr.setDataOffset(writer.offset() + 2); // 2 is for first 16 bits written by bitstream - - // Enqueue attribute's value - if (attrBuffer.size() > 0) - writer.writeBuffer(attrBuffer.data(), attrBuffer.size()); - - if (attrBuffer.size() & 0x3) - { - size_t paddingLength = 4 - (attrBuffer.size() & 0x3); - char paddingBytes[4] = { 0, 0, 0, 0 }; - writer.writeBuffer(paddingBytes, paddingLength); - } + // Enqueue attribute type + writer.writeUShort(attr.type()); + + // Enqueue length + writer.writeUShort((uint16_t)attrBuffer.size()); + + // Save data offset in generated buffer + attr.setDataOffset(writer.offset() + 2); // 2 is for first 16 bits written by bitstream + + // Enqueue attribute's value + if (attrBuffer.size() > 0) + writer.writeBuffer(attrBuffer.data(), attrBuffer.size()); + + if (attrBuffer.size() & 0x3) + { + size_t paddingLength = 4 - (attrBuffer.size() & 0x3); + char paddingBytes[4] = {0, 0, 0, 0}; + writer.writeBuffer(paddingBytes, paddingLength); + } } void StunMessage::buildPacket(ByteBuffer& buffer, const std::string& password) { - // Make enough space for packet - buffer.resize(1024); - - // Write bits - BitWriter bitstream(buffer); - - bitstream.writeBit(0) - .writeBit(0); - - unsigned int msgtype = mType & 0xFFF; - unsigned int msgclass = mClass & 0x3; + // Make enough space for packet + buffer.resize(1024); - // Enqueue last 5 bits of mtype - for (size_t i=0; i<5; i++) - bitstream.writeBit(bit(msgtype, 11 - i)); + // Write bits + BitWriter bitstream(buffer); - // Enqueue last bit of msgclass - bitstream.writeBit(bit(msgclass, 1)); - - // Enqueue 3 bits of msgtype - for (size_t i=0; i<3; i++) - bitstream.writeBit(bit(msgtype, 6 - i)); + bitstream.writeBit(0).writeBit(0); - // Enqueue first bit of msgclass - bitstream.writeBit(bit(msgclass, 0)); + unsigned int msgtype = mType & 0xFFF; + unsigned int msgclass = mClass & 0x3; - // Enqueue 4 bits of msgtype - for (size_t i=0; i<4; i++) - bitstream.writeBit(bit(msgtype, 3-i)); - - // Enqueue 2 bytes of length - now it is zero. - // Growable writer starting right after the bits already emitted; it resizes - // 'buffer' as attributes are appended so an oversized message cannot overflow. - BufferWriter stream(buffer, bitstream.count() / 8); - stream.writeUShort(0); + // Enqueue last 5 bits of mtype + for (size_t i = 0; i < 5; i++) + bitstream.writeBit(bit(msgtype, 11 - i)); - // Enqueue magic cookie value - unsigned int cookie = htonl(mMagicCookie); - stream.writeBuffer(&cookie, 4); + // Enqueue last bit of msgclass + bitstream.writeBit(bit(msgclass, 1)); - // Enqueue transaction ID - //memset(mTransactionID.mValue, 0, sizeof(mTransactionID.mValue)); // For debugging only - stream.writeBuffer(mTransactionID.mValue, 12); + // Enqueue 3 bits of msgtype + for (size_t i = 0; i < 3; i++) + bitstream.writeBit(bit(msgtype, 6 - i)); - // Iterate attributes - AttributeMap::iterator attrIter; - for (attrIter = mAttrMap.begin(); attrIter != mAttrMap.end(); ++attrIter) - { - StunAttribute& attr = *attrIter->second; + // Enqueue first bit of msgclass + bitstream.writeBit(bit(msgclass, 0)); - // Check if it is MessageIntegrity or Fingerprint - they comes last and skip them for now - if (attr.type() == StunAttribute::MessageIntegrity || attr.type() == StunAttribute::Fingerprint) - continue; + // Enqueue 4 bits of msgtype + for (size_t i = 0; i < 4; i++) + bitstream.writeBit(bit(msgtype, 3 - i)); - EmbedAttrBuffer(attr, stream); - } + // Enqueue 2 bytes of length - now it is zero. + // Growable writer starting right after the bits already emitted; it resizes + // 'buffer' as attributes are appended so an oversized message cannot overflow. + BufferWriter stream(buffer, bitstream.count() / 8); + stream.writeUShort(0); - // Append MessageIntegrity attribute if exists - AttributeMap::iterator miIter = mAttrMap.find(StunAttribute::MessageIntegrity); - if ( miIter != mAttrMap.end()) - { - EmbedAttrBuffer(*miIter->second, stream); - } + // Enqueue magic cookie value + unsigned int cookie = htonl(mMagicCookie); + stream.writeBuffer(&cookie, 4); - int lengthWithoutFingerprint = stream.offset() + 2; + // Enqueue transaction ID + // memset(mTransactionID.mValue, 0, sizeof(mTransactionID.mValue)); // For debugging only + stream.writeBuffer(mTransactionID.mValue, 12); - // Append Fingerprint attribute if exists - AttributeMap::iterator fpIter = mAttrMap.find(StunAttribute::Fingerprint); - if (fpIter != mAttrMap.end()) - { - EmbedAttrBuffer(*fpIter->second, stream); - } + // Iterate attributes + AttributeMap::iterator attrIter; + for (attrIter = mAttrMap.begin(); attrIter != mAttrMap.end(); ++attrIter) + { + StunAttribute& attr = *attrIter->second; - // Check for message integrity attribute - miIter = mAttrMap.find(StunAttribute::MessageIntegrity); - if (miIter != mAttrMap.end()) - { - // Update length in header - *((unsigned short*)buffer.mutableData() + 1) = htons(lengthWithoutFingerprint - STUN_HEADER_SIZE); - - // Prepare HMAC digest buffer - unsigned char digest[HMAC_DIGEST_SIZE]; - - // Get data offset for output digest - size_t dataOffset = miIter->second->dataOffset(); + // Check if it is MessageIntegrity or Fingerprint - they comes last and skip them for now + if (attr.type() == StunAttribute::MessageIntegrity || attr.type() == StunAttribute::Fingerprint) + continue; - // Get digest - hmacSha1Digest(buffer.data(), dataOffset - 4, digest, password.c_str(), password.length()); + EmbedAttrBuffer(attr, stream); + } - // Copy digest to proper place - memcpy((unsigned char*)buffer.data() + dataOffset, digest, HMAC_DIGEST_SIZE); - } + // Append MessageIntegrity attribute if exists + AttributeMap::iterator miIter = mAttrMap.find(StunAttribute::MessageIntegrity); + if (miIter != mAttrMap.end()) + { + EmbedAttrBuffer(*miIter->second, stream); + } - // Resize resulting buffer - buffer.resize(stream.offset() + 2); + int lengthWithoutFingerprint = stream.offset() + 2; - // Put length in header - *((unsigned short*)buffer.mutableData() + 1) = (uint16_t)(htons(buffer.size() - STUN_HEADER_SIZE)); + // Append Fingerprint attribute if exists + AttributeMap::iterator fpIter = mAttrMap.find(StunAttribute::Fingerprint); + if (fpIter != mAttrMap.end()) + { + EmbedAttrBuffer(*fpIter->second, stream); + } - // Check for fingerprint attribute - fpIter = mAttrMap.find(StunAttribute::Fingerprint); - if (fpIter != mAttrMap.end()) - { - // Get data offset for fingeprint attribute - size_t dataOffset = fpIter->second->dataOffset(); - - // Find CRC32 - CRC32 crc32; - unsigned int crc = crc32.fullCrc((unsigned char*)buffer.data(), dataOffset - 4); - - // Update attribute value with CRC32 value - memcpy((unsigned char*)buffer.data() + dataOffset, &crc, 4); - } - + // Check for message integrity attribute + miIter = mAttrMap.find(StunAttribute::MessageIntegrity); + if (miIter != mAttrMap.end()) + { + // Update length in header + *((unsigned short*)buffer.mutableData() + 1) = htons(lengthWithoutFingerprint - STUN_HEADER_SIZE); + + // Prepare HMAC digest buffer + unsigned char digest[HMAC_DIGEST_SIZE]; + + // Get data offset for output digest + size_t dataOffset = miIter->second->dataOffset(); + + // Get digest + hmacSha1Digest(buffer.data(), dataOffset - 4, digest, password.c_str(), password.length()); + + // Copy digest to proper place + memcpy((unsigned char*)buffer.data() + dataOffset, digest, HMAC_DIGEST_SIZE); + } + + // Resize resulting buffer + buffer.resize(stream.offset() + 2); + + // Put length in header + *((unsigned short*)buffer.mutableData() + 1) = (uint16_t)(htons(buffer.size() - STUN_HEADER_SIZE)); + + // Check for fingerprint attribute + fpIter = mAttrMap.find(StunAttribute::Fingerprint); + if (fpIter != mAttrMap.end()) + { + // Get data offset for fingeprint attribute + size_t dataOffset = fpIter->second->dataOffset(); + + // Find CRC32 + CRC32 crc32; + unsigned int crc = crc32.fullCrc((unsigned char*)buffer.data(), dataOffset - 4); + + // Update attribute value with CRC32 value + memcpy((unsigned char*)buffer.data() + dataOffset, &crc, 4); + } } #include "ICEStunAttributes.h" bool StunMessage::parsePacket(ByteBuffer& buffer) { - // Save incoming packet - mPacket2Parse = buffer; + // Save incoming packet + mPacket2Parse = buffer; - // Clear attribute list - mAttrMap.clear(); - - BufferReader stream(buffer); - - uint8_t firstByte = stream.readUChar(); - uint8_t secondByte = stream.readUChar(); + // Clear attribute list + mAttrMap.clear(); - if (firstByte & ~0x3F) - { - return false; - } + BufferReader stream(buffer); - int c1 = firstByte & 0x1; - int m11 = firstByte & 0x20 ? 1 : 0; - int m10 = firstByte & 0x10 ? 1 : 0; - int m9 = firstByte & 0x8 ? 1 : 0; - int m8 = firstByte & 0x4 ? 1 : 0; - int m7 = firstByte & 0x2 ? 1 : 0; + uint8_t firstByte = stream.readUChar(); + uint8_t secondByte = stream.readUChar(); - int m6 = secondByte & 0x80 ? 1 : 0; - int m5 = secondByte & 0x40 ? 1 : 0; - int m4 = secondByte & 0x20 ? 1 : 0; - int c0 = secondByte & 0x10 ? 1 : 0; - int m3 = secondByte & 0x8 ? 1 : 0; - int m2 = secondByte & 0x4 ? 1 : 0; - int m1 = secondByte & 0x2 ? 1 : 0; - int m0 = secondByte & 0x1 ? 1 : 0; - - mType = (StunMessage::Type)((m11 << 11) + (m10 << 10) + (m9 << 9) + (m8 << 8) + (m7 << 7) + (m6 << 6) + (m5 << 5) + (m4 << 4) + (m3 << 3) + (m2 << 2) + (m1 << 1) + m0); - mClass = (StunMessage::Class) ((c1 << 1) + c0); - - unsigned short length = stream.readUShort(); - if (length & 0x3) - { - return false; - } - - // Dequeue magic cookie - mMagicCookie = stream.readUInt(); - if (!isMagicCookieValid()) - return false; - - // Dequeue transaction id - char id[12]; - stream.readBuffer(id, 12); - - memcpy(mTransactionID.mValue, id, 12); - - // Dequeue attributes - while (stream.count() < buffer.size()) - { - int attrType = stream.readUShort(); - StunAttribute* attr = NULL; - switch (attrType) + if (firstByte & ~0x3F) { - case StunAttribute::Data: - attr = new DataAttribute(); - break; - - case StunAttribute::MappedAddress: - attr = new MappedAddress(); - break; - - case StunAttribute::XorMappedAddress: - attr = new XorMappedAddress(); - break; - - case StunAttribute::ErrorCode: - attr = new ErrorCode(); - break; - - case StunAttribute::AlternateServer: - attr = new AlternateServer(); - break; - - case StunAttribute::UnknownAttributes: - attr = new UnknownAttributes(); - break; - - case StunAttribute::Fingerprint: - attr = new Fingerprint(); - break; - - case StunAttribute::MessageIntegrity: - attr = new MessageIntegrity(); - break; - - case StunAttribute::Nonce: - attr = new Nonce(); - break; - - case StunAttribute::Realm: - attr = new Realm(); - break; - - case StunAttribute::Server: - attr = new Server(); - break; - - case StunAttribute::Username: - attr = new Username(); - break; - - case StunAttribute::ICEPriority: - attr = new ICEPriority(); - break; - - case StunAttribute::ControlledAttr: - attr = new ControlledAttr(); - break; - - case StunAttribute::ControllingAttr: - attr = new ControllingAttr(); - break; - - case StunAttribute::ICEUseCandidate: - attr = new ICEUseCandidate(); - break; - - case StunAttribute::XorRelayedAddress: - attr = new XorRelayedAddress(); - break; - - case StunAttribute::XorPeerAddress: - attr = new XorPeerAddress(); - break; - - case StunAttribute::Lifetime: - attr = new Lifetime(); - break; - - case StunAttribute::RequestedTransport: - attr = new RequestedTransport(); - break; - - case StunAttribute::RequestedAddressFamily: - attr = new RequestedAddressFamily(); - break; - - default: - attr = NULL; - } - - // Get attribute value length - int attrLen = stream.readUShort(); - - unsigned int dataOffset = stream.count(); - - // Get attribute buffer - ByteBuffer attrBuffer; - if (attrLen > 0) - { - attrBuffer.resize(attrLen); - stream.readBuffer(attrBuffer.mutableData(), attrLen); - } - - // Skip padding bytes - if (attrLen & 0x3) - { - size_t paddingLength = 4 - (attrLen & 0x3); - char paddingBytes[4]; - stream.readBuffer(paddingBytes, paddingLength); - } - - // Parse attribute value - if (attr) - { - // Parse attribute - BufferReader attrReader(attrBuffer); - if (!attr->parsePacket(attrReader)) return false; - - // Set data offset - attr->setDataOffset(dataOffset); - - // Add attribute - addAttribute(attr); } - } - return true; + + int c1 = firstByte & 0x1; + int m11 = firstByte & 0x20 ? 1 : 0; + int m10 = firstByte & 0x10 ? 1 : 0; + int m9 = firstByte & 0x8 ? 1 : 0; + int m8 = firstByte & 0x4 ? 1 : 0; + int m7 = firstByte & 0x2 ? 1 : 0; + + int m6 = secondByte & 0x80 ? 1 : 0; + int m5 = secondByte & 0x40 ? 1 : 0; + int m4 = secondByte & 0x20 ? 1 : 0; + int c0 = secondByte & 0x10 ? 1 : 0; + int m3 = secondByte & 0x8 ? 1 : 0; + int m2 = secondByte & 0x4 ? 1 : 0; + int m1 = secondByte & 0x2 ? 1 : 0; + int m0 = secondByte & 0x1 ? 1 : 0; + + mType = (StunMessage::Type)((m11 << 11) + (m10 << 10) + (m9 << 9) + (m8 << 8) + (m7 << 7) + (m6 << 6) + (m5 << 5) + + (m4 << 4) + (m3 << 3) + (m2 << 2) + (m1 << 1) + m0); + mClass = (StunMessage::Class)((c1 << 1) + c0); + + unsigned short length = stream.readUShort(); + if (length & 0x3) + { + return false; + } + + // Dequeue magic cookie + mMagicCookie = stream.readUInt(); + if (!isMagicCookieValid()) + return false; + + // Dequeue transaction id + char id[12]; + stream.readBuffer(id, 12); + + memcpy(mTransactionID.mValue, id, 12); + + // Dequeue attributes + while (stream.count() < buffer.size()) + { + int attrType = stream.readUShort(); + StunAttribute* attr = NULL; + switch (attrType) + { + case StunAttribute::Data: + attr = new DataAttribute(); + break; + + case StunAttribute::MappedAddress: + attr = new MappedAddress(); + break; + + case StunAttribute::XorMappedAddress: + attr = new XorMappedAddress(); + break; + + case StunAttribute::ErrorCode: + attr = new ErrorCode(); + break; + + case StunAttribute::AlternateServer: + attr = new AlternateServer(); + break; + + case StunAttribute::UnknownAttributes: + attr = new UnknownAttributes(); + break; + + case StunAttribute::Fingerprint: + attr = new Fingerprint(); + break; + + case StunAttribute::MessageIntegrity: + attr = new MessageIntegrity(); + break; + + case StunAttribute::Nonce: + attr = new Nonce(); + break; + + case StunAttribute::Realm: + attr = new Realm(); + break; + + case StunAttribute::Server: + attr = new Server(); + break; + + case StunAttribute::Username: + attr = new Username(); + break; + + case StunAttribute::ICEPriority: + attr = new ICEPriority(); + break; + + case StunAttribute::ControlledAttr: + attr = new ControlledAttr(); + break; + + case StunAttribute::ControllingAttr: + attr = new ControllingAttr(); + break; + + case StunAttribute::ICEUseCandidate: + attr = new ICEUseCandidate(); + break; + + case StunAttribute::XorRelayedAddress: + attr = new XorRelayedAddress(); + break; + + case StunAttribute::XorPeerAddress: + attr = new XorPeerAddress(); + break; + + case StunAttribute::Lifetime: + attr = new Lifetime(); + break; + + case StunAttribute::RequestedTransport: + attr = new RequestedTransport(); + break; + + case StunAttribute::RequestedAddressFamily: + attr = new RequestedAddressFamily(); + break; + + default: + attr = NULL; + } + + // Get attribute value length + int attrLen = stream.readUShort(); + + unsigned int dataOffset = stream.count(); + + // Get attribute buffer + ByteBuffer attrBuffer; + if (attrLen > 0) + { + attrBuffer.resize(attrLen); + stream.readBuffer(attrBuffer.mutableData(), attrLen); + } + + // Skip padding bytes + if (attrLen & 0x3) + { + size_t paddingLength = 4 - (attrLen & 0x3); + char paddingBytes[4]; + stream.readBuffer(paddingBytes, paddingLength); + } + + // Parse attribute value + if (attr) + { + // Parse attribute + BufferReader attrReader(attrBuffer); + if (!attr->parsePacket(attrReader)) + return false; + + // Set data offset + attr->setDataOffset(dataOffset); + + // Add attribute + addAttribute(attr); + } + } + return true; } bool StunMessage::validatePacket(std::string key) { - // Iterate attributes - if (hasAttribute(StunAttribute::MessageIntegrity)) - { - // Get HMAC digest - MessageIntegrity& mi = dynamic_cast(attribute(StunAttribute::MessageIntegrity)); - - unsigned char digest[HMAC_DIGEST_SIZE]; - - // Reset length to length of packet without Fingerprint - unsigned short* lengthPtr = ((unsigned short*)mPacket2Parse.mutableData() + 1); - - // Save old value - it is for backup purposes only. So there is no call to ntohs(). - unsigned short len = *lengthPtr; - - // Set fake length including MessageIntegrity attribute but excluding any attributes behind of it and excluding STUN header size - *lengthPtr = (uint16_t)(htons(mi.dataOffset() + HMAC_DIGEST_SIZE - STUN_HEADER_SIZE)); - - // Find HMAC-SHA1 again - hmacSha1Digest(mPacket2Parse.data(), mi.dataOffset() - 4, digest, key.c_str(), key.size()); - - // And restore old value - *lengthPtr = len; - - if (memcmp(mi.value(), digest, HMAC_DIGEST_SIZE) != 0) + // Iterate attributes + if (hasAttribute(StunAttribute::MessageIntegrity)) { - ICELogCritical(<< "Bad MessageIntegrity in STUN message"); - return false; + // Get HMAC digest + MessageIntegrity& mi = dynamic_cast(attribute(StunAttribute::MessageIntegrity)); + + unsigned char digest[HMAC_DIGEST_SIZE]; + + // Reset length to length of packet without Fingerprint + unsigned short* lengthPtr = ((unsigned short*)mPacket2Parse.mutableData() + 1); + + // Save old value - it is for backup purposes only. So there is no call to ntohs(). + unsigned short len = *lengthPtr; + + // Set fake length including MessageIntegrity attribute but excluding any attributes behind of it and excluding + // STUN header size + *lengthPtr = (uint16_t)(htons(mi.dataOffset() + HMAC_DIGEST_SIZE - STUN_HEADER_SIZE)); + + // Find HMAC-SHA1 again + hmacSha1Digest(mPacket2Parse.data(), mi.dataOffset() - 4, digest, key.c_str(), key.size()); + + // And restore old value + *lengthPtr = len; + + if (memcmp(mi.value(), digest, HMAC_DIGEST_SIZE) != 0) + { + ICELogCritical(<< "Bad MessageIntegrity in STUN message"); + return false; + } } - } - - /* - if (hasAttribute(StunAttribute::Fingerprint)) - { - // Get fingerpring attribute - Fingerprint& fp = dynamic_cast(attribute(StunAttribute::Fingerprint)); - // Find CRC32 - CRC32 crcObj; - unsigned long crcValue = crcObj.fullCrc((const unsigned char*)mPacket2Parse.data(), fp.dataOffset() - 4); - - // Compare with saved one - if (crcValue != fp.crc32()) + /* + if (hasAttribute(StunAttribute::Fingerprint)) { - ICELogCritical(<< "Bad CRC32 value in STUN message"); - return false; - } - }*/ + // Get fingerpring attribute + Fingerprint& fp = dynamic_cast(attribute(StunAttribute::Fingerprint)); - return true; + // Find CRC32 + CRC32 crcObj; + unsigned long crcValue = crcObj.fullCrc((const unsigned char*)mPacket2Parse.data(), fp.dataOffset() - 4); + + // Compare with saved one + if (crcValue != fp.crc32()) + { + ICELogCritical(<< "Bad CRC32 value in STUN message"); + return false; + } + }*/ + + return true; } inline char StunMessage::bit(unsigned int value, size_t index) { - unsigned int mask = (1 << index); - - return value & mask ? 1 : 0; + unsigned int mask = (1 << index); + + return value & mask ? 1 : 0; } inline void StunMessage::setBit(unsigned int& result, size_t index, char value) { - unsigned int mask = (1 << index); - if (value != 0) - result |= mask; - else - result &= ~mask; + unsigned int mask = (1 << index); + if (value != 0) + result |= mask; + else + result &= ~mask; } void StunMessage::addAttribute(StunAttribute* attr) { - assert(NULL != attr); - mAttrMap.insert(std::pair(attr->type(), attr)); + assert(NULL != attr); + mAttrMap.insert(std::pair(attr->type(), attr)); } -void StunMessage::setAttribute(StunAttribute *attr) +void StunMessage::setAttribute(StunAttribute* attr) { - assert(NULL != attr); - - AttributeMap::iterator attrIter = mAttrMap.find(attr->type()); - if (attrIter != mAttrMap.end()) - { - delete attrIter->second; - attrIter->second = attr; - } - else - mAttrMap.insert(std::pair(attr->type(), attr)); + assert(NULL != attr); + + AttributeMap::iterator attrIter = mAttrMap.find(attr->type()); + if (attrIter != mAttrMap.end()) + { + delete attrIter->second; + attrIter->second = attr; + } + else + mAttrMap.insert(std::pair(attr->type(), attr)); } bool StunMessage::hasAttribute(int attrType) const { - return (mAttrMap.find(attrType) != mAttrMap.end()); + return (mAttrMap.find(attrType) != mAttrMap.end()); } - + StunAttribute& StunMessage::attribute(int attrType) { - AttributeMap::iterator attrIter = mAttrMap.find(attrType); - if (attrIter != mAttrMap.end()) - return *attrIter->second; + AttributeMap::iterator attrIter = mAttrMap.find(attrType); + if (attrIter != mAttrMap.end()) + return *attrIter->second; - throw Exception(CANNOT_FIND_ATTRIBUTE, attrType); + throw Exception(CANNOT_FIND_ATTRIBUTE, attrType); } -const StunAttribute& -StunMessage::operator [] (int attribute) const +const StunAttribute& StunMessage::operator[](int attribute) const { - AttributeMap::iterator attrIter = mAttrMap.find(attribute); - if (attrIter != mAttrMap.end()) - return *attrIter->second; + AttributeMap::iterator attrIter = mAttrMap.find(attribute); + if (attrIter != mAttrMap.end()) + return *attrIter->second; - throw Exception(CANNOT_FIND_ATTRIBUTE, attribute); + throw Exception(CANNOT_FIND_ATTRIBUTE, attribute); } -StunAttribute& -StunMessage::operator[] (int attribute) +StunAttribute& StunMessage::operator[](int attribute) { - AttributeMap::iterator attrIter = mAttrMap.find(attribute); - if (attrIter != mAttrMap.end()) - return *attrIter->second; - - // Create attribute - StunAttribute* attr = NULL; + AttributeMap::iterator attrIter = mAttrMap.find(attribute); + if (attrIter != mAttrMap.end()) + return *attrIter->second; - switch (attribute) - { - case StunAttribute::MappedAddress: - attr = new MappedAddress(); - break; + // Create attribute + StunAttribute* attr = NULL; - case StunAttribute::XorMappedAddress: - attr = new XorMappedAddress(); - break; + switch (attribute) + { + case StunAttribute::MappedAddress: + attr = new MappedAddress(); + break; - case StunAttribute::ErrorCode: - attr = new ErrorCode(); - break; + case StunAttribute::XorMappedAddress: + attr = new XorMappedAddress(); + break; - case StunAttribute::AlternateServer: - attr = new AlternateServer(); - break; + case StunAttribute::ErrorCode: + attr = new ErrorCode(); + break; - case StunAttribute::UnknownAttributes: - attr = new UnknownAttributes(); - break; + case StunAttribute::AlternateServer: + attr = new AlternateServer(); + break; - case StunAttribute::Fingerprint: - attr = new Fingerprint(); - break; + case StunAttribute::UnknownAttributes: + attr = new UnknownAttributes(); + break; - case StunAttribute::MessageIntegrity: - attr = new MessageIntegrity(); - break; + case StunAttribute::Fingerprint: + attr = new Fingerprint(); + break; - case StunAttribute::Nonce: - attr = new Nonce(); - break; + case StunAttribute::MessageIntegrity: + attr = new MessageIntegrity(); + break; - case StunAttribute::Realm: - attr = new Realm(); - break; + case StunAttribute::Nonce: + attr = new Nonce(); + break; - case StunAttribute::Server: - attr = new Server(); - break; + case StunAttribute::Realm: + attr = new Realm(); + break; - case StunAttribute::Username: - attr = new Username(); - break; + case StunAttribute::Server: + attr = new Server(); + break; - case StunAttribute::ICEPriority: - attr = new ICEPriority(); - break; + case StunAttribute::Username: + attr = new Username(); + break; - case StunAttribute::ControlledAttr: - attr = new ControlledAttr(); - break; + case StunAttribute::ICEPriority: + attr = new ICEPriority(); + break; - case StunAttribute::ControllingAttr: - attr = new ControllingAttr(); - break; + case StunAttribute::ControlledAttr: + attr = new ControlledAttr(); + break; - case StunAttribute::ICEUseCandidate: - attr = new ICEUseCandidate(); - break; + case StunAttribute::ControllingAttr: + attr = new ControllingAttr(); + break; - case StunAttribute::XorRelayedAddress: - attr = new XorRelayedAddress(); - break; - - case StunAttribute::Lifetime: - attr = new Lifetime(); - break; + case StunAttribute::ICEUseCandidate: + attr = new ICEUseCandidate(); + break; - default: - attr = NULL; - } + case StunAttribute::XorRelayedAddress: + attr = new XorRelayedAddress(); + break; - if (!attr) - throw Exception(UNKNOWN_ATTRIBUTE, attribute); + case StunAttribute::Lifetime: + attr = new Lifetime(); + break; - mAttrMap.insert(std::pair(attribute, attr)); - return *attr; + default: + attr = NULL; + } + + if (!attr) + throw Exception(UNKNOWN_ATTRIBUTE, attribute); + + mAttrMap.insert(std::pair(attribute, attr)); + return *attr; } -Username& -StunMessage::usernameAttr() +Username& StunMessage::usernameAttr() { - StunMessage& self = *this; - return dynamic_cast(self[StunAttribute::Username]); + StunMessage& self = *this; + return dynamic_cast(self[StunAttribute::Username]); } -Realm& -StunMessage::realmAttr() +Realm& StunMessage::realmAttr() { - StunMessage& self = *this; - return dynamic_cast(self[StunAttribute::Realm]); + StunMessage& self = *this; + return dynamic_cast(self[StunAttribute::Realm]); } -ErrorCode& -StunMessage::errorCodeAttr() +ErrorCode& StunMessage::errorCodeAttr() { - StunMessage& self = *this; - return dynamic_cast(self[StunAttribute::ErrorCode]); + StunMessage& self = *this; + return dynamic_cast(self[StunAttribute::ErrorCode]); } -Nonce& -StunMessage::nonceAttr() +Nonce& StunMessage::nonceAttr() { - StunMessage& self = *this; - return dynamic_cast(self[StunAttribute::Nonce]); + StunMessage& self = *this; + return dynamic_cast(self[StunAttribute::Nonce]); } -MessageIntegrity& -StunMessage::messageIntegrityAttr() +MessageIntegrity& StunMessage::messageIntegrityAttr() { - StunMessage& self = *this; - return dynamic_cast(self[StunAttribute::MessageIntegrity]); + StunMessage& self = *this; + return dynamic_cast(self[StunAttribute::MessageIntegrity]); } -MappedAddress& -StunMessage::mappedAddressAttr() +MappedAddress& StunMessage::mappedAddressAttr() { - StunMessage& self = *this; - return dynamic_cast(self[StunAttribute::MappedAddress]); + StunMessage& self = *this; + return dynamic_cast(self[StunAttribute::MappedAddress]); } -XorMappedAddress& -StunMessage::xorMappedAddressAttr() +XorMappedAddress& StunMessage::xorMappedAddressAttr() { - StunMessage& self = *this; - return dynamic_cast(self[StunAttribute::XorMappedAddress]); + StunMessage& self = *this; + return dynamic_cast(self[StunAttribute::XorMappedAddress]); } -ControlledAttr& -StunMessage::iceControlledAttr() +ControlledAttr& StunMessage::iceControlledAttr() { - StunMessage& self = *this; - return dynamic_cast(self[StunAttribute::ControlledAttr]); + StunMessage& self = *this; + return dynamic_cast(self[StunAttribute::ControlledAttr]); } -ControllingAttr& -StunMessage::iceControllingAttr() +ControllingAttr& StunMessage::iceControllingAttr() { - StunMessage& self = *this; - return dynamic_cast(self[StunAttribute::ControllingAttr]); + StunMessage& self = *this; + return dynamic_cast(self[StunAttribute::ControllingAttr]); } -ICEPriority& -StunMessage::icePriorityAttr() +ICEPriority& StunMessage::icePriorityAttr() { - StunMessage& self = *this; - return dynamic_cast(self[StunAttribute::ICEPriority]); + StunMessage& self = *this; + return dynamic_cast(self[StunAttribute::ICEPriority]); } -Lifetime& -StunMessage::lifetimeAttr() +Lifetime& StunMessage::lifetimeAttr() { - StunMessage& self = *this; - return dynamic_cast(self[StunAttribute::Lifetime]); + StunMessage& self = *this; + return dynamic_cast(self[StunAttribute::Lifetime]); } -XorRelayedAddress& -StunMessage::xorRelayedAddressAttr() +XorRelayedAddress& StunMessage::xorRelayedAddressAttr() { - StunMessage& self = *this; - return dynamic_cast(self[StunAttribute::XorRelayedAddress]); + StunMessage& self = *this; + return dynamic_cast(self[StunAttribute::XorRelayedAddress]); } -ChannelNumber& -StunMessage::channelNumberAttr() +ChannelNumber& StunMessage::channelNumberAttr() { - StunMessage& self = *this; - if (!self.hasAttribute(StunAttribute::ChannelNumber)) - self.addAttribute(new ChannelNumber()); + StunMessage& self = *this; + if (!self.hasAttribute(StunAttribute::ChannelNumber)) + self.addAttribute(new ChannelNumber()); - return dynamic_cast(self[StunAttribute::ChannelNumber]); + return dynamic_cast(self[StunAttribute::ChannelNumber]); } -XorPeerAddress& -StunMessage::xorPeerAddressAttr() +XorPeerAddress& StunMessage::xorPeerAddressAttr() { - StunMessage& self = *this; - if (!self.hasAttribute(StunAttribute::XorPeerAddress)) - self.addAttribute(new XorPeerAddress()); - return dynamic_cast(self[StunAttribute::XorPeerAddress]); + StunMessage& self = *this; + if (!self.hasAttribute(StunAttribute::XorPeerAddress)) + self.addAttribute(new XorPeerAddress()); + return dynamic_cast(self[StunAttribute::XorPeerAddress]); } class CompareAttributesByOffsetFunctor { public: - bool operator () (const StunAttribute* attr1, const StunAttribute* attr2) - { - return attr1->dataOffset() < attr2->dataOffset(); - } + bool operator()(const StunAttribute* attr1, const StunAttribute* attr2) + { + return attr1->dataOffset() < attr2->dataOffset(); + } }; void StunMessage::dump(std::ostream& output) { - switch (messageClass()) - { - case RequestClass: output << "Request"; break; - case IndicationClass: output << "Indication"; break; - case SuccessClass: output << "Success"; break; - case ErrorClass: output << "Error"; break; - default: - output << "Invalid"; - break; - } + switch (messageClass()) + { + case RequestClass: + output << "Request"; + break; + case IndicationClass: + output << "Indication"; + break; + case SuccessClass: + output << "Success"; + break; + case ErrorClass: + output << "Error"; + break; + default: + output << "Invalid"; + break; + } - output << " / "; - switch (messageType()) - { - case Binding: output << "Binding"; break; - case Allocate: output << "Allocate"; break; - case Refresh: output << "Refresh"; break; - case Send: output << "Send"; break; - case Data: output << "Data"; break; - case CreatePermission: output << "CreatePermission"; break; - case ChannelBind: output << "ChannelBind"; break; - default: - output << "Invalid"; - break; - } + output << " / "; + switch (messageType()) + { + case Binding: + output << "Binding"; + break; + case Allocate: + output << "Allocate"; + break; + case Refresh: + output << "Refresh"; + break; + case Send: + output << "Send"; + break; + case Data: + output << "Data"; + break; + case CreatePermission: + output << "CreatePermission"; + break; + case ChannelBind: + output << "ChannelBind"; + break; + default: + output << "Invalid"; + break; + } - output << std::endl; - - // Sort attribytes by data offset - std::vector attrList; - for (AttributeMap::iterator attrIter = mAttrMap.begin(); attrIter != mAttrMap.end(); attrIter++) - attrList.push_back(attrIter->second); - - std::sort(attrList.begin(), attrList.end(), CompareAttributesByOffsetFunctor()); - - for (unsigned i=0; idataOffset() <<": "; - attrList[i]->dump(output); output << std::endl; - } + + // Sort attribytes by data offset + std::vector attrList; + for (AttributeMap::iterator attrIter = mAttrMap.begin(); attrIter != mAttrMap.end(); attrIter++) + attrList.push_back(attrIter->second); + + std::sort(attrList.begin(), attrList.end(), CompareAttributesByOffsetFunctor()); + + for (unsigned i = 0; i < attrList.size(); i++) + { + output << "Offset " << attrList[i]->dataOffset() << ": "; + attrList[i]->dump(output); + output << std::endl; + } } diff --git a/src/libs/ice/ICEStunMessage.h b/src/libs/ice/ICEStunMessage.h index 0f66f75d..2c3b47bc 100644 --- a/src/libs/ice/ICEStunMessage.h +++ b/src/libs/ice/ICEStunMessage.h @@ -12,189 +12,189 @@ namespace ice { - class StunAttribute - { - public: +class StunAttribute +{ +public: enum Type { - NotExist = 0, - MappedAddress = 1, - Username = 6, - MessageIntegrity = 8, - ErrorCode = 9, - UnknownAttributes = 10, - Realm = 20, - Nonce = 21, - XorMappedAddress = 32, - Server = 0x8022, - AlternateServer = 0x8023, - Fingerprint = 0x8028, - - // TURN - ChannelNumber = 0x0c, - Lifetime = 0x0d, - XorPeerAddress = 0x12, - Data = 0x13, - XorRelayedAddress = 0x16, - RequestedAddressFamily = 0x17, - RequestedTransport = 0x19, - ReservedToken = 0x22, + NotExist = 0, + MappedAddress = 1, + Username = 6, + MessageIntegrity = 8, + ErrorCode = 9, + UnknownAttributes = 10, + Realm = 20, + Nonce = 21, + XorMappedAddress = 32, + Server = 0x8022, + AlternateServer = 0x8023, + Fingerprint = 0x8028, - // ICE - ControlledAttr = 0x8029, - ControllingAttr = 0x802a, - ICEPriority = 0x0024, - ICEUseCandidate = 0x0025 + // TURN + ChannelNumber = 0x0c, + Lifetime = 0x0d, + XorPeerAddress = 0x12, + Data = 0x13, + XorRelayedAddress = 0x16, + RequestedAddressFamily = 0x17, + RequestedTransport = 0x19, + ReservedToken = 0x22, + + // ICE + ControlledAttr = 0x8029, + ControllingAttr = 0x802a, + ICEPriority = 0x0024, + ICEUseCandidate = 0x0025 }; StunAttribute(); virtual ~StunAttribute(); - - virtual int type() const = 0; - virtual void buildPacket(BufferWriter& writer) = 0; - virtual bool parsePacket(BufferReader& reader) = 0; - void setDataOffset(size_t offset); - size_t dataOffset() const; - virtual void dump(std::ostream& output) = 0; + virtual int type() const = 0; + virtual void buildPacket(BufferWriter& writer) = 0; + virtual bool parsePacket(BufferReader& reader) = 0; - protected: - int mType; - int mLength; + void setDataOffset(size_t offset); + size_t dataOffset() const; + virtual void dump(std::ostream& output) = 0; + +protected: + int mType; + int mLength; size_t mDataOffset; - }; - - - class Username; - class Realm; - class Nonce; - class ErrorCode; - class MessageIntegrity; - class MappedAddress; - class XorMappedAddress; - class ControlledAttr; - class ControllingAttr; - class ICEPriority; - class Lifetime; - class XorRelayedAddress; - class ChannelNumber; - class XorPeerAddress; +}; - class StunMessage - { - public: + +class Username; +class Realm; +class Nonce; +class ErrorCode; +class MessageIntegrity; +class MappedAddress; +class XorMappedAddress; +class ControlledAttr; +class ControllingAttr; +class ICEPriority; +class Lifetime; +class XorRelayedAddress; +class ChannelNumber; +class XorPeerAddress; + +class StunMessage +{ +public: struct TransactionID { - unsigned char mValue[12]; + unsigned char mValue[12]; - bool operator == (const TransactionID& rhs); - bool operator != (const TransactionID& rhs); - - TransactionID(); - std::string toStdString(); + bool operator==(const TransactionID& rhs); + bool operator!=(const TransactionID& rhs); - static TransactionID generateNew(); + TransactionID(); + std::string toStdString(); + + static TransactionID generateNew(); }; enum Class { - RequestClass = 0, //0b00, - IndicationClass = 1, //0b01, - SuccessClass = 2, //0b10, - ErrorClass = 3 //0b11 + RequestClass = 0, // 0b00, + IndicationClass = 1, // 0b01, + SuccessClass = 2, // 0b10, + ErrorClass = 3 // 0b11 }; enum Type { - Binding = 1, - Allocate = 3, - Refresh = 4, - Send = 6, - Data = 7, - CreatePermission = 8, - ChannelBind = 9 + Binding = 1, + Allocate = 3, + Refresh = 4, + Send = 6, + Data = 7, + CreatePermission = 8, + ChannelBind = 9 }; StunMessage(); virtual ~StunMessage(); - std::string comment(); - void setComment(std::string comment); + std::string comment(); + void setComment(std::string comment); - void setMessageType(Type type); - Type messageType(); - - void setMessageClass(Class value); - Class messageClass(); + void setMessageType(Type type); + Type messageType(); - unsigned int magicCookie(); - bool isMagicCookieValid(); - - void setTransactionId(TransactionID id); - TransactionID transactionId(); + void setMessageClass(Class value); + Class messageClass(); + + unsigned int magicCookie(); + bool isMagicCookieValid(); + + void setTransactionId(TransactionID id); + TransactionID transactionId(); // Builds STUN packet using specified password (if MessageIntegrity attribute is add before) - void buildPacket(ByteBuffer& buffer, const std::string& password); - + void buildPacket(ByteBuffer& buffer, const std::string& password); + // Parses STUN packet but do not validates it - bool parsePacket(ByteBuffer& buffer); + bool parsePacket(ByteBuffer& buffer); // Validate parsed packet. Must be called right after ParsePacket() method. // Returns true if validated ok, false otherwise. - bool validatePacket(std::string key); - + bool validatePacket(std::string key); + // Adds attribute to STUN message. If attribute of the same type exists - new one will be add. - void addAttribute(StunAttribute* attr); - + void addAttribute(StunAttribute* attr); + // Sets attribute to STUN message. If attribute of the same type exists - it will be overwritten. - void setAttribute(StunAttribute* attr); - + void setAttribute(StunAttribute* attr); + // Checks if there is specified attribute - bool hasAttribute(int attrType) const; + bool hasAttribute(int attrType) const; // Gets reference to attribute object - StunAttribute& attribute(int attrType); - - const StunAttribute& operator [] (int attribute) const; - StunAttribute& operator[] (int attribute); - - Username& usernameAttr(); - Realm& realmAttr(); - ErrorCode& errorCodeAttr(); - Nonce& nonceAttr(); - MessageIntegrity& messageIntegrityAttr(); - MappedAddress& mappedAddressAttr(); - XorMappedAddress& xorMappedAddressAttr(); - ControlledAttr& iceControlledAttr(); - ControllingAttr& iceControllingAttr(); - ICEPriority& icePriorityAttr(); - Lifetime& lifetimeAttr(); - XorRelayedAddress& xorRelayedAddressAttr(); - ChannelNumber& channelNumberAttr(); - XorPeerAddress& xorPeerAddressAttr(); + StunAttribute& attribute(int attrType); - void dump(std::ostream& output); + const StunAttribute& operator[](int attribute) const; + StunAttribute& operator[](int attribute); + + Username& usernameAttr(); + Realm& realmAttr(); + ErrorCode& errorCodeAttr(); + Nonce& nonceAttr(); + MessageIntegrity& messageIntegrityAttr(); + MappedAddress& mappedAddressAttr(); + XorMappedAddress& xorMappedAddressAttr(); + ControlledAttr& iceControlledAttr(); + ControllingAttr& iceControllingAttr(); + ICEPriority& icePriorityAttr(); + Lifetime& lifetimeAttr(); + XorRelayedAddress& xorRelayedAddressAttr(); + ChannelNumber& channelNumberAttr(); + XorPeerAddress& xorPeerAddressAttr(); + + void dump(std::ostream& output); + +protected: + unsigned int mMagicCookie; // STUN magic cookie predefined value + Type mType; // Type of STUN message + Class mClass; // Class of STUN message + TransactionID mTransactionID; // Transaction ID of STUN message - protected: - unsigned int mMagicCookie; // STUN magic cookie predefined value - Type mType; // Type of STUN message - Class mClass; // Class of STUN message - TransactionID mTransactionID; // Transaction ID of STUN message - typedef std::multimap AttributeMap; - mutable AttributeMap mAttrMap; // Attribute list - ByteBuffer mPacket2Parse; // Incoming packet - ByteBuffer mPacket2Send; // Outgoing packet + mutable AttributeMap mAttrMap; // Attribute list + ByteBuffer mPacket2Parse; // Incoming packet + ByteBuffer mPacket2Send; // Outgoing packet - std::string mComment; // Comment for this message + std::string mComment; // Comment for this message - //Helper method to get bit with specified index from 'value' parameter. - inline char bit(unsigned int value, size_t index); + // Helper method to get bit with specified index from 'value' parameter. + inline char bit(unsigned int value, size_t index); - //Helper method to set bit in specified 'result' parameter - inline void setBit(unsigned int& result, size_t index, char value); - }; -} + // Helper method to set bit in specified 'result' parameter + inline void setBit(unsigned int& result, size_t index, char value); +}; +} // namespace ice #endif diff --git a/src/libs/ice/ICEStunTransaction.cpp b/src/libs/ice/ICEStunTransaction.cpp index 3ff943b3..e731e50c 100644 --- a/src/libs/ice/ICEStunTransaction.cpp +++ b/src/libs/ice/ICEStunTransaction.cpp @@ -12,7 +12,7 @@ #include "ICETime.h" #ifndef _WIN32 -# include +#include #endif #include @@ -21,474 +21,476 @@ using namespace ice; const char* Transaction::stateToString(State state) { - switch (state) - { - case Running: return "Running"; - case Failed: return "Failed"; - case Success: return "Success"; - } - return "Undefined"; + switch (state) + { + case Running: + return "Running"; + case Failed: + return "Failed"; + case Success: + return "Success"; + } + return "Undefined"; } Transaction::Transaction() { - mTransportType = IPv4; + mTransportType = IPv4; - // There is no default ICE stack - mStackID = 0; + // There is no default ICE stack + mStackID = 0; - // There is no default logger - mLog = NULL; + // There is no default logger + mLog = NULL; - // Packet is not composed in constructor - mComposed = false; + // Packet is not composed in constructor + mComposed = false; - // Initial state of transaction - "Running" - mState = Transaction::Running; + // Initial state of transaction - "Running" + mState = Transaction::Running; - // Reset user data - mTag = 0; + // Reset user data + mTag = 0; - // Do not use message integrity attribute by default - mMessageIntegrity = false; + // Do not use message integrity attribute by default + mMessageIntegrity = false; - // Do not use fingerprint attribute by default - mFingerprint = false; + // Do not use fingerprint attribute by default + mFingerprint = false; - // Do not use long term credentials by default - mLongTerm = false; + // Do not use long term credentials by default + mLongTerm = false; - // Do not use short term credentials by default - mShortTerm = false; + // Do not use short term credentials by default + mShortTerm = false; - // Create new transaction ID - generateId(); - - // CONTROLLING attribute is not used by default - mEnableControlling = false; + // Create new transaction ID + generateId(); - // CONTROLLED attribute is not used by default - mEnableControlled = false; + // CONTROLLING attribute is not used by default + mEnableControlling = false; - // PRIORITY attribute is not used by default - mEnablePriority = false; - mPriority = 0; + // CONTROLLED attribute is not used by default + mEnableControlled = false; - // Transaction is not cancelled - mCancelled = false; + // PRIORITY attribute is not used by default + mEnablePriority = false; + mPriority = 0; - // Transaction is not relayed by default - mRelayed = false; + // Transaction is not cancelled + mCancelled = false; - // Component port is not set by default - mComponent = 0; + // Transaction is not relayed by default + mRelayed = false; - mKeepalive = false; - mInterval = 0; - mUserObject = NULL; - mType = None; - mRemoved = false; - mFailoverId = 0; + // Component port is not set by default + mComponent = 0; + + mKeepalive = false; + mInterval = 0; + mUserObject = NULL; + mType = None; + mRemoved = false; + mFailoverId = 0; } -Transaction::~Transaction() -{ -} +Transaction::~Transaction() {} void Transaction::generateId() { - for (size_t i=0; i<12; i++) - mTransactionID.mValue[i] = rand(); + for (size_t i = 0; i < 12; i++) + mTransactionID.mValue[i] = rand(); } void Transaction::setStackId(int id) { - mStackID = id; + mStackID = id; } int Transaction::stackId() { - return mStackID; + return mStackID; } void Transaction::setTransportType(int _type) { - assert(_type == IPv4 || _type == IPv6); - mTransportType = _type; + assert(_type == IPv4 || _type == IPv6); + mTransportType = _type; } int Transaction::transportType() { - return mTransportType; + return mTransportType; } std::string Transaction::toStdString() { - std::ostringstream output; - output << "State: " << Transaction::stateToString(mState) << ", "; - output << "Transport: " << (mTransportType == IPv4 ? "IPv4" : "IPv6") << ", "; - output << (mCancelled ? "Cancelled, " : ""); - output << "Destination: " << mDestination.toStdString().c_str() << ", "; - output << "Comment: " << mComment.c_str(); + std::ostringstream output; + output << "State: " << Transaction::stateToString(mState) << ", "; + output << "Transport: " << (mTransportType == IPv4 ? "IPv4" : "IPv6") << ", "; + output << (mCancelled ? "Cancelled, " : ""); + output << "Destination: " << mDestination.toStdString().c_str() << ", "; + output << "Comment: " << mComment.c_str(); - return output.str(); + return output.str(); } void Transaction::setTag(unsigned int tag) { - mTag = tag; + mTag = tag; } unsigned Transaction::tag() { - return mTag; + return mTag; } void Transaction::enqueueMessage(ice::StunMessage& msg) { - // Clear outgoing buffer - mOutgoingData.clear(); - - // Check if message should be secured by message integrity - std::string password = mPassword; - if (true == mMessageIntegrity) - { - // Ensure credentials are enabled - assert(mLongTerm || mShortTerm); + // Clear outgoing buffer + mOutgoingData.clear(); - // Create username attribute - Username* attr = new Username(); - - // Set username value - if (mLongTerm || mShortTerm) - attr->setValue(mUsername); + // Check if message should be secured by message integrity + std::string password = mPassword; + if (true == mMessageIntegrity) + { + // Ensure credentials are enabled + assert(mLongTerm || mShortTerm); - // Add username attribute itself - msg.setAttribute(attr); + // Create username attribute + Username* attr = new Username(); - // Add message integrity attribute - msg.setAttribute(new MessageIntegrity()); - } + // Set username value + if (mLongTerm || mShortTerm) + attr->setValue(mUsername); - if (mFingerprint) - msg.setAttribute(new Fingerprint()); - - // Add ICE-CONTROLLED attribute if needed - if (mEnableControlled) - { - assert(mTieBreaker.length() == 8); + // Add username attribute itself + msg.setAttribute(attr); - ControlledAttr* attr = new ControlledAttr(); - attr->setTieBreaker(mTieBreaker); - msg.setAttribute(attr); - } + // Add message integrity attribute + msg.setAttribute(new MessageIntegrity()); + } - // Add ICE-CONTROLLING attribute if needed - if (mEnableControlling) - { - assert(mTieBreaker.length() == 8); - - ControllingAttr* attr = new ControllingAttr(); - attr->setTieBreaker(mTieBreaker); - msg.setAttribute(attr); - } + if (mFingerprint) + msg.setAttribute(new Fingerprint()); - // Add ICE-PRIORITY attribute if needed - if (mEnablePriority) - { - ICEPriority* attr = new ICEPriority(); - attr->setPriority(mPriority); - msg.setAttribute(attr); - } + // Add ICE-CONTROLLED attribute if needed + if (mEnableControlled) + { + assert(mTieBreaker.length() == 8); - msg.buildPacket(mOutgoingData, password); + ControlledAttr* attr = new ControlledAttr(); + attr->setTieBreaker(mTieBreaker); + msg.setAttribute(attr); + } + + // Add ICE-CONTROLLING attribute if needed + if (mEnableControlling) + { + assert(mTieBreaker.length() == 8); + + ControllingAttr* attr = new ControllingAttr(); + attr->setTieBreaker(mTieBreaker); + msg.setAttribute(attr); + } + + // Add ICE-PRIORITY attribute if needed + if (mEnablePriority) + { + ICEPriority* attr = new ICEPriority(); + attr->setPriority(mPriority); + msg.setAttribute(attr); + } + + msg.buildPacket(mOutgoingData, password); } ByteBuffer* Transaction::generateData(bool force) { - if (mCancelled) + if (mCancelled) + return NULL; + + // Check if there is any outgoing data + if (mOutgoingData.size() == 0) + return NULL; + + // Check if there is timeout for next transmission attempt + if (mRTOTimer.isTimeout() && !force) + { + ICELogCritical(<< "Transaction " << mComment << " timeouted."); + return NULL; + } + + // Check if transmission was made too much times - client should not send billions of packets. + if (mRTOTimer.isAttemptLimitReached() && !force) + return NULL; + + // Check if time to retransmit now + if (mRTOTimer.isTimeToRetransmit() || force) + { + mRTOTimer.attemptMade(); + + // Copy outgoing data + ByteBuffer* buffer = new ByteBuffer(mOutgoingData); + + buffer->setComment(mComment); + buffer->setRemoteAddress(destination()); + buffer->setComponent(component()); + buffer->setComment(comment()); + buffer->setTag(this); + return buffer; + } + else + { + } return NULL; - - // Check if there is any outgoing data - if (mOutgoingData.size() == 0) - return NULL; - - // Check if there is timeout for next transmission attempt - if (mRTOTimer.isTimeout() && !force) - { - ICELogCritical(<< "Transaction " << mComment << " timeouted."); - return NULL; - } - - // Check if transmission was made too much times - client should not send billions of packets. - if (mRTOTimer.isAttemptLimitReached() && !force) - return NULL; - - // Check if time to retransmit now - if (mRTOTimer.isTimeToRetransmit() || force) - { - mRTOTimer.attemptMade(); - - // Copy outgoing data - ByteBuffer* buffer = new ByteBuffer(mOutgoingData); - - buffer->setComment(mComment); - buffer->setRemoteAddress(destination()); - buffer->setComponent(component()); - buffer->setComment(comment()); - buffer->setTag(this); - return buffer; - } - else - { - } - return NULL; } void Transaction::restart() { - mComposed = false; - mState = Transaction::Running; - mOutgoingData.clear(); - mRemoved = false; - mRTOTimer.stop(); - mRTOTimer.start(); + mComposed = false; + mState = Transaction::Running; + mOutgoingData.clear(); + mRemoved = false; + mRTOTimer.stop(); + mRTOTimer.start(); } bool Transaction::isTimeout() { - if (mRTOTimer.isTimeout()) - { - mState = Failed; - return true; - } - else - return false; + if (mRTOTimer.isTimeout()) + { + mState = Failed; + return true; + } + else + return false; } void Transaction::addMessageIntegrity(bool enable) { - mMessageIntegrity = enable; + mMessageIntegrity = enable; } void Transaction::addFingerprint(bool enable) { - mFingerprint = enable; + mFingerprint = enable; } void Transaction::addShortTermCredentials(bool enable) { - this->mShortTerm = enable; + this->mShortTerm = enable; } void Transaction::addLongTermCredentials(bool enable) { - this->mLongTerm = enable; + this->mLongTerm = enable; } void Transaction::addControllingRole(const std::string& tieBreaker) { - mEnableControlling = true; - mTieBreaker = tieBreaker; + mEnableControlling = true; + mTieBreaker = tieBreaker; } void Transaction::addControlledRole(const std::string& tieBreaker) { - mEnableControlled = true; - mTieBreaker = tieBreaker; + mEnableControlled = true; + mTieBreaker = tieBreaker; } void Transaction::addPriority(unsigned int priority) { - mEnablePriority = true; - mPriority = priority; + mEnablePriority = true; + mPriority = priority; } unsigned int Transaction::priorityValue() { - if (!mEnablePriority) - throw Exception(NO_PRIORITY_ATTRIBUTE); + if (!mEnablePriority) + throw Exception(NO_PRIORITY_ATTRIBUTE); - return mPriority; + return mPriority; } void Transaction::setUsername(const std::string& username) { - mUsername = username; + mUsername = username; } void Transaction::setPassword(const std::string& password) { - mPassword = password; + mPassword = password; } Transaction::State Transaction::state() const { - return mState; + return mState; } void Transaction::setAction(PAction action) { - mAction = action; + mAction = action; } PAction Transaction::action() const { - return mAction; + return mAction; } void Transaction::cancel() { - mCancelled = true; + mCancelled = true; } bool Transaction::isCancelled() const { - return mCancelled; + return mCancelled; } void Transaction::setComment(const std::string& comment) { - mComment = comment; + mComment = comment; } std::string Transaction::comment() const { - return mComment; + return mComment; } void Transaction::setDestination(const NetworkAddress& addr) { - mDestination = addr; + mDestination = addr; } void Transaction::setComponent(int component) { - mComponent = component; + mComponent = component; } int Transaction::component() { - return mComponent; + return mComponent; } NetworkAddress& Transaction::destination() { - return mDestination; + return mDestination; } bool Transaction::relayed() { - return mRelayed; + return mRelayed; } void Transaction::setRelayed(bool relayed) { - mRelayed = relayed; + mRelayed = relayed; } bool Transaction::keepalive() { - return mKeepalive; + return mKeepalive; } void Transaction::setKeepalive(bool keepalive) { - mKeepalive = keepalive; + mKeepalive = keepalive; } unsigned Transaction::interval() { - return mInterval; + return mInterval; } void Transaction::setInterval(unsigned interval) { - mInterval = interval; + mInterval = interval; } void* Transaction::userObject() { - return mUserObject; + return mUserObject; } void Transaction::setUserObject(void* obj) { - mUserObject = obj; + mUserObject = obj; } Transaction::Type Transaction::type() { - return mType; + return mType; } void Transaction::setType(Transaction::Type t) { - mType = t; + mType = t; } bool Transaction::removed() { - return mRemoved; + return mRemoved; } void Transaction::setRemoved(bool removed) { - if (!mRemoved && removed) - ICELogDebug(<< "Transaction " << mComment << " removed."); + if (!mRemoved && removed) + ICELogDebug(<< "Transaction " << mComment << " removed."); - mRemoved = removed; + mRemoved = removed; } unsigned Transaction::timestamp() { - return mTimestamp; + return mTimestamp; } void Transaction::setTimestamp(unsigned timestamp) { - mTimestamp = timestamp; + mTimestamp = timestamp; } StunMessage::TransactionID Transaction::transactionId() { - return mTransactionID; + return mTransactionID; } bool Transaction::hasToRunNow() { - if (!mKeepalive) - return true; - - //bool cf = (mComment == "ClientRefresh"); - - unsigned current = ICETimeHelper::timestamp(); - /*if (cf) - { - ICELogDebug(<< "ClientRefresh interval: " << ICETimeHelper::findDelta(timestamp(), current) << ", interval " << interval()*1000); - }*/ - - if (timestamp()) - { - if (ICETimeHelper::findDelta(timestamp(), current) < interval() * 1000) - return false; - - setTimestamp(current); - return true; - } - else - { - setTimestamp(current); - return false; - } + if (!mKeepalive) + return true; + + // bool cf = (mComment == "ClientRefresh"); + + unsigned current = ICETimeHelper::timestamp(); + /*if (cf) + { + ICELogDebug(<< "ClientRefresh interval: " << ICETimeHelper::findDelta(timestamp(), current) << ", interval " << + interval()*1000); + }*/ + + if (timestamp()) + { + if (ICETimeHelper::findDelta(timestamp(), current) < interval() * 1000) + return false; + + setTimestamp(current); + return true; + } + else + { + setTimestamp(current); + return false; + } } void Transaction::setFailoverId(int failoverId) { - mFailoverId = failoverId; + mFailoverId = failoverId; } int Transaction::failoverId() const { - return mFailoverId; + return mFailoverId; } diff --git a/src/libs/ice/ICEStunTransaction.h b/src/libs/ice/ICEStunTransaction.h index 402c76ae..9fdd59d9 100644 --- a/src/libs/ice/ICEStunTransaction.h +++ b/src/libs/ice/ICEStunTransaction.h @@ -16,229 +16,225 @@ namespace ice { - class Logger; +class Logger; - class Transaction - { - public: +class Transaction +{ +public: enum Type { - Binding = 1, - Relaying = 2, - KeepAlive = 4, - All = 7, - None = 8, + Binding = 1, + Relaying = 2, + KeepAlive = 4, + All = 7, + None = 8, }; enum State { - Running = 0, //Transaction is running now - Failed = 1, //Transaction is failed - Success = 2 //Transaction is succeeded + Running = 0, // Transaction is running now + Failed = 1, // Transaction is failed + Success = 2 // Transaction is succeeded }; static const char* stateToString(State state); Transaction(); virtual ~Transaction(); - - void generateId(); - + + void generateId(); + // Returns if transaction is relayed and must be sent to TURN server instead its regular destination - bool relayed(); + bool relayed(); // Marks if transaction works through relay - void setRelayed(bool relayed); - + void setRelayed(bool relayed); + // Attempts to generate outgoing data. // It is time-sensitive method - it can return empty pointer if there is not time to send data to network. - virtual ByteBuffer* - generateData(bool force = false); - + virtual ByteBuffer* generateData(bool force = false); + // Process incoming STUN message with source address - virtual bool processData(StunMessage& msg, NetworkAddress& address) = 0; + virtual bool processData(StunMessage& msg, NetworkAddress& address) = 0; // Attempts to restart transaction - virtual void restart(); + virtual void restart(); // Checks if transaction is timeouted. - bool isTimeout(); - - // Adds MESSAGE-INTEGRITY attribute to outgoing messages - void addMessageIntegrity(bool enable); - - // Adds FINGERPRINT attribute to outgoing messages - void addFingerprint(bool enable); - - // Enables shortterm credentials on this transaction - void addShortTermCredentials(bool enable); - - // Enables longterm credentials on this transaction - void addLongTermCredentials(bool enable); - - // Adds CONTROLLING attribute with specified tie breaker value - void addControllingRole(const std::string& tieBreaker); - - // Adds CONTROLLED attribute with specified tie breaker value - void addControlledRole(const std::string& tieBreaker); - - // Adds PRIORITY attribute with specified value - void addPriority(unsigned int priority); - - // Returns received PRIORITY attribute - unsigned int priorityValue(); + bool isTimeout(); + + // Adds MESSAGE-INTEGRITY attribute to outgoing messages + void addMessageIntegrity(bool enable); + + // Adds FINGERPRINT attribute to outgoing messages + void addFingerprint(bool enable); + + // Enables shortterm credentials on this transaction + void addShortTermCredentials(bool enable); + + // Enables longterm credentials on this transaction + void addLongTermCredentials(bool enable); + + // Adds CONTROLLING attribute with specified tie breaker value + void addControllingRole(const std::string& tieBreaker); + + // Adds CONTROLLED attribute with specified tie breaker value + void addControlledRole(const std::string& tieBreaker); + + // Adds PRIORITY attribute with specified value + void addPriority(unsigned int priority); + + // Returns received PRIORITY attribute + unsigned int priorityValue(); + + void setUsername(const std::string& username); + void setPassword(const std::string& password); - void setUsername(const std::string& username); - void setPassword(const std::string& password); - // Sets associated tag value - void setTag(unsigned int tag); - unsigned int tag(); - + void setTag(unsigned int tag); + unsigned int tag(); + // Returns transaction state - Succeeded, Failed, Running - State state() const; + State state() const; // Associates action to be performed on finish - void setAction(PAction action); - PAction action() const; - + void setAction(PAction action); + PAction action() const; + // Ceases all outgoing transmission for this transaction - void cancel(); - bool isCancelled() const; + void cancel(); + bool isCancelled() const; - void setComment(const std::string& comment); - std::string comment() const; - - void setDestination(const NetworkAddress& addr); - NetworkAddress& destination(); + void setComment(const std::string& comment); + std::string comment() const; - void setComponent(int component); - int component(); + void setDestination(const NetworkAddress& addr); + NetworkAddress& destination(); - void setStackId(int id); - int stackId(); + void setComponent(int component); + int component(); + + void setStackId(int id); + int stackId(); + + void setTransportType(int _type); + int transportType(); + + bool keepalive(); + void setKeepalive(bool keepalive); - void setTransportType(int _type); - int transportType(); - - bool keepalive(); - void setKeepalive(bool keepalive); - // Interval for keepalive transactions in seconds - unsigned interval(); - void setInterval(unsigned interval); - - unsigned timestamp(); - void setTimestamp(unsigned timestamp); + unsigned interval(); + void setInterval(unsigned interval); - void* userObject(); - void setUserObject(void* obj); - - Type type(); - void setType(Type t); - - bool removed(); - void setRemoved(bool removed); - - virtual bool hasToRunNow(); + unsigned timestamp(); + void setTimestamp(unsigned timestamp); + + void* userObject(); + void setUserObject(void* obj); + + Type type(); + void setType(Type t); + + bool removed(); + void setRemoved(bool removed); + + virtual bool hasToRunNow(); StunMessage::TransactionID transactionId(); - std::string toStdString(); - - void setFailoverId(int failoverId); - int failoverId() const; - - protected: - + std::string toStdString(); + + void setFailoverId(int failoverId); + int failoverId() const; + +protected: // Logger - Logger* mLog; - + Logger* mLog; + // Retransmission timer - PacketScheduler mRTOTimer; - + PacketScheduler mRTOTimer; + // Marks if transaction is cancelled - bool mCancelled; + bool mCancelled; // Marks if packet was created - bool mComposed; + bool mComposed; // Long-term credentials - std::string mUsername; - std::string mPassword; - + std::string mUsername; + std::string mPassword; + // Marks if long term credentials must be used - bool mLongTerm; - + bool mLongTerm; + // Marks if short term credentials must be used - bool mShortTerm; - + bool mShortTerm; + // Marks if CONTROLLING attribute must be used - bool mEnableControlling; + bool mEnableControlling; // Marks if CONTROLLED attribute must be used - bool mEnableControlled; - + bool mEnableControlled; + // Marks if PRIORITY attribute must be used - bool mEnablePriority; - + bool mEnablePriority; + // Priority value - unsigned int mPriority; + unsigned int mPriority; // Tie breaker value for CONTROLLING&CONTROLLED attributes - std::string mTieBreaker; + std::string mTieBreaker; // Transaction ID StunMessage::TransactionID mTransactionID; - + // Buffer to hold raw outgoing data - ByteBuffer mOutgoingData; + ByteBuffer mOutgoingData; // Marks if fingerprint attribute must be used for outgoing messages - bool mFingerprint; - + bool mFingerprint; + // Marks if message integrity attribyte must be used for outgoing messages - bool mMessageIntegrity; - + bool mMessageIntegrity; + // Tag associated with transaction - unsigned int mTag; - + unsigned int mTag; + // Transaction state - Running, Failed or Success - State mState; - + State mState; + // Action that must be run on transaction finish - PAction mAction; + PAction mAction; // Comment that describes this transaction - std::string mComment; - + std::string mComment; + // Destination address - NetworkAddress mDestination; + NetworkAddress mDestination; // Relayed flag - bool mRelayed; + bool mRelayed; // Source component's ID - int mComponent; - + int mComponent; + // Used ICE stack ID. This member is used for debugging purpose. - int mStackID; - int mTransportType; - - bool mKeepalive; - unsigned mInterval; - void* mUserObject; - Type mType; - bool mRemoved; - int mFailoverId; - + int mStackID; + int mTransportType; + + bool mKeepalive; + unsigned mInterval; + void* mUserObject; + Type mType; + bool mRemoved; + int mFailoverId; + // Timestamp when transaction runs in last time. Default is zero. - unsigned mTimestamp; + unsigned mTimestamp; // Updates msg with auth. data (MessageDigest + Fingerprint) + fills mOutgoingData - void enqueueMessage(ice::StunMessage& msg); - - - }; -} + void enqueueMessage(ice::StunMessage& msg); +}; +} // namespace ice #endif diff --git a/src/libs/ice/ICESync.cpp b/src/libs/ice/ICESync.cpp index 3a179925..0f500f4a 100644 --- a/src/libs/ice/ICESync.cpp +++ b/src/libs/ice/ICESync.cpp @@ -10,81 +10,80 @@ using namespace ice; Mutex::Mutex() { #ifdef _WIN32 - InitializeCriticalSection(&mSection); + InitializeCriticalSection(&mSection); #else - pthread_mutexattr_init(&mAttr); - pthread_mutexattr_settype(&mAttr, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(&mMutex, &mAttr); + pthread_mutexattr_init(&mAttr); + pthread_mutexattr_settype(&mAttr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&mMutex, &mAttr); #endif } Mutex::~Mutex() { #ifdef _WIN32 - DeleteCriticalSection(&mSection); + DeleteCriticalSection(&mSection); #else - pthread_mutex_destroy(&mMutex); - pthread_mutexattr_destroy(&mAttr); + pthread_mutex_destroy(&mMutex); + pthread_mutexattr_destroy(&mAttr); #endif } void Mutex::lock() { #ifdef _WIN32 - EnterCriticalSection(&mSection); + EnterCriticalSection(&mSection); #else - pthread_mutex_lock(&mMutex); + pthread_mutex_lock(&mMutex); #endif } void Mutex::unlock() { #ifdef _WIN32 - LeaveCriticalSection(&mSection); + LeaveCriticalSection(&mSection); #else - pthread_mutex_unlock(&mMutex); + pthread_mutex_unlock(&mMutex); #endif } -Lock::Lock(Mutex &mutex) -:mMutex(mutex) +Lock::Lock(Mutex& mutex) : mMutex(mutex) { - mMutex.lock(); + mMutex.lock(); } Lock::~Lock() { - mMutex.unlock(); + mMutex.unlock(); } #ifndef _WIN32 -static pthread_mutex_t DoGuard = PTHREAD_MUTEX_INITIALIZER ; +static pthread_mutex_t DoGuard = PTHREAD_MUTEX_INITIALIZER; #endif -long Atomic::increment(long *value) +long Atomic::increment(long* value) { #ifdef _WIN32 - return ::InterlockedIncrement((LONG*)value); + return ::InterlockedIncrement((LONG*)value); #else - pthread_mutex_lock(&DoGuard); - (void)*value++; - long result = *value; - pthread_mutex_unlock(&DoGuard); - return result; + pthread_mutex_lock(&DoGuard); + (void)*value++; + long result = *value; + pthread_mutex_unlock(&DoGuard); + return result; #endif } -long Atomic::decrement(long *value) +long Atomic::decrement(long* value) { #ifdef _WIN32 - return ::InterlockedDecrement((LONG*)value); + return ::InterlockedDecrement((LONG*)value); #else - pthread_mutex_lock(&DoGuard); - (void)*value--; - long result = *value; - pthread_mutex_unlock(&DoGuard); - return result; + pthread_mutex_lock(&DoGuard); + (void)*value--; + long result = *value; + pthread_mutex_unlock(&DoGuard); + return result; #endif } @@ -92,8 +91,8 @@ long Atomic::decrement(long *value) void* ThreadInfo::currentThread() { #ifdef _WIN32 - return (void*)::GetCurrentThreadId(); + return (void*)::GetCurrentThreadId(); #else - return (void*)(::pthread_self()); + return (void*)(::pthread_self()); #endif } diff --git a/src/libs/ice/ICESync.h b/src/libs/ice/ICESync.h index a6563aa3..0f151127 100644 --- a/src/libs/ice/ICESync.h +++ b/src/libs/ice/ICESync.h @@ -7,10 +7,10 @@ #define __ICE_SYNC_H #ifdef _WIN32 -# include -# include +#include +#include #else -# include +#include #endif namespace ice @@ -20,43 +20,43 @@ namespace ice class Mutex { public: - Mutex(); - ~Mutex(); - void lock(); - void unlock(); + Mutex(); + ~Mutex(); + void lock(); + void unlock(); protected: #ifdef _WIN32 - CRITICAL_SECTION mSection; + CRITICAL_SECTION mSection; #else - pthread_mutexattr_t mAttr; - pthread_mutex_t mMutex; + pthread_mutexattr_t mAttr; + pthread_mutex_t mMutex; #endif }; class Lock { public: - Lock(Mutex& mutex); - ~Lock(); + Lock(Mutex& mutex); + ~Lock(); protected: - Mutex& mMutex; + Mutex& mMutex; }; class Atomic { public: - static long increment(long* value); - static long decrement(long* value); + static long increment(long* value); + static long decrement(long* value); }; class ThreadInfo { public: - static void* currentThread(); + static void* currentThread(); }; -} +} // namespace ice #endif diff --git a/src/libs/ice/ICETime.cpp b/src/libs/ice/ICETime.cpp index 0eda1f5e..91761aee 100644 --- a/src/libs/ice/ICETime.cpp +++ b/src/libs/ice/ICETime.cpp @@ -4,13 +4,13 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifdef _WIN32 -# include -# include +#include +#include #else -# include -# include -# include -# include +#include +#include +#include +#include #endif #include "ICEPlatform.h" @@ -22,211 +22,194 @@ using namespace ice; #ifdef _WIN32 static unsigned GetMilliseconds() { - return ::GetTickCount(); + return ::GetTickCount(); } #else -static int ClocksPerSec = (int)sysconf(_SC_CLK_TCK); -static tms GlobalStartTimeStruct; -static clock_t GlobalStartTime = times(&GlobalStartTimeStruct); +static int ClocksPerSec = (int)sysconf(_SC_CLK_TCK); +static tms GlobalStartTimeStruct; +static clock_t GlobalStartTime = times(&GlobalStartTimeStruct); static unsigned GetMilliseconds() { - tms t; - clock_t result = times(&t) - GlobalStartTime; - float ticksPerMilliseconds = ClocksPerSec / 1000.0; - return unsigned( result / ticksPerMilliseconds ); + tms t; + clock_t result = times(&t) - GlobalStartTime; + float ticksPerMilliseconds = ClocksPerSec / 1000.0; + return unsigned(result / ticksPerMilliseconds); } #endif -TimeoutDetector::TimeoutDetector() - :mTimestamp(0), mAttempt(0) -{ -} +TimeoutDetector::TimeoutDetector() : mTimestamp(0), mAttempt(0) {} -TimeoutDetector::~TimeoutDetector() -{ -} +TimeoutDetector::~TimeoutDetector() {} void TimeoutDetector::start() { - mTimestamp = ::GetMilliseconds(); + mTimestamp = ::GetMilliseconds(); } -void TimeoutDetector::stop() -{ -} +void TimeoutDetector::stop() {} void TimeoutDetector::reset() { - mAttempt = 0; + mAttempt = 0; } bool TimeoutDetector::isTimeToRetransmit() { - static time_t RetransmissionIntervalArray[] = { 100, 200, 200, 200, 200, 200 }; - - //get current time - time_t current = ::GetMilliseconds(); + static time_t RetransmissionIntervalArray[] = {100, 200, 200, 200, 200, 200}; - //find the delta - time_t delta = current - mTimestamp; + // get current time + time_t current = ::GetMilliseconds(); - //find a wait interval for the mAttempt value - time_t referenceInterval = 0; - - size_t arrayLength = sizeof(RetransmissionIntervalArray) / sizeof(RetransmissionIntervalArray[0]); - - if (mAttempt < arrayLength ) - referenceInterval = RetransmissionIntervalArray[mAttempt]; - else - referenceInterval = RetransmissionIntervalArray[arrayLength-1]; + // find the delta + time_t delta = current - mTimestamp; - if (delta >= referenceInterval) - return true; + // find a wait interval for the mAttempt value + time_t referenceInterval = 0; - return false; + size_t arrayLength = sizeof(RetransmissionIntervalArray) / sizeof(RetransmissionIntervalArray[0]); + + if (mAttempt < arrayLength) + referenceInterval = RetransmissionIntervalArray[mAttempt]; + else + referenceInterval = RetransmissionIntervalArray[arrayLength - 1]; + + if (delta >= referenceInterval) + return true; + + return false; } void TimeoutDetector::nextAttempt() { - mAttempt++; - mTimestamp = ::GetMilliseconds(); + mAttempt++; + mTimestamp = ::GetMilliseconds(); } bool TimeoutDetector::isTimeout() { - // Get current time - time_t current = ::GetMilliseconds(); + // Get current time + time_t current = ::GetMilliseconds(); - // Find the delta - time_t delta = current - mTimestamp; + // Find the delta + time_t delta = current - mTimestamp; - return delta > ICE_TIMEOUT_VALUE; + return delta > ICE_TIMEOUT_VALUE; } -ICEStartTimer::ICEStartTimer() - :mTimestamp(0), mInterval(0), mEnabled(false) -{ -} +ICEStartTimer::ICEStartTimer() : mTimestamp(0), mInterval(0), mEnabled(false) {} -ICEStartTimer::~ICEStartTimer() -{ -} +ICEStartTimer::~ICEStartTimer() {} void ICEStartTimer::start(unsigned interval) { - mInterval = interval; - mTimestamp = ::GetMilliseconds(); - mEnabled = true; + mInterval = interval; + mTimestamp = ::GetMilliseconds(); + mEnabled = true; } void ICEStartTimer::stop() { - mEnabled = false; + mEnabled = false; } bool ICEStartTimer::isTimeToBegin() { - if (!mEnabled) - return false; + if (!mEnabled) + return false; - unsigned t = ::GetMilliseconds(); - unsigned delta = 0; + unsigned t = ::GetMilliseconds(); + unsigned delta = 0; - if (t < 0x7FFFFFFF && mTimestamp > 0x7FFFFFFF) - delta = 0xFFFFFFFF - mTimestamp + t; - else - delta = t - mTimestamp; + if (t < 0x7FFFFFFF && mTimestamp > 0x7FFFFFFF) + delta = 0xFFFFFFFF - mTimestamp + t; + else + delta = t - mTimestamp; - return delta >= mInterval; + return delta >= mInterval; } -ICEScheduleTimer::ICEScheduleTimer() -:mEnabled(false), mTimestamp(0), mTail(0), mInterval(0) -{ -} +ICEScheduleTimer::ICEScheduleTimer() : mEnabled(false), mTimestamp(0), mTail(0), mInterval(0) {} -ICEScheduleTimer::~ICEScheduleTimer() -{ -} +ICEScheduleTimer::~ICEScheduleTimer() {} void ICEScheduleTimer::start(int interval) { - mEnabled = true; - mInterval = interval; - mTail = 1; // First check is immediate! - mTimestamp = ICETimeHelper::timestamp(); + mEnabled = true; + mInterval = interval; + mTail = 1; // First check is immediate! + mTimestamp = ICETimeHelper::timestamp(); } - + bool ICEScheduleTimer::isTimeToSend() { - if (!mEnabled) - return false; + if (!mEnabled) + return false; #ifdef ICE_SIMPLE_SCHEDULE - unsigned current = ICETimeHelper::timestamp(); - unsigned delta = ICETimeHelper::findDelta(mTimestamp, current); - - return delta > mInterval; + unsigned current = ICETimeHelper::timestamp(); + unsigned delta = ICETimeHelper::findDelta(mTimestamp, current); + + return delta > mInterval; #else - // Check if there are already scheduled checks - if (mTail > 0) - { - mTail--; - return true; - } + // Check if there are already scheduled checks + if (mTail > 0) + { + mTail--; + return true; + } - unsigned current = ICETimeHelper::timestamp(); - unsigned delta = ICETimeHelper::findDelta(mTimestamp, current); + unsigned current = ICETimeHelper::timestamp(); + unsigned delta = ICETimeHelper::findDelta(mTimestamp, current); - if (delta > (unsigned)mInterval) - { - mTail += delta / mInterval; - mTimestamp = current - delta % mInterval; - } - - if (mTail > 0) - { - mTail--; - return true; - } + if (delta > (unsigned)mInterval) + { + mTail += delta / mInterval; + mTimestamp = current - delta % mInterval; + } - return false; + if (mTail > 0) + { + mTail--; + return true; + } + + return false; #endif } - + void ICEScheduleTimer::stop() { - mEnabled = false; + mEnabled = false; } int ICEScheduleTimer::remaining() { - unsigned delta = ICETimeHelper::findDelta(mTimestamp, ICETimeHelper::timestamp()); + unsigned delta = ICETimeHelper::findDelta(mTimestamp, ICETimeHelper::timestamp()); #ifdef ICE_SIMPLE_SCHEDULE - return (delta >= mInterval) ? 0 : mInterval - delta; + return (delta >= mInterval) ? 0 : mInterval - delta; #else - return ((int)delta + mTail >= mInterval) ? 0 : mInterval - delta - mTail; + return ((int)delta + mTail >= mInterval) ? 0 : mInterval - delta - mTail; #endif } int ICEScheduleTimer::interval() const { - return mInterval; + return mInterval; } void ICEScheduleTimer::setInterval(int interval) { - mTail = 0; - mInterval = interval; + mTail = 0; + mInterval = interval; } unsigned int ICETimeHelper::timestamp() { - return ::GetMilliseconds(); + return ::GetMilliseconds(); } unsigned int ICETimeHelper::findDelta(unsigned int oldTS, unsigned int newTS) { - return (oldTS > 0x7FFFFFFF && newTS < 0x7FFFFFFF) ? 0xFFFFFFFF - oldTS + newTS : newTS - oldTS; + return (oldTS > 0x7FFFFFFF && newTS < 0x7FFFFFFF) ? 0xFFFFFFFF - oldTS + newTS : newTS - oldTS; } diff --git a/src/libs/ice/ICETime.h b/src/libs/ice/ICETime.h index 687dacb2..ed47b8d0 100644 --- a/src/libs/ice/ICETime.h +++ b/src/libs/ice/ICETime.h @@ -9,46 +9,47 @@ #include "ICEPlatform.h" #include "ICETypes.h" #ifndef _WIN32 -# include -# include +#include +#include #endif -namespace ice { +namespace ice +{ - class TimeoutDetector - { - public: +class TimeoutDetector +{ +public: TimeoutDetector(); ~TimeoutDetector(); - + void start(); void stop(); - + /*! Resets the countdown. */ void reset(); /*! Checks if it is a time to retransmit non-answered packet * @return true if time to retransmit packet, false if not. */ bool isTimeToRetransmit(); - + /*! Notifies timer about retransmission. */ void nextAttempt(); - + /*! Checks if it is a time to mark the transaction timeouted. * @return true if transaction is timeouted, false if not. */ bool isTimeout(); - protected: - - /// Time tracking member - time_t mTimestamp; + +protected: + /// Time tracking member + time_t mTimestamp; /// Retransmission attempt counter - size_t mAttempt; - }; + size_t mAttempt; +}; - class ICEStartTimer - { - public: +class ICEStartTimer +{ +public: ICEStartTimer(); ~ICEStartTimer(); @@ -56,58 +57,57 @@ namespace ice { bool isTimeToBegin(); void stop(); - protected: - unsigned mTimestamp; - unsigned mInterval; - bool mEnabled; - }; - - /*! Class intendend to schedule connectivity checks. It is simple timer which returns true from IsTimeToSend() every interval milliseconds. */ - class ICEScheduleTimer - { - public: +protected: + unsigned mTimestamp; + unsigned mInterval; + bool mEnabled; +}; + +/*! Class intendend to schedule connectivity checks. It is simple timer which returns true from IsTimeToSend() every + * interval milliseconds. */ +class ICEScheduleTimer +{ +public: /*! Default constructor. */ ICEScheduleTimer(); - + /*! Destructor. */ ~ICEScheduleTimer(); /*! Start timer with interval in milliseconds. */ void start(int interval); - - /*! Check if it is a time to send next check. This method must be called in while (IsTimeToSend()) {} loop - + + /*! Check if it is a time to send next check. This method must be called in while (IsTimeToSend()) {} loop - * as multiple checks can be scheduled for elapsed time interval. */ bool isTimeToSend(); - + /*! Stops timer. */ void stop(); - + /*! Returns remaining time in milliseconds. */ - int remaining(); - + int remaining(); + /*! Returns interval time in milliseconds. */ - int interval() const; - + int interval() const; + /*! Sets new interval time in milliseconds. Can be called on active timer, will reschedule timeout event. */ void setInterval(int interval); - - protected: - bool mEnabled; /// Marks if timer is started - unsigned mTimestamp; /// Last timestamp - int mTail; /// How much checks was scheduled for elapsed time interval. - int mInterval; /// Timer interval - }; - - class ICETimeHelper - { - public: - static unsigned timestamp(); - static unsigned findDelta(unsigned oldTimestamp, unsigned int newTimestamp); - }; +protected: + bool mEnabled; /// Marks if timer is started + unsigned mTimestamp; /// Last timestamp + int mTail; /// How much checks was scheduled for elapsed time interval. + int mInterval; /// Timer interval }; +class ICETimeHelper +{ +public: + static unsigned timestamp(); + static unsigned findDelta(unsigned oldTimestamp, unsigned int newTimestamp); +}; +}; // namespace ice #endif diff --git a/src/libs/ice/ICETransactionList.cpp b/src/libs/ice/ICETransactionList.cpp index 5d02aa95..e424b596 100644 --- a/src/libs/ice/ICETransactionList.cpp +++ b/src/libs/ice/ICETransactionList.cpp @@ -11,278 +11,277 @@ using namespace ice; #define LOG_SUBSYSTEM "ice" -TransactionList::TransactionList() -:mRegularIndex(0), mPrioritizedIndex(0) +TransactionList::TransactionList() : mRegularIndex(0), mPrioritizedIndex(0) { - mRegularList.reserve(1024); - mPrioritizedList.reserve(1024); + mRegularList.reserve(1024); + mPrioritizedList.reserve(1024); } TransactionList::~TransactionList() { - for (unsigned i=0; iremoved()) - continue; - - finished = t->state() == Transaction::Success || t->state() == Transaction::Failed; - if (!finished) + unsigned index; + for (index = 0; index < l.size(); index++) { - if (t->processData(msg, address)) - { - finished = t->state() == Transaction::Success || t->state() == Transaction::Failed; - if (finished && t->action()) - t->action()->finished(*t); + bool finished = false; + Transaction* t = l[index]; + if (t->removed()) + continue; - // Previous action could restart transaction - so check transaction state again finished = t->state() == Transaction::Success || t->state() == Transaction::Failed; - - if (finished) + if (!finished) { - if (t->keepalive()) - t->restart(); - else - t->setRemoved(true); + if (t->processData(msg, address)) + { + finished = t->state() == Transaction::Success || t->state() == Transaction::Failed; + if (finished && t->action()) + t->action()->finished(*t); + + // Previous action could restart transaction - so check transaction state again + finished = t->state() == Transaction::Success || t->state() == Transaction::Failed; + + if (finished) + { + if (t->keepalive()) + t->restart(); + else + t->setRemoved(true); + } + return true; + } } - return true; - } } - } - return false; + return false; } bool TransactionList::processIncoming(StunMessage& msg, NetworkAddress& address) { - if (processIncoming(mRegularList, msg, address)) - return true; - if (processIncoming(mPrioritizedList, msg, address)) - return true; - - return false; + if (processIncoming(mRegularList, msg, address)) + return true; + if (processIncoming(mPrioritizedList, msg, address)) + return true; + + return false; } bool TransactionList::checkTimeout(List& l) { - // Iterate checks - unsigned index; - for (index=0; indexstate() == Transaction::Running) + // Iterate checks + unsigned index; + for (index = 0; index < l.size(); index++) { - // Is transaction timeouted? - if (t->isTimeout()) - { - ICELogDebug(<< "Transaction " << t->comment() << " timeouted"); - if (t->action()) - t->action()->finished(*t); - - if (t->keepalive()) - t->restart(); - else - t->setRemoved(true); - return true; - } + // Check only running transactions + Transaction* t = l[index]; + if (t->state() == Transaction::Running) + { + // Is transaction timeouted? + if (t->isTimeout()) + { + ICELogDebug(<< "Transaction " << t->comment() << " timeouted"); + if (t->action()) + t->action()->finished(*t); + + if (t->keepalive()) + t->restart(); + else + t->setRemoved(true); + return true; + } + } } - } - return false; + return false; } bool TransactionList::checkTimeout() { - if (checkTimeout(mPrioritizedList)) - return true; - if (checkTimeout(mRegularList)) - return true; + if (checkTimeout(mPrioritizedList)) + return true; + if (checkTimeout(mRegularList)) + return true; - return false; + return false; } void TransactionList::addRegular(Transaction* p) { - List::iterator regularIter = std::find(mRegularList.begin(), mRegularList.end(), p); - List::iterator prioritizedIter = std::find(mPrioritizedList.begin(), mPrioritizedList.end(), p); - - if (regularIter == mRegularList.end() && prioritizedIter == mPrioritizedList.end()) - mRegularList.push_back(p); + List::iterator regularIter = std::find(mRegularList.begin(), mRegularList.end(), p); + List::iterator prioritizedIter = std::find(mPrioritizedList.begin(), mPrioritizedList.end(), p); + + if (regularIter == mRegularList.end() && prioritizedIter == mPrioritizedList.end()) + mRegularList.push_back(p); } void TransactionList::erase(Transaction* p) { - List::iterator it = std::find(mRegularList.begin(), mRegularList.end(), p); - if (it != mRegularList.end()) - p->setRemoved(true); - else - { - it = std::find(mPrioritizedList.begin(), mPrioritizedList.end(), p); - if (it != mPrioritizedList.end()) - p->setRemoved(true); - } + List::iterator it = std::find(mRegularList.begin(), mRegularList.end(), p); + if (it != mRegularList.end()) + p->setRemoved(true); + else + { + it = std::find(mPrioritizedList.begin(), mPrioritizedList.end(), p); + if (it != mPrioritizedList.end()) + p->setRemoved(true); + } } void TransactionList::erase(const TransactionCondition& cond) { - List::iterator iter; - for (iter = mRegularList.begin();iter != mRegularList.end(); iter++) - { - if (cond.check(*iter)) - (*iter)->setRemoved(true); - } - - for (iter = mPrioritizedList.begin(); iter != mPrioritizedList.end(); iter++) - { - if (cond.check(*iter)) - (*iter)->setRemoved(true); - } + List::iterator iter; + for (iter = mRegularList.begin(); iter != mRegularList.end(); iter++) + { + if (cond.check(*iter)) + (*iter)->setRemoved(true); + } + + for (iter = mPrioritizedList.begin(); iter != mPrioritizedList.end(); iter++) + { + if (cond.check(*iter)) + (*iter)->setRemoved(true); + } } void TransactionList::eraseMatching(unsigned types) { - List::iterator iter; - for (iter = mRegularList.begin();iter != mRegularList.end(); iter++) - { - if (types && (*iter)->type()) - (*iter)->setRemoved(true); - } + List::iterator iter; + for (iter = mRegularList.begin(); iter != mRegularList.end(); iter++) + { + if (types && (*iter)->type()) + (*iter)->setRemoved(true); + } - for (iter = mPrioritizedList.begin(); iter != mPrioritizedList.end(); iter++) - { - if (types && (*iter)->type()) - (*iter)->setRemoved(true); - } + for (iter = mPrioritizedList.begin(); iter != mPrioritizedList.end(); iter++) + { + if (types && (*iter)->type()) + (*iter)->setRemoved(true); + } } int TransactionList::copyMatching(const TransactionCondition& condition, std::vector& result) { - List::iterator iter; - int counter = (int)result.size(); - for (iter = mRegularList.begin();iter != mRegularList.end(); iter++) - { - if (condition.check(*iter)) - result.push_back(*iter); - } - - for (iter = mPrioritizedList.begin(); iter != mPrioritizedList.end(); iter++) - { - if (condition.check(*iter)) - result.push_back(*iter); - } - - return (int)result.size() - counter; + List::iterator iter; + int counter = (int)result.size(); + for (iter = mRegularList.begin(); iter != mRegularList.end(); iter++) + { + if (condition.check(*iter)) + result.push_back(*iter); + } + + for (iter = mPrioritizedList.begin(); iter != mPrioritizedList.end(); iter++) + { + if (condition.check(*iter)) + result.push_back(*iter); + } + + return (int)result.size() - counter; } void TransactionList::prioritize(Transaction* p) { - // Check if this transaction is prioritized already - List::iterator iter = std::find(mPrioritizedList.begin(), mPrioritizedList.end(), p); - if (iter != mPrioritizedList.end()) - return; + // Check if this transaction is prioritized already + List::iterator iter = std::find(mPrioritizedList.begin(), mPrioritizedList.end(), p); + if (iter != mPrioritizedList.end()) + return; - // Check if the transaction is in regular list - iter = std::find(mRegularList.begin(), mRegularList.end(), p); - if (iter == mRegularList.end()) - return; + // Check if the transaction is in regular list + iter = std::find(mRegularList.begin(), mRegularList.end(), p); + if (iter == mRegularList.end()) + return; - // Remove the transaction from regular list - mRegularList.erase(iter); + // Remove the transaction from regular list + mRegularList.erase(iter); - // And move to priority list - mPrioritizedList.push_back(p); + // And move to priority list + mPrioritizedList.push_back(p); } Transaction* TransactionList::getNextTransaction() { - while (mPrioritizedIndex < mPrioritizedList.size() && mPrioritizedList[mPrioritizedIndex]->removed()) - mPrioritizedIndex++; - if (mPrioritizedIndex < mPrioritizedList.size()) - return mPrioritizedList[mPrioritizedIndex++]; - - while (mRegularIndex < mRegularList.size() && mRegularList[mRegularIndex]->removed()) - mRegularIndex++; - if (mRegularIndex < mRegularList.size()) - return mRegularList[mRegularIndex++]; - - mPrioritizedIndex = 0; - mRegularIndex = 0; - - while (mPrioritizedIndex < mPrioritizedList.size() && mPrioritizedList[mPrioritizedIndex]->removed()) - mPrioritizedIndex++; - if (mPrioritizedIndex < mPrioritizedList.size()) - return mPrioritizedList[mPrioritizedIndex++]; - - while (mRegularIndex < mRegularList.size() && mRegularList[mRegularIndex]->removed()) - mRegularIndex++; - if (mRegularIndex < mRegularList.size()) - return mRegularList[mRegularIndex++]; - - return NULL; + while (mPrioritizedIndex < mPrioritizedList.size() && mPrioritizedList[mPrioritizedIndex]->removed()) + mPrioritizedIndex++; + if (mPrioritizedIndex < mPrioritizedList.size()) + return mPrioritizedList[mPrioritizedIndex++]; + + while (mRegularIndex < mRegularList.size() && mRegularList[mRegularIndex]->removed()) + mRegularIndex++; + if (mRegularIndex < mRegularList.size()) + return mRegularList[mRegularIndex++]; + + mPrioritizedIndex = 0; + mRegularIndex = 0; + + while (mPrioritizedIndex < mPrioritizedList.size() && mPrioritizedList[mPrioritizedIndex]->removed()) + mPrioritizedIndex++; + if (mPrioritizedIndex < mPrioritizedList.size()) + return mPrioritizedList[mPrioritizedIndex++]; + + while (mRegularIndex < mRegularList.size() && mRegularList[mRegularIndex]->removed()) + mRegularIndex++; + if (mRegularIndex < mRegularList.size()) + return mRegularList[mRegularIndex++]; + + return NULL; } void TransactionList::addPrioritized(Transaction* p) { - List::iterator regularIter = std::find(mRegularList.begin(), mRegularList.end(), p); - List::iterator prioritizedIter = std::find(mPrioritizedList.begin(), mPrioritizedList.end(), p); - - if (regularIter != mRegularList.end()) - mRegularList.erase(regularIter); + List::iterator regularIter = std::find(mRegularList.begin(), mRegularList.end(), p); + List::iterator prioritizedIter = std::find(mPrioritizedList.begin(), mPrioritizedList.end(), p); - if (prioritizedIter == mPrioritizedList.end()) - mPrioritizedList.push_back(p); + if (regularIter != mRegularList.end()) + mRegularList.erase(regularIter); + + if (prioritizedIter == mPrioritizedList.end()) + mPrioritizedList.push_back(p); } int TransactionList::count() { - return (int)mRegularList.size() + (int)mPrioritizedList.size(); + return (int)mRegularList.size() + (int)mPrioritizedList.size(); } void TransactionList::clear() { - mRegularList.clear(); - mPrioritizedList.clear(); + mRegularList.clear(); + mPrioritizedList.clear(); } bool TransactionList::exists(Transaction* t) { - List::iterator regularIter = std::find(mRegularList.begin(), mRegularList.end(), t); - List::iterator prioritizedIter = std::find(mPrioritizedList.begin(), mPrioritizedList.end(), t); - - bool removed = true; - - if (regularIter != mRegularList.end()) - removed &= (*regularIter)->removed(); - - if (prioritizedIter != mPrioritizedList.end()) - removed &= (*prioritizedIter)->removed(); + List::iterator regularIter = std::find(mRegularList.begin(), mRegularList.end(), t); + List::iterator prioritizedIter = std::find(mPrioritizedList.begin(), mPrioritizedList.end(), t); - return !removed; + bool removed = true; + + if (regularIter != mRegularList.end()) + removed &= (*regularIter)->removed(); + + if (prioritizedIter != mPrioritizedList.end()) + removed &= (*prioritizedIter)->removed(); + + return !removed; } bool TransactionList::exists(const TransactionCondition& condition) { - int counter = 0; - List::iterator iter; - for (iter = mRegularList.begin();iter != mRegularList.end(); iter++) - { - if (condition.check(*iter)) - counter++; - } - - for (iter = mPrioritizedList.begin(); iter != mPrioritizedList.end(); iter++) - { - if (condition.check(*iter)) - counter++; - } - return counter > 0; + int counter = 0; + List::iterator iter; + for (iter = mRegularList.begin(); iter != mRegularList.end(); iter++) + { + if (condition.check(*iter)) + counter++; + } + + for (iter = mPrioritizedList.begin(); iter != mPrioritizedList.end(); iter++) + { + if (condition.check(*iter)) + counter++; + } + return counter > 0; } diff --git a/src/libs/ice/ICETransactionList.h b/src/libs/ice/ICETransactionList.h index d713d671..f2d53bab 100644 --- a/src/libs/ice/ICETransactionList.h +++ b/src/libs/ice/ICETransactionList.h @@ -11,40 +11,41 @@ namespace ice { - class TransactionCondition - { - public: +class TransactionCondition +{ +public: virtual bool check(Transaction* t) const = 0; - }; - - class TransactionList - { - protected: - typedef std::vector List; - List mRegularList, mPrioritizedList; - unsigned mRegularIndex, mPrioritizedIndex; +}; - bool processIncoming(List& l, StunMessage& msg, NetworkAddress& address); - bool checkTimeout(List& l); - public: +class TransactionList +{ +protected: + typedef std::vector List; + List mRegularList, mPrioritizedList; + unsigned mRegularIndex, mPrioritizedIndex; + + bool processIncoming(List& l, StunMessage& msg, NetworkAddress& address); + bool checkTimeout(List& l); + +public: TransactionList(); ~TransactionList(); - - bool processIncoming(StunMessage& msg, NetworkAddress& address); - bool checkTimeout(); - void addRegular(Transaction* p); - void addPrioritized(Transaction* p); - void prioritize(Transaction* p); - void erase(Transaction* p); - void erase(const TransactionCondition& condition); - void eraseMatching(unsigned types); - int copyMatching(const TransactionCondition& condition, std::vector& result); + + bool processIncoming(StunMessage& msg, NetworkAddress& address); + bool checkTimeout(); + void addRegular(Transaction* p); + void addPrioritized(Transaction* p); + void prioritize(Transaction* p); + void erase(Transaction* p); + void erase(const TransactionCondition& condition); + void eraseMatching(unsigned types); + int copyMatching(const TransactionCondition& condition, std::vector& result); Transaction* getNextTransaction(); - int count(); - void clear(); - bool exists(Transaction* t); - bool exists(const TransactionCondition& condition); - }; -} + int count(); + void clear(); + bool exists(Transaction* t); + bool exists(const TransactionCondition& condition); +}; +} // namespace ice #endif \ No newline at end of file diff --git a/src/libs/ice/ICETypes.h b/src/libs/ice/ICETypes.h index 145dd59a..bcb33e78 100644 --- a/src/libs/ice/ICETypes.h +++ b/src/libs/ice/ICETypes.h @@ -7,7 +7,7 @@ #define __ICE_TYPES_H #if !defined(TARGET_WIN) && !defined(SOCKET) -# define SOCKET int +#define SOCKET int #endif #endif diff --git a/test/rtp_decode/main.cpp b/test/rtp_decode/main.cpp index 2db3c613..1b398786 100644 --- a/test/rtp_decode/main.cpp +++ b/test/rtp_decode/main.cpp @@ -27,22 +27,23 @@ static void usage(const char* progname) { fprintf(stderr, - "Usage: %s --codec [--pt ] [--rate ] [--channels ]\n" - "\n" - "Codecs: pcmu pcma g722 g729 opus gsm gsmhr gsmefr\n" - " amrnb amrwb amrnb-bwe amrwb-bwe evs ilbc20 ilbc30 isac16 isac32\n" - "\n" - "Options:\n" - " --codec Codec name (required)\n" - " --pt Override RTP payload type\n" - " --rate Sample rate hint for Opus (default 48000)\n" - " --channels Channel count hint for Opus (default 2)\n", - progname); + "Usage: %s --codec [--pt ] [--rate ] [--channels ]\n" + "\n" + "Codecs: pcmu pcma g722 g729 opus gsm gsmhr gsmefr\n" + " amrnb amrwb amrnb-bwe amrwb-bwe evs ilbc20 ilbc30 isac16 isac32\n" + "\n" + "Options:\n" + " --codec Codec name (required)\n" + " --pt Override RTP payload type\n" + " --rate Sample rate hint for Opus (default 48000)\n" + " --channels Channel count hint for Opus (default 2)\n", + progname); } static const char* getOption(int argc, char* argv[], const char* name) { - for (int i = 1; i < argc - 1; ++i) { + for (int i = 1; i < argc - 1; ++i) + { if (strcmp(argv[i], name) == 0) return argv[i + 1]; } @@ -55,28 +56,15 @@ static const char* getOption(int argc, char* argv[], const char* name) struct CodecDefaults { const char* name; - int defaultPt; // -1 = must be specified via --pt - bool needsPt; // true if --pt is required when no default exists + int defaultPt; // -1 = must be specified via --pt + bool needsPt; // true if --pt is required when no default exists }; static const CodecDefaults kCodecTable[] = { - { "pcmu", 0, false }, - { "pcma", 8, false }, - { "g722", 9, false }, - { "g729", 18, false }, - { "gsm", 3, false }, - { "opus", 106, false }, - { "amrnb", -1, true }, - { "amrwb", -1, true }, - { "amrnb-bwe", -1, true }, - { "amrwb-bwe", -1, true }, - { "gsmhr", -1, true }, - { "gsmefr", 126, false }, - { "evs", 127, false }, - { "ilbc20", -1, true }, - { "ilbc30", -1, true }, - { "isac16", -1, true }, - { "isac32", -1, true }, + {"pcmu", 0, false}, {"pcma", 8, false}, {"g722", 9, false}, {"g729", 18, false}, {"gsm", 3, false}, + {"opus", 106, false}, {"amrnb", -1, true}, {"amrwb", -1, true}, {"amrnb-bwe", -1, true}, {"amrwb-bwe", -1, true}, + {"gsmhr", -1, true}, {"gsmefr", 126, false}, {"evs", 127, false}, {"ilbc20", -1, true}, {"ilbc30", -1, true}, + {"isac16", -1, true}, {"isac32", -1, true}, }; static const CodecDefaults* findCodecDefaults(const std::string& name) @@ -90,38 +78,62 @@ static const CodecDefaults* findCodecDefaults(const std::string& name) // --------------------------------------------------------------------------- // Build CodecList::Settings for the requested codec // --------------------------------------------------------------------------- -static MT::CodecList::Settings buildSettings(const std::string& codecName, int pt, - int opusRate, int opusChannels) +static MT::CodecList::Settings buildSettings(const std::string& codecName, int pt, int opusRate, int opusChannels) { MT::CodecList::Settings s; - if (codecName == "opus") { + if (codecName == "opus") + { s.mOpusSpec.push_back(MT::CodecList::Settings::OpusSpec(pt, opusRate, opusChannels)); - } else if (codecName == "gsm") { + } + else if (codecName == "gsm") + { s.mGsmFrPayloadType = pt; - } else if (codecName == "gsmhr") { + } + else if (codecName == "gsmhr") + { s.mGsmHrPayloadType = pt; - } else if (codecName == "gsmefr") { + } + else if (codecName == "gsmefr") + { s.mGsmEfrPayloadType = pt; - } else if (codecName == "amrnb") { + } + else if (codecName == "amrnb") + { s.mAmrNbOctetPayloadType.insert(pt); - } else if (codecName == "amrwb") { + } + else if (codecName == "amrwb") + { s.mAmrWbOctetPayloadType.insert(pt); - } else if (codecName == "amrnb-bwe") { + } + else if (codecName == "amrnb-bwe") + { s.mAmrNbPayloadType.insert(pt); - } else if (codecName == "amrwb-bwe") { + } + else if (codecName == "amrwb-bwe") + { s.mAmrWbPayloadType.insert(pt); - } else if (codecName == "evs") { + } + else if (codecName == "evs") + { MT::CodecList::Settings::EvsSpec ev; ev.mPayloadType = pt; s.mEvsSpec.push_back(ev); - } else if (codecName == "ilbc20") { + } + else if (codecName == "ilbc20") + { s.mIlbc20PayloadType = pt; - } else if (codecName == "ilbc30") { + } + else if (codecName == "ilbc30") + { s.mIlbc30PayloadType = pt; - } else if (codecName == "isac16") { + } + else if (codecName == "isac16") + { s.mIsac16KPayloadType = pt; - } else if (codecName == "isac32") { + } + else if (codecName == "isac32") + { s.mIsac32KPayloadType = pt; } // pcmu, pcma, g722, g729 — fixed PT, auto-registered by CodecList::init() @@ -134,16 +146,18 @@ static MT::CodecList::Settings buildSettings(const std::string& codecName, int p // --------------------------------------------------------------------------- int main(int argc, char* argv[]) { - if (argc < 4) { + if (argc < 4) + { usage(argv[0]); return 1; } - const char* inputPath = argv[1]; + const char* inputPath = argv[1]; const char* outputPath = argv[2]; const char* codecArg = getOption(argc, argv, "--codec"); - if (!codecArg) { + if (!codecArg) + { fprintf(stderr, "Error: --codec is required\n\n"); usage(argv[0]); return 1; @@ -151,25 +165,29 @@ int main(int argc, char* argv[]) std::string codecName = codecArg; const auto* defaults = findCodecDefaults(codecName); - if (!defaults) { + if (!defaults) + { fprintf(stderr, "Error: unknown codec '%s'\n\n", codecArg); usage(argv[0]); return 1; } // Resolve payload type - int pt = defaults->defaultPt; + int pt = defaults->defaultPt; const char* ptArg = getOption(argc, argv, "--pt"); - if (ptArg) { + if (ptArg) + { pt = atoi(ptArg); - } else if (defaults->needsPt) { + } + else if (defaults->needsPt) + { fprintf(stderr, "Error: --pt is required for codec '%s'\n\n", codecArg); usage(argv[0]); return 1; } - int opusRate = 48000; - int opusChannels = 2; + int opusRate = 48000; + int opusChannels = 2; const char* rateArg = getOption(argc, argv, "--rate"); if (rateArg) opusRate = atoi(rateArg); @@ -181,14 +199,18 @@ int main(int argc, char* argv[]) // 1. Load rtpdump // ----------------------------------------------------------------------- RtpDump dump(inputPath); - try { + try + { dump.load(); - } catch (const std::exception& e) { + } + catch (const std::exception& e) + { fprintf(stderr, "Error loading rtpdump '%s': %s\n", inputPath, e.what()); return 1; } - if (dump.count() == 0) { + if (dump.count() == 0) + { fprintf(stderr, "No packets in '%s'\n", inputPath); return 1; } @@ -197,24 +219,25 @@ int main(int argc, char* argv[]) // ----------------------------------------------------------------------- // 2. Create codec // ----------------------------------------------------------------------- - auto settings = buildSettings(codecName, pt, opusRate, opusChannels); + auto settings = buildSettings(codecName, pt, opusRate, opusChannels); MT::CodecList codecList(settings); - MT::PCodec codec = codecList.createCodecByPayloadType(pt); - if (!codec) { + MT::PCodec codec = codecList.createCodecByPayloadType(pt); + if (!codec) + { fprintf(stderr, "Error: could not create codec for payload type %d\n", pt); return 1; } auto codecInfo = codec->info(); - fprintf(stderr, "Codec: %s samplerate=%d channels=%d pcmLength=%d frameTime=%dms\n", - codecInfo.mName.c_str(), codecInfo.mSamplerate, codecInfo.mChannels, - codecInfo.mPcmLength, codecInfo.mFrameTime); + fprintf(stderr, "Codec: %s samplerate=%d channels=%d pcmLength=%d frameTime=%dms\n", codecInfo.mName.c_str(), + codecInfo.mSamplerate, codecInfo.mChannels, codecInfo.mPcmLength, codecInfo.mFrameTime); // ----------------------------------------------------------------------- // 3. Open WAV writer // ----------------------------------------------------------------------- Audio::WavFileWriter writer; - if (!writer.open(outputPath, codecInfo.mSamplerate, codecInfo.mChannels)) { + if (!writer.open(outputPath, codecInfo.mSamplerate, codecInfo.mChannels)) + { fprintf(stderr, "Error: could not open WAV file '%s' for writing\n", outputPath); return 1; } @@ -223,15 +246,17 @@ int main(int argc, char* argv[]) // 4. Decode loop // ----------------------------------------------------------------------- std::vector pcmBuffer(65536); - size_t totalDecodedBytes = 0; - size_t packetsDecoded = 0; - size_t packetsSkipped = 0; + size_t totalDecodedBytes = 0; + size_t packetsDecoded = 0; + size_t packetsSkipped = 0; - for (size_t i = 0; i < dump.count(); ++i) { + for (size_t i = 0; i < dump.count(); ++i) + { const auto& rawData = dump.rawDataAt(i); // Verify it's actually RTP - if (!RtpHelper::isRtp(rawData.data(), rawData.size())) { + if (!RtpHelper::isRtp(rawData.data(), rawData.size())) + { ++packetsSkipped; continue; } @@ -240,31 +265,37 @@ int main(int argc, char* argv[]) jrtplib::RTPPacket& rtpPacket = dump.packetAt(i); // Check payload type matches what we expect - int pktPt = rtpPacket.GetPayloadType(); - if (pktPt != pt) { + int pktPt = rtpPacket.GetPayloadType(); + if (pktPt != pt) + { ++packetsSkipped; continue; } uint8_t* payloadData = rtpPacket.GetPayloadData(); - size_t payloadLen = rtpPacket.GetPayloadLength(); + size_t payloadLen = rtpPacket.GetPayloadLength(); - if (!payloadData || payloadLen == 0) { + if (!payloadData || payloadLen == 0) + { ++packetsSkipped; continue; } std::span input(payloadData, payloadLen); - std::span output(pcmBuffer.data(), pcmBuffer.size()); + std::span output(pcmBuffer.data(), pcmBuffer.size()); - try { + try + { auto result = codec->decode(input, output); - if (result.mDecoded > 0) { + if (result.mDecoded > 0) + { writer.write(pcmBuffer.data(), result.mDecoded); totalDecodedBytes += result.mDecoded; ++packetsDecoded; } - } catch (const std::exception& e) { + } + catch (const std::exception& e) + { fprintf(stderr, "Warning: decode error at packet %zu: %s\n", i, e.what()); ++packetsSkipped; } @@ -276,9 +307,7 @@ int main(int argc, char* argv[]) writer.close(); size_t totalSamples = totalDecodedBytes / (sizeof(int16_t) * codecInfo.mChannels); - double durationSec = (codecInfo.mSamplerate > 0) - ? static_cast(totalSamples) / codecInfo.mSamplerate - : 0.0; + double durationSec = (codecInfo.mSamplerate > 0) ? static_cast(totalSamples) / codecInfo.mSamplerate : 0.0; fprintf(stderr, "\nDone.\n"); fprintf(stderr, " Packets decoded: %zu\n", packetsDecoded);