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 <AudioRtpPayloadEncoderNode.h>
18 #include <ImsMediaAudioUtil.h>
19 #include <ImsMediaTrace.h>
20 #include <AudioConfig.h>
21 #include <EvsParams.h>
22 
AudioRtpPayloadEncoderNode(BaseSessionCallback * callback)23 AudioRtpPayloadEncoderNode::AudioRtpPayloadEncoderNode(BaseSessionCallback* callback) :
24         BaseNode(callback)
25 {
26     mCodecType = 0;
27     mOctetAligned = false;
28     mPtime = 0;
29     memset(mPayload, 0, sizeof(mPayload));
30     mFirstFrame = false;
31     mTimestamp = 0;
32     mMaxNumOfFrame = 0;
33     mCurrNumOfFrame = 0;
34     mCurrFramePos = 0;
35     mTotalPayloadSize = 0;
36     mEvsBandwidth = kEvsBandwidthNone;
37     mEvsCodecMode = kEvsCodecModePrimary;
38     mEvsOffset = 0;
39     mSendCMR = 0;
40     mEvsMode = kEvsAmrIoModeBitrate00660;
41     mCoreEvsMode = 0;
42     mEvsPayloadHeaderMode = kRtpPyaloadHeaderModeEvsCompact;
43 }
44 
~AudioRtpPayloadEncoderNode()45 AudioRtpPayloadEncoderNode::~AudioRtpPayloadEncoderNode() {}
46 
GetNodeId()47 kBaseNodeId AudioRtpPayloadEncoderNode::GetNodeId()
48 {
49     return kNodeIdAudioPayloadEncoder;
50 }
51 
Start()52 ImsMediaResult AudioRtpPayloadEncoderNode::Start()
53 {
54     mMaxNumOfFrame = mPtime / 20;
55     mEvsMode = (kEvsBitrate)ImsMediaAudioUtil::GetMaximumEvsMode(mCoreEvsMode);
56     mEvsCodecMode = (kEvsCodecMode)ImsMediaAudioUtil::ConvertEvsCodecMode(mEvsMode);
57 
58     IMLOGD5("[Start] codecType[%d], mode[%d], num of frames[%d], evs bitrate[%d], evs mode[%d]",
59             mCodecType, mOctetAligned, mMaxNumOfFrame, mEvsMode, mEvsCodecMode);
60 
61     if (mMaxNumOfFrame == 0 || mMaxNumOfFrame > MAX_FRAME_IN_PACKET)
62     {
63         IMLOGE1("[Start] Invalid ptime [%d]", mPtime);
64         return RESULT_INVALID_PARAM;
65     }
66 
67     mCurrNumOfFrame = 0;
68     mCurrFramePos = 0;
69     mFirstFrame = true;
70     mTotalPayloadSize = 0;
71     mNodeState = kNodeStateRunning;
72     return RESULT_SUCCESS;
73 }
74 
Stop()75 void AudioRtpPayloadEncoderNode::Stop()
76 {
77     IMLOGD0("[Stop]");
78     mNodeState = kNodeStateStopped;
79 }
80 
IsRunTime()81 bool AudioRtpPayloadEncoderNode::IsRunTime()
82 {
83     return true;
84 }
85 
IsSourceNode()86 bool AudioRtpPayloadEncoderNode::IsSourceNode()
87 {
88     return false;
89 }
90 
OnDataFromFrontNode(ImsMediaSubType,uint8_t * pData,uint32_t nDataSize,uint32_t nTimestamp,bool bMark,uint32_t nSeqNum,ImsMediaSubType nDataType,uint32_t arrivalTime)91 void AudioRtpPayloadEncoderNode::OnDataFromFrontNode(ImsMediaSubType /*subtype*/, uint8_t* pData,
92         uint32_t nDataSize, uint32_t nTimestamp, bool bMark, uint32_t nSeqNum,
93         ImsMediaSubType nDataType, uint32_t arrivalTime)
94 {
95     switch (mCodecType)
96     {
97         case kAudioCodecAmr:
98         case kAudioCodecAmrWb:
99             EncodePayloadAmr(pData, nDataSize, nTimestamp);
100             break;
101         case kAudioCodecPcmu:
102         case kAudioCodecPcma:
103             SendDataToRearNode(MEDIASUBTYPE_RTPPAYLOAD, pData, nDataSize, nTimestamp, bMark,
104                     nSeqNum, nDataType, arrivalTime);
105             break;
106         case kAudioCodecEvs:
107             EncodePayloadEvs(pData, nDataSize, nTimestamp);
108             break;
109         default:
110             IMLOGE1("[OnDataFromFrontNode] invalid codec type[%d]", mCodecType);
111             SendDataToRearNode(MEDIASUBTYPE_RTPPAYLOAD, pData, nDataSize, nTimestamp, bMark,
112                     nSeqNum, nDataType, arrivalTime);
113             break;
114     }
115 }
116 
SetConfig(void * config)117 void AudioRtpPayloadEncoderNode::SetConfig(void* config)
118 {
119     AudioConfig* pConfig = reinterpret_cast<AudioConfig*>(config);
120 
121     if (pConfig != nullptr)
122     {
123         mCodecType = ImsMediaAudioUtil::ConvertCodecType(pConfig->getCodecType());
124         if (mCodecType == kAudioCodecAmr || mCodecType == kAudioCodecAmrWb)
125         {
126             mOctetAligned = pConfig->getAmrParams().getOctetAligned();
127         }
128         else if (mCodecType == kAudioCodecEvs)
129         {
130             mEvsBandwidth = (kEvsBandwidth)pConfig->getEvsParams().getEvsBandwidth();
131             mEvsPayloadHeaderMode =
132                     (kRtpPyaloadHeaderMode)pConfig->getEvsParams().getUseHeaderFullOnly();
133             mCoreEvsMode = pConfig->getEvsParams().getEvsMode();
134             mEvsOffset = pConfig->getEvsParams().getChannelAwareMode();
135             mSendCMR = pConfig->getEvsParams().getCodecModeRequest();
136         }
137 
138         mPtime = pConfig->getPtimeMillis();
139     }
140 }
141 
IsSameConfig(void * config)142 bool AudioRtpPayloadEncoderNode::IsSameConfig(void* config)
143 {
144     if (config == nullptr)
145         return true;
146     AudioConfig* pConfig = reinterpret_cast<AudioConfig*>(config);
147 
148     if (mCodecType == ImsMediaAudioUtil::ConvertCodecType(pConfig->getCodecType()))
149     {
150         if (mCodecType == kAudioCodecAmr || mCodecType == kAudioCodecAmrWb)
151         {
152             return (mOctetAligned == pConfig->getAmrParams().getOctetAligned());
153         }
154         else if (mCodecType == kAudioCodecEvs)
155         {
156             return (mEvsBandwidth == (kEvsBandwidth)pConfig->getEvsParams().getEvsBandwidth() &&
157                     mEvsPayloadHeaderMode ==
158                             (kRtpPyaloadHeaderMode)pConfig->getEvsParams().getUseHeaderFullOnly() &&
159                     mCoreEvsMode ==
160                             ImsMediaAudioUtil::GetMaximumEvsMode(
161                                     pConfig->getEvsParams().getEvsMode()) &&
162                     mEvsOffset == pConfig->getEvsParams().getChannelAwareMode());
163         }
164     }
165 
166     return false;
167 }
168 
EncodePayloadAmr(uint8_t * pData,uint32_t nDataSize,uint32_t nTimestamp)169 void AudioRtpPayloadEncoderNode::EncodePayloadAmr(
170         uint8_t* pData, uint32_t nDataSize, uint32_t nTimestamp)
171 {
172     uint32_t nCmr = 15;
173     uint32_t f, ft, q, nDataBitSize;
174 
175     // remove TOC from the encoder
176     pData++;
177     nDataSize -= 1;
178 
179     if (nDataSize > 4)
180     {
181         IMLOGD_PACKET5(IM_PACKET_LOG_PH, "[EncodePayloadAmr] src = %02X %02X %02X %02X, len[%d]",
182                 pData[0], pData[1], pData[2], pData[3], nDataSize);
183     }
184 
185     IMLOGD_PACKET2(IM_PACKET_LOG_PH, "[EncodePayloadAmr] codectype[%d], octetAligned[%d]",
186             mCodecType, mOctetAligned);
187 
188     mCurrNumOfFrame++;
189     f = (mCurrNumOfFrame == mMaxNumOfFrame) ? 0 : 1;
190 
191     if (mCodecType == kAudioCodecAmr)
192     {
193         nCmr = 0x0F;
194         ft = ImsMediaAudioUtil::ConvertLenToAmrMode(nDataSize);
195         nDataBitSize = ImsMediaAudioUtil::ConvertAmrModeToBitLen(ft);
196     }
197     else
198     {
199         nCmr = 0x0F;
200         ft = ImsMediaAudioUtil::ConvertLenToAmrWbMode(nDataSize);
201         nDataBitSize = ImsMediaAudioUtil::ConvertAmrWbModeToBitLen(ft);
202     }
203 
204     q = 1;
205 
206     // the first paylaod
207     if (mCurrNumOfFrame == 1)
208     {
209         memset(mPayload, 0, MAX_AUDIO_PAYLOAD_SIZE);
210         mBWHeader.SetBuffer(mPayload, MAX_AUDIO_PAYLOAD_SIZE);
211         mBWPayload.SetBuffer(mPayload, MAX_AUDIO_PAYLOAD_SIZE);
212         mBWHeader.Write(nCmr, 4);
213 
214         if (mOctetAligned == true)
215         {
216             mBWHeader.Write(0, 4);
217             mBWPayload.Seek(8 + mMaxNumOfFrame * 8);
218         }
219         else
220         {
221             mBWPayload.Seek(4 + mMaxNumOfFrame * 6);
222         }
223 
224         mTimestamp = nTimestamp;
225     }
226 
227     // Payload ToC
228     mBWHeader.Write(f, 1);
229     mBWHeader.Write(ft, 4);
230     mBWHeader.Write(q, 1);
231 
232     if (mOctetAligned == true)
233     {
234         mBWHeader.AddPadding();
235     }
236 
237     IMLOGD_PACKET2(IM_PACKET_LOG_PH, "[EncodePayloadAmr] nDataBitSize[%d], nDataSize[%d]",
238             nDataBitSize, nDataSize);
239 
240     // Speech Frame
241     mBWPayload.WriteByteBuffer(pData, nDataBitSize);
242 
243     if (mOctetAligned == true)
244     {
245         mBWPayload.AddPadding();
246     }
247 
248     mTotalPayloadSize += nDataSize;
249 
250     if (mCurrNumOfFrame == mMaxNumOfFrame)
251     {
252         mBWHeader.Flush();
253         mBWPayload.AddPadding();
254         mBWPayload.Flush();
255         uint32_t nTotalSize = mBWPayload.GetBufferSize();
256 
257         IMLOGD_PACKET7(IM_PACKET_LOG_PH,
258                 "[EncodePayloadAmr] result = %02X %02X %02X %02X %02X %02X, len[%d]", mPayload[0],
259                 mPayload[1], mPayload[2], mPayload[3], mPayload[4], mPayload[5], nTotalSize);
260 
261         if (mTotalPayloadSize > 0)
262         {
263             SendDataToRearNode(
264                     MEDIASUBTYPE_RTPPAYLOAD, mPayload, nTotalSize, mTimestamp, mFirstFrame, 0);
265         }
266 
267         mCurrNumOfFrame = 0;
268         mTotalPayloadSize = 0;
269 
270         if (mFirstFrame)
271         {
272             mFirstFrame = false;
273         }
274     }
275 }
276 
EncodePayloadEvs(uint8_t * pData,uint32_t nDataSize,uint32_t nTimeStamp)277 void AudioRtpPayloadEncoderNode::EncodePayloadEvs(
278         uint8_t* pData, uint32_t nDataSize, uint32_t nTimeStamp)
279 {
280     if (nDataSize == 0)
281     {
282         return;
283     }
284 
285     uint32_t nFrameType = 0;
286     // compact or header-full format, default is compact formats
287     // primary or amr-wb io mode, default is primary mode
288     // primary or amr-wb io mode base on frameSize.
289     mCurrNumOfFrame++;
290 
291     if (mEvsPayloadHeaderMode == kRtpPyaloadHeaderModeEvsCompact)
292     {
293         memset(mPayload, 0, MAX_AUDIO_PAYLOAD_SIZE);
294         mBWHeader.SetBuffer(mPayload, MAX_AUDIO_PAYLOAD_SIZE);
295         mBWPayload.SetBuffer(mPayload, MAX_AUDIO_PAYLOAD_SIZE);
296 
297         mTimestamp = nTimeStamp;
298         // exactly one coded frame without any additional EVS RTP payload header
299         if (mEvsCodecMode == kEvsCodecModePrimary)
300         {
301             // calculate nDataBitSize from nDataSize
302             nFrameType = (uint32_t)ImsMediaAudioUtil::ConvertLenToEVSAudioMode(nDataSize);
303             uint32_t nDataBitSize =
304                     ImsMediaAudioUtil::ConvertEVSAudioModeToBitLen((kImsAudioEvsMode)nFrameType);
305 
306             if (nDataBitSize == 0)
307             {
308                 return;
309             }
310 
311             // special case, EVS Primary 2.8 kbps frame in Compact format
312             if (nFrameType == 0)
313             {
314                 // First data bit d(0) of the EVS Primary 2.8 kbps is always set to '0'
315                 pData[0] = pData[0] & 0x7f;
316             }
317 
318             // write speech Frame
319             mBWPayload.WriteByteBuffer(pData, nDataBitSize);
320             mTotalPayloadSize += nDataSize;
321 
322             mBWHeader.AddPadding();
323             mBWHeader.Flush();
324 
325             mBWPayload.AddPadding();
326             mBWPayload.Flush();
327 
328             uint32_t nTotalSize = mBWPayload.GetBufferSize();
329 
330             IMLOGD_PACKET7(IM_PACKET_LOG_PH, "[EncodePayloadEvs] result =\
331                 %02X %02X %02X %02X %02X %02X, len[%d]",
332                     mPayload[0], mPayload[1], mPayload[2], mPayload[3], mPayload[4], mPayload[5],
333                     nTotalSize);
334 
335             if (mTotalPayloadSize > 0)
336             {
337                 SendDataToRearNode(
338                         MEDIASUBTYPE_RTPPAYLOAD, mPayload, nTotalSize, mTimestamp, mFirstFrame, 0);
339             }
340 
341             mCurrNumOfFrame = 0;
342             mTotalPayloadSize = 0;
343             if (mFirstFrame)
344                 mFirstFrame = false;
345         }
346         // one 3-bit CMR field, one coded frame, and zero-padding bits if necessary
347         else if (mEvsCodecMode == kEvsCodecModeAmrIo)
348         {
349             // calculate nDataBitSize from nDataSize
350             nFrameType = (uint32_t)ImsMediaAudioUtil::ConvertLenToAmrWbMode(nDataSize);
351             uint32_t nDataBitSize = ImsMediaAudioUtil::ConvertAmrWbModeToBitLen(nFrameType);
352 
353             // 0: 6.6, 1: 8.85, 2: 12.65, 3: 15.85, 4: 18.25, 5: 23.05, 6: 23.85, 7: none
354             // 0111(7) is no request.
355             uint32_t nCmr = 0x07;
356 
357             // write CMR except SID
358             // at EVS AMR WB IO Mode, SID packet does not include cmr field...and no processing
359             if (nFrameType != kImsAudioAmrWbModeSID)
360             {
361                 mBWHeader.Write(nCmr, 3);
362                 mBWPayload.Seek(3);
363 
364                 // append a speech data bit(0) after the last speech data bit
365                 uint8_t nDataBit0 = 0;
366                 uint32_t i = 0;
367                 uint32_t remain = 0;
368 
369                 nDataBit0 = pData[0] >> 7;
370                 for (i = 0; i < (nDataSize - 1); i++)
371                 {
372                     pData[i] = pData[i] << 1;
373                     pData[i] = pData[i] + (pData[i + 1] >> 7);
374                 }
375 
376                 // set the last speech data byte
377                 remain = nDataBitSize % 8;
378                 if (remain == 0)
379                     remain = 8;
380                 pData[nDataSize - 1] = pData[nDataSize - 1] << 1;
381                 nDataBit0 = nDataBit0 << (8 - remain);
382                 pData[nDataSize - 1] = pData[nDataSize - 1] + nDataBit0;
383             }
384             else  // kImsAudioAmrWbModeSID case
385             {
386                 // EVS amr io mode's SID is used HF format.
387                 // set cmr
388                 nCmr = 0xff;  // no request - 0xff
389                 mBWHeader.Write(nCmr, 8);
390                 mBWPayload.Seek(8);
391 
392                 // set ToC
393                 // Header Type identification bit(1bit) - always set to 0
394                 uint32_t toc_h = 0;
395                 // (1bit - always set to 0 in compact AMR WB IO mode)
396                 uint32_t toc_f = 0;
397                 // 1 1 1001 - EVS AMR IO Mode, Q bit set 1, 1001 indicate SID packet
398                 uint32_t ft = 0x39;
399 
400                 mBWHeader.Write(toc_h, 1);
401                 mBWHeader.Write(toc_f, 1);
402                 mBWHeader.Write(ft, 6);
403                 mBWPayload.Seek(8);
404             }
405 
406             // write speech Frame
407             mBWPayload.WriteByteBuffer(pData, nDataBitSize);
408             mTotalPayloadSize += nDataSize;
409 
410             mBWHeader.Flush();
411 
412             mBWPayload.AddPadding();
413             mBWPayload.Flush();
414 
415             uint32_t nTotalSize = mBWPayload.GetBufferSize();
416 
417             IMLOGD_PACKET7(IM_PACKET_LOG_PH,
418                     "[EncodePayloadEvs] Result = %02X %02X %02X %02X %02X %02X, len[%d]",
419                     mPayload[0], mPayload[1], mPayload[2], mPayload[3], mPayload[4], mPayload[5],
420                     nTotalSize);
421 
422             if (mTotalPayloadSize > 0)
423             {
424                 SendDataToRearNode(
425                         MEDIASUBTYPE_RTPPAYLOAD, mPayload, nTotalSize, mTimestamp, mFirstFrame, 0);
426             }
427 
428             mCurrNumOfFrame = 0;
429             mTotalPayloadSize = 0;
430             if (mFirstFrame)
431                 mFirstFrame = false;
432         }
433         else
434         {
435             IMLOGE0("[EncodePayloadEvs] Invalid codec mode");
436             return;
437         }
438     }
439     else if (mEvsPayloadHeaderMode == kRtpPyaloadHeaderModeEvsHeaderFull)
440     {
441         // 0111 1111 is no request.
442         uint32_t nEVSBW = 0x07;
443         uint32_t nEVSBR = 0x0f;
444 
445         uint32_t cmr_h, cmr_t, cmr_d = 0;  // CMR byte
446         memset(mPayload, 0, MAX_AUDIO_PAYLOAD_SIZE);
447         mBWHeader.SetBuffer(mPayload, MAX_AUDIO_PAYLOAD_SIZE);
448         mBWPayload.SetBuffer(mPayload, MAX_AUDIO_PAYLOAD_SIZE);
449 
450         if (mEvsCodecMode == kEvsCodecModePrimary)
451         {
452             if (nFrameType == kImsAudioEvsPrimaryModeSID || mSendCMR)  // CMR value
453             {
454                 // Header Type identification bit(1bit) - always set to 1
455                 cmr_h = 1;
456                 // Type of Request(3bits) - NB(000), IO(001), FB(100), WB(101), SWB(110)
457                 cmr_t = nEVSBW;
458                 // codec mode request(4bits)
459                 cmr_d = nEVSBR;
460             }
461 
462             // set ToC byte
463             uint32_t toc_h = 0;  // Header Type identification bit(1bit) - always set to 0
464             uint32_t toc_f = (mCurrNumOfFrame == mMaxNumOfFrame) ? 0 : 1;  // (1bit)
465             uint32_t toc_ft_m = 0;  // EVS mode(1bit), Primary mode is 0
466             uint32_t toc_ft_q = 0;  // Q bit(1bit) - zero for kEvsCodecModePrimary
467             uint32_t toc_ft_b =
468                     ImsMediaAudioUtil::ConvertLenToEVSAudioMode(nDataSize);  // EVS bit rate(4bits)
469             uint32_t nDataBitSize =
470                     ImsMediaAudioUtil::ConvertEVSAudioModeToBitLen((kImsAudioEvsMode)toc_ft_b);
471 
472             // write CMR and seek the position of the first paylaod
473             if (mCurrNumOfFrame == 1)
474             {
475                 // set CMR byte - it's optional field...
476                 if (nFrameType == kImsAudioEvsPrimaryModeSID || mSendCMR)
477                 {
478                     // check writing CMR or not
479                     // write CMR byte
480                     mBWHeader.Write(cmr_h, 1);
481                     mBWHeader.Write(cmr_t, 3);
482                     mBWHeader.Write(cmr_d, 4);
483 
484                     mBWPayload.Seek(8);
485                 }
486 
487                 // ToC field.
488                 mBWPayload.Seek(mMaxNumOfFrame * 8);  // jump ToC bytes
489                 mTimestamp = nTimeStamp;              // set timestamp as the first frame
490             }
491 
492             // write ToC
493             mBWHeader.Write(toc_h, 1);
494             mBWHeader.Write(toc_f, 1);
495             mBWHeader.Write(toc_ft_m, 1);
496             mBWHeader.Write(toc_ft_q, 1);
497             mBWHeader.Write(toc_ft_b, 4);
498 
499             // write Speech Frame
500             mBWPayload.WriteByteBuffer(pData, nDataBitSize);
501             mBWPayload.AddPadding();
502 
503             mTotalPayloadSize += nDataSize;
504 
505             if (mCurrNumOfFrame == mMaxNumOfFrame)
506             {
507                 // mBWHeader.AddPadding();
508                 mBWHeader.Flush();
509 
510                 mBWPayload.AddPadding();
511                 mBWPayload.Flush();
512 
513                 uint32_t nTotalSize = mBWPayload.GetBufferSize();
514                 IMLOGD_PACKET7(IM_PACKET_LOG_PH,
515                         "[EncodePayloadEvs] Result = %02X %02X %02X %02X %02X %02X, len[%d]",
516                         mPayload[0], mPayload[1], mPayload[2], mPayload[3], mPayload[4],
517                         mPayload[5], nTotalSize);
518 
519                 if (mTotalPayloadSize > 0)
520                 {
521                     SendDataToRearNode(MEDIASUBTYPE_RTPPAYLOAD, mPayload,
522                             CheckPaddingNecessity(nTotalSize), mTimestamp, mFirstFrame, 0);
523                 }
524 
525                 mCurrNumOfFrame = 0;
526                 mTotalPayloadSize = 0;
527                 if (mFirstFrame)
528                     mFirstFrame = false;
529             }
530         }
531         else if (mEvsCodecMode == kEvsCodecModeAmrIo)
532         {
533             // set CMR byte
534             // at EVS AMR WB IO Mode, CMR field shall include.
535             // Header Type identification bit(1bit) - always set to 1
536             cmr_h = 1;
537             /* Type of Request(3bits) - NB(000), IO(001), WB(010), SWB(011), FB(100), WB 13.2
538              * channel-aware(101), SWB 13.2 channel-aware(110), reserved(111) */
539             cmr_t = nEVSBW;
540             // codec mode request(4bits) 1111 is no request.
541             cmr_d = nEVSBR;
542 
543             // set ToC byte
544             // Header Type identification bit(1bit) - always set to 0
545             uint32_t toc_h = 0;
546             // (1bit)
547             uint32_t toc_f = (mCurrNumOfFrame == mMaxNumOfFrame) ? 0 : 1;
548             // EVS mode(1bit), AMR-WB IO mode is 1
549             uint32_t toc_ft_m = 1;
550             // Q bit(1bit) - 1 for AMR_WB_IO
551             // for ORG EVS to avoid the issue -#EURAVOLTE-567
552             uint32_t toc_ft_q = 1;
553             // EVS AMR WB IO bit rate(4bits)
554             uint32_t toc_ft_b = (uint32_t)ImsMediaAudioUtil::ConvertLenToAmrWbMode(nDataSize);
555             uint32_t nDataBitSize = ImsMediaAudioUtil::ConvertAmrWbModeToBitLen(toc_ft_b);
556 
557             // write CMR and seek the position of the first paylaod
558             if (mCurrNumOfFrame == 1)
559             {
560                 // write CMR byte
561                 mBWHeader.Write(cmr_h, 1);
562                 mBWHeader.Write(cmr_t, 3);
563                 mBWHeader.Write(cmr_d, 4);
564 
565                 // seek the position of the first paylaod
566                 // add speech data after CMR and ToC
567                 mBWPayload.Seek(8 + mMaxNumOfFrame * 8);
568 
569                 mTimestamp = nTimeStamp;  // set timestamp as the first frame
570             }
571 
572             // write ToC
573             mBWHeader.Write(toc_h, 1);
574             mBWHeader.Write(toc_f, 1);
575             mBWHeader.Write(toc_ft_m, 1);
576             mBWHeader.Write(toc_ft_q, 1);
577             mBWHeader.Write(toc_ft_b, 4);
578 
579             // write Speech Frame
580             mBWPayload.WriteByteBuffer(pData, nDataBitSize);
581             mBWPayload.AddPadding();
582 
583             mTotalPayloadSize += nDataSize;
584 
585             if (mCurrNumOfFrame == mMaxNumOfFrame)
586             {
587                 // mBWHeader.AddPadding();
588                 mBWHeader.Flush();
589 
590                 mBWPayload.AddPadding();
591                 mBWPayload.Flush();
592 
593                 uint32_t nTotalSize = mBWPayload.GetBufferSize();
594 
595                 IMLOGD_PACKET7(IM_PACKET_LOG_PH,
596                         "[EncodePayloadEvs] result = %02X %02X %02X %02X %02X %02X, len[%d]",
597                         mPayload[0], mPayload[1], mPayload[2], mPayload[3], mPayload[4],
598                         mPayload[5], nTotalSize);
599 
600                 if (mTotalPayloadSize > 0)
601                 {
602                     SendDataToRearNode(MEDIASUBTYPE_RTPPAYLOAD, mPayload,
603                             CheckPaddingNecessity(nTotalSize), mTimestamp, mFirstFrame, 0);
604                 }
605 
606                 mCurrNumOfFrame = 0;
607                 mTotalPayloadSize = 0;
608                 if (mFirstFrame)
609                     mFirstFrame = false;
610             }
611         }
612         else
613         {
614             IMLOGE0("[EncodePayloadEvs] invalid codec mode");
615             return;
616         }
617     }
618     else
619     {
620         IMLOGE0("[EncodePayloadEvs] invalid payload format");
621         return;
622     }
623 
624     return;
625 }
626 
CheckPaddingNecessity(uint32_t nTotalSize)627 uint32_t AudioRtpPayloadEncoderNode::CheckPaddingNecessity(uint32_t nTotalSize)
628 {
629     kEvsCodecMode evsCodecMode;
630     uint32_t nEVSCompactId;
631     uint32_t nSize = nTotalSize;
632 
633     // check EVS compact size
634     while (nSize != 0 &&
635             ImsMediaAudioUtil::ConvertEVSPayloadMode(nSize, &evsCodecMode, &nEVSCompactId) ==
636                     kRtpPyaloadHeaderModeEvsCompact)
637     {
638         mPayload[nSize] = 0;
639         nSize++;
640     }
641 
642     return nSize;
643 }
644