diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c index 67bd073..c3a6638 100644 --- a/src/mod/applications/mod_conference/mod_conference.c +++ b/src/mod/applications/mod_conference/mod_conference.c @@ -156,7 +156,8 @@ typedef enum { MFLAG_INDICATE_UNMUTE = (1 << 18), MFLAG_NOMOH = (1 << 19), MFLAG_VIDEO_BRIDGE = (1 << 20), - MFLAG_INDICATE_MUTE_DETECT = (1 << 21) + MFLAG_INDICATE_MUTE_DETECT = (1 << 21), + MFLAG_PAUSE_RECORDING = (1 << 22) } member_flag_t; typedef enum { @@ -231,6 +232,12 @@ typedef struct conference_file_node { char *file; } conference_file_node_t; +typedef enum { + REC_ACTION_STOP = 1, + REC_ACTION_PAUSE, + REC_ACTION_RESUME +} recording_action_type_t; + /* conference xml config sections */ typedef struct conf_xml_cfg { switch_xml_t profile; @@ -813,6 +820,40 @@ static switch_status_t conference_record_stop(conference_obj_t *conference, char switch_mutex_unlock(conference->member_mutex); return count; } +/* stop/pause/resume the specified recording */ +static switch_status_t conference_record_action(conference_obj_t *conference, char *path, recording_action_type_t action) +{ + conference_member_t *member = NULL; + int count = 0; + //switch_file_handle_t *fh = NULL; + + switch_assert(conference != NULL); + switch_mutex_lock(conference->member_mutex); + for (member = conference->members; member; member = member->next) + { + if (switch_test_flag(member, MFLAG_NOCHANNEL) && (!path || !strcmp(path, member->rec_path))) + { + //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Action: %d\n", action); + switch (action) + { + case REC_ACTION_STOP: + switch_clear_flag_locked(member, MFLAG_RUNNING); + count++; + break; + case REC_ACTION_PAUSE: + switch_set_flag_locked(member, MFLAG_PAUSE_RECORDING); + count = 1; + break; + case REC_ACTION_RESUME: + switch_clear_flag_locked(member, MFLAG_PAUSE_RECORDING); + count = 1; + break; + } + } + } + switch_mutex_unlock(conference->member_mutex); + return count; +} /* Add a custom relationship to a member */ @@ -3310,6 +3351,16 @@ static void *SWITCH_THREAD_FUNC conference_record_thread_run(switch_thread_t *th switch_clear_flag_locked(member, MFLAG_RUNNING); } + if (switch_test_flag(member, MFLAG_PAUSE_RECORDING) && !switch_test_flag((&fh), SWITCH_FILE_PAUSE)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Recording paused: %s\n", member->rec_path); + switch_set_flag((&fh), SWITCH_FILE_PAUSE); + } + + if (!switch_test_flag(member, MFLAG_PAUSE_RECORDING) && switch_test_flag((&fh), SWITCH_FILE_PAUSE)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Recording resumed: %s\n", member->rec_path); + switch_clear_flag((&fh), SWITCH_FILE_PAUSE); + } + loop: switch_core_timer_next(&timer); @@ -5178,6 +5229,47 @@ static switch_status_t conf_api_sub_norecord(conference_obj_t *conference, switc return SWITCH_STATUS_SUCCESS; } +static switch_status_t conf_api_sub_pauserec(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv) +{ + switch_event_t *event; + recording_action_type_t action; + + switch_assert(conference != NULL); + switch_assert(stream != NULL); + + if (argc <= 2) + return SWITCH_STATUS_GENERR; + + if (strcasecmp(argv[1], "pause") == 0) { + action = REC_ACTION_PAUSE; + stream->write_function(stream, "Pause recording file %s\n", argv[2]); + } else if (strcasecmp(argv[1], "resume") == 0) { + action = REC_ACTION_RESUME; + stream->write_function(stream, "Resume recording file %s\n", argv[2]); + } else { + return SWITCH_STATUS_GENERR; + } + + if (!conference_record_action(conference, argv[2], action)) { + stream->write_function(stream, "non-existant recording '%s'\n", argv[2]); + } else { + if (test_eflag(conference, EFLAG_RECORD) && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) + { + conference_add_event_data(conference, event); + if (action == REC_ACTION_PAUSE) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "pause-recording"); + } else { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "resume-recording"); + } + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Path", argv[2]); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Other-Recordings", conference->record_count ? "true" : "false"); + switch_event_fire(&event); + } + } + + return SWITCH_STATUS_SUCCESS; +} + static switch_status_t conf_api_sub_pin(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv) { switch_assert(conference != NULL); @@ -5348,6 +5440,8 @@ static api_command_t conf_api_sub_commands[] = { {"record", (void_fn_t) & conf_api_sub_record, CONF_API_SUB_ARGS_SPLIT, "record", ""}, {"chkrecord", (void_fn_t) & conf_api_sub_check_record, CONF_API_SUB_ARGS_SPLIT, "chkrecord", ""}, {"norecord", (void_fn_t) & conf_api_sub_norecord, CONF_API_SUB_ARGS_SPLIT, "norecord", "<[filename|all]>"}, + {"pause", (void_fn_t) & conf_api_sub_pauserec, CONF_API_SUB_ARGS_SPLIT, "pause", ""}, + {"resume", (void_fn_t) & conf_api_sub_pauserec, CONF_API_SUB_ARGS_SPLIT, "resume", ""}, {"exit_sound", (void_fn_t) & conf_api_sub_exit_sound, CONF_API_SUB_ARGS_SPLIT, "exit_sound", "on|off|none|file "}, {"enter_sound", (void_fn_t) & conf_api_sub_enter_sound, CONF_API_SUB_ARGS_SPLIT, "enter_sound", "on|off|none|file "}, {"pin", (void_fn_t) & conf_api_sub_pin, CONF_API_SUB_ARGS_SPLIT, "pin", ""},