mirror of
https://github.com/signalwire/freeswitch.git
synced 2025-06-01 11:10:24 +00:00
FS-7513: add video mute and suite of controls
This commit is contained in:
parent
2c1ab14074
commit
eca9107498
@ -224,7 +224,8 @@ typedef enum {
|
|||||||
MFLAG_POSITIONAL = (1 << 26),
|
MFLAG_POSITIONAL = (1 << 26),
|
||||||
MFLAG_NO_POSITIONAL = (1 << 27),
|
MFLAG_NO_POSITIONAL = (1 << 27),
|
||||||
MFLAG_JOIN_VID_FLOOR = (1 << 28),
|
MFLAG_JOIN_VID_FLOOR = (1 << 28),
|
||||||
MFLAG_RECEIVING_VIDEO = (1 << 29)
|
MFLAG_RECEIVING_VIDEO = (1 << 29),
|
||||||
|
MFLAG_CAN_SEE = (1 << 30)
|
||||||
} member_flag_t;
|
} member_flag_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@ -384,10 +385,12 @@ typedef struct mcu_layer_s {
|
|||||||
int x_pos;
|
int x_pos;
|
||||||
int y_pos;
|
int y_pos;
|
||||||
int banner_patched;
|
int banner_patched;
|
||||||
|
int mute_patched;
|
||||||
switch_image_t *img;
|
switch_image_t *img;
|
||||||
switch_image_t *cur_img;
|
switch_image_t *cur_img;
|
||||||
switch_image_t *banner_img;
|
switch_image_t *banner_img;
|
||||||
switch_image_t *logo_img;
|
switch_image_t *logo_img;
|
||||||
|
switch_image_t *mute_img;
|
||||||
switch_img_txt_handle_t *txthandle;
|
switch_img_txt_handle_t *txthandle;
|
||||||
} mcu_layer_t;
|
} mcu_layer_t;
|
||||||
|
|
||||||
@ -621,6 +624,7 @@ struct conference_member {
|
|||||||
int video_codec_index;
|
int video_codec_index;
|
||||||
int video_codec_id;
|
int video_codec_id;
|
||||||
char *video_banner_text;
|
char *video_banner_text;
|
||||||
|
char *video_mute_png;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@ -717,6 +721,9 @@ static void conference_member_itterator(conference_obj_t *conference, switch_str
|
|||||||
static switch_status_t conf_api_sub_mute(conference_member_t *member, switch_stream_handle_t *stream, void *data);
|
static switch_status_t conf_api_sub_mute(conference_member_t *member, switch_stream_handle_t *stream, void *data);
|
||||||
static switch_status_t conf_api_sub_tmute(conference_member_t *member, switch_stream_handle_t *stream, void *data);
|
static switch_status_t conf_api_sub_tmute(conference_member_t *member, switch_stream_handle_t *stream, void *data);
|
||||||
static switch_status_t conf_api_sub_unmute(conference_member_t *member, switch_stream_handle_t *stream, void *data);
|
static switch_status_t conf_api_sub_unmute(conference_member_t *member, switch_stream_handle_t *stream, void *data);
|
||||||
|
static switch_status_t conf_api_sub_vmute(conference_member_t *member, switch_stream_handle_t *stream, void *data);
|
||||||
|
static switch_status_t conf_api_sub_tvmute(conference_member_t *member, switch_stream_handle_t *stream, void *data);
|
||||||
|
static switch_status_t conf_api_sub_unvmute(conference_member_t *member, switch_stream_handle_t *stream, void *data);
|
||||||
static switch_status_t conf_api_sub_deaf(conference_member_t *member, switch_stream_handle_t *stream, void *data);
|
static switch_status_t conf_api_sub_deaf(conference_member_t *member, switch_stream_handle_t *stream, void *data);
|
||||||
static switch_status_t conf_api_sub_undeaf(conference_member_t *member, switch_stream_handle_t *stream, void *data);
|
static switch_status_t conf_api_sub_undeaf(conference_member_t *member, switch_stream_handle_t *stream, void *data);
|
||||||
static switch_status_t conference_add_event_data(conference_obj_t *conference, switch_event_t *event);
|
static switch_status_t conference_add_event_data(conference_obj_t *conference, switch_event_t *event);
|
||||||
@ -931,7 +938,7 @@ static void reset_layer(mcu_canvas_t *canvas, mcu_layer_t *layer)
|
|||||||
switch_img_free(&layer->cur_img);
|
switch_img_free(&layer->cur_img);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void scale_and_patch(conference_obj_t *conference, mcu_layer_t *layer)
|
static void scale_and_patch(conference_obj_t *conference, mcu_layer_t *layer, switch_image_t *ximg)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
switch_image_t *IMG, *img;
|
switch_image_t *IMG, *img;
|
||||||
@ -939,7 +946,7 @@ static void scale_and_patch(conference_obj_t *conference, mcu_layer_t *layer)
|
|||||||
switch_mutex_lock(conference->canvas->mutex);
|
switch_mutex_lock(conference->canvas->mutex);
|
||||||
|
|
||||||
IMG = conference->canvas->img;
|
IMG = conference->canvas->img;
|
||||||
img = layer->cur_img;
|
img = ximg ? ximg : layer->cur_img;
|
||||||
|
|
||||||
if (layer->geometry.scale) {
|
if (layer->geometry.scale) {
|
||||||
int img_w = 0, img_h = 0;
|
int img_w = 0, img_h = 0;
|
||||||
@ -1111,6 +1118,7 @@ static void layer_set_banner(conference_member_t *member, mcu_layer_t *layer, co
|
|||||||
|
|
||||||
switch_img_free(&layer->banner_img);
|
switch_img_free(&layer->banner_img);
|
||||||
switch_img_free(&layer->logo_img);
|
switch_img_free(&layer->logo_img);
|
||||||
|
switch_img_free(&layer->mute_img);
|
||||||
layer->banner_patched = 0;
|
layer->banner_patched = 0;
|
||||||
|
|
||||||
switch_color_set_rgb(&color, member->conference->video_layout_bgcolor);
|
switch_color_set_rgb(&color, member->conference->video_layout_bgcolor);
|
||||||
@ -1215,7 +1223,7 @@ static switch_status_t attach_video_layer(conference_member_t *member, int idx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
reset_layer(member->conference->canvas, layer);
|
reset_layer(member->conference->canvas, layer);
|
||||||
|
switch_img_free(&layer->mute_img);
|
||||||
|
|
||||||
res_id = switch_channel_get_variable_dup(channel, "video_reservation_id", SWITCH_FALSE, -1);
|
res_id = switch_channel_get_variable_dup(channel, "video_reservation_id", SWITCH_FALSE, -1);
|
||||||
|
|
||||||
@ -1427,6 +1435,23 @@ static video_layout_t *find_best_layout(conference_obj_t *conference, layout_gro
|
|||||||
return vlnode? vlnode->vlayout : last ? last->vlayout : NULL;
|
return vlnode? vlnode->vlayout : last ? last->vlayout : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void vmute_snap(conference_member_t *member, switch_bool_t clear)
|
||||||
|
{
|
||||||
|
if (member->conference->canvas && member->video_layer_id > -1) {
|
||||||
|
mcu_layer_t *layer = NULL;
|
||||||
|
|
||||||
|
switch_mutex_lock(member->conference->canvas->mutex);
|
||||||
|
layer = &member->conference->canvas->layers[member->video_layer_id];
|
||||||
|
switch_img_free(&layer->mute_img);
|
||||||
|
|
||||||
|
if (!clear) {
|
||||||
|
switch_img_copy(layer->cur_img, &layer->mute_img);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch_mutex_unlock(member->conference->canvas->mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thread, void *obj)
|
static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thread, void *obj)
|
||||||
{
|
{
|
||||||
conference_obj_t *conference = (conference_obj_t *) obj;
|
conference_obj_t *conference = (conference_obj_t *) obj;
|
||||||
@ -1591,8 +1616,30 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread
|
|||||||
|
|
||||||
if (layer) {
|
if (layer) {
|
||||||
switch_img_free(&layer->cur_img);
|
switch_img_free(&layer->cur_img);
|
||||||
layer->cur_img = img;
|
|
||||||
layer->tagged = 1;
|
if (switch_test_flag(imember, MFLAG_CAN_SEE)) {
|
||||||
|
layer->mute_patched = 0;
|
||||||
|
} else {
|
||||||
|
switch_img_free(&img);
|
||||||
|
if (imember->video_mute_png && !layer->mute_patched) {
|
||||||
|
|
||||||
|
if (imember->video_mute_png || layer->mute_img) {
|
||||||
|
reset_layer(conference->canvas, layer);
|
||||||
|
|
||||||
|
if (!layer->mute_img && imember->video_mute_png) {
|
||||||
|
layer->mute_img = switch_img_read_png(imember->video_mute_png);
|
||||||
|
}
|
||||||
|
|
||||||
|
scale_and_patch(conference, layer, layer->mute_img);
|
||||||
|
layer->mute_patched = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (img) {
|
||||||
|
layer->cur_img = img;
|
||||||
|
layer->tagged = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch_mutex_unlock(conference->canvas->mutex);
|
switch_mutex_unlock(conference->canvas->mutex);
|
||||||
@ -1609,7 +1656,7 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread
|
|||||||
mcu_layer_t *layer = &conference->canvas->layers[i];
|
mcu_layer_t *layer = &conference->canvas->layers[i];
|
||||||
|
|
||||||
if (layer->member_id > -1 && layer->cur_img && layer->tagged) {
|
if (layer->member_id > -1 && layer->cur_img && layer->tagged) {
|
||||||
scale_and_patch(conference, layer);
|
scale_and_patch(conference, layer, NULL);
|
||||||
layer->tagged = 0;
|
layer->tagged = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1698,6 +1745,7 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread
|
|||||||
layer->banner_patched = 0;
|
layer->banner_patched = 0;
|
||||||
switch_img_free(&layer->banner_img);
|
switch_img_free(&layer->banner_img);
|
||||||
switch_img_free(&layer->logo_img);
|
switch_img_free(&layer->logo_img);
|
||||||
|
switch_img_free(&layer->mute_img);
|
||||||
switch_mutex_unlock(conference->canvas->mutex);
|
switch_mutex_unlock(conference->canvas->mutex);
|
||||||
|
|
||||||
if (layer->txthandle) {
|
if (layer->txthandle) {
|
||||||
@ -2832,6 +2880,7 @@ static switch_status_t conference_add_event_member_data(conference_member_t *mem
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Hear", "%s", switch_test_flag(member, MFLAG_CAN_HEAR) ? "true" : "false" );
|
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Hear", "%s", switch_test_flag(member, MFLAG_CAN_HEAR) ? "true" : "false" );
|
||||||
|
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "See", "%s", switch_test_flag(member, MFLAG_CAN_SEE) ? "true" : "false" );
|
||||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Speak", "%s", switch_test_flag(member, MFLAG_CAN_SPEAK) ? "true" : "false" );
|
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Speak", "%s", switch_test_flag(member, MFLAG_CAN_SPEAK) ? "true" : "false" );
|
||||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Talking", "%s", switch_test_flag(member, MFLAG_TALKING) ? "true" : "false" );
|
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Talking", "%s", switch_test_flag(member, MFLAG_TALKING) ? "true" : "false" );
|
||||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Mute-Detect", "%s", switch_test_flag(member, MFLAG_MUTE_DETECT) ? "true" : "false" );
|
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Mute-Detect", "%s", switch_test_flag(member, MFLAG_MUTE_DETECT) ? "true" : "false" );
|
||||||
@ -3205,9 +3254,13 @@ static void member_update_status_field(conference_member_t *member)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (switch_channel_test_flag(member->channel, CF_VIDEO)) {
|
if (switch_channel_test_flag(member->channel, CF_VIDEO)) {
|
||||||
vstr = " VIDEO";
|
if (!switch_test_flag(member, MFLAG_CAN_SEE)) {
|
||||||
if (member && member->id == member->conference->video_floor_holder) {
|
vstr = " VIDEO (BLIND)";
|
||||||
vstr = " VIDEO (FLOOR)";
|
} else {
|
||||||
|
vstr = " VIDEO";
|
||||||
|
if (member && member->id == member->conference->video_floor_holder) {
|
||||||
|
vstr = " VIDEO (FLOOR)";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3372,7 +3425,7 @@ static switch_status_t conference_add_member(conference_obj_t *conference, confe
|
|||||||
char msg[512]; /* conference count announcement */
|
char msg[512]; /* conference count announcement */
|
||||||
call_list_t *call_list = NULL;
|
call_list_t *call_list = NULL;
|
||||||
switch_channel_t *channel;
|
switch_channel_t *channel;
|
||||||
const char *controls = NULL, *position = NULL;
|
const char *controls = NULL, *position = NULL, *var = NULL;
|
||||||
|
|
||||||
switch_assert(conference != NULL);
|
switch_assert(conference != NULL);
|
||||||
switch_assert(member != NULL);
|
switch_assert(member != NULL);
|
||||||
@ -3402,7 +3455,7 @@ static switch_status_t conference_add_member(conference_obj_t *conference, confe
|
|||||||
switch_mutex_unlock(conference->member_mutex);
|
switch_mutex_unlock(conference->member_mutex);
|
||||||
conference_cdr_add(member);
|
conference_cdr_add(member);
|
||||||
|
|
||||||
|
|
||||||
if (!switch_test_flag(member, MFLAG_NOCHANNEL)) {
|
if (!switch_test_flag(member, MFLAG_NOCHANNEL)) {
|
||||||
if (switch_test_flag(member, MFLAG_GHOST)) {
|
if (switch_test_flag(member, MFLAG_GHOST)) {
|
||||||
conference->count_ghosts++;
|
conference->count_ghosts++;
|
||||||
@ -3428,6 +3481,11 @@ static switch_status_t conference_add_member(conference_obj_t *conference, confe
|
|||||||
switch_channel_set_flag(channel, CF_VIDEO_DECODED_READ);
|
switch_channel_set_flag(channel, CF_VIDEO_DECODED_READ);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if ((var = switch_channel_get_variable_dup(member->channel, "video_mute_png", SWITCH_FALSE, -1))) {
|
||||||
|
member->video_mute_png = switch_core_strdup(member->pool, var);
|
||||||
|
}
|
||||||
|
|
||||||
switch_channel_set_variable_printf(channel, "conference_member_id", "%d", member->id);
|
switch_channel_set_variable_printf(channel, "conference_member_id", "%d", member->id);
|
||||||
switch_channel_set_variable_printf(channel, "conference_moderator", "%s", switch_test_flag(member, MFLAG_MOD) ? "true" : "false");
|
switch_channel_set_variable_printf(channel, "conference_moderator", "%s", switch_test_flag(member, MFLAG_MOD) ? "true" : "false");
|
||||||
switch_channel_set_variable_printf(channel, "conference_ghost", "%s", switch_test_flag(member, MFLAG_GHOST) ? "true" : "false");
|
switch_channel_set_variable_printf(channel, "conference_ghost", "%s", switch_test_flag(member, MFLAG_GHOST) ? "true" : "false");
|
||||||
@ -4837,6 +4895,42 @@ static void conference_loop_fn_mute_off(conference_member_t *member, caller_cont
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void conference_loop_fn_vmute_snap(conference_member_t *member, caller_control_action_t *action)
|
||||||
|
{
|
||||||
|
vmute_snap(member, SWITCH_FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void conference_loop_fn_vmute_snapoff(conference_member_t *member, caller_control_action_t *action)
|
||||||
|
{
|
||||||
|
vmute_snap(member, SWITCH_TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void conference_loop_fn_vmute_toggle(conference_member_t *member, caller_control_action_t *action)
|
||||||
|
{
|
||||||
|
if (member == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (switch_test_flag(member, MFLAG_CAN_SEE)) {
|
||||||
|
conf_api_sub_vmute(member, NULL, NULL);
|
||||||
|
} else {
|
||||||
|
conf_api_sub_unvmute(member, NULL, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void conference_loop_fn_vmute_on(conference_member_t *member, caller_control_action_t *action)
|
||||||
|
{
|
||||||
|
if (switch_test_flag(member, MFLAG_CAN_SEE)) {
|
||||||
|
conf_api_sub_vmute(member, NULL, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void conference_loop_fn_vmute_off(conference_member_t *member, caller_control_action_t *action)
|
||||||
|
{
|
||||||
|
if (!switch_test_flag(member, MFLAG_CAN_SEE)) {
|
||||||
|
conf_api_sub_unvmute(member, NULL, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void conference_loop_fn_lock_toggle(conference_member_t *member, caller_control_action_t *action)
|
static void conference_loop_fn_lock_toggle(conference_member_t *member, caller_control_action_t *action)
|
||||||
{
|
{
|
||||||
switch_event_t *event;
|
switch_event_t *event;
|
||||||
@ -7315,6 +7409,52 @@ static void conference_list_count_only(conference_obj_t *conference, switch_stre
|
|||||||
stream->write_function(stream, "%d", conference->count);
|
stream->write_function(stream, "%d", conference->count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static switch_status_t conf_api_sub_agc(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv)
|
||||||
|
{
|
||||||
|
int level;
|
||||||
|
int on = 0;
|
||||||
|
|
||||||
|
if (argc == 2) {
|
||||||
|
stream->write_function(stream, "+OK CURRENT AGC LEVEL IS %d\n", conference->agc_level);
|
||||||
|
return SWITCH_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!(on = !strcasecmp(argv[2], "on"))) {
|
||||||
|
stream->write_function(stream, "+OK AGC DISABLED\n");
|
||||||
|
conference->agc_level = 0;
|
||||||
|
return SWITCH_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc > 3) {
|
||||||
|
level = atoi(argv[3]);
|
||||||
|
} else {
|
||||||
|
level = DEFAULT_AGC_LEVEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (level > conference->energy_level) {
|
||||||
|
conference->avg_score = 0;
|
||||||
|
conference->avg_itt = 0;
|
||||||
|
conference->avg_tally = 0;
|
||||||
|
conference->agc_level = level;
|
||||||
|
|
||||||
|
if (stream) {
|
||||||
|
stream->write_function(stream, "OK AGC ENABLED %d\n", conference->agc_level);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (stream) {
|
||||||
|
stream->write_function(stream, "-ERR invalid level\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return SWITCH_STATUS_SUCCESS;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
static switch_status_t conf_api_sub_mute(conference_member_t *member, switch_stream_handle_t *stream, void *data)
|
static switch_status_t conf_api_sub_mute(conference_member_t *member, switch_stream_handle_t *stream, void *data)
|
||||||
{
|
{
|
||||||
switch_event_t *event;
|
switch_event_t *event;
|
||||||
@ -7368,51 +7508,6 @@ static switch_status_t conf_api_sub_tmute(conference_member_t *member, switch_st
|
|||||||
return conf_api_sub_unmute(member, stream, data);
|
return conf_api_sub_unmute(member, stream, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static switch_status_t conf_api_sub_agc(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv)
|
|
||||||
{
|
|
||||||
int level;
|
|
||||||
int on = 0;
|
|
||||||
|
|
||||||
if (argc == 2) {
|
|
||||||
stream->write_function(stream, "+OK CURRENT AGC LEVEL IS %d\n", conference->agc_level);
|
|
||||||
return SWITCH_STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (!(on = !strcasecmp(argv[2], "on"))) {
|
|
||||||
stream->write_function(stream, "+OK AGC DISABLED\n");
|
|
||||||
conference->agc_level = 0;
|
|
||||||
return SWITCH_STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (argc > 3) {
|
|
||||||
level = atoi(argv[3]);
|
|
||||||
} else {
|
|
||||||
level = DEFAULT_AGC_LEVEL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (level > conference->energy_level) {
|
|
||||||
conference->avg_score = 0;
|
|
||||||
conference->avg_itt = 0;
|
|
||||||
conference->avg_tally = 0;
|
|
||||||
conference->agc_level = level;
|
|
||||||
|
|
||||||
if (stream) {
|
|
||||||
stream->write_function(stream, "OK AGC ENABLED %d\n", conference->agc_level);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if (stream) {
|
|
||||||
stream->write_function(stream, "-ERR invalid level\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return SWITCH_STATUS_SUCCESS;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static switch_status_t conf_api_sub_unmute(conference_member_t *member, switch_stream_handle_t *stream, void *data)
|
static switch_status_t conf_api_sub_unmute(conference_member_t *member, switch_stream_handle_t *stream, void *data)
|
||||||
{
|
{
|
||||||
@ -7451,6 +7546,105 @@ static switch_status_t conf_api_sub_unmute(conference_member_t *member, switch_s
|
|||||||
return SWITCH_STATUS_SUCCESS;
|
return SWITCH_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static switch_status_t conf_api_sub_vmute_snap(conference_member_t *member, switch_stream_handle_t *stream, void *data)
|
||||||
|
{
|
||||||
|
switch_bool_t clear = SWITCH_FALSE;
|
||||||
|
|
||||||
|
if (member == NULL)
|
||||||
|
return SWITCH_STATUS_GENERR;
|
||||||
|
|
||||||
|
if (!member->conference->canvas) {
|
||||||
|
stream->write_function(stream, "Conference is not in mixing mode\n");
|
||||||
|
return SWITCH_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream != NULL) {
|
||||||
|
stream->write_function(stream, "OK vmute image snapped %u\n", member->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data && !strcasecmp((char *)data, "clear")) {
|
||||||
|
clear = SWITCH_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
vmute_snap(member, clear);
|
||||||
|
|
||||||
|
return SWITCH_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static switch_status_t conf_api_sub_vmute(conference_member_t *member, switch_stream_handle_t *stream, void *data)
|
||||||
|
{
|
||||||
|
switch_event_t *event;
|
||||||
|
|
||||||
|
if (member == NULL)
|
||||||
|
return SWITCH_STATUS_GENERR;
|
||||||
|
|
||||||
|
switch_clear_flag_locked(member, MFLAG_CAN_SEE);
|
||||||
|
|
||||||
|
if (!(data) || !strstr((char *) data, "quiet")) {
|
||||||
|
switch_set_flag(member, MFLAG_INDICATE_MUTE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream != NULL) {
|
||||||
|
stream->write_function(stream, "OK vmute %u\n", member->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (test_eflag(member->conference, EFLAG_MUTE_MEMBER) &&
|
||||||
|
switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
|
||||||
|
conference_add_event_member_data(member, event);
|
||||||
|
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "vmute-member");
|
||||||
|
switch_event_fire(&event);
|
||||||
|
}
|
||||||
|
|
||||||
|
member_update_status_field(member);
|
||||||
|
|
||||||
|
return SWITCH_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static switch_status_t conf_api_sub_tvmute(conference_member_t *member, switch_stream_handle_t *stream, void *data)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (member == NULL)
|
||||||
|
return SWITCH_STATUS_GENERR;
|
||||||
|
|
||||||
|
if (switch_test_flag(member, MFLAG_CAN_SEE)) {
|
||||||
|
return conf_api_sub_vmute(member, stream, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return conf_api_sub_unvmute(member, stream, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static switch_status_t conf_api_sub_unvmute(conference_member_t *member, switch_stream_handle_t *stream, void *data)
|
||||||
|
{
|
||||||
|
switch_event_t *event;
|
||||||
|
|
||||||
|
if (member == NULL)
|
||||||
|
return SWITCH_STATUS_GENERR;
|
||||||
|
|
||||||
|
switch_set_flag_locked(member, MFLAG_CAN_SEE);
|
||||||
|
|
||||||
|
if (!(data) || !strstr((char *) data, "quiet")) {
|
||||||
|
switch_set_flag(member, MFLAG_INDICATE_UNMUTE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream != NULL) {
|
||||||
|
stream->write_function(stream, "OK unvmute %u\n", member->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (test_eflag(member->conference, EFLAG_UNMUTE_MEMBER) &&
|
||||||
|
switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
|
||||||
|
conference_add_event_member_data(member, event);
|
||||||
|
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "unvmute-member");
|
||||||
|
switch_event_fire(&event);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
member_update_status_field(member);
|
||||||
|
|
||||||
|
return SWITCH_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static switch_status_t conf_api_sub_deaf(conference_member_t *member, switch_stream_handle_t *stream, void *data)
|
static switch_status_t conf_api_sub_deaf(conference_member_t *member, switch_stream_handle_t *stream, void *data)
|
||||||
{
|
{
|
||||||
switch_event_t *event;
|
switch_event_t *event;
|
||||||
@ -8087,6 +8281,44 @@ static switch_status_t conf_api_sub_clear_vid_floor(conference_obj_t *conference
|
|||||||
return SWITCH_STATUS_SUCCESS;
|
return SWITCH_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static switch_status_t conf_api_sub_vid_mute_img(conference_member_t *member, switch_stream_handle_t *stream, void *data)
|
||||||
|
{
|
||||||
|
char *text = (char *) data;
|
||||||
|
mcu_layer_t *layer = NULL;
|
||||||
|
|
||||||
|
if (member == NULL)
|
||||||
|
return SWITCH_STATUS_GENERR;
|
||||||
|
|
||||||
|
if (!switch_channel_test_flag(member->channel, CF_VIDEO)) {
|
||||||
|
return SWITCH_STATUS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch_mutex_lock(member->conference->mutex);
|
||||||
|
|
||||||
|
if (member->video_layer_id == -1 || !member->conference->canvas) {
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
member->video_mute_png = NULL;
|
||||||
|
|
||||||
|
if (text) {
|
||||||
|
switch_img_free(&layer->mute_img);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (text && strcasecmp(text, "clear")) {
|
||||||
|
member->video_mute_png = switch_core_strdup(member->pool, text);
|
||||||
|
layer = &member->conference->canvas->layers[member->video_layer_id];
|
||||||
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
|
|
||||||
|
stream->write_function(stream, "%s\n", member->video_mute_png ? member->video_mute_png : "_undef_");
|
||||||
|
|
||||||
|
switch_mutex_lock(member->conference->mutex);
|
||||||
|
return SWITCH_STATUS_SUCCESS;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
static switch_status_t conf_api_sub_vid_banner(conference_member_t *member, switch_stream_handle_t *stream, void *data)
|
static switch_status_t conf_api_sub_vid_banner(conference_member_t *member, switch_stream_handle_t *stream, void *data)
|
||||||
{
|
{
|
||||||
mcu_layer_t *layer = NULL;
|
mcu_layer_t *layer = NULL;
|
||||||
@ -8097,17 +8329,19 @@ static switch_status_t conf_api_sub_vid_banner(conference_member_t *member, swit
|
|||||||
|
|
||||||
if (!switch_channel_test_flag(member->channel, CF_VIDEO)) {
|
if (!switch_channel_test_flag(member->channel, CF_VIDEO)) {
|
||||||
stream->write_function(stream, "Channel %s does not have video capability!\n", switch_channel_get_name(member->channel));
|
stream->write_function(stream, "Channel %s does not have video capability!\n", switch_channel_get_name(member->channel));
|
||||||
return SWITCH_STATUS_FALSE;
|
return SWITCH_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch_mutex_lock(member->conference->mutex);
|
||||||
|
|
||||||
if (member->video_layer_id == -1 || !member->conference->canvas) {
|
if (member->video_layer_id == -1 || !member->conference->canvas) {
|
||||||
stream->write_function(stream, "Channel %s is not in a video layer\n", switch_channel_get_name(member->channel));
|
stream->write_function(stream, "Channel %s is not in a video layer\n", switch_channel_get_name(member->channel));
|
||||||
return SWITCH_STATUS_FALSE;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (zstr(text)) {
|
if (zstr(text)) {
|
||||||
stream->write_function(stream, "No text supplied\n", switch_channel_get_name(member->channel));
|
stream->write_function(stream, "No text supplied\n", switch_channel_get_name(member->channel));
|
||||||
return SWITCH_STATUS_FALSE;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
layer = &member->conference->canvas->layers[member->video_layer_id];
|
layer = &member->conference->canvas->layers[member->video_layer_id];
|
||||||
@ -8118,6 +8352,10 @@ static switch_status_t conf_api_sub_vid_banner(conference_member_t *member, swit
|
|||||||
|
|
||||||
stream->write_function(stream, "+OK\n");
|
stream->write_function(stream, "+OK\n");
|
||||||
|
|
||||||
|
end:
|
||||||
|
|
||||||
|
switch_mutex_unlock(member->conference->mutex);
|
||||||
|
|
||||||
return SWITCH_STATUS_SUCCESS;
|
return SWITCH_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -9520,6 +9758,10 @@ static api_command_t conf_api_sub_commands[] = {
|
|||||||
{"mute", (void_fn_t) & conf_api_sub_mute, CONF_API_SUB_MEMBER_TARGET, "mute", "<[member_id|all]|last|non_moderator> [<quiet>]"},
|
{"mute", (void_fn_t) & conf_api_sub_mute, CONF_API_SUB_MEMBER_TARGET, "mute", "<[member_id|all]|last|non_moderator> [<quiet>]"},
|
||||||
{"tmute", (void_fn_t) & conf_api_sub_tmute, CONF_API_SUB_MEMBER_TARGET, "tmute", "<[member_id|all]|last|non_moderator> [<quiet>]"},
|
{"tmute", (void_fn_t) & conf_api_sub_tmute, CONF_API_SUB_MEMBER_TARGET, "tmute", "<[member_id|all]|last|non_moderator> [<quiet>]"},
|
||||||
{"unmute", (void_fn_t) & conf_api_sub_unmute, CONF_API_SUB_MEMBER_TARGET, "unmute", "<[member_id|all]|last|non_moderator> [<quiet>]"},
|
{"unmute", (void_fn_t) & conf_api_sub_unmute, CONF_API_SUB_MEMBER_TARGET, "unmute", "<[member_id|all]|last|non_moderator> [<quiet>]"},
|
||||||
|
{"vmute", (void_fn_t) & conf_api_sub_vmute, CONF_API_SUB_MEMBER_TARGET, "vmute", "<[member_id|all]|last|non_moderator> [<quiet>]"},
|
||||||
|
{"tvmute", (void_fn_t) & conf_api_sub_tvmute, CONF_API_SUB_MEMBER_TARGET, "tvmute", "<[member_id|all]|last|non_moderator> [<quiet>]"},
|
||||||
|
{"vmute-snap", (void_fn_t) & conf_api_sub_vmute_snap, CONF_API_SUB_MEMBER_TARGET, "vmute-snap", "<[member_id|all]|last|non_moderator>"},
|
||||||
|
{"unvmute", (void_fn_t) & conf_api_sub_unvmute, CONF_API_SUB_MEMBER_TARGET, "unvmute", "<[member_id|all]|last|non_moderator> [<quiet>]"},
|
||||||
{"deaf", (void_fn_t) & conf_api_sub_deaf, CONF_API_SUB_MEMBER_TARGET, "deaf", "<[member_id|all]|last|non_moderator>"},
|
{"deaf", (void_fn_t) & conf_api_sub_deaf, CONF_API_SUB_MEMBER_TARGET, "deaf", "<[member_id|all]|last|non_moderator>"},
|
||||||
{"undeaf", (void_fn_t) & conf_api_sub_undeaf, CONF_API_SUB_MEMBER_TARGET, "undeaf", "<[member_id|all]|last|non_moderator>"},
|
{"undeaf", (void_fn_t) & conf_api_sub_undeaf, CONF_API_SUB_MEMBER_TARGET, "undeaf", "<[member_id|all]|last|non_moderator>"},
|
||||||
{"relate", (void_fn_t) & conf_api_sub_relate, CONF_API_SUB_ARGS_SPLIT, "relate", "<member_id> <other_member_id> [nospeak|nohear|clear]"},
|
{"relate", (void_fn_t) & conf_api_sub_relate, CONF_API_SUB_ARGS_SPLIT, "relate", "<member_id> <other_member_id> [nospeak|nohear|clear]"},
|
||||||
@ -9545,6 +9787,7 @@ static api_command_t conf_api_sub_commands[] = {
|
|||||||
{"floor", (void_fn_t) & conf_api_sub_floor, CONF_API_SUB_MEMBER_TARGET, "floor", "<member_id|last>"},
|
{"floor", (void_fn_t) & conf_api_sub_floor, CONF_API_SUB_MEMBER_TARGET, "floor", "<member_id|last>"},
|
||||||
{"vid-floor", (void_fn_t) & conf_api_sub_vid_floor, CONF_API_SUB_MEMBER_TARGET, "vid-floor", "<member_id|last> [force]"},
|
{"vid-floor", (void_fn_t) & conf_api_sub_vid_floor, CONF_API_SUB_MEMBER_TARGET, "vid-floor", "<member_id|last> [force]"},
|
||||||
{"vid-banner", (void_fn_t) & conf_api_sub_vid_banner, CONF_API_SUB_MEMBER_TARGET, "vid-banner", "<member_id|last> <text>"},
|
{"vid-banner", (void_fn_t) & conf_api_sub_vid_banner, CONF_API_SUB_MEMBER_TARGET, "vid-banner", "<member_id|last> <text>"},
|
||||||
|
{"vid-mute-img", (void_fn_t) & conf_api_sub_vid_mute_img, CONF_API_SUB_MEMBER_TARGET, "vid-mute-img", "<member_id|last> [<path>|clear]"},
|
||||||
{"clear-vid-floor", (void_fn_t) & conf_api_sub_clear_vid_floor, CONF_API_SUB_ARGS_AS_ONE, "clear-vid-floor", ""},
|
{"clear-vid-floor", (void_fn_t) & conf_api_sub_clear_vid_floor, CONF_API_SUB_ARGS_AS_ONE, "clear-vid-floor", ""},
|
||||||
{"vid-layout", (void_fn_t) & conf_api_sub_vid_layout, CONF_API_SUB_ARGS_SPLIT, "vid-layout", "<layout name>"},
|
{"vid-layout", (void_fn_t) & conf_api_sub_vid_layout, CONF_API_SUB_ARGS_SPLIT, "vid-layout", "<layout name>"},
|
||||||
{"vid-fps", (void_fn_t) & conf_api_sub_vid_fps, CONF_API_SUB_ARGS_SPLIT, "vid-fps", "<fps>"},
|
{"vid-fps", (void_fn_t) & conf_api_sub_vid_fps, CONF_API_SUB_ARGS_SPLIT, "vid-fps", "<fps>"},
|
||||||
@ -10108,7 +10351,7 @@ static void set_mflags(const char *flags, member_flag_t *f)
|
|||||||
char *argv[10] = { 0 };
|
char *argv[10] = { 0 };
|
||||||
int i, argc = 0;
|
int i, argc = 0;
|
||||||
|
|
||||||
*f |= MFLAG_CAN_SPEAK | MFLAG_CAN_HEAR;
|
*f |= MFLAG_CAN_SPEAK | MFLAG_CAN_HEAR | MFLAG_CAN_SEE;
|
||||||
|
|
||||||
for (p = dup; p && *p; p++) {
|
for (p = dup; p && *p; p++) {
|
||||||
if (*p == ',') {
|
if (*p == ',') {
|
||||||
@ -10652,7 +10895,7 @@ SWITCH_STANDARD_APP(conference_function)
|
|||||||
|
|
||||||
/* no conference yet, so check for join-only flag */
|
/* no conference yet, so check for join-only flag */
|
||||||
if (flags_str) {
|
if (flags_str) {
|
||||||
set_mflags(flags_str,&mflags);
|
set_mflags(flags_str, &mflags);
|
||||||
|
|
||||||
if (!(mflags & MFLAG_CAN_SPEAK)) {
|
if (!(mflags & MFLAG_CAN_SPEAK)) {
|
||||||
if (!(mflags & MFLAG_MUTE_DETECT)) {
|
if (!(mflags & MFLAG_MUTE_DETECT)) {
|
||||||
@ -11742,7 +11985,7 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c
|
|||||||
conference->perpetual_sound = switch_core_strdup(conference->pool, perpetual_sound);
|
conference->perpetual_sound = switch_core_strdup(conference->pool, perpetual_sound);
|
||||||
}
|
}
|
||||||
|
|
||||||
conference->mflags = MFLAG_CAN_SPEAK | MFLAG_CAN_HEAR;
|
conference->mflags = MFLAG_CAN_SPEAK | MFLAG_CAN_HEAR | MFLAG_CAN_SEE;
|
||||||
|
|
||||||
if (!zstr(moh_sound) && switch_is_moh(moh_sound)) {
|
if (!zstr(moh_sound) && switch_is_moh(moh_sound)) {
|
||||||
conference->moh_sound = switch_core_strdup(conference->pool, moh_sound);
|
conference->moh_sound = switch_core_strdup(conference->pool, moh_sound);
|
||||||
@ -11890,6 +12133,7 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c
|
|||||||
conference->ivr_input_timeout = ivr_input_timeout;
|
conference->ivr_input_timeout = ivr_input_timeout;
|
||||||
|
|
||||||
conference->eflags = 0xFFFFFFFF;
|
conference->eflags = 0xFFFFFFFF;
|
||||||
|
|
||||||
if (!zstr(suppress_events)) {
|
if (!zstr(suppress_events)) {
|
||||||
clear_eflags(suppress_events, &conference->eflags);
|
clear_eflags(suppress_events, &conference->eflags);
|
||||||
}
|
}
|
||||||
@ -12309,6 +12553,11 @@ static struct _mapping control_mappings[] = {
|
|||||||
{"mute", conference_loop_fn_mute_toggle},
|
{"mute", conference_loop_fn_mute_toggle},
|
||||||
{"mute on", conference_loop_fn_mute_on},
|
{"mute on", conference_loop_fn_mute_on},
|
||||||
{"mute off", conference_loop_fn_mute_off},
|
{"mute off", conference_loop_fn_mute_off},
|
||||||
|
{"vmute", conference_loop_fn_vmute_toggle},
|
||||||
|
{"vmute on", conference_loop_fn_vmute_on},
|
||||||
|
{"vmute off", conference_loop_fn_vmute_off},
|
||||||
|
{"vmute snap", conference_loop_fn_vmute_snap},
|
||||||
|
{"vmute snapoff", conference_loop_fn_vmute_snapoff},
|
||||||
{"deaf mute", conference_loop_fn_deafmute_toggle},
|
{"deaf mute", conference_loop_fn_deafmute_toggle},
|
||||||
{"energy up", conference_loop_fn_energy_up},
|
{"energy up", conference_loop_fn_energy_up},
|
||||||
{"energy equ", conference_loop_fn_energy_equ_conf},
|
{"energy equ", conference_loop_fn_energy_equ_conf},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user