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 ((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 = (int32_t)sizeof(RtcpSR) - (int32_t)sizeof(ReportItem) + itemCount * (int32_t)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 = (int64_t)(unixStampMs / 1000); // 1000:unit
111 tv.tv_usec = (int64_t)((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 += (size_t)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 delete[] (char *)ptr;
248 return nullptr;
249 }
250 itemPtr = (SdesChunk *)((char *)itemPtr + itemPtr->TotalBytes());
251 }
252
253 SetupHeader(ptr, RtcpType::RTCP_SDES, itemText.size(), bytes);
254 SetupPadding(ptr, bytes - realSize);
255 return std::shared_ptr<RtcpSdes>(ptr, [](RtcpSdes *ptr) { delete[] (char *)ptr; });
256 }
257
GetChunkList()258 std::vector<SdesChunk *> RtcpSdes::GetChunkList()
259 {
260 std::vector<SdesChunk *> list;
261 SdesChunk *ptr = &chunks_;
262 for (int32_t i = 0; i < (int32_t)reportCount_; ++i) {
263 list.emplace_back(ptr);
264 ptr = (SdesChunk *)((char *)ptr + ptr->TotalBytes());
265 }
266
267 return list;
268 }
269
270 //------------------------------ RtcpFB ------------------------------//
271
Create(PsfbType fmt,const void * fci,size_t fciLen)272 std::shared_ptr<RtcpFB> RtcpFB::Create(PsfbType fmt, const void *fci, size_t fciLen)
273 {
274 return RtcpFB::CreateInner(RtcpType::RTCP_PSFB, (int32_t)fmt, fci, fciLen);
275 }
276
Create(RtpfbType fmt,const void * fci,size_t fciLen)277 std::shared_ptr<RtcpFB> RtcpFB::Create(RtpfbType fmt, const void *fci, size_t fciLen)
278 {
279 return RtcpFB::CreateInner(RtcpType::RTCP_RTPFB, (int32_t)fmt, fci, fciLen);
280 }
281
GetFciPtr() const282 const uint8_t *RtcpFB::GetFciPtr() const
283 {
284 return (uint8_t *)&ssrcMedia_ + sizeof(ssrcMedia_);
285 }
286
GetFciSize() const287 int32_t RtcpFB::GetFciSize() const
288 {
289 return GetSize() - GetPaddingSize() - sizeof(RtcpFB);
290 }
291
CreateInner(RtcpType type,int32_t fmt,const void * fci,size_t fciLen)292 std::shared_ptr<RtcpFB> RtcpFB::CreateInner(RtcpType type, int32_t fmt, const void *fci, size_t fciLen)
293 {
294 if (!fci) {
295 fciLen = 0;
296 }
297
298 auto realSize = sizeof(RtcpFB) + fciLen;
299 auto bytes = AlignSize(realSize);
300 if (bytes == 0 || bytes < 0) {
301 return nullptr;
302 }
303 auto ptr = (RtcpFB *)new char[bytes];
304 if (fci && fciLen) {
305 auto ret = memcpy_s((char *)ptr + sizeof(RtcpFB), fciLen, fci, fciLen);
306 if (ret != EOK) {
307 return nullptr;
308 }
309 }
310 SetupHeader(ptr, type, fmt, bytes);
311 SetupPadding(ptr, bytes - realSize);
312 return std::shared_ptr<RtcpFB>((RtcpFB *)ptr, [](RtcpFB *ptr) { delete[] (char *)ptr; });
313 }
314
315 //------------------------------ RtcpBye ------------------------------//
316
Create(const std::vector<uint32_t> & ssrcs,const std::string & reason)317 std::shared_ptr<RtcpBye> RtcpBye::Create(const std::vector<uint32_t> &ssrcs, const std::string &reason)
318 {
319 auto realSize = sizeof(RtcpHeader) + sizeof(uint32_t) * ssrcs.size() + 1 + reason.size();
320 auto bytes = AlignSize(realSize);
321 if (bytes == 0 || bytes < 0) {
322 return nullptr;
323 }
324 auto ptr = (RtcpBye *)new char[bytes];
325 if (ptr == nullptr) {
326 return nullptr;
327 }
328 SetupHeader(ptr, RtcpType::RTCP_BYE, ssrcs.size(), bytes);
329 SetupPadding(ptr, bytes - realSize);
330
331 int32_t i = 0;
332 for (auto ssrc : ssrcs) {
333 ((RtcpBye *)ptr)->ssrc_[i++] = htonl(ssrc);
334 }
335
336 if (!reason.empty()) {
337 uint8_t *reasonLenPtr = (uint8_t *)ptr + sizeof(RtcpHeader) + sizeof(uint32_t) * ssrcs.size();
338 *reasonLenPtr = reason.size() & 0xFF;
339 auto ret = memcpy_s(reasonLenPtr + 1, *reasonLenPtr, reason.data(), *reasonLenPtr);
340 if (ret != EOK) {
341 return nullptr;
342 }
343 }
344
345 return std::shared_ptr<RtcpBye>(ptr, [](RtcpBye *ptr) { delete[] (char *)ptr; });
346 }
347
GetSSRC() const348 std::vector<uint32_t> RtcpBye::GetSSRC() const
349 {
350 std::vector<uint32_t> ret;
351 for (size_t i = 0; i < reportCount_; ++i) {
352 ret.emplace_back(ntohl(ssrc_[i]));
353 }
354
355 return ret;
356 }
357
GetReason() const358 std::string RtcpBye::GetReason() const
359 {
360 auto *reasonLenPtr = (uint8_t *)ssrc_ + sizeof(uint32_t) * reportCount_;
361 if (reasonLenPtr + 1 >= (uint8_t *)this + GetSize()) {
362 return "";
363 }
364
365 return std::string((char *)reasonLenPtr + 1, *reasonLenPtr);
366 }
367
368 //-----------------------------------------------------------------------------
369
Create(size_t itemCount)370 std::shared_ptr<RtcpXRDLRR> RtcpXRDLRR::Create(size_t itemCount)
371 {
372 auto realSize = sizeof(RtcpXRDLRR) - sizeof(RtcpXRDLRRReportItem) + itemCount * sizeof(RtcpXRDLRRReportItem);
373 auto bytes = AlignSize(realSize);
374 if (bytes == 0 || bytes < 0) {
375 return nullptr;
376 }
377 auto ptr = (RtcpXRDLRR *)new char[bytes];
378 if (ptr == nullptr) {
379 return nullptr;
380 }
381 SetupHeader(ptr, RtcpType::RTCP_XR, 0, bytes);
382 SetupPadding(ptr, bytes - realSize);
383 return std::shared_ptr<RtcpXRDLRR>(ptr, [](RtcpXRDLRR *ptr) { delete[] (char *)ptr; });
384 }
385
GetItemList()386 std::vector<RtcpXRDLRRReportItem *> RtcpXRDLRR::GetItemList()
387 {
388 auto count = blockLength_ / 3;
389 RtcpXRDLRRReportItem *ptr = &items_;
390 std::vector<RtcpXRDLRRReportItem *> list;
391 for (int32_t i = 0; i < (int32_t)count; ++i) {
392 list.emplace_back(ptr);
393 ++ptr;
394 }
395
396 return list;
397 }
398
399 } // namespace Sharing
400 } // namespace OHOS