1 /*
2  * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application - mod_managed
3  * Copyright (C) 2008, Michael Giagnocavo <mgg@giagnocavo.net>
4  *
5  * Version: MPL 1.1
6  *
7  * The contents of this file are subject to the Mozilla Public License Version
8  * 1.1 (the "License"); you may not use this file except in compliance with
9  * the License. You may obtain a copy of the License at
10  * http://www.mozilla.org/MPL/
11  *
12  * Software distributed under the License is distributed on an "AS IS" basis,
13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14  * for the specific language governing rights and limitations under the
15  * License.
16  *
17  * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application - mod_managed
18  *
19  * The Initial Developer of the Original Code is
20  * Michael Giagnocavo <mgg@giagnocavo.net>
21  * Portions created by the Initial Developer are Copyright (C)
22  * the Initial Developer. All Rights Reserved.
23  *
24  * Contributor(s):
25  *
26  * Michael Giagnocavo <mgg@giagnocavo.net>
27  *
28  * EventBinding.cs - Helpers for switch_event_bind function
29  *
30  */
31 using System;
32 using System.Collections.Generic;
33 using System.Linq;
34 using System.Text;
35 using System.Runtime.InteropServices;
36 using System.Reflection;
37 using FreeSWITCH.Native;
38 
39 namespace FreeSWITCH
40 {
41     public class SwitchEventWrap : switch_event, IDisposable
42     {
43         private bool disposed;
44         private SWIGTYPE_p_p_switch_event p_p_switch_event;
45         private IntPtr native_ptr_ptr;
46 
SwitchEventWrap(IntPtr ptrPtr)47         internal SwitchEventWrap(IntPtr ptrPtr) : base((IntPtr)Marshal.PtrToStructure(ptrPtr, typeof(IntPtr)), false)
48         {
49             native_ptr_ptr = ptrPtr;
50             p_p_switch_event = new SWIGTYPE_p_p_switch_event(ptrPtr, false);
51         }
52 
~SwitchEventWrap()53         ~SwitchEventWrap()
54         {
55             dispose();
56         }
57 
Dispose()58         public override void Dispose()
59         {
60             dispose();
61             GC.SuppressFinalize(this);
62         }
63 
dispose()64         internal void dispose()
65         {
66             if (disposed) return;
67             disposed = true;
68             freeswitch.switch_event_destroy(p_p_switch_event);
69             Marshal.FreeCoTaskMem(native_ptr_ptr);
70         }
71     }
72 
73     public class EventBinding : IDisposable
74     {
75 
76         public class EventBindingArgs : EventArgs
77         {
78             public switch_event EventObj { get; set; }
79         }
80 
81         //typedef void (*switch_event_callback_t) (switch_event_t *);
82 
83         [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
switch_event_callback_delegate(IntPtr event_data)84         delegate void switch_event_callback_delegate(IntPtr event_data);
85 
86         readonly switch_event_callback_delegate del; // Prevent GC
87         readonly SWIGTYPE_p_f_p_switch_event__void function;
88 
EventBinding(SWIGTYPE_p_f_p_switch_event__void function, switch_event_callback_delegate origDelegate)89         private EventBinding(SWIGTYPE_p_f_p_switch_event__void function, switch_event_callback_delegate origDelegate)
90         {
91             this.function = function;
92             this.del = origDelegate;
93         }
94         bool disposed;
Dispose()95         public void Dispose()
96         {
97             dispose();
98             GC.SuppressFinalize(this);
99         }
dispose()100         void dispose()
101         {
102             if (disposed) return;
103             // HACK: FS crashes if we unbind after shutdown is pretty complete. This is still a race condition.
104             if (freeswitch.switch_core_ready() == switch_bool_t.SWITCH_FALSE) return;
105             freeswitch.switch_event_unbind_callback(this.function);
106             disposed = true;
107         }
~EventBinding()108         ~EventBinding()
109         {
110             dispose();
111         }
SwitchEventDupe(switch_event evt)112         public static switch_event SwitchEventDupe(switch_event evt)
113         {
114             IntPtr clone_ptr_ptr = Marshal.AllocCoTaskMem(IntPtr.Size);
115             freeswitch.switch_event_dup(new SWIGTYPE_p_p_switch_event(clone_ptr_ptr, false), evt);
116             SwitchEventWrap dupe_evt = new SwitchEventWrap(clone_ptr_ptr);
117             return dupe_evt;
118         }
Bind(string id, switch_event_types_t event_types, string subclass_name, Action<EventBindingArgs> f, bool dupe)119         public static IDisposable Bind(string id, switch_event_types_t event_types, string subclass_name, Action<EventBindingArgs> f, bool dupe)
120         {
121             switch_event_callback_delegate boundFunc;
122             if (dupe)
123             {
124                 boundFunc = (eventObj) =>
125                 {
126                     var args = new EventBindingArgs { EventObj = SwitchEventDupe(new switch_event(eventObj,false)) };
127                     f(args);
128                 };
129             }
130             else
131             {
132                 boundFunc = (eventObj) =>
133                 {
134                     var args = new EventBindingArgs { EventObj = new switch_event(eventObj, false) };
135                     f(args);
136                 };
137             }
138             var fp = Marshal.GetFunctionPointerForDelegate(boundFunc);
139             var swigFp = new SWIGTYPE_p_f_p_switch_event__void(fp, false);
140             var res = freeswitch.switch_event_bind(id, event_types, subclass_name, swigFp, null);
141             if (res != switch_status_t.SWITCH_STATUS_SUCCESS)
142             {
143                 throw new InvalidOperationException("Call to switch_event_bind failed, result: " + res + ".");
144             }
145             return new EventBinding(swigFp, boundFunc);
146         }
147     }
148 }