From 9bc2dccc0adf52123c5a0394d29a39062b5e8081 Mon Sep 17 00:00:00 2001 From: Michael Giagnocavo Date: Tue, 10 Jun 2008 03:09:14 +0000 Subject: [PATCH] Move input and hangup delegates to reside on MonoSession instead of bound to app. git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@8791 d0543943-73ff-0310-b7d9-9358b9ac24b2 --- .../languages/mod_mono/freeswitch_wrap.cxx | 6 +- src/mod/languages/mod_mono/mod_mono.cpp | 698 ++++++++++++------ .../languages/mod_mono_managed/AppFunction.cs | 58 +- src/mod/languages/mod_mono_managed/Demo.cs | 5 +- src/mod/languages/mod_mono_managed/Loader.cs | 1 + .../languages/mod_mono_managed/MonoSession.cs | 65 +- 6 files changed, 529 insertions(+), 304 deletions(-) diff --git a/src/mod/languages/mod_mono/freeswitch_wrap.cxx b/src/mod/languages/mod_mono/freeswitch_wrap.cxx index 6aa5e7defd..8fc247ca66 100644 --- a/src/mod/languages/mod_mono/freeswitch_wrap.cxx +++ b/src/mod/languages/mod_mono/freeswitch_wrap.cxx @@ -24139,7 +24139,7 @@ SWIGEXPORT int SWIGSTDCALL CSharp_CoreSession_Originate(void * jarg1, void * jar } -SWIGEXPORT int SWIGSTDCALL CSharp_CoreSession_speak(void * jarg1, char * jarg2) { +SWIGEXPORT int SWIGSTDCALL CSharp_CoreSession_Speak(void * jarg1, char * jarg2) { int jresult ; CoreSession *arg1 = (CoreSession *) 0 ; char *arg2 = (char *) 0 ; @@ -24153,7 +24153,7 @@ SWIGEXPORT int SWIGSTDCALL CSharp_CoreSession_speak(void * jarg1, char * jarg2) } -SWIGEXPORT void SWIGSTDCALL CSharp_CoreSession_set_tts_parms(void * jarg1, char * jarg2, char * jarg3) { +SWIGEXPORT void SWIGSTDCALL CSharp_CoreSession_SetTtsParameters(void * jarg1, char * jarg2, char * jarg3) { CoreSession *arg1 = (CoreSession *) 0 ; char *arg2 = (char *) 0 ; char *arg3 = (char *) 0 ; @@ -24305,7 +24305,7 @@ SWIGEXPORT int SWIGSTDCALL CSharp_CoreSession_flushDigits(void * jarg1) { } -SWIGEXPORT int SWIGSTDCALL CSharp_CoreSession_setAutoHangup(void * jarg1, unsigned int jarg2) { +SWIGEXPORT int SWIGSTDCALL CSharp_CoreSession_SetAutoHangup(void * jarg1, unsigned int jarg2) { int jresult ; CoreSession *arg1 = (CoreSession *) 0 ; bool arg2 ; diff --git a/src/mod/languages/mod_mono/mod_mono.cpp b/src/mod/languages/mod_mono/mod_mono.cpp index 92f1ea02b6..2c3447c7b0 100644 --- a/src/mod/languages/mod_mono/mod_mono.cpp +++ b/src/mod/languages/mod_mono/mod_mono.cpp @@ -33,7 +33,10 @@ */ #include - SWITCH_BEGIN_EXTERN_C + + +SWITCH_BEGIN_EXTERN_C + #include "freeswitch_mono.h" #include #include @@ -47,272 +50,489 @@ #define EXPORT __declspec(dllexport) #elif #define EXPORT -#endif /* */ +#endif /* + */ #define MOD_MONO_MANAGED_DLL "mod_mono_managed.dll" - mod_mono_globals globals = { -0}; - - SWITCH_MODULE_LOAD_FUNCTION(mod_mono_load); - SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_mono_shutdown); - SWITCH_MODULE_DEFINITION(mod_mono, mod_mono_load, mod_mono_shutdown, NULL); - SWITCH_STANDARD_API(monorun_api_function); /* ExecuteBackground */ - SWITCH_STANDARD_API(mono_api_function); /* Execute */ - SWITCH_STANDARD_APP(mono_app_function); /* Run */ - + +mod_mono_globals globals = { +0}; + + + +SWITCH_MODULE_LOAD_FUNCTION(mod_mono_load); + +SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_mono_shutdown); + +SWITCH_MODULE_DEFINITION(mod_mono, mod_mono_load, mod_mono_shutdown, NULL); + + +SWITCH_STANDARD_API(monorun_api_function); /* ExecuteBackground */ + +SWITCH_STANDARD_API(mono_api_function); /* Execute */ + +SWITCH_STANDARD_APP(mono_app_function); /* Run */ + + // Sets up delegates (and anything else needed) on the MonoSession object // Called via internalcall - SWITCH_MOD_DECLARE(void) InitMonoSession(MonoSession * session, MonoObject * dtmfDelegate, MonoObject * hangupDelegate) -{ - switch_assert(session); - if (!session) - return; - session->setDTMFCallback(NULL, ""); - session->setHangupHook(NULL); - session->dtmfDelegateHandle = mono_gchandle_new(dtmfDelegate, FALSE); - session->hangupDelegateHandle = mono_gchandle_new(hangupDelegate, FALSE); - } - switch_status_t setMonoDirs() -{ +SWITCH_MOD_DECLARE(void) InitMonoSession(MonoSession * session, MonoObject * dtmfDelegate, MonoObject * hangupDelegate) +{ + switch_assert(session); + if (!session) { + return; + } + session->setDTMFCallback(NULL, ""); + session->setHangupHook(NULL); + session->dtmfDelegateHandle = mono_gchandle_new(dtmfDelegate, FALSE); + session->hangupDelegateHandle = mono_gchandle_new(hangupDelegate, FALSE); +} + + +switch_status_t setMonoDirs() +{ #ifdef WIN32 /* Win32 Mono installs can't figure out their own path // Guys in #mono say we should just deploy all the libs we need // I think it's much nicer to let the user deal with installing Mono // and we'll just look for it in program files. */ - HANDLE hFind; - WIN32_FIND_DATA findData; - char progFilesPath[MAX_PATH]; - char findPath[MAX_PATH]; - SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL, SHGFP_TYPE_CURRENT, progFilesPath); - switch_snprintf(findPath, MAX_PATH, "%s\\Mono-*", progFilesPath); - hFind = FindFirstFile(findPath, &findData); - if (hFind == INVALID_HANDLE_VALUE) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error looking for Mono in Program Files.\n"); - return SWITCH_STATUS_FALSE; - } - while ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY) { - if (FindNextFile(hFind, &findData) == 0) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not find Mono directory in Program Files.\n"); - FindClose(hFind); - return SWITCH_STATUS_FALSE; - } - } + HANDLE hFind; + +WIN32_FIND_DATA findData; + +char progFilesPath[MAX_PATH]; + +char findPath[MAX_PATH]; + +SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL, SHGFP_TYPE_CURRENT, progFilesPath); + +switch_snprintf(findPath, MAX_PATH, "%s\\Mono-*", progFilesPath); + +hFind = FindFirstFile(findPath, &findData); + +if (hFind == INVALID_HANDLE_VALUE) { + +switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error looking for Mono in Program Files.\n"); + +return SWITCH_STATUS_FALSE; + +} + +while ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY) { + +if (FindNextFile(hFind, &findData) == 0) { + +switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not find Mono directory in Program Files.\n"); + +FindClose(hFind); + +return SWITCH_STATUS_FALSE; + +} + +} /* Got it */ - { - char libPath[MAX_PATH]; - char etcPath[MAX_PATH]; - switch_snprintf(libPath, MAX_PATH, "%s\\%s\\lib", progFilesPath, findData.cFileName); - switch_snprintf(etcPath, MAX_PATH, "%s\\%s\\etc", progFilesPath, findData.cFileName); - FindClose(hFind); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Using Mono paths '%s' and '%s'.\n", libPath, etcPath); - mono_set_dirs(libPath, etcPath); - return SWITCH_STATUS_SUCCESS; - } + { + +char libPath[MAX_PATH]; + +char etcPath[MAX_PATH]; + +switch_snprintf(libPath, MAX_PATH, "%s\\%s\\lib", progFilesPath, findData.cFileName); + +switch_snprintf(etcPath, MAX_PATH, "%s\\%s\\etc", progFilesPath, findData.cFileName); + +FindClose(hFind); + +switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Using Mono paths '%s' and '%s'.\n", libPath, etcPath); + +mono_set_dirs(libPath, etcPath); + +return SWITCH_STATUS_SUCCESS; + +} #elif // On other platforms, it should just work if it hasn't been relocated - mono_set_dirs(NULL, NULL); - return SWITCH_STATUS_SUCCESS; + mono_set_dirs(NULL, NULL); -#endif /* */ -} - switch_status_t loadModMonoManaged() -{ +return SWITCH_STATUS_SUCCESS; + +#endif /* + */ +} + + +switch_status_t loadModMonoManaged() +{ /* Find and load mod_mono_managed.exe */ - char filename[256]; - switch_snprintf(filename, 256, "%s%s%s", SWITCH_GLOBAL_dirs.mod_dir, SWITCH_PATH_SEPARATOR, MOD_MONO_MANAGED_DLL); - globals.domain = mono_jit_init(filename); - if (!globals.domain) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mono_jit_init failed.\n"); - return SWITCH_STATUS_FALSE; - } - + char filename[256]; + +switch_snprintf(filename, 256, "%s%s%s", SWITCH_GLOBAL_dirs.mod_dir, SWITCH_PATH_SEPARATOR, MOD_MONO_MANAGED_DLL); + +globals.domain = mono_jit_init(filename); + + +if (!globals.domain) { + +switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mono_jit_init failed.\n"); + +return SWITCH_STATUS_FALSE; + +} + + /* Open the assembly */ - globals.mod_mono_asm = mono_domain_assembly_open(globals.domain, filename); - if (!globals.mod_mono_asm) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mono_domain_assembly_open failed.\n"); - return SWITCH_STATUS_FALSE; - } - return SWITCH_STATUS_SUCCESS; - } - - MonoMethod * getMethod(const char *name, MonoClass * klass) -{ - MonoMethodDesc * desc; - MonoMethod * method; - desc = mono_method_desc_new(name, TRUE); - method = mono_method_desc_search_in_class(desc, klass); - if (!method) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not find %s method.\n", name); - return NULL; - } - return method; - } - switch_status_t findLoader() -{ + globals.mod_mono_asm = mono_domain_assembly_open(globals.domain, filename); + +if (!globals.mod_mono_asm) { + +switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mono_domain_assembly_open failed.\n"); + +return SWITCH_STATUS_FALSE; + +} + +return SWITCH_STATUS_SUCCESS; + +} + + + +MonoMethod * getMethod(const char *name, MonoClass * klass) +{ + +MonoMethodDesc * desc; + +MonoMethod * method; + +desc = mono_method_desc_new(name, TRUE); + +method = mono_method_desc_search_in_class(desc, klass); + +if (!method) { + +switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not find %s method.\n", name); + +return NULL; + +} + +return method; + +} + + +switch_status_t findLoader() +{ /* Find loader class and methods */ - MonoImage * img; - MonoClass * loaderClass; - img = mono_assembly_get_image(globals.mod_mono_asm); - loaderClass = mono_class_from_name(img, "FreeSWITCH", "Loader"); - if (!loaderClass) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not find FreeSWITCH.Loader class.\n"); - return SWITCH_STATUS_FALSE; - } - globals.loadMethod = getMethod("FreeSWITCH.Loader:Load()", loaderClass); - if (!globals.loadMethod) - return SWITCH_STATUS_FALSE; - globals.unloadMethod = getMethod("FreeSWITCH.Loader:Unload()", loaderClass); - if (!globals.unloadMethod) - return SWITCH_STATUS_FALSE; - globals.runMethod = getMethod("FreeSWITCH.Loader:Run(string,intptr)", loaderClass); - if (!globals.runMethod) - return SWITCH_STATUS_FALSE; - globals.executeMethod = getMethod("FreeSWITCH.Loader:Execute(string,intptr,intptr)", loaderClass); - if (!globals.executeMethod) - return SWITCH_STATUS_FALSE; - globals.executeBackgroundMethod = getMethod("FreeSWITCH.Loader:ExecuteBackground(string)", loaderClass); - if (!globals.executeBackgroundMethod) - return SWITCH_STATUS_FALSE; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Found all loader functions.\n"); - return SWITCH_STATUS_SUCCESS; - } - - SWITCH_MODULE_LOAD_FUNCTION(mod_mono_load) -{ + MonoImage * img; + +MonoClass * loaderClass; + +img = mono_assembly_get_image(globals.mod_mono_asm); + +loaderClass = mono_class_from_name(img, "FreeSWITCH", "Loader"); + +if (!loaderClass) { + +switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not find FreeSWITCH.Loader class.\n"); + +return SWITCH_STATUS_FALSE; + +} + + +globals.loadMethod = getMethod("FreeSWITCH.Loader:Load()", loaderClass); + +if (!globals.loadMethod) + return SWITCH_STATUS_FALSE; + + +globals.unloadMethod = getMethod("FreeSWITCH.Loader:Unload()", loaderClass); + +if (!globals.unloadMethod) + return SWITCH_STATUS_FALSE; + + +globals.runMethod = getMethod("FreeSWITCH.Loader:Run(string,intptr)", loaderClass); + +if (!globals.runMethod) + return SWITCH_STATUS_FALSE; + + +globals.executeMethod = getMethod("FreeSWITCH.Loader:Execute(string,intptr,intptr)", loaderClass); + +if (!globals.executeMethod) + return SWITCH_STATUS_FALSE; + + +globals.executeBackgroundMethod = getMethod("FreeSWITCH.Loader:ExecuteBackground(string)", loaderClass); + +if (!globals.executeBackgroundMethod) + return SWITCH_STATUS_FALSE; + + +switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Found all loader functions.\n"); + +return SWITCH_STATUS_SUCCESS; + +} + + + +SWITCH_MODULE_LOAD_FUNCTION(mod_mono_load) +{ /* connect my internal structure to the blank pointer passed to me */ - *module_interface = switch_loadable_module_create_module_interface(pool, modname); - globals.pool = pool; - if (setMonoDirs() != SWITCH_STATUS_SUCCESS) { - return SWITCH_STATUS_FALSE; - } - if (loadModMonoManaged() != SWITCH_STATUS_SUCCESS) { - return SWITCH_STATUS_FALSE; - } - if (findLoader() != SWITCH_STATUS_SUCCESS) { - return SWITCH_STATUS_FALSE; - } - + *module_interface = switch_loadable_module_create_module_interface(pool, modname); + +globals.pool = pool; + + +if (setMonoDirs() != SWITCH_STATUS_SUCCESS) { + +return SWITCH_STATUS_FALSE; + +} + +if (loadModMonoManaged() != SWITCH_STATUS_SUCCESS) { + +return SWITCH_STATUS_FALSE; + +} + +if (findLoader() != SWITCH_STATUS_SUCCESS) { + +return SWITCH_STATUS_FALSE; + +} + + /* Not sure if this is necesary on the loading thread */ - mono_thread_attach(globals.domain); - mono_add_internal_call("FreeSWITCH.Native.MonoSession::InitMonoSession", InitMonoSession); - + mono_thread_attach(globals.domain); + +mono_add_internal_call("FreeSWITCH.Native.MonoSession::InitMonoSession", InitMonoSession); + + /* Run loader */ - MonoObject * objResult; - MonoObject * exception = NULL; - objResult = mono_runtime_invoke(globals.loadMethod, NULL, NULL, &exception); - if (exception) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Load threw an exception.\n"); - mono_print_unhandled_exception(exception); - return SWITCH_STATUS_FALSE; - } - if (*(int *) mono_object_unbox(objResult)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Load completed successfully.\n"); - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Load did not return true.\n"); - return SWITCH_STATUS_FALSE; - } - + MonoObject * objResult; + +MonoObject * exception = NULL; + +objResult = mono_runtime_invoke(globals.loadMethod, NULL, NULL, &exception); + +if (exception) { + +switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Load threw an exception.\n"); + +mono_print_unhandled_exception(exception); + +return SWITCH_STATUS_FALSE; + +} + +if (*(int *) mono_object_unbox(objResult)) { + +switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Load completed successfully.\n"); + +} else { + +switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Load did not return true.\n"); + +return SWITCH_STATUS_FALSE; + +} + + + /* We're good to register */ - switch_api_interface_t *api_interface; - switch_application_interface_t *app_interface; - SWITCH_ADD_API(api_interface, "monorun", "Run a module (ExecuteBackground)", monorun_api_function, " []"); - SWITCH_ADD_API(api_interface, "mono", "Run a module as an API function (Execute)", mono_api_function, " []"); - SWITCH_ADD_APP(app_interface, "mono", "Run Mono IVR", "Run a Mono IVR on a channel", mono_app_function, " []", SAF_NONE); - return SWITCH_STATUS_SUCCESS; - } - - SWITCH_STANDARD_API(monorun_api_function) -{ + switch_api_interface_t *api_interface; + +switch_application_interface_t *app_interface; + + +SWITCH_ADD_API(api_interface, "monorun", "Run a module (ExecuteBackground)", monorun_api_function, " []"); + +SWITCH_ADD_API(api_interface, "mono", "Run a module as an API function (Execute)", mono_api_function, " []"); + +SWITCH_ADD_APP(app_interface, "mono", "Run Mono IVR", "Run a Mono IVR on a channel", mono_app_function, " []", SAF_NONE); + + +return SWITCH_STATUS_SUCCESS; + +} + + + +SWITCH_STANDARD_API(monorun_api_function) +{ // TODO: Should we be detaching after all this? - mono_thread_attach(globals.domain); - if (switch_strlen_zero(cmd)) { - stream->write_function(stream, "-ERR no args specified!\n"); - return SWITCH_STATUS_SUCCESS; - } - + mono_thread_attach(globals.domain); + +if (switch_strlen_zero(cmd)) { + +stream->write_function(stream, "-ERR no args specified!\n"); + +return SWITCH_STATUS_SUCCESS; + +} + + // ExecuteBackground(string command) - void *args[1]; - args[0] = mono_string_new(globals.domain, cmd); - MonoObject * exception = NULL; - MonoObject * objResult = mono_runtime_invoke(globals.executeBackgroundMethod, NULL, args, &exception); - if (exception) { - stream->write_function(stream, "-ERR FreeSWITCH.Loader.ExecuteBackground threw an exception.\n"); - mono_print_unhandled_exception(exception); - return SWITCH_STATUS_SUCCESS; - } - if (*(int *) mono_object_unbox(objResult)) { - stream->write_function(stream, "+OK\n"); - } else { - stream->write_function(stream, "-ERR ExecuteBackground returned false (unknown module?).\n"); - } - return SWITCH_STATUS_SUCCESS; - } - - SWITCH_STANDARD_API(mono_api_function) -{ - mono_thread_attach(globals.domain); - if (switch_strlen_zero(cmd)) { - stream->write_function(stream, "-ERR no args specified!\n"); - return SWITCH_STATUS_SUCCESS; - } - + void *args[1]; + +args[0] = mono_string_new(globals.domain, cmd); + +MonoObject * exception = NULL; + +MonoObject * objResult = mono_runtime_invoke(globals.executeBackgroundMethod, NULL, args, &exception); + +if (exception) { + +stream->write_function(stream, "-ERR FreeSWITCH.Loader.ExecuteBackground threw an exception.\n"); + +mono_print_unhandled_exception(exception); + +return SWITCH_STATUS_SUCCESS; + +} + +if (*(int *) mono_object_unbox(objResult)) { + +stream->write_function(stream, "+OK\n"); + +} else { + +stream->write_function(stream, "-ERR ExecuteBackground returned false (unknown module?).\n"); + +} + +return SWITCH_STATUS_SUCCESS; + +} + + + +SWITCH_STANDARD_API(mono_api_function) +{ + +mono_thread_attach(globals.domain); + +if (switch_strlen_zero(cmd)) { + +stream->write_function(stream, "-ERR no args specified!\n"); + +return SWITCH_STATUS_SUCCESS; + +} + + // Method is: Execute(string command, IntPtr streamPtr, IntPtr eventPtr) - void *args[3]; - args[0] = mono_string_new(globals.domain, cmd); - args[1] = &stream; // Address of the arguments - args[2] = &(stream->param_event); - MonoObject * exception = NULL; - MonoObject * objResult = mono_runtime_invoke(globals.executeMethod, NULL, args, &exception); - if (exception) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Exception trying to execute mono %s.\n", cmd); - mono_print_unhandled_exception(exception); - } - if (!(*(int *) mono_object_unbox(objResult))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Execute failed for %s (unknown module?).\n", cmd); - } - return SWITCH_STATUS_SUCCESS; - } - - SWITCH_STANDARD_APP(mono_app_function) -{ - mono_thread_attach(globals.domain); - if (switch_strlen_zero(data)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No args specified!\n"); - } - + void *args[3]; + +args[0] = mono_string_new(globals.domain, cmd); + +args[1] = &stream; // Address of the arguments + args[2] = &(stream->param_event); + + +MonoObject * exception = NULL; + +MonoObject * objResult = mono_runtime_invoke(globals.executeMethod, NULL, args, &exception); + +if (exception) { + +switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Exception trying to execute mono %s.\n", cmd); + +mono_print_unhandled_exception(exception); + +} + +if (!(*(int *) mono_object_unbox(objResult))) { + +switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Execute failed for %s (unknown module?).\n", cmd); + +} + +return SWITCH_STATUS_SUCCESS; + +} + + + +SWITCH_STANDARD_APP(mono_app_function) +{ + +mono_thread_attach(globals.domain); + +if (switch_strlen_zero(data)) { + +switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No args specified!\n"); + +} + + // bool Run(string command, IntPtr sessionHandle) - void *args[2]; - args[0] = mono_string_new(globals.domain, data); - args[1] = &session; - MonoObject * exception = NULL; - MonoObject * objResult = mono_runtime_invoke(globals.runMethod, NULL, args, &exception); - if (exception) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Exception trying to execute application mono %s.\n", data); - mono_print_unhandled_exception(exception); - } - if (!(*(int *) mono_object_unbox(objResult))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Application run failed for %s (unknown module?).\n", data); - } - } SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_mono_shutdown) -{ - mono_thread_attach(globals.domain); - MonoObject * ex; - mono_runtime_invoke(globals.unloadMethod, NULL, NULL, &ex); - if (ex) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Exception occurred in Loader::Unload.\n"); - mono_print_unhandled_exception(ex); - } - mono_runtime_set_shutting_down(); - mono_runtime_cleanup(globals.domain); - mono_runtime_quit(); - return SWITCH_STATUS_SUCCESS; - } - - SWITCH_END_EXTERN_C + void *args[2]; + +args[0] = mono_string_new(globals.domain, data); + +args[1] = &session; + + +MonoObject * exception = NULL; + +MonoObject * objResult = mono_runtime_invoke(globals.runMethod, NULL, args, &exception); + +if (exception) { + +switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Exception trying to execute application mono %s.\n", data); + +mono_print_unhandled_exception(exception); + +} + +if (!(*(int *) mono_object_unbox(objResult))) { + +switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Application run failed for %s (unknown module?).\n", data); + +} + +} + +SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_mono_shutdown) +{ + +mono_thread_attach(globals.domain); + +MonoObject * ex; + +mono_runtime_invoke(globals.unloadMethod, NULL, NULL, &ex); + +if (ex) { + +switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Exception occurred in Loader::Unload.\n"); + +mono_print_unhandled_exception(ex); + +} + +mono_runtime_set_shutting_down(); + +mono_runtime_cleanup(globals.domain); + +mono_runtime_quit(); + +return SWITCH_STATUS_SUCCESS; + +} + + + +SWITCH_END_EXTERN_C diff --git a/src/mod/languages/mod_mono_managed/AppFunction.cs b/src/mod/languages/mod_mono_managed/AppFunction.cs index f6e2048446..160c68e650 100644 --- a/src/mod/languages/mod_mono_managed/AppFunction.cs +++ b/src/mod/languages/mod_mono_managed/AppFunction.cs @@ -43,60 +43,6 @@ namespace FreeSWITCH protected static void Unload() { } - void hangupCallback() - { - Log.WriteLine(LogLevel.Debug, "AppFunction is in hangupCallback."); - try { - abortRun(); - var f = HangupFunction; - if (f != null) f(); - } - catch (Exception ex) { - Log.WriteLine(LogLevel.Warning, "Exception in hangupCallback: {0}", ex.ToString()); - throw; - } - } - - protected Action HangupFunction { get; set; } - - protected Func DtmfReceivedFunction { get; set; } - - protected Func EventReceivedFunction { get; set; } - - string inputCallback(IntPtr input, Native.switch_input_type_t inputType) - { - switch (inputType) { - case FreeSWITCH.Native.switch_input_type_t.SWITCH_INPUT_TYPE_DTMF: - using (var dtmf = new Native.switch_dtmf_t(input, false)) { - return dtmfCallback(dtmf); - } - case FreeSWITCH.Native.switch_input_type_t.SWITCH_INPUT_TYPE_EVENT: - using (var swevt = new Native.switch_event(input, false)) { - return eventCallback(swevt); - } - default: - return ""; - } - } - - string dtmfCallback(Native.switch_dtmf_t dtmf) - { - var f = DtmfReceivedFunction; - return f == null ? - "-ERR No DtmfReceivedFunction set." : - f(((char)(byte)dtmf.digit), TimeSpan.FromMilliseconds(dtmf.duration)); - } - - string eventCallback(Native.switch_event swevt) - { - using (var evt = new FreeSWITCH.Native.Event(swevt, 0)) { - var f = EventReceivedFunction; - return f == null ? - "-ERR No EventReceivedFunction set." : - f(evt); - } - } - protected Native.MonoSession Session { get; private set; } protected string Arguments { get; private set; } @@ -115,7 +61,7 @@ namespace FreeSWITCH bool abortable = false; readonly object abortLock = new object(); Thread runThread; - void abortRun() + internal void AbortRun() { if (!AbortOnHangup) return; if (runThread == Thread.CurrentThread) { @@ -136,7 +82,7 @@ namespace FreeSWITCH { this.Session = session; this.Arguments = args; - Session.SetDelegates(this.inputCallback, this.hangupCallback); + Session.AppToAbort = this; try { this.Uuid = new Guid(Session.GetUuid()); } catch { } try { diff --git a/src/mod/languages/mod_mono_managed/Demo.cs b/src/mod/languages/mod_mono_managed/Demo.cs index b63b1ca650..d7a77d9d36 100644 --- a/src/mod/languages/mod_mono_managed/Demo.cs +++ b/src/mod/languages/mod_mono_managed/Demo.cs @@ -53,13 +53,12 @@ namespace FreeSWITCH.Demo protected override void Run() { - HangupFunction = hangupHook; Session.Answer(); - this.DtmfReceivedFunction = (d, t) => { + Session.DtmfReceivedFunction = (d, t) => { Log.WriteLine(LogLevel.Info, "Received {0} for {1}.", d, t); return ""; }; - Log.WriteLine(LogLevel.Info, "Inside AppDemo.Run (args '{0}'); HookState is {1}.", Arguments, Session.HookState); + Log.WriteLine(LogLevel.Info, "Inside AppDemo.Run (args '{0}'); HookState is {1}. Now will collect digits.", Arguments, Session.HookState); Session.CollectDigits(5000); // Hanging up here will cause an abort and the next line won't be written Log.WriteLine(LogLevel.Info, "AppDemo is finishing its run and will now hang up."); Session.Hangup("USER_BUSY"); diff --git a/src/mod/languages/mod_mono_managed/Loader.cs b/src/mod/languages/mod_mono_managed/Loader.cs index 4d7c0bc377..ce5f515ee8 100644 --- a/src/mod/languages/mod_mono_managed/Loader.cs +++ b/src/mod/languages/mod_mono_managed/Loader.cs @@ -227,6 +227,7 @@ namespace FreeSWITCH if (fType == null) return false; using (var session = new Native.MonoSession(new Native.SWIGTYPE_p_switch_core_session(sessionHandle, false))) { + session.Initialize(); session.SetAutoHangup(false); try { var f = (AppFunction)Activator.CreateInstance(fType); diff --git a/src/mod/languages/mod_mono_managed/MonoSession.cs b/src/mod/languages/mod_mono_managed/MonoSession.cs index 24c48b5222..8902928707 100644 --- a/src/mod/languages/mod_mono_managed/MonoSession.cs +++ b/src/mod/languages/mod_mono_managed/MonoSession.cs @@ -35,7 +35,7 @@ using System.Text; namespace FreeSWITCH.Native { - //switch_status_t MonoSession::run_dtmf_callback(void *input, switch_input_type_t itype) + // switch_status_t MonoSession::run_dtmf_callback(void *input, switch_input_type_t itype) // But, process_callback_result is used to turn a string into a switch_status_t using DtmfCallback = Func; public partial class MonoSession @@ -44,9 +44,68 @@ namespace FreeSWITCH.Native [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.InternalCall)] static extern void InitMonoSession(IntPtr sessionPtr, DtmfCallback dtmfDelegate, Action hangupDelegate); - internal void SetDelegates(DtmfCallback dtmfCallback, Action hangupHook) + /// Initializes the native MonoSession. Must be called after Originate. + public void Initialize() { - InitMonoSession(MonoSession.getCPtr(this).Handle, dtmfCallback, hangupHook); + InitMonoSession(MonoSession.getCPtr(this).Handle, inputCallback, hangupCallback); + } + + /// Function to execute when this session hangs up. + public Action HangupFunction { get; set; } + + /// Sets the application that should have it's run thread aborted (if enabled) when this session is hungup. + internal AppFunction AppToAbort { get; set; } + + void hangupCallback() + { + Log.WriteLine(LogLevel.Debug, "AppFunction is in hangupCallback."); + try { + if (AppToAbort != null) AppToAbort.AbortRun(); + var f = HangupFunction; + if (f != null) f(); + } + catch (Exception ex) { + Log.WriteLine(LogLevel.Warning, "Exception in hangupCallback: {0}", ex.ToString()); + throw; + } + } + + public Func DtmfReceivedFunction { get; set; } + + public Func EventReceivedFunction { get; set; } + + string inputCallback(IntPtr input, Native.switch_input_type_t inputType) + { + switch (inputType) { + case FreeSWITCH.Native.switch_input_type_t.SWITCH_INPUT_TYPE_DTMF: + using (var dtmf = new Native.switch_dtmf_t(input, false)) { + return dtmfCallback(dtmf); + } + case FreeSWITCH.Native.switch_input_type_t.SWITCH_INPUT_TYPE_EVENT: + using (var swevt = new Native.switch_event(input, false)) { + return eventCallback(swevt); + } + default: + return ""; + } + } + + string dtmfCallback(Native.switch_dtmf_t dtmf) + { + var f = DtmfReceivedFunction; + return f == null ? + "-ERR No DtmfReceivedFunction set." : + f(((char)(byte)dtmf.digit), TimeSpan.FromMilliseconds(dtmf.duration)); + } + + string eventCallback(Native.switch_event swevt) + { + using (var evt = new FreeSWITCH.Native.Event(swevt, 0)) { + var f = EventReceivedFunction; + return f == null ? + "-ERR No EventReceivedFunction set." : + f(evt); + } } }