diff options
Diffstat (limited to 'tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia')
16 files changed, 2197 insertions, 113 deletions
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/MediaQualityThresholdTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/MediaQualityThresholdTest.cpp index 1ab1ff01..33494468 100644 --- a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/MediaQualityThresholdTest.cpp +++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/MediaQualityThresholdTest.cpp @@ -26,6 +26,7 @@ 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; +const int32_t kVideoBitrateBps = 100000; class MediaQualityThresholdTest : public ::testing::Test { @@ -42,6 +43,7 @@ protected: threshold.setRtpPacketLossRate(kRtpPacketLossRate); threshold.setRtpJitterMillis(kRtpJitterMillis); threshold.setNotifyCurrentStatus(kNotifyCurrentStatus); + threshold.setVideoBitrateBps(kVideoBitrateBps); } virtual void TearDown() override {} @@ -56,6 +58,7 @@ TEST_F(MediaQualityThresholdTest, TestGetterSetter) EXPECT_EQ(threshold.getRtpPacketLossRate(), kRtpPacketLossRate); EXPECT_EQ(threshold.getRtpJitterMillis(), kRtpJitterMillis); EXPECT_EQ(threshold.getNotifyCurrentStatus(), kNotifyCurrentStatus); + EXPECT_EQ(threshold.getVideoBitrateBps(), kVideoBitrateBps); } TEST_F(MediaQualityThresholdTest, TestParcel) @@ -85,6 +88,7 @@ TEST_F(MediaQualityThresholdTest, TestEqual) threshold2.setRtpPacketLossRate(kRtpPacketLossRate); threshold2.setRtpJitterMillis(kRtpJitterMillis); threshold2.setNotifyCurrentStatus(kNotifyCurrentStatus); + threshold2.setVideoBitrateBps(kVideoBitrateBps); EXPECT_EQ(threshold, threshold2); } @@ -98,6 +102,7 @@ TEST_F(MediaQualityThresholdTest, TestNotEqual) threshold2.setRtpPacketLossRate(kRtpPacketLossRate); threshold2.setRtpJitterMillis(kRtpJitterMillis); threshold2.setNotifyCurrentStatus(kNotifyCurrentStatus); + threshold2.setVideoBitrateBps(kVideoBitrateBps); MediaQualityThreshold threshold3; threshold3.setRtpInactivityTimerMillis(kRtpInactivityTimerMillis); @@ -107,6 +112,7 @@ TEST_F(MediaQualityThresholdTest, TestNotEqual) threshold3.setRtpPacketLossRate(std::vector<int32_t>{5, 10}); threshold3.setRtpJitterMillis(kRtpJitterMillis); threshold3.setNotifyCurrentStatus(kNotifyCurrentStatus); + threshold3.setVideoBitrateBps(kVideoBitrateBps); EXPECT_NE(threshold, threshold2); EXPECT_NE(threshold, threshold3); 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(¶m); + 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(¶m); + 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 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 diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/rtp/core/RtcpPacketTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/rtp/core/RtcpPacketTest.cpp index 37185728..1c95e03b 100644 --- a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/rtp/core/RtcpPacketTest.cpp +++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/rtp/core/RtcpPacketTest.cpp @@ -671,6 +671,39 @@ TEST_F(RtcpPacketTest, DecodeOnlyRtcpSRHeader) EXPECT_EQ(pRtcpHeader.getLength(), 0 * RTP_WORD_SIZE); } +/** + * Test RTCP XR packet. + */ +TEST_F(RtcpPacketTest, TestDecodeRtcpXrPacket) +{ + RtcpPacket rtcpPacket; + + /* + * Real-time Transport Control Protocol (Sender Report) + * 10.. .... = Version: RFC 1889 Version (2) + * ..1. .... = Padding: False + * ...0 0001 = Report count: 1 + * Packet type: XR (207) + * Length: 5 (24 bytes) + * SSRC : 0xb1c8cb02 (2982726402) + * 0x00, 0x00, 0x00, 0x01, // XR block type: VoIP Metrics Report Block (207) + * 0x00, 0x0A, // Length of the XR block in 32-bit words: 10 + * 0x02, 0x01, // Loss rate (packets lost per million packets sent): 2 bytes; + * Type-specific: 1 0x00, 0x64, // Loss rate: 100 0x03, 0x01, // Delay + * since last report (milliseconds): 2 bytes; Type-specific: 1 0x00, 0x3C, // Delay: + * 60 milliseconds + */ + uint8_t bufPacket[] = {0xa1, 0xcf, 0x00, 0x05, 0xb1, 0xc8, 0xcb, 0x02, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x0A, 0x02, 0x01, 0x00, 0x64, 0x03, 0x01, 0x00, 0x3C, 0x00, 0x02}; + + RtcpConfigInfo rtcpConfigInfo; + RtpBuffer rtpBuffer(24, bufPacket); + eRTP_STATUS_CODE res = rtcpPacket.decodeRtcpPacket(&rtpBuffer, 0, &rtcpConfigInfo); + EXPECT_EQ(res, RTP_SUCCESS); + + // TODO: After Rtcp-Xr decoder function is implemented, add checks for each files in XR report. +} + TEST_F(RtcpPacketTest, CheckAllGetSets) { RtcpPacket rtcpPacket; diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/rtp/core/RtcpXrPacketTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/rtp/core/RtcpXrPacketTest.cpp index 1c9a1cb8..45624c71 100644 --- a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/rtp/core/RtcpXrPacketTest.cpp +++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/rtp/core/RtcpXrPacketTest.cpp @@ -47,8 +47,8 @@ TEST(RtcpXrPacketTest, TestDecodeXrPacket) 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xc8, 0x53, 0x81, 0xca, 0x00, 0x0a}; eRTP_STATUS_CODE res = objRtcpXrPacket.decodeRtcpXrPacket(reinterpret_cast<RtpDt_UChar*>(bufXrPacket), 24, 0); - // Result should be failure because decode XR packet is not supported or implemented. - EXPECT_EQ(res, RTP_FAILURE); + + EXPECT_EQ(res, RTP_SUCCESS); } TEST(RtcpXrPacketTest, TestFormXrPacket) |