blob: 38b59c39536f9612cf086a063e09bd041f371cf0 [file] [log] [blame]
/**
* Copyright (C) 2022 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 <AudioJitterBuffer.h>
#include <ImsMediaDataQueue.h>
#include <ImsMediaTimer.h>
#include <ImsMediaTrace.h>
#define AUDIO_JITTER_BUFFER_MIN_SIZE (3)
#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))
AudioJitterBuffer::AudioJitterBuffer()
{
mInitJitterBufferSize = AUDIO_JITTER_BUFFER_START_SIZE;
mMinJitterBufferSize = AUDIO_JITTER_BUFFER_MIN_SIZE;
mMaxJitterBufferSize = AUDIO_JITTER_BUFFER_MAX_SIZE;
AudioJitterBuffer::Reset();
mBufferIgnoreSIDPacket = false;
mBufferImprovement = false;
}
AudioJitterBuffer::~AudioJitterBuffer() {}
void AudioJitterBuffer::Reset()
{
mNextJitterBufferSize = mCurrJitterBufferSize;
mLastPlayedSeqNum = 0;
mLastPlayedTimestamp = 0;
mIsReceivedFirst = false;
mDtxOn = false;
mSIDCount = 0;
mWaiting = false;
mDeleteCount = 0;
mBaseTimestamp = 0;
mBaseArrivalTime = 0;
mUpdateJitterBufferSize = 0;
mCheckUpdateJitterPacketCnt = 0;
mFourceToUpdateJitterBuffer = false;
mNeedToUpdateBasePacket = false;
mCanNotGetCount = 0;
mNullDataCount = 0;
BaseJitterBuffer::Reset();
mJitterAnalyser.Reset();
mJitterAnalyser.SetMinMaxJitterBufferSize(mMinJitterBufferSize, mMaxJitterBufferSize);
mCurrPlayingSeq = 0;
mBufferUpdateDuration = 0;
}
void AudioJitterBuffer::SetJitterBufferSize(uint32_t nInit, uint32_t nMin, uint32_t nMax)
{
IMLOGD3("[SetJitterBufferSize] %02x, %02x, %02x", nInit, nMin, nMax);
if (nMin > 0)
{
mMinJitterBufferSize = nMin;
}
if (nMax > 0)
{
mMaxJitterBufferSize = nMax;
}
if (nInit > 0)
{
if (nInit < mMinJitterBufferSize)
{
nInit = mMinJitterBufferSize;
}
if (nInit > mMaxJitterBufferSize)
{
nInit = mMaxJitterBufferSize;
}
mInitJitterBufferSize = nInit;
mCurrJitterBufferSize = mInitJitterBufferSize;
mNextJitterBufferSize = mInitJitterBufferSize;
}
mJitterAnalyser.SetMinMaxJitterBufferSize(mMinJitterBufferSize, mMaxJitterBufferSize);
}
void AudioJitterBuffer::SetJitterOptions(
uint32_t nReduceTH, uint32_t nStepSize, double zValue, bool bIgnoreSID, bool bImprovement)
{
// do it later
mBufferIgnoreSIDPacket = bIgnoreSID;
mBufferImprovement = bImprovement;
mJitterAnalyser.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 arrivalTime)
{
(void)nDataType;
DataEntry currEntry = DataEntry();
currEntry.subtype = subtype;
currEntry.pbBuffer = pbBuffer;
currEntry.nBufferSize = nBufferSize;
currEntry.nTimestamp = nTimestamp;
currEntry.bMark = bMark;
currEntry.nSeqNum = nSeqNum;
currEntry.bHeader = true;
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)
{
if ((mCanNotGetCount > mMaxJitterBufferSize) && (mCanNotGetCount > mMinJitterBufferSize))
{
IMLOGD0("[Add] Refreshed");
CollectRxRtpStatus(nSeqNum, kRtpStatusDiscarded);
Reset();
}
}
int32_t jitter = 0;
if (mBufferIgnoreSIDPacket == false)
{
jitter = mJitterAnalyser.CalculateTransitTimeDifference(nTimestamp, arrivalTime);
mBaseTimestamp = currEntry.nTimestamp;
mBaseArrivalTime = currEntry.arrivalTime;
mJitterAnalyser.UpdateBaseTimestamp(mBaseTimestamp, mBaseArrivalTime);
}
// TODO: remove mBufferIgnoreSIDPacket logic and the statements
else if ((mBufferIgnoreSIDPacket == true) && !IsSID(currEntry.pbBuffer, currEntry.nBufferSize))
{
// first packet delay compensation
if ((mBaseTimestamp == 0 && mBaseArrivalTime == 0) || (mNeedToUpdateBasePacket == true))
{
mBaseTimestamp = currEntry.nTimestamp;
mBaseArrivalTime = currEntry.arrivalTime;
mJitterAnalyser.UpdateBaseTimestamp(mBaseTimestamp, mBaseArrivalTime);
mNeedToUpdateBasePacket = false;
}
else if (mBaseTimestamp > currEntry.nTimestamp || mBaseArrivalTime > currEntry.arrivalTime)
{
// rounding case (more consider case)
mBaseTimestamp = currEntry.nTimestamp;
mBaseArrivalTime = currEntry.arrivalTime;
mJitterAnalyser.UpdateBaseTimestamp(mBaseTimestamp, mBaseArrivalTime);
}
else
{
// update case
if (currEntry.nTimestamp - mBaseTimestamp > currEntry.arrivalTime - mBaseArrivalTime)
{
mBaseTimestamp = currEntry.nTimestamp;
mBaseArrivalTime = currEntry.arrivalTime;
mJitterAnalyser.UpdateBaseTimestamp(mBaseTimestamp, mBaseArrivalTime);
}
else
{ // compensation case
uint32_t temp = currEntry.arrivalTime;
IMLOGD_PACKET2(IM_PACKET_LOG_JITTER, "Before compensation[%u], nSeqNum[%d]", temp,
currEntry.nSeqNum);
currEntry.arrivalTime = mBaseArrivalTime + (currEntry.nTimestamp - mBaseTimestamp);
IMLOGD_PACKET2(IM_PACKET_LOG_JITTER, "After compensation[%u], delay[%u]",
currEntry.arrivalTime, temp - currEntry.arrivalTime);
}
}
jitter = mJitterAnalyser.CalculateTransitTimeDifference(nTimestamp, arrivalTime);
}
RtpPacket* packet = new RtpPacket();
if (nBufferSize == 0)
{
packet->rtpDataType = kRtpDataTypeNoData;
}
else
{
IsSID(currEntry.pbBuffer, currEntry.nBufferSize) ? packet->rtpDataType = kRtpDataTypeSid
: packet->rtpDataType = kRtpDataTypeNormal;
}
packet->ssrc = mSsrc;
packet->seqNum = nSeqNum;
packet->jitter = jitter;
packet->arrival = ImsMediaTimer::GetTimeInMilliSeconds();
mCallback->SendEvent(kCollectPacketInfo, kStreamRtpRx, reinterpret_cast<uint64_t>(packet));
if (nBufferSize == 0)
{
return;
}
std::lock_guard<std::mutex> guard(mMutex);
IMLOGD_PACKET7(IM_PACKET_LOG_JITTER,
"[Add] seq[%d], bMark[%d], TS[%d], size[%d] subtype[%d] queueSize[%d], arrivalTime[%u]",
nSeqNum, bMark, nTimestamp, nBufferSize, subtype, mDataQueue.GetCount() + 1,
arrivalTime);
if (mDataQueue.GetCount() == 0)
{ // jitter buffer is empty
mDataQueue.Add(&currEntry);
}
else
{
DataEntry* pEntry;
mDataQueue.GetLast(&pEntry);
if (pEntry == nullptr)
{
return;
}
// current data is the latest data
if (USHORT_SEQ_ROUND_COMPARE(nSeqNum, pEntry->nSeqNum))
{
mDataQueue.Add(&currEntry);
}
else
{
// find the position of current data and insert current data to the correct position
mDataQueue.SetReadPosFirst();
for (int32_t i = 0; mDataQueue.GetNext(&pEntry); i++)
{
// late arrival packet
if (!USHORT_SEQ_ROUND_COMPARE(nSeqNum, pEntry->nSeqNum))
{
mDataQueue.InsertAt(i, &currEntry);
break;
}
}
}
}
}
bool AudioJitterBuffer::Get(ImsMediaSubType* psubtype, uint8_t** ppData, uint32_t* pnDataSize,
uint32_t* pnTimestamp, bool* pbMark, uint32_t* pnSeqNum, uint32_t* pnChecker)
{
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)
{
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;
}
}
// set current jitter buffer size
// when dtx occur, calculate nextJitterBufferSize.
if (mBufferImprovement == false)
{
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;
}
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;
}
// Wait case
if (bWait)
{
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);
}
if (mDataQueue.GetCount() == 0 ||
((mDataQueue.Get(&pEntry) &&
(ImsMediaTimer::GetTimeInMilliSeconds() - pEntry->arrivalTime) <
((mCurrJitterBufferSize - 1) * 20 + 10)) &&
(mDataQueue.GetCount() <= mCurrJitterBufferSize)))
{
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;
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");
}
return false;
}
// 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)))
{
IMLOGD_PACKET0(IM_PACKET_LOG_JITTER, "[Get] CurrPlaying nTimestamp Reset!");
mCurrPlayingTS = pEntry->nTimestamp;
mCurrPlayingSeq = pEntry->nSeqNum;
}
// delete very old data
while (mDataQueue.GetCount() > 0)
{
mDataQueue.Get(&pEntry);
if (pEntry == nullptr)
{
return false;
}
if (mDeleteCount > 4 && mDataQueue.GetCount() < mCurrJitterBufferSize + 1)
{
IMLOGD0("[Get] Resync");
if (mBufferImprovement == false)
{
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;
}
}
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;
}
}
mNeedToUpdateBasePacket = true;
mDeleteCount = 0;
break;
}
if (USHORT_TS_ROUND_COMPARE(pEntry->nTimestamp, mCurrPlayingTS) == false)
{
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");
}
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;
}
}
// decrease jitter buffer
if (mDtxOn && mSIDCount > 4 && mDataQueue.GetCount() > mCurrJitterBufferSize)
{
mDataQueue.Get(&pEntry);
if (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]",
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);
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))
{
IMLOGD4("[Get] TS changing case [ %d / %u / %u / %d ]", pEntry->nSeqNum, pEntry->nTimestamp,
mCurrPlayingTS, mDataQueue.GetCount());
bForceToPlay = true;
}
if (mFourceToUpdateJitterBuffer == true)
{
// removing delete packet in min JitterBuffer size
if (mDataQueue.GetCount() > mCurrJitterBufferSize + 1)
{
mDataQueue.Get(&pEntry);
if (pEntry)
{
IMLOGD_PACKET5(IM_PACKET_LOG_JITTER,
"[Get] Delete Packets - seq[%d], bMark[%d], nTS[%d], curTS[%d], size[%d]",
pEntry->nSeqNum, pEntry->bMark, pEntry->nTimestamp, mCurrPlayingTS,
mDataQueue.GetCount());
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");
}
if (mDtxOn == true)
{
CollectRxRtpStatus(pEntry->nSeqNum, kRtpStatusNormal);
CollectJitterBufferStatus(
mCurrJitterBufferSize * 20, mMaxJitterBufferSize * 20);
}
else
{
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);
if (nTimediff > 0)
{
mCurrPlayingTS -= nTimediff;
mCurrPlayingSeq -= nTimediff / 20;
IMLOGD1("[Get] increase queue size [%d]", nTimediff / 20);
}
}
// reset
mFourceToUpdateJitterBuffer = false;
mUpdateJitterBufferSize = 0;
}
else
{
mFourceToUpdateJitterBuffer = false;
mUpdateJitterBufferSize = 0;
if ((mDataQueue.GetCount() < 2) ||
(mDataQueue.GetCount() < mCurrJitterBufferSize - mMinJitterBufferSize))
{
IMLOGD_PACKET0(IM_PACKET_LOG_JITTER, "[Get] increase packet");
return false;
}
}
}
// get data and check the duplication
if (mDataQueue.Get(&pEntry) && pEntry->nSeqNum == mLastPlayedSeqNum)
{
IMLOGD_PACKET6(IM_PACKET_LOG_JITTER,
"[Get] duplicate - curTS[%d], seq[%d], Mark[%d], TS[%d], buffer[%d], size[%d]",
mCurrPlayingTS, pEntry->nSeqNum, pEntry->bMark, pEntry->nTimestamp,
pEntry->nBufferSize, mDataQueue.GetCount());
CollectRxRtpStatus(pEntry->nSeqNum, kRtpStatusDuplicated);
mDataQueue.Delete();
mDeleteCount++;
}
if (mDataQueue.Get(&pEntry) && pEntry != nullptr &&
(pEntry->nTimestamp == mCurrPlayingTS || bForceToPlay ||
(pEntry->nTimestamp < TS_ROUND_QUARD && mCurrPlayingTS > 0xFFFF)))
{
if (psubtype)
*psubtype = pEntry->subtype;
if (ppData)
*ppData = pEntry->pbBuffer;
if (pnDataSize)
*pnDataSize = pEntry->nBufferSize;
if (pnTimestamp)
*pnTimestamp = pEntry->nTimestamp;
if (pbMark)
*pbMark = pEntry->bMark;
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)
{
/** Report the loss gap if the loss gap is over 0 */
uint16_t lostGap = GET_SEQ_GAP(pEntry->nSeqNum, mLastPlayedSeqNum);
if (lostGap > 1)
{
uint16_t lostSeq = mLastPlayedSeqNum + 1;
SessionCallbackParameter* param =
new SessionCallbackParameter(kReportPacketLossGap, lostSeq, lostGap - 1);
mCallback->SendEvent(kCollectOptionalInfo, reinterpret_cast<uint64_t>(param), 0);
}
}
mLastPlayedSeqNum = pEntry->nSeqNum;
mCanNotGetCount = 0;
CollectRxRtpStatus(pEntry->nSeqNum, kRtpStatusNormal);
CollectJitterBufferStatus(mCurrJitterBufferSize * 20, mMaxJitterBufferSize * 20);
return true;
}
else
{
// TODO: check EVS redundancy in channel aware mode
if (mDtxOn == false)
{
mCanNotGetCount++;
}
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;
IMLOGD_PACKET2(IM_PACKET_LOG_JITTER, "[Get] fail - dtx mode[%d], curTS[%d]", mDtxOn,
mCurrPlayingTS);
mCurrPlayingTS += 20;
mCurrPlayingSeq += 1;
return false;
}
return false;
}
bool AudioJitterBuffer::IsSID(uint8_t* pbBuffer, uint32_t nBufferSize)
{
// remove warning
(void)pbBuffer;
switch (mCodecType)
{
case kAudioCodecAmr:
case kAudioCodecAmrWb:
if (nBufferSize == 5)
return true;
else
return false;
case kAudioCodecEvs:
if ((nBufferSize == 6) || (nBufferSize == 5))
return true;
else
return false;
case kAudioCodecPcmu:
case kAudioCodecPcma:
return false;
default:
IMLOGE1("[IsSID] DTX detect method is not defined for[%u] codec", mCodecType);
return false;
}
}
void AudioJitterBuffer::CollectRxRtpStatus(int32_t seq, kRtpPacketStatus status)
{
IMLOGD_PACKET2(IM_PACKET_LOG_JITTER, "[CollectRxRtpStatus] seq[%d], status[%d]", seq, status);
if (mCallback != nullptr)
{
SessionCallbackParameter* param =
new SessionCallbackParameter(seq, status, ImsMediaTimer::GetTimeInMilliSeconds());
mCallback->SendEvent(kCollectRxRtpStatus, reinterpret_cast<uint64_t>(param));
}
}
void AudioJitterBuffer::CollectJitterBufferStatus(int32_t currSize, int32_t maxSize)
{
IMLOGD_PACKET2(IM_PACKET_LOG_JITTER, "[CollectJitterBufferStatus] currSize[%d], maxSize[%d]",
currSize, maxSize);
if (mCallback != nullptr)
{
mCallback->SendEvent(kCollectJitterBufferSize, currSize, maxSize);
}
}