From 5138f4d5a71b6f5937941049663874ca98e020bf Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 28 May 2014 07:31:24 +0500 Subject: [PATCH] add new stub module mod_rtc dummy signaling-free media engine endpoint --- build/modules.conf.in | 1 + configure.ac | 1 + src/mod/endpoints/mod_rtc/Makefile.am | 8 + src/mod/endpoints/mod_rtc/mod_rtc.c | 463 ++++++++++++++++++++++++++ 4 files changed, 473 insertions(+) create mode 100644 src/mod/endpoints/mod_rtc/Makefile.am create mode 100644 src/mod/endpoints/mod_rtc/mod_rtc.c diff --git a/build/modules.conf.in b/build/modules.conf.in index 348e3521aa..34e16be048 100644 --- a/build/modules.conf.in +++ b/build/modules.conf.in @@ -82,6 +82,7 @@ dialplans/mod_dialplan_xml #endpoints/mod_gsmopen #endpoints/mod_h323 #endpoints/mod_khomp +endpoints/mod_rtc endpoints/mod_loopback #endpoints/mod_opal #endpoints/mod_portaudio diff --git a/configure.ac b/configure.ac index 02fb30629a..4da80f2105 100644 --- a/configure.ac +++ b/configure.ac @@ -1499,6 +1499,7 @@ AC_CONFIG_FILES([Makefile src/mod/endpoints/mod_skypopen/Makefile src/mod/endpoints/mod_sofia/Makefile src/mod/endpoints/mod_unicall/Makefile + src/mod/endpoints/mod_rtc/Makefile src/mod/event_handlers/mod_cdr_csv/Makefile src/mod/event_handlers/mod_cdr_mongodb/Makefile src/mod/event_handlers/mod_cdr_pg_csv/Makefile diff --git a/src/mod/endpoints/mod_rtc/Makefile.am b/src/mod/endpoints/mod_rtc/Makefile.am new file mode 100644 index 0000000000..bc09a9c357 --- /dev/null +++ b/src/mod/endpoints/mod_rtc/Makefile.am @@ -0,0 +1,8 @@ +include $(top_srcdir)/build/modmake.rulesam +MODNAME=mod_rtc + +mod_LTLIBRARIES = mod_rtc.la +mod_rtc_la_SOURCES = mod_rtc.c +mod_rtc_la_CFLAGS = $(AM_CFLAGS) +mod_rtc_la_LIBADD = $(switch_builddir)/libfreeswitch.la +mod_rtc_la_LDFLAGS = -avoid-version -module -no-undefined -shared diff --git a/src/mod/endpoints/mod_rtc/mod_rtc.c b/src/mod/endpoints/mod_rtc/mod_rtc.c new file mode 100644 index 0000000000..06b2815052 --- /dev/null +++ b/src/mod/endpoints/mod_rtc/mod_rtc.c @@ -0,0 +1,463 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005-2014, Anthony Minessale II + * + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * + * The Initial Developer of the Original Code is + * Anthony Minessale II + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Anthony Minessale II + * + * + * mod_rtc.c -- RTC Endpoint + * + */ + +/* Best viewed in a 160 x 60 VT100 Terminal or so the line below at least fits across your screen*/ +/*************************************************************************************************************************************************************/ +#include + +SWITCH_MODULE_LOAD_FUNCTION(mod_rtc_load); +SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_rtc_shutdown); +SWITCH_MODULE_DEFINITION(mod_rtc, mod_rtc_load, mod_rtc_shutdown, NULL); + + +switch_endpoint_interface_t *rtc_endpoint_interface; + +#define STRLEN 15 + +static switch_status_t rtc_on_init(switch_core_session_t *session); + +static switch_status_t rtc_on_exchange_media(switch_core_session_t *session); +static switch_status_t rtc_on_soft_execute(switch_core_session_t *session); +static switch_call_cause_t rtc_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 rtc_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id); +static switch_status_t rtc_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id); +static switch_status_t rtc_read_video_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id); +static switch_status_t rtc_write_video_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id); +static switch_status_t rtc_kill_channel(switch_core_session_t *session, int sig); + +typedef struct { + switch_channel_t *channel; + switch_core_session_t *session; + switch_caller_profile_t *caller_profile; + switch_media_handle_t *media_handle; + switch_core_media_params_t mparams; +} private_object_t; + +static struct { + switch_memory_pool_t *pool; + switch_mutex_t *mutex; + int running; +} mod_rtc_globals; + + +/* BODY OF THE MODULE */ +/*************************************************************************************************************************************************************/ + +/* + 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 rtc_on_init(switch_core_session_t *session) +{ + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t rtc_on_routing(switch_core_session_t *session) +{ + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s RTC ROUTING\n", + switch_channel_get_name(switch_core_session_get_channel(session))); + + return SWITCH_STATUS_SUCCESS; +} + + +static switch_status_t rtc_on_reset(switch_core_session_t *session) +{ + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s RTC RESET\n", + switch_channel_get_name(switch_core_session_get_channel(session))); + + + return SWITCH_STATUS_SUCCESS; +} + + +static switch_status_t rtc_on_hibernate(switch_core_session_t *session) +{ + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s RTC HIBERNATE\n", + switch_channel_get_name(switch_core_session_get_channel(session))); + + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t rtc_on_execute(switch_core_session_t *session) +{ + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s RTC EXECUTE\n", + switch_channel_get_name(switch_core_session_get_channel(session))); + + return SWITCH_STATUS_SUCCESS; +} + + +switch_status_t rtc_on_destroy(switch_core_session_t *session) +{ + switch_channel_t *channel = switch_core_session_get_channel(session); + + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s RTC DESTROY\n", switch_channel_get_name(channel)); + switch_media_handle_destroy(session); + + return SWITCH_STATUS_SUCCESS; + +} + +switch_status_t rtc_on_hangup(switch_core_session_t *session) +{ + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t rtc_on_exchange_media(switch_core_session_t *session) +{ + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "RTC EXCHANGE_MEDIA\n"); + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t rtc_on_soft_execute(switch_core_session_t *session) +{ + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "RTC SOFT_EXECUTE\n"); + return SWITCH_STATUS_SUCCESS; +} + + +static switch_status_t rtc_read_video_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id) +{ + return switch_core_media_read_frame(session, frame, flags, stream_id, SWITCH_MEDIA_TYPE_VIDEO); +} + +static switch_status_t rtc_write_video_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id) +{ + private_object_t *tech_pvt = (private_object_t *) switch_core_session_get_private(session); + switch_assert(tech_pvt != NULL); + + + if (SWITCH_STATUS_SUCCESS == switch_core_media_write_frame(session, frame, flags, stream_id, SWITCH_MEDIA_TYPE_VIDEO)) { + return SWITCH_STATUS_SUCCESS; + } + + return SWITCH_STATUS_FALSE; +} + +static switch_status_t rtc_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id) +{ + switch_status_t status = SWITCH_STATUS_FALSE; + + status = switch_core_media_read_frame(session, frame, flags, stream_id, SWITCH_MEDIA_TYPE_AUDIO); + + return status; +} + +static switch_status_t rtc_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id) +{ + switch_status_t status = SWITCH_STATUS_SUCCESS; + + status = switch_core_media_write_frame(session, frame, flags, stream_id, SWITCH_MEDIA_TYPE_AUDIO); + + return status; +} + +static switch_status_t rtc_kill_channel(switch_core_session_t *session, int sig) +{ + private_object_t *tech_pvt = switch_core_session_get_private(session); + + if (!tech_pvt) { + return SWITCH_STATUS_FALSE; + } + + switch (sig) { + case SWITCH_SIG_BREAK: + if (switch_core_media_ready(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO)) { + switch_core_media_break(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO); + } + if (switch_core_media_ready(tech_pvt->session, SWITCH_MEDIA_TYPE_VIDEO)) { + switch_core_media_break(tech_pvt->session, SWITCH_MEDIA_TYPE_VIDEO); + } + break; + case SWITCH_SIG_KILL: + default: + + if (switch_core_media_ready(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO)) { + switch_core_media_kill_socket(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO); + } + if (switch_core_media_ready(tech_pvt->session, SWITCH_MEDIA_TYPE_VIDEO)) { + switch_core_media_kill_socket(tech_pvt->session, SWITCH_MEDIA_TYPE_VIDEO); + } + break; + } + return SWITCH_STATUS_SUCCESS; +} + + +static switch_status_t rtc_send_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf) +{ + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t rtc_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg) +{ + switch_channel_t *channel = switch_core_session_get_channel(session); + private_object_t *tech_pvt = switch_core_session_get_private(session); + switch_status_t status = SWITCH_STATUS_SUCCESS; + const char *var; + + if (switch_channel_down(channel) || !tech_pvt) { + status = SWITCH_STATUS_FALSE; + return SWITCH_STATUS_FALSE; + } + + /* ones that do not need to lock rtp mutex */ + switch (msg->message_id) { + + case SWITCH_MESSAGE_INDICATE_CLEAR_PROGRESS: + break; + case SWITCH_MESSAGE_INDICATE_ANSWER: + case SWITCH_MESSAGE_INDICATE_PROGRESS: + { + + if (((var = switch_channel_get_variable(channel, "rtp_secure_media"))) && + (switch_true(var) || switch_core_media_crypto_str2type(var) != CRYPTO_INVALID)) { + switch_channel_set_flag(tech_pvt->channel, CF_SECURE); + } + } + break; + + default: + break; + } + + + return status; + +} + +static switch_status_t rtc_receive_event(switch_core_session_t *session, switch_event_t *event) +{ + return SWITCH_STATUS_SUCCESS; +} + +switch_io_routines_t rtc_io_routines = { + /*.outgoing_channel */ rtc_outgoing_channel, + /*.read_frame */ rtc_read_frame, + /*.write_frame */ rtc_write_frame, + /*.kill_channel */ rtc_kill_channel, + /*.send_dtmf */ rtc_send_dtmf, + /*.receive_message */ rtc_receive_message, + /*.receive_event */ rtc_receive_event, + /*.state_change */ NULL, + /*.read_video_frame */ rtc_read_video_frame, + /*.write_video_frame */ rtc_write_video_frame, + /*.state_run*/ NULL, + /*.get_jb*/ NULL +}; + +switch_state_handler_table_t rtc_event_handlers = { + /*.on_init */ rtc_on_init, + /*.on_routing */ rtc_on_routing, + /*.on_execute */ rtc_on_execute, + /*.on_hangup */ rtc_on_hangup, + /*.on_exchange_media */ rtc_on_exchange_media, + /*.on_soft_execute */ rtc_on_soft_execute, + /*.on_consume_media */ NULL, + /*.on_hibernate */ rtc_on_hibernate, + /*.on_reset */ rtc_on_reset, + /*.on_park */ NULL, + /*.on_reporting */ NULL, + /*.on_destroy */ rtc_on_destroy +}; + + +void rtc_set_name(private_object_t *tech_pvt, const char *channame) +{ + char name[256]; + + switch_snprintf(name, sizeof(name), "rtc/%s", channame); + switch_channel_set_name(tech_pvt->channel, name); +} + + + +void rtc_attach_private(switch_core_session_t *session, private_object_t *tech_pvt, const char *channame) +{ + + switch_assert(session != NULL); + switch_assert(tech_pvt != NULL); + + switch_core_session_add_stream(session, NULL); + + tech_pvt->session = session; + tech_pvt->channel = switch_core_session_get_channel(session); + switch_core_media_check_dtmf_type(session); + switch_channel_set_cap(tech_pvt->channel, CC_JITTERBUFFER); + switch_channel_set_cap(tech_pvt->channel, CC_FS_RTP); + switch_media_handle_create(&tech_pvt->media_handle, session, &tech_pvt->mparams); + switch_core_session_set_private(session, tech_pvt); + + if (channame) { + rtc_set_name(tech_pvt, channame); + } +} + + +private_object_t *rtc_new_pvt(switch_core_session_t *session) +{ + private_object_t *tech_pvt = (private_object_t *) switch_core_session_alloc(session, sizeof(private_object_t)); + return tech_pvt; +} + +static switch_call_cause_t rtc_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) +{ + switch_call_cause_t cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; + switch_core_session_t *nsession = NULL; + switch_caller_profile_t *caller_profile = NULL; + private_object_t *tech_pvt = NULL; + switch_channel_t *nchannel; + const char *hval = NULL; + + *new_session = NULL; + + + if (!(nsession = switch_core_session_request_uuid(rtc_endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, + flags, pool, switch_event_get_header(var_event, "origination_uuid")))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error Creating Session\n"); + goto error; + } + + tech_pvt = rtc_new_pvt(nsession); + + nchannel = switch_core_session_get_channel(nsession); + + if (outbound_profile) { + caller_profile = switch_caller_profile_clone(nsession, outbound_profile); + switch_channel_set_caller_profile(nchannel, caller_profile); + } + + if ((hval = switch_event_get_header(var_event, "media_webrtc")) && switch_true(hval)) { + switch_channel_set_variable(nchannel, "rtc_secure_media", SWITCH_RTP_CRYPTO_KEY_80); + } + + if ((hval = switch_event_get_header(var_event, "rtc_secure_media"))) { + switch_channel_set_variable(nchannel, "rtc_secure_media", hval); + } + + rtc_attach_private(nsession, tech_pvt, NULL); + + + if (switch_channel_get_state(nchannel) == CS_NEW) { + switch_channel_set_state(nchannel, CS_INIT); + } + + tech_pvt->caller_profile = caller_profile; + *new_session = nsession; + cause = SWITCH_CAUSE_SUCCESS; + + + if (session) { + switch_ivr_transfer_variable(session, nsession, "rtc_video_fmtp"); + } + + goto done; + + error: + + if (nsession) { + switch_core_session_destroy(&nsession); + } + + if (pool) { + *pool = NULL; + } + + done: + + return cause; +} + +static int rtc_recover_callback(switch_core_session_t *session) +{ + private_object_t *tech_pvt = rtc_new_pvt(session); + rtc_attach_private(session, tech_pvt, NULL); + + return 1; +} + +SWITCH_MODULE_LOAD_FUNCTION(mod_rtc_load) +{ + memset(&mod_rtc_globals, 0, sizeof(mod_rtc_globals)); + mod_rtc_globals.pool = pool; + switch_mutex_init(&mod_rtc_globals.mutex, SWITCH_MUTEX_NESTED, mod_rtc_globals.pool); + + switch_mutex_lock(mod_rtc_globals.mutex); + mod_rtc_globals.running = 1; + switch_mutex_unlock(mod_rtc_globals.mutex); + + /* connect my internal structure to the blank pointer passed to me */ + *module_interface = switch_loadable_module_create_module_interface(pool, modname); + + rtc_endpoint_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_ENDPOINT_INTERFACE); + rtc_endpoint_interface->interface_name = "rtc"; + rtc_endpoint_interface->io_routines = &rtc_io_routines; + rtc_endpoint_interface->state_handler = &rtc_event_handlers; + rtc_endpoint_interface->recover_callback = rtc_recover_callback; + + /* indicate that the module should continue to be loaded */ + return SWITCH_STATUS_SUCCESS; +} + +SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_rtc_shutdown) +{ + switch_mutex_lock(mod_rtc_globals.mutex); + if (mod_rtc_globals.running == 1) { + mod_rtc_globals.running = 0; + } + switch_mutex_unlock(mod_rtc_globals.mutex); + + return SWITCH_STATUS_SUCCESS; +} + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: + */ +