summaryrefslogtreecommitdiff
path: root/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core
diff options
context:
space:
mode:
Diffstat (limited to 'tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core')
-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/core/audio/MediaQualityAnalyzerTest.cpp190
-rw-r--r--tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/node/AudioRtpPayloadNodeTest.cpp296
-rw-r--r--tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtcpDecoderNodeTests.cpp303
-rw-r--r--tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtcpEncoderNodeTests.cpp349
-rw-r--r--tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextStreamGraphRtcpTest.cpp8
-rw-r--r--tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/nodes/TextSourceNodeTest.cpp133
-rw-r--r--tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaBitReaderTest.cpp75
-rw-r--r--tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaBitWriterTest.cpp77
-rw-r--r--tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaImageRotateTest.cpp98
-rw-r--r--tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtcpTest.cpp10
-rw-r--r--tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtpTxTest.cpp6
12 files changed, 2117 insertions, 111 deletions
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/core/audio/MediaQualityAnalyzerTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/MediaQualityAnalyzerTest.cpp
index a94b6654..ba468406 100644
--- a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/MediaQualityAnalyzerTest.cpp
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/MediaQualityAnalyzerTest.cpp
@@ -19,7 +19,6 @@
#include <AudioConfig.h>
#include <ImsMediaAudioUtil.h>
#include <MediaQualityAnalyzer.h>
-#include <ImsMediaCondition.h>
#include <MockBaseSessionCallback.h>
#include <ImsMediaTimer.h>
@@ -27,7 +26,7 @@ using namespace android::telephony::imsmedia;
using ::testing::_;
// RtpConfig
-const int32_t kMediaDirection = RtpConfig::MEDIA_DIRECTION_INACTIVE;
+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;
@@ -100,13 +99,7 @@ public:
}
}
- virtual void onEvent(int32_t type, uint64_t param1, uint64_t param2)
- {
- (void)type;
- (void)param1;
- (void)param2;
- }
-
+ virtual void onEvent(int32_t /* type */, uint64_t /* param1 */, uint64_t /* param2 */) {}
CallQuality getCallQuality() { return mCallQuality; }
MediaQualityStatus getMediaQualityStatus() { return mStatus; }
@@ -115,6 +108,49 @@ private:
MediaQualityStatus mStatus;
};
+class FakeMediaQualityAnalyzer : public MediaQualityAnalyzer
+{
+public:
+ FakeMediaQualityAnalyzer() :
+ MediaQualityAnalyzer()
+ {
+ counter = 0;
+ }
+ virtual ~FakeMediaQualityAnalyzer() {}
+
+ virtual void start()
+ {
+ mCallQuality.setCodecType(convertAudioCodecType(
+ mCodecType, ImsMediaAudioUtil::FindMaxEvsBandwidthFromRange(mCodecAttribute)));
+ }
+
+ virtual void stop()
+ {
+ notifyCallQuality();
+ reset();
+ counter = 0;
+ }
+
+ void testProcessCycle(const int32_t numCycle)
+ {
+ for (int i = 0; i < numCycle; i++)
+ {
+ while (!mListevent.empty())
+ {
+ processEvent(mListevent.front(), mListParamA.front(), mListParamB.front());
+ mListevent.pop_front();
+ mListParamA.pop_front();
+ mListParamB.pop_front();
+ }
+
+ processData(++counter);
+ }
+ }
+
+private:
+ int32_t counter;
+};
+
class MediaQualityAnalyzerTest : public ::testing::Test
{
public:
@@ -122,21 +158,20 @@ public:
virtual ~MediaQualityAnalyzerTest() {}
protected:
- MediaQualityAnalyzer* mAnalyzer;
+ FakeMediaQualityAnalyzer* mAnalyzer;
AudioConfig mConfig;
RtcpConfig mRtcpConfig;
AmrParams mAmrParam;
EvsParams mEvsParam;
FakeMediaQualityCallback mFakeCallback;
MockBaseSessionCallback mCallback;
- ImsMediaCondition mCondition;
virtual void SetUp() override
{
mCallback.SetDelegate(&mFakeCallback);
mCallback.DelegateToFake();
- mAnalyzer = new MediaQualityAnalyzer();
+ mAnalyzer = new FakeMediaQualityAnalyzer();
mRtcpConfig.setCanonicalName(kCanonicalName);
mRtcpConfig.setTransmitPort(kTransmitPort);
mRtcpConfig.setIntervalSec(kIntervalSec);
@@ -172,7 +207,6 @@ protected:
mAnalyzer->setCallback(&mCallback);
mAnalyzer->setConfig(&mConfig);
- mCondition.reset();
}
virtual void TearDown() override
@@ -243,7 +277,8 @@ TEST_F(MediaQualityAnalyzerTest, TestCollectTxPackets)
mAnalyzer->SendEvent(kCollectPacketInfo, kStreamRtpTx, reinterpret_cast<uint64_t>(packet));
}
- mCondition.wait_timeout(1100); // 1.1 sec
+ mAnalyzer->testProcessCycle(1);
+
EXPECT_EQ(mAnalyzer->getTxPacketSize(), numPackets);
EXPECT_EQ(mAnalyzer->getRxPacketSize(), 0);
EXPECT_EQ(mAnalyzer->getLostPacketSize(), 0);
@@ -259,17 +294,69 @@ TEST_F(MediaQualityAnalyzerTest, TestCollectTxPackets)
TEST_F(MediaQualityAnalyzerTest, TestRtpInactivityNotRunning)
{
- EXPECT_CALL(mCallback, onEvent(kAudioCallQualityChangedInd, _, _)).Times(1);
+ EXPECT_CALL(mCallback, onEvent(kAudioCallQualityChangedInd, _, _)).Times(2);
EXPECT_CALL(mCallback, onEvent(kImsMediaEventMediaQualityStatus, _, _)).Times(0);
MediaQualityThreshold threshold;
threshold.setRtpInactivityTimerMillis(std::vector<int32_t>{0});
mAnalyzer->setMediaQualityThreshold(threshold);
mAnalyzer->start();
- mCondition.wait_timeout(2100); // 2.1 sec
+ mAnalyzer->testProcessCycle(2);
+ mAnalyzer->stop();
+
+ threshold.setRtpInactivityTimerMillis(std::vector<int32_t>{2000});
+ mConfig.setMediaDirection(RtpConfig::MEDIA_DIRECTION_INACTIVE);
+ mAnalyzer->setConfig(&mConfig);
+ mAnalyzer->setMediaQualityThreshold(threshold);
+ mAnalyzer->start();
+ mAnalyzer->testProcessCycle(2);
+ mAnalyzer->stop();
+}
+
+TEST_F(MediaQualityAnalyzerTest, TestRtpInactivityNoUpdateByDirection)
+{
+ EXPECT_CALL(mCallback, onEvent(kAudioCallQualityChangedInd, _, _)).Times(2);
+ EXPECT_CALL(mCallback, onEvent(kImsMediaEventMediaQualityStatus, _, _)).Times(1);
+ MediaQualityThreshold threshold;
+ threshold.setRtpInactivityTimerMillis(std::vector<int32_t>{4000});
+ mAnalyzer->setMediaQualityThreshold(threshold);
+ mAnalyzer->testProcessCycle(2);
+
+ mConfig.setMediaDirection(RtpConfig::MEDIA_DIRECTION_RECEIVE_ONLY);
+
+ if (!mAnalyzer->isSameConfig(&mConfig))
+ {
+ mAnalyzer->stop();
+ mAnalyzer->start();
+ }
+
+ mAnalyzer->testProcessCycle(2);
mAnalyzer->stop();
+ MediaQualityStatus quality = mFakeCallback.getMediaQualityStatus();
+ EXPECT_EQ(quality.getRtpInactivityTimeMillis(), 4000);
}
-TEST_F(MediaQualityAnalyzerTest, TestRtpInactivityRunning)
+TEST_F(MediaQualityAnalyzerTest, TestRtpInactivityUpdateByDirection)
+{
+ EXPECT_CALL(mCallback, onEvent(kAudioCallQualityChangedInd, _, _)).Times(2);
+ EXPECT_CALL(mCallback, onEvent(kImsMediaEventMediaQualityStatus, _, _)).Times(1);
+ MediaQualityThreshold threshold;
+ threshold.setRtpInactivityTimerMillis(std::vector<int32_t>{2000});
+ mAnalyzer->setMediaQualityThreshold(threshold);
+ mAnalyzer->testProcessCycle(2);
+
+ mConfig.setMediaDirection(RtpConfig::MEDIA_DIRECTION_INACTIVE);
+
+ if (!mAnalyzer->isSameConfig(&mConfig))
+ {
+ mAnalyzer->stop();
+ mAnalyzer->start();
+ }
+
+ mAnalyzer->testProcessCycle(2);
+ mAnalyzer->stop();
+}
+
+TEST_F(MediaQualityAnalyzerTest, TestRtpInactivityUpdate)
{
EXPECT_CALL(mCallback, onEvent(kAudioCallQualityChangedInd, _, _)).Times(2);
EXPECT_CALL(mCallback, onEvent(kImsMediaEventMediaQualityStatus, _, _)).Times(3);
@@ -277,13 +364,13 @@ TEST_F(MediaQualityAnalyzerTest, TestRtpInactivityRunning)
threshold.setRtpInactivityTimerMillis(kRtpInactivityTimerMillis);
mAnalyzer->setMediaQualityThreshold(threshold);
mAnalyzer->start();
- mCondition.wait_timeout(2100); // 2.1 sec
+ mAnalyzer->testProcessCycle(2);
// Check MediaQualityStatus value
MediaQualityStatus quality1 = mFakeCallback.getMediaQualityStatus();
EXPECT_EQ(quality1.getRtpInactivityTimeMillis(), 2000);
- mCondition.wait_timeout(2100); // 2.1 sec
+ mAnalyzer->testProcessCycle(2);
// Check MediaQualityStatus value
MediaQualityStatus quality2 = mFakeCallback.getMediaQualityStatus();
@@ -293,13 +380,43 @@ TEST_F(MediaQualityAnalyzerTest, TestRtpInactivityRunning)
packet->seqNum = 0;
mAnalyzer->SendEvent(kCollectPacketInfo, kStreamRtpRx, reinterpret_cast<uint64_t>(packet));
- mCondition.wait_timeout(3100); // 3.1 sec
+ mAnalyzer->testProcessCycle(3);
MediaQualityStatus quality3 = mFakeCallback.getMediaQualityStatus();
EXPECT_EQ(quality3.getRtpInactivityTimeMillis(), 2000);
mAnalyzer->stop();
}
+TEST_F(MediaQualityAnalyzerTest, TestRtcpInactivityNotRunning)
+{
+ EXPECT_CALL(mCallback, onEvent(kAudioCallQualityChangedInd, _, _)).Times(3);
+ EXPECT_CALL(mCallback, onEvent(kImsMediaEventMediaQualityStatus, _, _)).Times(0);
+ MediaQualityThreshold threshold;
+ threshold.setRtcpInactivityTimerMillis(0);
+ mAnalyzer->setMediaQualityThreshold(threshold);
+ mAnalyzer->start();
+ mAnalyzer->testProcessCycle(2);
+ mAnalyzer->stop();
+
+ threshold.setRtcpInactivityTimerMillis(2000);
+ mConfig.setMediaDirection(RtpConfig::MEDIA_DIRECTION_NO_FLOW);
+ mAnalyzer->setConfig(&mConfig);
+ mAnalyzer->setMediaQualityThreshold(threshold);
+ mAnalyzer->start();
+ mAnalyzer->testProcessCycle(2);
+ mAnalyzer->stop();
+
+ threshold.setRtcpInactivityTimerMillis(2000);
+ mRtcpConfig.setIntervalSec(0);
+ mConfig.setMediaDirection(RtpConfig::MEDIA_DIRECTION_INACTIVE);
+ mConfig.setRtcpConfig(mRtcpConfig);
+ mAnalyzer->setConfig(&mConfig);
+ mAnalyzer->setMediaQualityThreshold(threshold);
+ mAnalyzer->start();
+ mAnalyzer->testProcessCycle(2);
+ mAnalyzer->stop();
+}
+
TEST_F(MediaQualityAnalyzerTest, TestRtcpInactivity)
{
EXPECT_CALL(mCallback, onEvent(kAudioCallQualityChangedInd, _, _)).Times(2);
@@ -308,21 +425,20 @@ TEST_F(MediaQualityAnalyzerTest, TestRtcpInactivity)
threshold.setRtcpInactivityTimerMillis(kRtcpInactivityTimerMillis);
mAnalyzer->setMediaQualityThreshold(threshold);
mAnalyzer->start();
- mCondition.wait_timeout(2100); // 2.1 sec
+ mAnalyzer->testProcessCycle(2);
// Check MediaQualityStatus value
MediaQualityStatus quality1 = mFakeCallback.getMediaQualityStatus();
EXPECT_EQ(quality1.getRtcpInactivityTimeMillis(), 2000);
- mCondition.wait_timeout(2100); // 2.1 sec
+ mAnalyzer->testProcessCycle(2);
// Check MediaQualityStatus value
MediaQualityStatus quality2 = mFakeCallback.getMediaQualityStatus();
EXPECT_EQ(quality2.getRtcpInactivityTimeMillis(), 2000);
mAnalyzer->SendEvent(kCollectPacketInfo, kStreamRtcp);
-
- mCondition.wait_timeout(3100); // 3.1 sec
+ mAnalyzer->testProcessCycle(3);
MediaQualityStatus quality3 = mFakeCallback.getMediaQualityStatus();
EXPECT_EQ(quality3.getRtcpInactivityTimeMillis(), 2000);
@@ -333,7 +449,7 @@ TEST_F(MediaQualityAnalyzerTest, TestCallQualityInactivity)
{
EXPECT_CALL(mCallback, onEvent(kAudioCallQualityChangedInd, _, _)).Times(2);
mAnalyzer->start();
- mCondition.wait_timeout(4100); // 4.1 sec
+ mAnalyzer->testProcessCycle(4);
mAnalyzer->stop();
// Check CallQuality value
@@ -369,7 +485,7 @@ TEST_F(MediaQualityAnalyzerTest, TestCallQualityLevelChanged)
SessionCallbackParameter* param = new SessionCallbackParameter(kReportPacketLossGap, 5, 1);
mAnalyzer->SendEvent(kCollectOptionalInfo, reinterpret_cast<uint64_t>(param), 0);
- mCondition.wait_timeout(5100); // 5.1 sec
+ mAnalyzer->testProcessCycle(5);
EXPECT_EQ(mAnalyzer->getTxPacketSize(), 0);
EXPECT_EQ(mAnalyzer->getRxPacketSize(), numPackets - 1);
@@ -409,7 +525,7 @@ TEST_F(MediaQualityAnalyzerTest, TestJitterInd)
mAnalyzer->SendEvent(kCollectPacketInfo, kStreamRtpRx, reinterpret_cast<uint64_t>(packet));
}
- mCondition.wait_timeout(1100); // 1.1 sec
+ mAnalyzer->testProcessCycle(1);
EXPECT_EQ(mAnalyzer->getTxPacketSize(), 0);
EXPECT_EQ(mAnalyzer->getRxPacketSize(), numPackets);
@@ -452,7 +568,8 @@ TEST_F(MediaQualityAnalyzerTest, TestSsrcChange)
mAnalyzer->SendEvent(kCollectPacketInfo, kStreamRtpRx, reinterpret_cast<uint64_t>(packet));
}
- mCondition.wait_timeout(1100); // 1.1 sec
+ mAnalyzer->testProcessCycle(1);
+
EXPECT_EQ(mAnalyzer->getTxPacketSize(), 0);
EXPECT_EQ(mAnalyzer->getRxPacketSize(), numPackets);
EXPECT_EQ(mAnalyzer->getLostPacketSize(), 0);
@@ -481,7 +598,7 @@ TEST_F(MediaQualityAnalyzerTest, TestPacketLossInd)
{
RtpPacket* packet = new RtpPacket();
- if (i == 5) // make 10% loss rate
+ if (i == 5 || i == 6) // make 20% loss rate
{
continue;
}
@@ -492,14 +609,14 @@ TEST_F(MediaQualityAnalyzerTest, TestPacketLossInd)
mAnalyzer->SendEvent(kCollectPacketInfo, kStreamRtpRx, reinterpret_cast<uint64_t>(packet));
}
- SessionCallbackParameter* param = new SessionCallbackParameter(kReportPacketLossGap, 5, 1);
+ SessionCallbackParameter* param = new SessionCallbackParameter(kReportPacketLossGap, 5, 2);
mAnalyzer->SendEvent(kCollectOptionalInfo, reinterpret_cast<uint64_t>(param), 0);
- mCondition.wait_timeout(1100); // 1.1 sec
+ mAnalyzer->testProcessCycle(1);
EXPECT_EQ(mAnalyzer->getTxPacketSize(), 0);
- EXPECT_EQ(mAnalyzer->getRxPacketSize(), numPackets - 1);
- EXPECT_EQ(mAnalyzer->getLostPacketSize(), 1);
+ EXPECT_EQ(mAnalyzer->getRxPacketSize(), numPackets - 2);
+ EXPECT_EQ(mAnalyzer->getLostPacketSize(), 2);
mAnalyzer->stop();
@@ -507,10 +624,10 @@ TEST_F(MediaQualityAnalyzerTest, TestPacketLossInd)
EXPECT_EQ(mAnalyzer->getRxPacketSize(), 0);
EXPECT_EQ(mAnalyzer->getLostPacketSize(), 0);
- EXPECT_EQ(mFakeCallback.getCallQuality().getNumRtpPacketsNotReceived(), 1);
+ EXPECT_EQ(mFakeCallback.getCallQuality().getNumRtpPacketsNotReceived(), 2);
MediaQualityStatus status = mFakeCallback.getMediaQualityStatus();
- EXPECT_EQ(status.getRtpPacketLossRate(), 10);
+ EXPECT_EQ(status.getRtpPacketLossRate(), 20);
}
TEST_F(MediaQualityAnalyzerTest, TestNotifyMediaQualityStatus)
@@ -521,7 +638,6 @@ TEST_F(MediaQualityAnalyzerTest, TestNotifyMediaQualityStatus)
threshold.setNotifyCurrentStatus(true);
mAnalyzer->setMediaQualityThreshold(threshold);
mAnalyzer->start();
-
- mCondition.wait_timeout(2100); // 2.1 sec
+ mAnalyzer->testProcessCycle(2);
mAnalyzer->stop();
} \ No newline at end of file
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/node/AudioRtpPayloadNodeTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/node/AudioRtpPayloadNodeTest.cpp
new file mode 100644
index 00000000..0221f6fa
--- /dev/null
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/node/AudioRtpPayloadNodeTest.cpp
@@ -0,0 +1,296 @@
+/**
+ * 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 <AudioConfig.h>
+#include <AudioRtpPayloadEncoderNode.h>
+#include <AudioRtpPayloadDecoderNode.h>
+#include <string.h>
+
+using namespace android::telephony::imsmedia;
+using namespace android;
+
+// RtpConfig
+const int32_t kMediaDirection = RtpConfig::MEDIA_DIRECTION_SEND_RECEIVE;
+const 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 String8 kCanonicalName("name");
+const int32_t kTransmitPort = 10001;
+const int32_t kIntervalSec = 5;
+const int32_t kRtcpXrBlockTypes = 0;
+
+// AudioConfig
+const int8_t kPTimeMillis = 20;
+const int32_t kMaxPtimeMillis = 100;
+const bool kDtxEnabled = true;
+const int8_t kDtmfPayloadTypeNumber = 103;
+const int8_t kDtmfsamplingRateKHz = 16;
+
+// AmrParam
+const int32_t kAmrMode = AmrParams::AMR_MODE_8;
+const bool kOctetAligned = false;
+const int32_t kMaxRedundancyMillis = 240;
+
+// EvsParam
+const int32_t kEvsBandwidth = EvsParams::EVS_SUPER_WIDE_BAND;
+const int32_t kEvsMode = EvsParams::EVS_MODE_13;
+const int8_t kChannelAwareMode = 2;
+
+namespace
+{
+class FakeNode : public BaseNode
+{
+public:
+ explicit FakeNode(BaseSessionCallback* callback = nullptr) :
+ BaseNode(callback)
+ {
+ frameSize = 0;
+ memset(dataFrame, 0, sizeof(dataFrame));
+ }
+ virtual ~FakeNode() {}
+ virtual ImsMediaResult Start() { return RESULT_SUCCESS; }
+ virtual void Stop() {}
+ virtual bool IsRunTime() { return true; }
+ virtual bool IsSourceNode() { return false; }
+ virtual void SetConfig(void* config) { (void)config; }
+ virtual void OnDataFromFrontNode(ImsMediaSubType /*IMS_MEDIA_AUDIO*/, uint8_t* data,
+ uint32_t size, uint32_t /*timestamp*/, bool /*mark*/, uint32_t /*seq*/,
+ ImsMediaSubType /*dataType*/, uint32_t /*arrivalTime*/)
+ {
+ if (data != nullptr && size > 0)
+ {
+ memset(dataFrame, 0, sizeof(dataFrame));
+ memcpy(dataFrame, data, size);
+ frameSize = size;
+ }
+ }
+
+ virtual kBaseNodeState GetState() { return kNodeStateRunning; }
+
+ uint32_t GetFrameSize() { return frameSize; }
+ uint8_t* GetDataFrame() { return dataFrame; }
+
+private:
+ uint32_t frameSize;
+ uint8_t dataFrame[DEFAULT_MTU];
+};
+
+class AudioRtpPayloadNodeTest : public ::testing::Test
+{
+public:
+ AudioRtpPayloadNodeTest()
+ {
+ encoder = nullptr;
+ decoder = nullptr;
+ fakeNode = nullptr;
+ }
+ virtual ~AudioRtpPayloadNodeTest() {}
+
+protected:
+ AmrParams amr;
+ EvsParams evs;
+ RtcpConfig rtcp;
+ AudioConfig audioConfig;
+ AudioRtpPayloadEncoderNode* encoder;
+ AudioRtpPayloadDecoderNode* decoder;
+ FakeNode* fakeNode;
+ std::list<BaseNode*> nodes;
+
+ virtual void SetUp() override
+ {
+ rtcp.setCanonicalName(kCanonicalName);
+ rtcp.setTransmitPort(kTransmitPort);
+ rtcp.setIntervalSec(kIntervalSec);
+ rtcp.setRtcpXrBlockTypes(kRtcpXrBlockTypes);
+
+ setupAudioConfig();
+ setupNodes(&audioConfig);
+ }
+
+ virtual void TearDown() override
+ {
+ while (nodes.size() > 0)
+ {
+ BaseNode* node = nodes.front();
+ node->Stop();
+ delete node;
+ nodes.pop_front();
+ }
+ }
+
+public:
+ void setupNodes(AudioConfig* config)
+ {
+ encoder = new AudioRtpPayloadEncoderNode();
+ encoder->SetMediaType(IMS_MEDIA_AUDIO);
+ encoder->SetConfig(config);
+ nodes.push_back(encoder);
+
+ decoder = new AudioRtpPayloadDecoderNode();
+ decoder->SetMediaType(IMS_MEDIA_AUDIO);
+ decoder->SetConfig(config);
+ nodes.push_back(decoder);
+ encoder->ConnectRearNode(decoder);
+
+ fakeNode = new FakeNode();
+ fakeNode->SetMediaType(IMS_MEDIA_AUDIO);
+ fakeNode->SetConfig(config);
+ nodes.push_back(fakeNode);
+ decoder->ConnectRearNode(fakeNode);
+ }
+
+ void setupAudioConfig()
+ {
+ amr.setAmrMode(kAmrMode);
+ amr.setOctetAligned(kOctetAligned);
+ amr.setMaxRedundancyMillis(kMaxRedundancyMillis);
+
+ audioConfig.setMediaDirection(kMediaDirection);
+ audioConfig.setRemoteAddress(kRemoteAddress);
+ audioConfig.setRemotePort(kRemotePort);
+ audioConfig.setRtcpConfig(rtcp);
+ audioConfig.setDscp(kDscp);
+ audioConfig.setRxPayloadTypeNumber(kRxPayload);
+ audioConfig.setTxPayloadTypeNumber(kTxPayload);
+ audioConfig.setSamplingRateKHz(kSamplingRate);
+ audioConfig.setPtimeMillis(kPTimeMillis);
+ audioConfig.setMaxPtimeMillis(kMaxPtimeMillis);
+ audioConfig.setDtxEnabled(kDtxEnabled);
+ audioConfig.setCodecType(AudioConfig::CODEC_AMR_WB);
+ audioConfig.setTxDtmfPayloadTypeNumber(kDtmfPayloadTypeNumber);
+ audioConfig.setRxDtmfPayloadTypeNumber(kDtmfPayloadTypeNumber);
+ audioConfig.setDtmfsamplingRateKHz(kDtmfsamplingRateKHz);
+ audioConfig.setAmrParams(amr);
+ audioConfig.setEvsParams(evs);
+ }
+};
+
+TEST_F(AudioRtpPayloadNodeTest, startFail)
+{
+ audioConfig.setPtimeMillis(0);
+ encoder->SetConfig(&audioConfig);
+ EXPECT_EQ(encoder->Start(), RESULT_INVALID_PARAM);
+}
+
+TEST_F(AudioRtpPayloadNodeTest, startAndUpdate)
+{
+ EXPECT_EQ(encoder->Start(), RESULT_SUCCESS);
+ EXPECT_EQ(decoder->Start(), RESULT_SUCCESS);
+
+ // no update
+ EXPECT_EQ(encoder->UpdateConfig(&audioConfig), RESULT_SUCCESS);
+ EXPECT_EQ(decoder->UpdateConfig(&audioConfig), RESULT_SUCCESS);
+
+ // update
+ audioConfig.setCodecType(AudioConfig::CODEC_AMR);
+ EXPECT_EQ(encoder->UpdateConfig(&audioConfig), RESULT_SUCCESS);
+ EXPECT_EQ(decoder->UpdateConfig(&audioConfig), RESULT_SUCCESS);
+}
+
+TEST_F(AudioRtpPayloadNodeTest, testAmrBandwidthEfficientDataProcess)
+{
+ EXPECT_EQ(encoder->Start(), RESULT_SUCCESS);
+ EXPECT_EQ(decoder->Start(), RESULT_SUCCESS);
+
+ // AMR-WB mode 8 audio frame with toc field
+ uint8_t testFrame[] = {0x44, 0xe6, 0x6e, 0x84, 0x8a, 0xa4, 0xda, 0xc8, 0xf2, 0x6c, 0xeb, 0x87,
+ 0xe4, 0x56, 0x0f, 0x49, 0x47, 0xfa, 0xdc, 0xa7, 0x9d, 0xbb, 0xcf, 0xda, 0xda, 0x67,
+ 0x80, 0xc2, 0x7f, 0x8d, 0x5b, 0xab, 0xd9, 0xbb, 0xd7, 0x1e, 0x60, 0x96, 0x5d, 0xdd,
+ 0x28, 0x65, 0x5f, 0x43, 0xf4, 0xb9, 0x0d, 0x7d, 0x05, 0x4e, 0x30, 0x50, 0xe1, 0x98,
+ 0x03, 0xed, 0xee, 0x8a, 0xa8, 0x34, 0x40};
+
+ encoder->OnDataFromFrontNode(MEDIASUBTYPE_UNDEFINED, testFrame, sizeof(testFrame), 0, false, 0);
+ EXPECT_EQ(fakeNode->GetFrameSize(), sizeof(testFrame));
+ EXPECT_EQ(memcmp(fakeNode->GetDataFrame(), testFrame, fakeNode->GetFrameSize()), 0);
+}
+
+TEST_F(AudioRtpPayloadNodeTest, testAmrOctetAlignedDataProcess)
+{
+ amr.setOctetAligned(true);
+ audioConfig.setAmrParams(amr);
+ encoder->SetConfig(&audioConfig);
+ decoder->SetConfig(&audioConfig);
+ EXPECT_EQ(encoder->Start(), RESULT_SUCCESS);
+ EXPECT_EQ(decoder->Start(), RESULT_SUCCESS);
+
+ // AMR-WB mode 8 audio frame with toc field
+ uint8_t testFrame[] = {0x44, 0xe6, 0x6e, 0x84, 0x8a, 0xa4, 0xda, 0xc8, 0xf2, 0x6c, 0xeb, 0x87,
+ 0xe4, 0x56, 0x0f, 0x49, 0x47, 0xfa, 0xdc, 0xa7, 0x9d, 0xbb, 0xcf, 0xda, 0xda, 0x67,
+ 0x80, 0xc2, 0x7f, 0x8d, 0x5b, 0xab, 0xd9, 0xbb, 0xd7, 0x1e, 0x60, 0x96, 0x5d, 0xdd,
+ 0x28, 0x65, 0x5f, 0x43, 0xf4, 0xb9, 0x0d, 0x7d, 0x05, 0x4e, 0x30, 0x50, 0xe1, 0x98,
+ 0x03, 0xed, 0xee, 0x8a, 0xa8, 0x34, 0x40};
+
+ encoder->OnDataFromFrontNode(MEDIASUBTYPE_UNDEFINED, testFrame, sizeof(testFrame), 0, false, 0);
+ EXPECT_EQ(fakeNode->GetFrameSize(), sizeof(testFrame));
+ EXPECT_EQ(memcmp(fakeNode->GetDataFrame(), testFrame, fakeNode->GetFrameSize()), 0);
+}
+
+TEST_F(AudioRtpPayloadNodeTest, testEvsCompactModeDataProcess)
+{
+ evs.setEvsBandwidth(kEvsBandwidth);
+ evs.setEvsMode(kEvsMode);
+ evs.setChannelAwareMode(kChannelAwareMode);
+ evs.setUseHeaderFullOnly(false);
+ evs.setCodecModeRequest(-1);
+
+ audioConfig.setEvsParams(evs);
+ audioConfig.setCodecType(AudioConfig::CODEC_EVS);
+ encoder->SetConfig(&audioConfig);
+ decoder->SetConfig(&audioConfig);
+ EXPECT_EQ(encoder->Start(), RESULT_SUCCESS);
+ EXPECT_EQ(decoder->Start(), RESULT_SUCCESS);
+
+ // EVS mode 13.2 kbps frame without toc field
+ uint8_t testFrame[] = {0xce, 0x40, 0xf2, 0xb2, 0xa4, 0xce, 0x4f, 0xd9, 0xfa, 0xe9, 0x77, 0xdc,
+ 0x9b, 0xc0, 0xa8, 0x10, 0xc8, 0xc3, 0x0f, 0xc9, 0x52, 0xc1, 0xda, 0x45, 0x7e, 0x6c,
+ 0x55, 0x47, 0xff, 0xff, 0xff, 0xff, 0xe0};
+
+ encoder->OnDataFromFrontNode(MEDIASUBTYPE_UNDEFINED, testFrame, sizeof(testFrame), 0, false, 0);
+ EXPECT_EQ(fakeNode->GetFrameSize(), sizeof(testFrame));
+ EXPECT_EQ(memcmp(fakeNode->GetDataFrame(), testFrame, fakeNode->GetFrameSize()), 0);
+}
+
+TEST_F(AudioRtpPayloadNodeTest, testEvsHeaderFullModeDataProcess)
+{
+ evs.setEvsBandwidth(kEvsBandwidth);
+ evs.setEvsMode(kEvsMode);
+ evs.setChannelAwareMode(kChannelAwareMode);
+ evs.setUseHeaderFullOnly(true);
+ evs.setCodecModeRequest(-1);
+
+ audioConfig.setEvsParams(evs);
+ audioConfig.setCodecType(AudioConfig::CODEC_EVS);
+ encoder->SetConfig(&audioConfig);
+ decoder->SetConfig(&audioConfig);
+ EXPECT_EQ(encoder->Start(), RESULT_SUCCESS);
+ EXPECT_EQ(decoder->Start(), RESULT_SUCCESS);
+
+ // EVS mode 13.2 kbps frame with toc field
+ uint8_t testFrame[] = {0x04, 0xce, 0x40, 0xf2, 0xb2, 0xa4, 0xce, 0x4f, 0xd9, 0xfa, 0xe9, 0x77,
+ 0xdc, 0x9b, 0xc0, 0xa8, 0x10, 0xc8, 0xc3, 0x0f, 0xc9, 0x52, 0xc1, 0xda, 0x45, 0x7e,
+ 0x6c, 0x55, 0x47, 0xff, 0xff, 0xff, 0xff, 0xe0};
+
+ encoder->OnDataFromFrontNode(MEDIASUBTYPE_UNDEFINED, testFrame, sizeof(testFrame), 0, false, 0);
+ EXPECT_EQ(fakeNode->GetFrameSize(), sizeof(testFrame));
+ EXPECT_EQ(memcmp(fakeNode->GetDataFrame(), testFrame, fakeNode->GetFrameSize()), 0);
+}
+} // namespace
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtcpDecoderNodeTests.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtcpDecoderNodeTests.cpp
new file mode 100644
index 00000000..05687f48
--- /dev/null
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtcpDecoderNodeTests.cpp
@@ -0,0 +1,303 @@
+/**
+ * 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 <condition_variable>
+#include <mutex>
+#include <RtcpConfig.h>
+#include <AudioConfig.h>
+#include <VideoConfig.h>
+#include <TextConfig.h>
+#include <RtcpDecoderNode.h>
+#include <ImsMediaVideoUtil.h>
+#include <ImsMediaTrace.h>
+
+using namespace android::telephony::imsmedia;
+using namespace android;
+
+namespace
+{
+// RtpConfig
+const int32_t kMediaDirection = RtpConfig::MEDIA_DIRECTION_SEND_RECEIVE;
+const 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 String8 kCanonicalName("name");
+const int32_t kTransmitPort = 10001;
+const int32_t RTCP_INTERVAL = 1;
+const int32_t kIntervalSec = RTCP_INTERVAL;
+int32_t kRtcpXrBlockTypes = 0;
+
+// VideoConfig
+const int32_t kVideoMode = VideoConfig::VIDEO_MODE_PREVIEW;
+const int32_t kMtu = 1500;
+const int32_t kFramerate = DEFAULT_FRAMERATE;
+const int32_t kBitrate = DEFAULT_BITRATE;
+const int32_t kCodecProfile = VideoConfig::AVC_PROFILE_BASELINE;
+const int32_t kCodecLevel = VideoConfig::AVC_LEVEL_12;
+const int32_t kIntraFrameIntervalSec = 1;
+const int32_t kPacketizationMode = VideoConfig::MODE_NON_INTERLEAVED;
+const int32_t kCameraId = 0;
+const int32_t kCameraZoom = 10;
+const int32_t kResolutionWidth = DEFAULT_RESOLUTION_WIDTH;
+const int32_t kResolutionHeight = DEFAULT_RESOLUTION_HEIGHT;
+const int32_t kDeviceOrientationDegree = 0;
+const int32_t kCvoValue = 1;
+const int32_t kRtcpFbTypes = VideoConfig::RTP_FB_NONE;
+
+static std::condition_variable cond;
+static std::mutex timerMutex;
+
+class FakeNode : public BaseNode
+{
+public:
+ bool mOnDataFromFrontNodeCalled = false;
+ virtual ~FakeNode() {}
+ void Stop() {}
+ bool IsRunTime() { return true; }
+ bool IsSourceNode() { return false; }
+ virtual kBaseNodeState GetState() { return kNodeStateRunning; }
+ void SetConfig(void* config) { (void)config; }
+ void OnDataFromFrontNode(ImsMediaSubType, uint8_t*, uint32_t, uint32_t, bool, uint32_t,
+ ImsMediaSubType, uint32_t)
+ {
+ IMLOGI0("FakeNode::OnDataFromFrontNode");
+ mOnDataFromFrontNodeCalled = true;
+ cond.notify_all();
+ }
+
+ ImsMediaResult Start() { return RESULT_SUCCESS; }
+};
+
+class SessionCallback : public BaseSessionCallback
+{
+public:
+ bool mOnEventCalled = false;
+ int32_t mType;
+ uint64_t mParam1, mParam2;
+
+ virtual ~SessionCallback() {}
+ virtual void onEvent(int32_t type, uint64_t param1, uint64_t param2)
+ {
+ IMLOGI0("SessionCallback::onEvent");
+ mOnEventCalled = true;
+ mType = type;
+ mParam1 = param1;
+ mParam2 = param2;
+ cond.notify_all();
+ }
+};
+
+class RtcpDecoderNodeEx : public RtcpDecoderNode
+{
+public:
+ bool mCallBaseClassMethod = false;
+ bool mOnRtcpIndCalled = false;
+
+ RtcpDecoderNodeEx(BaseSessionCallback* callback = nullptr) :
+ RtcpDecoderNode(callback)
+ {
+ }
+ virtual ~RtcpDecoderNodeEx() {}
+};
+
+class RtcpDecoderNodeTests : public ::testing::Test
+{
+public:
+ virtual ~RtcpDecoderNodeTests() {}
+
+protected:
+ RtcpDecoderNodeEx* pRtcpDecNode;
+ VideoConfig videoConfig;
+ FakeNode* pFakeRearNode;
+ SessionCallback* pCallback;
+
+ virtual void SetUp() override
+ {
+ pCallback = new SessionCallback();
+ pRtcpDecNode = new RtcpDecoderNodeEx(pCallback);
+ pRtcpDecNode->SetMediaType(IMS_MEDIA_VIDEO);
+ setupVideoConfig(videoConfig);
+ pRtcpDecNode->SetConfig(&videoConfig);
+ pFakeRearNode = connectNodes(pRtcpDecNode);
+ }
+
+ virtual void TearDown() override
+ {
+ delete pRtcpDecNode;
+ delete pFakeRearNode;
+ delete pCallback;
+ }
+
+ void setupRtcpConfig(RtcpConfig& rtcpConfig)
+ {
+ rtcpConfig.setCanonicalName(kCanonicalName);
+ rtcpConfig.setTransmitPort(kTransmitPort);
+ rtcpConfig.setIntervalSec(kIntervalSec);
+ rtcpConfig.setRtcpXrBlockTypes(kRtcpXrBlockTypes);
+ }
+
+ // using video codec because RTCP has feedback implementation for video media type.
+ void setupVideoConfig(VideoConfig& videoConfig)
+ {
+ videoConfig.setMediaDirection(kMediaDirection);
+ videoConfig.setRemoteAddress(kRemoteAddress);
+ videoConfig.setRemotePort(kRemotePort);
+ RtcpConfig rtcpConfig;
+ setupRtcpConfig(rtcpConfig);
+ videoConfig.setRtcpConfig(rtcpConfig);
+ videoConfig.setMaxMtuBytes(kMtu);
+ videoConfig.setDscp(kDscp);
+ videoConfig.setRxPayloadTypeNumber(kRxPayload);
+ videoConfig.setTxPayloadTypeNumber(kTxPayload);
+ videoConfig.setSamplingRateKHz(kSamplingRate);
+ videoConfig.setVideoMode(kVideoMode);
+ videoConfig.setCodecType(VideoConfig::CODEC_AVC);
+ videoConfig.setFramerate(kFramerate);
+ videoConfig.setBitrate(kBitrate);
+ videoConfig.setCodecProfile(kCodecProfile);
+ videoConfig.setCodecLevel(kCodecLevel);
+ videoConfig.setIntraFrameInterval(kIntraFrameIntervalSec);
+ videoConfig.setPacketizationMode(kPacketizationMode);
+ videoConfig.setCameraId(kCameraId);
+ videoConfig.setCameraZoom(kCameraZoom);
+ videoConfig.setResolutionWidth(kResolutionWidth);
+ videoConfig.setResolutionHeight(kResolutionHeight);
+ videoConfig.setDeviceOrientationDegree(kDeviceOrientationDegree);
+ videoConfig.setCvoValue(kCvoValue);
+ videoConfig.setRtcpFbType(kRtcpFbTypes);
+ }
+
+ FakeNode* connectNodes(RtcpDecoderNode* pRtcpDecNode)
+ {
+ FakeNode* pFakeNode = new FakeNode();
+ pRtcpDecNode->ConnectRearNode(pFakeNode);
+ return pFakeNode;
+ }
+};
+
+TEST_F(RtcpDecoderNodeTests, TestInitState)
+{
+ EXPECT_EQ(pRtcpDecNode->GetNodeId(), kNodeIdRtcpDecoder);
+ EXPECT_EQ(pRtcpDecNode->IsRunTime(), true);
+ EXPECT_EQ(pRtcpDecNode->IsSourceNode(), false);
+}
+
+TEST_F(RtcpDecoderNodeTests, TestConfigChange)
+{
+ VideoConfig videoConfig;
+ setupVideoConfig(videoConfig);
+ EXPECT_EQ(pRtcpDecNode->IsSameConfig(&videoConfig), true);
+}
+
+TEST_F(RtcpDecoderNodeTests, TestStartStopSuccess)
+{
+ EXPECT_EQ(pRtcpDecNode->Start(), RESULT_SUCCESS);
+ EXPECT_EQ(pRtcpDecNode->GetState(), kNodeStateRunning);
+
+ pRtcpDecNode->Stop();
+ EXPECT_EQ(pRtcpDecNode->GetState(), kNodeStateStopped);
+}
+
+TEST_F(RtcpDecoderNodeTests, TestOnRtcpSrInd)
+{
+ pRtcpDecNode->SetMediaType(IMS_MEDIA_AUDIO);
+ tNotifyReceiveRtcpSrInd payload;
+ memset(&payload, 0x00, sizeof(payload));
+ pRtcpDecNode->OnRtcpInd(RTPSVC_RECEIVE_RTCP_SR_IND, &payload);
+ EXPECT_EQ(pCallback->mOnEventCalled, true);
+ EXPECT_EQ(pCallback->mType, kCollectPacketInfo);
+ EXPECT_EQ(pCallback->mParam1, kStreamRtcp);
+}
+
+TEST_F(RtcpDecoderNodeTests, TestOnRtcpRrInd)
+{
+ pRtcpDecNode->SetMediaType(IMS_MEDIA_AUDIO);
+ tNotifyReceiveRtcpRrInd payload;
+ memset(&payload, 0x00, sizeof(payload));
+ pRtcpDecNode->OnRtcpInd(RTPSVC_RECEIVE_RTCP_RR_IND, &payload);
+ EXPECT_EQ(pCallback->mOnEventCalled, true);
+ EXPECT_EQ(pCallback->mType, kCollectPacketInfo);
+ EXPECT_EQ(pCallback->mParam1, kStreamRtcp);
+}
+
+TEST_F(RtcpDecoderNodeTests, TestOnRtcpFbInd)
+{
+ pRtcpDecNode->SetMediaType(IMS_MEDIA_AUDIO);
+ tRtpSvcIndSt_ReceiveRtcpFeedbackInd payload;
+ memset(&payload, 0x00, sizeof(payload));
+ payload.wFmt = kRtpFbTmmbr;
+ uint8_t fbMsgData[64];
+ payload.pMsg = fbMsgData;
+ pRtcpDecNode->OnRtcpInd(RTPSVC_RECEIVE_RTCP_FB_IND, &payload);
+ EXPECT_EQ(pCallback->mOnEventCalled, true);
+ EXPECT_EQ(pCallback->mType, kRequestVideoSendTmmbn);
+}
+
+TEST_F(RtcpDecoderNodeTests, TestOnNumReceivedPacket)
+{
+ pRtcpDecNode->SetMediaType(IMS_MEDIA_AUDIO);
+ pRtcpDecNode->SetInactivityTimerSec(1);
+ pRtcpDecNode->OnNumReceivedPacket(0, 0);
+ EXPECT_EQ(pCallback->mOnEventCalled, true);
+ EXPECT_EQ(pCallback->mType, kImsMediaEventMediaInactivity);
+ EXPECT_EQ(pCallback->mParam1, kProtocolRtcp);
+ EXPECT_EQ(pCallback->mParam2, 1);
+
+ pCallback->mOnEventCalled = false;
+ pRtcpDecNode->OnNumReceivedPacket(1, 0);
+ EXPECT_EQ(pCallback->mOnEventCalled, false);
+
+ pCallback->mOnEventCalled = false;
+ pRtcpDecNode->OnNumReceivedPacket(0, 1);
+ EXPECT_EQ(pCallback->mOnEventCalled, false);
+
+ pCallback->mOnEventCalled = false;
+ pRtcpDecNode->OnNumReceivedPacket(1, 1);
+ EXPECT_EQ(pCallback->mOnEventCalled, false);
+}
+
+TEST_F(RtcpDecoderNodeTests, TestOnEvent)
+{
+ pRtcpDecNode->OnEvent(kRequestRoundTripTimeDelayUpdate, 100);
+ EXPECT_EQ(pCallback->mOnEventCalled, true);
+ EXPECT_EQ(pCallback->mType, kRequestRoundTripTimeDelayUpdate);
+}
+
+TEST_F(RtcpDecoderNodeTests, TestReceiveTmmbr)
+{
+ pRtcpDecNode->SetMediaType(IMS_MEDIA_AUDIO);
+ tRtpSvcIndSt_ReceiveRtcpFeedbackInd payload;
+ memset(&payload, 0x00, sizeof(payload));
+ uint8_t fbMsgData[64];
+ payload.pMsg = fbMsgData;
+ pRtcpDecNode->ReceiveTmmbr(&payload);
+ EXPECT_EQ(pCallback->mOnEventCalled, true);
+ EXPECT_EQ(pCallback->mType, kRequestVideoSendTmmbn);
+}
+
+TEST_F(RtcpDecoderNodeTests, TestRequestIdrFrame)
+{
+ pRtcpDecNode->RequestIdrFrame();
+ EXPECT_EQ(pCallback->mOnEventCalled, true);
+ EXPECT_EQ(pCallback->mType, kRequestVideoIdrFrame);
+}
+} // namespace
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtcpEncoderNodeTests.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtcpEncoderNodeTests.cpp
new file mode 100644
index 00000000..94fd213d
--- /dev/null
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtcpEncoderNodeTests.cpp
@@ -0,0 +1,349 @@
+/**
+ * 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 <condition_variable>
+#include <mutex>
+#include <RtcpConfig.h>
+#include <AudioConfig.h>
+#include <VideoConfig.h>
+#include <TextConfig.h>
+#include <RtcpEncoderNode.h>
+#include <android/log.h>
+
+using namespace android::telephony::imsmedia;
+using namespace android;
+
+namespace
+{
+// RtpConfig
+const int32_t kMediaDirection = RtpConfig::MEDIA_DIRECTION_SEND_RECEIVE;
+const 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 String8 kCanonicalName("name");
+const int32_t kTransmitPort = 10001;
+const int32_t RTCP_INTERVAL = 1;
+const int32_t kIntervalSec = RTCP_INTERVAL;
+int32_t kRtcpXrBlockTypes = 0;
+
+// VideoConfig
+const int32_t kVideoMode = VideoConfig::VIDEO_MODE_PREVIEW;
+const int32_t kMtu = 1500;
+const int32_t kFramerate = DEFAULT_FRAMERATE;
+const int32_t kBitrate = DEFAULT_BITRATE;
+const int32_t kCodecProfile = VideoConfig::AVC_PROFILE_BASELINE;
+const int32_t kCodecLevel = VideoConfig::AVC_LEVEL_12;
+const int32_t kIntraFrameIntervalSec = 1;
+const int32_t kPacketizationMode = VideoConfig::MODE_NON_INTERLEAVED;
+const int32_t kCameraId = 0;
+const int32_t kCameraZoom = 10;
+const int32_t kResolutionWidth = DEFAULT_RESOLUTION_WIDTH;
+const int32_t kResolutionHeight = DEFAULT_RESOLUTION_HEIGHT;
+const android::String8 kPauseImagePath("data/user_de/0/com.android.telephony.imsmedia/test.jpg");
+const int32_t kDeviceOrientationDegree = 0;
+const int32_t kCvoValue = 1;
+const int32_t kRtcpFbTypes = VideoConfig::RTP_FB_NONE;
+
+static std::condition_variable cond;
+static std::mutex timerMutex;
+
+class FakeNode : public BaseNode
+{
+public:
+ bool mOnDataFromFrontNodeCalled = false;
+ virtual ~FakeNode() {}
+ void Stop() {}
+ bool IsRunTime() { return true; }
+ bool IsSourceNode() { return false; }
+ virtual kBaseNodeState GetState() { return kNodeStateRunning; }
+ void SetConfig(void* config) { (void)config; }
+ void OnDataFromFrontNode(ImsMediaSubType, uint8_t*, uint32_t, uint32_t, bool, uint32_t,
+ ImsMediaSubType, uint32_t)
+ {
+ mOnDataFromFrontNodeCalled = true;
+ cond.notify_all();
+ }
+
+ ImsMediaResult Start() { return RESULT_SUCCESS; }
+};
+
+class SessionCallback : public BaseSessionCallback
+{
+public:
+ bool mOnEventCalled = false;
+ virtual ~SessionCallback() {}
+ virtual void onEvent(int32_t, uint64_t, uint64_t)
+ {
+ mOnEventCalled = true;
+ cond.notify_all();
+ }
+};
+
+class RtcpEncoderNodeEx : public RtcpEncoderNode
+{
+public:
+ bool mCallBaseClassMethod = false;
+ bool mProcessTimerMethodCalled = false;
+
+ RtcpEncoderNodeEx(BaseSessionCallback* callback = nullptr) :
+ RtcpEncoderNode(callback)
+ {
+ }
+ virtual ~RtcpEncoderNodeEx() {}
+
+ void ProcessTimer()
+ {
+ mProcessTimerMethodCalled = true;
+ cond.notify_all();
+
+ if (mCallBaseClassMethod)
+ {
+ RtcpEncoderNode::ProcessTimer();
+ }
+ }
+};
+
+class RtcpEncoderNodeTests : public ::testing::Test
+{
+public:
+ virtual ~RtcpEncoderNodeTests() {}
+
+protected:
+ void setupRtcpConfig(RtcpConfig& rtcpConfig)
+ {
+ rtcpConfig.setCanonicalName(kCanonicalName);
+ rtcpConfig.setTransmitPort(kTransmitPort);
+ rtcpConfig.setIntervalSec(kIntervalSec);
+ rtcpConfig.setRtcpXrBlockTypes(kRtcpXrBlockTypes);
+ }
+
+ // using video codec because RTCP has feedback implementation for video media type.
+ void setupVideoConfig(VideoConfig& videoConfig)
+ {
+ videoConfig.setMediaDirection(kMediaDirection);
+ videoConfig.setRemoteAddress(kRemoteAddress);
+ videoConfig.setRemotePort(kRemotePort);
+ RtcpConfig rtcpConfig;
+ setupRtcpConfig(rtcpConfig);
+ videoConfig.setRtcpConfig(rtcpConfig);
+ videoConfig.setMaxMtuBytes(kMtu);
+ videoConfig.setDscp(kDscp);
+ videoConfig.setRxPayloadTypeNumber(kRxPayload);
+ videoConfig.setTxPayloadTypeNumber(kTxPayload);
+ videoConfig.setSamplingRateKHz(kSamplingRate);
+ videoConfig.setVideoMode(kVideoMode);
+ videoConfig.setCodecType(VideoConfig::CODEC_AVC);
+ videoConfig.setFramerate(kFramerate);
+ videoConfig.setBitrate(kBitrate);
+ videoConfig.setCodecProfile(kCodecProfile);
+ videoConfig.setCodecLevel(kCodecLevel);
+ videoConfig.setIntraFrameInterval(kIntraFrameIntervalSec);
+ videoConfig.setPacketizationMode(kPacketizationMode);
+ videoConfig.setCameraId(kCameraId);
+ videoConfig.setCameraZoom(kCameraZoom);
+ videoConfig.setResolutionWidth(kResolutionWidth);
+ videoConfig.setResolutionHeight(kResolutionHeight);
+ videoConfig.setPauseImagePath(kPauseImagePath);
+ videoConfig.setDeviceOrientationDegree(kDeviceOrientationDegree);
+ videoConfig.setCvoValue(kCvoValue);
+ videoConfig.setRtcpFbType(kRtcpFbTypes);
+ }
+
+ FakeNode* connectNodes(RtcpEncoderNode* pRtcpEncNode)
+ {
+ FakeNode* pFakeNode = new FakeNode();
+ pRtcpEncNode->ConnectRearNode(pFakeNode);
+ return pFakeNode;
+ }
+};
+
+TEST_F(RtcpEncoderNodeTests, TestInitState)
+{
+ RtcpEncoderNode* pRtcpEncNode = new RtcpEncoderNode();
+ EXPECT_EQ(pRtcpEncNode->GetNodeId(), kNodeIdRtcpEncoder);
+ EXPECT_EQ(pRtcpEncNode->IsRunTime(), true);
+ EXPECT_EQ(pRtcpEncNode->IsSourceNode(), true);
+ delete pRtcpEncNode;
+}
+
+TEST_F(RtcpEncoderNodeTests, TestConfigChange)
+{
+ RtcpEncoderNode* pRtcpEncNode = new RtcpEncoderNode();
+ VideoConfig videoConfig;
+ setupVideoConfig(videoConfig);
+ pRtcpEncNode->SetConfig(&videoConfig);
+ EXPECT_EQ(pRtcpEncNode->IsSameConfig(&videoConfig), true);
+ delete pRtcpEncNode;
+}
+
+TEST_F(RtcpEncoderNodeTests, TestStartStopSuccess)
+{
+ SessionCallback callback;
+ RtcpEncoderNodeEx* pRtcpEncNode = new RtcpEncoderNodeEx(&callback);
+ kRtcpXrBlockTypes = RtcpConfig::FLAG_RTCPXR_LOSS_RLE_REPORT_BLOCK;
+ VideoConfig videoConfig;
+ setupVideoConfig(videoConfig);
+ pRtcpEncNode->SetConfig(&videoConfig);
+ EXPECT_EQ(pRtcpEncNode->Start(), RESULT_SUCCESS);
+
+ bool timeout = false;
+ constexpr std::chrono::duration<int> waittime = std::chrono::seconds(RTCP_INTERVAL + 1);
+ // Wait for RTCP timer expiry to confirm start success.
+ {
+ pRtcpEncNode->mCallBaseClassMethod = true;
+ std::unique_lock<std::mutex> lock(timerMutex);
+ if (cond.wait_for(lock, waittime) == std::cv_status::timeout)
+ timeout = true;
+
+ EXPECT_EQ(timeout, false);
+ EXPECT_EQ(pRtcpEncNode->mProcessTimerMethodCalled, true);
+ }
+
+ // Check if SendEvent is called.
+ {
+ timeout = false;
+ std::unique_lock<std::mutex> lock(timerMutex);
+ if (cond.wait_for(lock, waittime) == std::cv_status::timeout)
+ timeout = true;
+
+ EXPECT_EQ(timeout, false);
+ EXPECT_EQ(callback.mOnEventCalled, true);
+ }
+
+ // Call stop and make sure RTCP timer doesn't expire.
+ pRtcpEncNode->Stop();
+ {
+ timeout = false;
+ pRtcpEncNode->mProcessTimerMethodCalled = false;
+ std::unique_lock<std::mutex> lock(timerMutex);
+ if (cond.wait_for(lock, waittime) == std::cv_status::timeout)
+ timeout = true;
+
+ EXPECT_EQ(timeout, true);
+ EXPECT_EQ(pRtcpEncNode->mProcessTimerMethodCalled, false);
+ }
+ delete pRtcpEncNode;
+}
+
+TEST_F(RtcpEncoderNodeTests, TestOnRtcpPacket)
+{
+ RtcpEncoderNode* pRtcpEncNode = new RtcpEncoderNode();
+ FakeNode* pRearNode = connectNodes(pRtcpEncNode);
+
+ unsigned char data[10];
+ pRtcpEncNode->OnRtcpPacket(data, 10);
+ EXPECT_EQ(pRearNode->mOnDataFromFrontNodeCalled, true);
+ delete pRtcpEncNode;
+ delete pRearNode;
+}
+
+TEST_F(RtcpEncoderNodeTests, TestSendNack)
+{
+ RtcpEncoderNode* pRtcpEncNode = new RtcpEncoderNode();
+ pRtcpEncNode->SetMediaType(IMS_MEDIA_VIDEO);
+
+ bool bRet = pRtcpEncNode->SendNack(nullptr);
+ EXPECT_EQ(bRet, false);
+
+ NackParams param;
+ param.PID = 0;
+ param.BLP = 0;
+ param.nSecNackCnt = 0;
+ param.bNackReport = true;
+
+ bRet = pRtcpEncNode->SendNack(&param);
+ EXPECT_EQ(bRet, false);
+
+ VideoConfig videoConfig;
+ setupVideoConfig(videoConfig);
+ videoConfig.setRtcpFbType(VideoConfig::RTP_FB_NACK);
+ pRtcpEncNode->SetConfig(&videoConfig);
+ EXPECT_EQ(pRtcpEncNode->Start(), RESULT_SUCCESS);
+ bRet = pRtcpEncNode->SendNack(&param);
+ EXPECT_EQ(bRet, true);
+ pRtcpEncNode->Stop();
+ delete pRtcpEncNode;
+}
+
+TEST_F(RtcpEncoderNodeTests, TestSendPictureLost)
+{
+ RtcpEncoderNode* pRtcpEncNode = new RtcpEncoderNode();
+ pRtcpEncNode->SetMediaType(IMS_MEDIA_VIDEO);
+ VideoConfig videoConfig;
+ setupVideoConfig(videoConfig);
+ videoConfig.setRtcpFbType(VideoConfig::PSFB_PLI);
+ pRtcpEncNode->SetConfig(&videoConfig);
+ EXPECT_EQ(pRtcpEncNode->Start(), RESULT_SUCCESS);
+
+ bool bRet = pRtcpEncNode->SendPictureLost(kPsfbPli);
+ EXPECT_EQ(bRet, true);
+
+ videoConfig.setRtcpFbType(VideoConfig::PSFB_FIR);
+ pRtcpEncNode->SetConfig(&videoConfig);
+ bRet = pRtcpEncNode->SendPictureLost(kPsfbFir);
+ EXPECT_EQ(bRet, true);
+ pRtcpEncNode->Stop();
+ delete pRtcpEncNode;
+}
+
+TEST_F(RtcpEncoderNodeTests, TestSendTmmbrn)
+{
+ RtcpEncoderNode* pRtcpEncNode = new RtcpEncoderNode();
+ pRtcpEncNode->SetMediaType(IMS_MEDIA_VIDEO);
+ VideoConfig videoConfig;
+ setupVideoConfig(videoConfig);
+ videoConfig.setRtcpFbType(VideoConfig::RTP_FB_TMMBR);
+ pRtcpEncNode->SetConfig(&videoConfig);
+ EXPECT_EQ(pRtcpEncNode->Start(), RESULT_SUCCESS);
+
+ TmmbrParams tmmbr;
+ tmmbr.ssrc = 0x1111;
+ tmmbr.exp = 0x2222;
+ tmmbr.mantissa = 0x3333;
+ tmmbr.overhead = 0x4444;
+ bool bRet = pRtcpEncNode->SendTmmbrn(kRtpFbTmmbr, &tmmbr);
+ EXPECT_EQ(bRet, true);
+
+ videoConfig.setRtcpFbType(VideoConfig::RTP_FB_TMMBR);
+ pRtcpEncNode->SetConfig(&videoConfig);
+ bRet = pRtcpEncNode->SendTmmbrn(kRtpFbTmmbr, &tmmbr);
+ EXPECT_EQ(bRet, true);
+ pRtcpEncNode->Stop();
+ delete pRtcpEncNode;
+}
+
+TEST_F(RtcpEncoderNodeTests, SendRtcpXr)
+{
+ RtcpEncoderNode* pRtcpEncNode = new RtcpEncoderNode();
+ pRtcpEncNode->SetMediaType(IMS_MEDIA_VIDEO);
+ EXPECT_EQ(pRtcpEncNode->Start(), RESULT_SUCCESS);
+
+ bool bRet = pRtcpEncNode->SendRtcpXr(nullptr, 0);
+ EXPECT_EQ(bRet, false);
+
+ uint8_t* pDummyRtcpXrPacket = new uint8_t[10];
+ bRet = pRtcpEncNode->SendRtcpXr(pDummyRtcpXrPacket, 10);
+ EXPECT_EQ(bRet, true);
+ pRtcpEncNode->Stop();
+ delete pRtcpEncNode;
+}
+} // namespace \ No newline at end of file
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextStreamGraphRtcpTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextStreamGraphRtcpTest.cpp
index 4436e429..a292a5f5 100644
--- a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextStreamGraphRtcpTest.cpp
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextStreamGraphRtcpTest.cpp
@@ -23,7 +23,7 @@
using namespace android::telephony::imsmedia;
// RtpConfig
-const int32_t kMediaDirection = RtpConfig::MEDIA_DIRECTION_NO_FLOW;
+const int32_t kMediaDirection = RtpConfig::MEDIA_DIRECTION_INACTIVE;
const android::String8 kRemoteAddress("127.0.0.1");
const int32_t kRemotePort = 10000;
const int8_t kDscp = 0;
@@ -130,13 +130,11 @@ TEST_F(TextStreamGraphRtcpTest, TestRtcpStreamAndUpdate)
EXPECT_EQ(graph->update(&config), RESULT_SUCCESS);
EXPECT_EQ(graph->getState(), kStreamStateRunning);
- rtcp.setIntervalSec(0);
- config.setRtcpConfig(rtcp);
+ config.setMediaDirection(RtpConfig::MEDIA_DIRECTION_NO_FLOW);
EXPECT_EQ(graph->update(&config), RESULT_SUCCESS);
EXPECT_EQ(graph->getState(), kStreamStateCreated);
- rtcp.setIntervalSec(5);
- config.setRtcpConfig(rtcp);
+ config.setMediaDirection(RtpConfig::MEDIA_DIRECTION_INACTIVE);
EXPECT_EQ(graph->update(&config), RESULT_SUCCESS);
EXPECT_EQ(graph->getState(), kStreamStateRunning);
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/nodes/TextSourceNodeTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/nodes/TextSourceNodeTest.cpp
index d4ae8902..69a17eb4 100644
--- a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/nodes/TextSourceNodeTest.cpp
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/nodes/TextSourceNodeTest.cpp
@@ -15,17 +15,14 @@
*/
#include <gtest/gtest.h>
-#include <gmock/gmock.h>
#include <TextConfig.h>
#include <TextSourceNode.h>
#include <ImsMediaCondition.h>
-#include <MockBaseNode.h>
+#include <string.h>
using namespace android::telephony::imsmedia;
using namespace android;
-using ::testing::Return;
-
// RtpConfig
const int32_t kMediaDirection = RtpConfig::MEDIA_DIRECTION_SEND_ONLY;
const String8 kRemoteAddress("127.0.0.1");
@@ -48,41 +45,40 @@ const int8_t kRedundantPayload = 102;
const int8_t kRedundantLevel = 3;
const bool kKeepRedundantLevel = true;
const int kTextInterval = 300;
-const char* kBom = {"\xEF\xBB\xBF\0"};
+const uint8_t kBom[] = {0xEF, 0xBB, 0xBF};
-class FakeBaseNode : public BaseNode
+class FakeTextNode : public BaseNode
{
public:
- FakeBaseNode() { mEmptyFlag = false; }
- virtual ~FakeBaseNode() {}
+ FakeTextNode()
+ {
+ mEmptyFlag = false;
+ memset(mData, 0, sizeof(mData));
+ }
+ virtual ~FakeTextNode() {}
virtual ImsMediaResult Start() { return RESULT_SUCCESS; }
virtual void Stop() {}
virtual bool IsRunTime() { return true; }
virtual bool IsSourceNode() { return false; }
virtual void SetConfig(void* config) { (void)config; }
- virtual void OnDataFromFrontNode(ImsMediaSubType subtype, uint8_t* data, uint32_t size,
- uint32_t timestamp, bool mark, uint32_t seq, ImsMediaSubType dataType,
- uint32_t arrivalTime)
+ virtual void OnDataFromFrontNode(ImsMediaSubType /*subtype*/, uint8_t* data, uint32_t size,
+ uint32_t /*timestamp*/, bool /*mark*/, uint32_t /*seq*/, ImsMediaSubType /*dataType*/,
+ uint32_t /*arrivalTime*/)
{
- (void)subtype;
- (void)timestamp;
- (void)mark;
- (void)seq;
- (void)dataType;
- (void)arrivalTime;
-
if (size != 0 && size <= MAX_RTT_LEN)
{
memset(mData, 0, sizeof(mData));
memcpy(mData, data, size);
mEmptyFlag = false;
}
- else if (size == 0 && data == nullptr)
+ else if (data == nullptr)
{
mEmptyFlag = true;
}
}
+ virtual kBaseNodeState GetState() { return kNodeStateRunning; }
+
uint8_t* getData() { return mData; }
bool getEmptyFlag() { return mEmptyFlag; }
@@ -94,7 +90,11 @@ private:
class TextSourceNodeTest : public ::testing::Test
{
public:
- TextSourceNodeTest() {}
+ TextSourceNodeTest()
+ {
+ mNode = NULL;
+ mFakeNode = NULL;
+ }
virtual ~TextSourceNodeTest() {}
protected:
@@ -102,8 +102,7 @@ protected:
RtcpConfig mRtcp;
ImsMediaCondition mCondition;
TextSourceNode* mNode;
- MockBaseNode* mMockNode;
- FakeBaseNode mFakeNode;
+ FakeTextNode* mFakeNode;
std::list<BaseNode*> mNodes;
virtual void SetUp() override
@@ -132,18 +131,12 @@ protected:
mNode->SetConfig(&mConfig);
mNodes.push_back(mNode);
- mMockNode = new MockBaseNode();
- mMockNode->SetDelegate(&mFakeNode);
- mMockNode->DelegateToFake();
-
- mMockNode->SetMediaType(IMS_MEDIA_TEXT);
- mMockNode->SetConfig(&mConfig);
- mNodes.push_back(mMockNode);
-
- mNode->ConnectRearNode(mMockNode);
-
- ON_CALL(*mMockNode, GetState()).WillByDefault(Return(kNodeStateRunning));
- ON_CALL(*mMockNode, IsRunTime()).WillByDefault(Return(true));
+ mFakeNode = new FakeTextNode();
+ mFakeNode->SetMediaType(IMS_MEDIA_TEXT);
+ mFakeNode->SetConfig(&mConfig);
+ mNodes.push_back(mFakeNode);
+ mNode->ConnectRearNode(mFakeNode);
+ mCondition.reset();
}
virtual void TearDown() override
@@ -165,26 +158,46 @@ TEST_F(TextSourceNodeTest, startFail)
EXPECT_EQ(mNode->Start(), RESULT_INVALID_PARAM);
}
+TEST_F(TextSourceNodeTest, sendRttDisableBom)
+{
+ mConfig.setKeepRedundantLevel(false);
+ mNode->SetConfig(&mConfig);
+
+ EXPECT_EQ(mNode->Start(), RESULT_SUCCESS);
+ EXPECT_FALSE(mFakeNode->getEmptyFlag());
+
+ String8 testText1 = String8("a");
+ mNode->SendRtt(&testText1);
+
+ mNode->ProcessData();
+ EXPECT_EQ(memcmp(mFakeNode->getData(), testText1.string(), testText1.length()), 0);
+
+ mCondition.wait_timeout(kTextInterval);
+ mNode->ProcessData();
+ // expect empty flag set
+ EXPECT_TRUE(mFakeNode->getEmptyFlag());
+}
+
TEST_F(TextSourceNodeTest, sendRttTestChunkSizeOne)
{
String8 testText1 = String8("a");
EXPECT_EQ(mNode->Start(), RESULT_SUCCESS);
- EXPECT_FALSE(mFakeNode.getEmptyFlag());
+ EXPECT_FALSE(mFakeNode->getEmptyFlag());
mNode->SendRtt(&testText1);
mNode->ProcessData();
// expect BOM
- EXPECT_EQ(String8((char*)mFakeNode.getData()), String8(kBom));
+ EXPECT_EQ(memcmp(mFakeNode->getData(), kBom, sizeof(kBom)), 0);
mCondition.wait_timeout(kTextInterval);
mNode->ProcessData();
- EXPECT_EQ(String8((char*)mFakeNode.getData()), testText1);
+ EXPECT_EQ(memcmp(mFakeNode->getData(), testText1.string(), testText1.length()), 0);
mCondition.wait_timeout(kTextInterval);
mNode->ProcessData();
// expect empty flag set
- EXPECT_TRUE(mFakeNode.getEmptyFlag());
+ EXPECT_TRUE(mFakeNode->getEmptyFlag());
}
TEST_F(TextSourceNodeTest, sendRttTestChunkSizeTwo)
@@ -192,21 +205,21 @@ TEST_F(TextSourceNodeTest, sendRttTestChunkSizeTwo)
String8 testText2 = String8("\xC2\xA9");
EXPECT_EQ(mNode->Start(), RESULT_SUCCESS);
- EXPECT_FALSE(mFakeNode.getEmptyFlag());
+ EXPECT_FALSE(mFakeNode->getEmptyFlag());
mNode->SendRtt(&testText2);
mNode->ProcessData();
// expect BOM
- EXPECT_EQ(String8((char*)mFakeNode.getData()), String8(kBom));
+ EXPECT_EQ(memcmp(mFakeNode->getData(), kBom, sizeof(kBom)), 0);
mCondition.wait_timeout(kTextInterval);
mNode->ProcessData();
- EXPECT_EQ(String8((char*)mFakeNode.getData()), testText2);
+ EXPECT_EQ(memcmp(mFakeNode->getData(), testText2.string(), testText2.length()), 0);
mCondition.wait_timeout(kTextInterval);
mNode->ProcessData();
// expect empty flag set
- EXPECT_TRUE(mFakeNode.getEmptyFlag());
+ EXPECT_TRUE(mFakeNode->getEmptyFlag());
}
TEST_F(TextSourceNodeTest, sendRttTestChunkSizeThree)
@@ -214,21 +227,21 @@ TEST_F(TextSourceNodeTest, sendRttTestChunkSizeThree)
String8 testText3 = String8("\xE2\x9C\x82");
EXPECT_EQ(mNode->Start(), RESULT_SUCCESS);
- EXPECT_FALSE(mFakeNode.getEmptyFlag());
+ EXPECT_FALSE(mFakeNode->getEmptyFlag());
mNode->SendRtt(&testText3);
mNode->ProcessData();
// expect BOM
- EXPECT_EQ(String8((char*)mFakeNode.getData()), String8(kBom));
+ EXPECT_EQ(memcmp(mFakeNode->getData(), kBom, sizeof(kBom)), 0);
mCondition.wait_timeout(kTextInterval);
mNode->ProcessData();
- EXPECT_EQ(String8((char*)mFakeNode.getData()), testText3);
+ EXPECT_EQ(memcmp(mFakeNode->getData(), testText3.string(), testText3.length()), 0);
mCondition.wait_timeout(kTextInterval);
mNode->ProcessData();
// expect empty flag set
- EXPECT_TRUE(mFakeNode.getEmptyFlag());
+ EXPECT_TRUE(mFakeNode->getEmptyFlag());
}
TEST_F(TextSourceNodeTest, sendRttTestChunkSizeFour)
@@ -236,21 +249,21 @@ TEST_F(TextSourceNodeTest, sendRttTestChunkSizeFour)
String8 testText4 = String8("\xF0\x9F\x9A\x80");
EXPECT_EQ(mNode->Start(), RESULT_SUCCESS);
- EXPECT_FALSE(mFakeNode.getEmptyFlag());
+ EXPECT_FALSE(mFakeNode->getEmptyFlag());
mNode->SendRtt(&testText4);
mNode->ProcessData();
// expect BOM
- EXPECT_EQ(String8((char*)mFakeNode.getData()), String8(kBom));
+ EXPECT_EQ(memcmp(mFakeNode->getData(), kBom, sizeof(kBom)), 0);
mCondition.wait_timeout(kTextInterval);
mNode->ProcessData();
- EXPECT_EQ(String8((char*)mFakeNode.getData()), testText4);
+ EXPECT_EQ(memcmp(mFakeNode->getData(), testText4.string(), testText4.length()), 0);
mCondition.wait_timeout(kTextInterval);
mNode->ProcessData();
// expect empty flag set
- EXPECT_TRUE(mFakeNode.getEmptyFlag());
+ EXPECT_TRUE(mFakeNode->getEmptyFlag());
}
TEST_F(TextSourceNodeTest, sendRttTestLongString)
@@ -267,31 +280,19 @@ TEST_F(TextSourceNodeTest, sendRttTestLongString)
testText5.append(testText4);
EXPECT_EQ(mNode->Start(), RESULT_SUCCESS);
- EXPECT_FALSE(mFakeNode.getEmptyFlag());
+ EXPECT_FALSE(mFakeNode->getEmptyFlag());
mNode->SendRtt(&testText5);
mNode->ProcessData();
// expect BOM
- EXPECT_EQ(String8((char*)mFakeNode.getData()), String8(kBom));
-
- mCondition.wait_timeout(kTextInterval);
- mNode->ProcessData();
- EXPECT_EQ(String8((char*)mFakeNode.getData()), testText1);
-
- mCondition.wait_timeout(kTextInterval);
- mNode->ProcessData();
- EXPECT_EQ(String8((char*)mFakeNode.getData()), testText2);
-
- mCondition.wait_timeout(kTextInterval);
- mNode->ProcessData();
- EXPECT_EQ(String8((char*)mFakeNode.getData()), testText3);
+ EXPECT_EQ(memcmp(mFakeNode->getData(), kBom, sizeof(kBom)), 0);
mCondition.wait_timeout(kTextInterval);
mNode->ProcessData();
- EXPECT_EQ(String8((char*)mFakeNode.getData()), testText4);
+ EXPECT_EQ(memcmp(mFakeNode->getData(), testText5.string(), testText5.length()), 0);
mCondition.wait_timeout(kTextInterval);
mNode->ProcessData();
// expect empty flag set
- EXPECT_TRUE(mFakeNode.getEmptyFlag());
+ EXPECT_TRUE(mFakeNode->getEmptyFlag());
}
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaBitReaderTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaBitReaderTest.cpp
new file mode 100644
index 00000000..da66bcf8
--- /dev/null
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaBitReaderTest.cpp
@@ -0,0 +1,75 @@
+/**
+ * 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 <ImsMediaBitReader.h>
+#include <string.h>
+
+class ImsMediaBitReaderTest : public ::testing::Test
+{
+public:
+protected:
+ virtual void SetUp() override {}
+
+ virtual void TearDown() override {}
+};
+
+TEST_F(ImsMediaBitReaderTest, SetBufferAndReadBitTest)
+{
+ uint8_t testBuffer[] = {1, 2, 4, 8, 16, 32, 64, 128};
+
+ ImsMediaBitReader reader;
+ EXPECT_EQ(reader.Read(24), 0);
+ reader.SetBuffer(testBuffer, sizeof(testBuffer));
+ EXPECT_EQ(reader.Read(32), 0);
+
+ for (int32_t i = 0; i < sizeof(testBuffer); i++)
+ {
+ EXPECT_EQ(reader.Read(8), testBuffer[i]);
+ }
+
+ EXPECT_EQ(reader.Read(8), 0);
+}
+
+TEST_F(ImsMediaBitReaderTest, SetBufferAndReadByteTest)
+{
+ uint8_t testBuffer[] = {1, 2, 4, 8, 16, 32, 64, 128};
+
+ ImsMediaBitReader reader;
+ reader.SetBuffer(testBuffer, sizeof(testBuffer));
+
+ uint8_t dstBuffer[8] = {0};
+
+ for (int32_t i = 0; i < sizeof(testBuffer); i++)
+ {
+ reader.ReadByteBuffer(dstBuffer + i, 8);
+ }
+
+ EXPECT_EQ(memcmp(dstBuffer, testBuffer, sizeof(testBuffer)), 0);
+}
+
+TEST_F(ImsMediaBitReaderTest, SetBufferAndReadUEModeTest)
+{
+ uint8_t testBuffer[] = {0xDA}; // 11011010
+
+ ImsMediaBitReader reader;
+ reader.SetBuffer(testBuffer, sizeof(testBuffer));
+
+ EXPECT_EQ(reader.ReadByUEMode(), 0);
+ EXPECT_EQ(reader.ReadByUEMode(), 0);
+ EXPECT_EQ(reader.ReadByUEMode(), 2);
+ EXPECT_EQ(reader.ReadByUEMode(), 1);
+}
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaBitWriterTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaBitWriterTest.cpp
new file mode 100644
index 00000000..af10eaa2
--- /dev/null
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaBitWriterTest.cpp
@@ -0,0 +1,77 @@
+/**
+ * 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 <ImsMediaBitWriter.h>
+#include <string.h>
+
+class ImsMediaBitWriterTest : public ::testing::Test
+{
+public:
+protected:
+ virtual void SetUp() override {}
+
+ virtual void TearDown() override {}
+};
+
+TEST_F(ImsMediaBitWriterTest, SetBufferAndWriteBitTest)
+{
+ uint8_t testBuffer[] = {1, 2, 4, 8, 16, 32, 64, 128};
+ uint8_t dstBuffer[8] = {0};
+
+ ImsMediaBitWriter writer;
+
+ EXPECT_EQ(writer.Write(0, 24), false);
+ writer.SetBuffer(dstBuffer, sizeof(dstBuffer));
+ EXPECT_EQ(writer.Write(0, 32), false);
+
+ for (int32_t i = 0; i < sizeof(testBuffer); i++)
+ {
+ EXPECT_EQ(writer.Write(testBuffer[i], 8), true);
+ }
+
+ EXPECT_EQ(writer.Write(0, 8), false);
+ EXPECT_EQ(memcmp(dstBuffer, testBuffer, sizeof(testBuffer)), 0);
+}
+
+TEST_F(ImsMediaBitWriterTest, SetBufferAndWriteByteTest)
+{
+ uint8_t testBuffer[] = {1, 2, 4, 8, 16, 32, 64, 128};
+ uint8_t dstBuffer[8] = {0};
+
+ ImsMediaBitWriter writer;
+ writer.SetBuffer(dstBuffer, sizeof(dstBuffer));
+
+ for (int32_t i = 0; i < sizeof(testBuffer); i++)
+ {
+ EXPECT_EQ(writer.WriteByteBuffer(testBuffer + i, 8), true);
+ }
+
+ EXPECT_EQ(memcmp(dstBuffer, testBuffer, sizeof(testBuffer)), 0);
+}
+
+TEST_F(ImsMediaBitWriterTest, SetBufferAndSeekToWriteTest)
+{
+ uint8_t testBuffer[] = {1, 2, 4, 8, 16, 32, 64, 128};
+ uint8_t dstBuffer[8] = {1, 2, 4, 8};
+
+ ImsMediaBitWriter writer;
+ writer.SetBuffer(dstBuffer, sizeof(dstBuffer));
+ writer.Seek(32);
+ writer.WriteByteBuffer(testBuffer + 4, 32);
+
+ EXPECT_EQ(memcmp(dstBuffer, testBuffer, sizeof(testBuffer)), 0);
+}
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaImageRotateTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaImageRotateTest.cpp
index 60dc69fb..a5cbd157 100644
--- a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaImageRotateTest.cpp
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaImageRotateTest.cpp
@@ -72,6 +72,76 @@ TEST_F(ImsMediaImageRotateTest, Rotate90FlipTest_ZeroImageSize)
EXPECT_EQ(memcmp(output_img, exp_img, 0), 0);
}
+TEST_F(ImsMediaImageRotateTest, Rotate90Test)
+{
+ const uint16_t img_width = 4, img_height = 4;
+ const uint32_t img_buf_size = img_width * img_height * 1.5f;
+
+ // Input image Y buffer
+ uint8_t input_img_y[] = {0, 1, 2, 3, 10, 11, 12, 13, 20, 21, 22, 23, 30, 31, 32, 33};
+
+ // Input image UV buffer
+ uint8_t input_img_uv[] = {80, 90, 81, 91, 82, 92, 83, 93};
+
+ // Expected output Y buffer
+ uint8_t exp_img[img_buf_size] = {30, 20, 10, 0, 31, 21, 11, 1, 32, 22, 12, 2, 33, 23, 13, 3, 82,
+ 92, 80, 90, 83, 93, 81, 91};
+
+ // Output image buffer to be verified
+ uint8_t output_img[img_buf_size] = {0};
+
+ ImsMediaImageRotate::YUV420_SP_Rotate90(
+ output_img, img_buf_size, img_height, input_img_y, input_img_uv, img_width, img_height);
+
+ EXPECT_EQ(memcmp(output_img, exp_img, img_buf_size), 0);
+}
+
+TEST_F(ImsMediaImageRotateTest, Rotate90WithOutputStrideTest)
+{
+ const uint16_t img_width = 4, img_height = 4, outimg_stride = 6;
+ const uint32_t img_buf_size = outimg_stride * img_width * 1.5f;
+
+ // Input image Y buffer
+ uint8_t input_img_y[] = {0, 1, 2, 3, 10, 11, 12, 13, 20, 21, 22, 23, 30, 31, 32, 33};
+
+ // Input image UV buffer
+ uint8_t input_img_uv[] = {80, 90, 81, 91, 82, 92, 83, 93};
+
+ // Expected output Y buffer
+ uint8_t exp_img[img_buf_size] = {30, 20, 10, 0, 0, 0, 31, 21, 11, 1, 0, 0, 32, 22, 12, 2, 0, 0,
+ 33, 23, 13, 3, 0, 0, 82, 92, 80, 90, 0, 0, 83, 93, 81, 91, 0, 0};
+
+ // Output image buffer to be verified
+ uint8_t output_img[img_buf_size] = {0};
+
+ ImsMediaImageRotate::YUV420_SP_Rotate90(output_img, img_buf_size, outimg_stride, input_img_y,
+ input_img_uv, img_width, img_height);
+
+ EXPECT_EQ(memcmp(output_img, exp_img, img_buf_size), 0);
+}
+
+TEST_F(ImsMediaImageRotateTest, Rotate90Flip_ZeroImageSize)
+{
+ const uint16_t img_width = 0, img_height = 0;
+
+ // Input image Y buffer
+ uint8_t input_img_y[0] = {};
+
+ // Input image UV buffer
+ uint8_t input_img_uv[0] = {};
+
+ // Expected output Y buffer
+ uint8_t exp_img[0] = {};
+
+ // Output image buffer to be verified
+ uint8_t output_img[0] = {};
+
+ ImsMediaImageRotate::YUV420_SP_Rotate90(
+ output_img, 0, img_height, input_img_y, input_img_uv, img_width, img_height);
+
+ EXPECT_EQ(memcmp(output_img, exp_img, 0), 0);
+}
+
TEST_F(ImsMediaImageRotateTest, Rotate270Test)
{
const uint16_t img_width = 4, img_height = 4;
@@ -91,7 +161,31 @@ TEST_F(ImsMediaImageRotateTest, Rotate270Test)
uint8_t output_img[img_buf_size] = {0};
ImsMediaImageRotate::YUV420_SP_Rotate270(
- output_img, input_img_y, input_img_uv, img_width, img_height);
+ output_img, img_buf_size, img_height, input_img_y, input_img_uv, img_width, img_height);
+
+ EXPECT_EQ(memcmp(output_img, exp_img, img_buf_size), 0);
+}
+
+TEST_F(ImsMediaImageRotateTest, Rotate270WithOutStrideTest)
+{
+ const uint16_t img_width = 4, img_height = 4, outimg_stride = 6;
+ const uint32_t img_buf_size = outimg_stride * img_width * 1.5f;
+
+ // Input image Y buffer
+ uint8_t input_img_y[] = {0, 1, 2, 3, 10, 11, 12, 13, 20, 21, 22, 23, 30, 31, 32, 33};
+
+ // Input image UV buffer
+ uint8_t input_img_uv[] = {80, 90, 81, 91, 82, 92, 83, 93};
+
+ // Expected output Y buffer
+ uint8_t exp_img[img_buf_size] = {3, 13, 23, 33, 0, 0, 2, 12, 22, 32, 0, 0, 1, 11, 21, 31, 0, 0,
+ 0, 10, 20, 30, 0, 0, 81, 91, 83, 93, 0, 0, 80, 90, 82, 92, 0, 0};
+
+ // Output image buffer to be verified
+ uint8_t output_img[img_buf_size] = {0};
+
+ ImsMediaImageRotate::YUV420_SP_Rotate270(output_img, img_buf_size, outimg_stride, input_img_y,
+ input_img_uv, img_width, img_height);
EXPECT_EQ(memcmp(output_img, exp_img, img_buf_size), 0);
}
@@ -113,7 +207,7 @@ TEST_F(ImsMediaImageRotateTest, Rotate270Test_ZeroImageSize)
uint8_t output_img[0] = {};
ImsMediaImageRotate::YUV420_SP_Rotate270(
- output_img, input_img_y, input_img_uv, img_width, img_height);
+ output_img, 0, img_height, input_img_y, input_img_uv, img_width, img_height);
EXPECT_EQ(memcmp(output_img, exp_img, 0), 0);
}
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtcpTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtcpTest.cpp
index 327e42fc..0806fe7d 100644
--- a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtcpTest.cpp
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtcpTest.cpp
@@ -24,7 +24,7 @@
using namespace android::telephony::imsmedia;
// RtpConfig
-const int32_t kMediaDirection = RtpConfig::MEDIA_DIRECTION_SEND_RECEIVE;
+const int32_t kMediaDirection = RtpConfig::MEDIA_DIRECTION_INACTIVE;
const android::String8 kRemoteAddress("127.0.0.1");
const int32_t kRemotePort = 10000;
const int32_t kMtu = 1300;
@@ -163,6 +163,14 @@ TEST_F(VideoStreamGraphRtcpTest, TestRtcpStreamAndUpdate)
EXPECT_EQ(graph->update(&config), RESULT_SUCCESS);
EXPECT_EQ(graph->getState(), kStreamStateRunning);
+ config.setMediaDirection(RtpConfig::MEDIA_DIRECTION_NO_FLOW);
+ EXPECT_EQ(graph->update(&config), RESULT_SUCCESS);
+ EXPECT_EQ(graph->getState(), kStreamStateCreated);
+
+ config.setMediaDirection(RtpConfig::MEDIA_DIRECTION_INACTIVE);
+ EXPECT_EQ(graph->update(&config), RESULT_SUCCESS);
+ EXPECT_EQ(graph->getState(), kStreamStateRunning);
+
EXPECT_EQ(graph->stop(), RESULT_SUCCESS);
EXPECT_EQ(graph->getState(), kStreamStateCreated);
}
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtpTxTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtpTxTest.cpp
index 332041c4..20f368ba 100644
--- a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtpTxTest.cpp
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtpTxTest.cpp
@@ -123,6 +123,12 @@ protected:
1, &previewReader),
AMEDIA_OK);
AImageReader_getWindow(previewReader, &previewSurface);
+
+ /*
+ * TODO: Below line will skip all test under this class, need to remove to include it in
+ * atest
+ */
+ GTEST_SKIP();
}
virtual void TearDown() override