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 <RtcpEncoderNode.h>
18 #include <ImsMediaTrace.h>
19 #include <VideoConfig.h>
20 
21 #define RTCPFBMNGR_PLI_FIR_REQUEST_MIN_INTERVAL 1000
22 
RtcpEncoderNode(BaseSessionCallback * callback)23 RtcpEncoderNode::RtcpEncoderNode(BaseSessionCallback* callback) :
24         BaseNode(callback)
25 {
26     mRtpSession = nullptr;
27     mRtcpInterval = 0;
28     mRtcpXrPayload = nullptr;
29     mEnableRtcpBye = false;
30     mRtcpXrBlockTypes = RtcpConfig::FLAG_RTCPXR_NONE;
31     mRtcpXrCounter = 0;
32     mTimer = nullptr;
33     mLastTimeSentPli = 0;
34     mLastTimeSentFir = 0;
35 }
36 
~RtcpEncoderNode()37 RtcpEncoderNode::~RtcpEncoderNode()
38 {
39     if (mRtpSession != nullptr)
40     {
41         mRtpSession->StopRtcp();
42         mRtpSession->SetRtcpEncoderListener(nullptr);
43         IRtpSession::ReleaseInstance(mRtpSession);
44         mRtpSession = nullptr;
45     }
46 
47     mRtcpXrBlockTypes = RtcpConfig::FLAG_RTCPXR_NONE;
48     mRtcpXrCounter = 0;
49 }
50 
GetNodeId()51 kBaseNodeId RtcpEncoderNode::GetNodeId()
52 {
53     return kNodeIdRtcpEncoder;
54 }
55 
Start()56 ImsMediaResult RtcpEncoderNode::Start()
57 {
58     std::lock_guard<std::mutex> guard(mMutexTimer);
59 
60     if (mRtpSession == nullptr)
61     {
62         mRtpSession = IRtpSession::GetInstance(mMediaType, mLocalAddress, mPeerAddress);
63 
64         if (mRtpSession == nullptr)
65         {
66             IMLOGE0("[Start] Can't create rtp session");
67             return RESULT_NOT_READY;
68         }
69     }
70 
71     IMLOGD4("[Start] interval[%d], rtcpBye[%d], rtcpXrBlock[%d], rtcpFbTypes[%d]", mRtcpInterval,
72             mEnableRtcpBye, mRtcpXrBlockTypes, mRtcpFbTypes);
73     mRtpSession->SetRtcpEncoderListener(this);
74     mRtpSession->SetRtcpInterval(mRtcpInterval);
75 
76     if (mRtcpInterval > 0)
77     {
78         mRtpSession->StartRtcp(mEnableRtcpBye);
79     }
80 
81     if (mTimer == nullptr)
82     {
83         mTimer = ImsMediaTimer::TimerStart(1000, true, OnTimer, this);
84         IMLOGD0("[Start] Rtcp Timer started");
85     }
86 
87     mRtcpXrCounter = 1;
88     mNodeState = kNodeStateRunning;
89     return RESULT_SUCCESS;
90 }
91 
Stop()92 void RtcpEncoderNode::Stop()
93 {
94     IMLOGD0("[Stop]");
95     if (mTimer != nullptr)
96     {
97         ImsMediaTimer::TimerStop(mTimer, nullptr);
98         mTimer = nullptr;
99         IMLOGD0("[Stop] Rtcp Timer stopped");
100     }
101 
102     {
103         std::lock_guard<std::mutex> guard(mMutexTimer);
104         IMLOGD0("[Stop] mutex taken");
105 
106         if (mRtpSession != nullptr)
107         {
108             mRtpSession->StopRtcp();
109         }
110 
111         mNodeState = kNodeStateStopped;
112     }
113 }
114 
IsRunTime()115 bool RtcpEncoderNode::IsRunTime()
116 {
117     return true;
118 }
119 
IsSourceNode()120 bool RtcpEncoderNode::IsSourceNode()
121 {
122     return true;
123 }
124 
SetConfig(void * config)125 void RtcpEncoderNode::SetConfig(void* config)
126 {
127     RtpConfig* pConfig = reinterpret_cast<RtpConfig*>(config);
128     mPeerAddress = RtpAddress(pConfig->getRemoteAddress().c_str(), pConfig->getRemotePort());
129     mRtcpInterval = pConfig->getRtcpConfig().getIntervalSec();
130     mRtcpXrBlockTypes = pConfig->getRtcpConfig().getRtcpXrBlockTypes();
131     mEnableRtcpBye = false;
132 
133     IMLOGD4("[SetConfig] peer Ip[%s], port[%d], interval[%d], rtcpxr[%d]", mPeerAddress.ipAddress,
134             mPeerAddress.port, mRtcpInterval, mRtcpXrBlockTypes);
135 
136     if (mMediaType == IMS_MEDIA_VIDEO)
137     {
138         VideoConfig* videoConfig = reinterpret_cast<VideoConfig*>(config);
139         mRtcpFbTypes = videoConfig->getRtcpFbType();
140         IMLOGD1("[SetConfig] rtcpFbTypes[%d]", mRtcpFbTypes);
141     }
142 }
143 
IsSameConfig(void * config)144 bool RtcpEncoderNode::IsSameConfig(void* config)
145 {
146     if (config == nullptr)
147     {
148         return true;
149     }
150 
151     RtpConfig* pConfig = reinterpret_cast<RtpConfig*>(config);
152     RtpAddress peerAddress =
153             RtpAddress(pConfig->getRemoteAddress().c_str(), pConfig->getRemotePort());
154 
155     if (mMediaType == IMS_MEDIA_VIDEO)
156     {
157         VideoConfig* videoConfig = reinterpret_cast<VideoConfig*>(config);
158         return (mPeerAddress == peerAddress &&
159                 mRtcpInterval == videoConfig->getRtcpConfig().getIntervalSec() &&
160                 mRtcpXrBlockTypes == videoConfig->getRtcpConfig().getRtcpXrBlockTypes() &&
161                 mRtcpFbTypes == videoConfig->getRtcpFbType());
162     }
163     else
164     {
165         return (mPeerAddress == peerAddress &&
166                 mRtcpInterval == pConfig->getRtcpConfig().getIntervalSec() &&
167                 mRtcpXrBlockTypes == pConfig->getRtcpConfig().getRtcpXrBlockTypes());
168     }
169 }
170 
OnRtcpPacket(unsigned char * pData,uint32_t wLen)171 void RtcpEncoderNode::OnRtcpPacket(unsigned char* pData, uint32_t wLen)
172 {
173     ImsMediaSubType subtype = MEDIASUBTYPE_RTCPPACKET;
174 
175     if (mEnableRtcpBye == true)
176     {
177         uint8_t* pCurr;
178         int32_t nRemainSize;
179         pCurr = reinterpret_cast<uint8_t*>(pData);
180         nRemainSize = wLen;
181 
182         while (nRemainSize >= 4)
183         {
184             uint8_t PT = pCurr[1];
185             uint32_t length;
186             IMLOGD_PACKET1(IM_PACKET_LOG_RTCP, "[OnRtcpPacket] PT[%d]", PT);
187 
188             if (PT == 203)
189             {
190                 subtype = MEDIASUBTYPE_RTCPPACKET_BYE;
191                 break;
192             }
193 
194             length = pCurr[2];
195             length <<= 8;
196             length += pCurr[3];
197             length = (length + 1) * 4;
198 
199             pCurr += length;
200             nRemainSize -= length;
201         }
202     }
203 
204     SendDataToRearNode(subtype, pData, wLen, 0, 0, 0);
205 }
206 
OnTimer(hTimerHandler hTimer,void * pUserData)207 void RtcpEncoderNode::OnTimer(hTimerHandler hTimer, void* pUserData)
208 {
209     (void)hTimer;
210     RtcpEncoderNode* pNode = reinterpret_cast<RtcpEncoderNode*>(pUserData);
211 
212     if (pNode != nullptr)
213     {
214         pNode->ProcessTimer();
215     }
216 }
217 
ProcessTimer()218 void RtcpEncoderNode::ProcessTimer()
219 {
220     std::lock_guard<std::mutex> guard(mMutexTimer);
221 
222     if (mTimer == nullptr || mRtpSession == nullptr)
223     {
224         return;
225     }
226 
227     mRtpSession->OnRtpStatsTimerExpired();
228 
229     mRtcpXrCounter++;
230 
231     if (mRtcpXrBlockTypes != 0 && mRtcpInterval != 0 && mRtcpXrCounter % mRtcpInterval == 0)
232     {
233         mCallback->SendEvent(kGetRtcpXrReportBlock, mRtcpXrBlockTypes);
234     }
235 }
236 
SetLocalAddress(const RtpAddress & address)237 void RtcpEncoderNode::SetLocalAddress(const RtpAddress& address)
238 {
239     mLocalAddress = address;
240 }
241 
SetPeerAddress(const RtpAddress & address)242 void RtcpEncoderNode::SetPeerAddress(const RtpAddress& address)
243 {
244     mPeerAddress = address;
245 }
246 
SendNack(NackParams * param)247 bool RtcpEncoderNode::SendNack(NackParams* param)
248 {
249     if (param == nullptr)
250     {
251         return false;
252     }
253 
254     if (mRtcpFbTypes & VideoConfig::RTP_FB_NACK)
255     {
256         IMLOGD3("[SendNack] PID[%d], BLP[%d], nSecNackCnt[%d]", param->PID, param->BLP,
257                 param->nSecNackCnt);
258 
259         /* Generic NACK format
260             0                   1                   2                   3
261             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
262            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
263            |            PID                |             BLP               |
264            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*/
265 
266         // create a Nack payload
267         uint8_t pNackBuff[4];
268         mBitWriter.SetBuffer(pNackBuff, 32);
269         mBitWriter.Write(param->PID, 16);  // PID
270         mBitWriter.Write(param->BLP, 16);  // BLP
271 
272         if (param->bNackReport)
273         {
274             if (mRtpSession != nullptr)
275             {
276                 return mRtpSession->SendRtcpFeedback(kRtpFbNack, pNackBuff, 4);
277             }
278         }
279     }
280 
281     return false;
282 }
283 
SendPictureLost(const uint32_t type)284 bool RtcpEncoderNode::SendPictureLost(const uint32_t type)
285 {
286     if (mRtpSession == nullptr)
287     {
288         return false;
289     }
290 
291     IMLOGD1("[SendPictureLost] type[%d]", type);
292 
293     uint32_t nCurrentTime = ImsMediaTimer::GetTimeInMilliSeconds();
294 
295     if (type == kPsfbPli && mRtcpFbTypes & VideoConfig::PSFB_PLI)
296     {
297         if (mLastTimeSentPli == 0 ||
298                 (mLastTimeSentPli + RTCPFBMNGR_PLI_FIR_REQUEST_MIN_INTERVAL < nCurrentTime))
299         {
300             if (mRtpSession->SendRtcpFeedback(kPsfbPli, nullptr, 0))
301             {
302                 mLastTimeSentPli = nCurrentTime;
303                 return true;
304             }
305         }
306     }
307     else if (type == kPsfbFir && mRtcpFbTypes & VideoConfig::PSFB_FIR)
308     {
309         if (mLastTimeSentFir == 0 ||
310                 (mLastTimeSentFir + RTCPFBMNGR_PLI_FIR_REQUEST_MIN_INTERVAL < nCurrentTime))
311         {
312             if (mRtpSession->SendRtcpFeedback(kPsfbFir, nullptr, 0))
313             {
314                 mLastTimeSentFir = nCurrentTime;
315                 return true;
316             }
317         }
318     }
319 
320     return false;
321 }
322 
SendTmmbrn(const uint32_t type,TmmbrParams * param)323 bool RtcpEncoderNode::SendTmmbrn(const uint32_t type, TmmbrParams* param)
324 {
325     if (mRtpSession == nullptr || param == nullptr)
326     {
327         return false;
328     }
329 
330     IMLOGD5("[SendTmmbrn] type[%d], ssrc[%x], exp[%d], mantissa[%d], overhead[%d]", type,
331             param->ssrc, param->exp, param->mantissa, param->overhead);
332 
333     /** TMMBR/TMMBN message format
334        0                   1                   2                   3
335        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
336        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
337        |                              SSRC                             |
338        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
339        | MxTBR Exp |  MxTBR Mantissa                 |Measured Overhead|
340        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
341     */
342 
343     uint8_t buffer[8];
344     mBitWriter.SetBuffer(buffer, 64);
345     mBitWriter.Write((param->ssrc & 0xFFFF0000) >> 16, 16);
346     mBitWriter.Write(param->ssrc & 0x0000FFFF, 16);
347     // MxTBR = mantissa * 2^exp
348     mBitWriter.Write(param->exp, 6);        // MxTBR Exp
349     mBitWriter.Write(param->mantissa, 17);  // MxTBR Mantissa
350     // avg_OH (new) = 15/16*avg_OH (old) + 1/16*pckt_OH,
351     mBitWriter.Write(param->overhead, 9);  // Measured Overhead
352 
353     if (type == kRtpFbTmmbr && mRtcpFbTypes & VideoConfig::RTP_FB_TMMBR)
354     {
355         return mRtpSession->SendRtcpFeedback(kRtpFbTmmbr, buffer, 8);
356     }
357     else if (type == kRtpFbTmmbn && mRtcpFbTypes & VideoConfig::RTP_FB_TMMBN)
358     {
359         return mRtpSession->SendRtcpFeedback(kRtpFbTmmbn, buffer, 8);
360     }
361 
362     return false;
363 }
364 
SendRtcpXr(uint8_t * data,uint32_t size)365 bool RtcpEncoderNode::SendRtcpXr(uint8_t* data, uint32_t size)
366 {
367     if (data == nullptr || mRtpSession == nullptr)
368     {
369         return false;
370     }
371 
372     IMLOGD1("[SendRtcpXr] size[%d]", size);
373 
374     // send buffer to packets
375     mRtpSession->SendRtcpXr(data, size);
376 
377     delete data;
378     return true;
379 }