summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbodamnam <bodamnam@google.com>2022-12-22 13:01:04 +0000
committerbodamnam <bodamnam@google.com>2022-12-30 02:22:32 +0000
commita2929ca030c540db1cf76b454c1b732b6f0d2643 (patch)
tree5eb730bdd3475c09c8001de146542af404a4ab7a
parenta7cd9f1b43ba316fdb53b8aa6450880760af4556 (diff)
downloadImsMedia-a2929ca030c540db1cf76b454c1b732b6f0d2643.tar.gz
Fix crash in MediaQualityAnalyzer
The current MediaQualityAnalyzer is using direct function call from the multiple node module running in different thread. It causes the vilolated memory access crash when the data list is not synchronized. I modify MediaQualityAnalzyer the collecting statistics and process message in the same thread using the message queue to prevent the crash. Modify MediaQuality member valuable to use stack memory Bug: 262843907 Bug: 263464083 Bug: 263442080 Test: Voice Call test with device, atest ImsMediaNativeTests Change-Id: Ifd9be2102a7b959c404674f515486f661ca932f2
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioJitterBuffer.cpp4
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioSession.cpp87
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/MediaQualityAnalyzer.cpp325
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioSession.h6
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/MediaQualityAnalyzer.h65
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/IImsMediaThread.cpp3
-rw-r--r--tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/MediaQualityAnalyzerTest.cpp78
7 files changed, 318 insertions, 250 deletions
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioJitterBuffer.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioJitterBuffer.cpp
index 63250c47..a7c962da 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioJitterBuffer.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioJitterBuffer.cpp
@@ -756,7 +756,9 @@ void AudioJitterBuffer::CollectRxRtpStatus(int32_t seq, kRtpPacketStatus status)
if (mCallback != NULL)
{
- mCallback->SendEvent(kCollectRxRtpStatus, seq, status);
+ SessionCallbackParameter* param =
+ new SessionCallbackParameter(seq, status, ImsMediaTimer::GetTimeInMilliSeconds());
+ mCallback->SendEvent(kCollectRxRtpStatus, reinterpret_cast<uint64_t>(param));
}
}
void AudioJitterBuffer::CollectJitterBufferStatus(int32_t currSize, int32_t maxSize)
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioSession.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioSession.cpp
index b6b37f22..ddce5b95 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioSession.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioSession.cpp
@@ -73,6 +73,8 @@ AudioSession::~AudioSession()
mListGraphRtcp.pop_front();
delete graph;
}
+
+ mMediaQualityAnalyzer->stop();
}
SessionState AudioSession::getState()
@@ -243,9 +245,9 @@ ImsMediaResult AudioSession::startGraph(RtpConfig* config)
if (mMediaQualityAnalyzer != NULL &&
!mMediaQualityAnalyzer->isSameConfig(reinterpret_cast<AudioConfig*>(config)))
{
- mMediaQualityAnalyzer->stopTimer();
+ mMediaQualityAnalyzer->stop();
mMediaQualityAnalyzer->setConfig(reinterpret_cast<AudioConfig*>(config));
- mMediaQualityAnalyzer->startTimer(1000);
+ mMediaQualityAnalyzer->start();
}
return ret;
@@ -341,6 +343,15 @@ ImsMediaResult AudioSession::addGraph(RtpConfig* config, bool enableRtcp)
}
IMLOGD1("[addGraph] mListGraphRtcp size[%d]", mListGraphRtcp.size());
+
+ if (mMediaQualityAnalyzer != NULL &&
+ !mMediaQualityAnalyzer->isSameConfig(reinterpret_cast<AudioConfig*>(config)))
+ {
+ mMediaQualityAnalyzer->stop();
+ mMediaQualityAnalyzer->setConfig(reinterpret_cast<AudioConfig*>(config));
+ mMediaQualityAnalyzer->start();
+ }
+
return RESULT_SUCCESS;
}
@@ -631,40 +642,16 @@ void AudioSession::onEvent(int32_t type, uint64_t param1, uint64_t param2)
"AUDIO_REQUEST_EVENT", kRequestAudioCmr, mSessionId, param1, param2);
break;
case kRequestRoundTripTimeDelayUpdate:
- onCollectOptionalInfo(kRoundTripDelay, 0, param1);
- break;
case kCollectPacketInfo:
- onCollectInfo(
- static_cast<ImsMediaStreamType>(param1), reinterpret_cast<RtpPacket*>(param2));
- break;
case kCollectOptionalInfo:
- if (param1 != 0)
- {
- SessionCallbackParameter* param =
- reinterpret_cast<SessionCallbackParameter*>(param1);
- onCollectOptionalInfo(param->type, param->param1, param->param2);
- delete param;
- }
- break;
case kCollectRxRtpStatus:
- onCollectRxRtpStatus(
- static_cast<int32_t>(param1), static_cast<kRtpPacketStatus>(param2));
- break;
case kCollectJitterBufferSize:
- onCollectJitterBufferSize(static_cast<int32_t>(param1), static_cast<int32_t>(param2));
- break;
case kGetRtcpXrReportBlock:
- {
- uint32_t size = 0;
- uint8_t* reportBlock = new uint8_t[MAX_BLOCK_LENGTH];
-
- if (onGetRtcpXrReportBlock(static_cast<int32_t>(param1), reportBlock, size))
+ if (mMediaQualityAnalyzer != NULL)
{
- ImsMediaEventHandler::SendEvent("AUDIO_REQUEST_EVENT", kRequestSendRtcpXrReport,
- mSessionId, reinterpret_cast<uint64_t>(reportBlock), size);
+ mMediaQualityAnalyzer->SendEvent(type, param1, param2);
}
- }
- break;
+ break;
default:
break;
}
@@ -765,46 +752,4 @@ void AudioSession::SendInternalEvent(int32_t type, uint64_t param1, uint64_t par
default:
break;
}
-}
-
-void AudioSession::onCollectInfo(ImsMediaStreamType streamType, RtpPacket* packet)
-{
- if (packet == NULL)
- {
- return;
- }
-
- IMLOGD_PACKET1(IM_PACKET_LOG_RTP, "[onCollectInfo] streamType[%d]", streamType);
-
- mMediaQualityAnalyzer->collectInfo(streamType, packet);
-}
-
-void AudioSession::onCollectOptionalInfo(int32_t optionType, int32_t seq, int32_t value)
-{
- IMLOGD_PACKET3(IM_PACKET_LOG_RTP, "[onCollectOptionalInfo] optionType[%d], seq[%d], value[%d]",
- optionType, seq, value);
-
- mMediaQualityAnalyzer->collectOptionalInfo(optionType, seq, value);
-}
-
-void AudioSession::onCollectRxRtpStatus(int32_t seq, kRtpPacketStatus status)
-{
- IMLOGD_PACKET2(IM_PACKET_LOG_RTP, "[onCollectRxRtpStatus] seq[%d], status[%d]", seq, status);
-
- mMediaQualityAnalyzer->collectRxRtpStatus(seq, status);
-}
-
-void AudioSession::onCollectJitterBufferSize(int32_t currSize, int32_t maxSize)
-{
- IMLOGD_PACKET2(IM_PACKET_LOG_RTP, "[onCollectJitterBufferSize] current size[%d], max size[%d]",
- currSize, maxSize);
-
- mMediaQualityAnalyzer->collectJitterBufferSize(currSize, maxSize);
-}
-
-bool AudioSession::onGetRtcpXrReportBlock(uint32_t nReportBlocks, uint8_t* data, uint32_t& size)
-{
- IMLOGD1("[onGetRtcpXrReportBlock] nReportBlocks[%d]", nReportBlocks);
-
- return mMediaQualityAnalyzer->getRtcpXrReportBlock(nReportBlocks, data, size);
} \ No newline at end of file
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/MediaQualityAnalyzer.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/MediaQualityAnalyzer.cpp
index 30222227..3eee302a 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/MediaQualityAnalyzer.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/MediaQualityAnalyzer.cpp
@@ -29,10 +29,12 @@
#define CALL_QUALITY_MONITORING_TIME 5
#define MAX_NUM_PACKET_STORED 500
#define DELETE_ALL 65536
+#define TIMER_INTERVAL 1000 // 1 sec
+#define STOP_TIMEOUT 1000 // 1 sec
+#define MESSAGE_PROCESSING_INTERVAL 20000 // 20 msec
MediaQualityAnalyzer::MediaQualityAnalyzer()
{
- mMediaQuality = NULL;
mCodecType = 0;
mCodecAttribute = 0;
mCallback = NULL;
@@ -42,37 +44,14 @@ MediaQualityAnalyzer::MediaQualityAnalyzer()
mJitterDuration = 0;
mPacketLossThreshold = 0;
mPacketLossDuration = 0;
- mTimerHandler = NULL;
reset();
}
MediaQualityAnalyzer::~MediaQualityAnalyzer()
{
- if (mTimerHandler != NULL)
+ if (!IsThreadStopped())
{
- MediaQuality* quality = new MediaQuality(*mMediaQuality);
- mCallback->SendEvent(kAudioCallQualityChangedInd, reinterpret_cast<uint64_t>(quality));
-
- IMLOGD0("[stopTimer]");
- ImsMediaTimer::TimerStop(mTimerHandler, NULL);
- }
-
- reset();
-
- if (mMediaQuality != NULL)
- {
- delete mMediaQuality;
- }
-}
-
-void MediaQualityAnalyzer::onTimer(hTimerHandler hTimer, void* pUserData)
-{
- (void)hTimer;
-
- if (pUserData != NULL)
- {
- MediaQualityAnalyzer* analyzer = reinterpret_cast<MediaQualityAnalyzer*>(pUserData);
- analyzer->processTimer();
+ stop();
}
}
@@ -125,33 +104,32 @@ bool MediaQualityAnalyzer::isSameConfig(AudioConfig* config)
mCodecAttribute == config->getEvsParams().getEvsBandwidth());
}
-void MediaQualityAnalyzer::startTimer(const int32_t duration)
+void MediaQualityAnalyzer::start()
{
- mTimerDuration = duration;
-
- if (duration != 0 && mTimerHandler == NULL)
- {
- IMLOGD1("[startTimer] duration[%d]", duration);
- mTimerHandler = ImsMediaTimer::TimerStart(mTimerDuration, true, onTimer, this);
+ IMLOGD0("[start]");
+ mMediaQuality.setCodecType(convertAudioCodecType(
+ mCodecType, ImsMediaAudioUtil::FindMaxEvsBandwidthFromRange(mCodecAttribute)));
- mMediaQuality->setCodecType(convertAudioCodecType(
- mCodecType, ImsMediaAudioUtil::FindMaxEvsBandwidthFromRange(mCodecAttribute)));
- }
+ StartThread();
}
-void MediaQualityAnalyzer::stopTimer()
+void MediaQualityAnalyzer::stop()
{
- MediaQuality* quality = new MediaQuality(*mMediaQuality);
- mCallback->SendEvent(kAudioCallQualityChangedInd, reinterpret_cast<uint64_t>(quality));
-
- reset();
+ IMLOGD0("[stop]");
- if (mTimerHandler != NULL)
+ if (!IsThreadStopped())
{
- IMLOGD0("[stopTimer]");
- ImsMediaTimer::TimerStop(mTimerHandler, NULL);
- mTimerHandler = NULL;
+ StopThread();
+ mConditionExit.wait_timeout(STOP_TIMEOUT);
+
+ if (mCallback != NULL)
+ {
+ MediaQuality* quality = new MediaQuality(mMediaQuality);
+ mCallback->SendEvent(kAudioCallQualityChangedInd, reinterpret_cast<uint64_t>(quality));
+ }
}
+
+ reset();
}
void MediaQualityAnalyzer::collectInfo(const int32_t streamType, RtpPacket* packet)
@@ -172,8 +150,7 @@ void MediaQualityAnalyzer::collectInfo(const int32_t streamType, RtpPacket* pack
delete pPacket;
}
- mMediaQuality->setNumRtpPacketsTransmitted(
- mMediaQuality->getNumRtpPacketsTransmitted() + 1);
+ mMediaQuality.setNumRtpPacketsTransmitted(mMediaQuality.getNumRtpPacketsTransmitted() + 1);
IMLOGD_PACKET1(IM_PACKET_LOG_RTP, "[collectInfo] tx list size[%d]", mListTxPacket.size());
}
else if (streamType == kStreamRtpRx)
@@ -181,31 +158,28 @@ void MediaQualityAnalyzer::collectInfo(const int32_t streamType, RtpPacket* pack
if (mSSRC != DEFAULT_PARAM && mSSRC != packet->ssrc)
{
IMLOGW0("[collectInfo] ssrc changed");
- // TODO: check point, no codec update but ssrc changed
- stopTimer();
- startTimer(mTimerDuration);
}
// for call qualty report
- mMediaQuality->setNumRtpPacketsReceived(mMediaQuality->getNumRtpPacketsReceived() + 1);
+ mMediaQuality.setNumRtpPacketsReceived(mMediaQuality.getNumRtpPacketsReceived() + 1);
mCallQualitySumRelativeJitter += packet->jitter;
- if (mMediaQuality->getMaxRelativeJitter() < packet->jitter)
+ if (mMediaQuality.getMaxRelativeJitter() < packet->jitter)
{
- mMediaQuality->setMaxRelativeJitter(packet->jitter);
+ mMediaQuality.setMaxRelativeJitter(packet->jitter);
}
- mMediaQuality->setAverageRelativeJitter(
- mCallQualitySumRelativeJitter / mMediaQuality->getNumRtpPacketsReceived());
+ mMediaQuality.setAverageRelativeJitter(
+ mCallQualitySumRelativeJitter / mMediaQuality.getNumRtpPacketsReceived());
switch (packet->rtpDataType)
{
case kRtpDataTypeNoData:
- mMediaQuality->setNumNoDataFrames(mMediaQuality->getNumNoDataFrames() + 1);
+ mMediaQuality.setNumNoDataFrames(mMediaQuality.getNumNoDataFrames() + 1);
break;
case kRtpDataTypeSid:
- mMediaQuality->setNumRtpSidPacketsReceived(
- mMediaQuality->getNumRtpSidPacketsReceived() + 1);
+ mMediaQuality.setNumRtpSidPacketsReceived(
+ mMediaQuality.getNumRtpSidPacketsReceived() + 1);
break;
default:
case kRtpDataTypeNormal:
@@ -259,7 +233,8 @@ void MediaQualityAnalyzer::collectOptionalInfo(
{
mSumRoundTripTime += value;
mCountRoundTripTime++;
- mMediaQuality->setAverageRoundTripTime(mSumRoundTripTime / mCountRoundTripTime);
+ mMediaQuality.setAverageRoundTripTime(mSumRoundTripTime / mCountRoundTripTime);
+
mRtcpXrEncoder->setRoundTripDelay(value);
}
else if (optionType == kReportPacketLossGap)
@@ -273,10 +248,9 @@ void MediaQualityAnalyzer::collectOptionalInfo(
mRtcpXrEncoder->stackRxRtpStatus(kRtpStatusLost, 0);
// for call quality report
- mMediaQuality->setNumRtpPacketsNotReceived(
- mMediaQuality->getNumRtpPacketsNotReceived() + 1);
+ mMediaQuality.setNumRtpPacketsNotReceived(
+ mMediaQuality.getNumRtpPacketsNotReceived() + 1);
mCallQualityNumLostPacket++;
-
// for loss checking
mNumLostPacket++;
}
@@ -287,15 +261,16 @@ void MediaQualityAnalyzer::collectOptionalInfo(
}
}
-void MediaQualityAnalyzer::collectRxRtpStatus(const int32_t seq, kRtpPacketStatus status)
+void MediaQualityAnalyzer::collectRxRtpStatus(
+ const int32_t seq, const kRtpPacketStatus status, const uint32_t time)
{
- bool found = false;
-
if (mListRxPacket.empty())
{
return;
}
+ bool found = false;
+
for (std::list<RtpPacket*>::reverse_iterator rit = mListRxPacket.rbegin();
rit != mListRxPacket.rend(); ++rit)
{
@@ -304,7 +279,7 @@ void MediaQualityAnalyzer::collectRxRtpStatus(const int32_t seq, kRtpPacketStatu
if (packet->seqNum == seq)
{
packet->status = status;
- packet->delay = ImsMediaTimer::GetTimeInMilliSeconds() - packet->delay;
+ packet->delay = time - packet->delay;
mRtcpXrEncoder->stackRxRtpStatus(packet->status, packet->delay);
IMLOGD_PACKET3(IM_PACKET_LOG_RTP, "[collectRxRtpStatus] seq[%d], status[%d], delay[%u]",
seq, packet->status, packet->delay);
@@ -322,17 +297,16 @@ void MediaQualityAnalyzer::collectRxRtpStatus(const int32_t seq, kRtpPacketStatu
switch (status)
{
case kRtpStatusNormal:
- mMediaQuality->setNumVoiceFrames(mMediaQuality->getNumVoiceFrames() + 1);
+ mMediaQuality.setNumVoiceFrames(mMediaQuality.getNumVoiceFrames() + 1);
mCallQualityNumRxPacket++;
break;
case kRtpStatusLate:
case kRtpStatusDiscarded:
- mMediaQuality->setNumDroppedRtpPackets(mMediaQuality->getNumDroppedRtpPackets() + 1);
+ mMediaQuality.setNumDroppedRtpPackets(mMediaQuality.getNumDroppedRtpPackets() + 1);
mCallQualityNumRxPacket++;
break;
case kRtpStatusDuplicated:
- mMediaQuality->setNumRtpDuplicatePackets(
- mMediaQuality->getNumRtpDuplicatePackets() + 1);
+ mMediaQuality.setNumRtpDuplicatePackets(mMediaQuality.getNumRtpDuplicatePackets() + 1);
mCallQualityNumRxPacket++;
break;
default:
@@ -364,21 +338,25 @@ void MediaQualityAnalyzer::collectJitterBufferSize(const int32_t currSize, const
mRtcpXrEncoder->setJitterBufferStatus(currSize, maxSize);
}
-void MediaQualityAnalyzer::processTimer()
+void MediaQualityAnalyzer::processData(const int32_t timeCount)
{
- ++mTimerCount;
- IMLOGD_PACKET1(IM_PACKET_LOG_RTP, "[processTimer] count[%d]", mTimerCount);
+ IMLOGD_PACKET1(IM_PACKET_LOG_RTP, "[processData] count[%d]", timeCount);
- if (mTimerCount == DEFAULT_INACTIVITY_TIME && mMediaQuality->getNumRtpPacketsReceived() == 0)
+ if (timeCount == DEFAULT_INACTIVITY_TIME && mMediaQuality.getNumRtpPacketsReceived() == 0)
{
- mMediaQuality->setRtpInactivityDetected(true);
- MediaQuality* mediaQuality = new MediaQuality(*mMediaQuality);
- mCallback->SendEvent(kAudioCallQualityChangedInd, reinterpret_cast<uint64_t>(mediaQuality));
+ mMediaQuality.setRtpInactivityDetected(true);
+
+ if (mCallback != NULL)
+ {
+ MediaQuality* mediaQuality = new MediaQuality(mMediaQuality);
+ mCallback->SendEvent(
+ kAudioCallQualityChangedInd, reinterpret_cast<uint64_t>(mediaQuality));
+ }
}
- mMediaQuality->setCallDuration(mMediaQuality->getCallDuration() + 1000);
+ mMediaQuality.setCallDuration(mMediaQuality.getCallDuration() + TIMER_INTERVAL);
- if (mTimerCount % CALL_QUALITY_MONITORING_TIME == 0)
+ if (timeCount % CALL_QUALITY_MONITORING_TIME == 0)
{
double lossRate = 0;
@@ -388,15 +366,19 @@ void MediaQualityAnalyzer::processTimer()
int32_t quality = getCallQuality(lossRate);
- IMLOGD3("[processTimer] lost[%d], received[%d], quality[%d]", mCallQualityNumLostPacket,
+ IMLOGD3("[processData] lost[%d], received[%d], quality[%d]", mCallQualityNumLostPacket,
mCallQualityNumRxPacket, quality);
- if (mMediaQuality->getDownlinkCallQualityLevel() != quality)
+ if (mMediaQuality.getDownlinkCallQualityLevel() != quality)
{
- mMediaQuality->setDownlinkCallQualityLevel(quality);
- MediaQuality* mediaQuality = new MediaQuality(*mMediaQuality);
- mCallback->SendEvent(
- kAudioCallQualityChangedInd, reinterpret_cast<uint64_t>(mediaQuality));
+ mMediaQuality.setDownlinkCallQualityLevel(quality);
+
+ if (mCallback != NULL)
+ {
+ MediaQuality* mediaQuality = new MediaQuality(mMediaQuality);
+ mCallback->SendEvent(
+ kAudioCallQualityChangedInd, reinterpret_cast<uint64_t>(mediaQuality));
+ }
}
mCallQualityNumLostPacket = 0;
@@ -404,7 +386,7 @@ void MediaQualityAnalyzer::processTimer()
}
// check packet loss
- if (mPacketLossDuration != 0 && (mTimerCount % mPacketLossDuration) == 0)
+ if (mPacketLossDuration != 0 && (timeCount % mPacketLossDuration) == 0)
{
double lossRate = 0;
@@ -413,7 +395,7 @@ void MediaQualityAnalyzer::processTimer()
lossRate = (double)mNumLostPacket / (mNumRxPacket + mNumLostPacket) * 100;
}
- IMLOGD1("[processTimer] lossRate[%lf]", lossRate);
+ IMLOGD1("[processData] lossRate[%lf]", lossRate);
if (lossRate >= mPacketLossThreshold && mCallback != NULL)
{
@@ -425,9 +407,9 @@ void MediaQualityAnalyzer::processTimer()
}
// check average jitter
- if (mJitterDuration != 0 && mTimerCount % mJitterDuration == 0)
+ if (mJitterDuration != 0 && timeCount % mJitterDuration == 0)
{
- IMLOGD1("[processTimer] Jitter[%lf]", mJitterRxPacket);
+ IMLOGD1("[processData] Jitter[%lf]", mJitterRxPacket);
if (mJitterRxPacket >= mJitterThreshold && mCallback != NULL)
{
@@ -441,7 +423,7 @@ bool MediaQualityAnalyzer::getRtcpXrReportBlock(
{
IMLOGD1("[getRtcpXrReportBlock] rtcpXrReport[%d]", rtcpXrReport);
- if (rtcpXrReport == 0 || mRtcpXrEncoder == NULL)
+ if (rtcpXrReport == 0)
{
return false;
}
@@ -462,7 +444,7 @@ bool MediaQualityAnalyzer::getRtcpXrReportBlock(
MediaQuality MediaQualityAnalyzer::getMediaQuality()
{
- return *mMediaQuality;
+ return mMediaQuality;
}
uint32_t MediaQualityAnalyzer::getRxPacketSize()
@@ -480,18 +462,145 @@ uint32_t MediaQualityAnalyzer::getLostPacketSize()
return mListLostPacket.size();
}
+void MediaQualityAnalyzer::SendEvent(uint32_t event, uint64_t paramA, uint64_t paramB)
+{
+ AddEvent(event, paramA, paramB);
+}
+
+void MediaQualityAnalyzer::AddEvent(uint32_t event, uint64_t paramA, uint64_t paramB)
+{
+ IMLOGD_PACKET2(IM_PACKET_LOG_RTP, "[AddEvent] event[%d], size[%d]", event, mListevent.size());
+ std::lock_guard<std::mutex> guard(mEventMutex);
+ mListevent.push_back(event);
+ mListParamA.push_back(paramA);
+ mListParamB.push_back(paramB);
+}
+
+void MediaQualityAnalyzer::processEvent(uint32_t event, uint64_t paramA, uint64_t paramB)
+{
+ switch (event)
+ {
+ case kRequestRoundTripTimeDelayUpdate:
+ collectOptionalInfo(kRoundTripDelay, 0, paramA);
+ break;
+ case kCollectPacketInfo:
+ collectInfo(
+ static_cast<ImsMediaStreamType>(paramA), reinterpret_cast<RtpPacket*>(paramB));
+ break;
+ case kCollectOptionalInfo:
+ if (paramA != 0)
+ {
+ SessionCallbackParameter* param =
+ reinterpret_cast<SessionCallbackParameter*>(paramA);
+ collectOptionalInfo(param->type, param->param1, param->param2);
+ delete param;
+ }
+ break;
+ case kCollectRxRtpStatus:
+ if (paramA != 0)
+ {
+ SessionCallbackParameter* param =
+ reinterpret_cast<SessionCallbackParameter*>(paramA);
+ collectRxRtpStatus(
+ param->type, static_cast<kRtpPacketStatus>(param->param1), param->param2);
+ delete param;
+ }
+ break;
+ case kCollectJitterBufferSize:
+ collectJitterBufferSize(static_cast<int32_t>(paramA), static_cast<int32_t>(paramB));
+ break;
+ case kGetRtcpXrReportBlock:
+ {
+ uint32_t size = 0;
+ uint8_t* reportBlock = new uint8_t[MAX_BLOCK_LENGTH];
+
+ if (getRtcpXrReportBlock(static_cast<int32_t>(paramA), reportBlock, size))
+ {
+ mCallback->SendEvent(
+ kRequestSendRtcpXrReport, reinterpret_cast<uint64_t>(reportBlock), size);
+ }
+ else
+ {
+ delete[] reportBlock;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void* MediaQualityAnalyzer::run()
+{
+ IMLOGD1("[run] enter, %p", this);
+ uint64_t nextTime = ImsMediaTimer::GetTimeInMicroSeconds();
+ int32_t timeCount = 0;
+ uint32_t prevTimeInMsec = ImsMediaTimer::GetTimeInMilliSeconds();
+
+ while (true)
+ {
+ if (IsThreadStopped())
+ {
+ IMLOGD0("[run] terminated");
+ break;
+ }
+
+ nextTime += MESSAGE_PROCESSING_INTERVAL;
+ uint64_t nCurrTime = ImsMediaTimer::GetTimeInMicroSeconds();
+ int64_t nTime = nextTime - nCurrTime;
+
+ if (nTime > 0)
+ {
+ ImsMediaTimer::USleep(nTime);
+ }
+
+ // process event in the list
+ for (;;)
+ {
+ mEventMutex.lock();
+
+ if (IsThreadStopped() || mListevent.size() == 0)
+ {
+ mEventMutex.unlock();
+ break;
+ }
+
+ processEvent(mListevent.front(), mListParamA.front(), mListParamB.front());
+
+ mListevent.pop_front();
+ mListParamA.pop_front();
+ mListParamB.pop_front();
+ mEventMutex.unlock();
+ }
+
+ if (IsThreadStopped())
+ {
+ IMLOGD0("[run] terminated");
+ break;
+ }
+
+ uint32_t currTimeInMsec = ImsMediaTimer::GetTimeInMilliSeconds();
+
+ // process every TIMER_INTERVAL
+ if (currTimeInMsec - prevTimeInMsec >= TIMER_INTERVAL)
+ {
+ processData(++timeCount);
+ prevTimeInMsec = currTimeInMsec;
+ }
+ }
+
+ IMLOGD1("[run] exit %p", this);
+ mConditionExit.signal();
+ return NULL;
+}
+
void MediaQualityAnalyzer::reset()
{
mSSRC = DEFAULT_PARAM;
mBeginSeq = -1;
mEndSeq = -1;
- if (mMediaQuality != NULL)
- {
- delete mMediaQuality;
- }
-
- mMediaQuality = new MediaQuality();
+ mMediaQuality = MediaQuality();
mCallQualitySumRelativeJitter = 0;
mSumRoundTripTime = 0;
mCountRoundTripTime = 0;
@@ -502,7 +611,6 @@ void MediaQualityAnalyzer::reset()
clearPacketList(mListRxPacket, DELETE_ALL);
clearPacketList(mListTxPacket, DELETE_ALL);
clearLostPacketList(DELETE_ALL);
- mTimerCount = 0;
mNumRxPacket = 0;
mNumLostPacket = 0;
mJitterRxPacket = 0.0;
@@ -510,12 +618,14 @@ void MediaQualityAnalyzer::reset()
void MediaQualityAnalyzer::clearPacketList(std::list<RtpPacket*>& list, const int32_t seq)
{
- RtpPacket* packet = NULL;
- std::list<RtpPacket*>::iterator iter;
+ if (list.empty())
+ {
+ return;
+ }
- for (iter = list.begin(); iter != list.end();)
+ for (std::list<RtpPacket*>::iterator iter = list.begin(); iter != list.end();)
{
- packet = *iter;
+ RtpPacket* packet = *iter;
// do not remove the packet seq is larger than target seq
if (packet->seqNum > seq)
{
@@ -530,12 +640,15 @@ void MediaQualityAnalyzer::clearPacketList(std::list<RtpPacket*>& list, const in
void MediaQualityAnalyzer::clearLostPacketList(const int32_t seq)
{
- LostPktEntry* packet = NULL;
- std::list<LostPktEntry*>::iterator iter;
+ if (mListLostPacket.empty())
+ {
+ return;
+ }
- for (iter = mListLostPacket.begin(); iter != mListLostPacket.end();)
+ for (std::list<LostPktEntry*>::iterator iter = mListLostPacket.begin();
+ iter != mListLostPacket.end();)
{
- packet = *iter;
+ LostPktEntry* packet = *iter;
// do not remove the lost packet entry seq is larger than target seq
if (packet->seqNum > seq)
{
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioSession.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioSession.h
index f67215bc..ce3bd47e 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioSession.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioSession.h
@@ -96,12 +96,6 @@ public:
bool IsGraphAlreadyExist(RtpConfig* config);
private:
- void onCollectInfo(ImsMediaStreamType streamType, RtpPacket* packet);
- void onCollectOptionalInfo(int32_t optionType, int32_t seq, int32_t value);
- void onCollectRxRtpStatus(int32_t seq, kRtpPacketStatus status);
- void onCollectJitterBufferSize(int32_t currSize, int32_t maxSize);
- bool onGetRtcpXrReportBlock(uint32_t nReportBlocks, uint8_t* data, uint32_t& size);
-
std::list<AudioStreamGraphRtpTx*> mListGraphRtpTx;
std::list<AudioStreamGraphRtpRx*> mListGraphRtpRx;
std::list<AudioStreamGraphRtcp*> mListGraphRtcp;
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/MediaQualityAnalyzer.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/MediaQualityAnalyzer.h
index c5d32aea..85f57382 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/MediaQualityAnalyzer.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/MediaQualityAnalyzer.h
@@ -19,27 +19,21 @@
#include <MediaQuality.h>
#include <ImsMediaDefine.h>
-#include <ImsMediaTimer.h>
+#include <IImsMediaThread.h>
+#include <ImsMediaCondition.h>
#include <RtcpXrEncoder.h>
#include <BaseSessionCallback.h>
#include <AudioConfig.h>
#include <list>
+#include <mutex>
-class MediaQualityAnalyzer
+class MediaQualityAnalyzer : public IImsMediaThread
{
public:
MediaQualityAnalyzer();
virtual ~MediaQualityAnalyzer();
/**
- * @brief A function to invoke when timer expires in certain duration.
- *
- * @param hTimer timer handler
- * @param pUserData instance who invoke timer
- */
- static void onTimer(hTimerHandler hTimer, void* pUserData);
-
- /**
* @brief Set the session callback to send the event
*/
void setCallback(BaseSessionCallback* callback);
@@ -76,16 +70,14 @@ public:
bool isSameConfig(AudioConfig* config);
/**
- * @brief Set timer to trigger for calculating statistics from collected datas
- *
- * @param duration timer duration in seconds unit.
+ * @brief Start for calculating statistics from collected datas
*/
- void startTimer(const int32_t duration);
+ void start();
/**
- * @brief Stop timer and calculating statistics from collected datas
+ * @brief Stop calculating the statistics from collected datas and send a report
*/
- void stopTimer();
+ void stop();
/**
* @brief Collect information of sending or receiving the rtp or the rtcp packet datas.
@@ -109,8 +101,9 @@ public:
*
* @param seq The packet sequence number to collect.
* @param status The status of the packet. Check in @link{kRtpPacketStatus}
+ * @param time The time marked when the frame was played in milliseconds unit
*/
- void collectRxRtpStatus(const int32_t seq, kRtpPacketStatus status);
+ void collectRxRtpStatus(const int32_t seq, const kRtpPacketStatus status, const uint32_t time);
/**
* @brief Collects jitter buffer size.
@@ -121,11 +114,6 @@ public:
void collectJitterBufferSize(const int32_t currSize, const int32_t maxSize);
/**
- * @brief It is invoked when the timer expired
- */
- void processTimer();
-
- /**
* @brief generate Rtcp-Xr report blocks with given report block enabled in bitmask type
*
* @param nReportBlocks The bitmask of report block to creates
@@ -156,7 +144,25 @@ public:
*/
uint32_t getLostPacketSize();
-private:
+ /**
+ * @brief Send message event to event handler
+ *
+ * @param event The event type
+ * @param paramA The 1st parameter
+ * @param paramB The 2nd parameter
+ */
+ void SendEvent(uint32_t event, uint64_t paramA, uint64_t paramB = 0);
+
+protected:
+ /**
+ * @brief Process the data stacked in the list
+ *
+ * @param timeCount The count increased every second
+ */
+ void processData(const int32_t timeCount);
+ void AddEvent(uint32_t event, uint64_t paramA, uint64_t paramB);
+ void processEvent(uint32_t event, uint64_t paramA, uint64_t paramB);
+ virtual void* run();
void reset();
void clearPacketList(std::list<RtpPacket*>& list, const int32_t seq);
void clearLostPacketList(const int32_t seq);
@@ -165,11 +171,6 @@ private:
BaseSessionCallback* mCallback;
std::unique_ptr<RtcpXrEncoder> mRtcpXrEncoder;
- /** The interval of timer in milliseconds unit */
- int32_t mTimerDuration;
- /** The counter increased when the timer expires */
- uint32_t mTimerCount;
- hTimerHandler mTimerHandler;
/** The list of the packets received ordered by arrival time */
std::list<RtpPacket*> mListRxPacket;
/** The list of the lost packets object */
@@ -187,7 +188,7 @@ private:
/** The end of the rx rtp packet sequence number for Rtcp-Xr report */
int32_t mEndSeq;
/** The media quality structure to report */
- MediaQuality* mMediaQuality;
+ MediaQuality mMediaQuality;
/** The sum of the relative jitter of rx packet for call quality */
int64_t mCallQualitySumRelativeJitter;
/** The sum of the round trip delay of the session for call quality */
@@ -216,6 +217,12 @@ private:
uint32_t mNumLostPacket;
/** The cumulated jitter value when any rx packet received */
double mJitterRxPacket;
+
+ std::list<uint32_t> mListevent;
+ std::list<uint64_t> mListParamA;
+ std::list<uint64_t> mListParamB;
+ std::mutex mEventMutex;
+ ImsMediaCondition mConditionExit;
};
#endif \ No newline at end of file
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/IImsMediaThread.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/IImsMediaThread.cpp
index 3e46a712..ae4ef073 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/IImsMediaThread.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/IImsMediaThread.cpp
@@ -33,14 +33,12 @@ void* runThread(void* arg)
return NULL;
}
- IMLOGD0("[runThread]");
IImsMediaThread* thread = reinterpret_cast<IImsMediaThread*>(arg);
return thread->runBase();
}
bool IImsMediaThread::StartThread()
{
- IMLOGD0("[StartThread]");
std::lock_guard<std::mutex> guard(mThreadMutex);
mThreadStopped = false;
@@ -51,7 +49,6 @@ bool IImsMediaThread::StartThread()
void IImsMediaThread::StopThread()
{
- IMLOGD0("[StopThread]");
std::lock_guard<std::mutex> guard(mThreadMutex);
mThreadStopped = true;
}
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 6c4df9ee..1c5b3425 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
@@ -21,6 +21,7 @@
#include <MediaQualityAnalyzer.h>
#include <ImsMediaCondition.h>
#include <MockBaseSessionCallback.h>
+#include <ImsMediaTimer.h>
using namespace android::telephony::imsmedia;
using ::testing::_;
@@ -168,10 +169,10 @@ protected:
TEST_F(MediaQualityAnalyzerTest, TestStartStop)
{
EXPECT_CALL(mCallback, onEvent(kAudioCallQualityChangedInd, _, _)).Times(1);
- mAnalyzer->startTimer(1000);
+ mAnalyzer->start();
MediaQuality quality = mAnalyzer->getMediaQuality();
- mAnalyzer->stopTimer();
+ mAnalyzer->stop();
EXPECT_EQ(mFakeCallback.getMediaQuality(), quality);
}
@@ -179,22 +180,22 @@ TEST_F(MediaQualityAnalyzerTest, TestStartStop)
TEST_F(MediaQualityAnalyzerTest, TestCollectTxPackets)
{
EXPECT_CALL(mCallback, onEvent(kAudioCallQualityChangedInd, _, _)).Times(1);
- mAnalyzer->startTimer(1000);
+ mAnalyzer->start();
const int32_t numPackets = 10;
for (int32_t i = 0; i < numPackets; i++)
{
RtpPacket* packet = new RtpPacket();
- mAnalyzer->collectInfo(kStreamRtpTx, packet);
+ mAnalyzer->SendEvent(kCollectPacketInfo, kStreamRtpTx, reinterpret_cast<uint64_t>(packet));
}
+ mCondition.wait_timeout(1100); // 1.1 sec
EXPECT_EQ(mAnalyzer->getTxPacketSize(), numPackets);
EXPECT_EQ(mAnalyzer->getRxPacketSize(), 0);
EXPECT_EQ(mAnalyzer->getLostPacketSize(), 0);
-
MediaQuality quality = mAnalyzer->getMediaQuality();
- mAnalyzer->stopTimer();
+ mAnalyzer->stop();
EXPECT_EQ(mAnalyzer->getTxPacketSize(), 0);
EXPECT_EQ(mAnalyzer->getRxPacketSize(), 0);
@@ -209,11 +210,11 @@ TEST_F(MediaQualityAnalyzerTest, TestCollectTxPackets)
TEST_F(MediaQualityAnalyzerTest, TestRxInactivityInd)
{
EXPECT_CALL(mCallback, onEvent(kAudioCallQualityChangedInd, _, _)).Times(2);
- mAnalyzer->startTimer(1000);
- mCondition.wait_timeout(6000); // 6sec
+ mAnalyzer->start();
+ mCondition.wait_timeout(5100); // 5.1 sec
MediaQuality quality = mAnalyzer->getMediaQuality();
- mAnalyzer->stopTimer();
+ mAnalyzer->stop();
// Check MediaQuality value
MediaQuality quality2 = mFakeCallback.getMediaQuality();
@@ -224,7 +225,7 @@ TEST_F(MediaQualityAnalyzerTest, TestRxInactivityInd)
TEST_F(MediaQualityAnalyzerTest, TestCallQualityLevelChanged)
{
EXPECT_CALL(mCallback, onEvent(kAudioCallQualityChangedInd, _, _)).Times(2);
- mAnalyzer->startTimer(1000);
+ mAnalyzer->start();
const int32_t numPackets = 10;
const int32_t jitter = 10;
@@ -240,20 +241,23 @@ TEST_F(MediaQualityAnalyzerTest, TestCallQualityLevelChanged)
packet->seqNum = i;
packet->jitter = jitter;
- mAnalyzer->collectInfo(kStreamRtpRx, packet);
- mAnalyzer->collectRxRtpStatus(i, kRtpStatusNormal);
+ mAnalyzer->SendEvent(kCollectPacketInfo, kStreamRtpRx, reinterpret_cast<uint64_t>(packet));
+
+ SessionCallbackParameter* param = new SessionCallbackParameter(
+ i, kRtpStatusNormal, ImsMediaTimer::GetTimeInMilliSeconds());
+ mAnalyzer->SendEvent(kCollectRxRtpStatus, reinterpret_cast<uint64_t>(param));
}
+ SessionCallbackParameter* param = new SessionCallbackParameter(kReportPacketLossGap, 5, 1);
+ mAnalyzer->SendEvent(kCollectOptionalInfo, reinterpret_cast<uint64_t>(param), 0);
+
+ mCondition.wait_timeout(5100); // 5.1 sec
+
EXPECT_EQ(mAnalyzer->getTxPacketSize(), 0);
EXPECT_EQ(mAnalyzer->getRxPacketSize(), numPackets - 1);
- EXPECT_EQ(mAnalyzer->getLostPacketSize(), 0);
- mAnalyzer->collectOptionalInfo(kReportPacketLossGap, 5, 1);
EXPECT_EQ(mAnalyzer->getLostPacketSize(), 1);
-
- mCondition.wait_timeout(6000); // 6sec
-
MediaQuality quality = mAnalyzer->getMediaQuality();
- mAnalyzer->stopTimer();
+ mAnalyzer->stop();
EXPECT_EQ(mAnalyzer->getTxPacketSize(), 0);
EXPECT_EQ(mAnalyzer->getRxPacketSize(), 0);
@@ -272,7 +276,7 @@ TEST_F(MediaQualityAnalyzerTest, TestJitterInd)
EXPECT_CALL(mCallback, onEvent(kAudioCallQualityChangedInd, _, _)).Times(1);
// set 10 milliseconds jitter threshold in 1 sec interval
mAnalyzer->setJitterThreshold(1, 10);
- mAnalyzer->startTimer(1000);
+ mAnalyzer->start();
const int32_t numPackets = 20;
const int32_t jitter = 20;
@@ -284,17 +288,17 @@ TEST_F(MediaQualityAnalyzerTest, TestJitterInd)
packet->seqNum = i;
packet->jitter = jitter;
packet->ssrc = ssrc;
- mAnalyzer->collectInfo(kStreamRtpRx, packet);
+ mAnalyzer->SendEvent(kCollectPacketInfo, kStreamRtpRx, reinterpret_cast<uint64_t>(packet));
}
+ mCondition.wait_timeout(1100); // 1.1 sec
+
EXPECT_EQ(mAnalyzer->getTxPacketSize(), 0);
EXPECT_EQ(mAnalyzer->getRxPacketSize(), numPackets);
EXPECT_EQ(mAnalyzer->getLostPacketSize(), 0);
- mCondition.wait_timeout(1500); // wait 1.5sec
-
MediaQuality quality = mAnalyzer->getMediaQuality();
- mAnalyzer->stopTimer();
+ mAnalyzer->stop();
EXPECT_EQ(mAnalyzer->getTxPacketSize(), 0);
EXPECT_EQ(mAnalyzer->getRxPacketSize(), 0);
@@ -308,7 +312,7 @@ TEST_F(MediaQualityAnalyzerTest, TestJitterInd)
TEST_F(MediaQualityAnalyzerTest, TestSsrcChange)
{
- mAnalyzer->startTimer(1000);
+ mAnalyzer->start();
const int32_t numPackets = 20;
const int32_t jitter = 20;
@@ -327,11 +331,17 @@ TEST_F(MediaQualityAnalyzerTest, TestSsrcChange)
packet->ssrc = ssrc2;
}
- mAnalyzer->collectInfo(kStreamRtpRx, packet);
+ mAnalyzer->SendEvent(kCollectPacketInfo, kStreamRtpRx, reinterpret_cast<uint64_t>(packet));
}
+ mCondition.wait_timeout(1100); // 1.1 sec
EXPECT_EQ(mAnalyzer->getTxPacketSize(), 0);
- EXPECT_EQ(mAnalyzer->getRxPacketSize(), numPackets - 5);
+ EXPECT_EQ(mAnalyzer->getRxPacketSize(), numPackets);
+ EXPECT_EQ(mAnalyzer->getLostPacketSize(), 0);
+ mAnalyzer->stop();
+
+ EXPECT_EQ(mAnalyzer->getTxPacketSize(), 0);
+ EXPECT_EQ(mAnalyzer->getRxPacketSize(), 0);
EXPECT_EQ(mAnalyzer->getLostPacketSize(), 0);
}
@@ -341,7 +351,7 @@ TEST_F(MediaQualityAnalyzerTest, TestPacketLossInd)
EXPECT_CALL(mCallback, onEvent(kAudioCallQualityChangedInd, _, _)).Times(1);
// 1 percent packet loss threshold in 1 sec interval
mAnalyzer->setPacketLossThreshold(1, 1);
- mAnalyzer->startTimer(1000);
+ mAnalyzer->start();
const int32_t numPackets = 10;
@@ -356,20 +366,20 @@ TEST_F(MediaQualityAnalyzerTest, TestPacketLossInd)
packet->seqNum = i;
packet->jitter = 10;
- mAnalyzer->collectInfo(kStreamRtpRx, packet);
+ mAnalyzer->SendEvent(kCollectPacketInfo, kStreamRtpRx, reinterpret_cast<uint64_t>(packet));
}
+ SessionCallbackParameter* param = new SessionCallbackParameter(kReportPacketLossGap, 5, 1);
+ mAnalyzer->SendEvent(kCollectOptionalInfo, reinterpret_cast<uint64_t>(param), 0);
+
+ mCondition.wait_timeout(1100); // 1.1 sec
+
EXPECT_EQ(mAnalyzer->getTxPacketSize(), 0);
EXPECT_EQ(mAnalyzer->getRxPacketSize(), numPackets - 1);
- EXPECT_EQ(mAnalyzer->getLostPacketSize(), 0);
-
- mAnalyzer->collectOptionalInfo(kReportPacketLossGap, 5, 1);
EXPECT_EQ(mAnalyzer->getLostPacketSize(), 1);
- mCondition.wait_timeout(1500); // wait 1.5sec
-
MediaQuality quality = mAnalyzer->getMediaQuality();
- mAnalyzer->stopTimer();
+ mAnalyzer->stop();
EXPECT_EQ(mAnalyzer->getTxPacketSize(), 0);
EXPECT_EQ(mAnalyzer->getRxPacketSize(), 0);