diff -r 51a74ef9ed63 -r ae94777fff8f Symbian3/SDK/Source/GUID-CF17532E-5E90-5124-8F05-AA72B848F17F.dita --- a/Symbian3/SDK/Source/GUID-CF17532E-5E90-5124-8F05-AA72B848F17F.dita Wed Mar 31 11:11:55 2010 +0100 +++ b/Symbian3/SDK/Source/GUID-CF17532E-5E90-5124-8F05-AA72B848F17F.dita Fri Jun 11 12:39:03 2010 +0100 @@ -1,423 +1,423 @@ - - - - - -SIP -Example: Usage of the SIP Stack -

The SIP sample application is a game that can be played between two users -that use two different machines. The following figure illustrates the sample -application.

- - - -

All users who want to play the game must register to the server with their -identities. This informs the server that the user is active and prepared to -participate in the game. If User 1 wants to play the game with User 2 then -it must send a request to User 2 through the server. When User 2 accepts the -request and acknowledges it then the two users can start playing. A user can -disconnect from playing the game by sending a message. If a user wants to -be deactivated then it can deregister from the server.

-

This application is developed using the key features of the Symbian SIP -stack. It shows how to create profiles and do SIP registration using the profiles, -how to set up a SIP session and send an instant message using the SIP. For -example you can set up the SIP server using Brekeke and you can download the -same from http://www.brekeke.com/download/download_sip_2_0.php.

-
Features of the game

The main features of the game -are:

    -
  • Register or deregister - -A user registers to the server with a unique identity before playing the game. -This identity is the SIP URI of the user. The user registers by sending a -SIP REGISTER message to the SIP server and is active. A user deactivates by -deregistering to the server. This activity is done by sending the SIP REGISTER -message with the expires header set to 0. For more information on registering -or deregistering to the server see, Registering -or deregistering an user.

  • -
  • Invite another user - -A user invites another user to play the game by entering the SIP URI of the -other user in the INVITE message. For more information on inviting another -user to play the game see, Inviting -a participant for session setup.

  • -
  • Send a message to -another user - A user can send an instant message to another user. For -more information on how to send an instant message to another user see, Sending -an instant message.

  • -
  • Disconnect from -playing the game - A user can disconnect from playing the game by sending -a SIP BYE message to the other user.

  • -
-
How to play -the game

The following snapshot shows the different tabs available -in the game.

- -

The following list describes the different tabs available in the -game:

    -
  • Invite for game - -This tab allows you to invite a user to play the game. When you invoke this -tab, a UI screen appears which asks the user to provide the SIP URI of the -second user with whom the user wants to play the game. The SIP URI of the -second user is then sent to the SIP stack which passes on the invite request -to the second user. The second user can accept or reject the invite. If the -second user accepts the invite then it acknowledges by sending a message that -it is prepared to start playing the game. If the second user rejects the invite -then it cannot play the game.

  • -
  • Enable profile - -This tab allows you to enable a profile. When you invoke this tab, a UI screen -appears where the user enters the values. A profile is created using these -values and the user registers with the SIP server.

  • -
  • Send instant msg - -This tab allows you to send a message to another user. When you invoke this -tab, a message with the address of the recipient is sent to the SIP stack. -The SIP stack sends this message to the recipient address.

  • -
  • End game - This -tab allows you to disconnect from playing the game. When you invoke this tab, -a BYE message is sent to the other user and the game is terminated.

  • -
-
Registering -or deregistering an user

An application can register to the SIP -Server using:

    -
  • the CSIPRegistrationBinding class -and its methods

  • -
  • the SIP Profile Agent

  • -

This sample application uses the SIP Profile Agent method to do SIP -registration. To use this method you need a SIP profile setting, and you must -create a SIP profile before you start using the application. Note: -A list of SIP profile settings can be found in the CSIPProfile class.

The -SIP profile agent method provides APIs for:

    -
  • Registering and Deregistering

  • -
  • Listening to registration -events

  • -
  • Creating, modifying, -and deleting the SIP profile settings that the profile agent plug-in implementations -use for SIP registration.

  • -

The following code from SIPExProfileQueryDlg.cpp shows -how the sample application stores the settings entered by users on the SIP -profile store.

//Create a new profile - CSIPManagedProfile* profile = iMProfileRegistry->CreateL(iProfileData.iServiceProfile); - -//Copy attributes entered by the user to the new profile - iNewProfile = profile; - profile = CopyDataToProfileL(); - -//Set the profile to default and save some settings - TInt err= profile->SetParameter(KSIPDefaultProfile,ETrue); - -//Save the profile to persistent store - iMProfileRegistry->SaveL( *profile ); -

The applications can start SIP registration or deregistration -using the Enable or Disable methods from -the SIP profile API.

The following code from SIPExSIPEngine.cpp shows -how to register using the profile agent.

//Check for the existing profile - if ( iProfile ) - { - delete iProfile; - iProfile = NULL; - } - TBool registered( EFalse ); - -//Leaves with KErrNotFound if default profile is not found - iProfile = iProfileRegistry->DefaultProfileL(); - else - { - const TDesC8* aor = NULL; - iProfile->GetParameter( KSIPUserAor, aor ); - iProfileRegistry->EnableL( *iProfile, *this ); - - //Check if the profile was immediately set to the registered state - iProfile->GetParameter( KSIPProfileRegistered, registered ); - } -

The following code from SIPExSIPEngine.cpp shows -how to deregister using the profile agent.

if ( iProfile ) - { - iProfileRegistry->Disable( *iProfile ); - delete iProfile; - iProfile = NULL; - }

The SIP profile API also provides a notification -method that is used by an application to monitor profile related events.

The -following code from SIPExProfileQueryDlg.cpp shows the -profile related events that the sample applications monitors.

void ProfileRegistryEventOccurred( - TUint32 aProfileId, - TEvent aEvent ) - { - switch (aEvent) - { - case MSIPProfileRegistryObserver::EProfileRegistered: - { - HandleProfileRegistered( aProfileId ); - break; - } - case MSIPProfileRegistryObserver::EProfileDeregistered: - { - HandleProfileDeregistered( aProfileId ); - break; - } - case MSIPProfileRegistryObserver::EProfileDestroyed: - { - HandleProfileDestroyed( aProfileId ); - break; - } - default: - { - // MSIPProfileRegistryObserver::EProfileCreated and MSIPProfileRegistryObserver::EProfileUpdated are ignored - break; - } - } - } -void ProfileRegistryErrorOccurred( - TUint32 /* aSIPProfileId */, - TInt aError ) - { - iObserver->ProfileError( aError ); - } -

Classes containing APIs in scope

CSIPProfile, CSIPManagedProfile, CSIPProfileRegistry, CSIPManagedProfileRegistry, MSIPProfileRegistryObserver.

-
Inviting a -participant for session setup

The sample application uses the SIP -INVITE method to setup a session between two users. In this case, the application -does not accept any SDP parameters from the user and instead sends fixed SDP -values.

The following code from SIPExSIPIdleState.cpp shows -how the application sends an INVITE message.

void SendInviteL( - CSIPExSIPEngine& aEngine, - const TDesC8& aSipUri ) - { - //Retrieve the active profile and connection - CSIPProfile& prof = aEngine.Profile(); - CSIPConnection& conn = aEngine.ConnectionL(); - - //Create CUri8 from the passed descriptor. This value is given by the user - CUri8* uri8 = aEngine.ConvertToUri8LC( aSipUri ); - - //Get dialog association, save for future use - //The ownership of uri8 is transferred - CSIPInviteDialogAssoc* dialogAssoc = - CSIPInviteDialogAssoc::NewL( conn, uri8, prof ); - aEngine.SetDialogAssoc( *dialogAssoc ); //Ownership is transferred!! - - //Create the necessary message elements - CSIPMessageElements* msgElements = aEngine.CreateMessageElementsLC(); - - //Send the INVITE in the dialog - //The ownership of msgElements is transferred - INVITE SENT OUT - CSIPClientTransaction* tx = dialogAssoc->SendInviteL( msgElements ); - } -
-
Handling an -incoming invite

An application that wants to receive an incoming -invite outside the dialog must implement the Client Resolver API. The CSipResolvedClient (SipResolvedClient.h) interface is implemented by clients to enable a client resolution mechanism -when the SIP requests are received outside the SIP dialog. The application -must state the capabilities, that is the supported content types and media -formats. This is done using the SIP headers and SDP m-lines either in the -code of the plug-in, that is in const KCapabilities or in -the opaque_data field of the resource file.

The capabilities can be -provided to the plug-ins in two ways:

    -
  • The data is provided -in the ECOM resource file.

  • -
  • In the interface implementation -from where it is used to determine the target client.

  • -

The following code from SIPExResolverPlugin.cpp shows -how the data is provided in the ECOM resource file.

#include <RegistryInfo.rh> -RESOURCE REGISTRY_INFO theInfo - { - // UID for the DLL - dll_uid = 0xA00001EC; - // Declare array of interface info - interfaces = - { - INTERFACE_INFO - { - // UID of interface that is implemented - interface_uid = 0x102010DD; - implementations = - { - IMPLEMENTATION_INFO - { - implementation_uid = 0xA00001EC; - version_no = 1; - // SIPEx UID: Must match to the one SIPEx passes to CSIP::NewL. - default_data = "A00001EB"; - } - }; - } - }; - }

The following code from SIPExResolverPlugin.cpp shows -how the capabilities are defined in the plug-in.

//Code for defining capabilities in plugin -//File : SIPExResolverPlugin.cpp - -_LIT8(KCapabilities, -"<SIP_CLIENT ALLOW_STARTING=\"YES\">\ -<SIP_HEADERS>\ -<ACCEPT value=\"application/sdp\"/>\ -<ACCEPT value=\"SIPEx/InstantMessage\"/>\ -</SIP_HEADERS>\ -<SDP_LINES>\ -<LINE name=\"m\" value=\"application 0 TCP SIPEx\"/>\ -</SDP_LINES>\ -</SIP_CLIENT>"); - - -

When there is an incoming Invite Request with -SDP parameters the SIP stack passes the request to the Client Resolver to -get the resolved client for that request. The Client Resolver gets the capabilities -for all the applications that implement the Client Resolver API.

The -following code from SIPExResolverPlugin.cpp shows how -to get the capabilities for an application.

//Code for obtaining capabilities for an application -//File : SIPExResolverPlugin.cpp - -const TDesC8& CSIPExResolverPlugin::Capabilities() - { - return KCapabilities; - }

When the target client is identified, the Client Resolver -gets the ChannelID from the plug-in implementation and requests the resolved -client to connect to the SIP implementation on that UID. Note: The -ChannelID is same as Application UID3

The following code from SIPExResolverPlugin.cpp shows -how to get ChannelID for an application.

//Code for obtaining ChannelID for an application -//File : SIPExResolverPlugin.cpp - - TUid CSIPExResolverPlugin::ChannelL( RStringF /*aMethod*/, - const TDesC8& /*aRequestUri*/, - const RPointerArray<CSIPHeaderBase>& /*aHeaders*/, - const TDesC8& /*aContent*/, - const CSIPContentTypeHeader* /*aContentType*/) - { - return iApplicationUID; - } - -//Code for asking an application to connect on UID -//File : SIPExResolverPlugin.cpp - - void CSIPExResolverPlugin::ConnectL( TUid aUid ) - { - //Launch application is based on UID passed from the SIP stack - - TApaAppInfo appInfo; - User::LeaveIfError( iApaSession.GetAppInfo( appInfo, aUid ) ); - CApaCommandLine* cmdLine = CApaCommandLine::NewLC(); -#ifdef EKA2 - cmdLine->SetExecutableNameL( appInfo.iFullName ); -#else - cmdLine->SetLibraryNameL( appInfo.iFullName ); -#endif - User::LeaveIfError( iApaSession.StartApp( *cmdLine ) ); - CleanupStack::PopAndDestroy( cmdLine ); - }

When the resolved client connects, the INVITE is forwarded -to the client and it starts ringing (180 Ringing) and sends the provisional -response to the calling party. This part is implemented in InviteReceivedL as -shown in the following code.

The following code from SIPExSIPIdleState.cpp shows -how the application gets the INVITE and how the provisional response is sent.

/Code for CSIPExSIPIdleState::InviteReceivedL()... -//File : SIPExSIPIdleState.cpp - -void CSIPExSIPIdleState::InviteReceivedL( - CSIPExSIPEngine& aEngine, - CSIPServerTransaction* aTransaction ) - { - _LIT8( KLogEntry, "180 Ringing sent" ); - .. - .. - aEngine.Observer()->WriteLog( KLogEntry ); - .. - }

From this stage, the INVITE is sent to InviteReceived of CSIPExEngine in SIPExGameEngine.cpp from where it asks from the game observer if the user has accepted the invitation -or not. The game starts or does not start depends on action taken.

The -following code from SIPExStateRegistered.cpp shows how -the acceptance is asked from the game observer.

//The acceptance is asked from the user and if accepted the game is reset, start -//listening socket and signal the SIP engine to send Accepted to the remote peer. - -//File : SIPExStateRegistered.cpp - -void TSIPExStateRegistered::InviteReceived( - CSIPExEngine* aContext, - const TDesC8& aFrom, - const TUint32 aIapId ) - { - iEnded = EFalse; - - TBool retVal( EFalse ); - TRAPD( ignore, retVal = aContext->AcceptInvitationL( aFrom ) ); - if ( iEnded ) - { - return; - } - if( retVal ) - { - StatusInfo( aContext, KGameStarting() ); - ChangeState( aContext, aContext->iStateAcceptingSIP ); - aContext->ResetGame(); - aContext->SetPeer( CSIPExEngine::EServer ); - Info( aContext, KListening() ); - TInetAddr addr; - TRAP( ignore, addr = - aContext->SocketEngineL()->StartListeningL( aIapId ) ); - Info( aContext, KAccepting() ); - TRAP( ignore, aContext->SIPEngine()->AcceptInviteL( addr ) ); - Info( aContext, KWaitingRemoteConn() ); - } - else - { - TRAP( ignore, aContext->SIPEngine()->DeclineInviteL() ); - Info( aContext, KInviteDeclined() ); - } - } -

When the game observer accepts the invitation the following -code from SIPExGameEngine.cpp is run.

//File : SIPExGameEngine.cpp - -TBool CSIPExEngine::AcceptInvitationL( const TDesC8& aFrom ) - { - HBufC* from = HBufC::NewLC( aFrom.Length() ); - from->Des().Copy( aFrom ); - TBool retVal = iGameObserver.AcceptInvitationL( *from ); - CleanupStack::PopAndDestroy( from ); - return retVal; - }
-
Sending an -instant message

This sample application allows a user to send an -Instant Message (IM) to another user. The user requires SIP URI of the other -user and the message content that the user must enter. The application then -creates a MESSAGE (request message) with these parameters and uses SendRequestL() to -send it.

The following code from SIPExSIPEngine.cpp shows -how to send an instant message.

//Create and send an instant message to a recipient defined with the parameters. -//This is implemented with the MESSAGE method and is sent outside of a dialog. - -CreateIML(const TDesC8& aMessage, - const TDesC8& aSipUri ) - { - _LIT8( KMediaType, "SIPEx" ); // Part of content type - _LIT8( KMediaSubType, "InstantMessage" ); // Part of content type - -//Create the necessary elements of the IM - -CSIPRequestElements* reqElem = CreateReqElementsLC( aSipUri ); - CSIPToHeader* toHeader = CreateToHeaderLC( aSipUri ); - reqElem->SetToHeaderL( toHeader ); - -//Create the fromHeader value using the information from the profile - - const TDesC8* aor = NULL; - iProfile->GetParameter( KSIPUserAor, aor ); - CSIPAddress* addr = CSIPAddress::DecodeL( *aor ); - CSIPFromHeader* fromHeader = CSIPFromHeader::NewL( addr ); - reqElem->SetFromHeaderL( fromHeader ); - reqElem->SetMethodL( SIPStrings::StringF( SipStrConsts::EMessage ) ); - -//Get reference to the message elements from the request elements, create and insert content type header (ownership of the content type object is transferred) - - CSIPMessageElements& msgElem = reqElem->MessageElements(); - CSIPContentTypeHeader* ct = CSIPContentTypeHeader::NewLC( KMediaType, KMediaSubType ); - msgElem.SetContentL( aMessage.AllocL(), ct ); - -//Get the current connection - -CSIPConnection& conn = ConnectionL(); - -//Send the request using the connection (ownership of the request elements object is transferred) - - CSIPClientTransaction* ctx = conn.SendRequestL( reqElem ); - delete ctx; - } - -

Classes containing APIs in scope

CSIPRequestElements, CSIPToHeader, CSIPFromHeader, CSIPAddress, CSIPMessageElements, CSIPClientTransaction.

+ + + + + +SIP +Example: Usage of the SIP Stack +

The SIP sample application is a game that can be played between two users +that use two different machines. The following figure illustrates the sample +application.

+ + + +

All users who want to play the game must register to the server with their +identities. This informs the server that the user is active and prepared to +participate in the game. If User 1 wants to play the game with User 2 then +it must send a request to User 2 through the server. When User 2 accepts the +request and acknowledges it then the two users can start playing. A user can +disconnect from playing the game by sending a message. If a user wants to +be deactivated then it can deregister from the server.

+

This application is developed using the key features of the Symbian SIP +stack. It shows how to create profiles and do SIP registration using the profiles, +how to set up a SIP session and send an instant message using the SIP. For +example you can set up the SIP server using Brekeke and you can download the +same from http://www.brekeke.com/download/download_sip_2_0.php.

+
Features of the game

The main features of the game +are:

    +
  • Register or deregister - +A user registers to the server with a unique identity before playing the game. +This identity is the SIP URI of the user. The user registers by sending a +SIP REGISTER message to the SIP server and is active. A user deactivates by +deregistering to the server. This activity is done by sending the SIP REGISTER +message with the expires header set to 0. For more information on registering +or deregistering to the server see, Registering +or deregistering an user.

  • +
  • Invite another user - +A user invites another user to play the game by entering the SIP URI of the +other user in the INVITE message. For more information on inviting another +user to play the game see, Inviting +a participant for session setup.

  • +
  • Send a message to +another user - A user can send an instant message to another user. For +more information on how to send an instant message to another user see, Sending +an instant message.

  • +
  • Disconnect from +playing the game - A user can disconnect from playing the game by sending +a SIP BYE message to the other user.

  • +
+
How to play +the game

The following snapshot shows the different tabs available +in the game.

+ +

The following list describes the different tabs available in the +game:

    +
  • Invite for game - +This tab allows you to invite a user to play the game. When you invoke this +tab, a UI screen appears which asks the user to provide the SIP URI of the +second user with whom the user wants to play the game. The SIP URI of the +second user is then sent to the SIP stack which passes on the invite request +to the second user. The second user can accept or reject the invite. If the +second user accepts the invite then it acknowledges by sending a message that +it is prepared to start playing the game. If the second user rejects the invite +then it cannot play the game.

  • +
  • Enable profile - +This tab allows you to enable a profile. When you invoke this tab, a UI screen +appears where the user enters the values. A profile is created using these +values and the user registers with the SIP server.

  • +
  • Send instant msg - +This tab allows you to send a message to another user. When you invoke this +tab, a message with the address of the recipient is sent to the SIP stack. +The SIP stack sends this message to the recipient address.

  • +
  • End game - This +tab allows you to disconnect from playing the game. When you invoke this tab, +a BYE message is sent to the other user and the game is terminated.

  • +
+
Registering +or deregistering an user

An application can register to the SIP +Server using:

    +
  • the CSIPRegistrationBinding class +and its methods

  • +
  • the SIP Profile Agent

  • +

This sample application uses the SIP Profile Agent method to do SIP +registration. To use this method you need a SIP profile setting, and you must +create a SIP profile before you start using the application. Note: +A list of SIP profile settings can be found in the CSIPProfile class.

The +SIP profile agent method provides APIs for:

    +
  • Registering and Deregistering

  • +
  • Listening to registration +events

  • +
  • Creating, modifying, +and deleting the SIP profile settings that the profile agent plug-in implementations +use for SIP registration.

  • +

The following code from SIPExProfileQueryDlg.cpp shows +how the sample application stores the settings entered by users on the SIP +profile store.

//Create a new profile + CSIPManagedProfile* profile = iMProfileRegistry->CreateL(iProfileData.iServiceProfile); + +//Copy attributes entered by the user to the new profile + iNewProfile = profile; + profile = CopyDataToProfileL(); + +//Set the profile to default and save some settings + TInt err= profile->SetParameter(KSIPDefaultProfile,ETrue); + +//Save the profile to persistent store + iMProfileRegistry->SaveL( *profile ); +

The applications can start SIP registration or deregistration +using the Enable or Disable methods from +the SIP profile API.

The following code from SIPExSIPEngine.cpp shows +how to register using the profile agent.

//Check for the existing profile + if ( iProfile ) + { + delete iProfile; + iProfile = NULL; + } + TBool registered( EFalse ); + +//Leaves with KErrNotFound if default profile is not found + iProfile = iProfileRegistry->DefaultProfileL(); + else + { + const TDesC8* aor = NULL; + iProfile->GetParameter( KSIPUserAor, aor ); + iProfileRegistry->EnableL( *iProfile, *this ); + + //Check if the profile was immediately set to the registered state + iProfile->GetParameter( KSIPProfileRegistered, registered ); + } +

The following code from SIPExSIPEngine.cpp shows +how to deregister using the profile agent.

if ( iProfile ) + { + iProfileRegistry->Disable( *iProfile ); + delete iProfile; + iProfile = NULL; + }

The SIP profile API also provides a notification +method that is used by an application to monitor profile related events.

The +following code from SIPExProfileQueryDlg.cpp shows the +profile related events that the sample applications monitors.

void ProfileRegistryEventOccurred( + TUint32 aProfileId, + TEvent aEvent ) + { + switch (aEvent) + { + case MSIPProfileRegistryObserver::EProfileRegistered: + { + HandleProfileRegistered( aProfileId ); + break; + } + case MSIPProfileRegistryObserver::EProfileDeregistered: + { + HandleProfileDeregistered( aProfileId ); + break; + } + case MSIPProfileRegistryObserver::EProfileDestroyed: + { + HandleProfileDestroyed( aProfileId ); + break; + } + default: + { + // MSIPProfileRegistryObserver::EProfileCreated and MSIPProfileRegistryObserver::EProfileUpdated are ignored + break; + } + } + } +void ProfileRegistryErrorOccurred( + TUint32 /* aSIPProfileId */, + TInt aError ) + { + iObserver->ProfileError( aError ); + } +

Classes containing APIs in scope

CSIPProfile, CSIPManagedProfile, CSIPProfileRegistry, CSIPManagedProfileRegistry, MSIPProfileRegistryObserver.

+
Inviting a +participant for session setup

The sample application uses the SIP +INVITE method to setup a session between two users. In this case, the application +does not accept any SDP parameters from the user and instead sends fixed SDP +values.

The following code from SIPExSIPIdleState.cpp shows +how the application sends an INVITE message.

void SendInviteL( + CSIPExSIPEngine& aEngine, + const TDesC8& aSipUri ) + { + //Retrieve the active profile and connection + CSIPProfile& prof = aEngine.Profile(); + CSIPConnection& conn = aEngine.ConnectionL(); + + //Create CUri8 from the passed descriptor. This value is given by the user + CUri8* uri8 = aEngine.ConvertToUri8LC( aSipUri ); + + //Get dialog association, save for future use + //The ownership of uri8 is transferred + CSIPInviteDialogAssoc* dialogAssoc = + CSIPInviteDialogAssoc::NewL( conn, uri8, prof ); + aEngine.SetDialogAssoc( *dialogAssoc ); //Ownership is transferred!! + + //Create the necessary message elements + CSIPMessageElements* msgElements = aEngine.CreateMessageElementsLC(); + + //Send the INVITE in the dialog + //The ownership of msgElements is transferred + INVITE SENT OUT + CSIPClientTransaction* tx = dialogAssoc->SendInviteL( msgElements ); + } +
+
Handling an +incoming invite

An application that wants to receive an incoming +invite outside the dialog must implement the Client Resolver API. The CSipResolvedClient (SipResolvedClient.h) interface is implemented by clients to enable a client resolution mechanism +when the SIP requests are received outside the SIP dialog. The application +must state the capabilities, that is the supported content types and media +formats. This is done using the SIP headers and SDP m-lines either in the +code of the plug-in, that is in const KCapabilities or in +the opaque_data field of the resource file.

The capabilities can be +provided to the plug-ins in two ways:

    +
  • The data is provided +in the ECOM resource file.

  • +
  • In the interface implementation +from where it is used to determine the target client.

  • +

The following code from SIPExResolverPlugin.cpp shows +how the data is provided in the ECOM resource file.

#include <RegistryInfo.rh> +RESOURCE REGISTRY_INFO theInfo + { + // UID for the DLL + dll_uid = 0xA00001EC; + // Declare array of interface info + interfaces = + { + INTERFACE_INFO + { + // UID of interface that is implemented + interface_uid = 0x102010DD; + implementations = + { + IMPLEMENTATION_INFO + { + implementation_uid = 0xA00001EC; + version_no = 1; + // SIPEx UID: Must match to the one SIPEx passes to CSIP::NewL. + default_data = "A00001EB"; + } + }; + } + }; + }

The following code from SIPExResolverPlugin.cpp shows +how the capabilities are defined in the plug-in.

//Code for defining capabilities in plugin +//File : SIPExResolverPlugin.cpp + +_LIT8(KCapabilities, +"<SIP_CLIENT ALLOW_STARTING=\"YES\">\ +<SIP_HEADERS>\ +<ACCEPT value=\"application/sdp\"/>\ +<ACCEPT value=\"SIPEx/InstantMessage\"/>\ +</SIP_HEADERS>\ +<SDP_LINES>\ +<LINE name=\"m\" value=\"application 0 TCP SIPEx\"/>\ +</SDP_LINES>\ +</SIP_CLIENT>"); + + +

When there is an incoming Invite Request with +SDP parameters the SIP stack passes the request to the Client Resolver to +get the resolved client for that request. The Client Resolver gets the capabilities +for all the applications that implement the Client Resolver API.

The +following code from SIPExResolverPlugin.cpp shows how +to get the capabilities for an application.

//Code for obtaining capabilities for an application +//File : SIPExResolverPlugin.cpp + +const TDesC8& CSIPExResolverPlugin::Capabilities() + { + return KCapabilities; + }

When the target client is identified, the Client Resolver +gets the ChannelID from the plug-in implementation and requests the resolved +client to connect to the SIP implementation on that UID. Note: The +ChannelID is same as Application UID3

The following code from SIPExResolverPlugin.cpp shows +how to get ChannelID for an application.

//Code for obtaining ChannelID for an application +//File : SIPExResolverPlugin.cpp + + TUid CSIPExResolverPlugin::ChannelL( RStringF /*aMethod*/, + const TDesC8& /*aRequestUri*/, + const RPointerArray<CSIPHeaderBase>& /*aHeaders*/, + const TDesC8& /*aContent*/, + const CSIPContentTypeHeader* /*aContentType*/) + { + return iApplicationUID; + } + +//Code for asking an application to connect on UID +//File : SIPExResolverPlugin.cpp + + void CSIPExResolverPlugin::ConnectL( TUid aUid ) + { + //Launch application is based on UID passed from the SIP stack + + TApaAppInfo appInfo; + User::LeaveIfError( iApaSession.GetAppInfo( appInfo, aUid ) ); + CApaCommandLine* cmdLine = CApaCommandLine::NewLC(); +#ifdef EKA2 + cmdLine->SetExecutableNameL( appInfo.iFullName ); +#else + cmdLine->SetLibraryNameL( appInfo.iFullName ); +#endif + User::LeaveIfError( iApaSession.StartApp( *cmdLine ) ); + CleanupStack::PopAndDestroy( cmdLine ); + }

When the resolved client connects, the INVITE is forwarded +to the client and it starts ringing (180 Ringing) and sends the provisional +response to the calling party. This part is implemented in InviteReceivedL as +shown in the following code.

The following code from SIPExSIPIdleState.cpp shows +how the application gets the INVITE and how the provisional response is sent.

/Code for CSIPExSIPIdleState::InviteReceivedL()... +//File : SIPExSIPIdleState.cpp + +void CSIPExSIPIdleState::InviteReceivedL( + CSIPExSIPEngine& aEngine, + CSIPServerTransaction* aTransaction ) + { + _LIT8( KLogEntry, "180 Ringing sent" ); + .. + .. + aEngine.Observer()->WriteLog( KLogEntry ); + .. + }

From this stage, the INVITE is sent to InviteReceived of CSIPExEngine in SIPExGameEngine.cpp from where it asks from the game observer if the user has accepted the invitation +or not. The game starts or does not start depends on action taken.

The +following code from SIPExStateRegistered.cpp shows how +the acceptance is asked from the game observer.

//The acceptance is asked from the user and if accepted the game is reset, start +//listening socket and signal the SIP engine to send Accepted to the remote peer. + +//File : SIPExStateRegistered.cpp + +void TSIPExStateRegistered::InviteReceived( + CSIPExEngine* aContext, + const TDesC8& aFrom, + const TUint32 aIapId ) + { + iEnded = EFalse; + + TBool retVal( EFalse ); + TRAPD( ignore, retVal = aContext->AcceptInvitationL( aFrom ) ); + if ( iEnded ) + { + return; + } + if( retVal ) + { + StatusInfo( aContext, KGameStarting() ); + ChangeState( aContext, aContext->iStateAcceptingSIP ); + aContext->ResetGame(); + aContext->SetPeer( CSIPExEngine::EServer ); + Info( aContext, KListening() ); + TInetAddr addr; + TRAP( ignore, addr = + aContext->SocketEngineL()->StartListeningL( aIapId ) ); + Info( aContext, KAccepting() ); + TRAP( ignore, aContext->SIPEngine()->AcceptInviteL( addr ) ); + Info( aContext, KWaitingRemoteConn() ); + } + else + { + TRAP( ignore, aContext->SIPEngine()->DeclineInviteL() ); + Info( aContext, KInviteDeclined() ); + } + } +

When the game observer accepts the invitation the following +code from SIPExGameEngine.cpp is run.

//File : SIPExGameEngine.cpp + +TBool CSIPExEngine::AcceptInvitationL( const TDesC8& aFrom ) + { + HBufC* from = HBufC::NewLC( aFrom.Length() ); + from->Des().Copy( aFrom ); + TBool retVal = iGameObserver.AcceptInvitationL( *from ); + CleanupStack::PopAndDestroy( from ); + return retVal; + }
+
Sending an +instant message

This sample application allows a user to send an +Instant Message (IM) to another user. The user requires SIP URI of the other +user and the message content that the user must enter. The application then +creates a MESSAGE (request message) with these parameters and uses SendRequestL() to +send it.

The following code from SIPExSIPEngine.cpp shows +how to send an instant message.

//Create and send an instant message to a recipient defined with the parameters. +//This is implemented with the MESSAGE method and is sent outside of a dialog. + +CreateIML(const TDesC8& aMessage, + const TDesC8& aSipUri ) + { + _LIT8( KMediaType, "SIPEx" ); // Part of content type + _LIT8( KMediaSubType, "InstantMessage" ); // Part of content type + +//Create the necessary elements of the IM + +CSIPRequestElements* reqElem = CreateReqElementsLC( aSipUri ); + CSIPToHeader* toHeader = CreateToHeaderLC( aSipUri ); + reqElem->SetToHeaderL( toHeader ); + +//Create the fromHeader value using the information from the profile + + const TDesC8* aor = NULL; + iProfile->GetParameter( KSIPUserAor, aor ); + CSIPAddress* addr = CSIPAddress::DecodeL( *aor ); + CSIPFromHeader* fromHeader = CSIPFromHeader::NewL( addr ); + reqElem->SetFromHeaderL( fromHeader ); + reqElem->SetMethodL( SIPStrings::StringF( SipStrConsts::EMessage ) ); + +//Get reference to the message elements from the request elements, create and insert content type header (ownership of the content type object is transferred) + + CSIPMessageElements& msgElem = reqElem->MessageElements(); + CSIPContentTypeHeader* ct = CSIPContentTypeHeader::NewLC( KMediaType, KMediaSubType ); + msgElem.SetContentL( aMessage.AllocL(), ct ); + +//Get the current connection + +CSIPConnection& conn = ConnectionL(); + +//Send the request using the connection (ownership of the request elements object is transferred) + + CSIPClientTransaction* ctx = conn.SendRequestL( reqElem ); + delete ctx; + } + +

Classes containing APIs in scope

CSIPRequestElements, CSIPToHeader, CSIPFromHeader, CSIPAddress, CSIPMessageElements, CSIPClientTransaction.

\ No newline at end of file