差别
这里会显示出您选择的修订版和当前版本之间的差别。
两侧同时换到之前的修订记录 前一修订版 后一修订版 | 前一修订版 | ||
rtc:conference:web [2020/06/30 10:02] suqx [暂停/恢复自己的视频] |
rtc:conference:web [2021/03/26 08:01] (当前版本) huangfeipeng [2. 指定设备打开音视频] |
||
---|---|---|---|
行 1: | 行 1: | ||
- | ====== Web集成多人通话 ====== | + | ====== Web集成多人通话 ======= |
+ | ====== 跑通Demo ======= | ||
+ | 环信提供开源的多人视频会议项目WebVideoCallDemo,在使用SDK集成App前,您可以参考相关代码 | ||
+ | ===== 示例代码 ===== | ||
+ | ** 1.可在[[http://docs-im.easemob.com/rtc/scenario/meeting#demo_%E6%BA%90%E7%A0%81|环信音视频Demo源码]]下载页面,选择Web端Demo下载 **\\ | ||
+ | ** 2.进入github开源网站https://github.com/easemob/videocall-web, 克隆代码 **\\ | ||
+ | ==== 前提条件 ==== | ||
+ | ** 1.安装一款 Easemob Web SDK [[http://docs-im.easemob.com/rtc/common/introduction#%E5%85%BC%E5%AE%B9%E6%80%A7%E8%AF%B4%E6%98%8E|支持的浏览器]] \\ | ||
+ | 2.本地安装 node 环境 >= 6.3.0 \\ 3.必须为https+webkit内核浏览器** | ||
+ | ===== 运行 Demo ===== | ||
+ | 1. 下载下Demo \\ | ||
+ | 2. 进入 videocall-web 文件夹\\ | ||
+ | 3. 安装依赖包 | ||
+ | <code javascript> | ||
+ | npm install | ||
+ | </code> | ||
+ | 4. 启动项目 | ||
+ | <code javascript> | ||
+ | HTTPS=true npm start | ||
+ | </code> | ||
- | ---- | ||
- | ===== 产品特性 ===== | + | ====== 快速集成 ====== |
+ | ===== 1. 环信后台注册 appkey ===== | ||
+ | 在开始集成前,你需要注册环信开发者账号并创建后台应用,参见[[http://docs-im.easemob.com/im/ios/sdk/prepare#注册并创建应用|注册并创建应用]] | ||
+ | ===== 2. 创建项目 ===== | ||
+ | a.可以简单的写一个 html,引入 SDK 测试 | ||
+ | b.或者使用 脚手架搭建一个项目 | ||
+ | ===== 3.引入 SDK ===== | ||
- | *支持现代浏览器:Chrome/50+、Safari/11+、Firefox; | + | === 3.1通过 scrpit 标签的 src 引入 === |
- | + | [[http://docs-im.easemob.com/rtc/conference/web#%E8%8E%B7%E5%8F%96sdk%E9%9D%99%E6%80%81%E8%B5%84%E6%BA%90%E6%96%87%E4%BB%B6|获取静态SDK 文件]] | |
- | *遵守:UMD通用模块规范,支持require导入; | + | |
- | + | ||
- | *支持Promise; | + | |
- | + | ||
- | *支持手机端和 Web 端互通,极大方便开发者的全平台业务; | + | |
- | + | ||
- | *依赖https站点 | + | |
- | + | ||
- | ===== 音视频通信的简要步骤 ===== | + | |
- | + | ||
- | SDK 能够支持音频和视频通信。创建和操作音视频通信的过程简单来说,可以分为以下几步: | + | |
- | + | ||
- | - 初始化 SDK,设置监听代理 | + | |
- | - create: 创建会议 | + | |
- | - join: 加入会议 | + | |
- | - pub: 发布音视频数据流 | + | |
- | - sub: 订阅并播放音视频数据流 | + | |
- | - leave: 离开会议 | + | |
- | ===== 基本知识 ===== | + | |
- | + | ||
- | emedia.mgr.ConfrType:多人会议类型 | + | |
- | + | ||
- | 1. Communication:普通通信会议,最多支持参会者9人,成员都可以自由说话和发布视频,成员角色Speaker | + | |
- | 2. Large Communication:大型通信会议,最多参会者30人,成员都可以自由说话和发布视频,成员角色Speaker | + | |
- | 3. Live:互动视频会议,会议里支持最多9个主播和600个观众 | + | |
<code javascript> | <code javascript> | ||
- | emedia.mgr.ConfrType = { | + | <script src="EMedia_sdk-dev.js"></script> |
- | COMMUNICATION: 10, //普通会议模式 | + | |
- | COMMUNICATION_MIX: 11, //大会议模式 | + | |
- | LIVE: 12, //直播模式 | + | |
- | }; | + | |
</code> | </code> | ||
+ | ===3.2使用 npm 获取 SDK=== | ||
<code javascript> | <code javascript> | ||
- | emedia.mgr.Role = { | + | npm install easemob-emedia |
- | ADMIN: 7, // 能创建会议,销毁会议,移除会议成员,切换其他成员的角色,订阅流,发布流 | + | |
- | TALKER: 3, // 能上传自己的音视频,能观看收听其他主播的音视频,即能发布流和订阅流) | + | |
- | AUDIENCE: 1 // 观众Audience:只能观看收听音视频,即只能订阅流 | + | |
- | }; | + | |
</code> | </code> | ||
+ | ===3.3 在文件内引入 SDK=== | ||
<code javascript> | <code javascript> | ||
- | emedia.mgr.StreamType = { | + | import emedia from 'easemob-emedia'; |
- | VIDEO:0,//普通视频 | + | |
- | DESKTOP:1,//共享桌面 | + | |
- | MIXVIDEO:2 //混音视频 | + | |
- | }; | + | |
</code> | </code> | ||
+ | === 3.4 获取SDK静态资源文件 === | ||
+ | ** 1. 首先 [[https://www.easemob.com/download/rtc|下载 WebIM Demo 包]] ** | ||
+ | {{ :rtc:conference:wechatimg129.png?600 |}} | ||
+ | ** 2. 从Demo 中选取 SDK 文件(EMedia_sdk-dev.js) ** | ||
+ | {{ :rtc:conference:wechatimg130.png?300 |}} | ||
+ | ===== 4.初始化SDK ===== | ||
+ | |||
<code javascript> | <code javascript> | ||
- | //conference|confr | + | emedia.config({ |
- | { | + | appkey, // 从环信后台 获取的appkey、必填 |
- | confrId:"TS_X296786295944036352C27", | + | consoleLogger: true, // boolean 是否开启打印日志,默认true |
- | id:"TS_X296786295944036352C27", | + | ... 其他的一些配置 |
- | password: "password123", | + | }); |
- | roleToken:"roleToken", | + | |
- | ticket:"ticket", | + | |
- | type:12 | + | |
- | }; | + | |
</code> | </code> | ||
+ | ===== 5. 环信ID注册、登录 ===== | ||
+ | 在进行音视频通话前,需要首先登录IM账户,登录过程参见[[http://docs-im.easemob.com/im/web/intro/basic#登录|账号登录]]。 | ||
+ | |||
+ | 若您还没有IM账户,需要先注册账户,注册过程参见[[http://docs-im.easemob.com/im/web/intro/basic#注册|账号注册]] | ||
+ | |||
+ | |||
+ | ===== 6.进入会议 ===== | ||
+ | ** 注意:加入会议之前必须先要 调用 emedia.mgr.setIdentity 方法设置 emedia 对象的memName 、token ** | ||
<code javascript> | <code javascript> | ||
- | //member | + | emedia.mgr.setIdentity(memName, token); //memName:appkey +'_'+ 环信ID, token: 环信ID登录后返回的access_token |
- | { | + | |
- | "ext":{ //emedia.mgr.joinConference(confrId, password, {role: 'admin'})/* 用户可自定义扩展字段*/); | + | |
- | "role":"admin" | + | |
- | }, | + | |
- | "id":"MS_X197721744293023744C19M197756407719972865VISITOR", | + | |
- | "globalName":"easemob-demo#chatdemoui_yss000@easemob.com", | + | |
- | "name": "yss000", | + | |
- | "nickName": "yss000" //设置后会生效,不设置默认取name的值 | + | |
- | } | + | |
</code> | </code> | ||
+ | ** params 为进入会议需要的参数 ** | ||
<code javascript> | <code javascript> | ||
- | //stream | + | var params = { |
- | { | + | roomName, // string 房间名称 必需 |
- | "id":"RTC2__Of_C19M197756407719972865VISITOR", | + | password, // string 房间密码 必需 |
- | "voff":0, //1 视频关闭 | + | role // number 进入会议的角色 1: 观众 3:主播 必需 |
- | "aoff":0, //1 音频关闭 | + | config:{ |
- | "memId":"MS_X197721744293023744C19M197756407719972865VISITOR", | + | rec:false, //是否开启录制会议 |
- | "owner": member ,//member对象 | + | recMerge:false, //是否开启合并录制 |
- | "rtcId":"RTC1" | + | supportWechatMiniProgram: true //是否允许小程序加入会议 |
+ | } | ||
} | } | ||
- | var islocated = stream.located(); //islocated true 本地媒体流 | ||
</code> | </code> | ||
- | + | 调用 ** emedia.mgr.joinRoom ** 进入会议, 若该会议不存在,服务器将会自动创建 | |
- | 注意: | + | |
- | >> 每个人必须调用join接口成功后,才算是加入会议(即成为会议成员)。会议成员才允许进行其他操作比如订阅流、发布流等 | + | |
- | >> 成员如果想改变自己角色,必须想办法通知管理员,只有管理员才能修改 | + | |
- | ===== 多人音视频会议功能实现 ===== | + | <code javascript> |
+ | const user_room = await emedia.mgr.joinRoom(params); | ||
+ | </code> | ||
- | 以下是从创建会议到离开会议完整的流程讲解: | + | 返回的参数 ** user_room **,组成如下 |
+ | <code javascript> | ||
+ | user_room: { | ||
+ | confrId: "IM3U9Z0AHDYQTF8KNDAAD00C147" 会议ID | ||
+ | id: "IM3U9Z0AHDYQTF8KNDAAD00C147" | ||
+ | joinId: "IM3U9Z0AHDYQTF8KNDAAD00C147M2" 在会议中的唯一ID | ||
+ | role: 1|3|7 //角色 1观众 3主播 7管理员 | ||
+ | roleToken:"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJlYXNlbW9iLWRlbW8j..." | ||
+ | ticket: "{\"tktId\":\"IM3U9Z0AHDYQTF8KNDAAD00C147TK1\",..." | ||
+ | type: 10 //会议类型 | ||
+ | } | ||
+ | </code> | ||
- | ==== 引入SDK ==== | + | ===== 7.发布本地流 ===== |
+ | 加入会议之后 调用 ** emedia.publish ** 发布流 | ||
<code javascript> | <code javascript> | ||
- | // 可以使用easemob-webrtc 或者 easemob-emedia | + | var constaints = { // 发布音频流的配置参数, Object 必需。 video或audio属性 至少存在一个 |
- | // 使用easemob-webrtc | + | audio: true, // 是否发布音频 |
- | import webrtc from 'easemob-webrtc' | + | video: true // 是否发布视频 |
- | const emedia = webrtc.emedia | + | } |
+ | var ext = {} // 发布流的扩展信息 Object 非必需。会议其他成员可接收到 | ||
- | // 使用easemob-emedia | + | const pushedStream = await emedia.mgr.publish(constaints, ext); |
- | import emedia from 'easemob-emedia' | + | |
</code> | </code> | ||
- | ==== 初始化SDK ==== | + | |
+ | 发布本地流成功后, 调用 emedia.mgr.streamBindVideo 用于在video标签显示流 | ||
<code javascript> | <code javascript> | ||
- | // 初始化一些 sdk 的使用功能 | + | var videoTag = document.getElementById('#xxx') //需要显示本地流的 video 标签 |
- | emedia.config({ | + | emedia.mgr.streamBindVideo(pushedStream, videoTag); |
- | restPrefix, //配置服务器域名、必填 比如: 'https://a1-hsb.easemob.com' | + | |
- | appkey, // 配置appkey、必填 | + | |
- | ... 其他的一些配置 | + | |
- | }); | + | |
</code> | </code> | ||
- | ==== 设置SDK回调 ==== | + | ===== 8.订阅远端流 ===== |
- | 进入会议之前,设置SDK回调后,可获知成员加入或离开会议,数据流更新等。 | + | 当远端流加入频道时,会触发 emedia.mgr.onStreamAdded 方法,我们需要给 emedia.mgr 赋值 onStreamAdded 用来接收 stream \\ |
+ | ** 我们建议项目初始化后,立即设置[[http://docs-im.easemob.com/rtc/conference/web#%E4%BC%9A%E8%AE%AE%E5%B8%B8%E7%94%A8%E7%9B%91%E5%90%AC%E5%87%BD%E6%95%B0|常用监听函数]] ** | ||
+ | === 8.1 监听 onStreamAdded 方法, 当有远端流加入时订阅流 === | ||
+ | ** 注意: \\ | ||
+ | 自己发布的本地流也会触发 onStreamAdded 方法, \\ | ||
+ | stream.located() == true 为自己发的本地流, \\ | ||
+ | 也可以在 这里绑定 video标签,显示本地流 \\ ** | ||
<code javascript> | <code javascript> | ||
- | //有人加入会议,其他人调用joinXX等方法,如果加入成功,已经在会议中的人将会收到 | + | emedia.mgr.onStreamAdded = function(member, stream) { |
- | emedia.mgr.onMemberJoined = function (member) { | + | // member:发布流人员的信息、stream:流信息 |
- | + | if(!stream.located()) { | |
- | }; | + | var option = { |
+ | member: member, | ||
+ | stream: stream, | ||
+ | subVideo: true, | ||
+ | subAudio: true, | ||
+ | videoTag: document.getElementById('#xxx') | ||
+ | } | ||
+ | emedia.mgr.subscribe(option.member, option.stream, option.subVideo, option.subAudio, option.videoTag) | ||
+ | } | ||
+ | } | ||
</code> | </code> | ||
+ | |||
+ | ** 在emedia.mgr.subscribe 方法中注意以下参数的设置 ** | ||
+ | * option.member:发布流人员的信息,必需。也就是 onStreamAdded 方法的 member | ||
+ | * option.stream:流信息,必需。也就是 onStreamAdded 方法的 stream | ||
+ | * option.subVideo: 是否订阅视频,必需 | ||
+ | * option.subAudio: 是否订阅音频,必需 | ||
+ | * option.videotag: 需要显示流的 video 标签,必需 | ||
+ | |||
+ | === 8.2 监听 onStreamRemoved 方法,当远端流被移除时(例如远端用户调用了 Stream.unpublish), 停止订阅该流并移除它的画面。=== | ||
<code javascript> | <code javascript> | ||
- | //有人退出会议 | + | emedia.mgr.onStreamRemoved = function(member, stream) { |
- | emedia.mgr.onMemberExited = function (member) { | + | // member:发布流人员的信息、stream:流信息 |
- | + | emedia.mgr.unsubscribe(stream) // 停止订阅流 | |
- | }; | + | removeView(stream.id) // 移除video标签,removeView方法需自己实现 |
+ | } | ||
</code> | </code> | ||
+ | |||
+ | ===== 9.退出会议 ===== | ||
+ | 调用 emedia.mgr.exitConference 方法退出会议 | ||
<code javascript> | <code javascript> | ||
- | //有媒体流添加;比如 自己调用了publish方法(stream.located() === true时),或其他人调用了publish方法。 | + | emedia.mgr.exitConference() //无参数 |
- | emedia.mgr.onStreamAdded = function (member, stream) { | + | |
- | + | ||
- | }; | + | |
</code> | </code> | ||
- | <code objc> | ||
- | //有媒体流移除 | ||
- | emedia.mgr.onStreamRemoved = function (member, stream) { | ||
- | }; | + | ===== 10.会议常用监听函数 ===== |
- | </code> | + | ** ''强烈建议:''在加入会议之前定义需要的 SDK 回调函数 ** |
<code javascript> | <code javascript> | ||
- | //角色改变 | + | //有人加入会议 |
- | emedia.mgr.onRoleChanged = function (role) { | + | emedia.mgr.onMemberJoined = function (member) { } // member: 加入会议成员信息 |
+ | |||
+ | //有人退出会议 | ||
+ | emedia.mgr.onMemberExited = function (member) {} // member: 退出会议成员信息 | ||
+ | |||
+ | //有媒体流添加 (自己发布的流也会触发 stream.located() == true ) | ||
+ | emedia.mgr.onStreamAdded = function (member, stream) { }; // member: 发布流的成员信息,stream:流信息 | ||
+ | |||
+ | //有媒体流移除 | ||
+ | emedia.mgr.onStreamRemoved = function (member, stream) { } // member: 移除流的成员信息,stream:流信息 | ||
+ | |||
+ | //自己角色变更 | ||
+ | emedia.mgr.onRoleChanged = role => {} // role: 变更后的角色 | ||
- | }; | ||
- | </code> | ||
- | <code javascript> | ||
//会议退出;自己主动退 或 服务端主动关闭; | //会议退出;自己主动退 或 服务端主动关闭; | ||
emedia.mgr.onConferenceExit = function (reason, failed) { | emedia.mgr.onConferenceExit = function (reason, failed) { | ||
行 204: | 行 235: | ||
<code javascript> | <code javascript> | ||
//管理员变更 | //管理员变更 | ||
- | emedia.mger.onAdminChanged = admin => {} //admin 管理员信息 | + | emedia.mgr.onAdminChanged = admin => {} //admin 管理员信息 |
+ | |||
+ | //监听弱网状态 | ||
+ | emedia.mgr.onNetworkWeak = streamId => {} //streamId 会议中的流 ID | ||
+ | |||
+ | //监听断网状态 | ||
+ | emedia.mgr.onNetworkDisconnect = streamId => {} //streamId 会议中的流 ID | ||
</code> | </code> | ||
- | ==== 用户A创建会议 ==== | ||
+ | |||
+ | ====== 进阶功能 ====== | ||
+ | ===== 会议管理 ===== | ||
+ | ==== 1.创建会议并加入 ==== | ||
+ | 这里的创建会议 不同于快速集成中的加入会议,这里的是属于另一套逻辑,建议使用快速集成中的加入会议 \\ | ||
+ | |||
+ | ** 注意: 如果只单纯的创建,没进行操作,则创建者不是会议的成员,没有相应的角色,不能进行其他操作 ** \\ | ||
+ | |||
+ | 1.1 调用 emedia.mgr.createConference 方法创建会议 | ||
<code javascript> | <code javascript> | ||
- | // confrType: 会议类型;password: 会议密码;rec:是否录制;recMerge:是否合并录制;supportWechatMiniProgram:会议是否支持微信小程序 | ||
- | emedia.mgr.createConference(confrType, password, rec, recMerge, supportWechatMiniProgram).then(function(confr){ | ||
- | console.log(confr.confrId); | ||
- | }).catch(function(error){ | ||
- | }) | ||
- | // 支持对象形式的参数 | ||
let params = { | let params = { | ||
confrType, | confrType, | ||
行 220: | 行 260: | ||
rec, | rec, | ||
recMerge, | recMerge, | ||
- | supportWechatMiniProgram, | + | supportWechatMiniProgram |
- | maxTalkerCount:2,//会议最大主播人数 | + | ... 其他参数 |
- | maxVideoCount:1, //会议最大视频数 | + | |
- | maxPubDesktopCount:1, //会议最大共享桌面数 | + | |
- | maxAudienceCount:100 //会议最大观众数 | + | |
} | } | ||
- | const confr = await emedia.mgr.createConference(params) | + | const confr = await emedia.mgr.createConference(params); |
</code> | </code> | ||
- | + | 在 emedia.mgr.createConference 方法中,注意以下参数的设置: | |
- | 注意: 如果A只单纯的create,没进行join操作,则A不是Conference的成员,没有相应的角色,不能进行其他操作 | + | * confrType 会议类型 10:普通会议模式、11:大会议模式、12:直播模式。number 必需 |
- | + | * password 会议密码 string 必需 | |
- | ==== 用户A进入会议 ==== | + | * rec 是否开启通话录制 boolean 非必需 |
+ | * recMerge 是否开启通话录制合并 boolean 非必需 | ||
+ | * supportWechatMiniProgram 会议是否支持小程序端 boolean 非必需, 默认不支持 | ||
+ | |||
+ | 创建会议成功后,返回的参数 confr 结构如下: | ||
<code javascript> | <code javascript> | ||
- | emedia.mgr.joinConferenceWithTicket(confrId, ticket, ext).then(function(confr){ | + | confr:{ |
+ | error: 0, | ||
+ | confrId: "LBJ13H9WJJEVJTGL1U1PIQ00C2", // 会议id | ||
+ | password: "xxxx", // 创建会议时设置的密码 | ||
+ | role: 7, // 在会议中的角色 这里因为是创建者,所以是 7: 管理员 | ||
+ | roleToken:"eyJ0eXAiOiJKV1QiLCJhbG *** f1gg_QJWxhs-jqmuFok", //创建者的token | ||
+ | type: 10 // 会议类型 | ||
+ | } | ||
+ | </code> | ||
- | }).catch(function(error){ | ||
- | }) | + | 1.2 调用 emedia.mgr.joinUsePassword 方法加入会议 |
+ | <code javascript> | ||
+ | const join_result = await this.emedia.joinUsePassword(confrId, password) // 参数为 创建会议成功后返回的 confrId和password | ||
+ | </code> | ||
+ | 加入会议成功后返回的结果,结构如下: | ||
+ | <code javascript> | ||
+ | join_result: { | ||
+ | confrId: "LBJ13H9WJJEVJTGL1U1PIQ00C7", // 会议id | ||
+ | joinId: "LBJ13H9WJJEVJTGL1U1PIQ00C7M9", //创建会议时设置的密码 | ||
+ | password: "0.010568535799199363", // 会议成员在会议中的身份id(唯一) | ||
+ | role, // 在会议中的角色 创建者加入会议永远是 7: 管理员,其他人加入返回的是 3: 主播 | ||
+ | roleToken: "eyJ0eXAiOiJK *** FaXuMVlqPOTofRRdE", // 加入会议者的token | ||
+ | type: 10 // 会议类型 | ||
+ | } | ||
</code> | </code> | ||
+ | ==== 2.开启录制、录制合并 ==== | ||
+ | 2.1 调用 emedia.mgr.createConference 创建会议时配置 | ||
+ | <code javascript> | ||
+ | let params = { | ||
+ | ... | ||
+ | rec: true, | ||
+ | recMerge: true, | ||
+ | ... 其他参数 | ||
+ | } | ||
- | 用户也可以使用下列接口加入房间。可以指定房间的名称,并且在房间不存在时会自动创建。 另外可以在加入会议时指定角色。 | + | const confr = await emedia.mgr.createConference(params); |
+ | </code> | ||
+ | 2.2 调用 emedia.mgr.joinRoom 加入会议时配置\\ | ||
+ | 注意:只有第一个加入会议的人,配置的才有效\\ | ||
+ | 参数需要放到 config 对象中 | ||
<code javascript> | <code javascript> | ||
- | /** | + | let params = { |
- | * 创建房间并加入 | + | ... 其他参数 |
- | * @method joinRoom | + | config: { |
- | * @param {Object} option | + | rec: true, |
- | * @param {string} option.roomName - 房间名称 | + | recMerge: true |
- | * @param {string} option.password - 房间密码 | + | } |
- | * @param {string} option.role - 进入房间时的角色 | + | } |
- | * @param {object} option.config - 扩展能力 可设置以下参数 | + | |
- | * config:{ | + | |
- | nickName,//进入会议的昵称 | + | |
- | ext: {}, //扩展字段 用于自定义 | + | |
- | rec: true, // 开启录制 | + | |
- | recMerge: true, //开启录制合并 | + | |
- | supportWechatMiniProgram: true, //是否支持微信小程序 | + | |
- | maxTalkerCount:3 //自定义会议最大主播人数 | + | |
- | maxVideoCount:2 //自定义会议最大视频数 | + | |
- | maxAudienceCount:100 //自定义会议最大观众数 | + | |
- | maxPubDesktopCount: 1 //自定义会议共享屏幕最大数 | + | |
- | } | + | const confr = await emedia.mgr.createConference(params); |
- | */ | + | </code> |
+ | rec: 是否开启录制,默认 false\\ | ||
+ | recMerge: 是否开启录制合并,默认false | ||
+ | ==== 3.邀请成员加入会议 ==== | ||
+ | SDK 不提供邀请接口。邀请的形式,完全可以由用户自行定义,可以是条文本消息,也可以是个控制消息等等。SDK 不做限制。实现方式可以参考官方 demo,通过群组消息邀请,具体代码 可查询 demo/src/components/webrtc/AddAVMemberModal.js 中的 70-89 行。 | ||
+ | 3.1 成员收到邀请加入会议 \\ | ||
- | try { | + | 解析出邀请消息中带的 confrId 和 password ,调用 ** emedia.mgr.joinUsePassword ** 加入会议 |
- | const user_room = await emedia.mgr.joinRoom(option); | + | |
- | + | ==== 4.管理员销毁会议 ==== | |
- | user_room: | + | 调用 emedia.mgr.destroyConference 方法, ** 注意:只有管理员有权限,其他角色调用不生效 ** |
- | { | + | <code javascript> |
- | confrId: "IM3U9Z0AHDYQTF8KNDAAD00C147" 会议ID | + | await emedia.mgr.destroyConference(confrId); //confrId: 会议Id |
- | id: "IM3U9Z0AHDYQTF8KNDAAD00C147" | + | |
- | joinId: "IM3U9Z0AHDYQTF8KNDAAD00C147M2" 在会议中的唯一ID | + | |
- | mixed: false | + | |
- | role: 7 //角色 | + | |
- | roleToken:"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJlYXNlbW9iLWRlbW8j..." | + | |
- | ticket: "{\"tktId\":\"IM3U9Z0AHDYQTF8KNDAAD00C147TK1\",..." | + | |
- | type: 10 //会议类型 | + | |
- | } | + | |
- | + | ||
- | } catch (error) { | + | |
- | + | ||
- | } | + | |
</code> | </code> | ||
- | ==== 管理员A邀请其他人加入会议 ==== | + | 其他人会收到会议结束的回调 |
+ | <code javascript> | ||
+ | emedia.mgr.onConferenceExit = reason => {} // reason:退出会议的原因,因为会议被销毁了,所以这里应为 11: "会议关闭" | ||
+ | </code> | ||
+ | |||
- | SDK 不提供邀请接口。邀请的形式,完全可以由用户自行定义,可以是条文本消息,也可以是个控制消息等等。SDK 不做限制。实现方式可以参考官方 demo,通过群组消息邀请,具体代码 可查询 demo/src/components/webrtc/AddAVMemberModal.js 中的 70-89 行。 | + | ==== 5.设置会议人数限制 ==== |
- | ==== 用户B接收到邀请加入会议 ==== | + | 5.1 在 emedia.mgr.joinRoom 方法中设置 |
+ | ** 只有第一个加入房间的人员(也就是管理员),设置的才能生效 ** | ||
+ | <code javascript> | ||
+ | var params = { | ||
+ | ... 其他参数, | ||
+ | config:{ // 在 config 中指定字段 | ||
+ | maxTalkerCount:3, | ||
+ | maxAudienceCount:100, | ||
+ | maxVideoCount:2, | ||
+ | maxPubDesktopCount: 1 | ||
+ | } | ||
+ | } | ||
+ | const user_room = await emedia.mgr.joinRoom(params); | ||
+ | </code> | ||
+ | 5.2 在 emedia.mgr.createConference(创建会议) 方法中设置 | ||
+ | <code javascript> | ||
+ | var params = { | ||
+ | ... 其他参数, | ||
+ | maxTalkerCount:3 | ||
+ | maxVideoCount:2 | ||
+ | maxAudienceCount:100 | ||
+ | maxPubDesktopCount: 1 | ||
- | 用户B解析出邀请消息中带的 confrId 和 password ,调用 SDK 的 join 接口加入会议,成为会议成员且角色是 Speaker. | + | } |
+ | const confr = await emedia.mgr.createConference(params); | ||
+ | </code> | ||
+ | 以上设置会议参数的注意事项如下: | ||
+ | * maxTalkerCount:自定义会议最大主播人数,默认 100, | ||
+ | * maxAudienceCount:自定义会议最大观众数 默认 600 | ||
+ | * maxVideoCount:自定义会议最大视频数, 默认 9 | ||
+ | * maxPubDesktopCount: 自定义会议共享屏幕最大数 默认 2 | ||
+ | ==== 6.设置会议昵称 ==== | ||
+ | 在 emedia.mgr.joinRoom 方法中设置 | ||
<code javascript> | <code javascript> | ||
- | //javascript | + | var params = { |
- | emedia.mgr.joinConference(confr, password, ext).then(function(confr){ | + | ... 其他参数, |
+ | config:{ | ||
+ | ... 其他参数, | ||
+ | nickName: xxx, // string | ||
+ | } | ||
+ | } | ||
+ | const user_room = await emedia.mgr.joinRoom(params); | ||
+ | </code> | ||
- | }).catch(function(error){ | + | ==== 7. 获取会议信息 ==== |
- | + | 调用 ** emedia.mgr.selectConfr ** 方法获取会议信息 | |
- | }) | + | <code javascript> |
+ | const confr_info = await emedia.mgr.selectConfr(confrId, password); // confrId:会议id、password:会议密码 | ||
+ | // 返回的参数 confr_info 结构如下: | ||
+ | confr_info: { | ||
+ | confr: { | ||
+ | id: "LBJ13H05522QATGIJKXUF800C45639", // 会议id | ||
+ | type: 10, // 会议类型 | ||
+ | memTotal: 1, // 会议中总人数 主播和观众 | ||
+ | audienceTotal: 0, // 观众人数 | ||
+ | talkers: ["018ae39 *** 663282d7495"] // 主播的memName集合 | ||
+ | } | ||
+ | error: 0 | ||
+ | } | ||
</code> | </code> | ||
+ | ==== 8.CDN合流推流 ==== | ||
+ | CDN推流是指将会议画面,合并到一张画布推送到远程CDN,其他人可以从CDN拉流而不用加入会议 | ||
+ | == 8.1 开启CDN推流 == | ||
+ | **CDN推流参数 liveCfg为必需 结构如下:** | ||
+ | <code javascript> | ||
+ | let liveCfg = { | ||
+ | cdn:'', //推流地址、字符串;必需 | ||
+ | layoutStyle: 'GRID' | 'CUSTOM', // 格子显示 | 自定义,必需 | ||
+ | canvas :{// canvas 参数在 layoutStyle == 'CUSTOM' 必填 | ||
+ | bgclr : 0x980000,//背景色 980000 为 十六进制色值 | ||
+ | w : 640, //宽度 | ||
+ | h : 480, //高度 | ||
+ | fps: 20, //输出帧率 | ||
+ | bps: 1200000, //输出码率 | ||
+ | codec: "H264" //视频编码,现在必须是H264 | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
- | 用户B成功加入会议后,会议中其他成员会收到回调 [emedia.mgr.onMemberJoined(memberB)] | ||
- | ==== 成员A发布音视频流 ==== | + | **1.创建会议时指定 CDN推流** |
+ | <code javascript> | ||
+ | let option = { | ||
+ | ... | ||
+ | liveCfg // 创建CDN推流参数 | ||
+ | } | ||
+ | emedia.mgr.createConference(option) | ||
+ | </code> | ||
- | 成员A和成员B都有发布流的权限 | + | **2.加入房间时 指定CDN推流** |
+ | <code javascript> | ||
+ | // 只有第一个加入房间的人才能创建 CDN、以后加入的人指定CDN也无效 | ||
+ | let params = { | ||
+ | config:{ | ||
+ | ... | ||
+ | liveCfg // 创建CDN推流参数 | ||
+ | } | ||
+ | } | ||
+ | emedia.mgr.joinRoom(params); | ||
+ | </code> | ||
+ | == 8.2 多路推流 == | ||
+ | 通过 ** emedia.mgr.addLive ** 方法指定一路推流CDN,需要几路CDN,就调用几次方法 \\ | ||
+ | ** 注意:只有管理员,可创建 CDN ** | ||
<code javascript> | <code javascript> | ||
- | /** | + | // confrId: 会议id, 必需 |
- | * constaints: {audio: true, video: true} | + | // liveCfg: cdn 配置,必需 |
- | * videoTag 可缺失,如果有 此次publish的媒体数据将会在这个video上显示 将会与stream绑定 | + | media.mgr.addLive(confrId, liveCfg); |
- | * ext 用户自定义扩展,其他成员可以看到这个字段 | + | </code> |
- | * | + | |
- | */ | + | |
- | emedia.mgr.publish(constaints, videoTag, ext).then(function(pushedStream){ | + | |
- | //stream 对象 | + | |
- | }).catch(function(error){ | + | |
- | }); | + | == 8.3 更新CDN布局 == |
+ | <code javascript> | ||
+ | // 只有管理员才能 更新布局。更新布局会 将layoutStyle 变为 CUSTOM 而且不可逆 | ||
+ | emedia.mgr.updateLiveLayout(confrId, liveId, regions) | ||
- | /** | + | // confrId 会议id 必需 |
- | * videoTag 可缺失时 | + | // liveId 推流CDN id, 必需 可通过 emedia.config.liveCfgs 获取 Array |
- | * | + | |
- | */ | + | |
- | emedia.mgr.publish(constaints, ext).then(function(pushedStream){ | + | |
- | //stream 对象 | + | |
- | //如果需要将这个stream对象 显示,需要 emedia.mgr.streamBindVideo(videoTag, pushedStream) | + | |
- | }).catch(function(error){ | + | |
- | }); | + | regions:[ // 希望定义视频流 显示的配置集合 |
+ | { | ||
+ | "sid": stream_id,//视频流的id | ||
+ | "x": 320,//距离 x 轴的距离 Number | ||
+ | "y": 240,//距离 y 轴的距离 Number | ||
+ | "w": 960,//宽度 Number | ||
+ | "h": 720,//高度 Number | ||
+ | "style": "fill" | "AspectFit" //视频显示模式 fill:铺满、AspectFit:原比例显示 | ||
+ | }, | ||
+ | .... 其他视频流配置(数组有几个项,就显示几个视频流) | ||
+ | ] | ||
</code> | </code> | ||
- | *** 注意:A推流成功后,onStreamAdded 将被回调 *** | ||
- | ==== 其他成员收到通知并订阅流 ==== | ||
- | 成员A成功发布数据流后,会议中其他成员会收到监听类回调[emedia.mgr.onStreamAdded],如果成员B想看成员A的音视频,可以调用subscribe接口进行订阅 | + | == 8.4 删除CDN == |
+ | <code javascript> | ||
+ | // 只有管理员可操作 | ||
+ | //confrId 会议id 必需 | ||
+ | // liveId 推流CDN id, 必需 可通过 emedia.config.liveCfgs 获取 Array | ||
+ | emedia.mgr.deleteLive(confrId, liveId) | ||
+ | </code> | ||
+ | === 9.海外代理 === | ||
+ | ** 开启集群部署,SDK内部会自动请求代理,实现通话最优 ** \\ | ||
+ | 调用 emedia.config 方法开启 | ||
+ | <code javascript> | ||
+ | emedia.config({ | ||
+ | ... | ||
+ | useDeployMore: true // 默认:false 不开启 | ||
+ | rtcConfigUrl: 'yourConfigUrl' // 自定义config文件路径, 默认有一个路径 | ||
+ | ... | ||
+ | }) | ||
+ | </code> | ||
+ | ==== 10. 取日志 ==== | ||
+ | 在浏览器控制台,输入 ** emedia.fileReport **,敲下回车键会下载下一份日志文件 | ||
<code javascript> | <code javascript> | ||
- | //其他成员 | + | emedia.fileReport() //无参数 |
- | emedia.mgr.onStreamAdded = function (member, stream) { | + | |
- | if(!stream.located()){ //stream.located() === true, 自己发送的数据流 | + | |
- | emedia.mgr.subscribe(member, stream, true, true, video) | + | |
- | } | + | |
- | }; | + | |
</code> | </code> | ||
+ | ==== 11. 会议属性 ==== | ||
+ | <code javascript> | ||
+ | // 用来自定义一些属性,广播给会议中的成员 | ||
+ | // 有人设置会议属性,所有的成员都能收到 | ||
+ | let options = { | ||
+ | key:username, | ||
+ | val:'request_tobe_speaker' | ||
+ | } | ||
+ | // a. 设置会议属性 | ||
+ | emedia.mgr.setConferenceAttrs(options) | ||
+ | // b. 删除会议属性 | ||
+ | emedia.mgr.deleteConferenceAttrs(options) | ||
+ | // c. 会议属性变更回调 | ||
+ | emedia.mgr.onConfrAttrsUpdated = attrs => {} //attrs 会议属性集合 Array | ||
+ | </code> | ||
- | ==== 成员B取消订阅流 ==== | + | ==== 12.海外代理 ==== |
+ | 1v1通话支持不同集群区域的人员通话使用代理,减小延迟; | ||
+ | 使用多集群代理需要音视频后台配置IP及端口的映射文件rtcconfig.json,并禁用相关appkey的直连, | ||
+ | 也可以指定 rtcconfig.json 的私有化部署 | ||
+ | 调用 ** emedia.config 方法开启海外代理 ** | ||
+ | <code javascript> | ||
+ | emedia.config({ | ||
+ | ... | ||
+ | useDeployMore: true, // 默认:false 不开启 | ||
+ | rtcConfigUrl: 'your rtcConfigUrl' // 如果不设置,将使用 sdk 后台配置的代理文件 | ||
+ | }) | ||
+ | </code> | ||
- | 成员B如果不想再看成员A的音视频,可以调用SDK接口unsubscribe | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | ===== 音视频管理 ===== | ||
+ | ==== 1.设置通话参数 ==== | ||
+ | 发布本地媒体流时,可指定音视频的码率和分辨率,非必需。** 共享桌面不可指定 ** | ||
<code javascript> | <code javascript> | ||
- | //emedia.mgr.hungup(stream); | + | var constaints = { |
- | emedia.mgr.unsubscribe(stream); | + | audio: {bitrate: 100},// 指定音频码率 |
+ | video: { | ||
+ | width: { // 指定视频分辨率宽度 | ||
+ | exact: 1280 | ||
+ | }, | ||
+ | height: { // 指定视频分辨率高度 | ||
+ | exact: 720 | ||
+ | }, | ||
+ | bitrate: 200,// 指定视频码率 | ||
+ | } | ||
+ | } | ||
+ | emedia.mgr.publish(constaints) | ||
</code> | </code> | ||
- | ==== 成员A取消发布流 ==== | + | ==== 2. 指定设备打开音视频 ==== |
+ | <code javascript> | ||
+ | const devices = await emedia.mgr.mediaDevices(); //获取设备列表 | ||
- | 成员A可以调用unpublish接口取消自己已经发布的数据流,操作成功后,会议中收到回调[emedia.mgr.onStreamRemoved:removeStream:] ,将对应的数据流信息移除 | + | // 设备信息 |
+ | device: Object { | ||
+ | deviceId: "529a6fe76467d****9498ab22f5f362cd" // 设备ID | ||
+ | groupId: "2b74c9b9ab99*****d513fbabc1e86b3c5d99f7f8a0c16" | ||
+ | kind: "audioinput" | audiooutput | videoinput | videooutput // 设备类型 | ||
+ | label: "Internal Microphone (Built-in)" | ||
+ | } | ||
+ | constraints: { // 选择设备, 然后指定设备(只需要传入设备信息中的deviceId属性,为String类型,其他的属性在推流时暂时用不到) | ||
+ | audio: {deviceId: deviceId ? {exact: deviceId} : undefined}, //判断如果deviceId存在那么就传入对象。 | ||
+ | video: {deviceId: deviceId ? {exact: deviceId} : undefined} | ||
+ | }, | ||
+ | |||
+ | const stream = await emedia.mgr.publish(constraints) // 推流 | ||
+ | </code> | ||
+ | ==== 3. 停止发布流 ==== | ||
+ | 调用 ** emedia.mgr.unpublish ** 方法停止自己已经发布的流 | ||
<code javascript> | <code javascript> | ||
- | //emedia.mgr.hungup(pushedStream); | + | emedia.mgr.unpublish(pushedStream); // pushedStream:自己发布的流 |
- | emedia.mgr.unpublish(pushedStream); | + | |
</code> | </code> | ||
+ | 会议中人员(包括自己)会收到 流被移除的回调函数 ** emedia.mgr.onStreamRemoved ** | ||
<code javascript> | <code javascript> | ||
emedia.mgr.onStreamRemoved = function (member, stream) { | emedia.mgr.onStreamRemoved = function (member, stream) { | ||
- | if(stream.located(){ //自己发布流 | + | // member: 停止发布流人员信息 |
- | }else{ //会议其他人发布的流 | + | // stream:流的信息,stream.located() == true 代表是自己的流,false则为其他人的流 |
- | } | + | |
}; | }; | ||
</code> | </code> | ||
- | ==== 成员B离开会议 ==== | + | ==== 4. 停止订阅流 ==== |
+ | 调用 ** emedia.mgr.unsubscribe ** 方法停止订阅别人的流 | ||
+ | <code javascript> | ||
+ | emedia.mgr.unsubscribe(stream); // stream:已经订阅的流 | ||
+ | </code> | ||
- | 成员B调用SDK接口exitConference离开会议,会议中的其他成员会收到回调[emedia.mgr.onMemberExited:member:] | + | ==== 5. 通话过程中音视频控制 ==== |
+ | 5.1 打开/关闭自己的视频 | ||
+ | <code javascript> | ||
+ | const res_stream = await emedia.mgr.pauseVideo(own_stream) //关闭视频 | ||
+ | const res_stream = await emedia.mgr.resumeVideo(own_stream) //开启视频 | ||
+ | </code> | ||
+ | 5.2 打开/关闭自己的音频 | ||
<code javascript> | <code javascript> | ||
- | emedia.mgr.exitConference(); | + | const res_stream = await emedia.mgr.pauseAudio(own_stream) // 关闭音频 |
+ | const res_stream = await emedia.mgr.resumeAudio(own_stream) // 开启音频 | ||
</code> | </code> | ||
- | ===== 共享桌面 ===== | + | 执行开启/关闭音视频方法时, |
- | 共享桌面,仅支持PC Chrome浏览器或electron平台。 | + | * own_stream:自己已经发布的媒体流(不能是桌面流) |
+ | * res_stream:设置音视频成功后返回的流对象 | ||
+ | ** 执行上述操作后,会议中其他人员会收到流变化的回调 emedia.mgr.onMediaChanaged ** \\ | ||
+ | emedia.mgr.onMediaChanaged 应该在流变化之前监听 | ||
<code javascript> | <code javascript> | ||
- | /** | + | var videoTag = document.getElementById('#xxx') // 获取 video 标签 |
- | * let params = { | + | emedia.mgr.onMediaChanaged(videoTag, function(constaints, stream) { |
- | * videoConstaints, | + | |
- | * withAudio, | + | |
- | * videoTag, | + | |
- | * ext, | + | |
- | * confrId, | + | |
- | * stopSharedCallback | + | |
- | * } | + | |
- | */ | + | |
- | + | ||
- | /** | + | |
- | * videoConstaints {screenOptions: ['screen', 'window', 'tab']} or true | + | |
- | * withAudio: true 携带语音,false不携带 | + | |
- | * ext 用户自定义扩展,其他成员可以看到这个字段 | + | |
- | * stopSharedCallback 共享插件 点击【停止共享】的回调函数,做相应的处理(比如删除流...) | + | |
- | */ | + | |
- | emedia.mgr.shareDesktopWithAudio(params).then(function(pushedStream){ | + | |
- | //stream 对象 | + | |
- | }).catch(function(error){ | + | |
}); | }); | ||
- | + | // 回调函数中 constaints、stream | |
- | //electron平台 默认选择第一个屏幕,如果需要选择其他,需要重写方法 | + | constaints: { |
- | emedia.chooseElectronDesktopMedia = function(sources, accessApproved){ | + | audio: true // true: 开启了音频,false:关闭了音频 |
- | var firstSources = sources[0]; | + | video: true // true: 开启了视频,false:关闭了视频 |
- | accessApproved(firstSources); | + | |
} | } | ||
- | </code> | + | stream:媒体流变化后的 stream 对象 |
+ | </code> | ||
- | **注意:** | ||
- | %%在chrome浏览器中使用时,需要从%%[[https://chrome.google.com/webstore/detail/rtc-share-desktop/ccahbcjalpomijfpjemdgpnbogofnlgl|chrome store]] 或者从[[https://download-sdk.oss-cn-beijing.aliyuncs.com/rtc_desktop_share.zip|环信服务器]] %%中下载插件,解压后在chrome浏览器中输入 chrome://extensions/, 选择“Load unpacked” 选择解压后的文件夹中的1.0_0文件夹,加载插件。%% | ||
- | + | 5.3 切换摄像头 | |
- | ===== 其他接口 ===== | + | |
- | ==== 获取加入会议ticket ==== | + | |
<code javascript> | <code javascript> | ||
- | emedia.mgr.getConferenceTkt(confrType, password).then(function(confr){ | + | // 随机切换摄像头 |
- | + | emedia.mgr.changeCamera(confrId).then(function(){ | |
- | }).catch(function(error){ | + | // 无参数 |
+ | }).catch(function(){ | ||
}) | }) | ||
- | </code> | + | // 切换手机前后摄像头 |
+ | emedia.mgr.switchMobileCamera(confrId).then(function(){ | ||
+ | // 无参数 | ||
+ | }).catch(function(){ | ||
- | ==== 销毁会议 ==== | + | }) |
+ | </code> | ||
+ | ==== 6. 音视频网络状态监听 ==== | ||
+ | ** 建议进入会议之前绑定网络状态监听函数 ** | ||
<code javascript> | <code javascript> | ||
- | emedia.mgr.destroyConference(confrId).then(function(){ | + | //监听弱网状态 |
- | + | emedia.mgr.onNetworkWeak = streamId => {} //streamId 会议中的流 ID | |
- | }).catch(function(error){ | + | |
- | }) | + | //监听断网状态 |
- | </code> | + | emedia.mgr.onNetworkDisconnect = streamId => {} //streamId 会议中的流 ID |
+ | </code> | ||
- | ==== 踢人 ==== | + | ==== 7. 监听谁在说话 ==== |
+ | 这是监听的video标签,\\ | ||
+ | ** 建议:在将video标签与stream绑定时(emedia.mgr.streamBindVideo), 调用 emedia.mgr.onSoundChanaged 方法 ** | ||
<code javascript> | <code javascript> | ||
- | emedia.mgr.kickMembersById(confr, memberNames).then(function(){ | + | var videoTag = getElementById('#xxx'); |
- | + | emedia.mgr.onSoundChanaged(videoTag,, function (meterData) {}); | |
- | }).catch(function(error){ | + | |
- | }) | + | // 返回的参数 meterData 结构如下: |
- | </code> | + | meterData: { |
+ | instant: 0.26280892641627845 // instant 大约每50毫秒变化一次, 小于1的浮点数 | ||
+ | slow: 0.06802768487276245 // slow大约是一秒钟内的平均音量,小于1的浮点数 | ||
+ | clip: 0 | ||
+ | } | ||
+ | </code> | ||
- | ==== 获取会议信息 ==== | + | ==== 8. 共享桌面 ==== |
- | 在会议进行中,可以通过selectConfr 方法来查询会议信息,从而可以拿到主播列表,观众人数等信息。 | + | 仅支持PC Chrome浏览器或electron平台\\ |
+ | |||
+ | ** SDK 3.2.1 版本 文档 ** | ||
+ | === 8.1无插件共享 === | ||
+ | 需要 SDK 3.2.1 版本开始支持,并且 Chrome 72 或以上版本。 | ||
<code javascript> | <code javascript> | ||
- | // confrId: 会议Id | + | const screenStream = await emedia.mgr.shareDesktopWithAudio({ |
- | // password: 会议密码 | + | confrId: confrId, // 会议ID, 必须 |
- | emedia.mgr.selectConfr(confrId, password).then(function(){ | + | audio: false, |
- | + | }); | |
- | }).catch(function(error){ | + | </code> |
- | }) | + | === 8.2有插件共享 === |
- | </code> | + | |
- | ==== 授权 ==== | ||
<code javascript> | <code javascript> | ||
- | emedia.mgr.grantRole(confr, memberNames, role).then(function(){ | + | //在 sdk 内部会自动判断,浏览器是否含有 navigator.mediaDevices.getDisplayMedia API, |
- | + | //如果没有,将会跳转至 使用 插件的 API,如果没有安装插件将给出提示 | |
- | }).catch(function(error){ | + | </code> |
- | }) | ||
- | </code> | ||
- | ==== 使用用户名密码加入会议,可自定义ext ==== | + | === 8.3分享音频 === |
<code javascript> | <code javascript> | ||
- | emedia.mgr.joinConference(confrId, password, ext).then(function(){ | + | //1. 版本起支持在 Windows 平台的 Chrome 浏览器 74 及以上版本同时共享屏幕和本地播放的背景音, |
- | + | //2. 将 audio 设置为 true 即可 | |
- | }).catch(function(error){ | + | </code> |
- | }) | + | === 8.4Electron 屏幕共享 === |
- | </code> | + | |
- | ==== 使用ticket加入会议,可自定义ext ==== | ||
<code javascript> | <code javascript> | ||
- | emedia.mgr.joinConference(confrId, ticket, ext).then(function(){ | + | //1. sdk 内部会判断是否是在 electron 平台内 |
- | + | //2. electron 平台 会默认选择 第一个屏幕 | |
- | }).catch(function(error){ | + | //3. 如果需要自定义选择框,请重新定义 emedia.chooseElectronDesktopMedia 方法 |
+ | emedia.chooseElectronDesktopMedia = function(sources, accessApproved, accessDenied){ | ||
+ | sources // Array 获取到的屏幕列表 | ||
+ | accessApproved(source)// 选中的 source 对象,进行分享 | ||
+ | accessDenied()// 取消分享,关闭自定义框需要调用此方法 | ||
+ | } | ||
+ | </code> | ||
- | }) | + | === 8.5 停止共享桌面 === |
- | </code> | + | |
- | ==== 退出会议 ==== | ||
<code javascript> | <code javascript> | ||
- | emedia.mgr.exitConference(); | + | 停止共享桌面,执行 取消流的发布 emedia.mgr.unpublish(screenStream) |
</code> | </code> | ||
- | ==== publish 媒体流 ==== | + | |
+ | ** SDK 3.2.1 之前版本 文档 ** | ||
<code javascript> | <code javascript> | ||
/** | /** | ||
- | * constaints: {audio: true, video: true} | + | * let params = { |
- | * videoTag 可缺失,如果有 此次publish的媒体数据将会在这个video上显示 将会与stream绑定 | + | * videoConstaints, |
- | * ext 用户自定义扩展,其他成员可以看到这个字段 | + | * withAudio, |
- | * | + | * videoTag, |
+ | * ext, | ||
+ | * confrId, | ||
+ | * stopSharedCallback | ||
+ | * } | ||
*/ | */ | ||
- | emedia.mgr.publish(constaints, videoTag, ext).then(function(pushedStream){ | ||
- | //stream 对象 | ||
- | }).catch(function(error){ | ||
- | |||
- | }); | ||
/** | /** | ||
- | * videoTag 可缺失时 | + | * videoConstaints {screenOptions: ['screen', 'window', 'tab']} or true |
- | * | + | * withAudio: true 携带语音,false不携带 如携带语音,需自己调用关闭流,不会执行 stopSharedCallback 回调 |
+ | * ext 用户自定义扩展,其他成员可以看到这个字段 | ||
+ | * stopSharedCallback 共享插件 点击【停止共享】的回调函数,做相应的处理(比如删除流...) | ||
*/ | */ | ||
- | emedia.mgr.publish(constaints, ext).then(function(pushedStream){ | + | emedia.mgr.shareDesktopWithAudio(params).then(function(pushedStream){ |
//stream 对象 | //stream 对象 | ||
- | //如果需要将这个stream对象 显示,需要 emedia.mgr.streamBindVideo(videoTag, pushedStream) | ||
}).catch(function(error){ | }).catch(function(error){ | ||
}); | }); | ||
- | </code> | ||
- | ==== 取消publish ==== | + | //electron平台 默认选择第一个屏幕,如果需要选择其他,需要重写方法 |
- | <code javascript> | + | emedia.chooseElectronDesktopMedia = function(sources, accessApproved){ |
- | emedia.mgr.unpublish(pushedStream); | + | var firstSources = sources[0]; |
- | 或 | + | accessApproved(firstSources); |
- | emedia.mgr.hungup(pushedStream); | + | } |
</code> | </code> | ||
- | ==== 订阅 ==== | + | **注意:** |
+ | %%在chrome浏览器中使用时,需要从%%[[https://chrome.google.com/webstore/detail/rtc-share-desktop/ccahbcjalpomijfpjemdgpnbogofnlgl|chrome store]] 或者从[[https://download-sdk.oss-cn-beijing.aliyuncs.com/rtc_desktop_share.zip|环信服务器]] %%中下载插件,解压后在chrome浏览器中输入 chrome://extensions/, 选择“Load unpacked” 选择解压后的文件夹中的1.0_0文件夹,加载插件。%% | ||
+ | |||
+ | ===== 角色管理 ===== | ||
+ | 可通过 emedia.mgr.Role 获取会议中的角色类型 | ||
<code javascript> | <code javascript> | ||
- | /** | + | emedia.mgr.Role: { |
- | * subSVideo 看视频 | + | ADMIN: 7, // 会议管理员: 能创建会议,销毁会议,移除会议成员,切换其他成员的角色 |
- | * subSAudio 看音频 | + | TALKER: 3, // 主播: 能上传自己的音视频,能观看收听其他主播的音视频,即能发布流和订阅流) |
- | * videoTag 可缺失,如果有 将会与stream绑定,并播放stream | + | AUDIENCE: 1 // 观众: 只能观看收听音视频,即只能订阅流 |
- | */ | + | }; |
- | emedia.mgr.subscribe(member, stream, subSVideo, subSAudio, videoTag).then(function(){ | + | // 可在会议中定义更加语义化的判断: |
- | //stream 对象 | + | if(member.role == emedia.mgr.Role.ADMIN){ } |
- | }).catch(function(error){ | + | 等同于 |
+ | if(member.role == 7){ } | ||
+ | </code> | ||
+ | 在以下申请主播和申请管理员的过程,请注意: | ||
+ | 1.从发起申请到管理员回复(同意或拒绝),是一个完整的过程 | ||
+ | 2.因此可以认为:当管理员收到请求,会收到两个函数参数(同意和拒绝),用于管理员调用 | ||
+ | 3.当管理员处理了请求(同意或拒绝),申请者会收到处理结果(同意或拒绝),未处理则不会收到 | ||
+ | |||
+ | ** 以下方法非回调函数均为异步函数 ** | ||
+ | <code javascript> | ||
+ | try { | ||
+ | await emedia.mgr.xxx; | ||
+ | } catch(error) { } | ||
+ | |||
+ | // 以下出现的参数注解 | ||
+ | confrId: 会议id | ||
+ | memberId: 与会人员的id,member 中的id | ||
+ | nickName: 昵称 | ||
+ | </code> | ||
+ | ==== 1. 观众申请成为主播 ==== | ||
+ | 观众通过调用 ** emedia.mgr.requestToTalker ** 方法申请主播 | ||
+ | <code javascript> | ||
+ | // 观众上麦申请方法 | ||
+ | emedia.mgr.requestToTalker(confrId) | ||
- | }); | + | // 管理员收到上麦申请的回调 (主播不会收到这个回调) |
- | emedia.mgr.triggerSubscribe(videoTag, subSVideo, subSAudio).then(function(){ | + | emedia.mgr.onRequestToTalker = function(applicat, agreeCallback, refuseCallback) { |
- | //stream 对象 | + | /* |
- | }).catch(function(error){ | + | * applicat { memberId, nickName } object 申请者信息 |
+ | * agreeCallback 管理员同意的回调 示例:agreeCallback(memberId) memberId 申请者 id 必需 | ||
+ | * refuseCallback 管理员拒绝的回调 示例:refuseCallback(memberId) memberId 申请者 id必需 | ||
+ | */ | ||
+ | } | ||
+ | |||
+ | // 观众收到 上麦申请的回复 | ||
+ | emedia.mgr.onRequestToTalkerReply = function(result) { | ||
+ | // result 0: 同意 1: 拒绝 | ||
+ | } | ||
+ | </code> | ||
- | }); | + | ==== 2.主播申请成为管理员 ==== |
- | 也可以 | + | <code javascript> |
- | //仅订阅音频 | + | // 主播申请管理员 |
- | emedia.mgr.triggerResumeAudio(videoTag).then(function(){ | + | emedia.mgr.requestToAdmin(confrId); |
- | }).catch(function(error){ | + | |
- | }); | + | //管理员收到申请管理员的回调 (主播不会收到这个回调) |
- | //仅暂停订阅音频 | + | emedia.mgr.onRequestToAdmin = function(applicat, agreeCallback, refuseCallback) { |
- | emedia.mgr.triggerPauseAudio(videoTag).then(function(){ | + | /* |
- | }).catch(function(error){ | + | * applicat { memberId, nickName } object 申请者信息 |
- | }); | + | * agreeCallback 管理员同意的回调 示例:agreeCallback(memberId) memberId 申请者 id 必需 |
- | + | * refuseCallback 管理员拒绝的回调 示例:refuseCallback(memberId) memberId 申请者 id必需 | |
- | //仅订阅视频 | + | */ |
- | emedia.mgr.triggerResumeVideo(videoTag).then(function(){ | + | } |
- | }).catch(function(error){ | + | |
- | }); | + | |
- | //仅暂停订阅视频 | + | |
- | emedia.mgr.triggerPauseVideo(videoTag).then(function(){ | + | |
- | }).catch(function(error){ | + | |
- | }); | + | |
+ | // 主播收到 申请管理员的回复 | ||
+ | emedia.mgr.onRequestToAdminReply = function(result) { | ||
+ | // result 0: 同意 1: 拒绝 | ||
+ | } | ||
</code> | </code> | ||
- | ==== stream video 绑定 ==== | + | ====3.授权 ==== |
+ | ** 只有管理员有权限授权 ** \\ | ||
+ | 调用 方法改变与会人员的角色(可升可降) | ||
<code javascript> | <code javascript> | ||
- | //stream 与 video绑定后,video才可以播放stream;并且可以通过触发/监听video上的事件,来达到对stream的便捷操作 | + | var option = { |
- | emedia.mgr.streamBindVideo(stream, videoTag); | + | confr:, //会议对象 Object 必需 |
- | </code> | + | memberNames: // 被授权人员的memberName集合(可同时给多人授权)Array |
+ | role: // 需要授权成什么角色 Number 必需 | ||
+ | } | ||
+ | emedia.mgr.grantRole(option.confr, option.memberNames, option.role) | ||
+ | </code> | ||
- | ==== 获取stream绑定的video ==== | + | ==== 4.角色降级 ==== |
+ | ** 注意:只能角色降级 从管理员到主播、从主播到观众、从管理员到观众,不可逆向操作 ** \\ | ||
+ | 与会成员调用 ** emedia.mgr.degradeRole ** 方法就会角色降级 | ||
<code javascript> | <code javascript> | ||
- | emedia.mgr.getBindVideoBy(stream); | + | //[memName] 与会人员的memName、 toRole 想要 达到的角色 |
+ | emedia.mgr.degradeRole(confrId, [memName], toRole); | ||
</code> | </code> | ||
- | ==== 切换摄像头==== | + | ==== 5.管理员踢人 ==== |
+ | ** 只有管理员可踢人 ** | ||
<code javascript> | <code javascript> | ||
- | // 随机切换摄像头 | + | // confr: 会议对象,必需 Object |
- | emedia.mgr.changeCamera().then(function(){ | + | // memberNames: 被踢掉人员的 memberName, 必需 Array |
- | // 无参数 | + | emedia.mgr.kickMembersById(confr, memberNames) |
- | }).catch(function(){ | + | </code> |
- | }) | + | ==== 6.管理员执行全体静音/取消全体静音 ==== |
- | // 切换手机前后摄像头 | + | ** 只有管理员可操作,其他角色操作不生效,管理员不会被静音 ** \\ |
- | emedia.mgr.switchMobileCamera().then(function(){ | + | |
- | // 无参数 | + | |
- | }).catch(function(){ | + | |
- | }) | + | 6.1管理员静音全体 |
- | </code> | + | <code javascript> |
+ | await emedia.mgr.muteAll(confrId); // confrId: 会议Id | ||
- | ==== 暂停/恢复自己的视频 ==== | + | // 主播收到回调 |
+ | emedia.mgr.onMuteAll = () => { | ||
+ | // 在收到回调后,需要在程序中执行关闭麦克风的逻辑(emedia.mgr.pauseAudio(own_stream)) | ||
+ | } | ||
+ | </code> | ||
+ | 6.2取消全体静音 | ||
<code javascript> | <code javascript> | ||
- | emedia.mgr.pauseVideo(pubS).then(function(){ | + | await emedia.mgr.unmuteAll(confrId); // confrId: 会议Id |
- | }).catch(function(){ | + | //主播收到回调 |
+ | emedia.mgr.onUnMuteAll = () => { | ||
+ | // 在收到回调后,需要在程序中执行关闭麦克风的逻辑(emedia.mgr.resumeAudio(own_stream)) | ||
+ | } | ||
+ | </code> | ||
+ | ==== 7.管理员指定成员静音/取消指定成员静音 ==== | ||
+ | ** 只有管理员可操作,其他角色操作不生效 ** \\ | ||
- | }) | + | 7.1管理员指定成员静音 |
- | 等价于 | + | <code javascript> |
- | emedia.mgr.triggerPauseVideo(localVideoTag).then(function(){ | + | emedia.mgr.muteBymemberId(confrId, memberId);// memberId 被静音主播的memberId |
- | }).catch(function(){ | + | // 单个主播被管理员静音的回调(只他自己收到回调) |
- | + | emedia.mgr.onMuted = () => { | |
- | }) | + | // 在收到回调后,需要在程序中执行关闭麦克风的逻辑(emedia.mgr.pauseAudio(own_stream)) |
+ | } | ||
</code> | </code> | ||
+ | 7.2管理员取消指定成员静音 | ||
<code javascript> | <code javascript> | ||
- | emedia.mgr.resumeVideo(pubS).then(function(){ | + | emedia.mgr.unmuteBymemberId(confrId, memberId);// memberId 被取消静音主播的memberId |
- | }).catch(function(){ | + | // 单个主播被管理员取消静音的回调 (只他自己收到回调) |
+ | emedia.mgr.onUnmuted = () => { | ||
+ | // 在收到回调后,需要在程序中执行关闭麦克风的逻辑(emedia.mgr.resumeAudio(own_stream)) | ||
+ | } | ||
+ | </code> | ||
- | }) | + | ==== 8.本身角色变更回调 ==== |
- | 等价于 | + | ** 如果想要变更自己的角色,需要向管理员申请,管理员同意后,角色就会变更 ** |
- | emedia.mgr.triggerResumeVideo(localVideoTag).then(function(){ | + | <code javascript> |
+ | emedia.mgr.onRoleChanged = function (role) { | ||
+ | // role: 变更后的角色 | ||
+ | }; | ||
+ | </code> | ||
- | }).catch(function(){ | + | ==== 9.管理员变更回调 ==== |
- | + | ** 当会议中的管理员变更时,与会人员都会收到这个回调 ** | |
- | }) | + | <code javascript> |
+ | emedia.mgr.onAdminChanged = admin => {} //admin 管理员信息 | ||
</code> | </code> | ||
+ | ===== 其他接口 ===== | ||
==== 抓取 video图像,并保存 ==== | ==== 抓取 video图像,并保存 ==== | ||
<code javascript> | <code javascript> | ||
行 690: | 行 980: | ||
//用来对onFocusExpoRemoteWhenClickVideo的撤销 | //用来对onFocusExpoRemoteWhenClickVideo的撤销 | ||
emedia.mgr.offEventAtTag(videoTag); | emedia.mgr.offEventAtTag(videoTag); | ||
- | </code> | ||
- | |||
- | ==== video监听的事件 ==== | ||
- | <code javascript> | ||
- | //video的音频视频开关,将会触发 | ||
- | emedia.mgr.onMediaChanaged(videoTag, function (constaints) { | ||
- | $div.find("#aoff").html(constaints.audio ? "有声" : "无声"); | ||
- | $div.find("#voff").html(constaints.video ? "有像" : "无像"); | ||
- | |||
- | //可以通过video标签 得知发布方 是否关闭 音频 视频 | ||
- | console.warn($(videoTag).attr("easemob_stream"), "aoff", $(videoTag).attr("aoff")); | ||
- | console.warn($(videoTag).attr("easemob_stream"), "voff", $(videoTag).attr("voff")); | ||
- | }); | ||
- | </code> | ||
- | |||
- | <code javascript> | ||
- | //video的声音大小出发,比如谁在说话 | ||
- | emedia.mgr.onSoundChanaged(videoTag,, function (meterData) { | ||
- | var $volume = $div.find('#volume'); | ||
- | |||
- | $volume.html(meterData.instant.toFixed(2) | ||
- | + " " + meterData.slow.toFixed(2) | ||
- | + " " + meterData.clip.toFixed(2) | ||
- | + " " + (meterData.trackAudioLevel ? parseFloat(meterData.trackAudioLevel).toFixed(4) : "--") | ||
- | + " " + (meterData.trackTotalAudioEnergy ? parseFloat(meterData.trackAudioLevel).toFixed(4) : "--") | ||
- | ); | ||
- | }); | ||
</code> | </code> | ||
行 757: | 行 1020: | ||
</code> | </code> | ||
- | ===== 进阶功能 ===== | + | ====== 客户端api ====== |
- | ==== 房间内动作消息 ==== | + | 多人音视频通话的API包括以下接口 |
- | <code javascript> | + | * createConference: 创建会议 |
- | // 以下方法非回调函数均为异步函数 | + | * destroyConference:销毁会议 |
- | try { | + | * getConferenceInfo:获取会议信息 |
- | await emedia.mgr.xxx; | + | * publish:发布媒体流 |
- | } catch(error) { } | + | * unpublish:取消发布媒体流 |
- | + | * grantRole:改变角色 | |
- | // 以下出现的参数注解 | + | * joinConference:通过password 加入会议 |
- | confrId: 会议id | + | * kickMembersById:通过id踢出成员 |
- | memberId: 与会人员的id | + | |
- | nickName: 昵称 | + | |
- | </code> | + | |
- | === 1.上麦申请 === | + | |
- | <code javascript> | + | |
- | // 观众上麦申请方法 | + | |
- | emedia.mgr.requestToTalker(confrId) | + | |
- | // 主持人收到上麦申请的回调 (主播不会收到这个回调) | + | ** 以下方法均为 emedia.mgr 对象的属性方法: ** |
- | emedia.mgr.onRequestToTalker = function(applicat, agreeCallback, refuseCallback) { | + | |
- | /* | + | |
- | * applicat { memberId, nickName } object 申请者信息 | + | |
- | * agreeCallback 主持人同意的回调 示例:agreeCallback(memberId) memberId 申请者 id 必需 | + | |
- | * refuseCallback 主持人拒绝的回调 示例:refuseCallback(memberId) memberId 申请者 id必需 | + | |
- | */ | + | |
- | } | + | |
- | + | ||
- | // 观众收到 上麦申请的回复 | + | |
- | emedia.mgr.onRequestToTalkerReply = function(result) { | + | |
- | // result 0: 同意 1: 拒绝 | + | |
- | } | + | |
- | </code> | + | |
- | === 2.主播申请主持人 === | + | ^方法 ^功能 |
- | <code javascript> | + | |[[http://webim-h5.easemob.com/emedia/jsdoc/out/global.html#createConference | createConference]]| 创建会议 | |
- | // 主播申请主持人 | + | |[[http://webim-h5.easemob.com/emedia/jsdoc/out/global.html#destroyConference | createConference]]| 销毁会议| |
- | emedia.mgr.requestToAdmin(confrId); | + | |[[http://webim-h5.easemob.com/emedia/jsdoc/out/global.html#getConferenceInfo | getConferenceInfo]]|获取会议信息 | |
- | + | |[[http://webim-h5.easemob.com/emedia/jsdoc/out/global.html#grantRole | grantRole]]|改变角色 | | |
- | //主持人收到申请主持人的回调 (主播不会收到这个回调) | + | |[[http://webim-h5.easemob.com/emedia/jsdoc/out/global.html#joinConference | joinConference]]|通过password 加入会议 | |
- | emedia.mgr.onRequestToAdmin = function(applicat, agreeCallback, refuseCallback) { | + | |[[http://webim-h5.easemob.com/emedia/jsdoc/out/global.html#kickMembersById | kickMembersById]]|通过id踢出成员 | |
- | /* | + | |[[http://webim-h5.easemob.com/emedia/jsdoc/out/global.html#publish | publish]]|发布媒体流| |
- | * applicat { memberId, nickName } object 申请者信息 | + | |[[http://webim-h5.easemob.com/emedia/jsdoc/out/global.html#unpublish | unpublish]]|取消发布媒体流| |
- | * agreeCallback 主持人同意的回调 示例:agreeCallback(memberId) memberId 申请者 id 必需 | + | |
- | * refuseCallback 主持人拒绝的回调 示例:refuseCallback(memberId) memberId 申请者 id必需 | + | |
- | */ | + | |
- | } | + | |
- | + | ||
- | // 主播收到 申请主持人的回复 | + | |
- | emedia.mgr.onRequestToAdminReply = function(result) { | + | |
- | // result 0: 同意 1: 拒绝 | + | |
- | } | + | |
- | </code> | + | |
- | === 3.主持人执行全体静音 === | + | |
- | <code javascript> | + | |
- | // 只有主持人可操作,其他角色操作不生效,主持人不会被静音 | + | |
- | + | ||
- | // 主持人静音全体 | + | |
- | await emedia.mgr.muteAll(confrId); | + | |
- | + | ||
- | // 主播收到回调 | + | |
- | emedia.mgr.onMuteAll = () => { } | + | |
- | </code> | + | |
- | === 4.主持人执行取消全体静音 === | + | |
- | <code javascript> | + | |
- | // 只有主持人可操作,其他角色操作不生效 | + | |
- | + | ||
- | // 主持人取消全体静音 | + | |
- | await emedia.mgr.unmuteAll(confrId); | + | |
- | + | ||
- | //主播收到回调 | + | |
- | emedia.mgr.onUnMuteAll = () => { } | + | |
- | </code> | + | |
- | === 5.主持人静音单个主播 === | + | |
- | <code javascript> | + | |
- | // 主持人静音单个主播 | + | |
- | emedia.mgr.muteBymemberId(confrId, memberId);// memberId 被静音主播的memberId | + | |
- | + | ||
- | // 单个主播被管理员静音的回调(只他自己收到回调) | + | |
- | emedia.mgr.onMuted = () => { } | + | |
- | </code> | + | |
- | === 6.主持人取消静音 某个主播 === | + | |
- | <code javascript> | + | |
- | // 主持人取消静音单个主播 | + | |
- | emedia.mgr.unmuteBymemberId(confrId, memberId);// memberId 被取消静音主播的memberId | + | |
- | + | ||
- | // 单个主播被管理员取消静音的回调 (只他自己收到回调) | + | |
- | emedia.mgr.onUnmuted = () => { } | + | |
- | </code> | + | |
- | === 7.角色降级接口 === | + | |
- | <code javascript> | + | |
- | // 只能角色降级 从主持人到主播、从主播到观众、从主持人到观众,不可逆向操作 | + | |
- | + | ||
- | //[memName] 被降级人员的memName、 toRole 想要 达到的角色 | + | |
- | emedia.mgr.degradeRole(confrId, [memName], toRole); | + | |
- | </code> | + | |
- | + | ||
- | ==== 集群代理 ==== | + | |
- | <code javascript> | + | |
- | //开启集群部署,SDK内部会自动请求代理,实现通话最优 | + | |
- | + | ||
- | //开启方式 | + | |
- | emedia.config({ | + | |
- | ... | + | |
- | useDeployMore: true // 默认:false 不开启 | + | |
- | ... | + | |
- | }) | + | |
- | </code> | + | |
- | ==== 合流推流 CDN ==== | + | |
- | === 1.创建CDN === | + | |
- | <code javascript> | + | |
- | // 创建会议、加入房间时都可以创建CDN | + | |
- | + | ||
- | // 添加一个 liveCfg 参数 | + | |
- | liveCfg = { | + | |
- | cdn:'', //推流地址、字符串;必需 | + | |
- | layoutStyle: 'GRID' | 'CUSTOM', // 格子显示 | 自定义,必需 | + | |
- | canvas :{// canvas 参数在 layoutStyle == 'CUSTOM' 必填 | + | |
- | bgclr : 0x980000,//背景色 980000 为 十六进制色值 | + | |
- | w : 640, //宽度 | + | |
- | h : 480, //高度 | + | |
- | fps: 20, //输出帧率 | + | |
- | bps: 1200000, //输出码率 | + | |
- | codec: "H264" //视频编码,现在必须是H264 | + | |
- | } | + | |
- | } | + | |
- | + | ||
- | //创建会议时指定 CDN推流 | + | |
- | let option = { | + | |
- | confrType, | + | |
- | password, | + | |
- | ... | + | |
- | liveCfg // 创建CDN推流参数 | + | |
- | } | + | |
- | emedia.mgr.createConference(option) | + | |
- | + | ||
- | // 加入房间时 指定CDN推 | + | |
- | // 只有第一个加入房间的人才能创建 CDN、以后加入的人指定CDN也无效 | + | |
- | let params = { | + | |
- | roomName, | + | |
- | password, | + | |
- | ... | + | |
- | config:{ | + | |
- | ... | + | |
- | liveCfg // 创建CDN推流参数 | + | |
- | } | + | |
- | } | + | |
- | emedia.mgr.joinRoom(params); | + | |
- | </code> | + | |
- | === 2.更新CDN布局 === | + | |
- | <code javascript> | + | |
- | // 只有管理员才能 更新布局。更新布局会 将layoutStyle 变为 CUSTOM 而且不可逆 | + | |
- | + | ||
- | emedia.mgr.updateLiveLayout(confrId, regions) | + | |
- | + | ||
- | // confrId 会议id | + | |
- | regions:[ // 希望定义视频流 显示的配置集合 | + | |
- | { | + | |
- | "sid": stream_id,//视频流的id | + | |
- | "x": 320,//距离 x 轴的距离 Number | + | |
- | "y": 240,//距离 y 轴的距离 Number | + | |
- | "w": 960,//宽度 Number | + | |
- | "h": 720,//高度 Number | + | |
- | "style": "fill" | "AspectFit" //视频显示模式 fill:铺满、AspectFit:原比例显示 | + | |
- | }, | + | |
- | .... 其他视频流配置(数组有几个项,就显示几个视频流) | + | |
- | ] | + | |
- | </code> | + | |
- | === 3.删除CDN === | + | |
- | <code javascript> | + | |
- | // 只有管理员可操作 | + | |
- | emedia.mgr.deleteLive(confrId) //confrId 会议id | + | |
- | </code> | + |