module-rtp: fix direct timestamps

fix some other properties.
This commit is contained in:
Wim Taymans 2023-03-06 10:46:21 +01:00
parent 3b685581a4
commit 8e5b9da177
6 changed files with 46 additions and 16 deletions

View file

@ -648,8 +648,9 @@ static struct session *session_new_announce(struct impl *impl, struct node *node
sdp->ntp = (uint32_t) time(NULL) + 2208988800U; sdp->ntp = (uint32_t) time(NULL) + 2208988800U;
sess->props = props; sess->props = props;
if ((str = pw_properties_get(props, "sess.name")) != NULL) if ((str = pw_properties_get(props, "sess.name")) == NULL)
sdp->session_name = strdup(str); str = pw_get_host_name();
sdp->session_name = strdup(str);
if ((str = pw_properties_get(props, "rtp.destination.port")) == NULL) if ((str = pw_properties_get(props, "rtp.destination.port")) == NULL)
goto error_free; goto error_free;
@ -763,7 +764,7 @@ static int session_load_source(struct session *session, struct pw_properties *pr
return -EINVAL; return -EINVAL;
} }
if ((str = pw_properties_get(props, "rtp.ts-offset")) != NULL) if ((str = pw_properties_get(props, "rtp.ts-offset")) != NULL)
pw_properties_set(props, "sess.ts-offset", str); fprintf(f, "\"sess.ts-offset\" = %s, ", str);
fprintf(f, " stream.props = {"); fprintf(f, " stream.props = {");
pw_properties_serialize_dict(f, &props->dict, 0); pw_properties_serialize_dict(f, &props->dict, 0);

View file

@ -64,7 +64,7 @@
* - `sess.name = <str>`: a session name * - `sess.name = <str>`: a session name
* - `sess.ts-offset = <int>`: an offset to apply to the timestamp, default -1 = random offset * - `sess.ts-offset = <int>`: an offset to apply to the timestamp, default -1 = random offset
* - `sess.ts-refclk = <string>`: the name of a reference clock * - `sess.ts-refclk = <string>`: the name of a reference clock
* - `sess.media = <string>`: the media type audio|midi, default audio * - `sess.media = <string>`: the media type audio|midi, default midi
* - `stream.props = {}`: properties to be passed to the stream * - `stream.props = {}`: properties to be passed to the stream
* *
* ## General options * ## General options
@ -487,6 +487,7 @@ static struct session *make_session(struct impl *impl, struct pw_properties *pro
{ {
struct session *sess; struct session *sess;
const char *str; const char *str;
struct pw_properties *copy;
sess = calloc(1, sizeof(struct session)); sess = calloc(1, sizeof(struct session));
if (sess == NULL) if (sess == NULL)
@ -507,15 +508,29 @@ static struct session *make_session(struct impl *impl, struct pw_properties *pro
pw_properties_setf(props, "rtp.sender-ssrc", "%u", sess->ssrc); pw_properties_setf(props, "rtp.sender-ssrc", "%u", sess->ssrc);
pw_properties_set(props, "rtp.session", sess->name); pw_properties_set(props, "rtp.session", sess->name);
copy = pw_properties_copy(props);
if (pw_properties_get(props, PW_KEY_MEDIA_CLASS) == NULL) {
const char *media = NULL;
str = pw_properties_get(props, "sess.media");
if (spa_streq(str, "midi"))
media = "Midi";
else if (spa_streq(str, "audio"))
media = "Audio";
if (media != NULL) {
pw_properties_setf(copy, PW_KEY_MEDIA_CLASS, "%s/Sink", media);
pw_properties_setf(props, PW_KEY_MEDIA_CLASS, "%s/Source", media);
}
}
sess->send = rtp_stream_new(impl->core, sess->send = rtp_stream_new(impl->core,
PW_DIRECTION_INPUT, pw_properties_copy(props), PW_DIRECTION_INPUT, copy,
&send_stream_events, sess); &send_stream_events, sess);
sess->recv = rtp_stream_new(impl->core, sess->recv = rtp_stream_new(impl->core,
PW_DIRECTION_OUTPUT, pw_properties_copy(props), PW_DIRECTION_OUTPUT, props,
&recv_stream_events, sess); &recv_stream_events, sess);
pw_properties_free(props);
return sess; return sess;
error: error:
pw_properties_free(props); pw_properties_free(props);

View file

@ -111,6 +111,8 @@ PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME);
#define DEFAULT_LOOP false #define DEFAULT_LOOP false
#define DEFAULT_DSCP 34 /* Default to AES-67 AF41 (34) */ #define DEFAULT_DSCP 34 /* Default to AES-67 AF41 (34) */
#define DEFAULT_TS_OFFSET -1
#define USAGE "source.ip=<source IP address, default:"DEFAULT_SOURCE_IP"> " \ #define USAGE "source.ip=<source IP address, default:"DEFAULT_SOURCE_IP"> " \
"destination.ip=<destination IP address, default:"DEFAULT_DESTINATION_IP"> " \ "destination.ip=<destination IP address, default:"DEFAULT_DESTINATION_IP"> " \
"destination.port=<int, default random beteen 46000 and 47024> " \ "destination.port=<int, default random beteen 46000 and 47024> " \
@ -395,6 +397,7 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
struct pw_properties *props = NULL, *stream_props = NULL; struct pw_properties *props = NULL, *stream_props = NULL;
char addr[64]; char addr[64];
const char *str, *sess_name; const char *str, *sess_name;
int64_t ts_offset;
int res = 0; int res = 0;
PW_LOG_TOPIC_INIT(mod_topic); PW_LOG_TOPIC_INIT(mod_topic);
@ -460,6 +463,7 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
copy_props(impl, props, "sess.min-ptime"); copy_props(impl, props, "sess.min-ptime");
copy_props(impl, props, "sess.max-ptime"); copy_props(impl, props, "sess.max-ptime");
copy_props(impl, props, "sess.latency.msec"); copy_props(impl, props, "sess.latency.msec");
copy_props(impl, props, "sess.ts-refclk");
str = pw_properties_get(props, "local.ifname"); str = pw_properties_get(props, "local.ifname");
impl->ifname = str ? strdup(str) : NULL; impl->ifname = str ? strdup(str) : NULL;
@ -484,6 +488,11 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
impl->mcast_loop = pw_properties_get_bool(props, "net.loop", DEFAULT_LOOP); impl->mcast_loop = pw_properties_get_bool(props, "net.loop", DEFAULT_LOOP);
impl->dscp = pw_properties_get_uint32(props, "net.dscp", DEFAULT_DSCP); impl->dscp = pw_properties_get_uint32(props, "net.dscp", DEFAULT_DSCP);
ts_offset = pw_properties_get_int64(props, "sess.ts-offset", DEFAULT_TS_OFFSET);
if (ts_offset == -1)
ts_offset = pw_rand32();
pw_properties_setf(stream_props, "rtp.sender-ts-offset", "%u", (uint32_t)ts_offset);
get_ip(&impl->src_addr, addr, sizeof(addr)); get_ip(&impl->src_addr, addr, sizeof(addr));
pw_properties_set(stream_props, "rtp.source.ip", addr); pw_properties_set(stream_props, "rtp.source.ip", addr);
get_ip(&impl->dst_addr, addr, sizeof(addr)); get_ip(&impl->dst_addr, addr, sizeof(addr));

View file

@ -99,6 +99,8 @@ PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME);
#define DEFAULT_CLEANUP_SEC 60 #define DEFAULT_CLEANUP_SEC 60
#define DEFAULT_SOURCE_IP "224.0.0.56" #define DEFAULT_SOURCE_IP "224.0.0.56"
#define DEFAULT_TS_OFFSET -1
#define USAGE "local.ifname=<local interface name to use> " \ #define USAGE "local.ifname=<local interface name to use> " \
"source.ip=<source IP address, default:"DEFAULT_SOURCE_IP"> " \ "source.ip=<source IP address, default:"DEFAULT_SOURCE_IP"> " \
"source.port=<int, source port> " \ "source.port=<int, source port> " \
@ -427,6 +429,7 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
const char *str, *sess_name; const char *str, *sess_name;
struct timespec value, interval; struct timespec value, interval;
struct pw_properties *props, *stream_props; struct pw_properties *props, *stream_props;
int64_t ts_offset;
int res = 0; int res = 0;
PW_LOG_TOPIC_INIT(mod_topic); PW_LOG_TOPIC_INIT(mod_topic);
@ -483,6 +486,7 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
copy_props(impl, props, "sess.min-ptime"); copy_props(impl, props, "sess.min-ptime");
copy_props(impl, props, "sess.max-ptime"); copy_props(impl, props, "sess.max-ptime");
copy_props(impl, props, "sess.latency.msec"); copy_props(impl, props, "sess.latency.msec");
copy_props(impl, props, "sess.ts-direct");
str = pw_properties_get(props, "local.ifname"); str = pw_properties_get(props, "local.ifname");
impl->ifname = str ? strdup(str) : NULL; impl->ifname = str ? strdup(str) : NULL;
@ -499,6 +503,11 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
goto out; goto out;
} }
ts_offset = pw_properties_get_int64(props, "sess.ts-offset", DEFAULT_TS_OFFSET);
if (ts_offset == -1)
ts_offset = pw_rand32();
pw_properties_setf(stream_props, "rtp.receiver-ts-offset", "%u", (uint32_t)ts_offset);
impl->always_process = pw_properties_get_bool(stream_props, impl->always_process = pw_properties_get_bool(stream_props,
PW_KEY_NODE_ALWAYS_PROCESS, true); PW_KEY_NODE_ALWAYS_PROCESS, true);

View file

@ -141,9 +141,9 @@ static int receive_rtp_audio(struct impl *impl, uint8_t *buffer, ssize_t len)
write = timestamp + impl->target_buffer; write = timestamp + impl->target_buffer;
if (!impl->have_sync) { if (!impl->have_sync) {
pw_log_info("sync to timestamp:%u seq:%u ts_offset:%u SSRC:%u direct:%d", pw_log_info("sync to timestamp:%u seq:%u ts_offset:%u SSRC:%u target:%u direct:%u",
write, impl->seq-1, impl->ts_offset, impl->ssrc, write, impl->seq-1, impl->ts_offset, impl->ssrc,
impl->direct_timestamp); impl->target_buffer, impl->direct_timestamp);
/* we read from timestamp, keeping target_buffer of data /* we read from timestamp, keeping target_buffer of data
* in the ringbuffer. */ * in the ringbuffer. */

View file

@ -250,7 +250,7 @@ struct rtp_stream *rtp_stream_new(struct pw_core *core,
const struct rtp_stream_events *events, void *data) const struct rtp_stream_events *events, void *data)
{ {
struct impl *impl; struct impl *impl;
const char *str, *media_class; const char *str;
uint8_t buffer[1024]; uint8_t buffer[1024];
struct spa_pod_builder b; struct spa_pod_builder b;
uint32_t n_params, min_samples, max_samples; uint32_t n_params, min_samples, max_samples;
@ -301,7 +301,6 @@ struct rtp_stream *rtp_stream_new(struct pw_core *core,
} }
impl->stride = impl->format_info->size * impl->info.info.raw.channels; impl->stride = impl->format_info->size * impl->info.info.raw.channels;
impl->rate = impl->info.info.raw.rate; impl->rate = impl->info.info.raw.rate;
media_class = direction == PW_DIRECTION_INPUT ? "Audio/Sink" : "Audio/Source";
break; break;
case SPA_MEDIA_TYPE_application: case SPA_MEDIA_TYPE_application:
impl->format_info = find_audio_format_info(&impl->info); impl->format_info = find_audio_format_info(&impl->info);
@ -314,7 +313,6 @@ struct rtp_stream *rtp_stream_new(struct pw_core *core,
impl->rate = pw_properties_get_uint32(props, "midi.rate", 10000); impl->rate = pw_properties_get_uint32(props, "midi.rate", 10000);
if (impl->rate == 0) if (impl->rate == 0)
impl->rate = 10000; impl->rate = 10000;
media_class = direction == PW_DIRECTION_INPUT ? "Midi/Sink" : "Midi/Source";
break; break;
default: default:
spa_assert_not_reached(); spa_assert_not_reached();
@ -323,8 +321,6 @@ struct rtp_stream *rtp_stream_new(struct pw_core *core,
pw_properties_setf(props, "rtp.mime", "%s", impl->format_info->mime); pw_properties_setf(props, "rtp.mime", "%s", impl->format_info->mime);
if (pw_properties_get(props, PW_KEY_MEDIA_CLASS) == NULL)
pw_properties_set(props, PW_KEY_MEDIA_CLASS, media_class);
if (pw_properties_get(props, PW_KEY_NODE_VIRTUAL) == NULL) if (pw_properties_get(props, PW_KEY_NODE_VIRTUAL) == NULL)
pw_properties_set(props, PW_KEY_NODE_VIRTUAL, "true"); pw_properties_set(props, PW_KEY_NODE_VIRTUAL, "true");
if (pw_properties_get(props, PW_KEY_NODE_NETWORK) == NULL) if (pw_properties_get(props, PW_KEY_NODE_NETWORK) == NULL)
@ -337,7 +333,7 @@ struct rtp_stream *rtp_stream_new(struct pw_core *core,
impl->ts_offset = pw_properties_get_uint32(props, "rtp.sender-ts-offset", pw_rand32()); impl->ts_offset = pw_properties_get_uint32(props, "rtp.sender-ts-offset", pw_rand32());
} else { } else {
impl->have_ssrc = pw_properties_fetch_uint32(props, "rtp.receiver-ssrc", &impl->ssrc); impl->have_ssrc = pw_properties_fetch_uint32(props, "rtp.receiver-ssrc", &impl->ssrc);
if (!pw_properties_fetch_uint32(props, "rtp.receiver-ts-offset", &impl->ts_offset)) if (pw_properties_fetch_uint32(props, "rtp.receiver-ts-offset", &impl->ts_offset) < 0)
impl->direct_timestamp = false; impl->direct_timestamp = false;
} }