跳到主要内容

实现音视频会议

本教程将指导您快速实现音视频会议功能。通过本教程,您将学会如何创建多人音视频会议室,实现参会者之间的实时音视频通信。

开始前的准备:

  1. 注册融云开发者账户:前往融云官网注册开发者账户
  2. 获取 App Key:注册后系统将自动创建应用,请获取应用的 App Key 用于本教程
  3. 首次使用建议:如果您是首次使用融云音视频,建议先参考运行示例项目完成基础配置,以完成开发者账号注册、音视频服务开通等工作
环境说明

系统默认创建开发环境应用,使用国内数据中心。如需其他配置,请在控制台进行调整。

房间人数建议

考虑移动设备的带宽和 UI 交互效果,建议单次会议:

  • 视频会议:不超过 16 人
  • 纯音频会议:不超过 32 人

超过此上限可能影响会议质量和用户体验。

环境要求

在开始开发前,请确保您的开发环境满足以下要求:

Android 版本要求:

  • SDK ≥ 5.6.3:Android 5.0(API 21)或更高版本
  • SDK < 5.6.3:Android 4.4(API 19)或更高版本(推荐 Android 5.0)

开发工具要求:

  • Android Studio 3.0 或更高版本

步骤 1:开通音视频服务

在开始开发前,您需要为应用开通音视频直播服务。新创建的应用默认未开启音视频功能。

开通方法: 登录融云控制台,选择您的应用,开通音视频服务和音视频直播服务。详细步骤请参考:开通音视频服务

生效时间

服务开通、关闭等设置完成后需要 15 分钟生效,请耐心等待。

步骤 2:导入 SDK

实现直播功能需要导入以下 SDK 库:

必须导入:

  • RTCLib:音视频核心能力库
  • IMLib:即时通讯能力库(提供信令通道)

可选导入:

  • 美颜扩展库:提供美颜滤镜功能
  • CDN 扩展库:支持 CDN 推流功能

详细导入步骤请参考:导入 SDK

步骤 3:配置代码混淆

如果您的应用启用了代码混淆,需要添加相应的混淆规则以确保 SDK 正常工作。

配置方法:

app/proguard-rules.pro 文件中添加以下配置:

Java
-keepattributes Exceptions,InnerClasses

-keepattributes Signature
#RongRTCLib
-keep public class cn.rongcloud.** {*;}

#RongIMLib
-keep class io.rong.** {*;}
-keep class cn.rongcloud.** {*;}
-keep class * implements io.rong.imlib.model.MessageContent {*;}
-dontwarn io.rong.push.**
-dontnote com.xiaomi.**
-dontnote com.google.android.gms.gcm.**
-dontnote io.rong.**

-ignorewarnings
重要提醒

未正确配置混淆规则可能导致 SDK 功能异常,请务必添加上述配置。

步骤 4:配置应用权限

直播功能需要网络、摄像头和麦克风等权限,您需要在应用中正确配置这些权限。

声明权限

AndroidManifest.xml 中添加以下权限声明:

xml
<!-- 网络相关权限 -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

<!-- 摄像头权限 -->
<uses-permission android:name="android.permission.CAMERA" />

<!-- 音频相关权限 -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />

运行时权限

对于 Android 6.0(API 级别 23)及以上版本,您需要在使用相关功能时动态请求以下敏感权限:

  • CAMERA:摄像头权限
  • RECORD_AUDIO:麦克风权限

详见 Android 开发者官方文档: 运行时权限概览请求权限的工作流程

步骤 5:初始化 SDK

RTCLib 基于即时通讯 SDK 提供信令通道,因此需要先初始化 IM SDK,再初始化 RTCLib SDK。

初始化顺序: 初始化 IM SDK → 建立连接 → 初始化 RTCLib SDK

初始化 IM SDK

在 Application 的 onCreate() 方法中初始化 IM SDK,整个应用生命周期内只需初始化一次。

示例代码:(适用于 IM SDK 版本 ≥ 5.4.2)

Java
public class App extends Application {
@Override
public void onCreate() {
super.onCreate();

// 使用您从控制台获取的 App Key
String appKey = "Your_AppKey"; // 示例:bos9p5rlcm2ba
InitOption initOption = new InitOption.Builder().build();

// 初始化 IM SDK
RongIMClient.init(getApplicationContext(), appKey, initOption);
}
}

配置说明:

  • InitOption 包含区域码、服务地址等配置选项
  • 不传入配置表示使用默认设置(连接北京数据中心)
  • 如果您的 App Key 属于其他数据中心,需要传入对应的配置
更多配置

关于 IM SDK 初始化的详细配置请参考:初始化文档

步骤 6:连接融云服务器并初始化 RTCLib

建立 IM 连接

音视频用户之间的信令传输依赖于融云的即时通信(IM)服务,因此需要先调用 connect 与 IM 服务建立好 TCP 长连接。建议在功 能模块的加载位置处调用,之后再进行音视频直播业务。当模块退出后调用 disconnectlogout 断开该连接。

IM 连接成功建立后可以初始化 RTCLib SDK。 示例代码:

Java
// 使用从您服务器获取的 Token 建立连接
RongIMClient.connect("从您服务器端获取的 Token", new RongIMClient.ConnectCallback() {
@Override
public void onSuccess(String userId) {
// IM 连接成功,初始化 RTCLib SDK
RCRTCConfig.Builder config = RCRTCConfig.Builder.create();
RCRTCEngine.getInstance().init(context, config.build());
}

@Override
public void onError(RongIMClient.ConnectionErrorCode code) {
// 连接失败,处理错误
Log.e("RTC", "IM 连接失败: " + code);
}

@Override
public void onDatabaseOpened(RongIMClient.DatabaseOpenStatus status) {
// 数据库状态回调
}
});
引擎配置

更多 RTC 引擎配置选项请参考:引擎配置文档

步骤 7:加入会议房间

  1. 调用 RCRTCEngine.getInstance().joinRoom() 加入房间。通过 onSuccessonFailed 回调判断是否加入房间成功。
Java
String roomId = "your_meeting_room_id"; // 会议房间 ID

RCRTCEngine.getInstance().joinRoom(roomId, new IRCRTCResultDataCallback<RCRTCRoom>() {
@Override
public void onSuccess(RCRTCRoom rcrtcRoom) {
}

@Override
public void onFailed(RTCErrorCode rtcErrorCode) {
}
});
  1. 进入房间成功后调用 RCRTCRoom.registerRoomListener() 注册房间信息回调。
  2. 调用 RCRTCEngine.getInstance().getDefaultVideoStream().setVideoView() 方法设置本地视频的预览视图。
Java
 /**
* 初始化本地视频
*/
private void initLocalVideoView() {
// 初始化视图
RCRTCVideoView localVideoView = new RCRTCVideoView(getApplicationContext());
// 绑定视图
RCRTCEngine.getInstance().getDefaultVideoStream().setVideoView(localVideoView);
// 打开摄像机
RCRTCEngine.getInstance().getDefaultVideoStream().startCamera(null);
}

/**
* 处理入会成功后流程
*/
private void afterJoinRoomSuccess(RCRTCRoom rcrtcRoom) {
// 注册房间事件回调
rcrtcRoom.registerRoomListener(new IRCRTCRoomEventsListener(){
// 此处省略
});
// 开始推流
publishDefaultAVStream(rcrtcRoom);
// 订阅用户资源
subscribeAVStream(rcrtcRoom);
}

步骤 8:发布资源

  1. 调用 RCRTCEngine.getInstance().getDefaultVideoStream().startCamera() 开启摄像头。不开启摄像头,会导致对端订阅默认视频流后黑屏问题。

  2. 调用 RCRTCLocalUser 中的 publishDefaultStreams 方法发布默认音频视频资源。

Java
/**
* 发布默认视频流
*/
private void publishDefaultAVStream(RCRTCRoom room) {
room.getLocalUser().publishDefaultStreams(new IRCRTCResultCallback() {
@Override
public void onSuccess() {
}

@Override
public void onFailed(RTCErrorCode errorCode) {
}
});
}

步骤 9:订阅资源

  1. 调用 RCRTCLocalUser 中的 subscribeStreams 方法订阅会议参与者的资源,当远端用户发布资源时,会通过 onRemoteUserPublishResource 回调通知,需要订阅音视频流并显示视图。

    Java
    /**
    * 主动订阅远端用户发布的流
    * 视频流需要用户设置用于显示载体的 VideoView
    */
    public void subscribeAVStream() {
    final List<RCRTCInputStream> inputStreams = new ArrayList<>();
    for (final RCRTCRemoteUser remoteUser : mRtcRoom.getRemoteUsers()) {
    if (remoteUser.getStreams().size() == 0) {
    continue;
    }
    List<RCRTCInputStream> userStreams = remoteUser.getStreams();
    for (RCRTCInputStream inputStream : userStreams) {
    if (inputStream.getMediaType() == RCRTCMediaType.VIDEO) {
    RCRTCVideoInputStream videoInputStream = (RCRTCVideoInputStream) inputStream;
    //如果未绑定过VideoView,则需要创建并绑定VideoView
    if (videoInputStream.getVideoView() == null) {
    // 创建流对应的视图
    RCRTCVideoView videoView = new RCRTCVideoView(getApplicationContext());
    // 将视图和 stream 进行绑定
    videoInputStream.setVideoView(videoView);
    // 将远端视图添加至布局
    frameyout_remoteUser.addView(videoView);
    }
    }
    }
    inputStreams.addAll(remoteUser.getStreams());
    }

    if (inputStreams.size() == 0) {
    return;
    }
    mRtcRoom.getLocalUser().subscribeStreams(inputStreams, new IRCRTCResultDataCallback<List<RCRTCInputStream>>() {
    @Override
    public void onSuccess() {

    }
    @Override
    public void onSuccess(List<RCRTCInputStream> data) {

    }

    @Override
    // 如果 SDK ≧ 5.3.4,您可以使用 IRCRTCResultDataCallback,onFailed 方法会返回订阅失败的流列表和错误码。
    // 如果 SDK < 5.3.4,仅支持使用 IRCRTCResultCallback,onFailed 方法仅返回错误码。
    public void onFailed(List<RCRTCInputStream> failedStreams, RTCErrorCode errorCode) {

    }
    });
    }
  2. 在注册的房间事件回调中可根据业务需求监听远端用户发布的资源,并进行订阅。

    Java
    new IRCRTCRoomEventsListener() {
    /**
    * 房间内用户发布资源
    *
    * @param rcrtcRemoteUser 远端用户
    * @param list 发布的资源
    */
    @Override
    public void onRemoteUserPublishResource(RCRTCRemoteUser rcrtcRemoteUser, final List<RCRTCInputStream> list) {
    subscribeAVStream();
    }
    }