mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	module-rtp: parse some more SDP
This commit is contained in:
		
							parent
							
								
									38f908e758
								
							
						
					
					
						commit
						14194e137f
					
				
					 1 changed files with 169 additions and 16 deletions
				
			
		| 
						 | 
					@ -29,6 +29,7 @@
 | 
				
			||||||
#include <unistd.h>
 | 
					#include <unistd.h>
 | 
				
			||||||
#include <arpa/inet.h>
 | 
					#include <arpa/inet.h>
 | 
				
			||||||
#include <netinet/in.h>
 | 
					#include <netinet/in.h>
 | 
				
			||||||
 | 
					#include <ctype.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <spa/param/audio/format-utils.h>
 | 
					#include <spa/param/audio/format-utils.h>
 | 
				
			||||||
#include <spa/utils/hook.h>
 | 
					#include <spa/utils/hook.h>
 | 
				
			||||||
| 
						 | 
					@ -229,23 +230,30 @@ static const struct pw_impl_module_events module_events = {
 | 
				
			||||||
	.destroy = module_destroy,
 | 
						.destroy = module_destroy,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int rtp_source_setup(struct impl *data)
 | 
					struct sdp_info {
 | 
				
			||||||
 | 
						const char *origin;
 | 
				
			||||||
 | 
						const char *session;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct sockaddr_storage sa;
 | 
				
			||||||
 | 
						socklen_t salen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uint16_t port;
 | 
				
			||||||
 | 
						uint8_t payload;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct spa_audio_info_raw info;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int rtp_session_new(struct impl *data, struct sdp_info *sdp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct spa_audio_info_raw info = { 0 };
 | 
					 | 
				
			||||||
	const struct spa_pod *params[1];
 | 
						const struct spa_pod *params[1];
 | 
				
			||||||
	struct spa_pod_builder b;
 | 
						struct spa_pod_builder b;
 | 
				
			||||||
	uint32_t n_params;
 | 
						uint32_t n_params;
 | 
				
			||||||
	uint8_t buffer[1024];
 | 
						uint8_t buffer[1024];
 | 
				
			||||||
	int res;
 | 
						int res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	info.rate = 44100;
 | 
						data->stride = sdp->info.channels * sizeof(float);
 | 
				
			||||||
	info.channels = 2;
 | 
					 | 
				
			||||||
	info.format = SPA_AUDIO_FORMAT_F32;
 | 
					 | 
				
			||||||
	info.position[0] = SPA_AUDIO_CHANNEL_FL;
 | 
					 | 
				
			||||||
	info.position[1] = SPA_AUDIO_CHANNEL_FR;
 | 
					 | 
				
			||||||
	data->stride = info.channels * sizeof(float);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_properties_setf(data->playback_props, PW_KEY_NODE_RATE, "1/%d", info.rate);
 | 
						pw_properties_setf(data->playback_props, PW_KEY_NODE_RATE, "1/%d", sdp->info.rate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	data->playback = pw_stream_new(data->core,
 | 
						data->playback = pw_stream_new(data->core,
 | 
				
			||||||
			"rtp-source playback", data->playback_props);
 | 
								"rtp-source playback", data->playback_props);
 | 
				
			||||||
| 
						 | 
					@ -260,7 +268,7 @@ static int rtp_source_setup(struct impl *data)
 | 
				
			||||||
	n_params = 0;
 | 
						n_params = 0;
 | 
				
			||||||
	spa_pod_builder_init(&b, buffer, sizeof(buffer));
 | 
						spa_pod_builder_init(&b, buffer, sizeof(buffer));
 | 
				
			||||||
	params[n_params++] = spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat,
 | 
						params[n_params++] = spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat,
 | 
				
			||||||
			&info);
 | 
								&sdp->info);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((res = pw_stream_connect(data->playback,
 | 
						if ((res = pw_stream_connect(data->playback,
 | 
				
			||||||
			PW_DIRECTION_OUTPUT,
 | 
								PW_DIRECTION_OUTPUT,
 | 
				
			||||||
| 
						 | 
					@ -274,17 +282,158 @@ static int rtp_source_setup(struct impl *data)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int parse_sdp(struct impl *impl, const char *sdp)
 | 
					static int parse_sdp_c(struct impl *impl, char *c, struct sdp_info *info)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	pw_log_info("%s", sdp);
 | 
						int res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						c[strcspn(c, "/")] = 0;
 | 
				
			||||||
 | 
						if (spa_strstartswith(c, "c=IN IP4 ")) {
 | 
				
			||||||
 | 
							struct sockaddr_in *sa = (struct sockaddr_in*) &info->sa;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							c += sizeof("c=IN IP4 ");
 | 
				
			||||||
 | 
							if (inet_pton(AF_INET, c, &sa->sin_addr) <= 0) {
 | 
				
			||||||
 | 
								res = -errno;
 | 
				
			||||||
 | 
								pw_log_warn("inet_pton(%s) failed: %m", c);
 | 
				
			||||||
 | 
								goto error;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							sa->sin_family = AF_INET;
 | 
				
			||||||
 | 
							info->salen = sizeof(struct sockaddr_in);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else if (spa_strstartswith(c, "c=IN IP6 ")) {
 | 
				
			||||||
 | 
							struct sockaddr_in6 *sa = (struct sockaddr_in6*) &info->sa;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							c += sizeof("c=IN IP6 ");
 | 
				
			||||||
 | 
							if (inet_pton(AF_INET6, c, &sa->sin6_addr) <= 0) {
 | 
				
			||||||
 | 
								res = -errno;
 | 
				
			||||||
 | 
								pw_log_warn("inet_pton(%s) failed: %m", c);
 | 
				
			||||||
 | 
								goto error;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							sa->sin6_family = AF_INET6;
 | 
				
			||||||
 | 
							info->salen = sizeof(struct sockaddr_in6);
 | 
				
			||||||
 | 
						} else
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						res= 0;
 | 
				
			||||||
 | 
					error:
 | 
				
			||||||
 | 
						return res;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int parse_sdp_m(struct impl *impl, char *c, struct sdp_info *info)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int port, payload;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!spa_strstartswith(c, "m=audio "))
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						c += sizeof("m=audio ");
 | 
				
			||||||
 | 
						if (sscanf(c, "%i RTP/AVP %i", &port, &payload) != 2)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (port <= 0 || port > 0xFFFF)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (payload < 0 || payload > 127)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						info->port = (uint16_t) port;
 | 
				
			||||||
 | 
						info->payload = (uint8_t) payload;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int parse_sap(struct impl *impl, const void *data, size_t len)
 | 
					static int parse_sdp_a(struct impl *impl, char *c, struct sdp_info *info)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int payload, len, rate, channels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!spa_strstartswith(c, "a=rtpmap:"))
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						c += sizeof("a=rtpmap:");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (sscanf(c, "%i %n", &payload, &len) != 1)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (payload < 0 || payload > 127)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (payload != info->payload)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						c += len;
 | 
				
			||||||
 | 
						if (spa_strstartswith(c, "L16/")) {
 | 
				
			||||||
 | 
							info->info.format = SPA_AUDIO_FORMAT_S16_BE;
 | 
				
			||||||
 | 
							c += 4;
 | 
				
			||||||
 | 
						} else
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (sscanf(c, "%u/%u", &rate, &channels) == 2) {
 | 
				
			||||||
 | 
							info->info.rate = rate;
 | 
				
			||||||
 | 
							info->info.channels = channels;
 | 
				
			||||||
 | 
							if (channels == 2) {
 | 
				
			||||||
 | 
								info->info.position[0] = SPA_AUDIO_CHANNEL_FL;
 | 
				
			||||||
 | 
								info->info.position[1] = SPA_AUDIO_CHANNEL_FR;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else if (sscanf(c, "%u", &rate) == 1) {
 | 
				
			||||||
 | 
							info->info.rate = rate;
 | 
				
			||||||
 | 
							info->info.channels = 1;
 | 
				
			||||||
 | 
						} else
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int parse_sdp(struct impl *impl, char *sdp, struct sdp_info *info)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char *s = sdp;
 | 
				
			||||||
 | 
						int count = 0, res = 0;
 | 
				
			||||||
 | 
						size_t l;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (*s) {
 | 
				
			||||||
 | 
							if ((l = strcspn(s, "\r\n")) < 2)
 | 
				
			||||||
 | 
								goto too_short;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							s[l] = 0;
 | 
				
			||||||
 | 
							pw_log_info("%d: %s", count, s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (count++ == 0 && strcmp(s, "v=0") != 0)
 | 
				
			||||||
 | 
								goto invalid_version;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (spa_strstartswith(s, "o="))
 | 
				
			||||||
 | 
					            		info->origin = &s[2];
 | 
				
			||||||
 | 
							else if (spa_strstartswith(s, "s="))
 | 
				
			||||||
 | 
					            		info->session = &s[2];
 | 
				
			||||||
 | 
							else if (spa_strstartswith(s, "c="))
 | 
				
			||||||
 | 
								res = parse_sdp_c(impl, s, info);
 | 
				
			||||||
 | 
							else if (spa_strstartswith(s, "m="))
 | 
				
			||||||
 | 
								res = parse_sdp_m(impl, s, info);
 | 
				
			||||||
 | 
							else if (spa_strstartswith(s, "a="))
 | 
				
			||||||
 | 
								res = parse_sdp_a(impl, s, info);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (res < 0)
 | 
				
			||||||
 | 
								goto error;
 | 
				
			||||||
 | 
							s += l + 1;
 | 
				
			||||||
 | 
							while (isspace(*s))
 | 
				
			||||||
 | 
								s++;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					too_short:
 | 
				
			||||||
 | 
						pw_log_warn("SDP: line starting with `%.6s...' too short", s);
 | 
				
			||||||
 | 
						return -EINVAL;
 | 
				
			||||||
 | 
					invalid_version:
 | 
				
			||||||
 | 
						pw_log_warn("SDP: invalid first version line `%*s'", (int)l, s);
 | 
				
			||||||
 | 
						return -EINVAL;
 | 
				
			||||||
 | 
					error:
 | 
				
			||||||
 | 
						return res;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int parse_sap(struct impl *impl, void *data, size_t len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct sap_header *header;
 | 
						struct sap_header *header;
 | 
				
			||||||
	const char *mime;
 | 
						char *mime, *sdp;
 | 
				
			||||||
	const char *sdp;
 | 
						struct sdp_info info;
 | 
				
			||||||
 | 
						int res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (len < 8)
 | 
						if (len < 8)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
| 
						 | 
					@ -301,7 +450,11 @@ static int parse_sap(struct impl *impl, const void *data, size_t len)
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return parse_sdp(impl, sdp);
 | 
						spa_zero(info);
 | 
				
			||||||
 | 
						if ((res = parse_sdp(impl, sdp, &info)) < 0)
 | 
				
			||||||
 | 
							return res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return res;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue