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 &param : 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 &param)
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