功能简介

此示例演示了如何使用 SDK 加入频道进行音视频通话的功能

界面展示

image.png

API 调用时序图

在介绍实现音视频通话的具体代码之前,可参照下图对 API 的调用顺序建立基本概念。

对于一个完整的视频通话,一般将会包含以下几个流程:

  • 初始化 RtcEngine
  • 设置本地视图
  • 加入频道
  • 设置远端视图
  • 离开频道
  • 销毁 RtcEngine

image.png

代码路径

本节相关的实例代码请访问 src/main/java/io/agora/api/example/examples/basic/JoinChannelVideo.java

代码解析

初始化 RtcEngine

  1. engine = RtcEngine.create(context.getApplicationContext(),
  2. getString(R.string.agora_app_id), iRtcEngineEventHandler);

相关参数

参数 解释
context Android Activity 的 Context
appID App ID 是 Agora 为开发项目生成的字符串,是项目的唯一标识。从 Agora 的开发者后台获取:https://docs.agora.io/cn/Agora%20Platform/term_appid?platform=Android
handler IRtcEngineEventHandler 是一个提供默认实现的抽象类,SDK使用这个类来向应用程序报告SDK运行时的事件

设置本地视图

参考以下代码,对本地视图进行设置。

  1. // Create render view by RtcEngine
  2. // 通过 RtcEngine 创建渲染视图
  3. SurfaceView surfaceView = RtcEngine.CreateRendererView(context);
  4. if(fl_local.getChildCount() > 0)
  5. {
  6. fl_local.removeAllViews();
  7. }
  8. // Add to the local container
  9. // 添加到本地容器
  10. fl_local.addView(surfaceView, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
  11. // Setup local video to render your local camera preview
  12. // 设置本地视图来渲染本地摄像头预览
  13. engine.setupLocalVideo(new VideoCanvas(surfaceView, RENDER_MODE_HIDDEN, 0));
  14. // Set audio route to microPhone
  15. // 将默认音频路由设置成听筒(如设置为 true,则音频路由为扬声器)
  16. engine.setDefaultAudioRoutetoSpeakerphone(false);

设置 RtcEngine 的 Profile

根据你的使用场景,对 RtcEngine 的 Profile 进行设置,具体情况如下。

  • CHANNEL_PROFILE_COMMUNICATION(0): 通信场景(默认)
    用于常见的一对一通话或群聊,频道中的任何用户可以自由说话。

  • CHANNEL_PROFILE_LIVE_BROADCASTING(1): 直播场景
    直播场景有主播和观众两种用户角色,可以通过 setClientRole 方法设置主播和观众的角色。主播可以收发语音/视频流,而观众只能接收语音/视频,无法发送。 ```java engine.setChannelProfile(Constants.CHANNEL_PROFILE_LIVE_BROADCASTING);

engine.setClientRole(IRtcEngineEventHandler.ClientRole.CLIENT_ROLE_BROADCASTER); // Enable video module // 启用视频模块。在加入频道前调用,则自动开启视频模式,在通话中调用则由音频模式切换为视频模式。 engine.enableVideo();

  1. <a name="ggHOL"></a>
  2. ### 配置 accessToken
  3. 请在 string_config 文件中配置 accessToken
  4. - 在开发者控制台中生成的临时令牌。临时 Token 的有效期为24小时。详情请见:[https://docs.agora.io/cn/Agora%20Platform/token?platform=All%20Platforms#get-a-temporary-token](https://docs.agora.io/cn/Agora%20Platform/token?platform=All%20Platforms#get-a-temporary-token)
  5. - 在服务器上生成 Token ,适用于有高安全要求的场景。详情请见:[https://docs.agora.io/cn/Video/token_server?platform=Android](https://docs.agora.io/cn/Video/token_server?platform=Android)
  6. ```java
  7. String accessToken = getString(R.string.agora_access_token);
  8. if (TextUtils.equals(accessToken, "") || TextUtils.equals(accessToken, "<#YOUR ACCESS TOKEN#>"))
  9. {
  10. accessToken = null;
  11. }

加入频道

完成初始化和设置本地视图后(视频通话场景),你就可以调用 joinChannel 方法加入频道。

  1. ChannelMediaOptions option = new ChannelMediaOptions();
  2. option.autoSubscribeAudio = true;
  3. option.autoSubscribeVideo = true;
  4. int res = engine.joinChannel(accessToken, channelId, "Extra Optional Data", 0, option);
  5. if (res != 0)
  6. {
  7. // Usually happens with invalid parameters
  8. // Error code description can be found at:
  9. // en: https://docs.agora.io/en/Voice/API%20Reference/java/classio_1_1agora_1_1rtc_1_1_i_rtc_engine_event_handler_1_1_error_code.html
  10. // cn: https://docs.agora.io/cn/Voice/API%20Reference/java/classio_1_1agora_1_1rtc_1_1_i_rtc_engine_event_handler_1_1_error_code.html
  11. showAlert(RtcEngine.getErrorDescription(Math.abs(res)));
  12. return;
  13. }
  • autoSubscribeAudio/autoSubscribeVideo:设置是否自动订阅频道内所有远端音频/视频流。

调用 joinChannel 方法需要传入的参数包括:

参数 解释
token 可设为临时 Token 或者在你的服务器端生成的 Token 。
channelName 标识通话的频道名称,长度在 64 字节以内的字符串。
optionalInfo (非必选项)预留参数。
optionalUid (非必选项)本地用户的 ID。数据类型为整型,且频道内每个用户的 uid 必须是唯一的。若将 uid 设为 0,则 SDK 会自动分配一个 uid,并在 onJoinChannelSuccess 回调中报告。用户成功加入频道后,会默认订阅频道内其他所有用户的音频流和视频流,因此产生用量并影响计费。如果想取消订阅,可以通过调用相应的 mute 方法实现。

设置远端视图

当远端用户加入频道,会触发 onUserJoined 回调,对此进行处理并进行远端视图的设置。

  1. public void onUserJoined(int uid, int elapsed)
  2. {
  3. super.onUserJoined(uid, elapsed);
  4. Log.i(TAG, "onUserJoined->" + uid);
  5. showLongToast(String.format("user %d joined!", uid));
  6. /**Check if the context is correct*/
  7. /**检查 context 是否正确*/
  8. Context context = getContext();
  9. if (context == null) {
  10. return;
  11. }
  12. if(remoteViews.containsKey(uid)){
  13. return;
  14. }
  15. else{
  16. handler.post(() ->
  17. {
  18. /**Display remote video stream*/
  19. /**显示远端视频流*/
  20. SurfaceView surfaceView = null;
  21. // Create render view by RtcEngine
  22. // 通过 RtcEngine 创建远端视图
  23. surfaceView = RtcEngine.CreateRendererView(context);
  24. surfaceView.setZOrderMediaOverlay(true);
  25. ViewGroup view = getAvailableView();
  26. remoteViews.put(uid, view);
  27. // Add to the remote container
  28. // 加入远端容器
  29. view.addView(surfaceView, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
  30. // Setup remote video to render
  31. // 设置远端视图进行渲染
  32. engine.setupRemoteVideo(new VideoCanvas(surfaceView, RENDER_MODE_HIDDEN, uid));
  33. });
  34. }
  35. }

离开频道

根据场景需要,如结束通话、关闭 App 或 App 切换至后台时,调用 leaveChannel 离开当前通话频道。

  1. public void onDestroy()
  2. {
  3. super.onDestroy();
  4. /**leaveChannel and Destroy the RtcEngine instance*/
  5. /**离开频道并销毁 RtcEngine 实例*/
  6. if(engine != null)
  7. {
  8. engine.leaveChannel();
  9. }
  10. handler.post(RtcEngine::destroy);
  11. engine = null;
  12. }