Oracle® Communications Converged Application Server Developer's Guide Release 5.1 Part Number E27707-01 |
|
|
PDF · Mobi · ePub |
This chapter describes how to implement announcement support as defined in IR.92 Supplementary Services using the Service Foundation Toolkit (SFT).
Announcements are service-related messages played to a recipient to inform them about the state of a call. Announcements can be provided using either audio or video content.
SFT supports the following approaches to playing announcements:
Send the media stream to the recipient of the announcement for playback.
This approach uses a media server and Media Resource Function Processor (MRFP). The media is streamed to the recipient using the Real-time Transport Protocol (RTP) after establishing a media session with the media server. Based on the point-in-time at which the media session is initiated, an early- or non-early media session can be used.
SFT reserves a media resource using the JSR 309 API (the JSR 309 driver used by the media server). The underlying mechanism between the JSR309 driver and MRFP is protocol agnostic.
Send information about the media content that lets the recipient retrieve and playback the announcement.
This approach sends a URI identifying the media to the recipient, allowing them to determine whether or not to play the announcement.
Announcement support makes use of the following classes in the com.oracle.sft.api
package. For more information on these interfaces and their usage, refer to the Converged Application Server API Reference.
Table 22-1 lists the methods defined by the Interaction
interface to replace a participant in a communication with another participant. In the context of announcement support, the other participant you add to the communication is the media server.
Table 22-1 Methods Defined by the Interaction Interface
Method | Description |
---|---|
|
Adds a participant to the interaction. |
|
Removes a participant from the interaction. |
|
Enhanced function for participant replacement. If purge is set to false, the two methods provides the same are functionality. IMConversation, IMConference and QueryInteration do not support this function |
Table 22-2 lists the methods defined by the Conversation
interface.
Table 22-2 Methods Defined by the Conversation Interface
Method | Description |
---|---|
|
Gets the other party of the specified participant in the Conversation. |
|
Returns the MediaPartner joined in the Conversation instance if such a MediaPartner exists. |
Table 22-3 lists the methods defined by the Participant
interface.
Table 22-3 Methods Defined by the Participant Interface
Method | Description |
---|---|
|
Gets a |
Table 22-4 lists the methods defined by the ConversationParticipantExtension
interface
Table 22-4 Methods Defined by the ConversationParticipantExtension Interface
Method | Description |
---|---|
|
Decides if media information exchange of this participant involved need to be deferred. Only effective on the called party. When this method is invoke, the media information exchange between the called part and the calling party is deferred. A use case is when the called party needs to exchange media information with a third party, for example a media server. |
The MediaPartner
interface extends the MediaParticpant
interface, and allows you to add a Mediapartner
, which represents a media server that will play an announcement. Table 22-5 lists the methods defined by the MediaPartner
interface.
Table 22-5 Methods Defined by the MediaPartner Interface
|
Attaches with the specified UserParticipant, and acts as each other's partner. |
|
Detach from the user partner and restore Communication to the original state prior to the attach operation. |
|
Return the UserParticipant if the MediaPartner have already attached with a UserParticipant using |
|
Start playing the announcement from the specified URI. |
|
Record to the specified URI. |
|
Purges the party when it is replaced by this MediaPartner if This method must be invoked before calling |
|
Stop the specified operation this MediaPartner is related to. |
The following @CommunicationEvent
enumeration types are used in the playing of announcements.
Table 22-6 CommunicationEvents for Announcements
Enumeration | Description |
---|---|
FINISHING |
Indicates that the Participant is requesting to finish (or end) an established Communication. |
FORWARDING |
Indicates that a call is being forwarded. |
HELD |
Indicates that a call is in a held state. |
HOLDING |
Indicates that a call is being held. |
PICKUP |
Indicates that the called party has picked-up the phone (answered the call). |
MEDIA_INFO_EARLY_EXCHANGED |
Indicates that end-to-end media information is to be exchanged before the called party answers the call (picks-up the phone). End-to-end refers to information being exchanged between the calling party (the caller) to the called party (the callee). |
MEDIA_RESOURCE_RESERVED |
Indicates that a media resource has been reserved. This event is triggered after a media exchange between the calling and called party when the media server finishes streaming content. You can trigger this event by adding a MediaParticipant. |
RESUMED |
Indicates that a call is already resumed. |
RESUMING |
Indicates that a call is being resumed. |
The following @ParticipantEvent
enumeration types are used in the playing of announcements.
Table 22-7 ParticipantEvents for Announcements
Enumeration | Description |
---|---|
INITIALIZATION |
This is the first Participant event during the Participant's life-cycle. This event allows the CommunicationBean to set the Participant's attributes and properties, altering it's subsequent behaviors. Operations that lead to the state transition of the Communication or Participant are not permitted to use this event. Although this event occurs prior to any other disposal on this participant, however it occurs later than the INITIALIZATION event used by the CommunicationEvent. A typical use case is to invoke |
BEING_BANNED |
Indicates that the Participant is to be rejected by the AS (call barring). |
The MediaPartner
allows the UserPartner
to access media-related functions such as the playing or recording of announcements. A Conversation
can have one MediaPartner
in addition to the maximum two UserParticipant
objects. Each MediaPartner
interacts with one UserParticipant
. MediaPartner.attach(UserParticipant)
establishes a relationship between the MediaPartner
and the UserParticipant
. Before it attaches to the UserParticpant
, the MediaPartner
must first be added to the Conversation
.
Assume that a MediaPartner
has been added to a Conversation
, and that User A represents a member of the Conversation
. If the MediaPartner
attaches to User A via MediaPartner.attach(UserA)
, it starts the process of reserving the media resource. During the set-up process there is an SDP exchange between User A and the media server that will play the announcement. If in addition to User A, the Conversation
has another member identified as User B, then the MediaPartner
replaces User B. If the MediaPartner
is exclusive, then User B will be purged (using a BYE/CANCEL/REJECTED message) from the Conversation
.
If User B is not purged, the called party (callee) or calling party (caller) is temporarily replaced by another participant. In the case of playing an announcement the other participant is represented by the MediaPartner
. When the announcement is finished and the MediaPartner
terminates, the participant that was temporarily replaced is restored as the callee or caller, and participates in any subsequent stages of the conversation.
MediaPartner.play(uri)
invokes the play operation of the underlying JSR309 API. Once a media resource is reserved, SFT throws a corresponding event in which MediaPartner.play(uri)
is invoked to play an announcement. Note that MediaPartner.play(url)
must co-operate with MediaPartner.attach(UserParticipant)
.
When MediaPartner.detach()
is invoked, the MediaPartner
is removed from the Conversation
and purged, the temporarily replaced participant is restored, and both UserPartner attached to the MediaPartner
and the MediaPartner
of User A are purged.
Callout announcements play an announcement to the calling party when initiating a call, but prior to the call being forwarded to the called party. For example, a Change of Service announcement that informs the caller that the phone number they are calling has been changed, recites the new phone number, and then forwards the call to the new number.
Callout announcement is defined in section of A.1.1 of TS 24.628.
Example 22-1 shows the example code for a Communication Bean that plays a call out announcement. The trigger to play the announcement is defined in the method using CommunicationEvent.Type.MEDIA_RESOURCE_RESERVED
.
Example 22-1 Callout Announcement
@ServiceAttributes(mscontrolJndiName = "mscontrol/dlg309") @CommunicationBean(type = Conversation.class) public class CalloutAnnouncementBean { @Context CommunicationContext<Conversation, UserParticipant> ctx; @Context CommunicationSession session; String userSubsCalloutPrompt = "bob@example.com"; String uriStr = "file://prompts/generic/en_US/num_dialed.wav"; @CommunicationEvent(type = CommunicationEvent.Type.INITIALIZATION) public void handleInit() { Conversation conv = (Conversation)ctx.getCommunication(); if(conv.getCaller().getName().equals(userSubsCalloutPrompt)) { UserParticipant caller = (UserParticipant)conv.getCaller(); conv.addParticipant(MediaPartner.class, "theMP"); MediaPartner mediaPartner = conv.getMediaPartner(); mediaPartner.attach(caller); } @CommunicationEvent(type = CommunicationEvent.Type.MEDIA_RESOURCE_RESERVED) public void handleEarlyEstablished() { Conversation conv = (Conversation)ctx.getCommunication(); conv.getMediaPartner().play(media_file_uri); } //Handle end of the announcement playback @CommunicationEvent(type = CommunicationEvent.Type.MEDIAENDED) void handleMediaEnded(){ Conversation conv = ctx.getCommunication(); //Media partner quit the call, restore former call process. conv.getMediaPartner().detach(); } @ParticipantEvent(type = ParticipantEvent.Type.INITIALIZATION) public void handlePartInit(){ Participant currPart = ctx.getParticipant(); Conversation conv = (Conversation)ctx.getCommunication(); Participant callee = conv.getCallee(); if (currPart.equals(callee)){ if(conv.getCaller().getName().equals(userSubsCalloutPrompt)) { callee.getExtension(ConversationParticipantExtension.class). deferMediaInfoExchange(); } } } }
SFT supports the following call barring announcements, which are defined in Section 4.2.4 of the 3GPP TS 24.628 specification:
Call Barring Announcement by Error-Info
Call Barring Announcement by Early Media
Call Barring Announcement by Established Session
When rejecting the calling party, this scenario inserts an Error-Info header in the error response field (3xx, 4xx, 5xx, or 6xx). This header can also carry a media URI, allowing the calling party to play an announcement, or carry an indication about the call barring.
You can populate the Error-Info header with a response code using the EventReason.createReasonData(Reason reason)
method. Each of the reason types is translated into a corresponding SIP response code by SFT. See the Converged Application Server API Reference for more information.
Example 22-2 illustrates how to initiate a call barring announcement using the Error-Info event when a call barring event is identified, but before invoking the UserParticipant.reject event.
Example 22-2 Call Barring Announcement by Error-Info
@ParticipantEvent(type = ParticipantEvent.Type.JOINING) void handleJoining() { Conversation conv = (Conversation) ctx.getCommunication(); Participant currPart = ctx.getParticipant(); if(conv.getCaller().equals(currPart)){ //Application initiates call barring. UserParticipant caller = (UserParticipant)conv.getCaller(); String promptTone = "http://localhost/media/nopermission.wav"; AnnouncementIndication ai = ctx.getContextElement(AnnouncementIndication.class); ai.createErrorIndication(promptTone); caller.reject(Reason.DECLINE); } }
In Example 22-3 the ParticipantEvent.Type.BEING_BANNED
event occurs after the UserParticipant.reject(Reason.DECLINE)
method is invoked by the application, but prior to the call barring service being activated. This scenario also lets you play an announcement using the Error-Info header.
@ParticipantEvent(type = ParticipantEvent.Type.JOINING) void handleJoining() { Conversation conv = (Conversation) ctx.getCommunication(); Participant currPart = ctx.getParticipant(); //Application initiates call barring via the Reason.DECLINE reject event. if(conv.getCaller().equals(currPart)){ UserParticipant caller = (UserParticipant)conv.getCaller(); caller.reject(Reason.DECLINE); } } @ParticipantEvent(type = ParticipantEvent.Type.BEING_BANNED) void handleBarring() { String promptTone = "http://localhost/media/wav/nopermission.wav"; AnnouncementIndication ai = ctx.getContextElement(AnnouncementIndication.class); ai.createErrorIndication(promptTone); }
Early media is the ability to play an announcement prior to establishing a SIP session (before sending a 2xx response code). In conjunction with call barring, the early media announcement plays, and when it finishes playback the incoming call is barred
Audible announcements can be also provided when an Application Server is rejecting the establishment of a session (before sending a 2xx response code). In this scenario a caller sends an INVITE request that is received by the AS, which determines to reject the call. Before barring the call, the AS can provide an audible announcement to the caller, potentially indicating the reasons for the call rejection.
Example 22-4 shows how to initiate playback of the announcement prior to rejecting the call using the ParticipantEvent.Type.BEING_BANNED
event.
During the ParticipantEvent.Type.JOINING
method, the application invokes caller.reject(Reason.DECLINE), initiating call barring.
When the ParticipantEvent.Type.BEING_BANNED
event is subsequently thrown, the MediaParticipant.getMediaPartner() method plays the announcement.
After the announcement plays, the CommunicationEvent.Type.MEDIAENDED
event signifies that the media playback from the media server is over, releasing the media resource. Call barring can then be completed.
Example 22-4 Call Barring Announcement Using Early Media
@ParticipantEvent(type = ParticipantEvent.Type.JOINING) void handleJoining() { Conversation conv = (Conversation) ctx.getCommunication(); Participant currPart = ctx.getParticipant(); if(conv.getCaller().equals(currPart)){ //Initiate call barring using Reason.DECLINE UserParticipant caller = (UserParticipant)conv.getCaller(); caller.reject(Reason.DECLINE); } } @ParticipantEvent(type = ParticipantEvent.Type.BEING_BANNED) void handleBarring() { Conversation conv = (Conversation) ctx.getCommunication(); UserParticipant caller = (UserParticipant)conv.getCaller(); caller.getMediaPartner().play(uri); } @CommunicationEvent(type = CommunicationEvent.Type.MEDIAENDED) void handleMediaEnded(){ MediaParticipant mp = (MediaParticipant)ctx.getParticipant(); //MediaParticipant is released from the communication mp.unjoin(); } //Call reject process can now resume.
Another possibility is to play the announcement upon determining that the calling party is to be barred, and then invoking the caller reject event after removing the media resource.
Example 22-5 invokes the getMediaPartner()
method during the ParticipantEvent.Type.JOINING
event. Once the announcement is finished playing, the caller.reject()
method performs the call barring.
Example 22-5 Call Barring Announcement Using Early Media
@ParticipantEvent(type = ParticipantEvent.Type.JOINING) void handleJoining() { Conversation conv = (Conversation) ctx.getCommunication(); Participant currPart = ctx.getParticipant(); if(conv.getCaller().equals(currPart)){ //Application determines to bar the caller... UserParticipant caller = (UserParticipant)conv.getCaller(); caller.getMediaPartner().play(uri); } } @CommunicationEvent(type = CommunicationEvent.Type.MEDIAENDED) void handleMediaEnded(){ Conversation conv = ctx.getCommunication(); //Release media resource. MediaParticipant mp = (MediaParticipant)ctx.getParticipant(); conv.removeParticipant(mp); UserParticipant caller = (UserParticipant)conv.getCaller(); caller.reject(Reason.DECLINE); }
In this scenario the call is barred not by an error response, but with a BYE request in the Reason header. When the application determines the call is to be barred, a media session to play the announcement is established for the calling party. When the announcement finishes playing, the application releases the communication and includes an appropriate Reason header as the reject code in the BYE request.
Example 22-6 calls the EventReason.createReasonData(Reason reason)
method, which inserts a BYE request in the Reason header. The communication is then terminated with a method call to Communication.end()
.
Note:
Unlike the early media scenario described earlier in this chapter, playing an announcement in an established session requires that you create an exclusive media partner for the caller to play the announcement.Example 22-6 Playing an Announcement Before Rejecting the Call
@ParticipantEvent(type = ParticipantEvent.Type.JOINING) void handleJoining() { Conversation conv = (Conversation) ctx.getCommunication(); Participant currPart = ctx.getParticipant(); if(conv.getCaller().equals(currPart)){ //Application determines to bar the caller. UserParticipant caller = (UserParticipant)conv.getCaller(); //Create a media partner to play the announcement. caller.getMediaPartner(true).play(uri); } } @CommunicationEvent(type = CommunicationEvent.Type.MEDIAENDED) void handleMediaEnded(){ Conversation conv = ctx.getCommunication(); //Insert a BYE request in the Reason header. EventReason er = ctx.getContextElement(EventReason.class); er.createReasonData(Reason.DECLINE); //End the call. conv.end(); }
Example 22-7 shows how an application can terminate an established communication using caller.reject(Reason)
, and play an announcement. The application bars the calling party, and in the subsequent ParticipantEvent.Type.BEING_BANNED
event, plays an announcement with an exclusive media partner. After the announcement plays, the communication ends.
Example 22-7 Terminating a Communication and playing an Announcement
@ParticipantEvent(type = ParticipantEvent.Type.JOINING) void handleJoining() { Conversation conv = (Conversation) ctx.getCommunication(); Participant currPart = ctx.getParticipant(); if(conv.getCaller().equals(currPart)){ //Application determines to bar the caller. UserParticipant caller = (UserParticipant)conv.getCaller(); //The caller is rejected. caller.reject(Reason.DECLINE); } } //The participant will be rejected by the AS (call barring). @ParticipantEvent(type = ParticipantEvent.Type.BEING_BANNED) void handleBarring() { Conversation conv = (Conversation) ctx.getCommunication(); UserParticipant caller = (UserParticipant)conv.getCaller(); //Create a media partner to play the announcement. caller.getMediaPartner(true).play(uri); } //When the announcement ends, unjoin the MediaParticipant.player. @CommunicationEvent(type = CommunicationEvent.Type.MEDIAENDED) void handleMediaEnded(){ MediaParticipant player = (MediaParticipant)ctx.getParticipant(); player.unjoin(); }
Colorful Ring Tone (CRT) (defined in RFC 3959) allows an application to play a distinctive audio or video announcement to the called party to replace the default ring tone. SFT supports CRT by adding an Alert-Info header to the SIP INVITE sent to the callee. The Alert-Info header value is a media URI that the UE of the callee can play as an announcement. SFT adds the media URI to the Alert-Info header using the AnnouncementIndication.createDRIndication(uri)
method.
To specify an announcement as a CRT, use the ParticipantEvent.Type.INITIALIZATION
event to identify the callee. In this way the callee is subscribed to the CRT announcement.
Example 22-8 creates a method to handle the INITIALIZATION
event, in which the callee (alice@example.com) will receive the URI identifying the audio file ringtone.wav to be played as an announcement indication.
@ParticipantEvent(type= ParticipantEvent.Type.INITIALIZATION) void handleInit() { Participant currPart = ctx.getParticipant(); Conversation conv = (Conversation) ctx.getCommunication(); UserParticipant callee = (UserParticipant)conv.getCallee(); if(currPart.equals(callee)){ //Alice subscribes to the CRT service, which plays the specifed ringtone. if(conv.getCaller().getName().equals("alice@example.com")){ String url = "http://localhost/media/ringtone.wav"; //Add the media URI to the Alert-Info header. AnnouncementIndication ai = ctx.getContextElement(AnnouncementIndication.class); ai.createDRIndication(url); } } }
Colorful Ring Back Tone, (also referred to as Caller Ring Back Tone), allows an application to play a distinctive audio or video announcement to the calling party to replace the default ring tone. SFT supports the following methods to create a Colorful Ring Back Tone (CRBT):
CRBT by Alert-Info
CRBT using early media, however, there is no early media exchange between the original calling and called parties
CRBT using early media after the early media is exchanged between original calling and called parties
The above approaches for creating a CRBT application are defined in Section 4.2.2 of the 3GPP TS 24.628 specification. CRBT is also described in RFC 5009.
In this scenario, an Alert-Info header containing a media URI is inserted into the SIP message in response to the 180 Ringing response code. The Alert-Info header value can be a media URI that the UE of the calling party plays as announcement, or a conventional indication by which the UE of the calling party determines what media to play. SFT adds the media URI to the Alert-Info header using the AnnouncementIndication.createDRIndication(uri)
method.
To specify an announcement as a CRBT, use the ParticipantEvent.Type.JOINING
event to identify the callee. In this way the callee is subscribed to the CRBT announcement.
Example 22-9 creates a method to handle the JOINING
event, in which the callee (bob@example.com) receives the URI identifying the audio file ringtone.wav to be played as an announcement indication.
Example 22-9 CRBT Using a Media URI in the Alert-Info Header
@ParticipantEvent(type= ParticipantEvent.Type.JOINING) void handleJoining() { Conversation conv = (Conversation) ctx.getCommunication(); Participant callee = conv.getCallee(); Participant currPart = ctx.getParticipant(); if(currPart.equals(callee)){ //Bob subscribes to the CRBT service, which plays the specifed ringtone. if(callee.getName().equals("bob@example.com")){ String url = "http://localhost/media/ringtone.wav"; AnnouncementIndication ai = ctx.getContextElement(AnnouncementIndication.class); ai.createDRIndication(url); } } }
To specify an announcement as a CRBT without early media exchange, use the ParticipantEvent.Type.JOINING
event to identify the callee. In this way the callee is subscribed to the CRBT announcement.
Example 22-10 CRBT Without Early Media Exchange
@ServiceAttributes(mscontrolJndiName = "mscontrol/dlg309") @CommunicationBean(type = Conversation.class) public class ColorRingBackToneBean { @Context CommunicationContext<Conversation, UserParticipant> ctx; @Context CommunicationSession session; @ParticipantEvent(type = ParticipantEvent.Type.INITIALIZATION) public void handlePartInit(){ Conversation conv = ctx.getCommunication(); Participant currPart = ctx.getParticipant(); Participant callee = conv.getCallee(); //Bob subscribes to the CRBT service. if (callee.equals(currPart)&& callee.getName().equals("bob@example.com")) { callee.deferMediaInfoExchange(); } } @ParticipantEvent(type = ParticipantEvent.Type.JOINING) public void handleJoining() { Conversation conv = (Conversation)ctx.getCommunication(); Participant callee = conv.getCallee(); Participant currPart = ctx.getParticipant(); if (callee.equals(currPart)&& callee.getName().equals("bob@example.com")) { String uriStr = "file://prompts/generic/en_US/numDialed.wav"; UserParticipant caller = (UserParticipant)conv.getCaller(); caller.getMediaPartner().play(uriStr); } } //End announcement and release the media resource. @CommunicationEvent(type = CommunicationEvent.Type.MEDIAENDED) void handleMediaEnded(){ MediaParticipant mp = (MediaParticipant)ctx.getParticipant(); mp.unjoin(); }
To specify an announcement as a CRBT after early media exchange, use the ParticipantEvent.Type.MEDIA_INFO_EARLY_EXCHANGED
event to identify the callee. In this way the callee is subscribed to the CRBT announcement.
Example 22-11 CRBT After Early Media Exchange
@ServiceAttributes(mscontrolJndiName = "mscontrol/dlg309") @CommunicationBean(type = Conversation.class) public class ColorRingBackToneBean02 { @Context CommunicationContext<Conversation, UserParticipant> ctx; @Context CommunicationSession session; @CommunicationEvent(type = CommunicationEvent.Type.MEDIA_INFO_EARLY_EXCHANGED) public void handleMediaEarlyExchange() { Conversation conv = (Conversation)ctx.getCommunication(); Participant callee = conv.getCallee(); //Bob subscribes to the CRBT service. if(callee.getName().equals("bob@example.com")){ String uriStr = "file://prompts/generic/en_US/numDialed.wav"; UserParticipant caller = (UserParticipant)conv.getCaller(); caller.getMediaPartner().play(uriStr); } } //End announcement and release the media resource. @CommunicationEvent(type = CommunicationEvent.Type.MEDIAENDED) void handleMediaEnded(){ MediaParticipant mp = (MediaParticipant)ctx.getParticipant(); mp.unjoin(); } }
Call rejection announcements play when a callee rejects a caller. SFT supports the following methods to create a call rejection announcement:
Reject announcement using Error-Info
Reject announcement using early media
In this scenario, an Error-Info header containing a media URI is inserted into the SIP message in response to a 480 Temporarily Unavailable response code. The Error-Info header value can be a media URI that the UE of the calling party plays as announcement, or a conventional indication by which the UE of the calling party determines what media to play. SFT adds the media URI to the Error-Info header using the AnnouncementIndication.createDRIndication(uri)
method.
To play an announcement in response to a call rejection, use the ParticipantEvent.Type.REJECTED
event to identify the callee. If the EventReason interface returns NOTAVAILABLE, BUSY, or DECLINE reason types, then a call rejection announcement can be played in response.
Example 22-12 creates a method to handle the REJECTED
event, in which the callee (bob@example.com) receives the URI identifying the audio file reject.wav to be played as a rejection announcement.
Example 22-12 Call Rejection Using Error-Info
@ParticipantEvent(type= ParticipantEvent.Type.REJECTED) void handleRejected() { Conversation conv = (Conversation) ctx.getCommunication(); EventReason er = ctx.getContextElement(EventReason.class); if (er!=null){ ReasonData rd = er.getReasonData().get(0); if(rd.getReasonType()==Reason.NOTAVAILABLE|| rd.getReasonType()==Reason.BUSY|| rd.getReasonType()==Reason.DECLINE){ UserParticipant caller = (UserParticipant)conv.getCaller(); if(caller.getName().equals("bob@example.com")){ String promptTone = "http://localhost/media/reject.wav"; AnnouncementIndication ai = ctx.getContextElement(AnnouncementIndication.class); ai.createErrorIndication(promptTone); } } } }
To specify an announcement as a call rejection after early media exchange, use the ParticipantEvent.Type.REJECTED
event to identify and reject the callee.
Example 22-13 Call Rejection Announcement Using Early Media
@ParticipantEvent(type= ParticipantEvent.Type.REJECTED) void handleRejected() { Conversation conv = (Conversation) ctx.getCommunication(); EventReason er = ctx.getContextElement(EventReason.class); if (er!=null){ ReasonData rd = er.getReasonData().get(0); if(rd.getReasonType()==Reason.NOT_AVAILABLE|| rd.getReasonType()==Reason.BUSY|| rd.getReasonType()==Reason.DECLINE){ if(conv.getCaller().getName().equals("bob@example.com")){ UserParticipant caller = (UserParticipant)conv.getCaller(); conv.addParticipant(MediaPartner.class, "theMP"); conv.getMediaPartner().attach(caller); } } } } @CommunicationEvent(type = CommunicationEvent.Type.MEDIA_RESOURCE_RESERVED) public void handleEarlyEstablished() { Conversation conv = (Conversation)ctx.getCommunication(); String uri = "file:///prompts/en_US/rejected.wav"; conv.getMediaPartner().play(uri); } @CommunicationEvent(type = CommunicationEvent.Type.MEDIAENDED) void handleMediaEnded(){ MediaPartner player = ctx.getParticipant(); player.detach(); }
For all supported call forwarding modes, SFT supports announcements to the calling party using early media prior to forwarding the call. Call Forwarding announcements are referenced in RFC 5009.
Unconditional forwarding routes all incoming calls to a second phone number specified by the user of the service. The second number can be a work phone, voice-mail account, or other end-point in the network where the user would like their incoming calls to be received. In contrast, conditional call forwarding occurs when the user's phone is out of the service area, on another call, or the phone is turned off, and the call is forwarded to a secondary number.
SFT supports Unconditional Call Forwarding announcements using the following event types:
ParticipantEvent.Type.JOINING (Caller side)
CommunicationEvent.Type.STARTED
CommunicationEvent.Type.INITIALIZATION
Example 22-14 shows how to implement a Direct Call Forwarding Announcement by initiating the announcement without first triggering the Call Forwarding event. In this example Call Forwarding is triggered using the CommunicationEvent.Type.MEDIAENDED event.
Example 22-14 Direct Call Forwarding Announcement Without A Call Forwarding Event
@CommunicationEvent(type = CommunicationEvent.Type.INITIALIZATION) public void handleInit() { Conversation conv = (Conversation)ctx.getCommunication(); UserParticipant caller = (UserParticipant)conv.getCaller(); // Bob subscribes to call forwarding service. // Opensp subscribes to call forwarding announcement service. if(caller.getName().equals("opensp@example.com") && conv.getCallee().getName().equals("bob@example.com")) { conv.addParticipant(MediaPartner.class, "theMP"); conv.getMediaPartner().attach(caller); } } @CommunicationEvent(type = CommunicationEvent.Type.MEDIA_RESOURCE_RESERVED) public void handleMediaResourceReserved() { Conversation conv = (Conversation)ctx.getCommunication(); String uri = "file://prompts/generic/en_US/num_changed.wav"; conv.getMediaPartner().play(uri); } @CommunicationEvent(type = CommunicationEvent.Type.MEDIAENDED) void handleMediaEnded(){ Conversation conv = ctx.getCommunication(); UserParticipant p = session.createParticipant(UserParticipant.class, "amy@example.com"); MediaParticipant mp = conv.getMediaPartner(); conv.replaceParticipant(mp, p); } @ParticipantEvent(type = ParticipantEvent.Type.INITIALIZATION) public void handlePartInit(){ Participant currPart = ctx.getParticipant(); Conversation conv = (Conversation)ctx.getCommunication(); Participant callee = conv.getCallee(); if (currPart.equals(callee)){ if(conv.getCaller().getName().equals("opensp@example.com") &&callee.getName().equals("amy@example.com")) callee.getExtension(ConversationParticipantExtension.class).deferMediaInfoExchange(); } } }
Conditional call forwarding (also referred to as call diversion) routes all incoming calls to the specified phone number when a corresponding condition is met. Common call forwarding conditions include:
No answer after specified period of time
Unreachable due to no signal or phone powered off
Busy on another call
Example 22-15 shows how to initiate the call forwarding announcement in the CommunicationEvent.Type.FORWARDING event.
Example 22-15 Call Forwarding Announcement During CommunicationEvent.Type.FORWARDING
@ParticipantEvent(type= ParticipantEvent.Type.REJECTED) void handleIncomingResponse() { Conversation call = (Conversation) ctx.getCommunication(); EventReason er = ctx.getContextElement(EventReason.class); if (er!=null){ ReasonData rd = er.getReasonData().get(0); if(rd.getReasonType()==Reason.NOTAVAILABLE|| rd.getReasonType()==Reason.BUSY|| rd.getReasonType()==Reason.DECLINE){ if(call.getCallee().getName().equals("bob@example.com")){ Participant newCallee = session.createParticipant (UserParticipant.class, "amy@example.com"); //Use not removeParticipant+addParticipant but //replaceParticipant to assure both CF and announcement work fine. call.replaceParticipant(call.getCallee(), newCallee, true); } } } } @CommunicationEvent(type = CommunicationEvent.Type.FORWARDING) void handleForwarding(){ Conversation conv = (Conversation) ctx.getCommunication(); if(conv.getCaller().getName().equals("opensp@example.com")){ UserParticipant caller = (UserParticipant)conv.getCaller(); conv.addParticipant(MediaPartner.class, "theMP"); conv.getMediaPartner().attach(caller); } } @CommunicationEvent(type = CommunicationEvent.Type.MEDIA_RESOURCE_RESERVED) public void handleEarlyEstablished() { Conversation conv = (Conversation)ctx.getCommunication(); String uri = "file:////opt/snowshore/prompts/generic/en_US/num_changed.wav"; conv.getMediaPartner().play(uri); } @CommunicationEvent(type = CommunicationEvent.Type.MEDIAENDED) void handleMediaEnded() { MediaPartner player = (MediaPartner)ctx.getParticipant(); player.detach(); } @ParticipantEvent(type = ParticipantEvent.Type.INITIALIZATION) public void handlePartInit(){ Participant currPart = ctx.getParticipant(); Conversation conv = (Conversation)ctx.getCommunication(); Participant callee = conv.getCallee(); if (currPart.equals(callee)){ if(conv.getCaller().getName().equals("opensp@example.com")&&callee.getName().equals("amy@example.com")) { callee.getExtension(ConversationParticipantExtension.class).deferMediaInfoExchange(); } } }
Call waiting announcement plays an announcement to the calling parties in a communication waiting state. SFT supports call waiting announcement for all call waiting scenarios (including NDUB and UDUB). SFT provides two methods by which to implement communication waiting announcement:
Call waiting announcement by Alert-Info
Call waiting announcement by early media
When implementing either of these approaches, the announcement logic should be in the CommunicationEvent.Type.WAITING
event.
SFT's implementation of call waiting announcement using the Alert-Info header complies with RFC 3261, TS 24.628, TS 24.615, and the Alert-Info URNs for the Session Initiation Protocol (SIP).
Example 22-16 plays a Distinctive Ringing announcement (Alert-Info) to the calling party held in the call waiting state. The Alert-Info header is carried in the 180 response which forwards the calling party. The code example shown below is common for different call waiting scenarios.
//Communication waiting logic appears pior to this. @CommunicationEvent(type = CommunicationEvent.Type.WAITING) void handleCallWaiting() { String uri = "http://localhost/myapp/media/wav/busy.wav"; AnnouncementIndication ai = ctx.getContextElement(AnnouncementIndication.class); ai.createDRIndication(uri); }
Example 22-17 shows how to initiate playback of an announcement to a calling party in a call waiting state using early media. The code example shown below is common to different call waiting scenarios using early media to play announcements.
Example 22-17 Call Waiting Announcement Using Early Media
@ParticipantEvent(type = ParticipantEvent.Type.INITIALIZATION) public void handlePartInit(){ Conversation conv = (Conversation)ctx.getCommunication(); Participant currPart = ctx.getParticipant(); Participant callee = conv.getCallee(); if (currPart.equals(callee)&& callee.getName().equals(userSubsCWPrompt)) { callee.getExtension(ConversationParticipantExtension.class) .deferMediaInfoExchange(); } } //Add the MediaPartner as a Participant to the call. @CommunicationEvent(type = CommunicationEvent.Type.WAITING) void handleCallWaiting() { Conversation conv = (Conversation) ctx.getCommunication(); UserParticipant caller = (UserParticipant)conv.getCaller(); conv.addParticipant(MediaPartner.class, "theMP"); conv.getMediaPartner().attach(caller); } // @CommunicationEvent(type = CommunicationEvent.Type.MEDIA_RESOURCE_RESERVED) public void handleEarlyEstablished() { Conversation conv = (Conversation)ctx.getCommunication(); String uri = "file:////prompts/generic/en_US/circuit_busy.wav"; conv.getMediaPartner().play(uri); } //This method is optional to this Call Waiting case. @CommunicationEvent(type = CommunicationEvent.Type.MEDIAENDED) void handleMediaEnded(){ MediaPartner mp = (MediaPartner)ctx.getParticipant(); mp.detach(); }
Pickup announcements play an announcement to the called party when they pickup the phone (answer the call). Pickup Announcement is defined in Section 4.2.6 of the 3GPP TS 24.628 specification.
SFT supports Pickup Announcement using a media session. When the called party (the callee) answers the phone, the CommunicationEvent.Type.PICKUP
event is triggered; the SFT application must initiate pickup announcement during this event.
Example 22-18 illustrates the use of the CommunicationEvent.Type.PICKUP
event to play an announcement to a callee when they answer the phone. In this example the callee—identified by the SIP URI bob@example.com—will be played an announcement when he answers the incoming call.
Example 22-18 Pickup Announcement
@ParticipantEvent(type = ParticipantEvent.Type.INITIALIZATION) public void handlePartInit(){ Conversation conv = (Conversation)ctx.getCommunication(); Participant currPart = ctx.getParticipant(); Participant callee = conv.getCallee(); if (currPart.equals(callee)&& callee.getName().equals("bob@example.com")) { callee.getExtension(ConversationParticipantExtension.class).deferMediaInfoExchange(); } } @CommunicationEvent(type= CommunicationEvent.Type.PICKUP) void handlePickup() { UserParticipant pickupParty = ctx.getParticipant(); //The bob@exmaple.com is subscribed to the pickup announcement. if(pickupParty.getName().equals("bob@example.com")){ Conversation conv = ctx.getCommunication(); conv.addParticipant(MediaPartner.class, "theMP"); conv.getMediaPartner().attach(pickupParty); } } @CommunicationEvent(type = CommunicationEvent.Type.MEDIA_RESOURCE_RESERVED) public void handleEarlyEstablished() { Conversation conv = ctx.getCommunication(); String uri = "file:////opt/snowshore/prompts/generic/en_US/pickup_who.wav"; conv.getMediaPartner().play(uri); } @CommunicationEvent(type = CommunicationEvent.Type.MEDIAENDED) void handleMediaEnded(){ MediaPartner player = (MediaPartner)ctx.getParticipant(); player.detach(); }