summaryrefslogtreecommitdiff
path: root/main
diff options
context:
space:
mode:
Diffstat (limited to 'main')
-rw-r--r--main/asterisk.c21
-rw-r--r--main/autoservice.c66
-rw-r--r--main/bridge.c22
-rw-r--r--main/channel.c107
-rw-r--r--main/channel_internal_api.c6
-rw-r--r--main/codec_builtin.c16
-rw-r--r--main/file.c65
-rw-r--r--main/manager_bridges.c52
-rw-r--r--main/stasis_bridges.c29
9 files changed, 244 insertions, 140 deletions
diff --git a/main/asterisk.c b/main/asterisk.c
index be6c7cc32..4a6567f73 100644
--- a/main/asterisk.c
+++ b/main/asterisk.c
@@ -2691,7 +2691,11 @@ static void send_rasterisk_connect_commands(void)
}
}
+#ifdef HAVE_LIBEDIT_IS_UNICODE
+static int ast_el_read_char(EditLine *editline, wchar_t *cp)
+#else
static int ast_el_read_char(EditLine *editline, char *cp)
+#endif
{
int num_read = 0;
int lastpos = 0;
@@ -2721,10 +2725,16 @@ static int ast_el_read_char(EditLine *editline, char *cp)
}
if (!ast_opt_exec && fds[1].revents) {
- num_read = read(STDIN_FILENO, cp, 1);
+ char c = '\0';
+ num_read = read(STDIN_FILENO, &c, 1);
if (num_read < 1) {
break;
} else {
+#ifdef HAVE_LIBEDIT_IS_UNICODE
+ *cp = btowc(c);
+#else
+ *cp = c;
+#endif
return (num_read);
}
}
@@ -2768,7 +2778,11 @@ static int ast_el_read_char(EditLine *editline, char *cp)
console_print(buf);
if ((res < EL_BUF_SIZE - 1) && ((buf[res-1] == '\n') || (res >= 2 && buf[res-2] == '\n'))) {
+#ifdef HAVE_LIBEDIT_IS_UNICODE
+ *cp = btowc(CC_REFRESH);
+#else
*cp = CC_REFRESH;
+#endif
return(1);
} else {
lastpos = 1;
@@ -2776,7 +2790,12 @@ static int ast_el_read_char(EditLine *editline, char *cp)
}
}
+#ifdef HAVE_LIBEDIT_IS_UNICODE
+ *cp = btowc('\0');
+#else
*cp = '\0';
+#endif
+
return (0);
}
diff --git a/main/autoservice.c b/main/autoservice.c
index 11c9eab96..c3f24276c 100644
--- a/main/autoservice.c
+++ b/main/autoservice.c
@@ -59,10 +59,6 @@ struct asent {
unsigned int use_count;
unsigned int orig_end_dtmf_flag:1;
unsigned int ignore_frame_types;
- /*! Frames go on at the head of deferred_frames, so we have the frames
- * from newest to oldest. As we put them at the head of the readq, we'll
- * end up with them in the right order for the channel's readq. */
- AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames;
AST_LIST_ENTRY(asent) list;
};
@@ -77,19 +73,13 @@ static int as_chan_list_state;
static void *autoservice_run(void *ign)
{
ast_callid callid = 0;
- struct ast_frame hangup_frame = {
- .frametype = AST_FRAME_CONTROL,
- .subclass.integer = AST_CONTROL_HANGUP,
- };
while (!asexit) {
struct ast_channel *mons[MAX_AUTOMONS];
- struct asent *ents[MAX_AUTOMONS];
struct ast_channel *chan;
struct asent *as;
- int i, x = 0, ms = 50;
+ int x = 0, ms = 50;
struct ast_frame *f = NULL;
- struct ast_frame *defer_frame = NULL;
AST_LIST_LOCK(&aslist);
@@ -104,7 +94,6 @@ static void *autoservice_run(void *ign)
AST_LIST_TRAVERSE(&aslist, as, list) {
if (!ast_check_hangup(as->chan)) {
if (x < MAX_AUTOMONS) {
- ents[x] = as;
mons[x++] = as->chan;
} else {
ast_log(LOG_WARNING, "Exceeded maximum number of automatic monitoring events. Fix autoservice.c\n");
@@ -132,51 +121,9 @@ static void *autoservice_run(void *ign)
ast_callid_threadassoc_change(callid);
f = ast_read(chan);
-
- if (!f) {
- /* No frame means the channel has been hung up.
- * A hangup frame needs to be queued here as ast_waitfor() may
- * never return again for the condition to be detected outside
- * of autoservice. So, we'll leave a HANGUP queued up so the
- * thread in charge of this channel will know. */
-
- defer_frame = &hangup_frame;
- } else if (ast_is_deferrable_frame(f)) {
- defer_frame = f;
- } else {
- /* Can't defer. Discard and continue with next. */
+ if (f) {
ast_frfree(f);
- continue;
}
-
- for (i = 0; i < x; i++) {
- struct ast_frame *dup_f;
-
- if (mons[i] != chan) {
- continue;
- }
-
- if (!f) { /* defer_frame == &hangup_frame */
- if ((dup_f = ast_frdup(defer_frame))) {
- AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list);
- }
- } else {
- if ((dup_f = ast_frisolate(defer_frame))) {
- AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list);
- }
- if (dup_f != defer_frame) {
- ast_frfree(defer_frame);
- }
- }
-
- break;
- }
- /* The ast_waitfor_n() call will only read frames from
- * the channels' file descriptors. If ast_waitfor_n()
- * returns non-NULL, then one of the channels in the
- * mons array must have triggered the return. It's
- * therefore impossible that we got here while (i >= x).
- * If we did, we'd need to ast_frfree(f) if (f). */
}
ast_callid_threadassoc_change(0);
@@ -215,6 +162,7 @@ int ast_autoservice_start(struct ast_channel *chan)
as->orig_end_dtmf_flag = ast_test_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY) ? 1 : 0;
if (!as->orig_end_dtmf_flag)
ast_set_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY);
+ ast_channel_start_defer_frames(chan, 1);
ast_channel_unlock(chan);
AST_LIST_LOCK(&aslist);
@@ -248,7 +196,6 @@ int ast_autoservice_stop(struct ast_channel *chan)
{
int res = -1;
struct asent *as, *removed = NULL;
- struct ast_frame *f;
int chan_list_state;
AST_LIST_LOCK(&aslist);
@@ -300,12 +247,7 @@ int ast_autoservice_stop(struct ast_channel *chan)
}
ast_channel_lock(chan);
- while ((f = AST_LIST_REMOVE_HEAD(&as->deferred_frames, frame_list))) {
- if (!((1 << f->frametype) & as->ignore_frame_types)) {
- ast_queue_frame_head(chan, f);
- }
- ast_frfree(f);
- }
+ ast_channel_stop_defer_frames(chan);
ast_channel_unlock(chan);
ast_free(as);
diff --git a/main/bridge.c b/main/bridge.c
index 1bb60eb7a..13c01fa27 100644
--- a/main/bridge.c
+++ b/main/bridge.c
@@ -3774,8 +3774,7 @@ void ast_bridge_set_single_src_video_mode(struct ast_bridge *bridge, struct ast_
bridge->name, bridge->uniqueid,
ast_channel_name(video_src_chan),
ast_channel_uniqueid(video_src_chan));
- ast_test_suite_event_notify("BRIDGE_VIDEO_MODE", "Message: video mode set to single source\r\nVideo Mode: %u\r\nVideo Channel: %s",
- bridge->softmix.video_mode.mode, ast_channel_name(video_src_chan));
+ ast_bridge_publish_state(bridge);
ast_indicate(video_src_chan, AST_CONTROL_VIDUPDATE);
ast_bridge_unlock(bridge);
}
@@ -3785,8 +3784,6 @@ void ast_bridge_set_talker_src_video_mode(struct ast_bridge *bridge)
ast_bridge_lock(bridge);
cleanup_video_mode(bridge);
bridge->softmix.video_mode.mode = AST_BRIDGE_VIDEO_MODE_TALKER_SRC;
- ast_test_suite_event_notify("BRIDGE_VIDEO_MODE", "Message: video mode set to talker source\r\nVideo Mode: %u",
- bridge->softmix.video_mode.mode);
ast_bridge_unlock(bridge);
}
@@ -3818,7 +3815,7 @@ void ast_bridge_update_talker_src_video_mode(struct ast_bridge *bridge, struct a
bridge->name, bridge->uniqueid,
ast_channel_name(data->chan_vsrc),
ast_channel_uniqueid(data->chan_vsrc));
- ast_test_suite_event_notify("BRIDGE_VIDEO_SRC", "Message: video source updated\r\nVideo Channel: %s", ast_channel_name(data->chan_vsrc));
+ ast_bridge_publish_state(bridge);
ast_indicate(data->chan_vsrc, AST_CONTROL_VIDUPDATE);
} else if ((data->average_talking_energy < talker_energy) && !is_keyframe) {
ast_indicate(chan, AST_CONTROL_VIDUPDATE);
@@ -3829,7 +3826,7 @@ void ast_bridge_update_talker_src_video_mode(struct ast_bridge *bridge, struct a
bridge->name, bridge->uniqueid,
ast_channel_name(data->chan_vsrc),
ast_channel_uniqueid(data->chan_vsrc));
- ast_test_suite_event_notify("BRIDGE_VIDEO_SRC", "Message: video source updated\r\nVideo Channel: %s", ast_channel_name(data->chan_vsrc));
+ ast_bridge_publish_state(bridge);
ast_indicate(chan, AST_CONTROL_VIDUPDATE);
} else if (!data->chan_old_vsrc && is_keyframe) {
data->chan_old_vsrc = ast_channel_ref(chan);
@@ -3920,6 +3917,19 @@ void ast_bridge_remove_video_src(struct ast_bridge *bridge, struct ast_channel *
ast_bridge_unlock(bridge);
}
+const char *ast_bridge_video_mode_to_string(enum ast_bridge_video_mode_type video_mode)
+{
+ switch (video_mode) {
+ case AST_BRIDGE_VIDEO_MODE_TALKER_SRC:
+ return "talker";
+ case AST_BRIDGE_VIDEO_MODE_SINGLE_SRC:
+ return "single";
+ case AST_BRIDGE_VIDEO_MODE_NONE:
+ default:
+ return "none";
+ }
+}
+
static int channel_hash(const void *obj, int flags)
{
const struct ast_channel *chan = obj;
diff --git a/main/channel.c b/main/channel.c
index bdf918fab..bd5f35172 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -1062,6 +1062,26 @@ struct ast_channel *__ast_dummy_channel_alloc(const char *file, int line, const
return tmp;
}
+void ast_channel_start_defer_frames(struct ast_channel *chan, int defer_hangups)
+{
+ ast_set_flag(ast_channel_flags(chan), AST_FLAG_DEFER_FRAMES);
+ ast_set2_flag(ast_channel_flags(chan), defer_hangups, AST_FLAG_DEFER_HANGUP_FRAMES);
+}
+
+void ast_channel_stop_defer_frames(struct ast_channel *chan)
+{
+ ast_clear_flag(ast_channel_flags(chan), AST_FLAG_DEFER_FRAMES);
+
+ /* Move the deferred frames onto the channel read queue, ahead of other queued frames */
+ ast_queue_frame_head(chan, AST_LIST_FIRST(ast_channel_deferred_readq(chan)));
+ /* ast_frfree will mosey down the list and free them all */
+ if (!AST_LIST_EMPTY(ast_channel_deferred_readq(chan))) {
+ ast_frfree(AST_LIST_FIRST(ast_channel_deferred_readq(chan)));
+ }
+ /* Reset the list to be empty */
+ AST_LIST_HEAD_INIT_NOLOCK(ast_channel_deferred_readq(chan));
+}
+
static int __ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, int head, struct ast_frame *after)
{
struct ast_frame *f;
@@ -1525,19 +1545,18 @@ int ast_safe_sleep_conditional(struct ast_channel *chan, int timeout_ms, int (*c
int res = 0;
struct timeval start;
int ms;
- AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames;
-
- AST_LIST_HEAD_INIT_NOLOCK(&deferred_frames);
/* If no other generator is present, start silencegen while waiting */
if (ast_opt_transmit_silence && !ast_channel_generatordata(chan)) {
silgen = ast_channel_start_silence_generator(chan);
}
+ ast_channel_lock(chan);
+ ast_channel_start_defer_frames(chan, 0);
+ ast_channel_unlock(chan);
+
start = ast_tvnow();
while ((ms = ast_remaining_ms(start, timeout_ms))) {
- struct ast_frame *dup_f = NULL;
-
if (cond && ((*cond)(data) == 0)) {
break;
}
@@ -1552,18 +1571,7 @@ int ast_safe_sleep_conditional(struct ast_channel *chan, int timeout_ms, int (*c
res = -1;
break;
}
-
- if (!ast_is_deferrable_frame(f)) {
- ast_frfree(f);
- continue;
- }
-
- if ((dup_f = ast_frisolate(f))) {
- if (dup_f != f) {
- ast_frfree(f);
- }
- AST_LIST_INSERT_HEAD(&deferred_frames, dup_f, frame_list);
- }
+ ast_frfree(f);
}
}
@@ -1572,17 +1580,8 @@ int ast_safe_sleep_conditional(struct ast_channel *chan, int timeout_ms, int (*c
ast_channel_stop_silence_generator(chan, silgen);
}
- /* We need to free all the deferred frames, but we only need to
- * queue the deferred frames if there was no error and no
- * hangup was received
- */
ast_channel_lock(chan);
- while ((f = AST_LIST_REMOVE_HEAD(&deferred_frames, frame_list))) {
- if (!res) {
- ast_queue_frame_head(chan, f);
- }
- ast_frfree(f);
- }
+ ast_channel_stop_defer_frames(chan);
ast_channel_unlock(chan);
return res;
@@ -3883,6 +3882,36 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
if (!AST_LIST_EMPTY(ast_channel_readq(chan))) {
int skip_dtmf = should_skip_dtmf(chan);
+ if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_DEFER_FRAMES)) {
+ AST_LIST_TRAVERSE_SAFE_BEGIN(ast_channel_readq(chan), f, frame_list) {
+ if (ast_is_deferrable_frame(f)) {
+ if(f->frametype == AST_FRAME_CONTROL &&
+ (f->subclass.integer == AST_CONTROL_HANGUP ||
+ f->subclass.integer == AST_CONTROL_END_OF_Q)) {
+ /* Hangup is a special case. We want to defer the frame, but we also do not
+ * want to remove it from the frame queue. So rather than just moving the frame
+ * over, we duplicate it and move the copy to the deferred readq.
+ *
+ * The reason for this? This way, whoever calls ast_read() will get a NULL return
+ * immediately and can tell the channel has hung up and do what it needs to. Also,
+ * when frame deferral finishes, then whoever calls ast_read() next will also get
+ * the hangup.
+ */
+ if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_DEFER_HANGUP_FRAMES)) {
+ struct ast_frame *dup;
+
+ dup = ast_frdup(f);
+ AST_LIST_INSERT_TAIL(ast_channel_deferred_readq(chan), dup, frame_list);
+ }
+ } else {
+ AST_LIST_INSERT_TAIL(ast_channel_deferred_readq(chan), f, frame_list);
+ AST_LIST_REMOVE_CURRENT(frame_list);
+ }
+ }
+ }
+ AST_LIST_TRAVERSE_SAFE_END;
+ }
+
AST_LIST_TRAVERSE_SAFE_BEGIN(ast_channel_readq(chan), f, frame_list) {
/* We have to be picky about which frame we pull off of the readq because
* there are cases where we want to leave DTMF frames on the queue until
@@ -10278,9 +10307,15 @@ int ast_channel_connected_line_macro(struct ast_channel *autoservice_chan, struc
ast_party_connected_line_copy(ast_channel_connected(macro_chan), connected);
}
+ ast_channel_start_defer_frames(macro_chan, 0);
ast_channel_unlock(macro_chan);
retval = ast_app_run_macro(autoservice_chan, macro_chan, macro, macro_args);
+
+ ast_channel_lock(macro_chan);
+ ast_channel_stop_defer_frames(macro_chan);
+ ast_channel_unlock(macro_chan);
+
if (!retval) {
struct ast_party_connected_line saved_connected;
@@ -10328,9 +10363,15 @@ int ast_channel_redirecting_macro(struct ast_channel *autoservice_chan, struct a
ast_party_redirecting_copy(ast_channel_redirecting(macro_chan), redirecting);
}
+ ast_channel_start_defer_frames(macro_chan, 0);
ast_channel_unlock(macro_chan);
retval = ast_app_run_macro(autoservice_chan, macro_chan, macro, macro_args);
+
+ ast_channel_lock(macro_chan);
+ ast_channel_stop_defer_frames(macro_chan);
+ ast_channel_unlock(macro_chan);
+
if (!retval) {
struct ast_party_redirecting saved_redirecting;
@@ -10371,9 +10412,15 @@ int ast_channel_connected_line_sub(struct ast_channel *autoservice_chan, struct
ast_party_connected_line_copy(ast_channel_connected(sub_chan), connected);
}
+ ast_channel_start_defer_frames(sub_chan, 0);
ast_channel_unlock(sub_chan);
retval = ast_app_run_sub(autoservice_chan, sub_chan, sub, sub_args, 0);
+
+ ast_channel_lock(sub_chan);
+ ast_channel_stop_defer_frames(sub_chan);
+ ast_channel_unlock(sub_chan);
+
if (!retval) {
struct ast_party_connected_line saved_connected;
@@ -10414,9 +10461,15 @@ int ast_channel_redirecting_sub(struct ast_channel *autoservice_chan, struct ast
ast_party_redirecting_copy(ast_channel_redirecting(sub_chan), redirecting);
}
+ ast_channel_start_defer_frames(sub_chan, 0);
ast_channel_unlock(sub_chan);
retval = ast_app_run_sub(autoservice_chan, sub_chan, sub, sub_args, 0);
+
+ ast_channel_lock(sub_chan);
+ ast_channel_stop_defer_frames(sub_chan);
+ ast_channel_unlock(sub_chan);
+
if (!retval) {
struct ast_party_redirecting saved_redirecting;
diff --git a/main/channel_internal_api.c b/main/channel_internal_api.c
index 1cb91e7c3..50f6c5da9 100644
--- a/main/channel_internal_api.c
+++ b/main/channel_internal_api.c
@@ -221,6 +221,7 @@ struct ast_channel {
struct stasis_cp_single *topics; /*!< Topic for all channel's events */
struct stasis_forward *endpoint_forward; /*!< Subscription for event forwarding to endpoint's topic */
struct stasis_forward *endpoint_cache_forward; /*!< Subscription for cache updates to endpoint's topic */
+ struct ast_readq_list deferred_readq;
};
/*! \brief The monotonically increasing integer counter for channel uniqueids */
@@ -1681,3 +1682,8 @@ enum ast_channel_error ast_channel_internal_errno(void)
return *error_code;
}
+
+struct ast_readq_list *ast_channel_deferred_readq(struct ast_channel *chan)
+{
+ return &chan->deferred_readq;
+}
diff --git a/main/codec_builtin.c b/main/codec_builtin.c
index cc4edd239..f622c9105 100644
--- a/main/codec_builtin.c
+++ b/main/codec_builtin.c
@@ -729,6 +729,21 @@ static struct ast_codec g719 = {
.get_length = g719_length,
};
+static int opus_samples(struct ast_frame *frame)
+{
+ /*
+ * XXX This is likely not at all what's intended from this
+ * callback. If you have codec_opus.so loaded then this
+ * function is overridden anyway. However, since opus is
+ * variable bit rate and I cannot extract the calculation code
+ * from the opus library, I am going to punt and assume 20ms
+ * worth of samples. In testing, this has worked just fine.
+ * Pass through support doesn't seem to care about the value
+ * returned anyway.
+ */
+ return ast_format_get_sample_rate(frame->subclass.format) / 50;
+}
+
static struct ast_codec opus = {
.name = "opus",
.description = "Opus Codec",
@@ -737,6 +752,7 @@ static struct ast_codec opus = {
.minimum_ms = 20,
.maximum_ms = 60,
.default_ms = 20,
+ .samples_count = opus_samples,
.minimum_bytes = 10,
};
diff --git a/main/file.c b/main/file.c
index 37b9e7911..fb4ede6c8 100644
--- a/main/file.c
+++ b/main/file.c
@@ -1093,27 +1093,27 @@ int ast_filecopy(const char *filename, const char *filename2, const char *fmt)
return filehelper(filename, filename2, fmt, ACTION_COPY);
}
-static int __ast_file_read_dirs(struct ast_str **path, ast_file_on_file on_file,
+static int __ast_file_read_dirs(const char *path, ast_file_on_file on_file,
void *obj, int max_depth)
{
DIR *dir;
struct dirent *entry;
- size_t size;
int res;
- if (!(dir = opendir(ast_str_buffer(*path)))) {
+ if (!(dir = opendir(path))) {
ast_log(LOG_ERROR, "Error opening directory - %s: %s\n",
- ast_str_buffer(*path), strerror(errno));
+ path, strerror(errno));
return -1;
}
- size = ast_str_strlen(*path);
--max_depth;
res = 0;
while ((entry = readdir(dir)) != NULL && !errno) {
- int is_file, is_dir, used_stat = 0;
+ int is_file = 0;
+ int is_dir = 0;
+ RAII_VAR(char *, full_path, NULL, ast_free);
if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
continue;
@@ -1128,23 +1128,24 @@ static int __ast_file_read_dirs(struct ast_str **path, ast_file_on_file on_file,
if (entry->d_type != DT_UNKNOWN && entry->d_type != DT_LNK) {
is_file = entry->d_type == DT_REG;
is_dir = entry->d_type == DT_DIR;
- ast_log(LOG_VERBOSE, "!###### d_name=%s, path=%s, NO USE STAT used_stat=%d\n", entry->d_name, ast_str_buffer(*path), used_stat);
} else
#endif
{
struct stat statbuf;
/*
- * If using the stat function the file needs to be appended to the
- * path so it can be found. However, before appending make sure the
- * path contains only the directory for this depth level.
+ * Don't use alloca or we risk blowing out the stack if recursing
+ * into subdirectories.
*/
- ast_str_truncate(*path, size);
- ast_str_append(path, 0, "/%s", entry->d_name);
+ full_path = ast_malloc(strlen(path) + strlen(entry->d_name) + 2);
+ if (!full_path) {
+ return -1;
+ }
+ sprintf(full_path, "%s/%s", path, entry->d_name);
- if (stat(ast_str_buffer(*path), &statbuf)) {
+ if (stat(full_path, &statbuf)) {
ast_log(LOG_ERROR, "Error reading path stats - %s: %s\n",
- ast_str_buffer(*path), strerror(errno));
+ full_path, strerror(errno));
/*
* Output an error, but keep going. It could just be
* a broken link and other files could be fine.
@@ -1154,13 +1155,11 @@ static int __ast_file_read_dirs(struct ast_str **path, ast_file_on_file on_file,
is_file = S_ISREG(statbuf.st_mode);
is_dir = S_ISDIR(statbuf.st_mode);
- used_stat = 1;
- ast_log(LOG_VERBOSE, "!###### d_name=%s, path=%s, WE USED IT YO used_stat=%d\n", entry->d_name, ast_str_buffer(*path), used_stat);
}
if (is_file) {
/* If the handler returns non-zero then stop */
- if ((res = on_file(ast_str_buffer(*path), entry->d_name, obj))) {
+ if ((res = on_file(path, entry->d_name, obj))) {
break;
}
/* Otherwise move on to next item in directory */
@@ -1168,25 +1167,22 @@ static int __ast_file_read_dirs(struct ast_str **path, ast_file_on_file on_file,
}
if (!is_dir) {
- ast_debug(5, "Skipping %s: not a regular file or directory\n",
- ast_str_buffer(*path));
+ ast_debug(5, "Skipping %s: not a regular file or directory\n", full_path);
continue;
}
/* Only re-curse into sub-directories if not at the max depth */
if (max_depth != 0) {
- /*
- * If the stat function was used then the sub-directory has
- * already been appended, otherwise append it.
- */
- ast_log(LOG_VERBOSE, "!###### do dir d_name=%s, path=%s, used_stat=%d\n", entry->d_name, ast_str_buffer(*path), used_stat);
- if (!used_stat) {
- ast_str_truncate(*path, size);
- ast_str_append(path, 0, "/%s", entry->d_name);
- ast_log(LOG_VERBOSE, "!###### d_name=%s, path=%s\n", entry->d_name, ast_str_buffer(*path));
+ if (!full_path) {
+ /* Don't use alloca. See note above. */
+ full_path = ast_malloc(strlen(path) + strlen(entry->d_name) + 2);
+ if (!full_path) {
+ return -1;
+ }
+ sprintf(full_path, "%s/%s", path, entry->d_name);
}
- if ((res = __ast_file_read_dirs(path, on_file, obj, max_depth))) {
+ if ((res = __ast_file_read_dirs(full_path, on_file, obj, max_depth))) {
break;
}
}
@@ -1196,7 +1192,7 @@ static int __ast_file_read_dirs(struct ast_str **path, ast_file_on_file on_file,
if (!res && errno) {
ast_log(LOG_ERROR, "Error while reading directories - %s: %s\n",
- ast_str_buffer(*path), strerror(errno));
+ path, strerror(errno));
res = -1;
}
@@ -1217,27 +1213,20 @@ AST_MUTEX_DEFINE_STATIC(read_dirs_lock);
int ast_file_read_dirs(const char *dir_name, ast_file_on_file on_file, void *obj, int max_depth)
{
- struct ast_str *path;
int res;
- if (!(path = ast_str_create(256))) {
- return -1;
- }
-
- ast_str_set(&path, 0, "%s", dir_name);
errno = 0;
#if !defined(__GLIBC__)
ast_mutex_lock(&read_dirs_lock);
#endif
- res = __ast_file_read_dirs(&path, on_file, obj, max_depth);
+ res = __ast_file_read_dirs(dir_name, on_file, obj, max_depth);
#if !defined(__GLIBC__)
ast_mutex_unlock(&read_dirs_lock);
#endif
- ast_free(path);
return res;
}
diff --git a/main/manager_bridges.c b/main/manager_bridges.c
index c6e997f42..b7059f40c 100644
--- a/main/manager_bridges.c
+++ b/main/manager_bridges.c
@@ -91,6 +91,21 @@ static struct stasis_message_router *bridge_state_router;
</see-also>
</managerEventInstance>
</managerEvent>
+ <managerEvent language="en_US" name="BridgeVideoSourceUpdate">
+ <managerEventInstance class="EVENT_FLAG_CALL">
+ <synopsis>Raised when the channel that is the source of video in a bridge changes.</synopsis>
+ <syntax>
+ <bridge_snapshot/>
+ <parameter name="BridgePreviousVideoSource">
+ <para>The unique ID of the channel that was the video source.</para>
+ </parameter>
+ </syntax>
+ <see-also>
+ <ref type="managerEvent">BridgeCreate</ref>
+ <ref type="managerEvent">BridgeDestroy</ref>
+ </see-also>
+ </managerEventInstance>
+ </managerEvent>
<manager name="BridgeList" language="en_US">
<synopsis>
Get a list of bridges in the system.
@@ -222,18 +237,30 @@ struct ast_str *ast_manager_build_bridge_state_string_prefix(
"%sBridgeTechnology: %s\r\n"
"%sBridgeCreator: %s\r\n"
"%sBridgeName: %s\r\n"
- "%sBridgeNumChannels: %u\r\n",
+ "%sBridgeNumChannels: %u\r\n"
+ "%sBridgeVideoSourceMode: %s\r\n",
prefix, snapshot->uniqueid,
prefix, snapshot->subclass,
prefix, snapshot->technology,
prefix, ast_strlen_zero(snapshot->creator) ? "<unknown>": snapshot->creator,
prefix, ast_strlen_zero(snapshot->name) ? "<unknown>": snapshot->name,
- prefix, snapshot->num_channels);
+ prefix, snapshot->num_channels,
+ prefix, ast_bridge_video_mode_to_string(snapshot->video_mode));
if (!res) {
ast_free(out);
return NULL;
}
+ if (snapshot->video_mode != AST_BRIDGE_VIDEO_MODE_NONE
+ && !ast_strlen_zero(snapshot->video_source_id)) {
+ res = ast_str_append(&out, 0, "%sBridgeVideoSource: %s\r\n",
+ prefix, snapshot->video_source_id);
+ if (!res) {
+ ast_free(out);
+ return NULL;
+ }
+ }
+
return out;
}
@@ -261,6 +288,25 @@ static struct ast_manager_event_blob *bridge_create(
EVENT_FLAG_CALL, "BridgeCreate", NO_EXTRA_FIELDS);
}
+/* \brief Handle video source updates */
+static struct ast_manager_event_blob *bridge_video_update(
+ struct ast_bridge_snapshot *old_snapshot,
+ struct ast_bridge_snapshot *new_snapshot)
+{
+ if (!new_snapshot || !old_snapshot) {
+ return NULL;
+ }
+
+ if (!strcmp(old_snapshot->video_source_id, new_snapshot->video_source_id)) {
+ return NULL;
+ }
+
+ return ast_manager_event_blob_create(
+ EVENT_FLAG_CALL, "BridgeVideoSourceUpdate",
+ "BridgePreviousVideoSource: %s\r\n",
+ old_snapshot->video_source_id);
+}
+
/*! \brief Handle bridge destruction */
static struct ast_manager_event_blob *bridge_destroy(
struct ast_bridge_snapshot *old_snapshot,
@@ -274,9 +320,9 @@ static struct ast_manager_event_blob *bridge_destroy(
EVENT_FLAG_CALL, "BridgeDestroy", NO_EXTRA_FIELDS);
}
-
bridge_snapshot_monitor bridge_monitors[] = {
bridge_create,
+ bridge_video_update,
bridge_destroy,
};
diff --git a/main/stasis_bridges.c b/main/stasis_bridges.c
index 43722b90b..7f53bfe2d 100644
--- a/main/stasis_bridges.c
+++ b/main/stasis_bridges.c
@@ -242,7 +242,13 @@ struct ast_bridge_snapshot *ast_bridge_snapshot_create(struct ast_bridge *bridge
snapshot = ao2_alloc_options(sizeof(*snapshot), bridge_snapshot_dtor,
AO2_ALLOC_OPT_LOCK_NOLOCK);
- if (!snapshot || ast_string_field_init(snapshot, 128)) {
+ if (!snapshot) {
+ return NULL;
+ }
+
+ if (ast_string_field_init(snapshot, 128)
+ || ast_string_field_init_extended(snapshot, video_source_id)) {
+ ao2_ref(snapshot, -1);
return NULL;
}
@@ -268,6 +274,16 @@ struct ast_bridge_snapshot *ast_bridge_snapshot_create(struct ast_bridge *bridge
snapshot->capabilities = bridge->technology->capabilities;
snapshot->num_channels = bridge->num_channels;
snapshot->num_active = bridge->num_active;
+ snapshot->video_mode = bridge->softmix.video_mode.mode;
+ if (snapshot->video_mode == AST_BRIDGE_VIDEO_MODE_SINGLE_SRC
+ && bridge->softmix.video_mode.mode_data.single_src_data.chan_vsrc) {
+ ast_string_field_set(snapshot, video_source_id,
+ ast_channel_uniqueid(bridge->softmix.video_mode.mode_data.single_src_data.chan_vsrc));
+ } else if (snapshot->video_mode == AST_BRIDGE_VIDEO_MODE_TALKER_SRC
+ && bridge->softmix.video_mode.mode_data.talker_src_data.chan_vsrc) {
+ ast_string_field_set(snapshot, video_source_id,
+ ast_channel_uniqueid(bridge->softmix.video_mode.mode_data.talker_src_data.chan_vsrc));
+ }
ao2_ref(snapshot, +1);
return snapshot;
@@ -590,18 +606,25 @@ struct ast_json *ast_bridge_snapshot_to_json(
return NULL;
}
- json_bridge = ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: s, s: o}",
+ json_bridge = ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: s, s: o, s: s}",
"id", snapshot->uniqueid,
"technology", snapshot->technology,
"bridge_type", capability2str(snapshot->capabilities),
"bridge_class", snapshot->subclass,
"creator", snapshot->creator,
"name", snapshot->name,
- "channels", json_channels);
+ "channels", json_channels,
+ "video_mode", ast_bridge_video_mode_to_string(snapshot->video_mode));
if (!json_bridge) {
return NULL;
}
+ if (snapshot->video_mode != AST_BRIDGE_VIDEO_MODE_NONE
+ && !ast_strlen_zero(snapshot->video_source_id)) {
+ ast_json_object_set(json_bridge, "video_source_id",
+ ast_json_string_create(snapshot->video_source_id));
+ }
+
return ast_json_ref(json_bridge);
}