From 41b0388624469ddd65ab0604ace6b239c0fe20c8 Mon Sep 17 00:00:00 2001 From: Martin Pulec Date: Wed, 7 Aug 2024 14:32:20 +0200 Subject: [PATCH] rtsp server: fixed audio props Do not deduce audio properties from command-line parameters but from the actual format that is being to sent. Until now, the properties like ch_count and sample rate was deduced from command-line parameters (ch_count from `-a channels=` and sample rate from `-A xxx:sample_rate`). However, this is a bit fragile - the source may not respect the `-a` parameters and also the `-A sample_rate` doesn't need to be set, like in the following case: ``` uv -x rtsp -A A-law -a sample_r=8000 -s testcard ``` Here the capture sample_rate is set to 8000 but not parsed from parameters (it must have been in `-A`). So SDP parameeters for RTSP was set incorrectly (48000). --- src/audio/audio.cpp | 26 ++++++++++ src/audio/types.cpp | 8 +++ src/audio/types.h | 1 + src/main.cpp | 8 --- src/rtsp/BasicRTSPOnlySubsession.cpp | 6 +-- src/rtsp/c_basicRTSPOnlyServer.h | 5 +- src/video_rxtx.cpp | 8 +++ src/video_rxtx.hpp | 2 + src/video_rxtx/h264_rtp.cpp | 75 +++++++++++++++++++--------- src/video_rxtx/h264_rtp.hpp | 18 ++++--- 10 files changed, 113 insertions(+), 44 deletions(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index 68e3fdffd..df4503931 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -89,6 +89,7 @@ #include "utils/string_view_utils.hpp" #include "utils/thread.h" #include "utils/worker.h" +#include "video_rxtx.hpp" // for video_rxtx using std::array; using std::fixed; @@ -1066,10 +1067,31 @@ static int find_codec_sample_rate(int sample_rate, const int *supported) { return rate_hi > 0 ? rate_hi : rate_lo; } +static void +set_audio_spec_to_vrxtx(struct video_rxtx *vrxtx, audio_frame2 *compressed_frm, + struct rtp *netdev, bool *audio_spec_to_vrxtx_set) +{ + if (*audio_spec_to_vrxtx_set) { + return; + } + + *audio_spec_to_vrxtx_set = true; + + const struct audio_desc desc = compressed_frm->get_desc(); + const int rx_port = rtp_get_udp_rx_port(netdev); + + MSG(VERBOSE, "Setting audio desc %s, rx port=%d to RXTX.\n", + audio_desc_to_cstring(desc), rx_port); + + assert(vrxtx != nullptr); + vrxtx->set_audio_spec(&desc, rx_port); +} + static void *audio_sender_thread(void *arg) { set_thread_name(__func__); struct state_audio *s = (struct state_audio *) arg; + bool audio_spec_to_vrxtx_set = false; struct audio_frame *buffer = NULL; unique_ptr resampler_state; try { @@ -1155,6 +1177,10 @@ static void *audio_sender_thread(void *arg) //TODO to be dynamic as a function of the selected codec, now only accepting mulaw without checking errors audio_tx_send_standard(s->tx_session, s->audio_network_device, &compressed); uncompressed = NULL; + set_audio_spec_to_vrxtx( + s->vrxtx, &compressed, + s->audio_network_device, + &audio_spec_to_vrxtx_set); } } #ifdef HAVE_JACK_TRANS diff --git a/src/audio/types.cpp b/src/audio/types.cpp index 849843c3b..b98edb15e 100644 --- a/src/audio/types.cpp +++ b/src/audio/types.cpp @@ -202,6 +202,14 @@ int audio_frame2::get_bps() const return desc.bps; } +struct audio_desc audio_frame2::get_desc() const +{ + struct audio_desc ret = desc; + ret.ch_count = + get_channel_count(); // ch_count is not set in audio_frame2::desc + return ret; +} + audio_codec_t audio_frame2::get_codec() const { return desc.codec; diff --git a/src/audio/types.h b/src/audio/types.h index dfe6714ef..dd8c90b17 100644 --- a/src/audio/types.h +++ b/src/audio/types.h @@ -161,6 +161,7 @@ public: void reset(); void set_timestamp(int64_t ts); [[nodiscard]] int get_bps() const; + [[nodiscard]] struct audio_desc get_desc() const; [[nodiscard]] audio_codec_t get_codec() const; [[nodiscard]] char *get_data(int channel); [[nodiscard]] const char *get_data(int channel) const; diff --git a/src/main.cpp b/src/main.cpp index 2f40b2729..3984da8cc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1414,14 +1414,6 @@ int main(int argc, char *argv[]) // SAGE + RTSP params["opts"].str = opt.video_protocol_opts; - // RTSP - params["audio_codec"].l = ac_params.codec; - params["audio_sample_rate"].i = - IF_NOT_NULL_ELSE(ac_params.sample_rate, kHz48); - params["audio_channels"].i = audio_capture_channels; - params["audio_bps"].i = 2; - params["a_rx_port"].i = opt.audio.recv_port; - if (strcmp(opt.video_protocol, "rtsp") == 0) { rtsp_types_t avType = rtsp_type_none; if ((strcmp("none", opt.audio.send_cfg) != 0)) { diff --git a/src/rtsp/BasicRTSPOnlySubsession.cpp b/src/rtsp/BasicRTSPOnlySubsession.cpp index adb5f154f..72d9d5d8a 100644 --- a/src/rtsp/BasicRTSPOnlySubsession.cpp +++ b/src/rtsp/BasicRTSPOnlySubsession.cpp @@ -135,13 +135,13 @@ void BasicRTSPOnlySubsession::setSDPLines(int addressFamily) { char rtpmapLine[STR_LEN]; int rtpPayloadType = avType == rtsp_type_audio ? get_audio_rtp_pt_rtpmap( - rtsp_params.audio_codec, rtsp_params.audio_sample_rate, - rtsp_params.audio_channels, rtpmapLine) + rtsp_params.adesc.codec, rtsp_params.adesc.sample_rate, + rtsp_params.adesc.ch_count, rtpmapLine) : get_video_rtp_pt_rtpmap(rtsp_params.video_codec, rtpmapLine); if (rtpPayloadType < 0) { MSG(ERROR, "Unsupported %s codec %s!\n", mspec[avType].mname, avType == rtsp_type_audio - ? get_name_to_audio_codec(rtsp_params.audio_codec) + ? get_name_to_audio_codec(rtsp_params.adesc.codec) : get_codec_name(rtsp_params.video_codec)); } //char const* auxSDPLine = ""; diff --git a/src/rtsp/c_basicRTSPOnlyServer.h b/src/rtsp/c_basicRTSPOnlyServer.h index 6948b3d63..71cba1f28 100644 --- a/src/rtsp/c_basicRTSPOnlyServer.h +++ b/src/rtsp/c_basicRTSPOnlyServer.h @@ -68,10 +68,7 @@ struct rtsp_server_parameters { unsigned int rtsp_port; struct module *parent; rtsp_types_t avType; - audio_codec_t audio_codec; - int audio_sample_rate; - int audio_channels; - int audio_bps; + struct audio_desc adesc; int rtp_port_video; //server rtp port int rtp_port_audio; codec_t video_codec; diff --git a/src/video_rxtx.cpp b/src/video_rxtx.cpp index 6f2117af6..66f45253c 100644 --- a/src/video_rxtx.cpp +++ b/src/video_rxtx.cpp @@ -61,6 +61,8 @@ #include "video_display.h" #include "video_rxtx.hpp" +#define MOD_NAME "[vrxtx] " + using std::map; using std::shared_ptr; using std::string; @@ -220,3 +222,9 @@ void video_rxtx::list(bool full) list_modules(LIBRARY_CLASS_VIDEO_RXTX, VIDEO_RXTX_ABI_VERSION, full); } +void +video_rxtx::set_audio_spec(const struct audio_desc * /* desc */, + int /* audio_rx_port */) +{ + MSG(INFO, "video RXTX not h264_rtp, not setting audio...\n"); +} diff --git a/src/video_rxtx.hpp b/src/video_rxtx.hpp index f042fd8d1..3dd1da921 100644 --- a/src/video_rxtx.hpp +++ b/src/video_rxtx.hpp @@ -47,6 +47,7 @@ #define VIDEO_RXTX_ABI_VERSION 3 +struct audio_desc; struct display; struct module; struct video_compress; @@ -91,6 +92,7 @@ public: virtual void join(); static video_rxtx *create(std::string const & name, std::map const &); static void list(bool full); + virtual void set_audio_spec(const struct audio_desc *desc, int audio_rx_port); std::string m_port_id; protected: video_rxtx(std::map const &); diff --git a/src/video_rxtx/h264_rtp.cpp b/src/video_rxtx/h264_rtp.cpp index 9d75a5c52..5400df12f 100644 --- a/src/video_rxtx/h264_rtp.cpp +++ b/src/video_rxtx/h264_rtp.cpp @@ -40,6 +40,8 @@ */ #include +#include // for uint32_t +#include // for printf #include #include #include @@ -49,12 +51,13 @@ #include "host.h" #include "lib_common.h" #include "rtp/rtp.h" -#include "rtp/rtpenc_h264.h" +#include "rtsp/rtsp_utils.h" // for rtsp_types_t #include "transmit.h" #include "tv.h" +#include "types.h" // for video_frame, H264, JPEG, MJPG #include "utils/color_out.h" #include "utils/sdp.h" // for sdp_print_supported_codecs -#include "video.h" +#include "video_codec.h" // for get_codec_name #include "video_rxtx.hpp" #include "video_rxtx/h264_rtp.hpp" @@ -69,37 +72,50 @@ h264_rtp_video_rxtx::h264_rtp_video_rxtx(std::map const &p rtsp_params.rtsp_port = (unsigned) rtsp_port; rtsp_params.parent = static_cast(params.at("parent").ptr); rtsp_params.avType = static_cast(params.at("avType").l); - rtsp_params.audio_codec = static_cast(params.at("audio_codec").l); - rtsp_params.audio_sample_rate = params.at("audio_sample_rate").i; - rtsp_params.audio_channels = params.at("audio_channels").i; - rtsp_params.audio_bps = params.at("audio_bps").i; rtsp_params.rtp_port_video = params.at("rx_port").i; //server rtp port - rtsp_params.rtp_port_audio = params.at("a_rx_port").i; - rtsp_params.video_codec = H264; +} - if ((rtsp_params.avType & rtsp_type_video) == 0U) { - m_rtsp_server = c_start_server(rtsp_params); +/** + * this function is used to configure ther RTSP server either + * for video-only or using both audio and video. For audio-only + * RTSP server, the server is run directly from + * h264_rtp_video_rxtx::set_audio_spec(). + */ +void +h264_rtp_video_rxtx::configure_rtsp_server_video() +{ + assert((rtsp_params.avType & rtsp_type_video) != 0); + if (rtsp_params.video_codec == H264) { + tx_send_std = tx_send_h264; + } else if (rtsp_params.video_codec == JPEG || + rtsp_params.video_codec == MJPG) { + tx_send_std = tx_send_jpeg; + } else { + MSG(ERROR, + "codecs other than H.264 and JPEG currently not " + "supported, got %s\n", + get_codec_name(rtsp_params.video_codec)); + return; } + + if ((rtsp_params.avType & rtsp_type_audio) != 0) { + if (!audio_params_set) { + MSG(INFO, "Waiting for audio specs...\n"); + return; + } + } + m_rtsp_server = c_start_server(rtsp_params); } void h264_rtp_video_rxtx::send_frame(shared_ptr tx_frame) noexcept { if (m_rtsp_server == nullptr) { - if (tx_frame->color_spec == H264) { - tx_send_std = tx_send_h264; - } else if (tx_frame->color_spec == JPEG || - tx_frame->color_spec == MJPG) { - tx_send_std = tx_send_jpeg; - } else { - MSG(ERROR, - "codecs other than H.264 and JPEG currently not " - "supported, got %s\n", - get_codec_name(tx_frame->color_spec)); - return; - } rtsp_params.video_codec = tx_frame->color_spec; - m_rtsp_server = c_start_server(rtsp_params); + configure_rtsp_server_video(); + } + if (m_rtsp_server == nullptr) { + return; } tx_send_std(m_tx, tx_frame.get(), m_network_device); @@ -129,6 +145,19 @@ void h264_rtp_video_rxtx::join() video_rxtx::join(); } +void +h264_rtp_video_rxtx::set_audio_spec(const struct audio_desc *desc, + int audio_rx_port) +{ + rtsp_params.adesc = *desc; + rtsp_params.rtp_port_audio = audio_rx_port; + audio_params_set = true; + + if ((rtsp_params.avType & rtsp_type_video) == 0U) { + m_rtsp_server = c_start_server(rtsp_params); + } +} + static void rtps_server_usage(){ printf("\n[RTSP SERVER] usage:\n"); color_printf("\t" TBOLD("-x rtsp[:port=number]") "\n"); diff --git a/src/video_rxtx/h264_rtp.hpp b/src/video_rxtx/h264_rtp.hpp index 1636eb4f3..8363ad82c 100644 --- a/src/video_rxtx/h264_rtp.hpp +++ b/src/video_rxtx/h264_rtp.hpp @@ -42,12 +42,15 @@ #ifndef VIDEO_RXTX_H264_RTP_H_ #define VIDEO_RXTX_H264_RTP_H_ +#include // for atomic_bool +#include // for map +#include // for shared_ptr +#include // for string + #include "rtsp/c_basicRTSPOnlyServer.h" -#include "video_rxtx.hpp" #include "video_rxtx/rtp.hpp" -struct rtp; -struct tx; +union param_u; struct video_frame; class h264_rtp_video_rxtx : public rtp_video_rxtx { @@ -55,13 +58,16 @@ public: h264_rtp_video_rxtx(std::map const &, int); virtual ~h264_rtp_video_rxtx(); void join() override; + void set_audio_spec(const struct audio_desc *desc, int audio_rx_port) override; private: virtual void send_frame(std::shared_ptr) noexcept override; virtual void *(*get_receiver_thread() noexcept)(void *arg) override { - return NULL; + return nullptr; } - struct rtsp_server_parameters rtsp_params; - rtsp_serv_t *m_rtsp_server = nullptr; + void configure_rtsp_server_video(); + struct rtsp_server_parameters rtsp_params{}; + std::atomic audio_params_set = false; + rtsp_serv_t *m_rtsp_server = nullptr; void (*tx_send_std)(struct tx *tx_session, struct video_frame *frame, struct rtp *rtp_session); };