diff options
-rw-r--r-- | bridges/bridge_softmix.c | 33 | ||||
-rw-r--r-- | include/asterisk/bridging.h | 13 | ||||
-rw-r--r-- | main/bridging.c | 48 |
3 files changed, 87 insertions, 7 deletions
diff --git a/bridges/bridge_softmix.c b/bridges/bridge_softmix.c index 8828d640a..00b0556d0 100644 --- a/bridges/bridge_softmix.c +++ b/bridges/bridge_softmix.c @@ -435,13 +435,30 @@ static void softmix_pass_dtmf(struct ast_bridge *bridge, struct ast_bridge_chann } } -static void softmix_pass_video(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame) +static void softmix_pass_video_top_priority(struct ast_bridge *bridge, struct ast_frame *frame) { struct ast_bridge_channel *tmp; AST_LIST_TRAVERSE(&bridge->channels, tmp, entry) { if (tmp->suspended) { continue; } + if (ast_bridge_is_video_src(bridge, tmp->chan) == 1) { + ast_write(tmp->chan, frame); + break; + } + } +} + +static void softmix_pass_video_all(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame, int echo) +{ + struct ast_bridge_channel *tmp; + AST_LIST_TRAVERSE(&bridge->channels, tmp, entry) { + if (tmp->suspended) { + continue; + } + if ((tmp->chan == bridge_channel->chan) && !echo) { + continue; + } ast_write(tmp->chan, frame); } } @@ -472,20 +489,26 @@ static enum ast_bridge_write_result softmix_bridge_write(struct ast_bridge *brid /* Determine if this video frame should be distributed or not */ if (frame->frametype == AST_FRAME_VIDEO) { + int num_src = ast_bridge_number_video_src(bridge); + int video_src_priority = ast_bridge_is_video_src(bridge, bridge_channel->chan); + switch (bridge->video_mode.mode) { case AST_BRIDGE_VIDEO_MODE_NONE: break; case AST_BRIDGE_VIDEO_MODE_SINGLE_SRC: - if (ast_bridge_is_video_src(bridge, bridge_channel->chan)) { - softmix_pass_video(bridge, bridge_channel, frame); + if (video_src_priority == 1) { + softmix_pass_video_all(bridge, bridge_channel, frame, 1); } break; case AST_BRIDGE_VIDEO_MODE_TALKER_SRC: ast_mutex_lock(&sc->lock); ast_bridge_update_talker_src_video_mode(bridge, bridge_channel->chan, sc->video_talker.energy_average, ast_format_get_video_mark(&frame->subclass.format)); ast_mutex_unlock(&sc->lock); - if (ast_bridge_is_video_src(bridge, bridge_channel->chan)) { - softmix_pass_video(bridge, bridge_channel, frame); + if (video_src_priority == 1) { + int echo = num_src > 1 ? 0 : 1; + softmix_pass_video_all(bridge, bridge_channel, frame, echo); + } else if (video_src_priority == 2) { + softmix_pass_video_top_priority(bridge, frame); } break; } diff --git a/include/asterisk/bridging.h b/include/asterisk/bridging.h index 849f88741..54137b028 100644 --- a/include/asterisk/bridging.h +++ b/include/asterisk/bridging.h @@ -190,6 +190,9 @@ struct ast_bridge_video_talker_src_data { /*! Only accept video coming from this channel */ struct ast_channel *chan_vsrc; int average_talking_energy; + + /*! Current talker see's this person */ + struct ast_channel *chan_old_vsrc; }; struct ast_bridge_video_mode { @@ -528,7 +531,17 @@ void ast_bridge_set_talker_src_video_mode(struct ast_bridge *bridge); void ast_bridge_update_talker_src_video_mode(struct ast_bridge *bridge, struct ast_channel *chan, int talker_energy, int is_keyfame); /*! + * \brief Returns the number of video sources currently active in the bridge + */ +int ast_bridge_number_video_src(struct ast_bridge *bridge); + +/*! * \brief Determine if a channel is a video src for the bridge + * + * \retval 0 Not a current video source of the bridge. + * \retval None 0, is a video source of the bridge, The number + * returned represents the priority this video stream has + * on the bridge where 1 is the highest priority. */ int ast_bridge_is_video_src(struct ast_bridge *bridge, struct ast_channel *chan); diff --git a/main/bridging.c b/main/bridging.c index 1563e4789..835a849fb 100644 --- a/main/bridging.c +++ b/main/bridging.c @@ -1489,6 +1489,9 @@ static void cleanup_video_mode(struct ast_bridge *bridge) if (bridge->video_mode.mode_data.talker_src_data.chan_vsrc) { ast_channel_unref(bridge->video_mode.mode_data.talker_src_data.chan_vsrc); } + if (bridge->video_mode.mode_data.talker_src_data.chan_old_vsrc) { + ast_channel_unref(bridge->video_mode.mode_data.talker_src_data.chan_old_vsrc); + } } memset(&bridge->video_mode, 0, sizeof(bridge->video_mode)); } @@ -1525,20 +1528,51 @@ void ast_bridge_update_talker_src_video_mode(struct ast_bridge *bridge, struct a if (data->chan_vsrc == chan) { data->average_talking_energy = talker_energy; } else if ((data->average_talking_energy < talker_energy) && is_keyframe) { + if (data->chan_old_vsrc) { + ast_channel_unref(data->chan_old_vsrc); + } if (data->chan_vsrc) { - ast_channel_unref(data->chan_vsrc); + data->chan_old_vsrc = data->chan_vsrc; + ast_indicate(data->chan_old_vsrc, AST_CONTROL_VIDUPDATE); } data->chan_vsrc = ast_channel_ref(chan); data->average_talking_energy = talker_energy; - ast_indicate(chan, AST_CONTROL_VIDUPDATE); } else if ((data->average_talking_energy < talker_energy) && !is_keyframe) { ast_indicate(chan, AST_CONTROL_VIDUPDATE); } else if (!data->chan_vsrc && is_keyframe) { data->chan_vsrc = ast_channel_ref(chan); data->average_talking_energy = talker_energy; ast_indicate(chan, AST_CONTROL_VIDUPDATE); + } else if (!data->chan_old_vsrc && is_keyframe) { + data->chan_old_vsrc = ast_channel_ref(chan); + ast_indicate(chan, AST_CONTROL_VIDUPDATE); + } + ao2_unlock(bridge); +} + +int ast_bridge_number_video_src(struct ast_bridge *bridge) +{ + int res = 0; + + ao2_lock(bridge); + switch (bridge->video_mode.mode) { + case AST_BRIDGE_VIDEO_MODE_NONE: + break; + case AST_BRIDGE_VIDEO_MODE_SINGLE_SRC: + if (bridge->video_mode.mode_data.single_src_data.chan_vsrc) { + res = 1; + } + break; + case AST_BRIDGE_VIDEO_MODE_TALKER_SRC: + if (bridge->video_mode.mode_data.talker_src_data.chan_vsrc) { + res++; + } + if (bridge->video_mode.mode_data.talker_src_data.chan_old_vsrc) { + res++; + } } ao2_unlock(bridge); + return res; } int ast_bridge_is_video_src(struct ast_bridge *bridge, struct ast_channel *chan) @@ -1557,7 +1591,10 @@ int ast_bridge_is_video_src(struct ast_bridge *bridge, struct ast_channel *chan) case AST_BRIDGE_VIDEO_MODE_TALKER_SRC: if (bridge->video_mode.mode_data.talker_src_data.chan_vsrc == chan) { res = 1; + } else if (bridge->video_mode.mode_data.talker_src_data.chan_old_vsrc == chan) { + res = 2; } + } ao2_unlock(bridge); return res; @@ -1583,6 +1620,13 @@ void ast_bridge_remove_video_src(struct ast_bridge *bridge, struct ast_channel * ast_channel_unref(bridge->video_mode.mode_data.talker_src_data.chan_vsrc); } bridge->video_mode.mode_data.talker_src_data.chan_vsrc = NULL; + bridge->video_mode.mode_data.talker_src_data.average_talking_energy = 0; + } + if (bridge->video_mode.mode_data.talker_src_data.chan_old_vsrc == chan) { + if (bridge->video_mode.mode_data.talker_src_data.chan_old_vsrc) { + ast_channel_unref(bridge->video_mode.mode_data.talker_src_data.chan_old_vsrc); + } + bridge->video_mode.mode_data.talker_src_data.chan_old_vsrc = NULL; } } ao2_unlock(bridge); |