From 3d089f0075ef70bf9206334c3d4c5bb27fc804c5 Mon Sep 17 00:00:00 2001 From: Mathieu Parent Date: Thu, 8 Apr 2010 20:49:56 +0200 Subject: [PATCH 01/17] FSMOD-35: mod_tts_commandline core dump, temp file problem. flush can be called several times --- .../mod_tts_commandline/mod_tts_commandline.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/mod/asr_tts/mod_tts_commandline/mod_tts_commandline.c b/src/mod/asr_tts/mod_tts_commandline/mod_tts_commandline.c index f86b9d5156..6b261f1d96 100644 --- a/src/mod/asr_tts/mod_tts_commandline/mod_tts_commandline.c +++ b/src/mod/asr_tts/mod_tts_commandline/mod_tts_commandline.c @@ -186,10 +186,14 @@ static void tts_commandline_speech_flush_tts(switch_speech_handle_t *sh) { tts_commandline_t *info = (tts_commandline_t *) sh->private_info; assert(info != NULL); - - switch_core_file_close(info->fh); - if (unlink(info->file) != 0) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Sound file [%s] delete failed\n", info->file); + + if (info->fh != NULL && info->fh->file_interface != NULL) { + switch_core_file_close(info->fh); + } + if (switch_file_exists(info->file, NULL) == SWITCH_STATUS_SUCCESS) { + if (unlink(info->file) != 0) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Sound file [%s] delete failed\n", info->file); + } } } From 5c668de704414a7bc98e874ec657d1abaf533726 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Thu, 8 Apr 2010 19:40:53 +0000 Subject: [PATCH 02/17] Added a script to help committers configure git properly. --- scripts/setup-git.sh | 76 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100755 scripts/setup-git.sh diff --git a/scripts/setup-git.sh b/scripts/setup-git.sh new file mode 100755 index 0000000000..9781417f98 --- /dev/null +++ b/scripts/setup-git.sh @@ -0,0 +1,76 @@ +#!/bin/bash +##### -*- mode:shell-script; indent-tabs-mode:nil; sh-basic-offset:2 -*- +##### setup git properly for FreeSWITCH + +if [ ! -d .git ]; then + echo "error: must be run from within the top level of a FreeSWITCH git tree." 1>&2 + exit 1; +fi + +err () { + echo "error: $1" 1>&2 + exit 1 +} + +if ! git config user.name >/dev/null 2>&1; then + name=$(git config user.name) + [ -z "$name" ] \ + && [ -n "$NAME" ] && name="$NAME" || name="" + echo -n "What is your name? [$name]: " + read name_ + [ -n "$name_" ] && name="$name_" + [ -z "$name" ] && err "Your name is required." + git config --global user.name "$name" +fi + +if ! git config user.email >/dev/null 2>&1; then + email=$(git config user.email) + [ -z "$email" ] \ + && [ -n "$EMAIL" ] && email="$EMAIL" || email="" + echo -n "What is your email? [$email]: " + read email_ + [ -n "$email_" ] && email="$email_" + [ -z "$email" ] && err "Your email is required." + git config --global user.email "$email" +fi + +git config branch.master.rebase true + +cat 1>&2 <&2 <&2 <&2 < Date: Thu, 8 Apr 2010 14:43:44 -0500 Subject: [PATCH 03/17] Next time ask nicer bitch(drk) and don't talk to me like that please. --- .../languages/mod_managed/freeswitch_wrap.cxx | 23 +++++++++++++++---- src/mod/languages/mod_managed/managed/swig.cs | 14 ++++++++--- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/src/mod/languages/mod_managed/freeswitch_wrap.cxx b/src/mod/languages/mod_managed/freeswitch_wrap.cxx index 737940ec6c..49fb617ef6 100644 --- a/src/mod/languages/mod_managed/freeswitch_wrap.cxx +++ b/src/mod/languages/mod_managed/freeswitch_wrap.cxx @@ -21403,21 +21403,36 @@ SWIGEXPORT char * SWIGSTDCALL CSharp_switch_channel_get_variable_partner(void * } -SWIGEXPORT int SWIGSTDCALL CSharp_switch_channel_export_variable_var_check(void * jarg1, char * jarg2, char * jarg3, int jarg4, int jarg5) { +SWIGEXPORT int SWIGSTDCALL CSharp_switch_channel_export_variable_var_check(void * jarg1, char * jarg2, char * jarg3, int jarg4) { int jresult ; switch_channel_t *arg1 = (switch_channel_t *) 0 ; char *arg2 = (char *) 0 ; char *arg3 = (char *) 0 ; switch_bool_t arg4 ; - switch_bool_t arg5 ; switch_status_t result; arg1 = (switch_channel_t *)jarg1; arg2 = (char *)jarg2; arg3 = (char *)jarg3; arg4 = (switch_bool_t)jarg4; - arg5 = (switch_bool_t)jarg5; - result = (switch_status_t)switch_channel_export_variable_var_check(arg1,(char const *)arg2,(char const *)arg3,arg4,arg5); + result = (switch_status_t)switch_channel_export_variable_var_check(arg1,(char const *)arg2,(char const *)arg3,arg4); + jresult = result; + return jresult; +} + + +SWIGEXPORT int SWIGSTDCALL CSharp_switch_channel_export_variable_printf(void * jarg1, char * jarg2, char * jarg3) { + int jresult ; + switch_channel_t *arg1 = (switch_channel_t *) 0 ; + char *arg2 = (char *) 0 ; + char *arg3 = (char *) 0 ; + void *arg4 = 0 ; + switch_status_t result; + + arg1 = (switch_channel_t *)jarg1; + arg2 = (char *)jarg2; + arg3 = (char *)jarg3; + result = (switch_status_t)switch_channel_export_variable_printf(arg1,(char const *)arg2,(char const *)arg3,arg4); jresult = result; return jresult; } diff --git a/src/mod/languages/mod_managed/managed/swig.cs b/src/mod/languages/mod_managed/managed/swig.cs index 13756d32a6..1821bbb088 100644 --- a/src/mod/languages/mod_managed/managed/swig.cs +++ b/src/mod/languages/mod_managed/managed/swig.cs @@ -2904,8 +2904,13 @@ public class freeswitch { return ret; } - public static switch_status_t switch_channel_export_variable_var_check(SWIGTYPE_p_switch_channel channel, string varname, string value, switch_bool_t var_check, switch_bool_t nolocal) { - switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_channel_export_variable_var_check(SWIGTYPE_p_switch_channel.getCPtr(channel), varname, value, (int)var_check, (int)nolocal); + public static switch_status_t switch_channel_export_variable_var_check(SWIGTYPE_p_switch_channel channel, string varname, string value, switch_bool_t var_check) { + switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_channel_export_variable_var_check(SWIGTYPE_p_switch_channel.getCPtr(channel), varname, value, (int)var_check); + return ret; + } + + public static switch_status_t switch_channel_export_variable_printf(SWIGTYPE_p_switch_channel channel, string varname, string fmt) { + switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_channel_export_variable_printf(SWIGTYPE_p_switch_channel.getCPtr(channel), varname, fmt); return ret; } @@ -10215,7 +10220,10 @@ class freeswitchPINVOKE { public static extern string switch_channel_get_variable_partner(HandleRef jarg1, string jarg2); [DllImport("mod_managed", EntryPoint="CSharp_switch_channel_export_variable_var_check")] - public static extern int switch_channel_export_variable_var_check(HandleRef jarg1, string jarg2, string jarg3, int jarg4, int jarg5); + public static extern int switch_channel_export_variable_var_check(HandleRef jarg1, string jarg2, string jarg3, int jarg4); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_channel_export_variable_printf")] + public static extern int switch_channel_export_variable_printf(HandleRef jarg1, string jarg2, string jarg3); [DllImport("mod_managed", EntryPoint="CSharp_switch_channel_get_variable_dup")] public static extern string switch_channel_get_variable_dup(HandleRef jarg1, string jarg2, int jarg3); From 3b83541f7977f4b3e760adb7947418e30ec39454 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Thu, 8 Apr 2010 19:49:24 +0000 Subject: [PATCH 04/17] Clarify the syntax for git merge. --- scripts/setup-git.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/setup-git.sh b/scripts/setup-git.sh index 9781417f98..1a5e36d339 100755 --- a/scripts/setup-git.sh +++ b/scripts/setup-git.sh @@ -49,7 +49,7 @@ cat 1>&2 < See 'man git-config' for more information. EOF From 58595bdaec90efea3a0bb636a668910f1dd3c63f Mon Sep 17 00:00:00 2001 From: Mathieu Parent Date: Thu, 8 Apr 2010 22:38:24 +0200 Subject: [PATCH 05/17] Skinny: solve deadlocks and more - Solve deadlock: + associate all skinny_profile_find_session with the corresponding switch_core_session_rwunlock + lock the newly created session in skinny_create_ingoing_session + enhance rwlocks debugging - Shared lines: + Inform shared lines on answering + Answering line has info after other shared lines --- src/mod/endpoints/mod_skinny/mod_skinny.c | 9 ++- src/mod/endpoints/mod_skinny/mod_skinny.h | 5 ++ .../endpoints/mod_skinny/skinny_protocol.c | 63 ++++++++++++------- 3 files changed, 54 insertions(+), 23 deletions(-) diff --git a/src/mod/endpoints/mod_skinny/mod_skinny.c b/src/mod/endpoints/mod_skinny/mod_skinny.c index 571223ccac..e7476b53d5 100644 --- a/src/mod/endpoints/mod_skinny/mod_skinny.c +++ b/src/mod/endpoints/mod_skinny/mod_skinny.c @@ -235,14 +235,22 @@ char * skinny_profile_find_session_uuid(skinny_profile_t *profile, listener_t *l return helper.channel_uuid; } +#ifdef SWITCH_DEBUG_RWLOCKS +switch_core_session_t * skinny_profile_perform_find_session(skinny_profile_t *profile, listener_t *listener, uint32_t *line_instance_p, uint32_t call_id, const char *file, const char *func, int line) +#else switch_core_session_t * skinny_profile_find_session(skinny_profile_t *profile, listener_t *listener, uint32_t *line_instance_p, uint32_t call_id) +#endif { char *uuid; switch_core_session_t *result = NULL; uuid = skinny_profile_find_session_uuid(profile, listener, line_instance_p, call_id); if(!zstr(uuid)) { +#ifdef SWITCH_DEBUG_RWLOCKS + result = switch_core_session_perform_locate(uuid, file, func, line); +#else result = switch_core_session_locate(uuid); +#endif if(!result) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unable to find session %s on %s:%d, line %d\n", @@ -650,7 +658,6 @@ int channel_on_hangup_callback(void *pArg, int argc, char **argv, char **columnN /* TODO: DefineTimeDate */ send_set_speaker_mode(listener, SKINNY_SPEAKER_OFF); send_set_ringer(listener, SKINNY_RING_OFF, SKINNY_RING_FOREVER, 0, call_id); - } return 0; } diff --git a/src/mod/endpoints/mod_skinny/mod_skinny.h b/src/mod/endpoints/mod_skinny/mod_skinny.h index 7bcc40b96c..3443d2f7dd 100644 --- a/src/mod/endpoints/mod_skinny/mod_skinny.h +++ b/src/mod/endpoints/mod_skinny/mod_skinny.h @@ -189,7 +189,12 @@ switch_status_t skinny_profile_dump(const skinny_profile_t *profile, switch_stre switch_status_t skinny_profile_find_listener_by_device_name(skinny_profile_t *profile, const char *device_name, listener_t **listener); switch_status_t skinny_profile_find_listener_by_device_name_and_instance(skinny_profile_t *profile, const char *device_name, uint32_t device_instance, listener_t **listener); char * skinny_profile_find_session_uuid(skinny_profile_t *profile, listener_t *listener, uint32_t *line_instance_p, uint32_t call_id); +#ifdef SWITCH_DEBUG_RWLOCKS +switch_core_session_t * skinny_profile_perform_find_session(skinny_profile_t *profile, listener_t *listener, uint32_t *line_instance_p, uint32_t call_id, const char *file, const char *func, int line); +#define skinny_profile_find_session(profile, listener, line_instance_p, call_id) skinny_profile_perform_find_session(profile, listener, line_instance_p, call_id, __FILE__, __SWITCH_FUNC__, __LINE__) +#else switch_core_session_t * skinny_profile_find_session(skinny_profile_t *profile, listener_t *listener, uint32_t *line_instance_p, uint32_t call_id); +#endif switch_status_t dump_device(skinny_profile_t *profile, const char *device_name, switch_stream_handle_t *stream); /*****************************************************************************/ diff --git a/src/mod/endpoints/mod_skinny/skinny_protocol.c b/src/mod/endpoints/mod_skinny/skinny_protocol.c index 533a922f32..ec7ba83353 100644 --- a/src/mod/endpoints/mod_skinny/skinny_protocol.c +++ b/src/mod/endpoints/mod_skinny/skinny_protocol.c @@ -446,13 +446,13 @@ switch_status_t skinny_create_ingoing_session(listener_t *listener, uint32_t *li line_instance = *line_instance_p; if((nsession = skinny_profile_find_session(listener->profile, listener, line_instance_p, 0))) { - switch_core_session_rwunlock(nsession); if(skinny_line_get_state(listener, *line_instance_p, 0) == SKINNY_OFF_HOOK) { /* Reuse existing session */ *session = nsession; return SWITCH_STATUS_SUCCESS; } skinny_session_hold_line(nsession, listener, *line_instance_p); + switch_core_session_rwunlock(nsession); } *line_instance_p = line_instance; if(*line_instance_p == 0) { @@ -494,7 +494,11 @@ switch_status_t skinny_create_ingoing_session(listener_t *listener, uint32_t *li "Error Creating Session thread\n"); goto error; } - + if (switch_core_session_read_lock(nsession) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(nsession), SWITCH_LOG_CRIT, + "Error Locking Session\n"); + goto error; + } if (!(tech_pvt->caller_profile = switch_caller_profile_new(switch_core_session_get_pool(nsession), NULL, listener->profile->dialplan, button->shortname, button->name, @@ -579,8 +583,6 @@ switch_status_t skinny_session_process_dest(switch_core_session_t *session, list skinny_session_start_media(session, listener, line_instance); } - switch_core_session_rwunlock(session); - return SWITCH_STATUS_SUCCESS; } @@ -603,8 +605,6 @@ switch_status_t skinny_session_ring_out(switch_core_session_t *session, listener line_instance, tech_pvt->call_id); skinny_send_call_info(session, listener, line_instance); - switch_core_session_rwunlock(session); - return SWITCH_STATUS_SUCCESS; } @@ -643,16 +643,14 @@ int skinny_session_answer_callback(void *pArg, int argc, char **argv, char **col if(!strcmp(device_name, helper->listener->device_name) && (device_instance == helper->listener->device_instance) && (line_instance == helper->line_instance)) {/* the answering line */ - - - send_set_ringer(listener, SKINNY_RING_OFF, SKINNY_RING_FOREVER, 0, helper->tech_pvt->call_id); - send_set_speaker_mode(listener, SKINNY_SPEAKER_ON); + /* nothing */ + } else { + send_define_current_time_date(listener); send_set_lamp(listener, SKINNY_BUTTON_LINE, line_instance, SKINNY_LAMP_ON); - skinny_line_set_state(listener, line_instance, helper->tech_pvt->call_id, SKINNY_OFF_HOOK); - /* send_select_soft_keys(listener, line_instance, helper->tech_pvt->call_id, SKINNY_KEY_SET_OFF_HOOK, 0xffff); */ - /* display_prompt_status(listener, 0, "\200\000", - line_instance, tech_pvt->call_id); */ - send_activate_call_plane(listener, line_instance); + skinny_line_set_state(listener, line_instance, helper->tech_pvt->call_id, SKINNY_IN_USE_REMOTELY); + send_select_soft_keys(listener, line_instance, helper->tech_pvt->call_id, 10, 0x0002); + send_display_prompt_status(listener, 0, "\200\037", line_instance, helper->tech_pvt->call_id); + send_set_ringer(listener, SKINNY_RING_OFF, SKINNY_RING_FOREVER, 0, helper->tech_pvt->call_id); } } return 0; @@ -671,6 +669,12 @@ switch_status_t skinny_session_answer(switch_core_session_t *session, listener_t channel = switch_core_session_get_channel(session); tech_pvt = switch_core_session_get_private(session); + send_set_ringer(listener, SKINNY_RING_OFF, SKINNY_RING_FOREVER, 0, tech_pvt->call_id); + send_set_speaker_mode(listener, SKINNY_SPEAKER_ON); + send_set_lamp(listener, SKINNY_BUTTON_LINE, line_instance, SKINNY_LAMP_ON); + skinny_line_set_state(listener, line_instance, tech_pvt->call_id, SKINNY_OFF_HOOK); + send_activate_call_plane(listener, line_instance); + helper.tech_pvt = tech_pvt; helper.listener = listener; helper.line_instance = line_instance; @@ -679,8 +683,6 @@ switch_status_t skinny_session_answer(switch_core_session_t *session, listener_t skinny_session_start_media(session, listener, line_instance); - switch_core_session_rwunlock(session); - return SWITCH_STATUS_SUCCESS; } @@ -717,8 +719,6 @@ switch_status_t skinny_session_start_media(switch_core_session_t *session, liste tech_pvt->call_id); skinny_send_call_info(session, listener, line_instance); - switch_core_session_rwunlock(session); - return SWITCH_STATUS_SUCCESS; } @@ -739,8 +739,6 @@ switch_status_t skinny_session_hold_line(switch_core_session_t *session, listene switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING); - switch_core_session_rwunlock(session); - return SWITCH_STATUS_SUCCESS; } @@ -2002,6 +2000,11 @@ switch_status_t skinny_handle_off_hook_message(listener_t *listener, skinny_mess skinny_session_process_dest(session, listener, line_instance, NULL, '\0', 0); } + + if(session) { + switch_core_session_rwunlock(session); + } + return SWITCH_STATUS_SUCCESS; } @@ -2037,6 +2040,11 @@ switch_status_t skinny_handle_stimulus_message(listener_t *listener, skinny_mess default: switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unknown Stimulus Type Received [%d]\n", request->data.stimulus.instance_type); } + + if(session) { + switch_core_session_rwunlock(session); + } + return SWITCH_STATUS_SUCCESS; } @@ -2118,9 +2126,13 @@ switch_status_t skinny_handle_open_receive_channel_ack_message(listener_t *liste } switch_channel_mark_answered(channel); - switch_core_session_rwunlock(session); } end: + + if(session) { + switch_core_session_rwunlock(session); + } + return status; } @@ -2174,6 +2186,10 @@ switch_status_t skinny_handle_keypad_button_message(listener_t *listener, skinny switch_core_session_rwunlock(session); } + if(session) { + switch_core_session_rwunlock(session); + } + return SWITCH_STATUS_SUCCESS; } @@ -2195,9 +2211,12 @@ switch_status_t skinny_handle_on_hook_message(listener_t *listener, skinny_messa channel = switch_core_session_get_channel(session); switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING); + } + if(session) { switch_core_session_rwunlock(session); } + return status; } From ca8ec66ed36f67566017df054fdf24a2d57c00c3 Mon Sep 17 00:00:00 2001 From: Mathieu Parent Date: Thu, 8 Apr 2010 22:48:36 +0200 Subject: [PATCH 06/17] Skinny: avoid crash on shutdown Because of uninstancied listener --- src/mod/endpoints/mod_skinny/mod_skinny.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/mod/endpoints/mod_skinny/mod_skinny.c b/src/mod/endpoints/mod_skinny/mod_skinny.c index e7476b53d5..56f2b5ed0e 100644 --- a/src/mod/endpoints/mod_skinny/mod_skinny.c +++ b/src/mod/endpoints/mod_skinny/mod_skinny.c @@ -1236,6 +1236,9 @@ static void *SWITCH_THREAD_FUNC listener_run(switch_thread_t *thread, void *obj) switch_clear_flag_locked(listener, LFLAG_RUNNING); break; } + if (!listener_is_ready(listener)) { + break; + } if (!request) { continue; From d3d50e6eb38b6d02e31249c2b5ca96399f65b51f Mon Sep 17 00:00:00 2001 From: Mathieu Parent Date: Thu, 8 Apr 2010 22:59:31 +0200 Subject: [PATCH 07/17] Skinny: release XML config Fixes: reloadxml blocked --- src/mod/endpoints/mod_skinny/skinny_protocol.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/mod/endpoints/mod_skinny/skinny_protocol.c b/src/mod/endpoints/mod_skinny/skinny_protocol.c index ec7ba83353..2c96022bee 100644 --- a/src/mod/endpoints/mod_skinny/skinny_protocol.c +++ b/src/mod/endpoints/mod_skinny/skinny_protocol.c @@ -1478,6 +1478,9 @@ switch_status_t skinny_handle_register(listener_t *listener, skinny_message_t *r } } } + if (xroot) { + switch_xml_free(xroot); + } status = SWITCH_STATUS_SUCCESS; From c15e163b889df616f8b1c8542f321029df1e03c3 Mon Sep 17 00:00:00 2001 From: Mathieu Parent Date: Thu, 8 Apr 2010 23:16:44 +0200 Subject: [PATCH 08/17] Skinny: avoid non-set profile name --- src/mod/endpoints/mod_skinny/mod_skinny.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_skinny/mod_skinny.c b/src/mod/endpoints/mod_skinny/mod_skinny.c index 56f2b5ed0e..a6adf86c4a 100644 --- a/src/mod/endpoints/mod_skinny/mod_skinny.c +++ b/src/mod/endpoints/mod_skinny/mod_skinny.c @@ -1483,7 +1483,7 @@ static switch_status_t load_skinny_config(void) } profile = switch_core_alloc(profile_pool, sizeof(skinny_profile_t)); profile->pool = profile_pool; - profile->name = profile_name; + profile->name = switch_core_strdup(profile->pool, profile_name); switch_mutex_init(&profile->listener_mutex, SWITCH_MUTEX_NESTED, profile->pool); switch_mutex_init(&profile->sql_mutex, SWITCH_MUTEX_NESTED, profile->pool); switch_mutex_init(&profile->sock_mutex, SWITCH_MUTEX_NESTED, profile->pool); From bec8d75ef6d1195e36c99069205736f33458e476 Mon Sep 17 00:00:00 2001 From: Mathieu Parent Date: Thu, 8 Apr 2010 23:17:13 +0200 Subject: [PATCH 09/17] Skinny: don't double unlock on keypad double unlock is same as locking :P --- src/mod/endpoints/mod_skinny/skinny_protocol.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mod/endpoints/mod_skinny/skinny_protocol.c b/src/mod/endpoints/mod_skinny/skinny_protocol.c index 2c96022bee..8a96f7e629 100644 --- a/src/mod/endpoints/mod_skinny/skinny_protocol.c +++ b/src/mod/endpoints/mod_skinny/skinny_protocol.c @@ -2186,7 +2186,6 @@ switch_status_t skinny_handle_keypad_button_message(listener_t *listener, skinny switch_channel_queue_dtmf(channel, &dtmf); } } - switch_core_session_rwunlock(session); } if(session) { From 2666a40a122e074ddc3384311fab2d6638a6cadb Mon Sep 17 00:00:00 2001 From: Joao Mesquita Date: Thu, 8 Apr 2010 23:15:29 -0300 Subject: [PATCH 10/17] Lets test preprocessors --- fscomm/mainwindow.cpp | 16 + fscomm/mainwindow.h | 1 + fscomm/preferences/prefdialog.cpp | 1 + fscomm/preferences/prefdialog.h | 3 + fscomm/preferences/prefdialog.ui | 2098 ++++++++++++++------------ fscomm/preferences/prefportaudio.cpp | 22 + fscomm/preferences/prefportaudio.h | 5 + 7 files changed, 1173 insertions(+), 973 deletions(-) diff --git a/fscomm/mainwindow.cpp b/fscomm/mainwindow.cpp index b4720f5034..0cfb076f3e 100644 --- a/fscomm/mainwindow.cpp +++ b/fscomm/mainwindow.cpp @@ -179,10 +179,26 @@ void MainWindow::debugConsoleTriggered() } +void MainWindow::applyPreprocessors(QStringList cmds) +{ + if (g_FSHost.getCurrentActiveCall().isNull()) return; + QString uuid = g_FSHost.getCurrentActiveCall().data()->getUuid(); + foreach(QString cmd, cmds) + { + switch_stream_handle_t stream = { 0 }; + SWITCH_STANDARD_STREAM(stream); + switch_api_execute("uuid_preprocess", QString("%1 %2").arg(uuid, cmd).toAscii().data(), NULL, &stream); + switch_safe_free(stream.data); + } +} + void MainWindow::prefTriggered() { if (!preferences) + { preferences = new PrefDialog(); + connect(preferences, SIGNAL(preprocessorsApplied(QStringList)), this, SLOT(applyPreprocessors(QStringList))); + } preferences->raise(); preferences->show(); diff --git a/fscomm/mainwindow.h b/fscomm/mainwindow.h index e7348c13d6..3b87da18ed 100644 --- a/fscomm/mainwindow.h +++ b/fscomm/mainwindow.h @@ -85,6 +85,7 @@ private slots: void updateCallTimers(); void debugConsoleTriggered(); void debugEventsTriggered(); + void applyPreprocessors(QStringList); private: Ui::MainWindow *ui; diff --git a/fscomm/preferences/prefdialog.cpp b/fscomm/preferences/prefdialog.cpp index c615411591..233de4eb1b 100644 --- a/fscomm/preferences/prefdialog.cpp +++ b/fscomm/preferences/prefdialog.cpp @@ -15,6 +15,7 @@ PrefDialog::PrefDialog(QWidget *parent) : _pref_accounts = new PrefAccounts(ui); _mod_portaudio = new PrefPortaudio(ui, this); + connect(_mod_portaudio, SIGNAL(preprocessorsApplied(QStringList)), this, SIGNAL(preprocessorsApplied(QStringList))); _mod_sofia = new PrefSofia(ui, this); readConfig(); } diff --git a/fscomm/preferences/prefdialog.h b/fscomm/preferences/prefdialog.h index 7c9907f5c2..2704a501a8 100644 --- a/fscomm/preferences/prefdialog.h +++ b/fscomm/preferences/prefdialog.h @@ -26,6 +26,9 @@ protected: private slots: void writeConfig(); +signals: + void preprocessorsApplied(QStringList); + private: void readConfig(); QSettings *_settings; diff --git a/fscomm/preferences/prefdialog.ui b/fscomm/preferences/prefdialog.ui index 1192631e70..1aaef60118 100644 --- a/fscomm/preferences/prefdialog.ui +++ b/fscomm/preferences/prefdialog.ui @@ -6,1006 +6,1158 @@ 0 0 - 839 - 613 + 803 + 667 Preferences - - - - - - 120 - 0 - - - - - 120 - 16777215 - - - - false - - - QAbstractItemView::NoDragDrop - - - - 96 - 84 - - - - QListView::Static - - - QListView::LeftToRight - - - true - - - 12 - - - QListView::IconMode - + + + - - General - - - - :/images/pref_general.jpg:/images/pref_general.jpg - - - - - Accounts - - - - :/images/pref_accounts.jpg:/images/pref_accounts.jpg - - - - - Sofia - - - - :/images/pref_sip.png:/images/pref_sip.png - - - - - PortAudio - - - - :/images/pref_audio.gif:/images/pref_audio.gif - - - - - - - - 0 - - - + + + + 120 + 0 + + + + + 120 + 16777215 + + + + false + + + QAbstractItemView::NoDragDrop + + + + 96 + 84 + + + + QListView::Static + + + QListView::LeftToRight + + + true + + + 12 + + + QListView::IconMode + - - - User Information - - - - - - CallerID Name: - - - - - - - - - - CallerID Number: - - - - - - - - - - - - - - - - - QAbstractItemView::NoEditTriggers - - - QAbstractItemView::SelectRows - - - - Name - - - - - Username - - - + + General + + + + :/images/pref_general.jpg:/images/pref_general.jpg + - + + Accounts + + + + :/images/pref_accounts.jpg:/images/pref_accounts.jpg + + + + + Sofia + + + + :/images/pref_sip.png:/images/pref_sip.png + + + + + Audio + + + + :/images/pref_audio.gif:/images/pref_audio.gif + + + + + + + + 0 + + + - - - Add + + + User Information + + + + + CallerID Name: + + + + + + + + + + CallerID Number: + + + + + + + - - - - Remove - - - - - - - true - - - Edit - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - - 0 - - - - General - - - - - - Global - - - - QFormLayout::AllNonFixedFieldsGrow - - - - - log-level - - - - - - - - - - auto-restart - - - - - - - - true - - - - - false - - - - - - - - debug-presence - - - - - - - - - - rewrite-multicasted-fs-path - - - - - - - - false - - - - - true - - - - - - - - - - - - 0 - 0 - - - - Profile - - - - - - user-agent-string - - - - - - - FreeSWITCH/FSComm - - - - - - - hold-music - - - - - - - localstream://moh - - - - - - - context - - - - - - - public - - - - - - - dialplan - - - - - - - XML - - - - - - - - - - - Network - - - - - - Softphone Profile - - - - QFormLayout::AllNonFixedFieldsGrow - - - - - sip-port - - - - - - - 1 - - - 65535 - - - 12345 - - - - - - - use-rtp-timer - - - - - - - - true - - - - - false - - - - - - - - rtp-ip - - - - - - - auto - - - - - - - sip-ip - - - - - - - auto - - - - - - - apply-nat-acl - - - - - - - rfc1918 - - - - - - - ext-rtp-ip - - - - - - - stun:stun.freeswitch.org - - - - - - - ext-sip-ip - - - - - - - stun:stun.freeswitch.org - - - - - - - - - - - Codecs - - - - QFormLayout::AllNonFixedFieldsGrow + + + + + + + QAbstractItemView::NoEditTriggers - - - - inbound-codec-negotiation - - - - - - - - generous - - - - - greedy - - - - - - - - Codecs - - - - - - - - - - - Advanced - - + + QAbstractItemView::SelectRows + + + + Name + + + + + Username + + + + + + - - - Profile + + + Add - - - - - rfc2833-pt - - - - - - - 101 - - - - - - - debug - - - - - - - - - - sip-trace - - - - - - - - false - - - - - true - - - - - - - - dtmf-duration - - - - - - - 1000 - - - 100 - - - - - - - rtp-timer-name - - - - - - - soft - - - - - - - manage-presence - - - - - - - - false - - - - - true - - - - - - - - max-proceeding - - - - - - - 3 - - - - - - - nonce-ttl - - - - - - - 60 - - - - - - - rtp-timeout-sec - - - - - - - 1000 - - - 300 - - - - - - - rtp-hold-timeout-sec - - - - - - - 5000 - - - 1800 - - - - - - - auth-calls - - - - - - - - false - - - - - true - - - - - - - - auth-all-packets - - - - - - - - false - - - - - true - - - - - - - - disable-register - - - - - - - - true - - - - - false - - - - - - - - challenge-realm - - - - - - - - auto_from - - - - - auto_to - - - - - + + + + Remove + + + + + + + true + + + Edit + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + - - - - - - - - - - - - 0 - 0 - - - - Devices - - - - - - indev - + + + + + + + + + 0 + + + + General + + + + + + Global + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + log-level + + + + + + + + + + auto-restart + + + + + + + + true + + + + + false + + + + + + + + debug-presence + + + + + + + + + + rewrite-multicasted-fs-path + + + + + + + + false + + + + + true + + + + + + + + + + + + 0 + 0 + + + + Profile + + + + + + user-agent-string + + + + + + + FreeSWITCH/FSComm + + + + + + + hold-music + + + + + + + localstream://moh + + + + + + + context + + + + + + + public + + + + + + + dialplan + + + + + + + XML + + + + + + + - - - - - - - - outdev - + + + Network + + + + + + Softphone Profile + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + sip-port + + + + + + + 1 + + + 65535 + + + 12345 + + + + + + + use-rtp-timer + + + + + + + + true + + + + + false + + + + + + + + rtp-ip + + + + + + + auto + + + + + + + sip-ip + + + + + + + auto + + + + + + + apply-nat-acl + + + + + + + rfc1918 + + + + + + + ext-rtp-ip + + + + + + + stun:stun.freeswitch.org + + + + + + + ext-sip-ip + + + + + + + stun:stun.freeswitch.org + + + + + + + - - - - - - - - - - false - - - - 86 - 27 - - - - Test - - - - - - - - - rindgev - + + + Codecs + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + inbound-codec-negotiation + + + + + + + + generous + + + + + greedy + + + + + + + + Codecs + + + + + + + - - - - - - - - - - true - - - - 86 - 27 - - - - Test - - - - - - - - - - - Loop Test - - - - - - - Refresh DevList - - - - - - - - - Sample Rate - + + + Advanced + + + + + + Profile + + + + + + rfc2833-pt + + + + + + + 101 + + + + + + + debug + + + + + + + + + + sip-trace + + + + + + + + false + + + + + true + + + + + + + + dtmf-duration + + + + + + + 1000 + + + 100 + + + + + + + rtp-timer-name + + + + + + + soft + + + + + + + manage-presence + + + + + + + + false + + + + + true + + + + + + + + max-proceeding + + + + + + + 3 + + + + + + + nonce-ttl + + + + + + + 60 + + + + + + + rtp-timeout-sec + + + + + + + 1000 + + + 300 + + + + + + + rtp-hold-timeout-sec + + + + + + + 5000 + + + 1800 + + + + + + + auth-calls + + + + + + + + false + + + + + true + + + + + + + + auth-all-packets + + + + + + + + false + + + + + true + + + + + + + + disable-register + + + + + + + + true + + + + + false + + + + + + + + challenge-realm + + + + + + + + auto_from + + + + + auto_to + + + + + + + + - - - - - 16000 - + + + + + + + + + + 1 + + + + General + + + + + + + 0 + 0 + + + + Devices + + + + + + indev + + + + + + + + + + outdev + + + + + + + + + + + + false + + + + 86 + 27 + + + + Test + + + + + + + + + rindgev + + + + + + + + + + + + true + + + + 86 + 27 + + + + Test + + + + + + + + + + + Loop Test + + + + + + + Refresh DevList + + + + + + + + + Sample Rate + + + + + + + 16000 + + + + + + + Codec MS + + + + + + + 10 + + + + + + + + + + + 0 + 0 + + + + Files + + + + + + ring-file + + + + + + + + + tone_stream://%(2000,4000,440.0,480.0);loops=20 + + + + + + + Open + + + + + + + + + ring-interval + + + + + + + 5 + + + + + + + hold-file + + + + + + + + + true + + + + + + + Open + + + + + + + + + - - - - - Codec MS - + + + Preprocessor + + + + + + Echo canceller + + + + + + + read + + + + + + + write + + + + + + + Tail + + + + + + + + + + Echo Suppressor + + + + + + + read + + + + + + + write + + + + + + + Db + + + + + + + + + + Noise Supressor + + + + + + + read + + + + + + + write + + + + + + + Db + + + + + + + + + + read + + + + + + + write + + + + + + + + + + AGC + + + + + + + Apply + + + true + + + + - - - - - 10 - - - - - - - - - - - 0 - 0 - - - - Files - - - - - - ring-file - - - - - - - - - tone_stream://%(2000,4000,440.0,480.0);loops=20 - - - - - - - Open - - - - - - - - - ring-interval - - - - - - - 5 - - - - - - - hold-file - - - - - - - - - true - - - - - - - Open - - - - - - - - - - - + + + + + + + - + Qt::Horizontal diff --git a/fscomm/preferences/prefportaudio.cpp b/fscomm/preferences/prefportaudio.cpp index 14137956f1..8328c500b0 100644 --- a/fscomm/preferences/prefportaudio.cpp +++ b/fscomm/preferences/prefportaudio.cpp @@ -15,6 +15,28 @@ PrefPortaudio::PrefPortaudio(Ui::PrefDialog *ui, QObject *parent) : connect(_ui->PaRingdevTestBtn, SIGNAL(clicked()), this, SLOT(ringdevTest())); connect(_ui->PaLoopTestBtn, SIGNAL(clicked()), this, SLOT(loopTest())); connect(_ui->PaRefreshDevListBtn, SIGNAL(clicked()), this, SLOT(refreshDevList())); + connect(_ui->btnApplyPreprocessor, SIGNAL(toggled(bool)), this, SLOT(applyPreprocessors(bool))); +} + +void PrefPortaudio::applyPreprocessors(bool state) +{ + QStringList cmds; + if (!state) + { + cmds.append("stop"); + } + else + { + if (_ui->checkAECRead->isChecked()) cmds.append(QString("recho_cancel=%1").arg(_ui->spinAECTail->value())); + if (_ui->checkAECWrite->isChecked()) cmds.append(QString("wecho_cancel=%1").arg(_ui->spinAECTail->value())); + if (_ui->checkESRead->isChecked()) cmds.append(QString("recho_suppress=%1").arg(_ui->spinESDb->value())); + if (_ui->checkESWrite->isChecked()) cmds.append(QString("wecho_suppress=%1").arg(_ui->spinESDb->value())); + if (_ui->checkNSRead->isChecked()) cmds.append(QString("rnoise_suppress=%1").arg(_ui->spinNSDb->value())); + if (_ui->checkNSWrite->isChecked()) cmds.append(QString("wnoise_suppress=%1").arg(_ui->spinNSDb->value())); + if (_ui->checkAGCRead->isChecked()) cmds.append(QString("ragc=%1").arg(_ui->spinAGC->value())); + if (_ui->checkAGCWrite->isChecked()) cmds.append(QString("wagc=%1").arg(_ui->spinAGC->value())); + } + emit preprocessorsApplied(cmds); } void PrefPortaudio::ringdevTest() diff --git a/fscomm/preferences/prefportaudio.h b/fscomm/preferences/prefportaudio.h index 9ffd285636..d12750ab65 100644 --- a/fscomm/preferences/prefportaudio.h +++ b/fscomm/preferences/prefportaudio.h @@ -24,6 +24,11 @@ private slots: void ringdevTest(); void loopTest(); void refreshDevList(); + void applyPreprocessors(bool); + +signals: + void preprocessorsApplied(QStringList); + private: void getPaDevlist(void); QSettings *_settings; From 8ad17db191a327a0f3763cb73dcf30b84de23390 Mon Sep 17 00:00:00 2001 From: Joao Mesquita Date: Fri, 9 Apr 2010 00:40:55 -0300 Subject: [PATCH 11/17] Negative, not positive. --- fscomm/preferences/prefdialog.ui | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/fscomm/preferences/prefdialog.ui b/fscomm/preferences/prefdialog.ui index 1aaef60118..fbab506dab 100644 --- a/fscomm/preferences/prefdialog.ui +++ b/fscomm/preferences/prefdialog.ui @@ -796,7 +796,7 @@ - 1 + 0 @@ -1080,7 +1080,14 @@ - + + + -99 + + + 0 + + From adcb11f3d3424d8d8a8efc14b7928a8305757225 Mon Sep 17 00:00:00 2001 From: Mathieu Parent Date: Fri, 9 Apr 2010 11:11:40 +0200 Subject: [PATCH 12/17] Skinny: fix calls without media If party_id is 0, the phone will not properly release media --- src/mod/endpoints/mod_skinny/mod_skinny.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mod/endpoints/mod_skinny/mod_skinny.c b/src/mod/endpoints/mod_skinny/mod_skinny.c index a6adf86c4a..d086c9deb0 100644 --- a/src/mod/endpoints/mod_skinny/mod_skinny.c +++ b/src/mod/endpoints/mod_skinny/mod_skinny.c @@ -539,6 +539,7 @@ void tech_init(private_t *tech_pvt, skinny_profile_t *profile, switch_core_sessi 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)); tech_pvt->call_id = ++profile->next_call_id; + tech_pvt->party_id = tech_pvt->call_id; tech_pvt->profile = profile; switch_core_session_set_private(session, tech_pvt); tech_pvt->session = session; From 924e960d0a0931e34c372037573df9b0439cb183 Mon Sep 17 00:00:00 2001 From: Mathieu Parent Date: Fri, 9 Apr 2010 14:40:33 +0200 Subject: [PATCH 13/17] perl-skinny: enhance test - Use thread for: keepalive, receive and send - Run indefinitevly --- src/mod/endpoints/mod_skinny/Net/Skinny.pm | 36 +++--- .../endpoints/mod_skinny/Net/Skinny/Client.pm | 94 ++++++++++++++ .../mod_skinny/Net/Skinny/Message.pm | 118 ++++++++++++------ .../mod_skinny/Net/Skinny/Protocol.pm | 3 +- src/mod/endpoints/mod_skinny/test-skinny.pl | 12 +- 5 files changed, 199 insertions(+), 64 deletions(-) create mode 100644 src/mod/endpoints/mod_skinny/Net/Skinny/Client.pm diff --git a/src/mod/endpoints/mod_skinny/Net/Skinny.pm b/src/mod/endpoints/mod_skinny/Net/Skinny.pm index e0ae460eac..c4ee1992ad 100644 --- a/src/mod/endpoints/mod_skinny/Net/Skinny.pm +++ b/src/mod/endpoints/mod_skinny/Net/Skinny.pm @@ -6,26 +6,25 @@ package Net::Skinny; use strict; use warnings; -use IO::Socket; + +require IO::Socket; + use Net::Skinny::Protocol qw/:all/; -our(@ISA); -@ISA = qw(IO::Socket::INET); +our @ISA = qw(IO::Socket::INET); sub new { shift->SUPER::new(PeerPort => 2000, @_); } -sub send_data +sub send_raw { my $self = shift; my $type = shift; - my $data = shift; - my $len = length($data)+4; + my $raw = shift; + my $len = length($raw)+4; printf "Sending message (length=%d, type=%s (%X))", $len, Net::Skinny::Protocol::skinny_message_type2str($type), $type; - $self->send( - pack("VVV", $len, 0, $type). - $data); + $self->send(pack("VVV", $len, 0, $type).$raw); printf ".\n"; } @@ -33,11 +32,8 @@ sub send_message { my $self = shift; my $type = shift; - return Net::Skinny::Message->new( - $self, - $type, - @_ - )->send(); + my $message = Net::Skinny::Message->new($type, @_); + return $self->send_raw($message->type(), $message->raw()); } sub receive_message @@ -58,20 +54,26 @@ sub receive_message printf "type=%s (%X))", Net::Skinny::Protocol::skinny_message_type2str($type), $type; if($len > 4) { $self->recv($buf, $len-4); + } else { + $buf = ''; } printf ".\n"; + return Net::Skinny::Message->new_raw($type, $buf); } sub sleep { my $self = shift; my $t = shift; - + my %args = @_; + $args{'quiet'} = 0 if not $args{'quiet'}; printf "Sleeping %d seconds", $t; while(--$t){ sleep(1); - printf "." if $t % 10; - printf "_" unless $t % 10; + if(!$args{'quiet'}) { + printf "." if $t % 10; + printf "_" unless $t % 10; + } } printf ".\n"; } diff --git a/src/mod/endpoints/mod_skinny/Net/Skinny/Client.pm b/src/mod/endpoints/mod_skinny/Net/Skinny/Client.pm new file mode 100644 index 0000000000..ee063cc911 --- /dev/null +++ b/src/mod/endpoints/mod_skinny/Net/Skinny/Client.pm @@ -0,0 +1,94 @@ +# Copyright (c) 2010 Mathieu Parent . +# All rights reserved. This program is free software; you can redistribute it +# and/or modify it under the same terms as Perl itself. + +package Net::Skinny::Client; + +use strict; +use warnings; + +use Config; +use threads; +use threads::shared; +use Thread::Queue; + +require Net::Skinny; +use Net::Skinny::Protocol qw/:all/; +use Net::Skinny::Message; + +our(@ISA); +@ISA = qw(Net::Skinny); + +my $keep_alive_thread; +my $keep_alives :shared; +our $kept_self; +my $messages_send_queue; +my $messages_receive_queue; + +$Config{useithreads} or die('Recompile Perl with threads to run this program.'); + +sub new { + $kept_self = shift->SUPER::new(@_); + $messages_send_queue = Thread::Queue->new(); + $messages_receive_queue = Thread::Queue->new(); + threads->create(\&send_messages_thread_func); + threads->create(\&receive_messages_thread_func); + return $kept_self; +} + +sub send_message { + my $self = shift; + $messages_send_queue->enqueue(\@_); +} + +sub receive_message { + my $self = shift; + my $message = $messages_receive_queue->dequeue(); + if($message->type() == 0x100) {#keepaliveack + if(1) { + lock($keep_alives); + $keep_alives--; + } + $message = $messages_receive_queue->dequeue(); + } + return $message; +} + +sub launch_keep_alive_thread +{ + if(!$keep_alive_thread) { + $keep_alive_thread = threads->create(\&keep_alive_thread_func); + } else { + print "keep-alive thread is already running\n"; + } + return $keep_alive_thread; +} + +sub keep_alive_thread_func +{ + while($kept_self) { + if(1) { + lock($keep_alives); + $keep_alives++; + $kept_self->send_message(KEEP_ALIVE_MESSAGE); + } #mutex unlocked + $kept_self->sleep(30, quiet => 0); + } +} + +sub send_messages_thread_func +{ + while(my $message = $messages_send_queue->dequeue()) { + my $type = shift @$message; + $kept_self->SUPER::send_message($type, @$message); + } +} + +sub receive_messages_thread_func +{ + while(1) { + $messages_receive_queue->enqueue($kept_self->SUPER::receive_message()); + } +} + +1; diff --git a/src/mod/endpoints/mod_skinny/Net/Skinny/Message.pm b/src/mod/endpoints/mod_skinny/Net/Skinny/Message.pm index 6a1a0ef1cf..5955216e1c 100644 --- a/src/mod/endpoints/mod_skinny/Net/Skinny/Message.pm +++ b/src/mod/endpoints/mod_skinny/Net/Skinny/Message.pm @@ -7,54 +7,96 @@ package Net::Skinny::Message; use strict; use warnings; +use threads; +use threads::shared; + use Net::Skinny::Protocol qw/:all/; -use Data::Dumper; - -require Exporter; -our @ISA = qw(Exporter); -our @EXPORT = qw(send); - -sub new { +sub new_empty { my $class = shift; my $self = {}; bless $self, $class; - $self->{'socket'} = shift; - $self->{'type'} = shift; - %{$self->{'data'}} = @_; - return $ self; + $self->{'type'} = undef; + $self->{'data'} = undef; + $self->{'raw'} = undef; + return $self; } -sub send { +sub new { + my $self = shift->new_empty(); + $self->type(shift); + $self->data(@_) if @_; + return $self; +} + +sub new_raw { + my $self = shift->new_empty(); + $self->type(shift); + $self->raw(shift); + return $self; +} + +sub type +{ my $self = shift; - my $struct = Net::Skinny::Protocol::skinny_message_struct($self->{'type'}); - my $raw = ''; - my $parsed_count = 0; - for my $info ( @$struct) { - last if !defined($self->{'data'}{@$info[1]}); - if(@$info[0] eq 'char') { - $raw .= pack("a".@$info[2], $self->{'data'}{@$info[1]}); - } elsif(@$info[0] eq 'uint32_t') { - $raw .= pack("V".@$info[2], $self->{'data'}{@$info[1]}); - } elsif(@$info[0] eq 'uint16_t') { - $raw .= pack("n".@$info[2], $self->{'data'}{@$info[1]}); - } elsif(@$info[0] eq 'struct in_addr') { - $raw .= pack("V".@$info[2], $self->{'data'}{@$info[1]}); - } elsif(@$info[0] eq 'struct station_capabilities') { - $raw .= $self->{'data'}{@$info[1]}; - } else { - printf "Unknown type: %s\n", @$info[0]; - return; - } - $parsed_count++; + my $type = @_ ? shift : undef; + if(defined($type)) { + $self->{'type'} = $type; } - if($parsed_count != scalar(keys %{$self->{'data'}})) { - printf "Incomplete message (type=%s (%X)) %d out of %d\n", Net::Skinny::Protocol::skinny_message_type2str($self->{'type'}), $self->{'type'}, - $parsed_count, scalar(keys %{$self->{'data'}}); - print Dumper(@$struct); - return; + return $self->{'type'}; +} + +sub data +{ + my $self = shift; + my @data = @_; + if(@data) { + %{$self->{'data'}} = @data; + $self->{'raw'} = undef; + } elsif(!defined($self->{'data'})) { + printf "Conversion from raw to data not implemented\n"; } - $self->{'socket'}->send_data($self->{'type'}, $raw); + return $self->{'data'}; +} + +sub raw +{ + my $self = shift; + my $raw = shift || undef; + if(defined($raw)) { + $self->{'raw'} = $raw; + $self->{'data'} = undef; + } + if(!defined($self->{'raw'})) { + my $struct = Net::Skinny::Protocol::skinny_message_struct($self->{'type'}); + my $raw = ''; + my $parsed_count = 0; + for my $info ( @$struct) { + last if !defined($self->{'data'}{@$info[1]}); + if(@$info[0] eq 'char') { + $raw .= pack("a".@$info[2], $self->{'data'}{@$info[1]}); + } elsif(@$info[0] eq 'uint32_t') { + $raw .= pack("V".@$info[2], $self->{'data'}{@$info[1]}); + } elsif(@$info[0] eq 'uint16_t') { + $raw .= pack("n".@$info[2], $self->{'data'}{@$info[1]}); + } elsif(@$info[0] eq 'struct in_addr') { + $raw .= pack("V".@$info[2], $self->{'data'}{@$info[1]}); + } elsif(@$info[0] eq 'struct station_capabilities') { + $raw .= $self->{'data'}{@$info[1]}; + } else { + printf "Unknown type: %s\n", @$info[0]; + return; + } + $parsed_count++; + } + if($parsed_count != scalar(keys %{$self->{'data'}})) { + printf "Incomplete message (type=%s (%X)) %d out of %d\n", Net::Skinny::Protocol::skinny_message_type2str($self->{'type'}), $self->{'type'}, + $parsed_count, scalar(keys %{$self->{'data'}}); + return; + } + $self->{'raw'} = $raw; + } + return $self->{'raw'}; } 1; diff --git a/src/mod/endpoints/mod_skinny/Net/Skinny/Protocol.pm b/src/mod/endpoints/mod_skinny/Net/Skinny/Protocol.pm index bfe0202787..90de304817 100644 --- a/src/mod/endpoints/mod_skinny/Net/Skinny/Protocol.pm +++ b/src/mod/endpoints/mod_skinny/Net/Skinny/Protocol.pm @@ -8,7 +8,6 @@ use strict; no strict "refs"; use warnings; use Carp; -use Data::Dumper; require Exporter; our @ISA = qw(Exporter); @@ -69,7 +68,6 @@ sub _find { printf "Unparsed line '%s' in %s\n", $_, $struct_name; } } - #print "$name: ".Dumper($struct{$name}); } } @sub{@_}; @@ -77,6 +75,7 @@ sub _find { sub skinny_message_type2str { my $message_type = shift; + return "UndefinedTypeMessage" if !defined($message_type); keys %const; while (my ($key, $value) = each %const) { diff --git a/src/mod/endpoints/mod_skinny/test-skinny.pl b/src/mod/endpoints/mod_skinny/test-skinny.pl index 390466f530..a8c7bb5d68 100644 --- a/src/mod/endpoints/mod_skinny/test-skinny.pl +++ b/src/mod/endpoints/mod_skinny/test-skinny.pl @@ -15,6 +15,7 @@ use Sys::Hostname; use Net::Skinny; use Net::Skinny::Protocol qw/:all/; use Net::Skinny::Message; +use Net::Skinny::Client; #Config my $skinny_server = hostname; @@ -23,13 +24,13 @@ my $device_ip = 10+256*(11+256*(12+256*13)); # 10.11.12.13 #====== $| = 1; -my $socket = Net::Skinny->new( +my $socket = Net::Skinny::Client->new( PeerAddr => $skinny_server, PeerPort => 2000, ); if(!$socket) { - print "Unable to connect to server\n"; + printf "Unable to connect to server %s\n", $skinny_server; exit 1; } # ============================================================================= @@ -84,11 +85,8 @@ $socket->send_message( count => 2 ); -for(my $i = 0; $i < 1; $i++) { - $socket->sleep(5); - $socket->send_message(KEEP_ALIVE_MESSAGE); - $socket->receive_message(); # keepaliveack -} +$socket->launch_keep_alive_thread(); + $socket->sleep(5); #NewCall From 7e3c29c600a1109c16c7e7be5fac8d5fb984a1bf Mon Sep 17 00:00:00 2001 From: Mathieu Parent Date: Fri, 9 Apr 2010 14:59:18 +0200 Subject: [PATCH 14/17] Skinny: manage shared lines from the calling POV Called POV already implemented --- .../endpoints/mod_skinny/skinny_protocol.c | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/src/mod/endpoints/mod_skinny/skinny_protocol.c b/src/mod/endpoints/mod_skinny/skinny_protocol.c index 8a96f7e629..3d72a22640 100644 --- a/src/mod/endpoints/mod_skinny/skinny_protocol.c +++ b/src/mod/endpoints/mod_skinny/skinny_protocol.c @@ -547,6 +547,49 @@ done: return SWITCH_STATUS_SUCCESS; } +struct skinny_session_process_dest_helper { + private_t *tech_pvt; + listener_t *listener; + uint32_t line_instance; +}; + +int skinny_session_process_dest_callback(void *pArg, int argc, char **argv, char **columnNames) +{ + struct skinny_session_process_dest_helper *helper = pArg; + listener_t *listener = NULL; + + char *device_name = argv[0]; + uint32_t device_instance = atoi(argv[1]); + /* uint32_t position = atoi(argv[2]); */ + uint32_t line_instance = atoi(argv[3]); + /* char *label = argv[4]; */ + /* char *value = argv[5]; */ + /* char *caller_name = argv[6]; */ + /* uint32_t ring_on_idle = atoi(argv[7]); */ + /* uint32_t ring_on_active = atoi(argv[8]); */ + /* uint32_t busy_trigger = atoi(argv[9]); */ + /* char *forward_all = argv[10]; */ + /* char *forward_busy = argv[11]; */ + /* char *forward_noanswer = argv[12]; */ + /* uint32_t noanswer_duration = atoi(argv[13]); */ + /* char *channel_uuid = argv[14]; */ + /* uint32_t call_id = atoi(argv[15]); */ + /* uint32_t call_state = atoi(argv[16]); */ + + skinny_profile_find_listener_by_device_name_and_instance(helper->tech_pvt->profile, device_name, device_instance, &listener); + if(listener) { + if(!strcmp(device_name, helper->listener->device_name) + && (device_instance == helper->listener->device_instance) + && (line_instance == helper->line_instance)) {/* the calling line */ + /* nothing */ + } else { + /* TODO: capture and check what should happen here*/ + skinny_line_set_state(listener, line_instance, helper->tech_pvt->call_id, SKINNY_IN_USE_REMOTELY); + } + } + return 0; +} + switch_status_t skinny_session_process_dest(switch_core_session_t *session, listener_t *listener, uint32_t line_instance, char *dest, char append_dest, uint32_t backspace) { switch_channel_t *channel = NULL; @@ -577,10 +620,17 @@ switch_status_t skinny_session_process_dest(switch_core_session_t *session, list } /* TODO Number is complete -> check against dialplan */ if((strlen(tech_pvt->caller_profile->destination_number) >= 4) || dest) { + struct skinny_session_process_dest_helper helper = {0}; send_dialed_number(listener, tech_pvt->caller_profile->destination_number, line_instance, tech_pvt->call_id); skinny_line_set_state(listener, line_instance, tech_pvt->call_id, SKINNY_PROCEED); skinny_send_call_info(session, listener, line_instance); + skinny_session_start_media(session, listener, line_instance); + + helper.tech_pvt = tech_pvt; + helper.listener = listener; + helper.line_instance = line_instance; + skinny_session_walk_lines(tech_pvt->profile, switch_core_session_get_uuid(session), skinny_session_process_dest_callback, &helper); } return SWITCH_STATUS_SUCCESS; From a1952b863640e75f26a55e998c34bdeb26f85234 Mon Sep 17 00:00:00 2001 From: Mathieu Parent Date: Fri, 9 Apr 2010 16:12:58 +0200 Subject: [PATCH 15/17] Skinny: implement hold/resume Also rework a bit softkey sets --- src/mod/endpoints/mod_skinny/mod_skinny.c | 11 +-- .../endpoints/mod_skinny/skinny_protocol.c | 72 +++++++++++++++++-- .../endpoints/mod_skinny/skinny_protocol.h | 1 + 3 files changed, 68 insertions(+), 16 deletions(-) diff --git a/src/mod/endpoints/mod_skinny/mod_skinny.c b/src/mod/endpoints/mod_skinny/mod_skinny.c index d086c9deb0..7b5be3529f 100644 --- a/src/mod/endpoints/mod_skinny/mod_skinny.c +++ b/src/mod/endpoints/mod_skinny/mod_skinny.c @@ -642,16 +642,7 @@ int channel_on_hangup_callback(void *pArg, int argc, char **argv, char **columnN send_set_lamp(listener, SKINNY_BUTTON_LINE, line_instance, SKINNY_LAMP_OFF); send_clear_prompt_status(listener, line_instance, call_id); if(call_state == SKINNY_CONNECTED) { /* calling parties */ - send_close_receive_channel(listener, - call_id, /* uint32_t conference_id, */ - helper->tech_pvt->party_id, /* uint32_t pass_thru_party_id, */ - call_id /* uint32_t conference_id2, */ - ); - send_stop_media_transmission(listener, - call_id, /* uint32_t conference_id, */ - helper->tech_pvt->party_id, /* uint32_t pass_thru_party_id, */ - call_id /* uint32_t conference_id2, */ - ); + skinny_session_stop_media(helper->tech_pvt->session, listener, line_instance); } skinny_line_set_state(listener, line_instance, call_id, SKINNY_ON_HOOK); diff --git a/src/mod/endpoints/mod_skinny/skinny_protocol.c b/src/mod/endpoints/mod_skinny/skinny_protocol.c index 3d72a22640..2361fa2801 100644 --- a/src/mod/endpoints/mod_skinny/skinny_protocol.c +++ b/src/mod/endpoints/mod_skinny/skinny_protocol.c @@ -784,17 +784,66 @@ switch_status_t skinny_session_hold_line(switch_core_session_t *session, listene channel = switch_core_session_get_channel(session); tech_pvt = switch_core_session_get_private(session); - /* TODO */ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Hold is not implemented yet. Hanging up the line.\n"); + skinny_session_stop_media(session, listener, line_instance); + switch_ivr_hold(session, NULL, 1); - switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING); + send_define_current_time_date(listener); + send_set_lamp(listener, SKINNY_BUTTON_LINE, line_instance, SKINNY_LAMP_WINK); + skinny_line_set_state(listener, line_instance, tech_pvt->call_id, SKINNY_HOLD); + send_select_soft_keys(listener, line_instance, tech_pvt->call_id, SKINNY_KEY_SET_ON_HOLD, 0xffff); + send_display_prompt_status(listener, 0, "\200\003", + line_instance, tech_pvt->call_id); + skinny_send_call_info(tech_pvt->session, listener, line_instance); + send_set_speaker_mode(listener, SKINNY_SPEAKER_OFF); + send_set_ringer(listener, SKINNY_RING_OFF, SKINNY_RING_FOREVER, 0, tech_pvt->call_id); return SWITCH_STATUS_SUCCESS; } switch_status_t skinny_session_unhold_line(switch_core_session_t *session, listener_t *listener, uint32_t line_instance) { - /* TODO */ + switch_channel_t *channel = NULL; + private_t *tech_pvt = NULL; + + switch_assert(session); + switch_assert(listener); + switch_assert(listener->profile); + + channel = switch_core_session_get_channel(session); + tech_pvt = switch_core_session_get_private(session); + + send_set_ringer(listener, SKINNY_RING_OFF, SKINNY_RING_FOREVER, 0, tech_pvt->call_id); + send_set_speaker_mode(listener, SKINNY_SPEAKER_ON); + send_select_soft_keys(listener, line_instance, tech_pvt->call_id, SKINNY_KEY_SET_RING_OUT, 0xffff); + skinny_session_start_media(session, listener, line_instance); + switch_ivr_unhold(session); + send_set_lamp(listener, SKINNY_BUTTON_LINE, line_instance, SKINNY_LAMP_ON); + return SWITCH_STATUS_SUCCESS; +} + +switch_status_t skinny_session_stop_media(switch_core_session_t *session, listener_t *listener, uint32_t line_instance) +{ + switch_channel_t *channel = NULL; + private_t *tech_pvt = NULL; + + switch_assert(session); + switch_assert(listener); + switch_assert(listener->profile); + + channel = switch_core_session_get_channel(session); + tech_pvt = switch_core_session_get_private(session); + + send_close_receive_channel(listener, + tech_pvt->call_id, /* uint32_t conference_id, */ + tech_pvt->party_id, /* uint32_t pass_thru_party_id, */ + tech_pvt->call_id /* uint32_t conference_id2, */ + ); + send_stop_media_transmission(listener, + tech_pvt->call_id, /* uint32_t conference_id, */ + tech_pvt->party_id, /* uint32_t pass_thru_party_id, */ + tech_pvt->call_id /* uint32_t conference_id2, */ + ); + return SWITCH_STATUS_SUCCESS; } @@ -1840,10 +1889,21 @@ switch_status_t skinny_handle_soft_key_set_request(listener_t *listener, skinny_ message->data.soft_key_set.total_soft_key_set_count = 11; /* TODO fill the set */ - message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_ON_HOOK].soft_key_template_index[0] = SOFTKEY_REDIAL; - message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_ON_HOOK].soft_key_template_index[1] = SOFTKEY_NEWCALL; + message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_ON_HOOK].soft_key_template_index[0] = SOFTKEY_NEWCALL; + message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_ON_HOOK].soft_key_template_index[1] = SOFTKEY_REDIAL; + + message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_OFF_HOOK].soft_key_template_index[0] = SOFTKEY_BACKSPACE; + message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_OFF_HOOK].soft_key_template_index[1] = SOFTKEY_REDIAL; + message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_CONNECTED].soft_key_template_index[0] = SOFTKEY_ENDCALL; + message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_CONNECTED].soft_key_template_index[1] = SOFTKEY_HOLD; + message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_RING_IN].soft_key_template_index[0] = SOFTKEY_ENDCALL; + message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_RING_IN].soft_key_template_index[1] = SOFTKEY_ANSWER; + + message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_ON_HOLD].soft_key_template_index[0] = SOFTKEY_RESUME; + message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_ON_HOLD].soft_key_template_index[1] = SOFTKEY_NEWCALL; + message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_ON_HOLD].soft_key_template_index[2] = SOFTKEY_ENDCALL; skinny_send_reply(listener, message); diff --git a/src/mod/endpoints/mod_skinny/skinny_protocol.h b/src/mod/endpoints/mod_skinny/skinny_protocol.h index ea004f12fc..74a24a0590 100644 --- a/src/mod/endpoints/mod_skinny/skinny_protocol.h +++ b/src/mod/endpoints/mod_skinny/skinny_protocol.h @@ -630,6 +630,7 @@ switch_status_t skinny_session_answer(switch_core_session_t *session, listener_t switch_status_t skinny_session_start_media(switch_core_session_t *session, listener_t *listener, uint32_t line_instance); switch_status_t skinny_session_hold_line(switch_core_session_t *session, listener_t *listener, uint32_t line_instance); switch_status_t skinny_session_unhold_line(switch_core_session_t *session, listener_t *listener, uint32_t line_instance); +switch_status_t skinny_session_stop_media(switch_core_session_t *session, listener_t *listener, uint32_t line_instance); void skinny_line_get(listener_t *listener, uint32_t instance, struct line_stat_res_message **button); void skinny_speed_dial_get(listener_t *listener, uint32_t instance, struct speed_dial_stat_res_message **button); From 555b205344c89fd4df27fa82c8829e58c50a6c60 Mon Sep 17 00:00:00 2001 From: Mathieu Parent Date: Fri, 9 Apr 2010 16:54:29 +0200 Subject: [PATCH 16/17] Skinny: handle backspace --- .../endpoints/mod_skinny/skinny_protocol.c | 48 ++++++++++++------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/src/mod/endpoints/mod_skinny/skinny_protocol.c b/src/mod/endpoints/mod_skinny/skinny_protocol.c index 2361fa2801..0dab0fe47a 100644 --- a/src/mod/endpoints/mod_skinny/skinny_protocol.c +++ b/src/mod/endpoints/mod_skinny/skinny_protocol.c @@ -602,24 +602,31 @@ switch_status_t skinny_session_process_dest(switch_core_session_t *session, list channel = switch_core_session_get_channel(session); tech_pvt = switch_core_session_get_private(session); - if(!dest) { - if(append_dest == '\0') {/* no digit yet */ - send_start_tone(listener, SKINNY_TONE_DIALTONE, 0, line_instance, tech_pvt->call_id); - } else { - if(strlen(tech_pvt->caller_profile->destination_number) == 0) {/* first digit */ - send_stop_tone(listener, line_instance, tech_pvt->call_id); - send_select_soft_keys(listener, line_instance, tech_pvt->call_id, - SKINNY_KEY_SET_DIGITS_AFTER_DIALING_FIRST_DIGIT, 0xffff); - } + if (!dest) { + if (backspace) { /* backspace */ + *tech_pvt->caller_profile->destination_number++ = '\0'; + } + if (append_dest != '\0' && !backspace) {/* append digit */ tech_pvt->caller_profile->destination_number = switch_core_sprintf(tech_pvt->caller_profile->pool, "%s%c", tech_pvt->caller_profile->destination_number, append_dest); } + if (strlen(tech_pvt->caller_profile->destination_number) == 0) {/* no digit yet */ + send_start_tone(listener, SKINNY_TONE_DIALTONE, 0, line_instance, tech_pvt->call_id); + if(backspace) { + send_select_soft_keys(listener, line_instance, tech_pvt->call_id, SKINNY_KEY_SET_OFF_HOOK, 0xffff); + /* TODO: How to clear the screen? */ + } + } else if (strlen(tech_pvt->caller_profile->destination_number) == 1) {/* first digit */ + send_stop_tone(listener, line_instance, tech_pvt->call_id); + send_select_soft_keys(listener, line_instance, tech_pvt->call_id, + SKINNY_KEY_SET_DIGITS_AFTER_DIALING_FIRST_DIGIT, 0xffff); + } } else { tech_pvt->caller_profile->destination_number = switch_core_strdup(tech_pvt->caller_profile->pool, dest); } /* TODO Number is complete -> check against dialplan */ - if((strlen(tech_pvt->caller_profile->destination_number) >= 4) || dest) { + if ((strlen(tech_pvt->caller_profile->destination_number) >= 4) || dest) { struct skinny_session_process_dest_helper helper = {0}; send_dialed_number(listener, tech_pvt->caller_profile->destination_number, line_instance, tech_pvt->call_id); skinny_line_set_state(listener, line_instance, tech_pvt->call_id, SKINNY_PROCEED); @@ -1892,17 +1899,18 @@ switch_status_t skinny_handle_soft_key_set_request(listener_t *listener, skinny_ message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_ON_HOOK].soft_key_template_index[0] = SOFTKEY_NEWCALL; message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_ON_HOOK].soft_key_template_index[1] = SOFTKEY_REDIAL; - message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_OFF_HOOK].soft_key_template_index[0] = SOFTKEY_BACKSPACE; message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_OFF_HOOK].soft_key_template_index[1] = SOFTKEY_REDIAL; + message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_DIGITS_AFTER_DIALING_FIRST_DIGIT].soft_key_template_index[0] = SOFTKEY_BACKSPACE; + message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_CONNECTED].soft_key_template_index[0] = SOFTKEY_ENDCALL; message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_CONNECTED].soft_key_template_index[1] = SOFTKEY_HOLD; - message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_RING_IN].soft_key_template_index[0] = SOFTKEY_ENDCALL; - message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_RING_IN].soft_key_template_index[1] = SOFTKEY_ANSWER; + message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_RING_IN].soft_key_template_index[0] = SOFTKEY_ANSWER; + message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_RING_IN].soft_key_template_index[1] = SOFTKEY_ENDCALL; - message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_ON_HOLD].soft_key_template_index[0] = SOFTKEY_RESUME; - message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_ON_HOLD].soft_key_template_index[1] = SOFTKEY_NEWCALL; + message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_ON_HOLD].soft_key_template_index[0] = SOFTKEY_NEWCALL; + message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_ON_HOLD].soft_key_template_index[1] = SOFTKEY_RESUME; message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_ON_HOLD].soft_key_template_index[2] = SOFTKEY_ENDCALL; skinny_send_reply(listener, message); @@ -2042,7 +2050,6 @@ switch_status_t skinny_handle_soft_key_event_message(listener_t *listener, skinn case SOFTKEY_NEWCALL: status = skinny_create_ingoing_session(listener, &line_instance, &session); tech_pvt = switch_core_session_get_private(session); - assert(tech_pvt != NULL); skinny_session_process_dest(session, listener, line_instance, NULL, '\0', 0); break; @@ -2053,6 +2060,13 @@ switch_status_t skinny_handle_soft_key_event_message(listener_t *listener, skinn status = skinny_session_hold_line(session, listener, line_instance); } break; + case SOFTKEY_BACKSPACE: + session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.soft_key_event.call_id); + + if(session) { + skinny_session_process_dest(session, listener, line_instance, NULL, '\0', 1); + } + break; case SOFTKEY_ENDCALL: session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.soft_key_event.call_id); @@ -2078,7 +2092,7 @@ switch_status_t skinny_handle_soft_key_event_message(listener_t *listener, skinn break; default: switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, - "Unknown SoftKeyEvent type while busy: %d.\n", request->data.soft_key_event.event); + "Unknown SoftKeyEvent type: %d.\n", request->data.soft_key_event.event); } if(session) { From befd41c8294c0ab677800eac4b112d0df4402a15 Mon Sep 17 00:00:00 2001 From: Mathieu Parent Date: Fri, 9 Apr 2010 18:02:14 +0200 Subject: [PATCH 17/17] SKinny: handle hold corner cases - try to re-use existing OffHook session - hold active lines before: newcall, resume - allow endcall on: offHook, afterFirstDigit - allow newcall on: connected, ringin --- src/mod/endpoints/mod_skinny/mod_skinny.c | 10 ++- .../endpoints/mod_skinny/skinny_protocol.c | 67 ++++++++++++++++++- .../endpoints/mod_skinny/skinny_protocol.h | 1 + 3 files changed, 74 insertions(+), 4 deletions(-) diff --git a/src/mod/endpoints/mod_skinny/mod_skinny.c b/src/mod/endpoints/mod_skinny/mod_skinny.c index 7b5be3529f..391923d5e9 100644 --- a/src/mod/endpoints/mod_skinny/mod_skinny.c +++ b/src/mod/endpoints/mod_skinny/mod_skinny.c @@ -221,7 +221,7 @@ char * skinny_profile_find_session_uuid(skinny_profile_t *profile, listener_t *l "SELECT channel_uuid, line_instance " "FROM skinny_active_lines " "WHERE %s AND %s AND %s " - "ORDER BY channel_uuid DESC", + "ORDER BY call_state, channel_uuid", /* off hook first */ device_condition, line_instance_condition, call_id_condition ))) { skinny_execute_sql_callback(profile, profile->sql_mutex, sql, @@ -365,7 +365,9 @@ struct skinny_line_get_state_helper { int skinny_line_get_state_callback(void *pArg, int argc, char **argv, char **columnNames) { struct skinny_line_get_state_helper *helper = pArg; - helper->call_state = atoi(argv[0]); + if (helper->call_state == -1) { + helper->call_state = atoi(argv[0]); + } return 0; } @@ -391,10 +393,12 @@ uint32_t skinny_line_get_state(listener_t *listener, uint32_t line_instance, uin } switch_assert(call_id_condition); + helper.call_state = -1; if ((sql = switch_mprintf( "SELECT call_state FROM skinny_active_lines " "WHERE device_name='%s' AND device_instance=%d " - "AND %s AND %s", + "AND %s AND %s " + "ORDER BY call_state, channel_uuid", /* off hook first */ listener->device_name, listener->device_instance, line_instance_condition, call_id_condition ))) { diff --git a/src/mod/endpoints/mod_skinny/skinny_protocol.c b/src/mod/endpoints/mod_skinny/skinny_protocol.c index 0dab0fe47a..94c61eb1dd 100644 --- a/src/mod/endpoints/mod_skinny/skinny_protocol.c +++ b/src/mod/endpoints/mod_skinny/skinny_protocol.c @@ -451,7 +451,6 @@ switch_status_t skinny_create_ingoing_session(listener_t *listener, uint32_t *li *session = nsession; return SWITCH_STATUS_SUCCESS; } - skinny_session_hold_line(nsession, listener, *line_instance_p); switch_core_session_rwunlock(nsession); } *line_instance_p = line_instance; @@ -459,6 +458,8 @@ switch_status_t skinny_create_ingoing_session(listener_t *listener, uint32_t *li *line_instance_p = 1; } + skinny_hold_active_calls(listener); + skinny_line_get(listener, *line_instance_p, &button); if (!button || !button->shortname) { @@ -819,6 +820,7 @@ switch_status_t skinny_session_unhold_line(switch_core_session_t *session, liste channel = switch_core_session_get_channel(session); tech_pvt = switch_core_session_get_private(session); + skinny_hold_active_calls(listener); send_set_ringer(listener, SKINNY_RING_OFF, SKINNY_RING_FOREVER, 0, tech_pvt->call_id); send_set_speaker_mode(listener, SKINNY_SPEAKER_ON); send_select_soft_keys(listener, line_instance, tech_pvt->call_id, SKINNY_KEY_SET_RING_OUT, 0xffff); @@ -854,6 +856,65 @@ switch_status_t skinny_session_stop_media(switch_core_session_t *session, listen return SWITCH_STATUS_SUCCESS; } +struct skinny_hold_active_calls_helper { + listener_t *listener; +}; + +int skinny_hold_active_calls_callback(void *pArg, int argc, char **argv, char **columnNames) +{ + struct skinny_hold_active_calls_helper *helper = pArg; + switch_core_session_t *session; + + /* char *device_name = argv[0]; */ + /* uint32_t device_instance = atoi(argv[1]); */ + /* uint32_t position = atoi(argv[2]); */ + uint32_t line_instance = atoi(argv[3]); + /* char *label = argv[4]; */ + /* char *value = argv[5]; */ + /* char *caller_name = argv[6]; */ + /* uint32_t ring_on_idle = atoi(argv[7]); */ + /* uint32_t ring_on_active = atoi(argv[8]); */ + /* uint32_t busy_trigger = atoi(argv[9]); */ + /* char *forward_all = argv[10]; */ + /* char *forward_busy = argv[11]; */ + /* char *forward_noanswer = argv[12]; */ + /* uint32_t noanswer_duration = atoi(argv[13]); */ + /* char *channel_uuid = argv[14]; */ + uint32_t call_id = atoi(argv[15]); + /* uint32_t call_state = atoi(argv[16]); */ + + session = skinny_profile_find_session(helper->listener->profile, helper->listener, &line_instance, call_id); + + if(session) { + skinny_session_hold_line(session, helper->listener, line_instance); + switch_core_session_rwunlock(session); + } + + return 0; +} + +switch_status_t skinny_hold_active_calls(listener_t *listener) +{ + struct skinny_hold_active_calls_helper helper = {0}; + char *sql; + + helper.listener = listener; + + if ((sql = switch_mprintf( + "SELECT skinny_lines.*, channel_uuid, call_id, call_state " + "FROM skinny_active_lines " + "INNER JOIN skinny_lines " + "ON skinny_active_lines.device_name = skinny_lines.device_name " + "AND skinny_active_lines.device_instance = skinny_lines.device_instance " + "AND skinny_active_lines.line_instance = skinny_lines.line_instance " + "WHERE skinny_lines.device_name='%s' AND skinny_lines.device_instance=%d AND call_state=%d", + listener->device_name, listener->device_instance, SKINNY_CONNECTED))) { + skinny_execute_sql_callback(listener->profile, listener->profile->sql_mutex, sql, skinny_hold_active_calls_callback, &helper); + switch_safe_free(sql); + } + + return SWITCH_STATUS_SUCCESS; +} /*****************************************************************************/ /* SKINNY BUTTONS */ /*****************************************************************************/ @@ -1900,14 +1961,18 @@ switch_status_t skinny_handle_soft_key_set_request(listener_t *listener, skinny_ message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_ON_HOOK].soft_key_template_index[1] = SOFTKEY_REDIAL; message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_OFF_HOOK].soft_key_template_index[1] = SOFTKEY_REDIAL; + message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_OFF_HOOK].soft_key_template_index[2] = SOFTKEY_ENDCALL; message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_DIGITS_AFTER_DIALING_FIRST_DIGIT].soft_key_template_index[0] = SOFTKEY_BACKSPACE; + message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_DIGITS_AFTER_DIALING_FIRST_DIGIT].soft_key_template_index[2] = SOFTKEY_ENDCALL; message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_CONNECTED].soft_key_template_index[0] = SOFTKEY_ENDCALL; message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_CONNECTED].soft_key_template_index[1] = SOFTKEY_HOLD; + message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_CONNECTED].soft_key_template_index[2] = SOFTKEY_NEWCALL; message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_RING_IN].soft_key_template_index[0] = SOFTKEY_ANSWER; message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_RING_IN].soft_key_template_index[1] = SOFTKEY_ENDCALL; + message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_RING_IN].soft_key_template_index[2] = SOFTKEY_NEWCALL; message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_ON_HOLD].soft_key_template_index[0] = SOFTKEY_NEWCALL; message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_ON_HOLD].soft_key_template_index[1] = SOFTKEY_RESUME; diff --git a/src/mod/endpoints/mod_skinny/skinny_protocol.h b/src/mod/endpoints/mod_skinny/skinny_protocol.h index 74a24a0590..3199738856 100644 --- a/src/mod/endpoints/mod_skinny/skinny_protocol.h +++ b/src/mod/endpoints/mod_skinny/skinny_protocol.h @@ -631,6 +631,7 @@ switch_status_t skinny_session_start_media(switch_core_session_t *session, liste switch_status_t skinny_session_hold_line(switch_core_session_t *session, listener_t *listener, uint32_t line_instance); switch_status_t skinny_session_unhold_line(switch_core_session_t *session, listener_t *listener, uint32_t line_instance); switch_status_t skinny_session_stop_media(switch_core_session_t *session, listener_t *listener, uint32_t line_instance); +switch_status_t skinny_hold_active_calls(listener_t *listener); void skinny_line_get(listener_t *listener, uint32_t instance, struct line_stat_res_message **button); void skinny_speed_dial_get(listener_t *listener, uint32_t instance, struct speed_dial_stat_res_message **button);