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