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((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>(((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 ((uint8_t *)rtcp)[rtcp->GetSize() - 1] = paddingSize & 0xFF;
76 } else {
77 rtcp->padding_ = 0;
78 }
79 }
80
81 //------------------------------ RtcpSR ------------------------------//
82
Create(int32_t itemCount)83 std::shared_ptr<RtcpSR> RtcpSR::Create(int32_t itemCount)
84 {
85 auto realSize = sizeof(RtcpSR) - sizeof(ReportItem) + itemCount * sizeof(ReportItem);
86 auto bytes = AlignSize(realSize);
87 if (bytes == 0 || bytes < 0) {
88 return nullptr;
89 }
90 auto ptr = (RtcpSR *)new char[bytes];
91 if (ptr == nullptr) {
92 return nullptr;
93 }
94 SetupHeader(ptr, RtcpType::RTCP_SR, itemCount, bytes);
95 SetupPadding(ptr, bytes - realSize);
96
97 return std::shared_ptr<RtcpSR>(ptr, [](RtcpSR *ptr) { delete[] (char *)ptr; });
98 }
99
SetNtpStamp(timeval tv)100 RtcpSR &RtcpSR::SetNtpStamp(timeval tv)
101 {
102 ntpmsw_ = htonl(tv.tv_sec + 0x83AA7E80); /* 0x83AA7E80 is the number of seconds from 1900 to 1970 */
103 ntplsw_ = htonl((uint32_t)((double)tv.tv_usec * (double)(((uint64_t)1) << 32) * 1.0e-6)); // 32:byte offset
104 return *this;
105 }
106
SetNtpStamp(uint64_t unixStampMs)107 RtcpSR &RtcpSR::SetNtpStamp(uint64_t unixStampMs)
108 {
109 timeval tv;
110 tv.tv_sec = unixStampMs / 1000; // 1000:unit
111 tv.tv_usec = (unixStampMs % 1000) * 1000; // 1000:unit
112 return SetNtpStamp(tv);
113 }
114
GetNtpStamp() const115 std::string RtcpSR::GetNtpStamp() const
116 {
117 struct timeval tv;
118 tv.tv_sec = ntpmsw_ - 0x83AA7E80;
119 tv.tv_usec = (decltype(tv.tv_usec))(ntplsw_ / ((double)(((uint64_t)1) << 32) * 1.0e-6)); // 32:byte offset, 6:-
120
121 char ts[30] = {0};
122 auto tm = localtime(&tv.tv_sec);
123 if (tm == nullptr) {
124 return {};
125 }
126 if (strftime(ts, sizeof(ts), "%Y-%m-%d %H:%M:%S", tm) < 0) {
127 return {};
128 }
129 if (sprintf_s(ts + strlen(ts), sizeof(ts) - strlen(ts), ".%06lld", static_cast<long long>(tv.tv_usec)) < 0) {
130 return {};
131 }
132 // format: "2022-09-02 17:27:04.021154"
133 return std::string(ts);
134 }
135
GetNtpUnixStampMS() const136 uint64_t RtcpSR::GetNtpUnixStampMS() const
137 {
138 if (ntpmsw_ < 0x83AA7E80 /*1970 year*/) {
139 return 0;
140 }
141 struct timeval tv;
142 tv.tv_sec = ntpmsw_ - 0x83AA7E80;
143 tv.tv_usec = (decltype(tv.tv_usec))(ntplsw_ / ((double)(((uint64_t)1) << 32) * 1.0e-6)); // 32:byte offset, 6:-
144
145 return 1000 * tv.tv_sec + tv.tv_usec / 1000; // 1000:unit
146 }
147
SetSsrc(uint32_t ssrc)148 RtcpSR &RtcpSR::SetSsrc(uint32_t ssrc)
149 {
150 ssrc_ = htonl(ssrc);
151 return *this;
152 }
153
GetSsrc() const154 uint32_t RtcpSR::GetSsrc() const
155 {
156 return ntohl(ssrc_);
157 }
158
SetPacketCount(uint32_t count)159 RtcpSR &RtcpSR::SetPacketCount(uint32_t count)
160 {
161 packetCount_ = htonl(count);
162 return *this;
163 }
164
GetPacketCount() const165 uint32_t RtcpSR::GetPacketCount() const
166 {
167 return ntohl(packetCount_);
168 }
169
GetItemList()170 std::vector<ReportItem *> RtcpSR::GetItemList()
171 {
172 std::vector<ReportItem *> list;
173 ReportItem *ptr = &items_;
174 for (int32_t i = 0; i < (int32_t)reportCount_; ++i) {
175 list.emplace_back(ptr);
176 ++ptr;
177 }
178
179 return list;
180 }
181
182 //------------------------------ RtcpRR ------------------------------//
183
Create(size_t itemCount)184 std::shared_ptr<RtcpRR> RtcpRR::Create(size_t itemCount)
185 {
186 auto realSize = sizeof(RtcpRR) - sizeof(ReportItem) + itemCount * sizeof(ReportItem);
187 auto bytes = AlignSize(realSize);
188 if (bytes == 0 || bytes < 0) {
189 return nullptr;
190 }
191 auto ptr = (RtcpRR *)new char[bytes];
192 if (ptr == nullptr) {
193 return nullptr;
194 }
195 SetupHeader(ptr, RtcpType::RTCP_RR, itemCount, bytes);
196 SetupPadding(ptr, bytes - realSize);
197 return std::shared_ptr<RtcpRR>(ptr, [](RtcpRR *ptr) { delete[] (char *)ptr; });
198 }
199
GetItemList()200 std::vector<ReportItem *> RtcpRR::GetItemList()
201 {
202 std::vector<ReportItem *> list;
203 ReportItem *ptr = &items_;
204 for (int32_t i = 0; i < (int32_t)reportCount_; ++i) {
205 list.emplace_back(ptr);
206 ++ptr;
207 }
208
209 return list;
210 }
211
212 //------------------------------ RtcpSdes ------------------------------//
213
TotalBytes() const214 size_t SdesChunk::TotalBytes() const
215 {
216 return AlignSize(MinSize() + txtLen_);
217 }
218
219 // chunk length without variable length information
MinSize()220 size_t SdesChunk::MinSize()
221 {
222 return sizeof(SdesChunk) - sizeof(text_);
223 }
224
Create(const std::vector<std::string> & itemText)225 std::shared_ptr<RtcpSdes> RtcpSdes::Create(const std::vector<std::string> &itemText)
226 {
227 size_t itemTotalSize = 0;
228 for (auto &text : itemText) {
229 itemTotalSize += AlignSize(SdesChunk::MinSize() + (0xFF & text.size()));
230 }
231 auto realSize = sizeof(RtcpSdes) - sizeof(SdesChunk) + itemTotalSize;
232 auto bytes = AlignSize(realSize);
233 if (bytes == 0 || bytes < 0) {
234 return nullptr;
235 }
236 auto ptr = (RtcpSdes *)new char[bytes];
237 if (ptr == nullptr) {
238 return nullptr;
239 }
240 memset_s(ptr, bytes, 0, bytes);
241
242 auto itemPtr = &ptr->chunks_;
243 for (auto &text : itemText) {
244 itemPtr->txtLen_ = (0xFF & text.size());
245 auto ret = memcpy_s(itemPtr->text_, itemPtr->txtLen_ + 1, text.data(), itemPtr->txtLen_ + 1);
246 if (ret != EOK) {
247 return nullptr;
248 }
249 itemPtr = (SdesChunk *)((char *)itemPtr + itemPtr->TotalBytes());
250 }
251
252 SetupHeader(ptr, RtcpType::RTCP_SDES, itemText.size(), bytes);
253 SetupPadding(ptr, bytes - realSize);
254 return std::shared_ptr<RtcpSdes>(ptr, [](RtcpSdes *ptr) { delete[] (char *)ptr; });
255 }
256
GetChunkList()257 std::vector<SdesChunk *> RtcpSdes::GetChunkList()
258 {
259 std::vector<SdesChunk *> list;
260 SdesChunk *ptr = &chunks_;
261 for (int32_t i = 0; i < (int32_t)reportCount_; ++i) {
262 list.emplace_back(ptr);
263 ptr = (SdesChunk *)((char *)ptr + ptr->TotalBytes());
264 }
265
266 return list;
267 }
268
269 //------------------------------ RtcpFB ------------------------------//
270
Create(PsfbType fmt,const void * fci,size_t fciLen)271 std::shared_ptr<RtcpFB> RtcpFB::Create(PsfbType fmt, const void *fci, size_t fciLen)
272 {
273 return RtcpFB::CreateInner(RtcpType::RTCP_PSFB, (int32_t)fmt, fci, fciLen);
274 }
275
Create(RtpfbType fmt,const void * fci,size_t fciLen)276 std::shared_ptr<RtcpFB> RtcpFB::Create(RtpfbType fmt, const void *fci, size_t fciLen)
277 {
278 return RtcpFB::CreateInner(RtcpType::RTCP_RTPFB, (int32_t)fmt, fci, fciLen);
279 }
280
GetFciPtr() const281 const uint8_t *RtcpFB::GetFciPtr() const
282 {
283 return (uint8_t *)&ssrcMedia_ + sizeof(ssrcMedia_);
284 }
285
GetFciSize() const286 int32_t RtcpFB::GetFciSize() const
287 {
288 return GetSize() - GetPaddingSize() - sizeof(RtcpFB);
289 }
290
CreateInner(RtcpType type,int32_t fmt,const void * fci,size_t fciLen)291 std::shared_ptr<RtcpFB> RtcpFB::CreateInner(RtcpType type, int32_t fmt, const void *fci, size_t fciLen)
292 {
293 if (!fci) {
294 fciLen = 0;
295 }
296
297 auto realSize = sizeof(RtcpFB) + fciLen;
298 auto bytes = AlignSize(realSize);
299 if (bytes == 0 || bytes < 0) {
300 return nullptr;
301 }
302 auto ptr = (RtcpFB *)new char[bytes];
303 if (fci && fciLen) {
304 auto ret = memcpy_s((char *)ptr + sizeof(RtcpFB), fciLen, fci, fciLen);
305 if (ret != EOK) {
306 return nullptr;
307 }
308 }
309 SetupHeader(ptr, type, fmt, bytes);
310 SetupPadding(ptr, bytes - realSize);
311 return std::shared_ptr<RtcpFB>((RtcpFB *)ptr, [](RtcpFB *ptr) { delete[] (char *)ptr; });
312 }
313
314 //------------------------------ RtcpBye ------------------------------//
315
Create(const std::vector<uint32_t> & ssrcs,const std::string & reason)316 std::shared_ptr<RtcpBye> RtcpBye::Create(const std::vector<uint32_t> &ssrcs, const std::string &reason)
317 {
318 auto realSize = sizeof(RtcpHeader) + sizeof(uint32_t) * ssrcs.size() + 1 + reason.size();
319 auto bytes = AlignSize(realSize);
320 if (bytes == 0 || bytes < 0) {
321 return nullptr;
322 }
323 auto ptr = (RtcpBye *)new char[bytes];
324 if (ptr == nullptr) {
325 return nullptr;
326 }
327 SetupHeader(ptr, RtcpType::RTCP_BYE, ssrcs.size(), bytes);
328 SetupPadding(ptr, bytes - realSize);
329
330 int32_t i = 0;
331 for (auto ssrc : ssrcs) {
332 ((RtcpBye *)ptr)->ssrc_[i++] = htonl(ssrc);
333 }
334
335 if (!reason.empty()) {
336 uint8_t *reasonLenPtr = (uint8_t *)ptr + sizeof(RtcpHeader) + sizeof(uint32_t) * ssrcs.size();
337 *reasonLenPtr = reason.size() & 0xFF;
338 auto ret = memcpy_s(reasonLenPtr + 1, *reasonLenPtr, reason.data(), *reasonLenPtr);
339 if (ret != EOK) {
340 return nullptr;
341 }
342 }
343
344 return std::shared_ptr<RtcpBye>(ptr, [](RtcpBye *ptr) { delete[] (char *)ptr; });
345 }
346
GetSSRC() const347 std::vector<uint32_t> RtcpBye::GetSSRC() const
348 {
349 std::vector<uint32_t> ret;
350 for (size_t i = 0; i < reportCount_; ++i) {
351 ret.emplace_back(ntohl(ssrc_[i]));
352 }
353
354 return ret;
355 }
356
GetReason() const357 std::string RtcpBye::GetReason() const
358 {
359 auto *reasonLenPtr = (uint8_t *)ssrc_ + sizeof(uint32_t) * reportCount_;
360 if (reasonLenPtr + 1 >= (uint8_t *)this + GetSize()) {
361 return "";
362 }
363
364 return std::string((char *)reasonLenPtr + 1, *reasonLenPtr);
365 }
366
367 //-----------------------------------------------------------------------------
368
Create(size_t itemCount)369 std::shared_ptr<RtcpXRDLRR> RtcpXRDLRR::Create(size_t itemCount)
370 {
371 auto realSize = sizeof(RtcpXRDLRR) - sizeof(RtcpXRDLRRReportItem) + itemCount * sizeof(RtcpXRDLRRReportItem);
372 auto bytes = AlignSize(realSize);
373 if (bytes == 0 || bytes < 0) {
374 return nullptr;
375 }
376 auto ptr = (RtcpXRDLRR *)new char[bytes];
377 if (ptr == nullptr) {
378 return nullptr;
379 }
380 SetupHeader(ptr, RtcpType::RTCP_XR, 0, bytes);
381 SetupPadding(ptr, bytes - realSize);
382 return std::shared_ptr<RtcpXRDLRR>(ptr, [](RtcpXRDLRR *ptr) { delete[] (char *)ptr; });
383 }
384
GetItemList()385 std::vector<RtcpXRDLRRReportItem *> RtcpXRDLRR::GetItemList()
386 {
387 auto count = blockLength_ / 3;
388 RtcpXRDLRRReportItem *ptr = &items_;
389 std::vector<RtcpXRDLRRReportItem *> list;
390 for (int32_t i = 0; i < (int32_t)count; ++i) {
391 list.emplace_back(ptr);
392 ++ptr;
393 }
394
395 return list;
396 }
397
398 } // namespace Sharing
399 } // namespace OHOS