|
|
|
@ -300,8 +300,13 @@ static void attr_free(struct sdp_attribute *p);
|
|
|
|
|
static void attr_insert(struct sdp_attributes *attrs, struct sdp_attribute *attr);
|
|
|
|
|
INLINE void chopper_append_c(struct sdp_chopper *c, const char *s);
|
|
|
|
|
void handle_sdp_media_attributes(GString *s, struct call_media *media,
|
|
|
|
|
unsigned int port, struct packet_stream *rtp_ps,
|
|
|
|
|
const endpoint_t *address, struct call_media *source_media,
|
|
|
|
|
struct packet_stream *rtp_ps,
|
|
|
|
|
packet_stream_list *rtp_ps_link, sdp_ng_flags *flags);
|
|
|
|
|
static struct call_media *sdp_out_set_source_media_address(struct call_media *media,
|
|
|
|
|
struct packet_stream *rtp_ps,
|
|
|
|
|
struct sdp_ng_flags *flags,
|
|
|
|
|
const endpoint_t **sdp_address);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Checks whether an attribute removal request exists for a given session level.
|
|
|
|
@ -2255,6 +2260,12 @@ void sdp_insert_monologue_attributes(GString *gs, union sdp_attr_print_arg a, co
|
|
|
|
|
append_str_attr_to_gstring(gs, &s->strs.name, &s->strs.value, flags, MT_UNKNOWN);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
void sdp_insert_all_attributes(GString *s, struct call_media *media, struct sdp_ng_flags *flags) {
|
|
|
|
|
for (__auto_type l = media->all_attributes.head; l; l = l->next) {
|
|
|
|
|
__auto_type a = l->data;
|
|
|
|
|
append_str_attr_to_gstring(s, &a->strs.name, &a->strs.value, flags, media->type_id);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int replace_media_type(struct sdp_chopper *chop, struct sdp_media *media, struct call_media *cm) {
|
|
|
|
|
str *type = &media->media_type_str;
|
|
|
|
@ -2915,10 +2926,12 @@ static void insert_crypto(GString *s, struct call_media *media, const sdp_ng_fla
|
|
|
|
|
insert_crypto1(s, media, l->data, flags);
|
|
|
|
|
}
|
|
|
|
|
static void insert_rtcp_attr(GString *s, struct packet_stream *ps, const sdp_ng_flags *flags,
|
|
|
|
|
struct sdp_media *sdp_media) {
|
|
|
|
|
struct sdp_media *sdp_media)
|
|
|
|
|
{
|
|
|
|
|
if (flags->no_rtcp_attr)
|
|
|
|
|
return;
|
|
|
|
|
g_autoptr(GString) s_dst = g_string_new("");
|
|
|
|
|
|
|
|
|
|
g_string_append_printf(s_dst, "%u", ps->selected_sfd->socket.local.port);
|
|
|
|
|
|
|
|
|
|
if (flags->full_rtcp_attr) {
|
|
|
|
@ -3162,6 +3175,7 @@ static struct packet_stream *print_rtcp(GString *s, struct call_media *media, pa
|
|
|
|
|
}
|
|
|
|
|
else if (ps_rtcp && flags->ice_option != ICE_FORCE_RELAY) {
|
|
|
|
|
insert_rtcp_attr(s, ps_rtcp, flags, sdp_media);
|
|
|
|
|
|
|
|
|
|
if (MEDIA_ISSET(media, RTCP_MUX))
|
|
|
|
|
append_attr_to_gstring(s, "rtcp-mux", NULL, flags, media->type_id);
|
|
|
|
|
}
|
|
|
|
@ -3187,6 +3201,7 @@ static void print_sdp_session_section(GString *s, sdp_ng_flags *flags,
|
|
|
|
|
/* TODO: rework an appending of parameters in terms of sdp attribute manipulations */
|
|
|
|
|
static struct packet_stream *print_sdp_media_section(GString *s, struct call_media *media,
|
|
|
|
|
struct sdp_media *sdp_media,
|
|
|
|
|
struct call_media *source_media,
|
|
|
|
|
const sdp_ng_flags *flags,
|
|
|
|
|
packet_stream_list *rtp_ps_link,
|
|
|
|
|
bool is_active,
|
|
|
|
@ -3212,6 +3227,9 @@ static struct packet_stream *print_sdp_media_section(GString *s, struct call_med
|
|
|
|
|
if (!flags->original_sendrecv)
|
|
|
|
|
append_attr_to_gstring(s, sdp_get_sendrecv(media), NULL, flags,
|
|
|
|
|
media->type_id);
|
|
|
|
|
else if (source_media)
|
|
|
|
|
append_attr_to_gstring(s, sdp_get_sendrecv(source_media), NULL, flags,
|
|
|
|
|
media->type_id);
|
|
|
|
|
|
|
|
|
|
ps_rtcp = print_rtcp(s, media, rtp_ps_link, flags, sdp_media);
|
|
|
|
|
|
|
|
|
@ -3310,7 +3328,7 @@ static const char *replace_sdp_media_section(struct sdp_chopper *chop, struct ca
|
|
|
|
|
is_active = false;
|
|
|
|
|
|
|
|
|
|
next:
|
|
|
|
|
print_sdp_media_section(chop->output, call_media, sdp_media, flags, rtp_ps_link, is_active,
|
|
|
|
|
print_sdp_media_section(chop->output, call_media, sdp_media, NULL, flags, rtp_ps_link, is_active,
|
|
|
|
|
attr_get_by_id(&sdp_media->attributes, ATTR_END_OF_CANDIDATES), false);
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
@ -3690,26 +3708,18 @@ static void sdp_out_add_bandwidth(GString *out, struct call_monologue *monologue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void sdp_out_add_media_connection(GString *out, struct call_media *media,
|
|
|
|
|
struct packet_stream *rtp_ps, sdp_ng_flags *flags)
|
|
|
|
|
struct packet_stream *rtp_ps, const sockaddr_t *address, sdp_ng_flags *flags)
|
|
|
|
|
{
|
|
|
|
|
if (!is_addr_unspecified(&flags->parsed_media_address))
|
|
|
|
|
address = &flags->parsed_media_address;
|
|
|
|
|
|
|
|
|
|
const char *media_conn_address = NULL;
|
|
|
|
|
const char *media_conn_address_type = rtp_ps->selected_sfd->local_intf->advertised_address.addr.family->rfc_name;
|
|
|
|
|
const char *media_conn_address_type = address->family->rfc_name;
|
|
|
|
|
|
|
|
|
|
/* we want to keep an original media connection for message / force relay */
|
|
|
|
|
struct media_subscription *ms = media->media_subscriptions.head ? media->media_subscriptions.head->data : NULL;
|
|
|
|
|
if (ms && ms->media && ms->media->streams.head && (media->type_id == MT_MESSAGE || flags->ice_option == ICE_FORCE_RELAY))
|
|
|
|
|
{
|
|
|
|
|
__auto_type sub_ps = ms->media->streams.head->data;
|
|
|
|
|
media_conn_address = sockaddr_print_buf(&sub_ps->advertised_endpoint.address);
|
|
|
|
|
media_conn_address_type = media->desired_family->rfc_name;
|
|
|
|
|
}
|
|
|
|
|
else if (PS_ISSET(rtp_ps, ZERO_ADDR) && !MEDIA_ISSET(media, ICE)) {
|
|
|
|
|
media_conn_address = rtp_ps->selected_sfd->local_intf->spec->local_address.addr.family->unspec_string;
|
|
|
|
|
media_conn_address_type = rtp_ps->selected_sfd->local_intf->advertised_address.addr.family->rfc_name;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
media_conn_address = sockaddr_print_buf(&rtp_ps->selected_sfd->local_intf->advertised_address.addr);
|
|
|
|
|
}
|
|
|
|
|
if (PS_ISSET(rtp_ps, ZERO_ADDR) && !MEDIA_ISSET(media, ICE))
|
|
|
|
|
media_conn_address = address->family->unspec_string;
|
|
|
|
|
else
|
|
|
|
|
media_conn_address = sockaddr_print_buf(address);
|
|
|
|
|
|
|
|
|
|
g_string_append_printf(out,
|
|
|
|
|
"c=IN %s %s\r\n",
|
|
|
|
@ -3721,11 +3731,11 @@ static void sdp_out_add_media_connection(GString *out, struct call_media *media,
|
|
|
|
|
* Add OSRTP related media line.
|
|
|
|
|
*/
|
|
|
|
|
static void sdp_out_add_osrtp_media(GString *out, struct call_media *media,
|
|
|
|
|
const struct transport_protocol *prtp, unsigned int port)
|
|
|
|
|
const struct transport_protocol *prtp, const endpoint_t *address)
|
|
|
|
|
{
|
|
|
|
|
g_string_append_printf(out, "m=" STR_FORMAT " %d %s ",
|
|
|
|
|
STR_FMT(&media->type),
|
|
|
|
|
port,
|
|
|
|
|
address ? address->port : 0,
|
|
|
|
|
prtp->name);
|
|
|
|
|
|
|
|
|
|
/* print codecs and add newline */
|
|
|
|
@ -3759,27 +3769,8 @@ static bool sdp_out_add_media(GString *out, struct call_media *media,
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static unsigned int sdp_out_set_port(struct call_media *media,
|
|
|
|
|
struct packet_stream *rtp_ps, sdp_ng_flags *flags)
|
|
|
|
|
{
|
|
|
|
|
/* set port to 0 in case when there is no FD found (usecase with OSRTP scenarios) */
|
|
|
|
|
unsigned int port = rtp_ps->selected_sfd ? rtp_ps->selected_sfd->socket.local.port : 0;
|
|
|
|
|
|
|
|
|
|
/* we want to keep an original media port for message or force relay */
|
|
|
|
|
if (media->type_id == MT_MESSAGE || flags->ice_option == ICE_FORCE_RELAY) {
|
|
|
|
|
struct media_subscription *ms = media->media_subscriptions.head ? media->media_subscriptions.head->data : NULL;
|
|
|
|
|
if (ms && ms->media && ms->media->streams.head)
|
|
|
|
|
{
|
|
|
|
|
__auto_type sub_ps = ms->media->streams.head->data;
|
|
|
|
|
port = sub_ps->advertised_endpoint.port;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return port;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void sdp_out_handle_osrtp1(GString *out, struct call_media *media,
|
|
|
|
|
unsigned int port, const struct transport_protocol *prtp,
|
|
|
|
|
const endpoint_t *address, const struct transport_protocol *prtp,
|
|
|
|
|
struct packet_stream *rtp_ps, packet_stream_list *rtp_ps_link,
|
|
|
|
|
sdp_ng_flags *flags)
|
|
|
|
|
{
|
|
|
|
@ -3788,14 +3779,14 @@ static void sdp_out_handle_osrtp1(GString *out, struct call_media *media,
|
|
|
|
|
|
|
|
|
|
if (MEDIA_ISSET(media, LEGACY_OSRTP) && !MEDIA_ISSET(media, LEGACY_OSRTP_REV))
|
|
|
|
|
/* generate rejected m= line for accepted legacy OSRTP */
|
|
|
|
|
sdp_out_add_osrtp_media(out, media, prtp, 0);
|
|
|
|
|
sdp_out_add_osrtp_media(out, media, prtp, NULL);
|
|
|
|
|
else if(flags->osrtp_offer_legacy && (flags->opmode == OP_OFFER || flags->opmode == OP_REQUEST)) {
|
|
|
|
|
const struct transport_protocol *proto = media->protocol;
|
|
|
|
|
media->protocol = prtp;
|
|
|
|
|
|
|
|
|
|
sdp_out_add_osrtp_media(out, media, prtp, port);
|
|
|
|
|
sdp_out_add_osrtp_media(out, media, prtp, address);
|
|
|
|
|
/* add attributes and connection information */
|
|
|
|
|
handle_sdp_media_attributes(out, media, port, rtp_ps, rtp_ps_link, flags);
|
|
|
|
|
handle_sdp_media_attributes(out, media, address, NULL, rtp_ps, rtp_ps_link, flags);
|
|
|
|
|
|
|
|
|
|
media->protocol = proto;
|
|
|
|
|
}
|
|
|
|
@ -3817,11 +3808,27 @@ static void sdp_out_handle_osrtp2(GString *out, struct call_media *media,
|
|
|
|
|
* to `print_sdp_media_section()`.
|
|
|
|
|
*/
|
|
|
|
|
void handle_sdp_media_attributes(GString *s, struct call_media *media,
|
|
|
|
|
unsigned int port, struct packet_stream *rtp_ps,
|
|
|
|
|
const endpoint_t *address, struct call_media *source_media,
|
|
|
|
|
struct packet_stream *rtp_ps,
|
|
|
|
|
packet_stream_list *rtp_ps_link, sdp_ng_flags *flags)
|
|
|
|
|
{
|
|
|
|
|
if (source_media) {
|
|
|
|
|
// just print out all original values and attributes
|
|
|
|
|
sdp_out_add_media_connection(s, media, rtp_ps, &address->address, flags);
|
|
|
|
|
sdp_out_add_bandwidth(s, source_media->monologue, media);
|
|
|
|
|
sdp_insert_all_attributes(s, source_media, flags);
|
|
|
|
|
if (MEDIA_ISSET(source_media, ICE)) {
|
|
|
|
|
struct packet_stream *rtcp_ps = rtp_ps->rtcp_sibling;
|
|
|
|
|
// XXX is this a better or worse test than used in print_rtcp()?
|
|
|
|
|
if (rtcp_ps && (!rtcp_ps->selected_sfd || rtcp_ps->selected_sfd->socket.local.port == 0))
|
|
|
|
|
rtcp_ps = NULL;
|
|
|
|
|
insert_candidates(s, rtp_ps, rtcp_ps, flags, NULL);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* add attributes and connection information only when audio is accepted */
|
|
|
|
|
if (!port) {
|
|
|
|
|
if (!address || !address->port || !rtp_ps->selected_sfd) {
|
|
|
|
|
/* just add the mid before finalizing (see #1361 and #1362).
|
|
|
|
|
* TODO: after the content of this func is moved to the `print_sdp_media_section()`
|
|
|
|
|
* just move this logic there as well.
|
|
|
|
@ -3833,20 +3840,42 @@ void handle_sdp_media_attributes(GString *s, struct call_media *media,
|
|
|
|
|
|
|
|
|
|
struct call_monologue *monologue = media->monologue;
|
|
|
|
|
|
|
|
|
|
/* if this is a message type, just leave everything untouched */
|
|
|
|
|
bool is_active = (media->type_id == MT_MESSAGE) ? false : true;
|
|
|
|
|
|
|
|
|
|
/* add actual media connection */
|
|
|
|
|
sdp_out_add_media_connection(s, media, rtp_ps, flags);
|
|
|
|
|
sdp_out_add_media_connection(s, media, rtp_ps, &address->address, flags);
|
|
|
|
|
|
|
|
|
|
/* add per media bandwidth */
|
|
|
|
|
sdp_out_add_bandwidth(s, monologue, media);
|
|
|
|
|
|
|
|
|
|
/* print media level attributes */
|
|
|
|
|
print_sdp_media_section(s, media, NULL, flags, rtp_ps_link, is_active, false, true);
|
|
|
|
|
print_sdp_media_section(s, media, NULL, source_media, flags, rtp_ps_link, true, false, true);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// should we just pass through the original SDP (mostly) unchanged? if so, we need
|
|
|
|
|
// to look up the source media
|
|
|
|
|
static struct call_media *sdp_out_set_source_media_address(struct call_media *media,
|
|
|
|
|
struct packet_stream *rtp_ps,
|
|
|
|
|
struct sdp_ng_flags *flags,
|
|
|
|
|
const endpoint_t **sdp_address)
|
|
|
|
|
{
|
|
|
|
|
struct call_media *source_media = NULL;
|
|
|
|
|
// the port and address that goes into the SDP also depends on this
|
|
|
|
|
if (sdp_address)
|
|
|
|
|
*sdp_address = rtp_ps->selected_sfd ? &rtp_ps->selected_sfd->socket.local : NULL;
|
|
|
|
|
if (media->type_id == MT_MESSAGE || flags->ice_option == ICE_FORCE_RELAY || MEDIA_ISSET(media, PASSTHRU)) {
|
|
|
|
|
struct media_subscription *ms = media->media_subscriptions.head ? media->media_subscriptions.head->data : NULL;
|
|
|
|
|
if (ms && ms->media) {
|
|
|
|
|
source_media = ms->media;
|
|
|
|
|
if (source_media->streams.head) {
|
|
|
|
|
__auto_type sub_ps = ms->media->streams.head->data;
|
|
|
|
|
if (sdp_address)
|
|
|
|
|
*sdp_address = &sub_ps->advertised_endpoint;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return source_media;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* For the offer/answer model, SDP create will be triggered for the B monologue,
|
|
|
|
|
* which likely has empty paramaters (such as sdp origin, session name etc.), hence
|
|
|
|
@ -3860,7 +3889,6 @@ int sdp_create(str *out, struct call_monologue *monologue, sdp_ng_flags *flags)
|
|
|
|
|
const char *err = NULL;
|
|
|
|
|
GString *s = NULL;
|
|
|
|
|
const struct transport_protocol *prtp;
|
|
|
|
|
unsigned int port;
|
|
|
|
|
|
|
|
|
|
err = "Need at least one media";
|
|
|
|
|
if (!monologue->medias->len)
|
|
|
|
@ -3916,15 +3944,17 @@ int sdp_create(str *out, struct call_monologue *monologue, sdp_ng_flags *flags)
|
|
|
|
|
__auto_type rtp_ps_link = media->streams.head;
|
|
|
|
|
struct packet_stream *rtp_ps = rtp_ps_link->data;
|
|
|
|
|
|
|
|
|
|
/* determine media port to be used */
|
|
|
|
|
port = sdp_out_set_port(media, rtp_ps, flags);
|
|
|
|
|
const endpoint_t *sdp_address;
|
|
|
|
|
struct call_media *source_media = sdp_out_set_source_media_address(media, rtp_ps, flags,
|
|
|
|
|
&sdp_address);
|
|
|
|
|
unsigned int port = sdp_address ? sdp_address->port : 0;
|
|
|
|
|
|
|
|
|
|
prtp = NULL;
|
|
|
|
|
if (media->protocol && media->protocol->srtp)
|
|
|
|
|
prtp = &transport_protocols[media->protocol->rtp_proto];
|
|
|
|
|
|
|
|
|
|
/* handle first OSRTP part */
|
|
|
|
|
sdp_out_handle_osrtp1(s, media, port, prtp, rtp_ps, rtp_ps_link, flags);
|
|
|
|
|
sdp_out_handle_osrtp1(s, media, sdp_address, prtp, rtp_ps, rtp_ps_link, flags);
|
|
|
|
|
|
|
|
|
|
/* set: media type, port, protocol (e.g. RTP/SAVP) */
|
|
|
|
|
err = "Unknown media protocol";
|
|
|
|
@ -3932,7 +3962,7 @@ int sdp_create(str *out, struct call_monologue *monologue, sdp_ng_flags *flags)
|
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
|
|
/* add attributes and connection information */
|
|
|
|
|
handle_sdp_media_attributes(s, media, port, rtp_ps, rtp_ps_link, flags);
|
|
|
|
|
handle_sdp_media_attributes(s, media, sdp_address, source_media, rtp_ps, rtp_ps_link, flags);
|
|
|
|
|
|
|
|
|
|
/* handle second OSRTP part */
|
|
|
|
|
sdp_out_handle_osrtp2(s, media, prtp);
|
|
|
|
|