| 860 | } |
| 861 | |
| 862 | void cmd_setup(rtsp_server_t *server, tcp::socket &sock, launch_session_t &session, msg_t &&req) { |
| 863 | OPTION_ITEM options[4] {}; |
| 864 | |
| 865 | auto &seqn = options[0]; |
| 866 | auto &session_option = options[1]; |
| 867 | auto &port_option = options[2]; |
| 868 | auto &payload_option = options[3]; |
| 869 | |
| 870 | seqn.option = const_cast<char *>("CSeq"); |
| 871 | |
| 872 | auto seqn_str = std::to_string(req->sequenceNumber); |
| 873 | seqn.content = const_cast<char *>(seqn_str.c_str()); |
| 874 | |
| 875 | std::string_view target {req->message.request.target}; |
| 876 | auto begin = std::find(std::begin(target), std::end(target), '=') + 1; |
| 877 | auto end = std::find(begin, std::end(target), '/'); |
| 878 | std::string_view type {begin, (size_t) std::distance(begin, end)}; |
| 879 | |
| 880 | std::uint16_t port; |
| 881 | if (type == "audio"sv) { |
| 882 | port = net::map_port(stream::AUDIO_STREAM_PORT); |
| 883 | } else if (type == "video"sv) { |
| 884 | port = net::map_port(stream::VIDEO_STREAM_PORT); |
| 885 | } else if (type == "control"sv) { |
| 886 | port = net::map_port(stream::CONTROL_PORT); |
| 887 | } else { |
| 888 | cmd_not_found(sock, session, std::move(req)); |
| 889 | |
| 890 | return; |
| 891 | } |
| 892 | |
| 893 | seqn.next = &session_option; |
| 894 | |
| 895 | session_option.option = const_cast<char *>("Session"); |
| 896 | session_option.content = const_cast<char *>("DEADBEEFCAFE;timeout = 90"); |
| 897 | |
| 898 | session_option.next = &port_option; |
| 899 | |
| 900 | // Moonlight merely requires 'server_port=<port>' |
| 901 | auto port_value = std::format("server_port={}", static_cast<int>(port)); |
| 902 | |
| 903 | port_option.option = const_cast<char *>("Transport"); |
| 904 | port_option.content = port_value.data(); |
| 905 | |
| 906 | // Send identifiers that will be echoed in the other connections |
| 907 | auto connect_data = std::to_string(session.control_connect_data); |
| 908 | if (type == "control"sv) { |
| 909 | payload_option.option = const_cast<char *>("X-SS-Connect-Data"); |
| 910 | payload_option.content = connect_data.data(); |
| 911 | } else { |
| 912 | payload_option.option = const_cast<char *>("X-SS-Ping-Payload"); |
| 913 | payload_option.content = session.av_ping_payload.data(); |
| 914 | } |
| 915 | |
| 916 | port_option.next = &payload_option; |
| 917 | |
| 918 | respond(sock, session, &seqn, 200, "OK", req->sequenceNumber, {}); |
| 919 | } |