Merge "SDP: Create declined m= SDP lines using remote SDP if applicable."

This commit is contained in:
Joshua Colp
2017-07-26 08:20:38 -05:00
committed by Gerrit Code Review
2 changed files with 432 additions and 236 deletions

View File

@@ -2813,8 +2813,161 @@ static void add_ssrc_attributes(struct ast_sdp_m_line *m_line, const struct ast_
ast_sdp_m_add_a(m_line, a_line); ast_sdp_m_add_a(m_line, a_line);
} }
/*!
* \internal
* \brief Create a declined m-line from a remote requested stream.
* \since 15.0.0
*
* \details
* Using the last received remote SDP create a declined stream
* m-line for the requested stream. The stream may be unsupported.
*
* \param sdp Our SDP under construction to append the declined stream.
* \param sdp_state
* \param stream_index Which remote SDP stream we are declining.
*
* \retval 0 on success.
* \retval -1 on failure.
*/
static int sdp_add_m_from_declined_remote_stream(struct ast_sdp *sdp,
const struct ast_sdp_state *sdp_state, int stream_index)
{
const struct ast_sdp_m_line *m_line_remote;
struct ast_sdp_m_line *m_line;
int idx;
ast_assert(sdp && sdp_state && sdp_state->remote_sdp);
ast_assert(stream_index < ast_sdp_get_m_count(sdp_state->remote_sdp));
/*
* The only way we can generate a declined unsupported stream
* m-line is if the remote offered it to us.
*/
m_line_remote = ast_sdp_get_m(sdp_state->remote_sdp, stream_index);
/* Copy remote SDP stream m-line except for port number. */
m_line = ast_sdp_m_alloc(m_line_remote->type, 0, m_line_remote->port_count,
m_line_remote->proto, NULL);
if (!m_line) {
return -1;
}
/* Copy any m-line payload strings from the remote SDP */
for (idx = 0; idx < ast_sdp_m_get_payload_count(m_line_remote); ++idx) {
const struct ast_sdp_payload *payload_remote;
struct ast_sdp_payload *payload;
payload_remote = ast_sdp_m_get_payload(m_line_remote, idx);
payload = ast_sdp_payload_alloc(payload_remote->fmt);
if (!payload) {
ast_sdp_m_free(m_line);
return -1;
}
if (ast_sdp_m_add_payload(m_line, payload)) {
ast_sdp_payload_free(payload);
ast_sdp_m_free(m_line);
return -1;
}
}
if (ast_sdp_add_m(sdp, m_line)) {
ast_sdp_m_free(m_line);
return -1;
}
return 0;
}
/*!
* \internal
* \brief Create a declined m-line for our SDP stream.
* \since 15.0.0
*
* \param sdp Our SDP under construction to append the declined stream.
* \param sdp_state
* \param type Stream type we are declining.
* \param stream_index Which remote SDP stream we are declining.
*
* \retval 0 on success.
* \retval -1 on failure.
*/
static int sdp_add_m_from_declined_stream(struct ast_sdp *sdp,
const struct ast_sdp_state *sdp_state, enum ast_media_type type, int stream_index)
{
struct ast_sdp_m_line *m_line;
const char *proto;
const char *fmt;
struct ast_sdp_payload *payload;
if (sdp_state->role == SDP_ROLE_ANSWERER) {
/* We are declining the remote stream or it is still declined. */
return sdp_add_m_from_declined_remote_stream(sdp, sdp_state, stream_index);
}
/* Send declined remote stream in our offer if the type matches. */
if (sdp_state->remote_sdp
&& stream_index < ast_sdp_get_m_count(sdp_state->remote_sdp)) {
if (!sdp_is_stream_type_supported(type)
|| !strcasecmp(ast_sdp_get_m(sdp_state->remote_sdp, stream_index)->type,
ast_codec_media_type2str(type))) {
/* Stream is still declined */
return sdp_add_m_from_declined_remote_stream(sdp, sdp_state, stream_index);
}
}
/* Build a new declined stream in our offer. */
switch (type) {
case AST_MEDIA_TYPE_AUDIO:
case AST_MEDIA_TYPE_VIDEO:
proto = "RTP/AVP";
break;
case AST_MEDIA_TYPE_IMAGE:
proto = "udptl";
break;
default:
/* Stream type not supported */
ast_assert(0);
return -1;
}
m_line = ast_sdp_m_alloc(ast_codec_media_type2str(type), 0, 1, proto, NULL);
if (!m_line) {
return -1;
}
/* Add a dummy static payload type */
switch (type) {
case AST_MEDIA_TYPE_AUDIO:
fmt = "0"; /* ulaw */
break;
case AST_MEDIA_TYPE_VIDEO:
fmt = "31"; /* H.261 */
break;
case AST_MEDIA_TYPE_IMAGE:
fmt = "t38"; /* T.38 */
break;
default:
/* Stream type not supported */
ast_assert(0);
ast_sdp_m_free(m_line);
return -1;
}
payload = ast_sdp_payload_alloc(fmt);
if (!payload || ast_sdp_m_add_payload(m_line, payload)) {
ast_sdp_payload_free(payload);
ast_sdp_m_free(m_line);
return -1;
}
if (ast_sdp_add_m(sdp, m_line)) {
ast_sdp_m_free(m_line);
return -1;
}
return 0;
}
static int sdp_add_m_from_rtp_stream(struct ast_sdp *sdp, const struct ast_sdp_state *sdp_state, static int sdp_add_m_from_rtp_stream(struct ast_sdp *sdp, const struct ast_sdp_state *sdp_state,
const struct ast_sdp_options *options, const struct sdp_state_capabilities *capabilities, int stream_index) const struct sdp_state_capabilities *capabilities, int stream_index)
{ {
struct ast_stream *stream; struct ast_stream *stream;
struct ast_sdp_m_line *m_line; struct ast_sdp_m_line *m_line;
@@ -2829,11 +2982,14 @@ static int sdp_add_m_from_rtp_stream(struct ast_sdp *sdp, const struct ast_sdp_s
struct sdp_state_stream *stream_state; struct sdp_state_stream *stream_state;
struct ast_rtp_instance *rtp; struct ast_rtp_instance *rtp;
struct ast_sdp_a_line *a_line; struct ast_sdp_a_line *a_line;
const struct ast_sdp_options *options;
const char *direction;
stream = ast_stream_topology_get_stream(capabilities->topology, stream_index); stream = ast_stream_topology_get_stream(capabilities->topology, stream_index);
ast_assert(sdp && options && stream); ast_assert(sdp && sdp_state && stream);
options = sdp_state->options;
caps = ast_stream_get_formats(stream); caps = ast_stream_get_formats(stream);
stream_state = AST_VECTOR_GET(&capabilities->streams, stream_index); stream_state = AST_VECTOR_GET(&capabilities->streams, stream_index);
@@ -2856,146 +3012,119 @@ static int sdp_add_m_from_rtp_stream(struct ast_sdp *sdp, const struct ast_sdp_s
rtp_port = 0; rtp_port = 0;
} }
m_line = ast_sdp_m_alloc( media_type = ast_stream_get_type(stream);
ast_codec_media_type2str(ast_stream_get_type(stream)), if (!rtp_port) {
rtp_port, 1, /* Declined/disabled stream */
return sdp_add_m_from_declined_stream(sdp, sdp_state, media_type, stream_index);
}
/* Stream is not declined/disabled */
m_line = ast_sdp_m_alloc(ast_codec_media_type2str(media_type), rtp_port, 1,
options->encryption != AST_SDP_ENCRYPTION_DISABLED ? "RTP/SAVP" : "RTP/AVP", options->encryption != AST_SDP_ENCRYPTION_DISABLED ? "RTP/SAVP" : "RTP/AVP",
NULL); NULL);
if (!m_line) { if (!m_line) {
return -1; return -1;
} }
if (rtp_port) { for (i = 0; i < ast_format_cap_count(caps); i++) {
const char *direction; struct ast_format *format = ast_format_cap_get_format(caps, i);
/* Stream is not declined/disabled */
for (i = 0; i < ast_format_cap_count(caps); i++) {
struct ast_format *format = ast_format_cap_get_format(caps, i);
rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(rtp), 1,
format, 0);
if (rtp_code == -1) {
ast_log(LOG_WARNING,"Unable to get rtp codec payload code for %s\n",
ast_format_get_name(format));
ao2_ref(format, -1);
continue;
}
if (ast_sdp_m_add_format(m_line, options, rtp_code, 1, format, 0)) {
ast_sdp_m_free(m_line);
ao2_ref(format, -1);
return -1;
}
if (ast_format_get_maximum_ms(format)
&& ((ast_format_get_maximum_ms(format) < max_packet_size)
|| !max_packet_size)) {
max_packet_size = ast_format_get_maximum_ms(format);
}
rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(rtp), 1,
format, 0);
if (rtp_code == -1) {
ast_log(LOG_WARNING,"Unable to get rtp codec payload code for %s\n",
ast_format_get_name(format));
ao2_ref(format, -1); ao2_ref(format, -1);
continue;
} }
media_type = ast_stream_get_type(stream); if (ast_sdp_m_add_format(m_line, options, rtp_code, 1, format, 0)) {
if (media_type != AST_MEDIA_TYPE_VIDEO ast_sdp_m_free(m_line);
&& (options->dtmf == AST_SDP_DTMF_RFC_4733 || options->dtmf == AST_SDP_DTMF_AUTO)) { ao2_ref(format, -1);
i = AST_RTP_DTMF; return -1;
rtp_code = ast_rtp_codecs_payload_code( }
ast_rtp_instance_get_codecs(rtp), 0, NULL, i);
if (-1 < rtp_code) {
if (ast_sdp_m_add_format(m_line, options, rtp_code, 0, NULL, i)) {
ast_sdp_m_free(m_line);
return -1;
}
snprintf(tmp, sizeof(tmp), "%d 0-16", rtp_code); if (ast_format_get_maximum_ms(format)
a_line = ast_sdp_a_alloc("fmtp", tmp); && ((ast_format_get_maximum_ms(format) < max_packet_size)
if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { || !max_packet_size)) {
ast_sdp_a_free(a_line); max_packet_size = ast_format_get_maximum_ms(format);
ast_sdp_m_free(m_line); }
return -1;
} ao2_ref(format, -1);
}
if (media_type != AST_MEDIA_TYPE_VIDEO
&& (options->dtmf == AST_SDP_DTMF_RFC_4733 || options->dtmf == AST_SDP_DTMF_AUTO)) {
i = AST_RTP_DTMF;
rtp_code = ast_rtp_codecs_payload_code(
ast_rtp_instance_get_codecs(rtp), 0, NULL, i);
if (-1 < rtp_code) {
if (ast_sdp_m_add_format(m_line, options, rtp_code, 0, NULL, i)) {
ast_sdp_m_free(m_line);
return -1;
} }
}
/* If ptime is set add it as an attribute */ snprintf(tmp, sizeof(tmp), "%d 0-16", rtp_code);
min_packet_size = ast_rtp_codecs_get_framing(ast_rtp_instance_get_codecs(rtp)); a_line = ast_sdp_a_alloc("fmtp", tmp);
if (!min_packet_size) {
min_packet_size = ast_format_cap_get_framing(caps);
}
if (min_packet_size) {
snprintf(tmp, sizeof(tmp), "%d", min_packet_size);
a_line = ast_sdp_a_alloc("ptime", tmp);
if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { if (!a_line || ast_sdp_m_add_a(m_line, a_line)) {
ast_sdp_a_free(a_line); ast_sdp_a_free(a_line);
ast_sdp_m_free(m_line); ast_sdp_m_free(m_line);
return -1; return -1;
} }
} }
}
if (max_packet_size) { /* If ptime is set add it as an attribute */
snprintf(tmp, sizeof(tmp), "%d", max_packet_size); min_packet_size = ast_rtp_codecs_get_framing(ast_rtp_instance_get_codecs(rtp));
a_line = ast_sdp_a_alloc("maxptime", tmp); if (!min_packet_size) {
if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { min_packet_size = ast_format_cap_get_framing(caps);
ast_sdp_a_free(a_line); }
ast_sdp_m_free(m_line); if (min_packet_size) {
return -1; snprintf(tmp, sizeof(tmp), "%d", min_packet_size);
}
}
if (sdp_state->locally_held || stream_state->locally_held) { a_line = ast_sdp_a_alloc("ptime", tmp);
if (stream_state->remotely_held) { if (!a_line || ast_sdp_m_add_a(m_line, a_line)) {
direction = "inactive"; ast_sdp_a_free(a_line);
} else {
direction = "sendonly";
}
} else {
if (stream_state->remotely_held) {
direction = "recvonly";
} else {
/* Default is "sendrecv" */
direction = NULL;
}
}
if (direction) {
a_line = ast_sdp_a_alloc(direction, "");
if (!a_line || ast_sdp_m_add_a(m_line, a_line)) {
ast_sdp_a_free(a_line);
ast_sdp_m_free(m_line);
return -1;
}
}
add_ssrc_attributes(m_line, options, rtp);
} else {
/* Declined/disabled stream */
struct ast_sdp_payload *payload;
const char *fmt;
/*
* Add a static payload type placeholder to the declined/disabled stream.
*
* XXX We should use the default payload type in the received offer but
* we don't have that available.
*/
switch (ast_stream_get_type(stream)) {
default:
case AST_MEDIA_TYPE_AUDIO:
fmt = "0"; /* ulaw */
break;
case AST_MEDIA_TYPE_VIDEO:
fmt = "31"; /* H.261 */
break;
}
payload = ast_sdp_payload_alloc(fmt);
if (!payload || ast_sdp_m_add_payload(m_line, payload)) {
ast_sdp_payload_free(payload);
ast_sdp_m_free(m_line); ast_sdp_m_free(m_line);
return -1; return -1;
} }
} }
if (max_packet_size) {
snprintf(tmp, sizeof(tmp), "%d", max_packet_size);
a_line = ast_sdp_a_alloc("maxptime", tmp);
if (!a_line || ast_sdp_m_add_a(m_line, a_line)) {
ast_sdp_a_free(a_line);
ast_sdp_m_free(m_line);
return -1;
}
}
if (sdp_state->locally_held || stream_state->locally_held) {
if (stream_state->remotely_held) {
direction = "inactive";
} else {
direction = "sendonly";
}
} else {
if (stream_state->remotely_held) {
direction = "recvonly";
} else {
/* Default is "sendrecv" */
direction = NULL;
}
}
if (direction) {
a_line = ast_sdp_a_alloc(direction, "");
if (!a_line || ast_sdp_m_add_a(m_line, a_line)) {
ast_sdp_a_free(a_line);
ast_sdp_m_free(m_line);
return -1;
}
}
add_ssrc_attributes(m_line, options, rtp);
if (ast_sdp_add_m(sdp, m_line)) { if (ast_sdp_add_m(sdp, m_line)) {
ast_sdp_m_free(m_line); ast_sdp_m_free(m_line);
return -1; return -1;
@@ -3026,11 +3155,12 @@ static unsigned int t38_get_rate(enum ast_control_t38_rate rate)
} }
static int sdp_add_m_from_udptl_stream(struct ast_sdp *sdp, const struct ast_sdp_state *sdp_state, static int sdp_add_m_from_udptl_stream(struct ast_sdp *sdp, const struct ast_sdp_state *sdp_state,
const struct ast_sdp_options *options, const struct sdp_state_capabilities *capabilities, int stream_index) const struct sdp_state_capabilities *capabilities, int stream_index)
{ {
struct ast_stream *stream; struct ast_stream *stream;
struct ast_sdp_m_line *m_line; struct ast_sdp_m_line *m_line;
struct ast_sdp_payload *payload; struct ast_sdp_payload *payload;
enum ast_media_type media_type;
char tmp[64]; char tmp[64];
struct sdp_state_udptl *udptl; struct sdp_state_udptl *udptl;
struct ast_sdp_a_line *a_line; struct ast_sdp_a_line *a_line;
@@ -3039,7 +3169,7 @@ static int sdp_add_m_from_udptl_stream(struct ast_sdp *sdp, const struct ast_sdp
stream = ast_stream_topology_get_stream(capabilities->topology, stream_index); stream = ast_stream_topology_get_stream(capabilities->topology, stream_index);
ast_assert(sdp && options && stream); ast_assert(sdp && sdp_state && stream);
stream_state = AST_VECTOR_GET(&capabilities->streams, stream_index); stream_state = AST_VECTOR_GET(&capabilities->streams, stream_index);
if (stream_state->udptl if (stream_state->udptl
@@ -3061,9 +3191,15 @@ static int sdp_add_m_from_udptl_stream(struct ast_sdp *sdp, const struct ast_sdp
udptl_port = 0; udptl_port = 0;
} }
m_line = ast_sdp_m_alloc( media_type = ast_stream_get_type(stream);
ast_codec_media_type2str(ast_stream_get_type(stream)), if (!udptl_port) {
udptl_port, 1, "udptl", NULL); /* Declined/disabled stream */
return sdp_add_m_from_declined_stream(sdp, sdp_state, media_type, stream_index);
}
/* Stream is not declined/disabled */
m_line = ast_sdp_m_alloc(ast_codec_media_type2str(media_type), udptl_port, 1,
"udptl", NULL);
if (!m_line) { if (!m_line) {
return -1; return -1;
} }
@@ -3075,98 +3211,95 @@ static int sdp_add_m_from_udptl_stream(struct ast_sdp *sdp, const struct ast_sdp
return -1; return -1;
} }
if (udptl_port) { snprintf(tmp, sizeof(tmp), "%u", stream_state->t38_local_params.version);
/* Stream is not declined/disabled */ a_line = ast_sdp_a_alloc("T38FaxVersion", tmp);
snprintf(tmp, sizeof(tmp), "%u", stream_state->t38_local_params.version); if (!a_line || ast_sdp_m_add_a(m_line, a_line)) {
a_line = ast_sdp_a_alloc("T38FaxVersion", tmp); ast_sdp_a_free(a_line);
ast_sdp_m_free(m_line);
return -1;
}
snprintf(tmp, sizeof(tmp), "%u", t38_get_rate(stream_state->t38_local_params.rate));
a_line = ast_sdp_a_alloc("T38FaxMaxBitRate", tmp);
if (!a_line || ast_sdp_m_add_a(m_line, a_line)) {
ast_sdp_a_free(a_line);
ast_sdp_m_free(m_line);
return -1;
}
if (stream_state->t38_local_params.fill_bit_removal) {
a_line = ast_sdp_a_alloc("T38FaxFillBitRemoval", "");
if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { if (!a_line || ast_sdp_m_add_a(m_line, a_line)) {
ast_sdp_a_free(a_line); ast_sdp_a_free(a_line);
ast_sdp_m_free(m_line); ast_sdp_m_free(m_line);
return -1; return -1;
} }
}
snprintf(tmp, sizeof(tmp), "%u", t38_get_rate(stream_state->t38_local_params.rate)); if (stream_state->t38_local_params.transcoding_mmr) {
a_line = ast_sdp_a_alloc("T38FaxMaxBitRate", tmp); a_line = ast_sdp_a_alloc("T38FaxTranscodingMMR", "");
if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { if (!a_line || ast_sdp_m_add_a(m_line, a_line)) {
ast_sdp_a_free(a_line); ast_sdp_a_free(a_line);
ast_sdp_m_free(m_line); ast_sdp_m_free(m_line);
return -1; return -1;
} }
}
if (stream_state->t38_local_params.fill_bit_removal) { if (stream_state->t38_local_params.transcoding_jbig) {
a_line = ast_sdp_a_alloc("T38FaxFillBitRemoval", ""); a_line = ast_sdp_a_alloc("T38FaxTranscodingJBIG", "");
if (!a_line || ast_sdp_m_add_a(m_line, a_line)) {
ast_sdp_a_free(a_line);
ast_sdp_m_free(m_line);
return -1;
}
}
if (stream_state->t38_local_params.transcoding_mmr) {
a_line = ast_sdp_a_alloc("T38FaxTranscodingMMR", "");
if (!a_line || ast_sdp_m_add_a(m_line, a_line)) {
ast_sdp_a_free(a_line);
ast_sdp_m_free(m_line);
return -1;
}
}
if (stream_state->t38_local_params.transcoding_jbig) {
a_line = ast_sdp_a_alloc("T38FaxTranscodingJBIG", "");
if (!a_line || ast_sdp_m_add_a(m_line, a_line)) {
ast_sdp_a_free(a_line);
ast_sdp_m_free(m_line);
return -1;
}
}
switch (stream_state->t38_local_params.rate_management) {
case AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF:
a_line = ast_sdp_a_alloc("T38FaxRateManagement", "transferredTCF");
if (!a_line || ast_sdp_m_add_a(m_line, a_line)) {
ast_sdp_a_free(a_line);
ast_sdp_m_free(m_line);
return -1;
}
break;
case AST_T38_RATE_MANAGEMENT_LOCAL_TCF:
a_line = ast_sdp_a_alloc("T38FaxRateManagement", "localTCF");
if (!a_line || ast_sdp_m_add_a(m_line, a_line)) {
ast_sdp_a_free(a_line);
ast_sdp_m_free(m_line);
return -1;
}
break;
}
snprintf(tmp, sizeof(tmp), "%u", ast_udptl_get_local_max_datagram(udptl->instance));
a_line = ast_sdp_a_alloc("T38FaxMaxDatagram", tmp);
if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { if (!a_line || ast_sdp_m_add_a(m_line, a_line)) {
ast_sdp_a_free(a_line); ast_sdp_a_free(a_line);
ast_sdp_m_free(m_line); ast_sdp_m_free(m_line);
return -1; return -1;
} }
}
switch (ast_udptl_get_error_correction_scheme(udptl->instance)) { switch (stream_state->t38_local_params.rate_management) {
case UDPTL_ERROR_CORRECTION_NONE: case AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF:
break; a_line = ast_sdp_a_alloc("T38FaxRateManagement", "transferredTCF");
case UDPTL_ERROR_CORRECTION_FEC: if (!a_line || ast_sdp_m_add_a(m_line, a_line)) {
a_line = ast_sdp_a_alloc("T38FaxUdpEC", "t38UDPFEC"); ast_sdp_a_free(a_line);
if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { ast_sdp_m_free(m_line);
ast_sdp_a_free(a_line); return -1;
ast_sdp_m_free(m_line);
return -1;
}
break;
case UDPTL_ERROR_CORRECTION_REDUNDANCY:
a_line = ast_sdp_a_alloc("T38FaxUdpEC", "t38UDPRedundancy");
if (!a_line || ast_sdp_m_add_a(m_line, a_line)) {
ast_sdp_a_free(a_line);
ast_sdp_m_free(m_line);
return -1;
}
break;
} }
break;
case AST_T38_RATE_MANAGEMENT_LOCAL_TCF:
a_line = ast_sdp_a_alloc("T38FaxRateManagement", "localTCF");
if (!a_line || ast_sdp_m_add_a(m_line, a_line)) {
ast_sdp_a_free(a_line);
ast_sdp_m_free(m_line);
return -1;
}
break;
}
snprintf(tmp, sizeof(tmp), "%u", ast_udptl_get_local_max_datagram(udptl->instance));
a_line = ast_sdp_a_alloc("T38FaxMaxDatagram", tmp);
if (!a_line || ast_sdp_m_add_a(m_line, a_line)) {
ast_sdp_a_free(a_line);
ast_sdp_m_free(m_line);
return -1;
}
switch (ast_udptl_get_error_correction_scheme(udptl->instance)) {
case UDPTL_ERROR_CORRECTION_NONE:
break;
case UDPTL_ERROR_CORRECTION_FEC:
a_line = ast_sdp_a_alloc("T38FaxUdpEC", "t38UDPFEC");
if (!a_line || ast_sdp_m_add_a(m_line, a_line)) {
ast_sdp_a_free(a_line);
ast_sdp_m_free(m_line);
return -1;
}
break;
case UDPTL_ERROR_CORRECTION_REDUNDANCY:
a_line = ast_sdp_a_alloc("T38FaxUdpEC", "t38UDPRedundancy");
if (!a_line || ast_sdp_m_add_a(m_line, a_line)) {
ast_sdp_a_free(a_line);
ast_sdp_m_free(m_line);
return -1;
}
break;
} }
if (ast_sdp_add_m(sdp, m_line)) { if (ast_sdp_add_m(sdp, m_line)) {
@@ -3200,7 +3333,7 @@ static struct ast_sdp *sdp_create_from_state(const struct ast_sdp_state *sdp_sta
uint32_t t; uint32_t t;
int stream_count; int stream_count;
options = ast_sdp_state_get_options(sdp_state); options = sdp_state->options;
topology = capabilities->topology; topology = capabilities->topology;
t = tv.tv_sec + 2208988800UL; t = tv.tv_sec + 2208988800UL;
@@ -3233,18 +3366,22 @@ static struct ast_sdp *sdp_create_from_state(const struct ast_sdp_state *sdp_sta
switch (ast_stream_get_type(ast_stream_topology_get_stream(topology, stream_num))) { switch (ast_stream_get_type(ast_stream_topology_get_stream(topology, stream_num))) {
case AST_MEDIA_TYPE_AUDIO: case AST_MEDIA_TYPE_AUDIO:
case AST_MEDIA_TYPE_VIDEO: case AST_MEDIA_TYPE_VIDEO:
if (sdp_add_m_from_rtp_stream(sdp, sdp_state, options, capabilities, stream_num)) { if (sdp_add_m_from_rtp_stream(sdp, sdp_state, capabilities, stream_num)) {
goto error; goto error;
} }
break; break;
case AST_MEDIA_TYPE_IMAGE: case AST_MEDIA_TYPE_IMAGE:
if (sdp_add_m_from_udptl_stream(sdp, sdp_state, options, capabilities, stream_num)) { if (sdp_add_m_from_udptl_stream(sdp, sdp_state, capabilities, stream_num)) {
goto error; goto error;
} }
break; break;
case AST_MEDIA_TYPE_UNKNOWN: case AST_MEDIA_TYPE_UNKNOWN:
case AST_MEDIA_TYPE_TEXT: case AST_MEDIA_TYPE_TEXT:
case AST_MEDIA_TYPE_END: case AST_MEDIA_TYPE_END:
/* Decline any of these streams from the remote. */
if (sdp_add_m_from_declined_remote_stream(sdp, sdp_state, stream_num)) {
goto error;
}
break; break;
} }
} }

View File

@@ -88,6 +88,12 @@ static int validate_m_line(struct ast_test *test, const struct ast_sdp_m_line *m
return -1; return -1;
} }
if (m_line->port == 0) {
ast_test_status_update(test, "Expected %s m-line to not be declined\n",
media_type);
return -1;
}
if (ast_sdp_m_get_payload_count(m_line) != num_payloads) { if (ast_sdp_m_get_payload_count(m_line) != num_payloads) {
ast_test_status_update(test, "Expected %s m-line payload count %d but got %d\n", ast_test_status_update(test, "Expected %s m-line payload count %d but got %d\n",
media_type, num_payloads, ast_sdp_m_get_payload_count(m_line)); media_type, num_payloads, ast_sdp_m_get_payload_count(m_line));
@@ -462,17 +468,20 @@ static int build_sdp_option_formats(struct ast_sdp_options *options, int num_str
int idx; int idx;
for (idx = 0; idx < num_streams; ++idx) { for (idx = 0; idx < num_streams; ++idx) {
RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); struct ast_format_cap *caps;
caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); if (ast_strlen_zero(formats[idx].formats)) {
if (!caps) { continue;
return -1;
} }
if (ast_format_cap_update_by_allow_disallow(caps, formats[idx].formats, 1) < 0) { caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
if (!caps
|| ast_format_cap_update_by_allow_disallow(caps, formats[idx].formats, 1) < 0) {
ao2_cleanup(caps);
return -1; return -1;
} }
ast_sdp_options_set_format_cap_type(options, formats[idx].type, caps); ast_sdp_options_set_format_cap_type(options, formats[idx].type, caps);
ao2_cleanup(caps);
} }
return 0; return 0;
} }
@@ -494,10 +503,12 @@ static int build_sdp_option_formats(struct ast_sdp_options *options, int num_str
* \param opt_formats Array of new stream media types and formats allowed to create. * \param opt_formats Array of new stream media types and formats allowed to create.
* NULL if use a default stream creation. * NULL if use a default stream creation.
* Not used if test_options provided. * Not used if test_options provided.
* \param max_streams 0 if set max to max(3, num_streams) else max(max_streams, num_streams)
* Not used if test_options provided.
* \param test_options Optional SDP options. * \param test_options Optional SDP options.
*/ */
static struct ast_sdp_state *build_sdp_state(int num_streams, const struct sdp_format *formats, static struct ast_sdp_state *build_sdp_state(int num_streams, const struct sdp_format *formats,
int opt_num_streams, const struct sdp_format *opt_formats, int opt_num_streams, const struct sdp_format *opt_formats, unsigned int max_streams,
struct ast_sdp_options *test_options) struct ast_sdp_options *test_options)
{ {
struct ast_stream_topology *topology = NULL; struct ast_stream_topology *topology = NULL;
@@ -506,8 +517,6 @@ static struct ast_sdp_state *build_sdp_state(int num_streams, const struct sdp_f
int i; int i;
if (!test_options) { if (!test_options) {
unsigned int max_streams;
static const struct sdp_format sdp_formats[] = { static const struct sdp_format sdp_formats[] = {
{ AST_MEDIA_TYPE_AUDIO, "ulaw" }, { AST_MEDIA_TYPE_AUDIO, "ulaw" },
{ AST_MEDIA_TYPE_VIDEO, "vp8" }, { AST_MEDIA_TYPE_VIDEO, "vp8" },
@@ -520,8 +529,10 @@ static struct ast_sdp_state *build_sdp_state(int num_streams, const struct sdp_f
} }
/* Determine max_streams to allow */ /* Determine max_streams to allow */
max_streams = ARRAY_LEN(sdp_formats); if (!max_streams) {
if (ARRAY_LEN(sdp_formats) < num_streams) { max_streams = ARRAY_LEN(sdp_formats);
}
if (max_streams < num_streams) {
max_streams = num_streams; max_streams = num_streams;
} }
ast_sdp_options_set_max_streams(options, max_streams); ast_sdp_options_set_max_streams(options, max_streams);
@@ -544,21 +555,27 @@ static struct ast_sdp_state *build_sdp_state(int num_streams, const struct sdp_f
} }
for (i = 0; i < num_streams; ++i) { for (i = 0; i < num_streams; ++i) {
RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup);
struct ast_stream *stream; struct ast_stream *stream;
caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
if (!caps) {
goto end;
}
if (ast_format_cap_update_by_allow_disallow(caps, formats[i].formats, 1) < 0) {
goto end;
}
stream = ast_stream_alloc("sure_thing", formats[i].type); stream = ast_stream_alloc("sure_thing", formats[i].type);
if (!stream) { if (!stream) {
goto end; goto end;
} }
ast_stream_set_formats(stream, caps); if (!ast_strlen_zero(formats[i].formats)) {
struct ast_format_cap *caps;
caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
if (!caps
|| ast_format_cap_update_by_allow_disallow(caps, formats[i].formats, 1) < 0) {
ao2_cleanup(caps);
ast_stream_free(stream);
goto end;
}
ast_stream_set_formats(stream, caps);
ao2_cleanup(caps);
} else {
ast_stream_set_state(stream, AST_STREAM_STATE_REMOVED);
}
if (ast_stream_topology_append_stream(topology, stream) < 0) { if (ast_stream_topology_append_stream(topology, stream) < 0) {
ast_stream_free(stream); ast_stream_free(stream);
goto end; goto end;
@@ -604,7 +621,7 @@ AST_TEST_DEFINE(topology_to_sdp)
} }
sdp_state = build_sdp_state(ARRAY_LEN(formats), formats, sdp_state = build_sdp_state(ARRAY_LEN(formats), formats,
ARRAY_LEN(formats), formats, NULL); ARRAY_LEN(formats), formats, 0, NULL);
if (!sdp_state) { if (!sdp_state) {
goto end; goto end;
} }
@@ -749,7 +766,7 @@ AST_TEST_DEFINE(sdp_to_topology)
} }
sdp_state = build_sdp_state(ARRAY_LEN(sdp_formats), sdp_formats, sdp_state = build_sdp_state(ARRAY_LEN(sdp_formats), sdp_formats,
ARRAY_LEN(sdp_formats), sdp_formats, NULL); ARRAY_LEN(sdp_formats), sdp_formats, 0, NULL);
if (!sdp_state) { if (!sdp_state) {
res = AST_TEST_FAIL; res = AST_TEST_FAIL;
goto end; goto end;
@@ -848,6 +865,7 @@ static enum ast_test_result_state sdp_negotiation_completed_tests(struct ast_tes
int offer_num_streams, const struct sdp_format *offer_formats, int offer_num_streams, const struct sdp_format *offer_formats,
int answer_num_streams, const struct sdp_format *answer_formats, int answer_num_streams, const struct sdp_format *answer_formats,
int allowed_ans_num_streams, const struct sdp_format *allowed_ans_formats, int allowed_ans_num_streams, const struct sdp_format *allowed_ans_formats,
unsigned int max_streams,
int (*validate_sdp)(struct ast_test *test, const struct ast_sdp *sdp)) int (*validate_sdp)(struct ast_test *test, const struct ast_sdp *sdp))
{ {
enum ast_test_result_state res = AST_TEST_PASS; enum ast_test_result_state res = AST_TEST_PASS;
@@ -857,36 +875,42 @@ static enum ast_test_result_state sdp_negotiation_completed_tests(struct ast_tes
const struct ast_sdp *answerer_sdp; const struct ast_sdp *answerer_sdp;
sdp_state_offerer = build_sdp_state(offer_num_streams, offer_formats, sdp_state_offerer = build_sdp_state(offer_num_streams, offer_formats,
offer_num_streams, offer_formats, NULL); offer_num_streams, offer_formats, max_streams, NULL);
if (!sdp_state_offerer) { if (!sdp_state_offerer) {
ast_test_status_update(test, "Building offerer SDP state failed\n");
res = AST_TEST_FAIL; res = AST_TEST_FAIL;
goto end; goto end;
} }
sdp_state_answerer = build_sdp_state(answer_num_streams, answer_formats, sdp_state_answerer = build_sdp_state(answer_num_streams, answer_formats,
allowed_ans_num_streams, allowed_ans_formats, NULL); allowed_ans_num_streams, allowed_ans_formats, max_streams, NULL);
if (!sdp_state_answerer) { if (!sdp_state_answerer) {
ast_test_status_update(test, "Building answerer SDP state failed\n");
res = AST_TEST_FAIL; res = AST_TEST_FAIL;
goto end; goto end;
} }
offerer_sdp = ast_sdp_state_get_local_sdp(sdp_state_offerer); offerer_sdp = ast_sdp_state_get_local_sdp(sdp_state_offerer);
if (!offerer_sdp) { if (!offerer_sdp) {
ast_test_status_update(test, "Building offerer offer failed\n");
res = AST_TEST_FAIL; res = AST_TEST_FAIL;
goto end; goto end;
} }
if (ast_sdp_state_set_remote_sdp(sdp_state_answerer, offerer_sdp)) { if (ast_sdp_state_set_remote_sdp(sdp_state_answerer, offerer_sdp)) {
ast_test_status_update(test, "Setting answerer offer failed\n");
res = AST_TEST_FAIL; res = AST_TEST_FAIL;
goto end; goto end;
} }
answerer_sdp = ast_sdp_state_get_local_sdp(sdp_state_answerer); answerer_sdp = ast_sdp_state_get_local_sdp(sdp_state_answerer);
if (!answerer_sdp) { if (!answerer_sdp) {
ast_test_status_update(test, "Building answerer answer failed\n");
res = AST_TEST_FAIL; res = AST_TEST_FAIL;
goto end; goto end;
} }
if (ast_sdp_state_set_remote_sdp(sdp_state_offerer, answerer_sdp)) { if (ast_sdp_state_set_remote_sdp(sdp_state_offerer, answerer_sdp)) {
ast_test_status_update(test, "Setting offerer answer failed\n");
res = AST_TEST_FAIL; res = AST_TEST_FAIL;
goto end; goto end;
} }
@@ -902,6 +926,11 @@ static enum ast_test_result_state sdp_negotiation_completed_tests(struct ast_tes
goto end; goto end;
} }
offerer_sdp = ast_sdp_state_get_local_sdp(sdp_state_offerer); offerer_sdp = ast_sdp_state_get_local_sdp(sdp_state_offerer);
if (!offerer_sdp) {
ast_test_status_update(test, "Building offerer current sdp failed\n");
res = AST_TEST_FAIL;
goto end;
}
if (validate_sdp(test, offerer_sdp)) { if (validate_sdp(test, offerer_sdp)) {
res = AST_TEST_FAIL; res = AST_TEST_FAIL;
goto end; goto end;
@@ -944,6 +973,7 @@ AST_TEST_DEFINE(sdp_negotiation_initial)
ARRAY_LEN(offerer_formats), offerer_formats, ARRAY_LEN(offerer_formats), offerer_formats,
0, NULL, 0, NULL,
0, NULL, 0, NULL,
0,
validate_avi_sdp_streams); validate_avi_sdp_streams);
} }
@@ -978,10 +1008,11 @@ AST_TEST_DEFINE(sdp_negotiation_type_change)
ARRAY_LEN(offerer_formats), offerer_formats, ARRAY_LEN(offerer_formats), offerer_formats,
ARRAY_LEN(answerer_formats), answerer_formats, ARRAY_LEN(answerer_formats), answerer_formats,
0, NULL, 0, NULL,
0,
validate_avi_sdp_streams); validate_avi_sdp_streams);
} }
static int validate_ava_declined_sdp_streams(struct ast_test *test, const struct ast_sdp *sdp) static int validate_aviavia_declined_sdp_streams(struct ast_test *test, const struct ast_sdp *sdp)
{ {
struct ast_sdp_m_line *m_line; struct ast_sdp_m_line *m_line;
@@ -1000,6 +1031,26 @@ static int validate_ava_declined_sdp_streams(struct ast_test *test, const struct
} }
m_line = ast_sdp_get_m(sdp, 2); m_line = ast_sdp_get_m(sdp, 2);
if (validate_m_line_declined(test, m_line, "image")) {
return -1;
}
m_line = ast_sdp_get_m(sdp, 3);
if (validate_m_line_declined(test, m_line, "audio")) {
return -1;
}
m_line = ast_sdp_get_m(sdp, 4);
if (validate_m_line_declined(test, m_line, "video")) {
return -1;
}
m_line = ast_sdp_get_m(sdp, 5);
if (validate_m_line_declined(test, m_line, "image")) {
return -1;
}
m_line = ast_sdp_get_m(sdp, 6);
if (validate_m_line(test, m_line, "audio", 1)) { if (validate_m_line(test, m_line, "audio", 1)) {
return -1; return -1;
} }
@@ -1018,11 +1069,18 @@ static int validate_ava_declined_sdp_streams(struct ast_test *test, const struct
AST_TEST_DEFINE(sdp_negotiation_decline_incompatible) AST_TEST_DEFINE(sdp_negotiation_decline_incompatible)
{ {
static const struct sdp_format offerer_formats[] = { static const struct sdp_format offerer_formats[] = {
/* Incompatible declined streams */
{ AST_MEDIA_TYPE_AUDIO, "alaw" }, { AST_MEDIA_TYPE_AUDIO, "alaw" },
{ AST_MEDIA_TYPE_VIDEO, "vp8" }, { AST_MEDIA_TYPE_VIDEO, "vp8" },
{ AST_MEDIA_TYPE_IMAGE, "t38" },
/* Initially declined streams */
{ AST_MEDIA_TYPE_AUDIO, "" },
{ AST_MEDIA_TYPE_VIDEO, "" },
{ AST_MEDIA_TYPE_IMAGE, "" },
/* Compatible stream so not all are declined */
{ AST_MEDIA_TYPE_AUDIO, "ulaw,alaw" }, { AST_MEDIA_TYPE_AUDIO, "ulaw,alaw" },
}; };
static const struct sdp_format answerer_formats[] = { static const struct sdp_format allowed_formats[] = {
{ AST_MEDIA_TYPE_AUDIO, "ulaw" }, { AST_MEDIA_TYPE_AUDIO, "ulaw" },
}; };
@@ -1032,9 +1090,9 @@ AST_TEST_DEFINE(sdp_negotiation_decline_incompatible)
info->category = "/main/sdp/"; info->category = "/main/sdp/";
info->summary = "Simulate an initial negotiation declining streams"; info->summary = "Simulate an initial negotiation declining streams";
info->description = info->description =
"Initial negotiation tests declining incompatible streams on the answering side.\n" "Initial negotiation tests declining incompatible streams.\n"
"After negotiation both offerer and answerer sides should have the same\n" "After negotiation both offerer and answerer sides should have\n"
"expected stream types and formats."; "the same expected stream types and formats.";
return AST_TEST_NOT_RUN; return AST_TEST_NOT_RUN;
case TEST_EXECUTE: case TEST_EXECUTE:
break; break;
@@ -1042,9 +1100,10 @@ AST_TEST_DEFINE(sdp_negotiation_decline_incompatible)
return sdp_negotiation_completed_tests(test, return sdp_negotiation_completed_tests(test,
ARRAY_LEN(offerer_formats), offerer_formats, ARRAY_LEN(offerer_formats), offerer_formats,
ARRAY_LEN(answerer_formats), answerer_formats, 0, NULL,
ARRAY_LEN(answerer_formats), answerer_formats, ARRAY_LEN(allowed_formats), allowed_formats,
validate_ava_declined_sdp_streams); ARRAY_LEN(offerer_formats),
validate_aviavia_declined_sdp_streams);
} }
static int validate_aaaa_declined_sdp_streams(struct ast_test *test, const struct ast_sdp *sdp) static int validate_aaaa_declined_sdp_streams(struct ast_test *test, const struct ast_sdp *sdp)
@@ -1114,6 +1173,7 @@ AST_TEST_DEFINE(sdp_negotiation_decline_max_streams)
ARRAY_LEN(offerer_formats), offerer_formats, ARRAY_LEN(offerer_formats), offerer_formats,
0, NULL, 0, NULL,
0, NULL, 0, NULL,
0,
validate_aaaa_declined_sdp_streams); validate_aaaa_declined_sdp_streams);
} }
@@ -1143,13 +1203,13 @@ AST_TEST_DEFINE(sdp_negotiation_not_acceptable)
} }
sdp_state_offerer = build_sdp_state(ARRAY_LEN(offerer_formats), offerer_formats, sdp_state_offerer = build_sdp_state(ARRAY_LEN(offerer_formats), offerer_formats,
ARRAY_LEN(offerer_formats), offerer_formats, NULL); ARRAY_LEN(offerer_formats), offerer_formats, 0, NULL);
if (!sdp_state_offerer) { if (!sdp_state_offerer) {
res = AST_TEST_FAIL; res = AST_TEST_FAIL;
goto end; goto end;
} }
sdp_state_answerer = build_sdp_state(0, NULL, 0, NULL, NULL); sdp_state_answerer = build_sdp_state(0, NULL, 0, NULL, 0, NULL);
if (!sdp_state_answerer) { if (!sdp_state_answerer) {
res = AST_TEST_FAIL; res = AST_TEST_FAIL;
goto end; goto end;
@@ -1245,7 +1305,7 @@ AST_TEST_DEFINE(sdp_ssrc_attributes)
} }
ast_sdp_options_set_ssrc(options, 1); ast_sdp_options_set_ssrc(options, 1);
test_state = build_sdp_state(ARRAY_LEN(formats), formats, 0, NULL, options); test_state = build_sdp_state(ARRAY_LEN(formats), formats, 0, NULL, 0, options);
if (!test_state) { if (!test_state) {
ast_test_status_update(test, "Failed to create SDP state\n"); ast_test_status_update(test, "Failed to create SDP state\n");
goto end; goto end;
@@ -1335,11 +1395,10 @@ static struct ast_stream_topology *build_update_topology(const struct sdp_topolo
struct ast_format_cap *caps; struct ast_format_cap *caps;
caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
if (!caps) { if (!caps
goto fail; || ast_format_cap_update_by_allow_disallow(caps, desc->formats, 1) < 0) {
} ao2_cleanup(caps);
if (ast_format_cap_update_by_allow_disallow(caps, desc->formats, 1) < 0) { ast_stream_free(stream);
ao2_ref(caps, -1);
goto fail; goto fail;
} }
ast_stream_set_formats(stream, caps); ast_stream_set_formats(stream, caps);