mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-02 09:01:50 -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