summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbodamnam <bodamnam@google.com>2023-03-20 14:04:49 +0000
committerBodam Nam <bodamnam@google.com>2023-04-05 02:57:52 +0000
commit1e1b64767a2adb1b3526d29a6fc2348ad3cfcd2a (patch)
treebc60b860aa56b3a5f08a89eef0b8f7563ed1f78b
parent475cf479c2ee232bb9b42b9de437e78c853cd4e9 (diff)
downloadImsMedia-1e1b64767a2adb1b3526d29a6fc2348ad3cfcd2a.tar.gz
Add UT for AudioManager
Fix the crash during the AudioManager UT by the racing codition accessing the AudioManager instance between AudioManger destruction and processEvent in ImsMediaEventHandler. Bug: 272299058 Test: atest ImsMediaNativeTests, Verified the voice call in live network. Change-Id: I9bed59f9bfe2916ccdc2fae2c671c8811bcdcdca
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioManager.cpp116
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioManager.h22
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/text/TextManager.h8
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/utils/ImsMediaEventHandler.h4
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/VideoManager.h8
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextManager.cpp27
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaEventHandler.cpp31
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoManager.cpp27
-rw-r--r--tests/native/Android.bp1
-rw-r--r--tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioManagerTest.cpp683
-rw-r--r--tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/include/core/audio/MockAudioManager.h39
11 files changed, 835 insertions, 131 deletions
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 49efef54..e957cc3b 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
@@ -23,9 +23,18 @@ using namespace android;
AudioManager* AudioManager::sManager = nullptr;
-AudioManager::AudioManager() {}
+AudioManager::AudioManager()
+{
+ mRequestHandler.Init("AUDIO_REQUEST_EVENT");
+ mResponseHandler.Init("AUDIO_RESPONSE_EVENT");
+}
-AudioManager::~AudioManager() {}
+AudioManager::~AudioManager()
+{
+ mRequestHandler.Deinit();
+ mResponseHandler.Deinit();
+ sManager = nullptr;
+}
AudioManager* AudioManager::getInstance()
{
@@ -203,6 +212,22 @@ void AudioManager::setMediaQualityThreshold(int sessionId, MediaQualityThreshold
}
}
+void AudioManager::SendInternalEvent(
+ uint32_t event, uint64_t sessionId, uint64_t paramA, uint64_t paramB)
+{
+ auto session = mSessions.find(sessionId);
+ IMLOGI1("[SendInternalEvent] sessionId[%d]", sessionId);
+
+ if (session != mSessions.end())
+ {
+ (session->second)->SendInternalEvent(event, paramA, paramB);
+ }
+ else
+ {
+ IMLOGE1("[SendInternalEvent] no session id[%d]", sessionId);
+ }
+}
+
void AudioManager::sendMessage(const int sessionId, const android::Parcel& parcel)
{
int nMsg = parcel.readInt32();
@@ -283,35 +308,19 @@ void AudioManager::sendMessage(const int sessionId, const android::Parcel& parce
}
}
-void AudioManager::SendInternalEvent(
- uint32_t event, uint64_t sessionId, uint64_t paramA, uint64_t paramB)
-{
- auto session = mSessions.find(sessionId);
- IMLOGI1("[SendInternalEvent] sessionId[%d]", sessionId);
-
- if (session != mSessions.end())
- {
- (session->second)->SendInternalEvent(event, paramA, paramB);
- }
- else
- {
- IMLOGE1("[SendInternalEvent] no session id[%d]", sessionId);
- }
-}
-
-AudioManager::RequestHandler::RequestHandler() :
- ImsMediaEventHandler("AUDIO_REQUEST_EVENT")
-{
-}
-
-AudioManager::RequestHandler::~RequestHandler() {}
-
void AudioManager::RequestHandler::processEvent(
uint32_t event, uint64_t sessionId, uint64_t paramA, uint64_t paramB)
{
IMLOGI4("[processEvent] event[%d], sessionId[%d], paramA[%d], paramB[%d]", event, sessionId,
paramA, paramB);
ImsMediaResult result = RESULT_SUCCESS;
+
+ if (sManager == nullptr)
+ {
+ IMLOGE0("[processEvent] not ready");
+ return;
+ }
+
switch (event)
{
case kAudioOpenSession:
@@ -320,7 +329,7 @@ void AudioManager::RequestHandler::processEvent(
if (param != nullptr)
{
AudioConfig* pConfig = reinterpret_cast<AudioConfig*>(param->mConfig);
- result = AudioManager::getInstance()->openSession(
+ result = sManager->openSession(
static_cast<int>(sessionId), param->rtpFd, param->rtcpFd, pConfig);
if (result == RESULT_SUCCESS)
@@ -349,8 +358,7 @@ void AudioManager::RequestHandler::processEvent(
}
break;
case kAudioCloseSession:
- if (AudioManager::getInstance()->closeSession(static_cast<int>(sessionId)) ==
- RESULT_SUCCESS)
+ if (sManager->closeSession(static_cast<int>(sessionId)) == RESULT_SUCCESS)
{
ImsMediaEventHandler::SendEvent(
"AUDIO_RESPONSE_EVENT", kAudioSessionClosed, sessionId, 0, 0);
@@ -359,8 +367,7 @@ void AudioManager::RequestHandler::processEvent(
case kAudioModifySession:
{
AudioConfig* config = reinterpret_cast<AudioConfig*>(paramA);
- result =
- AudioManager::getInstance()->modifySession(static_cast<int>(sessionId), config);
+ result = sManager->modifySession(static_cast<int>(sessionId), config);
ImsMediaEventHandler::SendEvent(
"AUDIO_RESPONSE_EVENT", kAudioModifySessionResponse, sessionId, result, paramA);
}
@@ -368,7 +375,7 @@ void AudioManager::RequestHandler::processEvent(
case kAudioAddConfig:
{
AudioConfig* config = reinterpret_cast<AudioConfig*>(paramA);
- result = AudioManager::getInstance()->addConfig(static_cast<int>(sessionId), config);
+ result = sManager->addConfig(static_cast<int>(sessionId), config);
ImsMediaEventHandler::SendEvent(
"AUDIO_RESPONSE_EVENT", kAudioAddConfigResponse, sessionId, result, paramA);
}
@@ -376,8 +383,7 @@ void AudioManager::RequestHandler::processEvent(
case kAudioConfirmConfig:
{
AudioConfig* config = reinterpret_cast<AudioConfig*>(paramA);
- result =
- AudioManager::getInstance()->confirmConfig(static_cast<int>(sessionId), config);
+ result = sManager->confirmConfig(static_cast<int>(sessionId), config);
ImsMediaEventHandler::SendEvent(
"AUDIO_RESPONSE_EVENT", kAudioConfirmConfigResponse, sessionId, result, paramA);
}
@@ -387,7 +393,7 @@ void AudioManager::RequestHandler::processEvent(
AudioConfig* config = reinterpret_cast<AudioConfig*>(paramA);
if (config != nullptr)
{
- AudioManager::getInstance()->deleteConfig(static_cast<int>(sessionId), config);
+ sManager->deleteConfig(static_cast<int>(sessionId), config);
delete config;
}
}
@@ -397,8 +403,7 @@ void AudioManager::RequestHandler::processEvent(
EventParamDtmf* param = reinterpret_cast<EventParamDtmf*>(paramA);
if (param != nullptr)
{
- AudioManager::getInstance()->sendDtmf(
- static_cast<int>(sessionId), param->digit, param->duration);
+ sManager->sendDtmf(static_cast<int>(sessionId), param->digit, param->duration);
delete param;
}
}
@@ -410,8 +415,7 @@ void AudioManager::RequestHandler::processEvent(
if (listExtension != nullptr)
{
- AudioManager::getInstance()->sendRtpHeaderExtension(
- static_cast<int>(sessionId), listExtension);
+ sManager->sendRtpHeaderExtension(static_cast<int>(sessionId), listExtension);
delete listExtension;
}
}
@@ -421,34 +425,32 @@ void AudioManager::RequestHandler::processEvent(
MediaQualityThreshold* threshold = reinterpret_cast<MediaQualityThreshold*>(paramA);
if (threshold != nullptr)
{
- AudioManager::getInstance()->setMediaQualityThreshold(
- static_cast<int>(sessionId), threshold);
+ sManager->setMediaQualityThreshold(static_cast<int>(sessionId), threshold);
delete threshold;
}
}
break;
case kRequestAudioCmr:
case kRequestSendRtcpXrReport:
- AudioManager::getInstance()->SendInternalEvent(
- event, static_cast<int>(sessionId), paramA, paramB);
+ sManager->SendInternalEvent(event, static_cast<int>(sessionId), paramA, paramB);
break;
default:
break;
}
}
-AudioManager::ResponseHandler::ResponseHandler() :
- ImsMediaEventHandler("AUDIO_RESPONSE_EVENT")
-{
-}
-
-AudioManager::ResponseHandler::~ResponseHandler() {}
-
void AudioManager::ResponseHandler::processEvent(
uint32_t event, uint64_t sessionId, uint64_t paramA, uint64_t paramB)
{
IMLOGI4("[processEvent] event[%d], sessionId[%d], paramA[%d], paramB[%d]", event, sessionId,
paramA, paramB);
+
+ if (sManager == nullptr)
+ {
+ IMLOGE0("[processEvent] not ready");
+ return;
+ }
+
android::Parcel parcel;
switch (event)
{
@@ -461,7 +463,7 @@ void AudioManager::ResponseHandler::processEvent(
// fail reason
parcel.writeInt32(static_cast<int>(paramA));
}
- AudioManager::getInstance()->sendResponse(sessionId, parcel);
+ sManager->sendResponse(sessionId, parcel);
break;
case kAudioModifySessionResponse: // fall through
case kAudioAddConfigResponse: // fall through
@@ -473,7 +475,7 @@ void AudioManager::ResponseHandler::processEvent(
if (config != nullptr)
{
config->writeToParcel(&parcel);
- AudioManager::getInstance()->sendResponse(sessionId, parcel);
+ sManager->sendResponse(sessionId, parcel);
delete config;
}
}
@@ -485,7 +487,7 @@ void AudioManager::ResponseHandler::processEvent(
if (config != nullptr)
{
config->writeToParcel(&parcel);
- AudioManager::getInstance()->sendResponse(sessionId, parcel);
+ sManager->sendResponse(sessionId, parcel);
delete config;
}
}
@@ -505,7 +507,7 @@ void AudioManager::ResponseHandler::processEvent(
extension.writeToParcel(&parcel);
}
- AudioManager::getInstance()->sendResponse(sessionId, parcel);
+ sManager->sendResponse(sessionId, parcel);
delete listExtension;
}
}
@@ -517,7 +519,7 @@ void AudioManager::ResponseHandler::processEvent(
if (status != nullptr)
{
status->writeToParcel(&parcel);
- AudioManager::getInstance()->sendResponse(sessionId, parcel);
+ sManager->sendResponse(sessionId, parcel);
delete status;
}
}
@@ -529,7 +531,7 @@ void AudioManager::ResponseHandler::processEvent(
parcel.writeInt32(event);
parcel.writeByte(static_cast<uint8_t>(paramA));
parcel.writeInt32(static_cast<int>(paramB));
- AudioManager::getInstance()->sendResponse(sessionId, parcel);
+ sManager->sendResponse(sessionId, parcel);
break;
case kAudioCallQualityChangedInd:
{
@@ -538,7 +540,7 @@ void AudioManager::ResponseHandler::processEvent(
if (quality != nullptr)
{
quality->writeToParcel(&parcel);
- AudioManager::getInstance()->sendResponse(sessionId, parcel);
+ sManager->sendResponse(sessionId, parcel);
delete quality;
}
}
@@ -546,7 +548,7 @@ void AudioManager::ResponseHandler::processEvent(
case kAudioSessionClosed:
parcel.writeInt32(event);
parcel.writeInt32(static_cast<int>(sessionId));
- AudioManager::getInstance()->sendResponse(sessionId, parcel);
+ sManager->sendResponse(sessionId, parcel);
break;
default:
break;
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioManager.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioManager.h
index 231b4141..d2a0e441 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioManager.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioManager.h
@@ -37,10 +37,6 @@ public:
*/
class RequestHandler : public ImsMediaEventHandler
{
- public:
- RequestHandler();
- virtual ~RequestHandler();
-
protected:
virtual void processEvent(
uint32_t event, uint64_t sessionId, uint64_t paramA, uint64_t paramB);
@@ -51,10 +47,6 @@ public:
*/
class ResponseHandler : public ImsMediaEventHandler
{
- public:
- ResponseHandler();
- virtual ~ResponseHandler();
-
protected:
virtual void processEvent(
uint32_t event, uint64_t sessionId, uint64_t paramA, uint64_t paramB);
@@ -63,20 +55,22 @@ public:
static AudioManager* getInstance();
virtual int getState(int sessionId);
virtual void sendMessage(const int sessionId, const android::Parcel& parcel);
- void SendInternalEvent(uint32_t event, uint64_t sessionId, uint64_t paramA, uint64_t paramB);
-private:
+protected:
AudioManager();
virtual ~AudioManager();
ImsMediaResult openSession(int sessionId, int rtpFd, int rtcpFd, AudioConfig* config);
ImsMediaResult closeSession(int sessionId);
ImsMediaResult modifySession(int sessionId, AudioConfig* config);
ImsMediaResult addConfig(int sessionId, AudioConfig* config);
- ImsMediaResult deleteConfig(int sessionId, AudioConfig* config);
+ virtual ImsMediaResult deleteConfig(int sessionId, AudioConfig* config);
ImsMediaResult confirmConfig(int sessionId, AudioConfig* config);
- void sendDtmf(int sessionId, char dtmfDigit, int duration);
- void sendRtpHeaderExtension(int sessionId, std::list<RtpHeaderExtension>* listExtension);
- void setMediaQualityThreshold(int sessionId, MediaQualityThreshold* threshold);
+ virtual void sendDtmf(int sessionId, char dtmfDigit, int duration);
+ virtual void sendRtpHeaderExtension(
+ int sessionId, std::list<RtpHeaderExtension>* listExtension);
+ virtual void setMediaQualityThreshold(int sessionId, MediaQualityThreshold* threshold);
+ virtual void SendInternalEvent(
+ uint32_t event, uint64_t sessionId, uint64_t paramA, uint64_t paramB);
static AudioManager* sManager;
std::unordered_map<int, std::unique_ptr<AudioSession>> mSessions;
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/text/TextManager.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/text/TextManager.h
index 66201daa..67b24ed3 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/text/TextManager.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/text/TextManager.h
@@ -37,10 +37,6 @@ public:
*/
class RequestHandler : public ImsMediaEventHandler
{
- public:
- RequestHandler();
- virtual ~RequestHandler();
-
protected:
virtual void processEvent(
uint32_t event, uint64_t sessionId, uint64_t paramA, uint64_t paramB);
@@ -51,10 +47,6 @@ public:
*/
class ResponseHandler : public ImsMediaEventHandler
{
- public:
- ResponseHandler();
- virtual ~ResponseHandler();
-
protected:
virtual void processEvent(
uint32_t event, uint64_t sessionId, uint64_t paramA, uint64_t paramB);
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/utils/ImsMediaEventHandler.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/utils/ImsMediaEventHandler.h
index 4e5dc7f0..e01761da 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/utils/ImsMediaEventHandler.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/utils/ImsMediaEventHandler.h
@@ -46,8 +46,10 @@ private:
std::mutex mMutexEvent;
public:
- ImsMediaEventHandler(const char* strName);
+ ImsMediaEventHandler();
virtual ~ImsMediaEventHandler();
+ void Init(const char* strName);
+ void Deinit();
static void SendEvent(const char* strEventHandlerName, uint32_t event, uint64_t paramA,
uint64_t paramB = 0, uint64_t paramC = 0);
char* getName();
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/VideoManager.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/VideoManager.h
index 7c780fd0..91c2747b 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/VideoManager.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/VideoManager.h
@@ -37,10 +37,6 @@ public:
*/
class RequestHandler : public ImsMediaEventHandler
{
- public:
- RequestHandler();
- virtual ~RequestHandler();
-
protected:
virtual void processEvent(
uint32_t event, uint64_t sessionId, uint64_t paramA, uint64_t paramB);
@@ -51,10 +47,6 @@ public:
*/
class ResponseHandler : public ImsMediaEventHandler
{
- public:
- ResponseHandler();
- virtual ~ResponseHandler();
-
protected:
virtual void processEvent(
uint32_t event, uint64_t sessionId, uint64_t paramA, uint64_t paramB);
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextManager.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextManager.cpp
index f50a0ba8..33ad7a20 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextManager.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextManager.cpp
@@ -21,9 +21,18 @@
using namespace android;
TextManager* TextManager::manager;
-TextManager::TextManager() {}
+TextManager::TextManager()
+{
+ mRequestHandler.Init("TEXT_REQUEST_EVENT");
+ mResponseHandler.Init("TEXT_RESPONSE_EVENT");
+}
-TextManager::~TextManager() {}
+TextManager::~TextManager()
+{
+ mRequestHandler.Deinit();
+ mResponseHandler.Deinit();
+ manager = nullptr;
+}
TextManager* TextManager::getInstance()
{
@@ -200,13 +209,6 @@ void TextManager::sendMessage(const int sessionId, const android::Parcel& parcel
}
}
-TextManager::RequestHandler::RequestHandler() :
- ImsMediaEventHandler("TEXT_REQUEST_EVENT")
-{
-}
-
-TextManager::RequestHandler::~RequestHandler() {}
-
void TextManager::RequestHandler::processEvent(
uint32_t event, uint64_t sessionId, uint64_t paramA, uint64_t paramB)
{
@@ -294,13 +296,6 @@ void TextManager::RequestHandler::processEvent(
}
}
-TextManager::ResponseHandler::ResponseHandler() :
- ImsMediaEventHandler("TEXT_RESPONSE_EVENT")
-{
-}
-
-TextManager::ResponseHandler::~ResponseHandler() {}
-
void TextManager::ResponseHandler::processEvent(
uint32_t event, uint64_t sessionId, uint64_t paramA, uint64_t paramB)
{
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaEventHandler.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaEventHandler.cpp
index b3d165ab..336f2aa5 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaEventHandler.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaEventHandler.cpp
@@ -22,24 +22,29 @@
std::list<ImsMediaEventHandler*> ImsMediaEventHandler::gListEventHandler;
std::mutex ImsMediaEventHandler::mMutex;
-ImsMediaEventHandler::ImsMediaEventHandler(const char* strName)
+ImsMediaEventHandler::ImsMediaEventHandler() {}
+
+ImsMediaEventHandler::~ImsMediaEventHandler() {}
+
+void ImsMediaEventHandler::Init(const char* strName)
{
strncpy(mName, strName, MAX_EVENTHANDLER_NAME);
mbTerminate = false;
gListEventHandler.push_back(this);
- IMLOGD1("[ImsMediaEventHandler] %s", mName);
+ IMLOGD1("[Init] %s", mName);
StartThread();
}
-ImsMediaEventHandler::~ImsMediaEventHandler()
+void ImsMediaEventHandler::Deinit()
{
- IMLOGD1("[~ImsMediaEventHandler] %s", mName);
+ IMLOGD2("[Deinit] %s, queue size[%d]", mName, mListevent.size());
+ std::lock_guard<std::mutex> guard(mMutexEvent);
+ StopThread();
gListEventHandler.remove(this);
mListevent.clear();
mListParamA.clear();
mListParamB.clear();
mListParamC.clear();
- StopThread();
mCondition.signal();
mConditionExit.wait();
}
@@ -73,13 +78,12 @@ char* ImsMediaEventHandler::getName()
void ImsMediaEventHandler::AddEvent(
uint32_t event, uint64_t paramA, uint64_t paramB, uint64_t paramC)
{
+ std::lock_guard<std::mutex> guard(mMutexEvent);
IMLOGD3("[AddEvent] %s, event[%d], size[%d]", mName, event, mListevent.size());
- mMutexEvent.lock();
mListevent.push_back(event);
mListParamA.push_back(paramA);
mListParamB.push_back(paramB);
mListParamC.push_back(paramC);
- mMutexEvent.unlock();
mCondition.signal();
}
@@ -94,17 +98,22 @@ void* ImsMediaEventHandler::run()
for (;;)
{
- // lock
+ if (IsThreadStopped())
+ {
+ break;
+ }
+
mMutexEvent.lock();
- if (IsThreadStopped() || mListevent.size() == 0)
+
+ if (mListevent.size() == 0)
{
mMutexEvent.unlock();
break;
}
- mMutexEvent.unlock();
+
processEvent(mListevent.front(), mListParamA.front(), mListParamB.front(),
mListParamC.front());
- mMutexEvent.lock();
+
mListevent.pop_front();
mListParamA.pop_front();
mListParamB.pop_front();
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoManager.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoManager.cpp
index 9d98be37..37007b21 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoManager.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoManager.cpp
@@ -21,9 +21,18 @@
using namespace android;
VideoManager* VideoManager::manager;
-VideoManager::VideoManager() {}
+VideoManager::VideoManager()
+{
+ mRequestHandler.Init("VIDEO_REQUEST_EVENT");
+ mResponseHandler.Init("VIDEO_RESPONSE_EVENT");
+}
-VideoManager::~VideoManager() {}
+VideoManager::~VideoManager()
+{
+ mRequestHandler.Deinit();
+ mResponseHandler.Deinit();
+ manager = nullptr;
+}
VideoManager* VideoManager::getInstance()
{
@@ -245,13 +254,6 @@ void VideoManager::SendInternalEvent(
}
}
-VideoManager::RequestHandler::RequestHandler() :
- ImsMediaEventHandler("VIDEO_REQUEST_EVENT")
-{
-}
-
-VideoManager::RequestHandler::~RequestHandler() {}
-
void VideoManager::RequestHandler::processEvent(
uint32_t event, uint64_t sessionId, uint64_t paramA, uint64_t paramB)
{
@@ -351,13 +353,6 @@ void VideoManager::RequestHandler::processEvent(
}
}
-VideoManager::ResponseHandler::ResponseHandler() :
- ImsMediaEventHandler("VIDEO_RESPONSE_EVENT")
-{
-}
-
-VideoManager::ResponseHandler::~ResponseHandler() {}
-
void VideoManager::ResponseHandler::processEvent(
uint32_t event, uint64_t sessionId, uint64_t paramA, uint64_t paramB)
{
diff --git a/tests/native/Android.bp b/tests/native/Android.bp
index 5000dee4..4171f753 100644
--- a/tests/native/Android.bp
+++ b/tests/native/Android.bp
@@ -22,6 +22,7 @@ cc_library_headers {
name: "libimsmedia_tests_headers",
export_include_dirs: [
"service/src/com/android/telephony/imsmedia/lib/libimsmedia/include",
+ "service/src/com/android/telephony/imsmedia/lib/libimsmedia/include/core/audio",
],
}
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioManagerTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioManagerTest.cpp
new file mode 100644
index 00000000..9f8cc4c5
--- /dev/null
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioManagerTest.cpp
@@ -0,0 +1,683 @@
+/**
+ * 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 <gtest/gtest.h>
+#include <ImsMediaNetworkUtil.h>
+#include <AudioConfig.h>
+#include <MockAudioManager.h>
+#include <ImsMediaCondition.h>
+#include <unordered_map>
+#include <algorithm>
+
+using namespace android::telephony::imsmedia;
+
+using ::testing::_;
+using ::testing::Eq;
+using ::testing::Pointee;
+using ::testing::Ref;
+using ::testing::Return;
+
+// 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;
+
+int32_t kSessionId = 0;
+
+static ImsMediaCondition gCondition;
+
+class AudioManagerCallback
+{
+public:
+ int32_t resSessionId;
+ int32_t response;
+ AudioConfig resConfig;
+ ImsMediaResult result;
+ std::list<RtpHeaderExtension> extensions;
+ MediaQualityStatus mediaQualityStatus;
+ char receivedDtmfDigit;
+ int32_t receivedDtmfDuration;
+ CallQuality callQuality;
+
+ void resetRespond()
+ {
+ resSessionId = -1;
+ response = -1;
+ result = RESULT_NOT_READY;
+ }
+
+ void onCallback(const int id, const int event, const ImsMediaResult res)
+ {
+ resSessionId = id;
+ response = event;
+ result = res;
+ }
+
+ void onCallbackConfig(
+ const int id, const int event, const ImsMediaResult res, const AudioConfig& config)
+ {
+ resSessionId = id;
+ response = event;
+ resConfig = config;
+ result = res;
+ }
+
+ void onCallbackHeaderExtension(
+ const int id, const int event, const std::list<RtpHeaderExtension>& list)
+ {
+ extensions.clear();
+ resSessionId = id;
+ response = event;
+ std::copy(list.begin(), list.end(), std::back_inserter(extensions));
+ }
+
+ void onCallbackMediaQualityStatus(
+ const int id, const int event, const MediaQualityStatus& status)
+ {
+ resSessionId = id;
+ response = event;
+ mediaQualityStatus = status;
+ }
+
+ void onCallbackDtmfReceived(const int id, const int event, char digit, int32_t duration)
+ {
+ resSessionId = id;
+ response = event;
+ receivedDtmfDigit = digit;
+ receivedDtmfDuration = duration;
+ }
+
+ void onCallbackCallQuality(const int id, const int event, const CallQuality& status)
+ {
+ resSessionId = id;
+ response = event;
+ callQuality = status;
+ }
+};
+
+static std::unordered_map<int, AudioManagerCallback*> gMapCallback;
+
+class AudioManagerTest : public ::testing::Test
+{
+public:
+ MockAudioManager manager;
+ AudioConfig config;
+ RtcpConfig rtcp;
+ AmrParams amr;
+ EvsParams evs;
+ int socketRtpFd;
+ int socketRtcpFd;
+ AudioManagerCallback callback;
+
+ AudioManagerTest()
+ {
+ socketRtpFd = -1;
+ socketRtcpFd = -1;
+ callback.resetRespond();
+ gCondition.reset();
+ }
+ ~AudioManagerTest() {}
+
+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);
+
+ manager.setCallback(&audioCallback);
+ gMapCallback.insert(std::make_pair(kSessionId, &callback));
+ 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);
+ gCondition.reset();
+ }
+
+ virtual void TearDown() override
+ {
+ if (socketRtpFd != -1)
+ {
+ ImsMediaNetworkUtil::closeSocket(socketRtpFd);
+ }
+
+ if (socketRtcpFd != -1)
+ {
+ ImsMediaNetworkUtil::closeSocket(socketRtcpFd);
+ }
+
+ gMapCallback.erase(kSessionId);
+ }
+
+ void openSession(const int32_t sessionId)
+ {
+ callback.resetRespond();
+ android::Parcel parcel;
+ parcel.writeInt32(kAudioOpenSession);
+ parcel.writeInt32(socketRtpFd);
+ parcel.writeInt32(socketRtcpFd);
+ parcel.setDataPosition(0);
+ gCondition.reset();
+ manager.sendMessage(sessionId, parcel);
+ EXPECT_TRUE(!gCondition.wait_timeout(1000));
+ EXPECT_EQ(callback.resSessionId, sessionId);
+ EXPECT_EQ(callback.response, kAudioOpenSessionSuccess);
+ }
+
+ void closeSession(const int32_t sessionId)
+ {
+ callback.resetRespond();
+ android::Parcel parcel;
+ parcel.writeInt32(kAudioCloseSession);
+ parcel.setDataPosition(0);
+ gCondition.reset();
+ manager.sendMessage(sessionId, parcel);
+ EXPECT_TRUE(!gCondition.wait_timeout(1000));
+ EXPECT_EQ(callback.resSessionId, sessionId);
+ EXPECT_EQ(callback.response, kAudioSessionClosed);
+ }
+
+ void testEventResponse(const int32_t sessionId, const int32_t event, AudioConfig* config,
+ const int32_t response, const int32_t result)
+ {
+ callback.resetRespond();
+ android::Parcel parcel;
+ parcel.writeInt32(event);
+
+ if (config != nullptr)
+ {
+ config->writeToParcel(&parcel);
+ }
+
+ parcel.setDataPosition(0);
+ gCondition.reset();
+ manager.sendMessage(sessionId, parcel);
+ EXPECT_TRUE(!gCondition.wait_timeout(1000));
+ EXPECT_EQ(callback.resSessionId, sessionId);
+ EXPECT_EQ(callback.response, response);
+
+ if (callback.response >= kAudioOpenSessionFailure &&
+ callback.response <= kAudioConfirmConfigResponse)
+ {
+ EXPECT_EQ(result, result);
+
+ if (config != nullptr && callback.response >= kAudioModifySessionResponse &&
+ callback.response <= kAudioConfirmConfigResponse)
+ {
+ EXPECT_EQ(callback.resConfig, *config);
+ }
+ }
+ }
+
+ static int32_t audioCallback(int sessionId, const android::Parcel& parcel)
+ {
+ parcel.setDataPosition(0);
+
+ int response = parcel.readInt32();
+ ImsMediaResult result = RESULT_INVALID_PARAM;
+
+ auto callback = gMapCallback.find(sessionId);
+
+ if (callback != gMapCallback.end())
+ {
+ if (response >= kAudioOpenSessionFailure && response <= kAudioConfirmConfigResponse)
+ {
+ result = static_cast<ImsMediaResult>(parcel.readInt32());
+ }
+
+ switch (response)
+ {
+ case kAudioModifySessionResponse:
+ case kAudioAddConfigResponse:
+ case kAudioConfirmConfigResponse:
+ {
+ AudioConfig resConfig;
+ resConfig.readFromParcel(&parcel);
+ (callback->second)->onCallbackConfig(sessionId, response, result, resConfig);
+ }
+ break;
+ case kAudioFirstMediaPacketInd:
+ {
+ AudioConfig resConfig;
+ resConfig.readFromParcel(&parcel);
+ (callback->second)
+ ->onCallbackConfig(sessionId, response, RESULT_SUCCESS, resConfig);
+ }
+ break;
+ case kAudioRtpHeaderExtensionInd:
+ {
+ std::list<RtpHeaderExtension> listExtension;
+ int32_t listSize = parcel.readInt32();
+
+ for (int32_t i = 0; i < listSize; i++)
+ {
+ RtpHeaderExtension extension;
+ extension.readFromParcel(&parcel);
+ listExtension.push_back(extension);
+ }
+
+ (callback->second)
+ ->onCallbackHeaderExtension(sessionId, response, listExtension);
+ }
+ break;
+ case kAudioMediaQualityStatusInd:
+ {
+ MediaQualityStatus status;
+ status.readFromParcel(&parcel);
+ (callback->second)->onCallbackMediaQualityStatus(sessionId, response, status);
+ }
+ break;
+ case kAudioDtmfReceivedInd:
+ (callback->second)
+ ->onCallbackDtmfReceived(
+ sessionId, response, parcel.readByte(), parcel.readInt32());
+ break;
+ case kAudioCallQualityChangedInd:
+ {
+ CallQuality quality;
+ quality.readFromParcel(&parcel);
+ (callback->second)->onCallbackCallQuality(sessionId, response, quality);
+ }
+ break;
+ default:
+ (callback->second)->onCallback(sessionId, response, result);
+ break;
+ }
+ }
+
+ if (response != kAudioCallQualityChangedInd)
+ {
+ gCondition.signal();
+ }
+
+ return 0;
+ }
+};
+
+TEST_F(AudioManagerTest, testOpenCloseSession)
+{
+ EXPECT_EQ(manager.getState(kSessionId), kSessionStateClosed);
+ openSession(kSessionId);
+ closeSession(kSessionId);
+}
+
+TEST_F(AudioManagerTest, testModifySession)
+{
+ testEventResponse(kSessionId, kAudioModifySession, nullptr, kAudioModifySessionResponse,
+ RESULT_INVALID_PARAM);
+
+ openSession(kSessionId);
+
+ testEventResponse(kSessionId, kAudioModifySession, nullptr, kAudioModifySessionResponse,
+ RESULT_INVALID_PARAM);
+
+ testEventResponse(
+ kSessionId, kAudioModifySession, &config, kAudioModifySessionResponse, RESULT_SUCCESS);
+
+ closeSession(kSessionId);
+}
+
+TEST_F(AudioManagerTest, testAddConfig)
+{
+ testEventResponse(
+ kSessionId, kAudioAddConfig, nullptr, kAudioAddConfigResponse, RESULT_INVALID_PARAM);
+
+ openSession(kSessionId);
+
+ testEventResponse(
+ kSessionId, kAudioAddConfig, nullptr, kAudioAddConfigResponse, RESULT_INVALID_PARAM);
+
+ testEventResponse(
+ kSessionId, kAudioAddConfig, &config, kAudioAddConfigResponse, RESULT_SUCCESS);
+
+ closeSession(kSessionId);
+}
+
+TEST_F(AudioManagerTest, testConfirmConfig)
+{
+ testEventResponse(kSessionId, kAudioConfirmConfig, nullptr, kAudioConfirmConfigResponse,
+ RESULT_INVALID_PARAM);
+
+ openSession(kSessionId);
+
+ testEventResponse(kSessionId, kAudioConfirmConfig, nullptr, kAudioConfirmConfigResponse,
+ RESULT_INVALID_PARAM);
+
+ testEventResponse(
+ kSessionId, kAudioConfirmConfig, &config, kAudioConfirmConfigResponse, RESULT_SUCCESS);
+
+ closeSession(kSessionId);
+}
+
+TEST_F(AudioManagerTest, testDeleteConfig)
+{
+ openSession(kSessionId);
+
+ android::Parcel parcel;
+ parcel.writeInt32(kAudioDeleteConfig);
+
+ if (config != nullptr)
+ {
+ config.writeToParcel(&parcel);
+ }
+
+ EXPECT_CALL(manager, deleteConfig(kSessionId, Pointee(Eq(config))))
+ .Times(1)
+ .WillOnce(Return(RESULT_INVALID_PARAM));
+
+ parcel.setDataPosition(0);
+ manager.sendMessage(kSessionId, parcel);
+
+ closeSession(kSessionId);
+}
+
+TEST_F(AudioManagerTest, testSendDtmf)
+{
+ openSession(kSessionId);
+
+ const char kDigit = '1';
+ const int32_t kDuration = 100;
+
+ android::Parcel parcel;
+ parcel.writeInt32(kAudioSendDtmf);
+ parcel.writeByte(kDigit);
+ parcel.writeInt32(kDuration);
+ parcel.setDataPosition(0);
+
+ EXPECT_CALL(manager, sendDtmf(kSessionId, kDigit, kDuration)).Times(1).WillOnce(Return());
+
+ manager.sendMessage(kSessionId, parcel);
+
+ closeSession(kSessionId);
+}
+
+TEST_F(AudioManagerTest, testSendHeaderExtension)
+{
+ openSession(kSessionId);
+
+ std::list<RtpHeaderExtension> extensions;
+ RtpHeaderExtension extension;
+ const uint8_t kExtensionData[] = {0x01, 0x02};
+ const int32_t kExtensionDataSize = 2;
+ extension.setLocalIdentifier(15);
+ extension.setExtensionData(kExtensionData, kExtensionDataSize);
+ extensions.push_back(extension);
+
+ android::Parcel parcel;
+ parcel.writeInt32(kAudioSendRtpHeaderExtension);
+ parcel.writeInt32(extensions.size());
+
+ for (auto& item : extensions)
+ {
+ item.writeToParcel(&parcel);
+ }
+
+ parcel.setDataPosition(0);
+
+ EXPECT_CALL(manager, sendRtpHeaderExtension(kSessionId, Pointee(Eq(extensions))))
+ .Times(1)
+ .WillOnce(Return());
+
+ manager.sendMessage(kSessionId, parcel);
+
+ closeSession(kSessionId);
+}
+
+TEST_F(AudioManagerTest, testSetMediaQualityThreshold)
+{
+ openSession(kSessionId);
+
+ const std::vector<int32_t> kRtpInactivityTimerMillis = {10000, 20000};
+ const int32_t kRtcpInactivityTimerMillis = 20000;
+ const int32_t kRtpHysteresisTimeInMillis = 3000;
+ const int32_t kRtpPacketLossDurationMillis = 5000;
+ const std::vector<int32_t> kRtpPacketLossRate = {3, 5};
+ const std::vector<int32_t> kRtpJitterMillis = {100, 200};
+ const bool kNotifyCurrentStatus = false;
+
+ MediaQualityThreshold threshold;
+ threshold.setRtpInactivityTimerMillis(kRtpInactivityTimerMillis);
+ threshold.setRtcpInactivityTimerMillis(kRtcpInactivityTimerMillis);
+ threshold.setRtpHysteresisTimeInMillis(kRtpHysteresisTimeInMillis);
+ threshold.setRtpPacketLossDurationMillis(kRtpPacketLossDurationMillis);
+ threshold.setRtpPacketLossRate(kRtpPacketLossRate);
+ threshold.setRtpJitterMillis(kRtpJitterMillis);
+ threshold.setNotifyCurrentStatus(kNotifyCurrentStatus);
+
+ android::Parcel parcel;
+ parcel.writeInt32(kAudioSetMediaQualityThreshold);
+ threshold.writeToParcel(&parcel);
+ parcel.setDataPosition(0);
+
+ EXPECT_CALL(manager, setMediaQualityThreshold(kSessionId, Pointee(Eq(threshold))))
+ .Times(1)
+ .WillOnce(Return());
+
+ manager.sendMessage(kSessionId, parcel);
+
+ closeSession(kSessionId);
+}
+
+TEST_F(AudioManagerTest, testSendInternalEventCmr)
+{
+ openSession(kSessionId);
+
+ const int32_t kCmrCode = 1;
+ const int32_t kCmrDefine = 7;
+
+ EXPECT_CALL(manager, SendInternalEvent(kRequestAudioCmr, kSessionId, kCmrCode, kCmrDefine))
+ .Times(1)
+ .WillOnce(Return());
+
+ ImsMediaEventHandler::SendEvent(
+ "AUDIO_REQUEST_EVENT", kRequestAudioCmr, kSessionId, kCmrCode, kCmrDefine);
+
+ closeSession(kSessionId);
+}
+
+TEST_F(AudioManagerTest, testSendInternalEventRtcpXr)
+{
+ openSession(kSessionId);
+
+ const int32_t param1 = 10;
+ const int32_t param2 = 20;
+
+ EXPECT_CALL(manager, SendInternalEvent(kRequestSendRtcpXrReport, kSessionId, param1, param2))
+ .Times(1)
+ .WillOnce(Return());
+
+ ImsMediaEventHandler::SendEvent(
+ "AUDIO_REQUEST_EVENT", kRequestSendRtcpXrReport, kSessionId, param1, param2);
+
+ closeSession(kSessionId);
+}
+
+TEST_F(AudioManagerTest, testFirstMediaPacketInd)
+{
+ AudioConfig* param = new AudioConfig(config);
+
+ ImsMediaEventHandler::SendEvent("AUDIO_RESPONSE_EVENT", kAudioFirstMediaPacketInd, kSessionId,
+ reinterpret_cast<uint64_t>(param), 0);
+
+ gCondition.wait_timeout(20);
+ EXPECT_EQ(callback.resSessionId, kSessionId);
+ EXPECT_EQ(callback.response, kAudioFirstMediaPacketInd);
+ EXPECT_EQ(callback.resConfig, config);
+}
+
+TEST_F(AudioManagerTest, testRtpHeaderExtensionInd)
+{
+ std::list<RtpHeaderExtension> extensions;
+ RtpHeaderExtension extension;
+ const uint8_t kExtensionData[] = {0x01, 0x02};
+ const int32_t kExtensionDataSize = 2;
+ extension.setLocalIdentifier(15);
+ extension.setExtensionData(kExtensionData, kExtensionDataSize);
+ extensions.push_back(extension);
+
+ std::list<RtpHeaderExtension>* param = new std::list<RtpHeaderExtension>();
+ std::copy(extensions.begin(), extensions.end(), std::back_inserter(*param));
+
+ android::Parcel parcel;
+ parcel.writeInt32(param->size());
+
+ for (auto& item : *param)
+ {
+ item.writeToParcel(&parcel);
+ }
+
+ ImsMediaEventHandler::SendEvent("AUDIO_RESPONSE_EVENT", kAudioRtpHeaderExtensionInd, kSessionId,
+ reinterpret_cast<uint64_t>(param), 0);
+
+ gCondition.wait_timeout(20);
+ EXPECT_EQ(callback.resSessionId, kSessionId);
+ EXPECT_EQ(callback.response, kAudioRtpHeaderExtensionInd);
+ EXPECT_EQ(callback.extensions, extensions);
+}
+
+TEST_F(AudioManagerTest, testMediaQualityStatusInd)
+{
+ MediaQualityStatus status;
+ status.setRtpInactivityTimeMillis(10000);
+ status.setRtcpInactivityTimeMillis(10000);
+ status.setRtpPacketLossRate(1);
+ status.setRtpJitterMillis(100);
+
+ MediaQualityStatus* param = new MediaQualityStatus(status);
+
+ ImsMediaEventHandler::SendEvent("AUDIO_RESPONSE_EVENT", kAudioMediaQualityStatusInd, kSessionId,
+ reinterpret_cast<uint64_t>(param), 0);
+
+ gCondition.wait_timeout(20);
+ EXPECT_EQ(callback.resSessionId, kSessionId);
+ EXPECT_EQ(callback.response, kAudioMediaQualityStatusInd);
+ EXPECT_EQ(callback.mediaQualityStatus, status);
+}
+
+TEST_F(AudioManagerTest, testDtmfReceivedInd)
+{
+ const char digit = 1;
+ const int32_t duration = 100;
+
+ ImsMediaEventHandler::SendEvent(
+ "AUDIO_RESPONSE_EVENT", kAudioDtmfReceivedInd, kSessionId, digit, duration);
+
+ gCondition.wait_timeout(20);
+ EXPECT_EQ(callback.resSessionId, kSessionId);
+ EXPECT_EQ(callback.response, kAudioDtmfReceivedInd);
+ EXPECT_EQ(callback.receivedDtmfDigit, digit);
+ EXPECT_EQ(callback.receivedDtmfDuration, duration);
+}
+
+TEST_F(AudioManagerTest, testCallQualityInd)
+{
+ CallQuality quality;
+ quality.setDownlinkCallQualityLevel(0);
+ quality.setUplinkCallQualityLevel(0);
+ quality.setCallDuration(30000);
+ quality.setNumRtpPacketsTransmitted(1500);
+ quality.setNumRtpPacketsReceived(1500);
+ quality.setNumRtpPacketsTransmittedLost(1);
+ quality.setNumRtpPacketsNotReceived(2);
+ quality.setAverageRelativeJitter(50);
+ quality.setMaxRelativeJitter(150);
+ quality.setAverageRoundTripTime(60);
+ quality.setCodecType(AudioConfig::CODEC_AMR_WB);
+ quality.setRtpInactivityDetected(false);
+ quality.setRxSilenceDetected(false);
+ quality.setTxSilenceDetected(false);
+ quality.setNumVoiceFrames(1400);
+ quality.setNumNoDataFrames(0);
+ quality.setNumDroppedRtpPackets(0);
+ quality.setMinPlayoutDelayMillis(100);
+ quality.setMaxPlayoutDelayMillis(180);
+ quality.setNumRtpSidPacketsReceived(100);
+ quality.setNumRtpDuplicatePackets(1);
+
+ CallQuality* param = new CallQuality(quality);
+
+ ImsMediaEventHandler::SendEvent("AUDIO_RESPONSE_EVENT", kAudioCallQualityChangedInd, kSessionId,
+ reinterpret_cast<uint64_t>(param), 0);
+
+ gCondition.wait_timeout(20);
+ EXPECT_EQ(callback.resSessionId, kSessionId);
+ EXPECT_EQ(callback.response, kAudioCallQualityChangedInd);
+ EXPECT_EQ(callback.callQuality, quality);
+} \ No newline at end of file
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/include/core/audio/MockAudioManager.h b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/include/core/audio/MockAudioManager.h
new file mode 100644
index 00000000..4a46634b
--- /dev/null
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/include/core/audio/MockAudioManager.h
@@ -0,0 +1,39 @@
+/**
+ * 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.
+ */
+
+#ifndef MOCK_AUDIO_MANAGER_H
+#define MOCK_AUDIO_MANAGER_H
+
+#include <AudioManager.h>
+#include <ImsMediaDefine.h>
+#include <gmock/gmock.h>
+
+class MockAudioManager : public AudioManager
+{
+public:
+ MockAudioManager() { sManager = this; }
+ virtual ~MockAudioManager() { sManager = nullptr; }
+ MOCK_METHOD(ImsMediaResult, deleteConfig, (int sessionId, AudioConfig* config), (override));
+ MOCK_METHOD(void, sendDtmf, (int sessionId, char dtmfDigit, int duration), (override));
+ MOCK_METHOD(void, sendRtpHeaderExtension,
+ (int sessionId, std::list<RtpHeaderExtension>* listExtension), (override));
+ MOCK_METHOD(void, setMediaQualityThreshold, (int sessionId, MediaQualityThreshold* threshold),
+ (override));
+ MOCK_METHOD(void, SendInternalEvent,
+ (uint32_t event, uint64_t sessionId, uint64_t paramA, uint64_t paramB), (override));
+};
+
+#endif \ No newline at end of file