2

I'm trying to start a conference by using UCMA 4.0 basic conferencing sample and first user endpoint stuck at establishing the call (it's lync is not ringing). Timeout exception is triggered after a while. What's the main problem ?

BTW, platform is being started already with discovering 3 application endpoints as established.

sip:kl.dev.local@dev.local;gruu;opaque=srvr:yyapp:EHghH8UXNVqIedXU3YgJyQAAYYApp sip:kl.cdev.local@dev.local;gruu;opaque=srvr:yyapp:EHghH8UXNVqIedXU3YgJyQAAMachine1 sip:kl.dev.local@dev.local;gruu;opaque=srvr:yyapp:EHghH8UXNVqIedXU3YgJyQAAMachine2 sip:kl.dev.local@dev.local;gruu;opaque=srvr:yyapp:EHghH8UXNVqIedXU3YgJyQAAMachine3 'LyncGame.Gateway.TestConnection.vshost.exe' (CLR v4.0.30319: LyncGame.Gateway.TestConnection.vshost.exe): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Data.SqlXml\v4.0_4.0.0.0__b77a5c561934e089\System.Data.SqlXml.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled. 'LyncGame.Gateway.TestConnection.vshost.exe' (CLR v4.0.30319: LyncGame.Gateway.TestConnection.vshost.exe): Loaded 'System.Xml.Xsl.CompiledQuery.1'. The thread 0x6e8 has exited with code 259 (0x103). The thread 0x3dd4 has exited with code 259 (0x103). The thread 0x2138 has exited with code 259 (0x103). 'LyncGame.Gateway.TestConnection.vshost.exe' (CLR v4.0.30319: LyncGame.Gateway.TestConnection.vshost.exe): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Security\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Security.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled. The thread 0x3180 has exited with code 259 (0x103). The thread 0x350c has exited with code 259 (0x103). The thread 0x1698 has exited with code 0 (0x0). The thread 0x3ef4 has exited with code 0 (0x0). The thread 0x3f00 has exited with code 259 (0x103). The thread 0x2a24 has exited with code 259 (0x103). The thread 0x3fc0 has exited with code 259 (0x103). The thread 0x3750 has exited with code 259 (0x103). The thread 0x27b8 has exited with code 259 (0x103). The thread 0x11e0 has exited with code 259 (0x103). The thread 0x2214 has exited with code 259 (0x103). The thread 0x1564 has exited with code 259 (0x103). The thread 0x3740 has exited with code 259 (0x103). The thread 0x28a8 has exited with code 259 (0x103). The thread 0x1da8 has exited with code 259 (0x103). A first chance exception of type 'Microsoft.Rtc.Signaling.OperationTimeoutException' occurred in Microsoft.Rtc.Collaboration.dll

class UCMAConference
{
    #region Locals
    // The IM to send upon joining the MCU.
    private static String _messageToSend = "Hello, World!";

    private Conference _conference;

    private ApplicationEndpoint _callerEndpoint, _calleeEndpoint;

    //Wait handles are only present to keep things synchronous and easy to read.
    private AutoResetEvent _waitForCallEstablish = new AutoResetEvent(false);

    private AutoResetEvent _waitForConferenceScheduling = new AutoResetEvent(false);

    private AutoResetEvent _waitForConferenceJoin = new AutoResetEvent(false);

    private AutoResetEvent _waitForMessageReceived = new AutoResetEvent(false);

    private AutoResetEvent _waitForMessage2Received = new AutoResetEvent(false);

    private AutoResetEvent waitForUserEndpointEstablish = new AutoResetEvent(false);

    private AutoResetEvent _waitForShutdown = new AutoResetEvent(false);

    private AutoResetEvent _waitForConversationInviteRemoteParticipants = new AutoResetEvent(false);

    private InstantMessagingFlow _IMFlow;

    private InstantMessagingFlow _IMFlow2;
    #endregion

    public Conference StartConference()
    {
        try
        {
            foreach (var item in PlatformDataProvider.DataProvider.AppEndpoints)
            {
                WriteLog.AddLine(item.EndpointUri + item.OwnerDisplayName);
                Console.WriteLine(item.EndpointUri + item.OwnerDisplayName);
            }
            // to create end point(s)
            UCMACoach ucmaCoach = new UCMACoach();
            UserEndpointSettings settings = new UserEndpointSettings("sip:user8@dev.local");

            UserEndpoint _userEndpoint = new UserEndpoint(PlatformDataProvider.DataProvider.CollabPlatform, settings);
            _userEndpoint.BeginEstablish(ar =>
            {
                try
                {
                    _userEndpoint.EndEstablish(ar);
                    waitForUserEndpointEstablish.Set();
                }
                catch (Exception ex)
                {
                    WriteLog.AddLine("Error on establish: " + ex.Message);
                    waitForUserEndpointEstablish.Set();
                }

            }, null);
            waitForUserEndpointEstablish.WaitOne();


            WriteLog.AddLine("User endpoint has been established ");
            _userEndpoint.LocalOwnerPresence.BeginSubscribe(r =>
            {

            }, null);

            //IAsyncResult result = _userEndpoint.LocalOwnerPresence.BeginPublishPresence(Microsoft.Rtc.Collaboration.Presence.PresenceAvailability.Busy);
            // Create a user endpoint, using the network credential object
            // defined above.
            _callerEndpoint = PlatformDataProvider.DataProvider.AppEndpoints[1];
            /* friendly name for conference leader endpoint */

            // Create a second user endpoint, using the network credential object
            // defined above.
            _calleeEndpoint = PlatformDataProvider.DataProvider.AppEndpoints[2];
            /* friendly name for conference attendee endpoint */

            // Get the URI for the user logged onto Microsoft Lync
            String _ocUserURI = "sip:user9@dev.local";

            // One of the endpoints schedules the conference in advance. At 
            // schedule time, all the conference settings are set.

            // The base conference settings object, used to set the policies for the conference.
            ConferenceScheduleInformation conferenceScheduleInformation = new ConferenceScheduleInformation();
            // An open meeting (participants can join who are not on the list), 
            // but requiring authentication (no anonymous users allowed.)
            conferenceScheduleInformation.AccessLevel = ConferenceAccessLevel.SameEnterprise;
            // The below flag determines whether or not the passcode is optional
            // for users joining the conference.
            conferenceScheduleInformation.IsPasscodeOptional = true;
            conferenceScheduleInformation.Passcode = "1357924680";
            // The verbose description of the conference
            conferenceScheduleInformation.Description = "StartReady | Conference Testing";
            // The below field indicates the date and time after which the conference can be deleted.
            conferenceScheduleInformation.ExpiryTime = System.DateTime.Now.AddHours(5);

            // These two lines assign a set of modalities (here, only 
            // InstantMessage) from the available MCUs to the conference. Custom
            // modalities (and their corresponding MCUs) may be added at this 
            // time as part of the extensibility model.
            ConferenceMcuInformation instantMessageMCU = new ConferenceMcuInformation(McuType.InstantMessaging);
            conferenceScheduleInformation.Mcus.Add(instantMessageMCU);

            // Now that the setup object is complete, schedule the conference 
            // using the conference services off of Endpoint. Note: the conference
            // organizer is considered a leader of the conference by default.
            _callerEndpoint.ConferenceServices.BeginScheduleConference(conferenceScheduleInformation,
                EndScheduleConference, _callerEndpoint.ConferenceServices);

            // Wait for the scheduling to complete.
            _waitForConferenceScheduling.WaitOne();

            // Now that the conference is scheduled, it's time to join it. As we
            // already have a reference to the conference object populated from
            // the EndScheduleConference call, we do not need to get the 
            // conference first. Initialize a conversation off of the endpoint, 
            // and join the conference from the uri provided above.
            Conversation callerConversation = new Conversation(_callerEndpoint);
            callerConversation.ConferenceSession.StateChanged += new
                EventHandler<StateChangedEventArgs<ConferenceSessionState>>(ConferenceSession_StateChanged);

            // Join and wait, again forcing synchronization.
            callerConversation.ConferenceSession.BeginJoin(_conference.ConferenceUri, null /*joinOptions*/,
                EndJoinConference, callerConversation.ConferenceSession);
            _waitForConferenceJoin.WaitOne();

            // Placing the calls on the conference-connected conversation 
            // connects to the respective MCUs. These calls may then be used to
            // communicate with the conference/MCUs.
            InstantMessagingCall instantMessagingCall = new InstantMessagingCall(callerConversation);

            // Hooking up event handlers and then placing the call.
            instantMessagingCall.InstantMessagingFlowConfigurationRequested +=
                this.instantMessagingCall_InstantMessagingFlowConfigurationRequested;
            instantMessagingCall.StateChanged += this._call_StateChanged;
            instantMessagingCall.BeginEstablish(EndCallEstablish, instantMessagingCall);

            //Synchronize to ensure that call has completed.
            _waitForCallEstablish.WaitOne();

            //send conf invite
            ConferenceInvitationDeliverOptions deliverOptions = new ConferenceInvitationDeliverOptions();
            deliverOptions.ToastMessage = new ToastMessage("Welcome to conference of StartReady Demo");

            ConferenceInvitation invitation = new ConferenceInvitation(callerConversation);
            invitation.BeginDeliver(_ocUserURI, deliverOptions, EndDeliverInvitation, invitation);

            // Synchronize to ensure that invitation is complete
            _waitForConversationInviteRemoteParticipants.WaitOne();

            //And from the other endpoint's perspective:
            //Initialize a conversation off of the endpoint, and join the 
            //conference from the uri provided above.
            Conversation calleeConversation = new Conversation(_calleeEndpoint);
            calleeConversation.ConferenceSession.StateChanged += new
                EventHandler<StateChangedEventArgs<ConferenceSessionState>>(ConferenceSession_StateChanged);

            // Join and wait, again forcing synchronization.
            calleeConversation.ConferenceSession.BeginJoin(_conference.ConferenceUri, null /*joinOptions*/,
                EndJoinConference, calleeConversation.ConferenceSession);
            _waitForConferenceJoin.WaitOne();

            // Placing the calls on the conference-connected conversation 
            // connects to the respective MCUs. These calls may then be used to
            //communicate with the conference/MCUs.
            InstantMessagingCall instantMessagingCall2 = new InstantMessagingCall(calleeConversation);

            //Hooking up event handlers and then placing the call.
            instantMessagingCall2.InstantMessagingFlowConfigurationRequested +=
                this.instantMessagingCall2_InstantMessagingFlowConfigurationRequested;
            instantMessagingCall2.StateChanged += this._call_StateChanged;
            instantMessagingCall2.BeginEstablish(EndCallEstablish, instantMessagingCall2);

            //Synchronize to ensure that call has completed.
            _waitForCallEstablish.WaitOne();

            //Synchronize to ensure that all messages are sent and received
            _waitForMessageReceived.WaitOne();

            //Wait for shutdown initiated by user
            //_waitForShutdown.WaitOne();

            //UCMASampleHelper.PauseBeforeContinuing("Press ENTER to shutdown and exit.");

            return _conference;
        }
        catch (Exception ex)
        {
            WriteLog.AddLine("Cannot start conference: " + ex.Message);
            return null;
        }
    }

    #region side methods
    void ConferenceSession_StateChanged(object sender, StateChangedEventArgs<ConferenceSessionState> e)
    {
        ConferenceSession confSession = sender as ConferenceSession;

        //Session participants allow for disambiguation.
        WriteLog.AddLine("The conference session with Local Participant: " +
            confSession.Conversation.LocalParticipant + " has changed state. " +
            "The previous conference state was: " + e.PreviousState +
            " and the current state is: " + e.State);
    }

    // Flow created indicates that there is a flow present to begin media 
    // operations with, and that it is no longer null.
    public void instantMessagingCall_InstantMessagingFlowConfigurationRequested
        (object sender, InstantMessagingFlowConfigurationRequestedEventArgs e)
    {
        InstantMessagingFlow instantMessagingFlow = sender as InstantMessagingFlow;
        WriteLog.AddLine("Caller's Flow Created.");
        instantMessagingFlow = e.Flow;
        _IMFlow = instantMessagingFlow;

        // Now that the flow is non-null, bind the event handlers for State
        // Changed and Message Received. When the flow goes active, (as 
        // indicated by the state changed event) the program will send the 
        // IM in the event handler.
        instantMessagingFlow.StateChanged += this.instantMessagingFlow_StateChanged;

        // Message Received is the event used to indicate that a message has
        // been received from the far end.
        instantMessagingFlow.MessageReceived += this.instantMessagingFlow_MessageReceived;
    }

    // Flow created indicates that there is a flow present to begin media
    // operations with, and that it is no longer null.
    public void instantMessagingCall2_InstantMessagingFlowConfigurationRequested(
        object sender, InstantMessagingFlowConfigurationRequestedEventArgs e)
    {
        InstantMessagingFlow instantMessagingFlow = sender as InstantMessagingFlow;
        WriteLog.AddLine("Callee's Flow Created.");
        instantMessagingFlow = e.Flow;
        _IMFlow2 = instantMessagingFlow;

        // Now that the flow is non-null, bind the event handlers for State 
        // Changed and Message Received. When the flow goes active, the 
        // program will send the IM in the event handler.
        instantMessagingFlow.StateChanged += this.instantMessagingFlow2_StateChanged;

        // Message Received is the event used to indicate that a message 
        // from the far end has been received.
        instantMessagingFlow.MessageReceived += this.instantMessagingFlow2_MessageReceived;
    }

    private void instantMessagingFlow_StateChanged(object sender, MediaFlowStateChangedEventArgs e)
    {
        InstantMessagingFlow instantMessagingFlow = sender as InstantMessagingFlow;

        WriteLog.AddLine("Flow state changed from " + e.PreviousState + " to " + e.State);

        //When flow is active, media operations (here, sending an IM) may begin.
        if (e.State == MediaFlowState.Active)
        {
            _IMFlow = instantMessagingFlow;
            WriteLog.AddLine("Please type the message to send...");
            string msg = Console.ReadLine();
            //Send the message on the InstantMessagingFlow.
            instantMessagingFlow.BeginSendInstantMessage(msg, EndSendMessage, instantMessagingFlow);
        }
    }

    private void instantMessagingFlow2_StateChanged(object sender, MediaFlowStateChangedEventArgs e)
    {
        InstantMessagingFlow instantMessagingFlow = sender as InstantMessagingFlow;

        WriteLog.AddLine("Flow state changed from " + e.PreviousState + " to " + e.State);

        //When flow is active, media operations (here, sending an IM) may begin.
        if (e.State == MediaFlowState.Active)
        {
            _IMFlow2 = instantMessagingFlow;
        }
    }

    private void EndSendMessage(IAsyncResult ar)
    {
        InstantMessagingFlow instantMessagingFlow = ar.AsyncState as InstantMessagingFlow;
        try
        {
            instantMessagingFlow.EndSendInstantMessage(ar);
            WriteLog.AddLine("The message has been sent.");
        }
        catch (OperationTimeoutException opTimeEx)
        {
            // OperationFailureException: Indicates failure to connect the 
            // IM to the remote party due to timeout (called party failed 
            // to respond within the expected time).
            // TODO (Left to the reader): Add error handling code
            WriteLog.AddLine(opTimeEx.ToString());
        }
    }
    private void instantMessagingFlow_MessageReceived(object sender, InstantMessageReceivedEventArgs e)
    {
        InstantMessagingFlow instantMessagingFlow = sender as InstantMessagingFlow;
        //On an incoming Instant Message, print the contents to the console.
        WriteLog.AddLine("In caller's message handler: " + e.Sender.DisplayName + " said: " + e.TextBody);
        _waitForMessageReceived.Set();
    }

    private void instantMessagingFlow2_MessageReceived(object sender, InstantMessageReceivedEventArgs e)
    {
        InstantMessagingFlow instantMessagingFlow = sender as InstantMessagingFlow;
        //On an incoming Instant Message, print the contents to the console.
        WriteLog.AddLine("In callee's message handler: " + e.Sender.DisplayName + " said: " + e.TextBody);

        WriteLog.AddLine("Message received will be echoed");
        _messageToSend = "echo: " + e.TextBody;
        //Send the message on the InstantMessagingFlow.
        if (_IMFlow2 != null && _IMFlow2.State == MediaFlowState.Active)
        {
            _IMFlow2.BeginSendInstantMessage(_messageToSend, EndSendMessage, instantMessagingFlow);
        }
        else
            WriteLog.AddLine("Could not echo message because flow was either null or inactive");

        _waitForMessage2Received.Set();
    }

    private void EndCallEstablish(IAsyncResult ar)
    {
        Call call = ar.AsyncState as Call;
        try
        {
            call.EndEstablish(ar);
            WriteLog.AddLine("The call with Local Participant: " + call.Conversation.LocalParticipant +
                " and Remote Participant: " + call.RemoteEndpoint.Participant +
                " is now in the established state.");
        }
        catch (OperationFailureException opFailEx)
        {
            // OperationFailureException: Indicates failure to connect the 
            // call to the remote party.
            // TODO (Left to the reader): Add error handling code
            WriteLog.AddLine(opFailEx.ToString());
        }
        catch (RealTimeException exception)
        {
            // RealTimeException may be thrown on media or link-layer 
            //failures.
            // TODO (Left to the reader): Add error handling code
            WriteLog.AddLine(exception.ToString());
        }
        finally
        {
            //Again, just to sync the completion of the code.
            _waitForCallEstablish.Set();
        }
    }

    private void EndDeliverInvitation(IAsyncResult ar)
    {
        ConferenceInvitation invitation = ar.AsyncState as ConferenceInvitation;

        try
        {
            invitation.EndDeliver(ar);
        }
        catch (OperationFailureException opFailEx)
        {
            // OperationFailureException: Indicates failure to connect the 
            // call to the remote party.
            // TODO (Left to the reader): Add error handling code
            WriteLog.AddLine(opFailEx.ToString());
        }
        catch (RealTimeException exception)
        {
            // RealTimeException may be thrown on media or link-layer failures.
            // TODO (Left to the reader): Add error handling code
            WriteLog.AddLine(exception.ToString());
        }
        finally
        {
            //Again, just to sync the completion of the code.
            _waitForConversationInviteRemoteParticipants.Set();
        }
    }

    private void EndScheduleConference(IAsyncResult ar)
    {
        ConferenceServices confSession = ar.AsyncState as ConferenceServices;
        try
        {
            //End schedule conference returns the conference object, which 
            // contains the vast majority of the data relevant to that
            // conference.
            _conference = confSession.EndScheduleConference(ar);
            WriteLog.AddLine("");
            WriteLog.AddLine(" The conference is now scheduled.");
            WriteLog.AddLine("");

        }
        catch (ConferenceFailureException confFailEx)
        {
            // ConferenceFailureException may be thrown on failures to 
            // schedule due to MCUs being absent or unsupported, or due to
            // malformed parameters.
            // TODO (Left to the reader): Add error handling code
            WriteLog.AddLine(confFailEx.ToString());
        }

        //Again, for sync. reasons.
        _waitForConferenceScheduling.Set();
    }
    private void EndJoinConference(IAsyncResult ar)
    {
        ConferenceSession confSession = ar.AsyncState as ConferenceSession;
        try
        {
            confSession.EndJoin(ar);
        }
        catch (ConferenceFailureException confFailEx)
        {
            // ConferenceFailureException may be thrown on failures due to 
            // MCUs being absent or unsupported, or due to malformed parameters.
            // TODO (Left to the reader): Add error handling code
            WriteLog.AddLine(confFailEx.ToString());
        }
        catch (RealTimeException rTEx)
        {
            // TODO (Left to the reader): Add error handling code
            WriteLog.AddLine(rTEx.ToString());
        }
        finally
        {
            //Again, for sync. reasons.
            _waitForConferenceJoin.Set();
        }
    }

    //Just to record the state transitions in the console.
    void _call_StateChanged(object sender, CallStateChangedEventArgs e)
    {
        Call call = sender as Call;

        //Call participants allow for disambiguation.
        WriteLog.AddLine("The call with Local Participant: " + call.Conversation.LocalParticipant +
            " has changed state. The previous call state was: " + e.PreviousState +
            " and the current state is: " + e.State);
    }

    #endregion
}

}

  • 1
    Is there any chance of getting a call stack on the exception. For UCMA applications I would recommend adding exception logging to each of the UCMA event handlers this will make debugging your solution much simpler. – Paul Hodgson Jul 16 '15 at 08:24

1 Answers1

0

The other thing that's really useful here is to run OCSLogger on the application server and see what comes back. You can run S4 to get SIP traces. Might just be something simple like you're not able to receive messages on 5061 (or whichever callback port you specified in your provisioning). If it's only failing on A/V, look at what addresses are being used in the SDP offer/answer and see if those are reachable as well. Again, OCSLogger (or the Lync CLS) and Snooper are your friends here.

Chris Bardon
  • 430
  • 4
  • 13