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).
This commit is contained in:
Martin Pulec
2024-08-07 14:32:20 +02:00
parent 78f2a30f12
commit 41b0388624
10 changed files with 113 additions and 44 deletions

View File

@@ -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<audio_frame2_resampler> 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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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)) {

View File

@@ -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 = "";

View File

@@ -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;

View File

@@ -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");
}

View File

@@ -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<std::string, param_u> 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<std::string, param_u> const &);

View File

@@ -40,6 +40,8 @@
*/
#include <cctype>
#include <cstdint> // for uint32_t
#include <cstdio> // for printf
#include <cstdlib>
#include <cstring>
#include <memory>
@@ -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<std::string, param_u> const &p
rtsp_params.rtsp_port = (unsigned) rtsp_port;
rtsp_params.parent = static_cast<struct module *>(params.at("parent").ptr);
rtsp_params.avType = static_cast<rtsp_types_t>(params.at("avType").l);
rtsp_params.audio_codec = static_cast<audio_codec_t>(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<video_frame> 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");

View File

@@ -42,12 +42,15 @@
#ifndef VIDEO_RXTX_H264_RTP_H_
#define VIDEO_RXTX_H264_RTP_H_
#include <atomic> // for atomic_bool
#include <map> // for map
#include <memory> // for shared_ptr
#include <string> // 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<std::string, param_u> 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<video_frame>) 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<bool> 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);
};