summaryrefslogtreecommitdiff
path: root/main
diff options
context:
space:
mode:
Diffstat (limited to 'main')
-rw-r--r--main/app.c13
-rw-r--r--main/bridge_channel.c30
-rw-r--r--main/channel.c5
-rw-r--r--main/config.c49
-rw-r--r--main/config_options.c36
-rw-r--r--main/core_unreal.c13
-rw-r--r--main/rtp_engine.c68
7 files changed, 187 insertions, 27 deletions
diff --git a/main/app.c b/main/app.c
index 1eb0741ee..69c96c06c 100644
--- a/main/app.c
+++ b/main/app.c
@@ -3060,19 +3060,32 @@ int ast_app_parse_timelen(const char *timestr, int *result, enum ast_timelen uni
case 'h':
case 'H':
unit = TIMELEN_HOURS;
+ if (u[1] != '\0') {
+ return -1;
+ }
break;
case 's':
case 'S':
unit = TIMELEN_SECONDS;
+ if (u[1] != '\0') {
+ return -1;
+ }
break;
case 'm':
case 'M':
if (toupper(u[1]) == 'S') {
unit = TIMELEN_MILLISECONDS;
+ if (u[2] != '\0') {
+ return -1;
+ }
} else if (u[1] == '\0') {
unit = TIMELEN_MINUTES;
+ } else {
+ return -1;
}
break;
+ default:
+ return -1;
}
}
diff --git a/main/bridge_channel.c b/main/bridge_channel.c
index e8ab8a898..2e943000c 100644
--- a/main/bridge_channel.c
+++ b/main/bridge_channel.c
@@ -998,21 +998,6 @@ int ast_bridge_channel_queue_frame(struct ast_bridge_channel *bridge_channel, st
return 0;
}
- if (ast_channel_is_multistream(bridge_channel->chan) &&
- (fr->frametype == AST_FRAME_IMAGE || fr->frametype == AST_FRAME_TEXT ||
- fr->frametype == AST_FRAME_VIDEO || fr->frametype == AST_FRAME_VOICE)) {
- /* Media frames need to be mapped to an appropriate write stream */
- dup->stream_num = AST_VECTOR_GET(
- &bridge_channel->stream_map.to_bridge, fr->stream_num);
- if (dup->stream_num == -1) {
- ast_bridge_channel_unlock(bridge_channel);
- bridge_frame_free(dup);
- return 0;
- }
- } else {
- dup->stream_num = -1;
- }
-
AST_LIST_INSERT_TAIL(&bridge_channel->wr_queue, dup, frame_list);
if (ast_alertpipe_write(bridge_channel->alert_pipe)) {
ast_log(LOG_ERROR, "We couldn't write alert pipe for %p(%s)... something is VERY wrong\n",
@@ -2455,15 +2440,26 @@ static void bridge_handle_trip(struct ast_bridge_channel *bridge_channel)
}
if (bridge_channel->features->mute) {
- frame = ast_read_noaudio(bridge_channel->chan);
+ frame = ast_read_stream_noaudio(bridge_channel->chan);
} else {
- frame = ast_read(bridge_channel->chan);
+ frame = ast_read_stream(bridge_channel->chan);
}
if (!frame) {
ast_bridge_channel_kick(bridge_channel, 0);
return;
}
+
+ if (ast_channel_is_multistream(bridge_channel->chan) &&
+ (frame->frametype == AST_FRAME_IMAGE || frame->frametype == AST_FRAME_TEXT ||
+ frame->frametype == AST_FRAME_VIDEO || frame->frametype == AST_FRAME_VOICE)) {
+ /* Media frames need to be mapped to an appropriate write stream */
+ frame->stream_num = AST_VECTOR_GET(
+ &bridge_channel->stream_map.to_bridge, frame->stream_num);
+ } else {
+ frame->stream_num = -1;
+ }
+
switch (frame->frametype) {
case AST_FRAME_CONTROL:
switch (frame->subclass.integer) {
diff --git a/main/channel.c b/main/channel.c
index 27efb2ee3..66825559c 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -4183,6 +4183,11 @@ struct ast_frame *ast_read_noaudio(struct ast_channel *chan)
return __ast_read(chan, 1, 1);
}
+struct ast_frame *ast_read_stream_noaudio(struct ast_channel *chan)
+{
+ return __ast_read(chan, 1, 0);
+}
+
int ast_indicate(struct ast_channel *chan, int condition)
{
return ast_indicate_data(chan, condition, NULL, 0);
diff --git a/main/config.c b/main/config.c
index a3e09f67e..3d8dcfb3d 100644
--- a/main/config.c
+++ b/main/config.c
@@ -3741,6 +3741,55 @@ uint32_done:
break;
}
+ case PARSE_TIMELEN:
+ {
+ int x = 0;
+ int *result = p_result;
+ int def = result ? *result : 0;
+ int high = INT_MAX;
+ int low = INT_MIN;
+ enum ast_timelen defunit;
+
+ defunit = va_arg(ap, enum ast_timelen);
+ /* optional arguments: default value and/or (low, high) */
+ if (flags & PARSE_DEFAULT) {
+ def = va_arg(ap, int);
+ }
+ if (flags & (PARSE_IN_RANGE | PARSE_OUT_RANGE)) {
+ low = va_arg(ap, int);
+ high = va_arg(ap, int);
+ }
+ if (ast_strlen_zero(arg)) {
+ error = 1;
+ goto timelen_done;
+ }
+ error = ast_app_parse_timelen(arg, &x, defunit);
+ if (error || x < INT_MIN || x > INT_MAX) {
+ /* Parse error, or type out of int bounds */
+ error = 1;
+ goto timelen_done;
+ }
+ error = (x < low) || (x > high);
+ if (flags & PARSE_RANGE_DEFAULTS) {
+ if (x < low) {
+ def = low;
+ } else if (x > high) {
+ def = high;
+ }
+ }
+ if (flags & PARSE_OUT_RANGE) {
+ error = !error;
+ }
+timelen_done:
+ if (result) {
+ *result = error ? def : x;
+ }
+
+ ast_debug(3, "extract timelen from [%s] in [%d, %d] gives [%d](%d)\n",
+ arg, low, high, result ? *result : x, error);
+ break;
+ }
+
case PARSE_DOUBLE:
{
double *result = p_result;
diff --git a/main/config_options.c b/main/config_options.c
index c80777906..8eacbda35 100644
--- a/main/config_options.c
+++ b/main/config_options.c
@@ -34,6 +34,7 @@
#include "asterisk/config_options.h"
#include "asterisk/stringfields.h"
#include "asterisk/acl.h"
+#include "asterisk/app.h"
#include "asterisk/frame.h"
#include "asterisk/xmldoc.h"
#include "asterisk/cli.h"
@@ -118,6 +119,7 @@ static void config_option_destroy(void *obj)
static int int_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
static int uint_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
+static int timelen_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
static int double_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
static int sockaddr_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
static int stringfield_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
@@ -151,6 +153,7 @@ static aco_option_handler ast_config_option_default_handler(enum aco_option_type
case OPT_SOCKADDR_T: return sockaddr_handler_fn;
case OPT_STRINGFIELD_T: return stringfield_handler_fn;
case OPT_UINT_T: return uint_handler_fn;
+ case OPT_TIMELEN_T: return timelen_handler_fn;
case OPT_CUSTOM_T: return NULL;
}
@@ -1378,6 +1381,39 @@ static int uint_handler_fn(const struct aco_option *opt, struct ast_variable *va
return res;
}
+/*! \brief Default option handler for timelen signed integers
+ * \note For a description of the opt->flags and opt->args values, see the documentation for
+ * enum aco_option_type in config_options.h
+ */
+static int timelen_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+ int *field = (int *)(obj + opt->args[0]);
+ unsigned int flags = PARSE_TIMELEN | opt->flags;
+ int res = 0;
+ if (opt->flags & PARSE_IN_RANGE) {
+ if (opt->flags & PARSE_DEFAULT) {
+ res = ast_parse_arg(var->value, flags, field, (enum ast_timelen) opt->args[1], (int) opt->args[2], (int) opt->args[3], opt->args[4]);
+ } else {
+ res = ast_parse_arg(var->value, flags, field, (enum ast_timelen) opt->args[1], (int) opt->args[2], (int) opt->args[3]);
+ }
+ if (res) {
+ if (opt->flags & PARSE_RANGE_DEFAULTS) {
+ ast_log(LOG_WARNING, "Failed to set %s=%s. Set to %d instead due to range limit (%d, %d)\n", var->name, var->value, *field, (int) opt->args[2], (int) opt->args[3]);
+ res = 0;
+ } else if (opt->flags & PARSE_DEFAULT) {
+ ast_log(LOG_WARNING, "Failed to set %s=%s, Set to default value %d instead.\n", var->name, var->value, *field);
+ res = 0;
+ }
+ }
+ } else if ((opt->flags & PARSE_DEFAULT) && ast_parse_arg(var->value, flags, field, (enum ast_timelen) opt->args[1], (int) opt->args[2])) {
+ ast_log(LOG_WARNING, "Attempted to set %s=%s, but set it to %d instead due to default)\n", var->name, var->value, *field);
+ } else {
+ res = ast_parse_arg(var->value, flags, field, (enum ast_timelen) opt->args[1]);
+ }
+
+ return res;
+}
+
/*! \brief Default option handler for doubles
* \note For a description of the opt->flags and opt->args values, see the documentation for
* enum aco_option_type in config_options.h
diff --git a/main/core_unreal.c b/main/core_unreal.c
index 5da740877..3db6a4dbd 100644
--- a/main/core_unreal.c
+++ b/main/core_unreal.c
@@ -323,6 +323,19 @@ int ast_unreal_write(struct ast_channel *ast, struct ast_frame *f)
return -1;
}
+ /* If we are told to write a frame with a type that has no corresponding
+ * stream on the channel then drop it.
+ */
+ if (f->frametype == AST_FRAME_VOICE) {
+ if (!ast_channel_get_default_stream(ast, AST_MEDIA_TYPE_AUDIO)) {
+ return 0;
+ }
+ } else if (f->frametype == AST_FRAME_VIDEO) {
+ if (!ast_channel_get_default_stream(ast, AST_MEDIA_TYPE_VIDEO)) {
+ return 0;
+ }
+ }
+
/* Just queue for delivery to the other side */
ao2_ref(p, 1);
ao2_lock(p);
diff --git a/main/rtp_engine.c b/main/rtp_engine.c
index 9cfae09f4..abd4b1fcf 100644
--- a/main/rtp_engine.c
+++ b/main/rtp_engine.c
@@ -1495,21 +1495,24 @@ static int rtp_codecs_find_non_primary_dynamic_rx(struct ast_rtp_codecs *codecs)
* \param asterisk_format Non-zero if the given Asterisk format is present
* \param format Asterisk format to look for
* \param code The format to look for
+ * \param explicit Require the provided code to be explicitly used
*
* \note It is assumed that static_RTP_PT_lock is at least read locked before calling.
*
* \retval Numerical payload type
* \retval -1 if could not assign.
*/
-static int rtp_codecs_assign_payload_code_rx(struct ast_rtp_codecs *codecs, int asterisk_format, struct ast_format *format, int code)
+static int rtp_codecs_assign_payload_code_rx(struct ast_rtp_codecs *codecs, int asterisk_format, struct ast_format *format, int code, int explicit)
{
- int payload;
+ int payload = code;
struct ast_rtp_payload_type *new_type;
- payload = find_static_payload_type(asterisk_format, format, code);
+ if (!explicit) {
+ payload = find_static_payload_type(asterisk_format, format, code);
- if (payload < 0 && (!asterisk_format || ast_option_rtpusedynamic)) {
- return payload;
+ if (payload < 0 && (!asterisk_format || ast_option_rtpusedynamic)) {
+ return payload;
+ }
}
new_type = rtp_payload_type_alloc(format, payload, code, 1);
@@ -1525,9 +1528,9 @@ static int rtp_codecs_assign_payload_code_rx(struct ast_rtp_codecs *codecs, int
* The payload type is a static assignment
* or our default dynamic position is available.
*/
- rtp_codecs_payload_replace_rx(codecs, payload, new_type);
- } else if (-1 < (payload = find_unused_payload(codecs))
- || -1 < (payload = rtp_codecs_find_non_primary_dynamic_rx(codecs))) {
+ rtp_codecs_payload_replace_rx(codecs, payload, new_type);
+ } else if (!explicit && (-1 < (payload = find_unused_payload(codecs))
+ || -1 < (payload = rtp_codecs_find_non_primary_dynamic_rx(codecs)))) {
/*
* We found the first available empty dynamic position
* or we found a mapping that should no longer be
@@ -1535,6 +1538,11 @@ static int rtp_codecs_assign_payload_code_rx(struct ast_rtp_codecs *codecs, int
*/
new_type->payload = payload;
rtp_codecs_payload_replace_rx(codecs, payload, new_type);
+ } else if (explicit) {
+ /*
+ * They explicitly requested this payload number be used but it couldn't be
+ */
+ payload = -1;
} else {
/*
* There are no empty or non-primary dynamic positions
@@ -1595,13 +1603,18 @@ int ast_rtp_codecs_payload_code(struct ast_rtp_codecs *codecs, int asterisk_form
if (payload < 0) {
payload = rtp_codecs_assign_payload_code_rx(codecs, asterisk_format, format,
- code);
+ code, 0);
}
ast_rwlock_unlock(&static_RTP_PT_lock);
return payload;
}
+int ast_rtp_codecs_payload_set_rx(struct ast_rtp_codecs *codecs, int code, struct ast_format *format)
+{
+ return rtp_codecs_assign_payload_code_rx(codecs, 1, format, code, 1);
+}
+
int ast_rtp_codecs_payload_code_tx(struct ast_rtp_codecs *codecs, int asterisk_format, const struct ast_format *format, int code)
{
struct ast_rtp_payload_type *type;
@@ -2424,7 +2437,7 @@ int ast_rtp_instance_add_srtp_policy(struct ast_rtp_instance *instance, struct a
if (!*srtp) {
res = res_srtp->create(srtp, instance, remote_policy);
- } else {
+ } else if (remote_policy) {
res = res_srtp->replace(srtp, instance, remote_policy);
}
if (!res) {
@@ -3366,3 +3379,38 @@ const char *ast_rtp_instance_get_cname(struct ast_rtp_instance *rtp)
return cname;
}
+
+int ast_rtp_instance_bundle(struct ast_rtp_instance *child, struct ast_rtp_instance *parent)
+{
+ int res = -1;
+
+ if (child->engine != parent->engine) {
+ return -1;
+ }
+
+ ao2_lock(child);
+ if (child->engine->bundle) {
+ res = child->engine->bundle(child, parent);
+ }
+ ao2_unlock(child);
+
+ return res;
+}
+
+void ast_rtp_instance_set_remote_ssrc(struct ast_rtp_instance *rtp, unsigned int ssrc)
+{
+ ao2_lock(rtp);
+ if (rtp->engine->set_remote_ssrc) {
+ rtp->engine->set_remote_ssrc(rtp, ssrc);
+ }
+ ao2_unlock(rtp);
+}
+
+void ast_rtp_instance_set_stream_num(struct ast_rtp_instance *rtp, int stream_num)
+{
+ ao2_lock(rtp);
+ if (rtp->engine->set_stream_num) {
+ rtp->engine->set_stream_num(rtp, stream_num);
+ }
+ ao2_unlock(rtp);
+} \ No newline at end of file