By Mark Blomsma
May 9, 2008
In November 2007, AOL added AIM Call Out to the many features of AOL Instant Messenger (AIM). Recently, AOL opened up this service by offering the Open Voice API. The Open Voice API consists of a number of service offerings, all based on open standards, that allow any application to use the AIM Call Out infrastructure to place calls from any standards-based hardware device, or, for a developer, a more important, custom piece of software. This essentially allows you to build your own softphone or to integrate some sort of phone functionality into your line-of-business application. In this article, I will take on a journey of what it takes to actually make a call using these open standards, and show you the resources available for implementing phone functionality in a custom application.
For an example, suppose I want to create a situation in which an employee can start a phone conversation from within a custom, line-of-business application. I imagine the employee would use the microphone in the computer and select from a list of highlighted customers the customer that he or she wanted to call. The application could, for instance, be for a pharmacy application in which an employee is shown a list of customers whose prescription is running low; they need to be called to be reminded to come in and refill the prescription.
To achieve this, I need to do two things: first, establish a connection--in other words, "make the phone ring"; and second, transfer audio to the phone and receive audio from the other end. I achieve the first using Session Initiation Protocol (SIP), and the second using Real-time Transport Protocol (RTP). The Open Voice API supports a number of standards for these protocols.
Open Standards
The Open Voice API consists of services that adhere to the following standards:
- RFC 3261 - Session Initiation Protocol
- RFC 2833 - RTP Payload for DTFM Digits, Telephony Tones and Telephony Signals
- RFC 4028 - Session Timers in SIP
- ITU-T E.164 - Formatted Telephone Numbers
- RFC 2617 - Basic and Digest Access Authentication
By adhering to these standards the service is instantly accessible to softphones and other devices that also adhere to these standards. I've been using X-Lite and all I had to do was change the settings to point to the AOL SIP server, add my credentials, and life was good.
To use a third-party SIP application or device with the AIM Call gateway, configure it using the following settings:
- SIP Gateway: sip.aol.com
- STUN Server: turn.oscar.aol.com
- User Identity: AOLScreenName@aol.com or AIMScreenName@aim.com
- Device Password: As configured in the AIM Call Out dashboard
I've included some screen shots of what this looks like in X-Lite.


For an up-to-date list of softphones and devices on which AIM Call Out has been tested, go here.
The great thing about open standards is that there are usually a bunch of other parties supporting it with tools and libraries, and often there is quite a bit of open source material available for free, as well. If you're looking for Voice-over-IP (VoIP), SIP, or RTP programming stacks, I recommend you check out this page on Wikipedia.
Initiating a VoIP Call
Making a VoIP call, at the core, is quite simple. It involves the two parties finding each other, setting up a session, transferring data, and hanging up.
SIP is the standard used for two parties to find each other. RTP is used for exchanging data and an SIP message is used to end the session. Emmanuel Proulx has a great article on Dev2Dev that explains the basics of a SIP session. The following diagram shows the semantics of a SIP-based call:
Making the Phone Ring
If you look at the list of programming stacks available you'll undoubtedly notice that C# or Visual Basic .NET are not the top languages used for writing code in this domain. The following code was written using an evaluation version of the SIP .NET stack, a commercial offering from Independentsoft.
The code for setting up a connection using this programming stack looks like this:
static void Main( string[] args )
{
string domain = "sip.aol.com";
int port = 5060;
string account = "markdeveloper@aim.com";
string password = "<<password goes here>>"; // this is the password from your AIM Call Out dashboard
// Create a client and connect to the SIP server
SipClient client = new SipClient( domain, port, account, password );
client.Connect();
// Enable logging to the Console
// This allows you to see the SIP packages in the console.
Logger logger = new Logger();
logger.WriteLog += new WriteLogEventHandler( logger_WriteLog );
client.Logger = logger;
// Get the IP address of the STUN server
IPHostEntry stunHost = Dns.GetHostEntry( "turn.oscar.aol.com" );
IPEndPoint stunIP = new IPEndPoint( stunHost.AddressList[0], client.LocalIPEndPoint.Port );
string to = "sip:<<phonenumber goes here>>@sip.aol.com"; // sip:<phonenumer>@sip.aol.com
string from = "sip:markdeveloper@aim.com"; // sip:<accountname>
string contact = "sip:markdeveloper@" + stunIP.ToString(); // sip:<screenname> @stunserver
// Build session description based on what your RTP stack supports
SessionDescription session = BuildDescription( client.LocalIPEndPoint, stunIP );
// Build the SIP Invite
Invite invite = new Invite();
invite.Uri = to; // the phone has become the uri your trying to reach
invite.From = new ContactInfo( "markdeveloper", from );
invite.To = new ContactInfo( "phone", to );
invite.Contact = new Contact( contact );
invite.ContentType = "application/sdp";
invite.Body = session.ToString(); // put the session description in the body of the invite
RequestResponse inviteResponse = client.SendRequest( invite ); // send the invite
// ...
// Hang up
Bye bye = new Bye( inviteResponse.Response );
RequestResponse byeResponse = client.SendRequest( bye );
Console.ReadLine();
}
/// <summary>
/// Build a session description.
/// The content of the session description for this sample was taken by
/// using Wireshark to see what X-Lite was pushing across the wire.
/// </summary>
/// <param name="localIP"></param>
/// <param name="stunIP"></param>
/// <returns></returns>
private static SessionDescription BuildDescription( IPEndPoint localIP, IPEndPoint stunIP )
{
SessionDescription description = new SessionDescription();
description.Owner.Username = "markdeveloper";
description.Owner.AddressType = AddressType.InternetProtocolVersion4;
description.Owner.Address = stunIP.Address.ToString();
description.Owner.NetworkType = NetworkType.Internet;
description.Name = "Develop-One";
description.Connection = new Connection( stunIP.Address.ToString() );
Media m = new Media( "audio", 16384, "RTP/AVP 0 98 101" );
m.Attributes.Add( new Independentsoft.Sip.Sdp.Attribute( "rtpmap", "0 PCMU/8000" ) );
m.Attributes.Add( new Independentsoft.Sip.Sdp.Attribute( "rtpmap", "98 ilbc/8000" ) );
m.Attributes.Add( new Independentsoft.Sip.Sdp.Attribute( "fmtp", "98 alt:1 2 1hxq9YA4 BjTnC/X+ " + localIP.Address.ToString() + " " + localIP.Port.ToString() ) );
m.Attributes.Add( new Independentsoft.Sip.Sdp.Attribute( "fmtp", "98 alt:2 1 1hxq9YA4 BjTnC/X+ " + stunIP.Address.ToString() + " " + stunIP.Port.ToString() ) );
m.Attributes.Add( new Independentsoft.Sip.Sdp.Attribute( "rtpmap", "101 telephone-event/8000" ) );
m.Attributes.Add( new Independentsoft.Sip.Sdp.Attribute( "fmtp", "101 0-15" ) );
m.Attributes.Add( new Independentsoft.Sip.Sdp.Attribute( "sendrecv") );
description.Media.Add(m);
return description;
}
// Log to console
static void logger_WriteLog( object sender, WriteLogEventArgs e )
{
Console.WriteLine( e.Log );
}
The SIP .NET library offers tracing, which allows you to see the contents of the generated SIP message. This is useful in debugging the application.
When working on VoIP applications, however, you'll find that this level of logging is not enough. You need to be able to see what TCP packages actually go across the network. I found Wireshark to be indispensable for this purpose. The following screen shot shows the trace generated when using the application to set up a call.
I'd like to say thanks to Rade Josovic from Independentsoft and Gavin Murphy from AOL for their excellent support in getting the sample to work. As it turns out, Session Description Protocol (SDP), which defines the body of the SIP message, is quite particular that you follow the protocol to the letter. Following are a couple of points to be aware of:
- The media line specifying the audio needs to be above the attribute lines.
- The last line in the SDP session info needs to be
sendrecv. - The SDP needs to have a session name.
If these conditions are not meet, the SIP server (sip.aol.com) will reject the request.
Based on these three requirements, you can tell that the previous screen shot, of the console logging, is incorrect because the media element is at the bottom of the session information, the session does not have a name, and the last line in the SDP session is not sendrecv. The following screen shot shows a valid SIP invite as generated by my sample application and captured using Wireshark:
Making the Call
You've seen how to use SIP to initiate a session and make the phone ring. After the session is established, you need to transmit and receive audio using RTP. Sadly, there don't appear to be any RTP stacks for .NET; however, there is an open source project called SipekSDK that wraps a C DLL and offers a managed API that C# developers are able to use. The Sipek softphone is an open source SIP phone and messaging client based on a generic VoIP engine powered by a pjsip.org SIP stack. The project is based on the SipekSDK VoIP library. Currently, the Sipek softphone supports a C# wrapper to connect to the pjsip stack. The Sipek wrapper (pjsip.dll) can be used in other .NET projects, including Windows Mobile.
The C# wrapper offered by the SipekSDK is a very high-level API in which you don't need to worry about SIP session descriptions, codecs, and the like; even interaction with your PC's microphone is implemented out of the box. Creating a call comes down to some configuration and two lines of code:
// the call manager is a singleton used to manage calls. CCallManager manager = CCallManager.getInstance(); // create call will read the necessary configuration information from the config file. IStateMachine call = manager.createOutboundCall( "<phonenumber goes here>" ); // spend time talking // call.Duration shows time spend // ... // when the call is done release the session manager.onUserRelease( call.Session );
The API relies on the configuration file to contain the correct account information. I personally don't like that too much; I'd rather supply the information via the API--for instance, as a parameter to createOutboundCall. The sample application that comes with the API does offer a screen for managing the account settings, though. This screen is fairly similar to the X-Lite settings:
The settings form and the five lines of SipekSDK-based code are part of a complete open source softphone implementation.
Just browsing through the code of this project is very educational. You can download the Sipek sample softphone, including all source files, here. Happy coding!
Download the SIP sample application here.
Note: The SIP .NET library is an evaluation version that might have expired when you download this. Go to www.independentsoft.de to download your own free evaluation version.

AIM
AIM IS A BAD THING FOR 11 12 YEAR OLD KIDS
Great Article !
Thanks for this great article mark. Really found it very useful. I have written about this article today in my blog on how our Voice API's can support open sip stacks. More details on sip trunking can be found in my journal.