#include #include #include #include #include #include #include SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_bwe_shutdown); SWITCH_MODULE_RUNTIME_FUNCTION(mod_bwe_runtime); SWITCH_MODULE_LOAD_FUNCTION(mod_bwe_load); SWITCH_MODULE_DEFINITION(mod_bwe, mod_bwe_load, mod_bwe_shutdown, NULL); typedef enum { NONE, BANDEXT, }FilterType_t; typedef enum { LOCAL_PHONE, REMOTE_PHONE }DTMF_Control_Type_t; static switch_xml_config_enum_item_t config_DTMF_Control_Type_enum[] = { {"local_phone", LOCAL_PHONE}, {"remote_phone", REMOTE_PHONE}, {NULL, 0} }; typedef struct { // Freeswitch switch_core_session_t *local_session; switch_core_session_t *partner_session; DTMF_Control_Type_t dtmf_control; char remoteSessionFound; // 0 => try to find // -1 => do nothing // 1 => partner found FilterType_t filter; switch_frame_t *lastframe; // BWE struct bwext_data *bwext; float lowpassstate[1000]; } bwe_helper; typedef struct{ DTMF_Control_Type_t dtmf_control; }globals_t; static globals_t xml_globals; static switch_xml_config_item_t instructions[] = { SWITCH_CONFIG_ITEM("dtmf_control", SWITCH_CONFIG_ENUM, CONFIG_RELOADABLE, &xml_globals.dtmf_control, (void *) REMOTE_PHONE, &config_DTMF_Control_Type_enum, "local_phone|remote_phone", "dtmf control, 0 means dtmf_recv (local phone control), 1 means dtmf_send (remote phone control)"), SWITCH_CONFIG_ITEM_END() }; static switch_status_t do_config(switch_bool_t reload) { if (switch_xml_config_parse_module_settings("bwe.conf", reload, instructions) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Could not open bwe.conf\n"); return SWITCH_STATUS_FALSE; } //print current config parameters in file "bwe.conf.xml" if (xml_globals.dtmf_control == 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Current config param: DTMF Control : LOCAL_PHONE\n");} else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Current config param: DTMF Control : REMOTE_PHONE\n");} return SWITCH_STATUS_SUCCESS; } void bwehelper_init(bwe_helper *helper, switch_core_session_t *session, char remoteSessionFound, struct bwext_data *bwext, globals_t *xml_config) { /* set the parameters*/ helper->local_session = session; helper->dtmf_control = xml_config->dtmf_control; helper->remoteSessionFound = remoteSessionFound; helper->filter = NONE; helper->lastframe = NULL; } static switch_status_t on_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf, switch_dtmf_direction_t direction) { switch_status_t status; switch_media_bug_t *bug; switch_channel_t *channel = switch_core_session_get_channel(session); switch_channel_t *partner_channel = NULL; switch_core_session_t *partner_session = NULL; switch_codec_t *local_read_codec = NULL; switch_codec_t *partner_read_codec = NULL; switch_caller_profile_t *caller_profile = switch_channel_get_caller_profile(channel); const char *name, *number; int local_samplerate; int partner_samplerate; // retrieve local and partner codec details local_read_codec = switch_core_session_get_read_codec(session); status = switch_core_session_get_partner(session, &partner_session); if (status == SWITCH_STATUS_SUCCESS) { partner_channel = switch_core_session_get_channel(partner_session); partner_read_codec = switch_core_session_get_read_codec(partner_session); } //local_read_codec->implementation->actual_samples_per_second local_samplerate = local_read_codec->implementation->actual_samples_per_second; partner_samplerate = partner_read_codec->implementation->actual_samples_per_second; //to prepare the caller and callee name if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND && !switch_channel_test_flag(channel, CF_DIALPLAN)) { name = caller_profile->callee_id_name; number = caller_profile->callee_id_number; } else { name = caller_profile->caller_id_name; number = caller_profile->caller_id_number; } if ((bug = (switch_media_bug_t *) switch_channel_get_private(channel, "_bwe_"))) { bwe_helper *bweh = (bwe_helper *) switch_core_media_bug_get_user_data(bug); switch (dtmf->digit) { case '*': break; case '1': break; case '2': break; case '3': break; case '4': break; case '5': break; case '6': break; case '7': bweh->filter = NONE; break; case '8': break; case '9': bweh->filter = BANDEXT; break; case '0': break; } } return SWITCH_STATUS_SUCCESS; } static switch_bool_t bwe_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type) { switch_status_t status = SWITCH_STATUS_SUCCESS; switch_core_session_t *partner = NULL; bwe_helper *bweh = (bwe_helper *) user_data; bwe_helper *nbweh = NULL; switch_media_bug_t *bug_remote; switch_channel_t *channel_partner; switch_channel_t *channel_local; switch_codec_t *read_codec = NULL; switch_codec_t *write_codec = NULL; int remote_samplerate; if (bweh->remoteSessionFound == 0) { status = switch_core_session_get_partner(bweh->local_session, &partner); if (status == SWITCH_STATUS_SUCCESS) { read_codec = switch_core_session_get_read_codec(partner); } } channel_local = switch_core_session_get_channel(bweh->local_session); assert(channel_local != NULL); if ((bweh->remoteSessionFound == 0) && (status == SWITCH_STATUS_SUCCESS) && read_codec != NULL) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(bweh->local_session), SWITCH_LOG_INFO, "Partner session located\n"); bweh->remoteSessionFound = 1; channel_partner = switch_core_session_get_channel(partner); assert(channel_partner != NULL); nbweh = switch_core_session_alloc(partner, sizeof(bwe_helper)); assert(nbweh != NULL); bwehelper_init(nbweh, partner, -1, NULL, &xml_globals); nbweh->partner_session = bweh->local_session; bweh->partner_session = partner; if ((status = switch_core_media_bug_add(nbweh->local_session, "bwe_write", NULL, bwe_callback, nbweh, 0, SMBF_WRITE_REPLACE, &bug_remote)) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(nbweh->local_session), SWITCH_LOG_ERROR, "Installing remote BWE write failed!\n"); } else { write_codec = switch_core_session_get_write_codec(partner); remote_samplerate = write_codec->implementation->actual_samples_per_second; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "��Write Peplace�� Frame Actual Samplerate: %i Hz of remote session.\n", remote_samplerate); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(nbweh->local_session), SWITCH_LOG_INFO, "Partner BWE_W installed!\n"); } // add dtmf hook to local phone or remote phone, depends on dtmf_control setting in xml config file "bwe.conf.xml" under FREESWITCH BASE/conf/autoload_configs/ directory if (nbweh->dtmf_control == REMOTE_PHONE) switch_core_event_hook_add_send_dtmf(nbweh->local_session, on_dtmf); else switch_core_event_hook_add_recv_dtmf(nbweh->local_session, on_dtmf); switch_channel_set_private(channel_partner, "_bwe_", bug_remote); } switch (type) { case SWITCH_ABC_TYPE_INIT: { if (bweh->dtmf_control == REMOTE_PHONE) switch_core_event_hook_add_send_dtmf(bweh->local_session, on_dtmf); else switch_core_event_hook_add_recv_dtmf(bweh->local_session, on_dtmf); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(bweh->local_session), SWITCH_LOG_INFO, "%s: DTMF Hook installed!\n", switch_channel_get_uuid(channel_local)); } break; case SWITCH_ABC_TYPE_CLOSE: { switch_channel_set_private(channel_local, "_bwe_", NULL); if (bweh->dtmf_control == REMOTE_PHONE) switch_core_event_hook_remove_send_dtmf(bweh->local_session, on_dtmf); else switch_core_event_hook_remove_recv_dtmf(bweh->local_session, on_dtmf); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(bweh->local_session), SWITCH_LOG_INFO, "%s: Remove local variable store!\n", switch_channel_get_uuid(channel_local)); if (bweh->local_session != NULL) switch_core_session_rwunlock(bweh->local_session); } break; case SWITCH_ABC_TYPE_READ: case SWITCH_ABC_TYPE_WRITE: break; case SWITCH_ABC_TYPE_READ_REPLACE: { } case SWITCH_ABC_TYPE_WRITE_REPLACE: //change the audio stream from Freeswitch to phone { // do some magic stuff ;-) } default: break; } return SWITCH_TRUE; } SWITCH_STANDARD_APP(bwe_run_function) { switch_media_bug_t *bug; switch_status_t status; switch_channel_t *channel = switch_core_session_get_channel(session); bwe_helper *bweh; switch_codec_t *write_codec = NULL; int local_samplerate; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "DATA %s.\n", data); do_config(SWITCH_TRUE); if ((bug = (switch_media_bug_t *) switch_channel_get_private(channel, "_bwe_"))) { if (!zstr(data) && !strcasecmp(data, "stop")) { switch_channel_set_private(channel, "_bwe_", NULL); switch_core_media_bug_remove(session, &bug); } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Cannot run 2 at once on the same channel!\n"); } return; } bweh = switch_core_session_alloc(session, sizeof(bwe_helper)); assert(bweh != NULL); //initial bwe helper parameters bwehelper_init(bweh, session, 0, NULL, &xml_globals); if ((status = switch_core_media_bug_add(session, "bwe_write", NULL, bwe_callback, bweh, 0, SMBF_WRITE_REPLACE, &bug)) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Installing local BWE write failed!\n"); } else { write_codec = switch_core_session_get_write_codec(session); local_samplerate = write_codec->implementation->actual_samples_per_second; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "��Write Replace�� Frame Actual Samplerate: %i Hz of local session.\n", local_samplerate); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(bweh->local_session), SWITCH_LOG_INFO, "Local BWE_W installed!\n"); } switch_channel_set_private(channel, "_bwe_", bug); } SWITCH_MODULE_LOAD_FUNCTION(mod_bwe_load) { switch_application_interface_t *app_interface; *module_interface = switch_loadable_module_create_module_interface(pool, modname); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "BWE Starting (Version: 0.8)\n"); do_config(SWITCH_FALSE); SWITCH_ADD_APP(app_interface, "bwe", "Fancy Signal Processing (V. 0.8) Prototype", "Signal Processing...", bwe_run_function, "", SAF_NONE); return SWITCH_STATUS_SUCCESS; } SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_bwe_shutdown) { switch_xml_config_cleanup(instructions); return SWITCH_STATUS_SUCCESS; }