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;
}
{
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;
}
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;
}
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;
}
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;
conference_video_detach_video_layer(member);
- switch_mutex_unlock(member->conference->canvas->mutex);
+ switch_mutex_unlock(member->conference->canvas_mutex);
return SWITCH_STATUS_SUCCESS;
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);
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;
}
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);
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);
*/
#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;
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;
switch_event_t *event;
switch_size_t len = 0;
int flags = 0;
+ mcu_canvas_t *canvas = NULL;
data_buf_len = samples * sizeof(int16_t);
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);
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);
}
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);
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) {
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;
}
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;
}
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;
}
if (!super) {
conference->canvas_count++;
-
- if (!conference->canvas) {
- conference->canvas = canvas;
- }
}
conference->canvases[canvas->canvas_id] = canvas;
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;
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);
}
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);
}
}
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->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) {
- if (conference->fnode->layer_id > -1) {
- conference_video_patch_fnode(canvas, conference->fnode);
- } else {
- conference_video_fnode_check(conference->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);
}
}
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) {
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++) {
}
//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) {
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;
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;
}
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;
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;
}
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;
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);
} 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");
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);
}
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);
}
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;
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;
int video_timer_reset;
switch_queue_t *video_queue;
int32_t video_write_bandwidth;
+ int recording;
} mcu_canvas_t;
/* Record Node */
switch_bool_t autorec;
struct conference_record *next;
switch_file_handle_t fh;
+ int canvas_id;
} conference_record_t;
typedef enum {
char *sound_prefix;
char *special_announce;
char *auto_record;
+ int auto_record_canvas;
char *record_filename;
char *outcall_templ;
char *video_layout_name;
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;
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 *);