SWITCH_DECLARE(switch_status_t) switch_core_media_bug_read(switch_media_bug_t *bug, switch_frame_t *frame, switch_bool_t fill) { switch_size_t bytes = 0, datalen = 0; int16_t *dp, *fp; uint32_t x; size_t rlen = 0; size_t wlen = 0; uint32_t blen; switch_codec_implementation_t read_impl = { 0 }; int16_t *tp; switch_size_t do_read = 0, do_write = 0, has_read = 0, has_write = 0, fill_read = 0, fill_write = 0; switch_core_session_get_read_impl(bug->session, &read_impl); bytes = read_impl.decoded_bytes_per_packet; if (frame->buflen < bytes) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(switch_core_media_bug_get_session(bug)), SWITCH_LOG_ERROR, "%s frame buffer too small!\n", switch_channel_get_name(bug->session->channel)); return SWITCH_STATUS_FALSE; } if ((!bug->raw_read_buffer && (!bug->raw_write_buffer || !switch_test_flag(bug, SMBF_WRITE_STREAM)))) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(switch_core_media_bug_get_session(bug)), SWITCH_LOG_ERROR, "%s Buffer Error (raw_read_buffer=%p, raw_write_buffer=%p, read=%s, write=%s)\n", switch_channel_get_name(bug->session->channel), (void *)bug->raw_read_buffer, (void *)bug->raw_write_buffer, switch_test_flag(bug, SMBF_READ_STREAM) ? "yes" : "no", switch_test_flag(bug, SMBF_WRITE_STREAM) ? "yes" : "no"); return SWITCH_STATUS_FALSE; } frame->flags = 0; frame->datalen = 0; if (switch_test_flag(bug, SMBF_READ_STREAM)) { has_read = 1; switch_mutex_lock(bug->read_mutex); do_read = switch_buffer_inuse(bug->raw_read_buffer); switch_mutex_unlock(bug->read_mutex); } if (switch_test_flag(bug, SMBF_WRITE_STREAM)) { has_write = 1; switch_mutex_lock(bug->write_mutex); do_write = switch_buffer_inuse(bug->raw_write_buffer); switch_mutex_unlock(bug->write_mutex); } if (bug->record_frame_size && bug->record_pre_buffer_max && (do_read || do_write) && bug->record_pre_buffer_count < bug->record_pre_buffer_max) { bug->record_pre_buffer_count++; return SWITCH_STATUS_FALSE; } else { uint32_t frame_size; switch_codec_implementation_t read_impl = { 0 }; switch_core_session_get_read_impl(bug->session, &read_impl); frame_size = read_impl.decoded_bytes_per_packet; bug->record_frame_size = frame_size; } if (bug->record_frame_size && do_write > do_read && do_write > (bug->record_frame_size * 2)) { switch_mutex_lock(bug->write_mutex); switch_buffer_toss(bug->raw_write_buffer, bug->record_frame_size); do_write = switch_buffer_inuse(bug->raw_write_buffer); switch_mutex_unlock(bug->write_mutex); } if ((has_read && !do_read)) { fill_read = 1; } if ((has_write && !do_write)) { fill_write = 1; } if (bug->record_frame_size) { if ((do_read && do_read < bug->record_frame_size) || (do_write && do_write < bug->record_frame_size)) { return SWITCH_STATUS_FALSE; } if (do_read && do_read > bug->record_frame_size) { do_read = bug->record_frame_size; } if (do_write && do_write > bug->record_frame_size) { do_write = bug->record_frame_size; } } if ((fill_read && fill_write) || (fill && (fill_read || fill_write))) { return SWITCH_STATUS_FALSE; } if (do_read && do_read > SWITCH_RECOMMENDED_BUFFER_SIZE) { do_read = 1280; } if (do_write && do_write > SWITCH_RECOMMENDED_BUFFER_SIZE) { do_write = 1280; } if (do_read) { switch_mutex_lock(bug->read_mutex); frame->datalen = (uint32_t) switch_buffer_read(bug->raw_read_buffer, frame->data, do_read); if (frame->datalen != do_read) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(switch_core_media_bug_get_session(bug)), SWITCH_LOG_ERROR, "Framing Error Reading!\n"); switch_core_media_bug_flush(bug); switch_mutex_unlock(bug->read_mutex); return SWITCH_STATUS_FALSE; } switch_mutex_unlock(bug->read_mutex); } else if (fill_read) { frame->datalen = (uint32_t)bytes; memset(frame->data, 255, frame->datalen); } if (do_write) { switch_assert(bug->raw_write_buffer); switch_mutex_lock(bug->write_mutex); datalen = (uint32_t) switch_buffer_read(bug->raw_write_buffer, bug->data, do_write); if (datalen != do_write) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(switch_core_media_bug_get_session(bug)), SWITCH_LOG_ERROR, "Framing Error Writing!\n"); switch_core_media_bug_flush(bug); switch_mutex_unlock(bug->write_mutex); return SWITCH_STATUS_FALSE; } switch_mutex_unlock(bug->write_mutex); } else if (fill_write) { datalen = bytes; memset(bug->data, 255, datalen); } tp = bug->tmp; dp = (int16_t *) bug->data; fp = (int16_t *) frame->data; rlen = frame->datalen / 2; wlen = datalen / 2; blen = (uint32_t)(bytes / 2); if (switch_test_flag(bug, SMBF_STEREO)) { int16_t *left, *right; size_t left_len, right_len; if (switch_test_flag(bug, SMBF_STEREO_SWAP)) { left = dp; /* write stream */ left_len = wlen; right = fp; /* read stream */ right_len = rlen; } else { left = fp; /* read stream */ left_len = rlen; right = dp; /* write stream */ right_len = wlen; } for (x = 0; x < blen; x++) { if (x < left_len) { *(tp++) = *(left + x); } else { *(tp++) = 0; } if (x < right_len) { *(tp++) = *(right + x); } else { *(tp++) = 0; } } memcpy(frame->data, bug->tmp, bytes * 2); } else { for (x = 0; x < blen; x++) { int32_t w = 0, r = 0, z = 0; if (x < rlen) { r = (int32_t) * (fp + x); } if (x < wlen) { w = (int32_t) * (dp + x); } z = w + r; if (z > SWITCH_SMAX || z < SWITCH_SMIN) { if (r) z += (r/2); if (w) z += (w/2); } switch_normalize_to_16bit(z); *(fp + x) = (int16_t) z; } } frame->datalen = (uint32_t)bytes; frame->samples = (uint32_t)(bytes / sizeof(int16_t) / read_impl.number_of_channels); frame->rate = read_impl.actual_samples_per_second; frame->codec = NULL; if (switch_test_flag(bug, SMBF_STEREO)) { frame->datalen *= 2; frame->channels = 2; } else { frame->channels = read_impl.number_of_channels; } return SWITCH_STATUS_SUCCESS; }
SWITCH_DECLARE(switch_status_t) switch_core_session_set_real_read_codec(switch_core_session_t *session, switch_codec_t *codec) { switch_event_t *event; switch_channel_t *channel = switch_core_session_get_channel(session); char tmp[30]; switch_status_t status = SWITCH_STATUS_SUCCESS; int changed_read_codec = 0; switch_mutex_lock(session->codec_read_mutex); if (codec && (!codec->implementation || !switch_core_codec_ready(codec))) { codec = NULL; } if (codec) { /* set real_read_codec and read_codec */ if (!session->real_read_codec) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Original read codec set to %s:%d\n", switch_channel_get_name(session->channel), codec->implementation->iananame, codec->implementation->ianacode); session->read_codec = session->real_read_codec = codec; changed_read_codec = 1; if (codec->implementation) { session->read_impl = *codec->implementation; session->real_read_impl = *codec->implementation; } else { memset(&session->read_impl, 0, sizeof(session->read_impl)); } } else { /* replace real_read_codec */ switch_codec_t *cur_codec; switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Original read codec replaced with %s:%d\n", switch_channel_get_name(session->channel), codec->implementation->iananame, codec->implementation->ianacode); /* Set real_read_codec to front of the list of read_codecs */ cur_codec = session->read_codec; while (cur_codec != NULL) { if (cur_codec->next == session->real_read_codec) { cur_codec->next = codec; break; } cur_codec = cur_codec->next; } session->real_read_codec = codec; /* set read_codec with real_read_codec if it no longer is ready */ if (!switch_core_codec_ready(session->read_codec)) { session->read_codec = codec; changed_read_codec = 1; if (codec->implementation) { session->read_impl = *codec->implementation; session->real_read_impl = *codec->implementation; } else { memset(&session->read_impl, 0, sizeof(session->read_impl)); } } } /* force media bugs to copy the read codec from the next frame */ switch_thread_rwlock_wrlock(session->bug_rwlock); if (switch_core_codec_ready(&session->bug_codec)) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Destroying BUG Codec %s:%d\n", session->bug_codec.implementation->iananame, session->bug_codec.implementation->ianacode); switch_core_codec_destroy(&session->bug_codec); } switch_thread_rwlock_unlock(session->bug_rwlock); } else { status = SWITCH_STATUS_FALSE; goto end; } if (changed_read_codec && session->read_codec && session->read_impl.decoded_bytes_per_packet) { if (switch_event_create(&event, SWITCH_EVENT_CODEC) == SWITCH_STATUS_SUCCESS) { switch_channel_event_set_data(session->channel, event); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "channel-read-codec-name", session->read_impl.iananame); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "channel-read-codec-rate", "%d", session->read_impl.actual_samples_per_second); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "channel-read-codec-bit-rate", "%d", session->read_impl.bits_per_second); if (session->read_impl.actual_samples_per_second != session->read_impl.samples_per_second) { switch_event_add_header(event, SWITCH_STACK_BOTTOM, "channel-reported-read-codec-rate", "%d", session->read_impl.samples_per_second); } switch_event_fire(&event); } switch_channel_set_variable(channel, "read_codec", session->read_impl.iananame); switch_channel_set_variable(channel, "original_read_codec", session->read_impl.iananame); switch_snprintf(tmp, sizeof(tmp), "%d", session->read_impl.actual_samples_per_second); switch_channel_set_variable(channel, "read_rate", tmp); switch_channel_set_variable(channel, "original_read_rate", tmp); session->raw_read_frame.codec = session->read_codec; session->raw_write_frame.codec = session->read_codec; session->enc_read_frame.codec = session->read_codec; session->enc_write_frame.codec = session->read_codec; } end: if (session->read_codec) { switch_channel_set_flag(channel, CF_MEDIA_SET); } switch_mutex_unlock(session->codec_read_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 cepstral_speech_read_tts(switch_speech_handle_t *sh, void *data, size_t *datalen, switch_speech_flag_t *flags) { cepstral_t *cepstral; size_t desired = *datalen; switch_status_t status = SWITCH_STATUS_FALSE; size_t used, padding = 0; assert(sh != NULL); cepstral = sh->private_info; assert(cepstral != NULL); while (!cepstral->done) { if (!cepstral->done_gen) { int check = swift_port_status(cepstral->port, cepstral->tts_stream); if (!check == SWIFT_STATUS_RUNNING) { cepstral->done_gen = 1; } } switch_mutex_lock(cepstral->audio_lock); used = switch_buffer_inuse(cepstral->audio_buffer); switch_mutex_unlock(cepstral->audio_lock); if (!used && cepstral->done_gen) { status = SWITCH_STATUS_BREAK; break; } /* wait for the right amount of data (unless there is no blocking flag) */ if (used < desired) { if (cepstral->done_gen) { padding = desired - used; desired = used; } if (!(*flags & SWITCH_SPEECH_FLAG_BLOCKING)) { *datalen = 0; status = SWITCH_STATUS_SUCCESS; break; } switch_cond_next(); continue; } /* There is enough, read it and return */ switch_mutex_lock(cepstral->audio_lock); *datalen = switch_buffer_read(cepstral->audio_buffer, data, desired); if (padding) { size_t x = 0; unsigned char *p = data; for (x = 0; x < padding; x++) { *(p + x) = 0; (*datalen)++; } } switch_mutex_unlock(cepstral->audio_lock); status = SWITCH_STATUS_SUCCESS; break; } return status; }
SWITCH_DECLARE(switch_status_t) switch_core_session_set_write_codec(switch_core_session_t *session, switch_codec_t *codec) { switch_event_t *event; switch_channel_t *channel = switch_core_session_get_channel(session); char tmp[30]; switch_status_t status = SWITCH_STATUS_SUCCESS; switch_mutex_lock(session->codec_write_mutex); if (!codec || !codec->implementation || !switch_core_codec_ready(codec)) { if (session->real_write_codec) { session->write_codec = session->real_write_codec; session->write_impl = *session->real_write_codec->implementation; session->real_write_codec = NULL; } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot set NULL codec!\n"); status = SWITCH_STATUS_FALSE; goto end; } } else if (session->write_codec) { if (session->real_write_codec) { if (codec == session->real_write_codec) { session->write_codec = codec; session->write_impl = *codec->implementation; session->real_write_codec = NULL; } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot double-set codec!\n"); status = SWITCH_STATUS_FALSE; goto end; } } else { session->real_write_codec = session->write_codec; session->write_codec = codec; session->write_impl = *codec->implementation; } } else { session->write_codec = codec; session->write_impl = *codec->implementation; } if (session->write_codec && codec && session->write_impl.codec_id) { if (switch_event_create(&event, SWITCH_EVENT_CODEC) == SWITCH_STATUS_SUCCESS) { switch_channel_event_set_data(session->channel, event); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Channel-Write-Codec-Name", session->write_impl.iananame); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Channel-Write-Codec-Rate", "%d", session->write_impl.actual_samples_per_second); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Channel-Write-codec-bit-rate", "%d", session->write_impl.bits_per_second); if (session->write_impl.actual_samples_per_second != session->write_impl.samples_per_second) { switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Channel-Reported-Write-Codec-Rate", "%d", session->write_impl.actual_samples_per_second); } switch_event_fire(&event); } switch_channel_set_variable(channel, "write_codec", session->write_impl.iananame); switch_snprintf(tmp, sizeof(tmp), "%d", session->write_impl.actual_samples_per_second); switch_channel_set_variable(channel, "write_rate", tmp); } end: switch_mutex_unlock(session->codec_write_mutex); return status; }
/* {'$gen_call', {<[email protected]>, #Ref<254770.4.0>}, {is_auth, cpx@freecpx} */ static switch_status_t handle_net_kernel_msg(listener_t *listener, erlang_msg * msg, ei_x_buff * buf, ei_x_buff * rbuf) { int version, size, type, arity; char atom[MAXATOMLEN]; erlang_ref ref; erlang_pid pid; buf->index = 0; ei_decode_version(buf->buff, &buf->index, &version); ei_get_type(buf->buff, &buf->index, &type, &size); if (type != ERL_SMALL_TUPLE_EXT && type != ERL_SMALL_TUPLE_EXT) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "not a tuple\n"); return SWITCH_STATUS_FALSE; } ei_decode_tuple_header(buf->buff, &buf->index, &arity); if (arity != 3) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "wrong arity\n"); return SWITCH_STATUS_FALSE; } if (ei_decode_atom(buf->buff, &buf->index, atom) || strncmp(atom, "$gen_call", MAXATOMLEN)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "not gen_call\n"); return SWITCH_STATUS_FALSE; } ei_get_type(buf->buff, &buf->index, &type, &size); if (type != ERL_SMALL_TUPLE_EXT && type != ERL_SMALL_TUPLE_EXT) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "not a tuple\n"); return SWITCH_STATUS_FALSE; } ei_decode_tuple_header(buf->buff, &buf->index, &arity); if (arity != 2) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "wrong arity\n"); return SWITCH_STATUS_FALSE; } if (ei_decode_pid(buf->buff, &buf->index, &pid) || ei_decode_ref(buf->buff, &buf->index, &ref)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "decoding pid and ref error\n"); return SWITCH_STATUS_FALSE; } ei_get_type(buf->buff, &buf->index, &type, &size); if (type != ERL_SMALL_TUPLE_EXT && type != ERL_SMALL_TUPLE_EXT) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "not a tuple\n"); return SWITCH_STATUS_FALSE; } ei_decode_tuple_header(buf->buff, &buf->index, &arity); if (arity != 2) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "bad arity\n"); return SWITCH_STATUS_FALSE; } if (ei_decode_atom(buf->buff, &buf->index, atom) || strncmp(atom, "is_auth", MAXATOMLEN)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "not is_auth\n"); return SWITCH_STATUS_FALSE; } /* To ! {Tag, Reply} */ ei_x_encode_tuple_header(rbuf, 2); ei_x_encode_ref(rbuf, &ref); ei_x_encode_atom(rbuf, "yes"); switch_mutex_lock(listener->sock_mutex); ei_send(listener->sockfd, &pid, rbuf->buff, rbuf->index); switch_mutex_unlock(listener->sock_mutex); #ifdef EI_DEBUG ei_x_print_msg(rbuf, &pid, 1); #endif return SWITCH_STATUS_FALSE; }
static switch_status_t my_on_reporting(switch_core_session_t *session) { switch_status_t status = SWITCH_STATUS_SUCCESS; switch_channel_t *channel = switch_core_session_get_channel(session); switch_event_header_t *hi; switch_caller_profile_t *caller_profile; switch_app_log_t *app_log; bson cdr; int is_b; char *tmp; if (globals.shutdown) { return SWITCH_STATUS_SUCCESS; } is_b = channel && switch_channel_get_originator_caller_profile(channel); if (!globals.log_b && is_b) { const char *force_cdr = switch_channel_get_variable(channel, SWITCH_FORCE_PROCESS_CDR_VARIABLE); if (!switch_true(force_cdr)) { return SWITCH_STATUS_SUCCESS; } } bson_init(&cdr); /* Channel data */ bson_append_start_object(&cdr, "channel_data"); bson_append_string(&cdr, "state", switch_channel_state_name(switch_channel_get_state(channel))); bson_append_string(&cdr, "direction", switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND ? "outbound" : "inbound"); bson_append_int(&cdr, "state_number", switch_channel_get_state(channel)); if ((tmp = switch_channel_get_flag_string(channel))) { bson_append_string(&cdr, "flags", tmp); free(tmp); } if ((tmp = switch_channel_get_cap_string(channel))) { bson_append_string(&cdr, "caps", tmp); free(tmp); } bson_append_finish_object(&cdr); /* channel_data */ /* Channel variables */ bson_append_start_object(&cdr, "variables"); if ((hi = switch_channel_variable_first(channel))) { for (; hi; hi = hi->next) { if (!zstr(hi->name) && !zstr(hi->value)) { bson_append_string(&cdr, hi->name, hi->value); } } switch_channel_variable_last(channel); } bson_append_finish_object(&cdr); /* variables */ /* App log */ if ((app_log = switch_core_session_get_app_log(session))) { switch_app_log_t *ap; bson_append_start_object(&cdr, "app_log"); for (ap = app_log; ap; ap = ap->next) { bson_append_start_object(&cdr, "application"); bson_append_string(&cdr, "app_name", ap->app); bson_append_string(&cdr, "app_data", switch_str_nil(ap->arg)); bson_append_long(&cdr, "app_stamp", ap->stamp); bson_append_finish_object(&cdr); /* application */ } bson_append_finish_object(&cdr); /* app_log */ } /* Callflow */ caller_profile = switch_channel_get_caller_profile(channel); while (caller_profile) { bson_append_start_object(&cdr, "callflow"); if (!zstr(caller_profile->dialplan)) { bson_append_string(&cdr, "dialplan", caller_profile->dialplan); } if (!zstr(caller_profile->profile_index)) { bson_append_string(&cdr, "profile_index", caller_profile->profile_index); } if (caller_profile->caller_extension) { switch_caller_application_t *ap; bson_append_start_object(&cdr, "extension"); bson_append_string(&cdr, "name", caller_profile->caller_extension->extension_name); bson_append_string(&cdr, "number", caller_profile->caller_extension->extension_number); if (caller_profile->caller_extension->current_application) { bson_append_string(&cdr, "current_app", caller_profile->caller_extension->current_application->application_name); } for (ap = caller_profile->caller_extension->applications; ap; ap = ap->next) { bson_append_start_object(&cdr, "application"); if (ap == caller_profile->caller_extension->current_application) { bson_append_bool(&cdr, "last_executed", 1); } bson_append_string(&cdr, "app_name", ap->application_name); bson_append_string(&cdr, "app_data", switch_str_nil(ap->application_data)); bson_append_finish_object(&cdr); } if (caller_profile->caller_extension->children) { switch_caller_profile_t *cp = NULL; for (cp = caller_profile->caller_extension->children; cp; cp = cp->next) { if (!cp->caller_extension) { continue; } bson_append_start_object(&cdr, "sub_extensions"); bson_append_start_object(&cdr, "extension"); bson_append_string(&cdr, "name", cp->caller_extension->extension_name); bson_append_string(&cdr, "number", cp->caller_extension->extension_number); bson_append_string(&cdr, "dialplan", cp->dialplan); if (cp->caller_extension->current_application) { bson_append_string(&cdr, "current_app", cp->caller_extension->current_application->application_name); } for (ap = cp->caller_extension->applications; ap; ap = ap->next) { bson_append_start_object(&cdr, "application"); if (ap == cp->caller_extension->current_application) { bson_append_bool(&cdr, "last_executed", 1); } bson_append_string(&cdr, "app_name", ap->application_name); bson_append_string(&cdr, "app_data", switch_str_nil(ap->application_data)); bson_append_finish_object(&cdr); } bson_append_finish_object(&cdr); /* extension */ bson_append_finish_object(&cdr); /* sub_extensions */ } } bson_append_finish_object(&cdr); /* extension */ } bson_append_start_object(&cdr, "caller_profile"); set_bson_profile_data(&cdr, caller_profile); if (caller_profile->origination_caller_profile) { switch_caller_profile_t *cp = NULL; bson_append_start_object(&cdr, "origination"); for (cp = caller_profile->origination_caller_profile; cp; cp = cp->next) { bson_append_start_object(&cdr, "origination_caller_profile"); set_bson_profile_data(&cdr, cp); bson_append_finish_object(&cdr); } bson_append_finish_object(&cdr); /* origination */ } if (caller_profile->originator_caller_profile) { switch_caller_profile_t *cp = NULL; bson_append_start_object(&cdr, "originator"); for (cp = caller_profile->originator_caller_profile; cp; cp = cp->next) { bson_append_start_object(&cdr, "originator_caller_profile"); set_bson_profile_data(&cdr, cp); bson_append_finish_object(&cdr); } bson_append_finish_object(&cdr); /* originator */ } if (caller_profile->originatee_caller_profile) { switch_caller_profile_t *cp = NULL; bson_append_start_object(&cdr, "originatee"); for (cp = caller_profile->originatee_caller_profile; cp; cp = cp->next) { bson_append_start_object(&cdr, "originatee_caller_profile"); set_bson_profile_data(&cdr, cp); bson_append_finish_object(&cdr); } bson_append_finish_object(&cdr); /* originatee */ } bson_append_finish_object(&cdr); /* caller_profile */ /* Timestamps */ if (caller_profile->times) { bson_append_start_object(&cdr, "times"); /* Insert timestamps as long ints (microseconds) to preserve accuracy */ bson_append_long(&cdr, "created_time", caller_profile->times->created); bson_append_long(&cdr, "profile_created_time", caller_profile->times->profile_created); bson_append_long(&cdr, "progress_time", caller_profile->times->progress); bson_append_long(&cdr, "progress_media_time", caller_profile->times->progress_media); bson_append_long(&cdr, "answered_time", caller_profile->times->answered); bson_append_long(&cdr, "bridged_time", caller_profile->times->bridged); bson_append_long(&cdr, "last_hold_time", caller_profile->times->last_hold); bson_append_long(&cdr, "hold_accum_time", caller_profile->times->hold_accum); bson_append_long(&cdr, "hangup_time", caller_profile->times->hungup); bson_append_long(&cdr, "resurrect_time", caller_profile->times->resurrected); bson_append_long(&cdr, "transfer_time", caller_profile->times->transferred); bson_append_finish_object(&cdr); /* times */ } bson_append_finish_object(&cdr); /* callflow */ caller_profile = caller_profile->next; } bson_finish(&cdr); switch_mutex_lock(globals.mongo_mutex); if (mongo_insert(globals.mongo_conn, globals.mongo_namespace, &cdr) != MONGO_OK) { if (globals.mongo_conn->err == MONGO_IO_ERROR) { mongo_error_t db_status; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "MongoDB connection failed; attempting reconnect...\n"); db_status = mongo_reconnect(globals.mongo_conn); if (db_status != MONGO_OK) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "MongoDB reconnect failed with error code %d\n", db_status); status = SWITCH_STATUS_FALSE; } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "MongoDB connection re-established.\n"); if (mongo_insert(globals.mongo_conn, globals.mongo_namespace, &cdr) != MONGO_OK) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mongo_insert: error code %d\n", globals.mongo_conn->err); status = SWITCH_STATUS_FALSE; } } } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mongo_insert: error code %d\n", globals.mongo_conn->err); status = SWITCH_STATUS_FALSE; } } switch_mutex_unlock(globals.mongo_mutex); bson_destroy(&cdr); return status; }
static switch_status_t engage_device(portaudio_stream_source_t *source, int restart) { PaStreamParameters inputParameters, outputParameters; PaError err; int sample_rate = source->rate; int codec_ms = source->interval; switch_mutex_init(&source->device_lock, SWITCH_MUTEX_NESTED, module_pool); if (source->timer.timer_interface) { switch_core_timer_sync(&source->timer); } if (source->audio_stream) { return SWITCH_STATUS_SUCCESS; } if (!switch_core_codec_ready(&source->read_codec)) { if (switch_core_codec_init(&source->read_codec, "L16", NULL, sample_rate, codec_ms, 1, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, NULL) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n"); return SWITCH_STATUS_FALSE; } } switch_assert(source->read_codec.implementation); if (!switch_core_codec_ready(&source->write_codec)) { if (switch_core_codec_init(&source->write_codec, "L16", NULL, sample_rate, codec_ms, 1, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, NULL) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n"); switch_core_codec_destroy(&source->read_codec); return SWITCH_STATUS_FALSE; } } if (!source->timer.timer_interface) { if (switch_core_timer_init(&source->timer, source->timer_name, codec_ms, source->read_codec.implementation->samples_per_packet, module_pool) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "setup timer failed!\n"); switch_core_codec_destroy(&source->read_codec); switch_core_codec_destroy(&source->write_codec); return SWITCH_STATUS_FALSE; } } source->read_frame.rate = sample_rate; source->read_frame.codec = &source->read_codec; switch_mutex_lock(source->device_lock); /* LOCKED ************************************************************************************************** */ inputParameters.device = source->sourcedev; inputParameters.channelCount = 1; inputParameters.sampleFormat = SAMPLE_TYPE; inputParameters.suggestedLatency = Pa_GetDeviceInfo(inputParameters.device)->defaultLowInputLatency; inputParameters.hostApiSpecificStreamInfo = NULL; outputParameters.device = source->sourcedev; outputParameters.channelCount = 1; outputParameters.sampleFormat = SAMPLE_TYPE; outputParameters.suggestedLatency = Pa_GetDeviceInfo(outputParameters.device)->defaultLowOutputLatency; outputParameters.hostApiSpecificStreamInfo = NULL; err = OpenAudioStream(&source->audio_stream, &inputParameters, NULL, sample_rate, paClipOff, source->read_codec.implementation->samples_per_packet, 0); /* UNLOCKED ************************************************************************************************* */ if (err != paNoError) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error opening audio device retrying\n"); switch_yield(1000000); err = OpenAudioStream(&source->audio_stream, &inputParameters, &outputParameters, sample_rate, paClipOff, source->read_codec.implementation->samples_per_packet, 0); } switch_mutex_unlock(source->device_lock); if (err != paNoError) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open audio device\n"); switch_core_codec_destroy(&source->read_codec); switch_core_timer_destroy(&source->timer); return SWITCH_STATUS_FALSE; } return SWITCH_STATUS_SUCCESS; }
static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void *obj) { portaudio_stream_source_t *source = obj; portaudio_stream_context_t *cp; int samples = 0; int bused, bytesToWrite; switch_mutex_lock(globals.mutex); globals.threads++; switch_mutex_unlock(globals.mutex); if (!source->prebuf) { source->prebuf = DEFAULT_PREBUFFER_SIZE; } switch_mutex_lock(globals.mutex); switch_core_hash_insert(globals.source_hash, source->sourcename, source); switch_mutex_unlock(globals.mutex); switch_thread_rwlock_create(&source->rwlock, source->pool); if (engage_device(source, 0) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " Dev %d cant be engaged !\n", (int) source->sourcedev); } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " Dev %d engaged at %d rate!\n", (int) source->sourcedev, (int) source->rate); if (globals.running && !source->stopped) { source->ready = 1; if (!source->audio_stream) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No Audio Stream wops!\n"); source->stopped = 0; source->ready = 0; } else { while (globals.running && !source->stopped) { samples = 0; switch_mutex_lock(source->device_lock); samples = ReadAudioStream(source->audio_stream, source->databuf, source->read_codec.implementation->samples_per_packet, 0, &source->timer); switch_mutex_unlock(source->device_lock); if (samples) { bytesToWrite = source->samples; if (samples < bytesToWrite) { bytesToWrite = samples; } bytesToWrite *= source->audio_stream->bytesPerFrame; if (source->total) { switch_mutex_lock(source->mutex); for (cp = source->context_list; cp; cp = cp->next) { switch_mutex_lock(cp->audio_mutex); bused = switch_buffer_inuse(cp->audio_buffer); if (bused > source->samples * 768) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Leaking stream handle! [%s() %s:%d] %d used %d max\n", cp->func, cp->file, cp->line, (int) bused, (int) (source->samples * 768)); switch_buffer_zero(cp->audio_buffer); } else { switch_buffer_write(cp->audio_buffer, source->databuf, bytesToWrite); } switch_mutex_unlock(cp->audio_mutex); } switch_mutex_unlock(source->mutex); } } } } } } source->ready = 0; switch_mutex_lock(globals.mutex); switch_core_hash_delete(globals.source_hash, source->sourcename); switch_mutex_unlock(globals.mutex); switch_thread_rwlock_wrlock(source->rwlock); switch_thread_rwlock_unlock(source->rwlock); switch_mutex_lock(source->device_lock); CloseAudioStream(source->audio_stream); if (switch_core_codec_ready(&source->read_codec)) { switch_core_codec_destroy(&source->read_codec); switch_core_codec_destroy(&source->write_codec); } if (switch_core_codec_ready(&source->write_codec)) { switch_core_codec_destroy(&source->write_codec); } switch_mutex_unlock(source->device_lock); switch_core_destroy_memory_pool(&source->pool); switch_mutex_lock(globals.mutex); globals.threads--; switch_mutex_unlock(globals.mutex); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " thread ending succesfully !\n"); switch_thread_exit(thread, SWITCH_STATUS_SUCCESS); return NULL; }
static switch_status_t insert_cdr(const char *values) { char *sql = NULL, *path = NULL; PGresult *res; sql = switch_mprintf("INSERT INTO %s (%s) VALUES (%s);", globals.db_table, globals.db_schema->columns, values); assert(sql); if (globals.debug) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Query: \"%s\"\n", sql); } switch_mutex_lock(globals.db_mutex); if (!globals.db_online || PQstatus(globals.db_connection) != CONNECTION_OK) { globals.db_connection = PQconnectdb(globals.db_info); } if (PQstatus(globals.db_connection) == CONNECTION_OK) { globals.db_online = 1; } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Connection to database failed: %s", PQerrorMessage(globals.db_connection)); goto error; } res = PQexec(globals.db_connection, sql); if (PQresultStatus(res) != PGRES_COMMAND_OK) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "INSERT command failed: %s", PQresultErrorMessage(res)); PQclear(res); goto error; } PQclear(res); switch_safe_free(sql); switch_mutex_unlock(globals.db_mutex); return SWITCH_STATUS_SUCCESS; error: PQfinish(globals.db_connection); globals.db_online = 0; switch_mutex_unlock(globals.db_mutex); /* SQL INSERT failed for whatever reason. Spool the attempted query to disk */ if (globals.spool_format == SPOOL_FORMAT_SQL) { path = switch_mprintf("%s%scdr-spool.sql", globals.spool_dir, SWITCH_PATH_SEPARATOR); assert(path); spool_cdr(path, sql); } else { path = switch_mprintf("%s%scdr-spool.csv", globals.spool_dir, SWITCH_PATH_SEPARATOR); assert(path); spool_cdr(path, values); } switch_safe_free(path); switch_safe_free(sql); return SWITCH_STATUS_FALSE; }
static switch_status_t load_config(switch_bool_t reload) { switch_status_t status = SWITCH_STATUS_SUCCESS; switch_xml_t cfg, xml = NULL, settings, param, x_profiles, x_profile; switch_cache_db_handle_t *dbh = NULL; if (!(xml = switch_xml_open_cfg(global_cf, &cfg, NULL))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", global_cf); return SWITCH_STATUS_TERM; } switch_mutex_lock(globals.mutex); if ((settings = switch_xml_child(cfg, "settings"))) { for (param = switch_xml_child(settings, "param"); param; param = param->next) { char *var = (char *) switch_xml_attr_soft(param, "name"); char *val = (char *) switch_xml_attr_soft(param, "value"); if (!strcasecmp(var, "odbc-dsn") && !zstr(val)) { if (switch_odbc_available()) { switch_set_string(globals.odbc_dsn, val); if ((globals.odbc_user = strchr(globals.odbc_dsn, ':'))) { *globals.odbc_user++ = '\0'; if ((globals.odbc_pass = strchr(globals.odbc_user, ':'))) { *globals.odbc_pass++ = '\0'; } } } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ODBC IS NOT AVAILABLE!\n"); } } else if (!strcasecmp(var, "dbname") && !zstr(val)) { globals.dbname = switch_core_strdup(globals.pool, val); } if (!strcasecmp(var, "debug")) { globals.debug = atoi(val); } } } if ((x_profiles = switch_xml_child(cfg, "profiles"))) { for (x_profile = switch_xml_child(x_profiles, "profile"); x_profile; x_profile = x_profile->next) { load_profile(switch_xml_attr_soft(x_profile, "name")); } } if (zstr(globals.odbc_dsn) && zstr(globals.dbname)) { globals.dbname = switch_core_sprintf(globals.pool, "directory"); } dbh = directory_get_db_handle(); if (dbh) { if (!reload) { switch_cache_db_test_reactive(dbh, "delete from directory_search where uuid != '' and name_visible != '' ", "drop table directory_search", dir_sql); } switch_cache_db_release_db_handle(&dbh); } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Cannot open DB!2\n"); status = SWITCH_STATUS_TERM; goto end; } end: switch_mutex_unlock(globals.mutex); switch_xml_free(xml); return status; }
static void parse_naptr(const ldns_rr *naptr, const char *number, enum_record_t **results) { char *str = ldns_rr2str(naptr); char *argv[11] = { 0 }; int i, argc; char *pack[4] = { 0 }; int packc; char *p; int order = 10; int preference = 100; char *service = NULL; char *packstr; char *regex, *replace; if (zstr(str)) { return; } for (p = str; p && *p; p++) { if (*p == '\t') *p = ' '; if (*p == ' ' && *(p+1) == '.') *p = '\0'; } argc = switch_split(str, ' ', argv); for (i = 0; i < argc; i++) { if (i > 0) { strip_quotes(argv[i]); } } service = argv[7]; packstr = argv[8]; if (zstr(service) || zstr(packstr)) { goto end; } if (!zstr(argv[4])) { order = atoi(argv[4]); } if (!zstr(argv[5])) { preference = atoi(argv[5]); } if ((packc = switch_split(packstr, '!', pack))) { regex = pack[1]; replace = pack[2]; } else { goto end; } for (p = replace; p && *p; p++) { if (*p == '\\') { *p = '$'; } } if (service && regex && replace) { switch_regex_t *re = NULL, *re2 = NULL; int proceed = 0, ovector[30]; char *substituted = NULL; char *substituted_2 = NULL; char *uri; char *uri_expanded = NULL; enum_route_t *route; int supported = 0; uint32_t len = 0; if ((proceed = switch_regex_perform(number, regex, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) { if (strchr(regex, '(')) { len = (uint32_t) (strlen(number) + strlen(replace) + 10) * proceed; if (!(substituted = malloc(len))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n"); switch_regex_safe_free(re); goto end; } memset(substituted, 0, len); switch_perform_substitution(re, proceed, replace, number, substituted, len, ovector); uri = substituted; } else { uri = replace; } switch_mutex_lock(MUTEX); for (route = globals.route_order; route; route = route->next) { if (strcasecmp(service, route->service)) { continue; } if ((proceed = switch_regex_perform(uri, route->regex, &re2, ovector, sizeof(ovector) / sizeof(ovector[0])))) { switch_event_t *event = NULL; if (strchr(route->regex, '(')) { len = (uint32_t) (strlen(uri) + strlen(route->replace) + 10) * proceed; if (!(substituted_2 = malloc(len))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n"); switch_safe_free(substituted); switch_regex_safe_free(re); switch_regex_safe_free(re2); switch_mutex_unlock(MUTEX); goto end; } memset(substituted_2, 0, len); switch_perform_substitution(re2, proceed, route->replace, uri, substituted_2, len, ovector); uri = substituted_2; } else { uri = route->replace; } switch_event_create(&event, SWITCH_EVENT_REQUEST_PARAMS); uri_expanded = switch_event_expand_headers(event, uri); switch_event_destroy(&event); if (uri_expanded == uri) { uri_expanded = NULL; } else { uri = uri_expanded; } supported++; add_result(results, order, preference, service, uri, supported); } switch_safe_free(uri_expanded); switch_safe_free(substituted_2); switch_regex_safe_free(re2); } switch_mutex_unlock(MUTEX); if (!supported) { add_result(results, order, preference, service, uri, 0); } switch_safe_free(substituted); switch_regex_safe_free(re); } } end: switch_safe_free(str); return; }
/* State methods they get called when the state changes to the specific state returning SWITCH_STATUS_SUCCESS tells the core to execute the standard state method next so if you fully implement the state you can return SWITCH_STATUS_FALSE to skip it. */ static switch_status_t channel_on_init(switch_core_session_t *session) { switch_channel_t *channel, *b_channel; loopback_private_t *tech_pvt = NULL, *b_tech_pvt = NULL; switch_core_session_t *b_session; char name[128]; switch_caller_profile_t *caller_profile; switch_event_t *vars = NULL; const char *var; switch_status_t status = SWITCH_STATUS_FALSE; tech_pvt = switch_core_session_get_private(session); switch_assert(tech_pvt != NULL); channel = switch_core_session_get_channel(session); switch_assert(channel != NULL); if (switch_test_flag(tech_pvt, TFLAG_OUTBOUND) && !switch_test_flag(tech_pvt, TFLAG_BLEG)) { if (!(b_session = switch_core_session_request(loopback_endpoint_interface, SWITCH_CALL_DIRECTION_INBOUND, SOF_NONE, NULL))) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Failure.\n"); goto end; } if (switch_core_session_read_lock(b_session) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Failure.\n"); switch_core_session_destroy(&b_session); goto end; } switch_core_session_add_stream(b_session, NULL); b_channel = switch_core_session_get_channel(b_session); b_tech_pvt = (loopback_private_t *) switch_core_session_alloc(b_session, sizeof(*b_tech_pvt)); switch_snprintf(name, sizeof(name), "loopback/%s-b", tech_pvt->caller_profile->destination_number); switch_channel_set_name(b_channel, name); if (tech_init(b_tech_pvt, b_session, switch_core_session_get_read_codec(session)) != SWITCH_STATUS_SUCCESS) { switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); switch_core_session_destroy(&b_session); goto end; } caller_profile = switch_caller_profile_clone(b_session, tech_pvt->caller_profile); caller_profile->source = switch_core_strdup(caller_profile->pool, modname); switch_channel_set_caller_profile(b_channel, caller_profile); b_tech_pvt->caller_profile = caller_profile; switch_channel_set_state(b_channel, CS_INIT); switch_mutex_lock(tech_pvt->mutex); tech_pvt->other_session = b_session; tech_pvt->other_tech_pvt = b_tech_pvt; tech_pvt->other_channel = b_channel; switch_mutex_unlock(tech_pvt->mutex); //b_tech_pvt->other_session = session; //b_tech_pvt->other_tech_pvt = tech_pvt; //b_tech_pvt->other_channel = channel; b_tech_pvt->other_uuid = switch_core_session_strdup(b_session, switch_core_session_get_uuid(session)); switch_set_flag_locked(tech_pvt, TFLAG_LINKED); switch_set_flag_locked(b_tech_pvt, TFLAG_LINKED); switch_set_flag_locked(b_tech_pvt, TFLAG_BLEG); switch_channel_set_flag(channel, CF_ACCEPT_CNG); if ((vars = (switch_event_t *) switch_channel_get_private(channel, "__loopback_vars__"))) { switch_event_header_t *h; switch_channel_set_private(channel, "__loopback_vars__", NULL); for (h = vars->headers; h; h = h->next) { switch_channel_set_variable(tech_pvt->other_channel, h->name, h->value); } switch_event_destroy(&vars); } if ((var = switch_channel_get_variable(channel, "loopback_export"))) { int argc = 0; char *argv[128] = { 0 }; char *dup = switch_core_session_strdup(session, var); if ((argc = switch_split(dup, ',', argv))) { int i; for (i = 0; i < argc; i++) { if (!zstr(argv[i])) { const char *val = switch_channel_get_variable(channel, argv[i]); if(!zstr(val)) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Transfer variable [%s]=[%s] %s -> %s\n", argv[i], val, switch_channel_get_name(channel), switch_channel_get_name(tech_pvt->other_channel)); switch_channel_set_variable(tech_pvt->other_channel, argv[i], val); } } } } } if (switch_test_flag(tech_pvt, TFLAG_APP)) { switch_set_flag(b_tech_pvt, TFLAG_APP); switch_clear_flag(tech_pvt, TFLAG_APP); } switch_channel_set_variable(channel, "other_loopback_leg_uuid", switch_channel_get_uuid(b_channel)); switch_channel_set_variable(b_channel, "other_loopback_leg_uuid", switch_channel_get_uuid(channel)); if (switch_core_session_thread_launch(b_session) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Error spawning thread\n"); switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); goto end; } } else { switch_mutex_lock(tech_pvt->mutex); if ((tech_pvt->other_session = switch_core_session_locate(tech_pvt->other_uuid))) { tech_pvt->other_tech_pvt = switch_core_session_get_private(tech_pvt->other_session); tech_pvt->other_channel = switch_core_session_get_channel(tech_pvt->other_session); } switch_mutex_unlock(tech_pvt->mutex); } if (!tech_pvt->other_session) { switch_clear_flag_locked(tech_pvt, TFLAG_LINKED); switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); goto end; } switch_channel_set_variable(channel, "loopback_leg", switch_test_flag(tech_pvt, TFLAG_BLEG) ? "B" : "A"); status = SWITCH_STATUS_SUCCESS; switch_channel_set_state(channel, CS_ROUTING); end: return status; }
static switch_status_t local_stream_file_open(switch_file_handle_t *handle, const char *path) { local_stream_context_t *context; local_stream_source_t *source; char *alt_path = NULL; switch_status_t status = SWITCH_STATUS_SUCCESS; /* already buffering a step back, so always disable it */ handle->pre_buffer_datalen = 0; if (switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "This format does not support writing!\n"); return SWITCH_STATUS_FALSE; } switch_mutex_lock(globals.mutex); top: alt_path = switch_mprintf("%s/%d", path, handle->samplerate); if ((source = switch_core_hash_find(globals.source_hash, alt_path))) { path = alt_path; } else { source = switch_core_hash_find(globals.source_hash, path); } if (source) { if (switch_thread_rwlock_tryrdlock(source->rwlock) != SWITCH_STATUS_SUCCESS) { source = NULL; } } else { if (!switch_stristr("default", alt_path) && !switch_stristr("default", path)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unknown source %s, trying 'default'\n", path); free(alt_path); path = "default"; goto top; } } switch_mutex_unlock(globals.mutex); if (!source) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unknown source %s\n", path); status = SWITCH_STATUS_FALSE; goto end; } if ((context = switch_core_alloc(handle->memory_pool, sizeof(*context))) == 0) { status = SWITCH_STATUS_MEMERR; goto end; } handle->samples = 0; handle->samplerate = source->rate; handle->channels = source->channels; handle->format = 0; handle->sections = 0; handle->seekable = 0; handle->speed = 0; handle->private_info = context; handle->interval = source->interval; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Opening Stream [%s] %dhz\n", path, handle->samplerate); switch_mutex_init(&context->audio_mutex, SWITCH_MUTEX_NESTED, handle->memory_pool); if (switch_buffer_create_dynamic(&context->audio_buffer, 512, 1024, 0) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n"); status = SWITCH_STATUS_MEMERR; goto end; } context->source = source; context->file = handle->file; context->func = handle->func; context->line = handle->line; context->handle = handle; switch_mutex_lock(source->mutex); context->next = source->context_list; source->context_list = context; source->total++; switch_mutex_unlock(source->mutex); end: switch_safe_free(alt_path); return status; }
static void *SWITCH_THREAD_FUNC api_exec(switch_thread_t *thread, void *obj) { switch_bool_t r = SWITCH_TRUE; struct api_command_struct *acs = (struct api_command_struct *) obj; switch_stream_handle_t stream = { 0 }; char *reply, *freply = NULL; switch_status_t status; if (!acs) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Internal error.\n"); return NULL; } if (!acs->listener || !acs->listener->rwlock || switch_thread_rwlock_tryrdlock(acs->listener->rwlock) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error! cannot get read lock.\n"); goto done; } SWITCH_STANDARD_STREAM(stream); if ((status = switch_api_execute(acs->api_cmd, acs->arg, NULL, &stream)) == SWITCH_STATUS_SUCCESS) { reply = stream.data; } else { freply = switch_mprintf("%s: Command not found!\n", acs->api_cmd); reply = freply; r = SWITCH_FALSE; } if (!reply) { reply = "Command returned no output!"; r = SWITCH_FALSE; } if (*reply == '-') r = SWITCH_FALSE; if (acs->bg) { switch_event_t *event; if (switch_event_create(&event, SWITCH_EVENT_BACKGROUND_JOB) == SWITCH_STATUS_SUCCESS) { ei_x_buff ebuf; switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Job-UUID", acs->uuid_str); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Job-Command", acs->api_cmd); ei_x_new_with_version(&ebuf); if (acs->arg) { switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Job-Command-Arg", acs->arg); } switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Job-Successful", r ? "true" : "false"); switch_event_add_body(event, "%s", reply); switch_event_fire(&event); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Sending bgapi reply to %s\n", acs->pid.node); ei_x_encode_tuple_header(&ebuf, 3); if (r) ei_x_encode_atom(&ebuf, "bgok"); else ei_x_encode_atom(&ebuf, "bgerror"); _ei_x_encode_string(&ebuf, acs->uuid_str); _ei_x_encode_string(&ebuf, reply); switch_mutex_lock(acs->listener->sock_mutex); ei_send(acs->listener->sockfd, &acs->pid, ebuf.buff, ebuf.index); switch_mutex_unlock(acs->listener->sock_mutex); #ifdef EI_DEBUG ei_x_print_msg(&ebuf, &acs->pid, 1); #endif ei_x_free(&ebuf); } } else { ei_x_buff rbuf; ei_x_new_with_version(&rbuf); ei_x_encode_tuple_header(&rbuf, 2); if (!strlen(reply)) { reply = "Command returned no output!"; r = SWITCH_FALSE; } if (r) { ei_x_encode_atom(&rbuf, "ok"); } else { ei_x_encode_atom(&rbuf, "error"); } _ei_x_encode_string(&rbuf, reply); switch_mutex_lock(acs->listener->sock_mutex); ei_send(acs->listener->sockfd, &acs->pid, rbuf.buff, rbuf.index); switch_mutex_unlock(acs->listener->sock_mutex); #ifdef EI_DEBUG ei_x_print_msg(&rbuf, &acs->pid, 1); #endif ei_x_free(&rbuf); } switch_safe_free(stream.data); switch_safe_free(freply); if (acs->listener->rwlock) { switch_thread_rwlock_unlock(acs->listener->rwlock); } done: if (acs->bg) { switch_memory_pool_t *pool = acs->pool; acs = NULL; switch_core_destroy_memory_pool(&pool); pool = NULL; } return NULL; }
static switch_status_t portaudio_stream_file_open(switch_file_handle_t *handle, const char *path) { portaudio_stream_context_t *context; portaudio_stream_source_t *source; switch_memory_pool_t *pool; switch_status_t status = SWITCH_STATUS_FALSE; switch_thread_t *thread; switch_threadattr_t *thd_attr = NULL; uint32_t rate = PREFERRED_RATE; char *npath; int devNumber; int tmp; handle->pre_buffer_datalen = 0; if (switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "This format does not support writing! (yet)\n"); return status; } npath = switch_core_strdup(module_pool, path); tmp = handle->samplerate; if (tmp == 8000 || tmp == 16000 || tmp == 32000 || tmp == 48000) { rate = tmp; } if (*path == '#') { devNumber = get_dev_by_number(npath + 1, 1); } else { devNumber = get_dev_by_name(npath, 1); } npath = switch_mprintf("device-%d at %d", devNumber, rate); switch_mutex_lock(globals.mutex); source = switch_core_hash_find(globals.source_hash, npath); /* dev isnt there, try to start thread */ if (!source) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, " source isnt Created, create and start thread!\n"); if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, " :S no pool\n"); } else { source = switch_core_alloc(pool, sizeof(*source)); if (source != NULL) { source->pool = pool; source->sourcedev = devNumber; source->sourcename = switch_core_strdup(source->pool, npath); source->rate = rate; source->interval = 20; source->channels = 1; source->timer_name = "soft"; source->prebuf = DEFAULT_PREBUFFER_SIZE; source->stopped = 0; source->ready = 0; source->samples = switch_samples_per_packet(source->rate, source->interval); switch_mutex_init(&source->mutex, SWITCH_MUTEX_NESTED, source->pool); switch_threadattr_create(&thd_attr, source->pool); switch_threadattr_detach_set(thd_attr, 1); switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE); switch_thread_create(&thread, thd_attr, read_stream_thread, source, source->pool); } } } switch_mutex_unlock(globals.mutex); switch_yield(1000000); /* dev already engaged */ if (source) { /*wait for source to be ready */ while (source->ready == 0) { switch_yield(100000); } if (switch_thread_rwlock_tryrdlock(source->rwlock) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, " error rwlock !\n"); source = NULL; } } if (source) { status = SWITCH_STATUS_SUCCESS; if ((context = switch_core_alloc(handle->memory_pool, sizeof(*context))) == 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, " error allocating context!\n"); status = SWITCH_STATUS_MEMERR; } else { /* everything goes fine at this point */ handle->samples = 0; handle->samplerate = source->rate; handle->channels = 1; handle->format = 0; handle->sections = 0; handle->seekable = 0; handle->speed = 0; handle->private_info = context; handle->interval = source->interval; switch_mutex_init(&context->audio_mutex, SWITCH_MUTEX_NESTED, handle->memory_pool); if (switch_buffer_create_dynamic(&context->audio_buffer, 512, 1024, 0) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n"); status = SWITCH_STATUS_MEMERR; } else { /* context created... then continue */ context->source = source; context->file = handle->file; context->func = handle->func; context->line = handle->line; context->handle = handle; switch_mutex_lock(source->mutex); context->next = source->context_list; source->context_list = context; source->total++; switch_mutex_unlock(source->mutex); } } } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unknown source %s\n", path); status = SWITCH_STATUS_FALSE; } return status; }
static switch_status_t handle_ref_tuple(listener_t *listener, erlang_msg * msg, ei_x_buff * buf, ei_x_buff * rbuf) { erlang_ref ref; erlang_pid *pid; char hash[100]; int arity; const void *key; void *val; session_elem_t *se; switch_hash_index_t *iter; ei_decode_tuple_header(buf->buff, &buf->index, &arity); if (ei_decode_ref(buf->buff, &buf->index, &ref)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid reference\n"); return SWITCH_STATUS_FALSE; } if (!(pid = malloc(sizeof(erlang_pid)))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error\n"); ei_x_encode_tuple_header(rbuf, 2); ei_x_encode_atom(rbuf, "error"); ei_x_encode_atom(rbuf, "badmem"); return SWITCH_STATUS_SUCCESS; } if (ei_decode_pid(buf->buff, &buf->index, pid)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid pid in a reference/pid tuple\n"); return SWITCH_STATUS_FALSE; } ei_hash_ref(&ref, hash); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Hashed ref to %s\n", hash); switch_thread_rwlock_rdlock(listener->session_rwlock); for (iter = switch_hash_first(NULL, listener->sessions); iter; iter = switch_hash_next(iter)) { switch_hash_this(iter, &key, NULL, &val); se = (session_elem_t*)val; if (se->spawn_reply && !strncmp(se->spawn_reply->hash, hash, 100)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "found matching session for %s : %s\n", hash, se->uuid_str); switch_mutex_lock(se->spawn_reply->mutex); if (se->spawn_reply->state == reply_not_ready) { switch_thread_cond_wait(se->spawn_reply->ready_or_found, se->spawn_reply->mutex); } if (se->spawn_reply->state == reply_waiting) { se->spawn_reply->pid = pid; switch_thread_cond_broadcast(se->spawn_reply->ready_or_found); ei_x_encode_atom(rbuf, "ok"); switch_thread_rwlock_unlock(listener->session_rwlock); switch_mutex_unlock(se->spawn_reply->mutex); return SWITCH_STATUS_SUCCESS; } switch_mutex_unlock(se->spawn_reply->mutex); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "get_pid came in too late for %s; %s\n", hash, se->uuid_str); break; } } switch_thread_rwlock_unlock(listener->session_rwlock); ei_x_encode_tuple_header(rbuf, 2); ei_x_encode_atom(rbuf, "error"); ei_x_encode_atom(rbuf, "notfound"); switch_safe_free(pid); /* don't need it */ return SWITCH_STATUS_SUCCESS; }
SWITCH_DECLARE(switch_status_t) switch_core_media_bug_read(switch_media_bug_t *bug, switch_frame_t *frame, switch_bool_t fill) { switch_size_t bytes = 0, datalen = 0, ttl = 0; int16_t *dp, *fp; uint32_t x; size_t rlen = 0; size_t wlen = 0; uint32_t blen; switch_codec_implementation_t read_impl = { 0 }; int16_t *tp; switch_core_session_get_read_impl(bug->session, &read_impl); bytes = read_impl.decoded_bytes_per_packet; if (frame->buflen < bytes) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(switch_core_media_bug_get_session(bug)), SWITCH_LOG_ERROR, "%s frame buffer too small!\n", switch_channel_get_name(bug->session->channel)); return SWITCH_STATUS_FALSE; } if (!(bug->raw_read_buffer && (bug->raw_write_buffer || !switch_test_flag(bug, SMBF_WRITE_STREAM)))) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(switch_core_media_bug_get_session(bug)), SWITCH_LOG_ERROR, "%s Buffer Error\n", switch_channel_get_name(bug->session->channel)); return SWITCH_STATUS_FALSE; } frame->flags = 0; frame->datalen = 0; if (!switch_buffer_inuse(bug->raw_read_buffer)) { return SWITCH_STATUS_FALSE; } switch_mutex_lock(bug->read_mutex); frame->datalen = (uint32_t) switch_buffer_read(bug->raw_read_buffer, frame->data, bytes); ttl += frame->datalen; switch_mutex_unlock(bug->read_mutex); if (switch_test_flag(bug, SMBF_WRITE_STREAM)) { switch_assert(bug->raw_write_buffer); switch_mutex_lock(bug->write_mutex); datalen = (uint32_t) switch_buffer_read(bug->raw_write_buffer, bug->data, bytes); ttl += datalen; if (fill && datalen < bytes) { memset(((unsigned char *) bug->data) + datalen, 0, bytes - datalen); datalen = bytes; } switch_mutex_unlock(bug->write_mutex); } tp = bug->tmp; dp = (int16_t *) bug->data; fp = (int16_t *) frame->data; rlen = frame->datalen / 2; wlen = datalen / 2; blen = bytes / 2; if (!fill && rlen == 0 && wlen == 0) { frame->datalen = 0; frame->samples = 0; frame->rate = read_impl.actual_samples_per_second; frame->codec = NULL; return SWITCH_STATUS_FALSE; } if (switch_test_flag(bug, SMBF_STEREO)) { for (x = 0; x < blen; x++) { if (x < rlen) { *(tp++) = *(fp + x); } else { *(tp++) = 0; } if (x < wlen) { *(tp++) = *(dp + x); } else { *(tp++) = 0; } } memcpy(frame->data, bug->tmp, bytes * 2); } else { for (x = 0; x < blen; x++) { int32_t z = 0; if (x < rlen) { z += (int32_t) * (fp + x); } if (x < wlen) { z += (int32_t) * (dp + x); } switch_normalize_to_16bit(z); *(fp + x) = (int16_t) z / 2; } } if (!ttl) { switch_set_flag(frame, SFF_CNG); } frame->datalen = bytes; frame->samples = bytes / sizeof(int16_t); frame->rate = read_impl.actual_samples_per_second; frame->codec = NULL; return SWITCH_STATUS_SUCCESS; }
static int load_config(int reloading) { struct dist_list *main_list = NULL, *new_list, *old_list = NULL, *lp = NULL; switch_status_t status = SWITCH_STATUS_FALSE; char *cf = "distributor.conf"; switch_xml_t cfg, xml, lists, list, param; if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", cf); return SWITCH_STATUS_TERM; } if (!(lists = switch_xml_child(cfg, "lists"))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't find any lists!\n"); return status; } switch_mutex_lock(globals.mod_lock); for (list = switch_xml_child(lists, "list"); list; list = list->next) { const char *name = switch_xml_attr(list, "name"); const char *tweight = switch_xml_attr(list, "total-weight"); struct dist_node *node, *np = NULL; if (zstr(name)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing NAME!\n"); continue; } if (!zstr(tweight)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "The total-weight attribute is no longer necessary.\n"); } switch_zmalloc(new_list, sizeof(*new_list)); new_list->name = strdup(name); new_list->last = -1; if (lp) { lp->next = new_list; } else { main_list = new_list; } lp = new_list; for (param = switch_xml_child(list, "node"); param; param = param->next) { char *name_attr = (char *) switch_xml_attr_soft(param, "name"); char *weight_val = (char *) switch_xml_attr_soft(param, "weight"); int tmp; if ((tmp = atoi(weight_val)) < 1) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Weight %d value incorrect, must be > 0\n", tmp); continue; } switch_zmalloc(node, sizeof(*node)); node->name = strdup(name_attr); node->wval = tmp; if (np) { np->next = node; } else { lp->nodes = node; } np = node; lp->node_count++; } calc_weight(lp); } if (main_list) { old_list = globals.list; globals.list = main_list; status = SWITCH_STATUS_SUCCESS; } switch_mutex_unlock(globals.mod_lock); if (old_list) { destroy_list(old_list); } if (xml) { switch_xml_free(xml); } return status; }
void AsyncIOServer::OnRecvEvent(Socket* socket) { Client* client = (Client *)(socket->data); if( client != NULL ) { // switch_log_printf( // SWITCH_CHANNEL_LOG, // SWITCH_LOG_DEBUG, // "AsyncIOServer::OnRecvEvent( client : %p, socket : %p ) \n", // client, // socket // ); // 尝试读取数据 char buf[READ_BUFFER_SIZE]; switch_size_t len = sizeof(buf); switch_status_t status = SWITCH_STATUS_SUCCESS; bool disconnect = false; // 有足够的缓存空间 if( client->CheckBufferEnough() ) { while (true) { status = mTcpServer.Read(socket, (char *)buf, &len); // status = switch_socket_recv(socket->socket, (char *)buf, &len); if( status == SWITCH_STATUS_SUCCESS ) { // 读取数据成功, 缓存到客户端 // switch_log_printf( // SWITCH_CHANNEL_LOG, // SWITCH_LOG_DEBUG, // "AsyncIOServer::OnRecvEvent( client : %p, socket : %p, read ok ) \n", // client, // socket // ); if( client->Write(buf, len) ) { // 放到处理队列 // switch_log_printf( // SWITCH_CHANNEL_LOG, // SWITCH_LOG_DEBUG, // "AsyncIOServer::OnRecvEvent( client : %p, socket : %p, client write buffer ok ) \n", // client, // socket // ); RecvHandle(client); } else { // 没有足够的缓存空间 switch_log_printf( SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "AsyncIOServer::OnRecvEvent( client : %p, socket : %p, write error ) \n", client, socket ); disconnect = true; break; } } else if( SWITCH_STATUS_IS_BREAK(status) /*|| (status == SWITCH_STATUS_INTR)*/ ) { // 没有数据可读超时返回, 不处理 // switch_log_printf( // SWITCH_CHANNEL_LOG, // SWITCH_LOG_DEBUG, // "AsyncIOServer::OnRecvEvent( client : %p, socket : %p, nothing to read ) \n", // client, // socket // ); break; } else { // 读取数据出错, 断开 switch_log_printf( SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "AsyncIOServer::OnRecvEvent( client : %p, socket : %p, read error : %d ) \n", client, socket, status ); disconnect = true; break; } } } else { // 缓存数据过大, 断开 switch_log_printf( SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "AsyncIOServer::OnRecvEvent( client : %p, socket : %p, buffer not enough error ) \n", client, socket ); disconnect = true; } if( disconnect ) { Disconnect(client); } bool bFlag = false; switch_mutex_lock(client->clientMutex); bFlag = ClientCloseIfNeed(client); switch_mutex_unlock(client->clientMutex); if( bFlag ) { // 回调 if( mpAsyncIOServerCallback ) { mpAsyncIOServerCallback->OnDisconnect(client); } // 关闭Socket mTcpServer.Close(client->socket); // 销毁客户端 Client::Destroy(client); } } }
SWITCH_DECLARE(void) switch_core_session_run(switch_core_session_t *session) { switch_channel_state_t state = CS_NEW, midstate = CS_DESTROY, endstate; const switch_endpoint_interface_t *endpoint_interface; const switch_state_handler_table_t *driver_state_handler = NULL; const switch_state_handler_table_t *application_state_handler = NULL; int silly = 0; uint32_t new_loops = 60000; /* Life of the channel. you have channel and pool in your session everywhere you go you use the session to malloc with switch_core_session_alloc(session, <size>) The endpoint module gets the first crack at implementing the state if it wants to, it can cancel the default behavior by returning SWITCH_STATUS_FALSE Next comes the channel's event handler table that can be set by an application which also can veto the next behavior in line by returning SWITCH_STATUS_FALSE Finally the default state behavior is called. */ switch_assert(session != NULL); switch_set_flag(session, SSF_THREAD_RUNNING); endpoint_interface = session->endpoint_interface; switch_assert(endpoint_interface != NULL); driver_state_handler = endpoint_interface->state_handler; switch_assert(driver_state_handler != NULL); switch_mutex_lock(session->mutex); while ((state = switch_channel_get_state(session->channel)) != CS_DESTROY) { if (switch_channel_test_flag(session->channel, CF_BLOCK_STATE)) { switch_channel_wait_for_flag(session->channel, CF_BLOCK_STATE, SWITCH_FALSE, 0, NULL); if ((state = switch_channel_get_state(session->channel)) == CS_DESTROY) { break; } } midstate = state; if (state != switch_channel_get_running_state(session->channel) || state >= CS_HANGUP) { int index = 0; int proceed = 1; int global_proceed = 1; int do_extra_handlers = 1; switch_io_event_hook_state_run_t *ptr; switch_status_t rstatus = SWITCH_STATUS_SUCCESS; switch_channel_set_running_state(session->channel, state); switch_channel_clear_flag(session->channel, CF_TRANSFER); switch_channel_clear_flag(session->channel, CF_REDIRECT); if (session->endpoint_interface->io_routines->state_run) { rstatus = session->endpoint_interface->io_routines->state_run(session); } if (rstatus == SWITCH_STATUS_SUCCESS) { for (ptr = session->event_hooks.state_run; ptr; ptr = ptr->next) { if ((rstatus = ptr->state_run(session)) != SWITCH_STATUS_SUCCESS) { break; } } } switch (state) { case CS_NEW: /* Just created, Waiting for first instructions */ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "(%s) State NEW\n", switch_channel_get_name(session->channel)); break; case CS_DESTROY: goto done; case CS_REPORTING: /* Call Detail */ { switch_core_session_reporting_state(session); switch_channel_set_state(session->channel, CS_DESTROY); } goto done; case CS_HANGUP: /* Deactivate and end the thread */ { switch_core_session_hangup_state(session, SWITCH_TRUE); switch_channel_set_state(session->channel, CS_REPORTING); } break; case CS_INIT: /* Basic setup tasks */ { switch_event_t *event; STATE_MACRO(init, "INIT"); if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_CREATE) == SWITCH_STATUS_SUCCESS) { switch_channel_event_set_data(session->channel, event); switch_event_fire(&event); } } break; case CS_ROUTING: /* Look for a dialplan and find something to do */ STATE_MACRO(routing, "ROUTING"); break; case CS_RESET: /* Reset */ STATE_MACRO(reset, "RESET"); break; /* These other states are intended for prolonged durations so we do not signal lock for them */ case CS_EXECUTE: /* Execute an Operation */ STATE_MACRO(execute, "EXECUTE"); break; case CS_EXCHANGE_MEDIA: /* loop all data back to source */ STATE_MACRO(exchange_media, "EXCHANGE_MEDIA"); break; case CS_SOFT_EXECUTE: /* send/recieve data to/from another channel */ STATE_MACRO(soft_execute, "SOFT_EXECUTE"); break; case CS_PARK: /* wait in limbo */ STATE_MACRO(park, "PARK"); break; case CS_CONSUME_MEDIA: /* wait in limbo */ STATE_MACRO(consume_media, "CONSUME_MEDIA"); break; case CS_HIBERNATE: /* sleep */ STATE_MACRO(hibernate, "HIBERNATE"); break; case CS_NONE: abort(); break; } if (midstate == CS_DESTROY) { break; } } endstate = switch_channel_get_state(session->channel); if (endstate == switch_channel_get_running_state(session->channel)) { if (endstate == CS_NEW) { switch_cond_next(); switch_ivr_parse_all_events(session); if (!--new_loops) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "%s Timeout waiting for next instruction in CS_NEW!\n", session->uuid_str); switch_channel_hangup(session->channel, SWITCH_CAUSE_INVALID_CALL_REFERENCE); } } else { switch_ivr_parse_all_events(session); switch_ivr_parse_all_events(session); if (switch_channel_get_state(session->channel) == switch_channel_get_running_state(session->channel)) { switch_channel_set_flag(session->channel, CF_THREAD_SLEEPING); if (switch_channel_get_state(session->channel) == switch_channel_get_running_state(session->channel)) { switch_thread_cond_wait(session->cond, session->mutex); } switch_channel_clear_flag(session->channel, CF_THREAD_SLEEPING); } switch_ivr_parse_all_events(session); switch_ivr_parse_all_events(session); } } } done: switch_mutex_unlock(session->mutex); switch_clear_flag(session, SSF_THREAD_RUNNING); }
/*! function to load a grammar to the asr interface */ static switch_status_t pocketsphinx_asr_load_grammar(switch_asr_handle_t *ah, const char *grammar, const char *name) { char *jsgf, *dic, *model, *rate = NULL; pocketsphinx_t *ps = (pocketsphinx_t *) ah->private_info; switch_status_t status = SWITCH_STATUS_FALSE; if (switch_test_flag(ps, PSFLAG_READY)) { ps_end_utt(ps->ps); switch_clear_flag(ps, PSFLAG_READY); } if (switch_is_file_path(grammar)) { char *dot = strrchr(grammar, '.'); if (dot && !strcmp(dot, ".gram")) { jsgf = strdup(grammar); } else { jsgf = switch_mprintf("%s.gram", grammar); } } else { jsgf = switch_mprintf("%s%s%s.gram", SWITCH_GLOBAL_dirs.grammar_dir, SWITCH_PATH_SEPARATOR, grammar); } if (ah->rate == 8000) { model = switch_mprintf("%s%smodel%s%s", SWITCH_GLOBAL_dirs.grammar_dir, SWITCH_PATH_SEPARATOR, SWITCH_PATH_SEPARATOR, globals.model8k); } else { model = switch_mprintf("%s%smodel%s%s", SWITCH_GLOBAL_dirs.grammar_dir, SWITCH_PATH_SEPARATOR, SWITCH_PATH_SEPARATOR, globals.model16k); } dic = switch_mprintf("%s%s%s", SWITCH_GLOBAL_dirs.grammar_dir, SWITCH_PATH_SEPARATOR, globals.dictionary); if (switch_file_exists(dic, ah->memory_pool) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open dictionary %s.\n", dic); goto end; } if (switch_file_exists(model, ah->memory_pool) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Can't open speech model %s.\n", model); goto end; } if (switch_file_exists(jsgf, ah->memory_pool) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Can't open grammar file %s.\n", jsgf); goto end; } rate = switch_mprintf("%d", ah->rate); switch_assert(jsgf && dic && model); ps->config = cmd_ln_init(ps->config, ps_args(), FALSE, "-samprate", rate, "-hmm", model, "-jsgf", jsgf, "-lw", globals.language_weight, "-dict", dic, "-frate", "50", "-silprob", "0.005", NULL); if (ps->config == NULL) { status = SWITCH_STATUS_GENERR; goto end; } switch_mutex_lock(ps->flag_mutex); if (switch_test_flag(ps, PSFLAG_ALLOCATED)) { ps_reinit(ps->ps, ps->config); } else { if (!(ps->ps = ps_init(ps->config))) { switch_mutex_unlock(ps->flag_mutex); goto end; } switch_set_flag(ps, PSFLAG_ALLOCATED); } switch_mutex_unlock(ps->flag_mutex); ps_start_utt(ps->ps, NULL); switch_set_flag(ps, PSFLAG_READY); switch_safe_free(ps->grammar); ps->grammar = strdup(grammar); status = SWITCH_STATUS_SUCCESS; end: switch_safe_free(rate); switch_safe_free(jsgf); switch_safe_free(dic); switch_safe_free(model); return status; }
SWITCH_DECLARE(switch_status_t) switch_core_session_set_read_codec(switch_core_session_t *session, switch_codec_t *codec) { switch_event_t *event; switch_channel_t *channel = switch_core_session_get_channel(session); char tmp[30]; switch_status_t status = SWITCH_STATUS_SUCCESS; switch_mutex_lock(session->codec_read_mutex); if (codec && (!codec->implementation || !switch_core_codec_ready(codec))) { codec = NULL; } if (codec) { if (!session->real_read_codec) { session->read_codec = session->real_read_codec = codec; if (codec->implementation) { session->read_impl = *codec->implementation; session->real_read_impl = *codec->implementation; } else { memset(&session->read_impl, 0, sizeof(session->read_impl)); } } else { if (codec == session->read_codec) { goto end; } switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Push codec %s:%d\n", switch_channel_get_name(session->channel), codec->implementation->iananame, codec->implementation->ianacode); codec->next = session->read_codec; session->read_codec = codec; if (codec->implementation) { session->read_impl = *codec->implementation; } else { memset(&session->read_impl, 0, sizeof(session->read_impl)); } } } else { if (session->read_codec == session->real_read_codec) { goto end; } if (session->read_codec->next) { switch_codec_t *old = session->read_codec; session->read_codec = session->read_codec->next; if (session->read_codec->implementation) { session->read_impl = *session->read_codec->implementation; } else { memset(&session->read_impl, 0, sizeof(session->read_impl)); } old->next = NULL; switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Restore previous codec %s:%d.\n", switch_channel_get_name(session->channel), session->read_impl.iananame ? session->read_impl.iananame : "N/A", session->read_impl.ianacode); } else if (session->real_read_codec) { session->read_codec = session->real_read_codec; if (session->real_read_codec->implementation) { session->read_impl = *session->real_read_codec->implementation; } else { memset(&session->read_impl, 0, sizeof(session->read_impl)); } switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Restore original codec.\n"); } else { status = SWITCH_STATUS_FALSE; goto end; } } if (!session->read_codec) { status = SWITCH_STATUS_FALSE; goto end; } if (session->read_codec && session->read_impl.decoded_bytes_per_packet) { if (switch_event_create(&event, SWITCH_EVENT_CODEC) == SWITCH_STATUS_SUCCESS) { switch_channel_event_set_data(session->channel, event); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "channel-read-codec-name", session->read_impl.iananame); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "channel-read-codec-rate", "%d", session->read_impl.actual_samples_per_second); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "channel-read-codec-bit-rate", "%d", session->read_impl.bits_per_second); if (session->read_impl.actual_samples_per_second != session->read_impl.samples_per_second) { switch_event_add_header(event, SWITCH_STACK_BOTTOM, "channel-reported-read-codec-rate", "%d", session->read_impl.samples_per_second); } switch_event_fire(&event); } switch_channel_set_variable(channel, "read_codec", session->read_impl.iananame); switch_snprintf(tmp, sizeof(tmp), "%d", session->read_impl.actual_samples_per_second); switch_channel_set_variable(channel, "read_rate", tmp); session->raw_read_frame.codec = session->read_codec; session->raw_write_frame.codec = session->read_codec; session->enc_read_frame.codec = session->read_codec; session->enc_write_frame.codec = session->read_codec; } end: if (session->read_codec) { switch_channel_set_flag(channel, CF_MEDIA_SET); } switch_mutex_unlock(session->codec_read_mutex); return status; }
static void do_load(void) { switch_mutex_lock(MUTEX); load_config(); switch_mutex_unlock(MUTEX); }
SWITCH_DECLARE(void) switch_core_session_lock_codec_read(switch_core_session_t *session) { switch_mutex_lock(session->codec_read_mutex); }
int handle_msg(listener_t *listener, erlang_msg * msg, ei_x_buff * buf, ei_x_buff * rbuf) { int type, type2, size, version, arity, tmpindex; switch_status_t ret = SWITCH_STATUS_SUCCESS; if (msg->msgtype == ERL_REG_SEND && !strncmp(msg->toname, "net_kernel", MAXATOMLEN)) { /* try to respond to ping stuff */ ret = handle_net_kernel_msg(listener, msg, buf, rbuf); } else { buf->index = 0; ei_decode_version(buf->buff, &buf->index, &version); ei_get_type(buf->buff, &buf->index, &type, &size); switch (type) { case ERL_SMALL_TUPLE_EXT: case ERL_LARGE_TUPLE_EXT: tmpindex = buf->index; ei_decode_tuple_header(buf->buff, &tmpindex, &arity); ei_get_type(buf->buff, &tmpindex, &type2, &size); switch (type2) { case ERL_ATOM_EXT: ret = handle_msg_tuple(listener, msg, buf, rbuf); break; case ERL_REFERENCE_EXT: case ERL_NEW_REFERENCE_EXT: ret = handle_ref_tuple(listener, msg, buf, rbuf); break; default: switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "WEEEEEEEE %d %d\n", type, type2); /* some other kind of erlang term */ ei_x_encode_tuple_header(rbuf, 2); ei_x_encode_atom(rbuf, "error"); ei_x_encode_atom(rbuf, "undef"); break; } break; case ERL_ATOM_EXT: ret = handle_msg_atom(listener, msg, buf, rbuf); break; default: /* some other kind of erlang term */ ei_x_encode_tuple_header(rbuf, 2); ei_x_encode_atom(rbuf, "error"); ei_x_encode_atom(rbuf, "undef"); break; } } if (SWITCH_STATUS_FALSE == ret) { return 0; } else if (rbuf->index > 1) { switch_mutex_lock(listener->sock_mutex); ei_send(listener->sockfd, &msg->from, rbuf->buff, rbuf->index); switch_mutex_unlock(listener->sock_mutex); #ifdef EI_DEBUG ei_x_print_msg(rbuf, &msg->from, 1); #endif if (SWITCH_STATUS_SUCCESS == ret) return 0; else /* SWITCH_STATUS_TERM */ return 1; } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Empty reply, supressing\n"); return 0; } }
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; }
static switch_status_t handle_msg_fetch_reply(listener_t *listener, ei_x_buff * buf, ei_x_buff * rbuf) { char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1]; fetch_reply_t *p; if (ei_decode_string_or_binary(buf->buff, &buf->index, SWITCH_UUID_FORMATTED_LENGTH, uuid_str)) { ei_x_encode_tuple_header(rbuf, 2); ei_x_encode_atom(rbuf, "error"); ei_x_encode_atom(rbuf, "badarg"); } else { ei_x_buff *nbuf = malloc(sizeof(nbuf)); nbuf->buff = malloc(buf->buffsz); memcpy(nbuf->buff, buf->buff, buf->buffsz); nbuf->index = buf->index; nbuf->buffsz = buf->buffsz; switch_mutex_lock(globals.fetch_reply_mutex); if ((p = switch_core_hash_find(globals.fetch_reply_hash, uuid_str))) { /* Get the status and release the lock ASAP. */ enum { is_timeout, is_waiting, is_filled } status; if (p->state == reply_not_ready) { switch_thread_cond_wait(p->ready_or_found, globals.fetch_reply_mutex); } if (p->state == reply_waiting) { /* update the key with a reply */ status = is_waiting; p->reply = nbuf; p->state = reply_found; strncpy(p->winner, listener->peer_nodename, MAXNODELEN); switch_thread_cond_broadcast(p->ready_or_found); } else if (p->state == reply_timeout) { status = is_timeout; } else { status = is_filled; } put_reply_unlock(p, uuid_str); /* Relay the status back to the fetch responder. */ if (status == is_waiting) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Found waiting slot for %s\n", uuid_str); ei_x_encode_tuple_header(rbuf, 2); ei_x_encode_atom(rbuf, "ok"); _ei_x_encode_string(rbuf, uuid_str); /* Return here to avoid freeing the reply. */ return SWITCH_STATUS_SUCCESS; } else if (status == is_timeout) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Handler for %s timed out\n", uuid_str); ei_x_encode_tuple_header(rbuf, 3); ei_x_encode_atom(rbuf, "error"); _ei_x_encode_string(rbuf, uuid_str); ei_x_encode_atom(rbuf, "timeout"); } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Found filled slot for %s\n", uuid_str); ei_x_encode_tuple_header(rbuf, 3); ei_x_encode_atom(rbuf, "error"); _ei_x_encode_string(rbuf, uuid_str); ei_x_encode_atom(rbuf, "duplicate_response"); } } else { /* nothing in the hash */ switch_mutex_unlock(globals.fetch_reply_mutex); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Empty slot for %s\n", uuid_str); ei_x_encode_tuple_header(rbuf, 2); ei_x_encode_atom(rbuf, "error"); ei_x_encode_atom(rbuf, "invalid_uuid"); } switch_safe_free(nbuf->buff); switch_safe_free(nbuf); } return SWITCH_STATUS_SUCCESS; }
static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void *obj) { local_stream_source_t *source = obj; switch_file_handle_t fh = { 0 }; local_stream_context_t *cp; char file_buf[128] = "", path_buf[512] = ""; switch_timer_t timer = { 0 }; int fd = -1; switch_buffer_t *audio_buffer; switch_byte_t *dist_buf; switch_size_t used; int skip = 0; switch_memory_pool_t *temp_pool = NULL; switch_mutex_lock(globals.mutex); THREADS++; switch_mutex_unlock(globals.mutex); if (!source->prebuf) { source->prebuf = DEFAULT_PREBUFFER_SIZE; } switch_buffer_create_dynamic(&audio_buffer, 1024, source->prebuf + 10, 0); dist_buf = switch_core_alloc(source->pool, source->prebuf + 10); if (source->shuffle) { skip = do_rand(); } switch_thread_rwlock_create(&source->rwlock, source->pool); if (RUNNING) { switch_mutex_lock(globals.mutex); switch_core_hash_insert(globals.source_hash, source->name, source); switch_mutex_unlock(globals.mutex); source->ready = 1; } while (RUNNING && !source->stopped) { const char *fname; if (temp_pool) { switch_core_destroy_memory_pool(&temp_pool); } if (switch_core_new_memory_pool(&temp_pool) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error creating pool"); goto done; } if (switch_dir_open(&source->dir_handle, source->location, temp_pool) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Can't open directory: %s\n", source->location); goto done; } switch_yield(1000000); while (RUNNING && !source->stopped) { switch_size_t olen; uint8_t abuf[SWITCH_RECOMMENDED_BUFFER_SIZE] = { 0 }; if (fd > -1) { char *p; if (switch_fd_read_line(fd, path_buf, sizeof(path_buf))) { if ((p = strchr(path_buf, '\r')) || (p = strchr(path_buf, '\n'))) { *p = '\0'; } } else { close(fd); fd = -1; continue; } } else { if (!(fname = switch_dir_next_file(source->dir_handle, file_buf, sizeof(file_buf)))) { break; } switch_snprintf(path_buf, sizeof(path_buf), "%s%s%s", source->location, SWITCH_PATH_SEPARATOR, fname); if (switch_stristr(".loc", path_buf)) { if ((fd = open(path_buf, O_RDONLY)) < 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open %s\n", fname); switch_yield(1000000); } continue; } } if (skip > 0) { skip--; continue; } fname = path_buf; fh.prebuf = source->prebuf; fh.pre_buffer_datalen = source->prebuf; if (switch_core_file_open(&fh, (char *) fname, source->channels, source->rate, SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open %s\n", fname); switch_yield(1000000); continue; } if (switch_core_timer_init(&timer, source->timer_name, source->interval, (int)source->samples, temp_pool) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Can't start timer.\n"); switch_dir_close(source->dir_handle); source->dir_handle = NULL; goto done; } while (RUNNING && !source->stopped) { int is_open; switch_file_handle_t *use_fh = &fh; switch_core_timer_next(&timer); olen = source->samples; if (source->chime_total) { if (source->chime_counter > 0) { source->chime_counter -= (int32_t)source->samples; } if (!switch_test_flag((&source->chime_fh), SWITCH_FILE_OPEN) && source->chime_counter <= 0) { char *val; val = source->chime_list[source->chime_cur++]; if (source->chime_cur >= source->chime_total) { source->chime_cur = 0; } if (switch_core_file_open(&source->chime_fh, (char *) val, source->channels, source->rate, SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open %s\n", val); } } if (switch_test_flag((&source->chime_fh), SWITCH_FILE_OPEN)) { use_fh = &source->chime_fh; } } retry: is_open = switch_test_flag(use_fh, SWITCH_FILE_OPEN); if (source->hup) { source->hup = 0; if (is_open) { is_open = 0; switch_core_file_close(use_fh); if (use_fh == &source->chime_fh) { source->chime_counter = source->rate * source->chime_freq; use_fh = &fh; goto retry; //switch_core_file_close(&fh); } } } if (is_open) { if (switch_core_file_read(use_fh, abuf, &olen) != SWITCH_STATUS_SUCCESS || !olen) { switch_core_file_close(use_fh); if (use_fh == &source->chime_fh) { source->chime_counter = source->rate * source->chime_freq; } is_open = 0; } else { if (use_fh == &source->chime_fh && source->chime_max) { source->chime_max_counter += (int32_t)source->samples; if (source->chime_max_counter >= source->chime_max) { source->chime_max_counter = 0; switch_core_file_close(use_fh); source->chime_counter = source->rate * source->chime_freq; use_fh = &fh; goto retry; } } switch_buffer_write(audio_buffer, abuf, olen * 2); } } used = switch_buffer_inuse(audio_buffer); if (!used && !is_open) { break; } if (!is_open || used >= source->prebuf || (source->total && used > source->samples * 2)) { used = switch_buffer_read(audio_buffer, dist_buf, source->samples * 2); if (source->total) { uint32_t bused = 0; switch_mutex_lock(source->mutex); for (cp = source->context_list; cp && RUNNING; cp = cp->next) { if (switch_test_flag(cp->handle, SWITCH_FILE_CALLBACK)) { continue; } switch_mutex_lock(cp->audio_mutex); bused = (uint32_t)switch_buffer_inuse(cp->audio_buffer); if (bused > source->samples * 768) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Flushing Stream Handle Buffer [%s() %s:%d] size: %u samples: %ld\n", cp->func, cp->file, cp->line, bused, (long)source->samples); switch_buffer_zero(cp->audio_buffer); } else { switch_buffer_write(cp->audio_buffer, dist_buf, used); } switch_mutex_unlock(cp->audio_mutex); } switch_mutex_unlock(source->mutex); } } } switch_core_timer_destroy(&timer); if (RUNNING && source->shuffle) { skip = do_rand(); } } switch_dir_close(source->dir_handle); source->dir_handle = NULL; if (source->full_reload) { if (source->rwlock && switch_thread_rwlock_trywrlock(source->rwlock) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Cannot stop local_stream://%s because it is in use.\n",source->name); if (source->part_reload) { switch_xml_t cfg, xml, directory, param; if (!(xml = switch_xml_open_cfg(global_cf, &cfg, NULL))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", global_cf); } if ((directory = switch_xml_find_child(cfg, "directory", "name", source->name))) { for (param = switch_xml_child(directory, "param"); param; param = param->next) { char *var = (char *) switch_xml_attr_soft(param, "name"); char *val = (char *) switch_xml_attr_soft(param, "value"); if (!strcasecmp(var, "shuffle")) { source->shuffle = switch_true(val); } else if (!strcasecmp(var, "chime-freq")) { int tmp = atoi(val); if (tmp > 1) { source->chime_freq = tmp; } } else if (!strcasecmp(var, "chime-max")) { int tmp = atoi(val); if (tmp > 1) { source->chime_max = tmp; } } else if (!strcasecmp(var, "chime-list")) { char *list_dup = switch_core_strdup(source->pool, val); source->chime_total = switch_separate_string(list_dup, ',', source->chime_list, (sizeof(source->chime_list) / sizeof(source->chime_list[0]))); } else if (!strcasecmp(var, "interval")) { int tmp = atoi(val); if (SWITCH_ACCEPTABLE_INTERVAL(tmp)) { source->interval = tmp; } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Interval must be multiple of 10 and less than %d, Using default of 20\n", SWITCH_MAX_INTERVAL); } } if (source->chime_max) { source->chime_max *= source->rate; } if (source->chime_total) { source->chime_counter = source->rate * source->chime_freq; } } } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "local_stream://%s partially reloaded.\n",source->name); source->part_reload = 0; } } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "local_stream://%s fully reloaded.\n",source->name); launch_streams(source->name); goto done; } } } done: if (switch_test_flag((&fh), SWITCH_FILE_OPEN)) { switch_core_file_close(&fh); } if (switch_test_flag((&source->chime_fh), SWITCH_FILE_OPEN)) { switch_core_file_close(&source->chime_fh); } source->ready = 0; switch_mutex_lock(globals.mutex); switch_core_hash_delete(globals.source_hash, source->name); switch_mutex_unlock(globals.mutex); switch_thread_rwlock_wrlock(source->rwlock); switch_thread_rwlock_unlock(source->rwlock); switch_buffer_destroy(&audio_buffer); if (fd > -1) { close(fd); } if (temp_pool) { switch_core_destroy_memory_pool(&temp_pool); } switch_core_destroy_memory_pool(&source->pool); switch_mutex_lock(globals.mutex); THREADS--; switch_mutex_unlock(globals.mutex); return NULL; }
/** * Wraps file with interface that can be controlled by fileman flags * @param handle * @param path the file to play * @return SWITCH_STATUS_SUCCESS if opened */ static switch_status_t fileman_file_open(switch_file_handle_t *handle, const char *path) { int start_offset_ms = 0; switch_status_t status = SWITCH_STATUS_FALSE; struct fileman_file_context *context = switch_core_alloc(handle->memory_pool, sizeof(*context)); handle->private_info = context; if (handle->params) { const char *id = switch_event_get_header(handle->params, "id"); const char *uuid = switch_event_get_header(handle->params, "session"); const char *start_offset_ms_str = switch_event_get_header(handle->params, "start_offset_ms"); if (!zstr(id)) { context->id = switch_core_strdup(handle->memory_pool, id); } if (!zstr(uuid)) { context->uuid = switch_core_strdup(handle->memory_pool, uuid); } if (!zstr(start_offset_ms_str) && switch_is_number(start_offset_ms_str)) { start_offset_ms = atoi(start_offset_ms_str); if (start_offset_ms < 0) { start_offset_ms = 0; } } } switch_log_printf(SWITCH_CHANNEL_UUID_LOG(context->uuid), SWITCH_LOG_DEBUG, "Got path %s\n", path); if ((status = switch_core_file_open(&context->fh, path, handle->channels, handle->samplerate, handle->flags, NULL)) != SWITCH_STATUS_SUCCESS) { return status; } /* set up handle for external control */ if (!context->id) { /* use filename as ID */ context->id = switch_core_strdup(handle->memory_pool, path); } switch_mutex_lock(fileman_globals.mutex); if (!switch_core_hash_find(fileman_globals.hash, context->id)) { switch_core_hash_insert(fileman_globals.hash, context->id, handle); } else { switch_log_printf(SWITCH_CHANNEL_UUID_LOG(context->uuid), SWITCH_LOG_WARNING, "Duplicate fileman ID: %s\n", context->id); return SWITCH_STATUS_FALSE; } switch_mutex_unlock(fileman_globals.mutex); context->max_frame_len = (handle->samplerate / 1000 * SWITCH_MAX_INTERVAL); switch_zmalloc(context->abuf, FILE_STARTBYTES * sizeof(*context->abuf)); if (!context->fh.audio_buffer) { switch_log_printf(SWITCH_CHANNEL_UUID_LOG(context->uuid), SWITCH_LOG_DEBUG, "Create audio buffer\n"); switch_buffer_create_dynamic(&context->fh.audio_buffer, FILE_BLOCKSIZE, FILE_BUFSIZE, 0); switch_assert(context->fh.audio_buffer); } handle->samples = context->fh.samples; handle->format = context->fh.format; handle->sections = context->fh.sections; handle->seekable = context->fh.seekable; handle->speed = context->fh.speed; handle->vol = context->fh.vol; handle->offset_pos = context->fh.offset_pos; handle->interval = context->fh.interval; if (switch_test_flag((&context->fh), SWITCH_FILE_NATIVE)) { switch_set_flag(handle, SWITCH_FILE_NATIVE); } else { switch_clear_flag(handle, SWITCH_FILE_NATIVE); } if (handle->params && switch_true(switch_event_get_header(handle->params, "pause"))) { switch_set_flag(handle, SWITCH_FILE_PAUSE); } if (handle->seekable && start_offset_ms) { unsigned int pos = 0; int32_t target = start_offset_ms * (handle->samplerate / 1000); switch_log_printf(SWITCH_CHANNEL_UUID_LOG(context->uuid), SWITCH_LOG_DEBUG, "seek to position %d\n", target); switch_core_file_seek(&context->fh, &pos, target, SEEK_SET); } return status; }