mirror of
https://github.com/outbackdingo/UltraGrid.git
synced 2026-03-21 17:40:23 +00:00
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:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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 = "";
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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 &);
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user