/* * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application - mod_managed * Copyright (C) 2008, Michael Giagnocavo * * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application - mod_managed * * The Initial Developer of the Original Code is * Michael Giagnocavo * Portions created by the Initial Developer are Copyright (C) * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Michael Giagnocavo * * EventBinding.cs - Helpers for switch_event_bind function * */ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.InteropServices; using System.Reflection; using FreeSWITCH.Native; namespace FreeSWITCH { public class SwitchEventWrap : switch_event, IDisposable { private bool disposed; private SWIGTYPE_p_p_switch_event p_p_switch_event; private IntPtr native_ptr_ptr; internal SwitchEventWrap(IntPtr ptrPtr) : base((IntPtr)Marshal.PtrToStructure(ptrPtr, typeof(IntPtr)), false) { native_ptr_ptr = ptrPtr; p_p_switch_event = new SWIGTYPE_p_p_switch_event(ptrPtr, false); } ~SwitchEventWrap() { dispose(); } public override void Dispose() { dispose(); GC.SuppressFinalize(this); } internal void dispose() { if (disposed) return; disposed = true; freeswitch.switch_event_destroy(p_p_switch_event); Marshal.FreeCoTaskMem(native_ptr_ptr); } } public class EventBinding : IDisposable { public class EventBindingArgs : EventArgs { public switch_event EventObj { get; set; } } //typedef void (*switch_event_callback_t) (switch_event_t *); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] delegate void switch_event_callback_delegate(IntPtr event_data); readonly switch_event_callback_delegate del; // Prevent GC readonly SWIGTYPE_p_f_p_switch_event__void function; private EventBinding(SWIGTYPE_p_f_p_switch_event__void function, switch_event_callback_delegate origDelegate) { this.function = function; this.del = origDelegate; } bool disposed; public void Dispose() { dispose(); GC.SuppressFinalize(this); } void dispose() { if (disposed) return; // HACK: FS crashes if we unbind after shutdown is pretty complete. This is still a race condition. if (freeswitch.switch_core_ready() == switch_bool_t.SWITCH_FALSE) return; freeswitch.switch_event_unbind_callback(this.function); disposed = true; } ~EventBinding() { dispose(); } public static switch_event SwitchEventDupe(switch_event evt) { IntPtr clone_ptr_ptr = Marshal.AllocCoTaskMem(IntPtr.Size); freeswitch.switch_event_dup(new SWIGTYPE_p_p_switch_event(clone_ptr_ptr, false), evt); SwitchEventWrap dupe_evt = new SwitchEventWrap(clone_ptr_ptr); return dupe_evt; } public static IDisposable Bind(string id, switch_event_types_t event_types, string subclass_name, Action f, bool dupe) { switch_event_callback_delegate boundFunc; if (dupe) { boundFunc = (eventObj) => { var args = new EventBindingArgs { EventObj = SwitchEventDupe(new switch_event(eventObj,false)) }; f(args); }; } else { boundFunc = (eventObj) => { var args = new EventBindingArgs { EventObj = new switch_event(eventObj, false) }; f(args); }; } var fp = Marshal.GetFunctionPointerForDelegate(boundFunc); var swigFp = new SWIGTYPE_p_f_p_switch_event__void(fp, false); var res = freeswitch.switch_event_bind(id, event_types, subclass_name, swigFp, null); if (res != switch_status_t.SWITCH_STATUS_SUCCESS) { throw new InvalidOperationException("Call to switch_event_bind failed, result: " + res + "."); } return new EventBinding(swigFp, boundFunc); } } }