diff options
58 files changed, 1863 insertions, 705 deletions
diff --git a/service/src/com/android/telephony/imsmedia/AudioListener.java b/service/src/com/android/telephony/imsmedia/AudioListener.java index 738f4083..f1afc46b 100644 --- a/service/src/com/android/telephony/imsmedia/AudioListener.java +++ b/service/src/com/android/telephony/imsmedia/AudioListener.java @@ -19,10 +19,14 @@ package com.android.telephony.imsmedia; import android.os.Handler; import android.os.Parcel; import android.telephony.CallQuality; +import android.telephony.ims.RtpHeaderExtension; import android.telephony.imsmedia.AudioConfig; import android.telephony.imsmedia.MediaQualityStatus; import android.util.Log; +import java.util.ArrayList; +import java.util.List; + /** * Audio listener to process JNI messages from local AP based RTP stack */ @@ -91,7 +95,14 @@ public class AudioListener implements JNIImsMediaListener { } break; case AudioSession.EVENT_RTP_HEADER_EXTENSION_IND: - Utils.sendMessage(mHandler, event); + { + final List<RtpHeaderExtension> extensions = new ArrayList<RtpHeaderExtension>(); + final int listSize = parcel.readInt(); + for (int i = 0; i < listSize; i++) { + extensions.add(RtpHeaderExtension.CREATOR.createFromParcel(parcel)); + } + Utils.sendMessage(mHandler, event, extensions); + } break; case AudioSession.EVENT_MEDIA_QUALITY_STATUS_IND: { diff --git a/service/src/com/android/telephony/imsmedia/AudioLocalSession.java b/service/src/com/android/telephony/imsmedia/AudioLocalSession.java index fc5f1927..2955f952 100644 --- a/service/src/com/android/telephony/imsmedia/AudioLocalSession.java +++ b/service/src/com/android/telephony/imsmedia/AudioLocalSession.java @@ -158,8 +158,14 @@ public class AudioLocalSession { * @param extensions List of RTP header extensions to be transmitted */ public void sendHeaderExtension(final List<RtpHeaderExtension> extensions) { - Log.d(TAG, "sendHeaderExtension"); - // TODO: add implementation + Log.d(TAG, "sendHeaderExtension, extension=" + extensions); + Parcel parcel = Parcel.obtain(); + parcel.writeInt(AudioSession.CMD_SEND_RTP_HDR_EXTN); + parcel.writeInt(extensions.size()); + for (RtpHeaderExtension item : extensions) { + item.writeToParcel(parcel, 0); + } + sendRequest(mSessionId, parcel); } /** diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/include/CallQuality.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/include/CallQuality.h index 491a6f1f..67fb1f6d 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/include/CallQuality.h +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/include/CallQuality.h @@ -163,7 +163,7 @@ private: bool mRxSilenceDetected; /** True if only silence RTP packets are sent for 20 seconds immediately after the call is * connected. The silence packet can be detected by observing that the RTP timestamp is not - * contiguous with the end of the int32_terval covered by the previous packet even though the + * contiguous with the end of the interval covered by the previous packet even though the * RTP sequence number has been incremented only by one. Check RFC 3389. */ bool mTxSilenceDetected; /** The number of voice frames sent by jitter buffer to audio. */ @@ -172,9 +172,9 @@ private: int32_t mNumNoDataFrames; /** The number of RTP Voice packets dropped by jitter buffer. */ int32_t mNumDroppedRtpPackets; - /** The minimum playout delay in the reporting int32_terval in milliseconds. */ + /** The minimum playout delay in the reporting interval in milliseconds. */ int64_t mMinPlayoutDelayMillis; - /** The maximum Playout delay in the reporting int32_terval in milliseconds. */ + /** The maximum Playout delay in the reporting interval in milliseconds. */ int64_t mMaxPlayoutDelayMillis; /** The total number of RTP SID (Silence Insertion Descriptor) */ int32_t mNumRtpSidPacketsReceived; diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/include/RtpHeaderExtension.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/include/RtpHeaderExtension.h new file mode 100644 index 00000000..f3c52272 --- /dev/null +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/include/RtpHeaderExtension.h @@ -0,0 +1,71 @@ +/** + * 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 RTPEXTENSION_H +#define RTPEXTENSION_H + +#include <binder/Parcel.h> +#include <binder/Parcelable.h> +#include <binder/Status.h> +#include <stdint.h> + +namespace android +{ + +namespace telephony +{ + +namespace imsmedia +{ + +/** Native representation of android.telephony.imsmedia.RtpHeaderExtension */ + +/** + * The class to encapsulate RTP header extension. + * Per RFC8285, an RTP header extension consists of both a local identifier in the range 1-14, an + * 8-bit length indicator and a number of extension data bytes equivalent to the stated length. + */ +class RtpHeaderExtension : public Parcelable +{ +public: + RtpHeaderExtension(); + RtpHeaderExtension(const RtpHeaderExtension& extension); + virtual ~RtpHeaderExtension(); + RtpHeaderExtension& operator=(const RtpHeaderExtension& extension); + bool operator==(const RtpHeaderExtension& extension) const; + bool operator!=(const RtpHeaderExtension& extension) const; + virtual status_t writeToParcel(Parcel* parcel) const; + virtual status_t readFromParcel(const Parcel* in); + int32_t getLocalIdentifier(); + void setLocalIdentifier(int32_t id); + uint8_t* getExtensionData() const; + void setExtensionData(const uint8_t* data, const int32_t size); + int32_t getExtensionDataSize(); + void setExtensionDataSize(int32_t size); + +protected: + // The local identifier for this RTP header extension. + int32_t mLocalIdentifier; + // The data for this RTP header extension. + uint8_t* mExtensionData; + // The length of the mExtensionData + int32_t mExtensionDataSize; +}; +} // namespace imsmedia +} // namespace telephony +} // namespace android + +#endif
\ No newline at end of file diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/include/VideoConfig.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/include/VideoConfig.h index eff588ff..8a6f1f57 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/include/VideoConfig.h +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/include/VideoConfig.h @@ -252,8 +252,8 @@ protected: int32_t deviceOrientationDegree; /* The value to identify CVO RTP header extension features is enabled by the SDP negotiation. * When the flag is set, MediaStack sends CVO RTP extension byte in the RTP header when the - * sendHeaderExtension is invoked and the Video IDR frame is sent. if this value is -1, - * CVO is disabled, and non zero means CVO enabled with specified offset. Check RFC 5285 */ + * Video IDR frame is sent. if this value is -1, CVO is disabled, and non zero means CVO enabled + * with specified offset. Check RFC 5285 */ int32_t cvoValue; /* The RTPFB, PSFB configuration with RTCP Protocol */ int32_t rtcpFbTypes; diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/src/RtpHeaderExtension.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/src/RtpHeaderExtension.cpp new file mode 100644 index 00000000..e65bd752 --- /dev/null +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/src/RtpHeaderExtension.cpp @@ -0,0 +1,199 @@ +/** + * 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 <RtpHeaderExtension.h> + +namespace android +{ + +namespace telephony +{ + +namespace imsmedia +{ + +RtpHeaderExtension::RtpHeaderExtension() : + mLocalIdentifier(0), + mExtensionData(nullptr), + mExtensionDataSize(0) +{ +} + +RtpHeaderExtension::RtpHeaderExtension(const RtpHeaderExtension& extension) : + mLocalIdentifier(extension.mLocalIdentifier), + mExtensionData(nullptr), + mExtensionDataSize(extension.mExtensionDataSize) +{ + if (mExtensionDataSize > 0) + { + mExtensionData = new uint8_t[mExtensionDataSize]; + memcpy(mExtensionData, extension.mExtensionData, mExtensionDataSize); + } +} + +RtpHeaderExtension::~RtpHeaderExtension() +{ + if (mExtensionData != nullptr) + { + delete[] mExtensionData; + mExtensionData = nullptr; + } +} + +RtpHeaderExtension& RtpHeaderExtension::operator=(const RtpHeaderExtension& extension) +{ + if (this != &extension) + { + mLocalIdentifier = extension.mLocalIdentifier; + this->setExtensionData(extension.mExtensionData, extension.mExtensionDataSize); + } + + return *this; +} + +bool RtpHeaderExtension::operator==(const RtpHeaderExtension& extension) const +{ + return (mLocalIdentifier == extension.mLocalIdentifier && + memcmp(mExtensionData, extension.mExtensionData, mExtensionDataSize) == 0); +} + +bool RtpHeaderExtension::operator!=(const RtpHeaderExtension& extension) const +{ + return (mLocalIdentifier != extension.mLocalIdentifier || + memcmp(mExtensionData, extension.mExtensionData, mExtensionDataSize) != 0); +} + +status_t RtpHeaderExtension::writeToParcel(Parcel* parcel) const +{ + status_t err; + + if (parcel == nullptr) + { + return BAD_VALUE; + } + + err = parcel->writeInt32(mLocalIdentifier); + + if (err != NO_ERROR) + { + return err; + } + + err = parcel->writeInt32(mExtensionDataSize); + + if (err != NO_ERROR) + { + return err; + } + + void* dest = parcel->writeInplace(mExtensionDataSize); + + if (dest == nullptr) + { + return NO_MEMORY; + } + + memcpy(dest, mExtensionData, mExtensionDataSize); + return NO_ERROR; +} + +status_t RtpHeaderExtension::readFromParcel(const Parcel* parcel) +{ + status_t err; + + if (parcel == nullptr) + { + return BAD_VALUE; + } + + err = parcel->readInt32(&mLocalIdentifier); + + if (err != NO_ERROR) + { + return err; + } + + err = parcel->readInt32(&mExtensionDataSize); + + if (err != NO_ERROR) + { + return err; + } + + if (mExtensionDataSize != 0) + { + if (mExtensionData != nullptr) + { + delete[] mExtensionData; + mExtensionData = nullptr; + } + + mExtensionData = new uint8_t[mExtensionDataSize]; + const void* data = parcel->readInplace(mExtensionDataSize); + + if (data != nullptr) + { + memcpy(mExtensionData, data, mExtensionDataSize); + } + } + + return NO_ERROR; +} + +int32_t RtpHeaderExtension::getLocalIdentifier() +{ + return mLocalIdentifier; +} + +void RtpHeaderExtension::setLocalIdentifier(const int32_t id) +{ + mLocalIdentifier = id; +} + +uint8_t* RtpHeaderExtension::getExtensionData() const +{ + return mExtensionData; +} + +void RtpHeaderExtension::setExtensionData(const uint8_t* data, const int32_t size) +{ + if (mExtensionData != nullptr) + { + delete[] mExtensionData; + mExtensionData = nullptr; + mExtensionDataSize = 0; + } + + if (data != nullptr) + { + mExtensionDataSize = size; + mExtensionData = new uint8_t[mExtensionDataSize]; + memcpy(mExtensionData, data, mExtensionDataSize); + } +} + +int32_t RtpHeaderExtension::getExtensionDataSize() +{ + return mExtensionDataSize; +} +void RtpHeaderExtension::setExtensionDataSize(int32_t size) +{ + mExtensionDataSize = size; +} + +} // namespace imsmedia +} // namespace telephony +} // namespace android
\ No newline at end of file diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/BaseJitterBuffer.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/BaseJitterBuffer.cpp index 06eda0ff..c039e690 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/BaseJitterBuffer.cpp +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/BaseJitterBuffer.cpp @@ -32,7 +32,10 @@ BaseJitterBuffer::BaseJitterBuffer() mMaxSaveFrameNum = 0; } -BaseJitterBuffer::~BaseJitterBuffer() {} +BaseJitterBuffer::~BaseJitterBuffer() +{ + mDataQueue.Clear(); +} void BaseJitterBuffer::SetSessionCallback(BaseSessionCallback* callback) { @@ -58,13 +61,12 @@ void BaseJitterBuffer::SetJitterBufferSize(uint32_t nInit, uint32_t nMin, uint32 } void BaseJitterBuffer::SetJitterOptions( - uint32_t nReduceTH, uint32_t nStepSize, double zValue, bool bIgnoreSID, bool bImprovement) + uint32_t nReduceTH, uint32_t nStepSize, double zValue, bool bIgnoreSID) { (void)nReduceTH; (void)nStepSize; (void)zValue; (void)bIgnoreSID; - (void)bImprovement; } uint32_t BaseJitterBuffer::GetCount() diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/BaseStreamGraph.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/BaseStreamGraph.cpp index d2b2292c..0609cb31 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/BaseStreamGraph.cpp +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/BaseStreamGraph.cpp @@ -111,9 +111,8 @@ void BaseStreamGraph::AddNode(BaseNode* pNode, bool bReverse) mListNodeToStart.push_back(pNode); } - if (pNode->IsRunTime() == false) + if (!pNode->IsRunTime() || !pNode->IsRunTimeStart()) { - IMLOGD1("[AddNode] Add to scheduler[%s]", pNode->GetNodeName()); mScheduler->RegisterNode(pNode); } } @@ -125,7 +124,9 @@ void BaseStreamGraph::RemoveNode(BaseNode* pNode) return; } - if (pNode->IsRunTime() == false) + IMLOGD1("[RemoveNode] node[%s]", pNode->GetNodeName()); + + if (!pNode->IsRunTime() || !pNode->IsRunTimeStart()) { mScheduler->DeRegisterNode(pNode); } diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/IRtpSession.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/IRtpSession.cpp index f2a97fc4..11647e48 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/IRtpSession.cpp +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/IRtpSession.cpp @@ -298,40 +298,40 @@ void IRtpSession::StopRtcp() } } -bool IRtpSession::SendRtpPacket(uint32_t nPayloadType, uint8_t* pData, uint32_t nDataSize, - uint32_t nTimestamp, bool bMark, uint32_t nTimeDiff, bool bExtension, - tRtpHeaderExtensionInfo* pExtensionInfo) +bool IRtpSession::SendRtpPacket(uint32_t payloadType, uint8_t* data, uint32_t dataSize, + uint32_t timestamp, bool mark, uint32_t timeDiff, RtpHeaderExtensionInfo* extensionInfo) { - tRtpSvc_SendRtpPacketParm stRtpPacketParam; - memset(&stRtpPacketParam, 0, sizeof(tRtpSvc_SendRtpPacketParm)); + tRtpSvc_SendRtpPacketParam stRtpPacketParam; + memset(&stRtpPacketParam, 0, sizeof(tRtpSvc_SendRtpPacketParam)); IMLOGD_PACKET5(IM_PACKET_LOG_RTP, - "SendRtpPacket, payloadType[%u], size[%u], nTS[%u], bMark[%d], bExtension[%d]", - nPayloadType, nDataSize, nTimestamp, bMark, bExtension); - stRtpPacketParam.bMbit = bMark ? eRTP_TRUE : eRTP_FALSE; - stRtpPacketParam.byPayLoadType = nPayloadType; - stRtpPacketParam.diffFromLastRtpTimestamp = nTimeDiff; - stRtpPacketParam.bXbit = bExtension ? eRTP_TRUE : eRTP_FALSE; - - if (bExtension && pExtensionInfo != nullptr) + "SendRtpPacket, payloadType[%u], size[%u], TS[%u], mark[%d], extension[%d]", + payloadType, dataSize, timestamp, mark, extensionInfo != nullptr); + stRtpPacketParam.bMbit = mark ? eRTP_TRUE : eRTP_FALSE; + stRtpPacketParam.byPayLoadType = payloadType; + stRtpPacketParam.diffFromLastRtpTimestamp = timeDiff; + stRtpPacketParam.bXbit = extensionInfo != nullptr ? eRTP_TRUE : eRTP_FALSE; + + if (extensionInfo != nullptr) { - stRtpPacketParam.nDefinedByProfile = pExtensionInfo->nDefinedByProfile; - stRtpPacketParam.nLength = pExtensionInfo->nLength; - stRtpPacketParam.nExtensionData = pExtensionInfo->nExtensionData; + stRtpPacketParam.wDefinedByProfile = extensionInfo->definedByProfile; + stRtpPacketParam.wExtLen = extensionInfo->length; + stRtpPacketParam.pExtData = extensionInfo->extensionData; + stRtpPacketParam.nExtDataSize = extensionInfo->extensionDataSize; } - if (mPrevTimestamp == nTimestamp) + if (mPrevTimestamp == timestamp) { stRtpPacketParam.bUseLastTimestamp = eRTP_TRUE; } else { stRtpPacketParam.bUseLastTimestamp = eRTP_FALSE; - mPrevTimestamp = nTimestamp; + mPrevTimestamp = timestamp; } mNumRtpDataToSend++; IMS_RtpSvc_SendRtpPacket( - this, mRtpSessionId, reinterpret_cast<char*>(pData), nDataSize, &stRtpPacketParam); + this, mRtpSessionId, reinterpret_cast<char*>(data), dataSize, &stRtpPacketParam); return true; } @@ -421,26 +421,16 @@ void IRtpSession::OnPeerInd(tRtpSvc_IndicationFromStack type, void* pMsg) { tRtpSvcIndSt_ReceiveRtpInd* pstRtp = reinterpret_cast<tRtpSvcIndSt_ReceiveRtpInd*>(pMsg); - uint32_t nSSRC = 0; - - if (pstRtp->wMsgHdrLen >= 12) - { - nSSRC = pstRtp->pMsgHdr[8]; - nSSRC <<= 8; - nSSRC += pstRtp->pMsgHdr[9]; - nSSRC <<= 8; - nSSRC += pstRtp->pMsgHdr[10]; - nSSRC <<= 8; - nSSRC += pstRtp->pMsgHdr[11]; - } if ((mEnableDTMF == false || mRtpDtmfPayloadType != pstRtp->dwPayloadType) && pstRtp->dwPayloadType != 20) { + RtpHeaderExtensionInfo extensionInfo(pstRtp->wDefinedByProfile, pstRtp->wExtLen, + reinterpret_cast<int8_t*>(pstRtp->pExtData), pstRtp->wExtDataSize); + mRtpDecoderListener->OnMediaDataInd(pstRtp->pMsgBody, pstRtp->wMsgBodyLen, pstRtp->dwTimestamp, pstRtp->bMbit, pstRtp->dwSeqNum, - pstRtp->dwPayloadType, nSSRC, pstRtp->bExtension, - pstRtp->extensionData); + pstRtp->dwPayloadType, pstRtp->dwSsrc, extensionInfo); } } break; diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/StreamScheduler.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/StreamScheduler.cpp index 70922110..d71707c7 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/StreamScheduler.cpp +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/StreamScheduler.cpp @@ -41,15 +41,7 @@ void StreamScheduler::RegisterNode(BaseNode* pNode) IMLOGD2("[RegisterNode] [%p], node[%s]", this, pNode->GetNodeName()); std::lock_guard<std::mutex> guard(mMutex); - - if (pNode->IsSourceNode()) - { - mlistSourceNode.push_back(pNode); - } - else - { - mlistRegisteredNode.push_back(pNode); - } + mlistRegisteredNode.push_back(pNode); } void StreamScheduler::DeRegisterNode(BaseNode* pNode) @@ -61,41 +53,22 @@ void StreamScheduler::DeRegisterNode(BaseNode* pNode) IMLOGD2("[DeRegisterNode] [%p], node[%s]", this, pNode->GetNodeName()); std::lock_guard<std::mutex> guard(mMutex); - - if (pNode->IsSourceNode()) - { - mlistSourceNode.remove(pNode); - } - else - { - mlistRegisteredNode.remove(pNode); - } + mlistRegisteredNode.remove(pNode); } void StreamScheduler::Start() { - uint32_t nNumOfRegisteredNode = 0; IMLOGD1("[Start] [%p] enter", this); - for (auto& node : mlistSourceNode) - { - if (node != nullptr) - { - nNumOfRegisteredNode++; - IMLOGD2("[Start] [%p] registered source node [%s]", this, node->GetNodeName()); - } - } - for (auto& node : mlistRegisteredNode) { if (node != nullptr) { - nNumOfRegisteredNode++; IMLOGD2("[Start] [%p] registered node [%s]", this, node->GetNodeName()); } } - if (nNumOfRegisteredNode > 0) + if (!mlistRegisteredNode.empty()) { IMLOGD1("[Start] [%p] Start thread", this); StartThread(); @@ -123,7 +96,7 @@ void StreamScheduler::Awake() mConditionMain.signal(); } -BaseNode* StreamScheduler::DetermineProcessingNode(uint32_t* pnMaxDataInNode) +BaseNode* StreamScheduler::DetermineProcessingNode() { if (IsThreadStopped()) { @@ -133,9 +106,9 @@ BaseNode* StreamScheduler::DetermineProcessingNode(uint32_t* pnMaxDataInNode) BaseNode* pRetNode = nullptr; uint32_t nMaxDataInNode = 0; - for (auto& node : mlistNodeToRun) + for (auto& node : mlistRegisteredNode) { - if (node != nullptr) + if (node != nullptr && !node->IsRunTime()) { uint32_t nDataInNode = node->GetDataCount(); @@ -147,35 +120,14 @@ BaseNode* StreamScheduler::DetermineProcessingNode(uint32_t* pnMaxDataInNode) } } - *pnMaxDataInNode = nMaxDataInNode; return pRetNode; } void StreamScheduler::RunRegisteredNode() { - uint32_t nMaxDataInNode; - - // run source nodes - for (auto& node : mlistSourceNode) - { - if (node != nullptr && node->GetState() == kNodeStateRunning) - { - node->ProcessData(); - } - } - - // run nodes - for (auto& node : mlistRegisteredNode) - { - if (node != nullptr) - { - mlistNodeToRun.push_back(node); - } - } - for (;;) { - BaseNode* pNode = DetermineProcessingNode(&nMaxDataInNode); + BaseNode* pNode = DetermineProcessingNode(); if (pNode == nullptr) { @@ -191,17 +143,30 @@ void StreamScheduler::RunRegisteredNode() { break; } - - mlistNodeToRun.remove(pNode); }; - - mlistNodeToRun.clear(); } void* StreamScheduler::run() { IMLOGD1("[run] [%p] enter", this); + // start nodes + mMutex.lock(); + + for (auto& node : mlistRegisteredNode) + { + if (node != nullptr && !node->IsRunTimeStart()) + { + if (node->GetState() == kNodeStateStopped && node->ProcessStart() != RESULT_SUCCESS) + { + // TODO: report error + IMLOGE0("[run] error"); + } + } + } + + mMutex.unlock(); + while (!IsThreadStopped()) { mMutex.lock(); 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 38b59c39..7332af54 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 @@ -23,6 +23,14 @@ #define AUDIO_JITTER_BUFFER_MAX_SIZE (9) #define AUDIO_JITTER_BUFFER_START_SIZE (4) #define GET_SEQ_GAP(a, b) ((uint16_t)(a) - (uint16_t)(b)) +#define JITTER_BUFFER_UPDATE_INTERVAL (2000) // ms unit +#define FRAME_INTERVAL (20) // ms unit +#define ALLOWABLE_ERROR (10) // ms unit +#define RESET_THRESHOLD (10000) // ms unit +#define TS_ROUND_QUARD (3000) // ms unit +#define USHORT_TS_ROUND_COMPARE(a, b) \ + (((a) >= (b) && (b) >= TS_ROUND_QUARD) || ((a) <= 0xffff - TS_ROUND_QUARD) || \ + ((a) <= TS_ROUND_QUARD && (b) >= 0xffff - TS_ROUND_QUARD)) AudioJitterBuffer::AudioJitterBuffer() { @@ -31,7 +39,6 @@ AudioJitterBuffer::AudioJitterBuffer() mMaxJitterBufferSize = AUDIO_JITTER_BUFFER_MAX_SIZE; AudioJitterBuffer::Reset(); mBufferIgnoreSIDPacket = false; - mBufferImprovement = false; } AudioJitterBuffer::~AudioJitterBuffer() {} @@ -41,24 +48,21 @@ void AudioJitterBuffer::Reset() mNextJitterBufferSize = mCurrJitterBufferSize; mLastPlayedSeqNum = 0; mLastPlayedTimestamp = 0; - mIsReceivedFirst = false; + mFirstFrameReceived = false; mDtxOn = false; mSIDCount = 0; - mWaiting = false; + mWaiting = true; mDeleteCount = 0; mBaseTimestamp = 0; mBaseArrivalTime = 0; - mUpdateJitterBufferSize = 0; + mCannotGetCount = 0; mCheckUpdateJitterPacketCnt = 0; - mFourceToUpdateJitterBuffer = false; + mEnforceUpdate = false; mNeedToUpdateBasePacket = false; - mCanNotGetCount = 0; - mNullDataCount = 0; BaseJitterBuffer::Reset(); - mJitterAnalyser.Reset(); - mJitterAnalyser.SetMinMaxJitterBufferSize(mMinJitterBufferSize, mMaxJitterBufferSize); + mJitterAnalyzer.Reset(); + mJitterAnalyzer.SetMinMaxJitterBufferSize(mMinJitterBufferSize, mMaxJitterBufferSize); mCurrPlayingSeq = 0; - mBufferUpdateDuration = 0; } void AudioJitterBuffer::SetJitterBufferSize(uint32_t nInit, uint32_t nMin, uint32_t nMax) @@ -92,24 +96,20 @@ void AudioJitterBuffer::SetJitterBufferSize(uint32_t nInit, uint32_t nMin, uint3 mNextJitterBufferSize = mInitJitterBufferSize; } - mJitterAnalyser.SetMinMaxJitterBufferSize(mMinJitterBufferSize, mMaxJitterBufferSize); + mJitterAnalyzer.SetMinMaxJitterBufferSize(mMinJitterBufferSize, mMaxJitterBufferSize); } void AudioJitterBuffer::SetJitterOptions( - uint32_t nReduceTH, uint32_t nStepSize, double zValue, bool bIgnoreSID, bool bImprovement) + uint32_t nReduceTH, uint32_t nStepSize, double zValue, bool bIgnoreSID) { - // do it later mBufferIgnoreSIDPacket = bIgnoreSID; - mBufferImprovement = bImprovement; - mJitterAnalyser.SetJitterOptions(nReduceTH, nStepSize, zValue); + mJitterAnalyzer.SetJitterOptions(nReduceTH, nStepSize, zValue); } void AudioJitterBuffer::Add(ImsMediaSubType subtype, uint8_t* pbBuffer, uint32_t nBufferSize, - uint32_t nTimestamp, bool bMark, uint32_t nSeqNum, ImsMediaSubType nDataType, + uint32_t nTimestamp, bool bMark, uint32_t nSeqNum, ImsMediaSubType /*nDataType*/, uint32_t arrivalTime) { - (void)nDataType; - DataEntry currEntry = DataEntry(); currEntry.subtype = subtype; currEntry.pbBuffer = pbBuffer; @@ -121,40 +121,38 @@ void AudioJitterBuffer::Add(ImsMediaSubType subtype, uint8_t* pbBuffer, uint32_t currEntry.bValid = true; currEntry.arrivalTime = arrivalTime; - // non-voice issue when min buffer size is 10 (VT case) - if (mBufferImprovement == false && mCanNotGetCount > 500) - { - IMLOGD0("[Add] Refreshed"); - Reset(); - } - else if (mBufferImprovement) + int32_t jitter = 0; + + if (mCannotGetCount > mMaxJitterBufferSize) { - if ((mCanNotGetCount > mMaxJitterBufferSize) && (mCanNotGetCount > mMinJitterBufferSize)) + IMLOGD0("[Add] refreshed"); + DataEntry* resetData = nullptr; + + while (mDataQueue.Get(&resetData)) { - IMLOGD0("[Add] Refreshed"); - CollectRxRtpStatus(nSeqNum, kRtpStatusDiscarded); - Reset(); + CollectRxRtpStatus(resetData->nSeqNum, kRtpStatusDiscarded); + Delete(); } - } - int32_t jitter = 0; + Reset(); + } - if (mBufferIgnoreSIDPacket == false) + if (!mBufferIgnoreSIDPacket) { - jitter = mJitterAnalyser.CalculateTransitTimeDifference(nTimestamp, arrivalTime); + jitter = mJitterAnalyzer.CalculateTransitTimeDifference(nTimestamp, arrivalTime); mBaseTimestamp = currEntry.nTimestamp; mBaseArrivalTime = currEntry.arrivalTime; - mJitterAnalyser.UpdateBaseTimestamp(mBaseTimestamp, mBaseArrivalTime); + mJitterAnalyzer.UpdateBaseTimestamp(mBaseTimestamp, mBaseArrivalTime); } // TODO: remove mBufferIgnoreSIDPacket logic and the statements - else if ((mBufferIgnoreSIDPacket == true) && !IsSID(currEntry.pbBuffer, currEntry.nBufferSize)) + else if (mBufferIgnoreSIDPacket && !IsSID(currEntry.pbBuffer, currEntry.nBufferSize)) { // first packet delay compensation - if ((mBaseTimestamp == 0 && mBaseArrivalTime == 0) || (mNeedToUpdateBasePacket == true)) + if ((mBaseTimestamp == 0 && mBaseArrivalTime == 0) || mNeedToUpdateBasePacket) { mBaseTimestamp = currEntry.nTimestamp; mBaseArrivalTime = currEntry.arrivalTime; - mJitterAnalyser.UpdateBaseTimestamp(mBaseTimestamp, mBaseArrivalTime); + mJitterAnalyzer.UpdateBaseTimestamp(mBaseTimestamp, mBaseArrivalTime); mNeedToUpdateBasePacket = false; } else if (mBaseTimestamp > currEntry.nTimestamp || mBaseArrivalTime > currEntry.arrivalTime) @@ -162,7 +160,7 @@ void AudioJitterBuffer::Add(ImsMediaSubType subtype, uint8_t* pbBuffer, uint32_t // rounding case (more consider case) mBaseTimestamp = currEntry.nTimestamp; mBaseArrivalTime = currEntry.arrivalTime; - mJitterAnalyser.UpdateBaseTimestamp(mBaseTimestamp, mBaseArrivalTime); + mJitterAnalyzer.UpdateBaseTimestamp(mBaseTimestamp, mBaseArrivalTime); } else { @@ -171,10 +169,11 @@ void AudioJitterBuffer::Add(ImsMediaSubType subtype, uint8_t* pbBuffer, uint32_t { mBaseTimestamp = currEntry.nTimestamp; mBaseArrivalTime = currEntry.arrivalTime; - mJitterAnalyser.UpdateBaseTimestamp(mBaseTimestamp, mBaseArrivalTime); + mJitterAnalyzer.UpdateBaseTimestamp(mBaseTimestamp, mBaseArrivalTime); } else - { // compensation case + { + // compensation case uint32_t temp = currEntry.arrivalTime; IMLOGD_PACKET2(IM_PACKET_LOG_JITTER, "Before compensation[%u], nSeqNum[%d]", temp, currEntry.nSeqNum); @@ -184,7 +183,7 @@ void AudioJitterBuffer::Add(ImsMediaSubType subtype, uint8_t* pbBuffer, uint32_t } } - jitter = mJitterAnalyser.CalculateTransitTimeDifference(nTimestamp, arrivalTime); + jitter = mJitterAnalyzer.CalculateTransitTimeDifference(nTimestamp, arrivalTime); } RtpPacket* packet = new RtpPacket(); @@ -202,7 +201,7 @@ void AudioJitterBuffer::Add(ImsMediaSubType subtype, uint8_t* pbBuffer, uint32_t packet->ssrc = mSsrc; packet->seqNum = nSeqNum; packet->jitter = jitter; - packet->arrival = ImsMediaTimer::GetTimeInMilliSeconds(); + packet->arrival = arrivalTime; mCallback->SendEvent(kCollectPacketInfo, kStreamRtpRx, reinterpret_cast<uint64_t>(packet)); if (nBufferSize == 0) @@ -255,115 +254,41 @@ void AudioJitterBuffer::Add(ImsMediaSubType subtype, uint8_t* pbBuffer, uint32_t } bool AudioJitterBuffer::Get(ImsMediaSubType* psubtype, uint8_t** ppData, uint32_t* pnDataSize, - uint32_t* pnTimestamp, bool* pbMark, uint32_t* pnSeqNum, uint32_t* pnChecker) + uint32_t* pnTimestamp, bool* pbMark, uint32_t* pnSeqNum, uint32_t currentTime) { - if (mNullDataCount < 4) - { - mNullDataCount++; - IMLOGD1("[Get] mNullDataCount is [%d].", mNullDataCount); - - if (psubtype) - *psubtype = MEDIASUBTYPE_UNDEFINED; - if (ppData) - *ppData = nullptr; - if (pnDataSize) - *pnDataSize = 0; - if (pnTimestamp) - *pnTimestamp = 0; - if (pbMark) - *pbMark = false; - if (pnSeqNum) - *pnSeqNum = 0; - if (pnChecker) - *pnChecker = 0; - - return false; - } - std::lock_guard<std::mutex> guard(mMutex); - bool bWait = false; DataEntry* pEntry = nullptr; bool bForceToPlay = false; - mUpdateJitterBufferSize++; // add code for no dtx mCheckUpdateJitterPacketCnt++; - int32_t nTimediff = 0; - // determin bWait - if (mIsReceivedFirst == false) + // update jitter buffer size + if (mCheckUpdateJitterPacketCnt * FRAME_INTERVAL > JITTER_BUFFER_UPDATE_INTERVAL) { - bWait = true; - } - else if (mDtxOn && mDataQueue.GetCount() > 0) - { - if (mDataQueue.Get(&pEntry) && IsSID(pEntry->pbBuffer, pEntry->nBufferSize) == false) - { - IMLOGD_PACKET0(IM_PACKET_LOG_JITTER, "[Get] bWait = True"); - bWait = true; - } + mCurrJitterBufferSize = + mJitterAnalyzer.GetNextJitterBufferSize(mCurrJitterBufferSize, currentTime); + mCheckUpdateJitterPacketCnt = 0; } - // set current jitter buffer size - // when dtx occur, calculate nextJitterBufferSize. - if (mBufferImprovement == false) + // enforce update when breach the reset threshold + if (mCannotGetCount * FRAME_INTERVAL > RESET_THRESHOLD) { - if ((mWaiting == false && bWait == true) || mUpdateJitterBufferSize > 2 * 50) - { - uint32_t nPrev_jitterbufferSize = mCurrJitterBufferSize; - mCurrJitterBufferSize = mJitterAnalyser.GetNextJitterBufferSize( - mCurrJitterBufferSize, ImsMediaTimer::GetTimeInMilliSeconds()); - - if (mUpdateJitterBufferSize > 2 * 50) - { // 2s - nTimediff = ((int32_t)mCurrJitterBufferSize - (int32_t)nPrev_jitterbufferSize) * 20; - IMLOGD1("[Get] mFourceToUpdateJitterBuffer set. nTimediff[%d]", nTimediff); - mFourceToUpdateJitterBuffer = true; - } - mUpdateJitterBufferSize = 0; - } - - mWaiting = bWait; + IMLOGD_PACKET0(IM_PACKET_LOG_JITTER, "[Get] enforce update"); + mEnforceUpdate = true; + mWaiting = false; + mCannotGetCount = 0; } - else - { - if ((mWaiting == false && bWait == true) || mUpdateJitterBufferSize > 500) - { - // update mCurrJitterBufferSize - if (mCheckUpdateJitterPacketCnt > 50 * mBufferUpdateDuration) - { - mCurrJitterBufferSize = mJitterAnalyser.GetNextJitterBufferSize( - mCurrJitterBufferSize, ImsMediaTimer::GetTimeInMilliSeconds()); - mCheckUpdateJitterPacketCnt = 0; - } - if (mUpdateJitterBufferSize > 500) - { - IMLOGD_PACKET0(IM_PACKET_LOG_JITTER, "[Get] mFourceToUpdateJitterBuffer set"); - mFourceToUpdateJitterBuffer = true; - } - - mUpdateJitterBufferSize = 0; - } - - mWaiting = bWait; + if (mDataQueue.GetCount() == 0) + { + IMLOGD_PACKET0(IM_PACKET_LOG_JITTER, "[Get] wait - empty"); + return false; } - // Wait case - if (bWait) + else if (mDataQueue.Get(&pEntry) && mWaiting) { - if (mDataQueue.Get(&pEntry)) - { - IMLOGD_PACKET5(IM_PACKET_LOG_JITTER, - "[Get] time[%u], arrivalTime[%u], nTS[%d], mBaseTimestamp[%u], " - "mBaseArrivalTime[%u]", - ImsMediaTimer::GetTimeInMilliSeconds(), pEntry->arrivalTime, pEntry->nTimestamp, - mBaseTimestamp, mBaseArrivalTime); - } + uint32_t jitterDelay = currentTime - pEntry->arrivalTime; - if (mDataQueue.GetCount() == 0 || - ((mDataQueue.Get(&pEntry) && - (ImsMediaTimer::GetTimeInMilliSeconds() - pEntry->arrivalTime) < - ((mCurrJitterBufferSize - 1) * 20 + 10)) && - (mDataQueue.GetCount() <= mCurrJitterBufferSize))) + if (jitterDelay < (mCurrJitterBufferSize - 1) * FRAME_INTERVAL + ALLOWABLE_ERROR) { if (psubtype) *psubtype = MEDIASUBTYPE_UNDEFINED; @@ -377,86 +302,52 @@ bool AudioJitterBuffer::Get(ImsMediaSubType* psubtype, uint8_t** ppData, uint32_ *pbMark = false; if (pnSeqNum) *pnSeqNum = 0; - if (pnChecker) - *pnChecker = 0; - - if (mDataQueue.GetCount() > 0) - { - IMLOGD_PACKET5(IM_PACKET_LOG_JITTER, - "[Get] Wait - Seq[%u], CurrJBSize[%u], curr[%u], th[%u], QueueCount[%u]", - pEntry->nSeqNum, mCurrJitterBufferSize, - (uint32_t)(ImsMediaTimer::GetTimeInMilliSeconds() - pEntry->arrivalTime), - ((mCurrJitterBufferSize - 1) * 20 + 10), mDataQueue.GetCount()); - mCanNotGetCount++; - } - else - { - IMLOGD_PACKET0(IM_PACKET_LOG_JITTER, "[Get] Wait - empty"); - } + IMLOGD_PACKET4(IM_PACKET_LOG_JITTER, + "[Get] Wait - seq[%u], CurrJBSize[%u], delay[%u], QueueCount[%u]", + pEntry->nSeqNum, mCurrJitterBufferSize, jitterDelay, mDataQueue.GetCount()); + mCannotGetCount++; return false; } + else + { + mWaiting = false; // once waiting is reset, it will not set true until resync - // the first frame of voice term - mCurrPlayingTS = pEntry->nTimestamp; - mCurrPlayingSeq = pEntry->nSeqNum; + // the first frame of voice term + mCurrPlayingTS = pEntry->nTimestamp; + mCurrPlayingSeq = pEntry->nSeqNum; + } } - if (mDataQueue.Get(&pEntry) == true && pEntry->nTimestamp != mCurrPlayingTS && - ((mCurrPlayingTS - 10) < pEntry->nTimestamp) && - (pEntry->nTimestamp < (mCurrPlayingTS + 10))) + // adjust the playing timestamp + if (mDataQueue.Get(&pEntry) && pEntry->nTimestamp != mCurrPlayingTS && + ((mCurrPlayingTS - ALLOWABLE_ERROR) < pEntry->nTimestamp) && + (pEntry->nTimestamp < (mCurrPlayingTS + ALLOWABLE_ERROR))) { - IMLOGD_PACKET0(IM_PACKET_LOG_JITTER, "[Get] CurrPlaying nTimestamp Reset!"); mCurrPlayingTS = pEntry->nTimestamp; mCurrPlayingSeq = pEntry->nSeqNum; + IMLOGD_PACKET2(IM_PACKET_LOG_JITTER, "[Get] sync playing TS[%u], seq[%d]", mCurrPlayingTS, + mCurrPlayingSeq); } - // delete very old data - while (mDataQueue.GetCount() > 0) + while (mDataQueue.Get(&pEntry)) { - mDataQueue.Get(&pEntry); - - if (pEntry == nullptr) + if (mDeleteCount > mMinJitterBufferSize && + mDataQueue.GetCount() < mCurrJitterBufferSize + 1) { - return false; - } + IMLOGD0("[Get] resync"); + uint32_t nTempBuferSize = (mCurrJitterBufferSize + AUDIO_JITTER_BUFFER_MIN_SIZE) / 2; - if (mDeleteCount > 4 && mDataQueue.GetCount() < mCurrJitterBufferSize + 1) - { - IMLOGD0("[Get] Resync"); - - if (mBufferImprovement == false) + if (mDataQueue.GetCount() >= nTempBuferSize) { - uint32_t nTempBuferSize = (mCurrJitterBufferSize + mMinJitterBufferSize) / 2; - - if (mDataQueue.GetCount() > nTempBuferSize) - { - mCurrPlayingTS = pEntry->nTimestamp; - mCurrPlayingSeq = pEntry->nSeqNum; - } - else - { - mCurrPlayingTS = - pEntry->nTimestamp - (nTempBuferSize - mDataQueue.GetCount()) * 20; - mCurrPlayingSeq = 0; - } + mCurrPlayingTS = pEntry->nTimestamp; + mCurrPlayingSeq = pEntry->nSeqNum; } else { - uint32_t nTempBuferSize = - (mCurrJitterBufferSize + AUDIO_JITTER_BUFFER_MIN_SIZE) / 2; - - if (mDataQueue.GetCount() >= nTempBuferSize) - { - mCurrPlayingTS = pEntry->nTimestamp; - mCurrPlayingSeq = pEntry->nSeqNum; - } - else - { - mCurrPlayingTS = - pEntry->nTimestamp - (nTempBuferSize - mDataQueue.GetCount()) * 20; - mCurrPlayingSeq = 0; - } + mCurrPlayingTS = pEntry->nTimestamp - + (nTempBuferSize - mDataQueue.GetCount()) * FRAME_INTERVAL; + mCurrPlayingSeq = 0; } mNeedToUpdateBasePacket = true; @@ -464,95 +355,77 @@ bool AudioJitterBuffer::Get(ImsMediaSubType* psubtype, uint8_t** ppData, uint32_ break; } - if (USHORT_TS_ROUND_COMPARE(pEntry->nTimestamp, mCurrPlayingTS) == false) + // a >= b + if (USHORT_TS_ROUND_COMPARE(pEntry->nTimestamp, mCurrPlayingTS)) + { + uint32_t timediff = pEntry->nTimestamp - mCurrPlayingTS; + mDeleteCount = 0; + + // timestamp compensation logic + if ((timediff > 0) && (timediff < FRAME_INTERVAL)) + { + IMLOGD2("[Get] resync - TS[%u], currTS[%u]", pEntry->nTimestamp, mCurrPlayingTS); + bForceToPlay = true; + } + + break; + } + else // late arrival { if (IsSID(pEntry->pbBuffer, pEntry->nBufferSize)) { mSIDCount++; mDtxOn = true; - IMLOGD_PACKET0(IM_PACKET_LOG_JITTER, "[Get] Dtx On"); } else { mSIDCount = 0; - // mDtxOn = false; - IMLOGD_PACKET0(IM_PACKET_LOG_JITTER, "[Get] Dtx Off"); } + CollectRxRtpStatus(pEntry->nSeqNum, kRtpStatusLate); mDeleteCount++; - - if (mDtxOn == true) - { - CollectRxRtpStatus(pEntry->nSeqNum, kRtpStatusNormal); - CollectJitterBufferStatus(mCurrJitterBufferSize * 20, mMaxJitterBufferSize * 20); - } - else - { - CollectRxRtpStatus(pEntry->nSeqNum, kRtpStatusLate); - } - - IMLOGD_PACKET2(IM_PACKET_LOG_JITTER, "[Get] delete TS[%d], PlayingTS[%d]", - pEntry->nTimestamp, mCurrPlayingTS); mDataQueue.Delete(); - } - else - { - uint32_t timediff = pEntry->nTimestamp - mCurrPlayingTS; - mDeleteCount = 0; - - // timestamp compensation logic - if ((timediff > 0) && (timediff < 20)) - { - IMLOGD2("[Get] resync - TS[%d], PlayingTS[%d]", pEntry->nTimestamp, mCurrPlayingTS); - bForceToPlay = true; - } - - break; + IMLOGD_PACKET0(IM_PACKET_LOG_JITTER, "[Get] delete late arrival"); } } // decrease jitter buffer if (mDtxOn && mSIDCount > 4 && mDataQueue.GetCount() > mCurrJitterBufferSize) { - mDataQueue.Get(&pEntry); - if (pEntry && IsSID(pEntry->pbBuffer, pEntry->nBufferSize)) + if (mDataQueue.Get(&pEntry) && IsSID(pEntry->pbBuffer, pEntry->nBufferSize)) { IMLOGD_PACKET5(IM_PACKET_LOG_JITTER, - "[Get] Delete SID - seq[%d], bMark[%d], nTS[%d], curTS[%d], size[%d]", + "[Get] delete SID - seq[%d], mark[%d], TS[%u], currTS[%u], queue[%d]", pEntry->nSeqNum, pEntry->bMark, pEntry->nTimestamp, mCurrPlayingTS, mDataQueue.GetCount()); mSIDCount++; mDtxOn = true; - IMLOGD_PACKET0(IM_PACKET_LOG_JITTER, "[Get] Dtx On"); - - CollectRxRtpStatus(pEntry->nSeqNum, kRtpStatusNormal); - CollectJitterBufferStatus(mCurrJitterBufferSize * 20, mMaxJitterBufferSize * 20); + CollectRxRtpStatus(pEntry->nSeqNum, kRtpStatusDiscarded); + mDeleteCount++; mDataQueue.Delete(); bForceToPlay = true; } } // add condition in case of changing Seq# & TS - if ((mCanNotGetCount > 10) && (mDataQueue.Get(&pEntry) == true) && - (pEntry->nTimestamp - mCurrPlayingTS > TS_ROUND_QUARD)) + if (mDataQueue.Get(&pEntry) && (pEntry->nTimestamp - mCurrPlayingTS) > TS_ROUND_QUARD) { - IMLOGD4("[Get] TS changing case [ %d / %u / %u / %d ]", pEntry->nSeqNum, pEntry->nTimestamp, - mCurrPlayingTS, mDataQueue.GetCount()); + IMLOGD4("[Get] TS changing case, enforce play [ %d / %u / %u / %d ]", pEntry->nSeqNum, + pEntry->nTimestamp, mCurrPlayingTS, mDataQueue.GetCount()); bForceToPlay = true; } - if (mFourceToUpdateJitterBuffer == true) + if (mEnforceUpdate) { // removing delete packet in min JitterBuffer size if (mDataQueue.GetCount() > mCurrJitterBufferSize + 1) { - mDataQueue.Get(&pEntry); - - if (pEntry) + if (mDataQueue.Get(&pEntry)) { IMLOGD_PACKET5(IM_PACKET_LOG_JITTER, - "[Get] Delete Packets - seq[%d], bMark[%d], nTS[%d], curTS[%d], size[%d]", + "[Get] Delete Packets - seq[%d], bMark[%d], TS[%u], curTS[%u], " + "size[%d]", pEntry->nSeqNum, pEntry->bMark, pEntry->nTimestamp, mCurrPlayingTS, mDataQueue.GetCount()); @@ -569,61 +442,27 @@ bool AudioJitterBuffer::Get(ImsMediaSubType* psubtype, uint8_t** ppData, uint32_ IMLOGD_PACKET0(IM_PACKET_LOG_JITTER, "[Get] Dtx Off"); } - if (mDtxOn == true) - { - CollectRxRtpStatus(pEntry->nSeqNum, kRtpStatusNormal); - CollectJitterBufferStatus( - mCurrJitterBufferSize * 20, mMaxJitterBufferSize * 20); - } - else - { - CollectRxRtpStatus(pEntry->nSeqNum, kRtpStatusDiscarded); - } - + CollectRxRtpStatus(pEntry->nSeqNum, kRtpStatusDiscarded); mDataQueue.Delete(); bForceToPlay = true; } } - if (mBufferImprovement == false) - { - // increase case - if ((mDataQueue.GetCount() < 2) || (mDataQueue.GetCount() < mCurrJitterBufferSize)) - { - IMLOGD3("[Get] increase queue size[%d], curr buffer[%d], nTimediff[%d]", - mDataQueue.GetCount(), mCurrJitterBufferSize, nTimediff); + mEnforceUpdate = false; - if (nTimediff > 0) - { - mCurrPlayingTS -= nTimediff; - mCurrPlayingSeq -= nTimediff / 20; - IMLOGD1("[Get] increase queue size [%d]", nTimediff / 20); - } - } - - // reset - mFourceToUpdateJitterBuffer = false; - mUpdateJitterBufferSize = 0; - } - else + if ((mDataQueue.GetCount() < 2) || + (mDataQueue.GetCount() < mCurrJitterBufferSize - mMinJitterBufferSize)) { - mFourceToUpdateJitterBuffer = false; - mUpdateJitterBufferSize = 0; - - if ((mDataQueue.GetCount() < 2) || - (mDataQueue.GetCount() < mCurrJitterBufferSize - mMinJitterBufferSize)) - { - IMLOGD_PACKET0(IM_PACKET_LOG_JITTER, "[Get] increase packet"); - return false; - } + IMLOGD_PACKET0(IM_PACKET_LOG_JITTER, "[Get] wait stacking"); + return false; } } - // get data and check the duplication - if (mDataQueue.Get(&pEntry) && pEntry->nSeqNum == mLastPlayedSeqNum) + // discard duplicated packet + if (mDataQueue.Get(&pEntry) && mFirstFrameReceived && pEntry->nSeqNum == mLastPlayedSeqNum) { IMLOGD_PACKET6(IM_PACKET_LOG_JITTER, - "[Get] duplicate - curTS[%d], seq[%d], Mark[%d], TS[%d], buffer[%d], size[%d]", + "[Get] duplicate - curTS[%u], seq[%d], Mark[%d], TS[%u], size[%d], queue[%d]", mCurrPlayingTS, pEntry->nSeqNum, pEntry->bMark, pEntry->nTimestamp, pEntry->nBufferSize, mDataQueue.GetCount()); CollectRxRtpStatus(pEntry->nSeqNum, kRtpStatusDuplicated); @@ -631,7 +470,7 @@ bool AudioJitterBuffer::Get(ImsMediaSubType* psubtype, uint8_t** ppData, uint32_ mDeleteCount++; } - if (mDataQueue.Get(&pEntry) && pEntry != nullptr && + if (mDataQueue.Get(&pEntry) && (pEntry->nTimestamp == mCurrPlayingTS || bForceToPlay || (pEntry->nTimestamp < TS_ROUND_QUARD && mCurrPlayingTS > 0xFFFF))) { @@ -648,31 +487,17 @@ bool AudioJitterBuffer::Get(ImsMediaSubType* psubtype, uint8_t** ppData, uint32_ if (pnSeqNum) *pnSeqNum = pEntry->nSeqNum; - mIsReceivedFirst = true; - if (IsSID(pEntry->pbBuffer, pEntry->nBufferSize)) { mSIDCount++; mDtxOn = true; - IMLOGD_PACKET0(IM_PACKET_LOG_JITTER, "[Get] Dtx On"); } else { mSIDCount = 0; - mDtxOn = false; - IMLOGD_PACKET0(IM_PACKET_LOG_JITTER, "[Get] Dtx Off"); } - IMLOGD_PACKET7(IM_PACKET_LOG_JITTER, - "[Get] OK - dtx mode[%d], curTS[%d], seq[%d], Mark[%d], TS[%d], buffer[%d], " - "size[%d]", - mDtxOn, mCurrPlayingTS, pEntry->nSeqNum, pEntry->bMark, pEntry->nTimestamp, - pEntry->nBufferSize, mDataQueue.GetCount()); - - mCurrPlayingTS = pEntry->nTimestamp + 20; - mCurrPlayingSeq = pEntry->nSeqNum + 1; - - if (mLastPlayedSeqNum > 0) + if (mFirstFrameReceived) { /** Report the loss gap if the loss gap is over 0 */ uint16_t lostGap = GET_SEQ_GAP(pEntry->nSeqNum, mLastPlayedSeqNum); @@ -686,19 +511,28 @@ bool AudioJitterBuffer::Get(ImsMediaSubType* psubtype, uint8_t** ppData, uint32_ } } + IMLOGD_PACKET7(IM_PACKET_LOG_JITTER, + "[Get] OK - dtx[%d], curTS[%u], seq[%d], mark[%d], TS[%u], size[%d], queue[%d]", + mDtxOn, mCurrPlayingTS, pEntry->nSeqNum, pEntry->bMark, pEntry->nTimestamp, + pEntry->nBufferSize, mDataQueue.GetCount()); + + mCurrPlayingTS = pEntry->nTimestamp + FRAME_INTERVAL; + mCurrPlayingSeq = pEntry->nSeqNum + 1; + mFirstFrameReceived = true; mLastPlayedSeqNum = pEntry->nSeqNum; - mCanNotGetCount = 0; + mCannotGetCount = 0; CollectRxRtpStatus(pEntry->nSeqNum, kRtpStatusNormal); - CollectJitterBufferStatus(mCurrJitterBufferSize * 20, mMaxJitterBufferSize * 20); + CollectJitterBufferStatus( + mCurrJitterBufferSize * FRAME_INTERVAL, mMaxJitterBufferSize * FRAME_INTERVAL); return true; } else { // TODO: check EVS redundancy in channel aware mode - if (mDtxOn == false) + if (!mDtxOn) { - mCanNotGetCount++; + mCannotGetCount++; } if (psubtype) @@ -717,18 +551,16 @@ bool AudioJitterBuffer::Get(ImsMediaSubType* psubtype, uint8_t** ppData, uint32_ IMLOGD_PACKET2(IM_PACKET_LOG_JITTER, "[Get] fail - dtx mode[%d], curTS[%d]", mDtxOn, mCurrPlayingTS); - mCurrPlayingTS += 20; - mCurrPlayingSeq += 1; + mCurrPlayingTS += FRAME_INTERVAL; + mCurrPlayingSeq++; return false; } return false; } -bool AudioJitterBuffer::IsSID(uint8_t* pbBuffer, uint32_t nBufferSize) +bool AudioJitterBuffer::IsSID(uint8_t* /*pbBuffer*/, uint32_t nBufferSize) { - // remove warning - (void)pbBuffer; switch (mCodecType) { case kAudioCodecAmr: diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioManager.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioManager.cpp index 357a1d71..49efef54 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioManager.cpp +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioManager.cpp @@ -174,10 +174,20 @@ void AudioManager::sendDtmf(int sessionId, char dtmfDigit, int duration) } } -/*void AudioManager::sendHeaderExtension(int sessionId, RtpHeaderExtension* data) { - (void)sessionId; - (void)data; -}*/ +void AudioManager::sendRtpHeaderExtension( + int sessionId, std::list<RtpHeaderExtension>* listExtension) +{ + auto session = mSessions.find(sessionId); + IMLOGI1("[sendRtpHeaderExtension] sessionId[%d]", sessionId); + if (session != mSessions.end()) + { + (session->second)->sendRtpHeaderExtension(listExtension); + } + else + { + IMLOGE1("[sendRtpHeaderExtension] no session id[%d]", sessionId); + } +} void AudioManager::setMediaQualityThreshold(int sessionId, MediaQualityThreshold* threshold) { @@ -225,7 +235,7 @@ void AudioManager::sendMessage(const int sessionId, const android::Parcel& parce case kAudioDeleteConfig: { AudioConfig* config = new AudioConfig(); - config->readFromParcel(&parcel); + err = config->readFromParcel(&parcel); if (err != NO_ERROR) { IMLOGE1("[sendMessage] error readFromParcel[%d]", err); @@ -241,9 +251,25 @@ void AudioManager::sendMessage(const int sessionId, const android::Parcel& parce "AUDIO_REQUEST_EVENT", nMsg, sessionId, reinterpret_cast<uint64_t>(param)); } break; - case kAudioSendHeaderExtension: - // TO DO - break; + case kAudioSendRtpHeaderExtension: + { + std::list<RtpHeaderExtension>* listExtension = new std::list<RtpHeaderExtension>(); + int listSize = parcel.readInt32(); + + for (int32_t i = 0; i < listSize; i++) + { + RtpHeaderExtension extension; + + if (extension.readFromParcel(&parcel) == NO_ERROR) + { + listExtension->push_back(extension); + } + } + + ImsMediaEventHandler::SendEvent("AUDIO_REQUEST_EVENT", nMsg, sessionId, + reinterpret_cast<uint64_t>(listExtension)); + } + break; case kAudioSetMediaQualityThreshold: { MediaQualityThreshold* threshold = new MediaQualityThreshold(); @@ -377,9 +403,19 @@ void AudioManager::RequestHandler::processEvent( } } break; - case kAudioSendHeaderExtension: - // TO DO : add implementation - break; + case kAudioSendRtpHeaderExtension: + { + std::list<RtpHeaderExtension>* listExtension = + reinterpret_cast<std::list<RtpHeaderExtension>*>(paramA); + + if (listExtension != nullptr) + { + AudioManager::getInstance()->sendRtpHeaderExtension( + static_cast<int>(sessionId), listExtension); + delete listExtension; + } + } + break; case kAudioSetMediaQualityThreshold: { MediaQualityThreshold* threshold = reinterpret_cast<MediaQualityThreshold*>(paramA); @@ -455,8 +491,25 @@ void AudioManager::ResponseHandler::processEvent( } break; case kAudioRtpHeaderExtensionInd: - // TODO : add implementation - break; + { + parcel.writeInt32(event); + std::list<RtpHeaderExtension>* listExtension = + reinterpret_cast<std::list<RtpHeaderExtension>*>(paramA); + + if (listExtension != nullptr) + { + parcel.writeInt32(listExtension->size()); + + for (auto& extension : *listExtension) + { + extension.writeToParcel(&parcel); + } + + AudioManager::getInstance()->sendResponse(sessionId, parcel); + delete listExtension; + } + } + break; case kAudioMediaQualityStatusInd: { parcel.writeInt32(event); 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 e17112f6..13367521 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 @@ -123,6 +123,16 @@ ImsMediaResult AudioSession::startGraph(RtpConfig* config) return RESULT_INVALID_PARAM; } + IMLOGI1("[startGraph] state[%d]", getState()); + + if (mMediaQualityAnalyzer != nullptr && + !mMediaQualityAnalyzer->isSameConfig(reinterpret_cast<AudioConfig*>(config))) + { + mMediaQualityAnalyzer->stop(); + mMediaQualityAnalyzer->setConfig(reinterpret_cast<AudioConfig*>(config)); + mMediaQualityAnalyzer->start(); + } + ImsMediaResult ret = RESULT_NOT_READY; IMLOGD1("[startGraph] mListGraphRtpTx size[%d]", mListGraphRtpTx.size()); @@ -230,17 +240,6 @@ ImsMediaResult AudioSession::startGraph(RtpConfig* config) } } - // TODO : check that the timing is correct - IMLOGI1("[startGraph] state[%d]", getState()); - - if (mMediaQualityAnalyzer != nullptr && - !mMediaQualityAnalyzer->isSameConfig(reinterpret_cast<AudioConfig*>(config))) - { - mMediaQualityAnalyzer->stop(); - mMediaQualityAnalyzer->setConfig(reinterpret_cast<AudioConfig*>(config)); - mMediaQualityAnalyzer->start(); - } - return ret; } @@ -478,8 +477,8 @@ void AudioSession::onEvent(int32_t type, uint64_t param1, uint64_t param2) "AUDIO_RESPONSE_EVENT", kAudioFirstMediaPacketInd, mSessionId, param1, param2); break; case kImsMediaEventHeaderExtensionReceived: - ImsMediaEventHandler::SendEvent( - "AUDIO_RESPONSE_EVENT", kAudioRtpHeaderExtensionInd, 0, 0); + ImsMediaEventHandler::SendEvent("AUDIO_RESPONSE_EVENT", kAudioRtpHeaderExtensionInd, + mSessionId, param1, param2); break; case kImsMediaEventMediaQualityStatus: ImsMediaEventHandler::SendEvent("AUDIO_RESPONSE_EVENT", kAudioMediaQualityStatusInd, @@ -578,10 +577,19 @@ uint32_t AudioSession::getGraphSize(ImsMediaStreamType type) return 0; } -void AudioSession::SendInternalEvent(int32_t type, uint64_t param1, uint64_t param2) +void AudioSession::sendRtpHeaderExtension(std::list<RtpHeaderExtension>* listExtension) { - (void)param2; + for (auto& graph : mListGraphRtpTx) + { + if (graph != nullptr) + { + graph->sendRtpHeaderExtension(listExtension); + } + } +} +void AudioSession::SendInternalEvent(int32_t type, uint64_t param1, uint64_t param2) +{ switch (type) { case kRequestAudioCmr: diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtpTx.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtpTx.cpp index 4a991320..ae8624a5 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtpTx.cpp +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtpTx.cpp @@ -244,3 +244,13 @@ void AudioStreamGraphRtpTx::processCmr(const uint32_t cmr) (reinterpret_cast<IAudioSourceNode*>(node))->ProcessCmr(cmr); } } + +void AudioStreamGraphRtpTx::sendRtpHeaderExtension(std::list<RtpHeaderExtension>* listExtension) +{ + BaseNode* node = findNode(kNodeIdRtpEncoder); + + if (node != nullptr) + { + (reinterpret_cast<RtpEncoderNode*>(node))->SetRtpHeaderExtension(listExtension); + } +}
\ 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 c8fc8850..55c2568b 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 @@ -36,6 +36,7 @@ MediaQualityAnalyzer::MediaQualityAnalyzer() { + mTimeStarted = 0; mCodecType = 0; mCodecAttribute = 0; mCallback = nullptr; @@ -118,7 +119,7 @@ void MediaQualityAnalyzer::start() IMLOGD0("[start]"); mCallQuality.setCodecType(convertAudioCodecType( mCodecType, ImsMediaAudioUtil::FindMaxEvsBandwidthFromRange(mCodecAttribute))); - + mTimeStarted = ImsMediaTimer::GetTimeInMilliSeconds(); StartThread(); } @@ -130,13 +131,7 @@ void MediaQualityAnalyzer::stop() { StopThread(); mConditionExit.wait_timeout(STOP_TIMEOUT); - - if (mCallback != nullptr) - { - IMLOGD0("[notifyCallQuality]"); - CallQuality* quality = new CallQuality(mCallQuality); - mCallback->SendEvent(kAudioCallQualityChangedInd, reinterpret_cast<uint64_t>(quality)); - } + notifyCallQuality(); } reset(); @@ -290,6 +285,20 @@ void MediaQualityAnalyzer::collectRxRtpStatus( mRtcpXrEncoder->stackRxRtpStatus(packet->status, delay); IMLOGD_PACKET3(IM_PACKET_LOG_RTP, "[collectRxRtpStatus] seq[%d], status[%d], delay[%u]", seq, packet->status, delay); + + // set the max playout delay + if (delay > mCallQuality.getMaxPlayoutDelayMillis()) + { + mCallQuality.setMaxPlayoutDelayMillis(delay); + } + + // set the min playout delay + if (delay < mCallQuality.getMinPlayoutDelayMillis() || + mCallQuality.getMinPlayoutDelayMillis() == 0) + { + mCallQuality.setMinPlayoutDelayMillis(delay); + } + found = true; break; } @@ -354,18 +363,9 @@ void MediaQualityAnalyzer::processData(const int32_t timeCount) mCallQuality.getNumRtpPacketsReceived() == 0) { mCallQuality.setRtpInactivityDetected(true); - - if (mCallback != nullptr) - { - IMLOGD0("[notifyCallQuality]"); - CallQuality* callQuality = new CallQuality(mCallQuality); - mCallback->SendEvent( - kAudioCallQualityChangedInd, reinterpret_cast<uint64_t>(callQuality)); - } + notifyCallQuality(); } - mCallQuality.setCallDuration(mCallQuality.getCallDuration() + TIMER_INTERVAL); - // call quality packet loss if (timeCount % CALL_QUALITY_MONITORING_TIME == 0) { @@ -383,14 +383,7 @@ void MediaQualityAnalyzer::processData(const int32_t timeCount) if (mCallQuality.getDownlinkCallQualityLevel() != quality) { mCallQuality.setDownlinkCallQualityLevel(quality); - - if (mCallback != nullptr) - { - IMLOGD0("[notifyCallQuality]"); - CallQuality* callQuality = new CallQuality(mCallQuality); - mCallback->SendEvent( - kAudioCallQualityChangedInd, reinterpret_cast<uint64_t>(callQuality)); - } + notifyCallQuality(); } mCallQualityNumLostPacket = 0; @@ -528,6 +521,22 @@ void MediaQualityAnalyzer::processMediaQuality() } } +void MediaQualityAnalyzer::notifyCallQuality() +{ + if (mCallback != nullptr) + { + mCallQuality.setCallDuration(ImsMediaTimer::GetTimeInMilliSeconds() - mTimeStarted); + + IMLOGD1("[notifyCallQuality] duration[%d]", mCallQuality.getCallDuration()); + CallQuality* callQuality = new CallQuality(mCallQuality); + mCallback->SendEvent(kAudioCallQualityChangedInd, reinterpret_cast<uint64_t>(callQuality)); + + // reset the items to keep in reporting interval + mCallQuality.setMinPlayoutDelayMillis(0); + mCallQuality.setMaxPlayoutDelayMillis(0); + } +} + void MediaQualityAnalyzer::notifyMediaQualityStatus() { IMLOGD0("[notifyMediaQualityStatus]"); diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/IAudioPlayerNode.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/IAudioPlayerNode.cpp index 240861ff..c37fba98 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/IAudioPlayerNode.cpp +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/IAudioPlayerNode.cpp @@ -44,9 +44,9 @@ kBaseNodeId IAudioPlayerNode::GetNodeId() return kNodeIdAudioPlayer; } -ImsMediaResult IAudioPlayerNode::Start() +ImsMediaResult IAudioPlayerNode::ProcessStart() { - IMLOGD2("[Start] codec[%d], mode[%d]", mCodecType, mMode); + IMLOGD2("[ProcessStart] codec[%d], mode[%d]", mCodecType, mMode); if (mJitterBuffer) { mJitterBuffer->SetCodecType(mCodecType); @@ -101,6 +101,11 @@ bool IAudioPlayerNode::IsRunTime() return true; } +bool IAudioPlayerNode::IsRunTimeStart() +{ + return false; +} + bool IAudioPlayerNode::IsSourceNode() { return false; @@ -137,9 +142,9 @@ void IAudioPlayerNode::SetConfig(void* config) mSamplingRate = mConfig->getSamplingRateKHz(); SetJitterBufferSize(4, 4, 9); - SetJitterOptions(80, 1, (double)25 / 10, - false, /** TODO: when enable DTX, set this true on condition*/ - true); + SetJitterOptions( + 80, 1, (double)25 / 10, false /** TODO: when enable DTX, set this true on condition*/ + ); } bool IAudioPlayerNode::IsSameConfig(void* config) diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/IAudioSourceNode.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/IAudioSourceNode.cpp index 9e0fe4e0..8bedca46 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/IAudioSourceNode.cpp +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/IAudioSourceNode.cpp @@ -42,9 +42,9 @@ kBaseNodeId IAudioSourceNode::GetNodeId() return kNodeIdAudioSource; } -ImsMediaResult IAudioSourceNode::Start() +ImsMediaResult IAudioSourceNode::ProcessStart() { - IMLOGD2("[Start] codec[%d], mode[%d]", mCodecType, mCodecMode); + IMLOGD2("[ProcessStart] codec[%d], mode[%d]", mCodecType, mCodecMode); if (mAudioSource) { @@ -97,6 +97,11 @@ bool IAudioSourceNode::IsRunTime() return true; } +bool IAudioSourceNode::IsRunTimeStart() +{ + return false; +} + bool IAudioSourceNode::IsSourceNode() { return true; diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/BaseJitterBuffer.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/BaseJitterBuffer.h index 1883aecf..76225875 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/BaseJitterBuffer.h +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/BaseJitterBuffer.h @@ -41,8 +41,8 @@ public: */ virtual void SetCodecType(uint32_t type); virtual void SetJitterBufferSize(uint32_t nInit, uint32_t nMin, uint32_t nMax); - virtual void SetJitterOptions(uint32_t nReduceTH, uint32_t nStepSize, double zValue, - bool bIgnoreSID, bool bImprovement); + virtual void SetJitterOptions( + uint32_t nReduceTH, uint32_t nStepSize, double zValue, bool bIgnoreSID); virtual uint32_t GetCount(); virtual void Reset(); virtual void Delete(); @@ -62,6 +62,7 @@ public: */ virtual void Add(ImsMediaSubType subtype, uint8_t* data, uint32_t dataSize, uint32_t timestamp, bool mark, uint32_t seq, + /** TODO: remove deprecated argument dataType */ ImsMediaSubType dataType = ImsMediaSubType::MEDIASUBTYPE_UNDEFINED, uint32_t arrivalTime = 0) = 0; @@ -75,11 +76,10 @@ public: * @param timestamp The timestamp of data, it can be milliseconds unit or rtp timestamp unit * @param mark It is true when the data has marker bit set * @param seq The sequence number of data. it is 0 when there is no valid sequence number set - * @param pnChecker + * @param currentTime The current timestamp of this method invoked with milliseconds unit */ virtual bool Get(ImsMediaSubType* psubtype, uint8_t** ppData, uint32_t* pnDataSize, - uint32_t* ptimestamp, bool* pmark, uint32_t* pnSeqNum, - uint32_t* pnChecker = nullptr) = 0; + uint32_t* ptimestamp, bool* pmark, uint32_t* pnSeqNum, uint32_t currentTime) = 0; protected: BaseSessionCallback* mCallback; diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/IRtpSession.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/IRtpSession.h index bb667867..3075dd4d 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/IRtpSession.h +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/IRtpSession.h @@ -55,9 +55,9 @@ class IRtpDecoderListener public: IRtpDecoderListener() {} virtual ~IRtpDecoderListener() {} - virtual void OnMediaDataInd(unsigned char* pData, uint32_t nDataSize, uint32_t nTimestamp, - bool bMark, uint16_t nSeqNum, uint32_t nPayloadType, uint32_t nSSRC, bool bExtension, - uint16_t nExtensionData) = 0; + virtual void OnMediaDataInd(unsigned char* data, uint32_t dataSize, uint32_t timestamp, + bool mark, uint16_t seqNum, uint32_t payloadType, uint32_t ssrc, + const RtpHeaderExtensionInfo& extensionInfo) = 0; virtual void OnNumReceivedPacket(uint32_t nNumRtpPacket) = 0; }; @@ -103,9 +103,8 @@ public: void StopRtp(); void StartRtcp(bool bSendRtcpBye = false); void StopRtcp(); - bool SendRtpPacket(uint32_t nPayloadType, uint8_t* pData, uint32_t nDataSize, - uint32_t timestamp, bool mark, uint32_t nTimeDiff, bool bExtension = false, - tRtpHeaderExtensionInfo* pExtensionInfo = nullptr); + bool SendRtpPacket(uint32_t payloadType, uint8_t* data, uint32_t dataSize, uint32_t timestamp, + bool mark, uint32_t nTimeDiff, RtpHeaderExtensionInfo* extensionInfo = nullptr); bool ProcRtpPacket(uint8_t* pData, uint32_t nDataSize); bool ProcRtcpPacket(uint8_t* pData, uint32_t nDataSize); void OnTimer(); diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/ImsMediaDefine.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/ImsMediaDefine.h index 9006f64d..045051c1 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/ImsMediaDefine.h +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/ImsMediaDefine.h @@ -26,10 +26,7 @@ #define USHORT_SEQ_ROUND_COMPARE(a, b) \ ((((a) >= (b)) && (((b) >= SEQ_ROUND_QUARD) || (((a) <= 0xffff - SEQ_ROUND_QUARD)))) || \ (((a) <= SEQ_ROUND_QUARD) && ((b) >= 0xffff - SEQ_ROUND_QUARD))) -#define TS_ROUND_QUARD 3000 -#define USHORT_TS_ROUND_COMPARE(a, b) \ - (((a) >= (b) && (b) >= TS_ROUND_QUARD) || ((a) <= 0xffff - TS_ROUND_QUARD) || \ - ((a) <= TS_ROUND_QUARD && (b) >= 0xffff - TS_ROUND_QUARD)) +#define IMS_MEDIA_WORD_SIZE 4 using namespace android::telephony::imsmedia; @@ -293,7 +290,7 @@ enum ImsMediaAudioMsgRequest kAudioDeleteConfig, kAudioConfirmConfig, kAudioSendDtmf, - kAudioSendHeaderExtension, + kAudioSendRtpHeaderExtension, kAudioSetMediaQualityThreshold, }; @@ -320,7 +317,7 @@ enum ImsMediaVideoMsgRequest kVideoModifySession, kVideoSetPreviewSurface, kVideoSetDisplaySurface, - kVideoSendHeaderExtension, + kVideoSendRtpHeaderExtension, kVideoSetMediaQualityThreshold, kVideoRequestDataUsage, }; @@ -550,28 +547,77 @@ public: uint32_t option; }; -struct tRtpHeaderExtensionInfo +struct RtpHeaderExtensionInfo { - uint16_t nDefinedByProfile; - uint16_t nLength; - uint16_t nExtensionData; - tRtpHeaderExtensionInfo(uint16_t profile = 0, uint16_t length = 0, uint16_t data = 0) +public: + enum + { + // RFC 8285#section-4.2, The bit pattern for one byte header + kBitPatternForOneByteHeader = 0xBEDE, + // RFC 8285#section-4.3, The bit pattern for two byte header + kBitPatternForTwoByteHeader = 0x1000, + }; + + uint16_t definedByProfile; + uint16_t length; // length in word unit + int8_t* extensionData; + uint16_t extensionDataSize; + + RtpHeaderExtensionInfo( + uint16_t profile = 0, uint16_t len = 0, int8_t* data = nullptr, uint16_t size = 0) + { + definedByProfile = profile; + length = len; + extensionData = nullptr; + extensionDataSize = 0; + setExtensionData(data, size); + } + + RtpHeaderExtensionInfo(const RtpHeaderExtensionInfo& extension) { - nDefinedByProfile = profile; - nLength = length; - nExtensionData = data; + definedByProfile = extension.definedByProfile; + extensionData = nullptr; + length = extension.length; + setExtensionData(extension.extensionData, extension.extensionDataSize); } - tRtpHeaderExtensionInfo& operator=(const tRtpHeaderExtensionInfo& extension) + + ~RtpHeaderExtensionInfo() + { + if (extensionData != nullptr) + { + delete[] extensionData; + extensionData = nullptr; + } + } + + RtpHeaderExtensionInfo& operator=(const RtpHeaderExtensionInfo& extension) { if (this != &extension) { - nDefinedByProfile = extension.nDefinedByProfile; - nLength = extension.nLength; - nExtensionData = extension.nExtensionData; + definedByProfile = extension.definedByProfile; + length = extension.length; + setExtensionData(extension.extensionData, extension.extensionDataSize); } return *this; } + + void setExtensionData(int8_t* data, uint16_t dataSize) + { + if (extensionData != nullptr) + { + delete[] extensionData; + extensionData = nullptr; + extensionDataSize = 0; + } + + if (data != nullptr) + { + extensionDataSize = dataSize; + extensionData = new int8_t[extensionDataSize]; + memcpy(extensionData, data, extensionDataSize); + } + } }; #define MAX_IP_LEN 128 diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/StreamScheduler.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/StreamScheduler.h index a8d70e3f..b083096a 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/StreamScheduler.h +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/StreamScheduler.h @@ -37,11 +37,9 @@ public: virtual void* run(); private: - BaseNode* DetermineProcessingNode(uint32_t* pnMaxDataInNode); + BaseNode* DetermineProcessingNode(); void RunRegisteredNode(); - std::list<BaseNode*> mlistSourceNode; std::list<BaseNode*> mlistRegisteredNode; - std::list<BaseNode*> mlistNodeToRun; ImsMediaCondition mConditionMain; ImsMediaCondition mConditionExit; std::mutex mMutex; diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioJitterBuffer.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioJitterBuffer.h index 2ab210ce..001588fc 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioJitterBuffer.h +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioJitterBuffer.h @@ -27,38 +27,32 @@ public: virtual ~AudioJitterBuffer(); virtual void Reset(); virtual void SetJitterBufferSize(uint32_t nInit, uint32_t nMin, uint32_t nMax); - void SetJitterOptions(uint32_t nReduceTH, uint32_t nStepSize, double zValue, bool bIgnoreSID, - bool bImprovement); + void SetJitterOptions(uint32_t nReduceTH, uint32_t nStepSize, double zValue, bool bIgnoreSID); virtual void Add(ImsMediaSubType subtype, uint8_t* pbBuffer, uint32_t nBufferSize, uint32_t nTimestamp, bool bMark, uint32_t nSeqNum, ImsMediaSubType nDataType = ImsMediaSubType::MEDIASUBTYPE_UNDEFINED, uint32_t arrivalTime = 0); virtual bool Get(ImsMediaSubType* psubtype, uint8_t** ppData, uint32_t* pnDataSize, - uint32_t* pnTimestamp, bool* pbMark, uint32_t* pnSeqNum, uint32_t* pnChecker = nullptr); + uint32_t* pnTimestamp, bool* pbMark, uint32_t* pnSeqNum, uint32_t currentTime); private: bool IsSID(uint8_t* pbBuffer, uint32_t nBufferSize); void CollectRxRtpStatus(int32_t seq, kRtpPacketStatus status); void CollectJitterBufferStatus(int32_t currSize, int32_t maxSize); - JitterNetworkAnalyser mJitterAnalyser; + JitterNetworkAnalyser mJitterAnalyzer; bool mDtxOn; - bool mBufferImprovement; bool mBufferIgnoreSIDPacket; bool mNeedToUpdateBasePacket; - bool mIsReceivedFirst; bool mWaiting; - bool mFourceToUpdateJitterBuffer; - uint32_t mCanNotGetCount; + bool mEnforceUpdate; + uint32_t mCannotGetCount; uint32_t mCurrPlayingTS; uint16_t mCurrPlayingSeq; uint32_t mBaseTimestamp; uint32_t mBaseArrivalTime; - uint32_t mNullDataCount; - uint32_t mUpdateJitterBufferSize; uint32_t mCheckUpdateJitterPacketCnt; uint32_t mCurrJitterBufferSize; - uint32_t mBufferUpdateDuration; uint32_t mSIDCount; uint32_t mDeleteCount; uint32_t mNextJitterBufferSize; diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioManager.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioManager.h index a7b69c63..231b4141 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioManager.h +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioManager.h @@ -23,6 +23,7 @@ #include <AudioSession.h> #include <AudioConfig.h> #include <MediaQualityThreshold.h> +#include <RtpHeaderExtension.h> #include <unordered_map> using namespace std; @@ -74,7 +75,7 @@ private: ImsMediaResult deleteConfig(int sessionId, AudioConfig* config); ImsMediaResult confirmConfig(int sessionId, AudioConfig* config); void sendDtmf(int sessionId, char dtmfDigit, int duration); - // void sendHeaderExtension(int sessionId, RtpHeaderExtension* data); + void sendRtpHeaderExtension(int sessionId, std::list<RtpHeaderExtension>* listExtension); void setMediaQualityThreshold(int sessionId, MediaQualityThreshold* threshold); static AudioManager* sManager; 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 10d8b916..ac29bfde 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 @@ -24,6 +24,7 @@ #include <AudioStreamGraphRtcp.h> #include <RtpConfig.h> #include <MediaQualityAnalyzer.h> +#include <RtpHeaderExtension.h> #include <list> class AudioSession : public BaseSession @@ -103,6 +104,13 @@ public: */ uint32_t getGraphSize(ImsMediaStreamType type); + /** + * @brief Send rtp header extension to the audio rtp + * + * @param listExtension The list of rtp header extension data + */ + void sendRtpHeaderExtension(std::list<RtpHeaderExtension>* listExtension); + private: std::list<AudioStreamGraphRtpTx*> mListGraphRtpTx; std::list<AudioStreamGraphRtpRx*> mListGraphRtpRx; diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioStreamGraphRtpTx.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioStreamGraphRtpTx.h index 753774f1..0e9f00d6 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioStreamGraphRtpTx.h +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioStreamGraphRtpTx.h @@ -19,6 +19,7 @@ #include <ImsMediaDefine.h> #include <AudioStreamGraph.h> +#include <RtpHeaderExtension.h> class AudioStreamGraphRtpTx : public AudioStreamGraph { @@ -57,6 +58,13 @@ public: */ void processCmr(const uint32_t cmr); + /** + * @brief Send rtp header extension to the audio rtp + * + * @param listExtension The list of rtp header extension data + */ + void sendRtpHeaderExtension(std::list<RtpHeaderExtension>* listExtension); + private: std::list<BaseNode*> mListDtmfNodes; }; 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 29f0bb48..f83ea088 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 @@ -229,6 +229,7 @@ protected: */ void processData(const int32_t timeCount); void processMediaQuality(); + void notifyCallQuality(); void notifyMediaQualityStatus(); void AddEvent(uint32_t event, uint64_t paramA, uint64_t paramB); void processEvent(uint32_t event, uint64_t paramA, uint64_t paramB); @@ -247,6 +248,8 @@ protected: std::list<LostPacket*> mListLostPacket; /** The list of the packets sent */ std::list<RtpPacket*> mListTxPacket; + /** The time of call started in milliseconds unit*/ + int32_t mTimeStarted; /** The ssrc of the receiving Rtp stream to identify */ int32_t mSSRC; /** The codec type of the audio session retrieved from the AudioConfig.h */ diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/nodes/IAudioPlayerNode.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/nodes/IAudioPlayerNode.h index 8cd0e3cc..cb41c0c6 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/nodes/IAudioPlayerNode.h +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/nodes/IAudioPlayerNode.h @@ -34,9 +34,10 @@ public: IAudioPlayerNode(BaseSessionCallback* callback = nullptr); virtual ~IAudioPlayerNode(); virtual kBaseNodeId GetNodeId(); - virtual ImsMediaResult Start(); + virtual ImsMediaResult ProcessStart(); virtual void Stop(); virtual bool IsRunTime(); + virtual bool IsRunTimeStart(); virtual bool IsSourceNode(); virtual void SetConfig(void* config); virtual bool IsSameConfig(void* config); diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/nodes/IAudioSourceNode.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/nodes/IAudioSourceNode.h index 794e655e..1f5d8d6e 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/nodes/IAudioSourceNode.h +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/nodes/IAudioSourceNode.h @@ -30,9 +30,10 @@ public: IAudioSourceNode(BaseSessionCallback* callback = nullptr); virtual ~IAudioSourceNode(); virtual kBaseNodeId GetNodeId(); - virtual ImsMediaResult Start(); + virtual ImsMediaResult ProcessStart(); virtual void Stop(); virtual bool IsRunTime(); + virtual bool IsRunTimeStart(); virtual bool IsSourceNode(); virtual void SetConfig(void* config); virtual bool IsSameConfig(void* config); diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/BaseNode.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/BaseNode.h index 360c46bc..9ca79518 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/BaseNode.h +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/BaseNode.h @@ -116,7 +116,15 @@ public: * * @return ImsMediaResult return RESULT_SUCCESS when it starts well without error */ - virtual ImsMediaResult Start() = 0; + virtual ImsMediaResult Start(); + + /** + * @brief Starts to run node with the configuration already set by the SetConfig method in + * scheduler thread + * + * @return ImsMediaResult return RESULT_SUCCESS when it starts well without error + */ + virtual ImsMediaResult ProcessStart(); /** * @brief Stops the node operation @@ -125,14 +133,16 @@ public: virtual void Stop() = 0; /** - * @brief Checks the node is running in main thread. - * - * @return true running in main thread - * @return false running by the created in StreamScheduler + * @brief Checks the node processes data in main thread. */ virtual bool IsRunTime() = 0; /** + * @brief Checks the node to start in main thread + */ + virtual bool IsRunTimeStart(); + + /** * @brief Checks the node is initial node of data source * * @return true It is a source node diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/JitterBufferControlNode.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/JitterBufferControlNode.h index e794ce13..68ee9db1 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/JitterBufferControlNode.h +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/JitterBufferControlNode.h @@ -27,8 +27,7 @@ public: BaseSessionCallback* callback = nullptr, ImsMediaType type = IMS_MEDIA_AUDIO); virtual ~JitterBufferControlNode(); void SetJitterBufferSize(uint32_t nInit, uint32_t nMin, uint32_t nMax); - void SetJitterOptions(uint32_t nReduceTH, uint32_t nStepSize, double zValue, bool bIgnoreSID, - bool bImprovement); + void SetJitterOptions(uint32_t nReduceTH, uint32_t nStepSize, double zValue, bool bIgnoreSID); void Reset(); virtual uint32_t GetDataCount(); virtual void OnDataFromFrontNode(ImsMediaSubType subtype, uint8_t* pData, uint32_t nDataSize, diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/RtpDecoderNode.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/RtpDecoderNode.h index cf285891..efa933e6 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/RtpDecoderNode.h +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/RtpDecoderNode.h @@ -19,6 +19,7 @@ #include <BaseNode.h> #include <IRtpSession.h> +#include <RtpHeaderExtension.h> // #define DEBUG_JITTER_GEN_SIMULATION_DELAY // #define DEBUG_JITTER_GEN_SIMULATION_REORDER @@ -46,9 +47,9 @@ public: virtual void OnDataFromFrontNode(ImsMediaSubType subtype, uint8_t* pData, uint32_t nDataSize, uint32_t timestamp, bool mark, uint32_t nSeqNum, ImsMediaSubType nDataType, uint32_t arrivalTime = 0); - virtual void OnMediaDataInd(unsigned char* pData, uint32_t nDataSize, uint32_t timestamp, - bool mark, uint16_t nSeqNum, uint32_t nPayloadType, uint32_t nSSRC, bool bExtension, - uint16_t nExtensionData); + virtual void OnMediaDataInd(unsigned char* data, uint32_t dataSize, uint32_t timestamp, + bool mark, uint16_t seqNum, uint32_t payloadType, uint32_t ssrc, + const RtpHeaderExtensionInfo& extensionInfo); // IRtpDecoderListener virtual void OnNumReceivedPacket(uint32_t nNumRtpPacket); @@ -69,6 +70,8 @@ public: private: void processDtmf(uint8_t* data); + std::list<RtpHeaderExtension>* DecodeRtpHeaderExtension( + const RtpHeaderExtensionInfo& extensionInfo); IRtpSession* mRtpSession; RtpAddress mLocalAddress; diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/RtpEncoderNode.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/RtpEncoderNode.h index 788f227e..54253073 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/RtpEncoderNode.h +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/RtpEncoderNode.h @@ -19,6 +19,7 @@ #include <BaseNode.h> #include <IRtpSession.h> +#include <RtpHeaderExtension.h> #include <mutex> class RtpEncoderNode : public BaseNode, public IRtpEncoderListener @@ -49,13 +50,18 @@ public: /** * @brief Set the camera facing and device orientation parameter for cvo extension in rtp header + * + * @param facing The facing of camera define in kCameraFacing in ImsMediaVideoUtil.h + * @param orientation The orientation value to send in degree unit + * @return true Return true when the extension data set properly + * @return false Return false when the cvo configuration is disabled */ bool SetCvoExtension(const int64_t facing, const int64_t orientation); /** - * @brief Set the rtp header extension parameter + * @brief Convert list of the RtpHeaderExtension to Rtp header extension payload */ - void SetRtpHeaderExtension(tRtpHeaderExtensionInfo& tExtension); + void SetRtpHeaderExtension(std::list<RtpHeaderExtension>* listExtension); private: bool ProcessAudioData(ImsMediaSubType subtype, uint8_t* pData, uint32_t nDataSize); @@ -80,7 +86,7 @@ private: int32_t mCvoValue; int8_t mRedundantPayload; int8_t mRedundantLevel; - tRtpHeaderExtensionInfo mRtpExtension; + std::list<RtpHeaderExtensionInfo> mListRtpExtension; }; #endif diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/text/TextJitterBuffer.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/text/TextJitterBuffer.h index 0cab794c..f744d5fc 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/text/TextJitterBuffer.h +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/text/TextJitterBuffer.h @@ -30,7 +30,7 @@ public: ImsMediaSubType dataType = ImsMediaSubType::MEDIASUBTYPE_UNDEFINED, uint32_t arrivalTime = 0); virtual bool Get(ImsMediaSubType* subtype, uint8_t** data, uint32_t* dataSize, - uint32_t* timestamp, bool* mark, uint32_t* seqNum, uint32_t* checker = nullptr); + uint32_t* timestamp, bool* mark, uint32_t* seqNum, uint32_t currentTime); virtual void Delete(); }; diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/VideoJitterBuffer.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/VideoJitterBuffer.h index 9319e3fd..104b7cea 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/VideoJitterBuffer.h +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/VideoJitterBuffer.h @@ -44,8 +44,8 @@ public: virtual void Add(ImsMediaSubType subtype, uint8_t* pbBuffer, uint32_t nBufferSize, uint32_t nTimeStamp, bool mark, uint32_t nSeqNum, ImsMediaSubType nDataType, uint32_t arrivalTime); - virtual bool Get(ImsMediaSubType* pImsMediaSubType, uint8_t** ppData, uint32_t* pnDataSize, - uint32_t* pnTimeStamp, bool* pmark, uint32_t* pnSeqNum, uint32_t* pnChecker = nullptr); + virtual bool Get(ImsMediaSubType* psubtype, uint8_t** ppData, uint32_t* pnDataSize, + uint32_t* ptimestamp, bool* pmark, uint32_t* pnSeqNum, uint32_t currentTime); /** * @brief Set the video codec type diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/VideoManager.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/VideoManager.h index 6095335c..7c780fd0 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/VideoManager.h +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/VideoManager.h @@ -98,7 +98,6 @@ private: ImsMediaResult setPreviewSurfaceToSession(const int sessionId, ANativeWindow* surface); ImsMediaResult setDisplaySurfaceToSession(const int sessionId, ANativeWindow* surface); ImsMediaResult modifySession(const int sessionId, VideoConfig* config); - // void sendHeaderExtension(int sessionId, RtpHeaderExtension* data); void setMediaQualityThreshold(const int sessionId, MediaQualityThreshold* threshold); static VideoManager* manager; diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/BaseNode.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/BaseNode.cpp index b2fb076f..6ee0e6b5 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/BaseNode.cpp +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/BaseNode.cpp @@ -104,6 +104,30 @@ kBaseNodeId BaseNode::GetNodeId() return kNodeIdUnknown; } +ImsMediaResult BaseNode::Start() +{ + if (!IsRunTimeStart()) + { + return RESULT_SUCCESS; + } + else + { + IMLOGW0("[Start] Error - base method"); + return RESULT_NOT_SUPPORTED; + } +} + +ImsMediaResult BaseNode::ProcessStart() +{ + IMLOGW0("[ProcessStart] Error - base method"); + return RESULT_NOT_SUPPORTED; +} + +bool BaseNode::IsRunTimeStart() +{ + return true; +} + void BaseNode::SetConfig(void* config) { (void)config; diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/JitterBufferControlNode.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/JitterBufferControlNode.cpp index 76b82284..35caa337 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/JitterBufferControlNode.cpp +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/JitterBufferControlNode.cpp @@ -18,7 +18,7 @@ #include <AudioJitterBuffer.h> #include <VideoJitterBuffer.h> #include <TextJitterBuffer.h> -#include <ImsMediaTrace.h> +#include <ImsMediaTimer.h> JitterBufferControlNode::JitterBufferControlNode(BaseSessionCallback* callback, ImsMediaType type) : BaseNode(callback), @@ -50,8 +50,6 @@ JitterBufferControlNode::~JitterBufferControlNode() void JitterBufferControlNode::SetJitterBufferSize(uint32_t nInit, uint32_t nMin, uint32_t nMax) { - IMLOGD3("[SetJitterBufferSize] init[%d], min[%d], max[%d]", nInit, nMin, nMax); - if (mJitterBuffer) { mJitterBuffer->SetJitterBufferSize(nInit, nMin, nMax); @@ -59,21 +57,16 @@ void JitterBufferControlNode::SetJitterBufferSize(uint32_t nInit, uint32_t nMin, } void JitterBufferControlNode::SetJitterOptions( - uint32_t nReduceTH, uint32_t nStepSize, double zValue, bool bIgnoreSID, bool bImprovement) + uint32_t nReduceTH, uint32_t nStepSize, double zValue, bool bIgnoreSID) { - IMLOGD5("[SetJitterOptions] nReduceTH[%d], nStepSize[%d], zValue[%lf], bSID[%d], bImprove[%d]", - nReduceTH, nStepSize, zValue, bIgnoreSID, bImprovement); - if (mJitterBuffer) { - mJitterBuffer->SetJitterOptions(nReduceTH, nStepSize, zValue, bIgnoreSID, bImprovement); + mJitterBuffer->SetJitterOptions(nReduceTH, nStepSize, zValue, bIgnoreSID); } } void JitterBufferControlNode::Reset() { - IMLOGD0("[Reset]"); - if (mJitterBuffer) { mJitterBuffer->Reset(); @@ -112,12 +105,20 @@ bool JitterBufferControlNode::GetData(ImsMediaSubType* pSubtype, uint8_t** ppDat uint32_t* pnDataSize, uint32_t* pnTimestamp, bool* pbMark, uint32_t* pnSeqNum, ImsMediaSubType* pnDataType, uint32_t* arrivalTime) { - (void)arrivalTime; + if (arrivalTime) + { + *arrivalTime = 0; + } + + if (pnDataType) + { + *pnDataType = MEDIASUBTYPE_UNDEFINED; + } if (mJitterBuffer) { return mJitterBuffer->Get(pSubtype, ppData, pnDataSize, pnTimestamp, pbMark, pnSeqNum, - reinterpret_cast<uint32_t*>(pnDataType)); + ImsMediaTimer::GetTimeInMilliSeconds()); } return false; diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtpDecoderNode.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtpDecoderNode.cpp index 66e06141..a163d6ad 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtpDecoderNode.cpp +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtpDecoderNode.cpp @@ -386,13 +386,14 @@ bool RtpDecoderNode::IsSameConfig(void* config) } void RtpDecoderNode::OnMediaDataInd(unsigned char* data, uint32_t datasize, uint32_t timestamp, - bool mark, uint16_t seq, uint32_t payloadType, uint32_t ssrc, bool extension, - uint16_t nExtensionData) + bool mark, uint16_t seq, uint32_t payloadType, uint32_t ssrc, + const RtpHeaderExtensionInfo& extensionInfo) { IMLOGD_PACKET8(IM_PACKET_LOG_RTP, "[OnMediaDataInd] media[%d] size[%d], TS[%d], mark[%d], seq[%d], payloadType[%d] " - "sampling[%d], ext[%d]", - mMediaType, datasize, timestamp, mark, seq, payloadType, mSamplingRate, extension); + "sampling[%d], extensionSize[%d]", + mMediaType, datasize, timestamp, mark, seq, payloadType, mSamplingRate, + extensionInfo.length); if (mMediaType == IMS_MEDIA_AUDIO && mRtpPayloadRx != payloadType && mRtpPayloadTx != payloadType && payloadType != mRtpRxDtmfPayload && @@ -423,46 +424,53 @@ void RtpDecoderNode::OnMediaDataInd(unsigned char* data, uint32_t datasize, uint return; } - if (extension && mMediaType == IMS_MEDIA_VIDEO && mCvoValue != CVO_DEFINE_NONE) + if (extensionInfo.length > 0 && mMediaType == IMS_MEDIA_AUDIO) { - uint16_t nExtensionID; - uint16_t nCamID; - uint16_t nRotation; - nExtensionID = nExtensionData; - nExtensionID = nExtensionID >> 12; + std::list<RtpHeaderExtension>* extensions = DecodeRtpHeaderExtension(extensionInfo); - nCamID = nExtensionData; // 0: Front-facing camera, 1: Back-facing camera - nCamID = nCamID << 12; - nCamID = nCamID >> 15; + if (mCallback != nullptr && extensions != nullptr) + { + mCallback->SendEvent( + kImsMediaEventHeaderExtensionReceived, reinterpret_cast<uint64_t>(extensions)); + } + } - nRotation = nExtensionData; - nRotation = nRotation << 13; - nRotation = nRotation >> 13; + if (extensionInfo.extensionData != nullptr && extensionInfo.extensionDataSize >= 2 && + mMediaType == IMS_MEDIA_VIDEO && mCvoValue != CVO_DEFINE_NONE) + { + uint16_t extensionId = extensionInfo.extensionData[0] >> 4; - switch (nRotation) + if (extensionId == mCvoValue) { - case 0: // No rotation (Rotated 0CW/CCW = To rotate 0CW/CCW) - case 4: // + Horizontal Flip, but it's treated as same as above - mSubtype = MEDIASUBTYPE_ROT0; - break; - case 1: // Rotated 270CW(90CCW) = To rotate 90CW(270CCW) - case 5: // + Horizontal Flip, but it's treated as same as above - mSubtype = MEDIASUBTYPE_ROT90; - break; - case 2: // Rotated 180CW = To rotate 180CW - case 6: // + Horizontal Flip, but it's treated as same as above - mSubtype = MEDIASUBTYPE_ROT180; - break; - case 3: // Rotated 90CW(270CCW) = To rotate 270CW(90CCW) - case 7: // + Horizontal Flip, but it's treated as same as above - mSubtype = MEDIASUBTYPE_ROT270; - break; - default: - break; - } + // 0: Front-facing camera, 1: Back-facing camera + uint16_t cameraId = extensionInfo.extensionData[1] >> 3; + uint16_t rotation = extensionInfo.extensionData[1] & 0x07; - IMLOGD4("[OnMediaDataInd] extensionId[%d], camId[%d], rot[%d], subtype[%d]", nExtensionID, - nCamID, nRotation, mSubtype); + switch (rotation) + { + case 0: // No rotation (Rotated 0CW/CCW = To rotate 0CW/CCW) + case 4: // + Horizontal Flip, but it's treated as same as above + mSubtype = MEDIASUBTYPE_ROT0; + break; + case 1: // Rotated 270CW(90CCW) = To rotate 90CW(270CCW) + case 5: // + Horizontal Flip, but it's treated as same as above + mSubtype = MEDIASUBTYPE_ROT90; + break; + case 2: // Rotated 180CW = To rotate 180CW + case 6: // + Horizontal Flip, but it's treated as same as above + mSubtype = MEDIASUBTYPE_ROT180; + break; + case 3: // Rotated 90CW(270CCW) = To rotate 270CW(90CCW) + case 7: // + Horizontal Flip, but it's treated as same as above + mSubtype = MEDIASUBTYPE_ROT270; + break; + default: + break; + } + + IMLOGD4("[OnMediaDataInd] extensionId[%d], cameraId[%d], rotation[%d], subtype[%d]", + extensionId, cameraId, rotation, mSubtype); + } } if (mMediaType == IMS_MEDIA_TEXT) @@ -564,4 +572,76 @@ void RtpDecoderNode::processDtmf(uint8_t* data) // mark true when the new event started mDtmfEndBit = true; } +} + +std::list<RtpHeaderExtension>* RtpDecoderNode::DecodeRtpHeaderExtension( + const RtpHeaderExtensionInfo& extensionInfo) +{ + if (extensionInfo.length == 0 || extensionInfo.extensionData == nullptr || + extensionInfo.extensionDataSize == 0) + { + return nullptr; + } + + std::list<RtpHeaderExtension>* extensions = new std::list<RtpHeaderExtension>(); + + // header + bool useTwoByteHeader = + (extensionInfo.definedByProfile == RtpHeaderExtensionInfo::kBitPatternForTwoByteHeader); + uint32_t length = extensionInfo.length; // word size + IMLOGD2("[DecodeRtpHeaderExtension] twoByteHeader[%d], len[%d]", useTwoByteHeader, length); + + uint32_t offset = 0; + int32_t remainingSize = extensionInfo.extensionDataSize; + + while (remainingSize > 0) + { + RtpHeaderExtension extension; + + if (useTwoByteHeader) + { + // header + extension.setLocalIdentifier(extensionInfo.extensionData[offset++]); + int8_t dataSize = extensionInfo.extensionData[offset++]; // add header + + // payload + if (dataSize > 0) + { + extension.setExtensionData( + reinterpret_cast<const uint8_t*>(extensionInfo.extensionData + offset), + dataSize); + } + + offset += dataSize; + remainingSize -= (dataSize + 2); // remove two byte header too + } + else // one byte header + { + // header + extension.setLocalIdentifier(extensionInfo.extensionData[offset] >> 4); + int8_t dataSize = (extensionInfo.extensionData[offset] & 0x0F) + 1; // data + header + offset++; + + // payload + if (dataSize > 0) + { + extension.setExtensionData( + reinterpret_cast<const uint8_t*>(extensionInfo.extensionData + offset), + dataSize); + } + + offset += dataSize; + remainingSize -= (dataSize + 1); // remove one byte header too + } + + extensions->push_back(extension); + + while (remainingSize > 0 && extensionInfo.extensionData[offset] == 0x00) // ignore padding + { + offset++; + remainingSize--; + } + } + + return extensions; }
\ No newline at end of file diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtpEncoderNode.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtpEncoderNode.cpp index d89d5bed..bcd35a6d 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtpEncoderNode.cpp +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtpEncoderNode.cpp @@ -328,24 +328,91 @@ bool RtpEncoderNode::SetCvoExtension(const int64_t facing, const int64_t orienta } } - uint16_t extensionData; + int8_t extensionData[4]; // 32bit IMLOGD3("[SetCvoExtension] cvoValue[%d], facing[%d], orientation[%d]", mCvoValue, cameraId, rotation); - extensionData = ((mCvoValue << 12) | (1 << 8)) | ((cameraId << 3) | rotation); - mRtpExtension.nDefinedByProfile = 0xBEDE; - mRtpExtension.nLength = 1; - mRtpExtension.nExtensionData = extensionData; + extensionData[0] = (mCvoValue << 4) | 1; // local identifier and data length + extensionData[1] = (cameraId << 3) | rotation; + extensionData[2] = 0; // padding + extensionData[3] = 0; // padding + mListRtpExtension.push_back(RtpHeaderExtensionInfo( + RtpHeaderExtensionInfo::kBitPatternForOneByteHeader, 1, extensionData, 4)); return true; } return false; } -void RtpEncoderNode::SetRtpHeaderExtension(tRtpHeaderExtensionInfo& tExtension) +void RtpEncoderNode::SetRtpHeaderExtension(std::list<RtpHeaderExtension>* listExtension) { - mRtpExtension = tExtension; + if (listExtension == nullptr || listExtension->empty()) + { + return; + } + + /** + * Check number of byte of the header. Based on RFC8285 4.2, one byte header has a local + * identifier in range of 1 to 14. Two byte header has is a range of 1 to 255. + */ + bool useTwoByteHeader = false; + int32_t totalPayloadLength = 0; // accumulate payload length except the header size + + for (auto extension : *listExtension) + { + if (extension.getLocalIdentifier() > 15) + { + useTwoByteHeader = true; + } + + totalPayloadLength += extension.getExtensionDataSize(); + } + + // accumulate header size + useTwoByteHeader ? totalPayloadLength += 2 * listExtension->size() + : totalPayloadLength += listExtension->size(); + + // padding size + int32_t paddingSize = totalPayloadLength % IMS_MEDIA_WORD_SIZE == 0 + ? 0 + : IMS_MEDIA_WORD_SIZE - totalPayloadLength % IMS_MEDIA_WORD_SIZE; + totalPayloadLength += paddingSize; + + int8_t* extensionData = new int8_t[totalPayloadLength]; + int offset = 0; + + for (auto extension : *listExtension) + { + if (useTwoByteHeader) + { + extensionData[offset++] = extension.getLocalIdentifier(); + extensionData[offset++] = extension.getExtensionDataSize(); + } + else + { + extensionData[offset++] = + extension.getLocalIdentifier() << 4 | (extension.getExtensionDataSize() - 1); + } + + memcpy(extensionData + offset, extension.getExtensionData(), + extension.getExtensionDataSize()); + offset += extension.getExtensionDataSize(); + } + + // add padding + memset(extensionData + offset, 0, paddingSize); + + IMLOGD3("[SetRtpHeaderExtension] twoByte[%d], size[%d], list size[%d]", useTwoByteHeader, + totalPayloadLength, listExtension->size()); + + int16_t defineByProfile = useTwoByteHeader + ? RtpHeaderExtensionInfo::kBitPatternForTwoByteHeader + : RtpHeaderExtensionInfo::kBitPatternForOneByteHeader; + mListRtpExtension.push_back(RtpHeaderExtensionInfo( + defineByProfile, totalPayloadLength / 4, extensionData, totalPayloadLength)); + + delete[] extensionData; } bool RtpEncoderNode::ProcessAudioData(ImsMediaSubType subtype, uint8_t* data, uint32_t size) @@ -431,8 +498,18 @@ bool RtpEncoderNode::ProcessAudioData(ImsMediaSubType subtype, uint8_t* data, ui timestampDiff = timeDiff * mSamplingRate; IMLOGD_PACKET3(IM_PACKET_LOG_RTP, "[ProcessAudioData] PayloadTx[%d], Size[%d], TS[%d]", mRtpPayloadTx, size, currentTimestamp); - mRtpSession->SendRtpPacket( - mRtpPayloadTx, data, size, currentTimestamp, mMark, timestampDiff); + + if (!mListRtpExtension.empty()) + { + mRtpSession->SendRtpPacket(mRtpPayloadTx, data, size, currentTimestamp, mMark, + timestampDiff, &mListRtpExtension.front()); + mListRtpExtension.pop_front(); + } + else + { + mRtpSession->SendRtpPacket( + mRtpPayloadTx, data, size, currentTimestamp, mMark, timestampDiff); + } if (mMark) { @@ -453,11 +530,11 @@ void RtpEncoderNode::ProcessVideoData( if (mCvoValue > 0 && mark && subtype == MEDIASUBTYPE_VIDEO_IDR_FRAME) { mRtpSession->SendRtpPacket( - mRtpPayloadTx, data, size, timestamp, mark, 0, true, &mRtpExtension); + mRtpPayloadTx, data, size, timestamp, mark, 0, &mListRtpExtension.front()); } else { - mRtpSession->SendRtpPacket(mRtpPayloadTx, data, size, timestamp, mark, 0, false, nullptr); + mRtpSession->SendRtpPacket(mRtpPayloadTx, data, size, timestamp, mark, 0); } } @@ -483,19 +560,16 @@ void RtpEncoderNode::ProcessTextData( { if (mRedundantLevel > 1 && mRedundantPayload > 0) { - mRtpSession->SendRtpPacket( - mRedundantPayload, data, size, timestamp, mark, timeDiff, 0, nullptr); + mRtpSession->SendRtpPacket(mRedundantPayload, data, size, timestamp, mark, timeDiff); } else { - mRtpSession->SendRtpPacket( - mRtpPayloadRx, data, size, timestamp, mark, timeDiff, 0, nullptr); + mRtpSession->SendRtpPacket(mRtpPayloadRx, data, size, timestamp, mark, timeDiff); } } else if (subtype == MEDIASUBTYPE_BITSTREAM_T140_RED) { - mRtpSession->SendRtpPacket( - mRtpPayloadTx, data, size, timestamp, mark, timeDiff, 0, nullptr); + mRtpSession->SendRtpPacket(mRtpPayloadTx, data, size, timestamp, mark, timeDiff); } mMark = false; diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextJitterBuffer.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextJitterBuffer.cpp index b9ab83c2..beb1d015 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextJitterBuffer.cpp +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextJitterBuffer.cpp @@ -111,9 +111,8 @@ void TextJitterBuffer::Add(ImsMediaSubType subtype, uint8_t* buffer, uint32_t si } bool TextJitterBuffer::Get(ImsMediaSubType* subtype, uint8_t** data, uint32_t* dataSize, - uint32_t* timestamp, bool* mark, uint32_t* seqNum, uint32_t* checker) + uint32_t* timestamp, bool* mark, uint32_t* seqNum, uint32_t /*currentTime*/) { - (void)checker; std::lock_guard<std::mutex> guard(mMutex); DataEntry* pEntry; 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 6134121e..816cb014 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 @@ -20,7 +20,7 @@ IImsMediaThread::IImsMediaThread() { - mThreadStopped = false; + mThreadStopped = true; } IImsMediaThread::~IImsMediaThread() {} diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoJitterBuffer.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoJitterBuffer.cpp index a80f1b6a..c755360d 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoJitterBuffer.cpp +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoJitterBuffer.cpp @@ -306,10 +306,8 @@ void VideoJitterBuffer::Add(ImsMediaSubType subtype, uint8_t* pbBuffer, uint32_t } bool VideoJitterBuffer::Get(ImsMediaSubType* subtype, uint8_t** ppData, uint32_t* pnDataSize, - uint32_t* pnTimestamp, bool* pbMark, uint32_t* pnSeqNum, uint32_t* pnChecker) + uint32_t* pnTimestamp, bool* pbMark, uint32_t* pnSeqNum, uint32_t currentTime) { - (void)pnChecker; - DataEntry* pEntry = nullptr; bool bValidPacket = false; std::lock_guard<std::mutex> guard(mMutex); @@ -511,7 +509,7 @@ bool VideoJitterBuffer::Get(ImsMediaSubType* subtype, uint8_t** ppData, uint32_t "[Get] bValid[%u], LastPlayedTS[%u], Seq[%u], LastPlayedSeq[%u]", pEntry->bValid, mLastPlayedTimestamp, pEntry->nSeqNum, mLastPlayedSeqNum); - uint32_t nCurrTime = ImsMediaTimer::GetTimeInMilliSeconds(); + uint32_t nCurrTime = currentTime; if (mLastPlayedTimestamp == 0 || mLastPlayedTime == 0 || pEntry->nTimestamp == mLastPlayedTimestamp) diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoManager.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoManager.cpp index bec6234f..9d98be37 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoManager.cpp +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoManager.cpp @@ -199,7 +199,7 @@ void VideoManager::sendMessage(const int sessionId, const android::Parcel& parce "VIDEO_REQUEST_EVENT", nMsg, sessionId, reinterpret_cast<uint64_t>(config)); } break; - case kVideoSendHeaderExtension: + case kVideoSendRtpHeaderExtension: // TO DO break; case kVideoSetMediaQualityThreshold: @@ -321,7 +321,7 @@ void VideoManager::RequestHandler::processEvent( "VIDEO_RESPONSE_EVENT", kVideoModifySessionResponse, sessionId, result, paramA); } break; - case kVideoSendHeaderExtension: + case kVideoSendRtpHeaderExtension: /** TODO: add implementation */ break; case kVideoSetMediaQualityThreshold: diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/interface/rtp/RtpService.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/interface/rtp/RtpService.h index f4b62bc7..bf5e0025 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/interface/rtp/RtpService.h +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/interface/rtp/RtpService.h @@ -128,7 +128,7 @@ GLOBAL eRtp_Bool IMS_RtpSvc_DeleteSession(IN RTPSESSIONID hRtpSession); */ GLOBAL eRtp_Bool IMS_RtpSvc_SendRtpPacket(IN RtpServiceListener* pobjRtpServiceListener, IN RTPSESSIONID hRtpSession, IN RtpDt_Char* pBuffer, IN RtpDt_UInt16 wBufferLength, - IN tRtpSvc_SendRtpPacketParm* pstRtpParam); + IN tRtpSvc_SendRtpPacketParam* pstRtpParam); /** * This API processes the received RTP packet. Processed information is sent using diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/interface/rtp/RtpServiceTypes.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/interface/rtp/RtpServiceTypes.h index ea3796be..9c4c119e 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/interface/rtp/RtpServiceTypes.h +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/interface/rtp/RtpServiceTypes.h @@ -72,12 +72,13 @@ typedef struct eRtp_Bool bUseLastTimestamp; RtpDt_UInt32 diffFromLastRtpTimestamp; - // [CVO] for extension header + // Rtp extension header eRtp_Bool bXbit; - RtpDt_UInt16 nDefinedByProfile; - RtpDt_UInt16 nLength; - RtpDt_UInt16 nExtensionData; -} tRtpSvc_SendRtpPacketParm; + RtpDt_UInt16 wDefinedByProfile; + RtpDt_UInt16 wExtLen; + RtpDt_Int8* pExtData; + RtpDt_Int32 nExtDataSize; +} tRtpSvc_SendRtpPacketParam; /* typedef struct @@ -94,6 +95,7 @@ typedef struct RtpDt_UInt32 dwTimestamp; RtpDt_UInt32 dwPayloadType; RtpDt_UInt16 dwSeqNum; + RtpDt_UInt32 dwSsrc; RtpDt_UInt16 wMsgHdrLen; RtpDt_UChar* pMsgHdr; @@ -101,10 +103,11 @@ typedef struct RtpDt_UInt16 wMsgBodyLen; RtpDt_UChar* pMsgBody; - /* [CVO] for RTP Header Extension, seokhwan.chung@, 2013.05.22 */ - RtpDt_UInt16 extensionData; - eRtp_Bool bExtension; - + /* RTP Header extension */ + RtpDt_UInt16 wDefinedByProfile; + RtpDt_UInt16 wExtLen; + RtpDt_UChar* pExtData; + RtpDt_UInt16 wExtDataSize; } tRtpSvcIndSt_ReceiveRtpInd; typedef struct diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/rtp/RtpService.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/rtp/RtpService.cpp index 0b502bc1..16599644 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/rtp/RtpService.cpp +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/rtp/RtpService.cpp @@ -44,21 +44,29 @@ RtpDt_Void populateReceiveRtpIndInfo( pstRtpIndMsg->dwTimestamp = pobjRtpHeader->getRtpTimestamp(); pstRtpIndMsg->dwPayloadType = pobjRtpHeader->getPayloadType(); pstRtpIndMsg->dwSeqNum = pobjRtpHeader->getSequenceNumber(); + pstRtpIndMsg->dwSsrc = pobjRtpHeader->getRtpSsrc(); // Header length pstRtpIndMsg->wMsgHdrLen = RTP_FIXED_HDR_LEN; pstRtpIndMsg->wMsgHdrLen += RTP_WORD_SIZE * pobjRtpHeader->getCsrcCount(); + if (pobjRtpPkt->getExtHeader()) { pstRtpIndMsg->wMsgHdrLen += pobjRtpPkt->getExtHeader()->getLength(); - pstRtpIndMsg->bExtension = eRTP_TRUE; - RtpDt_UChar* pbuf = pobjRtpPkt->getExtHeader()->getBuffer(); - pstRtpIndMsg->extensionData = ((((unsigned)*pbuf) << 8) & 0xff00) | ((pbuf[1] & 0x00ff)); + RtpDt_UChar* pExtHdrBuffer = pobjRtpPkt->getExtHeader()->getBuffer(); + RtpDt_Int32 uiByte4Data = + RtpOsUtil::Ntohl(*(reinterpret_cast<RtpDt_UInt32*>(pExtHdrBuffer))); + pstRtpIndMsg->wDefinedByProfile = uiByte4Data >> 16; + pstRtpIndMsg->wExtLen = uiByte4Data & 0x00FF; + pstRtpIndMsg->pExtData = pExtHdrBuffer + 4; + pstRtpIndMsg->wExtDataSize = pobjRtpPkt->getExtHeader()->getLength() - 4; } else { - pstRtpIndMsg->bExtension = eRTP_FALSE; - pstRtpIndMsg->extensionData = 0; + pstRtpIndMsg->wDefinedByProfile = 0; + pstRtpIndMsg->wExtLen = 0; + pstRtpIndMsg->pExtData = nullptr; + pstRtpIndMsg->wExtDataSize = 0; } // End Header length // play the payload @@ -204,27 +212,33 @@ RtpDt_Void populateRtpProfile(OUT RtpStackProfile* pobjStackProfile) pobjStackProfile->setTermNumber(RTP_CONF_SSRC_SEED); } -RtpBuffer* GetCVOXHdr(IN tRtpSvc_SendRtpPacketParm* pstRtpParam) +RtpBuffer* SetRtpHeaderExtension(IN tRtpSvc_SendRtpPacketParam* pstRtpParam) { RtpBuffer* pobjXHdr = new RtpBuffer(); // HDR extension if (pstRtpParam->bXbit) { - RtpDt_UChar* pBuf = new RtpDt_UChar[8]; - pBuf[0] = (((unsigned)pstRtpParam->nDefinedByProfile) >> 8) & 0x00ff; - pBuf[1] = pstRtpParam->nDefinedByProfile & 0x00ff; + const RtpDt_Int32 headerSize = 4; + RtpDt_Int32 nBufferSize = headerSize + pstRtpParam->wExtLen * sizeof(int32_t); + RtpDt_UChar* pBuf = new RtpDt_UChar[nBufferSize]; - pBuf[2] = (((unsigned)pstRtpParam->nLength) >> 8) & 0x00ff; - pBuf[3] = (pstRtpParam->nLength) & 0x00ff; + if (pstRtpParam->wExtLen * sizeof(int32_t) != pstRtpParam->nExtDataSize) + { + RTP_TRACE_WARNING("SetRtpHeaderExtension invalid data size len[%d], size[%d]", + pstRtpParam->wExtLen, pstRtpParam->nExtDataSize); + } - pBuf[4] = (((unsigned)pstRtpParam->nExtensionData) >> 8) & 0x00ff; - pBuf[5] = (pstRtpParam->nExtensionData) & 0x00ff; + // define by profile + pBuf[0] = (((unsigned)pstRtpParam->wDefinedByProfile) >> 8) & 0x00ff; + pBuf[1] = pstRtpParam->wDefinedByProfile & 0x00ff; - pBuf[6] = 0; - pBuf[7] = 0; + // number of the extension data set + pBuf[2] = (((unsigned)pstRtpParam->wExtLen) >> 8) & 0x00ff; + pBuf[3] = (pstRtpParam->wExtLen) & 0x00ff; - pobjXHdr->setBufferInfo(8, pBuf); + memcpy(pBuf + 4, pstRtpParam->pExtData, pstRtpParam->nExtDataSize); + pobjXHdr->setBufferInfo(nBufferSize, pBuf); } else { @@ -234,7 +248,7 @@ RtpBuffer* GetCVOXHdr(IN tRtpSvc_SendRtpPacketParm* pstRtpParam) return pobjXHdr; } -RtpDt_UInt16 GetCVOXHdrLen(eRtp_Bool bEnableCVO) +RtpDt_UInt16 GetRtpHeaderExtensionSize(eRtp_Bool bEnableCVO) { if (bEnableCVO) return RTP_CVO_XHDR_LEN; @@ -351,7 +365,7 @@ GLOBAL eRtp_Bool IMS_RtpSvc_SetPayload(IN RTPSESSIONID hRtpSession, } eRTP_STATUS_CODE eInitSta = - pobjRtpSession->setPayload(pobjlPayloadInfo, GetCVOXHdrLen(bEnableXHdr)); + pobjRtpSession->setPayload(pobjlPayloadInfo, GetRtpHeaderExtensionSize(bEnableXHdr)); delete pobjlPayloadInfo; if (eInitSta != RTP_SUCCESS) { @@ -392,7 +406,7 @@ GLOBAL eRtp_Bool IMS_RtpSvc_DeleteSession(IN RTPSESSIONID hRtpSession) GLOBAL eRtp_Bool IMS_RtpSvc_SendRtpPacket(IN RtpServiceListener* pobjRtpServiceListener, IN RTPSESSIONID hRtpSession, IN RtpDt_Char* pBuffer, IN RtpDt_UInt16 wBufferLength, - IN tRtpSvc_SendRtpPacketParm* pstRtpParam) + IN tRtpSvc_SendRtpPacketParam* pstRtpParam) { RtpSession* pobjRtpSession = reinterpret_cast<RtpSession*>(hRtpSession); @@ -425,6 +439,7 @@ GLOBAL eRtp_Bool IMS_RtpSvc_SendRtpPacket(IN RtpServiceListener* pobjRtpServiceL // Create RTP packet // 1. Set Marker bit eRtp_Bool bMbit = eRTP_FALSE; + if (pstRtpParam->bMbit == eRTP_TRUE) { bMbit = eRTP_TRUE; @@ -435,7 +450,7 @@ GLOBAL eRtp_Bool IMS_RtpSvc_SendRtpPacket(IN RtpServiceListener* pobjRtpServiceL eRtp_Bool bUseLastTimestamp = pstRtpParam->bUseLastTimestamp ? eRTP_TRUE : eRTP_FALSE; eRTP_STATUS_CODE eRtpCreateStat = pobjRtpSession->createRtpPacket(pobjRtpPayload, bMbit, pstRtpParam->byPayLoadType, bUseLastTimestamp, pstRtpParam->diffFromLastRtpTimestamp, - GetCVOXHdr(pstRtpParam), pobjRtpBuf); + SetRtpHeaderExtension(pstRtpParam), pobjRtpBuf); // 3. de-init and free the temp variable both in success and failure case pobjRtpPayload->setBufferInfo(RTP_ZERO, nullptr); @@ -498,6 +513,7 @@ GLOBAL eRtp_Bool IMS_RtpSvc_ProcRtpPacket(IN RtpServiceListener* pvIRtpSession, RtpBuffer objRtpBuf; objRtpBuf.setBufferInfo(uiMsgLength, pMsg); + RtpDt_UInt32 uiTransLen = strlen(reinterpret_cast<const RtpDt_Char*>(pPeerIp)); RtpBuffer objRmtAddr; objRmtAddr.setBufferInfo(uiTransLen + 1, reinterpret_cast<RtpDt_UChar*>(pPeerIp)); diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/rtp/core/RtpPacket.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/rtp/core/RtpPacket.cpp index 7ee0e408..23fa9378 100644 --- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/rtp/core/RtpPacket.cpp +++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/rtp/core/RtpPacket.cpp @@ -149,34 +149,24 @@ eRtp_Bool RtpPacket::decodePacket(IN RtpBuffer* pobjRtpPktBuf) // extension header if (m_objRtpHeader.getExtension()) { - RTP_TRACE_MESSAGE("[XHdr] Extension Header detected", 0, 0); m_pobjExt = new RtpBuffer(); - if (m_pobjExt == nullptr) - { - return eRTP_FAILURE; - } // Get XHdr type and length RtpDt_UInt32 uiByte4Data = RtpOsUtil::Ntohl(*(reinterpret_cast<RtpDt_UInt32*>(pcRtpBuf))); - pcRtpBuf = pcRtpBuf + RTP_WORD_SIZE; - uiRtpBufPos = uiRtpBufPos + RTP_WORD_SIZE; - RtpDt_UInt16 uXHdrLen = (RtpDt_UInt16)(uiByte4Data & RTP_HEX_16_BIT_MAX); - // RtpDt_UInt16 uXHdrType = (RtpDt_UInt16)(uiByte4Data >> RTP_SIXTEEN); + RtpDt_UInt16 uXHdrLen = + (RtpDt_UInt16)(uiByte4Data & RTP_HEX_16_BIT_MAX); // add header size + + uXHdrLen += 1; // add a word for header type info + uXHdrLen *= RTP_WORD_SIZE; // convert word to byte - uXHdrLen += RTP_WORD_SIZE - (uXHdrLen % RTP_WORD_SIZE); // word align if ((uXHdrLen <= 0) || ((uiRtpBufPos + uXHdrLen) > uiRtpUtlBufLen)) { - RTP_TRACE_ERROR("[XHdr]Invalid Header Extension.Xbit-1 but XHdr len <= 0 OR xhdr len " - "> rtp buffer len", - 0, 0); + RTP_TRACE_ERROR("[decodePacket] Invalid Header Extension len[%d]", uXHdrLen, 0); return eRTP_FAILURE; } RtpDt_UChar* pRtpExtData = new RtpDt_UChar[uXHdrLen]; - if (pRtpExtData == nullptr) - { - return eRTP_FAILURE; - } + memcpy(pRtpExtData, pcRtpBuf, uXHdrLen); m_pobjExt->setBufferInfo(uXHdrLen, pRtpExtData); diff --git a/test/app/ImsMediaTestingApp/app/src/main/java/com/example/imsmediatestingapp/MainActivity.java b/test/app/ImsMediaTestingApp/app/src/main/java/com/example/imsmediatestingapp/MainActivity.java index e6800b57..f68076d5 100644 --- a/test/app/ImsMediaTestingApp/app/src/main/java/com/example/imsmediatestingapp/MainActivity.java +++ b/test/app/ImsMediaTestingApp/app/src/main/java/com/example/imsmediatestingapp/MainActivity.java @@ -17,6 +17,7 @@ import android.net.wifi.WifiManager; import android.os.Bundle; import android.telephony.AccessNetworkConstants.AccessNetworkType; import android.telephony.CallQuality; +import android.telephony.ims.RtpHeaderExtension; import android.telephony.imsmedia.AmrParams; import android.telephony.imsmedia.AudioConfig; import android.telephony.imsmedia.AudioSessionCallback; @@ -752,6 +753,12 @@ public class MainActivity extends AppCompatActivity { } @Override + public void onHeaderExtensionReceived(final List<RtpHeaderExtension> extensions) { + Log.d(TAG, "onHeaderExtensionReceived, list size=" + extensions.size() + + "list=" + extensions); + } + + @Override public void triggerAnbrQuery(AudioConfig config) { Log.d(TAG, "triggerAnbrQuery"); } @@ -2627,4 +2634,20 @@ public class MainActivity extends AppCompatActivity { Log.d(TAG, e.toString()); } } + + public void sendHeaderExtension(View btn) { + if (mAudioSession != null) { + List<RtpHeaderExtension> extensions = new ArrayList<>(); + byte[] testBytes1 = new byte[1]; + byte[] testBytes2 = new byte[1]; + testBytes1[0] = 5; + testBytes2[0] = 10; + RtpHeaderExtension extension1 = new RtpHeaderExtension(1, testBytes1); + RtpHeaderExtension extension2 = new RtpHeaderExtension(2, testBytes2); + extensions.add(extension1); + extensions.add(extension2); + Log.d(TAG, "[sendHeaderExtension] extension size=" + extensions.size()); + mAudioSession.sendHeaderExtension(extensions); + } + } } diff --git a/test/app/ImsMediaTestingApp/app/src/main/res/layout/activity_main.xml b/test/app/ImsMediaTestingApp/app/src/main/res/layout/activity_main.xml index 28189c98..fb2025a7 100644 --- a/test/app/ImsMediaTestingApp/app/src/main/res/layout/activity_main.xml +++ b/test/app/ImsMediaTestingApp/app/src/main/res/layout/activity_main.xml @@ -171,6 +171,7 @@ android:textColor="@color/black" /> <Button + android:id="@+id/getSpropButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="20dp" @@ -184,6 +185,20 @@ android:autoSizeTextType="uniform" android:textColor="@color/black" /> + <Button + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="20dp" + android:layout_marginEnd="15dp" + android:layout_alignParentEnd="true" + android:layout_below="@+id/getSpropButton" + android:backgroundTint="@drawable/selected_green" + android:enabled="true" + android:onClick="sendHeaderExtension" + android:text="@string/send_header_extension_button_text" + android:autoSizeTextType="uniform" + android:textColor="@color/black" /> + <Spinner android:id="@+id/spinnerAdditionalMedia" android:layout_width="150dp" diff --git a/test/app/ImsMediaTestingApp/app/src/main/res/values/strings.xml b/test/app/ImsMediaTestingApp/app/src/main/res/values/strings.xml index efdc710c..37d6b5a7 100644 --- a/test/app/ImsMediaTestingApp/app/src/main/res/values/strings.xml +++ b/test/app/ImsMediaTestingApp/app/src/main/res/values/strings.xml @@ -40,6 +40,8 @@ <string name="connected_call_toast_text">Connected!</string> <string name="connection_failed_toast_text">Connection failed!</string> + <!-- Send Header extension button text --> + <string name="send_header_extension_button_text">Send RtpHdrExt</string> <!-- Settings page Strings --> <string name="settings_remote_device_title">Remote Device</string> diff --git a/test/imsmediahal/src/com/android/telephony/testimsmediahal/AudioListenerProxy.java b/test/imsmediahal/src/com/android/telephony/testimsmediahal/AudioListenerProxy.java index 4917c3cc..2832c4d2 100644 --- a/test/imsmediahal/src/com/android/telephony/testimsmediahal/AudioListenerProxy.java +++ b/test/imsmediahal/src/com/android/telephony/testimsmediahal/AudioListenerProxy.java @@ -129,11 +129,14 @@ class AudioListenerProxy implements JNIImsMediaListener { } break; case AudioSession.EVENT_RTP_HEADER_EXTENSION_IND: - final List<RtpHeaderExtension> rtpHeaderExt = new ArrayList<RtpHeaderExtension>(); - parcel.readList(rtpHeaderExt, RtpHeaderExtension.class.getClassLoader()); + final List<RtpHeaderExtension> extensions = new ArrayList<RtpHeaderExtension>(); + final int listSize = parcel.readInt(); + for (int i = 0; i < listSize; i++) { + extensions.add(RtpHeaderExtension.CREATOR.createFromParcel(parcel)); + } try { - mMediaSessionListener.onHeaderExtensionReceived(rtpHeaderExt); + mMediaSessionListener.onHeaderExtensionReceived(extensions); } catch(RemoteException e) { Log.e(TAG, "Failed to notify rtp header extension: " + e); } diff --git a/test/imsmediahal/src/com/android/telephony/testimsmediahal/IImsMediaSessionImpl.java b/test/imsmediahal/src/com/android/telephony/testimsmediahal/IImsMediaSessionImpl.java index 1ea35ad9..8d84c325 100644 --- a/test/imsmediahal/src/com/android/telephony/testimsmediahal/IImsMediaSessionImpl.java +++ b/test/imsmediahal/src/com/android/telephony/testimsmediahal/IImsMediaSessionImpl.java @@ -118,8 +118,9 @@ public class IImsMediaSessionImpl extends IImsMediaSession.Stub { Log.d(TAG, "sendHeaderExtension: " + data); Parcel parcel = Parcel.obtain(); parcel.writeInt(AudioSession.CMD_SEND_RTP_HDR_EXTN); - if (data != null) { - parcel.writeList(data); + parcel.writeInt(data.size()); + for (RtpHeaderExtension item : data) { + item.writeToParcel(parcel, 0); } connector.sendRequest(mSessionId, parcel); } diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/RtpHeaderExtensionTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/RtpHeaderExtensionTest.cpp new file mode 100644 index 00000000..926e917f --- /dev/null +++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/RtpHeaderExtensionTest.cpp @@ -0,0 +1,100 @@ +/** + * 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 <RtpHeaderExtension.h> +#include <gtest/gtest.h> + +using namespace android::telephony::imsmedia; + +const int32_t kIdentifier = 15; +const uint8_t kExtensionData[] = {0x01, 0x02}; +const int32_t kExtensionDataSize = 2; + +class RtpHeaderExtensionTest : public ::testing::Test +{ +public: + RtpHeaderExtensionTest() { extension = nullptr; } + virtual ~RtpHeaderExtensionTest() {} + +protected: + RtpHeaderExtension* extension; + + virtual void SetUp() override + { + extension = new RtpHeaderExtension(); + extension->setExtensionData(kExtensionData, kExtensionDataSize); + extension->setLocalIdentifier(kIdentifier); + extension->setExtensionDataSize(kExtensionDataSize); + } + + virtual void TearDown() override { delete extension; } +}; + +TEST_F(RtpHeaderExtensionTest, TestGetterSetter) +{ + EXPECT_EQ(memcmp(extension->getExtensionData(), kExtensionData, kExtensionDataSize), 0); + EXPECT_EQ(extension->getLocalIdentifier(), kIdentifier); + EXPECT_EQ(extension->getExtensionDataSize(), kExtensionDataSize); +} + +TEST_F(RtpHeaderExtensionTest, TestParcel) +{ + android::Parcel parcel; + extension->writeToParcel(&parcel); + parcel.setDataPosition(0); + + RtpHeaderExtension* extension2 = new RtpHeaderExtension(); + extension2->readFromParcel(&parcel); + EXPECT_EQ(*extension2, *extension); + delete extension2; +} + +TEST_F(RtpHeaderExtensionTest, TestAssign) +{ + RtpHeaderExtension extension2; + extension2 = *extension; + EXPECT_EQ(*extension, extension2); +} + +TEST_F(RtpHeaderExtensionTest, TestEqual) +{ + RtpHeaderExtension* extension2 = new RtpHeaderExtension(); + extension2->setExtensionData(kExtensionData, kExtensionDataSize); + extension2->setLocalIdentifier(kIdentifier); + extension2->setExtensionDataSize(kExtensionDataSize); + EXPECT_EQ(*extension, *extension2); + delete extension2; +} + +TEST_F(RtpHeaderExtensionTest, TestNotEqual) +{ + RtpHeaderExtension* extension2 = new RtpHeaderExtension(); + const uint8_t data[] = {0x03, 0x04}; + extension2->setExtensionData(data, 2); + extension2->setLocalIdentifier(kIdentifier); + extension2->setExtensionDataSize(kExtensionDataSize); + + RtpHeaderExtension* extension3 = new RtpHeaderExtension(); + extension3->setExtensionData(kExtensionData, kExtensionDataSize); + extension3->setLocalIdentifier(9999); + extension3->setExtensionDataSize(kExtensionDataSize); + + EXPECT_NE(*extension, *extension2); + EXPECT_NE(*extension, *extension3); + + delete extension2; + delete extension3; +}
\ No newline at end of file diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioJitterBufferTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioJitterBufferTest.cpp new file mode 100644 index 00000000..5d1f19cb --- /dev/null +++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioJitterBufferTest.cpp @@ -0,0 +1,494 @@ +/** + * 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 <AudioJitterBuffer.h> + +#define TEST_BUFFER_SIZE 10 +#define TEST_FRAME_INTERVAL 20 + +class AudioJitterBufferCallback : public BaseSessionCallback +{ +public: + AudioJitterBufferCallback() + { + numNormal = 0; + numLost = 0; + numDuplicated = 0; + numDiscarded = 0; + } + virtual ~AudioJitterBufferCallback() {} + + virtual void onEvent(int32_t type, uint64_t param1, uint64_t /*param2*/) + { + if (type == kCollectRxRtpStatus) + { + SessionCallbackParameter* param = reinterpret_cast<SessionCallbackParameter*>(param1); + + if (param == nullptr) + { + return; + } + + switch (param->param1) + { + case kRtpStatusDuplicated: + numDuplicated++; + break; + case kRtpStatusDiscarded: + numDiscarded++; + break; + case kRtpStatusNormal: + numNormal++; + break; + default: + break; + } + + delete param; + } + else if (type == kCollectOptionalInfo) + { + SessionCallbackParameter* param = reinterpret_cast<SessionCallbackParameter*>(param1); + + if (param == nullptr) + { + return; + } + + if (param->type == kReportPacketLossGap) + { + numLost += param->param2; + } + + delete param; + } + } + + int32_t getNumNormal() { return numNormal; } + int32_t getNumLost() { return numLost; } + int32_t getNumDuplicated() { return numDuplicated; } + int32_t getNumDiscarded() { return numDiscarded; } + +private: + int32_t numNormal; + int32_t numLost; + int32_t numDuplicated; + int32_t numDiscarded; +}; + +class AudioJitterBufferTest : public ::testing::Test +{ +public: + AudioJitterBufferTest() {} + virtual ~AudioJitterBufferTest() {} + +protected: + AudioJitterBuffer* mJitterBuffer; + AudioJitterBufferCallback mCallback; + int32_t mStartJitterBufferSize; + int32_t mMinJitterBufferSize; + int32_t mMaxJitterBufferSize; + + virtual void SetUp() override + { + mStartJitterBufferSize = 4; + mMinJitterBufferSize = 4; + mMaxJitterBufferSize = 9; + + mJitterBuffer = new AudioJitterBuffer(); + mJitterBuffer->SetCodecType(kAudioCodecAmr); + mJitterBuffer->SetSessionCallback(&mCallback); + mJitterBuffer->SetJitterBufferSize( + mStartJitterBufferSize, mMinJitterBufferSize, mMaxJitterBufferSize); + mJitterBuffer->SetJitterOptions(80, 1, 2.5f, false); + } + + virtual void TearDown() override { delete mJitterBuffer; } +}; + +TEST_F(AudioJitterBufferTest, TestNormalAddGet) +{ + const int32_t kNumFrames = 50; + char buffer[TEST_BUFFER_SIZE] = {"\x1"}; + int32_t countGet = 0; + int32_t countGetFrame = 0; + int32_t countNotGet = 0; + int32_t getTime = 0; + + ImsMediaSubType subtype = MEDIASUBTYPE_UNDEFINED; + uint8_t* data = nullptr; + uint32_t size = 0; + uint32_t timestamp = 0; + bool mark = false; + uint32_t seq = 0; + + for (int32_t i = 0; i < kNumFrames; i++) + { + int32_t addTime = i * TEST_FRAME_INTERVAL; + mJitterBuffer->Add(MEDIASUBTYPE_UNDEFINED, reinterpret_cast<uint8_t*>(buffer), 1, + i * TEST_FRAME_INTERVAL, false, i, MEDIASUBTYPE_UNDEFINED, addTime); + + getTime = countGet * TEST_FRAME_INTERVAL; + + if (mJitterBuffer->Get(&subtype, &data, &size, ×tamp, &mark, &seq, getTime)) + { + EXPECT_EQ(size, 1); + EXPECT_EQ(timestamp, countGetFrame * TEST_FRAME_INTERVAL); + EXPECT_EQ(seq, countGetFrame); + mJitterBuffer->Delete(); + countGetFrame++; + } + else + { + countNotGet++; + } + + countGet++; + } + + while (mJitterBuffer->GetCount() > 0) + { + getTime = countGet * TEST_FRAME_INTERVAL; + + if (mJitterBuffer->Get(&subtype, &data, &size, ×tamp, &mark, &seq, getTime)) + { + EXPECT_EQ(size, 1); + EXPECT_EQ(timestamp, countGetFrame * TEST_FRAME_INTERVAL); + EXPECT_EQ(seq, countGetFrame); + mJitterBuffer->Delete(); + countGetFrame++; + } + else + { + countNotGet++; + } + + countGet++; + } + + EXPECT_EQ(countNotGet, mStartJitterBufferSize); + EXPECT_EQ(mCallback.getNumNormal(), kNumFrames); +} + +TEST_F(AudioJitterBufferTest, TestNormalAddGetSeqRounding) +{ + const int32_t kNumFrames = 20; + char buffer[TEST_BUFFER_SIZE] = {"\x1"}; + int32_t countGet = 0; + int32_t countGetFrame = 0; + int32_t countNotGet = 0; + int32_t getTime = 0; + + ImsMediaSubType subtype = MEDIASUBTYPE_UNDEFINED; + uint8_t* data = nullptr; + uint32_t size = 0; + uint32_t timestamp = 0; + bool mark = false; + uint32_t seq = 0; + uint16_t startSeq = 65530; + uint16_t addSeq = 0; + uint16_t getSeq = 0; + + for (int32_t i = 0; i < kNumFrames; i++) + { + addSeq = startSeq + (uint16_t)i; + int32_t addTime = i * TEST_FRAME_INTERVAL; + mJitterBuffer->Add(MEDIASUBTYPE_UNDEFINED, reinterpret_cast<uint8_t*>(buffer), 1, + i * TEST_FRAME_INTERVAL, false, addSeq, MEDIASUBTYPE_UNDEFINED, addTime); + + getTime = countGet * TEST_FRAME_INTERVAL; + + if (mJitterBuffer->Get(&subtype, &data, &size, ×tamp, &mark, &seq, getTime)) + { + getSeq = startSeq + (uint16_t)countGetFrame; + EXPECT_EQ(size, 1); + EXPECT_EQ(timestamp, countGetFrame * TEST_FRAME_INTERVAL); + EXPECT_EQ(seq, getSeq); + mJitterBuffer->Delete(); + countGetFrame++; + } + else + { + countNotGet++; + } + countGet++; + } + + while (mJitterBuffer->GetCount() > 0) + { + getTime = countGet * TEST_FRAME_INTERVAL; + + if (mJitterBuffer->Get(&subtype, &data, &size, ×tamp, &mark, &seq, getTime)) + { + getSeq = startSeq + (uint16_t)countGetFrame; + EXPECT_EQ(size, 1); + EXPECT_EQ(timestamp, countGetFrame * TEST_FRAME_INTERVAL); + EXPECT_EQ(seq, getSeq); + mJitterBuffer->Delete(); + countGetFrame++; + } + else + { + countNotGet++; + } + + countGet++; + } + + EXPECT_EQ(countNotGet, mStartJitterBufferSize); + EXPECT_EQ(mCallback.getNumNormal(), kNumFrames); +} + +TEST_F(AudioJitterBufferTest, TestNormalAddGetTimestampRounding) +{ + const int32_t kNumFrames = 50; + char buffer[TEST_BUFFER_SIZE] = {"\x1"}; + int32_t countGet = 0; + int32_t countGetFrame = 0; + int32_t countNotGet = 0; + int32_t getTime = 0; + + ImsMediaSubType subtype = MEDIASUBTYPE_UNDEFINED; + uint8_t* data = nullptr; + uint32_t size = 0; + uint32_t timestamp = 0; + bool mark = false; + uint32_t seq = 0; + uint32_t startTimestamp = 4294967295 - 200; + uint32_t addTimestamp = 0; + uint32_t getTimestamp = 0; + + for (int32_t i = 0; i < kNumFrames; i++) + { + addTimestamp = startTimestamp + i * TEST_FRAME_INTERVAL; + int32_t addTime = i * TEST_FRAME_INTERVAL; + mJitterBuffer->Add(MEDIASUBTYPE_UNDEFINED, reinterpret_cast<uint8_t*>(buffer), 1, + addTimestamp, false, i, MEDIASUBTYPE_UNDEFINED, addTime); + + getTime = countGet * TEST_FRAME_INTERVAL; + + if (mJitterBuffer->Get(&subtype, &data, &size, ×tamp, &mark, &seq, getTime)) + { + getTimestamp = startTimestamp + countGetFrame * TEST_FRAME_INTERVAL; + EXPECT_EQ(size, 1); + EXPECT_EQ(timestamp, getTimestamp); + EXPECT_EQ(seq, countGetFrame); + mJitterBuffer->Delete(); + countGetFrame++; + } + else + { + countNotGet++; + } + + countGet++; + } + + while (mJitterBuffer->GetCount() > 0) + { + getTime = countGet * TEST_FRAME_INTERVAL; + + if (mJitterBuffer->Get(&subtype, &data, &size, ×tamp, &mark, &seq, getTime)) + { + getTimestamp = startTimestamp + countGetFrame * TEST_FRAME_INTERVAL; + EXPECT_EQ(size, 1); + EXPECT_EQ(timestamp, getTimestamp); + EXPECT_EQ(seq, countGetFrame); + mJitterBuffer->Delete(); + countGetFrame++; + } + else + { + countNotGet++; + } + + countGet++; + } + + EXPECT_EQ(countNotGet, mStartJitterBufferSize); + EXPECT_EQ(mCallback.getNumNormal(), kNumFrames); +} + +TEST_F(AudioJitterBufferTest, TestAddGetDuplicatedSeqDetection) +{ + const int32_t kNumFrames = 20; + char buffer[TEST_BUFFER_SIZE] = {"\x1"}; + int32_t countGet = 0; + int32_t countGetFrame = 0; + int32_t countNotGet = 0; + int32_t getTime = 0; + + ImsMediaSubType subtype = MEDIASUBTYPE_UNDEFINED; + uint8_t* data = nullptr; + uint32_t size = 0; + uint32_t timestamp = 0; + bool mark = false; + uint32_t seq = 0; + uint16_t startSeq = 0; + uint16_t addSeq = 0; + uint16_t getSeq = 0; + + for (int32_t i = 0; i < kNumFrames; i++) + { + addSeq = startSeq + (uint16_t)i; + int32_t addTime = i * TEST_FRAME_INTERVAL; + mJitterBuffer->Add(MEDIASUBTYPE_UNDEFINED, reinterpret_cast<uint8_t*>(buffer), 1, + i * TEST_FRAME_INTERVAL, false, addSeq, MEDIASUBTYPE_UNDEFINED, addTime); + + if (i == 5) + { + mJitterBuffer->Add(MEDIASUBTYPE_UNDEFINED, reinterpret_cast<uint8_t*>(buffer), 1, + i * TEST_FRAME_INTERVAL, false, addSeq, MEDIASUBTYPE_UNDEFINED, addTime); + } + + getTime = countGet * TEST_FRAME_INTERVAL; + + if (mJitterBuffer->Get(&subtype, &data, &size, ×tamp, &mark, &seq, getTime)) + { + getSeq = startSeq + (uint16_t)countGetFrame; + EXPECT_EQ(size, 1); + EXPECT_EQ(timestamp, countGetFrame * TEST_FRAME_INTERVAL); + EXPECT_EQ(seq, getSeq); + mJitterBuffer->Delete(); + countGetFrame++; + } + else + { + countNotGet++; + } + + countGet++; + } + + while (mJitterBuffer->GetCount() > 0) + { + getTime = countGet * TEST_FRAME_INTERVAL; + + if (mJitterBuffer->Get(&subtype, &data, &size, ×tamp, &mark, &seq, getTime)) + { + getSeq = startSeq + (uint16_t)countGetFrame; + EXPECT_EQ(size, 1); + EXPECT_EQ(timestamp, countGetFrame * TEST_FRAME_INTERVAL); + EXPECT_EQ(seq, getSeq); + mJitterBuffer->Delete(); + countGetFrame++; + } + else + { + countNotGet++; + } + + countGet++; + } + + EXPECT_EQ(mCallback.getNumLost(), 0); + EXPECT_EQ(mCallback.getNumDuplicated(), 1); + EXPECT_EQ(mCallback.getNumDiscarded(), 0); + EXPECT_EQ(countNotGet, mStartJitterBufferSize); + EXPECT_EQ(mCallback.getNumNormal(), kNumFrames); +} + +TEST_F(AudioJitterBufferTest, TestAddGetInBurstIncoming) +{ + const int32_t kNumFrames = 20; + char buffer[TEST_BUFFER_SIZE] = {"\x1"}; + int32_t countGet = 0; + int32_t countGetFrame = 0; + int32_t countNotGet = 0; + int32_t getTime = 0; + + ImsMediaSubType subtype = MEDIASUBTYPE_UNDEFINED; + uint8_t* data = nullptr; + uint32_t size = 0; + uint32_t timestamp = 0; + bool mark = false; + uint32_t seq = 0; + uint16_t startSeq = 0; + uint16_t addSeq = startSeq; + uint16_t getSeq = startSeq; + uint32_t addTimestamp = 0; + + int32_t addTime = 0; + int iter = 0; + + while (addSeq < kNumFrames) + { + if (iter > 5 && iter < 10) // not added for 4 frame interval + { + addTime += TEST_FRAME_INTERVAL; + } + else if (iter >= 10 && iter < 15) // 5 frames burst added + { + mJitterBuffer->Add(MEDIASUBTYPE_UNDEFINED, reinterpret_cast<uint8_t*>(buffer), 1, + addTimestamp, false, addSeq++, MEDIASUBTYPE_UNDEFINED, addTime); + addTime += 1; // 1ms burst + addTimestamp += TEST_FRAME_INTERVAL; + } + else // normal + { + mJitterBuffer->Add(MEDIASUBTYPE_UNDEFINED, reinterpret_cast<uint8_t*>(buffer), 1, + addTimestamp, false, addSeq++, MEDIASUBTYPE_UNDEFINED, addTime); + addTime += TEST_FRAME_INTERVAL; + addTimestamp += TEST_FRAME_INTERVAL; + } + + iter++; + getTime = countGet * TEST_FRAME_INTERVAL; + + if (mJitterBuffer->Get(&subtype, &data, &size, ×tamp, &mark, &seq, getTime)) + { + EXPECT_EQ(size, 1); + EXPECT_EQ(timestamp, countGetFrame * TEST_FRAME_INTERVAL); + EXPECT_EQ(seq, getSeq++); + mJitterBuffer->Delete(); + countGetFrame++; + } + else + { + countNotGet++; + } + + countGet++; + } + + while (mJitterBuffer->GetCount() > 0) + { + getTime = countGet * TEST_FRAME_INTERVAL; + + if (mJitterBuffer->Get(&subtype, &data, &size, ×tamp, &mark, &seq, getTime)) + { + getSeq = startSeq + (uint16_t)countGetFrame; + EXPECT_EQ(size, 1); + EXPECT_EQ(timestamp, countGetFrame * TEST_FRAME_INTERVAL); + EXPECT_EQ(seq, getSeq); + mJitterBuffer->Delete(); + countGetFrame++; + } + else + { + countNotGet++; + } + + countGet++; + } + + EXPECT_EQ(mCallback.getNumLost(), 0); + EXPECT_EQ(mCallback.getNumDuplicated(), 0); + EXPECT_EQ(mCallback.getNumDiscarded(), 0); + EXPECT_EQ(countNotGet, mStartJitterBufferSize); + EXPECT_EQ(mCallback.getNumNormal(), kNumFrames); +}
\ 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 a979dd4a..a94b6654 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 @@ -184,15 +184,50 @@ protected: } }; -TEST_F(MediaQualityAnalyzerTest, TestStartStop) +TEST_F(MediaQualityAnalyzerTest, TestCodecType) { - EXPECT_CALL(mCallback, onEvent(kAudioCallQualityChangedInd, _, _)).Times(1); + EXPECT_CALL(mCallback, onEvent(kAudioCallQualityChangedInd, _, _)).Times(6); mAnalyzer->start(); + mAnalyzer->stop(); + EXPECT_EQ(CallQuality::AUDIO_QUALITY_AMR_WB, mFakeCallback.getCallQuality().getCodecType()); + + mConfig.setCodecType(AudioConfig::CODEC_AMR); + mAnalyzer->setConfig(&mConfig); + mAnalyzer->start(); + mAnalyzer->stop(); + EXPECT_EQ(CallQuality::AUDIO_QUALITY_AMR, mFakeCallback.getCallQuality().getCodecType()); - CallQuality quality = mAnalyzer->getCallQuality(); + mConfig.setCodecType(AudioConfig::CODEC_EVS); + mEvsParam.setEvsBandwidth(EvsParams::EVS_NARROW_BAND); + mConfig.setEvsParams(mEvsParam); + mAnalyzer->setConfig(&mConfig); + mAnalyzer->start(); + mAnalyzer->stop(); + EXPECT_EQ(CallQuality::AUDIO_QUALITY_EVS_NB, mFakeCallback.getCallQuality().getCodecType()); + + mConfig.setCodecType(AudioConfig::CODEC_EVS); + mEvsParam.setEvsBandwidth(EvsParams::EVS_WIDE_BAND); + mConfig.setEvsParams(mEvsParam); + mAnalyzer->setConfig(&mConfig); + mAnalyzer->start(); mAnalyzer->stop(); + EXPECT_EQ(CallQuality::AUDIO_QUALITY_EVS_WB, mFakeCallback.getCallQuality().getCodecType()); - EXPECT_EQ(mFakeCallback.getCallQuality(), quality); + mConfig.setCodecType(AudioConfig::CODEC_EVS); + mEvsParam.setEvsBandwidth(EvsParams::EVS_SUPER_WIDE_BAND); + mConfig.setEvsParams(mEvsParam); + mAnalyzer->setConfig(&mConfig); + mAnalyzer->start(); + mAnalyzer->stop(); + EXPECT_EQ(CallQuality::AUDIO_QUALITY_EVS_SWB, mFakeCallback.getCallQuality().getCodecType()); + + mConfig.setCodecType(AudioConfig::CODEC_EVS); + mEvsParam.setEvsBandwidth(EvsParams::EVS_FULL_BAND); + mConfig.setEvsParams(mEvsParam); + mAnalyzer->setConfig(&mConfig); + mAnalyzer->start(); + mAnalyzer->stop(); + EXPECT_EQ(CallQuality::AUDIO_QUALITY_EVS_FB, mFakeCallback.getCallQuality().getCodecType()); } TEST_F(MediaQualityAnalyzerTest, TestCollectTxPackets) @@ -212,7 +247,6 @@ TEST_F(MediaQualityAnalyzerTest, TestCollectTxPackets) EXPECT_EQ(mAnalyzer->getTxPacketSize(), numPackets); EXPECT_EQ(mAnalyzer->getRxPacketSize(), 0); EXPECT_EQ(mAnalyzer->getLostPacketSize(), 0); - CallQuality quality = mAnalyzer->getCallQuality(); mAnalyzer->stop(); EXPECT_EQ(mAnalyzer->getTxPacketSize(), 0); @@ -220,9 +254,7 @@ TEST_F(MediaQualityAnalyzerTest, TestCollectTxPackets) EXPECT_EQ(mAnalyzer->getLostPacketSize(), 0); // Check CallQuality value - CallQuality quality2 = mFakeCallback.getCallQuality(); - EXPECT_EQ(quality2, quality); - EXPECT_EQ(quality2.getNumRtpPacketsTransmitted(), numPackets); + EXPECT_EQ(mFakeCallback.getCallQuality().getNumRtpPacketsTransmitted(), numPackets); } TEST_F(MediaQualityAnalyzerTest, TestRtpInactivityNotRunning) @@ -302,14 +334,10 @@ TEST_F(MediaQualityAnalyzerTest, TestCallQualityInactivity) EXPECT_CALL(mCallback, onEvent(kAudioCallQualityChangedInd, _, _)).Times(2); mAnalyzer->start(); mCondition.wait_timeout(4100); // 4.1 sec - - CallQuality quality = mAnalyzer->getCallQuality(); mAnalyzer->stop(); // Check CallQuality value - CallQuality quality2 = mFakeCallback.getCallQuality(); - EXPECT_EQ(quality2, quality); - EXPECT_TRUE(quality2.getRtpInactivityDetected()); + EXPECT_TRUE(mFakeCallback.getCallQuality().getRtpInactivityDetected()); } TEST_F(MediaQualityAnalyzerTest, TestCallQualityLevelChanged) @@ -346,7 +374,6 @@ TEST_F(MediaQualityAnalyzerTest, TestCallQualityLevelChanged) EXPECT_EQ(mAnalyzer->getTxPacketSize(), 0); EXPECT_EQ(mAnalyzer->getRxPacketSize(), numPackets - 1); EXPECT_EQ(mAnalyzer->getLostPacketSize(), 1); - CallQuality quality = mAnalyzer->getCallQuality(); mAnalyzer->stop(); EXPECT_EQ(mAnalyzer->getTxPacketSize(), 0); @@ -354,10 +381,9 @@ TEST_F(MediaQualityAnalyzerTest, TestCallQualityLevelChanged) EXPECT_EQ(mAnalyzer->getLostPacketSize(), 0); // Check CallQuality value - CallQuality quality2 = mFakeCallback.getCallQuality(); - EXPECT_EQ(quality2, quality); - EXPECT_EQ(quality2.getNumRtpPacketsReceived(), numPackets - 1); - EXPECT_EQ(quality2.getDownlinkCallQualityLevel(), CallQuality::kCallQualityBad); + EXPECT_EQ(mFakeCallback.getCallQuality().getNumRtpPacketsReceived(), numPackets - 1); + EXPECT_EQ(mFakeCallback.getCallQuality().getDownlinkCallQualityLevel(), + CallQuality::kCallQualityBad); } TEST_F(MediaQualityAnalyzerTest, TestJitterInd) @@ -389,17 +415,14 @@ TEST_F(MediaQualityAnalyzerTest, TestJitterInd) EXPECT_EQ(mAnalyzer->getRxPacketSize(), numPackets); EXPECT_EQ(mAnalyzer->getLostPacketSize(), 0); - CallQuality quality = mAnalyzer->getCallQuality(); mAnalyzer->stop(); EXPECT_EQ(mAnalyzer->getTxPacketSize(), 0); EXPECT_EQ(mAnalyzer->getRxPacketSize(), 0); EXPECT_EQ(mAnalyzer->getLostPacketSize(), 0); - CallQuality quality2 = mFakeCallback.getCallQuality(); - EXPECT_EQ(quality2, quality); - EXPECT_EQ(quality2.getNumRtpPacketsReceived(), numPackets); - EXPECT_EQ(quality2.getAverageRelativeJitter(), jitter); + EXPECT_EQ(mFakeCallback.getCallQuality().getNumRtpPacketsReceived(), numPackets); + EXPECT_EQ(mFakeCallback.getCallQuality().getAverageRelativeJitter(), jitter); MediaQualityStatus status = mFakeCallback.getMediaQualityStatus(); EXPECT_EQ(status.getRtpJitterMillis(), jitter); @@ -433,6 +456,7 @@ TEST_F(MediaQualityAnalyzerTest, TestSsrcChange) EXPECT_EQ(mAnalyzer->getTxPacketSize(), 0); EXPECT_EQ(mAnalyzer->getRxPacketSize(), numPackets); EXPECT_EQ(mAnalyzer->getLostPacketSize(), 0); + mAnalyzer->stop(); EXPECT_EQ(mAnalyzer->getTxPacketSize(), 0); @@ -477,16 +501,13 @@ TEST_F(MediaQualityAnalyzerTest, TestPacketLossInd) EXPECT_EQ(mAnalyzer->getRxPacketSize(), numPackets - 1); EXPECT_EQ(mAnalyzer->getLostPacketSize(), 1); - CallQuality quality = mAnalyzer->getCallQuality(); mAnalyzer->stop(); EXPECT_EQ(mAnalyzer->getTxPacketSize(), 0); EXPECT_EQ(mAnalyzer->getRxPacketSize(), 0); EXPECT_EQ(mAnalyzer->getLostPacketSize(), 0); - CallQuality quality2 = mFakeCallback.getCallQuality(); - EXPECT_EQ(quality2, quality); - EXPECT_EQ(quality2.getNumRtpPacketsNotReceived(), 1); + EXPECT_EQ(mFakeCallback.getCallQuality().getNumRtpPacketsNotReceived(), 1); MediaQualityStatus status = mFakeCallback.getMediaQualityStatus(); EXPECT_EQ(status.getRtpPacketLossRate(), 10); @@ -502,6 +523,5 @@ TEST_F(MediaQualityAnalyzerTest, TestNotifyMediaQualityStatus) mAnalyzer->start(); mCondition.wait_timeout(2100); // 2.1 sec - mAnalyzer->stop(); }
\ No newline at end of file diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtpDecoderNodeTests.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtpDecoderNodeTests.cpp index dfa293e7..90c23056 100644 --- a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtpDecoderNodeTests.cpp +++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtpDecoderNodeTests.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2022 The Android Open Source Project + * 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. @@ -89,8 +89,15 @@ public: { dtmfDigit = 0; dtmfDuration = 0; + listExtensions = nullptr; + } + virtual ~FakeRtpDecoderCallback() + { + if (listExtensions != nullptr) + { + delete listExtensions; + } } - virtual ~FakeRtpDecoderCallback() {} virtual void onEvent(int32_t type, uint64_t param1, uint64_t param2) { if (type == kAudioDtmfReceivedInd) @@ -98,13 +105,24 @@ public: dtmfDigit = static_cast<uint8_t>(param1); dtmfDuration = static_cast<uint32_t>(param2); } + else if (type == kImsMediaEventHeaderExtensionReceived) + { + if (listExtensions != nullptr) + { + delete listExtensions; + } + + listExtensions = reinterpret_cast<std::list<RtpHeaderExtension>*>(param1); + } } uint8_t GetDtmfDigit() { return dtmfDigit; } uint32_t GetDtmfDuration() { return dtmfDuration; } + std::list<RtpHeaderExtension>* GetListExtension() { return listExtensions; } private: uint8_t dtmfDigit; uint32_t dtmfDuration; + std::list<RtpHeaderExtension>* listExtensions; }; class FakeRtpDecoderNode : public BaseNode @@ -370,6 +388,46 @@ TEST_F(RtpDecoderNodeTest, testAudioDtmfDataProcess) EXPECT_EQ(callback.GetDtmfDuration(), 100); } +TEST_F(RtpDecoderNodeTest, testAudioRtpExtension) +{ + setupAudioConfig(); + EXPECT_EQ(encoder->Start(), RESULT_SUCCESS); + EXPECT_EQ(decoder->Start(), RESULT_SUCCESS); + + // AMR mode 6 payload frame + uint8_t testFrame[] = {0x1c, 0x51, 0x06, 0x40, 0x32, 0xba, 0x8e, 0xc1, 0x25, 0x42, 0x2f, 0xc7, + 0xaf, 0x6e, 0xe0, 0xbb, 0xb2, 0x91, 0x09, 0xa5, 0xa6, 0x08, 0x18, 0x6f, 0x08, 0x1c, + 0x1c, 0x44, 0xd8, 0xe0, 0x48, 0x8c, 0x7c, 0xf8, 0x4c, 0x22, 0xd0}; + + const uint8_t testExtension1[] = {0xFF, 0xF2}; + const uint8_t testExtension2[] = {0xFF, 0xF2}; + + std::list<RtpHeaderExtension> listExtension; + + RtpHeaderExtension extension1; + extension1.setLocalIdentifier(1); + extension1.setExtensionData(testExtension1, 2); + listExtension.push_back(extension1); + + RtpHeaderExtension extension2; + extension2.setLocalIdentifier(2); + extension2.setExtensionData(testExtension2, 2); + listExtension.push_back(extension2); + + encoder->SetRtpHeaderExtension(&listExtension); + encoder->OnDataFromFrontNode(MEDIASUBTYPE_UNDEFINED, testFrame, sizeof(testFrame), 0, false, 0); + encoder->ProcessData(); + + std::list<RtpHeaderExtension>* receivedExtension = callback.GetListExtension(); + ASSERT_TRUE(receivedExtension != nullptr); + + for (auto& extension : *receivedExtension) + { + EXPECT_EQ(extension, listExtension.front()); + listExtension.pop_front(); + } +} + TEST_F(RtpDecoderNodeTest, startVideoAndUpdate) { setupVideoConfig(); diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/rtp/core/RtpPacketTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/rtp/core/RtpPacketTest.cpp index 17c758cb..319a2fe0 100644 --- a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/rtp/core/RtpPacketTest.cpp +++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/rtp/core/RtpPacketTest.cpp @@ -90,7 +90,7 @@ TEST(RtpPacketTest, TestDecodePacket) RtpBuffer* pobjRtpExtHdr = rtpPacket.getExtHeader(); ASSERT_TRUE(pobjRtpExtHdr != nullptr); - uint8_t pRtpExtHdr[] = {0x41, 0x78, 0x42, 0x00}; + uint8_t pRtpExtHdr[] = {0xbe, 0xde, 0x00, 0x01, 0x41, 0x78, 0x42, 0x00}; EXPECT_EQ(memcmp(pRtpExtHdr, pobjRtpExtHdr->getBuffer(), sizeof(pRtpExtHdr)), 0); EXPECT_EQ(pobjRtpExtHdr->getLength(), sizeof(pRtpExtHdr)); diff --git a/tests/unit/src/com/android/telephony/imsmedia/AudioListenerTest.java b/tests/unit/src/com/android/telephony/imsmedia/AudioListenerTest.java index a59a1646..353b6f7c 100644 --- a/tests/unit/src/com/android/telephony/imsmedia/AudioListenerTest.java +++ b/tests/unit/src/com/android/telephony/imsmedia/AudioListenerTest.java @@ -1,4 +1,4 @@ -/* +/** * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,6 +25,7 @@ import static org.mockito.Mockito.verify; import android.os.Parcel; import android.os.RemoteException; import android.telephony.CallQuality; +import android.telephony.ims.RtpHeaderExtension; import android.telephony.imsmedia.AudioConfig; import android.telephony.imsmedia.IImsAudioSessionCallback; import android.telephony.imsmedia.ImsMediaSession; @@ -39,6 +40,9 @@ 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 { private static final int SESSION_ID = 1; @@ -160,11 +164,21 @@ public class AudioListenerTest { @Test public void testEventRtpHeaderExtensionInd() throws RemoteException { - mAudioListener.onMessage(createParcel(AudioSession.EVENT_RTP_HEADER_EXTENSION_IND, - SESSION_ID, mAudioConfig)); + List<RtpHeaderExtension> extensions = new ArrayList<>(); + extensions.add(new RtpHeaderExtension(1, new byte[]{5})); + extensions.add(new RtpHeaderExtension(2, new byte[]{10})); + Parcel parcel = Parcel.obtain(); + parcel.writeInt(AudioSession.EVENT_RTP_HEADER_EXTENSION_IND); + parcel.writeInt(extensions.size()); + for (RtpHeaderExtension item : extensions) { + item.writeToParcel(parcel, 0); + } + parcel.setDataPosition(0); + mAudioListener.onMessage(parcel); + parcel.recycle(); processAllMessages(); verify(mMockIImsAudioSessionCallback, - times(1)).onHeaderExtensionReceived(any()); + times(1)).onHeaderExtensionReceived(eq(extensions)); } @Test |