• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <AudioJitterBuffer.h>
18 #include <ImsMediaAudioUtil.h>
19 #include <ImsMediaDataQueue.h>
20 #include <ImsMediaTimer.h>
21 #include <ImsMediaTrace.h>
22 #include <numeric>
23 
24 #define AUDIO_JITTER_BUFFER_MIN_SIZE    (3)
25 #define AUDIO_JITTER_BUFFER_MAX_SIZE    (9)
26 #define AUDIO_JITTER_BUFFER_START_SIZE  (4)
27 #define GET_SEQ_GAP(a, b)               ((uint16_t)(a) - (uint16_t)(b))
28 #define JITTER_BUFFER_UPDATE_INTERVAL   (100)   // ms unit
29 #define FRAME_INTERVAL                  (20)    // ms unit
30 #define ALLOWABLE_ERROR                 (10)    // ms unit
31 #define RESET_THRESHOLD_IN_DTX_ENABLED  (80)    // percentage
32 #define RESET_THRESHOLD_IN_DTX_DISABLED (35)    // percentage
33 #define TS_ROUND_QUARD                  (3000)  // ms unit
34 #define SEQ_OUTLIER_THRESHOLD           (3000)
35 #define USHORT_TS_ROUND_COMPARE(a, b)                                                   \
36     ((((a) >= (b)) && (((b) >= TS_ROUND_QUARD) || ((a) <= 0xffff - TS_ROUND_QUARD))) || \
37             (((a) <= TS_ROUND_QUARD) && ((b) >= 0xffff - TS_ROUND_QUARD)))
38 
39 #define MAX_STORED_BUFFER_SIZE (50 * 60 * 60)  // 1 hour in frame interval unit
40 #define MAX_QUEUE_SIZE         (150)           // 3 sec
41 #define DROP_WINDOW            (5000)          // 5 ec
42 
AudioJitterBuffer()43 AudioJitterBuffer::AudioJitterBuffer()
44 {
45     mInitJitterBufferSize = AUDIO_JITTER_BUFFER_START_SIZE;
46     mMinJitterBufferSize = AUDIO_JITTER_BUFFER_MIN_SIZE;
47     mMaxJitterBufferSize = AUDIO_JITTER_BUFFER_MAX_SIZE;
48     mJitterAnalyzer.Reset();
49     mJitterAnalyzer.SetMinMaxJitterBufferSize(mMinJitterBufferSize, mMaxJitterBufferSize);
50     mListJitterBufferSize.clear();
51     mEvsRedundantFrameOffset = -1;
52     AudioJitterBuffer::Reset();
53 }
54 
~AudioJitterBuffer()55 AudioJitterBuffer::~AudioJitterBuffer()
56 {
57     AudioJitterBuffer::ClearBuffer();
58 }
59 
Reset()60 void AudioJitterBuffer::Reset()
61 {
62     IMLOGD0("[Reset]");
63     mLastPlayedSeqNum = 0;
64     mLastPlayedTimestamp = 0;
65     mFirstFrameReceived = false;
66     mNextJitterBufferSize = mCurrJitterBufferSize;
67     mDtxPlayed = false;
68     mDtxReceived = false;
69     mWaiting = true;
70     mUpdatedDelay = 0;
71     mCheckUpdateJitterPacketCnt = 0;
72     mPreservedDtx = nullptr;
73     mPrevGetTime = 0;
74     mListVoiceFrames.clear();
75     mListDropVoiceFrames.clear();
76 }
77 
ClearBuffer()78 void AudioJitterBuffer::ClearBuffer()
79 {
80     IMLOGD0("[ClearBuffer]");
81     std::lock_guard<std::mutex> guard(mMutex);
82     DataEntry* entry = nullptr;
83 
84     while (mDataQueue.Get(&entry))
85     {
86         if (entry->eDataType != MEDIASUBTYPE_AUDIO_SID)
87         {
88             CollectRxRtpStatus(entry->nSeqNum, kRtpStatusDiscarded);
89         }
90 
91         mDataQueue.Delete();
92     }
93 }
94 
SetJitterBufferSize(uint32_t nInit,uint32_t nMin,uint32_t nMax)95 void AudioJitterBuffer::SetJitterBufferSize(uint32_t nInit, uint32_t nMin, uint32_t nMax)
96 {
97     IMLOGD3("[SetJitterBufferSize] %d, %d, %d", nInit, nMin, nMax);
98 
99     if (nMin > 0)
100     {
101         mMinJitterBufferSize = nMin;
102     }
103 
104     if (nMax > 0)
105     {
106         mMaxJitterBufferSize = nMax;
107     }
108 
109     if (nInit > 0)
110     {
111         if (nInit < mMinJitterBufferSize)
112         {
113             nInit = mMinJitterBufferSize;
114         }
115 
116         if (nInit > mMaxJitterBufferSize)
117         {
118             nInit = mMaxJitterBufferSize;
119         }
120 
121         mInitJitterBufferSize = nInit;
122         mCurrJitterBufferSize = mInitJitterBufferSize;
123         mNextJitterBufferSize = mInitJitterBufferSize;
124     }
125 
126     mJitterAnalyzer.SetMinMaxJitterBufferSize(mMinJitterBufferSize, mMaxJitterBufferSize);
127 }
128 
SetJitterOptions(uint32_t incThreshold,uint32_t decThreshold,uint32_t stepSize,double zValue)129 void AudioJitterBuffer::SetJitterOptions(
130         uint32_t incThreshold, uint32_t decThreshold, uint32_t stepSize, double zValue)
131 {
132     mJitterAnalyzer.SetJitterOptions(incThreshold, decThreshold, stepSize, zValue);
133 }
134 
SetEvsRedundantFrameOffset(const int32_t offset)135 void AudioJitterBuffer::SetEvsRedundantFrameOffset(const int32_t offset)
136 {
137     IMLOGD1("[SetEvsRedundantFrameOffset] offset[%d]", offset);
138     mEvsRedundantFrameOffset = offset;
139 }
140 
Add(ImsMediaSubType subtype,uint8_t * pbBuffer,uint32_t nBufferSize,uint32_t nTimestamp,bool bMark,uint32_t nSeqNum,ImsMediaSubType nDataType,uint32_t arrivalTime)141 void AudioJitterBuffer::Add(ImsMediaSubType subtype, uint8_t* pbBuffer, uint32_t nBufferSize,
142         uint32_t nTimestamp, bool bMark, uint32_t nSeqNum, ImsMediaSubType nDataType,
143         uint32_t arrivalTime)
144 {
145     DataEntry currEntry = DataEntry();
146     currEntry.subtype = subtype;
147     currEntry.pbBuffer = pbBuffer;
148     currEntry.nBufferSize = nBufferSize;
149     currEntry.nTimestamp = nTimestamp;
150     currEntry.bMark = bMark;
151     currEntry.nSeqNum = nSeqNum;
152     currEntry.bHeader = true;
153     currEntry.bValid = true;
154     currEntry.arrivalTime = arrivalTime;
155     currEntry.eDataType = nDataType;
156 
157     if (subtype == MEDIASUBTYPE_REFRESHED)
158     {
159         // nBufferSize is ssrc value
160         mSsrc = nBufferSize;
161         mTimeStarted = ImsMediaTimer::GetTimeInMilliSeconds();
162         mJitterAnalyzer.Reset();
163         mDataQueue.Add(&currEntry);
164 
165         IMLOGI2("[Add] ssrc[%u], startTime[%d]", mSsrc, mTimeStarted);
166         return;
167     }
168 
169     if (currEntry.eDataType == MEDIASUBTYPE_AUDIO_SID)
170     {
171         mDtxReceived = true;
172     }
173 
174     int32_t jitter = mJitterAnalyzer.CalculateTransitTimeDifference(nTimestamp, arrivalTime);
175 
176     RtpPacket* packet = new RtpPacket();
177 
178     switch (currEntry.eDataType)
179     {
180         case MEDIASUBTYPE_AUDIO_SID:
181             packet->rtpDataType = kRtpDataTypeSid;
182             break;
183         default:
184         case MEDIASUBTYPE_AUDIO_NODATA:
185             packet->rtpDataType = kRtpDataTypeNoData;
186             break;
187         case MEDIASUBTYPE_AUDIO_NORMAL:
188             packet->rtpDataType = kRtpDataTypeNormal;
189             break;
190     }
191 
192     packet->ssrc = mSsrc;
193     packet->seqNum = nSeqNum;
194     packet->jitter = jitter;
195     packet->arrival = arrivalTime;
196     mCallback->SendEvent(kCollectPacketInfo, kStreamRtpRx, reinterpret_cast<uint64_t>(packet));
197 
198     std::lock_guard<std::mutex> guard(mMutex);
199 
200     IMLOGD_PACKET8(IM_PACKET_LOG_JITTER,
201             "[Add] seq[%d], mark[%d], TS[%d], size[%d], jitter[%d], queue[%d], playingDiff[%d], "
202             "arrival[%d]",
203             nSeqNum, bMark, nTimestamp, nBufferSize, jitter, mDataQueue.GetCount() + 1,
204             mCurrPlayingTS - nTimestamp, arrivalTime);
205 
206     if (mDataQueue.GetCount() == 0)
207     {  // jitter buffer is empty
208         mDataQueue.Add(&currEntry);
209     }
210     else
211     {
212         DataEntry* pEntry;
213         mDataQueue.GetLast(&pEntry);
214 
215         if (pEntry == nullptr)
216         {
217             return;
218         }
219 
220         // current data is the latest data
221         if (USHORT_SEQ_ROUND_COMPARE(nSeqNum, pEntry->nSeqNum))
222         {
223             mDataQueue.Add(&currEntry);
224         }
225         else
226         {
227             // find the position of current data and insert current data to the correct position
228             mDataQueue.SetReadPosFirst();
229 
230             for (int32_t i = 0; mDataQueue.GetNext(&pEntry); i++)
231             {
232                 // late arrival packet
233                 if (!USHORT_SEQ_ROUND_COMPARE(nSeqNum, pEntry->nSeqNum))
234                 {
235                     mDataQueue.InsertAt(i, &currEntry);
236                     break;
237                 }
238             }
239         }
240     }
241 
242     if (currEntry.eDataType != MEDIASUBTYPE_AUDIO_SID)
243     {
244         mListVoiceFrames.push_back(arrivalTime);
245 
246         // keep the list 3 times of the drop window
247         if (mListVoiceFrames.size() > DROP_WINDOW * 3 / FRAME_INTERVAL)
248         {
249             mListVoiceFrames.pop_front();
250         }
251     }
252 }
253 
Get(ImsMediaSubType * psubtype,uint8_t ** ppData,uint32_t * pnDataSize,uint32_t * pnTimestamp,bool * pbMark,uint32_t * pnSeqNum,uint32_t currentTime,ImsMediaSubType * pDataType)254 bool AudioJitterBuffer::Get(ImsMediaSubType* psubtype, uint8_t** ppData, uint32_t* pnDataSize,
255         uint32_t* pnTimestamp, bool* pbMark, uint32_t* pnSeqNum, uint32_t currentTime,
256         ImsMediaSubType* pDataType)
257 {
258     std::lock_guard<std::mutex> guard(mMutex);
259 
260     if (mPrevGetTime == 0)
261     {
262         mPrevGetTime = currentTime;
263     }
264     else
265     {
266         IMLOGD_PACKET1(IM_PACKET_LOG_JITTER, "[Get] time diff[%d]", currentTime - mPrevGetTime);
267         mPrevGetTime = currentTime;
268     }
269 
270     DataEntry* pEntry = nullptr;
271     bool bForceToPlay = false;
272     mCheckUpdateJitterPacketCnt++;
273 
274     if (mDataQueue.Get(&pEntry) && pEntry->subtype == MEDIASUBTYPE_REFRESHED)  // ssrc changed
275     {
276         Reset();
277         mDataQueue.Delete();  // delete indication frame of ssrc
278 
279         if (!mWaiting && mDataQueue.Get(&pEntry))  // get next frame
280         {
281             mCurrPlayingTS = pEntry->nTimestamp;  // play directly
282             mWaiting = false;
283         }
284     }
285 
286     // update jitter buffer size
287     if (!mWaiting && mUpdatedDelay == 0 &&
288             ((mDtxPlayed && mDataQueue.Get(&pEntry) &&
289                      pEntry->eDataType != MEDIASUBTYPE_AUDIO_SID) ||
290                     mCheckUpdateJitterPacketCnt * FRAME_INTERVAL > JITTER_BUFFER_UPDATE_INTERVAL))
291     {
292         uint32_t nextJitterBufferSize =
293                 mJitterAnalyzer.GetNextJitterBufferSize(mCurrJitterBufferSize, currentTime);
294         mCheckUpdateJitterPacketCnt = 0;
295         mUpdatedDelay = nextJitterBufferSize - mCurrJitterBufferSize;
296 
297         if (mDataQueue.GetCount() < mMinJitterBufferSize && mUpdatedDelay < 0)
298         {
299             IMLOGD_PACKET1(
300                     IM_PACKET_LOG_JITTER, "[Get] ignore decrease[%d]", mDataQueue.GetCount());
301             mUpdatedDelay = 0;
302         }
303         else
304         {
305             mCurrJitterBufferSize = nextJitterBufferSize;
306         }
307     }
308 
309     // increase delay
310     if (!mWaiting && mDtxPlayed && mUpdatedDelay > 0)
311     {
312         IMLOGD2("[Get] increase delay[%d], curTS[%d]", mUpdatedDelay, mCurrPlayingTS);
313         mUpdatedDelay--;
314         return false;
315     }
316 
317     // decrease delay
318     if (!mWaiting && mDataQueue.Get(&pEntry) && pEntry->eDataType == MEDIASUBTYPE_AUDIO_SID &&
319             mUpdatedDelay < 0)
320     {
321         IMLOGD3("[Get] decrease delay[%d], curTS[%u], queue[%u]", mUpdatedDelay, mCurrPlayingTS,
322                 mDataQueue.GetCount());
323         mUpdatedDelay++;
324         mCurrPlayingTS += FRAME_INTERVAL;
325     }
326 
327     int32_t dropRate = GetDropVoiceRateInDuration(DROP_WINDOW, currentTime);
328 
329     // resync the jitter buffer
330     if ((dropRate > RESET_THRESHOLD_IN_DTX_ENABLED && mDtxReceived) ||
331             (dropRate > RESET_THRESHOLD_IN_DTX_DISABLED && !mDtxReceived))
332     {
333         if (mCurrJitterBufferSize == mMaxJitterBufferSize)
334         {
335             IMLOGD1("[Get] resync, drop rate[%u]", dropRate);
336             mWaiting = true;
337             mTimeStarted = currentTime;
338         }
339         else
340         {
341             IMLOGD1("[Get] increase delay by drop rate[%u]", dropRate);
342             mCurrPlayingTS -= FRAME_INTERVAL;
343             mCurrJitterBufferSize++;
344         }
345 
346         mListDropVoiceFrames.clear();
347     }
348 
349     if (mDataQueue.GetCount() == 0)
350     {
351         IMLOGD_PACKET1(IM_PACKET_LOG_JITTER, "[Get] fail - empty, curTS[%u]", mCurrPlayingTS);
352 
353         if (!mWaiting)
354         {
355             mCurrPlayingTS += FRAME_INTERVAL;
356         }
357 
358         return false;
359     }
360     else if (mDataQueue.Get(&pEntry) && mWaiting)
361     {
362         if (currentTime - mTimeStarted < mInitJitterBufferSize * FRAME_INTERVAL)
363         {
364             if (psubtype)
365                 *psubtype = MEDIASUBTYPE_UNDEFINED;
366             if (ppData)
367                 *ppData = nullptr;
368             if (pnDataSize)
369                 *pnDataSize = 0;
370             if (pnTimestamp)
371                 *pnTimestamp = 0;
372             if (pbMark)
373                 *pbMark = false;
374             if (pnSeqNum)
375                 *pnSeqNum = 0;
376             if (pDataType)
377                 *pDataType = MEDIASUBTYPE_UNDEFINED;
378 
379             IMLOGD_PACKET4(IM_PACKET_LOG_JITTER,
380                     "[Get] Wait - seq[%u], CurrJBSize[%u], delay[%u], QueueCount[%u]",
381                     pEntry->nSeqNum, mCurrJitterBufferSize, currentTime - pEntry->arrivalTime,
382                     GetCount());
383             return false;
384         }
385         else
386         {
387             // resync when the audio frame stacked over the current jitter buffer size
388             Resync(mInitJitterBufferSize + 1);
389             mWaiting = false;
390         }
391     }
392 
393     mListJitterBufferSize.push_back(mCurrJitterBufferSize);
394 
395     if (mListJitterBufferSize.size() > MAX_STORED_BUFFER_SIZE)  // 1hour
396     {
397         mListJitterBufferSize.pop_front();
398     }
399 
400     // discard duplicated packet
401     if (mDataQueue.Get(&pEntry) && mFirstFrameReceived && pEntry->nSeqNum == mLastPlayedSeqNum)
402     {
403         IMLOGD6("[Get] duplicate - curTS[%u], seq[%d], mark[%d], TS[%u], size[%d], queue[%d]",
404                 mCurrPlayingTS, pEntry->nSeqNum, pEntry->bMark, pEntry->nTimestamp,
405                 pEntry->nBufferSize, mDataQueue.GetCount());
406         CollectRxRtpStatus(pEntry->nSeqNum, kRtpStatusDuplicated);
407         mDataQueue.Delete();
408     }
409 
410     if (currentTime - mTimeStarted < 3000)
411     {
412         // resync when the audio frame stacked over the max jitter buffer size
413         Resync(mMaxJitterBufferSize);
414     }
415     else
416     {
417         Resync(MAX_QUEUE_SIZE);
418     }
419 
420     // adjust the playing timestamp
421     if (mDataQueue.Get(&pEntry) && pEntry->nTimestamp != mCurrPlayingTS &&
422             ((mCurrPlayingTS - ALLOWABLE_ERROR) < pEntry->nTimestamp) &&
423             (pEntry->nTimestamp < (mCurrPlayingTS + ALLOWABLE_ERROR)))
424     {
425         mCurrPlayingTS = pEntry->nTimestamp;
426         IMLOGD2("[Get] sync playing curTS[%u], seq[%d]", mCurrPlayingTS, pEntry->nSeqNum);
427     }
428 
429     // delete late arrival
430     while (mDataQueue.Get(&pEntry) && !USHORT_TS_ROUND_COMPARE(pEntry->nTimestamp, mCurrPlayingTS))
431     {
432         mDtxPlayed = (pEntry->eDataType == MEDIASUBTYPE_AUDIO_SID);
433 
434         // discard case that latest packet is about to cut by the jitter then update the
435         // sequence number to avoid incorrect lost counting
436         if (pEntry->nSeqNum >= mLastPlayedSeqNum)
437         {
438             CountLostFrames(pEntry->nSeqNum, mLastPlayedSeqNum);
439             mLastPlayedSeqNum = pEntry->nSeqNum;
440         }
441 
442         IMLOGD_PACKET3(IM_PACKET_LOG_JITTER,
443                 "[Get] delete late arrival seq[%d], curTS[%u], dtx[%d]", pEntry->nSeqNum,
444                 mCurrPlayingTS, mDtxPlayed);
445 
446         if (mPreservedDtx != nullptr)
447         {
448             delete mPreservedDtx;
449         }
450 
451         mPreservedDtx = nullptr;
452 
453         if (mDtxPlayed)
454         {
455             mPreservedDtx = new DataEntry(*pEntry);
456         }
457         else
458         {
459             CollectRxRtpStatus(pEntry->nSeqNum, kRtpStatusLate);
460             mListDropVoiceFrames.push_back(currentTime);
461 
462             // keep the list 3 times of the drop window
463             if (mListDropVoiceFrames.size() > DROP_WINDOW * 3 / FRAME_INTERVAL)
464             {
465                 mListDropVoiceFrames.pop_front();
466             }
467         }
468 
469         mJitterAnalyzer.SetLateArrivals(currentTime);
470         mDataQueue.Delete();
471     }
472 
473     // add condition in case of changing Seq# & TS
474     if (mDataQueue.Get(&pEntry) && (pEntry->nTimestamp - mCurrPlayingTS) > TS_ROUND_QUARD)
475     {
476         IMLOGD4("[Get] TS changing case, enforce play [ %d / %u / %u / %d ]", pEntry->nSeqNum,
477                 pEntry->nTimestamp, mCurrPlayingTS, mDataQueue.GetCount());
478         bForceToPlay = true;
479     }
480 
481     if (mDataQueue.Get(&pEntry) &&
482             (pEntry->nTimestamp == mCurrPlayingTS || bForceToPlay ||
483                     (pEntry->nTimestamp < TS_ROUND_QUARD && mCurrPlayingTS > 0xFFFF)))
484     {
485         if (psubtype)
486             *psubtype = pEntry->subtype;
487         if (ppData)
488             *ppData = pEntry->pbBuffer;
489         if (pnDataSize)
490             *pnDataSize = pEntry->nBufferSize;
491         if (pnTimestamp)
492             *pnTimestamp = pEntry->nTimestamp;
493         if (pbMark)
494             *pbMark = pEntry->bMark;
495         if (pnSeqNum)
496             *pnSeqNum = pEntry->nSeqNum;
497         if (pDataType)
498             *pDataType = pEntry->eDataType;
499 
500         mDtxPlayed = (pEntry->eDataType == MEDIASUBTYPE_AUDIO_SID);
501 
502         if (mFirstFrameReceived)
503         {
504             CountLostFrames(pEntry->nSeqNum, mLastPlayedSeqNum);
505         }
506 
507         IMLOGD_PACKET7(IM_PACKET_LOG_JITTER,
508                 "[Get] OK - dtx[%d], curTS[%u], seq[%u], TS[%u], size[%u], delay[%u], queue[%u]",
509                 mDtxPlayed, mCurrPlayingTS, pEntry->nSeqNum, pEntry->nTimestamp,
510                 pEntry->nBufferSize, currentTime - pEntry->arrivalTime, mDataQueue.GetCount());
511 
512         mCurrPlayingTS = pEntry->nTimestamp + FRAME_INTERVAL;
513         mFirstFrameReceived = true;
514         mLastPlayedSeqNum = pEntry->nSeqNum;
515         CollectRxRtpStatus(pEntry->nSeqNum, kRtpStatusNormal);
516         CollectJitterBufferStatus(
517                 mCurrJitterBufferSize * FRAME_INTERVAL, mMaxJitterBufferSize * FRAME_INTERVAL);
518 
519         if (mPreservedDtx != nullptr)
520         {
521             delete mPreservedDtx;
522             mPreservedDtx = nullptr;
523         }
524 
525         return true;
526     }
527     else
528     {
529         // use the preserved dtx when it is discarded as late arrival
530         if (mPreservedDtx != nullptr)
531         {
532             // push front the preserved dtx to the queue
533             mDataQueue.InsertAt(0, mPreservedDtx);
534             delete mPreservedDtx;
535             mPreservedDtx = nullptr;
536 
537             mDataQueue.Get(&pEntry);
538 
539             if (psubtype)
540                 *psubtype = pEntry->subtype;
541             if (ppData)
542                 *ppData = pEntry->pbBuffer;
543             if (pnDataSize)
544                 *pnDataSize = pEntry->nBufferSize;
545             if (pnTimestamp)
546                 *pnTimestamp = mCurrPlayingTS;
547             if (pbMark)
548                 *pbMark = pEntry->bMark;
549             if (pnSeqNum)
550                 *pnSeqNum = pEntry->nSeqNum;
551             if (pDataType)
552                 *pDataType = pEntry->eDataType;
553 
554             IMLOGD_PACKET3(IM_PACKET_LOG_JITTER,
555                     "[Get] preserved frame, dtx[%d], curTS[%u], current[%u]", mDtxPlayed,
556                     mCurrPlayingTS, currentTime);
557 
558             mLastPlayedSeqNum = pEntry->nSeqNum;
559             mCurrPlayingTS += FRAME_INTERVAL;
560             return true;
561         }
562         if (psubtype)
563             *psubtype = MEDIASUBTYPE_UNDEFINED;
564         if (ppData)
565             *ppData = nullptr;
566         if (pnDataSize)
567             *pnDataSize = 0;
568         if (pnTimestamp)
569             *pnTimestamp = 0;
570         if (pbMark)
571             *pbMark = false;
572         if (pnSeqNum)
573             *pnSeqNum = 0;
574         if (pDataType)
575             *pDataType = MEDIASUBTYPE_UNDEFINED;
576 
577         IMLOGD_PACKET3(IM_PACKET_LOG_JITTER, "[Get] fail - dtx[%d], curTS[%u], current[%u]",
578                 mDtxPlayed, mCurrPlayingTS, currentTime);
579 
580         mCurrPlayingTS += FRAME_INTERVAL;
581         return false;
582     }
583 
584     return false;
585 }
586 
GetMeanBufferSize()587 double AudioJitterBuffer::GetMeanBufferSize()
588 {
589     return std::accumulate(mListJitterBufferSize.begin(), mListJitterBufferSize.end(), 0.0f) /
590             mListJitterBufferSize.size();
591 }
592 
Resync(uint32_t spareFrames)593 void AudioJitterBuffer::Resync(uint32_t spareFrames)
594 {
595     bool isDeleted = false;
596     DataEntry* entry = nullptr;
597 
598     while (mDataQueue.Get(&entry) && GetCount() > spareFrames)
599     {
600         IMLOGD6("[Resync] state[%d], seq[%d], TS[%d], dtx[%d], queue[%d], spareFrames[%d]",
601                 mWaiting, entry->nSeqNum, entry->nTimestamp,
602                 entry->eDataType == MEDIASUBTYPE_AUDIO_SID, GetCount(), spareFrames);
603 
604         if (entry->eDataType != MEDIASUBTYPE_AUDIO_SID)
605         {
606             CollectRxRtpStatus(entry->nSeqNum, kRtpStatusDiscarded);
607         }
608 
609         if (!mWaiting)
610         {
611             mLastPlayedSeqNum = entry->nSeqNum;
612         }
613 
614         mDataQueue.Delete();
615         isDeleted = true;
616     }
617 
618     if ((mWaiting || isDeleted) && mDataQueue.Get(&entry))
619     {
620         mCurrPlayingTS = entry->nTimestamp;
621     }
622 }
623 
CountLostFrames(int32_t currentSeq,int32_t lastSeq)624 void AudioJitterBuffer::CountLostFrames(int32_t currentSeq, int32_t lastSeq)
625 {
626     /** Report the loss gap if the loss gap is over 0 */
627     uint16_t lostGap = GET_SEQ_GAP(currentSeq, lastSeq);
628 
629     if (lostGap > 1 && lostGap < SEQ_OUTLIER_THRESHOLD)
630     {
631         uint16_t lostSeq = lastSeq + 1;
632         IMLOGD_PACKET2(IM_PACKET_LOG_JITTER, "[CountLostFrames] lost seq[%u], num[%u]", lostSeq,
633                 lostGap - 1);
634 
635         SessionCallbackParameter* param =
636                 new SessionCallbackParameter(kReportPacketLossGap, lostSeq, lostGap - 1);
637         mCallback->SendEvent(kCollectOptionalInfo, reinterpret_cast<uint64_t>(param), 0);
638     }
639 }
640 
GetDropVoiceRateInDuration(uint32_t duration,uint32_t currentTime)641 uint32_t AudioJitterBuffer::GetDropVoiceRateInDuration(uint32_t duration, uint32_t currentTime)
642 {
643     uint32_t numVoice = std::count_if(mListVoiceFrames.begin(), mListVoiceFrames.end(),
644             [=](uint32_t frameTime)
645             {
646                 return ((currentTime - frameTime + mCurrJitterBufferSize * FRAME_INTERVAL) <=
647                         duration);
648             });
649 
650     uint32_t numDrop = std::count_if(mListDropVoiceFrames.begin(), mListDropVoiceFrames.end(),
651             [=](uint32_t frameTime)
652             {
653                 return (currentTime - frameTime <= duration);
654             });
655 
656     if (numVoice <= 5)
657     {
658         return 0;
659     }
660 
661     return numDrop * 100 / numVoice;
662 }
663 
CollectRxRtpStatus(int32_t seq,kRtpPacketStatus status)664 void AudioJitterBuffer::CollectRxRtpStatus(int32_t seq, kRtpPacketStatus status)
665 {
666     IMLOGD_PACKET2(IM_PACKET_LOG_JITTER, "[CollectRxRtpStatus] seq[%d], status[%d]", seq, status);
667 
668     if (mCallback != nullptr)
669     {
670         SessionCallbackParameter* param =
671                 new SessionCallbackParameter(seq, status, ImsMediaTimer::GetTimeInMilliSeconds());
672         mCallback->SendEvent(kCollectRxRtpStatus, reinterpret_cast<uint64_t>(param));
673     }
674 }
675 
CollectJitterBufferStatus(int32_t currSize,int32_t maxSize)676 void AudioJitterBuffer::CollectJitterBufferStatus(int32_t currSize, int32_t maxSize)
677 {
678     IMLOGD_PACKET2(IM_PACKET_LOG_JITTER, "[CollectJitterBufferStatus] currSize[%d], maxSize[%d]",
679             currSize, maxSize);
680 
681     if (mCallback != nullptr)
682     {
683         mCallback->SendEvent(kCollectJitterBufferSize, currSize, maxSize);
684     }
685 }
686 
GetPartialRedundancyFrame(uint32_t lostSeq,uint32_t currentTimestamp,uint32_t offset,DataEntry ** entry)687 bool AudioJitterBuffer::GetPartialRedundancyFrame(
688         uint32_t lostSeq, uint32_t currentTimestamp, uint32_t offset, DataEntry** entry)
689 {
690     bool foundPartialFrame = false;
691     DataEntry* tempEntry = nullptr;
692     uint32_t partialSeq = lostSeq + offset;
693 
694     // find redundancy frame from the queue
695     for (int32_t i = 0; i < mDataQueue.GetCount(); i++)
696     {
697         if (mDataQueue.GetAt(i, &tempEntry) && tempEntry->nSeqNum == partialSeq)
698         {
699             foundPartialFrame = true;
700             break;
701         }
702 
703         if (tempEntry->nSeqNum > partialSeq)
704         {
705             break;
706         }
707     }
708 
709     if (!foundPartialFrame)
710     {
711         *entry = nullptr;
712         IMLOGD_PACKET1(IM_PACKET_LOG_JITTER,
713                 "[GetPartialRedundancyFrame] lostSeq[%d] Redundant Frame not found", lostSeq);
714         return false;
715     }
716 
717     if (tempEntry->eDataType == MEDIASUBTYPE_AUDIO_SID)
718     {
719         *entry = nullptr;
720         IMLOGD_PACKET1(IM_PACKET_LOG_JITTER,
721                 "[GetPartialRedundancyFrame] lostSeq[%d] Redundant Frame is SID", lostSeq);
722         return false;
723     }
724 
725     // If the timestamp of RF is greater than the (currentframe_timestamp + offset*20msec) then it
726     // cannot be used for concealment.
727     if (tempEntry->nTimestamp > (currentTimestamp + offset * 20))
728     {
729         *entry = nullptr;
730         IMLOGD_PACKET2(IM_PACKET_LOG_JITTER,
731                 "[GetPartialRedundancyFrame] RF not in offset timeframe. \
732                 RF_timestamp[%u] LostFrame_timestamp[%u]",
733                 tempEntry->nTimestamp, currentTimestamp);
734         return false;
735     }
736 
737     if (tempEntry->nBufferSize == 33 || tempEntry->nBufferSize == 34)
738     {
739         *entry = tempEntry;
740         IMLOGD_PACKET4(IM_PACKET_LOG_JITTER,
741                 "[GetPartialRedundancyFrame] lostSeq[%d] RFSeq[%d], size[%d] , curTS[%u]", lostSeq,
742                 tempEntry->nSeqNum, tempEntry->nBufferSize, mCurrPlayingTS);
743         return true;
744     }
745 
746     *entry = nullptr;
747     IMLOGD_PACKET1(IM_PACKET_LOG_JITTER,
748             "[GetPartialRedundancyFrame] lostSeq[%d] Redundant Frame not found", lostSeq);
749     return false;
750 }
751 
GetNextFrameFirstByte(uint32_t nextSeq,uint8_t * nextFrameFirstByte)752 bool AudioJitterBuffer::GetNextFrameFirstByte(uint32_t nextSeq, uint8_t* nextFrameFirstByte)
753 {
754     DataEntry* pEntry = nullptr;
755     if (mDataQueue.Get(&pEntry) &&
756             (pEntry->eDataType != MEDIASUBTYPE_AUDIO_NODATA && pEntry->nSeqNum == nextSeq))
757     {
758         *nextFrameFirstByte =
759                 pEntry->pbBuffer[ImsMediaAudioUtil::CheckEVSPrimaryHeaderFullModeFromSize(
760                                          pEntry->nBufferSize)
761                                 ? 1
762                                 : 0];
763         IMLOGD_PACKET2(IM_PACKET_LOG_JITTER,
764                 "[GetNextFrameFirstByte] nextSeq[%d] nextFrameFirstByte[%02X]", pEntry->nSeqNum,
765                 nextFrameFirstByte[0]);
766         return true;
767     }
768     IMLOGD_PACKET0(IM_PACKET_LOG_JITTER, "[GetNextFrameFirstByte] Next Frame not found");
769     return false;
770 }
771 
GetRedundantFrame(uint32_t lostSeq,uint8_t ** ppData,uint32_t * pnDataSize,bool * hasNextFrame,uint8_t * nextFrameFirstByte)772 bool AudioJitterBuffer::GetRedundantFrame(uint32_t lostSeq, uint8_t** ppData, uint32_t* pnDataSize,
773         bool* hasNextFrame, uint8_t* nextFrameFirstByte)
774 {
775     std::lock_guard<std::mutex> guard(mMutex);
776     DataEntry* pEntry = nullptr;
777 
778     if (!mDtxPlayed &&
779             GetPartialRedundancyFrame(lostSeq, mCurrPlayingTS, mEvsRedundantFrameOffset, &pEntry))
780     {
781         if (ppData)
782             *ppData = pEntry->pbBuffer;
783         if (pnDataSize)
784             *pnDataSize = pEntry->nBufferSize;
785         *hasNextFrame = GetNextFrameFirstByte((lostSeq + 1), nextFrameFirstByte);
786 
787         return true;
788     }
789     return false;
790 }
791