diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bcd3a687..0a1cda18 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -91,7 +91,6 @@ set (RTPHONE_SOURCES ${rtphone_engine}/media/MT_AudioStream.cpp ${rtphone_engine}/media/MT_AudioReceiver.cpp ${rtphone_engine}/media/MT_AudioCodec.cpp - ${rtphone_engine}/media/MT_SevanaMos.cpp ${rtphone_engine}/media/MT_AmrCodec.cpp ${rtphone_engine}/media/MT_EvsCodec.cpp ${rtphone_engine}/media/MT_CngHelper.cpp @@ -120,7 +119,6 @@ set (RTPHONE_HEADERS ${rtphone_engine}/media/MT_AudioStream.h ${rtphone_engine}/media/MT_AudioReceiver.h ${rtphone_engine}/media/MT_AudioCodec.h - ${rtphone_engine}/media/MT_SevanaMos.h ${rtphone_engine}/media/MT_AmrCodec.h ${rtphone_engine}/media/MT_EvsCodec.h ${rtphone_engine}/media/MT_CngHelper.h diff --git a/src/engine/agent/Agent_Impl.cpp b/src/engine/agent/Agent_Impl.cpp index f7fd2bcd..39f6070b 100644 --- a/src/engine/agent/Agent_Impl.cpp +++ b/src/engine/agent/Agent_Impl.cpp @@ -4,12 +4,16 @@ #include "helper/HL_StreamState.h" #include "helper/HL_VariantMap.h" #include "helper/HL_CsvReader.h" - -#if defined(TARGET_ANDROID) -//# include "CAndroidSystemInfo.h" -#endif #include +#if defined(USE_PVQA_LIBRARY) +# include "pvqa++.h" +#endif + +#if defined(USE_AQUA_LIBRARY) +# include "aqua++.h" +#endif + const std::string Status_Ok = "ok"; const std::string Status_SessionNotFound = "session not found"; const std::string Status_AccountNotFound = "account not found"; @@ -18,566 +22,565 @@ const std::string Status_NoActiveProvider = "no active provider"; const std::string Status_NoMediaAction = "no valid media action"; const std::string Status_NoCommand = "no valid command"; - #define LOG_SUBSYSTEM "Agent" AgentImpl::AgentImpl() - :mShutdown(false), mEventListChangeCondVar() + :mShutdown(false), mEventListChangeCondVar() { #if defined(TARGET_ANDROID) || defined(TARGET_WIN) - ice::GLogger.useDebugWindow(true); + ice::GLogger.useDebugWindow(true); #endif - ice::GLogger.setLevel(ice::LogLevel::LL_DEBUG); + ice::GLogger.setLevel(ice::LogLevel::LL_DEBUG); } AgentImpl::~AgentImpl() { - stopAgentAndThread(); + stopAgentAndThread(); } void AgentImpl::run() { - while (!mShutdown) - { + while (!mShutdown) { - std::unique_lock l(mAgentMutex); - process(); + { + std::unique_lock l(mAgentMutex); + process(); + } + std::this_thread::sleep_for(std::chrono::milliseconds(10)); } - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - } } std::string AgentImpl::command(const std::string& command) { - if (command.empty()) - return ""; + if (command.empty()) + return ""; - Json::Value d, answer; - try - { - Json::Reader r; - if (!r.parse(command, d)) - return ""; + Json::Value d, answer; + try + { + Json::Reader r; + if (!r.parse(command, d)) + return ""; - std::string cmd = d["command"].asString(); + std::string cmd = d["command"].asString(); - 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") - 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; + 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") + 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; + } } - else - if (cmd == "attach_log") + catch(std::exception& e) { - GLogger.openFile(); - answer["status"] = Status_Ok; + answer["status"] = e.what(); } - else - if (cmd == "log_message") - processLogMessage(d, answer); - else - { - answer["status"] = Status_NoCommand; - } - } - catch(std::exception& e) - { - answer["status"] = e.what(); - } - return answer.toStyledString(); + return answer.toStyledString(); } -bool AgentImpl::waitForData(int milliseconds) +bool AgentImpl::waitForData(int /*milliseconds*/) { - return false; + return false; } std::string AgentImpl::read() { - return ""; + return ""; } void AgentImpl::processConfig(Json::Value &d, Json::Value &answer) { - std::unique_lock l(mAgentMutex); + std::unique_lock l(mAgentMutex); #if !defined(TARGET_ANDROID) && defined(USE_PVQA_LIBRARY) - // It works for desktop OSes only - // Because Android requires special initializing procedure (valid JNI environment context) - std::string pvqaLicense = d["pvqa-license"].asString(), pvqaConfig = d["pvqa-config"].asString(); - if (!pvqaLicense.empty() && !pvqaConfig.empty()) - MT::SevanaPVQA::initializeLibrary(pvqaLicense, pvqaConfig); + // It works for desktop OSes only + // Because Android requires special initializing procedure (valid JNI environment context) + std::string pvqaLicense = d["pvqa-license"].asString(), pvqaConfig = d["pvqa-config"].asString(); + if (!pvqaLicense.empty() && !pvqaConfig.empty()) + sevana::pvqa::initialize(pvqaLicense, pvqaConfig); #endif #if !defined(TARGET_ANDROID) && defined(USE_AQUA_LIBRARY) - std::string aquaLicense = d["aqua-license"].asString(); - if (!aquaLicense.empty()) - MT::SevanaAqua::initializeLibrary(aquaLicense); + std::string aquaLicense = d["aqua-license"].asString(); + if (!aquaLicense.empty()) + sevana::aqua::initializeLibrary(aquaLicense); #endif - std::string transport = d["transport"].asString(); - config()[CONFIG_TRANSPORT] = (transport == "any") ? 0 : (transport == "udp" ? 1 : (transport == "tcp" ? 2 : 3)); - config()[CONFIG_IPV4] = d["ipv4"].asBool(); - config()[CONFIG_IPV6] = d["ipv6"].asBool(); + std::string transport = d["transport"].asString(); + config()[CONFIG_TRANSPORT] = (transport == "any") ? 0 : (transport == "udp" ? 1 : (transport == "tcp" ? 2 : 3)); + config()[CONFIG_IPV4] = d["ipv4"].asBool(); + config()[CONFIG_IPV6] = d["ipv6"].asBool(); - // Log file - std::string logfile = d["logfile"].asString(); - ice::Logger& logger = ice::GLogger; - - logger.useFile(logfile.empty() ? nullptr : logfile.c_str()); - - config()[CONFIG_MULTIPLEXING] = true; - config()[CONFIG_DISPLAYNAME] = "Voip quality tester"; + // Log file + std::string logfile = d["logfile"].asString(); + ice::Logger& logger = ice::GLogger; - mUseNativeAudio = d["nativeaudio"].asBool(); - config()[CONFIG_OWN_DNS] = d["dns_servers"].asString(); - answer["status"] = Status_Ok; -} + logger.useFile(logfile.empty() ? nullptr : logfile.c_str()); -void AgentImpl::processStart(Json::Value &request, Json::Value &answer) -{ - std::unique_lock l(mAgentMutex); - if (mThread) - { + config()[CONFIG_MULTIPLEXING] = true; + config()[CONFIG_DISPLAYNAME] = "Voip quality tester"; + + mUseNativeAudio = d["nativeaudio"].asBool(); + config()[CONFIG_OWN_DNS] = d["dns_servers"].asString(); answer["status"] = Status_Ok; - return; // Started already - } - - // Start socket thread - SocketHeap::instance().start(); - - // Initialize terminal - MT::CodecList::Settings settings; - mTerminal = std::make_shared(settings); - - // Enable/disable codecs - PVariantMap priorityConfig = std::make_shared(); - MT::CodecList& cl = mTerminal->codeclist(); - for (int i=0; iat(i) = i; - else - priorityConfig->at(i) = -1; - - config()[CONFIG_CODEC_PRIORITY] = priorityConfig; - - // Enable audio - mAudioManager = std::make_shared(); - mAudioManager->setTerminal(mTerminal.get()); - - // Do not start here. Start right before call. - - // Initialize endpoint - start(); - - // Start worker thread - mShutdown = false; - mThread = std::make_shared(&AgentImpl::run, this); - answer["status"] = Status_Ok; } -void AgentImpl::processStop(Json::Value& request, Json::Value& answer) +void AgentImpl::processStart(Json::Value& /*request*/, Json::Value &answer) { - stopAgentAndThread(); - answer["status"] = Status_Ok; + std::unique_lock l(mAgentMutex); + if (mThread) + { + answer["status"] = Status_Ok; + return; // Started already + } + + // Start socket thread + SocketHeap::instance().start(); + + // Initialize terminal + MT::CodecList::Settings settings; + mTerminal = std::make_shared(settings); + + // Enable/disable codecs + PVariantMap priorityConfig = std::make_shared(); + MT::CodecList& cl = mTerminal->codeclist(); + for (int i=0; iat(i) = i; + else + priorityConfig->at(i) = -1; + + config()[CONFIG_CODEC_PRIORITY] = priorityConfig; + + // Enable audio + mAudioManager = std::make_shared(); + mAudioManager->setTerminal(mTerminal.get()); + + // Do not start here. Start right before call. + + // Initialize endpoint + start(); + + // Start worker thread + mShutdown = false; + mThread = std::make_shared(&AgentImpl::run, this); + answer["status"] = Status_Ok; +} + +void AgentImpl::processStop(Json::Value& /*request*/, Json::Value& answer) +{ + stopAgentAndThread(); + answer["status"] = Status_Ok; } void AgentImpl::processCreateAccount(Json::Value &d, Json::Value& answer) { - std::unique_lock l(mAgentMutex); - PVariantMap c = std::make_shared(); + std::unique_lock l(mAgentMutex); + PVariantMap c = std::make_shared(); - (*c)[CONFIG_USERNAME] = d["username"].asString(); - (*c)[CONFIG_PASSWORD] = d["password"].asString(); - (*c)[CONFIG_DOMAIN] = d["domain"].asString(); - (*c)[CONFIG_EXTERNALIP] = d["use_external_ip"].asBool(); + (*c)[CONFIG_USERNAME] = d["username"].asString(); + (*c)[CONFIG_PASSWORD] = d["password"].asString(); + (*c)[CONFIG_DOMAIN] = d["domain"].asString(); + (*c)[CONFIG_EXTERNALIP] = d["use_external_ip"].asBool(); - auto nameAndPort = StringHelper::parseHost(d["stun_server"].asString(), 3478); - (*c)[CONFIG_STUNSERVER_NAME] = nameAndPort.first; - (*c)[CONFIG_STUNSERVER_PORT] = nameAndPort.second; + auto nameAndPort = StringHelper::parseHost(d["stun_server"].asString(), 3478); + (*c)[CONFIG_STUNSERVER_NAME] = nameAndPort.first; + (*c)[CONFIG_STUNSERVER_PORT] = nameAndPort.second; - PAccount account = createAccount(c); - mAccountMap[account->id()] = account; - answer["account_id"] = account->id(); - answer["status"] = Status_Ok; + PAccount account = createAccount(c); + mAccountMap[account->id()] = account; + answer["account_id"] = account->id(); + answer["status"] = Status_Ok; } void AgentImpl::processStartAccount(Json::Value& request, Json::Value& answer) { - std::unique_lock l(mAgentMutex); - // Locate account in map - auto accountIter = mAccountMap.find(request["account_id"].asInt()); - if (accountIter != mAccountMap.end()) - { - accountIter->second->start(); - answer["status"] = Status_Ok; - } - else - answer["status"] = Status_AccountNotFound; + std::unique_lock l(mAgentMutex); + // Locate account in map + auto accountIter = mAccountMap.find(request["account_id"].asInt()); + if (accountIter != mAccountMap.end()) + { + accountIter->second->start(); + answer["status"] = Status_Ok; + } + else + answer["status"] = Status_AccountNotFound; } void AgentImpl::processSetUserInfoToAccount(Json::Value &request, Json::Value &answer) { - std::unique_lock l(mAgentMutex); - // Locate account in map - auto accountIter = mAccountMap.find(request["account_id"].asInt()); - if (accountIter != mAccountMap.end()) - { - Account::UserInfo info; - Json::Value& arg = request["userinfo"]; - std::vector keys = arg.getMemberNames(); - for (const std::string& k: keys) - info[k] = arg[k].asString(); - accountIter->second->setUserInfo(info); + std::unique_lock l(mAgentMutex); + // Locate account in map + auto accountIter = mAccountMap.find(request["account_id"].asInt()); + if (accountIter != mAccountMap.end()) + { + Account::UserInfo info; + Json::Value& arg = request["userinfo"]; + std::vector keys = arg.getMemberNames(); + for (const std::string& k: keys) + info[k] = arg[k].asString(); + accountIter->second->setUserInfo(info); - answer["status"] = Status_Ok; - } - else - answer["status"] = Status_AccountNotFound; + answer["status"] = Status_Ok; + } + else + answer["status"] = Status_AccountNotFound; } void AgentImpl::processCreateSession(Json::Value &request, Json::Value &answer) { - std::unique_lock l(mAgentMutex); - auto accountIter = mAccountMap.find(request["account_id"].asInt()); - if (accountIter != mAccountMap.end()) - { - PSession session = createSession(accountIter->second); - mSessionMap[session->id()] = session; - answer["session_id"] = session->id(); - answer["status"] = Status_Ok; - } - else - answer["status"] = Status_AccountNotFound; + std::unique_lock l(mAgentMutex); + auto accountIter = mAccountMap.find(request["account_id"].asInt()); + if (accountIter != mAccountMap.end()) + { + PSession session = createSession(accountIter->second); + mSessionMap[session->id()] = session; + answer["session_id"] = session->id(); + answer["status"] = Status_Ok; + } + else + answer["status"] = Status_AccountNotFound; } void AgentImpl::processStartSession(Json::Value& request, Json::Value& answer) { - std::unique_lock l(mAgentMutex); + std::unique_lock l(mAgentMutex); - // For debugging only - /*mIncomingAudioDump = std::make_shared(); + // For debugging only + /*mIncomingAudioDump = std::make_shared(); mIncomingAudioDump->open("incoming_dump", AUDIO_SAMPLERATE, AUDIO_CHANNELS); mOutgoingAudioDump = std::make_shared(); mOutgoingAudioDump->open("outgoing_dump", AUDIO_SAMPLERATE, AUDIO_CHANNELS);*/ - // Start audio manager - if (!mAudioManager) - { - // Agent was not started - ICELogError(<< "No audio manager installed."); - answer["status"] = "Audio manager not started. Most probably agent is not started."; - return; - } - - mAudioManager->start(mUseNativeAudio ? AudioManager::atReceiver : AudioManager::atNull); + // Start audio manager + if (!mAudioManager) + { + // Agent was not started + ICELogError(<< "No audio manager installed."); + answer["status"] = "Audio manager not started. Most probably agent is not started."; + return; + } - auto sessionIter = mSessionMap.find(request["session_id"].asInt()); - if (sessionIter != mSessionMap.end()) - { - // Ensure audio provider is here - PSession session = sessionIter->second; - PDataProvider audioProvider = std::make_shared(*this, *mTerminal); - audioProvider->setState(audioProvider->state() | (int)StreamState::Grabbing | (int)StreamState::Playing); + mAudioManager->start(mUseNativeAudio ? AudioManager::atReceiver : AudioManager::atNull); + + auto sessionIter = mSessionMap.find(request["session_id"].asInt()); + if (sessionIter != mSessionMap.end()) + { + // Ensure audio provider is here + PSession session = sessionIter->second; + PDataProvider audioProvider = std::make_shared(*this, *mTerminal); + audioProvider->setState(audioProvider->state() | static_cast(StreamState::Grabbing) | static_cast(StreamState::Playing)); #if defined(USE_AQUA_LIBRARY) - std::string temp_path = request["aqua_temp_path"].asString(); - 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"; - if (temp_path.size()) - config += " -fau " + temp_path; + std::string temp_path = request["aqua_temp_path"].asString(); + 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"; + if (temp_path.size()) + config += " -fau " + temp_path; - MT::PSevanaAqua qc = std::make_shared(); - qc->setTempPath(temp_path); - qc->configureWith(MT::SevanaAqua::parseConfig(config)); + MT::PSevanaAqua qc = std::make_shared(); + qc->setTempPath(temp_path); + qc->configureWith(MT::SevanaAqua::parseConfig(config)); - mAquaMap[sessionIter->first] = qc; - dynamic_cast(audioProvider.get())->configureMediaObserver(this, (void*)qc.get()); + mAquaMap[sessionIter->first] = qc; + dynamic_cast(audioProvider.get())->configureMediaObserver(this, (void*)qc.get()); #endif - // TODO: support SRTP via StreamState::Srtp option in audio provider state + // TODO: support SRTP via StreamState::Srtp option in audio provider state - // Get user headers - Session::UserHeaders info; - Json::Value& arg = request["userinfo"]; - std::vector keys = arg.getMemberNames(); - for (const std::string& k: keys) - info[k] = arg[k].asString(); - session->setUserHeaders(info); + // Get user headers + Session::UserHeaders info; + Json::Value& arg = request["userinfo"]; + std::vector keys = arg.getMemberNames(); + for (const std::string& k: keys) + info[k] = arg[k].asString(); + session->setUserHeaders(info); - session->addProvider(audioProvider); - session->start(request["target"].asString()); - answer["status"] = Status_Ok; - } - else - { - answer["status"] = Status_SessionNotFound; - } + session->addProvider(audioProvider); + session->start(request["target"].asString()); + answer["status"] = Status_Ok; + } + else + { + answer["status"] = Status_SessionNotFound; + } } void AgentImpl::processStopSession(Json::Value& request, Json::Value& answer) { - std::unique_lock l(mAgentMutex); + std::unique_lock l(mAgentMutex); - auto sessionIter = mSessionMap.find(request["session_id"].asInt()); - if (sessionIter != mSessionMap.end()) - { - PSession session = sessionIter->second; - session->stop(); - answer["status"] = Status_Ok; - } - else - answer["status"] = Status_SessionNotFound; + auto sessionIter = mSessionMap.find(request["session_id"].asInt()); + if (sessionIter != mSessionMap.end()) + { + PSession session = sessionIter->second; + session->stop(); + answer["status"] = Status_Ok; + } + else + answer["status"] = Status_SessionNotFound; } void AgentImpl::processAcceptSession(Json::Value& request, Json::Value& answer) { - std::unique_lock l(mAgentMutex); - auto sessionIter = mSessionMap.find(request["session_id"].asInt()); - if (sessionIter != mSessionMap.end()) - { - // Ensure audio manager is here - mAudioManager->start(mUseNativeAudio ? AudioManager::atReceiver : AudioManager::atNull); + std::unique_lock l(mAgentMutex); + auto sessionIter = mSessionMap.find(request["session_id"].asInt()); + if (sessionIter != mSessionMap.end()) + { + // Ensure audio manager is here + mAudioManager->start(mUseNativeAudio ? AudioManager::atReceiver : AudioManager::atNull); - // Accept session on SIP level - PSession session = sessionIter->second; + // Accept session on SIP level + PSession session = sessionIter->second; - // Get user headers - Session::UserHeaders info; - Json::Value& arg = request["userinfo"]; - std::vector keys = arg.getMemberNames(); - for (const std::string& k: keys) - info[k] = arg[k].asString(); - session->setUserHeaders(info); + // Get user headers + Session::UserHeaders info; + Json::Value& arg = request["userinfo"]; + std::vector keys = arg.getMemberNames(); + for (const std::string& k: keys) + info[k] = arg[k].asString(); + session->setUserHeaders(info); - // Accept finally - session->accept(); + // Accept finally + session->accept(); - answer["status"] = Status_Ok; - } - else - answer["status"] = Status_SessionNotFound; + answer["status"] = Status_Ok; + } + else + answer["status"] = Status_SessionNotFound; } void AgentImpl::processDestroySession(Json::Value& request, Json::Value& answer) { - std::unique_lock l(mAgentMutex); + std::unique_lock l(mAgentMutex); - int sessionId = request["session_id"].asInt(); - auto sessionIter = mSessionMap.find(sessionId); - if (sessionIter != mSessionMap.end()) - mSessionMap.erase(sessionIter); + int sessionId = request["session_id"].asInt(); + auto sessionIter = mSessionMap.find(sessionId); + if (sessionIter != mSessionMap.end()) + mSessionMap.erase(sessionIter); #if defined(USE_AQUA_LIBRARY) - auto aquaIter = mAquaMap.find(sessionId); - if (aquaIter != mAquaMap.end()) - mAquaMap.erase(aquaIter); + auto aquaIter = mAquaMap.find(sessionId); + if (aquaIter != mAquaMap.end()) + mAquaMap.erase(aquaIter); #endif - answer["status"] = Status_Ok; + answer["status"] = Status_Ok; } void AgentImpl::processWaitForEvent(Json::Value &request, Json::Value &answer) { - std::unique_lock l(mAgentMutex); + std::unique_lock l(mAgentMutex); - //int x = 0; - //int y = 1/x; - - int timeout = request["timeout"].asInt(); - std::unique_lock eventLock(mEventListMutex); - if (mEventList.empty()) - mEventListChangeCondVar.wait_for(eventLock, chrono::milliseconds(timeout)); + //int x = 0; + //int y = 1/x; - if (!mEventList.empty()) - { - answer = mEventList.front(); - mEventList.erase(mEventList.begin()); - } - answer["status"] = Status_Ok; + int timeout = request["timeout"].asInt(); + std::unique_lock eventLock(mEventListMutex); + if (mEventList.empty()) + mEventListChangeCondVar.wait_for(eventLock, chrono::milliseconds(timeout)); + + if (!mEventList.empty()) + { + answer = mEventList.front(); + mEventList.erase(mEventList.begin()); + } + answer["status"] = Status_Ok; } #if defined(USE_PVQA_LIBRARY) static Json::Value CsvReportToJson(const std::string& report) { - Json::Value detectorValues; - std::istringstream iss(report); - CsvReader reader(iss); - std::vector cells; - if (reader.readLine(cells)) - { - Json::Value detectorNames; - for (int nameIndex = 0; nameIndex < (int)cells.size(); nameIndex++) - detectorNames[nameIndex] = StringHelper::trim(cells[nameIndex]); - // Put first line name of columns - detectorValues[0] = detectorNames; - - int rowIndex = 1; - while (reader.readLine(cells)) + Json::Value detectorValues; + std::istringstream iss(report); + CsvReader reader(iss); + std::vector cells; + if (reader.readLine(cells)) { - // Skip last column for now - Json::Value row; - for (int valueIndex = 0; valueIndex < (int)cells.size(); valueIndex++) - { - bool isFloat = true; - float v = StringHelper::toFloat(cells[valueIndex], 0.0, &isFloat); - if (isFloat) - row[valueIndex] = v; - else - row[valueIndex] = cells[valueIndex]; - } - detectorValues[rowIndex++] = row; + Json::Value detectorNames; + for (size_t nameIndex = 0; nameIndex < cells.size(); nameIndex++) + detectorNames[static_cast(nameIndex)] = StringHelper::trim(cells[nameIndex]); + // Put first line name of columns + detectorValues[0] = detectorNames; + + int rowIndex = 1; + while (reader.readLine(cells)) + { + // Skip last column for now + Json::Value row; + for (size_t valueIndex = 0; valueIndex < cells.size(); valueIndex++) + { + bool isFloat = true; + float v = StringHelper::toFloat(cells[valueIndex], 0.0, &isFloat); + if (isFloat) + row[static_cast(valueIndex)] = static_cast(v); + else + row[static_cast(valueIndex)] = cells[valueIndex]; + } + detectorValues[rowIndex++] = row; + } } - } - return detectorValues; + return detectorValues; } #endif void AgentImpl::processGetMediaStats(Json::Value& request, Json::Value& answer) { - std::unique_lock l(mAgentMutex); - int sessionId = request["session_id"].asInt(); - SessionMap::iterator sessionIter = mSessionMap.find(sessionId); - if (sessionIter != mSessionMap.end()) - { - PSession session = sessionIter->second; - VariantMap result; - bool includePvqa = request["include_pvqa"].asBool(); -#if defined(USE_AQUA_LIBRARY) - bool includeAqua = request["include_aqua"].asBool(); - std::string aquaReference = request["aqua_reference_audio"].asString(); -#endif - session->getSessionInfo(includePvqa ? Session::InfoOptions::Detailed : Session::InfoOptions::Standard, - result); - - if (result.exists(SessionInfo_AudioCodec)) - answer["codec"] = result[SessionInfo_AudioCodec].asStdString(); - if (result.exists(SessionInfo_NetworkMos)) - answer["network_mos"] = result[SessionInfo_NetworkMos].asFloat(); -#if defined(USE_PVQA_LIBRARY) - if (result.exists(SessionInfo_PvqaMos)) - answer["pvqa_mos"] = result[SessionInfo_PvqaMos].asFloat(); - if (result.exists(SessionInfo_PvqaReport)) - answer["pvqa_report"] = CsvReportToJson(result[SessionInfo_PvqaReport].asStdString()); -#endif - if (result.exists(SessionInfo_PacketLoss)) - answer["rtp_lost"] = result[SessionInfo_LostRtp].asInt(); - if (result.exists(SessionInfo_SentRtp)) - answer["rtp_sent"] = result[SessionInfo_SentRtp].asInt(); - if (result.exists(SessionInfo_ReceivedRtp)) - answer["rtp_received"] = result[SessionInfo_ReceivedRtp].asInt(); - if (result.exists(SessionInfo_Duration)) - answer["duration"] = result[SessionInfo_Duration].asInt(); - if (result.exists(SessionInfo_Jitter)) - answer["jitter"] = result[SessionInfo_Jitter].asFloat() * 1000; // Take milliseconds - if (result.exists(SessionInfo_Rtt)) - answer["rtt"] = result[SessionInfo_Rtt].asFloat(); - if (result.exists(SessionInfo_BitrateSwitchCounter)) - answer["bitrate_switch_counter"] = result[SessionInfo_BitrateSwitchCounter].asInt(); - if (result.exists(SessionInfo_SSRC)) - answer["rtp_ssrc"] = result[SessionInfo_SSRC].asInt(); - if (result.exists(SessionInfo_RemotePeer)) - answer["rtp_remotepeer"] = result[SessionInfo_RemotePeer].asStdString(); - -#if defined(USE_AQUA_LIBRARY) - if (includeAqua) + std::unique_lock l(mAgentMutex); + int sessionId = request["session_id"].asInt(); + SessionMap::iterator sessionIter = mSessionMap.find(sessionId); + if (sessionIter != mSessionMap.end()) { - ByteBuffer referenceAudio; - // Read AQuA reference audio from file if available - if (!aquaReference.empty()) - { - Audio::WavFileReader reader; - reader.open(StringHelper::makeTstring(aquaReference)); + PSession session = sessionIter->second; + VariantMap result; + bool includePvqa = request["include_pvqa"].asBool(); +#if defined(USE_AQUA_LIBRARY) + bool includeAqua = request["include_aqua"].asBool(); + std::string aquaReference = request["aqua_reference_audio"].asString(); +#endif + session->getSessionInfo(includePvqa ? Session::InfoOptions::Detailed : Session::InfoOptions::Standard, + result); - if (reader.isOpened()) + if (result.exists(SessionInfo_AudioCodec)) + answer["codec"] = result[SessionInfo_AudioCodec].asStdString(); + if (result.exists(SessionInfo_NetworkMos)) + answer["network_mos"] = result[SessionInfo_NetworkMos].asFloat(); +#if defined(USE_PVQA_LIBRARY) + if (result.exists(SessionInfo_PvqaMos)) + answer["pvqa_mos"] = result[SessionInfo_PvqaMos].asFloat(); + if (result.exists(SessionInfo_PvqaReport)) + answer["pvqa_report"] = CsvReportToJson(result[SessionInfo_PvqaReport].asStdString()); +#endif + if (result.exists(SessionInfo_PacketLoss)) + answer["rtp_lost"] = result[SessionInfo_LostRtp].asInt(); + if (result.exists(SessionInfo_SentRtp)) + answer["rtp_sent"] = result[SessionInfo_SentRtp].asInt(); + if (result.exists(SessionInfo_ReceivedRtp)) + answer["rtp_received"] = result[SessionInfo_ReceivedRtp].asInt(); + if (result.exists(SessionInfo_Duration)) + answer["duration"] = result[SessionInfo_Duration].asInt(); + if (result.exists(SessionInfo_Jitter)) + answer["jitter"] = result[SessionInfo_Jitter].asFloat() * 1000; // Take milliseconds + if (result.exists(SessionInfo_Rtt)) + answer["rtt"] = result[SessionInfo_Rtt].asFloat(); + if (result.exists(SessionInfo_BitrateSwitchCounter)) + answer["bitrate_switch_counter"] = result[SessionInfo_BitrateSwitchCounter].asInt(); + if (result.exists(SessionInfo_SSRC)) + answer["rtp_ssrc"] = result[SessionInfo_SSRC].asInt(); + if (result.exists(SessionInfo_RemotePeer)) + answer["rtp_remotepeer"] = result[SessionInfo_RemotePeer].asStdString(); + +#if defined(USE_AQUA_LIBRARY) + if (includeAqua) { - char buffer[1024]; - int wasRead = 0; - do - { - wasRead = reader.read(buffer, 1024); - if (wasRead > 0) - referenceAudio.appendBuffer(buffer, wasRead); - } - while (wasRead == 1024); + ByteBuffer referenceAudio; + // Read AQuA reference audio from file if available + if (!aquaReference.empty()) + { + Audio::WavFileReader reader; + reader.open(StringHelper::makeTstring(aquaReference)); + + if (reader.isOpened()) + { + char buffer[1024]; + int wasRead = 0; + do + { + wasRead = reader.read(buffer, 1024); + if (wasRead > 0) + referenceAudio.appendBuffer(buffer, wasRead); + } + while (wasRead == 1024); + } + } + MT::PSevanaAqua sa = mAquaMap[sessionIter->first]; + MT::SevanaAqua::AudioBuffer test(mAquaIncoming.data(), mAquaIncoming.size()), + reference(referenceAudio.data(), referenceAudio.size()); + test.mRate = AUDIO_SAMPLERATE; reference.mRate = AUDIO_SAMPLERATE; + test.mChannels = AUDIO_CHANNELS; reference.mChannels = AUDIO_CHANNELS; + + MT::SevanaAqua::CompareResult r = sa->compare(reference, test); + answer["aqua_mos"] = r.mMos; + + if (r.mFaults) + { + Json::Value json(r.mReport); + Json::Value faults = r.mFaults->toJson(); + json["faults"] = faults; + answer["aqua_report"] = json.toStyledString(); + } + else + answer["aqua_report"] = r.mReport; } - } - MT::PSevanaAqua sa = mAquaMap[sessionIter->first]; - MT::SevanaAqua::AudioBuffer test(mAquaIncoming.data(), mAquaIncoming.size()), - reference(referenceAudio.data(), referenceAudio.size()); - test.mRate = AUDIO_SAMPLERATE; reference.mRate = AUDIO_SAMPLERATE; - test.mChannels = AUDIO_CHANNELS; reference.mChannels = AUDIO_CHANNELS; - - MT::SevanaAqua::CompareResult r = sa->compare(reference, test); - answer["aqua_mos"] = r.mMos; - - if (r.mFaults) - { - Json::Value json(r.mReport); - Json::Value faults = r.mFaults->toJson(); - json["faults"] = faults; - answer["aqua_report"] = json.toStyledString(); - } - else - answer["aqua_report"] = r.mReport; - } #endif - answer["status"] = Status_Ok; - } - else - answer["status"] = Status_SessionNotFound; + answer["status"] = Status_Ok; + } + else + answer["status"] = Status_SessionNotFound; } -void AgentImpl::processNetworkChanged(Json::Value& request, Json::Value& answer) +void AgentImpl::processNetworkChanged(Json::Value& /*request*/, Json::Value& /*answer*/) { - std::unique_lock l(mAgentMutex); + std::unique_lock l(mAgentMutex); } const std::string BeginCertificate = "-----BEGIN CERTIFICATE-----"; @@ -585,170 +588,170 @@ const std::string EndCertificate = "-----END CERTIFICATE-----"; void AgentImpl::processAddRootCert(Json::Value& request, Json::Value& answer) { - std::unique_lock l(mAgentMutex); - std::string pem = request["cert"].asString(); + std::unique_lock l(mAgentMutex); + std::string pem = request["cert"].asString(); - std::string::size_type pb = 0, pe = 0; + std::string::size_type pb = 0, pe = 0; - for(pb = pem.find(BeginCertificate, pb), pe = pem.find(EndCertificate, pe); - pb != std::string::npos && pe != std::string::npos; - pb = pem.find(BeginCertificate, pb + BeginCertificate.size()), pe = pem.find(EndCertificate, pe + EndCertificate.size())) - { - // Get single certificate - std::string cert = pem.substr(pb, pe + EndCertificate.size()); - int size = cert.size(); - addRootCert(ByteBuffer(cert.c_str(), cert.size())); - - // Delete processed part - pem.erase(0, pe + EndCertificate.size()); - } + for(pb = pem.find(BeginCertificate, pb), pe = pem.find(EndCertificate, pe); + pb != std::string::npos && pe != std::string::npos; + pb = pem.find(BeginCertificate, pb + BeginCertificate.size()), pe = pem.find(EndCertificate, pe + EndCertificate.size())) + { + // Get single certificate + std::string cert = pem.substr(pb, pe + EndCertificate.size()); + //int size = cert.size(); + addRootCert(ByteBuffer(cert.c_str(), cert.size())); - answer["status"] = Status_Ok; + // Delete processed part + pem.erase(0, pe + EndCertificate.size()); + } + + answer["status"] = Status_Ok; } void AgentImpl::processLogMessage(Json::Value &request, Json::Value &answer) { - int level = request["level"].asInt(); - std::string message = request["message"].asString(); + int level = request["level"].asInt(); + std::string message = request["message"].asString(); - ICELog((ice::LogLevel)level, "App", << message); + ICELog(static_cast(level), "App", << message); - answer["status"] = Status_Ok; + answer["status"] = Status_Ok; } void AgentImpl::stopAgentAndThread() { - // Stop user agent - std::unique_lock l(mAgentMutex); - try - { - stop(); - } - catch (...) - {} - - // Stop worker thread - if (mThread) - { - mShutdown = true; - if (mThread->joinable()) + // Stop user agent + std::unique_lock l(mAgentMutex); + try { - l.unlock(); - mThread->join(); - l.lock(); + stop(); } - mThread.reset(); - } + catch (...) + {} - // Close used audio - if (mAudioManager) - { - // Ensure audio manager is stopped - mAudioManager->stop(mUseNativeAudio ? AudioManager::atReceiver : AudioManager::atNull); + // Stop worker thread + if (mThread) + { + mShutdown = true; + if (mThread->joinable()) + { + l.unlock(); + mThread->join(); + l.lock(); + } + mThread.reset(); + } - // Free audio manager - mAudioManager.reset(); - } + // Close used audio + if (mAudioManager) + { + // Ensure audio manager is stopped + mAudioManager->stop(mUseNativeAudio ? AudioManager::atReceiver : AudioManager::atNull); - // Close terminal after audio manager - because audio manager has reference to terminal - mTerminal.reset(); + // Free audio manager + mAudioManager.reset(); + } - SocketHeap::instance().stop(); + // Close terminal after audio manager - because audio manager has reference to terminal + mTerminal.reset(); + + SocketHeap::instance().stop(); } void AgentImpl::processUseStreamForSession(Json::Value& request, Json::Value& answer) { - std::unique_lock l(mAgentMutex); - SessionMap::iterator sessionIter = mSessionMap.find(request["session_id"].asInt()); - if (sessionIter != mSessionMap.end()) - { - // Extract ptr to session - PSession session = sessionIter->second; - - // Parse command - 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(); - - // Try to open file - AudioProvider* prov = session->findProviderForActiveAudio(); - if (prov) + std::unique_lock l(mAgentMutex); + SessionMap::iterator sessionIter = mSessionMap.find(request["session_id"].asInt()); + if (sessionIter != mSessionMap.end()) { - if (actionText == "read") - { - if (path.empty()) + // Extract ptr to session + PSession session = sessionIter->second; + + // Parse command + 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(); + + // Try to open file + AudioProvider* prov = session->findProviderForActiveAudio(); + if (prov) { - // Turn off playing into the stream - prov->readFile(Audio::PWavFileReader(), direction); - answer["status"] = Status_Ok; + if (actionText == "read") + { + if (path.empty()) + { + // Turn off playing into the stream + prov->readFile(Audio::PWavFileReader(), direction); + answer["status"] = Status_Ok; + } + else + { + Audio::PWavFileReader reader = std::make_shared(); + if (!reader->open(StringHelper::makeTstring(path))) + answer["status"] = Status_FailedToOpenFile; + else + { + prov->readFile(reader, direction); + answer["status"] = Status_Ok; + } + } + } + else + if (actionText == "write") + { + 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(StringHelper::makeTstring(path), AUDIO_SAMPLERATE, AUDIO_CHANNELS)) + answer["status"] = Status_FailedToOpenFile; + else + { + prov->writeFile(writer, direction); + answer["status"] = Status_Ok; + } + } + } + else + if (actionText == "mirror") + { + prov->setupMirror(request["enable"].asBool()); + answer["status"] = Status_Ok; + } + else + answer["status"] = Status_AccountNotFound; } else - { - Audio::PWavFileReader reader = std::make_shared(); - if (!reader->open(StringHelper::makeTstring(path))) - answer["status"] = Status_FailedToOpenFile; - else - { - prov->readFile(reader, direction); - answer["status"] = Status_Ok; - } - } - } - else - if (actionText == "write") - { - 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(StringHelper::makeTstring(path), AUDIO_SAMPLERATE, AUDIO_CHANNELS)) - answer["status"] = Status_FailedToOpenFile; - else - { - prov->writeFile(writer, direction); - answer["status"] = Status_Ok; - } - } - } - else - if (actionText == "mirror") - { - prov->setupMirror(request["enable"].asBool()); - answer["status"] = Status_Ok; - } - else - answer["status"] = Status_AccountNotFound; + answer["status"] = Status_NoMediaAction; } - else - answer["status"] = Status_NoMediaAction; - } } #if defined(USE_AQUA_LIBRARY) void AgentImpl::onMedia(const void* data, int length, MT::Stream::MediaDirection direction, void* context, void* userTag) { -/* if (mIncomingAudioDump && direction == MT::Stream::MediaDirection::Incoming) + /* if (mIncomingAudioDump && direction == MT::Stream::MediaDirection::Incoming) mIncomingAudioDump->write(data, length); if (mOutgoingAudioDump && direction == MT::Stream::MediaDirection::Outgoing) mOutgoingAudioDump->write(data, length);*/ - // User tag points to accumulator object which includes - MT::SevanaAqua* sa = reinterpret_cast(userTag); + // User tag points to accumulator object which includes + MT::SevanaAqua* sa = reinterpret_cast(userTag); - switch (direction) - { - case MT::Stream::MediaDirection::Incoming: mAquaIncoming.appendBuffer(data, length); break; - case MT::Stream::MediaDirection::Outgoing: mAquaOutgoing.appendBuffer(data, length); break; - } + switch (direction) + { + case MT::Stream::MediaDirection::Incoming: mAquaIncoming.appendBuffer(data, length); break; + case MT::Stream::MediaDirection::Outgoing: mAquaOutgoing.appendBuffer(data, length); break; + } } #endif @@ -758,151 +761,151 @@ void AgentImpl::onMedia(const void* data, int length, MT::Stream::MediaDirection PDataProvider AgentImpl::onProviderNeeded(const std::string& name) { - EVENT_WITH_NAME("provider_needed"); - v["provider_name"] = name; - addEvent(v); + EVENT_WITH_NAME("provider_needed"); + v["provider_name"] = name; + addEvent(v); - return PDataProvider(new AudioProvider(*this, *mTerminal)); + return PDataProvider(new AudioProvider(*this, *mTerminal)); } // Called on new session offer void AgentImpl::onNewSession(PSession s) { - EVENT_WITH_NAME("session_incoming"); - v["session_id"] = s->id(); - v["remote_peer"] = s->remoteAddress(); - mSessionMap[s->id()] = s; + EVENT_WITH_NAME("session_incoming"); + v["session_id"] = s->id(); + v["remote_peer"] = s->remoteAddress(); + mSessionMap[s->id()] = s; - addEvent(v); + addEvent(v); } // Called when session is terminated void AgentImpl::onSessionTerminated(PSession s, int responsecode, int reason) { - /*if (mIncomingAudioDump) + /*if (mIncomingAudioDump) mIncomingAudioDump->close(); if (mOutgoingAudioDump) mOutgoingAudioDump->close(); */ - mAudioManager->stop(mUseNativeAudio ? AudioManager::atReceiver : AudioManager::atNull); - // Gather statistics before - EVENT_WITH_NAME("session_terminated"); - v["session_id"] = s->id(); - v["error_code"] = responsecode; - v["reason_code"] = reason; - addEvent(v); + mAudioManager->stop(mUseNativeAudio ? AudioManager::atReceiver : AudioManager::atNull); + // Gather statistics before + EVENT_WITH_NAME("session_terminated"); + v["session_id"] = s->id(); + v["error_code"] = responsecode; + v["reason_code"] = reason; + addEvent(v); } // 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 void AgentImpl::onSessionEstablished(PSession s, int conntype, const RtpPair& p) { - EVENT_WITH_NAME("session_established"); - v["session_id"] = s->id(); - v["conn_type"] = conntype == EV_SIP ? "sip" : "ice"; - if (conntype == EV_ICE) - v["media_target"] = p.mRtp.toStdString(); + EVENT_WITH_NAME("session_established"); + v["session_id"] = s->id(); + v["conn_type"] = conntype == EV_SIP ? "sip" : "ice"; + if (conntype == EV_ICE) + v["media_target"] = p.mRtp.toStdString(); - addEvent(v); + addEvent(v); } void AgentImpl::onSessionProvisional(PSession s, int code) { - EVENT_WITH_NAME("session_provisional"); - v["session_id"] = s->id(); - v["code"] = code; - addEvent(v); + EVENT_WITH_NAME("session_provisional"); + v["session_id"] = s->id(); + v["code"] = code; + addEvent(v); } // Called when user agent started void AgentImpl::onStart(int errorcode) { - EVENT_WITH_NAME("agent_started"); - v["error_code"] = errorcode; - addEvent(v); + EVENT_WITH_NAME("agent_started"); + v["error_code"] = errorcode; + addEvent(v); } // Called when user agent stopped void AgentImpl::onStop() { - EVENT_WITH_NAME("agent_stopped"); - addEvent(v); + EVENT_WITH_NAME("agent_stopped"); + addEvent(v); } // Called when account registered void AgentImpl::onAccountStart(PAccount account) { - EVENT_WITH_NAME("account_started"); - v["account_id"] = account->id(); - addEvent(v); + EVENT_WITH_NAME("account_started"); + v["account_id"] = account->id(); + addEvent(v); } // Called when account removed or failed (non zero error code) void AgentImpl::onAccountStop(PAccount account, int error) { - EVENT_WITH_NAME("account_stopped"); - v["account_id"] = account->id(); - v["error_code"] = error; - addEvent(v); + EVENT_WITH_NAME("account_stopped"); + v["account_id"] = account->id(); + v["error_code"] = error; + addEvent(v); } // Called when connectivity checks failed. void AgentImpl::onConnectivityFailed(PSession s) { - EVENT_WITH_NAME("session_connectivity_failed"); - v["session_id"] = s->id(); - addEvent(v); + EVENT_WITH_NAME("session_connectivity_failed"); + v["session_id"] = s->id(); + addEvent(v); } // Called when new candidate is gathered void AgentImpl::onCandidateGathered(PSession s, const char* address) { - EVENT_WITH_NAME("session_candidate_gathered"); - v["session_id"] = s->id(); - v["address"] = address; - addEvent(v); + EVENT_WITH_NAME("session_candidate_gathered"); + v["session_id"] = s->id(); + v["address"] = address; + addEvent(v); } // Called when network change detected void AgentImpl::onNetworkChange(PSession s) { - EVENT_WITH_NAME("session_network_changed"); - v["session_id"] = s->id(); - addEvent(v); + EVENT_WITH_NAME("session_network_changed"); + v["session_id"] = s->id(); + addEvent(v); } // Called when all candidates are gathered void AgentImpl::onGathered(PSession s) { - EVENT_WITH_NAME("session_candidates_gathered"); - v["session_id"] = s->id(); - addEvent(v); + EVENT_WITH_NAME("session_candidates_gathered"); + v["session_id"] = s->id(); + addEvent(v); } // Called when new connectivity check is finished void AgentImpl::onCheckFinished(PSession s, const char* description) { - EVENT_WITH_NAME("session_conncheck_finished"); - v["session_id"] = s->id(); - v["description"] = description; - addEvent(v); + EVENT_WITH_NAME("session_conncheck_finished"); + v["session_id"] = s->id(); + v["description"] = description; + addEvent(v); } // 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() { - EVENT_WITH_NAME("sip_connection_failed"); - addEvent(v); + EVENT_WITH_NAME("sip_connection_failed"); + addEvent(v); } void AgentImpl::addEvent(const Json::Value& v) { - std::unique_lock lock(mEventListMutex); - mEventList.push_back(v); - mEventListChangeCondVar.notify_one(); + std::unique_lock lock(mEventListMutex); + mEventList.push_back(v); + mEventListChangeCondVar.notify_one(); } diff --git a/src/engine/helper/HL_SocketHeap.cpp b/src/engine/helper/HL_SocketHeap.cpp index f8cf7e07..22ef3f1d 100644 --- a/src/engine/helper/HL_SocketHeap.cpp +++ b/src/engine/helper/HL_SocketHeap.cpp @@ -1,4 +1,4 @@ -/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com) +/* Copyright(C) 2007-2019 VoIP objects (voipobjects.com) * 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/. */ @@ -29,6 +29,10 @@ #endif +// ----------------------------- SocketSink ------------------------- +SocketSink::~SocketSink() +{} + // ----------------------------- SocketHeap ------------------------- SocketHeap::SocketHeap(unsigned short start, unsigned short finish) @@ -132,7 +136,7 @@ PDatagramSocket SocketHeap::allocSocket(int family, SocketSink* sink, int port) // Obtain port number sockaddr_in addr; sockaddr_in6 addr6; - int result; + int result = 0; int testport; do { @@ -144,7 +148,7 @@ PDatagramSocket SocketHeap::allocSocket(int family, SocketSink* sink, int port) memset(&addr, 0, sizeof addr); addr.sin_family = AF_INET; addr.sin_port = htons(testport); - result = ::bind(sock, (const sockaddr*)&addr, sizeof addr); + result = ::bind(sock, reinterpret_cast(&addr), sizeof addr); if (result) result = WSAGetLastError(); break; @@ -153,7 +157,7 @@ PDatagramSocket SocketHeap::allocSocket(int family, SocketSink* sink, int port) memset(&addr6, 0, sizeof addr6); addr6.sin6_family = AF_INET6; addr6.sin6_port = htons(testport); - result = ::bind(sock, (const sockaddr*)&addr6, sizeof addr6); + result = ::bind(sock, reinterpret_cast(&addr6), sizeof addr6); if (result) result = WSAGetLastError(); break; diff --git a/src/engine/helper/HL_SocketHeap.h b/src/engine/helper/HL_SocketHeap.h index 1100182f..d68182ec 100644 --- a/src/engine/helper/HL_SocketHeap.h +++ b/src/engine/helper/HL_SocketHeap.h @@ -11,11 +11,7 @@ #include #include -#ifdef USE_RESIP_INTEGRATION -# include "resiprocate/rutil/ThreadIf.hxx" -#else -# include -#endif +#include #include "HL_NetworkSocket.h" #include "HL_Sync.h" @@ -25,91 +21,92 @@ class SocketSink { public: - virtual void onReceivedData(PDatagramSocket socket, InternetAddress& src, const void* receivedPtr, unsigned receivedSize) = 0; + virtual ~SocketSink(); + 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 class SocketHeap { public: - enum Multiplex - { - DoMultiplexing, - DontMultiplexing - }; + enum Multiplex + { + DoMultiplexing, + DontMultiplexing + }; - SocketHeap(unsigned short start, unsigned short finish); - virtual ~SocketHeap(); + 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); + // Specifies ne\ port number range. The sockets will be allocated in range [start..finish] + void setRange(unsigned short start, unsigned short finish); - // Returns used port number range - 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); + // Returns used port number range + void range(unsigned short& start, unsigned short& finish); - // Stops receiving data for specified socket and frees socket itself. - void freeSocket(PDatagramSocket socket); - void freeSocketPair(const RtpPair& p); + // 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); + + // Sends data to specified address on specified socket. + void sendData(DatagramSocket& socket, InternetAddress& dest, const void* dataPtr, int dataSize); - // Sends data to specified address on specified socket. - void sendData(DatagramSocket& socket, InternetAddress& dest, const void* dataPtr, int dataSize); - protected: - struct SocketItem - { - // Local port number for socket - PDatagramSocket mSocket; - - // Data sink pointer - SocketSink* mSink; - - SocketItem() - :mSink(NULL) - { } + struct SocketItem + { + // Local port number for socket + PDatagramSocket mSocket; - SocketItem(unsigned short portnumber, SocketSink* sink) - :mSink(sink) - { - mSocket->mLocalPort = portnumber; - } - - ~SocketItem() - { } - }; + // Data sink pointer + SocketSink* mSink; - typedef std::map SocketMap; - typedef std::vector PortVector; - typedef std::vector SocketVector; + SocketItem() + :mSink(nullptr) + { } - Mutex mGuard; - SocketMap mSocketMap; - PortVector mPortVector; - unsigned short mStart, - mFinish; - SocketVector mDeleteVector; - Mutex mDeleteGuard; + SocketItem(unsigned short portnumber, SocketSink* sink) + :mSink(sink) + { + mSocket->mLocalPort = portnumber; + } - char mTempPacket[MAX_UDPPACKET_SIZE]; + ~SocketItem() + { } + }; + + typedef std::map SocketMap; + typedef std::vector PortVector; + typedef std::vector SocketVector; + + Mutex mGuard; + SocketMap mSocketMap; + PortVector mPortVector; + unsigned short mStart, + mFinish; + SocketVector mDeleteVector; + Mutex mDeleteGuard; + + char mTempPacket[MAX_UDPPACKET_SIZE]; std::shared_ptr mWorkerThread; - std::thread::id mThreadId; + std::thread::id mThreadId; bool mShutdown = false; bool isShutdown() const { return mShutdown; } void thread(); - - // Processes mDeleteVector -> updates mSocketMap, removes socket items and closes sockets specified in mDeleteVector - void processDeleted(); + + // Processes mDeleteVector -> updates mSocketMap, removes socket items and closes sockets specified in mDeleteVector + void processDeleted(); }; diff --git a/src/engine/helper/HL_VariantMap.cpp b/src/engine/helper/HL_VariantMap.cpp index f7cc6f44..518869a0 100644 --- a/src/engine/helper/HL_VariantMap.cpp +++ b/src/engine/helper/HL_VariantMap.cpp @@ -16,13 +16,13 @@ Variant::Variant() { - mType = VTYPE_INT; - mInt = 0; - mInt64 = 0; - mBool = 0; - mFloat = 0; - - mPointer = nullptr; + mType = VTYPE_INT; + mInt = 0; + mInt64 = 0; + mBool = 0; + mFloat = 0; + + mPointer = nullptr; } Variant::~Variant() @@ -30,315 +30,319 @@ Variant::~Variant() } Variant::Variant(bool value) - :mType(VTYPE_BOOL), mBool(value) + :mType(VTYPE_BOOL), mBool(value) {} Variant::Variant(int value) - :mType(VTYPE_INT), mInt(value) + :mType(VTYPE_INT), mInt(value) {} Variant::Variant(int64_t value) - :mType(VTYPE_INT64), mInt64(value) + :mType(VTYPE_INT64), mInt64(value) {} Variant::Variant(float value) - :mType(VTYPE_FLOAT), mFloat(value) + :mType(VTYPE_FLOAT), mFloat(value) {} Variant::Variant(double value) - :mType(VTYPE_FLOAT), mFloat((float)value) + :mType(VTYPE_FLOAT), mFloat((float)value) {} Variant::Variant(const std::string& value) - :mType(VTYPE_STRING), mString(value) + :mType(VTYPE_STRING), mString(value) {} Variant& Variant::operator = (bool value) { - mType = VTYPE_BOOL; - mBool = value; + mType = VTYPE_BOOL; + mBool = value; - return *this; + return *this; } Variant& Variant::operator = (int value) { - mType = VTYPE_INT; - mInt = value; + mType = VTYPE_INT; + mInt = value; - return *this; + return *this; } Variant& Variant::operator = (int64_t value) { - mType = VTYPE_INT64; - mInt64 = value; + mType = VTYPE_INT64; + mInt64 = value; - return *this; + return *this; } Variant& Variant::operator = (float value) { - mType = VTYPE_FLOAT; - mFloat = value; + mType = VTYPE_FLOAT; + mFloat = value; - return *this; + return *this; } Variant& Variant::operator = (const std::string& value) { - mType = VTYPE_STRING; - mString = value; + mType = VTYPE_STRING; + mString = value; - return *this; + return *this; } Variant& Variant::operator = (const char* value) { - mType = VTYPE_STRING; - mString = value; + mType = VTYPE_STRING; + mString = value; - return *this; + return *this; } Variant& Variant::operator = (void* value) { - mType = VTYPE_POINTER; - mPointer = value; + mType = VTYPE_POINTER; + mPointer = value; - return *this; + return *this; } Variant& Variant::operator = (PVariantMap map) { - mType = VTYPE_VMAP; - mVMap = map; + mType = VTYPE_VMAP; + mVMap = map; - return *this; + return *this; } 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(); - default: - return false; - } + 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(); + default: + return false; + } } 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(); + 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(); - default: - return false; - } + default: + return false; + } } 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(); - default: - return false; - } + 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(); + default: + return false; + } } 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(); + 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(); - default: - return false; - } + default: + return false; + } } bool Variant::operator < (const Variant& rhs) const { - switch (type()) - { - 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(); - default: - return false; - } + switch (type()) + { + 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(); + default: + return false; + } } bool Variant::operator > (const Variant& rhs) const { - return !(*this == rhs) && !(*this < rhs); + return !(*this == rhs) && !(*this < rhs); } 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; - default: - return false; - } + 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; + default: + return false; + } - return false; + return false; } bool Variant::operator != (const Variant& rhs) const { - return !(*this == rhs); + return !(*this == rhs); } bool Variant::operator <= (const Variant& rhs) const { - return (*this < rhs) || (*this == rhs); + return (*this < rhs) || (*this == rhs); } bool Variant::operator >= (const Variant& rhs) const { - return (*this > rhs) || (*this == rhs); + return (*this > rhs) || (*this == rhs); } int Variant::asInt() const { - if (mType != VTYPE_INT) - throw Exception(ERR_BAD_VARIANT_TYPE); - - return mInt; + if (mType != VTYPE_INT) + throw Exception(ERR_BAD_VARIANT_TYPE); + + return mInt; } int64_t Variant::asInt64() const { - if (mType != VTYPE_INT64) - throw Exception(ERR_BAD_VARIANT_TYPE); + if (mType != VTYPE_INT64) + throw Exception(ERR_BAD_VARIANT_TYPE); - return mInt; + return mInt; } bool Variant::asBool() const { - switch (mType) - { - case VTYPE_INT: - return mInt != 0; + switch (mType) + { + case VTYPE_INT: + return mInt != 0; - case VTYPE_INT64: - return mInt64 != 0; + case VTYPE_INT64: + return mInt64 != 0; - case VTYPE_BOOL: - return mBool; + case VTYPE_BOOL: + return mBool; - case VTYPE_FLOAT: - return mFloat != 0; + case VTYPE_FLOAT: + return mFloat != 0; - case VTYPE_STRING: - return mString.length() != 0; + case VTYPE_STRING: + return mString.length() != 0; - default: - throw Exception(ERR_BAD_VARIANT_TYPE); - } + default: + throw Exception(ERR_BAD_VARIANT_TYPE); + } } float Variant::asFloat() const { - switch (mType) - { - case VTYPE_INT: - return (float)mInt; + switch (mType) + { + case VTYPE_INT: + return (float)mInt; - case VTYPE_INT64: - return (float)mInt64; + case VTYPE_INT64: + return (float)mInt64; - case VTYPE_FLOAT: - return mFloat; + case VTYPE_FLOAT: + return mFloat; - default: - throw Exception(ERR_BAD_VARIANT_TYPE); - } + default: + throw Exception(ERR_BAD_VARIANT_TYPE); + } } +double Variant::asDouble() const +{ + return static_cast(asFloat()); +} std::string Variant::asStdString() const { - char buffer[32]; - switch (mType) - { - case VTYPE_STRING: - return mString; - - case VTYPE_INT: - sprintf(buffer, "%d", mInt); - return buffer; + char buffer[32]; + switch (mType) + { + case VTYPE_STRING: + return mString; - case VTYPE_INT64: - sprintf(buffer, "%lli", static_cast(mInt64)); - return buffer; + case VTYPE_INT: + sprintf(buffer, "%d", mInt); + return buffer; - case VTYPE_BOOL: - return mBool ? "true" : "false"; + case VTYPE_INT64: + sprintf(buffer, "%lli", static_cast(mInt64)); + return buffer; - case VTYPE_FLOAT: - sprintf(buffer, "%f", mFloat); - return buffer; + case VTYPE_BOOL: + return mBool ? "true" : "false"; - default: - throw Exception(ERR_BAD_VARIANT_TYPE); - } + case VTYPE_FLOAT: + sprintf(buffer, "%f", mFloat); + return buffer; + + default: + throw Exception(ERR_BAD_VARIANT_TYPE); + } } void* Variant::asPointer() const { - switch (mType) - { - case VTYPE_POINTER: - return mPointer; - default: - throw Exception(ERR_BAD_VARIANT_TYPE); - } + switch (mType) + { + case VTYPE_POINTER: + return mPointer; + default: + throw Exception(ERR_BAD_VARIANT_TYPE); + } } PVariantMap Variant::asVMap() { - switch (mType) - { - case VTYPE_VMAP: - return mVMap; - default: - throw Exception(ERR_BAD_VARIANT_TYPE); - } + switch (mType) + { + case VTYPE_VMAP: + return mVMap; + default: + throw Exception(ERR_BAD_VARIANT_TYPE); + } } VariantType Variant::type() const { - return mType; + return mType; } VariantMap::VariantMap() @@ -351,25 +355,25 @@ VariantMap::~VariantMap() bool VariantMap::empty() const { - return mData.empty(); + return mData.empty(); } void VariantMap::clear() { - mData.clear(); + mData.clear(); } bool VariantMap::exists(int itemId) const { - return mData.find(itemId) != mData.end(); + return mData.find(itemId) != mData.end(); } Variant& VariantMap::operator [](int itemId) { - return mData[itemId]; + return mData[itemId]; } Variant& VariantMap::at(int itemId) { - return mData[itemId]; + return mData[itemId]; } diff --git a/src/engine/helper/HL_VariantMap.h b/src/engine/helper/HL_VariantMap.h index 26827a40..706dcde2 100644 --- a/src/engine/helper/HL_VariantMap.h +++ b/src/engine/helper/HL_VariantMap.h @@ -60,7 +60,8 @@ public: int asInt() const; int64_t asInt64() const; bool asBool() const; - float asFloat() const ; + float asFloat() const; + double asDouble() const; std::string asStdString() const; //const char* asString(); void* asPointer() const; diff --git a/src/engine/media/MT_AudioReceiver.h b/src/engine/media/MT_AudioReceiver.h index f96fef23..66b31f3b 100644 --- a/src/engine/media/MT_AudioReceiver.h +++ b/src/engine/media/MT_AudioReceiver.h @@ -22,11 +22,6 @@ #include -#if defined(USE_PVQA_LIBRARY) -# include "MT_SevanaMos.h" -#endif - - // #define DUMP_DECODED namespace MT diff --git a/src/engine/media/MT_SevanaMos.cpp b/src/engine/media/MT_SevanaMos.cpp deleted file mode 100644 index 1300c54a..00000000 --- a/src/engine/media/MT_SevanaMos.cpp +++ /dev/null @@ -1,991 +0,0 @@ -#define NOMINMAX - -//#include "config.h" -#include "MT_SevanaMos.h" - -#if defined(USE_PVQA_LIBRARY) - -#if defined(TARGET_SERVER) -# include -#endif - -#include "../engine/helper/HL_Log.h" -#include "../engine/helper/HL_CsvReader.h" -#include "../engine/helper/HL_String.h" -#include "../engine/audio/Audio_WavFile.h" - -#include -#include -#include -#include -#include -#include - -#if defined(TARGET_SERVER) -extern std::string IntervalCacheDir; -#endif - -#define LOG_SUBSYSTEM "Sevana" - -#define PVQA_ECHO_DETECTOR_NAME "ECHO" -//#define PVQA_ECHO_DETECTOR_NAME "EchoM-00" - -namespace MT { - -#if !defined(MOS_BEST_COLOR) -# define MOS_BEST_COLOR 0x11FF11 -# define MOS_BAD_COLOR 0x000000 -#endif - -#if defined(TARGET_WIN) -# define popen _popen -# define pclose _pclose -#endif - -static std::string execCommand(const std::string& cmd) -{ - std::cout << cmd << "\n"; - - std::shared_ptr pipe(popen(cmd.c_str(), "r"), pclose); - if (!pipe) - throw std::runtime_error("Failed to run."); - - char buffer[1024]; - std::string result = ""; - while (!feof(pipe.get())) - { - if (fgets(buffer, 1024, pipe.get()) != nullptr) - result += buffer; - } - return result; -} - - -// -------------- SevanaMosUtility -------------- -void SevanaMosUtility::run(const std::string& pcmPath, const std::string& intervalPath, - std::string& estimation, std::string& intervals) -{ -/* -#if defined(TARGET_SERVER) - path sevana = current_path() / "sevana"; -#if defined(TARGET_LINUX) || defined(TARGET_OSX) - path exec = sevana / "pvqa"; -#else - path exec = sevana / "pvqa.exe"; -#endif - path lic = sevana / "pvqa.lic"; - path cfg = sevana / "settings.cfg"; - - estimation.clear(); - char cmdbuffer[1024]; - sprintf(cmdbuffer, "%s %s analysis %s %s %s 0.799", exec.string().c_str(), lic.string().c_str(), - intervalPath.c_str(), cfg.string().c_str(), pcmPath.c_str()); - std::string output = execCommand(cmdbuffer); - - //ICELogDebug(<< "Got PVQA analyzer output: " << output); - - std::string line; - std::istringstream is(output); - while (std::getline(is, line)) - { - std::string::size_type mosPosition = line.find("MOS = "); - if ( mosPosition != std::string::npos) - { - estimation = line.substr(mosPosition + 6); - boost::algorithm::trim(estimation); - } - } - - if (!estimation.size()) - { - // Dump utility output if estimation failed - ICELogError(<< "PVQA failed with message: " << output); - return; - } - - // Read intervals report file - if (boost::filesystem::exists(intervalPath) && !estimation.empty()) - { - std::ifstream t(intervalPath); - std::string str((std::istreambuf_iterator(t)), - std::istreambuf_iterator()); - intervals = str; - } -#endif -*/ - - -} - -float getSevanaMos(const std::string& audioPath, const std::string& intervalReportPath, - std::string& intervalReport) -{ - return 0.0f; - /* - // Find Sevana MOS estimation - ICELogDebug( << "Running MOS utitlity on resulted PCM file " << audioPath ); - try - { - std::string buffer; - SevanaMosUtility::run(audioPath, intervalReportPath, buffer, intervalReport); - ICELogDebug( << "MOS utility is finished on PCM file " << audioPath ); - return (float)atof(buffer.c_str()); - } - catch(std::exception& e) - { - ICELogError( << "MOS utility failed on PCM file " << audioPath << ". Error msg: " << e.what() ); - return 0.0; - }*/ -} - -// ------------------- SevanaPVQA ------------------- -void* SevanaPVQA::mLibraryConfiguration = nullptr; -int SevanaPVQA::mLibraryErrorCode = 0; -std::atomic_int SevanaPVQA::mInstanceCounter; -std::atomic_uint_least64_t SevanaPVQA::mAllProcessedMilliseconds; -bool SevanaPVQA::mPvqaLoaded = false; - -std::string SevanaPVQA::getVersion() -{ - return PVQA_GetVersion(); -} - -#if defined(TARGET_ANDROID) -void SevanaPVQA::setupAndroidEnvironment(void *environment, void *appcontext) -{ - PVQA_SetupAndroidEnvironment(environment, appcontext); -} -#endif - -bool SevanaPVQA::initializeLibrary(const std::string& pathToLicenseFile, const std::string& pathToConfigFile) -{ - mPvqaLoaded = false; - - ICELogInfo(<< "Sevana PVQA is about to be initialized."); - - // Initialize PVQA library - if (!mLibraryConfiguration) - { - mInstanceCounter = 0; - mLibraryErrorCode = PVQA_InitLib(const_cast(pathToLicenseFile.c_str())); - if (mLibraryErrorCode) - { - ICELogError(<< "Problem when initializing PVQA library. Error code: " << mLibraryErrorCode - << ". Path to license file is " << pathToLicenseFile - << ". Path to config file is " << pathToConfigFile); - return false; - } - - if (pathToConfigFile.size()) - { - mLibraryConfiguration = PVQA_LoadCFGFile(const_cast(pathToConfigFile.c_str()), &mLibraryErrorCode); - if (!mLibraryConfiguration) - { - PVQA_ReleaseLib(); - ICELogError(<< "Problem with PVQA configuration file."); - return false; - } - } - mPvqaLoaded = true; - } - return true; -} - -bool SevanaPVQA::initializeLibraryWithData(const void* license_buffer, size_t license_len, - const void* config_buffer, size_t config_len) -{ - mPvqaLoaded = false; -#if defined(OLD_PVQA) - return false; -#else - ICELogInfo(<< "Sevana PVQA is about to be initialized via byte buffers."); - - // Initialize PVQA library - if (!mLibraryConfiguration) - { - mInstanceCounter = 0; - mLibraryErrorCode = PVQA_InitLibWithLicData(license_buffer, license_len); - if (mLibraryErrorCode) - { - ICELogError(<< "Problem when initializing PVQA library. Error code: " << mLibraryErrorCode); - return false; - } - - if (config_buffer && config_len) - { - mLibraryConfiguration = PVQA_LoadCFGData(config_buffer, config_len, &mLibraryErrorCode); - if (!mLibraryConfiguration) - { - PVQA_ReleaseLib(); - ICELogError(<< "Problem with PVQA configuration file."); - return false; - } - } - mPvqaLoaded = true; - } - return true; -#endif -} - -bool SevanaPVQA::isInitialized() -{ - return mPvqaLoaded; -} - -int SevanaPVQA::getLibraryError() -{ - return mLibraryErrorCode; -} - -void SevanaPVQA::releaseLibrary() -{ - PVQA_ReleaseLib(); -} - -SevanaPVQA::SevanaPVQA() -{ -} - -SevanaPVQA::~SevanaPVQA() -{ - close(); -} - -void SevanaPVQA::open(double interval, Model model) -{ - if (!isInitialized()) - { - ICELogError(<< "PVQA library is not initialized."); - return; - } - - if (mOpenFailed) - { - ICELogError(<< "Open failed already, reject this attempt."); - return; - } - - if (mContext) - { - ICELogError(<< "Already opened (context is not nullptr)."); - return; - } - - ICELogDebug(<<"Attempt to create PVQA instance."); - mProcessedSamples = 0; - mModel = model; - mIntervalLength = interval; - mAudioLineInitialized = false; - - mContext = PVQA_CreateAudioQualityAnalyzer(mLibraryConfiguration); - if (!mContext) - { - ICELogError(<< "Failed to create PVQA instance. Instance counter: " << mInstanceCounter); - mOpenFailed = true; - return; - } - - mInstanceCounter++; - - int rescode = 0; - rescode = PVQA_AudioQualityAnalyzerSetIntervalLength(mContext, interval); - if (rescode) - { - ICELogError(<< "Failed to set interval length on PVQA instance. Result code: " << rescode); - close(); - mOpenFailed = true; - return; - } - - if (mModel == Model::Stream) - { - rescode = PVQA_OnStartStreamData(mContext); - if (rescode) - { - ICELogError(<< "Failed to start streaming analysis on PVQA instance. Result code: " << rescode); - close(); - mOpenFailed = true; - return; - } - } - ICELogDebug(<<"PVQA instance is created. Instance counter: " << mInstanceCounter); -} - -void SevanaPVQA::close() -{ - if (mContext) - { - ICELogDebug(<< "Attempt to destroy PVQA instance."); - PVQA_ReleaseAudioQualityAnalyzer(mContext); - mInstanceCounter--; - ICELogDebug(<< "PVQA instance destroyed. Current instance counter: " << mInstanceCounter); - mContext = nullptr; - mOpenFailed = false; - } -} - -bool SevanaPVQA::isOpen() const -{ - return mContext != nullptr; -} - -void SevanaPVQA::update(int samplerate, int channels, const void *pcmBuffer, int pcmLength) -{ - if (!mContext) - { - ICELogError(<< "No PVQA context."); - return; - } - - - // Model is assert here as it can be any if context is not created. - assert (mModel == Model::Stream); - - TPVQA_AudioItem item; - item.dNChannels = channels; - item.dSampleRate = samplerate; - item.dNSamples = pcmLength / 2 / channels; - item.pSamples = (short*)pcmBuffer; - int rescode = PVQA_OnAddStreamAudioData(mContext, &item); - if (rescode) - { - ICELogError(<< "Failed to stream data to PVQA instance. Result code: " << rescode); - } - - - int milliseconds = pcmLength / 2 / channels / (samplerate / 1000); - mProcessedMilliseconds += milliseconds; - mAllProcessedMilliseconds += milliseconds; -} - -SevanaPVQA::DetectorsList SevanaPVQA::getDetectorsNames(const std::string& report) -{ - DetectorsList result; - - if (!report.empty()) - { - std::istringstream iss(report); - CsvReader reader(iss); - reader.readLine(result.mNames); - result.mStartIndex = 2; - - // Remove first columns - if (result.mStartIndex < (int)result.mNames.size() - 1) - { - result.mNames.erase(result.mNames.begin(), result.mNames.begin() + result.mStartIndex); - - // Remove last column - result.mNames.erase(result.mNames.begin() + result.mNames.size() - 1); - - for (auto& name: result.mNames) - name = StringHelper::trim(name); - } - } - return result; -} - -float SevanaPVQA::getResults(std::string& report, EchoData** echo, int samplerate, Codec codec) -{ - if (!mContext) - { - ICELogError(<< "No PVQA context."); - return 0.0; - } - - if (mModel == Model::Stream) - { - if (mProcessedMilliseconds == 0) - { - ICELogError(<< "No audio in PVQA."); - return -1; - } - - if (PVQA_OnFinalizeStream(mContext, (long)samplerate)) - { - ICELogError(<< "Failed to finalize results from PVQA."); - return -1; - } - ICELogInfo(<< "Processed " << mProcessedMilliseconds << " milliseconds."); - } - - TPVQA_Results results; - if (PVQA_FillQualityResultsStruct(mContext, &results)) - { - ICELogError(<< "Failed to get results from PVQA."); - return -1; - } - - int reportLength = PVQA_GetQualityStringSize(mContext); - if (reportLength) - { - char* buffer = (char*)alloca(reportLength + 1); - if (PVQA_FillQualityString(mContext, buffer)) - { - ICELogError(<< "Failed to fill intervals report."); - } - else - report = buffer; - } - -#if defined(TARGET_LINUX) && defined(PVQA_WITH_ECHO_DATA) - if (mModel == SevanaPVQA::Model::Stream && echo) - { - // Return echo detector counters - // Get list of names for echo detector - for debugging only - std::vector names; - int errCode = 0; - const char** iNames = (const char **)PVQA_GetProcessorValuesNamesList(mContext, PVQA_ECHO_DETECTOR_NAME, &errCode); - if (!errCode && iNames) - { - int nameIndex = 0; - for(const char * locName = iNames[nameIndex]; locName; locName = iNames[++nameIndex]) - names.push_back(locName); - - // Get values for echo detector - PVQA_Array2D* array = PVQA_GetProcessorValuesList(mContext, PVQA_ECHO_DETECTOR_NAME, 0, mProcessedMilliseconds, "values", &errCode); - if (array) - { - *echo = new std::vector>(); - for (int r = 0; r < array->rows; r++) - { - std::vector row; - for (int c = 0; c < array->columns; c++) - row.push_back(array->data[r * array->columns + c]); - (*echo)->push_back(row); - } - PVQA_ReleaseArray2D(array); array = nullptr; - } - // For debugging only - /*if (*echo) - { - for (const auto& row: **echo) - { - std::cout << "<"; - for (const auto& v: row) - std::cout << v << " "; - std::cout << ">" << std::endl; - } - }*/ - // No need to delete maxValues - it will be deleted on PVQA analyzer context freeing. - } - } -#endif - - // Limit maximal value of MOS depending on codec - float result = (float)results.dMOSLike; - float mv = 5.0f; - switch (codec) - { - case Codec::G711: mv = 4.1f; break; - case Codec::G729: mv = 3.92f; break; - default: - mv = 5.0; - } - - return std::min(result, mv); -} - -void SevanaPVQA::setPathToDumpFile(const std::string& path) -{ - mDumpWavPath = path; -} - -float SevanaPVQA::process(int samplerate, int channels, const void *pcmBuffer, int pcmLength, std::string &report, Codec codec) -{ - //std::cout << "Sent " << pcmLength << " bytes of audio to analyzer." << std::endl; - assert (mModel == Model::Interval); - if (!mContext) - return 0.0; - - /*if (!mAudioLineInitialized) - { - mAudioLineInitialized = true; - if (PVQA_AudioQualityAnalyzerCreateDelayLine(mContext, samplerate, channels, 20)) - ICELogError(<< "Failed to create delay line."); - }*/ - - TPVQA_AudioItem item; - item.dNChannels = channels; - item.dSampleRate = samplerate; - item.dNSamples = pcmLength / 2 / channels; - item.pSamples = (short*)pcmBuffer; - - //std::cout << "Sending chunk of audio with rate = " << samplerate << ", channels = " << channels << ", number of samples " << item.dNSamples << std::endl; - - /* - if (!mDumpWavPath.empty()) - { - WavFileWriter writer; - writer.open(mDumpWavPath, samplerate, channels); - writer.write(item.pSamples, item.dNSamples * 2 * channels); - writer.close(); - ICELogError(<< "Sending chunk of audio with rate = " << samplerate << ", channels = " << channels << ", number of samples " << item.dNSamples); - } - */ - int code = PVQA_OnTestAudioData(mContext, &item); - if (code) - { - ICELogError(<< "Failed to run PVQA on audio buffer with code " << code); - return 0.0; - } - - /* - if (item.pSamples != pcmBuffer || item.dNSamples != pcmLength / 2 / channels || item.dSampleRate != samplerate || item.dNChannels != channels) - { - ICELogError(<< "PVQA changed input parameters!!!!"); - } - */ - // Increase counter of processed samples - mProcessedSamples += pcmLength / channels / 2; - - int milliseconds = pcmLength / channels / 2 / (samplerate / 1000); - mProcessedMilliseconds += milliseconds; - - // Overall counter - mAllProcessedMilliseconds += milliseconds; - - // Get results - return getResults(report, nullptr, samplerate, codec); -} - -struct RgbColor -{ - uint8_t mRed = 0; - uint8_t mGreen = 0; - uint8_t mBlue = 0; - - static RgbColor parse(uint32_t rgb) - { - RgbColor result; - result.mBlue = (uint8_t)(rgb & 0xff); - result.mGreen = (uint8_t)((rgb >> 8) & 0xff); - result.mRed = (uint8_t)((rgb >> 16) & 0xff); - return result; - } - - std::string toHex() const - { - char result[7]; - sprintf(result, "%02x%02x%02x", int(mRed), int(mGreen), int(mBlue)); - return std::string(result); - } -}; - -int SevanaPVQA::getSize() const -{ - int result = 0; - result += sizeof(*this); - - // TODO: add PVQA analyzer size - return result; -} - - -std::string SevanaPVQA::mosToColor(float mos) -{ - // Limit MOS value by 5.0 - mos = mos > 5.0f ? 5.0f : mos; - mos = mos < 1.0f ? 1.0f : mos; - - // Split to components - RgbColor start = RgbColor::parse(MOS_BEST_COLOR), end = RgbColor::parse(MOS_BAD_COLOR); - - float mosFraction = (mos - 1.0f) / 4.0f; - - end.mBlue += (uint8_t)((start.mBlue - end.mBlue) * mosFraction); - end.mGreen += (uint8_t)((start.mGreen - end.mGreen) * mosFraction); - end.mRed += (uint8_t)((start.mRed - end.mRed) * mosFraction); - - return end.toHex(); -} - -} // end of namespace MT -#endif - -#if defined(USE_AQUA_LIBRARY) - -#include -#include "helper/HL_String.h" -#include -#include - -namespace MT -{ - -int SevanaAqua::initializeLibrary(const std::string& pathToLicenseFile) -{ - //char buffer[pathToLicenseFile.length() + 1]; - //strcpy(buffer, pathToLicenseFile.c_str()); - return SSA_InitLib(const_cast(pathToLicenseFile.data())); -} - - -int SevanaAqua::initializeLibrary(const void* buffer, size_t len) -{ - return SSA_InitLibWithData(buffer, len); -} - -void SevanaAqua::releaseLibrary() -{ - SSA_ReleaseLib(); -} - -std::string SevanaAqua::FaultsReport::toText() const -{ - std::ostringstream oss; - - if (mSignalAdvancedInMilliseconds > -4999.0) - oss << "Signal advanced in milliseconds: " << mSignalAdvancedInMilliseconds << std::endl; - if (mMistimingInPercents > -4999.0) - oss << "Mistiming in percents: " << mMistimingInPercents << std::endl; - - for (ResultMap::const_iterator resultIter = mResultMap.begin(); resultIter != mResultMap.end(); resultIter++) - { - oss << resultIter->first << ":\t\t\t" << resultIter->second.mSource << " : \t" << resultIter->second.mDegrated << " \t" << resultIter->second.mUnit << std::endl; - } - - return oss.str(); -} - -Json::Value SevanaAqua::FaultsReport::toJson() const -{ - std::ostringstream oss; - Json::Value result; - - result["Mistiming"] = mMistimingInPercents; - result["SignalAdvanced"] = mSignalAdvancedInMilliseconds; - Json::Value items; - for (ResultMap::const_iterator resultIter = mResultMap.begin(); resultIter != mResultMap.end(); resultIter++) - { - Json::Value item; - item["name"] = resultIter->first; - item["source"] = resultIter->second.mSource; - item["degrated"] = resultIter->second.mDegrated; - item["unit"] = resultIter->second.mUnit; - - items.append(item); - } - - result["items"] = items; - - return result; -} - -std::string SevanaAqua::getVersion() -{ - TSSA_AQuA_Info* info = SSA_GetPAQuAInfo(); - if (info) - return info->dVersionString; - - return ""; -} - -SevanaAqua::SevanaAqua() -{ - open(); -} - -SevanaAqua::~SevanaAqua() -{ - close(); -} - -void SevanaAqua::open() -{ - std::unique_lock l(mMutex); - if (mContext) - return; - - mContext = SSA_CreateAudioQualityAnalyzer(); - if (!mContext) - ; - - //setParam("OutputFormats", "json"); -} - -void SevanaAqua::close() -{ - std::unique_lock l(mMutex); - if (!mContext) - return; - SSA_ReleaseAudioQualityAnalyzer(mContext); - mContext = nullptr; -} - -bool SevanaAqua::isOpen() const -{ - return mContext != nullptr; -} - -void SevanaAqua::setTempPath(const std::string& temp_path) -{ - mTempPath = temp_path; -} - -std::string SevanaAqua::getTempPath() const -{ - return mTempPath; -} - -SevanaAqua::CompareResult SevanaAqua::compare(AudioBuffer& reference, AudioBuffer& test) -{ - // Clear previous temporary file - if (!mTempPath.empty()) - ::remove(mTempPath.c_str()); - - // Result value - CompareResult r; - - std::unique_lock l(mMutex); - - if (!mContext || !reference.isInitialized() || !test.isInitialized()) - return r; - - // Make analysis - TSSA_AQuA_AudioData aad; - aad.dSrcData.dNChannels = reference.mChannels; - aad.dSrcData.dSampleRate = reference.mRate; - aad.dSrcData.pSamples = (short*)reference.mData->data(); - aad.dSrcData.dNSamples = (long)reference.mData->size() / 2 / reference.mChannels; - - aad.dTstData.dNChannels = test.mChannels; - aad.dTstData.dSampleRate = test.mRate; - aad.dTstData.pSamples = (short*)test.mData->data(); - aad.dTstData.dNSamples = (long)test.mData->size() / 2 / test.mChannels; - - int rescode; - rescode = SSA_OnTestAudioData(mContext, &aad); - if (rescode) - return r; - - // Get results - - int len = SSA_GetQualityStringSize(mContext); - char* qs = (char*)alloca(len + 10); - SSA_FillQualityString(mContext, qs); - //std::cout << qs << std::endl; - std::istringstream iss(qs); - while (!iss.eof()) - { - std::string l; - std::getline(iss, l); - - // Split by : - std::vector p; - StringHelper::split(l, p, "\t"); - if (p.size() == 3) - { - p[1] = StringHelper::trim(p[1]); - p[2] = StringHelper::trim(p[2]); - r.mReport[p[1]] = p[2]; - } - } - - len = SSA_GetSrcSignalSpecSize(mContext); - float* srcSpecs = new float[len]; - SSA_FillSrcSignalSpecArray(mContext, srcSpecs); - Json::Value src_spec_signal; - - for(int i=0; i<16 && i 0) { - faults_str = new char[faults_str_len + 1]; - SSA_FillFaultsAnalysisString(mContext, faults_str); - faults_str[faults_str_len] = 0; - } - } - - char* pairs_str = nullptr; - int pairs_str_len = SSA_GetSpecPairsStringSize(mContext); - if (pairs_str_len > 0) - { - char *pairs_str = new char[pairs_str_len + 1]; - SSA_FillSpecPairsString(mContext, pairs_str, pairs_str_len); - pairs_str[pairs_str_len] = 0; - } - - TSSA_AQuA_Results iResults; - SSA_FillQualityResultsStruct(mContext, &iResults); - r.mReport["dPercent"] = iResults.dPercent; - r.mReport["dMOSLike"] = iResults.dMOSLike; - - if (faults_str_len > 0) - { - std::istringstream iss(faults_str); - r.mFaults = loadFaultsReport(iss); - } - else - if (!mTempPath.empty()) - { - std::ifstream ifs(mTempPath.c_str()); - r.mFaults = loadFaultsReport(ifs); - } - - delete[] faults_str; faults_str = nullptr; - delete[] pairs_str; pairs_str = nullptr; - - r.mMos = (float)iResults.dMOSLike; - - return r; -} - -void SevanaAqua::configureWith(const Config& config) -{ - if (!mContext) - return; - - for (auto& item: config) - { - const std::string& name = item.first; - const std::string& value = item.second; - if (!SSA_SetAnyString(mContext, const_cast(name.c_str()), const_cast(value.c_str()))) - throw std::runtime_error(std::string("SSA_SetAnyString returned failed for pair ") + name + " " + value); - } -} - -SevanaAqua::Config SevanaAqua::parseConfig(const std::string& line) -{ - Config result; - - // Split command line to parts - std::vector pl; - StringHelper::split(line, pl, "-"); - - for (const std::string& s: pl) - { - std::string::size_type p = s.find(' '); - if (p != std::string::npos) - { - std::string name = StringHelper::trim(s.substr(0, p)); - std::string value = StringHelper::trim(s.substr(p + 1)); - - result[name] = value; - } - } - - return result; -} - - -SevanaAqua::PFaultsReport SevanaAqua::loadFaultsReport(std::istream& input) -{ - PFaultsReport result = std::make_shared(); - std::string line; - std::vector parts; - - // Parse output - while (!input.eof()) - { - std::getline(input, line); - if (line.size() < 3) - continue; - - std::string::size_type p = line.find(":"); - if (p != std::string::npos) - { - std::string name = StringHelper::trim(line.substr(0, p)); - - FaultsReport::Result r; - - // Split report line to components - parts.clear(); - StringHelper::split(line.substr(p + 1), parts, " \t"); - - // Remove empty components - parts.erase(std::remove_if(parts.begin(), parts.end(), [](const std::string& item){return item.empty();}), parts.end()); - - if (parts.size() >= 2) - { - r.mSource = parts[0]; - r.mDegrated = parts[1]; - if (parts.size()> 2) - r.mUnit = parts[2]; - result->mResultMap[name] = r; - } - } - else - { - p = line.find("ms."); - if (p != std::string::npos) - { - parts.clear(); - StringHelper::split(line, parts, " \t"); - if (parts.size() >= 3) - { - if (parts.back() == "ms.") - result->mSignalAdvancedInMilliseconds = (float)std::atof(parts[parts.size() - 2].c_str()); - } - } - else - { - p = line.find("percent."); - if (p != std::string::npos) - { - parts.clear(); - StringHelper::split(line, parts, " \t"); - if (parts.size() >= 3) - { - if (parts.back() == "percent.") - result->mMistimingInPercents = (float)std::atof(parts[parts.size() - 2].c_str()); - } - } - } - } - } - - return result; -} - -} // end of namespace MT - -// It is to workaround old AQuA NDK build - it has reference to ftime -/*#if defined(TARGET_ANDROID) -#include - -// This was removed from POSIX 2008. -int ftime(struct timeb* tb) { - struct timeval tv; - struct timezone tz; - - if (gettimeofday(&tv, &tz) < 0) - return -1; - - tb->time = tv.tv_sec; - tb->millitm = (tv.tv_usec + 500) / 1000; - - if (tb->millitm == 1000) { - ++tb->time; - tb->millitm = 0; - } - - tb->timezone = tz.tz_minuteswest; - tb->dstflag = tz.tz_dsttime; - - return 0; -} -#endif*/ - -#endif - diff --git a/src/engine/media/MT_SevanaMos.h b/src/engine/media/MT_SevanaMos.h deleted file mode 100644 index eec79af3..00000000 --- a/src/engine/media/MT_SevanaMos.h +++ /dev/null @@ -1,247 +0,0 @@ -#ifndef _SEVANA_MOS_H -#define _SEVANA_MOS_H - -#include -#include -#include -#include -#include -#include -#include - -#if defined(USE_PVQA_LIBRARY) -# include "pvqa.h" -# if !defined(PVQA_INTERVAL) -# define PVQA_INTERVAL (0.68) -# endif -#endif - -#if defined(USE_AQUA_LIBRARY) -# include "aqua.h" -# include -#endif -# include "helper/HL_ByteBuffer.h" - - -namespace MT -{ -enum class ReportType -{ - PlainText, - Html -}; - -#if defined(USE_PVQA_LIBRARY) -class SevanaMosUtility -{ -public: - // Returns MOS estimation as text representation of float value or "failed" word. - static void run(const std::string& pcmPath, const std::string& intervalPath, - std::string& estimation, std::string& intervals); -}; - -extern float getSevanaMos(const std::string& audioPath, const std::string& intervalReportPath, - std::string& intervalReport); - -class SevanaPVQA -{ -public: - enum class Model - { - Stream, - Interval - }; - -protected: - static void* mLibraryConfiguration; - static int mLibraryErrorCode; - static std::atomic_int mInstanceCounter; - static std::atomic_uint_least64_t mAllProcessedMilliseconds; - static bool mPvqaLoaded; - - void* mContext = nullptr; - Model mModel = Model::Interval; - double mIntervalLength = 0.68; - uint64_t mProcessedSamples = 0, - mProcessedMilliseconds = 0; - - bool mAudioLineInitialized = false; - std::string mDumpWavPath; - bool mOpenFailed = false; - - ByteBuffer mAudioDump; -public: - static std::string getVersion(); - - // Required to call before any call to SevanaPVQA instance methods - -#if defined(TARGET_ANDROID) - static void setupAndroidEnvironment(void* environment, void* appcontext); -#endif - // Path to config file can be empty - // In this case library will be considered initialized (but will produce zero MOS) - static bool initializeLibrary(const std::string& pathToLicenseFile, const std::string& pathToConfigFile); - static bool initializeLibraryWithData(const void* license_buffer, size_t license_len, - const void* config_buffer, size_t config_len); - static bool isInitialized(); - - static int getLibraryError(); - static void releaseLibrary(); - static int getInstanceCounter() { return mInstanceCounter; } - static uint64_t getProcessedMilliseconds() { return mAllProcessedMilliseconds; } - - SevanaPVQA(); - ~SevanaPVQA(); - - void open(double interval, Model model); - void close(); - bool isOpen() const; - - // Update/Get model - void update(int samplerate, int channels, const void* pcmBuffer, int pcmLength); - - typedef std::vector> EchoData; - enum class Codec - { - None, - G711, - ILBC, - G722, - G729, - GSM, - AMRNB, - AMRWB, - OPUS - }; - - float getResults(std::string& report, EchoData** echo, int samplerate, Codec codec); - - // Report is interval report. Names are output detector names. startIndex is column's start index in interval report of first detector. - struct DetectorsList - { - std::vector mNames; - int mStartIndex = 0; - }; - - static DetectorsList getDetectorsNames(const std::string& report); - - // Get MOS in one shot - void setPathToDumpFile(const std::string& path); - float process(int samplerate, int channels, const void* pcmBuffer, int pcmLength, std::string& report, Codec codec); - - Model getModel() const { return mModel; } - - int getSize() const; - - static std::string mosToColor(float mos); -}; - -typedef std::shared_ptr PSevanaPVQA; -#endif - -#if defined(USE_AQUA_LIBRARY) -class SevanaAqua -{ -protected: - void* mContext = nullptr; - std::mutex mMutex; - std::string mTempPath; - -public: - // Returns 0 (zero) on successful initialization, otherwise it is error code - static int initializeLibrary(const std::string& pathToLicenseFile); - static int initializeLibrary(const void* buffer, size_t len); - - static void releaseLibrary(); - static std::string getVersion(); - - SevanaAqua(); - ~SevanaAqua(); - - void open(); - void close(); - bool isOpen() const; - - void setTempPath(const std::string& temp_path); - std::string getTempPath() const; - - typedef std::map Config; - void configureWith(const Config& config); - static Config parseConfig(const std::string& line); - - // Report is returned in JSON format - struct AudioBuffer - { - AudioBuffer() - {} - - AudioBuffer(int size) - { - mData = std::make_shared>(); - mData->resize(size); - } - - AudioBuffer(const void* data, int size) - { - mData = std::make_shared>(); - mData->resize(size); - memcpy(mData->data(), data, size); - } - - void* data() - { - return mData ? mData->data() : nullptr; - } - - const void* data() const - { - return mData ? mData->data() : nullptr; - } - - int size() const - { - return mData ? mData->size() : 0; - } - - int mRate = 8000; - int mChannels = 1; - std::shared_ptr> mData; - bool isInitialized() const { return mRate > 0 && mChannels > 0 && mData; } - }; - - - struct FaultsReport - { - float mSignalAdvancedInMilliseconds = -5000.0; - float mMistimingInPercents = -5000.0; - - struct Result - { - std::string mSource, mDegrated, mUnit; - }; - typedef std::map ResultMap; - ResultMap mResultMap; - - Json::Value toJson() const; - std::string toText() const; - }; - - typedef std::shared_ptr PFaultsReport; - - static PFaultsReport loadFaultsReport(std::istream& input); - - // Compare in one shot. Report will include text representation of json report. - struct CompareResult - { - float mMos = 0.0f; - Json::Value mReport; - PFaultsReport mFaults; - }; - - CompareResult compare(AudioBuffer& reference, AudioBuffer& test); -}; -typedef std::shared_ptr PSevanaAqua; -#endif -} - -#endif diff --git a/src/engine/media/MT_Statistics.h b/src/engine/media/MT_Statistics.h index ff34f326..c552151f 100644 --- a/src/engine/media/MT_Statistics.h +++ b/src/engine/media/MT_Statistics.h @@ -9,8 +9,6 @@ #include "jrtplib/src/rtptimeutilities.h" #include "jrtplib/src/rtppacket.h" -#include "MT_SevanaMos.h" - using std::experimental::optional; namespace MT @@ -79,8 +77,8 @@ class JitterStatistics { public: void process(jrtplib::RTPPacket* packet, int samplerate); - ProbeStats get() const { return mJitter; } - double getMaxDelta() const { return mMaxDelta; } + ProbeStats get() const { return mJitter; } + float getMaxDelta() const { return mMaxDelta; } protected: // Jitter calculation @@ -90,13 +88,13 @@ protected: uint32_t mReceiveTimestamp = 0; // It is classic jitter value in units - optional mLastJitter; + optional mLastJitter; // Some statistics for jitter value in seconds - ProbeStats mJitter; + ProbeStats mJitter; // Maximal delta in seconds - double mMaxDelta = 0.0; + float mMaxDelta = 0.0f; }; class Statistics diff --git a/src/engine/media/MT_Stream.h b/src/engine/media/MT_Stream.h index b4b7d523..0e136d6a 100644 --- a/src/engine/media/MT_Stream.h +++ b/src/engine/media/MT_Stream.h @@ -21,10 +21,6 @@ #include #include "../helper/HL_Optional.hpp" -#if defined(USE_PVQA_LIBRARY) -# include "MT_SevanaMos.h" -#endif - using std::experimental::optional; namespace MT