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(WfdAudioCodec &codec)189 AudioFormat WfdRtspM3Response::GetAudioCodecs(WfdAudioCodec &codec)
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 if (codec.codecId != CODEC_AAC && audioFormat0 > 1) {
202 codec.codecId = CODEC_PCM;
203 codec.format = AUDIO_48000_16_2;
204 }
205 } else if (format == "AAC") { // AAC
206 codec.codecId = CODEC_AAC;
207 codec.format = AUDIO_48000_16_2;
208 } else if (format == "AC3") { // AC3
209 if (audioFormat0 == 1) {
210 }
211 continue;
212 }
213 }
214
215 return codec.format;
216 }
217
GetCoupledSink()218 std::string WfdRtspM3Response::GetCoupledSink()
219 {
220 std::string value = GetCustomParam(WFD_PARAM_COUPLED_SINK);
221 return value;
222 }
223
GetContentProtection()224 std::string WfdRtspM3Response::GetContentProtection()
225 {
226 std::string value = GetCustomParam(WFD_PARAM_CONTENT_PROTECTION);
227 return value;
228 }
229
GetVideoFormatsByCea(int index)230 VideoFormat WfdRtspM3Response::GetVideoFormatsByCea(int index)
231 {
232 WfdCeaResolution res = static_cast<WfdCeaResolution>(index);
233 switch (res) {
234 case CEA_640_480_P60:
235 return VIDEO_640X480_60;
236 case CEA_1280_720_P30:
237 return VIDEO_1280X720_30;
238 case CEA_1280_720_P60:
239 return VIDEO_1280X720_60;
240 case CEA_1920_1080_P25:
241 return VIDEO_1920X1080_25;
242 case CEA_1920_1080_P30:
243 return VIDEO_1920X1080_30;
244 case CEA_1920_1080_P60:
245 return VIDEO_1920X1080_60;
246 default:
247 return VIDEO_640X480_60;
248 }
249 }
250
GetVideoFormats()251 VideoFormat WfdRtspM3Response::GetVideoFormats()
252 {
253 // wfd_video_formats:
254 // 1 byte "native"
255 // 1 byte "preferred-display-mode-supported" 0 or 1
256 // one or more avc codec structures
257 // 1 byte profile
258 // 1 byte level
259 // 4 byte CEA mask
260 // 4 byte VESA mask
261 // 4 byte HH mask
262 // 1 byte latency
263 // 2 byte min-slice-slice
264 // 2 byte slice-enc-params
265 // 1 byte framerate-control-support
266 // max-hres (none or 2 byte)
267 // max-vres (none or 2 byte)
268 /**
269 * native: 2*2HEXDIG
270 * preferred-display-mode-supported: 2*2HEXDIG; 0-not supported, 1-supported, 2-255 reserved
271 * profile: 2*2HEXDIG, only one bit set
272 * level: 2*2HEXDIG, only one bit set
273 * CEA-Support: 8*8HEXDIG, 0-ignore
274 * VESA-Support:8*8HEXDIG, 0-ignore
275 * HH-Support: 8*8HEXDIG, 0-ignore
276 * latency: 2*2HEXDIG, decoder latency in units of 5 msecs
277 * min-slice-size: 4*4HEXDIG, number of macroblocks
278 * slice-enc-params: 4*4HEXDIG,
279 * frame-rate-control-support: 4*4HEXDIG
280 * max-hres: 4*4HEXDIG, "none" if preferred-display-mode-supported is 0
281 * max-vres: 4*4HEXDIG, "none" if preferred-display-mode-supported is 0
282 **/
283 std::string value = GetCustomParam(WFD_PARAM_VIDEO_FORMATS);
284 if (value.size() < MINIMAL_VIDEO_FORMAT_SIZE) {
285 return VIDEO_640X480_60;
286 }
287
288 std::string head = value.substr(0, 5); // 5: fix offset
289 uint16_t native = 0;
290 uint16_t preferredDisplayMode = 0;
291 int index = 0;
292 std::string temp = "";
293 bool run = true;
294 std::stringstream ss(head);
295 ss >> std::hex >> native >> std::hex >> preferredDisplayMode;
296 value = value.substr(5); // 5: fix offset
297
298 while (run) {
299 auto nPos = value.find_first_of(",", index + 1);
300 if (nPos != std::string::npos) {
301 index = nPos;
302 temp = value.substr(0, index);
303 } else {
304 temp = value.substr(index + 1);
305 run = false;
306 }
307 std::stringstream sss(temp);
308 WfdVideoFormatsInfo wfdVideoFormatsInfo;
309 wfdVideoFormatsInfo.native = native;
310 wfdVideoFormatsInfo.preferredDisplayMode = preferredDisplayMode;
311 sss >> std::hex >> wfdVideoFormatsInfo.profile >> std::hex >> wfdVideoFormatsInfo.level >> std::hex >>
312 wfdVideoFormatsInfo.ceaMask >> std::hex >> wfdVideoFormatsInfo.veaMask >> std::hex >>
313 wfdVideoFormatsInfo.hhMask >> std::hex >> wfdVideoFormatsInfo.latency >> std::hex >>
314 wfdVideoFormatsInfo.minSlice >> std::hex >> wfdVideoFormatsInfo.sliceEncParam >> std::hex >>
315 wfdVideoFormatsInfo.frameRateCtlSupport;
316 vWfdVideoFormatsInfo_.push_back(wfdVideoFormatsInfo);
317 }
318
319 uint8_t tableSelection = vWfdVideoFormatsInfo_[0].native & 0x7;
320 index = vWfdVideoFormatsInfo_[0].native >> BIT_OFFSET_THREE;
321 switch (tableSelection) {
322 case 0:
323 return GetVideoFormatsByCea(index);
324 default:
325 return VIDEO_640X480_60;
326 }
327 return VIDEO_640X480_60;
328 }
329
GetStandbyResumeCapability()330 std::string WfdRtspM3Response::GetStandbyResumeCapability()
331 {
332 std::string value = GetCustomParam(WFD_PARAM_STANDBY_RESUME);
333 return value;
334 }
335
GetCustomParam(const std::string &key)336 std::string WfdRtspM3Response::GetCustomParam(const std::string &key)
337 {
338 auto it = std::find_if(params_.begin(), params_.end(),
339 [=](std::pair<std::string, std::string> value) { return value.first == key; });
340 if (it != params_.end()) {
341 return it->second;
342 }
343
344 return "";
345 }
346
SetClientRtpPorts(int32_t port)347 void WfdRtspM4Request::SetClientRtpPorts(int32_t port)
348 {
349 std::stringstream ss;
350 ss << WFD_PARAM_RTP_PORTS << ":" << RTSP_SP << "RTP/AVP/UDP;unicast" << RTSP_SP << port << RTSP_SP << 0 << RTSP_SP
351 << "mode=play";
352 AddBodyItem(ss.str());
353 }
354
SetAudioCodecs(WfdAudioCodec &codec)355 void WfdRtspM4Request::SetAudioCodecs(WfdAudioCodec &codec)
356 {
357 std::stringstream ss;
358 ss << WFD_PARAM_AUDIO_CODECS << ":" << RTSP_SP;
359
360 switch (codec.codecId) {
361 case CODEC_PCM:
362 ss << "LPCM" << RTSP_SP << "00000002 00";
363 break;
364 case CODEC_AAC:
365 ss << "AAC" << RTSP_SP << "00000001 00";
366 break;
367 default:
368 ss << "AAC" << RTSP_SP << "00000001 00";
369 break;
370 }
371
372 AddBodyItem(ss.str());
373 }
374
SetPresentationUrl(const std::string &ip)375 void WfdRtspM4Request::SetPresentationUrl(const std::string &ip)
376 {
377 std::stringstream ss;
378 ss << WFD_PARAM_PRESENTATION_URL << ":" << RTSP_SP << "rtsp://" << ip.c_str() << "/wfd1.0/streamid=0 none";
379 AddBodyItem(ss.str());
380 }
381
SetVideoFormats(const WfdVideoFormatsInfo &wfdVideoFormatsInfo, VideoFormat format)382 void WfdRtspM4Request::SetVideoFormats(const WfdVideoFormatsInfo &wfdVideoFormatsInfo, VideoFormat format)
383 {
384 std::stringstream ss;
385 uint32_t native = wfdVideoFormatsInfo.native;
386 uint32_t h264Profile = wfdVideoFormatsInfo.profile;
387 uint32_t h264Level = wfdVideoFormatsInfo.level;
388 uint32_t ceaResolutionIndex = 0;
389 uint32_t vesaResolutionIndex = 0;
390 uint32_t hhResolutionIndex = 0;
391 (void)ceaResolutionIndex;
392 (void)vesaResolutionIndex;
393 (void)hhResolutionIndex;
394 (void)h264Profile;
395 (void)h264Level;
396
397 switch (format) {
398 case VIDEO_1920X1080_60:
399 case VIDEO_1920X1080_30:
400 native = (uint8_t)WfdResolutionType::RESOLUTION_CEA | (CEA_1920_1080_P30 << BIT_OFFSET_THREE);
401 ceaResolutionIndex = (1 << CEA_1920_1080_P30);
402 break;
403 case VIDEO_1920X1080_25:
404 native = (uint8_t)WfdResolutionType::RESOLUTION_CEA | (CEA_1920_1080_P25 << BIT_OFFSET_THREE);
405 ceaResolutionIndex = (1 << CEA_1920_1080_P25);
406 break;
407 case VIDEO_1280X720_30:
408 native = (uint8_t)WfdResolutionType::RESOLUTION_CEA | (CEA_1280_720_P30 << BIT_OFFSET_THREE);
409 ceaResolutionIndex = (1 << CEA_1280_720_P30);
410 break;
411 case VIDEO_1280X720_25:
412 native = (uint8_t)WfdResolutionType::RESOLUTION_CEA | (CEA_1280_720_P25 << BIT_OFFSET_THREE);
413 ceaResolutionIndex = (1 << CEA_1280_720_P25);
414 break;
415 case VIDEO_640X480_60:
416 default:
417 native =
418 (uint8_t)WfdResolutionType::RESOLUTION_CEA | (WfdCeaResolution::CEA_640_480_P60 << BIT_OFFSET_THREE);
419 ceaResolutionIndex = (1 << CEA_640_480_P60);
420 break;
421 }
422
423 ss << WFD_PARAM_VIDEO_FORMATS << ":" << RTSP_SP;
424 ss << std::setfill('0') << std::setw(BIT_OFFSET_TWO) << std::hex << native << RTSP_SP << "00" << RTSP_SP;
425 ss << std::setfill('0') << std::setw(BIT_OFFSET_TWO) << std::hex << h264Profile << RTSP_SP;
426 ss << std::setfill('0') << std::setw(BIT_OFFSET_TWO) << std::hex << h264Level << RTSP_SP;
427 ss << std::setfill('0') << std::setw(BIT_OFFSET_EIGHT) << std::hex << ceaResolutionIndex << RTSP_SP;
428 ss << std::setfill('0') << std::setw(BIT_OFFSET_EIGHT) << std::hex << vesaResolutionIndex << RTSP_SP;
429 ss << std::setfill('0') << std::setw(BIT_OFFSET_EIGHT) << std::hex << hhResolutionIndex << RTSP_SP;
430 ss << "00 0000 0000 00 none none";
431 AddBodyItem(ss.str());
432 }
433
Parse(const std::string &request)434 RtspError WfdRtspM4Request::Parse(const std::string &request)
435 {
436 auto res = RtspRequest::Parse(request);
437 if (res.code != RtspErrorType::OK) {
438 return res;
439 }
440
441 RtspCommon::SplitParameter(body_, params_);
442 return {};
443 }
444
GetParameterValue(const std::string ¶m)445 std::string WfdRtspM4Request::GetParameterValue(const std::string ¶m)
446 {
447 auto it = std::find_if(params_.begin(), params_.end(),
448 [=](std::pair<std::string, std::string> value) { return value.first == param; });
449 if (it != params_.end()) {
450 return it->second;
451 }
452
453 return "";
454 }
455
GetPresentationUrl()456 std::string WfdRtspM4Request::GetPresentationUrl()
457 {
458 std::string urls = GetParameterValue(WFD_PARAM_PRESENTATION_URL);
459 if (urls.empty()) {
460 return "";
461 }
462
463 auto urlVec = RtspCommon::Split(urls, " ");
464 if (!urlVec.empty()) {
465 return urlVec[0];
466 }
467
468 return "";
469 }
470
GetRtpPort()471 int32_t WfdRtspM4Request::GetRtpPort()
472 {
473 auto ports = GetParameterValue(WFD_PARAM_RTP_PORTS);
474 auto resVec = RtspCommon::Split(ports, " ");
475 if (resVec.size() > 2) { // 2: fix offset
476 return atoi(resVec[1].c_str());
477 }
478
479 return 0;
480 }
481
SetTriggerMethod(const std::string &method)482 void WfdRtspM5Request::SetTriggerMethod(const std::string &method)
483 {
484 std::stringstream ss;
485 ss << WFD_PARAM_TRIGGER << ":" << RTSP_SP << method;
486
487 body_.emplace_back(ss.str());
488 }
489
GetTriggerMethod()490 std::string WfdRtspM5Request::GetTriggerMethod()
491 {
492 std::list<std::pair<std::string, std::string>> params;
493 RtspCommon::SplitParameter(body_, params);
494
495 auto it = std::find_if(params.begin(), params.end(),
496 [](std::pair<std::string, std::string> value) { return value.first == WFD_PARAM_TRIGGER; });
497 if (it != params.end()) {
498 return it->second;
499 }
500
501 return {};
502 }
503
GetClientPort()504 int32_t WfdRtspM6Response::GetClientPort()
505 {
506 auto transport = GetToken(RTSP_TOKEN_TRANSPORT);
507 if (transport.empty()) {
508 return 0;
509 }
510
511 auto tsVec = RtspCommon::Split(transport, ";");
512 for (auto &item : tsVec) {
513 if (item.find("client_port=") != std::string::npos) {
514 auto val = item.substr(item.find('=') + 1);
515 return atoi(val.c_str());
516 }
517 }
518
519 return 0;
520 }
521
GetServerPort()522 int32_t WfdRtspM6Response::GetServerPort()
523 {
524 auto transport = GetToken(RTSP_TOKEN_TRANSPORT);
525 if (transport.empty()) {
526 return 0;
527 }
528
529 auto tsVec = RtspCommon::Split(transport, ";");
530 for (auto &item : tsVec) {
531 if (item.find("server_port=") != std::string::npos) {
532 auto val = item.substr(item.find('=') + 1);
533 return atoi(val.c_str());
534 }
535 }
536
537 return 0;
538 }
539
SetClientPort(int port)540 void WfdRtspM6Response::SetClientPort(int port)
541 {
542 clientPort_ = port;
543 }
544
SetServerPort(int port)545 void WfdRtspM6Response::SetServerPort(int port)
546 {
547 serverPort_ = port;
548 }
549
StringifyEx()550 std::string WfdRtspM6Response::StringifyEx()
551 {
552 std::stringstream ss;
553 auto message = Stringify();
554 std::string temp = RTSP_CRLF;
555 auto nPos = message.find_last_of(RTSP_CRLF);
556 if (nPos != std::string::npos) {
557 message = message.substr(0, message.size() - temp.size());
558 }
559 ss << message << "Transport: RTP/AVP/UDP;unicast;client_port=" << clientPort_ << ";server_port=" << serverPort_
560 << RTSP_CRLF;
561 ss << RTSP_CRLF;
562 return ss.str();
563 }
564
StringifyEx()565 std::string WfdRtspM7Response::StringifyEx()
566 {
567 std::stringstream ss;
568 auto message = Stringify();
569 std::string temp = RTSP_CRLF;
570 auto nPos = message.find_last_of(RTSP_CRLF);
571 if (nPos != std::string::npos) {
572 message = message.substr(0, message.size() - temp.size());
573 }
574 ss << message << "Range: npt=now-" << RTSP_CRLF;
575 ss << RTSP_CRLF;
576 return ss.str();
577 }
578
579 } // namespace Sharing
580 } // namespace OHOS
581