static switch_status_t channel_on_destroy(switch_core_session_t *session) { switch_channel_t *channel = NULL; private_t *tech_pvt = NULL; void *pop; channel = switch_core_session_get_channel(session); switch_assert(channel != NULL); tech_pvt = switch_core_session_get_private(session); if (tech_pvt) { switch_core_timer_destroy(&tech_pvt->timer); if (switch_core_codec_ready(&tech_pvt->read_codec)) { switch_core_codec_destroy(&tech_pvt->read_codec); } if (switch_core_codec_ready(&tech_pvt->write_codec)) { switch_core_codec_destroy(&tech_pvt->write_codec); } if (tech_pvt->write_frame) { switch_frame_free(&tech_pvt->write_frame); } while (switch_queue_trypop(tech_pvt->frame_queue, &pop) == SWITCH_STATUS_SUCCESS && pop) { switch_frame_t *frame = (switch_frame_t *) pop; switch_frame_free(&frame); } } return SWITCH_STATUS_SUCCESS; }
static void clear_queue(private_t *tech_pvt) { void *pop; while (switch_queue_trypop(tech_pvt->frame_queue, &pop) == SWITCH_STATUS_SUCCESS && pop) { switch_frame_t *frame = (switch_frame_t *) pop; switch_frame_free(&frame); } }
static switch_status_t channel_on_destroy(switch_core_session_t *session) { switch_channel_t *channel = NULL; loopback_private_t *tech_pvt = NULL; switch_event_t *vars; channel = switch_core_session_get_channel(session); switch_assert(channel != NULL); tech_pvt = switch_core_session_get_private(session); if ((vars = (switch_event_t *) switch_channel_get_private(channel, "__loopback_vars__"))) { switch_channel_set_private(channel, "__loopback_vars__", NULL); switch_event_destroy(&vars); } if (tech_pvt) { switch_core_timer_destroy(&tech_pvt->timer); if (switch_core_codec_ready(&tech_pvt->read_codec)) { switch_core_codec_destroy(&tech_pvt->read_codec); } if (switch_core_codec_ready(&tech_pvt->write_codec)) { switch_core_codec_destroy(&tech_pvt->write_codec); } if (tech_pvt->write_frame) { switch_frame_free(&tech_pvt->write_frame); } clear_queue(tech_pvt); } return SWITCH_STATUS_SUCCESS; }
static switch_status_t channel_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg) { switch_channel_t *channel; private_t *tech_pvt; channel = switch_core_session_get_channel(session); switch_assert(channel != NULL); tech_pvt = switch_core_session_get_private(session); switch_assert(tech_pvt != NULL); switch (msg->message_id) { case SWITCH_MESSAGE_INDICATE_ANSWER: if (tech_pvt->other_channel && !switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) { switch_channel_mark_answered(tech_pvt->other_channel); } break; case SWITCH_MESSAGE_INDICATE_PROGRESS: if (tech_pvt->other_channel && !switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) { switch_channel_mark_pre_answered(tech_pvt->other_channel); } break; case SWITCH_MESSAGE_INDICATE_BRIDGE: { switch_set_flag_locked(tech_pvt, TFLAG_BRIDGE); } break; case SWITCH_MESSAGE_INDICATE_UNBRIDGE: { switch_clear_flag_locked(tech_pvt, TFLAG_BRIDGE); } break; default: break; } switch (msg->message_id) { case SWITCH_MESSAGE_INDICATE_BRIDGE: case SWITCH_MESSAGE_INDICATE_UNBRIDGE: case SWITCH_MESSAGE_INDICATE_AUDIO_SYNC: { void *pop; while (switch_queue_trypop(tech_pvt->frame_queue, &pop) == SWITCH_STATUS_SUCCESS && pop) { switch_frame_t *frame = (switch_frame_t *) pop; switch_frame_free(&frame); } while (switch_queue_trypop(tech_pvt->other_tech_pvt->frame_queue, &pop) == SWITCH_STATUS_SUCCESS && pop) { switch_frame_t *frame = (switch_frame_t *) pop; switch_frame_free(&frame); } switch_core_timer_sync(&tech_pvt->timer); } break; default: break; } return SWITCH_STATUS_SUCCESS; }
static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id) { switch_channel_t *channel = NULL; private_t *tech_pvt = NULL; switch_status_t status = SWITCH_STATUS_FALSE; channel = switch_core_session_get_channel(session); switch_assert(channel != NULL); tech_pvt = switch_core_session_get_private(session); switch_assert(tech_pvt != NULL); if (switch_test_flag(frame, SFF_CNG) || switch_test_flag(tech_pvt, TFLAG_CNG) || switch_test_flag(tech_pvt, TFLAG_BOWOUT)) { return SWITCH_STATUS_SUCCESS; } switch_mutex_lock(tech_pvt->mutex); if (!switch_test_flag(tech_pvt, TFLAG_BOWOUT) && tech_pvt->other_tech_pvt && switch_test_flag(tech_pvt, TFLAG_BRIDGE) && switch_test_flag(tech_pvt->other_tech_pvt, TFLAG_BRIDGE) && switch_channel_test_flag(tech_pvt->channel, CF_BRIDGED) && switch_channel_test_flag(tech_pvt->other_channel, CF_BRIDGED) && switch_channel_test_flag(tech_pvt->channel, CF_ANSWERED) && switch_channel_test_flag(tech_pvt->other_channel, CF_ANSWERED) && !--tech_pvt->bowout_frame_count <= 0) { const char *a_uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE); const char *b_uuid = switch_channel_get_variable(tech_pvt->other_channel, SWITCH_SIGNAL_BOND_VARIABLE); const char *vetoa, *vetob; switch_set_flag_locked(tech_pvt, TFLAG_BOWOUT); switch_set_flag_locked(tech_pvt->other_tech_pvt, TFLAG_BOWOUT); vetoa = switch_channel_get_variable(tech_pvt->channel, "loopback_bowout"); vetob = switch_channel_get_variable(tech_pvt->other_tech_pvt->channel, "loopback_bowout"); if ((!vetoa || switch_true(vetoa)) && (!vetob || switch_true(vetob))) { switch_clear_flag_locked(tech_pvt, TFLAG_WRITE); switch_clear_flag_locked(tech_pvt->other_tech_pvt, TFLAG_WRITE); if (a_uuid && b_uuid) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s detected bridge on both ends, attempting direct connection.\n", switch_channel_get_name(channel)); /* channel_masquerade eat your heart out....... */ switch_ivr_uuid_bridge(a_uuid, b_uuid); switch_mutex_unlock(tech_pvt->mutex); return SWITCH_STATUS_SUCCESS; } } } if (switch_test_flag(tech_pvt, TFLAG_LINKED) && tech_pvt->other_tech_pvt) { switch_frame_t *clone; if (frame->codec->implementation != tech_pvt->write_codec.implementation) { /* change codecs to match */ tech_init(tech_pvt, session, frame->codec); tech_init(tech_pvt->other_tech_pvt, tech_pvt->other_session, frame->codec); } if (switch_queue_size(tech_pvt->other_tech_pvt->frame_queue) < FRAME_QUEUE_LEN) { if (switch_frame_dup(frame, &clone) != SWITCH_STATUS_SUCCESS) { abort(); } if (switch_queue_trypush(tech_pvt->other_tech_pvt->frame_queue, clone) != SWITCH_STATUS_SUCCESS) { switch_frame_free(&clone); } switch_set_flag_locked(tech_pvt->other_tech_pvt, TFLAG_WRITE); } status = SWITCH_STATUS_SUCCESS; } switch_mutex_unlock(tech_pvt->mutex); return status; }
static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id) { switch_channel_t *channel = NULL; private_t *tech_pvt = NULL; switch_status_t status = SWITCH_STATUS_FALSE; switch_mutex_t *mutex = NULL; void *pop = NULL; channel = switch_core_session_get_channel(session); switch_assert(channel != NULL); tech_pvt = switch_core_session_get_private(session); switch_assert(tech_pvt != NULL); if (!switch_test_flag(tech_pvt, TFLAG_LINKED)) { goto end; } *frame = NULL; if (!switch_channel_ready(channel)) { goto end; } switch_core_timer_next(&tech_pvt->timer); mutex = tech_pvt->mutex; switch_mutex_lock(mutex); if (switch_queue_trypop(tech_pvt->frame_queue, &pop) == SWITCH_STATUS_SUCCESS && pop) { if (tech_pvt->write_frame) { switch_frame_free(&tech_pvt->write_frame); } tech_pvt->write_frame = (switch_frame_t *) pop; tech_pvt->write_frame->codec = &tech_pvt->read_codec; *frame = tech_pvt->write_frame; } else { switch_set_flag(tech_pvt, TFLAG_CNG); } if (switch_test_flag(tech_pvt, TFLAG_CNG)) { unsigned char data[SWITCH_RECOMMENDED_BUFFER_SIZE]; uint32_t flag = 0; switch_status_t encode_status; uint32_t rate = tech_pvt->read_codec.implementation->actual_samples_per_second; *frame = &tech_pvt->cng_frame; tech_pvt->cng_frame.codec = &tech_pvt->read_codec; tech_pvt->cng_frame.datalen = tech_pvt->read_codec.implementation->decoded_bytes_per_packet; memset(tech_pvt->cng_frame.data, 0, tech_pvt->cng_frame.datalen); memset(&data, 0, tech_pvt->read_codec.implementation->decoded_bytes_per_packet); if (strcasecmp(tech_pvt->read_codec.implementation->iananame, "L16")) { encode_status = switch_core_codec_encode(&tech_pvt->read_codec, NULL, data, tech_pvt->read_codec.implementation->decoded_bytes_per_packet, tech_pvt->read_codec.implementation->actual_samples_per_second, tech_pvt->cng_frame.data, &tech_pvt->cng_frame.datalen, &rate, &flag); if (encode_status != SWITCH_STATUS_SUCCESS) { switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); } } //switch_set_flag((&tech_pvt->cng_frame), SFF_CNG); switch_clear_flag_locked(tech_pvt, TFLAG_CNG); } if (*frame) { status = SWITCH_STATUS_SUCCESS; } else { status = SWITCH_STATUS_FALSE; } end: if (mutex) { switch_mutex_unlock(mutex); } return status; }
static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id) { switch_channel_t *channel = NULL; private_t *tech_pvt = NULL; switch_status_t status = SWITCH_STATUS_FALSE; channel = switch_core_session_get_channel(session); switch_assert(channel != NULL); tech_pvt = switch_core_session_get_private(session); switch_assert(tech_pvt != NULL); if (switch_test_flag(frame, SFF_CNG) || (switch_test_flag(tech_pvt, TFLAG_BOWOUT) && switch_test_flag(tech_pvt, TFLAG_BOWOUT_USED))) { switch_core_timer_sync(&tech_pvt->timer); switch_core_timer_sync(&tech_pvt->other_tech_pvt->timer); return SWITCH_STATUS_SUCCESS; } switch_mutex_lock(tech_pvt->mutex); if (!switch_test_flag(tech_pvt, TFLAG_BOWOUT) && tech_pvt->other_tech_pvt && switch_test_flag(tech_pvt, TFLAG_BRIDGE) && switch_test_flag(tech_pvt->other_tech_pvt, TFLAG_BRIDGE) && switch_channel_test_flag(tech_pvt->channel, CF_BRIDGED) && switch_channel_test_flag(tech_pvt->other_channel, CF_BRIDGED) && switch_channel_test_flag(tech_pvt->channel, CF_ANSWERED) && switch_channel_test_flag(tech_pvt->other_channel, CF_ANSWERED) && --tech_pvt->bowout_frame_count <= 0) { const char *a_uuid = NULL; const char *b_uuid = NULL; const char *vetoa, *vetob; vetoa = switch_channel_get_variable(tech_pvt->channel, "loopback_bowout"); vetob = switch_channel_get_variable(tech_pvt->other_tech_pvt->channel, "loopback_bowout"); if ((!vetoa || switch_true(vetoa)) && (!vetob || switch_true(vetob))) { switch_core_session_t *br_a, *br_b; switch_channel_t *ch_a = NULL, *ch_b = NULL; int good_to_go = 0; switch_mutex_unlock(tech_pvt->mutex); find_non_loopback_bridge(session, &br_a, &a_uuid); find_non_loopback_bridge(tech_pvt->other_session, &br_b, &b_uuid); switch_mutex_lock(tech_pvt->mutex); if (br_a) { ch_a = switch_core_session_get_channel(br_a); switch_core_media_bug_transfer_recordings(session, br_a); } if (br_b) { ch_b = switch_core_session_get_channel(br_b); switch_core_media_bug_transfer_recordings(tech_pvt->other_session, br_b); } if (ch_a && ch_b && switch_channel_test_flag(ch_a, CF_BRIDGED) && switch_channel_test_flag(ch_b, CF_BRIDGED)) { switch_set_flag_locked(tech_pvt, TFLAG_BOWOUT); switch_set_flag_locked(tech_pvt->other_tech_pvt, TFLAG_BOWOUT); switch_clear_flag_locked(tech_pvt, TFLAG_WRITE); switch_clear_flag_locked(tech_pvt->other_tech_pvt, TFLAG_WRITE); switch_set_flag_locked(tech_pvt, TFLAG_BOWOUT_USED); switch_set_flag_locked(tech_pvt->other_tech_pvt, TFLAG_BOWOUT_USED); if (a_uuid && b_uuid) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s detected bridge on both ends, attempting direct connection.\n", switch_channel_get_name(channel)); /* channel_masquerade eat your heart out....... */ switch_ivr_uuid_bridge(a_uuid, b_uuid); good_to_go = 1; switch_mutex_unlock(tech_pvt->mutex); } } if (br_a) switch_core_session_rwunlock(br_a); if (br_b) switch_core_session_rwunlock(br_b); if (good_to_go) { return SWITCH_STATUS_SUCCESS; } } } if (switch_test_flag(tech_pvt, TFLAG_LINKED) && tech_pvt->other_tech_pvt) { switch_frame_t *clone; if (frame->codec->implementation != tech_pvt->write_codec.implementation) { /* change codecs to match */ tech_init(tech_pvt, session, frame->codec); tech_init(tech_pvt->other_tech_pvt, tech_pvt->other_session, frame->codec); } if (switch_frame_dup(frame, &clone) != SWITCH_STATUS_SUCCESS) { abort(); } if ((status = switch_queue_trypush(tech_pvt->other_tech_pvt->frame_queue, clone)) != SWITCH_STATUS_SUCCESS) { clear_queue(tech_pvt->other_tech_pvt); status = switch_queue_trypush(tech_pvt->other_tech_pvt->frame_queue, clone); } if (status == SWITCH_STATUS_SUCCESS) { switch_set_flag_locked(tech_pvt->other_tech_pvt, TFLAG_WRITE); } else { switch_frame_free(&clone); } status = SWITCH_STATUS_SUCCESS; } switch_mutex_unlock(tech_pvt->mutex); return status; }
static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id) { switch_channel_t *channel = NULL; private_t *tech_pvt = NULL; switch_status_t status = SWITCH_STATUS_FALSE; switch_mutex_t *mutex = NULL; void *pop = NULL; channel = switch_core_session_get_channel(session); switch_assert(channel != NULL); tech_pvt = switch_core_session_get_private(session); switch_assert(tech_pvt != NULL); if (!switch_test_flag(tech_pvt, TFLAG_LINKED)) { goto end; } *frame = NULL; if (!switch_channel_ready(channel)) { goto end; } switch_core_timer_next(&tech_pvt->timer); mutex = tech_pvt->mutex; switch_mutex_lock(mutex); if (switch_test_flag(tech_pvt, TFLAG_CLEAR)) { clear_queue(tech_pvt); switch_clear_flag(tech_pvt, TFLAG_CLEAR); } if (switch_queue_trypop(tech_pvt->frame_queue, &pop) == SWITCH_STATUS_SUCCESS && pop) { if (tech_pvt->write_frame) { switch_frame_free(&tech_pvt->write_frame); } tech_pvt->write_frame = (switch_frame_t *) pop; tech_pvt->write_frame->codec = &tech_pvt->read_codec; *frame = tech_pvt->write_frame; tech_pvt->packet_count++; switch_clear_flag(tech_pvt->write_frame, SFF_CNG); tech_pvt->first_cng = 0; } else { *frame = &tech_pvt->cng_frame; tech_pvt->cng_frame.codec = &tech_pvt->read_codec; tech_pvt->cng_frame.datalen = tech_pvt->read_codec.implementation->decoded_bytes_per_packet; switch_set_flag((&tech_pvt->cng_frame), SFF_CNG); if (!tech_pvt->first_cng) { switch_yield(tech_pvt->read_codec.implementation->samples_per_packet); tech_pvt->first_cng = 1; } } if (*frame) { status = SWITCH_STATUS_SUCCESS; } else { status = SWITCH_STATUS_FALSE; } end: if (mutex) { switch_mutex_unlock(mutex); } return status; }