架构师:多媒体
   下载
 Oracle Communications Converged Application Server
 会议应用程序示例
 
   标签
java, middleware, 全部
 

使用 JSR 309 Media Server Control API 加速多媒体应用程序开发

作者:Marc Brandt、Tomas Ericson、Alain Comment

了解如何使用 JSR 309 参考实现驱动程序构建一个在 Oracle Communications Converged Application Server 中运行并可访问 HP OpenCall Media Platform 的 SIP Servlet 会议应用程序。

2010 年 4 月发布

近年来,部署富多媒体通信应用程序的体系结构已经有了很大发展,可以支持应用程序逻辑与媒体处理之间的分发。3GPP IMS MRF 部署体系结构的发展以及 IETF SIP 和媒体服务器控制协议的出现,对此作出有力的说明,这些技术均支持应用服务器和媒体服务器之间的分解模型。

这里简要说明的是,新兴的开放标准支持 AS-MS 体系结构这样的互操作性部署。Oracle 和 HP 都承诺要推动开放标准及其采用。这种部署模型成功的一个关键促成因素是简化其上所部署应用程序的开发。

JSR 309 API 提供了与丰富的底层 AS-MS 分解兼容的、灵活的编程模型。它支持将多媒体功能委托给媒体服务器,如使用 VoiceXML,还支持通过 RFC 5022 MSCML 或 IETF 媒体服务器控制协议(参见 RFC 5167、5552、5567)等协议对媒体服务器操作实现精细控制。

图 1 说明了近来 3GPP 如何发展 MRF 体系结构以支持丰富特性媒体服务器的部署,这一支持是通过一个基于 IP 多媒体核心网络子系统(在 3GPP TS 23.002 网络体系结构第 8 版中引入)中的 Cr 参考点的开放标准媒体接口实现的。

摘自与新兴标准对应一起引入了新的 Cr 参考点的 3GPP TS 23.218
图 1 摘自与新兴标准对应一起引入了新的 Cr 参考点的 3GPP TS 23.218

HP 作为 TR 24.880 的特别报告单位,一直非常积极地推动 3GPP 的这些发展,同时作为 IETF MediaCtrl 的合作编写者和 W3C Voice Browser 工作组的成员,一直积极参与分布式媒体服务器控制标准的制定工作。

JSR 309 标准化:通过 Java 控制媒体服务器资源

Oracle(JSR 289 SIP Servlet 1.1 API 的规范领导者)和 HP 都认识到了媒体服务器部署模型和控制协议的多样性,二者于 2007 年强强联手,共同推动适用于 Java 平台编程模型的 JSR 309 API,该 API 对应用程序开发人员是透明的,可以支持各种协议和委托模型。

图 2 说明了这个 API 在一个典型的基于开放标准的分布式应用程序和媒体服务器部署的标准化规划中所处的位置。


图 2 将开放的 API 和协议标准工作融入媒体服务器控制规划中

JSR 309 的一个主要优点是提供了一个独立于底层媒体服务器控制协议的 Java API。由 JSR 309 驱动程序对媒体服务器规范进行处理,这类似于 JDBC 对数据库规范的提炼,从而使开发人员可以使用 JSR 309 API 进行透明编程,而无需考虑媒体服务器来自哪个供应商。操作人员和服务提供商无需重写应用程序即可轻松地使用不同的媒体服务器。

JSR 309 提供了极大的灵活性,支持驱动程序实现中现有的和新兴的标准协议,同时简化了应用程序编程并保证了跨所有 AS-MS 部署模型的可移植性。

HP 提供的 JSR 309 参考实现是一个使用 SIP Servlet 技术和广泛部署的 IETF MSCML 协议实现的驱动程序。IETF Mediactrl 在上图中也进行了说明,它定位为 AS-MS 互操作性的一个未来开放标准协议。

JSR 309 概述

JSR 309 Media Server Control API 1.0 定义了一个非常领会的对象模型,通过联接操作来控制媒体服务器资源和媒体流的拓扑结构。

JSR 309 的目标应用程序如下:

  • 使用 MediaGroup、Player、Record、SignalDetector 对象实现交互式语音响应 (IVR):提示和记录语音或视频、提示和采集 DTMF、与 VoiceXML 服务器和 VoiceMail 服务器交互
  • 使用 MediaMixer 对象举行会议:音频、视频、布局
  • 这些功能与其他 JSR 309 核心对象功能相组合:多媒体 IVR、回电话、视频监视、呼叫中心/联系中心

图 3 显示了该对象模型的一些接口,在整个会议应用程序示例中我们会一直使用这些接口。

会议应用程序中常用的 JSR 309 的核心对象
图 3 会议应用程序中常用的 JSR 309 的核心对象

JSR 309 旨在满足分解的应用服务器/媒体服务器部署模型的需要,其中:

  • 应用程序通过 SIP 信号连接和处理各端点间的多媒体分支
  • 媒体服务器(应用程序通过 JSR 309 API 对其进行控制)处理由 SDP 属性描述的相关媒体流

图 4 显示了本文介绍的会议应用程序所使用的 JSR 309 部署体系结构。

典型的 JSR 309 部署体系结构
图 4.典型的 JSR 309 部署体系结构

部署在 Oracle Communications Converged Application Server OCCAS 内部的会议应用程序使用 HP OpenCall JSR 309 参考实现和 HP OpenCall Media Platform (OCMP)。

会议应用程序说明和设置

会议应用程序说明了 JSR 309 和 SIP Servlet API 在分布式环境中的强大功能和灵活性。尽管商业应用程序通常会利用 JSR 309 API 的更多特性,但这个示例应用程序仅从功能上说明连接多个与会者并使其参与到一个会议中所需的呼叫控制逻辑和媒体处理。

为了部署和测试会议应用程序,请参见部署和运行会议应用程序

设计概述

下图说明了该应用程序使用的主要组件。

会议应用程序高级体系结构
图 5.会议应用程序高级体系结构

通常,用户将使用 SIP 电话连接到会议应用程序。系统将提示用户输入会议 ID 号,并建议记录用户的姓名。记录的姓名将作为一个通知进行播放,并且可供以后通过 Web 界面进行检索。要参加一个会议,需要有口令。因为这个示例用例用于演示的,因此可以由首个到会者设置口令。会议期间,与会者可以将线路静音或取消静音。类似对某个与会者静音这样的应用程序交互操作,可以通过 SIP 电话的 DTMF 执行,也可以通过 Web 界面执行。上图说明了应用程序如何从不同的输入源控制相同的媒体功能。

会议应用程序代码概览

本部分通过一些重要应用程序流程和代码来介绍 JSR 309 的使用。有关 SIP Servlet API 和 JSR 309 Media Server Control API 的详细信息,请参阅参考资料部分。

会议应用程序是一个所谓的聚合应用程序,它将 HTTP Servlet 和 SIP Servlet 组合在一个 Web 存档(war 文件)中。该应用程序通过调用 JSR 309 API 来控制媒体资源。SIP Servlet 代码负责处理对端点(会议参与者)的呼叫控制。它提供了一个用 HTTP Servlet 和 JSP 实现的简单 Web 界面,以便用户监视和控制正在进行的会议,并且在同一个应用程序环境中集中显示了 SIP、HTTP 和媒体控制功能。

下图是一个高级类图,对该应用程序的各种类进行了说明。

高级类图
图 6.高级类图 [单击此处放大该图]

ConferenceServlet 概述

SIP Servlet ConferenceServlet 处理会议参与者终端和应用程序服务器之间的 SIP 信号,回答传入的 SIP 呼叫等。

                               
// Common factory for JSR 309 objects used by all service classes
public static MsControlFactory theMsControlFactory;

完成 ConferenceServlet 初始化后,就立刻从名为“com.hp.opencall”的 HP 参考实现中检索 MsControlFactory 实例。在整个应用程序中都将使用该 MsControlFactory 实例创建 JSR 309 对象。

                               
public void init() throws ServletException {
try {…
theMsControlFactory =
DriverManager.getFactory("com.hp.opencall", info);
…} …

调用 getFactory 方法后,DriverManager 将查找请求的驱动程序并从该驱动程序中检索一个 MsControlFactory。DriverManager 作为 JSR 309 API 的一个组成部分,将自动加载和注册驱动程序包(受驱动程序打包的影响)。

ConferenceServlet 还会实例化一个管理 Participant 对象和 ConferecenSessions 对象的 ConferenceManager (confManager)。

收到一个初始 SIP INVITE 后,将实例化一个新 Participant,从而触发启动 SDP 协商的 NetworkConnection 的创建。一旦收到 SIP ACK,将开始与会者交互,要求与会者输入会议 ID。直到收到 SIP BYE 后,才会允许 Participant 退出会议。

                               
… doInvite(SipServletRequest req) …{
// Create a new Participant
ConferenceManager.getInstance().addParticipant(
userId, req.getRawContent(),
req.getSession().getApplicationSession().getId());… }

… doAck(SipServletRequest req) … {
// Launch the media service
… participant.start(); … }

doBye(SipServletRequest req) … {
// Terminate the service
… participant.release();
// Send 200 OK to the UA
… }

ConferenceSession 概述

该类对会议室进行建模,它拥有自己的 JSR 309 MediaSession、MediaMixer 和 MediaGroup。MediaGroup 用于向会议播放通知。

                               
// JSR 309 objects
private final

MediaSession
mMediaSession;
private final

MediaMixer
mMediaMixer;
private final

MediaGroup
mMediaGroup;

每个会议都有自己的会议 ID 和口令,还拥有各自的与会者和组织者。参见 Participant 对象。

                               
// Conference identifier and participants list
private final String confId;
private List<Participant> mParticipants;
private Participant mOrganizer;
private String mPassword;

对 ConferenceSession 实例化后,就会从 MsControlFactory 创建 JSR 309 对象,这个 MsControlFactory 是在初始化 ConferenceServlet 时通过 DriverManager 获得的。

                               
public ConferenceSession(String confId, Participant aParticipant, ConferenceServlet aServlet) … {

mMediaSession = ConferenceServlet.theMsControlFactory.

createMediaSession
();
mMediaMixer = mMediaSession.

createMediaMixer
(MediaMixer.

AUDIO
);
mMediaGroup =
mMediaSession.

createMediaGroup
(MediaGroup.

PLAYER
);
mMediaGroup.

join
(Direction.

SEND
, mMediaMixer);


}


第一步是在 MsControlFactory 上创建一个调用 createMediaSession() 的 MediaSession。MediaSession 是容纳会议应用程序将使用的媒体对象的容器和工厂。

对每个初始化的 ConferencenSession,为其分配只支持 AUDIO 的 MediaMixer 和只支持 PLAYER 的 MediaGroup。以 SEND 模式将 MediaGroup 联接到 MediaMixer,这样它可以向会议播放媒体。

为了增强应用程序以对会议进行记录,必须将 MediaGroup 配置为 PLAYER_RECORDER_SIGNALDETECTOR,并且 MediaGroup 必须以 DUPLEX 模式联接。然后,必须与 HTTP URL 一起使用 record() 方法,这样才可以发布记录的文件。

在与会者加入会议或离开会议时,ConferenceSession 将播放通知。例如,当有人离开会议时向仍在的与会者播放通知:

  • 首先,构建到要播放的文件的引用:
                               
public void removeParticipant(Participant participant) {
…{
String[] fileURLs =
new String[] { participant.getRecordingURI().toString() +
"

&disconnected=true
",
Participant.getPromptDirPath() +
"HasLeftTheConference.wav" };
}; …
playAnnouncement(fileURLs);
… }
  • 然后,在连接到该会议的 MediaMixer 的 MediaGroup 上播放该文件。
                               
public void playAnnouncement(String[] fileURLs) {
… mMediaGroup.

getPlayer
().

play
( streamIDs,
null,
Parameters.NO_PARAMETER);
… }

播放结束后,Player 发送一个 PLAY_COMPLETED 事件。通过在 Player 的 MediaEventNotifier 接口上注册一个 MediaEventListener,应用程序可以捕获该事件。

Participant 概述

该类对会议参与者进行建模,并且实现一个处理与会者交互的状态机。

与会者状态机示意图
图 7.与会者状态机示意图

每个 Participant 都拥有自己的 JSR 309 MediaSession、NetworkConnection 和 MediaGroup。NetworkConnection 及其 SdpPortManager 处理 SDP 配置以及用户代理和媒体服务器之间的通信。MediaGroup 用于处理和与会者的 DTMF 交互,例如,一个新与会者呼入时获取会议 ID 或口令,以及播放提示和记录与会者姓名。

                               
private final

NetworkConnection
mNetworkConnection;
private final

SdpPortManager
mSdpPortManager;
private final

MediaGroup
mMediaGroup;
private final

MediaSession
mMediaSession;

Participant 的 NetworkConnection 和 MediaGroup 的初始化

一旦从 ConferenceServlet 收到初始 SIP INVITE,就会对 Participant 进行初始化。

                               
public Participant(final SipServletRequest req) … {…}

将创建以下 JSR 309 对象:

                               
mMediaSession =
ConferenceServlet.theMsControlFactory.

createMediaSession
();
myNetworkConnection =
myMediaSession.

createNetworkConnection
(NetworkConnection.

BASIC
);
mySdpPortManager = myNetworkConnection.

getSdpPortManager
();
myMediaGroup = myMediaSession.

createMediaGroup
(
MediaGroup.

PLAYER_RECORDER_SIGNALDETECTOR
);

使用默认配置创建一个常规 NetworkConnection。创建的 Participant 的 MediaGroup 将包含 Player、Recorder 和 SignalDetector 资源。

为了在 MediaGroup 资源上调用的媒体操作完成时得到通知,必须注册事件监听器。通常,这些监听器将捕获播放、记录或 DTMF 采集操作的完成情况:

                               
myMediaGroup.

getPlayer
().

addListener
(new
ConfListener<PlayerEvent>());
mMediaGroup.

getRecorder
().

addListener
(new
ConfListener<RecorderEvent>());
mMediaGroup.

getSignalDetector
().

addListener
(new
ConfListener<SignalDetectorEvent>());

然后,将新的 NetworkConnection 联接到 MediaGroup。注意,要在 SDP 协商完成前执行该操作。为了允许播放提示、记录或检测 DTMF,join 操作应该为 DUPLEX 模式。

                               
mNetworkConnection.

join
(Direction.

DUPLEX
, mMediaGroup);

从用户代理接收的 SDP 提议被提供给 SdpPortManager:

                               
mSdpPortManager.

processSdpOffer
(sdpOffer);
SDP 协商的呼叫流程
图 8.SDP 协商的呼叫流程

为了处理来自媒体服务器的 SDP 应答,需要在 SdpPortManager 上注册事件监听器。从 SdpPortManager 收到成功事件后,随同媒体服务器获得的 SDP 应答一起发送 200OK。

                               
mSdpPortManager.addListener(new
MediaEventListener() {…}
{
If(event.getEventType().equals(

SdpPortManagerEvent.ANSWER_GENERATED
)) {
// The NetworkConnection has been setup properly.
// Send a 200 OK, with negotiated SDP from the Media Server attached.
ConferenceServlet.sendResponse(sipAppSessionId,
SipServletResponse.SC_OK,
"application/sdp", event.getMediaServerSdp());
}

有与会者加入时的媒体交互

通过用 java enum: private enum State { } 在 Participant 中实现的状态机模式来处理与会者和会议之间的交互图 7 显示了这个高级状态机。

下图显示了用户加入会议时的用户交互。

与会者加入会议的呼叫流程
图 9.与会者加入会议的呼叫流程

一旦连接上一个与会者,第一个交互就是通过提示和采集操作获取会议 ID。使用 receiveSignal() 操作和 SignalDetector.PROMPT 功能实现这一目的。这里还设置了初始超时和数字间超时,最多允许采集 4 位数字,同时还启用了强行闯入控制,在用户开始输入数字时将停止 PROMPT。在 EnterConfId 状态下通过以下输入操作实现这一目的:

                               
{ Parameters params =
ConferenceServlet.theMsControlFactory.

createParameters
();
params.put(SignalDetector.

INITIAL_TIMEOUT
, 5000);
params.put(SignalDetector.

INTER_SIG_TIMEOUT
, 5000);
URI prompt = URI.create(getPromptDirPath() +
"PleaseEnterYour4DigitConferenceID.wav");
params.put(SignalDetector.

PROMPT
, prompt);
part.mMediaGroup.

getSignalDetector
().

receiveSignals
(
4, null,
new RTC[] { //barge-in
new RTC(SignalDetector.

DETECTION_OF_ONE_SIGNAL
, Player.

STOP
)},
params);
}

为了检索现有的 ConferenceSession 或创建新的 ConferenceSession,EnterConfId 状态将接收相应的 SignalDetectorEvent 并处理采集到的会议 ID。

                               
if (event.getEventType() ==
SignalDetectorEvent.

RECEIVE_SIGNALS_COMPLETED
) {…}

注意,类似地将使用 SignalDetector 请求与会者在 EnterConfPwd 状态下输入会议口令。

在另一个交互中,将使用 Recorder 记录与会者的姓名。这是在 RecordingName 状态中实现的。使用带有 PROMPT 参数的 record() 操作,并通过使用运行时控制 (RTC) 来启用强行进入控制,这样在用户按下“#”时就停止记录。

                               
{ Parameters params =
ConferenceServlet.theMsControlFactory.createParameters();
URI prompt = URI.create(getPromptDirPath() +
"PleaseSayYourNameEndWithHash.wav");
params.put(Recorder.

PROMPT
, prompt);
params.put(SignalDetector.

PATTERN[0]
, "#");
part.mMediaGroup.getRecorder().

record
(
part.getRecordingURI(),
new RTC[] { // barge-in
new RTC(SignalDetector.

DETECTION_OF_ONE_SIGNAL
, Player.

STOP
),
// stop recording key
new RTC(SignalDetector.

PATTERN_MATCH[0],
Recorder.

STOP
)},
params);
}

RecordingName 状态将接收相应的 RecorderEvent,识别与会者是否已经根据事件类型和限定符记录了一些内容。

                               
…if (event.getEventType() == RecorderEvent.RECORD_COMPLETED) {
if (event.getQualifier() == RecorderEvent.SILENCE) {
…}… else if (event.getQualifier() == ResourceEvent.RTC_TRIGGERED
&& event.getRTCTrigger() ==
SignalDetector.PATTERN_MATCH[0]) {…

与会者一旦输入了会议 id、记录了与会者的姓名并输入了会议口令,与会者就加入到会议中。这需要通过两个步骤实现。首先,向与会者播放欢迎提示。接着,与会者参与到会议中,同时向整个会议播放通知有新与会者加入的欢迎提示。在 Welcome 状态中实现该操作:

                               
{… // use the participant's MediaGroup
part.mMediaGroup.getPlayer().

play
(
URI.create(getPromptDirPath() + "PutIntoSession.wav"),
null, Parameters.NO_PARAMETER);

part.mNetworkConnection.

join
(Direction.

DUPLEX
,
confSession.getMediaMixer());

// play an announcement to the conference using conference's MediaGroup
confSession.playAnnouncement(fileURLs);

会议期间同与会者的媒体交互

一旦与会者参与到会议中,他们通过按键触发 DTMF 仍可以控制某些功能,如静音/取消静音。注意,要进行这种操作,每个与会者都要加入到会议中并且要加入到自己的 MediaGroup 中:

                               
// upon Participant initialization
mNetworkConnection.

join
(Direction.

DUPLEX
, mMediaGroup);

// upon Participant joining the Conference
part.mNetworkConnection.

join
(Direction.

DUPLEX
,
confSession.getMediaMixer());

这两个 join 操作的结果是 Participant 的媒体流与会议之间建立了双向连接,但是,来自与会者的输入仍发送到 Participant 的 MediaGroup,因此,可以检测来自与会者的 DTMF。尽管 receiveSignal() 操作处于 Conferencing 或 ConferenceMuted 状态,但是始终在 Participant 的 MediaGroup 上激活 receiveSignal() 操作,这样可以接收与会者按键触发的每个 DTMF。

                               
part.mMediaGroup.getSignalDetector().

receiveSignals
(

1
, null, null, null);

与会者输入键“6”时,与会者将变成静音。下面的 join 操作将 Participant 的 NetworkConnection 与其 MediaGroup 相连接,因此断开了 NetworkConnection 与 MediaMixer 的联接。然后,使用 MediaGroup 播放静音通知(只对被静音的与会者播放)。静音通知一旦播放完毕,又将该与会者以 RECV 方式联接到 MediaMixer,继续收听会议发言。

                               

private void mute(Participant part) … {
part.mNetworkConnection.

join
(Direction.

DUPLEX
, part.mMediaGroup);
part.mMediaGroup.getPlayer().

play
(URI.create(getPromptDirPath() +
"MuteOn.wav"), null,
Parameters.NO_PARAMETER);

part.mNetworkConnection.

join
(Direction.

DUPLEX
,
confSession.getMediaMixer());

注意,该与会者仍然连接到其 MediaGroup,因此活动的 receiveSignals() 操作仍可检测到 DTMF。

尽管与会者处于 ConferencingMuted 状态,但是,通过按“9”键使用其 MediaGroup 的同一个 SignalDetector 可以取消静音。收到取消静音事件后,将与会者联接到 MediaGroup 以便播放取消静音通知,并且在 play() 操作结束后再将与会者以 DUPLEX 模式联接到 MediaMixer。现在,与会者又回到 Conferencing 状态。

                               

part.myNetworkConnection.

join
(Direction.

DUPLEX
, part.myMediaGroup);
part.myMediaGroup.getPlayer().play(URI.create(getPromptDirPath() +
"MuteOff.wav"), null, Parameters.NO_PARAMETER);>

part.myNetworkConnection.

join
(Direction.

DUPLEX
,
part.myConferenceSession.getMediaMixer());

与身为会议组织者的与会者的媒体交互

状态图中显示了这些交互。为了获得使用 JSR 309 的其他示例,建议读者查看与组织者角色有关的以下 Participant 状态的源代码:

  • 在等待会议组织者时与会者在线收听音乐
  • 组织者设置会议口令
  • 静音/取消静音/将与会者退出 Web 界面

Media Server Control API 的发展

尽管部署是基于商业化应用服务器和媒体服务器的,但该示例应用程序还有一些方面没有涉及到,例如,在实际网络中部署时完全分布解决方案的可伸缩性和可用性问题。通常通过部署体系结构来处理应用服务器或媒体服务器选择、负载平衡、资源中介、资源模拟和可用性管理等大部分功能。

作为 Media Server Control API 的 1.0 版,JSR 309 不提供用于应对这些功能的特性,这些功能应该是实现差异的组成部分,并且应该尽可能多的对程序员保持透明。虽然 JSR 309 专家组已经基于部署认识了这些操作特性,但在该 API 的发展中仍然需要研究媒体服务器特性的发展。

该 API 的目标是针对不同 MS 上提供的每个特定媒体功能支持可移植的编程模型。但是,它也考虑了每个 MS 可能支持的不同特性,并非一定要立即支持 JSR 309 中定义的所有功能。应用程序可以利用 SupportedFeatures 接口检测某个特定 JSR 309 驱动程序实现动态支持的特性。这有望通过新的协议得以发展,并且实际的应用程序编程经验将有助于提高这一特性。

JSR 309 1.0 支持一组使用丰富的布局呈现处理视频会议的功能。随着进一步设计视频丰富和交互性应用程序,将认识到一些新特性,这是因为需要由目前的接口发展成为一个公用的、标准的 API。其中一个例子是除音频和视频外支持使用媒体流类型消息(如 RFC 4975 MSRP 消息传递会话)的更多功能。

JSR 309 1.0 规范重点关注一组非常灵活的、负责媒体服务器功能的核心对象。JSR 309 专家组成立时就已经认识到组合操作的需要。像提示与记录,或者提示与采集这样的组合操作已经包含在 MediaGroup 的操作中。可能添加的功能包括立刻对到会的所有与会者静音,转向处理其他会议。尽管可以在核心对象的基础上开发这些组合操作,但可能有必要进一步标准化,从而使这些组合操作得到广泛应用。

总结

在本文中,我们介绍了基于新的 JSR 309 Media Server Control API 和 Java SIP Servlet 技术的会议应用程序示例。我们提供了一个完整的应用程序示例,说明了用户代理、应用服务器和媒体服务器之间的端到端的流程。该应用程序演示了,在无需了解底层媒体服务器控制协议(如 MSCML)和市场上提供的或作为新 IETF 标准出现的其他协议的情况下,编写应用程序的价值和方便性。

该示例使用大约 1500 行 Java 代码实现了会议应用程序的所有业务逻辑、SIP 呼叫控制和 Web 界面。这表明 JSR 309 API 可以使应用程序开发人员专注于业务逻辑和用户界面的设计,而将有效处理媒体服务器交互的工作留给 JSR 309 驱动程序。

可以使用 JSR 309 轻松地进一步增强会议应用程序。例如:

  • 可以选择使用 VoiceXML 处理与会者交互。JSR 309 通过 VxmlDialog 接口支持 VoiceXML 资源控制。
  • 尽管该会议应用程序只处理音频,但是添加视频支持也非常容易,并且 JSR 309 支持的其他用于设置 VideoLayout 的特性也能够轻松地添加到该应用程序中。
  • 添加对活动发言人的检测,并在 Web 界面上显示正在发言的与会者。

本会议应用程序示例演示了使用开放的标准 Java API(如 SIP Servlet 1.1 和 Media Server Control 1.0)在分布的应用服务器 — 媒体服务器内部开发和部署多媒体应用程序的价值和可行性。

参考资料


Marc Brandt 是 HP 软件与解决方案 CMS(通信和媒体解决方案)的首席专家。他一直以来负责协调不同组织的行业标准活动,是 HP CMS 论坛的成员。从 2007 年 1 月 JSR 309 创始以来,他一直参与 JSR 309 的领导工作。

Tomas Ericson 是 Oracle 技术团队的主要成员。总的来说,他在电信/通信领域的 Java 服务器编程方面具有长期的经验,特别是在 IMS/SIP//VoIP/在线状态等领域具有丰富的经验。他是 JSR 309 联合规范的负责人,也是 JSR 289 (SIP Servlet API) 专家组成员。

Marc Brandt 是 HP 软件与解决方案 CMS(通信和媒体解决方案)的高级开发人员。他领导了 HP OpenCall Media Platform 接口及内部机制的开发,参与了 JSR 309 规范的制定。