diff options
Diffstat (limited to 'tests')
26 files changed, 2381 insertions, 261 deletions
diff --git a/tests/native/Android.bp b/tests/native/Android.bp index 5000dee4..4171f753 100644 --- a/tests/native/Android.bp +++ b/tests/native/Android.bp @@ -22,6 +22,7 @@ cc_library_headers { name: "libimsmedia_tests_headers", export_include_dirs: [ "service/src/com/android/telephony/imsmedia/lib/libimsmedia/include", + "service/src/com/android/telephony/imsmedia/lib/libimsmedia/include/core/audio", ], } diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/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) diff --git a/tests/unit/src/com/android/telephony/imsmedia/AudioListenerTest.java b/tests/unit/src/com/android/telephony/imsmedia/AudioListenerTest.java index 353b6f7c..5dace993 100644 --- a/tests/unit/src/com/android/telephony/imsmedia/AudioListenerTest.java +++ b/tests/unit/src/com/android/telephony/imsmedia/AudioListenerTest.java @@ -22,6 +22,7 @@ import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import android.os.Looper; import android.os.Parcel; import android.os.RemoteException; import android.telephony.CallQuality; @@ -30,21 +31,22 @@ import android.telephony.imsmedia.AudioConfig; import android.telephony.imsmedia.IImsAudioSessionCallback; import android.telephony.imsmedia.ImsMediaSession; import android.telephony.imsmedia.MediaQualityStatus; +import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.List; -@RunWith(JUnit4.class) -public class AudioListenerTest { +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class AudioListenerTest extends ImsMediaTest { private static final int SESSION_ID = 1; private static final char DTMF_DIGIT = '7'; private static final int DTMF_DURATION = 120; @@ -58,30 +60,23 @@ public class AudioListenerTest { @Mock private IImsAudioSessionCallback mMockIImsAudioSessionCallback; private AudioConfig mAudioConfig; - private TestableLooper mLooper; @Before public void setUp() { MockitoAnnotations.initMocks(this); AudioSession audioSession = new AudioSession(SESSION_ID, mMockIImsAudioSessionCallback, - mAudioService, mMockAudioLocalSession, null); + mAudioService, mMockAudioLocalSession, null, Looper.myLooper()); AudioSession.AudioSessionHandler handler = audioSession.getAudioSessionHandler(); mAudioListener = new AudioListener(handler); mAudioListener.setMediaCallback(mMockCallback); mAudioConfig = AudioConfigTest.createAudioConfig(); - try { - mLooper = new TestableLooper(handler.getLooper()); - } catch (Exception e) { - throw new AssertionError("Unable to create TestableLooper", e); - } + mTestClass = AudioListenerTest.this; + super.setUp(); } @After public void tearDown() throws Exception { - if (mLooper != null) { - mLooper.destroy(); - mLooper = null; - } + super.tearDown(); } private Parcel createParcel(int event, int result, AudioConfig config) { @@ -238,10 +233,4 @@ public class AudioListenerTest { doNothing().when(mMockCallback).onSessionClosed(eq(SESSION_ID)); verify(mMockCallback, times(1)).onSessionClosed(eq(SESSION_ID)); } - - private void processAllMessages() { - while (!mLooper.getLooper().getQueue().isIdle()) { - mLooper.processAllMessages(); - } - } } diff --git a/tests/unit/src/com/android/telephony/imsmedia/AudioOffloadTest.java b/tests/unit/src/com/android/telephony/imsmedia/AudioOffloadTest.java index 5eb92175..c3013544 100644 --- a/tests/unit/src/com/android/telephony/imsmedia/AudioOffloadTest.java +++ b/tests/unit/src/com/android/telephony/imsmedia/AudioOffloadTest.java @@ -30,6 +30,7 @@ import android.hardware.radio.ims.media.IImsMedia; import android.hardware.radio.ims.media.IImsMediaSession; import android.hardware.radio.ims.media.RtpConfig; import android.hardware.radio.ims.media.RtpError; +import android.os.Looper; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.telephony.CallQuality; @@ -39,6 +40,7 @@ import android.telephony.imsmedia.IImsAudioSessionCallback; import android.telephony.imsmedia.ImsMediaSession; import android.telephony.imsmedia.MediaQualityStatus; import android.telephony.imsmedia.MediaQualityThreshold; +import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import com.android.telephony.imsmedia.AudioSession; @@ -49,7 +51,6 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -60,8 +61,9 @@ import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; -@RunWith(JUnit4.class) -public class AudioOffloadTest { +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class AudioOffloadTest extends ImsMediaTest { private static final int SESSION_ID = 1; private static final int DTMF_DURATION = 120; private static final int NO_RESOURCES = ImsMediaSession.RESULT_NO_RESOURCES; @@ -73,7 +75,6 @@ public class AudioOffloadTest { private AudioSession audioSession; private AudioOffloadListener offloadListener; private AudioSession.AudioSessionHandler handler; - private TestableLooper looper; @Mock private IImsAudioSessionCallback callback; @Mock @@ -88,24 +89,19 @@ public class AudioOffloadTest { MockitoAnnotations.initMocks(this); offloadService = spy(AudioOffloadService.getInstance()); doReturn(imsMedia).when(offloadService).getIImsMedia(); - audioSession = new AudioSession(SESSION_ID, callback, null, null, offloadService); + audioSession = new AudioSession(SESSION_ID, callback, null, null, offloadService, + Looper.myLooper()); handler = audioSession.getAudioSessionHandler(); audioSession.setAudioOffload(true); offloadListener = audioSession.getOffloadListener(); audioSession.onOpenSessionSuccess(imsMediaSession); - try { - looper = new TestableLooper(handler.getLooper()); - } catch (Exception e) { - throw new AssertionError("Unable to create TestableLooper", e); - } + mTestClass = AudioOffloadTest.this; + super.setUp(); } @After public void tearDown() throws Exception { - if (looper != null) { - looper.destroy(); - looper = null; - } + super.tearDown(); } @Test @@ -263,7 +259,8 @@ public class AudioOffloadTest { @Test public void testSetMediaQualityThreshold() { // Set Media Quality Threshold - MediaQualityThreshold threshold = MediaQualityThresholdTest.createMediaQualityThreshold(); + MediaQualityThreshold threshold = + MediaQualityThresholdTest.createMediaQualityThresholdForHal(); audioSession.setMediaQualityThreshold(threshold); processAllMessages(); try { @@ -397,10 +394,4 @@ public class AudioOffloadTest { fail("Failed to notify onCallQualityChanged: " + e); } } - - private void processAllMessages() { - while (!looper.getLooper().getQueue().isIdle()) { - looper.processAllMessages(); - } - } } diff --git a/tests/unit/src/com/android/telephony/imsmedia/AudioSessionTest.java b/tests/unit/src/com/android/telephony/imsmedia/AudioSessionTest.java index 2c9bf484..e51a46fb 100644 --- a/tests/unit/src/com/android/telephony/imsmedia/AudioSessionTest.java +++ b/tests/unit/src/com/android/telephony/imsmedia/AudioSessionTest.java @@ -21,6 +21,7 @@ import static org.mockito.Mockito.eq; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import android.os.Looper; import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.RemoteException; @@ -31,6 +32,7 @@ import android.telephony.imsmedia.IImsAudioSessionCallback; import android.telephony.imsmedia.ImsMediaSession; import android.telephony.imsmedia.MediaQualityStatus; import android.telephony.imsmedia.MediaQualityThreshold; +import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import com.android.telephony.imsmedia.AudioService; @@ -42,7 +44,6 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -50,8 +51,9 @@ import java.net.DatagramSocket; import java.net.SocketException; import java.util.ArrayList; -@RunWith(JUnit4.class) -public class AudioSessionTest { +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class AudioSessionTest extends ImsMediaTest { private static final int SESSION_ID = 1; private static final int DTMF_DURATION = 140; private static final int UNUSED = -1; @@ -69,28 +71,21 @@ public class AudioSessionTest { private AudioLocalSession audioLocalSession; @Mock private IImsAudioSessionCallback callback; - private TestableLooper looper; @Before public void setUp() { MockitoAnnotations.initMocks(this); audioSession = new AudioSession(SESSION_ID, callback, - audioService, audioLocalSession, null); + audioService, audioLocalSession, null, Looper.myLooper()); audioListener = audioSession.getAudioListener(); handler = audioSession.getAudioSessionHandler(); - try { - looper = new TestableLooper(handler.getLooper()); - } catch (Exception e) { - throw new AssertionError("Unable to create TestableLooper", e); - } + mTestClass = AudioSessionTest.this; + super.setUp(); } @After public void tearDown() throws Exception { - if (looper != null) { - looper.destroy(); - looper = null; - } + super.tearDown(); } private Parcel createParcel(int message, int result, AudioConfig config) { @@ -366,10 +361,4 @@ public class AudioSessionTest { fail("Failed to notify onSessionClosed: " + e); } } - - private void processAllMessages() { - while (!looper.getLooper().getQueue().isIdle()) { - looper.processAllMessages(); - } - } } diff --git a/tests/unit/src/com/android/telephony/imsmedia/ImsMediaTest.java b/tests/unit/src/com/android/telephony/imsmedia/ImsMediaTest.java new file mode 100644 index 00000000..759e6f32 --- /dev/null +++ b/tests/unit/src/com/android/telephony/imsmedia/ImsMediaTest.java @@ -0,0 +1,88 @@ +/* + * 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. + */ + +package com.android.telephony.imsmedia; + +import static org.junit.Assert.fail; + +import android.testing.TestableLooper; + +import org.junit.After; +import org.junit.Before; + +import java.util.ArrayList; +import java.util.List; + +public class ImsMediaTest { + protected List<TestableLooper> mTestableLoopers = new ArrayList<>(); + protected TestableLooper mTestableLooper; + protected Object mTestClass; + + @Before + public void setUp() { + mTestableLooper = TestableLooper.get(mTestClass); + if (mTestableLooper != null) { + monitorTestableLooper(mTestableLooper); + } + } + + @After + public void tearDown() throws Exception { + if (!mTestableLoopers.isEmpty()) { + for (TestableLooper looper : mTestableLoopers) { + looper.getLooper().quit(); + } + } + // Unmonitor TestableLooper for ImsMediaTest class + if (mTestableLooper != null) { + unmonitorTestableLooper(mTestableLooper); + } + // Destroy all newly created TestableLoopers so they can be reused + for (TestableLooper looper : mTestableLoopers) { + looper.destroy(); + } + TestableLooper.remove(mTestClass); + + } + + private void monitorTestableLooper(TestableLooper looper) { + if (!mTestableLoopers.contains(looper)) { + mTestableLoopers.add(looper); + } + } + + private void unmonitorTestableLooper(TestableLooper looper) { + if (mTestableLoopers.contains(looper)) { + mTestableLoopers.remove(looper); + } + } + + private boolean areAllTestableLoopersIdle() { + for (TestableLooper looper : mTestableLoopers) { + if (!looper.getLooper().getQueue().isIdle()) return false; + } + return true; + } + + public void processAllMessages() { + if (mTestableLoopers.isEmpty()) { + fail("mTestableLoopers is empty. Please make sure to add @RunWithLooper annotation"); + } + while (!areAllTestableLoopersIdle()) { + for (TestableLooper looper : mTestableLoopers) looper.processAllMessages(); + } + } +} diff --git a/tests/unit/src/com/android/telephony/imsmedia/MediaQualityThresholdTest.java b/tests/unit/src/com/android/telephony/imsmedia/MediaQualityThresholdTest.java index 40dfe866..d61e0f33 100644 --- a/tests/unit/src/com/android/telephony/imsmedia/MediaQualityThresholdTest.java +++ b/tests/unit/src/com/android/telephony/imsmedia/MediaQualityThresholdTest.java @@ -37,6 +37,7 @@ public class MediaQualityThresholdTest { private static final int[] PACKET_LOSS_RATE = { 1, 3 }; private static final int[] JITTER_THRESHOLD = { 100, 200 }; private static final boolean NOTIFY_STATUS = false; + private static final int VIDEO_BITRATE_BPS = 100000; @Test public void testConstructorAndGetters() { @@ -48,6 +49,7 @@ public class MediaQualityThresholdTest { assertThat(Arrays.equals(threshold.getRtpPacketLossRate(), PACKET_LOSS_RATE)).isTrue(); assertThat(Arrays.equals(threshold.getRtpJitterMillis(), JITTER_THRESHOLD)).isTrue(); assertThat(threshold.getNotifyCurrentStatus()).isEqualTo(NOTIFY_STATUS); + assertThat(threshold.getVideoBitrateBps()).isEqualTo(VIDEO_BITRATE_BPS); } @Test @@ -82,6 +84,7 @@ public class MediaQualityThresholdTest { .setRtpPacketLossRate(PACKET_LOSS_RATE) .setRtpJitterMillis(JITTER_THRESHOLD) .setNotifyCurrentStatus(NOTIFY_STATUS) + .setVideoBitrateBps(VIDEO_BITRATE_BPS) .build(); assertThat(threshold1).isNotEqualTo(threshold2); @@ -94,6 +97,7 @@ public class MediaQualityThresholdTest { .setRtpPacketLossRate(PACKET_LOSS_RATE) .setRtpJitterMillis(JITTER_THRESHOLD) .setNotifyCurrentStatus(NOTIFY_STATUS) + .setVideoBitrateBps(VIDEO_BITRATE_BPS) .build(); assertThat(threshold1).isNotEqualTo(threshold3); @@ -106,6 +110,7 @@ public class MediaQualityThresholdTest { .setRtpPacketLossRate(PACKET_LOSS_RATE) .setRtpJitterMillis(JITTER_THRESHOLD) .setNotifyCurrentStatus(NOTIFY_STATUS) + .setVideoBitrateBps(VIDEO_BITRATE_BPS) .build(); assertThat(threshold1).isNotEqualTo(threshold4); @@ -119,6 +124,7 @@ public class MediaQualityThresholdTest { .setRtpPacketLossRate(PACKET_LOSS_RATE) .setRtpJitterMillis(JITTER_THRESHOLD) .setNotifyCurrentStatus(NOTIFY_STATUS) + .setVideoBitrateBps(VIDEO_BITRATE_BPS) .build(); assertThat(threshold1).isNotEqualTo(threshold5); @@ -133,6 +139,20 @@ public class MediaQualityThresholdTest { .setRtpPacketLossRate(PACKET_LOSS_RATE) .setRtpJitterMillis(JITTER_THRESHOLD) .setNotifyCurrentStatus(NOTIFY_STATUS) + .setVideoBitrateBps(VIDEO_BITRATE_BPS) + .build(); + } + + static MediaQualityThreshold createMediaQualityThresholdForHal() { + return new MediaQualityThreshold.Builder() + .setRtpInactivityTimerMillis(RTP_TIMEOUT) + .setRtcpInactivityTimerMillis(RTCP_TIMEOUT) + .setRtpHysteresisTimeInMillis(RTP_HYSTERESIS_TIME) + .setRtpPacketLossDurationMillis(RTP_PACKET_LOSS_DURATION) + .setRtpPacketLossRate(PACKET_LOSS_RATE) + .setRtpJitterMillis(JITTER_THRESHOLD) + .setNotifyCurrentStatus(NOTIFY_STATUS) + .setVideoBitrateBps(0) .build(); } } diff --git a/tests/unit/src/com/android/telephony/imsmedia/TextListenerTest.java b/tests/unit/src/com/android/telephony/imsmedia/TextListenerTest.java index ce2520c1..a7f016f5 100644 --- a/tests/unit/src/com/android/telephony/imsmedia/TextListenerTest.java +++ b/tests/unit/src/com/android/telephony/imsmedia/TextListenerTest.java @@ -22,23 +22,25 @@ import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import android.os.Looper; import android.os.Parcel; import android.os.RemoteException; import android.telephony.imsmedia.IImsTextSessionCallback; import android.telephony.imsmedia.ImsMediaSession; import android.telephony.imsmedia.TextConfig; +import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -@RunWith(JUnit4.class) -public class TextListenerTest { +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class TextListenerTest extends ImsMediaTest { private static final int SESSION_ID = 1; private static final String TEXT_STREAM = "Hello"; private static final long NATIVE_OBJECT = 1234L; @@ -52,31 +54,24 @@ public class TextListenerTest { @Mock private IImsTextSessionCallback mMockIImsTextSessionCallback; private TextConfig mTextConfig; - private TestableLooper mLooper; @Before public void setUp() { MockitoAnnotations.initMocks(this); TextSession textSession = new TextSession(SESSION_ID, mMockIImsTextSessionCallback, - mTextService, mMockTextLocalSession); + mTextService, mMockTextLocalSession, Looper.myLooper()); TextSession.TextSessionHandler handler = textSession.getTextSessionHandler(); mTextListener = new TextListener(handler); mTextListener.setMediaCallback(mMockCallback); mTextListener.setNativeObject(NATIVE_OBJECT); mTextConfig = TextConfigTest.createTextConfig(); - try { - mLooper = new TestableLooper(handler.getLooper()); - } catch (Exception e) { - throw new AssertionError("Unable to create TestableLooper", e); - } + mTestClass = TextListenerTest.this; + super.setUp(); } @After - public void tearDown() { - if (mLooper != null) { - mLooper.destroy(); - mLooper = null; - } + public void tearDown() throws Exception { + super.tearDown(); } private Parcel createParcel(int event, int result, TextConfig config) { @@ -166,10 +161,4 @@ public class TextListenerTest { parcel.recycle(); verify(mMockCallback, times(1)).onSessionClosed(eq(SESSION_ID)); } - - private void processAllMessages() { - while (!mLooper.getLooper().getQueue().isIdle()) { - mLooper.processAllMessages(); - } - } } diff --git a/tests/unit/src/com/android/telephony/imsmedia/TextSessionTest.java b/tests/unit/src/com/android/telephony/imsmedia/TextSessionTest.java index 7319711e..0c150026 100644 --- a/tests/unit/src/com/android/telephony/imsmedia/TextSessionTest.java +++ b/tests/unit/src/com/android/telephony/imsmedia/TextSessionTest.java @@ -21,6 +21,7 @@ import static org.mockito.Mockito.eq; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import android.os.Looper; import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.RemoteException; @@ -28,6 +29,7 @@ import android.telephony.imsmedia.IImsTextSessionCallback; import android.telephony.imsmedia.ImsMediaSession; import android.telephony.imsmedia.MediaQualityThreshold; import android.telephony.imsmedia.TextConfig; +import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import com.android.telephony.imsmedia.Utils.OpenSessionParams; @@ -36,15 +38,15 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.net.DatagramSocket; import java.net.SocketException; -@RunWith(JUnit4.class) -public class TextSessionTest { +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class TextSessionTest extends ImsMediaTest { private static final int SESSION_ID = 1; private static final int SUCCESS = ImsMediaSession.RESULT_SUCCESS; private static final int NO_RESOURCES = ImsMediaSession.RESULT_NO_RESOURCES; @@ -60,27 +62,21 @@ public class TextSessionTest { private TextLocalSession mTextLocalSession; @Mock private IImsTextSessionCallback mCallback; - private TestableLooper mLooper; @Before public void setUp() { MockitoAnnotations.initMocks(this); - mTextSession = new TextSession(SESSION_ID, mCallback, mTextService, mTextLocalSession); + mTextSession = new TextSession(SESSION_ID, mCallback, mTextService, mTextLocalSession, + Looper.myLooper()); mTextListener = mTextSession.getTextListener(); mHandler = mTextSession.getTextSessionHandler(); - try { - mLooper = new TestableLooper(mHandler.getLooper()); - } catch (Exception e) { - throw new AssertionError("Unable to create TestableLooper", e); - } + mTestClass = TextSessionTest.this; + super.setUp(); } @After public void tearDown() throws Exception { - if (mLooper != null) { - mLooper.destroy(); - mLooper = null; - } + super.tearDown(); } private Parcel createParcel(int message, int result, TextConfig config) { @@ -241,10 +237,4 @@ public class TextSessionTest { fail("Failed to notify onSessionClosed: " + e); } } - - private void processAllMessages() { - while (!mLooper.getLooper().getQueue().isIdle()) { - mLooper.processAllMessages(); - } - } } diff --git a/tests/unit/src/com/android/telephony/imsmedia/VideoListenerTest.java b/tests/unit/src/com/android/telephony/imsmedia/VideoListenerTest.java index ad90f957..d00ccb1b 100644 --- a/tests/unit/src/com/android/telephony/imsmedia/VideoListenerTest.java +++ b/tests/unit/src/com/android/telephony/imsmedia/VideoListenerTest.java @@ -22,23 +22,25 @@ import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import android.os.Looper; import android.os.Parcel; import android.os.RemoteException; import android.telephony.imsmedia.IImsVideoSessionCallback; import android.telephony.imsmedia.ImsMediaSession; import android.telephony.imsmedia.VideoConfig; +import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -@RunWith(JUnit4.class) -public class VideoListenerTest { +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class VideoListenerTest extends ImsMediaTest { private static final int SESSION_ID = 1; private static final long VIDEO_DATA = 1024; private static final int RESOLUTION_WIDTH = 640; @@ -54,31 +56,24 @@ public class VideoListenerTest { @Mock private IImsVideoSessionCallback mMockIImsVideoSessionCallback; private VideoConfig mVideoConfig; - private TestableLooper mLooper; @Before public void setUp() { MockitoAnnotations.initMocks(this); VideoSession videoSession = new VideoSession(SESSION_ID, mMockIImsVideoSessionCallback, - mVideoService, mMockVideoLocalSession); + mVideoService, mMockVideoLocalSession, Looper.myLooper()); VideoSession.VideoSessionHandler handler = videoSession.getVideoSessionHandler(); mVideoListener = new VideoListener(handler); mVideoListener.setMediaCallback(mMockCallback); mVideoListener.setNativeObject(NATIVE_OBJECT); mVideoConfig = VideoConfigTest.createVideoConfig(); - try { - mLooper = new TestableLooper(handler.getLooper()); - } catch (Exception e) { - throw new AssertionError("Unable to create TestableLooper", e); - } + mTestClass = VideoListenerTest.this; + super.setUp(); } @After - public void tearDown() { - if (mLooper != null) { - mLooper.destroy(); - mLooper = null; - } + public void tearDown() throws Exception { + super.tearDown(); } private Parcel createParcel(int event, int result) { @@ -170,14 +165,14 @@ public class VideoListenerTest { } @Test - public void testEventPacketLossInd() throws RemoteException { - Parcel parcel = createParcel(VideoSession.EVENT_PACKET_LOSS_IND, + public void testEventNotifyBitrateInd() throws RemoteException { + Parcel parcel = createParcel(VideoSession.EVENT_NOTIFY_BITRATE_IND, ImsMediaSession.PACKET_TYPE_RTCP); mVideoListener.onMessage(parcel); processAllMessages(); parcel.recycle(); verify(mMockIImsVideoSessionCallback, - times(1)).notifyPacketLoss(eq(ImsMediaSession.PACKET_TYPE_RTCP)); + times(1)).notifyBitrate(eq(ImsMediaSession.PACKET_TYPE_RTCP)); } @Test @@ -201,10 +196,4 @@ public class VideoListenerTest { parcel.recycle(); verify(mMockCallback, times(1)).onSessionClosed(eq(SESSION_ID)); } - - private void processAllMessages() { - while (!mLooper.getLooper().getQueue().isIdle()) { - mLooper.processAllMessages(); - } - } } diff --git a/tests/unit/src/com/android/telephony/imsmedia/VideoSessionTest.java b/tests/unit/src/com/android/telephony/imsmedia/VideoSessionTest.java index 3f781886..d9e4b897 100644 --- a/tests/unit/src/com/android/telephony/imsmedia/VideoSessionTest.java +++ b/tests/unit/src/com/android/telephony/imsmedia/VideoSessionTest.java @@ -23,6 +23,7 @@ import static org.mockito.Mockito.verify; import android.graphics.ImageFormat; import android.media.ImageReader; +import android.os.Looper; import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.RemoteException; @@ -31,6 +32,7 @@ import android.telephony.imsmedia.IImsVideoSessionCallback; import android.telephony.imsmedia.ImsMediaSession; import android.telephony.imsmedia.MediaQualityThreshold; import android.telephony.imsmedia.VideoConfig; +import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.view.Surface; @@ -40,7 +42,6 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -48,8 +49,9 @@ import java.net.DatagramSocket; import java.net.SocketException; import java.util.ArrayList; -@RunWith(JUnit4.class) -public class VideoSessionTest { +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class VideoSessionTest extends ImsMediaTest { private static final int SESSION_ID = 1; private static final int UNUSED = -1; private static final int SUCCESS = ImsMediaSession.RESULT_SUCCESS; @@ -79,22 +81,16 @@ public class VideoSessionTest { public void setUp() { MockitoAnnotations.initMocks(this); mVideoSession = new VideoSession(SESSION_ID, mCallback, - mVideoService, mVideoLocalSession); + mVideoService, mVideoLocalSession, Looper.myLooper()); mVideoListener = mVideoSession.getVideoListener(); mHandler = mVideoSession.getVideoSessionHandler(); - try { - mLooper = new TestableLooper(mHandler.getLooper()); - } catch (Exception e) { - throw new AssertionError("Unable to create TestableLooper", e); - } + mTestClass = VideoSessionTest.this; + super.setUp(); } @After public void tearDown() throws Exception { - if (mLooper != null) { - mLooper.destroy(); - mLooper = null; - } + super.tearDown(); } private Parcel createParcel(int message, int result, VideoConfig config) { @@ -289,12 +285,12 @@ public class VideoSessionTest { @Test public void testPacketLossInd() { // Receive Packet Loss - Utils.sendMessage(mHandler, VideoSession.EVENT_PACKET_LOSS_IND, PACKET_LOSS, UNUSED); + Utils.sendMessage(mHandler, VideoSession.EVENT_NOTIFY_BITRATE_IND, PACKET_LOSS, UNUSED); processAllMessages(); try { - verify(mCallback, times(1)).notifyPacketLoss(eq(PACKET_LOSS)); + verify(mCallback, times(1)).notifyBitrate(eq(PACKET_LOSS)); } catch (RemoteException e) { - fail("Failed to notify notifyPacketLoss: " + e); + fail("Failed to notify notifyBitrate: " + e); } } @@ -330,10 +326,4 @@ public class VideoSessionTest { fail("Failed to notify onSessionClosed: " + e); } } - - private void processAllMessages() { - while (!mLooper.getLooper().getQueue().isIdle()) { - mLooper.processAllMessages(); - } - } } |