Technical Helpweb

PowerMedia XMS RESTful C# demo

Introduction

This article showcases using .NET 3.5 framework with C# programming language for creating HTTP RESTful applications for controlling Dialogic® PowerMedia™ Extended Media Server (XMS). Although the demo demonstrates a simple feature set, like inbound and outbound calls, playing and recording audio data, it's composition allows for it to be enhanced with more functionality.

Program Features

The PowerMedia XMS RESTful demo is a GUI C# demo written to work with PowerMedia XMS. The demo currently has the following functionality:

The application is ready to receive incoming calls at any time, as long as the server has free call resources. Simultaneously, a user can make an outbound call from XMS using demo’s GUI. Upon connection the demo plays or plays/records audio files; although the call flow is currently hardcoded, the application provides means for developing more complex call scenarios.

Code Composition

The program consists of three threads. The main thread (GUI form), event processing thread, and a thread for handling HTTP responses in asynchronous manner. Below is a brief description of main classes and their roles in the application.

XmsDemoForm:Form : Static (singleton in terms of C++). User interface for controlling the application. Allows users to specify IP address/port of the PowerMedia XMS system, start/stop the program and make outbound calls. Contains a list box, where top-level messages, errors, and events are displayed.

EventHandler : Static. Launched by the main thread at initialization time, creates event handler. Then spawns a thread which waits for incoming PowerMedia XMS events in a loop. When an event arrives, the handler defines its type (call, conference, keep alive) and passes data to consumers for processing.

The Read() operation is blocking when reading junked input, this is why a separate thread is needed for the event reader.

3. Dispatching Events to Consumers

The ProcessEvent() method defines the type of the signaling resource and sends the event for further processing to the owner:

Type tp = l_ws.Item.GetType();

@event l_event = (@event)l_ws.Item;

switch (l_event.resource_type)

{

case "call":

CallManager.ProcessEvent(l_event);

break;

case "conference":

ConfManager.ProcessEvent(l_event);

break;

case "keepalive":

Logger.Log("Keepalive from XMS", false);

break;

default:

Logger.Log("ERROR - Unknown event type", false); break;

}

OTHER KEY CLASSES

CallManager : Static. Answers and makes calls. Maintains a hash table of all active calls, advances call states according to the events and commands, implements a call flow. Interacts with EventHandler, GUI and XmsCall classes.

ConfManager : Static. Reserved for implementation.

Logger Static. Simple logger, prints HTTP – XML messages to a file and topmost messages and errors to the list box on the form.

XmsCall : Represents call objects. Stateless, run in a context of event thread. Provides methods for answering and making calls, play-record, collecting digits etc. Since some call control operations, like SIP answer or SIP teardown are not atomic and may be delayed by network, this class implements asynchronous HTTP interactions on such procedures, so the event thread is never blocked. This is done with BeginGetResponse/EndGetResponse .NET HTTP API.

Below you will find an overview of XmsCall class and use of the .NET HTTP API:

1) Call manager receives an event indicating a new incoming call. It creates a new XmsCall object and sends an Answer command to it:

// CallManager:

private static void OnOffered(ref XmsCall a_call)

{

a_call.CallState = XmsCall.e_CallState.STATE_OFFERED;

a_call.CallDirection = XmsCall.e_CallDirection.Incoming;

addCall(ref a_call); // adding the new call to the hash table

if (a_call.Answer() != 0) // invoking ASYNC Answer procedure

{

a_call.Drop();

deleteCall(a_call);

}

}

2) The XmsCall object initiates an answer procedure and returns control to the thread immediately:

// When the XMS response arrives, the onAnswer callback will be invoked by .NET

3) When the operation completes, the .NET invokes a callback indicating end of task. The XmsCall object then raises an unnamed .NET event which can be consumed by any listener in this address space, in this case, by the CallManager:

l_call.CallEvent.Set(); // signal to listeners about completion of ASYNC operation

4) The CallManager runs a thread where it waits for completion events from all call objects it owns.

Thread l_callCompletionThread = new Thread(onAsyncCallEvent);

l_callCompletionThread.Start();

When one of the calls raises an event, the CallManager defines the call state and acts accordingly:

foreach(XmsCall l_call in l_callList)

{

if (l_call.CallEvent.WaitOne(1))// completion event on this call

{

switch(l_call.CallState)

{

case XmsCall.e_CallState.STATE_FAIL:

deleteCall(l_call); // delete ther call

break;

case XmsCall.e_CallState.STATE_CONNECTED:

OnAnswer(l_call);

break;

case XmsCall.e_CallState.STATE_IDLE:

OnDrop(l_call);

break;

}

}

}

Multithreading Considerations

The three threads comprising the demo may need to access a sharable resource, like a call hash table or ListBox GUI control at same time, which is not safe. To synchronize such tasks, the program uses mutex objects and delegates. For example, each time the hash table needs to be updated, the code first makes sure that there is no one else currently working with the table, and only then proceeds:

Another example of handling shared resources is accessing a sharable GUI control from a thread other than the control’s creator. In this demo example, this happens when the event thread needs to print something to the main window. .NET does not allow such operation directly. Instead, the code defines a delegate – in this context, the thread-safe event-processing method, and invokes it (sends the event to the XmsDemoForm class) when needed:

When an object calls the WriteMessage() method of XmsDemoForm class to update the list box, the form first checks whether the request is made from the same thread where the list box was created, and, if not, it stores the data to print and returns a negative response to the caller. The caller then invokes a delegate to complete the printing:

Building and Running the Demo

The demo was developed with VS 9.0 (Microsoft Visual Studio 2008) and does not use any external references besides those provided by the .NET 3.5 framework. Some definitions around HTTP functionality may be incompatible with .NET 2.0, so as of October 2012, .NET 3.5 is recommended. The demo does not require any arguments when started. A user starts the demo, fills in the XMS system's IP address and port, XMS Application ID and press “Start” button. The application now is ready to receive and make calls.

Due to schema changes between XMS versions, the application required slight changes. Below you will find specific versions of the application that match specific XMS versions:

Company:

Connect:

DSC Registration and Login
Dialogic Service Center uses the Dialogic
Single Sign On system.

You want to register?
Registration is free. Click 'LOGIN' at the top right of the page, then click 'REGISTER' to create a Single Sign On profile.
Registering and signing on gives you automatic access to DSC.