private async Task <ConnectResult> InternalConnectAsync(List <List <CallDevice> > devices) { await API.API.SetupAsync(); ConnectResult resultConnect = new ConnectResult(); TaskCompletionSource <bool> tcsCompletion = new TaskCompletionSource <bool>(); // Hook callbacks temporarily to catch required events ConnectConnectedCallback connectedCallback = (a, c, cp, e, p) => { resultConnect.Event = new Event(e.EventType, JObject.FromObject(p)); resultConnect.Call = cp; tcsCompletion.SetResult(true); }; ConnectFailedCallback failedCallback = (a, c, e, p) => { resultConnect.Event = new Event(e.EventType, JObject.FromObject(p)); tcsCompletion.SetResult(false); }; OnConnectConnected += connectedCallback; OnConnectFailed += failedCallback; try { Task <LL_ConnectResult> taskLLConnect = mAPI.LL_ConnectAsync(new LL_ConnectParams() { CallID = ID, NodeID = NodeID, Devices = devices, }); // The use of await rethrows exceptions from the task LL_ConnectResult resultLLConnect = await taskLLConnect; if (resultLLConnect.Code == "200") { mLogger.LogDebug("Connect for call {0} waiting for completion events", ID); resultConnect.Successful = await tcsCompletion.Task; mLogger.LogDebug("Connect for call {0} {1}", ID, resultConnect.Successful ? "successful" : "unsuccessful"); } } catch (Exception exc) { mLogger.LogError(exc, "Connect for call {0} exception", ID); } // Unhook temporary callbacks OnConnectConnected -= connectedCallback; OnConnectFailed -= failedCallback; return(resultConnect); }
public async Task <Call> ConnectAsync(List <List <CallDevice> > devices) { await mAPI.Setup(); if (string.IsNullOrWhiteSpace(CallID)) { throw new ArgumentNullException("CallID"); } // Completion source and callbacks for detecting when an appropriate event is received TaskCompletionSource <bool> connectFinished = new TaskCompletionSource <bool>(); ConnectConnectedCallback connectedCallback = (a, c, cc, cp) => connectFinished.SetResult(true); ConnectFailedCallback failedCallback = (a, c, cp) => connectFinished.SetResult(false); // Hook temporary callbacks for the completion source OnConnectConnected += connectedCallback; OnConnectFailed += failedCallback; // TODO: Prevent connect on a call that is already being connected but may not yet have peer associated? or will FS error back if tried? Task <CallConnectResult> taskCallConnectResult = mAPI.LL_CallConnectAsync(new CallConnectParams() { CallID = CallID, NodeID = NodeID, Devices = devices, }); bool connected = false; try { // The use of await ensures that exceptions are rethrown, or OperationCancelledException is thrown CallConnectResult callConnectResult = await taskCallConnectResult; // If there was an internal error of any kind then throw an exception mAPI.ThrowIfError(callConnectResult.Code, callConnectResult.Message); // Wait for completion source, either connected or failed connect state connected = await connectFinished.Task; } catch { // Rethrow the exception, we catch and throw to ensure the finally block is called in case the exception // isn't caught up the stack otherwise, which can cause the finally block not to be called throw; } finally { // Unhook the temporary callbacks whether an exception occurs or not OnConnectConnected -= connectedCallback; OnConnectFailed -= failedCallback; } // We get here if no exceptions or errors occurred, this means it was connected and a peer will get returned, // or it failed and null is returned which means the call could not be connected but no real errors occurred if (!connected) { mLogger.LogWarning("Call {0} connect failed", CallID); } return(mPeer); }