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); }