forked from Mirrors/freeswitch
Add hangup handler for Originate, expose state handlers in general. Various fixes.
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@14861 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
parent
88b15b9e09
commit
26df0f6881
@ -21,6 +21,7 @@ static SWIG_CSharpStringHelperCallback SWIG_csharp_string_callback_real = NULL;
|
||||
%}
|
||||
|
||||
%pragma(csharp) imclasscode=%{
|
||||
|
||||
protected class SWIGStringHelper {
|
||||
|
||||
public delegate string SWIGStringDelegate(string message);
|
||||
@ -120,13 +121,14 @@ char * SWIG_csharp_string_callback(const char * str) {
|
||||
%ignore run_dtmf_callback;
|
||||
%ignore setDTMFCallback;
|
||||
|
||||
// These methods need a bit of wrapping help
|
||||
%csmethodmodifiers CoreSession::originate "protected";
|
||||
|
||||
// Rename some things to make them more .NET-like
|
||||
//%csmethodmodifiers CoreSession::hangup "internal";
|
||||
%rename (Answer) CoreSession::answer;
|
||||
%rename (Hangup) CoreSession::hangup;
|
||||
%rename (Ready) CoreSession::ready;
|
||||
%rename (Transfer) CoreSession::transfer;
|
||||
%rename (Originate) CoreSession::originate;
|
||||
%rename (SetVariable) CoreSession::setVariable;
|
||||
%rename (GetVariable) CoreSession::getVariable;
|
||||
%rename (SetPrivate) CoreSession::setPrivate;
|
||||
|
@ -69,7 +69,6 @@ ManagedSession::~ManagedSession()
|
||||
// Do auto-hangup ourselves because CoreSession can't call check_hangup_hook
|
||||
// after ManagedSession destruction (cause at point it's pure virtual)
|
||||
if (session) {
|
||||
channel = switch_core_session_get_channel(session);
|
||||
if (switch_test_flag(this, S_HUP) && !switch_channel_test_flag(channel, CF_TRANSFER)) {
|
||||
switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
|
||||
setAutoHangup(0);
|
||||
@ -104,3 +103,6 @@ switch_status_t ManagedSession::run_dtmf_callback(void *input, switch_input_type
|
||||
return status;
|
||||
}
|
||||
|
||||
static switch_status_t stateHangupHandler(switch_core_session_t *session) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
@ -41,7 +41,6 @@ SWITCH_BEGIN_EXTERN_C
|
||||
typedef void (*hangupFunction)(void);
|
||||
typedef char* (*inputFunction)(void*, switch_input_type_t);
|
||||
|
||||
|
||||
#ifndef _MANAGED
|
||||
#include <glib.h>
|
||||
#include <mono/jit/jit.h>
|
||||
@ -136,7 +135,6 @@ public:
|
||||
virtual bool begin_allow_threads();
|
||||
virtual bool end_allow_threads();
|
||||
virtual void check_hangup_hook();
|
||||
|
||||
virtual switch_status_t run_dtmf_callback(void *input, switch_input_type_t itype);
|
||||
|
||||
// P/Invoke function pointer to delegates
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -103,7 +103,7 @@ namespace FreeSWITCH.Native {
|
||||
/*** Times ***/
|
||||
const string created_time = "created_time";
|
||||
const string answered_time = "answered_time";
|
||||
const string hangup_time = "hangup_time";
|
||||
const string hangup_time = "hungup_time";
|
||||
const string progress_time = "progress_time";
|
||||
const string transfer_time = "transfer_time";
|
||||
|
||||
|
@ -295,6 +295,7 @@ namespace FreeSWITCH {
|
||||
pi.Manager.BlockUntilUnloadIsSafe();
|
||||
pi.Manager = null;
|
||||
pi.Domain = null;
|
||||
// This can crash if there is still sessions in the appdomain. Plugin code should use dispose properly.
|
||||
AppDomain.Unload(d);
|
||||
Log.WriteLine(LogLevel.Info, "Unloaded {0}, domain {1}.", pi.FileName, friendlyName);
|
||||
} catch (Exception ex) {
|
||||
|
@ -43,17 +43,21 @@ namespace FreeSWITCH.Native
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
delegate void CdeclAction();
|
||||
|
||||
// This callback is used for originate
|
||||
[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
|
||||
public delegate switch_status_t switch_state_handler_t_delegate(IntPtr sessionPtr);
|
||||
|
||||
public partial class ManagedSession
|
||||
{
|
||||
// SWITCH_DECLARE(void) InitManagedSession(ManagedSession *session, MonoObject *dtmfDelegate, MonoObject *hangupDelegate)
|
||||
[DllImport("mod_managed.dll", CharSet = CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)]
|
||||
[DllImport("mod_managed.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
|
||||
static extern void InitManagedSession(IntPtr sessionPtr, DtmfCallback dtmfDelegate, CdeclAction hangupDelegate);
|
||||
|
||||
/// <summary>Initializes the native ManagedSession. Must be called after Originate.</summary>
|
||||
public void Initialize()
|
||||
/// <summary>Initializes the native ManagedSession. Called after Originate completes successfully .</summary>
|
||||
internal void Initialize()
|
||||
{
|
||||
if (allocated == 0) {
|
||||
Log.WriteLine(LogLevel.Critical, "Cannot initialize a ManagedSession until it is allocated (originated successfully).");
|
||||
throw new InvalidOperationException("Cannot initialize a ManagedSession until it is allocated (originated successfully).");
|
||||
}
|
||||
// P/Invoke generated function pointers stick around until the delegate is collected
|
||||
// By sticking the delegates in fields, their lifetime won't be less than the session
|
||||
@ -121,6 +125,88 @@ namespace FreeSWITCH.Native
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("Use static Originate method.", false)]
|
||||
public bool Originate(CoreSession aLegSession, string destination, TimeSpan timeout) {
|
||||
var res = 0 == this.originate(aLegSession, destination, (int)timeout.TotalMilliseconds, null);
|
||||
if (res) {
|
||||
this.Initialize();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
// Creating these function pointers is a two-stage process.
|
||||
// The delegate needs to be stored so it doesn't get GC'd, so we can't just return GetFunctionPointerForDelegate right away.
|
||||
|
||||
/// <summary>Wraps a nice handler into a delegate suitable for reverse P/Invoke. This only currently works well for hangup/reporting handlers.</summary>
|
||||
public static switch_state_handler_t_delegate CreateStateHandlerDelegate(Action<ManagedSession> handler) {
|
||||
// We create a ManagedSession on top of the session so callbacks can use it "nicely"
|
||||
// Then we sort of dispose it.
|
||||
switch_state_handler_t_delegate del = ptr => {
|
||||
using (var sess = new ManagedSession(new SWIGTYPE_p_switch_core_session(ptr, false))) {
|
||||
handler(sess);
|
||||
return switch_status_t.SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
};
|
||||
return del;
|
||||
}
|
||||
public static SWIGTYPE_p_f_p_switch_core_session__switch_status_t WrapStateHandlerDelegate(switch_state_handler_t_delegate del) {
|
||||
return new SWIGTYPE_p_f_p_switch_core_session__switch_status_t(Marshal.GetFunctionPointerForDelegate(del), false);
|
||||
}
|
||||
|
||||
|
||||
// These are needed on the ManagedSession bleg, so they don't get GC'd
|
||||
// while the B Leg is still around
|
||||
switch_state_handler_t_delegate originate_onhangup_delegate;
|
||||
switch_state_handler_t_delegate originate_ondestroy_delegate;
|
||||
switch_state_handler_table originate_table;
|
||||
GCHandle originate_keepalive_handle; // Make sure the B Leg is not collected and disposed until we run ondestroy
|
||||
|
||||
switch_status_t originate_onhangup_method(IntPtr channelPtr) {
|
||||
// CS_DESTROY lets the bleg be collected
|
||||
// and frees originate_table memory
|
||||
// Note that this (bleg ManagedSession) is invalid
|
||||
// to touch right now - the unmanaged memory has already been free'd
|
||||
if (this.originate_keepalive_handle.IsAllocated) {
|
||||
this.originate_keepalive_handle.Free(); // GC can now collect this bleg
|
||||
}
|
||||
if (this.originate_table != null) {
|
||||
this.originate_table.Dispose();
|
||||
this.originate_table = null;
|
||||
}
|
||||
return switch_status_t.SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs originate. Returns ManagedSession on success, null on failure.
|
||||
/// onHangup is called as a state handler, after the channel is truly hungup.
|
||||
/// </summary>
|
||||
public static ManagedSession OriginateHandleHangup(CoreSession aLegSession, string destination, TimeSpan timeout, Action<ManagedSession> onHangup) {
|
||||
var bleg = new ManagedSession();
|
||||
|
||||
bleg.originate_ondestroy_delegate = bleg.originate_onhangup_method;
|
||||
bleg.originate_onhangup_delegate = CreateStateHandlerDelegate(sess_b => {
|
||||
if (onHangup != null) {
|
||||
onHangup(sess_b);
|
||||
}
|
||||
});
|
||||
bleg.originate_table = new switch_state_handler_table();
|
||||
bleg.originate_table.on_hangup = WrapStateHandlerDelegate(bleg.originate_onhangup_delegate);
|
||||
bleg.originate_table.on_destroy = WrapStateHandlerDelegate(bleg.originate_ondestroy_delegate);
|
||||
var res = 0 == bleg.originate(aLegSession, destination, (int)timeout.TotalSeconds, bleg.originate_table);
|
||||
bleg.originate_keepalive_handle = GCHandle.Alloc(bleg, GCHandleType.Normal); // Prevent GC from eating the bleg
|
||||
if (res) {
|
||||
bleg.Initialize();
|
||||
return bleg;
|
||||
} else {
|
||||
// Dispose to free the lock
|
||||
// The bleg lives on with its unmanaged memory freed
|
||||
// Until CS_DESTROY gets called
|
||||
bleg.Dispose();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Convenience
|
||||
public bool IsAvailable {
|
||||
get { return this.Ready(); }
|
||||
@ -128,8 +214,16 @@ namespace FreeSWITCH.Native
|
||||
|
||||
public Guid Uuid {
|
||||
get {
|
||||
if (allocated == 0) throw new InvalidOperationException("Session has not been initialized.");
|
||||
return new Guid(this.GetUuid());
|
||||
}
|
||||
}
|
||||
|
||||
public switch_call_cause_t CallCause {
|
||||
get {
|
||||
if (allocated == 0) throw new InvalidOperationException("Session has not been initialized.");
|
||||
return freeswitch.switch_channel_get_cause(this.channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -254,6 +254,7 @@ namespace FreeSWITCH {
|
||||
ApiExecutors.ForEach(x => x.SetZeroUseNotification(decreaseUnloadCount));
|
||||
AppExecutors.ForEach(x => x.SetZeroUseNotification(decreaseUnloadCount));
|
||||
unloadSignal.WaitOne();
|
||||
GC.WaitForPendingFinalizers();
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -288,7 +289,7 @@ namespace FreeSWITCH {
|
||||
// Ensure it's a plugin assembly
|
||||
var ourName = Assembly.GetExecutingAssembly().GetName().Name;
|
||||
if (!asm.GetReferencedAssemblies().Any(n => n.Name == ourName)) {
|
||||
Log.WriteLine(LogLevel.Debug, "Assembly {0} doesn't reference FreeSWITCH.Managed, not loading.");
|
||||
Log.WriteLine(LogLevel.Debug, "Assembly {0} doesn't reference FreeSWITCH.Managed, not loading.", asm.FullName);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user