diff --git a/src/include/switch_core.h b/src/include/switch_core.h index 0168c50228..20ed1e355c 100644 --- a/src/include/switch_core.h +++ b/src/include/switch_core.h @@ -196,6 +196,8 @@ SWITCH_DECLARE(void) switch_core_media_bug_set_read_replace_frame(_In_ switch_me */ SWITCH_DECLARE(switch_status_t) switch_core_media_bug_remove(_In_ switch_core_session_t *session, _Inout_ switch_media_bug_t **bug); +SWITCH_DECLARE(switch_status_t) switch_core_media_bug_remove_callback(switch_core_session_t *session, switch_media_bug_callback_t callback); + /*! \brief Close and destroy a media bug \param bug bug to remove diff --git a/src/switch_core_media_bug.c b/src/switch_core_media_bug.c index a8d8ec5e36..d339aa9e6a 100644 --- a/src/switch_core_media_bug.c +++ b/src/switch_core_media_bug.c @@ -370,15 +370,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_bug_remove(switch_core_session if (session->bugs) { switch_thread_rwlock_wrlock(session->bug_rwlock); for (bp = session->bugs; bp; bp = bp->next) { - if (bp->thread_id && bp->thread_id != switch_thread_self()) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "BUG is thread locked skipping.\n"); - continue; - } - - if (!bp->ready) { - continue; - } - if (bp == *bug) { + if ((!bp->thread_id || bp->thread_id == switch_thread_self()) && bp->ready && bp == *bug) { if (last) { last->next = bp->next; } else { @@ -386,6 +378,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_bug_remove(switch_core_session } break; } + last = bp; } switch_thread_rwlock_unlock(session->bug_rwlock); @@ -402,6 +395,44 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_bug_remove(switch_core_session return status; } + +SWITCH_DECLARE(switch_status_t) switch_core_media_bug_remove_callback(switch_core_session_t *session, switch_media_bug_callback_t callback) +{ + switch_media_bug_t *cur = NULL, *bp = NULL, *last = NULL; + int total = 0; + + if (session->bugs) { + switch_thread_rwlock_wrlock(session->bug_rwlock); + + bp = session->bugs; + while (bp) { + cur = bp; + bp = bp->next; + + if ((!cur->thread_id || cur->thread_id == switch_thread_self()) && cur->ready && cur->callback == callback) { + if (last) { + last->next = cur->next; + } else { + session->bugs = cur->next; + } + if (switch_core_media_bug_close(&cur) == SWITCH_STATUS_SUCCESS) { + total++; + } + } else { + last = cur; + } + } + switch_thread_rwlock_unlock(session->bug_rwlock); + } + + if (!session->bugs && session->bug_codec.implementation) { + switch_core_codec_destroy(&session->bug_codec); + memset(&session->bug_codec, 0, sizeof(session->bug_codec)); + } + + return total ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE; +} + /* For Emacs: * Local Variables: * mode:c diff --git a/src/switch_ivr_async.c b/src/switch_ivr_async.c index 82bec090e8..881413c35b 100644 --- a/src/switch_ivr_async.c +++ b/src/switch_ivr_async.c @@ -424,23 +424,31 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_displace_session(switch_core_session_ return SWITCH_STATUS_SUCCESS; } +struct record_helper { + char *file; + switch_file_handle_t *fh; +}; + static switch_bool_t record_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type) { - switch_file_handle_t *fh = (switch_file_handle_t *) user_data; + switch_core_session_t *session = switch_core_media_bug_get_session(bug); + switch_channel_t *channel = switch_core_session_get_channel(session); + struct record_helper *rh = (struct record_helper *) user_data; switch (type) { case SWITCH_ABC_TYPE_INIT: break; case SWITCH_ABC_TYPE_CLOSE: - if (fh) { - switch_core_file_close(fh); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Stop recording file %s\n", rh->file); + switch_channel_set_private(channel, rh->file, NULL); + + if (rh->fh) { + switch_core_file_close(rh->fh); } break; case SWITCH_ABC_TYPE_READ_PING: - if (fh) { + if (rh->fh) { switch_size_t len; - switch_core_session_t *session = switch_core_media_bug_get_session(bug); - switch_channel_t *channel = switch_core_session_get_channel(session); uint8_t data[SWITCH_RECOMMENDED_BUFFER_SIZE]; switch_frame_t frame = { 0 }; @@ -455,7 +463,7 @@ static switch_bool_t record_callback(switch_media_bug_t *bug, void *user_data, s if (doit) { len = (switch_size_t) frame.datalen / 2; - switch_core_file_write(fh, data, &len); + switch_core_file_write(rh->fh, data, &len); } } } @@ -473,8 +481,9 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_stop_record_session(switch_core_sessi switch_media_bug_t *bug; switch_channel_t *channel = switch_core_session_get_channel(session); - if ((bug = switch_channel_get_private(channel, file))) { - switch_channel_set_private(channel, file, NULL); + if (!strcasecmp(file, "all")) { + return switch_core_media_bug_remove_callback(session, record_callback); + } else if ((bug = switch_channel_get_private(channel, file))) { switch_core_media_bug_remove(session, &bug); return SWITCH_STATUS_SUCCESS; } @@ -838,6 +847,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session(switch_core_session_t switch_media_bug_flag_t flags = SMBF_READ_STREAM | SMBF_WRITE_STREAM | SMBF_READ_PING; uint8_t channels; switch_codec_implementation_t read_impl = {0}; + struct record_helper *rh = NULL; + switch_core_session_get_read_impl(session, &read_impl); if ((status = switch_channel_pre_answer(channel)) != SWITCH_STATUS_SUCCESS) { @@ -925,7 +936,11 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session(switch_core_session_t to = switch_epoch_time_now(NULL) + limit; } - if ((status = switch_core_media_bug_add(session, record_callback, fh, to, flags, &bug)) != SWITCH_STATUS_SUCCESS) { + rh = switch_core_session_alloc(session, sizeof(*rh)); + rh->fh = fh; + rh->file = switch_core_session_strdup(session, file); + + if ((status = switch_core_media_bug_add(session, record_callback, rh, to, flags, &bug)) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error adding media bug for file %s\n", file); switch_core_file_close(fh); return status;