差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

两侧同时换到之前的修订记录 前一修订版
后一修订版
前一修订版
im:android:basics:multiuserconference [2020/02/07 07:55]
huanxinfudh [产品简介]
— (当前版本)
行 1: 行 1:
-====== 多人音视频会议功能 ====== 
  
------- 
- 
-===== 产品简介 ===== 
-  
- ​为满足不同场景需求,3.5.0版本开始将实时音视频会议划分了不同的类型,不同类型对应了不同场景,使你能够轻松地将实时音视频功能集成到你的应用或者网站中。 
-  
- ​可以创建以下几种类型的会议: 
-  
-     ​1.Communication:普通通信会议,最多支持参会者9人,会议里的每个参会者都可以自由说话和发布视频,该会议类型在服务器不做语音的再编码,音质最好,适用于远程医疗,在线客服等场景; 
-  
-     ​2.Large Communication:大型通信会议,最多参会者30人,会议里的每个参会者都可以自由说话,最多支持6个人发布视频,该会议模式在服务器做混音处理,支持更多的人说话,适用于大型会议等场景; 
-  
-     ​3.Live:互动视频会议,会议里支持最多6个主播和600个观众,观众可以通过连麦与主播互动,该会议类型适用于在线教育,互动直播等场景; 
-  
- ==== 产品特性 ==== 
-  * SDK采用模块化设计,极简的 API 设计,方便用户使用单一模块实现特定功能; 
-  
-  * 适配主流 iOS 设备和 主流 Android 终端设备,保证用户体验一致; 
-  
-  * 支持手机端和 Web 端互通,极大方便开发者的全平台业务; 
-  
-  * 视频码率(带宽占用)自适应的,非固定值,会自动根据网络拥塞情况调整清晰度,码率,帧率等。各个分辨率的码率范围如下: 
- 
-      240p:150k~400kbps,推荐 300kbps 
-      480p:300k~1Mbps,推荐 500kbps 
-      720p:900k ~2.5Mbps,推荐 1Mbps 
-      1080p: 2M ~ 5Mbps,推荐 3Mbps 
-  
- ==== 音视频通信的简要步骤 ==== 
-  
- SDK 能够支持音频和视频通信。创建音视频通信的过程简单来说,可以分为以下几步: 
-  - 设置监听 
-  - create: 创建会议 
-  - join: 加入会议 
-  - pub: 发布音视频数据流 
-  - sub: 订阅并播放音视频数据流 
-  - leave: 离开会议 
-  
- ==== 基本知识 ==== 
-   * EMConference:​ 会议实例,保存着与当前会议的相关信息,会议加入成功后会在callback中返回该实例 
-  
-   * EMConferenceMember:​ 会议成员实例,保存着该会议成员的相关信息,有成员加入或退出会议时会在callback中返回该实例 ​ 
-  
-   * EMConferenceStream:​ 会议中的数据流,包含音频数据和视频数据的相关信息,有成员推流或停止推流时会在相应callback中返回该实例 
-  
-   * EMStreamParam:自己发布的数据流的各种配置,需要在调用发布接口时作为参数传入 
-  
-   * EMConferenceListener:会议监听类,会回调会议成员变化,会议数据流变化等,需要在代码中设置监听 
-  
-   * EMConferenceRole:多人会议成员角色 
- 
-       1. 观众Audience:只能观看收听音视频,即只能订阅流 
-       2. 主播Speaker:能上传自己的音视频,能观看收听其他主播的音视频,即能发布流和订阅流 
-       3. 管理员Admin:能创建会议,销毁会议,移除会议成员,切换其他成员的角色,订阅流,发布流 
-    ​ 
-       ​注意: 
-       >>​ 每个人必须调用join接口成功后,才算是加入会议(即成为会议成员)。会议成员才允许进行其他操作比如订阅流、发布流等 
-       >>​ 成员如果想改变自己角色,必须想办法通知管理员,只有管理员才能修改 
-  
-   * EMConferenceType:多人会议类型 
- 
-       1. Communication:普通通信会议,最多支持参会者6人,成员都可以自由说话和发布视频,成员角色Speaker 
-       2. Large Communication:大型通信会议,最多参会者30人,成员都可以自由说话和发布视频,成员角色Speaker 
-       3. Live:互动视频会议,会议里支持最多6个主播和600个观众 
- 
- ===== 多人通信会议功能实现 ===== 
-  
- ​如何使用SDK实现多人实时音视频会议 
-  
- ​Communication和Large Communication除了最大成员数不一样,流程几乎是一样的。以下是从创建会议到离开会议完整的流程讲解: 
- 
-==== 注册监听 ==== 
- 
-进入会议之前,调用''​EMConferenceManager#​addConferenceListener(EMConferenceListener listener)''​方法指定回调监听,成员加入或离开会议,数据流更新等 
-注意:该回调监听中的所有方法运行在子线程中,请勿在其中操作UI 
-<code java> 
-EMConferenceListener listener = new EMConferenceListener() { 
-    @Override public void onMemberJoined(String username) { 
-        // 有成员加入 
-    } 
-                                                            
-    @Override public void onMemberExited(String username) { 
-        // 有成员离开 
-    } 
-                                                                
-    @Override public void onStreamAdded(EMConferenceStream stream) { 
-        // 有流加入 
-    } 
-                                                                
-    @Override public void onStreamRemoved(EMConferenceStream stream) { 
-        // 有流移除 
-    } 
-                                                                
-    @Override public void onStreamUpdate(EMConferenceStream stream) { 
-        // 有流更新 
-    } 
-                                                                
-    @Override public void onPassiveLeave(int error, String message) { 
-        // 被动离开 
-    } 
-                                                                
-    @Override public void onConferenceState(ConferenceState state) { 
-        // 聊天室状态回调 
-    } 
-                                                                
-    @Override public void onStreamSetup(String streamId) { 
-        // 流操作成功回调 
-    } 
-                                                                    
-    @Override public void onSpeakers(final List<​String>​ speakers) { 
-        // 当前说话者回调 
-    } 
-                                                                    
-    @Override public void onReceiveInvite(String confId, String password, String extension) { 
-        // 收到会议邀请 
-        if(easeUI.getTopActivity().getClass().getSimpleName().equals("​ConferenceActivity"​)) { 
-            return; 
-        } 
-        Intent conferenceIntent = new Intent(appContext,​ ConferenceActivity.class);​ 
-        conferenceIntent.putExtra(Constant.EXTRA_CONFERENCE_ID,​ confId); 
-        conferenceIntent.putExtra(Constant.EXTRA_CONFERENCE_PASS,​ password); 
-        conferenceIntent.putExtra(Constant.EXTRA_CONFERENCE_IS_CREATOR,​ false); 
-        conferenceIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);​ 
-        appContext.startActivity(conferenceIntent);​ 
-    } 
-}); 
-    ​ 
-// 在Activity#​onCreate()中添加监听 
-EMClient.getInstance().conferenceManager().addConferenceListener(conferenceListener);​ 
-    ​ 
-// 在Activity#​onDestroy()中移除监听 
-EMClient.getInstance().conferenceManager().removeConferenceListener(conferenceListener);​ 
-</​code> ​   ​ 
- 
-==== 用户A创建会议 ==== 
- 
-SDK没有提供单独的创建接口,只提供了一个createAndJoin接口,A调用该接口后,将拥有一个会议实例Conference,并且A已经是Conference的成员且角色是Admin 
- 
-<code java> 
-EMClient.getInstance().conferenceManager().createAndJoinConference(emConferenceType,​ 
-                conference-password,​ new EMValueCallBack<​EMConference>​() { 
-                    @Override 
-                    public void onSuccess(EMConference value) { 
-                        // 返回当前会议对象实例 value 
-                        // 可进行推流等相关操作 
-                        // 运行在子线程中,勿直接操作UI 
-                    } 
-    ​ 
-                    @Override 
-                    public void onError(int error, String errorMsg) { 
-                        // 运行在子线程中,勿直接操作UI 
-                    } 
-                }); 
-</​code>​ 
- 
-==== 管理员A邀请其他人加入会议 ==== 
- 
-SDK没有提供邀请接口,你可以自己实现,比如使用环信IM通过发消息邀请,比如通过发邮件邀请等等。 
-至于需要发送哪些邀请信息,可以参照SDK中的join接口,目前是需要Conference的confrId和password 
- 
-比如用环信IM发消息邀请 
-<code java> 
-final EMMessage message = EMMessage.createTxtSendMessage("​邀请你观看直播",​ to); 
-message.setAttribute(Constant.EM_CONFERENCE_ID,​ conference.getConferenceId());​ 
-message.setAttribute(Constant.EM_CONFERENCE_PASSWORD,​ conference.getPassword());​ 
-EMClient.getInstance().chatManager().sendMessage(message);​ 
-</​code>​ 
- 
-    注意: 使用环信IM邀请多个人时,建议使用群组消息,如果使用单聊发消息请注意每条消息中间的时间间隔,以防触发环信的垃圾消息防御机制 
- 
-==== 用户B接收到邀请加入会议 ==== 
- 
-用户B解析出邀请消息中带的confrId和password,调用SDK的join接口加入会议,成为会议成员且角色是Speaker. 
- 
-<code java> 
-EMClient.getInstance().conferenceManager().joinConference(conferenceId,​ password, new  
-    EMValueCallBack<​EMConference>​() { 
-        @Override 
-        public void onSuccess(EMConference value) { 
-            // 返回当前会议对象实例 value 
-            // 可进行推流等相关操作 
-            // 运行在子线程中,勿直接操作UI 
-        } 
-    ​ 
-        @Override 
-        public void onError(int error, String errorMsg) { 
-            // 运行在子线程中,勿直接操作UI 
-        } 
-    }); 
-</​code>​ 
- 
-用户B成功加入会议后,会议中其他成员会收到回调''​EMConferenceListener#​onMemberJoined(EMConferenceMember member)''​ 
- 
-<code java> 
-@Override 
-public void onMemberJoined(final EMConferenceMember member) { 
-    runOnUiThread(new Runnable() { 
-        @Override 
-        public void run() { 
-            Toast.makeText(activity,​ member.memberName + " joined conference!",​ Toast.LENGTH_SHORT).show();​ 
-        } 
-    }); 
-} 
-</​code>​ 
- 
-==== 成员A发布音视频流 ==== 
- 
-成员A和成员B都有发布流的权限,可以调用SDK的publish接口发布流,该接口用到了EMStreamParam参数,你可以自由配置,比如是否上传视频,是否上传音频,使用前置或后置摄像头,视频码率,显示视频页面等等 
- 
-<code java> 
-pirvate void pubLocalStream() { 
-    EMStreamParam param = new EMStreamParam();​ 
-    param.setStreamType(EMConferenceStream.StreamType.NORMAL);​ 
-    param.setVideoOff(false);​ 
-    param.setAudioOff(false);​ 
-        ​ 
-    EMClient.getInstance().conferenceManager().publish(param,​ new EMValueCallBack<​String>​() { 
-        @Override 
-        public void onSuccess(String streamId) { 
-        } 
-        ​ 
-        @Override 
-        public void onError(int error, String errorMsg) { 
-            EMLog.e(TAG,​ "​publish failed: error="​ + error + ", msg=" + errorMsg); 
-        } 
-    }); 
-} 
-</​code>​ 
-    ​ 
-    注意:如果是纯音频会议,只需要在发布数据流时将EMStreamParam中的setVideoOff置为true即可 
- 
-==== 其他成员收到通知并订阅流 ==== 
- 
-成员A成功发布数据流后,会议中其他成员会收到监听类回调''​EMConferenceListener#​onStreamAdded(EMConferenceStream stream)''​,如果成员B想看成员A的音视频,可以调用subscribe接口进行订阅 
- 
-<code java> 
-@Override 
-public void onStreamAdded(final EMConferenceStream stream) { 
-    runOnUiThread(new Runnable() { 
-        @Override 
-        public void run() { 
-            ConferenceMemberView memberView = new ConferenceMemberView(activity);​ 
-            // 添加当前view到界面 
-            callConferenceViewGroup.addView(memberView);​ 
-            // 设置当前view的一些状态 
-            memberView.setUsername(stream.getUsername());​ 
-            memberView.setStreamId(stream.getStreamId());​ 
-            memberView.setAudioOff(stream.isAudioOff());​ 
-            memberView.setVideoOff(stream.isVideoOff());​ 
-            memberView.setDesktop(stream.getStreamType() == EMConferenceStream.StreamType.DESKTOP);​ 
-                ​ 
-            EMClient.getInstance().conferenceManager().subscribe(stream,​ memberView.getSurfaceView(),​ new EMValueCallBack<​String>​() { 
-                @Override 
-                public void onSuccess(String value) { 
-                } 
-                ​ 
-                @Override 
-                public void onError(int error, String errorMsg) { 
-                ​ 
-                } 
-            }); 
-        } 
-    }); 
-} 
-</​code>​ 
- 
-==== 成员A设置自己发布的流 ==== 
- 
-当成员A对自己的数据流做以上操作成功后,会议中的其他成员会收到回调''​EMConferenceListener#​onStreamUpdate(EMConferenceStream stream)''​ 
- 
-<code java> 
-@Override 
-public void onStreamUpdate(final EMConferenceStream stream) { 
-    runOnUiThread(new Runnable() { 
-        @Override 
-        public void run() { 
-            Toast.makeText(activity,​ stream.getUsername() + " stream update!",​ Toast.LENGTH_SHORT).show();​ 
-            // 更新当前stream所对应View 
-            updateConferenceMemberView(stream);​ 
-    } 
-    }); 
-} 
-</​code>​ 
- 
- 
-==== 成员B取消订阅流 ==== 
- 
-成员B如果不想再看成员A的音视频,可以调用SDK接口unsubscribe 
- 
-<code java> 
-EMClient.getInstance().conferenceManager().unsubscribe(emConferenceStream,​ new EMValueCallBack<​String>​() { 
-    @Override 
-    public void onSuccess(String value) { 
-    } 
-    ​ 
-    @Override 
-    public void onError(int error, String errorMsg) { 
-    ​ 
-    } 
-}); 
-</​code>​ 
- 
-==== 成员A取消发布流 ==== 
- 
-成员A可以调用unpublish接口取消自己已经发布的数据流,操作成功后,会议中的其他成员会收到回调''​EMConferenceListener#​onStreamRemoved(EMConferenceStream stream)''​,将对应的数据流信息移除 
- 
-<code java> 
-@Override 
-public void onStreamRemoved(final EMConferenceStream stream) { 
-    runOnUiThread(new Runnable() { 
-        @Override 
-        public void run() { 
-            Toast.makeText(activity,​ stream.getUsername() + " stream removed!",​ Toast.LENGTH_SHORT).show();​ 
-            if (streamList.contains(stream)) { 
-                removeConferenceView(stream);​ 
-            } 
-        } 
-    }); 
-} 
-</​code>​ 
- 
-==== 成员B离开会议 ==== 
- 
-成员B调用SDK接口leave离开会议,会议中的其他成员会收到回调''​EMConferenceListener#​onMemberExited(EMConferenceMember member)''​ 
- 
-    注意:当最后一个成员调用leave接口后,会议会自动销毁 
- 
-<code java> 
-@Override 
-public void onMemberExited(final EMConferenceMember member) { 
-    runOnUiThread(new Runnable() { 
-        @Override 
-        public void run() { 
-            Toast.makeText(activity,​ member.memberName + " removed conference!",​ Toast.LENGTH_SHORT).show();​ 
-        } 
-    }); 
-} 
-</​code>​ 
- 
- ===== 互动视频会议 ===== 
-  
- ​互动视频会议的基本操作(创建、邀请人、发布流、取消发布流、订阅流、取消订阅流、更新发布流程、离开)对应的接口和回调同通信会议是一样的。也可以说 互动视频会议是在通信会议的基础上,增加了角色管理功能,以下着重讲解互动视频会议中的角色管理相关知识点 
-  
- 1. 创建互动视频会议时,接口''​EMConferenceManager#​createAndJoinConference(EMConferenceType type, String password, EMValueCallBack<​EMConference>​ callback)''​传入的type参数是''​EMConferenceManager#​EMConferenceType#​LiveStream''​ 
-  
- 2. 创建者createAndJoin后的角色是Admin,其他成员第一次调用接口''​EMConferenceManager#​joinConference(String confId, String password, EMValueCallBack<​EMConference>​ callback)''​加入直播后的权限是观众Audience,Audience只能订阅数据流 
-  
- 3. 观众Audience如果想发布数据流 即上麦,需要给管理员发申请。SDK没有提供申请接口,你可以自定义。 
-  
- ​管理员如果同意Audience上麦,需要调用接口''​EMConferenceManager#​grantRole(String confId, EMConferenceMember member, EMConferenceRole toRole, EMValueCallBack<​String>​ callback)''​将角色Audience更改为Speaker 
- 
-<code java> 
-EMClient.getInstance().conferenceManager().grantRole(conference.getConferenceId() 
-        , new EMConferenceMember(jid,​ null, null) 
-        , EMConferenceManager.EMConferenceRole.Talker,​ new EMValueCallBack<​String>​() { 
-            @Override 
-            public void onSuccess(String value) { 
-                EMLog.i(TAG,​ "​changeRole success, result: " + value); 
-            } 
-  
-            @Override 
-            public void onError(int error, String errorMsg) { 
-                EMLog.i(TAG,​ "​changeRole failed, error: " + error + " - " + errorMsg); 
-            } 
-        }); 
-</​code>​ 
-      
-成员角色改变后,被改变的成员会在接口''​EMConferenceManager#​onRoleChanged(EMConferenceManager.EMConferenceRole role)''​中收到回调 
- 
-    @Override 
-    public void onRoleChanged(EMConferenceManager.EMConferenceRole role) { 
-        EMLog.i(TAG,​ "​onRoleChanged,​ role: " + role); 
-        currentRole = role; 
-    ​ 
-        if (role == EMConferenceManager.EMConferenceRole.Talker) { 
-            // 管理员把当前用户角色更改为主播,​可以进行publish本地流等操作 
-        } else if (role == EMConferenceManager.EMConferenceRole.Audience) { 
-            // 管理员把当前用户角色改变为观众 
-        } 
-    } 
-  
-4. 角色从Audience变为Speaker,成员就可以发布数据流了 
- 
-    注意: 
-    >> MemberName和UserName是两个不同的概念,UserName是环信ID,MemberName是环信AppKey和环信ID拼接成的字符串,可通过接口EasyUtils#​getMediaRequestUid(String appKey, String username)获取 
-    >> 接口中的MemberName参数都是一样的类型 
- 
- ===== 其他方法 ===== 
- <​code java> 
- // 开启音频传输 
- ​EMClient.getInstance().conferenceManager().openVoiceTransfer();​ 
- // 关闭音频传输 
- ​EMClient.getInstance().conferenceManager().closeVoiceTransfer();​ 
- // 开启视频传输 
- ​EMClient.getInstance().conferenceManager().openVideoTransfer();​ 
- // 关闭视频传输 
- ​EMClient.getInstance().conferenceManager().closeVideoTransfer();​ 
-  
- ​PS:以上这四个方法都是修改 stream,群里其他成员都会收到 EMConferenceListener.onStreamUpdate()回调 
-  
- // 切换摄像头 
- ​EMClient.getInstance().conferenceManager().switchCamera();​ 
- // 设置展示本地画面的 view 
- ​EMClient.getInstance().conferenceManager().setLocalSurfaceView(localView);​ 
- // 更新展示本地画面 view 
- ​EMClient.getInstance().conferenceManager().updateLocalSurfaceView(localView);​ 
- // 更新展示远端画面的 view 
- ​EMClient.getInstance().conferenceManager().updateRemoteSurfaceView(streamId,​ remoteView);​ 
-  
- // 开始监听说话者,参数为间隔时间 
- ​EMClient.getInstance().conferenceManager().startMonitorSpeaker(300);​ 
-  
- // 停止监听说话者 
- ​EMClient.getInstance().conferenceManager().stopMonitorSpeaker();​ 
- </​code>​ 
- 
----- 
-<WRAP group> 
-<WRAP half column> 
-上一页:[[im:​android:​basics:​audiovideo|1V1实时通话]] 
-</​WRAP>​ 
- 
-<WRAP half column> 
-下一页:[[im:​android:​basics:​multidevices|多设备]] 
-</​WRAP>​ 
-</​WRAP>​