快速入门视频通话

最近更新时间:2022-09-20 05:17:40

概述

本文主要介绍如何基于 anyRTC SDK 实现一个简单的视频通话功能。本文仅罗列最常用的几个接口,如果您希望了解更多的接口函数,请参见 API 文档

示例代码

Github地址

音频通话

1. 初始化 SDK

使用 anyRTC SDK 的第一步,是先通过 createARRtcEngine 创建一个 IRtcEngine 对象的指针 IRtcEngine*,并配置开发者信息和注册监听 SDK 事件的回调。

  • 继承 IRtcEngineEventHandler 事件回调接口类,重写关键事件的回调接口,包括本地用户进房/退房事件、远端用户加入/退出事件、错误事件和警告事件等。
  • 调用 initialize 接口配置开发者信息并注册监听 SDK 事件。
CArObject *CArObject::GetArObject(LPCTSTR lpAppId)
{
    if (m_lpArObject == NULL)
        m_lpArObject = new CArObject();
    if (m_lpArEngine == NULL)

        // 创建实例。
        m_lpArEngine = (IRtcEngine *)createARRtcEngine();
    if (lpAppId == NULL)
        return m_lpArObject;
    RtcEngineContext ctx;

    // 添加注册回调和事件。
    ctx.eventHandler = &m_EngineEventHandler;
#ifdef UNICODE
    char szAppId[128];
    ::WideCharToMultiByte(CP_ACP, 0, lpAppId, -1, szAppId, 128, NULL, NULL);

    // 输入你的 App ID。
    ctx.appId = szAppId;
#else
    ctx.appId = lpAppId;
#endif

    // 初始化 IRtcEngine。
    m_lpArEngine->initialize(ctx);
    return m_lpArObject;
}
// 继承 IRtcEngineEventHandler 类中的回调与事件。
class CAGEngineEventHandler :
    public IRtcEngineEventHandler
{
public:
    CAGEngineEventHandler(void);
    ~CAGEngineEventHandler(void);
    void SetMsgReceiver(HWND hWnd = NULL);
    HWND GetMsgReceiver() {return m_hMainWnd;};
 
    // 注册 onJoinChannelSuccess 回调。
    // 本地用户成功加入频道时,会触发该回调。
    virtual void onJoinChannelSuccess(const char* channel, uid_t uid, int elapsed);
 
    // 注册 onLeaveChannel 回调。
    // 本地用户成功离开频道时,会触发该回调。
    virtual void onLeaveChannel(const RtcStats& stat);
 
    // 注册 onUserOffline 回调。
    // 远端用户离开频道或掉线时,会触发该回调。
    virtual void onUserOffline(uid_t uid, USER_OFFLINE_REASON_TYPE reason);
private:
    HWND        m_hMainWnd;
};

2. 设置本地视图

anyRTC SDK 并不会默认打开视频模块,enableVideo可以开启视频模块,开启模块后才能调用本地采集以及接收远端视频。

调用 enableVideo 开启视频模块。 调用 setupLocalVideo 接口,打开本地视频采集。 ?>
1.在调用joinChannel前,setupLocalVideo并不会立即显示视频,需要调用startPreview方法才能获得预览。 2.如果调用setupLocalVideo方法后,立即调用joinChannel后可立即显示本地视频。

// 启用视频模块。
m_lpArObject->GetEngine()->enableVideo();

// 设置本地视图。
VideoCanvas vc;
vc.uid = 0;
vc.view = m_wndLocal.GetSafeHwnd();
vc.renderMode = RENDER_MODE_FIT;
m_lpArObject->GetEngine()->setupLocalVideo(vc);

3. 加入频道

调用 joinChannel 可以加入频道。 参数:

  • channelName:频道名称,只有输入相同的频道才能进行通信。
  • token:权限密钥,项目启动了权限密钥功能,加入房间必须使用Token。对安全要求高的用户,请开启该功能。
  • uid:用户本地ID,一般为业务用户的uid,请保持频道内该uid唯一。设置NULL,SDK会自动分配一个uid给该用户。
// 加入频道。
BOOL CArObject::JoinChannel(LPCTSTR lpChannelName, UINT nUID,LPCTSTR lpToken)
{
    int nRet = 0;
#ifdef UNICODE
    CHAR szChannelName[128];
    ::WideCharToMultiByte(CP_UTF8, 0, lpChannelName, -1, szChannelName, 128, NULL, NULL);
    char szToken[128];
    ::WideCharToMultiByte(CP_UTF8, 0, lpToken, -1, szToken, 128, NULL, NULL);
    if(0 == _tcslen(lpToken))
        nRet = m_lpArEngine->joinChannel(NULL, szChannelName, NULL, nUID);
    else
        nRet = m_lpArEngine->joinChannel(szToken, szChannelName, NULL, nUID);
#else
    if(0 == _tcslen(lpToken))
        nRet = m_lpArEngine->joinChannel(NULL, lpChannelName, NULL, nUID);
    else
        nRet = m_lpArEngine->joinChannel(lpToken, lpChannelName, NULL, nUID);
#endif
    if (nRet == 0)
        m_strChannelName = lpChannelName;
    return nRet == 0 ? TRUE : FALSE;
}

4. 观看远端视频流

anyRTC SDK 并不会默认拉取远端的视频流,当房间里有用户上行视频数据时,频道里的其他用户可以通过 IRtcEngineEventHandler 中的 OnFirstRemoteVideoDecoded 回调获知该用户的 uid。之后,即可调用 setupRemoteVideo 方法来显示该用户的视频画面。

// SDK 接收到第一帧远端视频并成功解码时,会触发该回调。
// 在该回调中调用 setupRemoteVideo 方法设置远端视图。
LRESULT CArTutorialDlg::OnFirstRemoteVideoDecoded(WPARAM wParam, LPARAM lParam)
{
    LPAGE_FIRST_REMOTE_VIDEO_DECODED lpData = (LPAGE_FIRST_REMOTE_VIDEO_DECODED)wParam;
    VideoCanvas vc;
    vc.renderMode = RENDER_MODE_FIT;
    vc.uid = lpData->uid;
    vc.view = m_wndRemote.GetSafeHwnd();
    // 设置远端视图。
    m_lpArObject->GetEngine()->setupRemoteVideo(vc);
    delete lpData;
    return 0;
}

5. 退出频道

调用 leaveChannel 方法退出频道。不论当前是否还在通话中,调用该方法会把音频通话相关的所有资源释放掉。

BOOL CArObject::LeaveChannel()
{
    m_lpArEngine->stopPreview();
    // 离开频道。
    int nRet = m_lpArEngine->leaveChannel();
    return nRet == 0 ? TRUE : FALSE;
}
 
 void CArObject::CloseArObject()
{
    if(m_lpArEngine != NULL)
        // 释放 IRtcEngine 对象。
        m_lpArEngine->release();
    if(m_lpArObject != NULL)
        delete m_lpArObject;
    m_lpArEngine = NULL;
    m_lpArObject = NULL;
}