diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 38237e54fa..d8255f13f3 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -365,6 +365,7 @@ typedef enum { SWITCH_MESSAGE_INDICATE_UNHOLD - indicate unhold SWITCH_MESSAGE_INDICATE_REDIRECT - indicate redirect SWITCH_MESSAGE_INDICATE_REJECT - indicate reject + SWITCH_MESSAGE_INDICATE_BROADCAST - indicate media broadcast */ typedef enum { @@ -381,7 +382,8 @@ typedef enum { SWITCH_MESSAGE_INDICATE_HOLD, SWITCH_MESSAGE_INDICATE_UNHOLD, SWITCH_MESSAGE_INDICATE_REDIRECT, - SWITCH_MESSAGE_INDICATE_REJECT + SWITCH_MESSAGE_INDICATE_REJECT, + SWITCH_MESSAGE_INDICATE_BROADCAST } switch_core_session_message_types_t; diff --git a/src/mod/applications/mod_esf/Makefile b/src/mod/applications/mod_esf/Makefile new file mode 100644 index 0000000000..c6d645e6aa --- /dev/null +++ b/src/mod/applications/mod_esf/Makefile @@ -0,0 +1,2 @@ +BASE=../../../.. +include /usr/src/freeswitch.trunk/build/modmake.rules diff --git a/src/mod/applications/mod_esf/mod_esf.c b/src/mod/applications/mod_esf/mod_esf.c new file mode 100644 index 0000000000..11c8747135 --- /dev/null +++ b/src/mod/applications/mod_esf/mod_esf.c @@ -0,0 +1,269 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005/2006, 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_esf.c -- Extra SIP Functionality + * + */ +#include + +static const char modname[] = "mod_esf"; + +struct ls_control_packet { + uint32_t unique_id; + uint32_t command; + uint32_t ip; + uint32_t port; +}; +typedef struct ls_control_packet ls_control_packet_t; + +typedef enum { + LS_START_BCAST = 6, + LS_STOP_BCAST = 7 +} ls_command_t; + +typedef enum { + SEND_TYPE_UNKNOWN = 0, + SEND_TYPE_RTP = 1, + SEND_TYPE_RAW = 2, + SEND_TYPE_NOMEDIA = 3 +} ls_how_t; + +static void bcast_function(switch_core_session_t *session, char *data) +{ + switch_channel_t *channel; + switch_socket_t *socket; + switch_sockaddr_t *audio_addr, *control_packet_addr; + switch_frame_t *read_frame; + switch_status_t status; + switch_size_t bytes; + ls_control_packet_t control_packet; + switch_codec_t *read_codec; + uint32_t flags = 0; + const char *err; + switch_rtp_t *rtp_session; + uint32_t rtp_port; + char guess_ip[25]; + ls_how_t ready = SEND_TYPE_UNKNOWN; + int argc; + char *mydata, *argv[5]; + char *mcast_ip = "224.168.168.168"; + uint32_t mcast_port = 34567; + uint32_t mcast_control_port = 6061; + char *mcast_port_str = "34567"; + + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + + if (!switch_strlen_zero((char *) data)) { + mydata = switch_core_session_strdup(session, data); + assert(mydata != NULL); + + argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); + + if (!switch_strlen_zero(argv[0])) { + mcast_ip = argv[0]; + } + + if (!switch_strlen_zero(argv[1])) { + mcast_port_str = argv[1]; + mcast_port = atoi(mcast_port_str); + } + + if (!switch_strlen_zero(argv[2])) { + mcast_control_port = atoi(argv[2]); + } + } + + + if (switch_true(switch_channel_get_variable(channel, "no_media"))) { + switch_core_session_message_t msg = { 0 }; + + ready = SEND_TYPE_NOMEDIA; + + switch_channel_set_variable(channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, mcast_ip); + switch_channel_set_variable(channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, mcast_port_str); + + /* special answer with the mcast addr */ + msg.from = __FILE__; + msg.string_arg = data; + msg.message_id = SWITCH_MESSAGE_INDICATE_BROADCAST; + switch_core_session_receive_message(session, &msg); + } else { + switch_channel_answer(channel); + } + + read_codec = switch_core_session_get_read_codec(session); + + if (switch_socket_create(&socket, AF_INET, SOCK_DGRAM, 0, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Socket Error 1\n"); + goto fail; + } + + if (switch_sockaddr_info_get(&control_packet_addr, mcast_ip, SWITCH_UNSPEC, + mcast_control_port, 0, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Socket Error 3\n"); + goto fail; + } + + + while(!ready) { + status = switch_core_session_read_frame(session, &read_frame, -1, 0); + if (switch_test_flag(read_frame, SFF_CNG)) { + continue; + } + + if (!SWITCH_READ_ACCEPTABLE(status)) { + goto fail; + } + + if (read_frame->packet && read_frame->packetlen) { + ready = SEND_TYPE_RAW; + } else { + ready = SEND_TYPE_RTP; + } + + } + + if (ready == SEND_TYPE_RTP) { + rtp_port = switch_rtp_request_port(); + switch_find_local_ip(guess_ip, sizeof(guess_ip), AF_INET); + rtp_session = switch_rtp_new(guess_ip, + rtp_port, + mcast_ip, + mcast_port, + read_codec->implementation->ianacode, + read_codec->implementation->samples_per_frame, + read_codec->implementation->microseconds_per_frame, + (switch_rtp_flag_t) flags, + NULL, "soft", &err, switch_core_session_get_pool(session)); + + if (!switch_rtp_ready(rtp_session)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "RTP Error\n"); + goto fail; + } + } else if (ready == SEND_TYPE_NOMEDIA) { + switch_yield(10000); + } else if (ready == SEND_TYPE_RAW) { + if (switch_sockaddr_info_get(&audio_addr, mcast_ip, SWITCH_UNSPEC, mcast_port, 0, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Socket Error 2\n"); + goto fail; + } + } + + control_packet.unique_id = htonl(time(NULL)); + control_packet.command = htonl(LS_START_BCAST); + control_packet.ip = inet_addr(mcast_ip); + control_packet.port = htonl(mcast_port); + + bytes = 16; + switch_socket_sendto(socket, control_packet_addr, 0, (void *)&control_packet, &bytes); + bytes = 16; + switch_socket_sendto(socket, control_packet_addr, 0, (void *)&control_packet, &bytes); + + + for(;;) { + status = switch_core_session_read_frame(session, &read_frame, -1, 0); + if (!SWITCH_READ_ACCEPTABLE(status)) { + break; + } + if (switch_test_flag(read_frame, SFF_CNG)) { + continue; + } + if (ready == SEND_TYPE_RTP) { + switch_rtp_write_frame(rtp_session, read_frame, 0); + } else { + bytes = read_frame->packetlen; + switch_socket_sendto(socket, audio_addr, 0, read_frame->packet, &bytes); + } + } + + + + control_packet.unique_id = htonl(time(NULL)); + control_packet.command = htonl(LS_STOP_BCAST); + bytes = 8; + switch_socket_sendto(socket, control_packet_addr, 0, (void *)&control_packet, &bytes); + bytes = 8; + switch_socket_sendto(socket, control_packet_addr, 0, (void *)&control_packet, &bytes); + + fail: + + if (ready == SEND_TYPE_RTP && switch_rtp_ready(rtp_session)) { + switch_rtp_destroy(&rtp_session); + } + + if (socket) { + switch_socket_close(socket); + } + + return; +} + + +static const switch_application_interface_t bcast_application_interface = { + /*.interface_name */ "esf_ls_page_group", + /*.application_function */ bcast_function, + NULL, NULL, NULL, + /* flags */ SAF_NONE, + /*.next */ NULL +}; + +static const switch_loadable_module_interface_t mod_ivrtest_module_interface = { + /*.module_name = */ modname, + /*.endpoint_interface = */ NULL, + /*.timer_interface = */ NULL, + /*.dialplan_interface = */ NULL, + /*.codec_interface = */ NULL, + /*.application_interface */ &bcast_application_interface +}; + +SWITCH_MOD_DECLARE(switch_status_t) switch_module_load(const switch_loadable_module_interface_t **module_interface, char *filename) +{ + + /* connect my internal structure to the blank pointer passed to me */ + *module_interface = &mod_ivrtest_module_interface; + + /* indicate that the module should continue to be loaded */ + return SWITCH_STATUS_SUCCESS; +} + + +//switch_status_t switch_module_runtime(void) + +/* 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 expandtab: + */ diff --git a/src/mod/applications/mod_esf/mod_esf.vcproj b/src/mod/applications/mod_esf/mod_esf.vcproj new file mode 100644 index 0000000000..c95ae93f98 --- /dev/null +++ b/src/mod/applications/mod_esf/mod_esf.vcproj @@ -0,0 +1,210 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 24dc2c4e89..991dd69926 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -674,7 +674,20 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi switch (msg->message_id) { - case SWITCH_MESSAGE_INDICATE_NOMEDIA:{ + case SWITCH_MESSAGE_INDICATE_BROADCAST: { + char *ip = NULL, *port = NULL; + ip = switch_channel_get_variable(channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE); + port = switch_channel_get_variable(channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE); + if (ip && port) { + sofia_glue_set_local_sdp(tech_pvt, ip, atoi(port), NULL, 1); + } + nua_respond(tech_pvt->nh, SIP_200_OK, + SIPTAG_CONTACT_STR(tech_pvt->profile->url), + SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str), SOATAG_AUDIO_AUX("cn telephone-event"), NUTAG_INCLUDE_EXTRA_SDP(1), TAG_END()); + switch_channel_mark_answered(channel); + } + break; + case SWITCH_MESSAGE_INDICATE_NOMEDIA: { char *uuid; switch_core_session_t *other_session; switch_channel_t *other_channel; @@ -696,7 +709,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi sofia_glue_tech_absorb_sdp(tech_pvt); } sofia_glue_do_invite(session); - } + } break; case SWITCH_MESSAGE_INDICATE_MEDIA:{ switch_clear_flag_locked(tech_pvt, TFLAG_NOMEDIA);