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 "wfd_message.h"
17 #include <iomanip>
18 #include <iostream>
19 #include <sstream>
20 #include <cstdio>
21 #include "common/sharing_log.h"
22
23 namespace OHOS {
24 namespace Sharing {
25 constexpr int32_t BIT_OFFSET_TWO = 2;
26 constexpr int32_t BIT_OFFSET_THREE = 3;
27 constexpr int32_t BIT_OFFSET_EIGHT = 8;
28
WfdRtspM1Response(int32_t cseq,int32_t status)29 WfdRtspM1Response::WfdRtspM1Response(int32_t cseq, int32_t status) : RtspResponseOptions(cseq, status)
30 {
31 std::stringstream ss;
32 ss << RTSP_METHOD_WFD << "," << RTSP_SP << RTSP_METHOD_SET_PARAMETER << "," << RTSP_SP << RTSP_METHOD_GET_PARAMETER;
33 SetPublicItems(ss.str());
34 }
35
Parse(const std::string & response)36 RtspError WfdRtspM3Response::Parse(const std::string &response)
37 {
38 auto res = RtspResponse::Parse(response);
39 if (res.code != RtspErrorType::OK) {
40 return res;
41 }
42
43 RtspCommon::SplitParameter(body_, params_);
44 return {};
45 }
46
Stringify()47 std::string WfdRtspM3Response::Stringify()
48 {
49 std::stringstream body;
50 std::stringstream ss;
51
52 for (auto ¶m : params_) {
53 body << param.first << ":" << RTSP_SP << param.second << RTSP_CRLF;
54 }
55
56 ss << RTSP_TOKEN_CONTENT_TYPE << ":" << RTSP_SP << "text/parameters" << RTSP_CRLF;
57 ss << RTSP_TOKEN_CONTENT_LENGTH << ":" << RTSP_SP << body.str().length();
58
59 ClearCustomHeader();
60 AddCustomHeader(ss.str());
61
62 if (body.str().empty()) {
63 return RtspResponse::Stringify();
64 }
65
66 return RtspResponse::Stringify() + body.str();
67 }
68
SetVideoFormats(VideoFormat format)69 void WfdRtspM3Response::SetVideoFormats(VideoFormat format)
70 {
71 std::stringstream ss;
72 std::stringstream sinkVideoList;
73
74 uint8_t native = 0;
75 uint8_t h264Profile = (1 << (uint8_t)WfdH264Profile::PROFILE_CHP);
76 uint8_t h264Level = (1 << (uint8_t)WfdH264Level::LEVEL_42);
77 uint32_t ceaResolutionIndex = 0;
78 uint32_t vesaResolutionIndex = 0;
79 uint32_t hhResolutionIndex = 0;
80
81 switch (format) {
82 case VIDEO_1920X1080_30:
83 native = (uint8_t)WfdResolutionType::RESOLUTION_CEA | (CEA_1920_1080_P30 << BIT_OFFSET_THREE);
84 ceaResolutionIndex = (1 << CEA_1920_1080_P30);
85 break;
86 case VIDEO_1920X1080_25:
87 native = (uint8_t)WfdResolutionType::RESOLUTION_CEA | (CEA_1920_1080_P25 << BIT_OFFSET_THREE);
88 ceaResolutionIndex = (1 << CEA_1920_1080_P25);
89 break;
90 case VIDEO_1280X720_30:
91 native = (uint8_t)WfdResolutionType::RESOLUTION_CEA | (CEA_1280_720_P30 << BIT_OFFSET_THREE);
92 ceaResolutionIndex = (1 << CEA_1280_720_P30);
93 break;
94 case VIDEO_1280X720_25:
95 native = (uint8_t)WfdResolutionType::RESOLUTION_CEA | (CEA_1280_720_P25 << BIT_OFFSET_THREE);
96 ceaResolutionIndex = (1 << CEA_1280_720_P25);
97 break;
98 case VIDEO_640X480_60:
99 default:
100 native =
101 (uint8_t)WfdResolutionType::RESOLUTION_CEA | (WfdCeaResolution::CEA_640_480_P60 << BIT_OFFSET_THREE);
102 ceaResolutionIndex = (1 << CEA_640_480_P60);
103 break;
104 }
105
106 ss << std::setfill('0') << std::setw(BIT_OFFSET_TWO) << std::hex << (int32_t)native << RTSP_SP << "00" << RTSP_SP;
107 ss << std::setfill('0') << std::setw(BIT_OFFSET_TWO) << std::hex << (int32_t)h264Profile << RTSP_SP;
108 ss << std::setfill('0') << std::setw(BIT_OFFSET_TWO) << std::hex << (int32_t)h264Level << RTSP_SP;
109 ss << std::setfill('0') << std::setw(BIT_OFFSET_EIGHT) << std::hex << ceaResolutionIndex << RTSP_SP;
110 ss << std::setfill('0') << std::setw(BIT_OFFSET_EIGHT) << std::hex << vesaResolutionIndex << RTSP_SP;
111 ss << std::setfill('0') << std::setw(BIT_OFFSET_EIGHT) << std::hex << hhResolutionIndex << RTSP_SP;
112
113 ss << "00 0000 0000 00 none none";
114
115 params_.emplace_back(WFD_PARAM_VIDEO_FORMATS, ss.str());
116 }
117
SetAudioCodecs(AudioFormat format)118 void WfdRtspM3Response::SetAudioCodecs(AudioFormat format)
119 {
120 std::stringstream ss;
121 switch (format) {
122 case AUDIO_44100_8_2:
123 ss << "LPCM" << RTSP_SP << "00000001 00";
124 break;
125 case AUDIO_44100_16_2:
126 ss << "LPCM" << RTSP_SP << "00000002 00";
127 break;
128 case AUDIO_48000_16_2:
129 ss << "AAC" << RTSP_SP << "00000001 00";
130 break;
131 default:
132 ss << "AAC" << RTSP_SP << "00000001 00";
133 break;
134 }
135
136 params_.emplace_back(WFD_PARAM_AUDIO_CODECS, ss.str());
137 }
138
SetClientRtpPorts(int32_t port)139 void WfdRtspM3Response::SetClientRtpPorts(int32_t port)
140 {
141 std::stringstream ss;
142 ss << "RTP/AVP/UDP;unicast" << RTSP_SP << port << RTSP_SP << 0 << RTSP_SP << "mode=play";
143 params_.emplace_back(WFD_PARAM_RTP_PORTS, ss.str());
144 }
145
SetContentProtection(const std::string & value)146 void WfdRtspM3Response::SetContentProtection(const std::string &value)
147 {
148 params_.emplace_back(WFD_PARAM_CONTENT_PROTECTION, value);
149 }
150
SetCoupledSink(const std::string & value)151 void WfdRtspM3Response::SetCoupledSink(const std::string &value)
152 {
153 params_.emplace_back(WFD_PARAM_COUPLED_SINK, value);
154 }
155
SetUibcCapability(const std::string & value)156 void WfdRtspM3Response::SetUibcCapability(const std::string &value)
157 {
158 params_.emplace_back(WFD_PARAM_UIBC_CAPABILITY, value);
159 }
160
SetStandbyResumeCapability(const std::string & value)161 void WfdRtspM3Response::SetStandbyResumeCapability(const std::string &value)
162 {
163 params_.emplace_back(WFD_PARAM_UIBC_CAPABILITY, value);
164 }
165
SetCustomParam(const std::string & key,const std::string & value)166 void WfdRtspM3Response::SetCustomParam(const std::string &key, const std::string &value)
167 {
168 params_.emplace_back(key, value);
169 }
170
GetClientRtpPorts()171 int32_t WfdRtspM3Response::GetClientRtpPorts()
172 {
173 int32_t port0 = -1;
174 int32_t port1 = -1;
175 std::string profile = "RTP/AVP/UDP;unicast";
176 std::string mode = "mode=play";
177 std::string value = GetCustomParam(WFD_PARAM_RTP_PORTS);
178 std::stringstream ss(value);
179 ss >> profile >> port0 >> port1 >> mode;
180 return port0;
181 }
182
GetUibcCapability()183 std::string WfdRtspM3Response::GetUibcCapability()
184 {
185 std::string value = GetCustomParam(WFD_PARAM_UIBC_CAPABILITY);
186 return value;
187 }
188
GetAudioCodecs()189 AudioFormat WfdRtspM3Response::GetAudioCodecs()
190 {
191 std::string value = GetCustomParam(WFD_PARAM_AUDIO_CODECS);
192 int32_t audioFormat0 = -1;
193 int32_t audioFormat1 = -1;
194 std::string format;
195 auto audioCaps = RtspCommon::Split(value, ", ");
196 for (size_t i = 0; i < audioCaps.size(); i++) {
197 std::string audioCap = audioCaps[i];
198 std::stringstream ss(audioCap);
199 ss >> format >> audioFormat0 >> audioFormat1;
200 if (format == "LPCM") { // LPCM
201 continue;
202 } else if (format == "AAC") { // AAC
203 if (audioFormat0 == 1) {
204 return AUDIO_48000_16_2;
205 }
206 } else if (format == "AC3") { // AC3
207 if (audioFormat0 == 1) {
208 }
209 continue;
210 }
211 }
212 return AUDIO_48000_8_2;
213 }
214
GetCoupledSink()215 std::string WfdRtspM3Response::GetCoupledSink()
216 {
217 std::string value = GetCustomParam(WFD_PARAM_COUPLED_SINK);
218 return value;
219 }
220
GetContentProtection()221 std::string WfdRtspM3Response::GetContentProtection()
222 {
223 std::string value = GetCustomParam(WFD_PARAM_CONTENT_PROTECTION);
224 return value;
225 }
226
GetVideoFormatsByCea(int index)227 VideoFormat WfdRtspM3Response::GetVideoFormatsByCea(int index)
228 {
229 WfdCeaResolution res = static_cast<WfdCeaResolution>(index);
230 switch (res) {
231 case CEA_640_480_P60:
232 return VIDEO_640X480_60;
233 case CEA_1280_720_P30:
234 return VIDEO_1280X720_30;
235 case CEA_1280_720_P60:
236 return VIDEO_1280X720_60;
237 case CEA_1920_1080_P25:
238 return VIDEO_1920X1080_25;
239 case CEA_1920_1080_P30:
240 return VIDEO_1920X1080_30;
241 case CEA_1920_1080_P60:
242 return VIDEO_1920X1080_60;
243 default:
244 return VIDEO_640X480_60;
245 }
246 }
247
GetVideoFormats()248 VideoFormat WfdRtspM3Response::GetVideoFormats()
249 {
250 // wfd_video_formats:
251 // 1 byte "native"
252 // 1 byte "preferred-display-mode-supported" 0 or 1
253 // one or more avc codec structures
254 // 1 byte profile
255 // 1 byte level
256 // 4 byte CEA mask
257 // 4 byte VESA mask
258 // 4 byte HH mask
259 // 1 byte latency
260 // 2 byte min-slice-slice
261 // 2 byte slice-enc-params
262 // 1 byte framerate-control-support
263 // max-hres (none or 2 byte)
264 // max-vres (none or 2 byte)
265 /**
266 * native: 2*2HEXDIG
267 * preferred-display-mode-supported: 2*2HEXDIG; 0-not supported, 1-supported, 2-255 reserved
268 * profile: 2*2HEXDIG, only one bit set
269 * level: 2*2HEXDIG, only one bit set
270 * CEA-Support: 8*8HEXDIG, 0-ignore
271 * VESA-Support:8*8HEXDIG, 0-ignore
272 * HH-Support: 8*8HEXDIG, 0-ignore
273 * latency: 2*2HEXDIG, decoder latency in units of 5 msecs
274 * min-slice-size: 4*4HEXDIG, number of macroblocks
275 * slice-enc-params: 4*4HEXDIG,
276 * frame-rate-control-support: 4*4HEXDIG
277 * max-hres: 4*4HEXDIG, "none" if preferred-display-mode-supported is 0
278 * max-vres: 4*4HEXDIG, "none" if preferred-display-mode-supported is 0
279 **/
280 std::string value = GetCustomParam(WFD_PARAM_VIDEO_FORMATS);
281 if (value.size() < MINIMAL_VIDEO_FORMAT_SIZE) {
282 return VIDEO_640X480_60;
283 }
284
285 std::string head = value.substr(0, 5); // 5: fix offset
286 uint16_t native = 0;
287 uint16_t preferredDisplayMode = 0;
288 int index = 0;
289 std::string temp = "";
290 bool run = true;
291 std::stringstream ss(head);
292 ss >> std::hex >> native >> std::hex >> preferredDisplayMode;
293 value = value.substr(5); // 5: fix offset
294
295 while (run) {
296 auto nPos = value.find_first_of(",", index + 1);
297 if (nPos != std::string::npos) {
298 index = nPos;
299 temp = value.substr(0, index);
300 } else {
301 temp = value.substr(index + 1);
302 run = false;
303 }
304 std::stringstream sss(temp);
305 WfdVideoFormatsInfo wfdVideoFormatsInfo;
306 wfdVideoFormatsInfo.native = native;
307 wfdVideoFormatsInfo.preferredDisplayMode = preferredDisplayMode;
308 sss >> std::hex >> wfdVideoFormatsInfo.profile >> std::hex >> wfdVideoFormatsInfo.level >> std::hex >>
309 wfdVideoFormatsInfo.ceaMask >> std::hex >> wfdVideoFormatsInfo.veaMask >> std::hex >>
310 wfdVideoFormatsInfo.hhMask >> std::hex >> wfdVideoFormatsInfo.latency >> std::hex >>
311 wfdVideoFormatsInfo.minSlice >> std::hex >> wfdVideoFormatsInfo.sliceEncParam >> std::hex >>
312 wfdVideoFormatsInfo.frameRateCtlSupport;
313 vWfdVideoFormatsInfo_.push_back(wfdVideoFormatsInfo);
314 }
315
316 uint8_t tableSelection = vWfdVideoFormatsInfo_[0].native & 0x7;
317 index = vWfdVideoFormatsInfo_[0].native >> BIT_OFFSET_THREE;
318 switch (tableSelection) {
319 case 0:
320 return GetVideoFormatsByCea(index);
321 default:
322 return VIDEO_640X480_60;
323 }
324 return VIDEO_640X480_60;
325 }
326
GetStandbyResumeCapability()327 std::string WfdRtspM3Response::GetStandbyResumeCapability()
328 {
329 std::string value = GetCustomParam(WFD_PARAM_STANDBY_RESUME);
330 return value;
331 }
332
GetCustomParam(const std::string & key)333 std::string WfdRtspM3Response::GetCustomParam(const std::string &key)
334 {
335 auto it = std::find_if(params_.begin(), params_.end(),
336 [=](std::pair<std::string, std::string> value) { return value.first == key; });
337 if (it != params_.end()) {
338 return it->second;
339 }
340
341 return "";
342 }
343
SetClientRtpPorts(int32_t port)344 void WfdRtspM4Request::SetClientRtpPorts(int32_t port)
345 {
346 std::stringstream ss;
347 ss << WFD_PARAM_RTP_PORTS << ":" << RTSP_SP << "RTP/AVP/UDP;unicast" << RTSP_SP << port << RTSP_SP << 0 << RTSP_SP
348 << "mode=play";
349 AddBodyItem(ss.str());
350 }
351
SetAudioCodecs(AudioFormat format)352 void WfdRtspM4Request::SetAudioCodecs(AudioFormat format)
353 {
354 std::stringstream ss;
355 ss << WFD_PARAM_AUDIO_CODECS << ":" << RTSP_SP;
356 switch (format) {
357 case AUDIO_44100_8_2:
358 ss << "LPCM" << RTSP_SP << "00000001 00";
359 break;
360 case AUDIO_44100_16_2:
361 ss << "LPCM" << RTSP_SP << "00000002 00";
362 break;
363 case AUDIO_48000_16_2:
364 ss << "AAC" << RTSP_SP << "00000001 00";
365 break;
366 default:
367 ss << "AAC" << RTSP_SP << "00000001 00";
368 break;
369 }
370 AddBodyItem(ss.str());
371 }
372
SetPresentationUrl(const std::string & ip)373 void WfdRtspM4Request::SetPresentationUrl(const std::string &ip)
374 {
375 std::stringstream ss;
376 ss << WFD_PARAM_PRESENTATION_URL << ":" << RTSP_SP << "rtsp://" << ip.c_str() << "/wfd1.0/streamid=0 none";
377 AddBodyItem(ss.str());
378 }
379
SetVideoFormats(const WfdVideoFormatsInfo & wfdVideoFormatsInfo,VideoFormat format)380 void WfdRtspM4Request::SetVideoFormats(const WfdVideoFormatsInfo &wfdVideoFormatsInfo, VideoFormat format)
381 {
382 std::stringstream ss;
383 uint32_t native = wfdVideoFormatsInfo.native;
384 uint32_t h264Profile = wfdVideoFormatsInfo.profile;
385 uint32_t h264Level = wfdVideoFormatsInfo.level;
386 uint32_t ceaResolutionIndex = 0;
387 uint32_t vesaResolutionIndex = 0;
388 uint32_t hhResolutionIndex = 0;
389 (void)ceaResolutionIndex;
390 (void)vesaResolutionIndex;
391 (void)hhResolutionIndex;
392 (void)h264Profile;
393 (void)h264Level;
394
395 switch (format) {
396 case VIDEO_1920X1080_60:
397 case VIDEO_1920X1080_30:
398 native = (uint8_t)WfdResolutionType::RESOLUTION_CEA | (CEA_1920_1080_P30 << BIT_OFFSET_THREE);
399 ceaResolutionIndex = (1 << CEA_1920_1080_P30);
400 break;
401 case VIDEO_1920X1080_25:
402 native = (uint8_t)WfdResolutionType::RESOLUTION_CEA | (CEA_1920_1080_P25 << BIT_OFFSET_THREE);
403 ceaResolutionIndex = (1 << CEA_1920_1080_P25);
404 break;
405 case VIDEO_1280X720_30:
406 native = (uint8_t)WfdResolutionType::RESOLUTION_CEA | (CEA_1280_720_P30 << BIT_OFFSET_THREE);
407 ceaResolutionIndex = (1 << CEA_1280_720_P30);
408 break;
409 case VIDEO_1280X720_25:
410 native = (uint8_t)WfdResolutionType::RESOLUTION_CEA | (CEA_1280_720_P25 << BIT_OFFSET_THREE);
411 ceaResolutionIndex = (1 << CEA_1280_720_P25);
412 break;
413 case VIDEO_640X480_60:
414 default:
415 native =
416 (uint8_t)WfdResolutionType::RESOLUTION_CEA | (WfdCeaResolution::CEA_640_480_P60 << BIT_OFFSET_THREE);
417 ceaResolutionIndex = (1 << CEA_640_480_P60);
418 break;
419 }
420
421 ss << WFD_PARAM_VIDEO_FORMATS << ":" << RTSP_SP;
422 ss << std::setfill('0') << std::setw(BIT_OFFSET_TWO) << std::hex << native << RTSP_SP << "00" << RTSP_SP;
423 ss << std::setfill('0') << std::setw(BIT_OFFSET_TWO) << std::hex << h264Profile << RTSP_SP;
424 ss << std::setfill('0') << std::setw(BIT_OFFSET_TWO) << std::hex << h264Level << RTSP_SP;
425 ss << std::setfill('0') << std::setw(BIT_OFFSET_EIGHT) << std::hex << ceaResolutionIndex << RTSP_SP;
426 ss << std::setfill('0') << std::setw(BIT_OFFSET_EIGHT) << std::hex << vesaResolutionIndex << RTSP_SP;
427 ss << std::setfill('0') << std::setw(BIT_OFFSET_EIGHT) << std::hex << hhResolutionIndex << RTSP_SP;
428 ss << "00 0000 0000 00 none none";
429 AddBodyItem(ss.str());
430 }
431
Parse(const std::string & request)432 RtspError WfdRtspM4Request::Parse(const std::string &request)
433 {
434 auto res = RtspRequest::Parse(request);
435 if (res.code != RtspErrorType::OK) {
436 return res;
437 }
438
439 RtspCommon::SplitParameter(body_, params_);
440 return {};
441 }
442
GetParameterValue(const std::string & param)443 std::string WfdRtspM4Request::GetParameterValue(const std::string ¶m)
444 {
445 auto it = std::find_if(params_.begin(), params_.end(),
446 [=](std::pair<std::string, std::string> value) { return value.first == param; });
447 if (it != params_.end()) {
448 return it->second;
449 }
450
451 return "";
452 }
453
GetPresentationUrl()454 std::string WfdRtspM4Request::GetPresentationUrl()
455 {
456 std::string urls = GetParameterValue(WFD_PARAM_PRESENTATION_URL);
457 if (urls.empty()) {
458 return "";
459 }
460
461 auto urlVec = RtspCommon::Split(urls, " ");
462 if (!urlVec.empty()) {
463 return urlVec[0];
464 }
465
466 return "";
467 }
468
GetRtpPort()469 int32_t WfdRtspM4Request::GetRtpPort()
470 {
471 auto ports = GetParameterValue(WFD_PARAM_RTP_PORTS);
472 auto resVec = RtspCommon::Split(ports, " ");
473 if (resVec.size() > 2) { // 2: fix offset
474 return atoi(resVec[1].c_str());
475 }
476
477 return 0;
478 }
479
SetTriggerMethod(const std::string & method)480 void WfdRtspM5Request::SetTriggerMethod(const std::string &method)
481 {
482 std::stringstream ss;
483 ss << WFD_PARAM_TRIGGER << ":" << RTSP_SP << method;
484
485 body_.emplace_back(ss.str());
486 }
487
GetTriggerMethod()488 std::string WfdRtspM5Request::GetTriggerMethod()
489 {
490 std::list<std::pair<std::string, std::string>> params;
491 RtspCommon::SplitParameter(body_, params);
492
493 auto it = std::find_if(params.begin(), params.end(),
494 [](std::pair<std::string, std::string> value) { return value.first == WFD_PARAM_TRIGGER; });
495 if (it != params.end()) {
496 return it->second;
497 }
498
499 return {};
500 }
501
GetClientPort()502 int32_t WfdRtspM6Response::GetClientPort()
503 {
504 auto transport = GetToken(RTSP_TOKEN_TRANSPORT);
505 if (transport.empty()) {
506 return 0;
507 }
508
509 auto tsVec = RtspCommon::Split(transport, ";");
510 for (auto &item : tsVec) {
511 if (item.find("client_port=") != std::string::npos) {
512 auto val = item.substr(item.find('=') + 1);
513 return atoi(val.c_str());
514 }
515 }
516
517 return 0;
518 }
519
GetServerPort()520 int32_t WfdRtspM6Response::GetServerPort()
521 {
522 auto transport = GetToken(RTSP_TOKEN_TRANSPORT);
523 if (transport.empty()) {
524 return 0;
525 }
526
527 auto tsVec = RtspCommon::Split(transport, ";");
528 for (auto &item : tsVec) {
529 if (item.find("server_port=") != std::string::npos) {
530 auto val = item.substr(item.find('=') + 1);
531 return atoi(val.c_str());
532 }
533 }
534
535 return 0;
536 }
537
SetClientPort(int port)538 void WfdRtspM6Response::SetClientPort(int port)
539 {
540 clientPort_ = port;
541 }
542
SetServerPort(int port)543 void WfdRtspM6Response::SetServerPort(int port)
544 {
545 serverPort_ = port;
546 }
547
StringifyEx()548 std::string WfdRtspM6Response::StringifyEx()
549 {
550 std::stringstream ss;
551 auto message = Stringify();
552 std::string temp = RTSP_CRLF;
553 auto nPos = message.find_last_of(RTSP_CRLF);
554 if (nPos != std::string::npos) {
555 message = message.substr(0, message.size() - temp.size());
556 }
557 ss << message << "Transport: RTP/AVP/UDP;unicast;client_port=" << clientPort_ << ";server_port=" << serverPort_
558 << RTSP_CRLF;
559 ss << RTSP_CRLF;
560 return ss.str();
561 }
562
StringifyEx()563 std::string WfdRtspM7Response::StringifyEx()
564 {
565 std::stringstream ss;
566 auto message = Stringify();
567 std::string temp = RTSP_CRLF;
568 auto nPos = message.find_last_of(RTSP_CRLF);
569 if (nPos != std::string::npos) {
570 message = message.substr(0, message.size() - temp.size());
571 }
572 ss << message << "Range: npt=now-" << RTSP_CRLF;
573 ss << RTSP_CRLF;
574 return ss.str();
575 }
576
577 } // namespace Sharing
578 } // namespace OHOS
579