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