Web Scheduler Walkthrough

This content is no longer actively maintained. It is provided as is, for anyone who may still be using these technologies, with no warranties or claims of accuracy with regard to the most recent product version or service release.

This walkthrough discusses the principal conference management features provided by the Unified Communications Managed API 2.0 Core SDK that can be used by a Web scheduler application, an application that presents a Web user interface that can be used to manage conference scheduling. The walkthrough focuses on conference management operations that an application must perform for Web scheduling. Other aspects of the application are left to the developer.

Starting the Collaboration Platform

A server platform initialized with a trusted service GRUU is the recommended choice for such an application.

ServerPlatformSettings platformSettings =
new ServerPlatformSettings(_applicationName, _localhost, _port, _trustedGruu, _certificate);

// We do not need the AudioVideo provider for conference management operations.
platformSettings.DefaultAudioVideoProviderEnabled = false;

// Create the CollaborationPlatform object.
_platform = new CollaborationPlatform(platformSettings);

// Start the the platform object.
_platform.BeginStartup(PlatformStartupCallback, state);

In the previous code example, the application passes the trusted service GRUU provisioned for the specified port on the hosting computer. The application must provide an appropriate certificate to enable MTLS as well.

Important

Because the platform uses a trusted service GRUU, any request initiated by an endpoint that uses this platform is not challenged by Office Communications Server. For that reason it is important for an application to authenticate a user through the Web interface using KERBEROS or other secure authentication method before proceeding with endpoint creation and executing user requests.

Creating a UserEndpoint Instance

The application must create an endpoint for each user. It is assumed that the application has already authenticated the user through KERBEROS or other form of secure authentication through the Web interface before proceeding with endpoint creation.

UserEndpointSettings userEndpointSettings = new UserEndpointSettings(_userUri, _userServer, 5061);

_userEndpoint = new UserEndpoint(_platform, userEndpointSettings);

There is no need to establish the endpoint for conference scheduling applications. This approach avoids multiple points of presence (MPOP) scenarios and other presence-related complications. In addition, the application must know the meeting policies that are provisioned for the user.

Scheduling a New Conference

At this stage the application is ready to schedule a conference on behalf of the user. The application first must retrieve information about the available conferencing capabilities, such as activated MCUs and phone access support, offered by the deployed Office Communications Server. In addition to these capabilities, the application must know the meeting policies provisioned for the user.

Retrieving Conference Capabilities

The following code example demonstrates how the application can retrieve the conferencing capabilities offered by the deployed Office Communications Server.

   _userEndpoint.ConferenceServices.BeginGetConferencingCapabilities(GetConferencingCapabilitiesCallback, state);


private void GetConferencingCapabilitiesCallback(IAsyncResult asyncResult)
{
  try
  {
    // Returns the conferencing capabilities available to the endpoint owner.
    _conferencingCapabilities = _userEndpoint.ConferenceServices.EndGetConferencingCapabilities(asyncResult);

    _avmcuAvailable = false;
    foreach (ConferenceMcuInformation mcuInformation in _conferencingCapabilities.Mcus)
    {
      if (McuType.AudioVideo == mcuInformation.McuType)
      {
        // Indicates that the AVMCU is activated.
        _avmcuAvailable = true;
      }
    }

    // Indicates whether phone access is supported.
    _isPhoneAccessSupported = _conferenceCapabilities.SupportsPhoneAccess;

  }
  catch (ConferenceFailureException cfex)
  {
    // Perform appropriate error handling here.
    // ConferenceFailureException wraps Centralized Conferencing Control Protocol (C3P) error information in the
    // Reason, GeneralReason, and DiagnosticInformation properties.
  }
  catch (RealTimeException rte)
  {
    // Perform appropriate error handling here.
    // RealTimeException and RealTimeException derivatives are thrown when no C3P error information is available.
  }
}

The ConferencingCapabilities instance that is returned contains the following information:

  • Activated MCUs in the system, such as the InstantMessaging MCU (IM MCU) and the AudioVideo MCU (AV MCU).

  • Whether the deployed Office Communications Server supports phone access, and if so, the available phone numbers and regions.

ConferencingCapabilities lists the activated MCUs in the system, but a user might be provisioned for Instant Messaging (IM) only and not audio. The application should permit such a user to schedule only IM-enabled conferences.

In addition to this information, the application must retrieve the user’s provisioning information to determine the meeting policy that applies to this user.

The user provisioning information also indicates whether a user can schedule conferences that allow anonymous users to bypass passcode verification. This is discussed further in a later section.

The next code example demonstrates how to retrieve and parse provisioning data.

_userEndpoint.BeginGetProvisioningData(GetProvisioningDataCallback, state);
private void GetProvisioningDataCallback(IAsyncResult asyncResult)
{
  try
  {
    _provisioningData = _userEndpoint.EndGetProvisioningData(asyncResult);
    ParseProvisioningData(_provisioningData, _isAudioAllowed, _canPasscodeVerificationBeOptional);
  }
  catch (RealTimeException rte)
  {
    // Perform appropriate error handling here.
  }
}

private static bool ParseProvisioningData(
    ProvisioningData provisioningData,
    out bool isAudioAllowed,
    out bool canPasscodeVerificationBeOptional)
{
  bool parsingSuccessful = false;

  // Assume false by default.
  isAudioAllowed = false;
  canPasscodeVerificationBeOptional = false;

  if (provisioningData != null &&
      provisioningData.MeetingPolicyConfiguration != null &&
      !string.IsNullOrEmpty(provisioningData.MeetingPolicyConfiguration.ElementXml))
  {
    // Parse the meeting policy section of the provisioning data.

    // The meeting policy XML blob does not have a root, so just add a fictitious root.
    string xml = string.Format("<{0}>{1}</{0}>", "root", provisioningData.MeetingPolicyConfiguration.ElementXml);

    XmlDocument meetingPolicyXML = new XmlDocument();
    meetingPolicyXML.LoadXml(xml);
    XmlNamespaceManager xmlnsMgr = new XmlNamespaceManager(meetingPolicyXML.NameTable);
    xmlnsMgr.AddNamespace("tempNs", "http://schemas.microsoft.com/2006/09/sip/provisiongrouplist-notification");

    // Confirm whether the endpoint owner is provisioned for audio.
    isAudioAllowed = GetProvisioningSetting(meetingPolicyXML, "root", "AllowIPAudio", xmlnsMgr);

    // Confirm whether passcode verfication can be optional.
    canPasscodeVerificationBeOptional = !GetProvisioningSetting(meetingPolicyXML, "root", "TrustedConferencingPinRequired", xmlnsMgr);

    parsingSuccessful = true;
  }
   
}

private static bool GetProvisioningSetting(
XmlDocument xmlDocument, 
string root, 
string provisioningKey, 
XmlNamespaceManager xmlnsMgr)
{
  string xpath = string.Format("//{0}/tempNs:property[@name='{1}']", root, provisioningKey);

  XmlNode node = xmlDocument.DocumentElement.SelectSingleNode(xpath, xmlnsMgr);

  if (node != null)
  {
    return Convert.ToBoolean(node.FirstChild.Value);
  }
  else
  {
    throw new InvalidOperationException("Provisioning key does not exist");
  }
}

The Web Scheduler application can use the information retrieved in the previous example to render user interface options to the user. The following sections explain how to schedule an audio-enabled conference and a PSTN-enabled conference.

Scheduling an Audio-Enabled Conference

Before scheduling an audio-enabled conference, the application must check that the AV MCU is available and that the user is provisioned for audio, as shown in the previous code example.

The ConferenceServices.BeginScheduleConference method is used to schedule new conferences. The application uses a ConferenceScheduleInformation instance to create a conference with specific settings.

Note

A UserEndpoint instance can schedule conferences only for the endpoint owner and no other user. Each conference is identified by the conference organizer and a conference ID that is unique among the other conferences scheduled by the same organizer. If the application does not supply its own conference ID, the UCMA 2.0 Core SDK creates a GUID as the conference ID.

The following code example creates a ConferenceScheduleInformation instance and sets basic conference properties on that instance.

ConferenceScheduleInformation csi = new ConferenceScheduleInformation();
csi.Subject = "An audio-enabled conference";
csi.Description = "Demonstration of how to schedule an audio-enabled conference";
csi.ExpiryTime = DateTime.Now.AddDays(2); //The default expiration time is 8 hours.

The application must specify the admission policy. Three options are available:

  • ClosedAuthenticated

    Allows authenticated enterprise and federated users that are explicitly included in the participant list to join the conference. Other users are denied access.

  • OpenAuthenticated

    Allows authenticated enterprise users to join the conference (even those not explicitly included in the participant list). Federated users who are included in the participant list are allowed into the conference as well.

  • Anonymous

    Allows any authenticated enterprise, federated, or anonymous user to join the conference. Anonymous access is discussed in more detail in the next section.

The admission policy options are members of the ConferenceAdmissionPolicy enumeration.

The next code example sets the admission policy to ClosedAuthenticated and adds participants to the participant list, including a leader.

csi.AdmissionPolicy = ConferenceAdmissionPolicy.ClosedAuthenticated;
csi.Participants.Add(new ConferenceParticipantInformation("sip:alice@contoso.com", ConferencingRole.Attendee));
csi.Participants.Add(new ConferenceParticipantInformation("sip:bob@contoso.com", ConferencingRole.Leader)); // Bob is admitted as a leader.

The application must specify the list of participants who can join the conference by adding participants and specifying their role. On scheduling a closed authenticated conference, the organizer can use the participant list to specify other conference leaders and to allow federated users into the conference. The organizer does not need to be added to the list. By default, the organizer is considered to be a conference leader.

Assuming that the AV MCU is activated and the user is provisioned for audio, the application can add an audio-video MCU and an instant messaging MCU to the scheduled conference.

csi.Mcus.Add(new ConferenceMcuInformation(McuType.AudioVideo));
csi.Mcus.Add(new ConferenceMcuInformation(McuType.InstantMessaging)); //For IM-enabled clients.

The ConferenceServices.EndScheduleConference method returns a Conference instance for the scheduled conference. The Conference.ConferenceUri property returns the URI that participants can use to join the conference.

_userEndpoint.ConferenceServices.BeginScheduleConference(csi, ScheduleAudioConferenceCallback, state);
private void ScheduleAudioConferenceCallback(IAsyncResult asyncResult)
{
  try
  {
    _conference = _userEndpoint.ConferenceServices.EndScheduleConference(asyncResult);
    // Conference ID : _conference.ConferenceID
    // Conference URI: _conference.ConferenceUri
  }
  catch (ConferenceFailureException cfex)
  {
    // Perform appropriate error handling here.
    // ConferenceFailureException wraps Centralized Conferencing Control Protocol (C3P) error information.
    // ConferenceFailureException wraps error information in the
    // Reason, GeneralReason, and DiagnosticInformation properties.
  }
  catch (RealTimeException rte)
  {
    // Perform appropriate error handling here.
    // RealTimeException and RealTimeException derivatives are thrown 
    // when no C3P error information is available.
  }
}

Scheduling a PSTN-Enabled Conference

A public switched telephone network-enabled (PSTN-enabled) conference is a conference that allows participants to join by phone as well as from other traditional clients. PSTN users dial specific access numbers to reach the deployed and activated application.

After calling the phone access number, a PSTN user is asked to enter the conference phone ID to identify the conference to join. Based on the conference settings, an application might challenge the user for a passcode. If the user provides a previously-assigned corporate PIN, the user is admitted as an authenticated participant. Otherwise, the user is admitted into the conference as an anonymous participant.

To organize a PSTN-enabled conference, the returned conferencing capabilities should indicate that phone access is supported (in other words, ConferencingCapabilities.SupportsPhoneAccess is set to true) and the AV MCU must be activated. The organizer should be provisioned for audio as well. Retrieving this information was illustrated in a previous section.

ConferenceScheduleInformation csi = new ConferenceScheduleInformation();
csi.Subject = "A PSTN-enabled conference";
csi.Description = "Demonstrating scheduling an PSTN-enabled conference";
csi.ExpiryTime = DateTime.Now.AddDays(1); // The default expiration time is 8 hours.

Tto allow anonymous users access to the conference, the conference admission policy must be set to anonymous.

csi.AdmissionPolicy = ConferenceAdmissionPolicy.Anonymous;

Then, phone access must be enabled for this conference, and MCUs must be added to the list of MCUs supported by this conference.

csi.PhoneAccessEnabled = true;
csi.Mcus.Add(new ConferenceMcuInformation(McuType.AudioVideo));
csi.Mcus.Add(new ConferenceMcuInformation(McuType.InstantMessaging)); // For IM-enabled clients.

The organizer might require that anonymous users be challenged for a passcode before they are admitted into the conference. In other scenarios, the organizer can choose to have the application admit anonymous users into the conference without verifying their passcodes.

The organizer must be allowed by the administrator to schedule such a conference. Example code in a previous section demonstrated how to parse a user’s provisioning data to determine whether passcode verification is optional or required.

Note

In case a client, for example Office Live Meeting 2007, does not support optional passcode verification for anonymous users, an organizer who schedules a conference with anonymous access must always provide a passcode, even if optional passcode verification was elected.

For PSTN-enabled conferences, the passcode must be a numeric string so that PSTN users can key in the passcode, when requested. The following example assumes that the user is provisioned to schedule conferences with optional passcode verification.

// For a PSTN-enabled conference, the passcode must be a numeric string.
csi.Passcode = "22907323";

csi.IsPasscodeOptional = true;
_userEndpoint.ConferenceServices.BeginScheduleConference(csi, SchedulePSTNConferenceCallback, state);
private void SchedulePSTNConferenceCallback(IAsyncResult asyncResult)
{
  try
  {
    _conference = _userEndpoint.ConferenceServices.EndScheduleConference(asyncResult);
  }
  catch (ConferenceFailureException cfex)
  {
    // Perform appropriate error handling here.
    // ConferenceFailureException wraps Centralized Conferencing Control Protocol (C3P) error information.
    // ConferenceFailureException wraps error information in the 
    // Reason, GeneralReason, and DiagnosticInformation properties.
  }
  catch (RealTimeException rte)
  {
    // Perform appropriate error handling here.
    // RealTimeException and RealTimeException derivatives are thrown when no C3P error information is
    // available.
  }
}

The Conference object that is returned should include the conference ID that uniquely identifies the conference among all of the conferences scheduled by the organizer, and should include the conference phone ID to be used by PSTN users. The phone conference ID is a numeric string generated by the Office Communications Server computer that is unique among all PSTN-enabled conferences (including those organized by others). The returned Conference object will also include the phone access numbers used by PSTN users to dial into the conference. A conference organizer must share the conference phone ID, phone access information, and passcode (if required) with PSTN users.

// The conference phone ID to be used by PSTN users to identify which conference they want to join.
_conference.PhoneInformation.ConferencePhoneId;

// The phone access numbers to dial into the conference.
_conference.PhoneInformation.PhoneAccess;

Note

A PSTN-enabled conference can also be joined using the conference URI that is returned in the Conference object.

Summary

This section discusses how to retrieve conferencing capabilities provided by the system, and the organizer’s provisioning data, to determine the different scheduling mechanisms that are available to the organizer.

An application that is intended to schedule a conference on behalf of a user must:

  1. Retrieve conferencing capabilities by using the ConferenceServices.BeginGetConferencingCapabilities method to determine

    • Deployed and activated MCUs.

    • Whether phone access is enabled.

  2. Retrieve the organizer’s provisioning data and parse it to extract:

    • The MCUs provisioned for the organizer.

    • Whether the organizer can schedule conferences with optional passcode verification or not.

Enumerating and Retrieving Conference Details

The following example code retrieves a list of basic information for all conferences organized by the user.

_userEndpoint.ConferenceServices.BeginGetConferenceSummaries(GetConferenceSummariesCallback, state);
private void GetConferenceSummariesCallback(IAsyncResult asyncResult)
{
  try
  {
    _conferenceSummaries = _userEndpoint.ConferenceServices.EndGetConferenceSummaries(asyncResult);

  }
  catch (ConferenceFailureException cfex)
  {
    // Perform appropriate error handling here.
    // ConferenceFailureException wraps Centralized Conferencing Control Protocol (C3P) error information.
    // ConferenceFailureException wraps error information in the Reason,
    // GeneralReason, and DiagnosticInformation properties.
  }
  catch (RealTimeException rte)
  {
    // Perform appropriate error handling here.
    // RealTimeException and RealTimeException derivatives are thrown when no C3P error information is
    // available.
  }
}

The ConferenceSummary collection that is returned includes a list of all conferences organized by the user. Each ConferenceSummary instance in the collection contains the conference ID, subject, admission policy, and conference URI. The application can retrieve this information about a conference by calling the ConferenceServices.BeginGetConference method.

_userEndpoint.ConferenceServices.BeginGetConference(_conferenceSummaries[0].ConferenceId, GetConferenceCallback, state);
private void GetConferenceCallback(IAsyncResult asyncResult)
{
  try
  {
    _conference = _userEndpoint.ConferenceServices.EndGetConference(asyncResult);
  }
  catch (ConferenceFailureException cfex)
  {
    // Perform appropriate error handling here.
    // ConferenceFailureException wraps Centralized Conferencing Control Protocol (C3P) error information.
    // ConferenceFailureException wraps error information in the
    // Reason, GeneralReason, and DiagnosticInformation properties.
  }
  catch (RealTimeException rte)
  {
    // Perform appropriate error handling here.
    // RealTimeException and RealTimeException derivatives are thrown when no C3P error information is
    // available.
  }

}

Updating and Canceling Existing Conferences

An existing conference can be updated by a call to the ConferenceServices.BeginUpdateConference method. This method takes a ConferenceScheduleInformation object. To update the conference, the ConferenceScheduleInformation object must include the conference ID and should also include the other properties that the application does not intend to change. If those properties are not set to the same values, their values are overridden.

The recommended way to update a conference is to first retrieve the full conference details using the ConferenceServices.BeginUpdateConference method and convert the Conference object that is returned by the ConferenceServices.EndUpdateConference method into a ConferenceScheduleInformation object.

This conversion preserves all the conference properties with the exception of phone access support. The application can then modify the specific properties it needs and leave the rest unchanged.

// Convert the retrieved Conference object to a ConferenceScheduleInformation object.
ConferenceScheduleInformation csi = _conference;

// Preserve the phone access setting after conversion, as the conversion does not preserve the value.
// If the conference contains phone information, then phone access is enabled.
csi.PhoneAccessEnabled = (_conference.PhoneInformation != null);

// You can change most of the properties but do not change the conference ID or the conference version.
// You must ensure that you retrieved the most updated conference, or the update request will fail.
csi.Subject = string.Format("New conference updated at {0}",DateTime.Now);

_userEndpoint.ConferenceServices.BeginUpdateConference(csi, UpdateConferenceCallback, null);
private void UpdateConferenceCallback(IAsyncResult asyncResult)
{
  try
  {
    _updatedConference = _userEndpoint.ConferenceServices.EndUpdateConference(asyncResult);
  }
  catch (ConferenceFailureException cfex)
  {
    // Perform appropriate error handling here.
    // ConferenceFailureException wraps Centralized Conferencing Control Protocol (C3P) error information.
    // ConferenceFailureException wraps error information in the 
    // Reason, GeneralReason, and DiagnosticInformation properties.
  }
  catch (RealTimeException rte)
  {
    // Perform appropriate error handling here.
    // RealTimeException and RealTimeException derivatives are thrown when no C3P error information is
    // available.
  }

}