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 23namespace OHOS { 24namespace Sharing { 25constexpr int32_t BIT_OFFSET_TWO = 2; 26constexpr int32_t BIT_OFFSET_THREE = 3; 27constexpr int32_t BIT_OFFSET_EIGHT = 8; 28 29WfdRtspM1Response::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 36RtspError 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 47std::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 69void 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 118void 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 139void 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 146void WfdRtspM3Response::SetContentProtection(const std::string &value) 147{ 148 params_.emplace_back(WFD_PARAM_CONTENT_PROTECTION, value); 149} 150 151void WfdRtspM3Response::SetCoupledSink(const std::string &value) 152{ 153 params_.emplace_back(WFD_PARAM_COUPLED_SINK, value); 154} 155 156void WfdRtspM3Response::SetUibcCapability(const std::string &value) 157{ 158 params_.emplace_back(WFD_PARAM_UIBC_CAPABILITY, value); 159} 160 161void WfdRtspM3Response::SetStandbyResumeCapability(const std::string &value) 162{ 163 params_.emplace_back(WFD_PARAM_UIBC_CAPABILITY, value); 164} 165 166void WfdRtspM3Response::SetCustomParam(const std::string &key, const std::string &value) 167{ 168 params_.emplace_back(key, value); 169} 170 171int32_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 183std::string WfdRtspM3Response::GetUibcCapability() 184{ 185 std::string value = GetCustomParam(WFD_PARAM_UIBC_CAPABILITY); 186 return value; 187} 188 189AudioFormat 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 218std::string WfdRtspM3Response::GetCoupledSink() 219{ 220 std::string value = GetCustomParam(WFD_PARAM_COUPLED_SINK); 221 return value; 222} 223 224std::string WfdRtspM3Response::GetContentProtection() 225{ 226 std::string value = GetCustomParam(WFD_PARAM_CONTENT_PROTECTION); 227 return value; 228} 229 230VideoFormat 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 251VideoFormat 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 330std::string WfdRtspM3Response::GetStandbyResumeCapability() 331{ 332 std::string value = GetCustomParam(WFD_PARAM_STANDBY_RESUME); 333 return value; 334} 335 336std::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 347void 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 355void 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 375void 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 382void 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 434RtspError 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 445std::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 456std::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 471int32_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 482void 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 490std::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 504int32_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 522int32_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 540void WfdRtspM6Response::SetClientPort(int port) 541{ 542 clientPort_ = port; 543} 544 545void WfdRtspM6Response::SetServerPort(int port) 546{ 547 serverPort_ = port; 548} 549 550std::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 565std::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