mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	module-rtp: fix direct timestamps
fix some other properties.
This commit is contained in:
		
							parent
							
								
									3b685581a4
								
							
						
					
					
						commit
						8e5b9da177
					
				
					 6 changed files with 46 additions and 16 deletions
				
			
		| 
						 | 
					@ -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);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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));
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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. */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue