mirror of
https://github.com/LizardByte/Sunshine.git
synced 2025-08-10 00:52:16 +00:00
style: adjust clang-format rules (#2186)
Co-authored-by: Vithorio Polten <reach@vithor.io>
This commit is contained in:
269
src/rtsp.cpp
269
src/rtsp.cpp
@@ -9,13 +9,18 @@ extern "C" {
|
||||
#include <moonlight-common-c/src/Rtsp.h>
|
||||
}
|
||||
|
||||
// standard includes
|
||||
#include <array>
|
||||
#include <cctype>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
// lib includes
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
// local includes
|
||||
#include "config.h"
|
||||
#include "globals.h"
|
||||
#include "input.h"
|
||||
@@ -26,9 +31,6 @@ extern "C" {
|
||||
#include "sync.h"
|
||||
#include "video.h"
|
||||
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace asio = boost::asio;
|
||||
|
||||
using asio::ip::tcp;
|
||||
@@ -37,8 +39,7 @@ using asio::ip::udp;
|
||||
using namespace std::literals;
|
||||
|
||||
namespace rtsp_stream {
|
||||
void
|
||||
free_msg(PRTSP_MESSAGE msg) {
|
||||
void free_msg(PRTSP_MESSAGE msg) {
|
||||
freeMessage(msg);
|
||||
|
||||
delete msg;
|
||||
@@ -51,18 +52,15 @@ namespace rtsp_stream {
|
||||
// parsing code to be able to tell encrypted from plaintext messages.
|
||||
static constexpr std::uint32_t ENCRYPTED_MESSAGE_TYPE_BIT = 0x80000000;
|
||||
|
||||
uint8_t *
|
||||
payload() {
|
||||
uint8_t *payload() {
|
||||
return (uint8_t *) (this + 1);
|
||||
}
|
||||
|
||||
std::uint32_t
|
||||
payload_length() {
|
||||
std::uint32_t payload_length() {
|
||||
return util::endian::big<std::uint32_t>(typeAndLength) & ~ENCRYPTED_MESSAGE_TYPE_BIT;
|
||||
}
|
||||
|
||||
bool
|
||||
is_encrypted() {
|
||||
bool is_encrypted() {
|
||||
return !!(util::endian::big<std::uint32_t>(typeAndLength) & ENCRYPTED_MESSAGE_TYPE_BIT);
|
||||
}
|
||||
|
||||
@@ -83,23 +81,21 @@ namespace rtsp_stream {
|
||||
using msg_t = util::safe_ptr<RTSP_MESSAGE, free_msg>;
|
||||
using cmd_func_t = std::function<void(rtsp_server_t *server, tcp::socket &, launch_session_t &, msg_t &&)>;
|
||||
|
||||
void
|
||||
print_msg(PRTSP_MESSAGE msg);
|
||||
void
|
||||
cmd_not_found(tcp::socket &sock, launch_session_t &, msg_t &&req);
|
||||
void
|
||||
respond(tcp::socket &sock, launch_session_t &session, POPTION_ITEM options, int statuscode, const char *status_msg, int seqn, const std::string_view &payload);
|
||||
void print_msg(PRTSP_MESSAGE msg);
|
||||
void cmd_not_found(tcp::socket &sock, launch_session_t &, msg_t &&req);
|
||||
void respond(tcp::socket &sock, launch_session_t &session, POPTION_ITEM options, int statuscode, const char *status_msg, int seqn, const std::string_view &payload);
|
||||
|
||||
class socket_t: public std::enable_shared_from_this<socket_t> {
|
||||
public:
|
||||
socket_t(boost::asio::io_context &io_context, std::function<void(tcp::socket &sock, launch_session_t &, msg_t &&)> &&handle_data_fn):
|
||||
handle_data_fn { std::move(handle_data_fn) }, sock { io_context } {}
|
||||
handle_data_fn {std::move(handle_data_fn)},
|
||||
sock {io_context} {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Queue an asynchronous read to begin the next message.
|
||||
*/
|
||||
void
|
||||
read() {
|
||||
void read() {
|
||||
if (begin == std::end(msg_buf) || (session->rtsp_cipher && begin + sizeof(encrypted_rtsp_header_t) >= std::end(msg_buf))) {
|
||||
BOOST_LOG(error) << "RTSP: read(): Exceeded maximum rtsp packet size: "sv << msg_buf.size();
|
||||
|
||||
@@ -113,20 +109,17 @@ namespace rtsp_stream {
|
||||
|
||||
if (session->rtsp_cipher) {
|
||||
// For encrypted RTSP, we will read the the entire header first
|
||||
boost::asio::async_read(sock,
|
||||
boost::asio::buffer(begin, sizeof(encrypted_rtsp_header_t)),
|
||||
boost::bind(
|
||||
&socket_t::handle_read_encrypted_header, shared_from_this(),
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred));
|
||||
}
|
||||
else {
|
||||
boost::asio::async_read(sock, boost::asio::buffer(begin, sizeof(encrypted_rtsp_header_t)), boost::bind(&socket_t::handle_read_encrypted_header, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
|
||||
} else {
|
||||
sock.async_read_some(
|
||||
boost::asio::buffer(begin, (std::size_t)(std::end(msg_buf) - begin)),
|
||||
boost::bind(
|
||||
&socket_t::handle_read_plaintext, shared_from_this(),
|
||||
&socket_t::handle_read_plaintext,
|
||||
shared_from_this(),
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred));
|
||||
boost::asio::placeholders::bytes_transferred
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,8 +129,7 @@ namespace rtsp_stream {
|
||||
* @param ec The error code of the read operation.
|
||||
* @param bytes The number of bytes read.
|
||||
*/
|
||||
static void
|
||||
handle_read_encrypted_header(std::shared_ptr<socket_t> &socket, const boost::system::error_code &ec, std::size_t bytes) {
|
||||
static void handle_read_encrypted_header(std::shared_ptr<socket_t> &socket, const boost::system::error_code &ec, std::size_t bytes) {
|
||||
BOOST_LOG(debug) << "handle_read_encrypted_header(): Handle read of size: "sv << bytes << " bytes"sv;
|
||||
|
||||
auto sock_close = util::fail_guard([&socket]() {
|
||||
@@ -177,12 +169,7 @@ namespace rtsp_stream {
|
||||
sock_close.disable();
|
||||
|
||||
// Read the remainder of the header and full encrypted payload
|
||||
boost::asio::async_read(socket->sock,
|
||||
boost::asio::buffer(socket->begin + bytes, payload_length),
|
||||
boost::bind(
|
||||
&socket_t::handle_read_encrypted_message, socket->shared_from_this(),
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred));
|
||||
boost::asio::async_read(socket->sock, boost::asio::buffer(socket->begin + bytes, payload_length), boost::bind(&socket_t::handle_read_encrypted_message, socket->shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -191,8 +178,7 @@ namespace rtsp_stream {
|
||||
* @param ec The error code of the read operation.
|
||||
* @param bytes The number of bytes read.
|
||||
*/
|
||||
static void
|
||||
handle_read_encrypted_message(std::shared_ptr<socket_t> &socket, const boost::system::error_code &ec, std::size_t bytes) {
|
||||
static void handle_read_encrypted_message(std::shared_ptr<socket_t> &socket, const boost::system::error_code &ec, std::size_t bytes) {
|
||||
BOOST_LOG(debug) << "handle_read_encrypted(): Handle read of size: "sv << bytes << " bytes"sv;
|
||||
|
||||
auto sock_close = util::fail_guard([&socket]() {
|
||||
@@ -229,14 +215,14 @@ namespace rtsp_stream {
|
||||
iv[11] = 'R'; // RTSP
|
||||
|
||||
std::vector<uint8_t> plaintext;
|
||||
if (socket->session->rtsp_cipher->decrypt(std::string_view { (const char *) header->tag, sizeof(header->tag) + bytes }, plaintext, &iv)) {
|
||||
if (socket->session->rtsp_cipher->decrypt(std::string_view {(const char *) header->tag, sizeof(header->tag) + bytes}, plaintext, &iv)) {
|
||||
BOOST_LOG(error) << "Failed to verify RTSP message tag"sv;
|
||||
|
||||
respond(socket->sock, *socket->session, nullptr, 400, "BAD REQUEST", 0, {});
|
||||
return;
|
||||
}
|
||||
|
||||
msg_t req { new msg_t::element_type {} };
|
||||
msg_t req {new msg_t::element_type {}};
|
||||
if (auto status = parseRtspMessage(req.get(), (char *) plaintext.data(), plaintext.size())) {
|
||||
BOOST_LOG(error) << "Malformed RTSP message: ["sv << status << ']';
|
||||
|
||||
@@ -254,8 +240,7 @@ namespace rtsp_stream {
|
||||
/**
|
||||
* @brief Queue an asynchronous read of the payload portion of a plaintext message.
|
||||
*/
|
||||
void
|
||||
read_plaintext_payload() {
|
||||
void read_plaintext_payload() {
|
||||
if (begin == std::end(msg_buf)) {
|
||||
BOOST_LOG(error) << "RTSP: read_plaintext_payload(): Exceeded maximum rtsp packet size: "sv << msg_buf.size();
|
||||
|
||||
@@ -270,9 +255,12 @@ namespace rtsp_stream {
|
||||
sock.async_read_some(
|
||||
boost::asio::buffer(begin, (std::size_t)(std::end(msg_buf) - begin)),
|
||||
boost::bind(
|
||||
&socket_t::handle_plaintext_payload, shared_from_this(),
|
||||
&socket_t::handle_plaintext_payload,
|
||||
shared_from_this(),
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred));
|
||||
boost::asio::placeholders::bytes_transferred
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -281,8 +269,7 @@ namespace rtsp_stream {
|
||||
* @param ec The error code of the read operation.
|
||||
* @param bytes The number of bytes read.
|
||||
*/
|
||||
static void
|
||||
handle_plaintext_payload(std::shared_ptr<socket_t> &socket, const boost::system::error_code &ec, std::size_t bytes) {
|
||||
static void handle_plaintext_payload(std::shared_ptr<socket_t> &socket, const boost::system::error_code &ec, std::size_t bytes) {
|
||||
BOOST_LOG(debug) << "handle_plaintext_payload(): Handle read of size: "sv << bytes << " bytes"sv;
|
||||
|
||||
auto sock_close = util::fail_guard([&socket]() {
|
||||
@@ -301,7 +288,7 @@ namespace rtsp_stream {
|
||||
}
|
||||
|
||||
auto end = socket->begin + bytes;
|
||||
msg_t req { new msg_t::element_type {} };
|
||||
msg_t req {new msg_t::element_type {}};
|
||||
if (auto status = parseRtspMessage(req.get(), socket->msg_buf.data(), (std::size_t)(end - socket->msg_buf.data()))) {
|
||||
BOOST_LOG(error) << "Malformed RTSP message: ["sv << status << ']';
|
||||
|
||||
@@ -322,8 +309,10 @@ namespace rtsp_stream {
|
||||
|
||||
// If content_length > bytes read, then we need to store current data read,
|
||||
// to be appended by the next read.
|
||||
std::string_view content { option->content };
|
||||
auto begin = std::find_if(std::begin(content), std::end(content), [](auto ch) { return (bool) std::isdigit(ch); });
|
||||
std::string_view content {option->content};
|
||||
auto begin = std::find_if(std::begin(content), std::end(content), [](auto ch) {
|
||||
return (bool) std::isdigit(ch);
|
||||
});
|
||||
|
||||
content_length = util::from_chars(begin, std::end(content));
|
||||
break;
|
||||
@@ -350,8 +339,7 @@ namespace rtsp_stream {
|
||||
* @param ec The error code of the read operation.
|
||||
* @param bytes The number of bytes read.
|
||||
*/
|
||||
static void
|
||||
handle_read_plaintext(std::shared_ptr<socket_t> &socket, const boost::system::error_code &ec, std::size_t bytes) {
|
||||
static void handle_read_plaintext(std::shared_ptr<socket_t> &socket, const boost::system::error_code &ec, std::size_t bytes) {
|
||||
BOOST_LOG(debug) << "handle_read_plaintext(): Handle read of size: "sv << bytes << " bytes"sv;
|
||||
|
||||
if (ec) {
|
||||
@@ -393,8 +381,7 @@ namespace rtsp_stream {
|
||||
handle_plaintext_payload(socket, ec, buf_size);
|
||||
}
|
||||
|
||||
void
|
||||
handle_data(msg_t &&req) {
|
||||
void handle_data(msg_t &&req) {
|
||||
handle_data_fn(sock, *session, std::move(req));
|
||||
}
|
||||
|
||||
@@ -416,14 +403,13 @@ namespace rtsp_stream {
|
||||
clear();
|
||||
}
|
||||
|
||||
int
|
||||
bind(net::af_e af, std::uint16_t port, boost::system::error_code &ec) {
|
||||
int bind(net::af_e af, std::uint16_t port, boost::system::error_code &ec) {
|
||||
acceptor.open(af == net::IPV4 ? tcp::v4() : tcp::v6(), ec);
|
||||
if (ec) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
acceptor.set_option(boost::asio::socket_base::reuse_address { true });
|
||||
acceptor.set_option(boost::asio::socket_base::reuse_address {true});
|
||||
|
||||
acceptor.bind(tcp::endpoint(af == net::IPV4 ? tcp::v4() : tcp::v6(), port), ec);
|
||||
if (ec) {
|
||||
@@ -446,19 +432,16 @@ namespace rtsp_stream {
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class T, class X>
|
||||
void
|
||||
iterate(std::chrono::duration<T, X> timeout) {
|
||||
template<class T, class X>
|
||||
void iterate(std::chrono::duration<T, X> timeout) {
|
||||
io_context.run_one_for(timeout);
|
||||
}
|
||||
|
||||
void
|
||||
handle_msg(tcp::socket &sock, launch_session_t &session, msg_t &&req) {
|
||||
void handle_msg(tcp::socket &sock, launch_session_t &session, msg_t &&req) {
|
||||
auto func = _map_cmd_cb.find(req->message.request.command);
|
||||
if (func != std::end(_map_cmd_cb)) {
|
||||
func->second(this, sock, session, std::move(req));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
cmd_not_found(sock, session, std::move(req));
|
||||
}
|
||||
|
||||
@@ -466,8 +449,7 @@ namespace rtsp_stream {
|
||||
sock.shutdown(boost::asio::socket_base::shutdown_type::shutdown_both, ec);
|
||||
}
|
||||
|
||||
void
|
||||
handle_accept(const boost::system::error_code &ec) {
|
||||
void handle_accept(const boost::system::error_code &ec) {
|
||||
if (ec) {
|
||||
BOOST_LOG(error) << "Couldn't accept incoming connections: "sv << ec.message();
|
||||
|
||||
@@ -478,13 +460,12 @@ namespace rtsp_stream {
|
||||
|
||||
auto socket = std::move(next_socket);
|
||||
|
||||
auto launch_session { launch_event.view(0s) };
|
||||
auto launch_session {launch_event.view(0s)};
|
||||
if (launch_session) {
|
||||
// Associate the current RTSP session with this socket and start reading
|
||||
socket->session = launch_session;
|
||||
socket->read();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// This can happen due to normal things like port scanning, so let's not make these visible by default
|
||||
BOOST_LOG(debug) << "No pending session for incoming RTSP connection"sv;
|
||||
|
||||
@@ -502,8 +483,7 @@ namespace rtsp_stream {
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
map(const std::string_view &type, cmd_func_t cb) {
|
||||
void map(const std::string_view &type, cmd_func_t cb) {
|
||||
_map_cmd_cb.emplace(type, std::move(cb));
|
||||
}
|
||||
|
||||
@@ -513,8 +493,7 @@ namespace rtsp_stream {
|
||||
* the session will be discarded.
|
||||
* @param launch_session Streaming session information.
|
||||
*/
|
||||
void
|
||||
session_raise(std::shared_ptr<launch_session_t> launch_session) {
|
||||
void session_raise(std::shared_ptr<launch_session_t> launch_session) {
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
|
||||
// If a launch event is still pending, don't overwrite it.
|
||||
@@ -530,16 +509,14 @@ namespace rtsp_stream {
|
||||
* @brief Clear state for the oldest launch session.
|
||||
* @param launch_session_id The ID of the session to clear.
|
||||
*/
|
||||
void
|
||||
session_clear(uint32_t launch_session_id) {
|
||||
void session_clear(uint32_t launch_session_id) {
|
||||
// We currently only support a single pending RTSP session,
|
||||
// so the ID should always match the one for that session.
|
||||
auto launch_session = launch_event.view(0s);
|
||||
if (launch_session) {
|
||||
if (launch_session->id != launch_session_id) {
|
||||
BOOST_LOG(error) << "Attempted to clear unexpected session: "sv << launch_session_id << " vs "sv << launch_session->id;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
launch_event.pop();
|
||||
}
|
||||
}
|
||||
@@ -549,8 +526,7 @@ namespace rtsp_stream {
|
||||
* @brief Get the number of active sessions.
|
||||
* @return Count of active sessions.
|
||||
*/
|
||||
int
|
||||
session_count() {
|
||||
int session_count() {
|
||||
auto lg = _session_slots.lock();
|
||||
return _session_slots->size();
|
||||
}
|
||||
@@ -564,8 +540,7 @@ namespace rtsp_stream {
|
||||
* clear(false);
|
||||
* @examples_end
|
||||
*/
|
||||
void
|
||||
clear(bool all = true) {
|
||||
void clear(bool all = true) {
|
||||
// if a launch event timed out --> Remove it.
|
||||
if (raised_timeout < std::chrono::steady_clock::now()) {
|
||||
auto discarded = launch_event.pop(0s);
|
||||
@@ -583,8 +558,7 @@ namespace rtsp_stream {
|
||||
stream::session::join(slot);
|
||||
|
||||
i = _session_slots->erase(i);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
@@ -594,8 +568,7 @@ namespace rtsp_stream {
|
||||
* @brief Removes the provided session from the set of sessions.
|
||||
* @param session The session to remove.
|
||||
*/
|
||||
void
|
||||
remove(const std::shared_ptr<stream::session_t> &session) {
|
||||
void remove(const std::shared_ptr<stream::session_t> &session) {
|
||||
auto lg = _session_slots.lock();
|
||||
_session_slots->erase(session);
|
||||
}
|
||||
@@ -604,8 +577,7 @@ namespace rtsp_stream {
|
||||
* @brief Inserts the provided session into the set of sessions.
|
||||
* @param session The session to insert.
|
||||
*/
|
||||
void
|
||||
insert(const std::shared_ptr<stream::session_t> &session) {
|
||||
void insert(const std::shared_ptr<stream::session_t> &session) {
|
||||
auto lg = _session_slots.lock();
|
||||
_session_slots->emplace(session);
|
||||
BOOST_LOG(info) << "New streaming session started [active sessions: "sv << _session_slots->size() << ']';
|
||||
@@ -619,38 +591,33 @@ namespace rtsp_stream {
|
||||
std::chrono::steady_clock::time_point raised_timeout;
|
||||
|
||||
boost::asio::io_context io_context;
|
||||
tcp::acceptor acceptor { io_context };
|
||||
tcp::acceptor acceptor {io_context};
|
||||
|
||||
std::shared_ptr<socket_t> next_socket;
|
||||
};
|
||||
|
||||
rtsp_server_t server {};
|
||||
|
||||
void
|
||||
launch_session_raise(std::shared_ptr<launch_session_t> launch_session) {
|
||||
void launch_session_raise(std::shared_ptr<launch_session_t> launch_session) {
|
||||
server.session_raise(std::move(launch_session));
|
||||
}
|
||||
|
||||
void
|
||||
launch_session_clear(uint32_t launch_session_id) {
|
||||
void launch_session_clear(uint32_t launch_session_id) {
|
||||
server.session_clear(launch_session_id);
|
||||
}
|
||||
|
||||
int
|
||||
session_count() {
|
||||
int session_count() {
|
||||
// Ensure session_count is up-to-date
|
||||
server.clear(false);
|
||||
|
||||
return server.session_count();
|
||||
}
|
||||
|
||||
void
|
||||
terminate_sessions() {
|
||||
void terminate_sessions() {
|
||||
server.clear(true);
|
||||
}
|
||||
|
||||
int
|
||||
send(tcp::socket &sock, const std::string_view &sv) {
|
||||
int send(tcp::socket &sock, const std::string_view &sv) {
|
||||
std::size_t bytes_send = 0;
|
||||
|
||||
while (bytes_send != sv.size()) {
|
||||
@@ -666,8 +633,7 @@ namespace rtsp_stream {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
respond(tcp::socket &sock, launch_session_t &session, msg_t &resp) {
|
||||
void respond(tcp::socket &sock, launch_session_t &session, msg_t &resp) {
|
||||
auto payload = std::make_pair(resp->payload, resp->payloadLength);
|
||||
|
||||
// Restore response message for proper destruction
|
||||
@@ -680,11 +646,11 @@ namespace rtsp_stream {
|
||||
resp->payloadLength = 0;
|
||||
|
||||
int serialized_len;
|
||||
util::c_ptr<char> raw_resp { serializeRtspMessage(resp.get(), &serialized_len) };
|
||||
util::c_ptr<char> raw_resp {serializeRtspMessage(resp.get(), &serialized_len)};
|
||||
BOOST_LOG(debug)
|
||||
<< "---Begin Response---"sv << std::endl
|
||||
<< std::string_view { raw_resp.get(), (std::size_t) serialized_len } << std::endl
|
||||
<< std::string_view { payload.first, (std::size_t) payload.second } << std::endl
|
||||
<< std::string_view {raw_resp.get(), (std::size_t) serialized_len} << std::endl
|
||||
<< std::string_view {payload.first, (std::size_t) payload.second} << std::endl
|
||||
<< "---End Response---"sv << std::endl;
|
||||
|
||||
// Encrypt the RTSP message if encryption is enabled
|
||||
@@ -718,13 +684,12 @@ namespace rtsp_stream {
|
||||
header->sequenceNumber = util::endian::big<std::uint32_t>(session.rtsp_iv_counter);
|
||||
|
||||
// Encrypt the RTSP message in place
|
||||
session.rtsp_cipher->encrypt(std::string_view { (const char *) header->payload(), (std::size_t) payload_length }, header->tag, &iv);
|
||||
session.rtsp_cipher->encrypt(std::string_view {(const char *) header->payload(), (std::size_t) payload_length}, header->tag, &iv);
|
||||
|
||||
// Send the full encrypted message
|
||||
send(sock, std::string_view { (char *) message.data(), message.size() });
|
||||
}
|
||||
else {
|
||||
std::string_view tmp_resp { raw_resp.get(), (size_t) serialized_len };
|
||||
send(sock, std::string_view {(char *) message.data(), message.size()});
|
||||
} else {
|
||||
std::string_view tmp_resp {raw_resp.get(), (size_t) serialized_len};
|
||||
|
||||
// Send the plaintext RTSP message header
|
||||
if (send(sock, tmp_resp)) {
|
||||
@@ -732,25 +697,22 @@ namespace rtsp_stream {
|
||||
}
|
||||
|
||||
// Send the plaintext RTSP message payload (if present)
|
||||
send(sock, std::string_view { payload.first, (std::size_t) payload.second });
|
||||
send(sock, std::string_view {payload.first, (std::size_t) payload.second});
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
respond(tcp::socket &sock, launch_session_t &session, POPTION_ITEM options, int statuscode, const char *status_msg, int seqn, const std::string_view &payload) {
|
||||
msg_t resp { new msg_t::element_type };
|
||||
void respond(tcp::socket &sock, launch_session_t &session, POPTION_ITEM options, int statuscode, const char *status_msg, int seqn, const std::string_view &payload) {
|
||||
msg_t resp {new msg_t::element_type};
|
||||
createRtspResponse(resp.get(), nullptr, 0, const_cast<char *>("RTSP/1.0"), statuscode, const_cast<char *>(status_msg), seqn, options, const_cast<char *>(payload.data()), (int) payload.size());
|
||||
|
||||
respond(sock, session, resp);
|
||||
}
|
||||
|
||||
void
|
||||
cmd_not_found(tcp::socket &sock, launch_session_t &session, msg_t &&req) {
|
||||
void cmd_not_found(tcp::socket &sock, launch_session_t &session, msg_t &&req) {
|
||||
respond(sock, session, nullptr, 404, "NOT FOUND", req->sequenceNumber, {});
|
||||
}
|
||||
|
||||
void
|
||||
cmd_option(rtsp_server_t *server, tcp::socket &sock, launch_session_t &session, msg_t &&req) {
|
||||
void cmd_option(rtsp_server_t *server, tcp::socket &sock, launch_session_t &session, msg_t &&req) {
|
||||
OPTION_ITEM option {};
|
||||
|
||||
// I know these string literals will not be modified
|
||||
@@ -762,8 +724,7 @@ namespace rtsp_stream {
|
||||
respond(sock, session, &option, 200, "OK", req->sequenceNumber, {});
|
||||
}
|
||||
|
||||
void
|
||||
cmd_describe(rtsp_server_t *server, tcp::socket &sock, launch_session_t &session, msg_t &&req) {
|
||||
void cmd_describe(rtsp_server_t *server, tcp::socket &sock, launch_session_t &session, msg_t &&req) {
|
||||
OPTION_ITEM option {};
|
||||
|
||||
// I know these string literals will not be modified
|
||||
@@ -846,8 +807,7 @@ namespace rtsp_stream {
|
||||
respond(sock, session, &option, 200, "OK", req->sequenceNumber, ss.str());
|
||||
}
|
||||
|
||||
void
|
||||
cmd_setup(rtsp_server_t *server, tcp::socket &sock, launch_session_t &session, msg_t &&req) {
|
||||
void cmd_setup(rtsp_server_t *server, tcp::socket &sock, launch_session_t &session, msg_t &&req) {
|
||||
OPTION_ITEM options[4] {};
|
||||
|
||||
auto &seqn = options[0];
|
||||
@@ -860,22 +820,19 @@ namespace rtsp_stream {
|
||||
auto seqn_str = std::to_string(req->sequenceNumber);
|
||||
seqn.content = const_cast<char *>(seqn_str.c_str());
|
||||
|
||||
std::string_view target { req->message.request.target };
|
||||
std::string_view target {req->message.request.target};
|
||||
auto begin = std::find(std::begin(target), std::end(target), '=') + 1;
|
||||
auto end = std::find(begin, std::end(target), '/');
|
||||
std::string_view type { begin, (size_t) std::distance(begin, end) };
|
||||
std::string_view type {begin, (size_t) std::distance(begin, end)};
|
||||
|
||||
std::uint16_t port;
|
||||
if (type == "audio"sv) {
|
||||
port = net::map_port(stream::AUDIO_STREAM_PORT);
|
||||
}
|
||||
else if (type == "video"sv) {
|
||||
} else if (type == "video"sv) {
|
||||
port = net::map_port(stream::VIDEO_STREAM_PORT);
|
||||
}
|
||||
else if (type == "control"sv) {
|
||||
} else if (type == "control"sv) {
|
||||
port = net::map_port(stream::CONTROL_PORT);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
cmd_not_found(sock, session, std::move(req));
|
||||
|
||||
return;
|
||||
@@ -899,8 +856,7 @@ namespace rtsp_stream {
|
||||
if (type == "control"sv) {
|
||||
payload_option.option = const_cast<char *>("X-SS-Connect-Data");
|
||||
payload_option.content = connect_data.data();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
payload_option.option = const_cast<char *>("X-SS-Ping-Payload");
|
||||
payload_option.content = session.av_ping_payload.data();
|
||||
}
|
||||
@@ -910,8 +866,7 @@ namespace rtsp_stream {
|
||||
respond(sock, session, &seqn, 200, "OK", req->sequenceNumber, {});
|
||||
}
|
||||
|
||||
void
|
||||
cmd_announce(rtsp_server_t *server, tcp::socket &sock, launch_session_t &session, msg_t &&req) {
|
||||
void cmd_announce(rtsp_server_t *server, tcp::socket &sock, launch_session_t &session, msg_t &&req) {
|
||||
OPTION_ITEM option {};
|
||||
|
||||
// I know these string literals will not be modified
|
||||
@@ -920,7 +875,7 @@ namespace rtsp_stream {
|
||||
auto seqn_str = std::to_string(req->sequenceNumber);
|
||||
option.content = const_cast<char *>(seqn_str.c_str());
|
||||
|
||||
std::string_view payload { req->payload, (size_t) req->payloadLength };
|
||||
std::string_view payload {req->payload, (size_t) req->payloadLength};
|
||||
|
||||
std::vector<std::string_view> lines;
|
||||
|
||||
@@ -935,7 +890,9 @@ namespace rtsp_stream {
|
||||
if (whitespace(*pos++)) {
|
||||
lines.emplace_back(begin, pos - begin - 1);
|
||||
|
||||
while (pos != std::end(payload) && whitespace(*pos)) { ++pos; }
|
||||
while (pos != std::end(payload) && whitespace(*pos)) {
|
||||
++pos;
|
||||
}
|
||||
begin = pos;
|
||||
}
|
||||
}
|
||||
@@ -948,8 +905,7 @@ namespace rtsp_stream {
|
||||
auto type = line.substr(0, 2);
|
||||
if (type == "s="sv) {
|
||||
client = line.substr(2);
|
||||
}
|
||||
else if (type == "a=") {
|
||||
} else if (type == "a=") {
|
||||
auto pos = line.find(':');
|
||||
|
||||
auto name = line.substr(2, pos - 2);
|
||||
@@ -1016,8 +972,7 @@ namespace rtsp_stream {
|
||||
config.monitor.enableIntraRefresh = util::from_view(args.at("x-ss-video[0].intraRefresh"sv));
|
||||
|
||||
configuredBitrateKbps = util::from_view(args.at("x-ml-video.configuredBitrateKbps"sv));
|
||||
}
|
||||
catch (std::out_of_range &) {
|
||||
} catch (std::out_of_range &) {
|
||||
respond(sock, session, &option, 400, "BAD REQUEST", req->sequenceNumber, {});
|
||||
return;
|
||||
}
|
||||
@@ -1028,13 +983,12 @@ namespace rtsp_stream {
|
||||
if (config.audio.channels == 2) {
|
||||
for (auto option = req->options; option != nullptr; option = option->next) {
|
||||
if ("Host"sv == option->option) {
|
||||
std::string_view content { option->content };
|
||||
std::string_view content {option->content};
|
||||
BOOST_LOG(debug) << "Found Host: "sv << content;
|
||||
config.audio.flags[audio::config_t::HIGH_QUALITY] = (content.find("0.0.0.0"sv) == std::string::npos);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (session.surround_params.length() > 3) {
|
||||
} else if (session.surround_params.length() > 3) {
|
||||
// Channels
|
||||
std::uint8_t c = session.surround_params[0] - '0';
|
||||
// Streams
|
||||
@@ -1122,8 +1076,7 @@ namespace rtsp_stream {
|
||||
respond(sock, session, &option, 200, "OK", req->sequenceNumber, {});
|
||||
}
|
||||
|
||||
void
|
||||
cmd_play(rtsp_server_t *server, tcp::socket &sock, launch_session_t &session, msg_t &&req) {
|
||||
void cmd_play(rtsp_server_t *server, tcp::socket &sock, launch_session_t &session, msg_t &&req) {
|
||||
OPTION_ITEM option {};
|
||||
|
||||
// I know these string literals will not be modified
|
||||
@@ -1135,8 +1088,7 @@ namespace rtsp_stream {
|
||||
respond(sock, session, &option, 200, "OK", req->sequenceNumber, {});
|
||||
}
|
||||
|
||||
void
|
||||
rtpThread() {
|
||||
void rtpThread() {
|
||||
auto shutdown_event = mail::man->event<bool>(mail::shutdown);
|
||||
auto broadcast_shutdown_event = mail::man->event<bool>(mail::broadcast_shutdown);
|
||||
|
||||
@@ -1159,8 +1111,7 @@ namespace rtsp_stream {
|
||||
|
||||
if (broadcast_shutdown_event->peek()) {
|
||||
server.clear();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// cleanup all stopped sessions
|
||||
server.clear(false);
|
||||
}
|
||||
@@ -1169,14 +1120,13 @@ namespace rtsp_stream {
|
||||
server.clear();
|
||||
}
|
||||
|
||||
void
|
||||
print_msg(PRTSP_MESSAGE msg) {
|
||||
void print_msg(PRTSP_MESSAGE msg) {
|
||||
std::string_view type = msg->type == TYPE_RESPONSE ? "RESPONSE"sv : "REQUEST"sv;
|
||||
|
||||
std::string_view payload { msg->payload, (size_t) msg->payloadLength };
|
||||
std::string_view protocol { msg->protocol };
|
||||
std::string_view payload {msg->payload, (size_t) msg->payloadLength};
|
||||
std::string_view protocol {msg->protocol};
|
||||
auto seqnm = msg->sequenceNumber;
|
||||
std::string_view messageBuffer { msg->messageBuffer };
|
||||
std::string_view messageBuffer {msg->messageBuffer};
|
||||
|
||||
BOOST_LOG(debug) << "type ["sv << type << ']';
|
||||
BOOST_LOG(debug) << "sequence number ["sv << seqnm << ']';
|
||||
@@ -1187,24 +1137,23 @@ namespace rtsp_stream {
|
||||
auto &resp = msg->message.response;
|
||||
|
||||
auto statuscode = resp.statusCode;
|
||||
std::string_view status { resp.statusString };
|
||||
std::string_view status {resp.statusString};
|
||||
|
||||
BOOST_LOG(debug) << "statuscode :: "sv << statuscode;
|
||||
BOOST_LOG(debug) << "status :: "sv << status;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
auto &req = msg->message.request;
|
||||
|
||||
std::string_view command { req.command };
|
||||
std::string_view target { req.target };
|
||||
std::string_view command {req.command};
|
||||
std::string_view target {req.target};
|
||||
|
||||
BOOST_LOG(debug) << "command :: "sv << command;
|
||||
BOOST_LOG(debug) << "target :: "sv << target;
|
||||
}
|
||||
|
||||
for (auto option = msg->options; option != nullptr; option = option->next) {
|
||||
std::string_view content { option->content };
|
||||
std::string_view name { option->option };
|
||||
std::string_view content {option->content};
|
||||
std::string_view name {option->option};
|
||||
|
||||
BOOST_LOG(debug) << name << " :: "sv << content;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user