摘要
學習如何創建或集成實時通信(RTC)應用編程接口(API)的基本知識以實現音視頻會議、應用程序共享、白板、簡單的點對點聊天和音視頻調節向導。RTC API 提供了卓越的基於PC的通信革新,這可應用於所有基於 Microsoft Windows XP的應用程序。
緒論
微軟的實時通信(RTC)應用編程接口(API)提供了卓越的基於PC的通信革新——即時消息、音視頻會議和應用程序共享/協作,這可應用於所有基於 Microsoft Windows XP 的應用程序。
使用RTC的API來進行通信是一個非常簡單的過程。
增強的客戶端應用決定客戶端通信平台的能力。
應用程序在通信期間使用首選的視音頻設備。
應用程序發起通信會話。
在 RTC 層協調數據捕獲、壓縮和傳輸,這使得應用程序不用負責這一任務。使用哪一種音視頻的編碼解碼器由通信雙方的連接質量決定。
參與會話的應用程序接受、解壓並重放被傳輸的數據。
圖一、音視頻會議例子界面
本文描述了怎樣為一個應用程序添加 PC-to-PC 的 RTC 基本能力;我們假定你對使用COM對象開發Windows應用程序已經很熟悉。本文所討論的源代碼可在本文開始所給出的連接裡獲得。我們以後將會討論PC-to-Phone、 出席和XML配置。
例子代碼展示了使用實時通信API實現音視頻會議、應用程序共享、白板、簡單的點對點聊天和音視頻調節向導的基本要素。其他RTC 支持但本文沒有討論的特征有回波抵消(AEC)、前向錯誤校驗(FEC)、 帶寬估計、動態抖動緩沖管理、自動增益控制(AGC)和服務質量(QC)控制算法。在《Microsoft Windows 實時通信(RTC)客戶端的媒體支持》中描述了上述特征。
RTC客戶端接口
所需頭文件:rtccore.h
你的應用程序需要通過 CoCreateInstance()來獲得RTC接口,CLSID_RTCClient(GUID = {7a42ea29-a2b7-40c4-b091-f6f024aa89be})作為參數。一旦獲得了接口,用Initialize()來初始化COM對象,以確定該平台的通信能力。
// Initialize the RTC COM object
hr = CoCreateInstance (CLSID_RTCClient, NULL,
CLSCTX_INPROC_SERVER, IID_IRTCClient,
(LPVOID *)&m_pClient);
// Initialize the client interface
hr = m_pClient->Initialize();
選擇通信類型
下一步是選擇首選的通信類型和相關設備(攝像機、麥克風等)。缺省配置是激活所有通信類型。如果會話的參與者能共享應用程序、傳送即時消息和音視頻會議,那麼這些通信類型自動被激活。如果某一參與者不支持某種通信類型,那麼所有的參與者都不能激活該類型。
m_pClient->SetPreferredMediaTypes ( RTCMT_ALL, VARIANT_TRUE );
會議參與者的平台性能和可用帶寬決定了使用哪一種codec。
視頻:Windows RTC 客戶端支持分辨率為QCIF(176×144)的H.261和H.263 codecs。 這些比特率可變的codecs以6~125 Kbps傳送視頻數據。使用IRTCClient方法中的put_MaxBitRate和put_TemporalSpatialTradeOff有可能會影響到視頻傳送的空間和瞬時清晰度。
音頻:Windows RTC客戶端支持許多音頻codec。音頻codec由連接的兩端共同決定。下表列出了所支持的音頻codec。
G.711 8 64 20 G.722.1 16 24 20 G.723 8 6.4 30, 60, or 90 GSM 8 13 20 DVI4 8 32 20 SIREN 16 16 20, or 40
調整通信設備
選擇了首選的通信類型和相關設備之後,調整通信設備。RTC的API提供了向導對攝像機和麥克風進行調整。使用RTCClient中的方法InvokeTuningWizard()可調整它們的設置。
圖2:攝像機調節向導
圖3:麥克風調節向導
初始化會話
在應用程序與其他參與者連接之前,它必須能夠處理會話中的RTC事件。PC-to-PC的通信中,應用程序捕獲即時消息事件、音量事件、媒體事件、客戶端消息事件和會話狀態改變事件。下述代碼展示了怎樣創建一個事件過濾器來捕獲RTC客戶端的特定事件。
lEventMask設置了一組應用程序感興趣的事件。(為獲得全部的事件列表,可在 MSDN 站點搜索RTC_EVENT,這樣可以獲得關於每一事件的更多信息。)CRTCEvents 類在客戶端之間分配事件。RTCEvents 對象在應用程序和 IRTCEventNotification 接口之間創建接口。所有的RTC事件由RTCEvents 類處理。
// Set the event filter to listen for RTC events
// Using RTCEF_ALL will listen for all events
// For the sample application, we will demonstrate how to set the
// event listener for a limited set of events.
long lEventMask = RTCEF_SESSION_STATE_CHANGE |
RTCEF_MESSAGING |
RTCEF_MEDIA |
RTCEF_INTENSITY |
RTCEF_CLIENT;
hr = m_pClient->put_EventFilter( lEventMask );
// Create the event sink object
m_pEvents = new CRTCEvents;
// initialize the event handler
hr = m_pEvents->Advise( m_pClient, m_hWnd );
// Set the listen mode for RTC client
// RTCLM_BOTH opens the standard SIP port 5060, as well as
// a dynamic port.
hr = m_pClient->put_ListenForIncomingSessions(RTCLM_BOTH);
音視頻的媒體類型可在會話過程中添加或刪除,因此客戶端必須能監聽這些類型的事件。在"處理實時流會話事件"這一節中可獲得關於狀態改變和事件處理的更多信息。
處理RTC事件
一旦事件處理者 IRTCEventNotification 接收器中進行了注冊,接收和處理RTC事件就變得相當的容易了。當例子程序接收到RTC事件時,應用程序的事件處理者就對應用程序的消息處理者發一個消息。OnRTCEvent() 處理應用程序接收到的所有事件。
OnRTCEvent(UINT message, WPARAM wParam, LPARAM lParam)
{
// Based on the RTC_EVENT type, query for the
// appropriate event interface and call a helper
// method to handle the event
switch ( wParam )
{
...
case RTCE_MEDIA:
{
IRTCMediaEvent * pEvent = NULL;
hr = pDisp->QueryInterface( IID_IRTCMediaEvent,
(void **)&pEvent );
if (SUCCEEDED(hr))
{
OnRTCMediaEvent(pEvent);
SAFE_RELEASE(pEvent);
}
}
break;
...
}
創建通信會話
當你在RTC中發起一個呼叫之前,你必須創建並且初始化一個會話。 然後你可以輸入參與者的IP地址來發起一個呼叫。可可能通過屬於一個e-mail 地址或者一個電話號碼來激活一個會話。然而,這一功能需要一個SIP注冊服務器,對它的討論超出了本文的范圍。參閱MSDN可獲得關於SIP注冊服務器的更多信息。
RTC目前還不支持多方視頻通話,因此應用程序在初始化一個新會話之前,必須保證沒有視頻會議在進行。在它第一個發布版本中,Windows RTC客戶端只支持多方電話會議,並不支持多方音視頻會話和視頻會議。
為與另一台PC通話,確定RTC會話類型並且使用IRTCSession接口創建一個同類型的會話。下列代碼展示了如何創建會話。
HRESULT CAVDConfDlg::MakeCall(RTC_SESSION_TYPE enType, BSTR bstrURI)
{
...
// Create the session
IRTCSession * pSession = NULL;
hr = m_pClient->CreateSession(enType, NULL, NULL, 0, &pSession);
// Add the participant to the session
hr = pSession->AddParticipant(bstrURI, NULL, &m_Participant);
...
return S_OK;
}
處理實時流會話事件
根據不同的會話類型,存在媒體事件、音量事件、即時消息事件和會話狀態改變事件。
媒體事件
處理媒體事件需要得到媒體類型、事件類型和原因,然後發送消息給會話窗口。應用程序可以使用get_MediaType()從視頻、音頻、T120和實時傳輸協議(RTP)事件中接收消息。例子程序展示了如何獲得媒體事件並將其發送給媒體對話框去處理。
void CAVDConfDlg::OnRTCMediaEvent(IRTCMediaEvent *pEvent)
{
...
hr = pEvent->get_MediaType(&lMediaType);
hr = pEvent->get_EventType(&enType);
hr = pEvent->get_EventReason(&enReason);
if ((m_AVDlg) && (m_AVDlg.GetState () != RTCSS_IDLE))
{
// Deliver the media state to the session window
m_AVDlg.DeliverMedia(lMediaType, enType, enReason);
}
}
音量事件
當揚聲器或者麥克風的音量水平發生變化時產生音量事件。應用程序可使用get_Direction()函數獲得發生改變的音頻設備。一旦確定了設備,應用程序可獲得設備的屬性並處理改變。應用程序可通過slider控件來顯示音量的改變,或者顯示給用戶一個音量表。
void CAVDConfDlg::OnRTCIntensityEvent(IRTCIntensityEvent *pEvent)
{
...
hr = pEvent->get_Direction(&enDevice);
hr = pEvent->get_Level(&lLevel);
hr = pEvent->get_Min(&lMin);
hr = pEvent->get_Max(&lMax);
if (m_AVDlg.GetState () != RTCSS_IDLE)
{
// Deliver the intensity state to the session window
m_AVDlg.DeliverIntensity(enDevice, lLevel);
}
}
即時消息事件
使用IRTCMessagingEvent可在會話參與者中傳遞即時消息。當一個消息事件產生時,應用程序必須獲得會話和事件類型,得到相關會話中的參與者信息,以便能將消息傳遞給適當一方。事件處理者也能處理會話狀態的改變。
HRESULT CAVDConfDlg::OnRTCMessagingEvent(IRTCMessagingEvent *pEvent)
{
...
hr = pEvent->get_Session(&pSession);
hr = pEvent->get_EventType(&enType);
hr = pEvent->get_Participant(&pParticipant);
if (enType == RTCMSET_MESSAGE)
{
hr = pEvent->get_MessageHeader(&bstrContentType);
hr = pEvent->get_Message(&bstrMessage);
// Deliver the message to the session window
if (m_cMessageDlg)
m_cMessageDlg.DeliverMessage(pParticipant, bstrContentType,
bstrMessage);
}
else if (enType == RTCMSET_STATUS)
{
hr = pEvent->get_UserStatus(&enStatus);
// Deliver the user status to the session window
m_cMessageDlg.DeliverUserStatus(pParticipant, enStatus);
}
return S_OK;
}
會話狀態改變事件
會話狀態改變事件的處理過程與其他RTC事件相同。會話狀態的改變包括建立一個新的音/視頻會話,或者通知客戶端一個到來的即時消息。下列例子展示了當請求會話時所作的處理;客戶端通過一陣鈴聲被通知,請求被應答,然後會話開始。
Void CAVDConfDlg::OnRTCSessionStateChangeEvent(IRTCSessionStateChangeEvent *pEvent)
{
...
hr = pEvent->get_State(&enState);
hr = pEvent->get_Session(&pSession);
switch ( enState )
{
case RTCSS_INCOMING:
{
...
// This event is called when an incoming call occurs
RTC_SESSION_TYPE enType;
hr = pSession->get_Type(&enType);
// Ring the bell
m_pClient->PlayRing(RTCRT_PHONE, VARIANT_TRUE);
// Accept the session
hr = pSession->Answer();
}
}
...
}
應用程序共享:
開啟T120應用程序共享非常容易,只需調用 IRTCClient 接口的 StartT120Applet 方法。
hr = m_pClient->StartT120Applet ( RTCTA_APPSHARING );
白板支持:
在應用程序中支持白板,需要調用 StartT120Applet 方法,使用 RTCTA_WHITEBOARD 枚舉作為參數。
hr = m_pClient->StartT120Applet ( RTCTA_WHITEBOARD );
關閉會話
要關閉一個會話,所有正在運行T120的應用程序必須被關閉。然後RTC 客戶端接口調用ShutDown()並完成關閉會話的過程。
平台性能
使用RTC進行通信需要處理器具有適當的性能。下列例子中,一個1 GHz的Pentium? III處理器和一個2.2 GHz的Pentium 4處理器用於確定當使用RTC特征時處理器的利用率。下表描述了使用本文介紹的RTC特征時處理器的利用率。
僅音/視頻會議 9% 22% 添加程序共享(共享IE浏覽器) 10% 35% 增加白板 12% 37% 增加即時消息 12% 37%
注1:P4處理器配置:Intel?主板D850MV;256MB PC800 RDRAM,主板集成聲卡, nVidia* GeForce*2 Ultra; Windows XP專業版
注2: P III處理器配置:Intel 主板VC820; 256MB PC133 SDRAM, nVidia* GeForce*2 Ultra, Creative* Sound Blaster* Live*, Windows XP 專業版
結論
通過使用實時通信客戶端API,在 Windows XP 下開發通信工具已變得相當簡單。開發者可迅速設計、配置和開發他們的應用程序。現有的音視頻會議應用程序可通過添加 RTC 豐富的通信特征而獲益。使用 RTC API 進行開發的程序也可以從一個統一的通信協議中獲益。這提高了你的程序與其它文本消息和音視頻會議程序互相合作的能力。將 RTC API 與 Intel 的處理器以及 Microsoft Windows XP 相結合,從而向最終用戶傳達一種創新的通信體驗。
本文配套源碼