diff options
Diffstat (limited to 'main')
-rw-r--r-- | main/asterisk.c | 21 | ||||
-rw-r--r-- | main/autoservice.c | 66 | ||||
-rw-r--r-- | main/bridge.c | 22 | ||||
-rw-r--r-- | main/channel.c | 107 | ||||
-rw-r--r-- | main/channel_internal_api.c | 6 | ||||
-rw-r--r-- | main/codec_builtin.c | 16 | ||||
-rw-r--r-- | main/file.c | 65 | ||||
-rw-r--r-- | main/manager_bridges.c | 52 | ||||
-rw-r--r-- | main/stasis_bridges.c | 29 |
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); } |