|
|
|
|
@ -1788,62 +1788,63 @@ static int replace_transport_protocol(struct sdp_chopper *chop,
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int replace_format_str(struct sdp_chopper *chop,
|
|
|
|
|
struct sdp_media *media, struct call_media *cm)
|
|
|
|
|
{
|
|
|
|
|
static int print_format_str(GString *s, struct call_media *cm) {
|
|
|
|
|
if (!cm->format_str.s)
|
|
|
|
|
return 0;
|
|
|
|
|
chopper_append_c(chop, " ");
|
|
|
|
|
chopper_append_str(chop, &cm->format_str);
|
|
|
|
|
if (skip_over(chop, &media->formats))
|
|
|
|
|
return -1;
|
|
|
|
|
g_string_append(s, " ");
|
|
|
|
|
g_string_append_len(s, cm->format_str.s, cm->format_str.len);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int replace_codec_list(struct sdp_chopper *chop,
|
|
|
|
|
struct sdp_media *media, struct call_media *cm)
|
|
|
|
|
{
|
|
|
|
|
if (proto_is_not_rtp(cm->protocol))
|
|
|
|
|
return replace_format_str(chop, media, cm);
|
|
|
|
|
static int print_codec_list(GString *s, struct call_media *media) {
|
|
|
|
|
if (proto_is_not_rtp(media->protocol))
|
|
|
|
|
return print_format_str(s, media);
|
|
|
|
|
|
|
|
|
|
if (cm->codecs.codec_prefs.length == 0)
|
|
|
|
|
if (media->codecs.codec_prefs.length == 0)
|
|
|
|
|
return 0; // legacy protocol or usage error
|
|
|
|
|
|
|
|
|
|
for (GList *l = cm->codecs.codec_prefs.head; l; l = l->next) {
|
|
|
|
|
for (GList *l = media->codecs.codec_prefs.head; l; l = l->next) {
|
|
|
|
|
struct rtp_payload_type *pt = l->data;
|
|
|
|
|
chopper_append_printf(chop, " %u", pt->payload_type);
|
|
|
|
|
g_string_append_printf(s, " %u", pt->payload_type);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int replace_codec_list(struct sdp_chopper *chop,
|
|
|
|
|
struct sdp_media *media, struct call_media *cm)
|
|
|
|
|
{
|
|
|
|
|
if (skip_over(chop, &media->formats))
|
|
|
|
|
return -1;
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
return print_codec_list(chop->output, cm);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void insert_codec_parameters(struct sdp_chopper *chop, struct call_media *cm) {
|
|
|
|
|
static void insert_codec_parameters(GString *s, struct call_media *cm) {
|
|
|
|
|
for (GList *l = cm->codecs.codec_prefs.head; l; l = l->next) {
|
|
|
|
|
struct rtp_payload_type *pt = l->data;
|
|
|
|
|
if (!pt->encoding_with_params.len)
|
|
|
|
|
continue;
|
|
|
|
|
chopper_append_printf(chop, "a=rtpmap:%u " STR_FORMAT "\r\n",
|
|
|
|
|
g_string_append_printf(s, "a=rtpmap:%u " STR_FORMAT "\r\n",
|
|
|
|
|
pt->payload_type,
|
|
|
|
|
STR_FMT(&pt->encoding_with_params));
|
|
|
|
|
if (pt->format_parameters.len) {
|
|
|
|
|
chopper_append_printf(chop, "a=fmtp:%u " STR_FORMAT "\r\n",
|
|
|
|
|
g_string_append_printf(s, "a=fmtp:%u " STR_FORMAT "\r\n",
|
|
|
|
|
pt->payload_type,
|
|
|
|
|
STR_FMT(&pt->format_parameters));
|
|
|
|
|
}
|
|
|
|
|
for (GList *l = pt->rtcp_fb.head; l; l = l->next) {
|
|
|
|
|
str *fb = l->data;
|
|
|
|
|
chopper_append_printf(chop, "a=rtcp-fb:%u " STR_FORMAT "\r\n",
|
|
|
|
|
g_string_append_printf(s, "a=rtcp-fb:%u " STR_FORMAT "\r\n",
|
|
|
|
|
pt->payload_type,
|
|
|
|
|
STR_FMT(fb));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void insert_sdp_attributes(struct sdp_chopper *chop, struct call_media *cm) {
|
|
|
|
|
static void insert_sdp_attributes(GString *gs, struct call_media *cm) {
|
|
|
|
|
for (GList *l = cm->sdp_attributes.head; l; l = l->next) {
|
|
|
|
|
str *s = l->data;
|
|
|
|
|
chopper_append_printf(chop, "a=" STR_FORMAT "\r\n",
|
|
|
|
|
g_string_append_printf(gs, "a=" STR_FORMAT "\r\n",
|
|
|
|
|
STR_FMT(s));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -1910,7 +1911,7 @@ warn:
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int insert_ice_address(struct sdp_chopper *chop, struct stream_fd *sfd, struct sdp_ng_flags *flags) {
|
|
|
|
|
static int insert_ice_address(GString *s, struct stream_fd *sfd, struct sdp_ng_flags *flags) {
|
|
|
|
|
char buf[64];
|
|
|
|
|
int len;
|
|
|
|
|
|
|
|
|
|
@ -1919,25 +1920,25 @@ static int insert_ice_address(struct sdp_chopper *chop, struct stream_fd *sfd, s
|
|
|
|
|
sockaddr_print_buf(&flags->parsed_media_address));
|
|
|
|
|
else
|
|
|
|
|
call_stream_address46(buf, sfd->stream, SAF_ICE, &len, sfd->local_intf, 0);
|
|
|
|
|
chopper_append(chop, buf, len);
|
|
|
|
|
chopper_append_printf(chop, " %u", sfd->socket.local.port);
|
|
|
|
|
g_string_append_len(s, buf, len);
|
|
|
|
|
g_string_append_printf(s, " %u", sfd->socket.local.port);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int insert_raddr_rport(struct sdp_chopper *chop, struct stream_fd *sfd, struct sdp_ng_flags *flags) {
|
|
|
|
|
static int insert_raddr_rport(GString *s, struct stream_fd *sfd, struct sdp_ng_flags *flags) {
|
|
|
|
|
char buf[64];
|
|
|
|
|
int len;
|
|
|
|
|
|
|
|
|
|
chopper_append_c(chop, " raddr ");
|
|
|
|
|
g_string_append(s, " raddr ");
|
|
|
|
|
if (!is_addr_unspecified(&flags->parsed_media_address))
|
|
|
|
|
len = sprintf(buf, "%s",
|
|
|
|
|
sockaddr_print_buf(&flags->parsed_media_address));
|
|
|
|
|
else
|
|
|
|
|
call_stream_address46(buf, sfd->stream, SAF_ICE, &len, sfd->local_intf, 0);
|
|
|
|
|
chopper_append(chop, buf, len);
|
|
|
|
|
chopper_append_c(chop, " rport ");
|
|
|
|
|
chopper_append_printf(chop, "%u", sfd->socket.local.port);
|
|
|
|
|
g_string_append_len(s, buf, len);
|
|
|
|
|
g_string_append(s, " rport ");
|
|
|
|
|
g_string_append_printf(s, "%u", sfd->socket.local.port);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
@ -2205,7 +2206,7 @@ out:
|
|
|
|
|
*lprefp = lpref;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void insert_candidate(struct sdp_chopper *chop, struct stream_fd *sfd,
|
|
|
|
|
static void insert_candidate(GString *s, struct stream_fd *sfd,
|
|
|
|
|
unsigned int type_pref, unsigned int local_pref, enum ice_candidate_type type,
|
|
|
|
|
struct sdp_ng_flags *flags)
|
|
|
|
|
{
|
|
|
|
|
@ -2217,19 +2218,19 @@ static void insert_candidate(struct sdp_chopper *chop, struct stream_fd *sfd,
|
|
|
|
|
local_pref = ifa->unique_id;
|
|
|
|
|
|
|
|
|
|
priority = ice_priority_pref(type_pref, local_pref, ps->component);
|
|
|
|
|
chopper_append_c(chop, "a=candidate:");
|
|
|
|
|
chopper_append_str(chop, &ifa->ice_foundation);
|
|
|
|
|
chopper_append_printf(chop, " %u UDP %lu ", ps->component, priority);
|
|
|
|
|
insert_ice_address(chop, sfd, flags);
|
|
|
|
|
chopper_append_c(chop, " typ ");
|
|
|
|
|
chopper_append_c(chop, ice_candidate_type_str(type));
|
|
|
|
|
g_string_append(s, "a=candidate:");
|
|
|
|
|
g_string_append_printf(s, STR_FORMAT, STR_FMT(&ifa->ice_foundation));
|
|
|
|
|
g_string_append_printf(s, " %u UDP %lu ", ps->component, priority);
|
|
|
|
|
insert_ice_address(s, sfd, flags);
|
|
|
|
|
g_string_append(s, " typ ");
|
|
|
|
|
g_string_append(s, ice_candidate_type_str(type));
|
|
|
|
|
/* raddr and rport are required for non-host candidates: rfc5245 section-15.1 */
|
|
|
|
|
if(type != ICT_HOST)
|
|
|
|
|
insert_raddr_rport(chop, sfd, flags);
|
|
|
|
|
chopper_append_c(chop, "\r\n");
|
|
|
|
|
insert_raddr_rport(s, sfd, flags);
|
|
|
|
|
g_string_append(s, "\r\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void insert_sfd_candidates(struct sdp_chopper *chop, struct packet_stream *ps,
|
|
|
|
|
static void insert_sfd_candidates(GString *s, struct packet_stream *ps,
|
|
|
|
|
unsigned int type_pref, unsigned int local_pref, enum ice_candidate_type type,
|
|
|
|
|
struct sdp_ng_flags *flags)
|
|
|
|
|
{
|
|
|
|
|
@ -2238,14 +2239,14 @@ static void insert_sfd_candidates(struct sdp_chopper *chop, struct packet_stream
|
|
|
|
|
|
|
|
|
|
for (l = ps->sfds.head; l; l = l->next) {
|
|
|
|
|
sfd = l->data;
|
|
|
|
|
insert_candidate(chop, sfd, type_pref, local_pref, type, flags);
|
|
|
|
|
insert_candidate(s, sfd, type_pref, local_pref, type, flags);
|
|
|
|
|
|
|
|
|
|
if (local_pref != -1)
|
|
|
|
|
local_pref++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void insert_candidates(struct sdp_chopper *chop, struct packet_stream *rtp, struct packet_stream *rtcp,
|
|
|
|
|
static void insert_candidates(GString *s, struct packet_stream *rtp, struct packet_stream *rtcp,
|
|
|
|
|
struct sdp_ng_flags *flags, struct sdp_media *sdp_media)
|
|
|
|
|
{
|
|
|
|
|
const struct local_intf *ifa;
|
|
|
|
|
@ -2260,7 +2261,7 @@ static void insert_candidates(struct sdp_chopper *chop, struct packet_stream *rt
|
|
|
|
|
cand_type = ICT_HOST;
|
|
|
|
|
if (flags->ice_option == ICE_FORCE_RELAY)
|
|
|
|
|
cand_type = ICT_RELAY;
|
|
|
|
|
if (MEDIA_ISSET(media, PASSTHRU))
|
|
|
|
|
if (MEDIA_ISSET(media, PASSTHRU) && sdp_media)
|
|
|
|
|
new_priority(sdp_media, cand_type, &type_pref, &local_pref);
|
|
|
|
|
else {
|
|
|
|
|
type_pref = ice_type_preference(cand_type);
|
|
|
|
|
@ -2271,35 +2272,35 @@ static void insert_candidates(struct sdp_chopper *chop, struct packet_stream *rt
|
|
|
|
|
|
|
|
|
|
if (ag && AGENT_ISSET(ag, COMPLETED)) {
|
|
|
|
|
ifa = rtp->selected_sfd->local_intf;
|
|
|
|
|
insert_candidate(chop, rtp->selected_sfd, type_pref, ifa->unique_id, cand_type, flags);
|
|
|
|
|
insert_candidate(s, rtp->selected_sfd, type_pref, ifa->unique_id, cand_type, flags);
|
|
|
|
|
if (rtcp) /* rtcp-mux only possible in answer */
|
|
|
|
|
insert_candidate(chop, rtcp->selected_sfd, type_pref, ifa->unique_id, cand_type, flags);
|
|
|
|
|
insert_candidate(s, rtcp->selected_sfd, type_pref, ifa->unique_id, cand_type, flags);
|
|
|
|
|
|
|
|
|
|
if (flags->opmode == OP_OFFER && AGENT_ISSET(ag, CONTROLLING)) {
|
|
|
|
|
GQueue rc;
|
|
|
|
|
GList *l;
|
|
|
|
|
chopper_append_c(chop, "a=remote-candidates:");
|
|
|
|
|
g_string_append(s, "a=remote-candidates:");
|
|
|
|
|
ice_remote_candidates(&rc, ag);
|
|
|
|
|
for (l = rc.head; l; l = l->next) {
|
|
|
|
|
if (l != rc.head)
|
|
|
|
|
chopper_append_c(chop, " ");
|
|
|
|
|
g_string_append(s, " ");
|
|
|
|
|
cand = l->data;
|
|
|
|
|
chopper_append_printf(chop, "%lu %s %u", cand->component_id,
|
|
|
|
|
g_string_append_printf(s, "%lu %s %u", cand->component_id,
|
|
|
|
|
sockaddr_print_buf(&cand->endpoint.address), cand->endpoint.port);
|
|
|
|
|
}
|
|
|
|
|
chopper_append_c(chop, "\r\n");
|
|
|
|
|
g_string_append(s, "\r\n");
|
|
|
|
|
g_queue_clear(&rc);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
insert_sfd_candidates(chop, rtp, type_pref, local_pref, cand_type, flags);
|
|
|
|
|
insert_sfd_candidates(s, rtp, type_pref, local_pref, cand_type, flags);
|
|
|
|
|
|
|
|
|
|
if (rtcp) /* rtcp-mux only possible in answer */
|
|
|
|
|
insert_sfd_candidates(chop, rtcp, type_pref, local_pref, cand_type, flags);
|
|
|
|
|
insert_sfd_candidates(s, rtcp, type_pref, local_pref, cand_type, flags);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void insert_dtls(struct call_media *media, struct sdp_chopper *chop) {
|
|
|
|
|
static void insert_dtls(GString *s, struct call_media *media) {
|
|
|
|
|
char hexbuf[DTLS_MAX_DIGEST_LEN * 3 + 2];
|
|
|
|
|
unsigned char *p;
|
|
|
|
|
char *o;
|
|
|
|
|
@ -2346,16 +2347,18 @@ static void insert_dtls(struct call_media *media, struct sdp_chopper *chop) {
|
|
|
|
|
else if (MEDIA_ISSET(media, SETUP_ACTIVE))
|
|
|
|
|
actpass = "active";
|
|
|
|
|
|
|
|
|
|
chopper_append_c(chop, "a=setup:");
|
|
|
|
|
chopper_append_c(chop, actpass);
|
|
|
|
|
chopper_append_c(chop, "\r\na=fingerprint:");
|
|
|
|
|
chopper_append_c(chop, hf->name);
|
|
|
|
|
chopper_append_c(chop, " ");
|
|
|
|
|
chopper_append(chop, hexbuf, o - hexbuf);
|
|
|
|
|
chopper_append_c(chop, "\r\n");
|
|
|
|
|
g_string_append(s, "a=setup:");
|
|
|
|
|
g_string_append(s, actpass);
|
|
|
|
|
g_string_append(s, "\r\na=fingerprint:");
|
|
|
|
|
g_string_append(s, hf->name);
|
|
|
|
|
g_string_append(s, " ");
|
|
|
|
|
g_string_append_len(s, hexbuf, o - hexbuf);
|
|
|
|
|
g_string_append(s, "\r\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void insert_crypto1(struct call_media *media, struct sdp_chopper *chop, struct crypto_params_sdes *cps, struct sdp_ng_flags *flags) {
|
|
|
|
|
static void insert_crypto1(GString *s, struct call_media *media, struct crypto_params_sdes *cps,
|
|
|
|
|
struct sdp_ng_flags *flags)
|
|
|
|
|
{
|
|
|
|
|
char b64_buf[((SRTP_MAX_MASTER_KEY_LEN + SRTP_MAX_MASTER_SALT_LEN) / 3 + 1) * 4 + 4];
|
|
|
|
|
char *p;
|
|
|
|
|
int state = 0, save = 0, i;
|
|
|
|
|
@ -2379,37 +2382,35 @@ static void insert_crypto1(struct call_media *media, struct sdp_chopper *chop, s
|
|
|
|
|
p--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
chopper_append_c(chop, "a=crypto:");
|
|
|
|
|
chopper_append_printf(chop, "%u ", cps->tag);
|
|
|
|
|
chopper_append_c(chop, cps->params.crypto_suite->name);
|
|
|
|
|
chopper_append_c(chop, " inline:");
|
|
|
|
|
chopper_append(chop, b64_buf, p - b64_buf);
|
|
|
|
|
g_string_append(s, "a=crypto:");
|
|
|
|
|
g_string_append_printf(s, "%u ", cps->tag);
|
|
|
|
|
g_string_append(s, cps->params.crypto_suite->name);
|
|
|
|
|
g_string_append(s, " inline:");
|
|
|
|
|
g_string_append_len(s, b64_buf, p - b64_buf);
|
|
|
|
|
if (flags->sdes_lifetime)
|
|
|
|
|
chopper_append_c(chop, "|2^31");
|
|
|
|
|
g_string_append(s, "|2^31");
|
|
|
|
|
if (cps->params.mki_len) {
|
|
|
|
|
ull = 0;
|
|
|
|
|
for (i = 0; i < cps->params.mki_len && i < sizeof(ull); i++)
|
|
|
|
|
ull |= (unsigned long long) cps->params.mki[cps->params.mki_len - i - 1] << (i * 8);
|
|
|
|
|
chopper_append_printf(chop, "|%llu:%u", ull, cps->params.mki_len);
|
|
|
|
|
g_string_append_printf(s, "|%llu:%u", ull, cps->params.mki_len);
|
|
|
|
|
}
|
|
|
|
|
if (cps->params.session_params.unencrypted_srtp)
|
|
|
|
|
chopper_append_c(chop, " UNENCRYPTED_SRTP");
|
|
|
|
|
g_string_append(s, " UNENCRYPTED_SRTP");
|
|
|
|
|
if (cps->params.session_params.unencrypted_srtcp)
|
|
|
|
|
chopper_append_c(chop, " UNENCRYPTED_SRTCP");
|
|
|
|
|
g_string_append(s, " UNENCRYPTED_SRTCP");
|
|
|
|
|
if (cps->params.session_params.unauthenticated_srtp)
|
|
|
|
|
chopper_append_c(chop, " UNAUTHENTICATED_SRTP");
|
|
|
|
|
chopper_append_c(chop, "\r\n");
|
|
|
|
|
g_string_append(s, " UNAUTHENTICATED_SRTP");
|
|
|
|
|
g_string_append(s, "\r\n");
|
|
|
|
|
}
|
|
|
|
|
static void insert_crypto(struct call_media *media, struct sdp_chopper *chop, struct sdp_ng_flags *flags) {
|
|
|
|
|
static void insert_crypto(GString *s, struct call_media *media, struct sdp_ng_flags *flags) {
|
|
|
|
|
for (GList *l = media->sdes_out.head; l; l = l->next)
|
|
|
|
|
insert_crypto1(media, chop, l->data, flags);
|
|
|
|
|
insert_crypto1(s, media, l->data, flags);
|
|
|
|
|
}
|
|
|
|
|
static void insert_rtcp_attr(struct sdp_chopper *chop, struct packet_stream *ps,
|
|
|
|
|
const struct sdp_ng_flags *flags)
|
|
|
|
|
{
|
|
|
|
|
static void insert_rtcp_attr(GString *s, struct packet_stream *ps, const struct sdp_ng_flags *flags) {
|
|
|
|
|
if (flags->no_rtcp_attr)
|
|
|
|
|
return;
|
|
|
|
|
chopper_append_printf(chop, "a=rtcp:%u", ps->selected_sfd->socket.local.port);
|
|
|
|
|
g_string_append_printf(s, "a=rtcp:%u", ps->selected_sfd->socket.local.port);
|
|
|
|
|
if (flags->full_rtcp_attr) {
|
|
|
|
|
char buf[64];
|
|
|
|
|
int len;
|
|
|
|
|
@ -2419,9 +2420,9 @@ static void insert_rtcp_attr(struct sdp_chopper *chop, struct packet_stream *ps,
|
|
|
|
|
sockaddr_print_buf(&flags->parsed_media_address));
|
|
|
|
|
else
|
|
|
|
|
call_stream_address46(buf, ps, SAF_NG, &len, NULL, 0);
|
|
|
|
|
chopper_append_printf(chop, " IN %.*s", len, buf);
|
|
|
|
|
g_string_append_printf(s, " IN %.*s", len, buf);
|
|
|
|
|
}
|
|
|
|
|
chopper_append_c(chop, "\r\n");
|
|
|
|
|
g_string_append(s, "\r\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -2460,16 +2461,118 @@ dup:
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void print_sendrecv(GString *s, struct call_media *media) {
|
|
|
|
|
if (MEDIA_ARESET2(media, SEND, RECV))
|
|
|
|
|
g_string_append(s, "a=sendrecv\r\n");
|
|
|
|
|
else if (MEDIA_ISSET(media, SEND))
|
|
|
|
|
g_string_append(s, "a=sendonly\r\n");
|
|
|
|
|
else if (MEDIA_ISSET(media, RECV))
|
|
|
|
|
g_string_append(s, "a=recvonly\r\n");
|
|
|
|
|
else
|
|
|
|
|
g_string_append(s, "a=inactive\r\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct packet_stream *print_rtcp(GString *s, struct call_media *media, GList *rtp_ps_link,
|
|
|
|
|
struct sdp_ng_flags *flags)
|
|
|
|
|
{
|
|
|
|
|
struct packet_stream *ps = rtp_ps_link->data;
|
|
|
|
|
struct packet_stream *ps_rtcp = NULL;
|
|
|
|
|
|
|
|
|
|
if (ps->rtcp_sibling) {
|
|
|
|
|
ps_rtcp = ps->rtcp_sibling;
|
|
|
|
|
GList *rtcp_ps_link = rtp_ps_link->next;
|
|
|
|
|
if (!rtcp_ps_link)
|
|
|
|
|
return NULL;
|
|
|
|
|
assert(rtcp_ps_link->data == ps_rtcp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (proto_is_rtp(media->protocol)) {
|
|
|
|
|
if (MEDIA_ISSET(media, RTCP_MUX)
|
|
|
|
|
&& (flags->opmode == OP_ANSWER || flags->opmode == OP_OTHER
|
|
|
|
|
|| (flags->opmode == OP_OFFER
|
|
|
|
|
&& flags->rtcp_mux_require)))
|
|
|
|
|
{
|
|
|
|
|
insert_rtcp_attr(s, ps, flags);
|
|
|
|
|
g_string_append(s, "a=rtcp-mux\r\n");
|
|
|
|
|
ps_rtcp = NULL;
|
|
|
|
|
}
|
|
|
|
|
else if (ps_rtcp && flags->ice_option != ICE_FORCE_RELAY) {
|
|
|
|
|
insert_rtcp_attr(s, ps_rtcp, flags);
|
|
|
|
|
if (MEDIA_ISSET(media, RTCP_MUX))
|
|
|
|
|
g_string_append(s, "a=rtcp-mux\r\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
ps_rtcp = NULL;
|
|
|
|
|
|
|
|
|
|
return ps_rtcp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static struct packet_stream *print_sdp_media_section(GString *s, struct call_media *media,
|
|
|
|
|
struct sdp_media *sdp_media,
|
|
|
|
|
struct sdp_ng_flags *flags,
|
|
|
|
|
GList *rtp_ps_link, bool is_active, bool force_end_of_ice)
|
|
|
|
|
{
|
|
|
|
|
struct packet_stream *ps_rtcp = NULL;
|
|
|
|
|
|
|
|
|
|
if (is_active) {
|
|
|
|
|
if (media->media_id.s) {
|
|
|
|
|
g_string_append(s, "a=mid:");
|
|
|
|
|
g_string_append_printf(s, STR_FORMAT, STR_FMT(&media->media_id));
|
|
|
|
|
g_string_append(s, "\r\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (proto_is_rtp(media->protocol))
|
|
|
|
|
insert_codec_parameters(s, media);
|
|
|
|
|
|
|
|
|
|
insert_sdp_attributes(s, media);
|
|
|
|
|
|
|
|
|
|
if (!flags->original_sendrecv)
|
|
|
|
|
print_sendrecv(s, media);
|
|
|
|
|
|
|
|
|
|
ps_rtcp = print_rtcp(s, media, rtp_ps_link, flags);
|
|
|
|
|
|
|
|
|
|
insert_crypto(s, media, flags);
|
|
|
|
|
insert_dtls(s, media);
|
|
|
|
|
|
|
|
|
|
if (proto_is_rtp(media->protocol) && media->ptime)
|
|
|
|
|
g_string_append_printf(s, "a=ptime:%i\r\n", media->ptime);
|
|
|
|
|
|
|
|
|
|
if (MEDIA_ISSET(media, ICE) && media->ice_agent) {
|
|
|
|
|
g_string_append(s, "a=ice-ufrag:");
|
|
|
|
|
g_string_append_printf(s, STR_FORMAT, STR_FMT(&media->ice_agent->ufrag[1]));
|
|
|
|
|
g_string_append(s, "\r\na=ice-pwd:");
|
|
|
|
|
g_string_append_printf(s, STR_FORMAT, STR_FMT(&media->ice_agent->pwd[1]));
|
|
|
|
|
g_string_append(s, "\r\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (MEDIA_ISSET(media, TRICKLE_ICE) && media->ice_agent)
|
|
|
|
|
g_string_append(s, "a=ice-options:trickle\r\n");
|
|
|
|
|
if (MEDIA_ISSET(media, ICE))
|
|
|
|
|
insert_candidates(s, rtp_ps_link->data, ps_rtcp, flags, sdp_media);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (MEDIA_ISSET(media, TRICKLE_ICE) && media->ice_agent)
|
|
|
|
|
g_string_append(s, "a=end-of-candidates\r\n");
|
|
|
|
|
else if (force_end_of_ice)
|
|
|
|
|
g_string_append(s, "a=end-of-candidates\r\n");
|
|
|
|
|
|
|
|
|
|
return ps_rtcp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* called with call->master_lock held in W */
|
|
|
|
|
int sdp_replace(struct sdp_chopper *chop, GQueue *sessions, struct call_monologue *monologue,
|
|
|
|
|
struct sdp_ng_flags *flags)
|
|
|
|
|
{
|
|
|
|
|
struct sdp_session *session;
|
|
|
|
|
struct sdp_media *sdp_media;
|
|
|
|
|
GList *l, *k, *m, *j;
|
|
|
|
|
GList *l, *k, *m, *rtp_ps_link;
|
|
|
|
|
int media_index, sess_conn;
|
|
|
|
|
struct call_media *call_media;
|
|
|
|
|
struct packet_stream *ps, *ps_rtcp;
|
|
|
|
|
struct packet_stream *ps;
|
|
|
|
|
const char *err = NULL;
|
|
|
|
|
|
|
|
|
|
m = monologue->medias.head;
|
|
|
|
|
@ -2485,10 +2588,10 @@ int sdp_replace(struct sdp_chopper *chop, GQueue *sessions, struct call_monologu
|
|
|
|
|
if (call_media->index != media_index)
|
|
|
|
|
goto error;
|
|
|
|
|
err = "no matching session media stream";
|
|
|
|
|
j = call_media->streams.head;
|
|
|
|
|
if (!j)
|
|
|
|
|
rtp_ps_link = call_media->streams.head;
|
|
|
|
|
if (!rtp_ps_link)
|
|
|
|
|
goto error;
|
|
|
|
|
ps = j->data;
|
|
|
|
|
ps = rtp_ps_link->data;
|
|
|
|
|
|
|
|
|
|
err = "error while processing o= line";
|
|
|
|
|
if (!monologue->sdp_username)
|
|
|
|
|
@ -2578,10 +2681,12 @@ int sdp_replace(struct sdp_chopper *chop, GQueue *sessions, struct call_monologu
|
|
|
|
|
if (call_media->index != media_index)
|
|
|
|
|
goto error;
|
|
|
|
|
err = "no matching media stream";
|
|
|
|
|
j = call_media->streams.head;
|
|
|
|
|
if (!j)
|
|
|
|
|
rtp_ps_link = call_media->streams.head;
|
|
|
|
|
if (!rtp_ps_link)
|
|
|
|
|
goto error;
|
|
|
|
|
ps = j->data;
|
|
|
|
|
ps = rtp_ps_link->data;
|
|
|
|
|
|
|
|
|
|
bool is_active = true;
|
|
|
|
|
|
|
|
|
|
if (flags->ice_option != ICE_FORCE_RELAY && call_media->type_id != MT_MESSAGE) {
|
|
|
|
|
err = "failed to replace media type";
|
|
|
|
|
@ -2591,7 +2696,7 @@ int sdp_replace(struct sdp_chopper *chop, GQueue *sessions, struct call_monologu
|
|
|
|
|
if (replace_media_port(chop, sdp_media, ps))
|
|
|
|
|
goto error;
|
|
|
|
|
err = "failed to replace media port count";
|
|
|
|
|
if (replace_consecutive_port_count(chop, sdp_media, ps, j))
|
|
|
|
|
if (replace_consecutive_port_count(chop, sdp_media, ps, rtp_ps_link))
|
|
|
|
|
goto error;
|
|
|
|
|
err = "failed to replace media protocol";
|
|
|
|
|
if (replace_transport_protocol(chop, sdp_media, call_media))
|
|
|
|
|
@ -2613,6 +2718,7 @@ int sdp_replace(struct sdp_chopper *chop, GQueue *sessions, struct call_monologu
|
|
|
|
|
if (synth_session_connection(chop, sdp_media))
|
|
|
|
|
goto error;
|
|
|
|
|
// leave everything untouched
|
|
|
|
|
is_active = false;
|
|
|
|
|
goto next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -2623,83 +2729,11 @@ int sdp_replace(struct sdp_chopper *chop, GQueue *sessions, struct call_monologu
|
|
|
|
|
copy_up_to_end_of(chop, &sdp_media->s);
|
|
|
|
|
|
|
|
|
|
if (!sdp_media->port_num || !ps->selected_sfd)
|
|
|
|
|
goto next;
|
|
|
|
|
|
|
|
|
|
if (call_media->media_id.s) {
|
|
|
|
|
chopper_append_c(chop, "a=mid:");
|
|
|
|
|
chopper_append_str(chop, &call_media->media_id);
|
|
|
|
|
chopper_append_c(chop, "\r\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (proto_is_rtp(call_media->protocol))
|
|
|
|
|
insert_codec_parameters(chop, call_media);
|
|
|
|
|
|
|
|
|
|
insert_sdp_attributes(chop, call_media);
|
|
|
|
|
|
|
|
|
|
ps_rtcp = NULL;
|
|
|
|
|
if (ps->rtcp_sibling) {
|
|
|
|
|
ps_rtcp = ps->rtcp_sibling;
|
|
|
|
|
j = j->next;
|
|
|
|
|
err = "no RTCP sibling";
|
|
|
|
|
if (!j)
|
|
|
|
|
goto error;
|
|
|
|
|
assert(j->data == ps_rtcp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!flags->original_sendrecv) {
|
|
|
|
|
if (MEDIA_ARESET2(call_media, SEND, RECV))
|
|
|
|
|
chopper_append_c(chop, "a=sendrecv\r\n");
|
|
|
|
|
else if (MEDIA_ISSET(call_media, SEND))
|
|
|
|
|
chopper_append_c(chop, "a=sendonly\r\n");
|
|
|
|
|
else if (MEDIA_ISSET(call_media, RECV))
|
|
|
|
|
chopper_append_c(chop, "a=recvonly\r\n");
|
|
|
|
|
else
|
|
|
|
|
chopper_append_c(chop, "a=inactive\r\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (proto_is_rtp(call_media->protocol)) {
|
|
|
|
|
if (MEDIA_ISSET(call_media, RTCP_MUX)
|
|
|
|
|
&& (flags->opmode == OP_ANSWER
|
|
|
|
|
|| (flags->opmode == OP_OFFER
|
|
|
|
|
&& flags->rtcp_mux_require)))
|
|
|
|
|
{
|
|
|
|
|
insert_rtcp_attr(chop, ps, flags);
|
|
|
|
|
chopper_append_c(chop, "a=rtcp-mux\r\n");
|
|
|
|
|
ps_rtcp = NULL;
|
|
|
|
|
}
|
|
|
|
|
else if (ps_rtcp && flags->ice_option != ICE_FORCE_RELAY) {
|
|
|
|
|
insert_rtcp_attr(chop, ps_rtcp, flags);
|
|
|
|
|
if (MEDIA_ISSET(call_media, RTCP_MUX))
|
|
|
|
|
chopper_append_c(chop, "a=rtcp-mux\r\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
ps_rtcp = NULL;
|
|
|
|
|
|
|
|
|
|
insert_crypto(call_media, chop, flags);
|
|
|
|
|
insert_dtls(call_media, chop);
|
|
|
|
|
|
|
|
|
|
if (proto_is_rtp(call_media->protocol) && call_media->ptime)
|
|
|
|
|
chopper_append_printf(chop, "a=ptime:%i\r\n", call_media->ptime);
|
|
|
|
|
|
|
|
|
|
if (MEDIA_ISSET(call_media, ICE) && call_media->ice_agent) {
|
|
|
|
|
chopper_append_c(chop, "a=ice-ufrag:");
|
|
|
|
|
chopper_append_str(chop, &call_media->ice_agent->ufrag[1]);
|
|
|
|
|
chopper_append_c(chop, "\r\na=ice-pwd:");
|
|
|
|
|
chopper_append_str(chop, &call_media->ice_agent->pwd[1]);
|
|
|
|
|
chopper_append_c(chop, "\r\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (MEDIA_ISSET(call_media, TRICKLE_ICE) && call_media->ice_agent)
|
|
|
|
|
chopper_append_c(chop, "a=ice-options:trickle\r\n");
|
|
|
|
|
if (MEDIA_ISSET(call_media, ICE))
|
|
|
|
|
insert_candidates(chop, ps, ps_rtcp, flags, sdp_media);
|
|
|
|
|
is_active = false;
|
|
|
|
|
|
|
|
|
|
next:
|
|
|
|
|
if (MEDIA_ISSET(call_media, TRICKLE_ICE) && call_media->ice_agent)
|
|
|
|
|
chopper_append_c(chop, "a=end-of-candidates\r\n");
|
|
|
|
|
else if (attr_get_by_id(&sdp_media->attributes, ATTR_END_OF_CANDIDATES))
|
|
|
|
|
chopper_append_c(chop, "a=end-of-candidates\r\n");
|
|
|
|
|
print_sdp_media_section(chop->output, call_media, sdp_media,flags, rtp_ps_link, is_active,
|
|
|
|
|
attr_get_by_id(&sdp_media->attributes, ATTR_END_OF_CANDIDATES));
|
|
|
|
|
|
|
|
|
|
media_index++;
|
|
|
|
|
m = m->next;
|
|
|
|
|
|