diff --git a/src/include/private/switch_core_pvt.h b/src/include/private/switch_core_pvt.h index e4e8dc7c6f..60240e646d 100644 --- a/src/include/private/switch_core_pvt.h +++ b/src/include/private/switch_core_pvt.h @@ -184,6 +184,8 @@ struct switch_media_bug { switch_frame_t *read_replace_frame_out; switch_frame_t *write_replace_frame_in; switch_frame_t *write_replace_frame_out; + switch_frame_t *native_read_frame; + switch_frame_t *native_write_frame; switch_media_bug_callback_t callback; switch_mutex_t *read_mutex; switch_mutex_t *write_mutex; diff --git a/src/include/switch_core.h b/src/include/switch_core.h index e3f5634ce4..3383b67bc0 100644 --- a/src/include/switch_core.h +++ b/src/include/switch_core.h @@ -203,6 +203,11 @@ SWITCH_DECLARE(void *) switch_core_media_bug_get_user_data(_In_ switch_media_bug */ SWITCH_DECLARE(switch_frame_t *) switch_core_media_bug_get_write_replace_frame(_In_ switch_media_bug_t *bug); + +SWITCH_DECLARE(switch_frame_t *) switch_core_media_bug_get_native_read_frame(switch_media_bug_t *bug); +SWITCH_DECLARE(switch_frame_t *) switch_core_media_bug_get_native_write_frame(switch_media_bug_t *bug); + + /*! \brief Set a return replace frame \param bug the bug to set the frame on diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 5fa7c158f0..2c8b9503cf 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -443,6 +443,8 @@ typedef enum { SWITCH_ABC_TYPE_WRITE_REPLACE, SWITCH_ABC_TYPE_READ_REPLACE, SWITCH_ABC_TYPE_READ_PING, + SWITCH_ABC_TYPE_TAP_NATIVE_READ, + SWITCH_ABC_TYPE_TAP_NATIVE_WRITE, SWITCH_ABC_TYPE_CLOSE } switch_abc_type_t; @@ -1498,7 +1500,9 @@ typedef enum { SMBF_PRUNE = (1 << 8), SMBF_NO_PAUSE = (1 << 9), SMBF_STEREO_SWAP = (1 << 10), - SMBF_LOCK = (1 << 11) + SMBF_LOCK = (1 << 11), + SMBF_TAP_NATIVE_READ = (1 << 12), + SMBF_TAP_NATIVE_WRITE = (1 << 13) } switch_media_bug_flag_enum_t; typedef uint32_t switch_media_bug_flag_t; diff --git a/src/switch_core_io.c b/src/switch_core_io.c index effb500e04..22e0cc811d 100644 --- a/src/switch_core_io.c +++ b/src/switch_core_io.c @@ -221,7 +221,6 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi status = SWITCH_STATUS_FALSE; goto even_more_done; } - } if (status != SWITCH_STATUS_SUCCESS) { @@ -247,6 +246,49 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi goto done; } + + if (session->bugs && !((*frame)->flags & SFF_NOT_AUDIO) && !((*frame)->flags & SFF_CNG)) { + switch_media_bug_t *bp; + switch_bool_t ok = SWITCH_TRUE; + int prune = 0; + + switch_thread_rwlock_rdlock(session->bug_rwlock); + + for (bp = session->bugs; bp; bp = bp->next) { + if (switch_channel_test_flag(session->channel, CF_PAUSE_BUGS) && !switch_core_media_bug_test_flag(bp, SMBF_NO_PAUSE)) { + continue; + } + + if (!switch_channel_test_flag(session->channel, CF_ANSWERED) && switch_core_media_bug_test_flag(bp, SMBF_ANSWER_REQ)) { + continue; + } + if (switch_test_flag(bp, SMBF_PRUNE)) { + prune++; + continue; + } + + if (bp->ready) { + if (switch_test_flag(bp, SMBF_TAP_NATIVE_READ)) { + if (bp->callback) { + bp->native_read_frame = *frame; + ok = bp->callback(bp, bp->user_data, SWITCH_ABC_TYPE_TAP_NATIVE_READ); + bp->native_read_frame = NULL; + } + } + } + + if ((bp->stop_time && bp->stop_time <= switch_epoch_time_now(NULL)) || ok == SWITCH_FALSE) { + switch_set_flag(bp, SMBF_PRUNE); + prune++; + } + } + switch_thread_rwlock_unlock(session->bug_rwlock); + + if (prune) { + switch_core_media_bug_prune(session); + } + } + codec_impl = *(*frame)->codec->implementation; if (session->read_codec->implementation->impl_id != codec_impl.impl_id) { @@ -257,11 +299,6 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi do_resample = 1; } - if (session->bugs && !need_codec) { - do_bugs = 1; - need_codec = 1; - } - if (switch_test_flag(*frame, SFF_CNG)) { if (!session->bugs && !session->plc) { /* Check if other session has bugs */ @@ -769,6 +806,50 @@ static switch_status_t perform_write(switch_core_session_t *session, switch_fram switch_io_event_hook_write_frame_t *ptr; switch_status_t status = SWITCH_STATUS_FALSE; + + if (session->bugs && !(frame->flags & SFF_NOT_AUDIO)) { + switch_media_bug_t *bp; + switch_bool_t ok = SWITCH_TRUE; + int prune = 0; + + switch_thread_rwlock_rdlock(session->bug_rwlock); + + for (bp = session->bugs; bp; bp = bp->next) { + if (switch_channel_test_flag(session->channel, CF_PAUSE_BUGS) && !switch_core_media_bug_test_flag(bp, SMBF_NO_PAUSE)) { + continue; + } + + if (!switch_channel_test_flag(session->channel, CF_ANSWERED) && switch_core_media_bug_test_flag(bp, SMBF_ANSWER_REQ)) { + continue; + } + if (switch_test_flag(bp, SMBF_PRUNE)) { + prune++; + continue; + } + + if (bp->ready) { + if (switch_test_flag(bp, SMBF_TAP_NATIVE_WRITE)) { + if (bp->callback) { + bp->native_write_frame = frame; + ok = bp->callback(bp, bp->user_data, SWITCH_ABC_TYPE_TAP_NATIVE_WRITE); + bp->native_write_frame = NULL; + } + } + } + + if ((bp->stop_time && bp->stop_time <= switch_epoch_time_now(NULL)) || ok == SWITCH_FALSE) { + switch_set_flag(bp, SMBF_PRUNE); + prune++; + } + } + switch_thread_rwlock_unlock(session->bug_rwlock); + + if (prune) { + switch_core_media_bug_prune(session); + } + } + + if (session->endpoint_interface->io_routines->write_frame) { if ((status = session->endpoint_interface->io_routines->write_frame(session, frame, flags, stream_id)) == SWITCH_STATUS_SUCCESS) { @@ -872,11 +953,6 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_sess need_codec = TRUE; } - if (session->bugs && !need_codec) { - do_bugs = TRUE; - need_codec = TRUE; - } - if (frame->codec->implementation->actual_samples_per_second != session->write_impl.actual_samples_per_second) { need_codec = TRUE; do_resample = TRUE; diff --git a/src/switch_core_media_bug.c b/src/switch_core_media_bug.c index 7beb048155..938d9b5996 100644 --- a/src/switch_core_media_bug.c +++ b/src/switch_core_media_bug.c @@ -103,6 +103,16 @@ SWITCH_DECLARE(switch_frame_t *) switch_core_media_bug_get_read_replace_frame(sw return bug->read_replace_frame_in; } +SWITCH_DECLARE(switch_frame_t *) switch_core_media_bug_get_native_read_frame(switch_media_bug_t *bug) +{ + return bug->native_read_frame; +} + +SWITCH_DECLARE(switch_frame_t *) switch_core_media_bug_get_native_write_frame(switch_media_bug_t *bug) +{ + return bug->native_write_frame; +} + SWITCH_DECLARE(void) switch_core_media_bug_set_read_replace_frame(switch_media_bug_t *bug, switch_frame_t *frame) { bug->read_replace_frame_out = frame; diff --git a/src/switch_ivr_async.c b/src/switch_ivr_async.c index 80d945f875..8b1ce552d4 100644 --- a/src/switch_ivr_async.c +++ b/src/switch_ivr_async.c @@ -1078,6 +1078,9 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_displace_session(switch_core_session_ struct record_helper { char *file; switch_file_handle_t *fh; + switch_file_handle_t in_fh; + switch_file_handle_t out_fh; + int native; uint32_t packet_len; int min_sec; switch_bool_t hangup_on_error; @@ -1089,7 +1092,8 @@ static switch_bool_t record_callback(switch_media_bug_t *bug, void *user_data, s switch_channel_t *channel = switch_core_session_get_channel(session); struct record_helper *rh = (struct record_helper *) user_data; switch_event_t *event; - + switch_frame_t *nframe; + switch_size_t len; switch (type) { case SWITCH_ABC_TYPE_INIT: @@ -1099,6 +1103,22 @@ static switch_bool_t record_callback(switch_media_bug_t *bug, void *user_data, s switch_event_fire(&event); } + break; + case SWITCH_ABC_TYPE_TAP_NATIVE_READ: + { + nframe = switch_core_media_bug_get_native_read_frame(bug); + len = nframe->datalen; + printf("WRITE IN %d\n", nframe->datalen); + switch_core_file_write(&rh->in_fh, nframe->data, &len); + } + break; + case SWITCH_ABC_TYPE_TAP_NATIVE_WRITE: + { + nframe = switch_core_media_bug_get_native_write_frame(bug); + printf("WRITE OUT %d\n", nframe->datalen); + len = nframe->datalen; + switch_core_file_write(&rh->out_fh, nframe->data, &len); + } break; case SWITCH_ABC_TYPE_CLOSE: { @@ -1110,7 +1130,10 @@ static switch_bool_t record_callback(switch_media_bug_t *bug, void *user_data, s switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Stop recording file %s\n", rh->file); switch_channel_set_private(channel, rh->file, NULL); - if (rh->fh) { + if (rh->native) { + switch_core_file_close(&rh->in_fh); + switch_core_file_close(&rh->out_fh); + } else if (rh->fh) { switch_size_t len; uint8_t data[SWITCH_RECOMMENDED_BUFFER_SIZE]; switch_frame_t frame = { 0 }; @@ -1150,7 +1173,7 @@ static switch_bool_t record_callback(switch_media_bug_t *bug, void *user_data, s char *cmd = switch_core_session_strdup(session, var); char *data, *expanded = NULL; switch_stream_handle_t stream = { 0 }; - + SWITCH_STANDARD_STREAM(stream); if ((data = strchr(cmd, ':'))) { @@ -1196,8 +1219,6 @@ static switch_bool_t record_callback(switch_media_bug_t *bug, void *user_data, s return SWITCH_FALSE; } } - - } break; case SWITCH_ABC_TYPE_WRITE: @@ -1739,6 +1760,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session(switch_core_session_t int file_flags = SWITCH_FILE_FLAG_WRITE | SWITCH_FILE_DATA_SHORT; switch_bool_t hangup_on_error = SWITCH_FALSE; char *file_path = NULL; + char *ext; + char *in_file = NULL, *out_file = NULL; if ((p = switch_channel_get_variable(channel, "RECORD_HANGUP_ON_ERROR"))) { hangup_on_error = switch_true(p); @@ -1889,7 +1912,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session(switch_core_session_t if (file_path && !strstr(file_path, SWITCH_URL_SEPARATOR)) { char *p; char *path = switch_core_session_strdup(session, file_path); - + if ((p = strrchr(path, *SWITCH_PATH_SEPARATOR))) { *p = '\0'; if (switch_dir_make_recursive(path, SWITCH_DEFAULT_DIR_PERMS, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) { @@ -1902,49 +1925,96 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session(switch_core_session_t path = NULL; } } + + rh = switch_core_session_alloc(session, sizeof(*rh)); - if (switch_core_file_open(fh, file, channels, read_impl.actual_samples_per_second, file_flags, NULL) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error opening %s\n", file); - if (hangup_on_error) { - switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); - switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE); + if ((ext = strrchr(file, '.'))) { + ext++; + if (switch_core_file_open(fh, file, channels, read_impl.actual_samples_per_second, file_flags, NULL) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error opening %s\n", file); + if (hangup_on_error) { + switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE); + } + return SWITCH_STATUS_GENERR; } - return SWITCH_STATUS_GENERR; + } else { + int tflags = 0; + + ext = read_impl.iananame; + + in_file = switch_core_session_sprintf(session, "%s-in.%s", file, ext); + out_file = switch_core_session_sprintf(session, "%s-out.%s", file, ext); + + + if (switch_core_file_open(&rh->in_fh, in_file, channels, read_impl.actual_samples_per_second, file_flags, NULL) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error opening %s\n", in_file); + if (hangup_on_error) { + switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE); + } + return SWITCH_STATUS_GENERR; + } + + if (switch_core_file_open(&rh->out_fh, out_file, channels, read_impl.actual_samples_per_second, file_flags, NULL) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error opening %s\n", out_file); + switch_core_file_close(&rh->in_fh); + if (hangup_on_error) { + switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE); + } + return SWITCH_STATUS_GENERR; + } + + rh->native = 1; + fh = NULL; + + if ((flags & SMBF_WRITE_STREAM)) { + tflags |= SMBF_TAP_NATIVE_WRITE; + } + + if ((flags & SMBF_READ_STREAM)) { + tflags |= SMBF_TAP_NATIVE_READ; + } + + flags = tflags; } + + if ((p = switch_channel_get_variable(channel, "RECORD_TITLE"))) { vval = (const char *) switch_core_session_strdup(session, p); - switch_core_file_set_string(fh, SWITCH_AUDIO_COL_STR_TITLE, vval); + if (fh) switch_core_file_set_string(fh, SWITCH_AUDIO_COL_STR_TITLE, vval); switch_channel_set_variable(channel, "RECORD_TITLE", NULL); } if ((p = switch_channel_get_variable(channel, "RECORD_COPYRIGHT"))) { vval = (const char *) switch_core_session_strdup(session, p); - switch_core_file_set_string(fh, SWITCH_AUDIO_COL_STR_COPYRIGHT, vval); + if (fh) switch_core_file_set_string(fh, SWITCH_AUDIO_COL_STR_COPYRIGHT, vval); switch_channel_set_variable(channel, "RECORD_COPYRIGHT", NULL); } if ((p = switch_channel_get_variable(channel, "RECORD_SOFTWARE"))) { vval = (const char *) switch_core_session_strdup(session, p); - switch_core_file_set_string(fh, SWITCH_AUDIO_COL_STR_SOFTWARE, vval); + if (fh) switch_core_file_set_string(fh, SWITCH_AUDIO_COL_STR_SOFTWARE, vval); switch_channel_set_variable(channel, "RECORD_SOFTWARE", NULL); } if ((p = switch_channel_get_variable(channel, "RECORD_ARTIST"))) { vval = (const char *) switch_core_session_strdup(session, p); - switch_core_file_set_string(fh, SWITCH_AUDIO_COL_STR_ARTIST, vval); + if (fh) switch_core_file_set_string(fh, SWITCH_AUDIO_COL_STR_ARTIST, vval); switch_channel_set_variable(channel, "RECORD_ARTIST", NULL); } if ((p = switch_channel_get_variable(channel, "RECORD_COMMENT"))) { vval = (const char *) switch_core_session_strdup(session, p); - switch_core_file_set_string(fh, SWITCH_AUDIO_COL_STR_COMMENT, vval); + if (fh) switch_core_file_set_string(fh, SWITCH_AUDIO_COL_STR_COMMENT, vval); switch_channel_set_variable(channel, "RECORD_COMMENT", NULL); } if ((p = switch_channel_get_variable(channel, "RECORD_DATE"))) { vval = (const char *) switch_core_session_strdup(session, p); - switch_core_file_set_string(fh, SWITCH_AUDIO_COL_STR_DATE, vval); + if (fh) switch_core_file_set_string(fh, SWITCH_AUDIO_COL_STR_DATE, vval); switch_channel_set_variable(channel, "RECORD_DATE", NULL); } @@ -1952,7 +2022,6 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session(switch_core_session_t to = switch_epoch_time_now(NULL) + limit; } - rh = switch_core_session_alloc(session, sizeof(*rh)); rh->fh = fh; rh->file = switch_core_session_strdup(session, file); rh->packet_len = read_impl.decoded_bytes_per_packet;