From 3a1bf17f69890421dfca05c35cf5a8debcf79c55 Mon Sep 17 00:00:00 2001 From: bodamnam Date: Thu, 15 Dec 2022 08:12:59 +0000 Subject: Modify AudioSession to delete old stream when modifySession is called with new remote address. 1) The current code is create a set of audiostream when modifySession called with the new AudioConfig which has new remote address. It make audioSession to keep creates stream everytime the addConfig invoked. I change the code to delete old stream when the modifySession called with AudioConfig with a new remote address. 2) Add UT for the AudioSession Bug: 264833064 Test: atest ImsMediaNativeTests, Verified Voice Call test with forking/non-forking case in live network. Verified by device testing the TC of ATT LTE_BTR_5_5573 pased Change-Id: Icbf809d17113c0afcb24f2ca7c3f093db9bbdc9d --- .../lib/libimsmedia/core/audio/AudioManager.cpp | 3 +- .../lib/libimsmedia/core/audio/AudioSession.cpp | 294 ++++++------------ .../core/audio/AudioStreamGraphRtpRx.cpp | 21 ++ .../core/audio/AudioStreamGraphRtpTx.cpp | 22 ++ .../lib/libimsmedia/core/include/ImsMediaDefine.h | 6 +- .../libimsmedia/core/include/audio/AudioSession.h | 8 + .../core/include/audio/AudioStreamGraph.h | 8 + .../core/include/audio/AudioStreamGraphRtpRx.h | 1 + .../core/include/audio/AudioStreamGraphRtpTx.h | 1 + .../libimsmedia/core/audio/AudioSessionTest.cpp | 337 +++++++++++++++++++++ 10 files changed, 495 insertions(+), 206 deletions(-) create mode 100644 tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioSessionTest.cpp diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioManager.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioManager.cpp index faabe4fc..357a1d71 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioManager.cpp +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioManager.cpp @@ -97,7 +97,8 @@ ImsMediaResult AudioManager::modifySession(int sessionId, AudioConfig* config) IMLOGI1("[modifySession] sessionId[%d]", sessionId); if (session != mSessions.end()) { - if ((session->second)->IsGraphAlreadyExist(config)) + if ((session->second)->IsGraphAlreadyExist(config) || + (session->second)->getGraphSize(kStreamRtpTx) == 0) { return (session->second)->startGraph(config); } diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioSession.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioSession.cpp index b2bb681b..e17112f6 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioSession.cpp +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioSession.cpp @@ -18,9 +18,7 @@ #include #include #include - #include - #include AudioSession::AudioSession() @@ -85,7 +83,8 @@ SessionState AudioSession::getState() { if (graph != nullptr && graph->getState() == kStreamStateRunning) { - return kSessionStateActive; + state = kSessionStateSending; + break; } } @@ -93,7 +92,7 @@ SessionState AudioSession::getState() { if (graph != nullptr && graph->getState() == kStreamStateRunning) { - return kSessionStateActive; + return state == kSessionStateSending ? kSessionStateActive : kSessionStateReceiving; } } @@ -101,7 +100,7 @@ SessionState AudioSession::getState() { if (graph != nullptr && graph->getState() == kStreamStateRunning) { - return kSessionStateSuspended; + return state == kSessionStateSending ? kSessionStateSending : kSessionStateSuspended; } } @@ -127,16 +126,15 @@ ImsMediaResult AudioSession::startGraph(RtpConfig* config) ImsMediaResult ret = RESULT_NOT_READY; IMLOGD1("[startGraph] mListGraphRtpTx size[%d]", mListGraphRtpTx.size()); - if (mListGraphRtpTx.size() != 0) - { - for (auto& graph : mListGraphRtpTx) - { - if (graph != nullptr && graph->isSameGraph(config)) + AudioStreamGraphRtpTx* graphTx = AudioStreamGraph::findGraph(mListGraphRtpTx, + [&config](AudioStreamGraphRtpTx* graph) { - ret = graph->update(config); - break; - } - } + return graph != nullptr && graph->isSameGraph(config); + }); + + if (graphTx != nullptr) + { + ret = graphTx->update(config); if (ret != RESULT_SUCCESS) { @@ -147,13 +145,11 @@ ImsMediaResult AudioSession::startGraph(RtpConfig* config) else { mListGraphRtpTx.push_back(new AudioStreamGraphRtpTx(this, mRtpFd)); - ret = mListGraphRtpTx.back()->create(config); - if (ret == RESULT_SUCCESS && - (pConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_SEND_ONLY || - pConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_SEND_RECEIVE)) + if (mListGraphRtpTx.back()->create(config) == RESULT_SUCCESS) { ret = mListGraphRtpTx.back()->start(); + if (ret != RESULT_SUCCESS) { IMLOGE1("[startGraph] start error[%d]", ret); @@ -162,19 +158,18 @@ ImsMediaResult AudioSession::startGraph(RtpConfig* config) } } - IMLOGD1("[startGraph] mListGraphRtpRx size[%d]", mListGraphRtpRx.size()); + IMLOGD1("[startGraph] ListGraphRtpRx size[%d]", mListGraphRtpRx.size()); - if (mListGraphRtpRx.size() != 0) - { - for (auto& graph : mListGraphRtpRx) - { - if (graph != nullptr && graph->isSameGraph(config)) + AudioStreamGraphRtpRx* graphRx = AudioStreamGraph::findGraph(mListGraphRtpRx, + [&config](AudioStreamGraphRtpRx* graph) { - graph->setMediaQualityThreshold(&mThreshold); - ret = graph->update(config); - break; - } - } + return graph != nullptr && graph->isSameGraph(config); + }); + + if (graphRx != nullptr) + { + graphRx->setMediaQualityThreshold(&mThreshold); + ret = graphRx->update(config); if (ret != RESULT_SUCCESS) { @@ -185,11 +180,8 @@ ImsMediaResult AudioSession::startGraph(RtpConfig* config) else { mListGraphRtpRx.push_back(new AudioStreamGraphRtpRx(this, mRtpFd)); - ret = mListGraphRtpRx.back()->create(config); - if (ret == RESULT_SUCCESS && - (pConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_RECEIVE_ONLY || - pConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_SEND_RECEIVE)) + if (mListGraphRtpRx.back()->create(config) == RESULT_SUCCESS) { mListGraphRtpRx.back()->setMediaQualityThreshold(&mThreshold); ret = mListGraphRtpRx.back()->start(); @@ -204,17 +196,16 @@ ImsMediaResult AudioSession::startGraph(RtpConfig* config) IMLOGD1("[startGraph] mListGraphRtcp size[%d]", mListGraphRtcp.size()); - if (mListGraphRtcp.size() != 0) - { - for (auto& graph : mListGraphRtcp) - { - if (graph != nullptr && graph->isSameGraph(config)) + AudioStreamGraphRtcp* graphRtcp = AudioStreamGraph::findGraph(mListGraphRtcp, + [&config](AudioStreamGraphRtcp* graph) { - graph->setMediaQualityThreshold(&mThreshold); - ret = graph->update(config); - break; - } - } + return graph != nullptr && graph->isSameGraph(config); + }); + + if (graphRtcp != nullptr) + { + graphRtcp->setMediaQualityThreshold(&mThreshold); + ret = graphRtcp->update(config); if (ret != RESULT_SUCCESS) { @@ -225,12 +216,12 @@ ImsMediaResult AudioSession::startGraph(RtpConfig* config) else { mListGraphRtcp.push_back(new AudioStreamGraphRtcp(this, mRtcpFd)); - ret = mListGraphRtcp.back()->create(config); - if (ret == RESULT_SUCCESS) + if (mListGraphRtcp.back()->create(config) == RESULT_SUCCESS) { mListGraphRtcp.back()->setMediaQualityThreshold(&mThreshold); ret = mListGraphRtcp.back()->start(); + if (ret != RESULT_SUCCESS) { IMLOGE1("[startGraph] start error[%d]", ret); @@ -262,97 +253,43 @@ ImsMediaResult AudioSession::addGraph(RtpConfig* config, bool enableRtcp) return RESULT_INVALID_PARAM; } - for (auto& graph : mListGraphRtpTx) - { - if (graph != nullptr && graph->isSameGraph(config)) - { - IMLOGW0("[addGraph] same config is exist"); - return startGraph(config); - } - } - - for (auto& graph : mListGraphRtpTx) + if (IsGraphAlreadyExist(config) || mListGraphRtpTx.empty()) { - if (graph != nullptr) - { - graph->stop(); - } + return startGraph(config); } - for (auto& graph : mListGraphRtpRx) + if (enableRtcp) // update current graph to inactive mode { - if (graph != nullptr) + for (auto& graph : mListGraphRtpTx) { - graph->stop(); + if (graph != nullptr) + { + graph->stop(); + } } - } - for (auto& graph : mListGraphRtcp) - { - if (graph != nullptr && graph->getState() != kStreamStateRunning) + for (auto& graph : mListGraphRtpRx) { - enableRtcp ? graph->start() : graph->stop(); + if (graph != nullptr) + { + graph->stop(); + } } - } - - ImsMediaResult ret = RESULT_NOT_READY; - - mListGraphRtpTx.push_back(new AudioStreamGraphRtpTx(this, mRtpFd)); - ret = mListGraphRtpTx.back()->create(config); - if (ret == RESULT_SUCCESS) - { - ret = mListGraphRtpTx.back()->start(); - if (ret != RESULT_SUCCESS) + for (auto& graph : mListGraphRtcp) { - IMLOGE1("[addGraph] start error[%d]", ret); - return ret; + if (graph != nullptr && graph->getState() != kStreamStateRunning) + { + graph->start(); + } } - } - - IMLOGD1("[addGraph] mListGraphTx size[%d]", mListGraphRtpTx.size()); - - mListGraphRtpRx.push_back(new AudioStreamGraphRtpRx(this, mRtpFd)); - ret = mListGraphRtpRx.back()->create(config); - if (ret == RESULT_SUCCESS) - { - mListGraphRtpRx.back()->setMediaQualityThreshold(&mThreshold); - ret = mListGraphRtpRx.back()->start(); - if (ret != RESULT_SUCCESS) - { - IMLOGE1("[addGraph] start error[%d]", ret); - return ret; - } + return startGraph(config); } - - IMLOGD1("[addGraph] mListGraphRx size[%d]", mListGraphRtpRx.size()); - - mListGraphRtcp.push_back(new AudioStreamGraphRtcp(this, mRtcpFd)); - ret = mListGraphRtcp.back()->create(config); - - if (ret == RESULT_SUCCESS) + else { - mListGraphRtcp.back()->setMediaQualityThreshold(&mThreshold); - ret = mListGraphRtcp.back()->start(); - if (ret != RESULT_SUCCESS) - { - IMLOGE1("[addGraph] start error[%d]", ret); - return ret; - } + return confirmGraph(config); } - - IMLOGD1("[addGraph] mListGraphRtcp size[%d]", mListGraphRtcp.size()); - - if (mMediaQualityAnalyzer != nullptr && - !mMediaQualityAnalyzer->isSameConfig(reinterpret_cast(config))) - { - mMediaQualityAnalyzer->stop(); - mMediaQualityAnalyzer->setConfig(reinterpret_cast(config)); - mMediaQualityAnalyzer->start(); - } - - return RESULT_SUCCESS; } ImsMediaResult AudioSession::confirmGraph(RtpConfig* config) @@ -362,99 +299,44 @@ ImsMediaResult AudioSession::confirmGraph(RtpConfig* config) return RESULT_INVALID_PARAM; } - ImsMediaResult ret = RESULT_NOT_READY; - - /** Stop unmatched running instances of StreamGraph. */ - for (auto& graph : mListGraphRtpTx) - { - if (graph != nullptr && !graph->isSameGraph(config)) - { - graph->stop(); - } - } - - for (auto& graph : mListGraphRtpRx) + if (mListGraphRtpTx.empty() || mListGraphRtpRx.empty() || mListGraphRtcp.empty()) { - if (graph != nullptr && !graph->isSameGraph(config)) - { - graph->stop(); - } + return startGraph(config); } - for (auto& graph : mListGraphRtcp) - { - if (graph != nullptr && !graph->isSameGraph(config)) - { - graph->stop(); - } - } - - bool bFound = false; + /** Stop and delete unmatched running instances of StreamGraph. */ for (std::list::iterator iter = mListGraphRtpTx.begin(); iter != mListGraphRtpTx.end();) { AudioStreamGraphRtpTx* graph = *iter; - if (graph == nullptr) - { - continue; - } - - if (!graph->isSameGraph(config)) + if (graph != nullptr && !graph->isSameGraph(config)) { + graph->stop(); iter = mListGraphRtpTx.erase(iter); delete graph; } else { - if (graph->getState() != kStreamStateRunning) - { - ret = graph->start(); - if (ret != RESULT_SUCCESS) - { - IMLOGE1("[confirmGraph] start tx error[%d]", ret); - return ret; - } - } iter++; - bFound = true; } } IMLOGD1("[confirmGraph] mListGraphTx size[%d]", mListGraphRtpTx.size()); - if (bFound == false) - { - IMLOGE0("[confirmGraph] no graph to confirm"); - return RESULT_INVALID_PARAM; - } - for (std::list::iterator iter = mListGraphRtpRx.begin(); iter != mListGraphRtpRx.end();) { AudioStreamGraphRtpRx* graph = *iter; - if (graph == nullptr) - { - continue; - } - - if (!graph->isSameGraph(config)) + if (graph != nullptr && !graph->isSameGraph(config)) { + graph->stop(); iter = mListGraphRtpRx.erase(iter); delete graph; } else { - if (graph->getState() != kStreamStateRunning) - { - ret = graph->start(); - if (ret != RESULT_SUCCESS) - { - IMLOGE1("[confirmGraph] start rx error[%d]", ret); - return ret; - } - } iter++; } } @@ -466,35 +348,21 @@ ImsMediaResult AudioSession::confirmGraph(RtpConfig* config) { AudioStreamGraphRtcp* graph = *iter; - if (graph == nullptr) - { - continue; - } - - if (!graph->isSameGraph(config)) + if (graph != nullptr && !graph->isSameGraph(config)) { + graph->stop(); iter = mListGraphRtcp.erase(iter); delete graph; } else { - if (graph->getState() != kStreamStateRunning) - { - ret = graph->start(); - if (ret != RESULT_SUCCESS) - { - IMLOGE1("[confirmGraph] start rtcp error[%d]", ret); - return ret; - } - } - iter++; } } IMLOGD1("[confirmGraph] mListGraphRtcp size[%d]", mListGraphRtcp.size()); - return RESULT_SUCCESS; + return startGraph(config); } ImsMediaResult AudioSession::deleteGraph(RtpConfig* config) @@ -514,11 +382,7 @@ ImsMediaResult AudioSession::deleteGraph(RtpConfig* config) if (graph->isSameGraph(config)) { - if (graph->getState() == kStreamStateRunning) - { - graph->stop(); - } - + graph->stop(); iter = mListGraphRtpTx.erase(iter); delete graph; bFound = true; @@ -553,6 +417,7 @@ ImsMediaResult AudioSession::deleteGraph(RtpConfig* config) { graph->stop(); } + iter = mListGraphRtpRx.erase(iter); delete graph; break; @@ -581,6 +446,7 @@ ImsMediaResult AudioSession::deleteGraph(RtpConfig* config) { graph->stop(); } + iter = mListGraphRtcp.erase(iter); delete graph; break; @@ -664,6 +530,11 @@ void AudioSession::setMediaQualityThreshold(const MediaQualityThreshold& thresho void AudioSession::sendDtmf(char digit, int duration) { + if (mListGraphRtpTx.empty()) + { + return; + } + for (std::list::iterator iter = mListGraphRtpTx.begin(); iter != mListGraphRtpTx.end(); iter++) { @@ -692,6 +563,21 @@ bool AudioSession::IsGraphAlreadyExist(RtpConfig* config) return false; } +uint32_t AudioSession::getGraphSize(ImsMediaStreamType type) +{ + switch (type) + { + case kStreamRtpTx: + return mListGraphRtpTx.size(); + case kStreamRtpRx: + return mListGraphRtpRx.size(); + case kStreamRtcp: + return mListGraphRtcp.size(); + } + + return 0; +} + void AudioSession::SendInternalEvent(int32_t type, uint64_t param1, uint64_t param2) { (void)param2; diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtpRx.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtpRx.cpp index d3d0d791..70963147 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtpRx.cpp +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtpRx.cpp @@ -106,15 +106,18 @@ ImsMediaResult AudioStreamGraphRtpRx::update(RtpConfig* config) IMLOGI0("[update] pause RX"); return stop(); } + ImsMediaResult ret = RESULT_NOT_READY; if (mGraphState == kStreamStateRunning) { mScheduler->Stop(); + for (auto& node : mListNodeStarted) { IMLOGD1("[update] update node[%s]", node->GetNodeName()); ret = node->UpdateConfig(mConfig); + if (ret != RESULT_SUCCESS) { IMLOGE2("[update] error in update node[%s], ret[%d]", node->GetNodeName(), ret); @@ -128,6 +131,7 @@ ImsMediaResult AudioStreamGraphRtpRx::update(RtpConfig* config) { IMLOGD1("[update] update node[%s]", node->GetNodeName()); ret = node->UpdateConfig(mConfig); + if (ret != RESULT_SUCCESS) { IMLOGE2("[update] error in update node[%s], ret[%d]", node->GetNodeName(), ret); @@ -144,4 +148,21 @@ ImsMediaResult AudioStreamGraphRtpRx::update(RtpConfig* config) } return ret; +} + +ImsMediaResult AudioStreamGraphRtpRx::start() +{ + if (mConfig == nullptr) + { + return RESULT_NOT_READY; + } + + if (mConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_RECEIVE_ONLY || + mConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_SEND_RECEIVE) + { + return BaseStreamGraph::start(); + } + + // not started + return RESULT_SUCCESS; } \ No newline at end of file diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtpTx.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtpTx.cpp index 372a137d..1f8260cc 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtpTx.cpp +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtpTx.cpp @@ -155,6 +155,23 @@ ImsMediaResult AudioStreamGraphRtpTx::update(RtpConfig* config) return ret; } +ImsMediaResult AudioStreamGraphRtpTx::start() +{ + if (mConfig == nullptr) + { + return RESULT_NOT_READY; + } + + if (mConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_SEND_ONLY || + mConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_SEND_RECEIVE) + { + return BaseStreamGraph::start(); + } + + // not started + return RESULT_SUCCESS; +} + bool AudioStreamGraphRtpTx::createDtmfGraph(RtpConfig* config, BaseNode* rtpEncoderNode) { if (config == nullptr) @@ -169,6 +186,11 @@ bool AudioStreamGraphRtpTx::createDtmfGraph(RtpConfig* config, BaseNode* rtpEnco return false; } + if (mConfig == nullptr) + { + mConfig = new AudioConfig(*audioConfig); + } + BaseNode* pDtmfEncoderNode = new DtmfEncoderNode(mCallback); pDtmfEncoderNode->SetMediaType(IMS_MEDIA_AUDIO); pDtmfEncoderNode->SetConfig(audioConfig); diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/ImsMediaDefine.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/ImsMediaDefine.h index 74699708..9006f64d 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/ImsMediaDefine.h +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/ImsMediaDefine.h @@ -447,7 +447,11 @@ enum SessionState { /** The state that the session is created but graph is not created */ kSessionStateOpened, - /** The state that the session is created and the Rtp StreamGraphs are running */ + /** The state that the session is created and the TX rtp StreamGraphs are running */ + kSessionStateSending, + /** The state that the session is created and the RX rtp StreamGraphs are running */ + kSessionStateReceiving, + /** The state that the session is created and the both TX and Rx rtp StreamGraphs are running */ kSessionStateActive, /** The state that the session is created and the Rtp StreamGraphs is not running */ kSessionStateSuspended, diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioSession.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioSession.h index ce3bd47e..10d8b916 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioSession.h +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioSession.h @@ -95,6 +95,14 @@ public: */ bool IsGraphAlreadyExist(RtpConfig* config); + /** + * @brief Get graph list size with repective stream type + * + * @param type The graph type to fetch + * @return uint32_t The size of list + */ + uint32_t getGraphSize(ImsMediaStreamType type); + private: std::list mListGraphRtpTx; std::list mListGraphRtpRx; diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioStreamGraph.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioStreamGraph.h index 203ea682..211b981d 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioStreamGraph.h +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioStreamGraph.h @@ -20,6 +20,7 @@ #include #include #include +#include // std::find_if class AudioStreamGraph : public BaseStreamGraph { @@ -49,6 +50,13 @@ public: mConfig->getRemotePort() == config->getRemotePort()); } + template + static T1* findGraph(std::list list, T2 func) + { + typename std::list::iterator iter = std::find_if(list.begin(), list.end(), func); + return iter == list.end() ? nullptr : *iter; + } + protected: AudioConfig* mConfig; }; diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioStreamGraphRtpRx.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioStreamGraphRtpRx.h index cfc9e55f..78e80a82 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioStreamGraphRtpRx.h +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioStreamGraphRtpRx.h @@ -27,6 +27,7 @@ public: virtual ~AudioStreamGraphRtpRx(); virtual ImsMediaResult create(RtpConfig* config); virtual ImsMediaResult update(RtpConfig* config); + virtual ImsMediaResult start(); }; #endif \ No newline at end of file diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioStreamGraphRtpTx.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioStreamGraphRtpTx.h index 5853de91..f2cb1744 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioStreamGraphRtpTx.h +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioStreamGraphRtpTx.h @@ -27,6 +27,7 @@ public: virtual ~AudioStreamGraphRtpTx(); virtual ImsMediaResult create(RtpConfig* config); virtual ImsMediaResult update(RtpConfig* config); + virtual ImsMediaResult start(); /** * @brief Create a graph for send dtmf digit to network diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioSessionTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioSessionTest.cpp new file mode 100644 index 00000000..bd4a6010 --- /dev/null +++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioSessionTest.cpp @@ -0,0 +1,337 @@ +/** + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +using namespace android::telephony::imsmedia; + +// RtpConfig +const int32_t kMediaDirection = RtpConfig::MEDIA_DIRECTION_SEND_RECEIVE; +const android::String8 kRemoteAddress("127.0.0.1"); +const int32_t kRemotePort = 10000; +const int8_t kDscp = 0; +const int8_t kRxPayload = 96; +const int8_t kTxPayload = 96; +const int8_t kSamplingRate = 16; + +// RtcpConfig +const android::String8 kCanonicalName("name"); +const int32_t kTransmitPort = 1001; +const int32_t kIntervalSec = 5; +const int32_t kRtcpXrBlockTypes = RtcpConfig::FLAG_RTCPXR_STATISTICS_SUMMARY_REPORT_BLOCK | + RtcpConfig::FLAG_RTCPXR_VOIP_METRICS_REPORT_BLOCK; + +// AudioConfig +const int8_t kPTimeMillis = 20; +const int32_t kMaxPtimeMillis = 100; +const bool kDtxEnabled = true; +const int32_t kCodecType = AudioConfig::CODEC_AMR_WB; +const int8_t kDtmfTxPayloadTypeNumber = 100; +const int8_t kDtmfRxPayloadTypeNumber = 101; +const int8_t kDtmfsamplingRateKHz = 16; + +// AmrParam +const int32_t kAmrMode = 8; +const bool kOctetAligned = false; +const int32_t kMaxRedundancyMillis = 240; + +// EvsParam +const int32_t kEvsBandwidth = EvsParams::EVS_BAND_NONE; +const int32_t kEvsMode = 8; +const int8_t kChannelAwareMode = 3; +const bool kUseHeaderFullOnly = false; +const int8_t kcodecModeRequest = 15; + +class AudioSessionTest : public ::testing::Test +{ +public: + AudioSession* session; + AudioConfig config; + RtcpConfig rtcp; + AmrParams amr; + EvsParams evs; + int socketRtpFd; + int socketRtcpFd; + + AudioSessionTest() + { + session = nullptr; + socketRtpFd = -1; + socketRtcpFd = -1; + } + ~AudioSessionTest() {} + +protected: + virtual void SetUp() override + { + rtcp.setCanonicalName(kCanonicalName); + rtcp.setTransmitPort(kTransmitPort); + rtcp.setIntervalSec(kIntervalSec); + rtcp.setRtcpXrBlockTypes(kRtcpXrBlockTypes); + + amr.setAmrMode(kAmrMode); + amr.setOctetAligned(kOctetAligned); + amr.setMaxRedundancyMillis(kMaxRedundancyMillis); + + evs.setEvsBandwidth(kEvsBandwidth); + evs.setEvsMode(kEvsMode); + evs.setChannelAwareMode(kChannelAwareMode); + evs.setUseHeaderFullOnly(kUseHeaderFullOnly); + evs.setCodecModeRequest(kcodecModeRequest); + + config.setMediaDirection(kMediaDirection); + config.setRemoteAddress(kRemoteAddress); + config.setRemotePort(kRemotePort); + config.setRtcpConfig(rtcp); + config.setDscp(kDscp); + config.setRxPayloadTypeNumber(kRxPayload); + config.setTxPayloadTypeNumber(kTxPayload); + config.setSamplingRateKHz(kSamplingRate); + config.setPtimeMillis(kPTimeMillis); + config.setMaxPtimeMillis(kMaxPtimeMillis); + config.setDtxEnabled(kDtxEnabled); + config.setCodecType(kCodecType); + config.setTxDtmfPayloadTypeNumber(kDtmfTxPayloadTypeNumber); + config.setRxDtmfPayloadTypeNumber(kDtmfRxPayloadTypeNumber); + config.setDtmfsamplingRateKHz(kDtmfsamplingRateKHz); + config.setAmrParams(amr); + config.setEvsParams(evs); + + session = new AudioSession(); + const char testIp[] = "127.0.0.1"; + unsigned int testPortRtp = 30000; + socketRtpFd = ImsMediaNetworkUtil::openSocket(testIp, testPortRtp, AF_INET); + EXPECT_NE(socketRtpFd, -1); + unsigned int testPortRtcp = 30001; + socketRtcpFd = ImsMediaNetworkUtil::openSocket(testIp, testPortRtcp, AF_INET); + EXPECT_NE(socketRtcpFd, -1); + } + + virtual void TearDown() override + { + if (session != nullptr) + { + delete session; + } + + if (socketRtpFd != -1) + { + ImsMediaNetworkUtil::closeSocket(socketRtpFd); + } + + if (socketRtcpFd != -1) + { + ImsMediaNetworkUtil::closeSocket(socketRtcpFd); + } + } +}; + +TEST_F(AudioSessionTest, testLocalEndpoint) +{ + EXPECT_EQ(session->getState(), kSessionStateOpened); + EXPECT_EQ(session->getLocalRtpFd(), -1); + EXPECT_EQ(session->getLocalRtcpFd(), -1); + + session->setLocalEndPoint(socketRtpFd, socketRtcpFd); + EXPECT_EQ(session->getLocalRtpFd(), socketRtpFd); + EXPECT_EQ(session->getLocalRtcpFd(), socketRtcpFd); +} + +TEST_F(AudioSessionTest, testStartGraphFail) +{ + EXPECT_EQ(session->startGraph(nullptr), RESULT_INVALID_PARAM); + EXPECT_EQ(session->getState(), kSessionStateOpened); + + session->setLocalEndPoint(socketRtpFd, socketRtcpFd); + config.setRemoteAddress(android::String8("")); + EXPECT_EQ(session->startGraph(&config), RESULT_INVALID_PARAM); + EXPECT_EQ(session->getState(), kSessionStateOpened); +} + +TEST_F(AudioSessionTest, testStartGraphAndUpdate) +{ + session->setLocalEndPoint(socketRtpFd, socketRtcpFd); + EXPECT_EQ(session->startGraph(&config), RESULT_SUCCESS); + EXPECT_EQ(session->getState(), kSessionStateActive); + EXPECT_EQ(session->getGraphSize(kStreamRtpTx), 1); + EXPECT_EQ(session->getGraphSize(kStreamRtpRx), 1); + EXPECT_EQ(session->getGraphSize(kStreamRtcp), 1); + + EXPECT_TRUE(session->IsGraphAlreadyExist(&config)); + + // normal update + config.setTxPayloadTypeNumber(120); + EXPECT_EQ(session->startGraph(&config), RESULT_SUCCESS); + EXPECT_EQ(session->getState(), kSessionStateActive); + EXPECT_EQ(session->getGraphSize(kStreamRtpTx), 1); + EXPECT_EQ(session->getGraphSize(kStreamRtpRx), 1); + EXPECT_EQ(session->getGraphSize(kStreamRtcp), 1); + + // create one more graph + config.setRemotePort(20000); + EXPECT_EQ(session->startGraph(&config), RESULT_SUCCESS); + EXPECT_EQ(session->getState(), kSessionStateActive); + EXPECT_EQ(session->getGraphSize(kStreamRtpTx), 2); + EXPECT_EQ(session->getGraphSize(kStreamRtpRx), 2); + EXPECT_EQ(session->getGraphSize(kStreamRtcp), 2); + + config.setRemotePort(30000); + EXPECT_FALSE(session->IsGraphAlreadyExist(&config)); +} + +TEST_F(AudioSessionTest, testStartGraphSendOnly) +{ + session->setLocalEndPoint(socketRtpFd, socketRtcpFd); + config.setMediaDirection(RtpConfig::MEDIA_DIRECTION_SEND_ONLY); + EXPECT_EQ(session->startGraph(&config), RESULT_SUCCESS); + EXPECT_EQ(session->getState(), kSessionStateSending); + EXPECT_EQ(session->getGraphSize(kStreamRtpTx), 1); + EXPECT_EQ(session->getGraphSize(kStreamRtpRx), 1); + EXPECT_EQ(session->getGraphSize(kStreamRtcp), 1); +} + +TEST_F(AudioSessionTest, testStartGraphReceiveOnly) +{ + session->setLocalEndPoint(socketRtpFd, socketRtcpFd); + config.setMediaDirection(RtpConfig::MEDIA_DIRECTION_RECEIVE_ONLY); + EXPECT_EQ(session->startGraph(&config), RESULT_SUCCESS); + EXPECT_EQ(session->getState(), kSessionStateReceiving); + EXPECT_EQ(session->getGraphSize(kStreamRtpTx), 1); + EXPECT_EQ(session->getGraphSize(kStreamRtpRx), 1); + EXPECT_EQ(session->getGraphSize(kStreamRtcp), 1); +} + +TEST_F(AudioSessionTest, testStartGraphInactive) +{ + session->setLocalEndPoint(socketRtpFd, socketRtcpFd); + config.setMediaDirection(RtpConfig::MEDIA_DIRECTION_INACTIVE); + EXPECT_EQ(session->startGraph(&config), RESULT_SUCCESS); + EXPECT_EQ(session->getState(), kSessionStateSuspended); + EXPECT_EQ(session->getGraphSize(kStreamRtpTx), 1); + EXPECT_EQ(session->getGraphSize(kStreamRtpRx), 1); + EXPECT_EQ(session->getGraphSize(kStreamRtcp), 1); +} + +TEST_F(AudioSessionTest, testStartAndHoldResumeWithSameRemoteAddress) +{ + session->setLocalEndPoint(socketRtpFd, socketRtcpFd); + EXPECT_EQ(session->startGraph(&config), RESULT_SUCCESS); + EXPECT_EQ(session->getState(), kSessionStateActive); + + EXPECT_EQ(session->getGraphSize(kStreamRtpTx), 1); + EXPECT_EQ(session->getGraphSize(kStreamRtpRx), 1); + EXPECT_EQ(session->getGraphSize(kStreamRtcp), 1); + + config.setMediaDirection(RtpConfig::MEDIA_DIRECTION_INACTIVE); + EXPECT_EQ(session->startGraph(&config), RESULT_SUCCESS); + EXPECT_EQ(session->getState(), kSessionStateSuspended); + + EXPECT_EQ(session->getGraphSize(kStreamRtpTx), 1); + EXPECT_EQ(session->getGraphSize(kStreamRtpRx), 1); + EXPECT_EQ(session->getGraphSize(kStreamRtcp), 1); +} + +TEST_F(AudioSessionTest, testStartAndHoldResumeWithDifferentRemoteAddress) +{ + session->setLocalEndPoint(socketRtpFd, socketRtcpFd); + EXPECT_EQ(session->startGraph(&config), RESULT_SUCCESS); + EXPECT_EQ(session->getState(), kSessionStateActive); + + config.setRemotePort(20000); + config.setMediaDirection(RtpConfig::MEDIA_DIRECTION_INACTIVE); + EXPECT_EQ(session->addGraph(&config, false), RESULT_SUCCESS); + EXPECT_EQ(session->getState(), kSessionStateSuspended); + + EXPECT_EQ(session->getGraphSize(kStreamRtpTx), 1); + EXPECT_EQ(session->getGraphSize(kStreamRtpRx), 1); + EXPECT_EQ(session->getGraphSize(kStreamRtcp), 1); + + config.setRemotePort(30000); + config.setMediaDirection(RtpConfig::MEDIA_DIRECTION_SEND_RECEIVE); + EXPECT_EQ(session->addGraph(&config, false), RESULT_SUCCESS); + EXPECT_EQ(session->getState(), kSessionStateActive); + + EXPECT_EQ(session->getGraphSize(kStreamRtpTx), 1); + EXPECT_EQ(session->getGraphSize(kStreamRtpRx), 1); + EXPECT_EQ(session->getGraphSize(kStreamRtcp), 1); +} + +TEST_F(AudioSessionTest, testAddGraphWithoutStartGraph) +{ + session->setLocalEndPoint(socketRtpFd, socketRtcpFd); + config.setMediaDirection(RtpConfig::MEDIA_DIRECTION_INACTIVE); + EXPECT_EQ(session->addGraph(&config, false), RESULT_SUCCESS); + EXPECT_EQ(session->getState(), kSessionStateSuspended); + + EXPECT_EQ(session->getGraphSize(kStreamRtpTx), 1); + EXPECT_EQ(session->getGraphSize(kStreamRtpRx), 1); + EXPECT_EQ(session->getGraphSize(kStreamRtcp), 1); + + config.setRemotePort(20000); + config.setMediaDirection(RtpConfig::MEDIA_DIRECTION_SEND_ONLY); + EXPECT_EQ(session->addGraph(&config, false), RESULT_SUCCESS); + EXPECT_EQ(session->getState(), kSessionStateSending); + + EXPECT_EQ(session->getGraphSize(kStreamRtpTx), 1); + EXPECT_EQ(session->getGraphSize(kStreamRtpRx), 1); + EXPECT_EQ(session->getGraphSize(kStreamRtcp), 1); + + config.setRemotePort(30000); + config.setMediaDirection(RtpConfig::MEDIA_DIRECTION_RECEIVE_ONLY); + EXPECT_EQ(session->addGraph(&config, true), RESULT_SUCCESS); + EXPECT_EQ(session->getState(), kSessionStateReceiving); + + EXPECT_EQ(session->getGraphSize(kStreamRtpTx), 2); + EXPECT_EQ(session->getGraphSize(kStreamRtpRx), 2); + EXPECT_EQ(session->getGraphSize(kStreamRtcp), 2); +} + +TEST_F(AudioSessionTest, testStartAddDeleteConfirmGraph) +{ + session->setLocalEndPoint(socketRtpFd, socketRtcpFd); + EXPECT_EQ(session->startGraph(&config), RESULT_SUCCESS); + EXPECT_EQ(session->getState(), kSessionStateActive); + + config.setRemotePort(20000); + EXPECT_EQ(session->addGraph(&config, true), RESULT_SUCCESS); + EXPECT_EQ(session->getState(), kSessionStateActive); + EXPECT_EQ(session->getGraphSize(kStreamRtpTx), 2); + EXPECT_EQ(session->getGraphSize(kStreamRtpRx), 2); + EXPECT_EQ(session->getGraphSize(kStreamRtcp), 2); + + EXPECT_EQ(session->confirmGraph(&config), RESULT_SUCCESS); + EXPECT_EQ(session->getState(), kSessionStateActive); + EXPECT_EQ(session->getGraphSize(kStreamRtpTx), 1); + EXPECT_EQ(session->getGraphSize(kStreamRtpRx), 1); + EXPECT_EQ(session->getGraphSize(kStreamRtcp), 1); +} + +TEST_F(AudioSessionTest, testStartAndAddWithRtcpOff) +{ + session->setLocalEndPoint(socketRtpFd, socketRtcpFd); + EXPECT_EQ(session->startGraph(&config), RESULT_SUCCESS); + EXPECT_EQ(session->getState(), kSessionStateActive); + + config.setRemotePort(20000); + EXPECT_EQ(session->addGraph(&config, false), RESULT_SUCCESS); + EXPECT_EQ(session->getState(), kSessionStateActive); + EXPECT_EQ(session->getGraphSize(kStreamRtpTx), 1); + EXPECT_EQ(session->getGraphSize(kStreamRtpRx), 1); + EXPECT_EQ(session->getGraphSize(kStreamRtcp), 1); +} \ No newline at end of file -- cgit v1.2.3