Requirements

Prerequisite knowledge

Some experience with basic Java programming and Adobe Connect. Familiarity with the provider's service interface and telephony in Adobe Connect is also helpful to build your own audio conferencing adaptor.

 

Additional required products:

Asterisk telephony software

Asterisk-Java library

User level

Intermediate

Adobe Connect 8, an enterprise web conferencing solution for online meetings, eLearning, and webinars, supports integrated telephone-based audio conferences during live meetings. Through this integration, you can use the Adobe Connect meeting room to control the audio conference. You can start and stop an audio conference, manage recording, mute or unmute participants, and more. This article describes the basics of integrating an audio conferencing service with Adobe Connect 8.

Adaptor basics

The Adobe Connect telephony support is provided through a separate service: Adobe Connect Telephony Service. This service includes several telephony adaptors, which are Java extensions that serve as the interface between individual conferencing services and Adobe Connect. To integrate a new audio conferencing service, you need to create a new telephony adaptor that connects Adobe Connect to an audio bridge.

In writing the telephony adaptor, you'll need to implement a Java-based telephony adaptor interface. The interface provides methods to facilitate interaction between Adobe Connect and the conferencing service. More specifically, it has methods that enable hosts and presenters to control the audio conference from the meeting—for example, starting and stopping an audio conference, recording, and so on. Additionally it provides a callback facility so that the conferencing bridge can initiate interactions with the meeting room—for example, to indicate that a new participant has joined the audio conference.

For more information on the telephony adaptor interface, including details on each method, see the TelephonyAdaptor interface documentation.

Asterisk MeetMe integration

Asterisk is free, open-source telephony software, and MeetMe is an audio conferencing application for Asterisk. MeetMe conferences can be controlled via the Asterisk Manager Interface (AMI). Asterisk-Java is a freely available Java library for accessing AMI though a Java-based application (the adaptor in this case). In addition to Asterisk-Java, the example attached with this article uses the MeetMe Java library, which is an extension of Asterisk-Java for managing MeetMe conferencing through a Java application.

Asterisk adaptor classes

The Asterisk adaptor has three classes (see Figure 1):

  • Adaptor: This class implements the TelephonyAdaptor interface and is the core of the adaptor. For most operations, the adaptor identifies the conference object based on the conference ID passed as a parameter to its methods and the appropriate method is called on the conference object.
  • AdaptorState: This class manages the state related information for the adaptor, which includes a list of active conferences, the callback object, and the MeetMe conferencing state.
  • ConnectConference: This class represents an audio conference. The various call control features available via the Asterisk Manager Interface are accessed through this class. This class adds itself as an observer to the MeetMe Conference to receive the notifications dispatched by the conference. This class also acts as the observer for all the MeetMe conference participants and handles any events dispatched by them.

Audio conference life cycle

While implementing an adaptor interface, keep in mind that there is a specific sequence of methods that are called during the life cycle of an audio conference, which typically follow the start, in session, and ended phases.

The sequence diagrams in Figures 2–5 illustrate the sequence of methods that may get called during the life cycle of an audio conference.

Typical conferencing use case

To understand better how an adaptor is implemented, consider the following typical use case:

  1. An audio conference is started from the Adobe Connect meeting room.
  2. A participant dials into the audio conference.
  3. Another participant is dialed from the meeting room.
  4. One of the participants is muted for some time.
  5. One of the participants hangs up the phone.
  6. The audio conference is ended, causing the remaining participants to exit the audio conference.

The next sections explain the adaptor code associated with each step above. You may want to keep to the TelephonyAdaptor interface documentation open as you go through the code, so you can refer to each method's arguments and return value.

Note: The following code snippets are provided to convey the general idea of what should be done in specific adaptor methods and should not be taken as a reference implementation. As a developer, you are free to choose the way you want to code your adaptor as long as you correctly implement the telephony adaptor interface.

An audio conference is started from the Adobe Connect meeting room

When the Telephony Service is first started, it loads the adaptors that are placed in its web/WEB-INF/lib directory. When an adaptor is loaded, the first method that gets called after its constructor is initAdaptor() :

@Override public void initAdaptor(TelephonyCallback callback,Map<String, String> telephonySettings, String adaptorInstanceId)throws AdaptorException { try { /* * Adaptor state is the data class containing the state information * for an adaptor instance like the running conference instances, * pending downloads etc. */ state = new AdaptorState(telephonySettings, callback); } catch (Exception ex) { throw new AdaptorException(null, ex); } }

When an Adobe Connect meeting room with an associated telephony audio conference is launched, the initConferenceSession() method gets called:

@Override public String initConferenceSession(Map<String, String> telephonyProfile) throws AdaptorException { /* * TelephonyProfile consists of all the fields that we returned by * getTelephonyFieldInfo along with their values */ String conferenceId = telephonyProfile.get("x-tel-asterisk-room-number"); String recordingNumber = telephonyProfile.get("x-tel-asterisk-recording-number"); /* ConnectConference is a class representing an audio conference */ ConnectConference conference = new ConnectConference(conferenceId,recordingNumber, this.state); /* The conference is added to the adaptor state as an active conference */ this.state.getConferenceMap().put(conferenceId, conference); return conferenceId; }

The startConference() method is invoked when a participant requests a conference start from the meeting room:

@Override public void startConference(final String conferenceId)throws AdaptorException { state.getConferenceMap().get(conferenceId).requestStartConference(); }

A participant dials into the audio conference

When a new participant joins the audio conference, the ConnectConference class receives the user-joined event; as a result, the handleAddTelephonyUser() method is called. The ConnectConference object adds itself as an observer to this user so that it may receive any notifications related to the changes in the state of the user. Additionally it invokes a callback to the Adobe Connect meeting room, informing the room about the new user:

public void handleAddTelephonyUser(User conferenceUser) throws Exception { logger.fine("A new telephony user joined"); conferenceUser.addObserver(this); state.getTelephonyCallback().userOnline(getConferenceId(), conferenceUserToTelephonyUser(conferenceUser)); }

Another participant is dialed from the meeting room

When a new participant is called from the meeting room, the adaptor's dialOut() method is invoked. The method fetches the appropriate ConnectConference object and calls the requestDialOut() method on it, which in turn calls the requestDialOut() method on the MeetMe conference. If the dial out is successful and the participant answers the phone call, the user-joined event is received and handled as in the previous step:

@Override public String dialOut(String conferenceId, String phoneNumber, UserType userType, String userName, boolean isVideo) throws AdaptorException { String telephonyUserId = null; try { ConnectConference conference = state.getConferenceMap().get( conferenceId); telephonyUserId = conference.requestDialOut(phoneNumber); } catch (Exception ex) { throw new AdaptorException(null, ex); } return telephonyUserId; } public String requestDialOut(String phoneNumber) throws Exception { return conference.requestDialOut(phoneNumber); }

One of the participants is muted for some time

To mute a participant, the setUserOption() method on the adaptor is called with mute as the UserOption and true as the optionValue. To unmute, use false as the optionValue. The adaptor determines which conference room the participant is in and calls setTelephonyUserMuteState() on it. The conference in turn forwards this call to the appropriate MeetMe conference:

@Override public void setUserOption(String conferenceId, String telephonyUserId, UserOption optionName, String optionValue) throws AdaptorException { try { ConnectConference conference = state.getConferenceMap().get( conferenceId); if (UserOption.MUTE.equals(optionName)) { logger.fine("Setting mute to:" + Boolean.parseBoolean(optionValue) + " for telephony user:" + telephonyUserId + " in conference:" + conferenceId); conference.setTelephonyUserMuteState(telephonyUserId, Boolean.parseBoolean(optionValue)); } } catch (Exception ex) { throw new AdaptorException(FailureCode.TELEPHONY_UNKNOWN_ERROR, ex); } } public void setTelephonyUserMuteState(String telephonyUserId, boolean mute) throws Exception { conference.setConferenceUserMuteState(telephonyUserId, mute); }

When a participant is muted or unmuted, the conference receives a MUTE event along with the updated user's state. The ConnectConference object handles this event in the handleMuteTelephonyUser(), which invokes a callback to the Adobe Connect meeting indicating the modified user state:

public void handleMuteTelephonyUser(User conferenceUser) { state.getTelephonyCallback().userInfoUpdated(getConferenceId(), conferenceUserToTelephonyUser(conferenceUser)); }

One of the participants hangs up the phone

When a participant hangs up the phone to quit the audio conference, a user-left event is dispatched. The associated ConnectConference object receives this event and handles it in the handleRemoveTelephonyUser() method. This method removes itself from being an event receiver for the participant and invokes the callback on the Adobe Connect meeting room to indicate that the user has left:

public void handleRemoveTelephonyUser(User conferenceUser) { conferenceUser.deleteObserver(this); state.getTelephonyCallback().userOffline(getConferenceId(), conferenceUser.getUserId()); }

The audio conference is ended, causing the remaining participants to exit the audio conference

When the audio conference is terminated from the Adobe Connect meeting room, all audio participants are disconnected from the conference and the conference ends. This process is initiated by a call to the endConference() method on the adaptor. The adaptor identifies the appropriate ConnectConference object and calls the requestEndConference() method on it. This method, in turn, calls the requestEndConference() method on the MeetMe conference:

@Override public void endConference(String conferenceId) throws AdaptorException { try { ConnectConference conference = state.getConferenceMap().get( conferenceId); conference.requestEndConference(); } catch (Exception ex) { throw new AdaptorException(null, ex); } } public void requestEndConference() throws Exception { conference.requestEndConference(); }

Once the conference has ended on the bridge, the CONFERENCE_ENDED event is received by the ConnectConference object. The handler for this even invokes a callback to the meeting room to indicate the conference has ended:

public void handleEndConference() { started = false; state.getTelephonyCallback().conferenceEnded(getConferenceId()); }

A short while (in practice, about 8–10 minutes) after the Adobe Connect meeting has ended, the destroyConferenceSession() method is called on the telephony adaptor. In this method, the adaptor removes this conference from its list of active conferences and calls the destroy() method on the ConnectConference object:

@Override public void destroyConferenceSession(String conferenceId) { state.getConferenceMap().get(conferenceId).destroy(); state.getConferenceMap().remove(conferenceId); }

In the remove() method, ConnectConference removes itself from receiving events for the conference participants and the audio conference. Finally, it calls the destroy() method on the MeetMe conference:

public void destroy() { for (User user : conference.getUsers().values()) user.deleteObserver(this); conference.deleteObserver(this); conference.destroy(); }

Where to go from here

Now that you've seen how to build a telephony adaptor for Asterisk MeetMe, you can apply the same techniques to integrate other conferencing serviced with Adobe Connect. Apply the principles illustrated in this article to any conferencing provider that provides a conference control service. A few vendors provide a SOAP-based service interface instead of a Java library. In such cases, you can often create Java stubs from the WSDL file and use them to communicate between the adaptor and the conferencing bridge.

I encourage you to explore the Asterisk adaptor source code available in the sample files for this article to see the full adaptor implementation. As you do so, refer to the following resources for additional details: