• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Shenzhen Kaihong Digital Industry Development Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "rtcp.h"
17 #include <cstring>
18 #include <ctime>
19 #include <netinet/in.h>
20 #include <securec.h>
21 #include "common/common_macro.h"
22 #include "common/media_log.h"
23 
24 namespace OHOS {
25 namespace Sharing {
26 
27 //------------------------------ RtcpHeader ------------------------------//
28 
GetSize() const29 int32_t RtcpHeader::GetSize() const
30 {
31     return (1 + ntohs(length_)) << 2; // 2:byte offset
32 }
33 
SetSize(int32_t size)34 void RtcpHeader::SetSize(int32_t size)
35 {
36     length_ = htons(((uint32_t)size >> 2) - 1); // 2:byte offset
37 }
38 
GetPaddingSize() const39 int32_t RtcpHeader::GetPaddingSize() const
40 {
41     if (!padding_) {
42         return 0;
43     }
44 
45     return ((uint8_t *)this)[GetSize() - 1];
46 }
47 
48 //------------------------------ common ------------------------------//
49 
AlignSize(int32_t bytes)50 static inline int32_t AlignSize(int32_t bytes)
51 {
52     return static_cast<int32_t>((static_cast<uint32_t>(bytes + 3) >> 2) << 2); // 2:byte offset, 3:byte length
53 }
54 
SetupHeader(RtcpHeader * rtcp,RtcpType type,int32_t reportCount,int32_t totalBytes)55 static void SetupHeader(RtcpHeader *rtcp, RtcpType type, int32_t reportCount, int32_t totalBytes)
56 {
57     RETURN_IF_NULL(rtcp);
58     rtcp->version_ = 2; // 2:byte offset
59     rtcp->padding_ = 0;
60     if (reportCount > 0x1F) {
61         SHARING_LOGD("reportCount is too large.");
62     }
63 
64     rtcp->reportCount_ = reportCount;
65     rtcp->pt_ = (uint8_t)type;
66     rtcp->SetSize(totalBytes);
67 }
68 
SetupPadding(RtcpHeader * rtcp,size_t paddingSize)69 static void SetupPadding(RtcpHeader *rtcp, size_t paddingSize)
70 {
71     RETURN_IF_NULL(rtcp);
72 
73     if (paddingSize) {
74         rtcp->padding_ = 1;
75         int32_t size = rtcp->GetSize();
76         if (size - 1 < 0 || size - 1 >= (int32_t)sizeof(RtcpHeader)) {
77             return;
78         }
79         ((uint8_t *)rtcp)[size - 1] = paddingSize & 0xFF;
80     } else {
81         rtcp->padding_ = 0;
82     }
83 }
84 
85 //------------------------------ RtcpSR ------------------------------//
86 
Create(int32_t itemCount)87 std::shared_ptr<RtcpSR> RtcpSR::Create(int32_t itemCount)
88 {
89     auto realSize = (int32_t)sizeof(RtcpSR) - (int32_t)sizeof(ReportItem) + itemCount * (int32_t)sizeof(ReportItem);
90     auto bytes = AlignSize(realSize);
91     if (bytes == 0 || bytes < 0) {
92         return nullptr;
93     }
94     auto ptr = (RtcpSR *)new char[bytes];
95     if (ptr == nullptr) {
96         return nullptr;
97     }
98     SetupHeader(ptr, RtcpType::RTCP_SR, itemCount, bytes);
99     SetupPadding(ptr, bytes - realSize);
100 
101     return std::shared_ptr<RtcpSR>(ptr, [](RtcpSR *ptr) { delete[] (char *)ptr; });
102 }
103 
SetNtpStamp(timeval tv)104 RtcpSR &RtcpSR::SetNtpStamp(timeval tv)
105 {
106     ntpmsw_ = htonl(tv.tv_sec + 0x83AA7E80); /* 0x83AA7E80 is the number of seconds from 1900 to 1970 */
107     ntplsw_ = htonl((uint32_t)((double)tv.tv_usec * (double)(((uint64_t)1) << 32) * 1.0e-6)); // 32:byte offset
108     return *this;
109 }
110 
SetNtpStamp(uint64_t unixStampMs)111 RtcpSR &RtcpSR::SetNtpStamp(uint64_t unixStampMs)
112 {
113     timeval tv;
114     tv.tv_sec = (int64_t)(unixStampMs / 1000);           // 1000:unit
115     tv.tv_usec = (int64_t)((unixStampMs % 1000) * 1000); // 1000:unit
116     return SetNtpStamp(tv);
117 }
118 
GetNtpStamp() const119 std::string RtcpSR::GetNtpStamp() const
120 {
121     struct timeval tv;
122     tv.tv_sec = ntpmsw_ - 0x83AA7E80;
123     tv.tv_usec = (decltype(tv.tv_usec))(ntplsw_ / ((double)(((uint64_t)1) << 32) * 1.0e-6)); // 32:byte offset, 6:-
124 
125     char ts[30] = {0};
126     struct tm local = {0};
127     if (!localtime_r(&tv.tv_sec, &local)) {
128         return {};
129     }
130     if (strftime(ts, sizeof(ts), "%Y-%m-%d %H:%M:%S", &local) < 0) {
131         return {};
132     }
133     if (sprintf_s(ts + strlen(ts), sizeof(ts) - strlen(ts), ".%06lld", static_cast<long long>(tv.tv_usec)) < 0) {
134         return {};
135     }
136     // format: "2022-09-02 17:27:04.021154"
137     return std::string(ts);
138 }
139 
GetNtpUnixStampMS() const140 uint64_t RtcpSR::GetNtpUnixStampMS() const
141 {
142     if (ntpmsw_ < 0x83AA7E80 /*1970 year*/) {
143         return 0;
144     }
145     struct timeval tv;
146     tv.tv_sec = ntpmsw_ - 0x83AA7E80;
147     tv.tv_usec = (decltype(tv.tv_usec))(ntplsw_ / ((double)(((uint64_t)1) << 32) * 1.0e-6)); // 32:byte offset, 6:-
148 
149     return 1000 * tv.tv_sec + tv.tv_usec / 1000; // 1000:unit
150 }
151 
SetSsrc(uint32_t ssrc)152 RtcpSR &RtcpSR::SetSsrc(uint32_t ssrc)
153 {
154     ssrc_ = htonl(ssrc);
155     return *this;
156 }
157 
GetSsrc() const158 uint32_t RtcpSR::GetSsrc() const
159 {
160     return ntohl(ssrc_);
161 }
162 
SetPacketCount(uint32_t count)163 RtcpSR &RtcpSR::SetPacketCount(uint32_t count)
164 {
165     packetCount_ = htonl(count);
166     return *this;
167 }
168 
GetPacketCount() const169 uint32_t RtcpSR::GetPacketCount() const
170 {
171     return ntohl(packetCount_);
172 }
173 
GetItemList()174 std::vector<ReportItem *> RtcpSR::GetItemList()
175 {
176     std::vector<ReportItem *> list;
177     ReportItem *ptr = &items_;
178     for (int32_t i = 0; i < (int32_t)reportCount_; ++i) {
179         list.emplace_back(ptr);
180         ++ptr;
181     }
182 
183     return list;
184 }
185 
186 //------------------------------ RtcpRR ------------------------------//
187 
Create(size_t itemCount)188 std::shared_ptr<RtcpRR> RtcpRR::Create(size_t itemCount)
189 {
190     auto realSize = sizeof(RtcpRR) - sizeof(ReportItem) + itemCount * sizeof(ReportItem);
191     auto bytes = AlignSize(realSize);
192     if (bytes == 0 || bytes < 0) {
193         return nullptr;
194     }
195     auto ptr = (RtcpRR *)new char[bytes];
196     if (ptr == nullptr) {
197         return nullptr;
198     }
199     SetupHeader(ptr, RtcpType::RTCP_RR, itemCount, bytes);
200     SetupPadding(ptr, bytes - realSize);
201     return std::shared_ptr<RtcpRR>(ptr, [](RtcpRR *ptr) { delete[] (char *)ptr; });
202 }
203 
GetItemList()204 std::vector<ReportItem *> RtcpRR::GetItemList()
205 {
206     std::vector<ReportItem *> list;
207     ReportItem *ptr = &items_;
208     for (int32_t i = 0; i < (int32_t)reportCount_; ++i) {
209         list.emplace_back(ptr);
210         ++ptr;
211     }
212 
213     return list;
214 }
215 
216 //------------------------------ RtcpSdes ------------------------------//
217 
TotalBytes() const218 size_t SdesChunk::TotalBytes() const
219 {
220     return AlignSize(MinSize() + txtLen_);
221 }
222 
223 // chunk length without variable length information
MinSize()224 size_t SdesChunk::MinSize()
225 {
226     return sizeof(SdesChunk) - sizeof(text_);
227 }
228 
Create(const std::vector<std::string> & itemText)229 std::shared_ptr<RtcpSdes> RtcpSdes::Create(const std::vector<std::string> &itemText)
230 {
231     size_t itemTotalSize = 0;
232     for (auto &text : itemText) {
233         itemTotalSize += (size_t)AlignSize(SdesChunk::MinSize() + (0xFF & text.size()));
234     }
235     auto realSize = sizeof(RtcpSdes) - sizeof(SdesChunk) + itemTotalSize;
236     auto bytes = AlignSize(realSize);
237     if (bytes == 0 || bytes < 0) {
238         return nullptr;
239     }
240     auto ptr = (RtcpSdes *)new char[bytes];
241     if (ptr == nullptr) {
242         return nullptr;
243     }
244     (void)memset_s(ptr, bytes, 0, bytes);
245 
246     auto itemPtr = &ptr->chunks_;
247     for (auto &text : itemText) {
248         itemPtr->txtLen_ = (0xFF & text.size());
249         auto ret = memcpy_s(itemPtr->text_, itemPtr->txtLen_ + 1, text.data(), itemPtr->txtLen_ + 1);
250         if (ret != EOK) {
251             delete[] (char *)ptr;
252             return nullptr;
253         }
254         itemPtr = (SdesChunk *)((char *)itemPtr + itemPtr->TotalBytes());
255     }
256 
257     SetupHeader(ptr, RtcpType::RTCP_SDES, itemText.size(), bytes);
258     SetupPadding(ptr, bytes - realSize);
259     return std::shared_ptr<RtcpSdes>(ptr, [](RtcpSdes *ptr) { delete[] (char *)ptr; });
260 }
261 
GetChunkList()262 std::vector<SdesChunk *> RtcpSdes::GetChunkList()
263 {
264     std::vector<SdesChunk *> list;
265     SdesChunk *ptr = &chunks_;
266     for (int32_t i = 0; i < (int32_t)reportCount_; ++i) {
267         list.emplace_back(ptr);
268         ptr = (SdesChunk *)((char *)ptr + ptr->TotalBytes());
269     }
270 
271     return list;
272 }
273 
274 //------------------------------ RtcpFB ------------------------------//
275 
Create(PsfbType fmt,const void * fci,size_t fciLen)276 std::shared_ptr<RtcpFB> RtcpFB::Create(PsfbType fmt, const void *fci, size_t fciLen)
277 {
278     return RtcpFB::CreateInner(RtcpType::RTCP_PSFB, (int32_t)fmt, fci, fciLen);
279 }
280 
Create(RtpfbType fmt,const void * fci,size_t fciLen)281 std::shared_ptr<RtcpFB> RtcpFB::Create(RtpfbType fmt, const void *fci, size_t fciLen)
282 {
283     return RtcpFB::CreateInner(RtcpType::RTCP_RTPFB, (int32_t)fmt, fci, fciLen);
284 }
285 
GetFciPtr() const286 const uint8_t *RtcpFB::GetFciPtr() const
287 {
288     return (uint8_t *)&ssrcMedia_ + sizeof(ssrcMedia_);
289 }
290 
GetFciSize() const291 int32_t RtcpFB::GetFciSize() const
292 {
293     return GetSize() - GetPaddingSize() - sizeof(RtcpFB);
294 }
295 
CreateInner(RtcpType type,int32_t fmt,const void * fci,size_t fciLen)296 std::shared_ptr<RtcpFB> RtcpFB::CreateInner(RtcpType type, int32_t fmt, const void *fci, size_t fciLen)
297 {
298     if (!fci) {
299         fciLen = 0;
300     }
301 
302     auto realSize = sizeof(RtcpFB) + fciLen;
303     auto bytes = AlignSize(realSize);
304     if (bytes == 0 || bytes < 0) {
305         return nullptr;
306     }
307     auto ptr = (RtcpFB *)new char[bytes];
308     if (ptr == nullptr) {
309         return nullptr;
310     }
311     if (fci && fciLen) {
312         auto ret = memcpy_s((char *)ptr + sizeof(RtcpFB), fciLen, fci, fciLen);
313         if (ret != EOK) {
314             return nullptr;
315         }
316     }
317     SetupHeader(ptr, type, fmt, bytes);
318     SetupPadding(ptr, bytes - realSize);
319     return std::shared_ptr<RtcpFB>((RtcpFB *)ptr, [](RtcpFB *ptr) { delete[] (char *)ptr; });
320 }
321 
322 //------------------------------ RtcpBye ------------------------------//
323 
Create(const std::vector<uint32_t> & ssrcs,const std::string & reason)324 std::shared_ptr<RtcpBye> RtcpBye::Create(const std::vector<uint32_t> &ssrcs, const std::string &reason)
325 {
326     auto realSize = sizeof(RtcpHeader) + sizeof(uint32_t) * ssrcs.size() + 1 + reason.size();
327     auto bytes = AlignSize(realSize);
328     if (bytes == 0 || bytes < 0) {
329         return nullptr;
330     }
331     auto ptr = (RtcpBye *)new char[bytes];
332     if (ptr == nullptr) {
333         return nullptr;
334     }
335     SetupHeader(ptr, RtcpType::RTCP_BYE, ssrcs.size(), bytes);
336     SetupPadding(ptr, bytes - realSize);
337 
338     int32_t i = 0;
339     for (auto ssrc : ssrcs) {
340         ((RtcpBye *)ptr)->ssrc_[i++] = htonl(ssrc);
341     }
342 
343     if (!reason.empty()) {
344         uint8_t *reasonLenPtr = (uint8_t *)ptr + sizeof(RtcpHeader) + sizeof(uint32_t) * ssrcs.size();
345         *reasonLenPtr = reason.size() & 0xFF;
346         auto ret = memcpy_s(reasonLenPtr + 1, *reasonLenPtr, reason.data(), *reasonLenPtr);
347         if (ret != EOK) {
348             return nullptr;
349         }
350     }
351 
352     return std::shared_ptr<RtcpBye>(ptr, [](RtcpBye *ptr) { delete[] (char *)ptr; });
353 }
354 
GetSSRC() const355 std::vector<uint32_t> RtcpBye::GetSSRC() const
356 {
357     std::vector<uint32_t> ret;
358     for (size_t i = 0; i < reportCount_; ++i) {
359         ret.emplace_back(ntohl(ssrc_[i]));
360     }
361 
362     return ret;
363 }
364 
GetReason() const365 std::string RtcpBye::GetReason() const
366 {
367     auto *reasonLenPtr = (uint8_t *)ssrc_ + sizeof(uint32_t) * reportCount_;
368     if (reasonLenPtr + 1 >= (uint8_t *)this + GetSize()) {
369         return "";
370     }
371 
372     return std::string((char *)reasonLenPtr + 1, *reasonLenPtr);
373 }
374 
375 //-----------------------------------------------------------------------------
376 
Create(size_t itemCount)377 std::shared_ptr<RtcpXRDLRR> RtcpXRDLRR::Create(size_t itemCount)
378 {
379     auto realSize = sizeof(RtcpXRDLRR) - sizeof(RtcpXRDLRRReportItem) + itemCount * sizeof(RtcpXRDLRRReportItem);
380     auto bytes = AlignSize(realSize);
381     if (bytes == 0 || bytes < 0) {
382         return nullptr;
383     }
384     auto ptr = (RtcpXRDLRR *)new char[bytes];
385     if (ptr == nullptr) {
386         return nullptr;
387     }
388     SetupHeader(ptr, RtcpType::RTCP_XR, 0, bytes);
389     SetupPadding(ptr, bytes - realSize);
390     return std::shared_ptr<RtcpXRDLRR>(ptr, [](RtcpXRDLRR *ptr) { delete[] (char *)ptr; });
391 }
392 
GetItemList()393 std::vector<RtcpXRDLRRReportItem *> RtcpXRDLRR::GetItemList()
394 {
395     auto count = blockLength_ / 3;
396     RtcpXRDLRRReportItem *ptr = &items_;
397     std::vector<RtcpXRDLRRReportItem *> list;
398     for (int32_t i = 0; i < (int32_t)count; ++i) {
399         list.emplace_back(ptr);
400         ++ptr;
401     }
402 
403     return list;
404 }
405 
406 } // namespace Sharing
407 } // namespace OHOS