# 概述 本篇文章主要用于记录我在实现agora一对一视频通话的时候遇到的一些问题。实现视频通话主要步骤还是要看 [agora官网-实现视频通话](https://docs.agora.io/cn/video-call-4.x/start_call_android_ng?platform=Android "agora官网-实现视频通话") # 实现步骤 ## 1、实现前准备 此处需要参考 [agora官网-实现视频通话](https://docs.agora.io/cn/video-call-4.x/start_call_android_ng?platform=Android "agora官网-实现视频通话") 描述的前提条件。  我的使用配置: **Android Studio:**Android Studio Chipmunk | 2021.2.1 这里需要实现的功能和样式 1、一对一视频通话 ui样式:  ## 2、开始实现 此时通过官网的前提条件最后一条的说明和操作已经拿到了:App ID 和 临时Token。 这里就开始写代码来实现功能了。 ### 2.1、首先添加依赖: ```java implementation 'io.agora.rtc:full-sdk:4.0.0-rc.1' ``` ### 2.2、xml布局: ```java ``` ### 2.3、Java实现: ```java public class MainActivity extends AppCompatActivity { private final String TAG = "通话测试"; private static final int PERMISSION_REQ_ID = 22; private static final String[] REQUESTED_PERMISSIONS = { Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA }; private FrameLayout local_container; private FrameLayout remote_container; private Button hangup; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); local_container = findViewById(R.id.local_video_view_container);//本地视图 remote_container = findViewById(R.id.remote_video_view_container);//远端视图 hangup = findViewById(R.id.btn_hangup); // 如果已经授权,则初始化 RtcEngine 并加入频道。 if (checkSelfPermission(REQUESTED_PERMISSIONS[0], PERMISSION_REQ_ID) && checkSelfPermission(REQUESTED_PERMISSIONS[1], PERMISSION_REQ_ID)) { initializeAndJoinChannel(); } //挂断按钮点击事件 hangup.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mRtcEngine.stopPreview(); mRtcEngine.leaveChannel(); } }); } private boolean checkSelfPermission(String permission, int requestCode) { if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, REQUESTED_PERMISSIONS, requestCode); return false; } return true; } // 填写频道名称。 private String channelName = "test"; // 填写 Agora 控制台中生成的临时 Token。 private String token = ""; private int myUid = 101;//自己进入视频通话的uid标识,相当于一个人的身份证 private RtcEngine mRtcEngine; private final IRtcEngineEventHandler mRtcEventHandler = new IRtcEngineEventHandler() { @Override // 监听频道内的远端主播,获取主播的 uid 信息。 public void onUserJoined(int uid, int elapsed) { Log.i(TAG, "远端用户上线: "+uid); runOnUiThread(new Runnable() { @Override public void run() { setupRemoteVideo(uid); } }); } @Override public void onUserOffline(int uid, int reason) { super.onUserOffline(uid, reason); Log.i(TAG, "远端用户掉线: "+uid); } }; //初始化并加入频道 private void initializeAndJoinChannel() { try { RtcEngineConfig config = new RtcEngineConfig(); config.mContext = getBaseContext(); config.mAppId = getString(R.string.agora_app_id);//重点1、此处是你的appID config.mEventHandler = mRtcEventHandler; mRtcEngine = RtcEngine.create(config); } catch (Exception e) { Log.i(TAG, "Check the error.: "); throw new RuntimeException("Check the error."); } // 视频默认禁用,你需要调用 enableVideo 启用视频流。 mRtcEngine.enableVideo(); // 开启本地视频预览。 mRtcEngine.startPreview(); //设置本地视图预览 setupLocalVideo(); ChannelMediaOptions options = new ChannelMediaOptions(); // 视频通话场景下,设置频道场景为 BROADCASTING。 options.channelProfile = Constants.CHANNEL_PROFILE_LIVE_BROADCASTING; // 将用户角色设置为 BROADCASTER。 options.clientRoleType = Constants.CLIENT_ROLE_BROADCASTER; // 使用临时 Token 加入频道。 // 你需要自行指定用户 ID,并确保其在频道内的唯一性。 //重点2 mRtcEngine.joinChannel(token, channelName, myUid, options); } //设置本地视图预览 private void setupLocalVideo(){ // 创建一个 SurfaceView 对象,并将其作为 FrameLayout 的子对象。 SurfaceView surfaceView = new SurfaceView (getBaseContext()); surfaceView.setZOrderMediaOverlay(true);//会使surface置于其它surfaceview之上 local_container.addView(surfaceView); // 将 SurfaceView 对象传入 Agora,以渲染本地视频。 mRtcEngine.setupLocalVideo(new VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_HIDDEN, 0)); } //设置远端用户视图 private void setupRemoteVideo(int uid) { SurfaceView surfaceView = new SurfaceView (getBaseContext()); remote_container.addView(surfaceView); mRtcEngine.setupRemoteVideo(new VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_HIDDEN, uid)); } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == PERMISSION_REQ_ID){ // 如果已经授权,则初始化 RtcEngine 并加入频道。 if (checkSelfPermission(REQUESTED_PERMISSIONS[0], PERMISSION_REQ_ID) && checkSelfPermission(REQUESTED_PERMISSIONS[1], PERMISSION_REQ_ID)) { initializeAndJoinChannel(); } } } @Override protected void onDestroy() { super.onDestroy(); mRtcEngine.stopPreview(); mRtcEngine.leaveChannel(); /* 销毁RtcEngine实例并释放AgoraSDK使用的所有资源。 这种方法对于偶尔进行语音或视频呼叫的应用程序非常有用, 在不进行呼叫时释放其他操作的资源。 */ RtcEngine.destroy(); } } ``` 到这里就做完了。 ## 3、注意事项 ### 3.1、加入频道 `mRtcEngine.joinChannel(token, channelName, myUid, options);` 这句代码的作用是加入频道 参数: - token:录官网注册账户申请的临时token。 - channelName:频道名,类似于抖音各个直播间的房间名。 - myUid:自己视频房间的身份证,可用于辨别进入房间的身份。 - options:视频房间的一些配置,如进入的角色等。 ### 3.2、开启视频预览 `mRtcEngine.setupLocalVideo(new VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_HIDDEN, 0));` `mRtcEngine.setupRemoteVideo(new VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_HIDDEN, uid));` 第一句是开启本地视频预览,即显示自己的视频画面 第二句是开启远端视频预览,即显示对方的视频画面 开启本地视频预览和开启远端视频预览的步骤都是: 先创建一个SurfaceView添加到布局中的视图组件上,然后设置`mRtcEngine.setupLocalVideo`或`mRtcEngine.setupRemoteVideo`,将创建的SurfaceView、视频画面渲染模式、uid 放到VideoCanvas中传进去即可。 其中: - surfaceView:是预览画面的容器, ***注意:***在创建surfaceView的时候有`surfaceView.setZOrderMediaOverlay(true);`这一句代码的作用是使当前这个surface置于其它surfaceview之上。这里就很容易出现一个bug,做agora视频通话时,FrameLayout中层叠两个视频画面,在远端用户上线后,下面的视频画面会直接覆盖上面的画面,造成这个问题的原因之一就是我们在设置远端视频画面预览和本地视频画面预览的时候把放在下面显示的视频画面的surfaceView设置了`surfaceView.setZOrderMediaOverlay(true);`,导致下面的视频画面处于所有surfaceView的顶部。这个问题参考:[Android SurfaceView的setZOrderMediaOverlay和setZOrderOnTop区别](https://blog.csdn.net/qq_44381427/article/details/118517002 "Android SurfaceView的setZOrderMediaOverlay和setZOrderOnTop区别") - VideoCanvas.RENDER_MODE_HIDDEN:视频画面渲染模式,这个参数是铺满全屏,通话时视频画面出现黑边就有可能是这个渲染模式设置成了显示全部画面。 - uid:需要显示谁的视频画面,就传入谁的uid,设置本地的视频画面传入的就是0或自己的uid,设置远端视频画面传入的就是别人的uid ### 3.3、挂断视频后使视频画面变黑 在对方掉线/离线或自己挂断等情况下,离开的那个人的视频画面应该变成黑色,但是实际上离开频道后视频画面会一直卡在刚才视频的最后一个画面上。 此时设置布局中视图组件的背景颜色变成黑色都没有任何作用,这是因为在开启视频的时候是创建了一个SurfaceView容器添加到布局里是视图组件中。离开频道后布局中的视图组件里SurfaceView还在,这时候去设置视图组件的颜色是会被它里面的SurfaceView盖住而看不到颜色。 因此解决办法也很简单。在离线后把对应的布局中的视图组件清空掉它里面的子组件就行了,如远端用户离线后就设置:`remote_container.removeAllViews();`即可。 最后编辑:2023年03月10日 ©著作权归作者所有
最新回复