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 <RtpDecoderNode.h>
18 #include <ImsMediaTrace.h>
19 #include <ImsMediaCondition.h>
20 #include <AudioConfig.h>
21 #include <VideoConfig.h>
22 #include <TextConfig.h>
23
24 #if defined(SIMULATION_DELAY) || defined(SIMULATION_REORDER) || defined(SIMULATION_LOSS)
25 #include <ImsMediaTimer.h>
26 #endif
27 #ifdef SIMULATION_DELAY
28 #define DEBUG_JITTER_MAX_PACKET_INTERVAL 15 // milliseconds
29 #endif
30 #ifdef SIMULATION_REORDER
31 #include <ImsMediaDataQueue.h>
32 #define DEBUG_JITTER_REORDER_MAX 4
33 #define DEBUG_JITTER_REORDER_MIN 4
34 #define DEBUG_JITTER_NORMAL 2
35 #endif
36 #ifdef SIMULATION_LOSS
37 #define DEBUG_JITTER_LOSS_PACKET_INTERVAL 20
38 #endif
39 #ifdef SIMULATION_DUPLICATE
40 #define DEBUG_JITTER_DUPLICATE_PACKET_INTERVAL 30
41 #endif
42
RtpDecoderNode(BaseSessionCallback * callback)43 RtpDecoderNode::RtpDecoderNode(BaseSessionCallback* callback) :
44 BaseNode(callback)
45 {
46 mRtpSession = nullptr;
47 mReceivingSSRC = 0;
48 mInactivityTime = 0;
49 mNoRtpTime = 0;
50 mRtpPayloadTx = 0;
51 mRtpPayloadRx = 0;
52 mRtpTxDtmfPayload = 0;
53 mRtpRxDtmfPayload = 0;
54 mDtmfSamplingRate = 0;
55 mCvoValue = CVO_DEFINE_NONE;
56 mRedundantPayload = 0;
57 mArrivalTime = 0;
58 mSubtype = MEDIASUBTYPE_UNDEFINED;
59 mDtmfEndBit = false;
60 #if defined(SIMULATION_LOSS) || defined(SIMULATION_DUPLICATE) || defined(SIMULATION_SSRC_CHANGE)
61 mPacketCounter = 1;
62 #endif
63 #ifdef SIMULATION_DELAY
64 mNextTime = 0;
65 #endif
66 #ifdef SIMULATION_REORDER
67 mReorderDataCount = 0;
68 #endif
69 }
70
~RtpDecoderNode()71 RtpDecoderNode::~RtpDecoderNode()
72 {
73 // remove IRtpSession here to avoid shared instance in other node from unable to use
74 if (mRtpSession)
75 {
76 mRtpSession->StopRtp();
77 mRtpSession->SetRtpDecoderListener(nullptr);
78 IRtpSession::ReleaseInstance(mRtpSession);
79 mRtpSession = nullptr;
80 }
81 }
82
GetNodeId()83 kBaseNodeId RtpDecoderNode::GetNodeId()
84 {
85 return kNodeIdRtpDecoder;
86 }
87
Start()88 ImsMediaResult RtpDecoderNode::Start()
89 {
90 IMLOGD1("[Start] type[%d]", mMediaType);
91
92 if (mRtpPayloadTx == 0 || mRtpPayloadRx == 0)
93 {
94 IMLOGE0("[Start] invalid payload number");
95 return RESULT_INVALID_PARAM;
96 }
97
98 if (mRtpSession == nullptr)
99 {
100 mRtpSession = IRtpSession::GetInstance(mMediaType, mLocalAddress, mPeerAddress);
101
102 if (mRtpSession == nullptr)
103 {
104 IMLOGE0("[Start] - Can't create rtp session");
105 return RESULT_NOT_READY;
106 }
107 }
108
109 if (mMediaType == IMS_MEDIA_AUDIO)
110 {
111 mRtpSession->SetRtpPayloadParam(mRtpPayloadTx, mRtpPayloadRx, mSamplingRate * 1000,
112 mRtpTxDtmfPayload, mRtpRxDtmfPayload, mDtmfSamplingRate * 1000);
113 }
114 else if (mMediaType == IMS_MEDIA_VIDEO)
115 {
116 mRtpSession->SetRtpPayloadParam(mRtpPayloadTx, mRtpPayloadRx, mSamplingRate * 1000);
117 }
118 else if (mMediaType == IMS_MEDIA_TEXT)
119 {
120 if (mRedundantPayload > 0)
121 {
122 mRtpSession->SetRtpPayloadParam(mRtpPayloadTx, mRtpPayloadRx, mSamplingRate * 1000,
123 mRedundantPayload, mSamplingRate * 1000);
124 }
125 else
126 {
127 mRtpSession->SetRtpPayloadParam(mRtpPayloadTx, mRtpPayloadRx, mSamplingRate * 1000);
128 }
129 }
130
131 mRtpSession->SetRtpDecoderListener(this);
132 mRtpSession->StartRtp();
133 mReceivingSSRC = 0;
134 mNoRtpTime = 0;
135 mSubtype = MEDIASUBTYPE_UNDEFINED;
136 mNodeState = kNodeStateRunning;
137 #if defined(SIMULATION_LOSS) || defined(SIMULATION_DUPLICATE) || defined(SIMULATION_SSRC_CHANGE)
138 mPacketCounter = 1;
139 #endif
140 return RESULT_SUCCESS;
141 }
142
Stop()143 void RtpDecoderNode::Stop()
144 {
145 IMLOGD1("[Stop] type[%d]", mMediaType);
146
147 mReceivingSSRC = 0;
148
149 if (mRtpSession)
150 {
151 mRtpSession->StopRtp();
152 }
153
154 mNodeState = kNodeStateStopped;
155 }
156
OnDataFromFrontNode(ImsMediaSubType subtype,uint8_t * data,uint32_t datasize,uint32_t timestamp,bool mark,uint32_t seq,ImsMediaSubType nDataType,uint32_t arrivalTime)157 void RtpDecoderNode::OnDataFromFrontNode(ImsMediaSubType subtype, uint8_t* data, uint32_t datasize,
158 uint32_t timestamp, bool mark, uint32_t seq, ImsMediaSubType nDataType,
159 uint32_t arrivalTime)
160 {
161 IMLOGD_PACKET8(IM_PACKET_LOG_RTP,
162 "[OnDataFromFrontNode] media[%d], subtype[%d] Size[%d], TS[%d], Mark[%d], Seq[%d], "
163 "datatype[%d], arrivalTime[%u]",
164 mMediaType, subtype, datasize, timestamp, mark, seq, nDataType, arrivalTime);
165
166 mArrivalTime = arrivalTime;
167 #ifdef SIMULATION_DELAY
168 {
169 ImsMediaCondition condition;
170 uint32_t delay = ImsMediaTimer::GenerateRandom(DEBUG_JITTER_MAX_PACKET_INTERVAL);
171 mArrivalTime += delay;
172 condition.wait_timeout(delay);
173 }
174 #endif
175
176 #if defined(SIMULATION_LOSS) || defined(SIMULATION_DUPLICATE) || defined(SIMULATION_SSRC_CHANGE)
177 #if defined(SIMULATION_LOSS) || defined(SIMULATION_DUPLICATE)
178 bool flag = false;
179 #endif
180 #ifdef SIMULATION_LOSS
181
182 uint32_t seed = ImsMediaTimer::GenerateRandom(5);
183 if (mPacketCounter % DEBUG_JITTER_LOSS_PACKET_INTERVAL == 0 || seed % 5 == 0)
184 {
185 flag = true;
186 }
187 #endif
188 #ifdef SIMULATION_DUPLICATE
189 if ((mPacketCounter % DEBUG_JITTER_DUPLICATE_PACKET_INTERVAL) == 0)
190 {
191 flag = true;
192 }
193 #endif
194 #ifdef SIMULATION_SSRC_CHANGE
195 if (mPacketCounter == 1)
196 {
197 mTestSsrc = *reinterpret_cast<uint32_t*>(data + 8);
198 mTestSeq = 0;
199 }
200 else if (mPacketCounter % 15 == 0)
201 {
202 mTestSsrc += mPacketCounter;
203 mTestSeq += mPacketCounter;
204 }
205
206 *reinterpret_cast<uint32_t*>(data + 8) = mTestSsrc;
207 #endif
208 mPacketCounter++;
209 #endif
210 #ifdef SIMULATION_REORDER
211 {
212 // add data to jitter gen buffer
213 DataEntry entry;
214 entry.subtype = MEDIASUBTYPE_RTPPACKET;
215 entry.pbBuffer = data;
216 entry.nBufferSize = datasize;
217 entry.nTimestamp = 0;
218 entry.bMark = 0;
219 entry.nSeqNum = 0;
220 entry.arrivalTime = arrivalTime;
221
222 if (mReorderDataCount < DEBUG_JITTER_NORMAL)
223 {
224 jitterData.Add(&entry);
225 }
226 else if (mReorderDataCount < DEBUG_JITTER_NORMAL + DEBUG_JITTER_REORDER_MAX)
227 {
228 int32_t nCurrReorderSize;
229 int32_t nInsertPos;
230 uint32_t nCurrJitterBufferSize;
231 nCurrJitterBufferSize = jitterData.GetCount();
232
233 if (DEBUG_JITTER_REORDER_MAX > DEBUG_JITTER_REORDER_MIN)
234 {
235 nCurrReorderSize = mReorderDataCount - DEBUG_JITTER_NORMAL + 1 -
236 ImsMediaTimer::GenerateRandom(
237 DEBUG_JITTER_REORDER_MAX - DEBUG_JITTER_REORDER_MIN + 1);
238 }
239 else
240 {
241 nCurrReorderSize = mReorderDataCount - DEBUG_JITTER_NORMAL + 1;
242 }
243
244 if (nCurrReorderSize > 0)
245 {
246 nCurrReorderSize = ImsMediaTimer::GenerateRandom(nCurrReorderSize + 1);
247 }
248
249 nInsertPos = nCurrJitterBufferSize - nCurrReorderSize;
250
251 if (nInsertPos < 0)
252 {
253 nInsertPos = 0;
254 }
255
256 jitterData.InsertAt(nInsertPos, &entry);
257 }
258
259 mReorderDataCount++;
260
261 if (mReorderDataCount >= DEBUG_JITTER_NORMAL + DEBUG_JITTER_REORDER_MAX)
262 {
263 mReorderDataCount = 0;
264 }
265
266 // send
267 while (jitterData.GetCount() >= DEBUG_JITTER_REORDER_MAX)
268 {
269 DataEntry* pEntry;
270
271 if (jitterData.Get(&pEntry))
272 {
273 #ifdef SIMULATION_LOSS
274 if (flag == false)
275 {
276 mRtpSession->ProcRtpPacket(pEntry->pbBuffer, pEntry->nBufferSize);
277 }
278 #else
279 #ifdef SIMULATION_DUPLICATE
280 if (flag == true)
281 {
282 mRtpSession->ProcRtpPacket(pEntry->pbBuffer, pEntry->nBufferSize);
283 }
284 #endif
285 mRtpSession->ProcRtpPacket(pEntry->pbBuffer, pEntry->nBufferSize);
286 #endif
287 jitterData.Delete();
288 }
289 }
290 }
291 #else
292 #ifdef SIMULATION_LOSS
293 if (flag == false)
294 {
295 mRtpSession->ProcRtpPacket(data, datasize);
296 }
297 #else
298 #ifdef SIMULATION_DUPLICATE
299 if (flag == true)
300 {
301 mRtpSession->ProcRtpPacket(data, datasize);
302 }
303 #endif
304 mRtpSession->ProcRtpPacket(data, datasize);
305 #endif
306 #endif
307 }
308
IsRunTime()309 bool RtpDecoderNode::IsRunTime()
310 {
311 return true;
312 }
313
IsSourceNode()314 bool RtpDecoderNode::IsSourceNode()
315 {
316 return false;
317 }
318
SetConfig(void * config)319 void RtpDecoderNode::SetConfig(void* config)
320 {
321 IMLOGD1("[SetConfig] type[%d]", mMediaType);
322
323 if (config == nullptr)
324 {
325 return;
326 }
327
328 if (mMediaType == IMS_MEDIA_AUDIO)
329 {
330 AudioConfig* pConfig = reinterpret_cast<AudioConfig*>(config);
331 mPeerAddress = RtpAddress(pConfig->getRemoteAddress().c_str(), pConfig->getRemotePort());
332 mSamplingRate = pConfig->getSamplingRateKHz();
333 mRtpPayloadTx = pConfig->getTxPayloadTypeNumber();
334 mRtpPayloadRx = pConfig->getRxPayloadTypeNumber();
335 mRtpTxDtmfPayload = pConfig->getTxDtmfPayloadTypeNumber();
336 mRtpRxDtmfPayload = pConfig->getRxDtmfPayloadTypeNumber();
337 mDtmfSamplingRate = pConfig->getDtmfsamplingRateKHz();
338 }
339 else if (mMediaType == IMS_MEDIA_VIDEO)
340 {
341 VideoConfig* pConfig = reinterpret_cast<VideoConfig*>(config);
342 mPeerAddress = RtpAddress(pConfig->getRemoteAddress().c_str(), pConfig->getRemotePort());
343 mSamplingRate = pConfig->getSamplingRateKHz();
344 mRtpPayloadTx = pConfig->getTxPayloadTypeNumber();
345 mRtpPayloadRx = pConfig->getRxPayloadTypeNumber();
346 mCvoValue = pConfig->getCvoValue();
347 }
348 else if (mMediaType == IMS_MEDIA_TEXT)
349 {
350 TextConfig* pConfig = reinterpret_cast<TextConfig*>(config);
351 mPeerAddress = RtpAddress(pConfig->getRemoteAddress().c_str(), pConfig->getRemotePort());
352 mSamplingRate = pConfig->getSamplingRateKHz();
353 mRtpPayloadTx = pConfig->getTxPayloadTypeNumber();
354 mRtpPayloadRx = pConfig->getRxPayloadTypeNumber();
355 mRedundantPayload = pConfig->getRedundantPayload();
356 }
357
358 IMLOGD2("[SetConfig] peer Ip[%s], port[%d]", mPeerAddress.ipAddress, mPeerAddress.port);
359 }
360
IsSameConfig(void * config)361 bool RtpDecoderNode::IsSameConfig(void* config)
362 {
363 if (config == nullptr)
364 {
365 return true;
366 }
367
368 if (mMediaType == IMS_MEDIA_AUDIO)
369 {
370 AudioConfig* pConfig = reinterpret_cast<AudioConfig*>(config);
371 return (mPeerAddress ==
372 RtpAddress(pConfig->getRemoteAddress().c_str(), pConfig->getRemotePort()) &&
373 mSamplingRate == pConfig->getSamplingRateKHz() &&
374 mRtpPayloadTx == pConfig->getTxPayloadTypeNumber() &&
375 mRtpPayloadRx == pConfig->getRxPayloadTypeNumber() &&
376 mRtpTxDtmfPayload == pConfig->getTxDtmfPayloadTypeNumber() &&
377 mRtpRxDtmfPayload == pConfig->getRxDtmfPayloadTypeNumber() &&
378 mDtmfSamplingRate == pConfig->getDtmfsamplingRateKHz());
379 }
380 else if (mMediaType == IMS_MEDIA_VIDEO)
381 {
382 VideoConfig* pConfig = reinterpret_cast<VideoConfig*>(config);
383 return (mPeerAddress ==
384 RtpAddress(pConfig->getRemoteAddress().c_str(), pConfig->getRemotePort()) &&
385 mSamplingRate == pConfig->getSamplingRateKHz() &&
386 mRtpPayloadTx == pConfig->getTxPayloadTypeNumber() &&
387 mRtpPayloadRx == pConfig->getRxPayloadTypeNumber() &&
388 mCvoValue == pConfig->getCvoValue());
389 }
390 else if (mMediaType == IMS_MEDIA_TEXT)
391 {
392 TextConfig* pConfig = reinterpret_cast<TextConfig*>(config);
393 return (mPeerAddress ==
394 RtpAddress(pConfig->getRemoteAddress().c_str(), pConfig->getRemotePort()) &&
395 mSamplingRate == pConfig->getSamplingRateKHz() &&
396 mRtpPayloadTx == pConfig->getTxPayloadTypeNumber() &&
397 mRtpPayloadRx == pConfig->getRxPayloadTypeNumber() &&
398 mRedundantPayload == pConfig->getRedundantPayload());
399 }
400
401 return false;
402 }
403
OnMediaDataInd(unsigned char * data,uint32_t datasize,uint32_t timestamp,bool mark,uint16_t seq,uint32_t payloadType,uint32_t ssrc,const RtpHeaderExtensionInfo & extensionInfo)404 void RtpDecoderNode::OnMediaDataInd(unsigned char* data, uint32_t datasize, uint32_t timestamp,
405 bool mark, uint16_t seq, uint32_t payloadType, uint32_t ssrc,
406 const RtpHeaderExtensionInfo& extensionInfo)
407 {
408 IMLOGD_PACKET8(IM_PACKET_LOG_RTP,
409 "[OnMediaDataInd] media[%d] size[%d], TS[%d], mark[%d], seq[%d], payloadType[%d] "
410 "sampling[%d], extensionSize[%d]",
411 mMediaType, datasize, timestamp, mark, seq, payloadType, mSamplingRate,
412 extensionInfo.length);
413
414 if (mMediaType == IMS_MEDIA_AUDIO && mRtpPayloadRx != payloadType &&
415 mRtpPayloadTx != payloadType && payloadType != mRtpRxDtmfPayload &&
416 payloadType != mRtpTxDtmfPayload)
417 {
418 IMLOGE1("[OnMediaDataInd] media[%d] invalid frame", mMediaType);
419 return;
420 }
421
422 // no need to change to timestamp to milliseconds unit in audio or text packet
423 if (mMediaType != IMS_MEDIA_VIDEO && mSamplingRate != 0)
424 {
425 timestamp = timestamp / (mSamplingRate);
426 }
427
428 if (mReceivingSSRC != ssrc)
429 {
430 IMLOGI3("[OnMediaDataInd] media[%d] SSRC changed, [%x] -> [%x]", mMediaType, mReceivingSSRC,
431 ssrc);
432 mReceivingSSRC = ssrc;
433 SendDataToRearNode(MEDIASUBTYPE_REFRESHED, nullptr, mReceivingSSRC, 0, 0, 0);
434 }
435
436 if (mMediaType == IMS_MEDIA_AUDIO &&
437 (payloadType == mRtpRxDtmfPayload || payloadType == mRtpTxDtmfPayload) && datasize >= 4)
438 {
439 processDtmf(data);
440 return;
441 }
442
443 if (extensionInfo.length > 0 && mMediaType == IMS_MEDIA_AUDIO)
444 {
445 std::list<RtpHeaderExtension>* extensions = DecodeRtpHeaderExtension(extensionInfo);
446
447 if (mCallback != nullptr && extensions != nullptr)
448 {
449 mCallback->SendEvent(
450 kImsMediaEventHeaderExtensionReceived, reinterpret_cast<uint64_t>(extensions));
451 }
452 }
453
454 if (extensionInfo.extensionData != nullptr && extensionInfo.extensionDataSize >= 2 &&
455 mMediaType == IMS_MEDIA_VIDEO && mCvoValue != CVO_DEFINE_NONE)
456 {
457 uint16_t extensionId = extensionInfo.extensionData[0] >> 4;
458
459 if (extensionId == mCvoValue)
460 {
461 // 0: Front-facing camera, 1: Back-facing camera
462 uint16_t cameraId = extensionInfo.extensionData[1] >> 3;
463 uint16_t rotation = extensionInfo.extensionData[1] & 0x07;
464
465 switch (rotation)
466 {
467 case 0: // No rotation (Rotated 0CW/CCW = To rotate 0CW/CCW)
468 case 4: // + Horizontal Flip, but it's treated as same as above
469 mSubtype = MEDIASUBTYPE_ROT0;
470 break;
471 case 1: // Rotated 270CW(90CCW) = To rotate 90CW(270CCW)
472 case 5: // + Horizontal Flip, but it's treated as same as above
473 mSubtype = MEDIASUBTYPE_ROT90;
474 break;
475 case 2: // Rotated 180CW = To rotate 180CW
476 case 6: // + Horizontal Flip, but it's treated as same as above
477 mSubtype = MEDIASUBTYPE_ROT180;
478 break;
479 case 3: // Rotated 90CW(270CCW) = To rotate 270CW(90CCW)
480 case 7: // + Horizontal Flip, but it's treated as same as above
481 mSubtype = MEDIASUBTYPE_ROT270;
482 break;
483 default:
484 break;
485 }
486
487 IMLOGD4("[OnMediaDataInd] extensionId[%d], cameraId[%d], rotation[%d], subtype[%d]",
488 extensionId, cameraId, rotation, mSubtype);
489 }
490 }
491
492 if (mMediaType == IMS_MEDIA_TEXT)
493 {
494 if (payloadType == mRtpPayloadTx)
495 {
496 if (mRedundantPayload == 0)
497 {
498 mSubtype = MEDIASUBTYPE_BITSTREAM_T140;
499 }
500 else
501 {
502 mSubtype = MEDIASUBTYPE_BITSTREAM_T140_RED;
503 }
504 }
505 else if (payloadType == mRedundantPayload)
506 {
507 mSubtype = MEDIASUBTYPE_BITSTREAM_T140;
508 }
509 else
510 {
511 IMLOGI2("[OnMediaDataInd] media[%d] INVALID payload[%d] is received", mMediaType,
512 payloadType);
513 }
514 }
515
516 #ifdef SIMULATION_SSRC_CHANGE
517 seq += mTestSeq;
518 #endif
519 SendDataToRearNode(
520 mSubtype, data, datasize, timestamp, mark, seq, MEDIASUBTYPE_UNDEFINED, mArrivalTime);
521 }
522
OnNumReceivedPacket(uint32_t nNumRtpPacket)523 void RtpDecoderNode::OnNumReceivedPacket(uint32_t nNumRtpPacket)
524 {
525 IMLOGD_PACKET2(IM_PACKET_LOG_RTP, "[OnNumReceivedPacket] InactivityTime[%d], numRtp[%d]",
526 mInactivityTime, nNumRtpPacket);
527
528 if (nNumRtpPacket == 0)
529 {
530 mNoRtpTime++;
531 }
532 else
533 {
534 mNoRtpTime = 0;
535 }
536
537 if (mInactivityTime != 0 && mNoRtpTime == mInactivityTime)
538 {
539 if (mCallback != nullptr)
540 {
541 mCallback->SendEvent(kImsMediaEventMediaInactivity, kProtocolRtp, mInactivityTime);
542 }
543 }
544 }
545
SetLocalAddress(const RtpAddress & address)546 void RtpDecoderNode::SetLocalAddress(const RtpAddress& address)
547 {
548 mLocalAddress = address;
549 }
550
SetPeerAddress(const RtpAddress & address)551 void RtpDecoderNode::SetPeerAddress(const RtpAddress& address)
552 {
553 mPeerAddress = address;
554 }
555
SetInactivityTimerSec(const uint32_t time)556 void RtpDecoderNode::SetInactivityTimerSec(const uint32_t time)
557 {
558 IMLOGD2("[SetInactivityTimerSec] media[%d], time[%d] reset", mMediaType, time);
559 mInactivityTime = time;
560 mNoRtpTime = 0;
561 }
562
processDtmf(uint8_t * data)563 void RtpDecoderNode::processDtmf(uint8_t* data)
564 {
565 /** dtmf event payload format
566 * 0 1 2 3
567 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
568 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
569 * | event |E|R| volume | duration |
570 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
571 */
572
573 // check end bit and send event once per event
574 if (data[1] & 0x80)
575 {
576 if (mDtmfEndBit)
577 {
578 uint8_t digit = data[0];
579 int32_t duration = data[2];
580 mSamplingRate != 0 ? duration = ((duration << 8) | data[3]) / mSamplingRate
581 : 0; // convert milliseconds
582
583 IMLOGD2("[processDtmf] dtmf received, digit[%d], duration[%d]", digit, duration);
584
585 mCallback->SendEvent(kAudioDtmfReceivedInd, digit, duration);
586 mDtmfEndBit = false;
587 }
588 }
589 else
590 {
591 // mark true when the new event started
592 mDtmfEndBit = true;
593 }
594 }
595
DecodeRtpHeaderExtension(const RtpHeaderExtensionInfo & extensionInfo)596 std::list<RtpHeaderExtension>* RtpDecoderNode::DecodeRtpHeaderExtension(
597 const RtpHeaderExtensionInfo& extensionInfo)
598 {
599 if (extensionInfo.length == 0 || extensionInfo.extensionData == nullptr ||
600 extensionInfo.extensionDataSize == 0)
601 {
602 return nullptr;
603 }
604
605 std::list<RtpHeaderExtension>* extensions = new std::list<RtpHeaderExtension>();
606
607 // header
608 bool useTwoByteHeader =
609 (extensionInfo.definedByProfile == RtpHeaderExtensionInfo::kBitPatternForTwoByteHeader);
610 uint32_t length = extensionInfo.length; // word size
611 IMLOGD2("[DecodeRtpHeaderExtension] twoByteHeader[%d], len[%d]", useTwoByteHeader, length);
612
613 uint32_t offset = 0;
614 int32_t remainingSize = extensionInfo.extensionDataSize;
615
616 while (remainingSize > 0)
617 {
618 RtpHeaderExtension extension;
619
620 if (useTwoByteHeader)
621 {
622 // header
623 extension.setLocalIdentifier(extensionInfo.extensionData[offset++]);
624 int8_t dataSize = extensionInfo.extensionData[offset++]; // add header
625
626 // payload
627 if (dataSize > 0)
628 {
629 extension.setExtensionData(
630 reinterpret_cast<const uint8_t*>(extensionInfo.extensionData + offset),
631 dataSize);
632 }
633
634 offset += dataSize;
635 remainingSize -= (dataSize + 2); // remove two byte header too
636 }
637 else // one byte header
638 {
639 // header
640 extension.setLocalIdentifier(extensionInfo.extensionData[offset] >> 4);
641 int8_t dataSize = (extensionInfo.extensionData[offset] & 0x0F) + 1; // data + header
642 offset++;
643
644 // payload
645 if (dataSize > 0)
646 {
647 extension.setExtensionData(
648 reinterpret_cast<const uint8_t*>(extensionInfo.extensionData + offset),
649 dataSize);
650 }
651
652 offset += dataSize;
653 remainingSize -= (dataSize + 1); // remove one byte header too
654 }
655
656 extensions->push_back(extension);
657
658 while (remainingSize > 0 && extensionInfo.extensionData[offset] == 0x00) // ignore padding
659 {
660 offset++;
661 remainingSize--;
662 }
663 }
664
665 return extensions;
666 }