[Freeswitch-svn] [commit] r11153 - in freeswitch/branches/ctrix/mod_airpe: . config
FreeSWITCH SVN
ctrix at freeswitch.org
Mon Jan 12 15:24:44 PST 2009
Author: ctrix
Date: Mon Jan 12 17:24:44 2009
New Revision: 11153
Log:
Initial import of airpe...
Not yet fully working, don't expect too much.
Added:
freeswitch/branches/ctrix/mod_airpe/airpe_api.c
freeswitch/branches/ctrix/mod_airpe/airpe_apps.c
freeswitch/branches/ctrix/mod_airpe/airpe_if_common.c
freeswitch/branches/ctrix/mod_airpe/airpe_if_osx.c
freeswitch/branches/ctrix/mod_airpe/airpe_if_win32.c
freeswitch/branches/ctrix/mod_airpe/airpe_if_x11.c
freeswitch/branches/ctrix/mod_airpe/config/
freeswitch/branches/ctrix/mod_airpe/config/airpe.conf.xml
freeswitch/branches/ctrix/mod_airpe/mod_airpe.c
freeswitch/branches/ctrix/mod_airpe/mod_airpe.h
Added: freeswitch/branches/ctrix/mod_airpe/airpe_api.c
==============================================================================
--- (empty file)
+++ freeswitch/branches/ctrix/mod_airpe/airpe_api.c Mon Jan 12 17:24:44 2009
@@ -0,0 +1,262 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct at yahoo.com>
+ *
+ * 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 mod_airpe.
+ *
+ * The Initial Developer of the Original Code is
+ * Massimo Cetra <devel at navynet.it>
+ *
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Thanks to gmaruzz for his work on skypiax (both * and freeswitch).
+ * Some of his code inspired this module
+ *
+ */
+
+#include "mod_airpe.h"
+
+#define AIRPE_MOODTEXT_SYNTAX "airpe_moodtext <clientname> <text>"
+SWITCH_STANDARD_API(airpe_moodtext_command)
+{
+ int argc = 0;
+ char *argv[2] = { 0 };
+ char *mycmd = NULL;
+ char *client = NULL;
+ airpe_interface_t *airpe = NULL;
+
+ if (!switch_strlen_zero(cmd) && (mycmd = strdup(cmd))) {
+ argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+ switch_assert(argv[0]);
+ }
+
+ if ( argc < 1 ) {
+ stream->write_function(stream, "-USAGE: %s\n", AIRPE_MOODTEXT_SYNTAX);
+ goto done;
+ }
+
+ client = argv[0];
+ airpe = airpe_find_interface(client);
+
+ if ( !airpe ) {
+ stream->write_function(stream, "-ERR interface not found for client ");
+ stream->write_function(stream, client);
+ stream->write_function(stream, "\n");
+ goto done;
+ }
+
+ if ( argc == 1 ) {
+ stream->write_function(stream, "+OK: ");
+ if ( airpe->mood_text )
+ stream->write_function(stream, airpe->mood_text);
+ else
+ stream->write_function(stream, "UNKNOWN");
+ stream->write_function(stream, "\n");
+ }
+ else {
+ if ( airpe_set_mood_text(airpe, argv[1]) != SWITCH_STATUS_SUCCESS ) {
+ stream->write_function(stream, "-ERR cannot send message to the client\n");
+ goto done;
+ }
+ else {
+ char buf[SKYPE_MSG_LEN];
+ snprintf(buf, SKYPE_MSG_LEN, "SET PROFILE MOOD_TEXT %s", airpe->mood_text );
+ airpe_cmd_write(airpe, buf);
+ }
+ stream->write_function(stream, "+OK mood_text set.\n");
+ }
+
+ done:
+ return SWITCH_STATUS_SUCCESS;
+}
+
+#define AIRPE_INFO_SYNTAX "airpe_status <clientname>"
+SWITCH_STANDARD_API(airpe_info_command)
+{
+ int argc = 0;
+ char *argv[4] = { 0 };
+ char *mycmd = NULL;
+ char *client = NULL;
+ char buf[512];
+ airpe_interface_t *airpe = NULL;
+
+ if (!switch_strlen_zero(cmd) && (mycmd = strdup(cmd))) {
+ argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+ switch_assert(argv[0]);
+ }
+
+ if ( argc < 1 ) {
+ stream->write_function(stream, "-USAGE: %s\n", AIRPE_INFO_SYNTAX);
+ goto done;
+ }
+
+ client = argv[0];
+ airpe = airpe_find_interface(client);
+
+ if ( !airpe ) {
+ stream->write_function(stream, "-ERR interface not found for client ");
+ stream->write_function(stream, client);
+ stream->write_function(stream, "\n");
+ goto done;
+ }
+
+ switch_snprintf(buf, sizeof(buf), "%-20s: %s\n", "Client name", airpe->name);
+ stream->write_function(stream, buf);
+ switch_snprintf(buf, sizeof(buf), "%-20s: %s\n", "Dialplan", airpe->dialplan);
+ stream->write_function(stream, buf);
+ switch_snprintf(buf, sizeof(buf), "%-20s: %s\n", "Context", airpe->context);
+ stream->write_function(stream, buf);
+ switch_snprintf(buf, sizeof(buf), "%-20s: %s\n", "Destination", airpe->destination);
+ stream->write_function(stream, buf);
+ switch_snprintf(buf, sizeof(buf), "%-20s: %s\n", "Skype username", airpe->skype_user);
+ stream->write_function(stream, buf);
+ if ( airpe->audio_in_port > 0 )
+ switch_snprintf(buf, sizeof(buf), "%-20s: %d\n", "Audio in port", airpe->audio_in_port);
+ else
+ switch_snprintf(buf, sizeof(buf), "%-20s: %s\n", "Audio in port", "NOT SET");
+ stream->write_function(stream, buf);
+ if ( airpe->audio_in_port > 0 )
+ switch_snprintf(buf, sizeof(buf), "%-20s: %d\n", "Audio out port", airpe->audio_out_port);
+ else
+ switch_snprintf(buf, sizeof(buf), "%-20s: %s\n", "Audio out port", "NOT SET");
+ stream->write_function(stream, buf);
+
+ switch_snprintf(buf, sizeof(buf), "%-20s: %s\n", "Connection status", skype_conn_status_string(airpe->conn_status) );
+ stream->write_function(stream, buf);
+ switch_snprintf(buf, sizeof(buf), "%-20s: %s\n", "Client status", skype_user_status_string(airpe->user_status) );
+ stream->write_function(stream, buf);
+
+ switch_snprintf(buf, sizeof(buf), "%-20s: %s\n", "Skype version", (airpe->skype_version) ? airpe->skype_version : "Unknown" );
+ stream->write_function(stream, buf);
+ switch_snprintf(buf, sizeof(buf), "%-20s: %s\n", "Mood text", (airpe->mood_text ) ? airpe->mood_text : "Unknown" );
+ stream->write_function(stream, buf);
+
+ done:
+ return SWITCH_STATUS_SUCCESS;
+}
+
+#define AIRPE_STATUS_SYNTAX "airpe_status <clientname> <status>"
+SWITCH_STANDARD_API(airpe_status_command)
+{
+ int argc = 0;
+ char *argv[4] = { 0 };
+ char *mycmd = NULL;
+ char *client = NULL;
+ char *cstatus= NULL;
+ airpe_interface_t *airpe = NULL;
+
+ if (!switch_strlen_zero(cmd) && (mycmd = strdup(cmd))) {
+ argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+ switch_assert(argv[0]);
+ }
+
+ if ( argc < 1 ) {
+ stream->write_function(stream, "-USAGE: %s\n", AIRPE_STATUS_SYNTAX);
+ goto done;
+ }
+
+ client = argv[0];
+ if ( argc > 1 )
+ cstatus = argv[1];
+
+ airpe = airpe_find_interface(client);
+
+ if ( !airpe ) {
+ stream->write_function(stream, "-ERR interface not found: \n");
+ stream->write_function(stream, client);
+ stream->write_function(stream, "\n");
+ goto done;
+ }
+
+ if ( !cstatus ) {
+ const char *str_status = NULL;
+ str_status = skype_user_status_string( airpe->user_status );
+ stream->write_function(stream, "+OK status is ");
+ if ( str_status )
+ stream->write_function(stream, str_status);
+ else
+ stream->write_function(stream, "... uhmmm, ehmm, DUNNO... ");
+ stream->write_function(stream, "\n");
+ }
+ else {
+ char buf[SKYPE_MSG_LEN];
+ const char *str_status = NULL;
+
+ if ( !strncasecmp(cstatus, "unknown", sizeof("unknown") ) )
+ str_status = skype_user_status_string(USER_STATUS_UNKNOWN);
+ else if ( !strncasecmp(cstatus, "online", sizeof("online") ) )
+ str_status = skype_user_status_string(USER_STATUS_ONLINE);
+ else if ( !strncasecmp(cstatus, "offline", sizeof("offline") ) )
+ str_status = skype_user_status_string(USER_STATUS_OFFLINE);
+ else if ( !strncasecmp(cstatus, "skypeme", sizeof("skypeme") ) )
+ str_status = skype_user_status_string(USER_STATUS_SKYPEME);
+ else if ( !strncasecmp(cstatus, "away", sizeof("away") ) )
+ str_status = skype_user_status_string(USER_STATUS_AWAY);
+ else if ( !strncasecmp(cstatus, "na", sizeof("na") ) )
+ str_status = skype_user_status_string(USER_STATUS_NA);
+ else if ( !strncasecmp(cstatus, "dnd", sizeof("dnd") ) )
+ str_status = skype_user_status_string(USER_STATUS_DND);
+ else if ( !strncasecmp(cstatus, "invisible", sizeof("invisible") ) )
+ str_status = skype_user_status_string(USER_STATUS_INVISIBLE);
+ else if ( !strncasecmp(cstatus, "loggedout", sizeof("loggedout") ) )
+ str_status = skype_user_status_string(USER_STATUS_LOGGEDOUT);
+
+ if ( str_status ) {
+ snprintf(buf, SKYPE_MSG_LEN, "SET USERSTATUS %s", cstatus );
+ if ( airpe_cmd_write(airpe, buf) != SWITCH_STATUS_SUCCESS ) {
+ stream->write_function(stream, "-ERR cannot send message to the client\n");
+ goto done;
+ }
+ stream->write_function(stream, "+OK status set.\n");
+ }
+ else {
+ stream->write_function(stream, "-ERR invalid status string\n");
+ }
+ }
+
+ done:
+ return SWITCH_STATUS_SUCCESS;
+}
+
+
+
+switch_status_t airpe_register_api( switch_loadable_module_interface_t **module_interface ) {
+
+ switch_api_interface_t *api;
+
+ switch_console_set_complete("add airpe_moodtext ");
+ SWITCH_ADD_API(api, "airpe_moodtext", "sets the mood text of an airpe client", airpe_moodtext_command, AIRPE_MOODTEXT_SYNTAX);
+
+ switch_console_set_complete("add airpe_info ");
+ SWITCH_ADD_API(api, "airpe_info", "shows the status of an airpe client", airpe_info_command, AIRPE_INFO_SYNTAX);
+
+ switch_console_set_complete("add airpe_status ");
+ SWITCH_ADD_API(api, "airpe_status", "sets the status of an airpe client", airpe_status_command, AIRPE_STATUS_SYNTAX);
+
+ 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 expandtab:
+ */
Added: freeswitch/branches/ctrix/mod_airpe/airpe_apps.c
==============================================================================
--- (empty file)
+++ freeswitch/branches/ctrix/mod_airpe/airpe_apps.c Mon Jan 12 17:24:44 2009
@@ -0,0 +1,56 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct at yahoo.com>
+ *
+ * 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 mod_airpe.
+ *
+ * The Initial Developer of the Original Code is
+ * Massimo Cetra <devel at navynet.it>
+ *
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Thanks to gmaruzz for his work on skypiax (both * and freeswitch).
+ * Some of his code inspired this module
+ *
+ */
+
+#include "mod_airpe.h"
+
+SWITCH_STANDARD_APP(airpe_app_test)
+{
+}
+
+
+switch_status_t airpe_register_apps( switch_loadable_module_interface_t **module_interface ) {
+ switch_application_interface_t *app_interface;
+
+ SWITCH_ADD_APP(app_interface, "airpe_test", "test text", "test text", airpe_app_test, "", SAF_SUPPORT_NOMEDIA);
+
+ 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 expandtab:
+ */
+
Added: freeswitch/branches/ctrix/mod_airpe/airpe_if_common.c
==============================================================================
--- (empty file)
+++ freeswitch/branches/ctrix/mod_airpe/airpe_if_common.c Mon Jan 12 17:24:44 2009
@@ -0,0 +1,770 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct at yahoo.com>
+ *
+ * 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 mod_airpe.
+ *
+ * The Initial Developer of the Original Code is
+ * Massimo Cetra <devel at navynet.it>
+ *
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Thanks to gmaruzz for his work on skypiax (both * and freeswitch).
+ * Some of his code inspired this module
+ *
+ */
+
+#include "mod_airpe.h"
+
+static struct {
+ USER_STATUS status;
+ const char *name;
+} user_status_names[] = {
+ { USER_STATUS_UNKNOWN, "UNKNOWN" },
+ { USER_STATUS_ONLINE, "ONLINE" },
+ { USER_STATUS_OFFLINE, "OFFLINE" },
+ { USER_STATUS_SKYPEME, "SKYPEME" },
+ { USER_STATUS_AWAY, "AWAY" },
+ { USER_STATUS_NA, "NA" },
+ { USER_STATUS_DND, "DND" },
+ { USER_STATUS_INVISIBLE, "INVISIBLE" },
+ { USER_STATUS_LOGGEDOUT, "LOGGEDOUT" },
+};
+
+static struct {
+ CONN_STATUS status;
+ const char *name;
+} connection_status_names[] = {
+ { CONN_STATUS_UNKNOWN, "UNKNOWN" },
+ { CONN_STATUS_OFFLINE, "OFFLINE" },
+ { CONN_STATUS_CONNECTING, "CONNECTING" },
+ { CONN_STATUS_PAUSING, "PAUSING" },
+ { CONN_STATUS_ONLINE, "ONLINE" },
+};
+
+/* ************************************************************************* */
+
+const char *skype_user_status_string(USER_STATUS st) {
+ int t;
+ const char *ret = NULL;
+
+ for ( t = 0; t < sizeof(user_status_names) / sizeof(user_status_names[0]); t++ ) {
+ if ( user_status_names[t].status == st ) {
+ ret = user_status_names[t].name;
+ break;
+ }
+ }
+ return ret;
+}
+
+USER_STATUS skype_user_status(const char *str) {
+ int t;
+ USER_STATUS ret = USER_STATUS_UNKNOWN;
+
+ for ( t = 0; t < sizeof(user_status_names) / sizeof(user_status_names[0]); t++ ) {
+ if ( !strncasecmp(user_status_names[t].name, str, strlen(user_status_names[t].name) ) ) {
+ ret = user_status_names[t].status;
+ break;
+ }
+ }
+ return ret;
+}
+
+/* ************************************************************************* */
+
+const char *skype_conn_status_string(CONN_STATUS st) {
+ int t;
+ const char *ret = NULL;
+
+ for ( t = 0; t < sizeof(connection_status_names) / sizeof(connection_status_names[0]); t++ ) {
+ if ( connection_status_names[t].status == st ) {
+ ret = connection_status_names[t].name;
+ break;
+ }
+ }
+ return ret;
+}
+
+CONN_STATUS skype_conn_status(const char *str) {
+ int t;
+ CONN_STATUS ret = CONN_STATUS_UNKNOWN;
+
+ for ( t = 0; t < sizeof(connection_status_names) / sizeof(connection_status_names[0]); t++ ) {
+ if ( !strncasecmp(connection_status_names[t].name, str, strlen(connection_status_names[t].name) ) ) {
+ ret = connection_status_names[t].status;
+ break;
+ }
+ }
+ return ret;
+}
+
+/* ************************************************************************* */
+
+switch_status_t airpe_set_version(airpe_interface_t *airpe, char *string) {
+ assert(airpe);
+ switch_safe_free(airpe->skype_version);
+ if ( string )
+ airpe->skype_version = strdup(string);
+ return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t airpe_set_mood_text(airpe_interface_t *airpe, char *string) {
+ assert(airpe);
+ switch_safe_free(airpe->mood_text);
+ if ( string )
+ airpe->mood_text = strdup(string);
+ return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t airpe_set_partner_displayname(airpe_interface_t *airpe, char *string) {
+ assert(airpe);
+ switch_safe_free(airpe->partner_displayname);
+ if ( string )
+ airpe->partner_displayname = strdup(string);
+ return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t airpe_set_partner_handle(airpe_interface_t *airpe, char *string) {
+ assert(airpe);
+ switch_safe_free(airpe->partner_handle);
+ if ( string )
+ airpe->partner_handle = strdup(string);
+ return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t airpe_cmd_write(airpe_interface_t *airpe, char *msg) {
+ if ( airpe->debug )
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "msg to airpe client %s: %s\n", airpe->name, msg);
+ return airpe_skype_send_message(airpe->skype_window, msg);
+}
+
+switch_status_t airpe_originate(airpe_interface_t *airpe, char *dest) {
+ char msg[SKYPE_MSG_LEN];
+
+ /*
+ Those commands are outdated and shouldn't be used
+ Documented so that no one adds them.
+ airpe_cmd_write(p, "SET AGC OFF");
+ airpe_cmd_write(p, "SET AEC OFF");
+ */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "airpe client %s: Originating to %s\n", airpe->name, dest);
+
+ snprintf(msg, sizeof(msg), "CALL %s", dest);
+
+ if ( (airpe_cmd_write(airpe, msg) != SWITCH_STATUS_SUCCESS) ) {
+ return SWITCH_STATUS_FALSE;
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t airpe_explicit_hangup(airpe_interface_t *airpe) {
+ char buf[SKYPE_MSG_LEN];
+
+ if ( airpe->active_call_id > 0 ) {
+ snprintf(buf, sizeof(buf), "SET CALL %d STATUS FINISHED", airpe->active_call_id);
+ return airpe_cmd_write(airpe, buf);
+ }
+ return SWITCH_STATUS_FALSE;
+}
+
+
+
+/*****************************************************************************
+ SKYPE AUDIO
+ *****************************************************************************/
+
+switch_status_t airpe_hangup( private_object_t *pvt ) {
+ airpe_interface_t *airpe;
+
+ assert(pvt);
+ assert(pvt->session);
+ assert(pvt->airpe);
+
+ airpe = pvt->airpe;
+
+ if ( airpe->audio_in_active_socket ) {
+ switch_socket_shutdown(airpe->audio_in_active_socket, SWITCH_SHUTDOWN_READWRITE);
+ switch_socket_close(airpe->audio_in_active_socket);
+ airpe->audio_in_active_socket = 0;
+ }
+
+ if ( airpe->audio_out_active_socket ) {
+ switch_socket_shutdown(airpe->audio_out_active_socket, SWITCH_SHUTDOWN_READWRITE);
+ switch_socket_close(airpe->audio_out_active_socket);
+ airpe->audio_out_active_socket = 0;
+ }
+
+ airpe->tech_pvt = NULL;
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t airpe_audio_write( private_object_t *pvt, switch_frame_t *frame ) {
+ switch_socket_t *inbound_socket = NULL;
+ switch_memory_pool_t *pool;
+ airpe_interface_t *airpe;
+ switch_status_t rv;
+ switch_size_t mlen;
+ char *mbuf;
+
+ assert(pvt);
+ assert(pvt->session);
+ assert(pvt->airpe);
+
+ airpe = pvt->airpe;
+ pool = switch_core_session_get_pool(pvt->session);
+
+ if ( !airpe->audio_in_active_socket ) {
+ rv = switch_socket_accept(&inbound_socket, airpe->audio_in_socket, pool);
+ if ( rv == SWITCH_STATUS_SUCCESS ) {
+ airpe->audio_in_active_socket = inbound_socket;
+ switch_sleep(100000);
+ }
+ else {
+ return SWITCH_STATUS_FALSE;
+ }
+ }
+
+ mbuf = frame->data;
+ mlen = frame->datalen;
+ rv = switch_socket_send(airpe->audio_in_active_socket, mbuf, &mlen);
+
+ return rv;
+}
+
+switch_status_t airpe_audio_read( private_object_t *pvt ) {
+ switch_socket_t *inbound_socket = NULL;
+ switch_memory_pool_t *pool;
+ airpe_interface_t *airpe;
+ switch_status_t rv;
+ switch_size_t mlen;
+ char *ptr;
+
+ assert(pvt);
+ assert(pvt->session);
+ assert(pvt->airpe);
+
+ airpe = pvt->airpe;
+ pool = switch_core_session_get_pool(pvt->session);
+
+ if ( !airpe->audio_out_active_socket ) {
+ rv = switch_socket_accept(&inbound_socket, airpe->audio_out_socket, pool);
+ if ( rv == SWITCH_STATUS_SUCCESS ) {
+ airpe->audio_out_active_socket = inbound_socket;
+ switch_sleep(100000);
+ }
+ else {
+ return SWITCH_STATUS_FALSE;
+ }
+ }
+
+ pvt->read_frame.datalen = 0;
+ ptr = pvt->read_frame.data;
+ mlen = sizeof(pvt->databuf);
+ rv = switch_socket_recv(airpe->audio_out_active_socket, ptr, &mlen);
+
+ if ( (rv==SWITCH_STATUS_SUCCESS) ) {
+ pvt->read_frame.datalen = mlen;
+ }
+// if ( mlen == 0 )
+// return SWITCH_STATUS_SUCCESS;
+
+ return rv;
+}
+
+/*****************************************************************************
+ SKYPE CONTROL MESSAGES
+ *****************************************************************************/
+
+static switch_status_t airpe_manage_incoming_call( airpe_interface_t *airpe, int callid ) {
+ char chan_name[256];
+ switch_channel_t *channel = NULL;
+ switch_core_session_t *new_session = NULL;
+ private_object_t *tech_pvt = NULL;
+
+ new_session = airpe_request_session(NULL);
+ if ( !new_session ) {
+ return SWITCH_STATUS_FALSE;
+ }
+
+ switch_core_session_add_stream(new_session, NULL);
+
+ tech_pvt = (private_object_t *) switch_core_session_alloc(new_session, sizeof(private_object_t));
+ if ( !tech_pvt ) {
+ switch_core_session_destroy(&new_session);
+ return SWITCH_STATUS_FALSE;
+ }
+ memset(tech_pvt, 0, sizeof(private_object_t));
+
+ channel = switch_core_session_get_channel(new_session);
+ assert(channel);
+
+ if ( airpe_tech_init(tech_pvt, new_session) != SWITCH_STATUS_SUCCESS ) {
+ switch_core_session_destroy(&new_session);
+ return SWITCH_STATUS_FALSE;
+ }
+ tech_pvt->airpe = airpe;
+
+ switch_snprintf(chan_name, sizeof(chan_name), MODNAME"/%s", airpe->name);
+ switch_channel_set_name(channel, chan_name);
+
+ tech_pvt->caller_profile = switch_caller_profile_new( switch_core_session_get_pool(new_session),
+ airpe->name, /* Username */
+ airpe->dialplan, /* Diaplan */
+ airpe->partner_displayname, /* cid_name */
+ airpe->partner_handle, /* cid_number */
+ NULL, /* network_addr */
+ NULL, /* ani */
+ NULL, /* aniii */
+ NULL, /* rdnis */
+ MODNAME, /* source */
+ airpe->context, /* context */
+ airpe->destination /* destination_number */
+ );
+
+ if ( !tech_pvt->caller_profile ) {
+ switch_core_session_destroy(&new_session);
+ return SWITCH_STATUS_FALSE;
+ }
+ else
+ switch_channel_set_caller_profile(channel, tech_pvt->caller_profile);
+
+
+ switch_set_flag(tech_pvt, TFLAG_INBOUND);
+ airpe->active_call_id = callid;
+ switch_channel_set_state(channel, CS_INIT);
+
+ if ( switch_core_session_thread_launch(new_session) != SWITCH_STATUS_SUCCESS ) {
+ airpe->active_call_id = 0;
+ switch_core_session_destroy(&new_session);
+ return SWITCH_STATUS_FALSE;
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t airpe_manage_call_status( airpe_interface_t *airpe, int callid, const char *status ) {
+ char buf[SKYPE_MSG_LEN];
+ switch_core_session_t *session = NULL;
+ switch_channel_t *channel = NULL;
+
+ if ( airpe->active_call_id && airpe->active_call_id != callid ) {
+ADEBUG("CASE 1 - different call\n");
+ if ( !strncmp(status, "UNPLACED", strlen("UNPLACED")) ) {
+ snprintf(buf, sizeof(buf), "SET CALL %d STATUS FINISHED", callid);
+ airpe_cmd_write(airpe, buf);
+ }
+ else {
+ ADEBUG("*** (%d/%d) Unmanaged status %s\n", airpe->active_call_id, callid, status);
+ }
+
+ }
+ else if ( airpe->active_call_id && airpe->active_call_id == callid ) {
+ADEBUG("CASE 2 - my call\n");
+ if ( airpe->tech_pvt ) {
+ assert(airpe->tech_pvt);
+ session = airpe->tech_pvt->session;
+ assert(session);
+
+ channel = switch_core_session_get_channel(session);
+ assert(channel);
+ }
+
+ if ( !strncmp(status, "ROUTING", strlen("ROUTING")) ) {
+ }
+ else if ( !strncmp(status, "RINGING", strlen("RINGING")) ) {
+ //if ( switch_test_flag(tech_pvt, TFLAG_OUTBOUND) ) {
+ //switch_channel_set_state(channel, CS_RINGING);
+ switch_core_session_queue_indication(session, SWITCH_MESSAGE_INDICATE_RINGING);
+ switch_channel_mark_ring_ready(channel);
+ //}
+
+ snprintf(buf, sizeof(buf), "ALTER CALL %d SET_INPUT PORT=\"%d\"", callid, airpe->audio_in_port);
+ airpe_cmd_write(airpe, buf);
+ snprintf(buf, sizeof(buf), "ALTER CALL %d SET_OUTPUT PORT=\"%d\"", callid, airpe->audio_out_port);
+ airpe_cmd_write(airpe, buf);
+
+
+
+ switch_channel_set_state(channel, CS_ROUTING);
+
+ }
+ else if ( !strncmp(status, "INPROGRESS", strlen("INPROGRESS")) ) {
+ snprintf(buf, sizeof(buf), "ALTER CALL %d STOP_VIDEO_SEND", callid );
+ airpe_cmd_write(airpe, buf);
+ snprintf(buf, sizeof(buf), "ALTER CALL %d STOP_VIDEO_RECEIVE", callid );
+ airpe_cmd_write(airpe, buf);
+
+ if ( channel ) {
+ switch_channel_mark_answered(channel);
+ }
+ else {
+ if ( airpe_manage_incoming_call(airpe, callid) != SWITCH_STATUS_SUCCESS ) {
+ snprintf(buf, sizeof(buf), "ALTER CALL %d END HANGUP", callid );
+ airpe_cmd_write(airpe, buf);
+ airpe->active_call_id = 0;
+ }
+ }
+ }
+ else if ( !strncmp(status, "FINISHED", strlen("FINISHED")) ) {
+ if ( channel )
+ switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
+ airpe->active_call_id = 0;
+ }
+ else if ( !strncmp(status, "FAILED", strlen("FAILED")) ) {
+ if ( channel )
+ switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+ airpe->active_call_id = 0;
+ }
+ else if ( !strncmp(status, "CANCELLED", strlen("CANCELLED")) ) {
+ if ( channel )
+ switch_channel_hangup(channel, SWITCH_CAUSE_ORIGINATOR_CANCEL);
+ airpe->active_call_id = 0;
+ }
+ else if ( !strncmp(status, "REFUSED", strlen("REFUSED")) ) {
+ if ( channel )
+ switch_channel_hangup(channel, SWITCH_CAUSE_CALL_REJECTED);
+ airpe->active_call_id = 0;
+ }
+ else if ( !strncmp(status, "MISSED", strlen("MISSED")) ) {
+ if ( channel )
+ switch_channel_hangup(channel, SWITCH_CAUSE_NO_ANSWER);
+ airpe->active_call_id = 0;
+ }
+ else if ( !strncmp(status, "UNPLACED", strlen("UNPLACED")) ) {
+ }
+ else {
+ADEBUG("Unmanaged status \n");
+ }
+ }
+ else {
+ADEBUG("CASE 3 - no calls online\n");
+ if ( !strncmp(status, "UNPLACED", strlen("UNPLACED")) ) {
+ airpe->active_call_id = callid;
+ }
+ else if ( !strncmp(status, "RINGING", strlen("RINGING")) ) {
+ airpe->active_call_id = callid;
+ snprintf(buf, sizeof(buf), "ALTER CALL %d ANSWER", callid );
+ airpe_cmd_write(airpe, buf);
+ }
+ else {
+ ADEBUG("--- (%d/%d) Unmanaged status %s\n", airpe->active_call_id, callid, status);
+ }
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t airpe_manage_skype_msg( airpe_interface_t *airpe, const char *msg ) {
+ char *buf = NULL;
+ int argc = 0;
+ char *argv[9] = { 0 };
+
+ assert(airpe);
+ assert(msg);
+
+ if ( airpe->debug )
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "airpe client %s: %s\n", airpe->name, msg);
+
+ buf = strdup(msg);
+ argc = switch_separate_string(buf, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+
+ if ( argc == 0 ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "airpe client %s: %s - Message without arguments? uh?\n", airpe->name, msg);
+ free(buf);
+ return SWITCH_STATUS_FALSE;
+ }
+
+
+
+ if ( !strncmp( buf, "CURRENTUSERHANDLE", strlen("CURRENTUSERHANDLE")) ) {
+ /* The username that the client is using. */
+ // TODO ... if the user handle mismatches, disconnect the channel or simply disable
+ // all operations
+ }
+ else if ( !strncmp( buf, "USERSTATUS", strlen("USERSTATUS")) && argc > 1 ) {
+ /* The status of the user of the client (ex: NA, ONLINE) */
+ airpe->user_status = skype_user_status(argv[1]);
+ }
+ else if ( !strncmp( buf, "PROTOCOL", strlen("PROTOCOL")) && argc > 1 ) {
+ /* The protocol of the client */
+ airpe->protocol = atoi(argv[1]);
+ }
+ else if ( !strncmp( buf, "CLEAR", strlen("CLEAR")) ) {
+ /* something has been cleared in the UI - Ignored */
+ }
+ else if ( !strncmp( buf, "PONG", strlen("PONG")) ) {
+ /* keepalive */
+ airpe_skype_watchdog_reset(airpe->skype_window);
+ }
+ else if ( !strncmp( buf, "CONNSTATUS", strlen("CONNSTATUS")) && argc >= 2 ) {
+ /* The connection status of the client (ex: ONLINE) */
+ airpe->conn_status = skype_conn_status( argv[1] );
+ }
+ else if ( !strncmp( buf, "USER", strlen("USER")) ) {
+ /* Updates about the users of our list - ignored */
+ }
+ else if ( !strncmp( buf, "GROUP", strlen("GROUP")) ) {
+ /* Updates about the groups of our list - ignored */
+ }
+ else if ( !strncmp( buf, "CONTACTS", strlen("CONTACTS")) ) {
+ /* Other messages referring to the contact list - ignored */
+ }
+ else if ( !strncmp( buf, "OK", strlen("OK")) ) {
+ /* Acknowledge - ignored */
+ }
+ else if ( !strncmp( buf, "AUTOAWAY", strlen("AUTOAWAY")) ) {
+ /* Autoaway - ignored */
+ }
+//TODO: RECEIVEDAUTHREQUEST - Add a config option to authorize or forget about it.
+ else if ( !strncmp( buf, "MUTE", strlen("MUTE")) && argc >= 2 ) {
+ if ( !strncmp(argv[1], "ON", 2) ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "airpe client %s: I don't like to be muted...\n", airpe->name);
+ airpe_cmd_write(airpe, "MUTE OFF");
+ }
+ }
+ else if ( !strncmp( buf, "CHATMESSAGE", strlen("CHATMESSAGE")) ) {
+ /* a message has been received (unknown content) - ignored */
+ }
+ else if ( !strncmp( buf, "CHAT", strlen("CHAT")) && argc >=2 ) {
+ /* Chat status - ignored. */
+ if ( airpe->protocol > 6 ) {
+ //TODO : ALTER CHAT <chat_id> DISBAND - Doesn't seems to work on linux
+ char buf[SKYPE_MSG_LEN] = "";
+ snprintf(buf, sizeof(buf), "ALTER CHAT %s DISBAND", argv[1]);
+ airpe_cmd_write(airpe, buf);
+ }
+ }
+ else if ( !strncmp( buf, "CHATMEMBER", strlen("CHATMEMBER")) ) {
+ /* Informations about the chat members - ignored */
+ }
+ else if ( !strncmp( buf, "PROFILE", strlen("PROFILE")) && argc >= 2 ) {
+ if ( !strncmp(argv[1], "MOOD_TEXT", strlen("MOOD_TEXT")) ) {
+ char *tmp = NULL;
+ char *mood;
+ tmp = strdup(msg);
+ if ( tmp ) {
+ mood = strstr(tmp, "PROFILE MOOD_TEXT ");
+ if ( mood ) {
+ mood += strlen("PROFILE MOOD_TEXT ");
+ airpe_set_mood_text(airpe, mood);
+ }
+ switch_safe_free(tmp);
+ }
+ }
+ }
+ else if ( !strncmp( buf, "SKYPEVERSION", strlen("SKYPEVERSION")) ) {
+ airpe_set_version(airpe, argv[1]);
+ }
+ else if ( !strncmp( buf, "CALL", strlen("CALL")) && argc >= 3 ) {
+ char *cmd = argv[2];
+ int callid = atoi(argv[1]);
+
+ if ( !strncmp(cmd, "DURATION", strlen("DURATION")) ) {
+ /* Ignore the duration that is updated every second */
+ if ( callid != airpe->active_call_id ) {
+ char buf[SKYPE_MSG_LEN] = "";
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "airpe client %s: hanging up unknown call id %d\n", airpe->name, callid);
+ snprintf(buf, sizeof(buf), "SET CALL %d STATUS FINISHED", callid);
+ airpe_cmd_write(airpe, buf);
+ }
+ //TODO: maybe we could consider this message as a keepalive signal
+ }
+ else if ( !strncmp(cmd, "STATUS", strlen("STATUS")) && argc >=4 ) {
+ char *callstatus = argv[3];
+ airpe_manage_call_status( airpe, callid, callstatus );
+ }
+ else if ( !strncmp(cmd, "CONF_ID", strlen("CONF_ID")) ) {
+ char buf[SKYPE_MSG_LEN];
+
+ if ( !airpe->active_call_id ) {
+ airpe_set_partner_displayname(airpe, NULL);
+ airpe_set_partner_handle(airpe, NULL);
+
+ snprintf(buf, sizeof(buf), "GET CALL %d PARTNER_DISPNAME", callid);
+ airpe_cmd_write(airpe, buf);
+
+ snprintf(buf, sizeof(buf), "GET CALL %d PARTNER_HANDLE", callid);
+ airpe_cmd_write(airpe, buf);
+
+ airpe_cmd_write(airpe, "PING");
+ }
+ else {
+ snprintf(buf, sizeof(buf), "ALTER CALL %d END HANGUP", callid );
+ airpe_cmd_write(airpe, buf);
+ }
+ }
+ else if ( !strncmp(cmd, "VAA_INPUT_STATUS", strlen("VAA_INPUT_STATUS")) ) {
+ /* Let's ignore */
+ }
+ else if ( !strncmp(cmd, "DTMF", strlen("DTMF")) ) {
+ /* This is an incoming DTMF */
+ switch_core_session_t *session;
+ switch_channel_t *channel;
+ switch_dtmf_t dtmf = { 0, switch_core_default_dtmf_duration(0) };
+ const char *signal_ptr;
+ int tmp;
+
+ assert(airpe->tech_pvt);
+ session = airpe->tech_pvt->session;
+ assert(session);
+ channel = switch_core_session_get_channel(session);
+ assert(channel);
+
+ signal_ptr = argv[3];
+
+ if (*signal_ptr && (*signal_ptr == '*' || *signal_ptr == '#' || *signal_ptr == 'A' || *signal_ptr == 'B' || *signal_ptr == 'C' || *signal_ptr == 'D')) {
+ dtmf.digit = *signal_ptr;
+ } else {
+ tmp = atoi(signal_ptr);
+ dtmf.digit = switch_rfc2833_to_char(tmp);
+ }
+
+ switch_mutex_lock(airpe->tech_pvt->flag_mutex);
+ switch_channel_queue_dtmf(channel, &dtmf);
+ switch_mutex_unlock(airpe->tech_pvt->flag_mutex);
+ }
+ else if ( !strncmp(cmd, "FAILUREREASON", strlen("FAILUREREASON")) && argc >=2 ) {
+ airpe->last_fail_reason = atoi(argv[1]);
+ airpe_cmd_write(airpe, "CLEAR CALLHISTORY ALL");
+ }
+ else if ( !strncmp(cmd, "SEEN", strlen("SEEN")) && argc >=4 ) {
+ /*
+ char buf[SKYPE_MSG_LEN] = "";
+ char *seenstatus = argv[3];
+ if ( !strncmp(seenstatus, "FALSE", strlen("FALSE")) ) {
+ snprintf(buf, sizeof(buf), "SET CALL %d SEEN", callid);
+ airpe_cmd_write(airpe, buf);
+ }
+ */
+ airpe_cmd_write(airpe, "CLEAR CALLHISTORY ALL");
+ }
+ else if ( !strncmp(cmd, "PARTNER_DISPNAME", strlen("PARTNER_DISPNAME")) && argc >=2 ) {
+ char *data, *tmp = NULL;
+ tmp = strdup(msg);
+ if ( tmp && (callid == airpe->active_call_id) ) {
+ data = strstr(tmp, "PARTNER_DISPNAME ");
+ if ( data ) {
+ data += strlen("PARTNER_DISPNAME ");
+ airpe_set_partner_displayname(airpe, data);
+ }
+ }
+ switch_safe_free(tmp);
+ }
+ else if ( !strncmp(cmd, "PARTNER_HANDLE", strlen("PARTNER_HANDLE")) && argc >=2 ) {
+ char *data, *tmp = NULL;
+ tmp = strdup(msg);
+ if ( tmp && (callid == airpe->active_call_id) ) {
+ data = strstr(tmp, "PARTNER_HANDLE ");
+ if ( data ) {
+ data += strlen("PARTNER_HANDLE ");
+ airpe_set_partner_handle(airpe, data);
+ }
+ switch_safe_free(tmp);
+ }
+ }
+ else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "CALL ID %d\n", callid);
+ }
+ }
+ else if ( !strncmp( buf, "DTMF", strlen("DTMF")) && argc>3 ) {
+ /* We are alerted that a DTMF we was sent to the other party - Ignored */
+ }
+ else if ( !strncmp( msg, "ERROR 68", strlen("ERROR 68")) ) {
+ /* The client needs authorization. Probably we reconnected to a new skype window. */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Airpe client %s needs authorization.\n", airpe->name);
+ switch_sleep(1000000);
+ airpe_on_connect_messages(airpe, airpe->protocol);
+ }
+ else if ( !strncmp( msg, "ALTER CALL", strlen("ALTER CALL")) ) {
+ /* The response to our hangup - Ignored */
+ }
+ else if ( !strncmp( msg, "SET CALL", strlen("SET CALL")) ) {
+ /* Ignoring by now */
+ }
+ else if ( !strncmp( buf, "ERROR", strlen("ERROR")) ) {
+ //TODO If we are in the middle of a call, hangup
+ }
+ else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unmanaged message\n");
+ }
+
+ switch_safe_free(buf);
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t airpe_on_connect_messages( airpe_interface_t *airpe, int protocol ) {
+ char buf[SKYPE_MSG_LEN] = "";
+
+ snprintf(buf, sizeof(buf), "NAME airpe");
+ if ( airpe_cmd_write(airpe, buf) != SWITCH_STATUS_SUCCESS )
+ return SWITCH_STATUS_FALSE;
+ snprintf(buf, sizeof(buf), "PROTOCOL %d", protocol);
+ if ( airpe_cmd_write(airpe, buf) != SWITCH_STATUS_SUCCESS )
+ return SWITCH_STATUS_FALSE;
+ snprintf(buf, sizeof(buf), "CLEAR CALLHISTORY ALL");
+ if ( airpe_cmd_write(airpe, buf) != SWITCH_STATUS_SUCCESS )
+ return SWITCH_STATUS_FALSE;
+ snprintf(buf, sizeof(buf), "CLEAR CHATHISTORY");
+ if ( airpe_cmd_write(airpe, buf) != SWITCH_STATUS_SUCCESS )
+ return SWITCH_STATUS_FALSE;
+ snprintf(buf, sizeof(buf), "GET SKYPEVERSION");
+ if ( airpe_cmd_write(airpe, buf) != SWITCH_STATUS_SUCCESS )
+ return SWITCH_STATUS_FALSE;
+ snprintf(buf, sizeof(buf), "GET PROFILE MOOD_TEXT");
+ if ( airpe_cmd_write(airpe, buf) != SWITCH_STATUS_SUCCESS )
+ return SWITCH_STATUS_FALSE;
+ snprintf(buf, sizeof(buf), "GET PROFILE FULLNAME");
+ if ( airpe_cmd_write(airpe, buf) != SWITCH_STATUS_SUCCESS )
+ return SWITCH_STATUS_FALSE;
+ snprintf(buf, sizeof(buf), "GET CONNSTATUS");
+ if ( airpe_cmd_write(airpe, buf) != SWITCH_STATUS_SUCCESS )
+ return SWITCH_STATUS_FALSE;
+ snprintf(buf, sizeof(buf), "SET AUTOAWAY OFF");
+ if ( airpe_cmd_write(airpe, buf) != SWITCH_STATUS_SUCCESS )
+ return SWITCH_STATUS_FALSE;
+ snprintf(buf, sizeof(buf), "SET MUTE OFF");
+ if ( airpe_cmd_write(airpe, buf) != SWITCH_STATUS_SUCCESS )
+ return SWITCH_STATUS_FALSE;
+
+ /*
+ The following two raise an error on linux, even if are supported from protocol 6 upwards.
+ That's not a big problem so we'll send them.
+ */
+
+ snprintf(buf, sizeof(buf), "SET PCSPEAKER OFF");
+ if ( airpe_cmd_write(airpe, buf) != SWITCH_STATUS_SUCCESS )
+ return SWITCH_STATUS_FALSE;
+ snprintf(buf, sizeof(buf), "SET SILENT_MODE ON");
+ if ( airpe_cmd_write(airpe, buf) != SWITCH_STATUS_SUCCESS )
+ return SWITCH_STATUS_FALSE;
+
+ 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 expandtab:
+ */
Added: freeswitch/branches/ctrix/mod_airpe/airpe_if_osx.c
==============================================================================
--- (empty file)
+++ freeswitch/branches/ctrix/mod_airpe/airpe_if_osx.c Mon Jan 12 17:24:44 2009
@@ -0,0 +1,19 @@
+
+#include "mod_airpe.h"
+
+#if defined (MACOSX) || defined(DARWIN)
+
+#error OSX Not yet supported
+
+#endif
+
+/* 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:
+ */
Added: freeswitch/branches/ctrix/mod_airpe/airpe_if_win32.c
==============================================================================
--- (empty file)
+++ freeswitch/branches/ctrix/mod_airpe/airpe_if_win32.c Mon Jan 12 17:24:44 2009
@@ -0,0 +1,19 @@
+
+#include "mod_airpe.h"
+
+#ifdef WIN32
+
+#error WIN32 Not yet supported
+
+#endif
+
+/* 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:
+ */
Added: freeswitch/branches/ctrix/mod_airpe/airpe_if_x11.c
==============================================================================
--- (empty file)
+++ freeswitch/branches/ctrix/mod_airpe/airpe_if_x11.c Mon Jan 12 17:24:44 2009
@@ -0,0 +1,355 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct at yahoo.com>
+ *
+ * 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 mod_airpe.
+ *
+ * The Initial Developer of the Original Code is
+ * Massimo Cetra <devel at navynet.it>
+ *
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Thanks to gmaruzz for his work on skypiax (both * and freeswitch).
+ * Some of his code inspired this module
+ *
+ */
+
+#if defined (__GNUC__) && !(defined (MACOSX) || defined(DARWIN) )
+
+#include "mod_airpe.h"
+
+#include <X11/Xlib.h>
+#include <X11/Xlibint.h>
+#include <X11/Xatom.h>
+
+#define X11_MSG_LEN 20
+
+struct skype_window_handler_s {
+ Display *disp;
+ Window win;
+ uint8_t api_connected;
+ int fdesc[2];
+ Window skype_win;
+ int watchdog;
+};
+
+
+
+
+static XErrorHandler old_handler = 0;
+static int xerror = 0;
+
+static int xerrhandler(Display *dpy, XErrorEvent *err)
+{
+ xerror = err->error_code;
+ /* Return 0 so that the error is ignored */
+ return 0;
+}
+
+static void trap_errors()
+{
+ xerror = 0;
+ old_handler = XSetErrorHandler(xerrhandler);
+}
+
+static int untrap_errors()
+{
+ XSetErrorHandler(old_handler);
+ return (xerror != BadValue) && (xerror != BadWindow);
+}
+
+switch_status_t airpe_skype_watchdog_reset(skype_window_handler_t *window) {
+ window->watchdog = 0;
+ return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t airpe_skype_watchdog_increment(skype_window_handler_t *window) {
+ window->watchdog++;
+
+ if ( window->watchdog >= 5 ) {
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+skype_window_handler_t *skype_window_alloc( switch_memory_pool_t *pool) {
+ return switch_core_alloc( pool, sizeof(skype_window_handler_t));
+}
+
+switch_status_t skype_restart( skype_window_handler_t *window, const char *params ) {
+
+ switch_log_printf( SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
+ "HEY! where is my skype window gone ? Restarting skype for client...\n");
+/*
+
+ TODO AND TO USE
+
+ int fid;
+ const char *args[] = { "skype", "--actiondispatch", params, 0 };
+
+ if((fid = fork()) == 0) {
+ if(execvp("skype", (char *const*)args) == -1) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "airpe client: cannot launch Skype, error %d: %s.\n", errno, strerror(errno) );
+ return SWITCH_STATUS_FALSE;
+ }
+ }
+ else if(fid == -1) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "airpe client: cannot launch Skype.\n");
+ return SWITCH_STATUS_FALSE;
+ }
+*/
+ return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t airpe_skype_send_message(skype_window_handler_t *window, const char *message_P) {
+ Window w_P;
+ Display *disp;
+ Window handle_P;
+ Atom atom1;
+ Atom atom2;
+ unsigned int pos;
+ unsigned int len;
+ XEvent xev;
+ int ok;
+
+ w_P = window->skype_win;
+ disp = window->disp;
+ handle_P = window->win;
+
+ atom1 = XInternAtom(disp, "SKYPECONTROLAPI_MESSAGE_BEGIN", False);
+ atom2 = XInternAtom(disp, "SKYPECONTROLAPI_MESSAGE", False);
+ pos = 0;
+ len = strlen(message_P);
+
+ memset(&xev, 0, sizeof(XEvent));
+ xev.xclient.type = ClientMessage;
+ xev.xclient.message_type = atom1;
+ xev.xclient.display = disp;
+ xev.xclient.window = handle_P;
+ xev.xclient.format = 8;
+
+ trap_errors();
+ do {
+ unsigned int i;
+ for (i = 0; i < 20 && i + pos <= len; ++i)
+ xev.xclient.data.b[i] = message_P[i + pos];
+ XSendEvent(disp, w_P, False, 0, &xev);
+
+ xev.xclient.message_type = atom2;
+ pos += i;
+ } while (pos <= len);
+
+ XSync(disp, False);
+ ok = untrap_errors();
+ if (!ok) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "airpe client X11 error.\n");
+ airpe_skype_avalaible(window);
+ }
+ return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t airpe_skype_avalaible(skype_window_handler_t *window)
+{
+
+ Atom skype_inst;
+ Atom type_ret;
+ int format_ret;
+ unsigned long nitems_ret;
+ unsigned long bytes_after_ret;
+ unsigned char *prop;
+ int status, ok;
+
+ skype_inst = XInternAtom(window->disp, "_SKYPE_INSTANCE", True);
+
+ trap_errors();
+ status = XGetWindowProperty(
+ window->disp,
+ DefaultRootWindow(window->disp),
+ skype_inst,
+ 0,
+ 1,
+ False,
+ XA_WINDOW,
+ &type_ret,
+ &format_ret,
+ &nitems_ret,
+ &bytes_after_ret, &prop);
+
+ ok = untrap_errors();
+ if (!ok) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "airpe client X11 error.\n");
+ airpe_skype_avalaible(window);
+ }
+
+ /* sanity check */
+ if (status != Success || format_ret != 32 || nitems_ret != 1) {
+ window->skype_win = (Window) - 1;
+ return SWITCH_STATUS_FALSE;
+ }
+
+ window->skype_win = *(const unsigned long *) prop & 0xffffffff;
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+
+
+/*****************************************************************************
+ THREADS
+ *****************************************************************************/
+
+void *SWITCH_THREAD_FUNC airpe_skype_thread(switch_thread_t * thread, void *obj) {
+
+ skype_window_handler_t *skype_window = NULL;
+ airpe_interface_t *airpe = NULL;
+ Display *disp = NULL;
+ Window root = -1;
+ Window win = -1;
+ int xfd;
+
+ assert(obj);
+
+ airpe = obj;
+
+ skype_window = airpe->skype_window;
+ assert(skype_window);
+
+ disp = XOpenDisplay(airpe->X11_display);
+ if (!disp) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "airpe client %s: cannot open display %s\n", airpe->name, airpe->X11_display);
+ return NULL;
+ }
+
+ xfd = XConnectionNumber(disp);
+ fcntl(xfd, F_SETFD, FD_CLOEXEC);
+
+ skype_window->disp = disp;
+
+ if ( airpe_skype_avalaible(skype_window) == SWITCH_STATUS_SUCCESS ) {
+ root = DefaultRootWindow(disp);
+ win = XCreateSimpleWindow(
+ disp,
+ root,
+ 0, 0, 1, 1, 0,
+ BlackPixel(disp, DefaultScreen(disp)),
+ BlackPixel(disp, DefaultScreen(disp))
+ );
+
+ skype_window->win = win;
+
+ if ( airpe_on_connect_messages( airpe, 6 ) != SWITCH_STATUS_SUCCESS ) {
+ switch_log_printf( SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
+ "airpe client %s. Failed to send handshake messages\n",
+ airpe->name);
+ return NULL;
+ }
+
+ // perform an events loop
+ XEvent an_event;
+ char buf[X11_MSG_LEN + 2] = "";
+ char buffer[SKYPE_MSG_LEN] = "";
+ int i;
+ fd_set rset;
+ int x11_fd;
+ int empty_loops = 0;
+
+ airpe->running = 1;
+ XFlush(disp);
+ x11_fd = ConnectionNumber(disp);
+
+ while ( airpe->running ) {
+ FD_ZERO(&rset);
+ FD_SET( x11_fd, &rset);
+
+ struct timeval timeout;
+ int ret;
+
+ timeout.tv_usec = 10 * 1000;
+ ret = select(x11_fd+1, &rset, 0, 0, &timeout);
+
+ if ( !airpe->running ) /* Quick way to skip the loop when we are signaled to exit. */
+ break;
+
+ if ( ret <=0 ) {
+ empty_loops ++;
+ if ( empty_loops >= 250 ) {
+ airpe_cmd_write(airpe, "PING");
+ airpe_skype_watchdog_increment(skype_window);
+ empty_loops = 0;
+ }
+ continue;
+ }
+
+ airpe_skype_watchdog_reset(skype_window);
+
+ /* Process all the pending messages queued (not only one) */
+ while ( XPending(disp) )
+ {
+ XNextEvent(disp, &an_event);
+
+ switch (an_event.type)
+ {
+ case ClientMessage:
+ if (an_event.xclient.format != 8)
+ break;
+
+ for (i = 0; i < X11_MSG_LEN && an_event.xclient.data.b[i] != '\0'; ++i) {
+ buf[i] = an_event.xclient.data.b[i];
+ }
+ buf[i] = '\0';
+
+ strcat(buffer, buf);
+
+ if (i < X11_MSG_LEN) {
+ unsigned int howmany;
+ howmany = strlen(buffer) + 1;
+ airpe_manage_skype_msg( airpe, buffer);
+ memset(&buffer, 0, sizeof(buffer));
+ }
+ break;
+ default:
+ if ( airpe->debug )
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "airpe client %s: unknown event\n", airpe->name);
+ break;
+ }
+ }
+ }
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "airpe client %s: exiting thread\n", airpe->name);
+
+ /* Hangup our call, if we have one */
+ airpe_explicit_hangup(airpe);
+
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "airpe client %s: skype not running on display %s\n", airpe->name, airpe->X11_display);
+ }
+
+ return NULL;
+}
+
+#endif
+
+/* 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:
+ */
Added: freeswitch/branches/ctrix/mod_airpe/config/airpe.conf.xml
==============================================================================
--- (empty file)
+++ freeswitch/branches/ctrix/mod_airpe/config/airpe.conf.xml Mon Jan 12 17:24:44 2009
@@ -0,0 +1,36 @@
+<configuration name="airpe.conf" description="Airpe Configuration">
+ <globals>
+ <param name="audio-tcp-port_start" value="21000"/>
+
+ <!-- Those params are used for all clients if not explicitly set for each one -->
+ <param name="context" value="public"/>
+ <param name="dialplan" value="XML"/>
+ <param name="destination" value="5000"/>
+ </globals>
+
+ <!-- one entry here per airpe client -->
+ <clients>
+ <client name="airpe1">
+ <!-- Print out as notices the client messages -->
+ <param name="debug" value="1"/>
+
+ <!-- Where our calls will land -->
+ <param name="dialplan" value="XML"/>
+ <param name="context" value="default"/>
+ <param name="destination" value="4321"/>
+
+ <!-- Linux only -->
+ <param name="X11-display" value=":101"/>
+
+ <!-- Not used yet -->
+ <param name="cid-name" value="Skype 1"/>
+ <param name="cid-num" value="0000001"/>
+
+ <!-- Not used... maybe should be removed.
+ The purpose is restarting the client with those credentials -->
+ <param name="skype-user" value="username"/>
+ <param name="skype-password" value="password"/>
+ </client>
+ </clients>
+
+</configuration>
Added: freeswitch/branches/ctrix/mod_airpe/mod_airpe.c
==============================================================================
--- (empty file)
+++ freeswitch/branches/ctrix/mod_airpe/mod_airpe.c Mon Jan 12 17:24:44 2009
@@ -0,0 +1,868 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct at yahoo.com>
+ *
+ * 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 mod_airpe.
+ *
+ * The Initial Developer of the Original Code is
+ * Massimo Cetra <devel at navynet.it>
+ *
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Thanks to gmaruzz for his work on skypiax (both * and freeswitch).
+ * Some of his code inspired this module
+ *
+ */
+
+#include "mod_airpe.h"
+
+/*****************************************************************************
+ MODULE PRIVATE STRUCTS && FUNCTIONS
+ *****************************************************************************/
+
+static switch_endpoint_interface_t *airpe_endpoint_interface;
+
+static struct {
+ char *dialplan;
+ char *context;
+ char *destination;
+ int audio_tcp_port_start;
+
+ switch_mutex_t *mutex;
+ switch_hash_t *interfaces_hash;
+ int last_port_used;
+} globals;
+
+static switch_memory_pool_t *airpe_module_pool = NULL;
+
+
+airpe_interface_t *airpe_find_interface( const char *name) {
+ return switch_core_hash_find(globals.interfaces_hash, name);
+}
+
+
+/*****************************************************************************
+ TECH STUFF
+ *****************************************************************************/
+
+static switch_status_t airpe_codec_init(private_object_t * tech_pvt, int sample_rate, int codec_ms) {
+ airpe_interface_t *airpe = NULL;
+
+ if ( switch_core_codec_init(&tech_pvt->read_codec, "L16", NULL, sample_rate, codec_ms, 1, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, NULL) != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "airpe client: %s - Cannot init read codec.\n", airpe->name);
+ return SWITCH_STATUS_FALSE;
+ }
+
+ if ( switch_core_codec_init(&tech_pvt->write_codec, "L16", NULL, sample_rate, codec_ms, 1, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, NULL) != SWITCH_STATUS_SUCCESS ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "airpe client: %s - Cannot init write codec.\n", airpe->name);
+ switch_core_codec_destroy(&tech_pvt->read_codec);
+ return SWITCH_STATUS_FALSE;
+ }
+
+ tech_pvt->read_frame.rate = sample_rate;
+ tech_pvt->read_frame.codec = &tech_pvt->read_codec;
+
+ switch_core_session_set_read_codec(tech_pvt->session, &tech_pvt->read_codec);
+ switch_core_session_set_write_codec(tech_pvt->session, &tech_pvt->write_codec);
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t airpe_tech_init( private_object_t * tech_pvt, switch_core_session_t * session ) {
+
+ tech_pvt->read_frame.data = tech_pvt->databuf;
+ tech_pvt->read_frame.buflen = sizeof(tech_pvt->databuf);
+
+ switch_mutex_init(&tech_pvt->mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
+ switch_mutex_init(&tech_pvt->flag_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
+
+ switch_core_session_set_private(session, tech_pvt);
+ tech_pvt->session = session;
+ return airpe_codec_init(tech_pvt, CODEC_SAMPLE_RATE, CODEC_INTERVAL_MS);
+}
+
+static switch_socket_t *airpe_socket_create( const char *host, int port ) {
+ switch_status_t rv;
+ switch_socket_t *new_sock = NULL;
+ switch_sockaddr_t *sa;
+
+ rv = switch_sockaddr_info_get(&sa, host, AF_INET, port, 0, airpe_module_pool);
+ if ( rv != SWITCH_STATUS_SUCCESS ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Socket Creation Error! (1)\n");
+ return NULL;
+ }
+
+ rv = switch_socket_create(&new_sock, AF_INET, SOCK_STREAM, SWITCH_PROTO_TCP, airpe_module_pool);
+ if ( rv != SWITCH_STATUS_SUCCESS ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Socket Creation Error! (2)\n");
+ return NULL;
+ }
+
+ rv = switch_socket_opt_set(new_sock, SWITCH_SO_REUSEADDR, 1);
+ if ( rv != SWITCH_STATUS_SUCCESS ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Socket Creation Error! (3)\n");
+ return NULL;
+ }
+
+ rv = switch_socket_opt_set(new_sock, SWITCH_SO_NONBLOCK, 1);
+ if ( rv != SWITCH_STATUS_SUCCESS ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Socket Creation Error! (3)\n");
+ return NULL;
+ }
+
+ rv = switch_socket_bind(new_sock, sa);
+ if ( rv != SWITCH_STATUS_SUCCESS ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Socket Creation Error! (4)\n");
+ return NULL;
+ }
+
+ rv = switch_socket_listen(new_sock, 5);
+ if ( rv != SWITCH_STATUS_SUCCESS ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Socket Creation Error! (5)\n");
+ return NULL;
+ }
+
+ return new_sock;
+}
+
+static int fetch_next_port(void) {
+ int port = 0;
+
+ if ( !globals.last_port_used )
+ globals.last_port_used = globals.audio_tcp_port_start;
+
+ switch_mutex_lock(globals.mutex);
+ port = globals.last_port_used;
+ globals.last_port_used++;
+ switch_mutex_unlock(globals.mutex);
+
+ return port;
+}
+
+static switch_status_t airpe_audio_sockets_create( airpe_interface_t *airpe ) {
+ switch_socket_t *new_sock;
+ int port;
+
+ new_sock = NULL;
+ while ( !new_sock ) {
+ port = fetch_next_port();
+ if ( airpe->debug )
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Assigning in port %d for client %s\n", port, airpe->name);
+ new_sock = airpe_socket_create("127.0.0.1", port);
+ if ( new_sock ) {
+ airpe->audio_in_socket = new_sock;
+ airpe->audio_in_port = port;
+ }
+ }
+
+ new_sock = NULL;
+ while ( !new_sock ) {
+ port = fetch_next_port();
+ if ( airpe->debug )
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Assigning out port %d for client %s\n", port, airpe->name);
+ new_sock = airpe_socket_create("127.0.0.1", port);
+ if ( new_sock ) {
+ airpe->audio_out_socket = new_sock;
+ airpe->audio_out_port = port;
+ }
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+
+static switch_status_t airpe_start_client(airpe_interface_t *airpe) {
+
+ switch_threadattr_t *attr_skype = NULL;
+
+ airpe->user_status = USER_STATUS_UNKNOWN;
+ airpe->conn_status = CONN_STATUS_UNKNOWN;
+ airpe->call_status = CALL_STATUS_UNKNOWN;
+
+ airpe_audio_sockets_create(airpe);
+
+ switch_threadattr_create(&attr_skype, airpe_module_pool);
+ //switch_threadattr_detach_set(attr_skype, 1);
+ switch_threadattr_stacksize_set(attr_skype, SWITCH_THREAD_STACKSIZE);
+
+ switch_thread_create(&airpe->airpe_thread_skype,
+ attr_skype,
+ airpe_skype_thread,
+ airpe,
+ airpe_module_pool);
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t airpe_stop_client(airpe_interface_t *airpe) {
+
+ if ( airpe->audio_in_socket ) {
+ if ( airpe->debug )
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Shutting down socket on port %d for client %s\n", airpe->audio_in_port, airpe->name);
+ airpe->audio_in_port = 0;
+ switch_socket_shutdown(airpe->audio_in_socket, SWITCH_SHUTDOWN_READWRITE);
+ switch_socket_close(airpe->audio_in_socket);
+ }
+
+ if ( airpe->audio_out_socket ) {
+ if ( airpe->debug )
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Shutting down socket on port %d for client %s\n", airpe->audio_out_port, airpe->name);
+ airpe->audio_out_port = 0;
+ switch_socket_shutdown(airpe->audio_out_socket, SWITCH_SHUTDOWN_READWRITE);
+ switch_socket_close(airpe->audio_out_socket);
+ }
+
+ airpe_set_version(airpe, NULL);
+ airpe_set_mood_text(airpe, NULL);
+ airpe_set_partner_displayname(airpe, NULL);
+ airpe_set_partner_handle(airpe, NULL);
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+switch_core_session_t *airpe_request_session( switch_memory_pool_t **pool ) {
+ /* I prefer not to expose airpe_endpoint_interface out of this file. */
+ return switch_core_session_request(airpe_endpoint_interface, pool);
+}
+
+
+/*****************************************************************************
+ CHANNEL STATE HANDLERS
+ *****************************************************************************/
+
+static switch_status_t channel_on_init(switch_core_session_t * session)
+{
+ switch_channel_t *channel;
+ private_object_t *tech_pvt = NULL;
+
+ channel = switch_core_session_get_channel(session);
+ assert(channel);
+
+ tech_pvt = switch_core_session_get_private(session);
+ assert(tech_pvt);
+ assert(tech_pvt->airpe);
+
+ tech_pvt->airpe->tech_pvt = tech_pvt;
+
+ if ( switch_test_flag(tech_pvt, TFLAG_OUTBOUND) ) {
+ airpe_originate(tech_pvt->airpe, tech_pvt->destination );
+ // TODO if fail switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+ }
+
+ if ( switch_test_flag(tech_pvt, TFLAG_INBOUND) ) {
+ char buf[SKYPE_MSG_LEN];
+ snprintf(buf, sizeof(buf), "ALTER CALL %d SET_INPUT PORT=\"%d\"", tech_pvt->airpe->active_call_id, tech_pvt->airpe->audio_in_port);
+ airpe_cmd_write(tech_pvt->airpe, buf);
+ snprintf(buf, sizeof(buf), "ALTER CALL %d SET_OUTPUT PORT=\"%d\"", tech_pvt->airpe->active_call_id, tech_pvt->airpe->audio_out_port);
+ airpe_cmd_write(tech_pvt->airpe, buf);
+
+ switch_channel_set_state(channel, CS_ROUTING);
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_routing(switch_core_session_t * session) {
+ char buf[SKYPE_MSG_LEN];
+ switch_channel_t *channel = NULL;
+ private_object_t *tech_pvt = NULL;
+
+ channel = switch_core_session_get_channel(session);
+ assert(channel);
+
+ tech_pvt = switch_core_session_get_private(session);
+ assert(tech_pvt);
+
+ if ( switch_test_flag(tech_pvt, TFLAG_INBOUND) ) {
+ snprintf(buf, sizeof(buf), "ALTER CALL %d ANSWER", tech_pvt->airpe->active_call_id);
+ airpe_cmd_write(tech_pvt->airpe, buf);
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_execute(switch_core_session_t * session) {
+ switch_channel_t *channel = NULL;
+ private_object_t *tech_pvt = NULL;
+
+ channel = switch_core_session_get_channel(session);
+ assert(channel);
+
+ tech_pvt = switch_core_session_get_private(session);
+ assert(tech_pvt);
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_hangup(switch_core_session_t * session)
+{
+ switch_channel_t *channel = NULL;
+ private_object_t *tech_pvt = NULL;
+ airpe_interface_t *airpe = NULL;
+ char msg[SKYPE_MSG_LEN];
+
+ channel = switch_core_session_get_channel(session);
+ assert(channel);
+
+ tech_pvt = switch_core_session_get_private(session);
+ assert(tech_pvt);
+
+ airpe = tech_pvt->airpe;
+ assert(airpe);
+
+ if ( airpe->active_call_id ) {
+ snprintf(msg, sizeof(msg), "ALTER CALL %d HANGUP", airpe->active_call_id);
+ airpe_cmd_write(airpe, msg);
+// airpe->active_call_id = 0;
+// airpe->tech_pvt = NULL;
+ }
+
+ airpe_hangup( tech_pvt );
+
+ if (tech_pvt->read_codec.implementation) {
+ switch_core_codec_destroy(&tech_pvt->read_codec);
+ }
+
+ if (tech_pvt->write_codec.implementation) {
+ switch_core_codec_destroy(&tech_pvt->write_codec);
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_exchange_media(switch_core_session_t * session) {
+ return SWITCH_STATUS_SUCCESS;
+}
+
+/*****************************************************************************
+ CHANNEL IO INTERFACE / ROUTINES
+ *****************************************************************************/
+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_caller_profile_t *caller_profile = NULL;
+ private_object_t *tech_pvt = NULL;
+ switch_channel_t *channel = NULL;
+
+ assert(outbound_profile);
+
+ /* New session creation */
+ *new_session = airpe_request_session(pool);
+ if ( *new_session )
+ {
+ char *chan_interface = NULL;
+ char *chan_destination = NULL;
+
+ switch_core_session_add_stream(*new_session, NULL);
+
+ tech_pvt = (private_object_t *) switch_core_session_alloc(*new_session, sizeof(private_object_t));
+
+ if ( tech_pvt ) {
+ channel = switch_core_session_get_channel(*new_session);
+ if ( airpe_tech_init( tech_pvt, *new_session ) != SWITCH_STATUS_SUCCESS ) {
+ switch_core_session_destroy(new_session);
+ return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+ }
+ } else {
+ switch_core_session_destroy(new_session);
+ return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+ }
+
+
+ chan_interface = switch_core_session_strdup( *new_session, outbound_profile->destination_number);
+ if (( chan_destination = strchr(chan_interface, '/'))) {
+ *chan_destination++ = '\0';
+ }
+ if ( !chan_interface || !chan_destination ) {
+ switch_core_session_destroy(new_session);
+ return SWITCH_CAUSE_INVALID_NUMBER_FORMAT;
+ }
+
+ if ( (tech_pvt->airpe = airpe_find_interface(chan_interface))==NULL ) {
+ switch_core_session_destroy(new_session);
+ return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+ }
+ tech_pvt->destination = chan_destination;
+
+ if ( tech_pvt->airpe->active_call_id != 0 ) {
+ /* We're busy, man! */
+ switch_core_session_destroy(new_session);
+ return SWITCH_CAUSE_REQUESTED_CHAN_UNAVAIL;
+ }
+
+ if (outbound_profile) {
+ char name[128];
+ snprintf(name, sizeof(name), "airpe/%s", outbound_profile->destination_number);
+ switch_channel_set_name(channel, name);
+ caller_profile = switch_caller_profile_clone(*new_session, outbound_profile);
+ switch_channel_set_caller_profile(channel, caller_profile);
+ tech_pvt->caller_profile = caller_profile;
+ }
+ else
+ {
+ switch_core_session_destroy(new_session);
+ return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+ }
+
+ switch_channel_set_flag(channel, CF_OUTBOUND);
+ switch_set_flag_locked(tech_pvt, TFLAG_OUTBOUND);
+ switch_channel_set_state(channel, CS_INIT);
+ return SWITCH_CAUSE_SUCCESS;
+ }
+ else
+ {
+ return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+ }
+}
+
+static switch_status_t channel_read_frame(switch_core_session_t * session,
+ switch_frame_t ** frame,
+ switch_io_flag_t flags,
+ int stream_id)
+{
+ switch_channel_t *channel = NULL;
+ private_object_t *tech_pvt = NULL;
+ switch_byte_t *data;
+
+ channel = switch_core_session_get_channel(session);
+ assert(channel);
+
+ tech_pvt = switch_core_session_get_private(session);
+ assert(tech_pvt);
+
+ tech_pvt->read_frame.flags = SFF_NONE;
+ *frame = NULL;
+
+ if ( airpe_audio_read(tech_pvt) != SWITCH_STATUS_SUCCESS) {
+ ADEBUG("airpe_audio_read ERROR\n");
+ return SWITCH_STATUS_FALSE;
+ }
+
+ if (!tech_pvt->read_frame.datalen) {
+ goto cng;
+ }
+
+ *frame = &tech_pvt->read_frame;
+
+ return SWITCH_STATUS_SUCCESS;
+
+cng:
+ data = (switch_byte_t *) tech_pvt->read_frame.data;
+ data[0] = 65;
+ data[1] = 0;
+ tech_pvt->read_frame.datalen = 2;
+ tech_pvt->read_frame.flags = SFF_CNG;
+ *frame = &tech_pvt->read_frame;
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_write_frame(switch_core_session_t * session,
+ switch_frame_t * frame,
+ switch_io_flag_t flags,
+ int stream_id)
+{
+ switch_channel_t *channel = NULL;
+ private_object_t *tech_pvt = NULL;
+ airpe_interface_t *airpe = NULL;
+ switch_status_t rv;
+
+ channel = switch_core_session_get_channel(session);
+ assert(channel);
+
+ tech_pvt = switch_core_session_get_private(session);
+ assert(tech_pvt);
+
+ if ( !tech_pvt->airpe ) {
+ return SWITCH_STATUS_FALSE;
+ }
+
+ airpe = tech_pvt->airpe;
+
+ rv = airpe_audio_write(tech_pvt, frame);
+ return rv;
+}
+
+static switch_status_t channel_kill_channel(switch_core_session_t * session, int sig)
+{
+ switch_channel_t *channel = NULL;
+ private_object_t *tech_pvt = NULL;
+
+ channel = switch_core_session_get_channel(session);
+ assert(channel);
+
+ tech_pvt = switch_core_session_get_private(session);
+ assert(tech_pvt);
+
+ switch (sig) {
+ case SWITCH_SIG_KILL:
+ break;
+ case SWITCH_SIG_BREAK:
+ break;
+ default:
+ //TODO Log unhandled signal
+ break;
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_send_dtmf(switch_core_session_t * session, const switch_dtmf_t * dtmf) {
+ private_object_t *tech_pvt = switch_core_session_get_private(session);
+ airpe_interface_t *airpe;
+ char buf[SKYPE_MSG_LEN];
+
+ switch_assert(tech_pvt);
+
+ airpe = tech_pvt->airpe;
+
+ if ( airpe->active_call_id ) {
+ snprintf(buf, sizeof(buf), "SET CALL %d DTMF %c", airpe->active_call_id, dtmf->digit);
+ airpe_cmd_write(airpe, buf);
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_receive_message(switch_core_session_t * session, switch_core_session_message_t * msg)
+{
+ switch_channel_t *channel;
+ private_object_t *tech_pvt;
+
+ channel = switch_core_session_get_channel(session);
+ assert(channel);
+
+ tech_pvt = (private_object_t *) switch_core_session_get_private(session);
+ assert(tech_pvt);
+
+ switch (msg->message_id) {
+ case SWITCH_MESSAGE_INDICATE_ANSWER:
+ ADEBUG("received message indicate answer...\n");
+/*
+ //switch_answer_channel(session);
+ char buf[SKYPE_MSG_LEN];
+ snprintf(buf, sizeof(buf), "ALTER CALL %d ANSWER", tech_pvt->airpe->active_call_id );
+ airpe_cmd_write(tech_pvt->airpe, buf);
+*/
+ break;
+ case SWITCH_MESSAGE_INDICATE_UNBRIDGE:
+ ADEBUG("received message indicate unbridge...\n");
+ break;
+ case SWITCH_MESSAGE_INDICATE_TRANSCODING_NECESSARY:
+ ADEBUG("received message indicate transcode necessary...\n");
+ break;
+ case SWITCH_MESSAGE_INDICATE_AUDIO_SYNC:
+ ADEBUG("received message indicate audio sync...\n");
+ break;
+ case SWITCH_MESSAGE_INDICATE_TRANSFER:
+ ADEBUG("received message indicate transfer...\n");
+ break;
+ default:
+ ADEBUG("Unmanaged received message... %d\n", msg->message_id);
+ break;
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_receive_event(switch_core_session_t * session, switch_event_t * event)
+{
+ char *body = NULL;
+ switch_channel_t *channel;
+ private_object_t *tech_pvt;
+
+ channel = switch_core_session_get_channel(session);
+ assert(channel);
+
+ tech_pvt = (private_object_t *) switch_core_session_get_private(session);
+ assert(tech_pvt);
+
+ body = switch_event_get_body(event);
+
+ if (!body) {
+ body = "";
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+
+/*****************************************************************************
+ CONFIGURATION
+ *****************************************************************************/
+
+static switch_status_t load_config(void) {
+ switch_xml_t cfg,
+ xml,
+ global_settings,
+ param,
+ clients,
+ client;
+ switch_memory_pool_t *pool;
+
+ pool = airpe_module_pool;
+
+ if (!(xml = switch_xml_open_cfg("airpe.conf", &cfg, NULL))) {
+ return SWITCH_STATUS_TERM;
+ }
+
+ if ( (global_settings = switch_xml_child(cfg, "globals") ) ) {
+ for (param = switch_xml_child(global_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 (!strcmp(var, "dialplan")) {
+ globals.dialplan = switch_core_strdup(pool, val);
+ } else if (!strcmp(var, "context")) {
+ globals.context = switch_core_strdup(pool, val);
+ } else if (!strcmp(var, "destination")) {
+ globals.destination = switch_core_strdup(pool, val);
+ } else if (!strcmp(var, "audio-tcp-port_start")) {
+ globals.audio_tcp_port_start = atoi(val);
+ }
+ }
+ }
+
+ if ( globals.audio_tcp_port_start <= 0 ) {
+ globals.audio_tcp_port_start = 21000;
+ }
+
+ if ( !globals.dialplan )
+ globals.dialplan = switch_core_strdup(pool, "XML");
+ if ( !globals.context )
+ globals.context = switch_core_strdup(pool, "default");
+ if ( !globals.destination )
+ globals.destination = switch_core_strdup(pool, "4321");
+
+ if ((clients = switch_xml_child(cfg, "clients"))) {
+
+ for (client = switch_xml_child(clients, "client"); client; client = client->next)
+ {
+ char *name = (char *) switch_xml_attr(client, "name");
+ char *context = NULL;
+ char *dialplan = NULL;
+ char *destination = NULL;
+ char *X11_display = NULL;
+ char *skype_user = NULL;
+ char *skype_password= NULL;
+ char *cid_name = NULL;
+ char *cid_num = NULL;
+ int debug = 0;
+
+ airpe_interface_t *newconf = NULL;
+
+ if (!name) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No name attribute. Skipping unnamed client.\n");
+ continue;
+ }
+
+ if ( (newconf = switch_core_hash_find(globals.interfaces_hash, name)) ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Duplicated client %s. Skipping\n", name);
+ continue;
+ }
+
+ for (param = switch_xml_child(client, "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, "debug")) {
+ debug = switch_true(val) ? 1 : 0;
+ } else if (!strcasecmp(var, "context")) {
+ context = val;
+ } else if (!strcasecmp(var, "dialplan")) {
+ dialplan = val;
+ } else if (!strcasecmp(var, "destination")) {
+ destination = val;
+ } else if (!strcasecmp(var, "skype-user")) {
+ skype_user = val;
+ } else if (!strcasecmp(var, "skype-password")) {
+ skype_password = val;
+ } else if (!strcasecmp(var, "X11-display")) {
+ X11_display = val;
+ } else if (!strcasecmp(var, "cid-name")) {
+ cid_name = val;
+ } else if (!strcasecmp(var, "cid-num")) {
+ cid_num = val;
+ }
+ else
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unknown config param %s\n", var);
+ }
+ if (!skype_user) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No skype-user param for client %s. Skipping\n", name);
+ continue;
+ }
+ if (!skype_password) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No skype-password param for client %s. Skipping\n", name);
+ continue;
+ }
+ if (!X11_display) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No X11-display param for client %s. Skipping\n", name);
+ continue;
+ }
+
+ if ( !dialplan )
+ dialplan = globals.dialplan;
+ if ( !context )
+ context = globals.context;
+ if ( !destination )
+ destination = globals.destination;
+
+ newconf = (airpe_interface_t *) switch_core_alloc( pool, sizeof(airpe_interface_t) );
+
+ if ( newconf ) {
+ switch_status_t status;
+
+ memset(newconf, 0, sizeof(airpe_interface_t));
+
+ newconf->name = switch_core_strdup(pool, name);
+ newconf->dialplan = switch_core_strdup(pool, dialplan);
+ newconf->context = switch_core_strdup(pool, context);
+ newconf->destination = switch_core_strdup(pool, destination);
+ newconf->skype_user = switch_core_strdup(pool, skype_user);
+ newconf->skype_password = switch_core_strdup(pool, skype_password);
+ newconf->X11_display = switch_core_strdup(pool, X11_display);
+ newconf->audio_in_port = 0;
+ newconf->audio_in_port = 0;
+ newconf->debug = debug;
+
+ newconf->skype_window = skype_window_alloc(pool);
+
+ if ( newconf->skype_window ) {
+ status = airpe_start_client(newconf);
+
+ if ( status == SWITCH_STATUS_SUCCESS ) {
+ switch_core_hash_insert(globals.interfaces_hash, name, newconf);
+ }
+ else {
+ // LOG OUR ERROR
+ }
+ }
+ else {
+ // LOG OUR ERROR
+ }
+
+ }
+ else {
+ //TODO LOG ERROR ABOUT CREATING INTERFACE
+ }
+ }
+
+ }
+
+ switch_xml_free(xml);
+ return SWITCH_STATUS_SUCCESS;
+}
+
+
+/*****************************************************************************
+ MODULE INITIALIZATION FUNCTIONS
+ *****************************************************************************/
+
+static switch_state_handler_table_t airpe_state_handlers = {
+ /*.on_init */ channel_on_init,
+ /*.on_routing */ channel_on_routing,
+ /*.on_execute */ channel_on_execute,
+ /*.on_hangup */ channel_on_hangup,
+ /*.on_exchange_media*/ channel_on_exchange_media,
+ /*.on_soft_execute */ NULL
+};
+
+static switch_io_routines_t airpe_io_routines = {
+ /*.outgoing_channel */ channel_outgoing_channel,
+ /*.read_frame */ channel_read_frame,
+ /*.write_frame */ channel_write_frame,
+ /*.kill_channel */ channel_kill_channel,
+ /*.send_dtmf */ channel_send_dtmf,
+ /*.receive_message */ channel_receive_message,
+ /*.receive_event */ channel_receive_event
+};
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_airpe_load);
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_airpe_shutdown);
+SWITCH_MODULE_DEFINITION(mod_airpe, mod_airpe_load, mod_airpe_shutdown, NULL);
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_airpe_load)
+{
+ airpe_module_pool = pool;
+
+ memset(&globals, 0, sizeof(globals));
+
+ switch_core_hash_init(&globals.interfaces_hash, pool);
+ switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, pool);
+
+ load_config();
+
+ *module_interface = switch_loadable_module_create_module_interface(pool, modname);
+
+ airpe_endpoint_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_ENDPOINT_INTERFACE);
+
+ airpe_endpoint_interface->interface_name = "airpe";
+ airpe_endpoint_interface->io_routines = &airpe_io_routines;
+ airpe_endpoint_interface->state_handler = &airpe_state_handlers;
+
+ airpe_register_api( &*module_interface );
+ airpe_register_apps( &*module_interface );
+
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_airpe_shutdown)
+{
+ switch_memory_pool_t *pool;
+ airpe_interface_t *airpe;
+ switch_hash_index_t *hi;
+ void *val;
+
+ pool = airpe_module_pool;
+
+ for (hi = switch_hash_first(NULL, globals.interfaces_hash); hi; hi = switch_hash_next(hi)) {
+ switch_hash_this(hi, NULL, NULL, &val);
+ airpe = ( airpe_interface_t *) val;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Shutting down airpe client: %s\n", airpe->name);
+ airpe->running = 0;
+ /* Wake up the socket */
+ airpe_cmd_write(airpe, "PING");
+ airpe_stop_client(airpe);
+ /*
+ we won't delete the hash element. we're going to destroy the whole pool
+ switch_core_hash_delete(globals.interfaces_hash, airpe->name);
+ */
+ }
+ switch_yield(500000);
+
+ /* TODO... should we check that all interfaces has been switched off ? */
+
+ switch_core_hash_destroy(&globals.interfaces_hash);
+ switch_core_destroy_memory_pool(&pool);
+ return SWITCH_STATUS_UNLOAD;
+}
+
+/* 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:
+ */
Added: freeswitch/branches/ctrix/mod_airpe/mod_airpe.h
==============================================================================
--- (empty file)
+++ freeswitch/branches/ctrix/mod_airpe/mod_airpe.h Mon Jan 12 17:24:44 2009
@@ -0,0 +1,235 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct at yahoo.com>
+ *
+ * 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 mod_airpe.
+ *
+ * The Initial Developer of the Original Code is
+ * Massimo Cetra <devel at navynet.it>
+ *
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Thanks to gmaruzz for his work on skypiax (both * and freeswitch).
+ * Some of his code inspired this module
+ *
+ */
+
+#include <switch.h>
+#include <switch_version.h>
+
+#define MODNAME "airpe"
+
+#define SKYPE_MSG_LEN 1024
+
+#define CODEC_SAMPLE_RATE 16000
+#define CODEC_INTERVAL_MS 20
+#define FRAMES_PER_SECOND 1000 / CODEC_INTERVAL_MS
+#define SAMPLES_PER_FRAME CODEC_SAMPLE_RATE / FRAMES_PER_SECOND
+
+#define ADEBUG(...) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, __VA_ARGS__ );
+
+typedef enum {
+ CONN_STATUS_UNKNOWN,
+ CONN_STATUS_OFFLINE,
+ CONN_STATUS_CONNECTING,
+ CONN_STATUS_PAUSING,
+ CONN_STATUS_ONLINE,
+} CONN_STATUS;
+
+typedef enum {
+ USER_STATUS_UNKNOWN,
+ USER_STATUS_ONLINE,
+ USER_STATUS_OFFLINE,
+ USER_STATUS_SKYPEME,
+ USER_STATUS_AWAY,
+ USER_STATUS_NA,
+ USER_STATUS_DND,
+ USER_STATUS_INVISIBLE,
+ USER_STATUS_LOGGEDOUT
+} USER_STATUS;
+
+typedef enum {
+ CALL_STATUS_UNKNOWN,
+ CALL_STATUS_UNPLACED,
+ CALL_STATUS_ROUTING,
+ CALL_STATUS_EARLYMEDIA,
+ CALL_STATUS_FAILED,
+ CALL_STATUS_RINGING,
+ CALL_STATUS_INPROGRESS,
+ CALL_STATUS_ONHOLD,
+ CALL_STATUS_LOCALHOLD,
+ CALL_STATUS_REMOTEHOLD,
+ CALL_STATUS_FINISHED,
+ CALL_STATUS_MISSED,
+ CALL_STATUS_REFUSED,
+ CALL_STATUS_BUSY,
+ CALL_STATUS_CANCELLED,
+ CALL_STATUS_TRANSFERRING, /* Protocol 7 */
+ CALL_STATUS_TRANSFERRED, /* Protocol 7 */
+
+ CALL_STATUS_VM_BUFFERING_GREETING,
+ CALL_STATUS_VM_PLAYING_GREETING,
+ CALL_STATUS_VM_RECORDING,
+ CALL_STATUS_VM_UPLOADING,
+ CALL_STATUS_VM_SENT,
+ CALL_STATUS_VM_CANCELLED ,
+ CALL_STATUS_VM_FAILED,
+ CALL_STATUS_WAITING_REDIAL_COMMAND,
+ CALL_STATUS_REDIAL_PENDING, /* Protocol 8 */
+
+} CALL_STATUS;
+
+typedef enum {
+ FAILURE_CODE_MISC = 1,
+ FAILURE_CODE_BAD_DESTINATION_NUM = 2,
+ FAILURE_CODE_USER_OFFLINE = 3,
+ FAILURE_CODE_NO_PROXY_FOUND = 4,
+ FAILURE_CODE_SESSION_TERMINATED = 5,
+ FAILURE_CODE_NO_CODEC_FOUND = 6,
+ FAILURE_CODE_LOCAL_SOUND_ERR = 7,
+ FAILURE_CODE_REMOTE_SOUND_ERR = 8,
+ FAILURE_CODE_CALL_BLOCKED = 9,
+ FAILURE_CODE_RECIPIENT_NOT_FRIEND = 10,
+ FAILURE_CODE_CALL_UNAUTHORIZED = 11,
+ FAILURE_CODE_SOUND_REC_ERR = 12,
+} FAILURE_CODES;
+
+
+typedef enum {
+ TFLAG_INBOUND = (1 << 1),
+ TFLAG_OUTBOUND = (1 << 2),
+/*
+ TFLAG_IO = (1 << 0),
+ TFLAG_DTMF = (1 << 3),
+ TFLAG_VOICE = (1 << 4),
+ TFLAG_HANGUP = (1 << 5),
+ TFLAG_LINEAR = (1 << 6),
+ TFLAG_CODEC = (1 << 7),
+ TFLAG_BREAK = (1 << 8),
+ TFLAG_ANSWER = (1 << 9)
+*/
+} TFLAGS;
+
+typedef struct skype_window_handler_s skype_window_handler_t;
+
+typedef struct airpe_interface_s airpe_interface_t;
+typedef struct private_object_s private_object_t;
+
+struct airpe_interface_s {
+ char *name;
+ int debug;
+ char *dialplan;
+ char *context;
+ char *destination;
+ char *X11_display;
+ char *skype_user;
+ char *skype_password;
+
+ int audio_in_port;
+ int audio_out_port;
+ switch_socket_t *audio_in_socket;
+ switch_socket_t *audio_out_socket;
+ switch_socket_t *audio_in_active_socket;
+ switch_socket_t *audio_out_active_socket;
+
+ switch_thread_t *airpe_thread_skype;
+ skype_window_handler_t *skype_window;
+
+ int protocol;
+ USER_STATUS user_status;
+ CALL_STATUS call_status;
+ CONN_STATUS conn_status;
+
+ char *skype_version;
+ char *mood_text;
+ int active_call_id;
+ int last_fail_reason;
+ int running;
+ private_object_t *tech_pvt;
+ char *partner_displayname;
+ char *partner_handle;
+};
+
+struct private_object_s {
+ unsigned int flags;
+ switch_mutex_t *flag_mutex;
+ switch_mutex_t *mutex;
+
+ airpe_interface_t *airpe;
+ switch_core_session_t *session;
+ switch_caller_profile_t *caller_profile;
+ char *destination;
+
+ switch_codec_t read_codec;
+ switch_codec_t write_codec;
+ switch_frame_t read_frame;
+ uint8_t databuf[SWITCH_RECOMMENDED_BUFFER_SIZE];
+};
+
+
+/* CORE */
+airpe_interface_t *airpe_find_interface( const char *name);
+switch_core_session_t *airpe_request_session( switch_memory_pool_t **pool );
+switch_status_t airpe_tech_init( private_object_t * tech_pvt, switch_core_session_t * session );
+
+/* API */
+switch_status_t airpe_register_api( switch_loadable_module_interface_t **module_interface );
+
+/* APPS */
+switch_status_t airpe_register_apps( switch_loadable_module_interface_t **module_interface );
+
+/* INTERFACE - COMMON FUNCTIONS */
+const char *skype_user_status_string(USER_STATUS st);
+USER_STATUS skype_user_status(const char *str);
+const char *skype_conn_status_string(CONN_STATUS st);
+CONN_STATUS skype_conn_status(const char *str);
+
+switch_status_t airpe_set_version(airpe_interface_t *airpe, char *string);
+switch_status_t airpe_set_mood_text(airpe_interface_t *airpe, char *string);
+switch_status_t airpe_set_partner_displayname(airpe_interface_t *airpe, char *string);
+switch_status_t airpe_set_partner_handle(airpe_interface_t *airpe, char *string);
+
+switch_status_t airpe_hangup( private_object_t *pvt );
+switch_status_t airpe_audio_read( private_object_t *pvt );
+switch_status_t airpe_audio_write( private_object_t *pvt, switch_frame_t *frame );
+
+switch_status_t airpe_cmd_write(airpe_interface_t *p, char *msg);
+switch_status_t airpe_originate(airpe_interface_t *p, char *dest);
+switch_status_t airpe_explicit_hangup(airpe_interface_t *airpe);
+switch_status_t airpe_manage_skype_msg( airpe_interface_t *airpe, const char *msg );
+
+switch_status_t airpe_on_connect_messages( airpe_interface_t *airpe, int protocol );
+
+/* INTERFACE - PLATFORM DEPENDANT FUNCTIONS */
+switch_status_t airpe_skype_watchdog_reset(skype_window_handler_t *window);
+switch_status_t airpe_skype_watchdog_increment(skype_window_handler_t *window);
+skype_window_handler_t *skype_window_alloc( switch_memory_pool_t *pool);
+switch_status_t airpe_skype_avalaible(skype_window_handler_t *window);
+switch_status_t skype_restart( skype_window_handler_t *airpe, const char *params );
+switch_status_t airpe_skype_send_message(skype_window_handler_t *window, const char *message_P);
+void *SWITCH_THREAD_FUNC airpe_skype_thread(switch_thread_t * thread, void *obj);
+
+/* 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:
+ */
More information about the Freeswitch-svn
mailing list