• 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((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