factor out conference->canvas and allow per canvas record and play

This commit is contained in:
Anthony Minessale 2015-07-21 16:54:19 -05:00
parent 42274f34cf
commit cbccadaa2f
6 changed files with 130 additions and 69 deletions

View File

@ -403,7 +403,7 @@ switch_status_t conference_api_sub_conference_video_vmute_snap(conference_member
return SWITCH_STATUS_SUCCESS;
}
if (!member->conference->canvas) {
if (!member->conference->canvases[0]) {
stream->write_function(stream, "Conference is not in mixing mode\n");
return SWITCH_STATUS_SUCCESS;
}
@ -1028,7 +1028,7 @@ switch_status_t conference_api_sub_vid_fps(conference_obj_t *conference, switch_
{
float fps = 0;
if (!conference->canvas) {
if (!conference->canvases[0]) {
stream->write_function(stream, "Conference is not in mixing mode\n");
return SWITCH_STATUS_SUCCESS;
}
@ -1091,7 +1091,7 @@ switch_status_t conference_api_sub_vid_layout(conference_obj_t *conference, swit
return SWITCH_STATUS_SUCCESS;
}
if (!conference->canvas) {
if (!conference->canvases[0]) {
stream->write_function(stream, "Conference is not in mixing mode\n");
return SWITCH_STATUS_SUCCESS;
}
@ -1491,7 +1491,7 @@ switch_status_t conference_api_sub_vid_res_id(conference_member_t *member, switc
return SWITCH_STATUS_FALSE;
}
if (!member->conference->canvas) {
if (!member->conference->canvases[0]) {
stream->write_function(stream, "-ERR conference is not in mixing mode\n");
return SWITCH_STATUS_SUCCESS;
}
@ -1501,7 +1501,7 @@ switch_status_t conference_api_sub_vid_res_id(conference_member_t *member, switc
return SWITCH_STATUS_SUCCESS;
}
switch_mutex_lock(member->conference->canvas->mutex);
switch_mutex_lock(member->conference->canvas_mutex);
if (!strcasecmp(text, "clear") || (member->video_reservation_id && !strcasecmp(text, member->video_reservation_id))) {
member->video_reservation_id = NULL;
@ -1513,7 +1513,7 @@ switch_status_t conference_api_sub_vid_res_id(conference_member_t *member, switc
conference_video_detach_video_layer(member);
switch_mutex_unlock(member->conference->canvas->mutex);
switch_mutex_unlock(member->conference->canvas_mutex);
return SWITCH_STATUS_SUCCESS;
@ -2266,6 +2266,8 @@ switch_status_t conference_api_sub_check_record(conference_obj_t *conference, sw
switch_status_t conference_api_sub_record(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv)
{
int id = 0;
switch_assert(conference != NULL);
switch_assert(stream != NULL);
@ -2273,10 +2275,33 @@ switch_status_t conference_api_sub_record(conference_obj_t *conference, switch_s
return SWITCH_STATUS_GENERR;
}
stream->write_function(stream, "Record file %s\n", argv[2]);
if (argv[3]) {
if (argv[3]) {
id = atoi(argv[3]);
}
if (id < 1 || id > MAX_CANVASES+1) {
id = -1;
}
if (id < 1) {
stream->write_function(stream, "-ERR Invalid canvas\n");
}
}
if (id == 0 && conference->canvases[0]) id = 1;
if (id > 0) {
stream->write_function(stream, "Record file %s canvas %d\n", argv[2], id);
} else {
stream->write_function(stream, "Record file %s\n", argv[2]);
}
conference->record_filename = switch_core_strdup(conference->pool, argv[2]);
conference->record_count++;
conference_record_launch_thread(conference, argv[2], SWITCH_FALSE);
conference_record_launch_thread(conference, argv[2], id - 1, SWITCH_FALSE);
return SWITCH_STATUS_SUCCESS;
}

View File

@ -86,11 +86,11 @@ switch_status_t conference_file_close(conference_obj_t *conference, conference_f
conference_al_close(node->al);
}
#endif
if (switch_core_file_has_video(&node->fh) && conference->canvas) {
conference->canvas->timer.interval = conference->video_fps.ms;
conference->canvas->timer.samples = conference->video_fps.samples;
switch_core_timer_sync(&conference->canvas->timer);
conference->canvas->send_keyframe = 1;
if (switch_core_file_has_video(&node->fh) && conference->canvases[0] && node->canvas_id > -1) {
conference->canvases[node->canvas_id]->timer.interval = conference->video_fps.ms;
conference->canvases[node->canvas_id]->timer.samples = conference->video_fps.samples;
switch_core_timer_sync(&conference->canvases[node->canvas_id]->timer);
conference->canvases[node->canvas_id]->send_keyframe = 1;
conference->playing_video_file = 0;
}
return switch_core_file_close(&node->fh);
@ -265,6 +265,16 @@ switch_status_t conference_file_play(conference_obj_t *conference, char *file, u
if (fnode->fh.params) {
const char *vol = switch_event_get_header(fnode->fh.params, "vol");
const char *position = switch_event_get_header(fnode->fh.params, "position");
const char *canvasstr = switch_event_get_header(fnode->fh.params, "canvas");
int canvas_id = -1;
if (canvasstr) {
canvas_id = atoi(canvasstr) - 1;
}
if (canvas_id > -1 && canvas_id < MAX_CANVASES) {
fnode->canvas_id = canvas_id;
}
if (!zstr(vol)) {
fnode->fh.vol = atoi(vol);

View File

@ -41,7 +41,7 @@
*/
#include <mod_conference.h>
void conference_record_launch_thread(conference_obj_t *conference, char *path, switch_bool_t autorec)
void conference_record_launch_thread(conference_obj_t *conference, char *path, int canvas_id, switch_bool_t autorec)
{
switch_thread_t *thread;
switch_threadattr_t *thd_attr = NULL;
@ -65,6 +65,10 @@ void conference_record_launch_thread(conference_obj_t *conference, char *path, s
rec->pool = pool;
rec->autorec = autorec;
if (canvas_id > -1) {
rec->canvas_id = canvas_id;
}
switch_mutex_lock(conference->flag_mutex);
rec->next = conference->rec_node_head;
conference->rec_node_head = rec;
@ -157,6 +161,7 @@ void *SWITCH_THREAD_FUNC conference_record_thread_run(switch_thread_t *thread, v
switch_event_t *event;
switch_size_t len = 0;
int flags = 0;
mcu_canvas_t *canvas = NULL;
data_buf_len = samples * sizeof(int16_t);
@ -187,11 +192,16 @@ void *SWITCH_THREAD_FUNC conference_record_thread_run(switch_thread_t *thread, v
member->rec->fh.samplerate = conference->rate;
member->id = next_member_id();
member->pool = rec->pool;
member->frame_size = SWITCH_RECOMMENDED_BUFFER_SIZE;
member->frame = switch_core_alloc(member->pool, member->frame_size);
member->mux_frame = switch_core_alloc(member->pool, member->frame_size);
if (conference->canvases[0]) {
member->canvas_id = rec->canvas_id;
canvas = conference->canvases[member->canvas_id];
canvas->recording++;
canvas->send_keyframe = 1;
}
switch_mutex_init(&member->write_mutex, SWITCH_MUTEX_NESTED, rec->pool);
switch_mutex_init(&member->flag_mutex, SWITCH_MUTEX_NESTED, rec->pool);
@ -213,23 +223,19 @@ void *SWITCH_THREAD_FUNC conference_record_thread_run(switch_thread_t *thread, v
goto end;
}
if (conference->canvas) {
conference->canvas->send_keyframe = 1;
}
member->rec->fh.pre_buffer_datalen = SWITCH_DEFAULT_FILE_BUFFER_LEN;
flags = SWITCH_FILE_FLAG_WRITE | SWITCH_FILE_DATA_SHORT;
if (conference->members_with_video && conference_utils_test_flag(conference, CFLAG_TRANSCODE_VIDEO)) {
flags |= SWITCH_FILE_FLAG_VIDEO;
if (conference->canvas) {
if (canvas) {
char *orig_path = rec->path;
rec->path = switch_core_sprintf(rec->pool, "{channels=%d,samplerate=%d,vw=%d,vh=%d,fps=%0.2f}%s",
conference->channels,
conference->rate,
conference->canvas->width,
conference->canvas->height,
canvas->width,
canvas->height,
conference->video_fps.fps,
orig_path);
}
@ -365,8 +371,8 @@ void *SWITCH_THREAD_FUNC conference_record_thread_run(switch_thread_t *thread, v
switch_core_timer_destroy(&timer);
conference_member_del(conference, member);
if (conference->canvas) {
conference->canvas->send_keyframe = 1;
if (canvas) {
canvas->send_keyframe = 1;
}
switch_buffer_destroy(&member->audio_buffer);
@ -392,6 +398,10 @@ void *SWITCH_THREAD_FUNC conference_record_thread_run(switch_thread_t *thread, v
conference->auto_recording--;
}
if (canvas) {
canvas->recording--;
}
switch_mutex_lock(conference->flag_mutex);
for (rp = conference->rec_node_head; rp; rp = rp->next) {
if (rec == rp) {

View File

@ -662,8 +662,8 @@ void conference_video_layer_set_logo(conference_member_t *member, mcu_layer_t *l
switch_img_free(&layer->banner_img);
layer->banner_patched = 0;
switch_img_fill(member->conference->canvas->img, layer->x_pos, layer->y_pos, layer->screen_w, layer->screen_h,
&member->conference->canvas->letterbox_bgcolor);
switch_img_fill(layer->canvas->img, layer->x_pos, layer->y_pos, layer->screen_w, layer->screen_h,
&layer->canvas->letterbox_bgcolor);
goto end;
}
@ -745,8 +745,8 @@ void conference_video_layer_set_banner(conference_member_t *member, mcu_layer_t
switch_img_free(&layer->banner_img);
layer->banner_patched = 0;
switch_img_fill(member->conference->canvas->img, layer->x_pos, layer->y_pos, layer->screen_w, layer->screen_h,
&member->conference->canvas->letterbox_bgcolor);
switch_img_fill(layer->canvas->img, layer->x_pos, layer->y_pos, layer->screen_w, layer->screen_h,
&layer->canvas->letterbox_bgcolor);
goto end;
}
@ -796,8 +796,8 @@ void conference_video_layer_set_banner(conference_member_t *member, mcu_layer_t
switch_img_free(&layer->banner_img);
layer->banner_patched = 0;
switch_img_fill(member->conference->canvas->img, layer->x_pos, layer->y_pos, layer->screen_w, layer->screen_h,
&member->conference->canvas->letterbox_bgcolor);
switch_img_fill(layer->canvas->img, layer->x_pos, layer->y_pos, layer->screen_w, layer->screen_h,
&layer->canvas->letterbox_bgcolor);
goto end;
}
@ -1018,10 +1018,6 @@ switch_status_t conference_video_attach_canvas(conference_obj_t *conference, mcu
if (!super) {
conference->canvas_count++;
if (!conference->canvas) {
conference->canvas = canvas;
}
}
conference->canvases[canvas->canvas_id] = canvas;
@ -1393,7 +1389,7 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_write_thread_run(switch_thread_
return NULL;
}
void conference_video_check_recording(conference_obj_t *conference, switch_frame_t *frame)
void conference_video_check_recording(conference_obj_t *conference, mcu_canvas_t *canvas, switch_frame_t *frame)
{
conference_member_t *imember;
@ -1407,6 +1403,11 @@ void conference_video_check_recording(conference_obj_t *conference, switch_frame
if (!imember->rec) {
continue;
}
if (canvas && imember->canvas_id != canvas->canvas_id) {
continue;
}
if (switch_test_flag((&imember->rec->fh), SWITCH_FILE_OPEN) && switch_core_file_has_video(&imember->rec->fh)) {
switch_core_file_write_video(&imember->rec->fh, frame);
}
@ -1775,7 +1776,7 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr
if (conference->video_layout_group && (lg = switch_core_hash_find(conference->layout_group_hash, conference->video_layout_group))) {
if ((vlayout = conference_video_find_best_layout(conference, lg, canvas_count))) {
switch_mutex_lock(conference->member_mutex);
conference->canvas->new_vlayout = vlayout;
canvas->new_vlayout = vlayout;
switch_mutex_unlock(conference->member_mutex);
}
}
@ -2230,21 +2231,20 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr
switch_mutex_unlock(conference->member_mutex);
} else {
if (canvas->canvas_id == 0) {
if (conference->async_fnode) {
if (conference->async_fnode->layer_id > -1) {
conference_video_patch_fnode(canvas, conference->async_fnode);
} else {
conference_video_fnode_check(conference->async_fnode);
}
}
if (conference->fnode) {
if (conference->fnode->layer_id > -1) {
conference_video_patch_fnode(canvas, conference->fnode);
} else {
conference_video_fnode_check(conference->fnode);
}
if (conference->async_fnode && conference->async_fnode->canvas_id == canvas->canvas_id) {
if (conference->async_fnode->layer_id > -1) {
conference_video_patch_fnode(canvas, conference->async_fnode);
} else {
conference_video_fnode_check(conference->async_fnode);
}
}
if (conference->fnode && conference->fnode->canvas_id == canvas->canvas_id) {
if (conference->fnode->layer_id > -1) {
conference_video_patch_fnode(canvas, conference->fnode);
} else {
conference_video_fnode_check(conference->fnode);
}
}
@ -2312,8 +2312,8 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr
write_frame.img = write_img;
if (conference->canvas_count == 1) {
conference_video_check_recording(conference, &write_frame);
if (canvas->recording) {
conference_video_check_recording(conference, canvas, &write_frame);
}
if (conference->canvas_count > 1) {
@ -2660,7 +2660,10 @@ void *SWITCH_THREAD_FUNC conference_video_super_muxing_thread_run(switch_thread_
if (!write_img) continue;
write_frame.img = write_img;
conference_video_check_recording(conference, &write_frame);
if (canvas->recording) {
conference_video_check_recording(conference, canvas, &write_frame);
}
if (min_members && conference_utils_test_flag(conference, CFLAG_MINIMIZE_VIDEO_ENCODING)) {
for (i = 0; write_codecs[i] && switch_core_codec_ready(&write_codecs[i]->codec) && i < MAX_MUX_CODECS; i++) {
@ -2867,8 +2870,8 @@ void conference_video_set_floor_holder(conference_obj_t *conference, conference_
}
//VIDFLOOR
if (conference->canvas_count == 1 && member && conference->canvas && conference->canvas->layout_floor_id > -1) {
conference_video_attach_video_layer(member, conference->canvas, conference->canvas->layout_floor_id);
if (conference->canvas_count == 1 && member && conference->canvases[0] && conference->canvases[0]->layout_floor_id > -1) {
conference_video_attach_video_layer(member, conference->canvases[0], conference->canvases[0]->layout_floor_id);
}
if (member) {
@ -2943,14 +2946,14 @@ void conference_video_write_frame(conference_obj_t *conference, conference_membe
conference_utils_clear_flag(conference, CFLAG_FLOOR_CHANGE);
}
if (vid_frame->img && conference->canvas) {
if (vid_frame->img && conference->canvases[0]) {
switch_image_t *frame_img = NULL, *tmp_img = NULL;
int x,y;
switch_img_copy(vid_frame->img, &tmp_img);
switch_img_fit(&tmp_img, conference->canvas->width, conference->canvas->height);
frame_img = switch_img_alloc(NULL, SWITCH_IMG_FMT_I420, conference->canvas->width, conference->canvas->height, 1);
conference_video_reset_image(frame_img, &conference->canvas->bgcolor);
switch_img_fit(&tmp_img, conference->canvases[0]->width, conference->canvases[0]->height);
frame_img = switch_img_alloc(NULL, SWITCH_IMG_FMT_I420, conference->canvases[0]->width, conference->canvases[0]->height, 1);
conference_video_reset_image(frame_img, &conference->canvases[0]->bgcolor);
switch_img_find_position(POS_CENTER_MID, frame_img->d_w, frame_img->d_h, tmp_img->d_w, tmp_img->d_h, &x, &y);
switch_img_patch(frame_img, tmp_img, x, y);
tmp_frame.packet = buf;
@ -2976,7 +2979,7 @@ void conference_video_write_frame(conference_obj_t *conference, conference_membe
if (isession && switch_channel_test_flag(imember->channel, CF_VIDEO)) {
int send_frame = 0;
if (conference->canvas && conference_utils_test_flag(imember->conference, CFLAG_VIDEO_BRIDGE_FIRST_TWO)) {
if (conference->canvases[0] && conference_utils_test_flag(imember->conference, CFLAG_VIDEO_BRIDGE_FIRST_TWO)) {
if (switch_channel_test_flag(imember->channel, CF_VIDEO) && (conference->members_with_video == 1 || imember != floor_holder)) {
send_frame = 1;
}
@ -2988,7 +2991,7 @@ void conference_video_write_frame(conference_obj_t *conference, conference_membe
if (send_frame) {
if (vid_frame->img) {
if (conference->canvas) {
if (conference->canvases[0]) {
tmp_frame.packet = buf;
tmp_frame.packetlen = sizeof(buf) - 12;
tmp_frame.data = buf + 12;
@ -3042,7 +3045,7 @@ switch_status_t conference_video_thread_callback(switch_core_session_t *session,
if (conference_utils_test_flag(member->conference, CFLAG_VIDEO_BRIDGE_FIRST_TWO)) {
if (member->conference->members_with_video < 3) {
conference_video_write_frame(member->conference, member, frame);
conference_video_check_recording(member->conference, frame);
conference_video_check_recording(member->conference, NULL, frame);
switch_thread_rwlock_unlock(member->conference->rwlock);
return SWITCH_STATUS_SUCCESS;
}
@ -3091,7 +3094,7 @@ switch_status_t conference_video_thread_callback(switch_core_session_t *session,
if (member) {
if (member->id == member->conference->video_floor_holder) {
conference_video_write_frame(member->conference, member, frame);
conference_video_check_recording(member->conference, frame);
conference_video_check_recording(member->conference, NULL, frame);
} else if (!conference_utils_test_flag(member->conference, CFLAG_VID_FLOOR_LOCK) && member->id == member->conference->last_video_floor_holder) {
conference_member_t *fmember;

View File

@ -357,8 +357,9 @@ void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, void *ob
if (imember) {
switch_channel_t *channel = switch_core_session_get_channel(imember->session);
char *rfile = switch_channel_expand_variables(channel, conference->auto_record);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Auto recording file: %s\n", rfile);
conference_record_launch_thread(conference, rfile, SWITCH_TRUE);
conference_record_launch_thread(conference, rfile, -1, SWITCH_TRUE);
if (rfile != conference->auto_record) {
conference->record_filename = switch_core_strdup(conference->pool, rfile);
@ -366,11 +367,13 @@ void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, void *ob
} else {
conference->record_filename = switch_core_strdup(conference->pool, conference->auto_record);
}
/* Set the conference recording variable for each member */
for (omember = conference->members; omember; omember = omember->next) {
if (!omember->session) continue;
channel = switch_core_session_get_channel(omember->session);
switch_channel_set_variable(channel, "conference_recording", conference->record_filename);
switch_channel_set_variable_printf(channel, "conference_recording_canvas", "%d", conference->auto_record_canvas + 1);
}
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Auto Record Failed. No members in conference.\n");
@ -620,7 +623,7 @@ void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, void *ob
if (conference->async_fnode && conference->async_fnode->done) {
switch_memory_pool_t *pool;
if (conference->canvas && conference->async_fnode->layer_id > -1 ) {
if (conference->canvases[0] && conference->async_fnode->layer_id > -1 ) {
conference_video_canvas_del_fnode_layer(conference, conference->async_fnode);
}
@ -634,7 +637,7 @@ void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, void *ob
conference_file_node_t *fnode;
switch_memory_pool_t *pool;
if (conference->canvas && conference->fnode->layer_id > -1 ) {
if (conference->canvases[0] && conference->fnode->layer_id > -1 ) {
conference_video_canvas_del_fnode_layer(conference, conference->fnode);
}
@ -2404,6 +2407,7 @@ conference_obj_t *conference_new(char *name, conference_xml_cfg_t cfg, switch_co
char *suppress_events = NULL;
char *verbose_events = NULL;
char *auto_record = NULL;
int auto_record_canvas = 0;
int min_recording_participants = 1;
char *conference_log_dir = NULL;
char *cdr_event_mode = NULL;
@ -2678,6 +2682,13 @@ conference_obj_t *conference_new(char *name, conference_xml_cfg_t cfg, switch_co
verbose_events = val;
} else if (!strcasecmp(var, "auto-record") && !zstr(val)) {
auto_record = val;
} else if (!strcasecmp(var, "auto-record-canvas-id") && !zstr(val)) {
auto_record_canvas = atoi(val);
if (auto_record_canvas) {
auto_record_canvas--;
if (auto_record_canvas < 1) auto_record_canvas = 0;
}
} else if (!strcasecmp(var, "min-required-recording-participants") && !zstr(val)) {
if (!strcmp(val, "1")) {
min_recording_participants = 1;

View File

@ -490,6 +490,7 @@ typedef struct mcu_canvas_s {
int video_timer_reset;
switch_queue_t *video_queue;
int32_t video_write_bandwidth;
int recording;
} mcu_canvas_t;
/* Record Node */
@ -500,6 +501,7 @@ typedef struct conference_record {
switch_bool_t autorec;
struct conference_record *next;
switch_file_handle_t fh;
int canvas_id;
} conference_record_t;
typedef enum {
@ -536,6 +538,7 @@ typedef struct conference_obj {
char *sound_prefix;
char *special_announce;
char *auto_record;
int auto_record_canvas;
char *record_filename;
char *outcall_templ;
char *video_layout_name;
@ -630,7 +633,6 @@ typedef struct conference_obj {
struct vid_helper mh;
conference_record_t *rec_node_head;
int last_speech_channels;
mcu_canvas_t *canvas;
mcu_canvas_t *canvases[MAX_CANVASES+1];
int canvas_count;
int super_canvas_label_layers;
@ -982,7 +984,7 @@ conference_obj_t *conference_new(char *name, conference_xml_cfg_t cfg, switch_co
switch_status_t chat_send(switch_event_t *message_event);
void conference_record_launch_thread(conference_obj_t *conference, char *path, switch_bool_t autorec);
void conference_record_launch_thread(conference_obj_t *conference, char *path, int canvas_id, switch_bool_t autorec);
typedef switch_status_t (*conference_api_args_cmd_t) (conference_obj_t *, switch_stream_handle_t *, int, char **);
typedef switch_status_t (*conference_api_member_cmd_t) (conference_member_t *, switch_stream_handle_t *, void *);