/* NB. this starts the input thread after some initial setup for the call leg */ void conference_loop_output(conference_member_t *member) { switch_channel_t *channel; switch_frame_t write_frame = { 0 }; uint8_t *data = NULL; switch_timer_t timer = { 0 }; uint32_t interval; uint32_t samples; //uint32_t csamples; uint32_t tsamples; uint32_t flush_len; uint32_t low_count, bytes; call_list_t *call_list, *cp; switch_codec_implementation_t read_impl = { 0 }; int sanity; switch_status_t st; switch_core_session_get_read_impl(member->session, &read_impl); channel = switch_core_session_get_channel(member->session); interval = read_impl.microseconds_per_packet / 1000; samples = switch_samples_per_packet(member->conference->rate, interval); //csamples = samples; tsamples = member->orig_read_impl.samples_per_packet; low_count = 0; bytes = samples * 2 * member->conference->channels; call_list = NULL; cp = NULL; member->loop_loop = 0; switch_assert(member->conference != NULL); flush_len = switch_samples_per_packet(member->conference->rate, member->conference->interval) * 2 * member->conference->channels * (500 / member->conference->interval); if (switch_core_timer_init(&timer, member->conference->timer_name, interval, tsamples, NULL) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_ERROR, "Timer Setup Failed. Conference Cannot Start\n"); return; } switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_DEBUG, "Setup timer %s success interval: %u samples: %u\n", member->conference->timer_name, interval, tsamples); write_frame.data = data = switch_core_session_alloc(member->session, SWITCH_RECOMMENDED_BUFFER_SIZE); write_frame.buflen = SWITCH_RECOMMENDED_BUFFER_SIZE; write_frame.codec = &member->write_codec; /* Start the input thread */ conference_loop_launch_input(member, switch_core_session_get_pool(member->session)); if ((call_list = switch_channel_get_private(channel, "_conference_autocall_list_"))) { const char *cid_name = switch_channel_get_variable(channel, "conference_auto_outcall_caller_id_name"); const char *cid_num = switch_channel_get_variable(channel, "conference_auto_outcall_caller_id_number"); const char *toval = switch_channel_get_variable(channel, "conference_auto_outcall_timeout"); const char *flags = switch_channel_get_variable(channel, "conference_utils_auto_outcall_flags"); const char *profile = switch_channel_get_variable(channel, "conference_auto_outcall_profile"); const char *ann = switch_channel_get_variable(channel, "conference_auto_outcall_announce"); const char *prefix = switch_channel_get_variable(channel, "conference_auto_outcall_prefix"); const char *maxwait = switch_channel_get_variable(channel, "conference_auto_outcall_maxwait"); const char *delimiter_val = switch_channel_get_variable(channel, "conference_auto_outcall_delimiter"); int to = 60; int wait_sec = 2; int loops = 0; if (ann && !switch_channel_test_app_flag_key("conference_silent", channel, CONF_SILENT_REQ)) { member->conference->special_announce = switch_core_strdup(member->conference->pool, ann); } switch_channel_set_private(channel, "_conference_autocall_list_", NULL); conference_utils_set_flag(member->conference, CFLAG_OUTCALL); if (toval) { to = atoi(toval); if (to < 10 || to > 500) { to = 60; } } for (cp = call_list; cp; cp = cp->next) { int argc; char *argv[512] = { 0 }; char *cpstr = strdup(cp->string); int x = 0; switch_assert(cpstr); if (!zstr(delimiter_val) && strlen(delimiter_val) == 1) { char delimiter = *delimiter_val; argc = switch_separate_string(cpstr, delimiter, argv, (sizeof(argv) / sizeof(argv[0]))); } else { argc = switch_separate_string(cpstr, ',', argv, (sizeof(argv) / sizeof(argv[0]))); } for (x = 0; x < argc; x++) { char *dial_str = switch_mprintf("%s%s", switch_str_nil(prefix), argv[x]); switch_assert(dial_str); conference_outcall_bg(member->conference, NULL, NULL, dial_str, to, switch_str_nil(flags), cid_name, cid_num, NULL, profile, &member->conference->cancel_cause, NULL); switch_safe_free(dial_str); } switch_safe_free(cpstr); } if (maxwait) { int tmp = atoi(maxwait); if (tmp > 0) { wait_sec = tmp; } } loops = wait_sec * 10; switch_channel_set_app_flag(channel, CF_APP_TAGGED); do { switch_ivr_sleep(member->session, 100, SWITCH_TRUE, NULL); } while(switch_channel_up(channel) && (member->conference->originating && --loops)); switch_channel_clear_app_flag(channel, CF_APP_TAGGED); if (!switch_channel_ready(channel)) { member->conference->cancel_cause = SWITCH_CAUSE_ORIGINATOR_CANCEL; goto end; } conference_member_play_file(member, "tone_stream://%(500,0,640)", 0, SWITCH_TRUE); } if (!conference_utils_test_flag(member->conference, CFLAG_ANSWERED)) { switch_channel_answer(channel); } sanity = 2000; while(!conference_utils_member_test_flag(member, MFLAG_ITHREAD) && sanity > 0) { switch_cond_next(); sanity--; } /* Fair WARNING, If you expect the caller to hear anything or for digit handling to be processed, */ /* you better not block this thread loop for more than the duration of member->conference->timer_name! */ while (!member->loop_loop && conference_utils_member_test_flag(member, MFLAG_RUNNING) && conference_utils_member_test_flag(member, MFLAG_ITHREAD) && switch_channel_ready(channel)) { switch_event_t *event; int use_timer = 0; switch_buffer_t *use_buffer = NULL; uint32_t mux_used = 0; //if (member->reset_media || switch_channel_test_flag(member->channel, CF_CONFERENCE_RESET_MEDIA)) { // switch_cond_next(); // continue; //} switch_mutex_lock(member->write_mutex); if (switch_channel_test_flag(member->channel, CF_CONFERENCE_ADV)) { if (member->conference->la) { conference_event_adv_la(member->conference, member, SWITCH_TRUE); } switch_channel_clear_flag(member->channel, CF_CONFERENCE_ADV); } if (switch_core_session_dequeue_event(member->session, &event, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) { if (event->event_id == SWITCH_EVENT_MESSAGE) { char *from = switch_event_get_header(event, "from"); char *to = switch_event_get_header(event, "to"); char *body = switch_event_get_body(event); if (to && from && body) { if (strchr(to, '+') && strncmp(to, CONF_CHAT_PROTO, strlen(CONF_CHAT_PROTO))) { switch_event_del_header(event, "to"); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "to", "%s+%s@%s", CONF_CHAT_PROTO, member->conference->name, member->conference->domain); } else { switch_event_del_header(event, "to"); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "to", "%s", member->conference->name); } chat_send(event); } } switch_event_destroy(&event); } if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { /* test to see if outbound channel has answered */ if (switch_channel_test_flag(channel, CF_ANSWERED) && !conference_utils_test_flag(member->conference, CFLAG_ANSWERED)) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_DEBUG, "Outbound conference channel answered, setting CFLAG_ANSWERED\n"); conference_utils_set_flag(member->conference, CFLAG_ANSWERED); } } else { if (conference_utils_test_flag(member->conference, CFLAG_ANSWERED) && !switch_channel_test_flag(channel, CF_ANSWERED)) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_DEBUG, "CLFAG_ANSWERED set, answering inbound channel\n"); switch_channel_answer(channel); } } use_buffer = NULL; mux_used = (uint32_t) switch_buffer_inuse(member->mux_buffer); use_timer = 1; if (mux_used) { if (mux_used < bytes) { if (++low_count >= 5) { /* partial frame sitting around this long is useless and builds delay */ conference_utils_member_set_flag_locked(member, MFLAG_FLUSH_BUFFER); } } else if (mux_used > flush_len) { /* getting behind, clear the buffer */ conference_utils_member_set_flag_locked(member, MFLAG_FLUSH_BUFFER); } } if (switch_channel_test_app_flag(channel, CF_APP_TAGGED)) { conference_utils_member_set_flag_locked(member, MFLAG_FLUSH_BUFFER); } else if (mux_used >= bytes) { /* Flush the output buffer and write all the data (presumably muxed) back to the channel */ switch_mutex_lock(member->audio_out_mutex); write_frame.data = data; use_buffer = member->mux_buffer; low_count = 0; if ((write_frame.datalen = (uint32_t) switch_buffer_read(use_buffer, write_frame.data, bytes))) { if (write_frame.datalen) { write_frame.samples = write_frame.datalen / 2 / member->conference->channels; if( !conference_utils_member_test_flag(member, MFLAG_CAN_HEAR)) { memset(write_frame.data, 255, write_frame.datalen); } else if (member->volume_out_level) { /* Check for output volume adjustments */ switch_change_sln_volume(write_frame.data, write_frame.samples * member->conference->channels, member->volume_out_level); } write_frame.timestamp = timer.samplecount; if (member->fnode) { conference_member_add_file_data(member, write_frame.data, write_frame.datalen); } conference_member_check_channels(&write_frame, member, SWITCH_FALSE); if (switch_core_session_write_frame(member->session, &write_frame, SWITCH_IO_FLAG_NONE, 0) != SWITCH_STATUS_SUCCESS) { switch_mutex_unlock(member->audio_out_mutex); break; } } } switch_mutex_unlock(member->audio_out_mutex); } if (conference_utils_member_test_flag(member, MFLAG_FLUSH_BUFFER)) { if (switch_buffer_inuse(member->mux_buffer)) { switch_mutex_lock(member->audio_out_mutex); switch_buffer_zero(member->mux_buffer); switch_mutex_unlock(member->audio_out_mutex); } conference_utils_member_clear_flag_locked(member, MFLAG_FLUSH_BUFFER); } switch_mutex_unlock(member->write_mutex); if (conference_utils_member_test_flag(member, MFLAG_INDICATE_MUTE)) { if (!zstr(member->conference->muted_sound)) { conference_member_play_file(member, member->conference->muted_sound, 0, SWITCH_TRUE); } else { char msg[512]; switch_snprintf(msg, sizeof(msg), "Muted"); conference_member_say(member, msg, 0); } conference_utils_member_clear_flag(member, MFLAG_INDICATE_MUTE); } if (conference_utils_member_test_flag(member, MFLAG_INDICATE_MUTE_DETECT)) { if (!zstr(member->conference->mute_detect_sound)) { conference_member_play_file(member, member->conference->mute_detect_sound, 0, SWITCH_TRUE); } else { char msg[512]; switch_snprintf(msg, sizeof(msg), "Currently Muted"); conference_member_say(member, msg, 0); } conference_utils_member_clear_flag(member, MFLAG_INDICATE_MUTE_DETECT); } if (conference_utils_member_test_flag(member, MFLAG_INDICATE_UNMUTE)) { if (!zstr(member->conference->unmuted_sound)) { conference_member_play_file(member, member->conference->unmuted_sound, 0, SWITCH_TRUE); } else { char msg[512]; switch_snprintf(msg, sizeof(msg), "Un-Muted"); conference_member_say(member, msg, 0); } conference_utils_member_clear_flag(member, MFLAG_INDICATE_UNMUTE); } if (switch_core_session_private_event_count(member->session)) { switch_channel_set_app_flag(channel, CF_APP_TAGGED); switch_ivr_parse_all_events(member->session); switch_channel_clear_app_flag(channel, CF_APP_TAGGED); conference_utils_member_set_flag_locked(member, MFLAG_FLUSH_BUFFER); switch_core_session_set_read_codec(member->session, &member->read_codec); } else { switch_ivr_parse_all_messages(member->session); } if (use_timer) { switch_core_timer_next(&timer); } else { switch_cond_next(); } } /* Rinse ... Repeat */ end: if (!member->loop_loop) { conference_utils_member_clear_flag_locked(member, MFLAG_RUNNING); /* Wait for the input thread to end */ if (member->input_thread) { switch_thread_join(&st, member->input_thread); member->input_thread = NULL; } } switch_core_timer_destroy(&timer); if (member->loop_loop) { return; } switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_INFO, "Channel leaving conference, cause: %s\n", switch_channel_cause2str(switch_channel_get_cause(channel))); /* if it's an outbound channel, store the release cause in the conference struct, we might need it */ if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { member->conference->bridge_hangup_cause = switch_channel_get_cause(channel); } }
static switch_status_t my_on_reporting(switch_core_session_t *session) { struct json_object *json_cdr = NULL; const char *json_text = NULL; char *path = NULL; char *curl_json_text = NULL; const char *logdir = NULL; char *json_text_escaped = NULL; int fd = -1, err_dir_index; uint32_t cur_try; long httpRes; CURL *curl_handle = NULL; switch_curl_slist_t *headers = NULL; switch_curl_slist_t *slist = NULL; switch_channel_t *channel = switch_core_session_get_channel(session); switch_status_t status = SWITCH_STATUS_FALSE; int is_b; const char *a_prefix = ""; 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; } } if (!is_b && globals.prefix_a) a_prefix = "a_"; if (generate_json_cdr(session, &json_cdr) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Generating Data!\n"); return SWITCH_STATUS_FALSE; } json_text = json_object_to_json_string(json_cdr); if (!json_text) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n"); goto error; } switch_thread_rwlock_rdlock(globals.log_path_lock); if (!(logdir = switch_channel_get_variable(channel, "json_cdr_base"))) { logdir = globals.log_dir; } if (!zstr(logdir) && (globals.log_http_and_disk || !globals.url_count)) { path = switch_mprintf("%s%s%s%s.cdr.json", logdir, SWITCH_PATH_SEPARATOR, a_prefix, switch_core_session_get_uuid(session)); switch_thread_rwlock_unlock(globals.log_path_lock); if (path) { #ifdef _MSC_VER if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) > -1) { #else if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) > -1) { #endif int wrote; wrote = write(fd, json_text, (unsigned) strlen(json_text)); close(fd); fd = -1; if(wrote < 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error writing [%s]\n",path); } } else { char ebuf[512] = { 0 }; #ifdef WIN32 strerror_s(ebuf, sizeof(ebuf), errno); #else strerror_r(errno, ebuf, sizeof(ebuf)); #endif switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error writing [%s][%s]\n", path, ebuf); } switch_safe_free(path); } } else { switch_thread_rwlock_unlock(globals.log_path_lock); } /* try to post it to the web server */ if (globals.url_count) { char *destUrl = NULL; curl_handle = switch_curl_easy_init(); if (globals.encode) { switch_size_t need_bytes = strlen(json_text) * 3; json_text_escaped = malloc(need_bytes); switch_assert(json_text_escaped); memset(json_text_escaped, 0, need_bytes); if (globals.encode == ENCODING_DEFAULT) { headers = switch_curl_slist_append(headers, "Content-Type: application/x-www-form-urlencoded"); switch_url_encode(json_text, json_text_escaped, need_bytes); } else { headers = switch_curl_slist_append(headers, "Content-Type: application/x-www-form-base64-encoded"); switch_b64_encode((unsigned char *) json_text, need_bytes / 3, (unsigned char *) json_text_escaped, need_bytes); } json_text = json_text_escaped; if (!(curl_json_text = switch_mprintf("cdr=%s", json_text))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n"); goto error; } } else { headers = switch_curl_slist_append(headers, "Content-Type: application/json"); curl_json_text = (char *)json_text; } if (!zstr(globals.cred)) { switch_curl_easy_setopt(curl_handle, CURLOPT_HTTPAUTH, globals.auth_scheme); switch_curl_easy_setopt(curl_handle, CURLOPT_USERPWD, globals.cred); } switch_curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, headers); switch_curl_easy_setopt(curl_handle, CURLOPT_POST, 1); switch_curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1); switch_curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, curl_json_text); switch_curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "freeswitch-json/1.0"); switch_curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, httpCallBack); if (globals.disable100continue) { slist = switch_curl_slist_append(slist, "Expect:"); switch_curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, slist); } if (globals.ssl_cert_file) { switch_curl_easy_setopt(curl_handle, CURLOPT_SSLCERT, globals.ssl_cert_file); } if (globals.ssl_key_file) { switch_curl_easy_setopt(curl_handle, CURLOPT_SSLKEY, globals.ssl_key_file); } if (globals.ssl_key_password) { switch_curl_easy_setopt(curl_handle, CURLOPT_SSLKEYPASSWD, globals.ssl_key_password); } if (globals.ssl_version) { if (!strcasecmp(globals.ssl_version, "SSLv3")) { switch_curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_SSLv3); } else if (!strcasecmp(globals.ssl_version, "TLSv1")) { switch_curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); } } if (globals.ssl_cacert_file) { switch_curl_easy_setopt(curl_handle, CURLOPT_CAINFO, globals.ssl_cacert_file); } /* these were used for testing, optionally they may be enabled if someone desires switch_curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, 120); // tcp timeout switch_curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1); // 302 recursion level */ for (cur_try = 0; cur_try < globals.retries; cur_try++) { if (cur_try > 0) { switch_yield(globals.delay * 1000000); } destUrl = switch_mprintf("%s?uuid=%s", globals.urls[globals.url_index], switch_core_session_get_uuid(session)); switch_curl_easy_setopt(curl_handle, CURLOPT_URL, destUrl); if (!strncasecmp(destUrl, "https", 5)) { switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0); switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0); } if (globals.enable_cacert_check) { switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, TRUE); } if (globals.enable_ssl_verifyhost) { switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 2); } switch_curl_easy_perform(curl_handle); switch_curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &httpRes); switch_safe_free(destUrl); if (httpRes >= 200 && httpRes < 300) { goto success; } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Got error [%ld] posting to web server [%s]\n", httpRes, globals.urls[globals.url_index]); globals.url_index++; switch_assert(globals.url_count <= MAX_URLS); if (globals.url_index >= globals.url_count) { globals.url_index = 0; } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Retry will be with url [%s]\n", globals.urls[globals.url_index]); } } switch_curl_easy_cleanup(curl_handle); switch_curl_slist_free_all(headers); switch_curl_slist_free_all(slist); slist = NULL; headers = NULL; curl_handle = NULL; /* if we are here the web post failed for some reason */ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to post to web server, writing to file\n"); for (err_dir_index = 0; err_dir_index < globals.err_dir_count; err_dir_index++) { switch_thread_rwlock_rdlock(globals.log_path_lock); path = switch_mprintf("%s%s%s%s.cdr.json", globals.err_log_dir[err_dir_index], SWITCH_PATH_SEPARATOR, a_prefix, switch_core_session_get_uuid(session)); switch_thread_rwlock_unlock(globals.log_path_lock); if (path) { #ifdef _MSC_VER if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) > -1) { #else if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) > -1) { #endif int wrote; wrote = write(fd, json_text, (unsigned) strlen(json_text)); close(fd); fd = -1; if(wrote < 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error writing [%s]\n",path); } break; } else { char ebuf[512] = { 0 }; #ifdef WIN32 strerror_s(ebuf, sizeof(ebuf), errno); #else strerror_r(errno, ebuf, sizeof(ebuf)); #endif switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open %s! [%s]\n", path, ebuf); } switch_safe_free(path); } } } success: status = SWITCH_STATUS_SUCCESS; error: if (curl_handle) { switch_curl_easy_cleanup(curl_handle); } if (headers) { switch_curl_slist_free_all(headers); } if (slist) { switch_curl_slist_free_all(slist); } if (curl_json_text != json_text) { switch_safe_free(curl_json_text); } json_object_put(json_cdr); switch_safe_free(json_text_escaped); return status; } static void event_handler(switch_event_t *event) { const char *sig = switch_event_get_header(event, "Trapped-Signal"); if (sig && !strcmp(sig, "HUP")) { if (globals.rotate) { set_json_cdr_log_dirs(); } } } static switch_state_handler_table_t state_handlers = { /*.on_init */ NULL, /*.on_routing */ NULL, /*.on_execute */ NULL, /*.on_hangup */ NULL, /*.on_exchange_media */ NULL, /*.on_soft_execute */ NULL, /*.on_consume_media */ NULL, /*.on_hibernate */ NULL, /*.on_reset */ NULL, /*.on_park */ NULL, /*.on_reporting */ my_on_reporting }; SWITCH_MODULE_LOAD_FUNCTION(mod_json_cdr_load) { char *cf = "json_cdr.conf"; switch_xml_t cfg, xml, settings, param; switch_status_t status = SWITCH_STATUS_SUCCESS; /* test global state handlers */ switch_core_add_state_handler(&state_handlers); *module_interface = switch_loadable_module_create_module_interface(pool, modname); memset(&globals, 0, sizeof(globals)); if (switch_event_bind_removable(modname, SWITCH_EVENT_TRAP, SWITCH_EVENT_SUBCLASS_ANY, event_handler, NULL, &globals.node) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n"); return SWITCH_STATUS_GENERR; } globals.log_http_and_disk = 0; globals.log_b = 1; globals.disable100continue = 0; globals.pool = pool; globals.auth_scheme = CURLAUTH_BASIC; globals.encode_values = ENCODING_DEFAULT; switch_thread_rwlock_create(&globals.log_path_lock, pool); /* parse the config */ 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 ((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, "cred") && !zstr(val)) { globals.cred = switch_core_strdup(globals.pool, val); } else if (!strcasecmp(var, "url") && !zstr(val)) { if (globals.url_count >= MAX_URLS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "maximum urls configured!\n"); } else { globals.urls[globals.url_count++] = switch_core_strdup(globals.pool, val); } } else if (!strcasecmp(var, "log-http-and-disk")) { globals.log_http_and_disk = switch_true(val); } else if (!strcasecmp(var, "delay") && !zstr(val)) { globals.delay = (uint32_t) atoi(val); } else if (!strcasecmp(var, "log-b-leg")) { globals.log_b = switch_true(val); } else if (!strcasecmp(var, "prefix-a-leg")) { globals.prefix_a = switch_true(val); } else if (!strcasecmp(var, "disable-100-continue") && switch_true(val)) { globals.disable100continue = 1; } else if (!strcasecmp(var, "encode") && !zstr(val)) { if (!strcasecmp(val, "base64")) { globals.encode = ENCODING_BASE64; } else { globals.encode = switch_true(val) ? ENCODING_DEFAULT : ENCODING_NONE; } } else if (!strcasecmp(var, "retries") && !zstr(val)) { globals.retries = (uint32_t) atoi(val); } else if (!strcasecmp(var, "rotate") && !zstr(val)) { globals.rotate = switch_true(val); } else if (!strcasecmp(var, "log-dir")) { if (zstr(val)) { globals.base_log_dir = switch_core_sprintf(globals.pool, "%s%sjson_cdr", SWITCH_GLOBAL_dirs.log_dir, SWITCH_PATH_SEPARATOR); } else { if (switch_is_file_path(val)) { globals.base_log_dir = switch_core_strdup(globals.pool, val); } else { globals.base_log_dir = switch_core_sprintf(globals.pool, "%s%s%s", SWITCH_GLOBAL_dirs.log_dir, SWITCH_PATH_SEPARATOR, val); } } } else if (!strcasecmp(var, "err-log-dir")) { if (globals.err_dir_count >= MAX_ERR_DIRS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "maximum error directories configured!\n"); } else { if (zstr(val)) { globals.base_err_log_dir[globals.err_dir_count++] = switch_core_sprintf(globals.pool, "%s%sjson_cdr", SWITCH_GLOBAL_dirs.log_dir, SWITCH_PATH_SEPARATOR); } else { if (switch_is_file_path(val)) { globals.base_err_log_dir[globals.err_dir_count++] = switch_core_strdup(globals.pool, val); } else { globals.base_err_log_dir[globals.err_dir_count++] = switch_core_sprintf(globals.pool, "%s%s%s", SWITCH_GLOBAL_dirs.log_dir, SWITCH_PATH_SEPARATOR, val); } } } } else if (!strcasecmp(var, "enable-cacert-check") && switch_true(val)) { globals.enable_cacert_check = 1; } else if (!strcasecmp(var, "ssl-cert-path")) { globals.ssl_cert_file = val; } else if (!strcasecmp(var, "ssl-key-path")) { globals.ssl_key_file = val; } else if (!strcasecmp(var, "ssl-key-password")) { globals.ssl_key_password = val; } else if (!strcasecmp(var, "ssl-version")) { globals.ssl_version = val; } else if (!strcasecmp(var, "ssl-cacert-file")) { globals.ssl_cacert_file = val; } else if (!strcasecmp(var, "enable-ssl-verifyhost") && switch_true(val)) { globals.enable_ssl_verifyhost = 1; } else if (!strcasecmp(var, "auth-scheme")) { if (*val == '=') { globals.auth_scheme = 0; val++; } if (!strcasecmp(val, "basic")) { globals.auth_scheme |= CURLAUTH_BASIC; } else if (!strcasecmp(val, "digest")) { globals.auth_scheme |= CURLAUTH_DIGEST; } else if (!strcasecmp(val, "NTLM")) { globals.auth_scheme |= CURLAUTH_NTLM; } else if (!strcasecmp(val, "GSS-NEGOTIATE")) { globals.auth_scheme |= CURLAUTH_GSSNEGOTIATE; } else if (!strcasecmp(val, "any")) { globals.auth_scheme = CURLAUTH_ANY; } } else if (!strcasecmp(var, "encode-values") && !zstr(val)) { globals.encode_values = switch_true(val) ? ENCODING_DEFAULT : ENCODING_NONE; } } if (!globals.err_dir_count) { if (!zstr(globals.base_log_dir)) { globals.base_err_log_dir[globals.err_dir_count++] = switch_core_strdup(globals.pool, globals.base_log_dir); } else { globals.base_err_log_dir[globals.err_dir_count++] = switch_core_sprintf(globals.pool, "%s%sjson_cdr", SWITCH_GLOBAL_dirs.log_dir, SWITCH_PATH_SEPARATOR); } } } if (globals.retries < 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Retries is negative, setting to 0\n"); globals.retries = 0; } if (globals.retries && globals.delay <= 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Retries set but delay 0 setting to 5000ms\n"); globals.delay = 5000; } globals.retries++; set_json_cdr_log_dirs(); switch_xml_free(xml); return status; } SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_json_cdr_shutdown) { int err_dir_index = 0; globals.shutdown = 1; switch_safe_free(globals.log_dir); for (;err_dir_index < globals.err_dir_count; err_dir_index++) { switch_safe_free(globals.err_log_dir[err_dir_index]); } switch_event_unbind(&globals.node); switch_core_remove_state_handler(&state_handlers); switch_thread_rwlock_destroy(globals.log_path_lock); return SWITCH_STATUS_SUCCESS; }
int modem_close(modem_t *modem) { int r = 0; switch_status_t was_running = switch_test_flag(modem, MODEM_FLAG_RUNNING); switch_clear_flag(modem, MODEM_FLAG_RUNNING); #ifndef WIN32 if (modem->master > -1) { shutdown(modem->master, 2); close(modem->master); modem->master = -1; #else if (modem->master) { SetEvent(modem->threadAbort); CloseHandle(modem->threadAbort); CloseHandle(modem->master); modem->master = 0; #endif r++; } if (modem->slave > -1) { shutdown(modem->slave, 2); close(modem->slave); modem->slave = -1; r++; } if (modem->t31_state) { t31_free(modem->t31_state); modem->t31_state = NULL; } unlink(modem->devlink); if (was_running) { switch_mutex_lock(globals.mutex); globals.REF_COUNT--; switch_mutex_unlock(globals.mutex); } return r; } switch_status_t modem_init(modem_t *modem, modem_control_handler_t control_handler) { switch_status_t status = SWITCH_STATUS_SUCCESS; #ifdef WIN32 COMMTIMEOUTS timeouts={0}; #endif memset(modem, 0, sizeof(*modem)); modem->master = -1; modem->slave = -1; /* windows will have to try something like: http://com0com.cvs.sourceforge.net/viewvc/com0com/com0com/ReadMe.txt?revision=RELEASED */ #if USE_OPENPTY if (openpty(&modem->master, &modem->slave, NULL, NULL, NULL)) { if (modem->master < 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: failed to initialize pty\n"); status = SWITCH_STATUS_FALSE; goto end; } modem->stty = ttyname(modem->slave); #else #if WIN32 modem->slot = 4+globals.NEXT_ID++; /* need work here we start at COM4 for now*/ snprintf(modem->devlink, sizeof(modem->devlink), "COM%d", modem->slot); modem->master = CreateFile(modem->devlink, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); if(modem->master==INVALID_HANDLE_VALUE) { status = SWITCH_STATUS_FALSE; if(GetLastError()==ERROR_FILE_NOT_FOUND) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: Serial port does not exist\n"); goto end; } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: Serial port open error\n"); goto end; } #elif !defined(HAVE_POSIX_OPENPT) modem->master = open("/dev/ptmx", O_RDWR); #else modem->master = posix_openpt(O_RDWR | O_NOCTTY); #endif #ifndef WIN32 if (modem->master < 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: failed to initialize UNIX98 master pty\n"); } if (grantpt(modem->master) < 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: failed to grant access to slave pty\n"); } if (unlockpt(modem->master) < 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: failed to unlock slave pty\n"); } modem->stty = ptsname(modem->master); if (modem->stty == NULL) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: failed to obtain slave pty filename\n"); } modem->slave = open(modem->stty, O_RDWR); if (modem->slave < 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: failed to open slave pty %s\n", modem->stty); } #endif #ifdef SOLARIS ioctl(modem->slave, I_PUSH, "ptem"); /* push ptem */ ioctl(modem->slave, I_PUSH, "ldterm"); /* push ldterm*/ #endif #endif #ifndef WIN32 modem->slot = globals.NEXT_ID++; snprintf(modem->devlink, sizeof(modem->devlink), "/dev/FS%d", modem->slot); unlink(modem->devlink); if (symlink(modem->stty, modem->devlink)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: failed to create %s symbolic link\n", modem->devlink); modem_close(modem); status = SWITCH_STATUS_FALSE; goto end; } if (fcntl(modem->master, F_SETFL, fcntl(modem->master, F_GETFL, 0) | O_NONBLOCK)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot set up non-blocking read on %s\n", ttyname(modem->master)); modem_close(modem); status = SWITCH_STATUS_FALSE; goto end; } #else timeouts.ReadIntervalTimeout=50; timeouts.ReadTotalTimeoutConstant=50; timeouts.ReadTotalTimeoutMultiplier=10; timeouts.WriteTotalTimeoutConstant=50; timeouts.WriteTotalTimeoutMultiplier=10; SetCommMask(modem->master, EV_RXCHAR); if(!SetCommTimeouts(modem->master, &timeouts)){ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot set up non-blocking read on %s\n", modem->devlink); modem_close(modem); status = SWITCH_STATUS_FALSE; goto end; } modem->threadAbort = CreateEvent(NULL, TRUE, FALSE, NULL); #endif if (!(modem->t31_state = t31_init(NULL, t31_at_tx_handler, modem, t31_call_control_handler, modem, NULL, NULL))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot initialize the T.31 modem\n"); modem_close(modem); status = SWITCH_STATUS_FALSE; goto end; } if (spandsp_globals.modem_verbose) { span_log_set_message_handler(&modem->t31_state->logging, spanfax_log_message, NULL); span_log_set_message_handler(&modem->t31_state->audio.modems.fast_modems.v17_rx.logging, spanfax_log_message, NULL); span_log_set_message_handler(&modem->t31_state->audio.modems.fast_modems.v29_rx.logging, spanfax_log_message, NULL); span_log_set_message_handler(&modem->t31_state->audio.modems.fast_modems.v27ter_rx.logging, spanfax_log_message, NULL); modem->t31_state->logging.level = SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW; modem->t31_state->audio.modems.fast_modems.v17_rx.logging.level = SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW; modem->t31_state->audio.modems.fast_modems.v29_rx.logging.level = SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW; modem->t31_state->audio.modems.fast_modems.v27ter_rx.logging.level = SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW; } modem->control_handler = control_handler; modem->flags = 0; switch_set_flag(modem, MODEM_FLAG_RUNNING); switch_mutex_init(&modem->mutex, SWITCH_MUTEX_NESTED, globals.pool); switch_mutex_init(&modem->cond_mutex, SWITCH_MUTEX_NESTED, globals.pool); switch_thread_cond_create(&modem->cond, globals.pool); modem_set_state(modem, MODEM_STATE_INIT); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Modem [%s]->[%s] Ready\n", modem->devlink, modem->stty); switch_mutex_lock(globals.mutex); globals.REF_COUNT++; switch_mutex_unlock(globals.mutex); end: return status; } static switch_endpoint_interface_t *modem_endpoint_interface = NULL; struct private_object { switch_mutex_t *mutex; switch_core_session_t *session; switch_channel_t *channel; switch_codec_t read_codec; switch_codec_t write_codec; switch_frame_t read_frame; unsigned char databuf[SWITCH_RECOMMENDED_BUFFER_SIZE]; switch_timer_t timer; modem_t *modem; switch_caller_profile_t *caller_profile; int dead; }; typedef struct private_object private_t; static switch_status_t channel_on_init(switch_core_session_t *session); static switch_status_t channel_on_hangup(switch_core_session_t *session); static switch_status_t channel_on_destroy(switch_core_session_t *session); static switch_status_t channel_on_routing(switch_core_session_t *session); static switch_status_t channel_on_exchange_media(switch_core_session_t *session); static switch_status_t channel_on_soft_execute(switch_core_session_t *session); static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event, switch_caller_profile_t *outbound_profile, switch_core_session_t **new_session, switch_memory_pool_t **pool, switch_originate_flag_t flags, switch_call_cause_t *cancel_cause); static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id); static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id); static switch_status_t channel_kill_channel(switch_core_session_t *session, int sig); /* 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; private_t *tech_pvt = NULL; int to_ticks = 60, ring_ticks = 10, rt = ring_ticks; int rest = 500000; 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_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { #ifndef WIN32 int tioflags; #endif char call_time[16]; char call_date[16]; switch_size_t retsize; switch_time_exp_t tm; switch_time_exp_lt(&tm, switch_micro_time_now()); switch_strftime(call_date, &retsize, sizeof(call_date), "%m%d", &tm); switch_strftime(call_time, &retsize, sizeof(call_time), "%H%M", &tm); #ifndef WIN32 ioctl(tech_pvt->modem->slave, TIOCMGET, &tioflags); tioflags |= TIOCM_RI; ioctl(tech_pvt->modem->slave, TIOCMSET, &tioflags); #endif at_reset_call_info(&tech_pvt->modem->t31_state->at_state); at_set_call_info(&tech_pvt->modem->t31_state->at_state, "DATE", call_date); at_set_call_info(&tech_pvt->modem->t31_state->at_state, "TIME", call_time); at_set_call_info(&tech_pvt->modem->t31_state->at_state, "NAME", tech_pvt->caller_profile->caller_id_name); at_set_call_info(&tech_pvt->modem->t31_state->at_state, "NMBR", tech_pvt->caller_profile->caller_id_number); at_set_call_info(&tech_pvt->modem->t31_state->at_state, "ANID", tech_pvt->caller_profile->ani); at_set_call_info(&tech_pvt->modem->t31_state->at_state, "USER", tech_pvt->caller_profile->username); at_set_call_info(&tech_pvt->modem->t31_state->at_state, "CDID", tech_pvt->caller_profile->context); at_set_call_info(&tech_pvt->modem->t31_state->at_state, "NDID", tech_pvt->caller_profile->destination_number); modem_set_state(tech_pvt->modem, MODEM_STATE_RINGING); t31_call_event(tech_pvt->modem->t31_state, AT_CALL_EVENT_ALERTING); while(to_ticks > 0 && switch_channel_up(channel) && modem_get_state(tech_pvt->modem) == MODEM_STATE_RINGING) { if (--rt <= 0) { t31_call_event(tech_pvt->modem->t31_state, AT_CALL_EVENT_ALERTING); rt = ring_ticks; } switch_yield(rest); to_ticks--; } if (to_ticks < 1 || modem_get_state(tech_pvt->modem) != MODEM_STATE_ANSWERED) { t31_call_event(tech_pvt->modem->t31_state, AT_CALL_EVENT_NO_ANSWER); switch_channel_hangup(channel, SWITCH_CAUSE_NO_ANSWER); } else { t31_call_event(tech_pvt->modem->t31_state, AT_CALL_EVENT_ANSWERED); modem_set_state(tech_pvt->modem, MODEM_STATE_CONNECTED); switch_channel_mark_answered(channel); } } switch_channel_set_state(channel, CS_ROUTING); return SWITCH_STATUS_SUCCESS; }
SWITCH_DECLARE(switch_status_t) switch_core_perform_new_memory_pool(switch_memory_pool_t **pool, const char *file, const char *func, int line) { char *tmp; #ifdef INSTANTLY_DESTROY_POOLS apr_pool_create(pool, NULL); switch_assert(*pool != NULL); #else #ifdef PER_POOL_LOCK apr_allocator_t *my_allocator = NULL; apr_thread_mutex_t *my_mutex; #else void *pop = NULL; #endif #ifdef USE_MEM_LOCK switch_mutex_lock(memory_manager.mem_lock); #endif switch_assert(pool != NULL); #ifndef PER_POOL_LOCK if (switch_queue_trypop(memory_manager.pool_recycle_queue, &pop) == SWITCH_STATUS_SUCCESS && pop) { *pool = (switch_memory_pool_t *) pop; } else { #endif #ifdef PER_POOL_LOCK if ((apr_allocator_create(&my_allocator)) != APR_SUCCESS) { abort(); } if ((apr_pool_create_ex(pool, NULL, NULL, my_allocator)) != APR_SUCCESS) { abort(); } if ((apr_thread_mutex_create(&my_mutex, APR_THREAD_MUTEX_NESTED, *pool)) != APR_SUCCESS) { abort(); } apr_allocator_mutex_set(my_allocator, my_mutex); apr_allocator_owner_set(my_allocator, *pool); apr_pool_mutex_set(*pool, my_mutex); #else apr_pool_create(pool, NULL); switch_assert(*pool != NULL); } #endif #endif tmp = switch_core_sprintf(*pool, "%s:%d", file, line); apr_pool_tag(*pool, tmp); #ifdef DEBUG_ALLOC2 switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_CONSOLE, "%p New Pool %s\n", (void *) *pool, apr_pool_tag(*pool, NULL)); #endif #ifdef USE_MEM_LOCK switch_mutex_unlock(memory_manager.mem_lock); #endif return SWITCH_STATUS_SUCCESS; }
switch_memory_pool_t *switch_core_memory_init(void) { #ifndef INSTANTLY_DESTROY_POOLS switch_threadattr_t *thd_attr; #endif #ifdef PER_POOL_LOCK apr_allocator_t *my_allocator = NULL; apr_thread_mutex_t *my_mutex; #endif memset(&memory_manager, 0, sizeof(memory_manager)); #ifdef PER_POOL_LOCK if ((apr_allocator_create(&my_allocator)) != APR_SUCCESS) { abort(); } if ((apr_pool_create_ex(&memory_manager.memory_pool, NULL, NULL, my_allocator)) != APR_SUCCESS) { apr_allocator_destroy(my_allocator); my_allocator = NULL; abort(); } if ((apr_thread_mutex_create(&my_mutex, APR_THREAD_MUTEX_NESTED, memory_manager.memory_pool)) != APR_SUCCESS) { abort(); } apr_allocator_mutex_set(my_allocator, my_mutex); apr_pool_mutex_set(memory_manager.memory_pool, my_mutex); apr_allocator_owner_set(my_allocator, memory_manager.memory_pool); apr_pool_tag(memory_manager.memory_pool, "core_pool"); #else apr_pool_create(&memory_manager.memory_pool, NULL); switch_assert(memory_manager.memory_pool != NULL); #endif #ifdef USE_MEM_LOCK switch_mutex_init(&memory_manager.mem_lock, SWITCH_MUTEX_NESTED, memory_manager.memory_pool); #endif #ifdef INSTANTLY_DESTROY_POOLS { void *foo; foo = (void *) (intptr_t) pool_thread; } #else switch_queue_create(&memory_manager.pool_queue, 50000, memory_manager.memory_pool); switch_queue_create(&memory_manager.pool_recycle_queue, 50000, memory_manager.memory_pool); switch_threadattr_create(&thd_attr, memory_manager.memory_pool); switch_threadattr_detach_set(thd_attr, 0); switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE); switch_thread_create(&pool_thread_p, thd_attr, pool_thread, NULL, memory_manager.memory_pool); while (!memory_manager.pool_thread_running) { switch_cond_next(); } #endif return memory_manager.memory_pool; }
SWITCH_DECLARE(switch_status_t) switch_core_asr_feed(switch_asr_handle_t *ah, void *data, unsigned int len, switch_asr_flag_t *flags) { switch_assert(ah != NULL); return ah->asr_interface->asr_feed(ah, data, len, flags); }
SWITCH_DECLARE(switch_status_t) switch_core_asr_get_results(switch_asr_handle_t *ah, char **xmlstr, switch_asr_flag_t *flags) { switch_assert(ah != NULL); return ah->asr_interface->asr_get_results(ah, xmlstr, flags); }
static void switch_core_standard_on_soft_execute(switch_core_session_t *session) { switch_assert(session != NULL); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Standard SOFT_EXECUTE\n", switch_channel_get_name(session->channel)); }
static void switch_core_standard_on_consume_media(switch_core_session_t *session) { switch_assert(session != NULL); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Standard CONSUME_MEDIA\n", switch_channel_get_name(session->channel)); }
static switch_status_t my_on_reporting_cb(switch_core_session_t *session, cdr_profile_t *profile) { switch_xml_t xml_cdr = NULL; cJSON *json_cdr = NULL; char *cdr_text = NULL; char *dpath = NULL; char *path = NULL; char *curl_cdr_text = NULL; const char *logdir = NULL; char *cdr_text_escaped = NULL; int fd = -1; uint32_t cur_try; long httpRes; switch_CURL *curl_handle = NULL; switch_curl_slist_t *headers = NULL; switch_curl_slist_t *slist = NULL; switch_channel_t *channel = switch_core_session_get_channel(session); switch_status_t status = SWITCH_STATUS_FALSE; int is_b; const char *a_prefix = ""; if (globals.shutdown) { return SWITCH_STATUS_SUCCESS; } is_b = channel && switch_channel_get_originator_caller_profile(channel); if (!profile->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; } } if (!is_b && profile->prefix_a) a_prefix = "a_"; if ( ! strcasecmp(profile->format, "json") ) { if (switch_ivr_generate_json_cdr(session, &json_cdr, profile->encode_values == ENCODING_DEFAULT) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Generating JSON Data!\n"); return SWITCH_STATUS_FALSE; } /* build the JSON */ cdr_text = cJSON_PrintUnformatted(json_cdr); if (!cdr_text) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error generating JSON!\n"); goto error; } } else if ( ! strcasecmp(profile->format, "xml") ) { if (switch_ivr_generate_xml_cdr(session, &xml_cdr) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Generating XML Data!\n"); return SWITCH_STATUS_FALSE; } /* build the XML */ cdr_text = switch_xml_toxml(xml_cdr, SWITCH_TRUE); if (!cdr_text) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error generating XML!\n"); goto error; } } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Unhandled format for mod_format_cdr!\n"); goto error; } switch_thread_rwlock_rdlock(profile->log_path_lock); if (!(logdir = switch_channel_get_variable(channel, "format_cdr_base"))) { logdir = profile->log_dir; } if (!zstr(logdir) && (profile->log_http_and_disk || !profile->url_count)) { dpath = switch_mprintf("%s%s%s", logdir, SWITCH_PATH_SEPARATOR, a_prefix); path = switch_mprintf("%s%s%s%s.cdr.%s", logdir, SWITCH_PATH_SEPARATOR, a_prefix, switch_core_session_get_uuid(session), profile->format); switch_thread_rwlock_unlock(profile->log_path_lock); if (path) { if (switch_directory_exists(dpath, profile->pool) != SWITCH_STATUS_SUCCESS) { switch_dir_make_recursive(dpath, SWITCH_FPROT_OS_DEFAULT, profile->pool); } #ifdef _MSC_VER if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) > -1) { #else if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) > -1) { #endif int wrote; wrote = write(fd, cdr_text, (unsigned) strlen(cdr_text)); wrote++; close(fd); fd = -1; } else { char ebuf[512] = { 0 }; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error writing [%s][%s]\n", path, switch_strerror_r(errno, ebuf, sizeof(ebuf))); } switch_safe_free(path); switch_safe_free(dpath); } } else { switch_thread_rwlock_unlock(profile->log_path_lock); } /* try to post it to the web server */ if (profile->url_count) { char *destUrl = NULL; curl_handle = switch_curl_easy_init(); if (profile->encode == ENCODING_TEXTXML) { headers = switch_curl_slist_append(headers, "Content-Type: text/xml"); } else if (profile->encode == ENCODING_APPLJSON) { headers = switch_curl_slist_append(headers, "Content-Type: application/json"); } else if (profile->encode) { switch_size_t need_bytes = strlen(cdr_text) * 3 + 1; cdr_text_escaped = malloc(need_bytes); switch_assert(cdr_text_escaped); memset(cdr_text_escaped, 0, need_bytes); if (profile->encode == ENCODING_DEFAULT) { headers = switch_curl_slist_append(headers, "Content-Type: application/x-www-form-urlencoded"); switch_url_encode(cdr_text, cdr_text_escaped, need_bytes); } else { headers = switch_curl_slist_append(headers, "Content-Type: application/x-www-form-base64-encoded"); switch_b64_encode((unsigned char *) cdr_text, need_bytes / 3, (unsigned char *) cdr_text_escaped, need_bytes); } switch_safe_free(cdr_text); cdr_text = cdr_text_escaped; } else { headers = switch_curl_slist_append(headers, "Content-Type: application/x-www-form-plaintext"); } if (profile->encode == ENCODING_TEXTXML) { curl_cdr_text = cdr_text; } else if (profile->encode == ENCODING_APPLJSON) { curl_cdr_text = cdr_text; } else if (!(curl_cdr_text = switch_mprintf("cdr=%s", cdr_text))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n"); goto error; } if (!zstr(profile->cred)) { switch_curl_easy_setopt(curl_handle, CURLOPT_HTTPAUTH, profile->auth_scheme); switch_curl_easy_setopt(curl_handle, CURLOPT_USERPWD, profile->cred); } switch_curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, headers); switch_curl_easy_setopt(curl_handle, CURLOPT_POST, 1); switch_curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1); switch_curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, curl_cdr_text); switch_curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "freeswitch-format-cdr/1.0"); switch_curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, httpCallBack); if (profile->disable100continue) { slist = switch_curl_slist_append(slist, "Expect:"); switch_curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, slist); } if (profile->ssl_cert_file) { switch_curl_easy_setopt(curl_handle, CURLOPT_SSLCERT, profile->ssl_cert_file); } if (profile->ssl_key_file) { switch_curl_easy_setopt(curl_handle, CURLOPT_SSLKEY, profile->ssl_key_file); } if (profile->ssl_key_password) { switch_curl_easy_setopt(curl_handle, CURLOPT_SSLKEYPASSWD, profile->ssl_key_password); } if (profile->ssl_version) { if (!strcasecmp(profile->ssl_version, "SSLv3")) { switch_curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_SSLv3); } else if (!strcasecmp(profile->ssl_version, "TLSv1")) { switch_curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); } } if (profile->ssl_cacert_file) { switch_curl_easy_setopt(curl_handle, CURLOPT_CAINFO, profile->ssl_cacert_file); } switch_curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, profile->timeout); /* these were used for testing, optionally they may be enabled if someone desires switch_curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1); // 302 recursion level */ for (cur_try = 0; cur_try < profile->retries; cur_try++) { if (cur_try > 0) { switch_yield(profile->delay * 1000000); } destUrl = switch_mprintf("%s?uuid=%s%s", profile->urls[profile->url_index], a_prefix, switch_core_session_get_uuid(session)); switch_curl_easy_setopt(curl_handle, CURLOPT_URL, destUrl); if (!strncasecmp(destUrl, "https", 5)) { switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0); switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0); } if (profile->enable_cacert_check) { switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, TRUE); } if (profile->enable_ssl_verifyhost) { switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 2); } switch_curl_easy_perform(curl_handle); switch_curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &httpRes); switch_safe_free(destUrl); if (httpRes >= 200 && httpRes <= 299) { goto success; } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Got error [%ld] posting to web server [%s]\n", httpRes, profile->urls[profile->url_index]); profile->url_index++; switch_assert(profile->url_count <= MAX_URLS); if (profile->url_index >= profile->url_count) { profile->url_index = 0; } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Retry will be with url [%s]\n", profile->urls[profile->url_index]); } } switch_curl_easy_cleanup(curl_handle); switch_curl_slist_free_all(headers); switch_curl_slist_free_all(slist); slist = NULL; headers = NULL; curl_handle = NULL; /* if we are here the web post failed for some reason */ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to post to web server, writing to file\n"); switch_thread_rwlock_rdlock(profile->log_path_lock); dpath = switch_mprintf("%s%s%s", profile->err_log_dir, SWITCH_PATH_SEPARATOR, a_prefix); path = switch_mprintf("%s%s%s%s.cdr.%s", profile->err_log_dir, SWITCH_PATH_SEPARATOR, a_prefix, switch_core_session_get_uuid(session), profile->format); switch_thread_rwlock_unlock(profile->log_path_lock); if (path) { if (switch_directory_exists(dpath, profile->pool) != SWITCH_STATUS_SUCCESS) { switch_dir_make_recursive(dpath, SWITCH_FPROT_OS_DEFAULT, profile->pool); } #ifdef _MSC_VER if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) > -1) { #else if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) > -1) { #endif int wrote; wrote = write(fd, cdr_text, (unsigned) strlen(cdr_text)); wrote++; close(fd); fd = -1; } else { char ebuf[512] = { 0 }; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error![%s]\n", switch_strerror_r(errno, ebuf, sizeof(ebuf))); } switch_safe_free(path); switch_safe_free(dpath); } } success: status = SWITCH_STATUS_SUCCESS; error: if (curl_handle) { switch_curl_easy_cleanup(curl_handle); } if (headers) { switch_curl_slist_free_all(headers); } if (slist) { switch_curl_slist_free_all(slist); } if (curl_cdr_text != cdr_text) { switch_safe_free(curl_cdr_text); } switch_safe_free(cdr_text); switch_safe_free(path); switch_safe_free(dpath); if ( xml_cdr ) { switch_xml_free(xml_cdr); } if ( json_cdr ) { cJSON_Delete(json_cdr); } return status; } static switch_status_t my_on_reporting(switch_core_session_t *session) { switch_hash_index_t *hi; void *val; switch_status_t status, tmpstatus; status = SWITCH_STATUS_SUCCESS; for (hi = switch_hash_first(NULL, globals.profile_hash); hi; hi = switch_hash_next(hi)) { cdr_profile_t *profile; switch_hash_this(hi, NULL, NULL, &val); profile = (cdr_profile_t *) val; tmpstatus = my_on_reporting_cb(session, profile); if ( tmpstatus != SWITCH_STATUS_SUCCESS ) { status = tmpstatus; } } return status; }
static switch_status_t my_on_reporting(switch_core_session_t *session) { switch_channel_t *channel = switch_core_session_get_channel(session); switch_status_t status = SWITCH_STATUS_SUCCESS; char *values = NULL, *tmp = NULL, *pq_var = NULL; const char *var = NULL; cdr_field_t *cdr_field = NULL; switch_size_t len, offset; if (globals.shutdown) { return SWITCH_STATUS_SUCCESS; } if (!((globals.legs & CDR_LEG_A) && (globals.legs & CDR_LEG_B))) { if ((globals.legs & CDR_LEG_A)) { if (switch_channel_get_originator_caller_profile(channel)) { return SWITCH_STATUS_SUCCESS; } } else { if (switch_channel_get_originatee_caller_profile(channel)) { return SWITCH_STATUS_SUCCESS; } } } if (switch_dir_make_recursive(globals.spool_dir, SWITCH_DEFAULT_DIR_PERMS, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error creating %s\n", globals.spool_dir); return SWITCH_STATUS_FALSE; } if (globals.debug) { switch_event_t *event; if (switch_event_create(&event, SWITCH_EVENT_COMMAND) == SWITCH_STATUS_SUCCESS) { char *buf; switch_channel_event_set_data(channel, event); switch_event_serialize(event, &buf, SWITCH_FALSE); switch_assert(buf); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "CHANNEL_DATA:\n%s\n", buf); switch_event_destroy(&event); switch_safe_free(buf); } } switch_zmalloc(values, 1); offset = 0; for (cdr_field = globals.db_schema->fields; cdr_field->var_name; cdr_field++) { if ((var = switch_channel_get_variable(channel, cdr_field->var_name))) { /* Allocate sufficient buffer for PQescapeString */ len = strlen(var); tmp = switch_core_session_alloc(session, len * 2 + 1); PQescapeString(tmp, var, len); var = tmp; } if ((cdr_field->not_null == SWITCH_FALSE) && zstr(var)) { pq_var = switch_mprintf("null,", var); } else { if (cdr_field->quote) { pq_var = switch_mprintf("'%s',", var); } else { pq_var = switch_mprintf("%s,", var); } } /* Resize values buffer to accomodate next var */ len = strlen(pq_var); tmp = realloc(values, offset + len); values = tmp; memcpy(values + offset, pq_var, len); switch_safe_free(pq_var); offset += len; } *(values + --offset) = '\0'; insert_cdr(values); switch_safe_free(values); return status; }
static cid_data_t *do_lookup(switch_memory_pool_t *pool, switch_event_t *event, const char *num, switch_bool_t skipurl, switch_bool_t skipcitystate) { char *number = NULL; char *name = NULL; char *url_query = NULL; cid_data_t *cid = NULL; cid_data_t *cidtmp = NULL; switch_bool_t save_cache = SWITCH_FALSE; cid = switch_core_alloc(pool, sizeof(cid_data_t)); switch_assert(cid); number = string_digitsonly(pool, num); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "caller_id_number", number); /* database always wins */ if ((switch_odbc_available() || switch_pgsql_available()) && globals.odbc_dsn && globals.sql) { name = do_db_lookup(pool, event, number, globals.sql); if (name) { cid->name = name; cid->src = "phone_database"; goto done; } } if (globals.cache) { cidtmp = check_cache(pool, number); if (cidtmp) { cid = cidtmp; cid->src = switch_core_sprintf(pool, "%s (cache)", cid->src); goto done; } } if (!skipurl && globals.whitepages_apikey) { cid = do_whitepages_lookup(pool, event, number); if (cid && cid->name) { /* only cache if we have a name */ save_cache = SWITCH_TRUE; goto done; } } if (!skipurl && globals.url) { url_query = switch_event_expand_headers(event, globals.url); do_lookup_url(pool, event, &name, url_query, NULL, NULL, 0); if (name) { cid->name = name; cid->src = "url"; save_cache = SWITCH_TRUE; } if (url_query != globals.url) { switch_safe_free(url_query); } } done: if (!cid) { cid = switch_core_alloc(pool, sizeof(cid_data_t)); switch_assert(cid); } /* append area if we can */ if (!cid->area && !skipcitystate && strlen(number) == 11 && number[0] == '1' && (switch_odbc_available() || switch_pgsql_available()) && globals.odbc_dsn && globals.citystate_sql) { /* yes, this is really area */ name = do_db_lookup(pool, event, number, globals.citystate_sql); if (name) { cid->area = name; if (cid->src) { cid->src = switch_core_sprintf(pool, "%s,%s", cid->src, "npanxx_database"); } else { cid->src = "npanxx_database"; } } } if (!cid->area) { cid->area = "UNKNOWN"; } if (!cid->name) { if (skipcitystate) { if (strlen(number) == 11 && number[0] == '1') { int a, b, c; sscanf(number, "1%3d%3d%4d", &a, &b, &c); cid->name = switch_core_sprintf(pool, "%03d-%03d-%04d", a, b, c); } else { cid->name = number; } } else { cid->name = cid->area; } } if (!cid->src) { cid->src = "UNKNOWN"; } if (globals.cache && save_cache) { set_cache(pool, number, cid); } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10, "cidlookup source: %s\n", cid->src); return cid; }
static cid_data_t *do_whitepages_lookup(switch_memory_pool_t *pool, switch_event_t *event, const char *num) { char *xml_s = NULL; char *query = NULL; char *name = NULL; char *city = NULL; char *state = NULL; char *area = NULL; switch_xml_t xml = NULL; switch_xml_t node = NULL; cid_data_t *cid = NULL; /* NANPA check */ if (strlen(num) == 11 && num[0] == '1') { num++; /* skip past leading 1 */ } else { goto done; } switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "whitepages-cid", num); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "whitepages-api-key", globals.whitepages_apikey); query = switch_event_expand_headers(event, "http://api.whitepages.com/reverse_phone/1.0/?phone=${whitepages-cid};api_key=${whitepages-api-key}"); do_lookup_url(pool, event, &xml_s, query, NULL, NULL, 0); if (zstr(xml_s)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No XML returned for number %s\n", num); goto done; } xml = switch_xml_parse_str_dup(xml_s); if (!xml) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to parse XML: %s\n", xml_s); goto done; } /* try for bizname first */ node = switch_xml_get(xml, "wp:listings", 0, "wp:listing", 0, "wp:business", 0, "wp:businessname", -1); if (node) { name = switch_core_strdup(pool, switch_xml_txt(node)); goto area; } node = switch_xml_get(xml, "wp:listings", 0, "wp:listing", 0, "wp:displayname", -1); if (node) { name = switch_core_strdup(pool, switch_xml_txt(node)); } area: node = switch_xml_get(xml, "wp:listings", 0, "wp:listing", 0, "wp:address", 0, "wp:city", -1); if (node) { city = switch_xml_txt(node); } node = switch_xml_get(xml, "wp:listings", 0, "wp:listing", 0, "wp:address", 0, "wp:state", -1); if (node) { state = switch_xml_txt(node); } if (city || state) { area = switch_core_sprintf(pool, "%s %s", city ? city : "", state ? state : ""); } done: if (query) { switch_safe_free(query); } if (xml) { switch_xml_free(xml); } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10, "whitepages XML: %s\n", xml_s); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10, "whitepages name: %s, area: %s\n", name ? name : "(null)", area ? area : "(null)"); cid = switch_core_alloc(pool, sizeof(cid_data_t)); switch_assert(cid); cid->name = name; cid->area = area; cid->src = "whitepages"; return cid; }
/* marshall frames from the call leg to the conference thread for muxing to other call legs */ void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, void *obj) { switch_event_t *event; conference_member_t *member = obj; switch_channel_t *channel; switch_status_t status; switch_frame_t *read_frame = NULL; uint32_t hangover = 40, hangunder = 5, hangover_hits = 0, hangunder_hits = 0, diff_level = 400; switch_core_session_t *session = member->session; uint32_t flush_len; switch_frame_t tmp_frame = { 0 }; if (switch_core_session_read_lock(session) != SWITCH_STATUS_SUCCESS) { goto end; } switch_assert(member != NULL); conference_utils_member_clear_flag_locked(member, MFLAG_TALKING); channel = switch_core_session_get_channel(session); switch_core_session_get_read_impl(session, &member->read_impl); switch_channel_audio_sync(channel); flush_len = switch_samples_per_packet(member->conference->rate, member->conference->interval) * 2 * member->conference->channels * (500 / member->conference->interval); /* As long as we have a valid read, feed that data into an input buffer where the conference thread will take it and mux it with any audio from other channels. */ while (conference_utils_member_test_flag(member, MFLAG_RUNNING) && switch_channel_ready(channel)) { if (switch_channel_ready(channel) && switch_channel_test_app_flag(channel, CF_APP_TAGGED)) { switch_yield(100000); continue; } /* Read a frame. */ status = switch_core_session_read_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0); switch_mutex_lock(member->read_mutex); /* end the loop, if appropriate */ if (!SWITCH_READ_ACCEPTABLE(status) || !conference_utils_member_test_flag(member, MFLAG_RUNNING)) { switch_mutex_unlock(member->read_mutex); break; } if (switch_channel_test_flag(channel, CF_VIDEO) && !conference_utils_member_test_flag(member, MFLAG_ACK_VIDEO)) { conference_utils_member_set_flag_locked(member, MFLAG_ACK_VIDEO); conference_video_check_avatar(member, SWITCH_FALSE); switch_core_session_video_reinit(member->session); conference_video_set_floor_holder(member->conference, member, SWITCH_FALSE); } else if (conference_utils_member_test_flag(member, MFLAG_ACK_VIDEO) && !switch_channel_test_flag(channel, CF_VIDEO)) { conference_video_check_avatar(member, SWITCH_FALSE); } /* if we have caller digits, feed them to the parser to find an action */ if (switch_channel_has_dtmf(channel)) { char dtmf[128] = ""; switch_channel_dequeue_dtmf_string(channel, dtmf, sizeof(dtmf)); if (conference_utils_member_test_flag(member, MFLAG_DIST_DTMF)) { conference_member_send_all_dtmf(member, member->conference, dtmf); } else if (member->dmachine) { char *p; char str[2] = ""; for (p = dtmf; p && *p; p++) { str[0] = *p; switch_ivr_dmachine_feed(member->dmachine, str, NULL); } } } else if (member->dmachine) { switch_ivr_dmachine_ping(member->dmachine, NULL); } if (switch_queue_size(member->dtmf_queue)) { switch_dtmf_t *dt; void *pop; if (switch_queue_trypop(member->dtmf_queue, &pop) == SWITCH_STATUS_SUCCESS) { dt = (switch_dtmf_t *) pop; switch_core_session_send_dtmf(member->session, dt); free(dt); } } if (switch_channel_test_flag(member->channel, CF_CONFERENCE_RESET_MEDIA)) { member->reset_media = 10; switch_channel_audio_sync(member->channel); switch_channel_clear_flag(member->channel, CF_CONFERENCE_RESET_MEDIA); } if (member->reset_media) { if (--member->reset_media > 0) { goto do_continue; } if (conference_member_setup_media(member, member->conference)) { switch_mutex_unlock(member->read_mutex); break; } member->loop_loop = 1; goto do_continue; } if (switch_test_flag(read_frame, SFF_CNG)) { if (member->conference->agc_level) { member->nt_tally++; } if (hangunder_hits) { hangunder_hits--; } if (conference_utils_member_test_flag(member, MFLAG_TALKING)) { if (++hangover_hits >= hangover) { hangover_hits = hangunder_hits = 0; conference_utils_member_clear_flag_locked(member, MFLAG_TALKING); conference_member_update_status_field(member); conference_member_check_agc_levels(member); conference_member_clear_avg(member); member->score_iir = 0; member->floor_packets = 0; if (test_eflag(member->conference, EFLAG_STOP_TALKING) && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) { conference_member_add_event_data(member, event); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "stop-talking"); switch_event_fire(&event); } } } goto do_continue; } if (member->nt_tally > (int32_t)(member->read_impl.actual_samples_per_second / member->read_impl.samples_per_packet) * 3) { member->agc_volume_in_level = 0; conference_member_clear_avg(member); } /* Check for input volume adjustments */ if (!member->conference->agc_level) { member->conference->agc_level = 0; conference_member_clear_avg(member); } /* if the member can speak, compute the audio energy level and */ /* generate events when the level crosses the threshold */ if ((conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK) || conference_utils_member_test_flag(member, MFLAG_MUTE_DETECT))) { uint32_t energy = 0, i = 0, samples = 0, j = 0; int16_t *data; int agc_period = (member->read_impl.actual_samples_per_second / member->read_impl.samples_per_packet) / 4; data = read_frame->data; member->score = 0; if (member->volume_in_level) { switch_change_sln_volume(read_frame->data, (read_frame->datalen / 2) * member->conference->channels, member->volume_in_level); } if (member->agc_volume_in_level) { switch_change_sln_volume_granular(read_frame->data, (read_frame->datalen / 2) * member->conference->channels, member->agc_volume_in_level); } if ((samples = read_frame->datalen / sizeof(*data) / member->read_impl.number_of_channels)) { for (i = 0; i < samples; i++) { energy += abs(data[j]); j += member->read_impl.number_of_channels; } member->score = energy / samples; } if (member->vol_period) { member->vol_period--; } if (member->conference->agc_level && member->score && conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK) && conference_member_noise_gate_check(member) ) { int last_shift = abs((int)(member->last_score - member->score)); if (member->score && member->last_score && last_shift > 900) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG7, "AGC %s:%d drop anomalous shift of %d\n", member->conference->name, member->id, last_shift); } else { member->avg_tally += member->score; member->avg_itt++; if (!member->avg_itt) member->avg_itt++; member->avg_score = member->avg_tally / member->avg_itt; } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG7, "AGC %s:%d diff:%d level:%d cur:%d avg:%d vol:%d\n", member->conference->name, member->id, member->conference->agc_level - member->avg_score, member->conference->agc_level, member->score, member->avg_score, member->agc_volume_in_level); if (++member->agc_concur >= agc_period) { if (!member->vol_period) { conference_member_check_agc_levels(member); } member->agc_concur = 0; } } else { member->nt_tally++; } member->score_iir = (int) (((1.0 - SCORE_DECAY) * (float) member->score) + (SCORE_DECAY * (float) member->score_iir)); if (member->score_iir > SCORE_MAX_IIR) { member->score_iir = SCORE_MAX_IIR; } if (conference_member_noise_gate_check(member)) { uint32_t diff = member->score - member->energy_level; if (hangover_hits) { hangover_hits--; } if (member->conference->agc_level) { member->nt_tally = 0; } if (member == member->conference->floor_holder) { member->floor_packets++; } if (diff >= diff_level || ++hangunder_hits >= hangunder) { hangover_hits = hangunder_hits = 0; member->last_talking = switch_epoch_time_now(NULL); if (!conference_utils_member_test_flag(member, MFLAG_TALKING)) { conference_utils_member_set_flag_locked(member, MFLAG_TALKING); conference_member_update_status_field(member); member->floor_packets = 0; if (test_eflag(member->conference, EFLAG_START_TALKING) && conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK) && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) { conference_member_add_event_data(member, event); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "start-talking"); switch_event_fire(&event); } if (conference_utils_member_test_flag(member, MFLAG_MUTE_DETECT) && !conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK)) { if (!zstr(member->conference->mute_detect_sound)) { conference_utils_member_set_flag(member, MFLAG_INDICATE_MUTE_DETECT); } if (test_eflag(member->conference, EFLAG_MUTE_DETECT) && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) { conference_member_add_event_data(member, event); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "mute-detect"); switch_event_fire(&event); } } } } } else { if (hangunder_hits) { hangunder_hits--; } if (member->conference->agc_level) { member->nt_tally++; } if (conference_utils_member_test_flag(member, MFLAG_TALKING) && conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK)) { switch_event_t *event; if (++hangover_hits >= hangover) { hangover_hits = hangunder_hits = 0; conference_utils_member_clear_flag_locked(member, MFLAG_TALKING); conference_member_update_status_field(member); conference_member_check_agc_levels(member); conference_member_clear_avg(member); if (test_eflag(member->conference, EFLAG_STOP_TALKING) && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) { conference_member_add_event_data(member, event); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "stop-talking"); switch_event_fire(&event); } } } } member->last_score = member->score; if (member == member->conference->floor_holder) { if (member->id != member->conference->video_floor_holder && (member->floor_packets > member->conference->video_floor_packets || member->energy_level == 0)) { conference_video_set_floor_holder(member->conference, member, SWITCH_FALSE); } } } /* skip frames that are not actual media or when we are muted or silent */ if ((conference_utils_member_test_flag(member, MFLAG_TALKING) || member->energy_level == 0 || conference_utils_test_flag(member->conference, CFLAG_AUDIO_ALWAYS)) && conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK) && !conference_utils_test_flag(member->conference, CFLAG_WAIT_MOD) && (member->conference->count > 1 || (member->conference->record_count && member->conference->count >= member->conference->min_recording_participants))) { switch_audio_resampler_t *read_resampler = member->read_resampler; void *data; uint32_t datalen; if (read_resampler) { int16_t *bptr = (int16_t *) read_frame->data; int len = (int) read_frame->datalen; switch_resample_process(read_resampler, bptr, len / 2 / member->read_impl.number_of_channels); memcpy(member->resample_out, read_resampler->to, read_resampler->to_len * 2 * member->read_impl.number_of_channels); len = read_resampler->to_len * 2 * member->read_impl.number_of_channels; datalen = len; data = member->resample_out; } else { data = read_frame->data; datalen = read_frame->datalen; } tmp_frame.data = data; tmp_frame.datalen = datalen; tmp_frame.rate = member->conference->rate; conference_member_check_channels(&tmp_frame, member, SWITCH_TRUE); if (datalen) { switch_size_t ok = 1; /* Write the audio into the input buffer */ switch_mutex_lock(member->audio_in_mutex); if (switch_buffer_inuse(member->audio_buffer) > flush_len) { switch_buffer_toss(member->audio_buffer, tmp_frame.datalen); } ok = switch_buffer_write(member->audio_buffer, tmp_frame.data, tmp_frame.datalen); switch_mutex_unlock(member->audio_in_mutex); if (!ok) { switch_mutex_unlock(member->read_mutex); break; } } } do_continue: switch_mutex_unlock(member->read_mutex); } if (switch_queue_size(member->dtmf_queue)) { switch_dtmf_t *dt; void *pop; while (switch_queue_trypop(member->dtmf_queue, &pop) == SWITCH_STATUS_SUCCESS) { dt = (switch_dtmf_t *) pop; free(dt); } } switch_resample_destroy(&member->read_resampler); switch_core_session_rwunlock(session); end: conference_utils_member_clear_flag_locked(member, MFLAG_ITHREAD); return NULL; }
static switch_status_t channel_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg) { switch_channel_t *channel; loopback_private_t *tech_pvt; int done = 1, pass = 0; switch_core_session_t *other_session; channel = switch_core_session_get_channel(session); switch_assert(channel != NULL); tech_pvt = switch_core_session_get_private(session); switch_assert(tech_pvt != NULL); switch (msg->message_id) { case SWITCH_MESSAGE_INDICATE_ANSWER: if (tech_pvt->other_channel && !switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) { switch_channel_mark_answered(tech_pvt->other_channel); } break; case SWITCH_MESSAGE_INDICATE_PROGRESS: if (tech_pvt->other_channel && !switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) { switch_channel_mark_pre_answered(tech_pvt->other_channel); } break; case SWITCH_MESSAGE_INDICATE_RINGING: if (tech_pvt->other_channel && !switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) { switch_channel_mark_ring_ready(tech_pvt->other_channel); } break; case SWITCH_MESSAGE_INDICATE_BRIDGE: { switch_set_flag_locked(tech_pvt, TFLAG_BRIDGE); } break; case SWITCH_MESSAGE_INDICATE_UNBRIDGE: { switch_clear_flag_locked(tech_pvt, TFLAG_BRIDGE); } break; default: done = 0; break; } switch (msg->message_id) { case SWITCH_MESSAGE_INDICATE_BRIDGE: case SWITCH_MESSAGE_INDICATE_UNBRIDGE: case SWITCH_MESSAGE_INDICATE_AUDIO_SYNC: { done = 1; switch_set_flag(tech_pvt, TFLAG_CLEAR); switch_set_flag(tech_pvt->other_tech_pvt, TFLAG_CLEAR); switch_core_timer_sync(&tech_pvt->timer); switch_core_timer_sync(&tech_pvt->other_tech_pvt->timer); } break; default: break; } switch (msg->message_id) { case SWITCH_MESSAGE_INDICATE_DISPLAY: if (tech_pvt->other_channel) { if (switch_test_flag(tech_pvt, TFLAG_BLEG)) { if (!zstr(msg->string_array_arg[0])) { switch_channel_set_profile_var(tech_pvt->other_channel, "caller_id_name", msg->string_array_arg[0]); } if (!zstr(msg->string_array_arg[1])) { switch_channel_set_profile_var(tech_pvt->other_channel, "caller_id_number", msg->string_array_arg[1]); } } else { if (!zstr(msg->string_array_arg[0])) { switch_channel_set_profile_var(tech_pvt->other_channel, "callee_id_name", msg->string_array_arg[0]); } if (!zstr(msg->string_array_arg[1])) { switch_channel_set_profile_var(tech_pvt->other_channel, "callee_id_number", msg->string_array_arg[1]); } } pass = 1; } break; case SWITCH_MESSAGE_INDICATE_DEFLECT: { pass = 0; if (!zstr(msg->string_arg) && switch_core_session_get_partner(tech_pvt->other_session, &other_session) == SWITCH_STATUS_SUCCESS) { char *ext = switch_core_session_strdup(other_session, msg->string_arg); char *context = NULL, *dp = NULL; if ((context = strchr(ext, ' '))) { *context++ = '\0'; if ((dp = strchr(context, ' '))) { *dp++ = '\0'; } } switch_ivr_session_transfer(other_session, ext, context, dp); switch_core_session_rwunlock(other_session); } } break; default: break; } if (!done && tech_pvt->other_session && (pass || switch_test_flag(tech_pvt, TFLAG_RUNNING_APP))) { switch_status_t r = SWITCH_STATUS_FALSE; if (switch_core_session_get_partner(tech_pvt->other_session, &other_session) == SWITCH_STATUS_SUCCESS) { r = switch_core_session_receive_message(other_session, msg); switch_core_session_rwunlock(other_session); } return r; } return SWITCH_STATUS_SUCCESS; }
static void switch_core_standard_on_hibernate(switch_core_session_t *session) { switch_assert(session != NULL); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Standard HIBERNATE\n", switch_channel_get_name(session->channel)); }
SWITCH_DECLARE(switch_status_t) switch_core_asr_resume(switch_asr_handle_t *ah) { switch_assert(ah != NULL); return ah->asr_interface->asr_resume(ah); }
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 */ STATE_MACRO(init, "INIT"); 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(); 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_core_session_message_t *message; while (switch_core_session_dequeue_message(session, &message) == SWITCH_STATUS_SUCCESS) { switch_core_session_receive_message(session, message); message = NULL; } 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); while (switch_core_session_dequeue_message(session, &message) == SWITCH_STATUS_SUCCESS) { switch_core_session_receive_message(session, message); message = NULL; } } } } done: switch_mutex_unlock(session->mutex); switch_clear_flag(session, SSF_THREAD_RUNNING); }
SWITCH_DECLARE(switch_status_t) switch_core_asr_check_results(switch_asr_handle_t *ah, switch_asr_flag_t *flags) { switch_assert(ah != NULL); return ah->asr_interface->asr_check_results(ah, flags); }
SWITCH_DECLARE(void) switch_core_session_hangup_state(switch_core_session_t *session, switch_bool_t force) { switch_call_cause_t cause = switch_channel_get_cause(session->channel); switch_call_cause_t cause_q850 = switch_channel_get_cause_q850(session->channel); int proceed = 1; int global_proceed = 1; int do_extra_handlers = 1; int silly = 0; int index = 0; switch_channel_state_t state = switch_channel_get_state(session->channel), midstate = state; 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; const char *hook_var; int use_session = 0; if (!force) { if (!switch_channel_test_flag(session->channel, CF_EARLY_HANGUP) && !switch_test_flag((&runtime), SCF_EARLY_HANGUP)) { return; } if (switch_thread_self() != session->thread_id) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG10, "%s thread mismatch skipping state handler.\n", switch_channel_get_name(session->channel)); return; } } if (switch_test_flag(session, SSF_HANGUP)) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG10, "%s handler already called, skipping state handler.\n", switch_channel_get_name(session->channel)); return; } endpoint_interface = session->endpoint_interface; switch_assert(endpoint_interface != NULL); driver_state_handler = endpoint_interface->state_handler; switch_assert(driver_state_handler != NULL); switch_channel_set_hangup_time(session->channel); switch_core_media_bug_remove_all(session); switch_channel_stop_broadcast(session->channel); switch_channel_set_variable(session->channel, "hangup_cause", switch_channel_cause2str(cause)); switch_channel_set_variable_printf(session->channel, "hangup_cause_q850", "%d", cause_q850); //switch_channel_presence(session->channel, "unknown", switch_channel_cause2str(cause), NULL); switch_channel_set_timestamps(session->channel); STATE_MACRO(hangup, "HANGUP"); if ((hook_var = switch_channel_get_variable(session->channel, SWITCH_API_HANGUP_HOOK_VARIABLE))) { if (switch_true(switch_channel_get_variable(session->channel, SWITCH_SESSION_IN_HANGUP_HOOK_VARIABLE))) { use_session = 1; } api_hook(session, hook_var, use_session); } switch_set_flag(session, SSF_HANGUP); }
SWITCH_DECLARE(switch_status_t) switch_core_asr_load_grammar(switch_asr_handle_t *ah, const char *grammar, const char *name) { switch_status_t status = SWITCH_STATUS_SUCCESS; char *param_string = NULL; char *data = NULL; char *lgrammar = NULL; switch_assert(ah != NULL); if (zstr(grammar)) { status = SWITCH_STATUS_FALSE; goto done; } /* Set ASR parameters from params in the grammar string * Params are defined as follows {name1=val1,name2=val2,name3=val3}grammar text */ lgrammar = strdup(grammar); data = lgrammar; /* strip leading spaces */ while (data && *data == ' ') { data++; } if (zstr(data)) { status = SWITCH_STATUS_FALSE; goto done; } /* extract params */ if (*data == '{') { param_string = data + 1; data = switch_find_end_paren(data, '{', '}'); if (zstr(data)) { status = SWITCH_STATUS_FALSE; goto done; } else { *data = '\0'; data++; } } /* set ASR params */ if (!zstr(param_string)) { char *param[256] = { 0 }; int i; int argc = switch_separate_string(param_string, ',', param, (sizeof(param) / sizeof(param[0]))); for (i = 0; i < argc && param[i]; ++i) { char *param_pair[2] = { 0 }; if (switch_separate_string(param[i], '=', param_pair, (sizeof(param_pair) / sizeof(param_pair[0]))) == 2) { switch_core_asr_text_param(ah, param_pair[0], param_pair[1]); } } } status = ah->asr_interface->asr_load_grammar(ah, data, name); done: switch_safe_free(lgrammar); return status; }
SWITCH_DECLARE(void) switch_core_session_reporting_state(switch_core_session_t *session) { switch_channel_state_t state = switch_channel_get_state(session->channel), midstate = state; 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 proceed = 1; int global_proceed = 1; int do_extra_handlers = 1; int silly = 0; int index = 0; const char *var = switch_channel_get_variable(session->channel, SWITCH_PROCESS_CDR_VARIABLE); const char *hook_var; int use_session = 0; switch_event_t *event; switch_call_cause_t cause = switch_channel_get_cause(session->channel); if (switch_channel_test_flag(session->channel, CF_REPORTING)) { return; } switch_channel_set_flag(session->channel, CF_REPORTING); switch_assert(session != NULL); endpoint_interface = session->endpoint_interface; switch_assert(endpoint_interface != NULL); driver_state_handler = endpoint_interface->state_handler; switch_assert(driver_state_handler != NULL); if (!zstr(var)) { if (!strcasecmp(var, "a_only")) { if (switch_channel_get_originator_caller_profile(session->channel)) { do_extra_handlers = 0; } } else if (!strcasecmp(var, "b_only")) { if (switch_channel_get_originatee_caller_profile(session->channel)) { do_extra_handlers = 0; } } else if (!switch_true(var)) { do_extra_handlers = 0; } } STATE_MACRO(reporting, "REPORTING"); if ((hook_var = switch_channel_get_variable(session->channel, SWITCH_API_REPORTING_HOOK_VARIABLE))) { if (switch_true(switch_channel_get_variable(session->channel, SWITCH_SESSION_IN_HANGUP_HOOK_VARIABLE))) { use_session = 1; } api_hook(session, hook_var, use_session); } if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_HANGUP_COMPLETE) == SWITCH_STATUS_SUCCESS) { switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Hangup-Cause", switch_channel_cause2str(cause)); switch_channel_event_set_data(session->channel, event); if (switch_true(switch_channel_get_variable(session->channel, "hangup_complete_with_xml"))) { switch_xml_t cdr = NULL; char *xml_cdr_text; if (switch_ivr_generate_xml_cdr(session, &cdr) == SWITCH_STATUS_SUCCESS) { xml_cdr_text = switch_xml_toxml(cdr, SWITCH_FALSE); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CDR-Attached", "xml"); switch_event_add_body(event, "%s", xml_cdr_text); switch_xml_free(cdr); switch_safe_free(xml_cdr_text); } } switch_event_fire(&event); } return; }
SWITCH_DECLARE(switch_memory_pool_t *) switch_core_session_get_pool(switch_core_session_t *session) { switch_assert(session != NULL); switch_assert(session->pool != NULL); return session->pool; }
/* 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; 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"); switch_channel_set_state(channel, CS_ROUTING); end: return SWITCH_STATUS_SUCCESS; }
SWITCH_DECLARE(switch_status_t) switch_core_codec_init_with_bitrate(switch_codec_t *codec, const char *codec_name, const char *fmtp, uint32_t rate, int ms, int channels, uint32_t bitrate, uint32_t flags, const switch_codec_settings_t *codec_settings, switch_memory_pool_t *pool) { switch_codec_interface_t *codec_interface; const switch_codec_implementation_t *iptr, *implementation = NULL; switch_assert(codec != NULL); switch_assert(codec_name != NULL); memset(codec, 0, sizeof(*codec)); if (channels == 2) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Stereo is currently unsupported. please downsample audio source to mono.\n"); return SWITCH_STATUS_GENERR; } if ((codec_interface = switch_loadable_module_get_codec_interface(codec_name)) == 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid codec %s!\n", codec_name); return SWITCH_STATUS_GENERR; } /* If no specific codec interval is requested opt for 20ms above all else because lots of stuff assumes it */ if (!ms) { for (iptr = codec_interface->implementations; iptr; iptr = iptr->next) { if ((!rate || rate == iptr->samples_per_second) && (!bitrate || bitrate == (uint32_t)iptr->bits_per_second) && (20 == (iptr->microseconds_per_packet / 1000)) && (!channels || channels == iptr->number_of_channels)) { implementation = iptr; goto found; } } } /* Either looking for a specific interval or there was no interval specified and there wasn't one @20ms available */ for (iptr = codec_interface->implementations; iptr; iptr = iptr->next) { if ((!rate || rate == iptr->samples_per_second) && (!bitrate || bitrate == (uint32_t)iptr->bits_per_second) && (!ms || ms == (iptr->microseconds_per_packet / 1000)) && (!channels || channels == iptr->number_of_channels)) { implementation = iptr; break; } } found: if (implementation) { switch_status_t status; codec->codec_interface = codec_interface; codec->implementation = implementation; codec->flags = flags; if (pool) { codec->memory_pool = pool; } else { if ((status = switch_core_new_memory_pool(&codec->memory_pool)) != SWITCH_STATUS_SUCCESS) { return status; } switch_set_flag(codec, SWITCH_CODEC_FLAG_FREE_POOL); } if (fmtp) { codec->fmtp_in = switch_core_strdup(codec->memory_pool, fmtp); } implementation->init(codec, flags, codec_settings); switch_mutex_init(&codec->mutex, SWITCH_MUTEX_NESTED, codec->memory_pool); switch_set_flag(codec, SWITCH_CODEC_FLAG_READY); return SWITCH_STATUS_SUCCESS; } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Codec %s Exists but not at the desired implementation. %dhz %dms\n", codec_name, rate, ms); } UNPROTECT_INTERFACE(codec_interface); return SWITCH_STATUS_NOTIMPL; }
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; loopback_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 void event_handler(switch_event_t *event) { uint8_t send = 0; if (globals.running != 1) { return; } if (event->subclass_name && (!strcmp(event->subclass_name, MULTICAST_EVENT) || !strcmp(event->subclass_name, MULTICAST_PEERUP) || !strcmp(event->subclass_name, MULTICAST_PEERDOWN))) { char *event_name, *sender; if ((event_name = switch_event_get_header(event, "orig-event-name")) && !strcasecmp(event_name, "HEARTBEAT") && (sender = switch_event_get_header(event, "orig-multicast-sender"))) { struct peer_status *p; time_t now = switch_epoch_time_now(NULL); if (!(p = switch_core_hash_find(globals.peer_hash, sender))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Host %s not already in hash\n", sender); p = switch_core_alloc(module_pool, sizeof(struct peer_status)); p->active = SWITCH_FALSE; p->lastseen = 0; /*} else { */ /*switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Host %s last seen %d seconds ago\n", sender, now - p->lastseen); */ } if (!p->active) { switch_event_t *local_event; if (switch_event_create_subclass(&local_event, SWITCH_EVENT_CUSTOM, MULTICAST_PEERUP) == SWITCH_STATUS_SUCCESS) { char lastseen[21]; switch_event_add_header_string(local_event, SWITCH_STACK_BOTTOM, "Peer", sender); if (p->lastseen) { switch_snprintf(lastseen, sizeof(lastseen), "%d", (int) p->lastseen); } else { switch_snprintf(lastseen, sizeof(lastseen), "%s", "Never"); } switch_event_add_header_string(local_event, SWITCH_STACK_BOTTOM, "Lastseen", lastseen); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Peer %s has come up; last seen: %s\n", sender, lastseen); switch_event_fire(&local_event); } } p->active = SWITCH_TRUE; p->lastseen = now; switch_core_hash_insert(globals.peer_hash, sender, p); } /* ignore our own events to avoid ping pong */ return; } if (event->event_id == SWITCH_EVENT_RELOADXML) { switch_mutex_lock(globals.mutex); switch_core_hash_destroy(&globals.event_hash); globals.event_hash = NULL; if (globals.psk) { switch_safe_free(globals.psk); globals.psk = NULL; } switch_core_hash_init(&globals.event_hash, module_pool); memset(globals.event_list, 0, SWITCH_EVENT_ALL + 1); if (load_config() != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Failed to reload config file\n"); } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Event Multicast Reloaded\n"); } switch_mutex_unlock(globals.mutex); } if (event->event_id == SWITCH_EVENT_HEARTBEAT) { switch_hash_index_t *cur; switch_ssize_t keylen; const void *key; void *value; time_t now = switch_epoch_time_now(NULL); struct peer_status *last; char *host; for (cur = switch_hash_first(NULL, globals.peer_hash); cur; cur = switch_hash_next(cur)) { switch_hash_this(cur, &key, &keylen, &value); host = (char *) key; last = (struct peer_status *) value; if (last->active && (now - (last->lastseen)) > 60) { switch_event_t *local_event; last->active = SWITCH_FALSE; if (switch_event_create_subclass(&local_event, SWITCH_EVENT_CUSTOM, MULTICAST_PEERDOWN) == SWITCH_STATUS_SUCCESS) { char lastseen[21]; switch_event_add_header_string(local_event, SWITCH_STACK_BOTTOM, "Peer", host); switch_snprintf(lastseen, sizeof(lastseen), "%d", (int) last->lastseen); switch_event_add_header_string(local_event, SWITCH_STACK_BOTTOM, "Lastseen", lastseen); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Peer %s has gone down; last seen: %s\n", host, lastseen); switch_event_fire(&local_event); } } } } switch_mutex_lock(globals.mutex); if (globals.event_list[(uint8_t) SWITCH_EVENT_ALL]) { send = 1; } else if ((globals.event_list[(uint8_t) event->event_id])) { if (event->event_id != SWITCH_EVENT_CUSTOM || (event->subclass_name && switch_core_hash_find(globals.event_hash, event->subclass_name))) { send = 1; } } switch_mutex_unlock(globals.mutex); if (send) { char *packet; switch (event->event_id) { case SWITCH_EVENT_LOG: return; default: switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Multicast-Sender", switch_core_get_switchname()); if (switch_event_serialize(event, &packet, SWITCH_TRUE) == SWITCH_STATUS_SUCCESS) { size_t len; char *buf; #ifdef HAVE_OPENSSL int outlen, tmplen; EVP_CIPHER_CTX ctx; char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1]; switch_uuid_t uuid; switch_uuid_get(&uuid); switch_uuid_format(uuid_str, &uuid); len = strlen(packet) + SWITCH_UUID_FORMATTED_LENGTH + EVP_MAX_IV_LENGTH + strlen((char *) MAGIC); #else len = strlen(packet) + strlen((char *) MAGIC); #endif buf = malloc(len + 1); memset(buf, 0, len + 1); switch_assert(buf); #ifdef HAVE_OPENSSL if (globals.psk) { switch_copy_string(buf, uuid_str, SWITCH_UUID_FORMATTED_LENGTH); EVP_CIPHER_CTX_init(&ctx); EVP_EncryptInit(&ctx, EVP_bf_cbc(), NULL, NULL); EVP_CIPHER_CTX_set_key_length(&ctx, strlen(globals.psk)); EVP_EncryptInit(&ctx, NULL, (unsigned char *) globals.psk, (unsigned char *) uuid_str); EVP_EncryptUpdate(&ctx, (unsigned char *) buf + SWITCH_UUID_FORMATTED_LENGTH, &outlen, (unsigned char *) packet, (int) strlen(packet)); EVP_EncryptUpdate(&ctx, (unsigned char *) buf + SWITCH_UUID_FORMATTED_LENGTH + outlen, &tmplen, (unsigned char *) MAGIC, (int) strlen((char *) MAGIC)); outlen += tmplen; EVP_EncryptFinal(&ctx, (unsigned char *) buf + SWITCH_UUID_FORMATTED_LENGTH + outlen, &tmplen); outlen += tmplen; len = (size_t) outlen + SWITCH_UUID_FORMATTED_LENGTH; *(buf + SWITCH_UUID_FORMATTED_LENGTH + outlen) = '\0'; } else { #endif switch_copy_string(buf, packet, len); switch_copy_string(buf + strlen(packet), (char *) MAGIC, strlen((char *) MAGIC) + 1); #ifdef HAVE_OPENSSL } #endif switch_socket_sendto(globals.udp_socket, globals.addr, 0, buf, &len); switch_safe_free(packet); switch_safe_free(buf); } break; } } return; }
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; loopback_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, TFLAG_BLEG) && 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; }
/** * 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; }
int main(int argc, char *argv[]) { int r = 1; switch_bool_t verbose = SWITCH_FALSE; const char *err = NULL; int i; char *extra_modules[100] = { 0 }; int extra_modules_count = 0; int cmd_fail = 0; const char *fmtp = ""; int ptime = 20; const char *input, *output, *format = NULL; int channels = 1; int rate = 8000; switch_file_handle_t fh_input = { 0 }, fh_output = { 0 }; switch_codec_t codec = { 0 }; switch_codec_t raw_codec = { 0 }; char buf[2048]; switch_size_t len = sizeof(buf)/2; switch_memory_pool_t *pool = NULL; int bitrate = 0; int blocksize; int in_asis = 0; int out_asis = 0; int out_flags = SWITCH_FILE_FLAG_WRITE; for (i = 1; i < argc; i++) { if (argv[i][0] == '-') { switch(argv[i][1]) { case 'c': i++; if((SWITCH_GLOBAL_dirs.conf_dir = (char *) malloc(strlen(argv[i]) + 1)) == NULL) { return 255; } strcpy(SWITCH_GLOBAL_dirs.conf_dir, argv[i]); break; case 'k': i++; if((SWITCH_GLOBAL_dirs.log_dir = (char *) malloc(strlen(argv[i]) + 1)) == NULL) { return 255; } strcpy(SWITCH_GLOBAL_dirs.log_dir, argv[i]); break; case 'm': i++; if((SWITCH_GLOBAL_dirs.mod_dir = (char *) malloc(strlen(argv[i]) + 1)) == NULL) { return 255; } strcpy(SWITCH_GLOBAL_dirs.mod_dir, argv[i]); break; case 'l': i++; /* Load extra modules */ if (strchr(argv[i], ',')) { extra_modules_count = switch_split(argv[i], ',', extra_modules); } else { extra_modules_count = 1; extra_modules[0] = argv[i]; } break; case 'f': fmtp = argv[++i]; break; case 'p': ptime = atoi(argv[++i]); break; case 'r': rate = atoi(argv[++i]); break; case 'b': bitrate = atoi(argv[++i]); break; case 'v': verbose = SWITCH_TRUE; break; default: printf("Command line option not recognized: %s\n", argv[i]); cmd_fail = 1; } } else { break; } } if (argc - i < 2 || cmd_fail) { goto usage; } input = argv[i++]; output = argv[i++]; if (zstr(input) || zstr(output) || !(format = strchr(output, '.'))) { goto usage; } format++; if (switch_core_init(SCF_MINIMAL, verbose, &err) != SWITCH_STATUS_SUCCESS) { fprintf(stderr, "Cannot init core [%s]\n", err); goto end; } switch_loadable_module_init(SWITCH_FALSE); switch_loadable_module_load_module("", "CORE_PCM_MODULE", SWITCH_TRUE, &err); switch_loadable_module_load_module("", "CORE_SPEEX_MODULE", SWITCH_TRUE, &err); switch_loadable_module_load_module("", "CORE_SOFTTIMER_MODULE", SWITCH_TRUE, &err); for (i = 0; i < extra_modules_count; i++) { if (switch_loadable_module_load_module((char *) SWITCH_GLOBAL_dirs.mod_dir, (char *) extra_modules[i], SWITCH_TRUE, &err) != SWITCH_STATUS_SUCCESS) { fprintf(stderr, "Cannot init %s [%s]\n", extra_modules[i], err); goto end; } } if (switch_loadable_module_load_module((char *) SWITCH_GLOBAL_dirs.mod_dir, (char *) "mod_spandsp", SWITCH_TRUE, &err) != SWITCH_STATUS_SUCCESS) { fprintf(stderr, "Cannot init mod_spandsp [%s]\n", err); goto end; } if (switch_loadable_module_load_module((char *) SWITCH_GLOBAL_dirs.mod_dir, (char *) "mod_sndfile", SWITCH_TRUE, &err) != SWITCH_STATUS_SUCCESS) { fprintf(stderr, "Cannot init mod_sndfile [%s]\n", err); goto end; } if (switch_loadable_module_load_module((char *) SWITCH_GLOBAL_dirs.mod_dir, (char *) "mod_native_file", SWITCH_TRUE, &err) != SWITCH_STATUS_SUCCESS) { fprintf(stderr, "Cannot init mod_native_file [%s]\n", err); goto end; } switch_core_new_memory_pool(&pool); if (verbose) { fprintf(stderr, "Opening file %s\n", input); } if (switch_core_file_open(&fh_input, input, channels, rate, SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) { fprintf(stderr, "Couldn't open %s\n", input); goto end; } if (verbose) { fprintf(stderr, "Opening file %s\n", output); } if (switch_stristr(".wav", output)) { out_asis = 0; out_flags |= SWITCH_FILE_DATA_SHORT; } else { out_asis = 1; out_flags |= SWITCH_FILE_NATIVE; } if (out_asis) { if (switch_core_codec_init_with_bitrate(&codec, format, NULL, fmtp, rate, ptime, channels, bitrate, SWITCH_CODEC_FLAG_ENCODE, NULL, pool) != SWITCH_STATUS_SUCCESS) { fprintf(stderr, "Couldn't initialize codec for %s@%dh@%di\n", format, rate, ptime); goto end; } } else { char *p; if ((p = strchr(input, '.'))) { p++; } if (!p || switch_core_codec_init_with_bitrate(&codec, p, NULL, fmtp, rate, ptime, channels, bitrate, SWITCH_CODEC_FLAG_ENCODE|SWITCH_CODEC_FLAG_DECODE, NULL, pool) != SWITCH_STATUS_SUCCESS) { fprintf(stderr, "Couldn't initialize codec for %s@%dh@%di\n", p, rate, ptime); goto end; } if (switch_core_codec_init_with_bitrate(&raw_codec, "L16", NULL, fmtp, rate, ptime, channels, bitrate, SWITCH_CODEC_FLAG_ENCODE|SWITCH_CODEC_FLAG_DECODE, NULL, pool) != SWITCH_STATUS_SUCCESS) { fprintf(stderr, "Couldn't initialize codec for %s@%dh@%di\n", "L16", rate, ptime); goto end; } } if (switch_core_file_open(&fh_output, output, channels, codec.implementation->actual_samples_per_second, out_flags, NULL) != SWITCH_STATUS_SUCCESS) { fprintf(stderr, "Couldn't open %s\n", output); goto end; } if (switch_test_flag(&fh_input, SWITCH_FILE_NATIVE)) { in_asis = 1; } if (in_asis) { blocksize = len = codec.implementation->encoded_bytes_per_packet; } else { blocksize = len = (rate*ptime)/1000; } switch_assert(sizeof(buf) >= len * 2); if (verbose) { fprintf(stderr, "Frame size is %d\n", blocksize); } while (switch_core_file_read(&fh_input, buf, &len) == SWITCH_STATUS_SUCCESS) { char encode_buf[2048]; uint32_t encoded_len = sizeof(buf); uint32_t encoded_rate = rate; unsigned int flags = 0; if (out_asis) { if (switch_core_codec_encode(&codec, NULL, buf, len*2, rate, encode_buf, &encoded_len, &encoded_rate, &flags) != SWITCH_STATUS_SUCCESS) { fprintf(stderr, "Codec encoder error\n"); goto end; } len = encoded_len; } else { if (!in_asis) { encoded_len = len; } else if (in_asis) { switch_core_codec_decode(&codec, &raw_codec, buf, len, rate, encode_buf, &encoded_len, &encoded_rate, &flags); encoded_len /= 2; len = encoded_len; } } if (switch_core_file_write(&fh_output, encode_buf, &len) != SWITCH_STATUS_SUCCESS) { fprintf(stderr, "Write error\n"); goto end; } if (len != encoded_len) { printf("Short write: wrote %"SWITCH_SIZE_T_FMT"/%d bytes\n", len, encoded_len); } len = blocksize; } r = 0; end: switch_core_codec_destroy(&codec); switch_core_codec_destroy(&raw_codec); if (fh_input.file_interface) { switch_core_file_close(&fh_input); } if (fh_output.file_interface) { switch_core_file_close(&fh_output); } if (pool) { switch_core_destroy_memory_pool(&pool); } fs_encode_cleanup(); //switch_core_destroy(); return r; usage: printf("Usage: %s [options] input output\n\n", argv[0]); printf("The output must end in the format, e.g., myfile.SPEEX\n"); printf("\t\t -c path\t\t Path to the FS configurations.\n"); printf("\t\t -k path\t\t Path to the FS log directory\n"); printf("\t\t -l module[,module]\t Load additional modules (comma-separated)\n"); printf("\t\t -m path\t\t Path to the modules.\n"); printf("\t\t -f format\t\t fmtp to pass to the codec\n"); printf("\t\t -p ptime\t\t ptime to use while encoding\n"); printf("\t\t -r rate\t\t sampling rate\n"); printf("\t\t -b bitrate\t\t codec bitrate (if supported)\n"); printf("\t\t -v\t\t\t verbose\n"); fs_encode_cleanup(); return 1; }