差别
这里会显示出您选择的修订版和当前版本之间的差别。
后一修订版 两侧同时换到之后的修订记录 | |||
im:web:draft:sticker [2019/03/11 06:55] jk 创建 |
im:web:draft:sticker [2019/03/11 06:56] jk |
||
---|---|---|---|
行 1: | 行 1: | ||
- | ====== 多人实时通话 ====== | + | ===== 导入第三方表情包 ===== |
- | + | 在项目下面新建一个文件夹,用于存放表情图片文件。 | |
- | ---- | + | 在引用了sdk之后执行如下代码: |
- | + | ||
- | ===== 产品简介 ===== | + | |
- | + | ||
- | 为满足不同场景需求,[[https://github.com/easemob/webim/tree/master/webrtc/dist/EMedia_x1v1.js|EMedia_x1v1.js]]不仅提供了对1v1通话的支持,而且提供了多人通话功能。多人实时音视频会议划分了不同的类型,不同类型对应了不同场景,使你能够轻松地将实时音视频功能集成到你的应用或者网站中。本片将介绍多人音视频使用接入。可参照[[https://github.com/easemob/webim|demo]]。 | + | |
- | 在创建会议时可以传入以下几种类型: | + | |
- | + | ||
- | - Communication:普通通信会议,最多支持参会者6人,会议里的每个参会者都可以自由说话和发布视频,该会议类型在服务器不做语音的再编码,音质最好,适用于远程医疗,在线客服等场景; | + | |
- | - Large Communication:大型通信会议,最多参会者30人,会议里的每个参会者都可以自由说话,最多支持6个人发布视频,该会议模式在服务器做混音处理,支持更多的人说话,适用于大型会议等场景; | + | |
- | - Live:互动视频会议,会议里支持最多6个主播和600个观众,观众可以通过连麦与主播互动,该会议类型适用于在线教育,互动直播等场景。 | + | |
- | + | ||
- | + | ||
- | ==== 产品特性 ==== | + | |
- | + | ||
- | *支持现代浏览器:Chrome/50+、Safari/11+、Firefox; | + | |
- | + | ||
- | *遵守:UMD通用模块规范,支持require导入; | + | |
- | + | ||
- | *支持Promise; | + | |
- | + | ||
- | *支持手机端和 Web 端互通,极大方便开发者的全平台业务; | + | |
- | + | ||
- | *依赖https站点 | + | |
- | + | ||
- | ==== 音视频通信的简要步骤 ==== | + | |
- | + | ||
- | SDK 能够支持音频和视频通信。创建音视频通信的过程简单来说,可以分为以下几步: | + | |
- | + | ||
- | 1. 初始化 SDK,设置监听代理 | + | |
- | 2. create: 创建会议 | + | |
- | 3. join: 加入会议 | + | |
- | 4. pub: 发布音视频数据流 | + | |
- | 5. sub: 订阅并播放音视频数据流 | + | |
- | 6. leave: 离开会议 | + | |
- | ==== 基本知识 ==== | + | |
- | + | ||
- | emedia.mgr.ConfrType:多人会议类型 | + | |
- | 1. Communication:普通通信会议,最多支持参会者6人,成员都可以自由说话和发布视频,成员角色Speaker | + | |
- | 2. Large Communication:大型通信会议,最多参会者30人,成员都可以自由说话和发布视频,成员角色Speaker | + | |
- | 3. Live:互动视频会议,会议里支持最多6个主播和600个观众 | + | |
<code javascript> | <code javascript> | ||
- | emedia.mgr.ConfrType = { | + | WebIM.Emoji = { |
- | COMMUNICATION: 10, //普通会议模式 | + | path: 'demo/images/faces/' /*表情包路径*/ |
- | COMMUNICATION_MIX: 11, //大会议模式 | + | , map: { |
- | LIVE: 12, //直播模式 | + | '[):]': 'ee_1.png', |
- | }; | + | '[:D]': 'ee_2.png', |
- | </code> | + | '[;)]': 'ee_3.png', |
- | <code javascript> | + | '[:-o]': 'ee_4.png', |
- | emedia.mgr.Role = { | + | '[:p]': 'ee_5.png' |
- | ADMIN: 7, // 能创建会议,销毁会议,移除会议成员,切换其他成员的角色,订阅流,发布流 | + | |
- | TALKER: 3, // 能上传自己的音视频,能观看收听其他主播的音视频,即能发布流和订阅流) | + | |
- | AUDIENCE: 1 // 观众Audience:只能观看收听音视频,即只能订阅流 | + | |
- | }; | + | |
- | </code> | + | |
- | <code javascript> | + | |
- | //conference|confr | + | |
- | { | + | |
- | confrId:"TS_X296786295944036352C27", | + | |
- | id:"TS_X296786295944036352C27", | + | |
- | password: "password123", | + | |
- | roleToken:"roleToken", | + | |
- | ticket:"ticket", | + | |
- | type:12 | + | |
- | }; | + | |
- | </code> | + | |
- | <code javascript> | + | |
- | //member | + | |
- | { | + | |
- | "ext":{ //emedia.mgr.joinConference(confrId, password, {role: 'admin'})/* 用户可自定义扩展字段*/); | + | |
- | "role":"admin" | + | |
- | }, | + | |
- | "id":"MS_X197721744293023744C19M197756407719972865VISITOR", | + | |
- | "globalName":"easemob-demo#chatdemoui_yss000@easemob.com", | + | |
- | "name": "yss000" | + | |
- | } | + | |
- | </code> | + | |
- | <code javascript> | + | |
- | //stream | + | |
- | { | + | |
- | "id":"RTC2__Of_C19M197756407719972865VISITOR", | + | |
- | "voff":0, //1 视频关闭 | + | |
- | "aoff":0, //1 音频关闭 | + | |
- | "memId":"MS_X197721744293023744C19M197756407719972865VISITOR", | + | |
- | "owner": member ,//member对象 | + | |
- | "rtcId":"RTC1" | + | |
- | } | + | |
- | var islocated = stream.located(); //islocated true 本地媒体流 | + | |
- | </code> | + | |
- | + | ||
- | 注意: | + | |
- | >> 每个人必须调用join接口成功后,才算是加入会议(即成为会议成员)。会议成员才允许进行其他操作比如订阅流、发布流等 | + | |
- | >> 成员如果想改变自己角色,必须想办法通知管理员,只有管理员才能修改 | + | |
- | + | ||
- | ===== 多人通信会议功能实现 ===== | + | |
- | + | ||
- | 如何使用SDK实现多人实时音视频会议 | + | |
- | + | ||
- | Communication和Large Communication除了最大成员数不一样,流程几乎是一样的。以下是从创建会议到离开会议完整的流程讲解: | + | |
- | + | ||
- | ==== 设置SDK回调 ==== | + | |
- | + | ||
- | 进入会议之前,设置SDK回调后,可获知成员加入或离开会议,数据流更新等。 | + | |
- | + | ||
- | <code javascript> | + | |
- | //有人加入会议,其他人调用joinXX等方法,如果加入成功,已经在会议中的人将会收到 | + | |
- | emedia.mgr.onMemberJoined = function (member) { | + | |
- | + | ||
- | }; | + | |
- | </code> | + | |
- | <code javascript> | + | |
- | //有人退出会议 | + | |
- | emedia.mgr.onMemberExited = function (member) { | + | |
- | + | ||
- | }; | + | |
- | </code> | + | |
- | <code javascript> | + | |
- | //有媒体流添加;比如 自己调用了publish方法(stream.located() === true时),或其他人调用了publish方法。 | + | |
- | emedia.mgr.onStreamAdded = function (member, stream) { | + | |
- | + | ||
- | }; | + | |
- | </code> | + | |
- | <code objc> | + | |
- | //有媒体流移除 | + | |
- | emedia.mgr.onStreamRemoved = function (member, stream) { | + | |
- | + | ||
- | }; | + | |
- | </code> | + | |
- | <code javascript> | + | |
- | //角色改变 | + | |
- | emedia.mgr.onRoleChanged = function (role) { | + | |
- | + | ||
- | }; | + | |
- | </code> | + | |
- | <code javascript> | + | |
- | //会议退出;自己主动退 或 服务端主动关闭; | + | |
- | emedia.mgr.onConferenceExit = function (reason, failed) { | + | |
- | reason = (reason || 0); | + | |
- | switch (reason){ | + | |
- | case 0: | + | |
- | reason = "正常挂断"; | + | |
- | break; | + | |
- | case 1: | + | |
- | reason = "没响应"; | + | |
- | break; | + | |
- | case 2: | + | |
- | reason = "服务器拒绝"; | + | |
- | break; | + | |
- | case 3: | + | |
- | reason = "对方忙"; | + | |
- | break; | + | |
- | case 4: | + | |
- | reason = "失败,可能是网络或服务器拒绝"; | + | |
- | if(failed === -9527){ | + | |
- | reason = "失败,网络原因"; | + | |
- | } | + | |
- | if(failed === -500){ | + | |
- | reason = "Ticket失效"; | + | |
- | } | + | |
- | if(failed === -502){ | + | |
- | reason = "Ticket过期"; | + | |
- | } | + | |
- | if(failed === -504){ | + | |
- | reason = "链接已失效"; | + | |
- | } | + | |
- | if(failed === -508){ | + | |
- | reason = "会议无效"; | + | |
- | } | + | |
- | if(failed === -510){ | + | |
- | reason = "服务端限制"; | + | |
- | } | + | |
- | break; | + | |
- | case 5: | + | |
- | reason = "不支持"; | + | |
- | break; | + | |
- | case 10: | + | |
- | reason = "其他设备登录"; | + | |
- | break; | + | |
- | case 11: | + | |
- | reason = "会议关闭"; | + | |
- | break; | + | |
} | } | ||
}; | }; | ||
</code> | </code> | ||
+ | 全局变量WebIM添加一个Emoji属性,path表示你表情图片存放的路径,map里面的key表示代表表情图片的字符,value表示表情图片的文件名。 | ||
- | ==== 用户A创建会议 ==== | + | 发送和接收表情消息与文本消息类似,如果发送的文本消息中带有表情的key字符,sdk会将此消息转换成表情图片的实际路径,如:文本消息中包含"[):]"字符串,则解析为WebIM.Emoji.path+WebIM.Emoji.map['[):]']= "demo/images/faces/ee_1.png"。 |
- | + | ||
- | <code javascript> | + | |
- | emedia.mgr.createConference(confrType, password).then(function(confr){ | + | |
- | }).catch(function(error){ | + | |
- | }) | + | |
- | </code> | + | |
- | + | ||
- | 注意: 如果A只单纯的create,没进行join操作,则A不是Conference的成员,没有相应的角色,不能进行其他操作 | + | |
- | + | ||
- | ==== 用户A进入会议 ==== | + | |
- | <code javascript> | + | |
- | emedia.mgr.joinConferenceWithTicket(confrId, ticket, ext).then(function(confr){ | + | |
- | + | ||
- | }).catch(function(error){ | + | |
- | + | ||
- | }) | + | |
- | </code> | + | |
- | ==== 管理员A邀请其他人加入会议 ==== | + | |
- | + | ||
- | SDK没有提供邀请接口,你可以自己实现,比如使用环信IM通过发消息邀请,比如通过发邮件邀请等等。 | + | |
- | + | ||
- | 至于需要发送哪些邀请信息,可以参照SDK中的join接口,目前是需要Conference的confrId和password | + | |
- | + | ||
- | 比如用环信IM发消息邀请 | + | |
- | <code javascript> | + | |
- | WebIM.call.inviteConference(confrId, password, jid, gid) | + | |
- | </code> | + | |
- | + | ||
- | 注意:使用环信IM邀请多个人时,建议使用群组消息。如果使用单聊发消息请注意每条消息中间的时间间隔,以防触发环信的垃圾消息防御机制 | + | |
- | ==== 用户B接收到邀请加入会议 ==== | + | |
- | + | ||
- | + | ||
- | 用户B解析出邀请消息中带的confrId和password,调用SDK的join接口加入会议,成为会议成员且角色是Speaker. | + | |
- | + | ||
- | <code javascript> | + | |
- | //javascript | + | |
- | emedia.mgr.joinConference(confr, password, ext).then(function(confr){ | + | |
- | + | ||
- | }).catch(function(error){ | + | |
- | + | ||
- | }) | + | |
- | </code> | + | |
- | + | ||
- | + | ||
- | + | ||
- | 用户B成功加入会议后,会议中其他成员会收到回调[emedia.mgr.onMemberJoined(memberB)] | + | |
- | + | ||
- | ==== 成员A发布音视频流 ==== | + | |
- | + | ||
- | + | ||
- | 成员A和成员B都有发布流的权限 | + | |
- | + | ||
- | <code javascript> | + | |
- | /** | + | |
- | * constaints: {audio: true, video: true} | + | |
- | * videoTag 可缺失,如果有 此次publish的媒体数据将会在这个video上显示 将会与stream绑定 | + | |
- | * ext 用户自定义扩展,其他成员可以看到这个字段 | + | |
- | * | + | |
- | */ | + | |
- | emedia.mgr.publish(constaints, videoTag, ext).then(function(pushedStream){ | + | |
- | //stream 对象 | + | |
- | }).catch(function(error){ | + | |
- | + | ||
- | }); | + | |
- | + | ||
- | /** | + | |
- | * videoTag 可缺失时 | + | |
- | * | + | |
- | */ | + | |
- | emedia.mgr.publish(constaints, ext).then(function(pushedStream){ | + | |
- | //stream 对象 | + | |
- | //如果需要将这个stream对象 显示,需要 emedia.mgr.streamBindVideo(videoTag, pushedStream) | + | |
- | }).catch(function(error){ | + | |
- | + | ||
- | }); | + | |
- | </code> | + | |
- | *** 注意:A推流成功后,onStreamAdded 将被回调 *** | + | |
- | ==== 其他成员收到通知并订阅流 ==== | + | |
- | + | ||
- | 成员A成功发布数据流后,会议中其他成员会收到监听类回调[emedia.mgr.onStreamAdded],如果成员B想看成员A的音视频,可以调用subscribe接口进行订阅 | + | |
- | + | ||
- | <code javascript> | + | |
- | //其他成员 | + | |
- | emedia.mgr.onStreamAdded = function (member, stream) { | + | |
- | if(!stream.located()){ //stream.located() === true, 是自己发布刚刚发布的流 | + | |
- | emedia.mgr.subscribe(member, stream, true, true, video) | + | |
- | } | + | |
- | }; | + | |
- | </code> | + | |
- | + | ||
- | + | ||
- | ==== 成员B取消订阅流 ==== | + | |
- | + | ||
- | 成员B如果不想再看成员A的音视频,可以调用SDK接口unsubscribe | + | |
- | + | ||
- | <code javascript> | + | |
- | //emedia.mgr.hungup(stream); | + | |
- | emedia.mgr.unsubscribe(stream); | + | |
- | </code> | + | |
- | + | ||
- | ==== 成员A取消发布流 ==== | + | |
- | + | ||
- | 成员A可以调用unpublish接口取消自己已经发布的数据流,操作成功后,会议中收到回调[emedia.mgr.onStreamRemoved:removeStream:] ,将对应的数据流信息移除 | + | |
- | + | ||
- | <code javascript> | + | |
- | //emedia.mgr.hungup(pushedStream); | + | |
- | emedia.mgr.unpublish(pushedStream); | + | |
- | </code> | + | |
- | + | ||
- | <code javascript> | + | |
- | emedia.mgr.onStreamRemoved = function (member, stream) { | + | |
- | if(stream.located(){ //自己发布流 | + | |
- | }else{ //会议其他人发布的流 | + | |
- | } | + | |
- | }; | + | |
- | </code> | + | |
- | + | ||
- | ==== 成员B离开会议 ==== | + | |
- | + | ||
- | 成员B调用SDK接口exitConference离开会议,会议中的其他成员会收到回调[emedia.mgr.onMemberExited:member:] | + | |
- | + | ||
- | <code javascript> | + | |
- | emedia.mgr.exitConference(); | + | |
- | </code> | + | |
- | + | ||
- | + | ||
- | ===== 互动视频会议功能实现 ===== | + | |
- | + | ||
- | 互动视频会议的基本操作(创建、邀请人、发布流、取消发布流、订阅流、取消订阅流、更新发布流程、离开)对应的接口和回调同通信会议是一样的。也可以说 互动视频会议是在通信会议的基础上,增加了角色管理功能,以下着重讲解互动视频会议中的角色管理相关知识点 | + | |
- | + | ||
- | 1. 创建互动视频会议时,接口emedia.mgr.createConference传入的type参数是emedia.mgr.ConfrType.LIVE | + | |
- | + | ||
- | 2. 创建者createAndJoin后的角色是Admin,其他成员第一次调用接口[emedia.mgr.joinConference(confrId, password, ext)]加入直播后的权限是观众Audience,Audience只能订阅数据流 | + | |
- | + | ||
- | 3. 观众Audience如果想发布数据流 即上麦,需要给管理员发申请。SDK没有提供申请接口,你可以自定义。 | + | |
- | + | ||
- | 管理员如果同意Audience上麦,需要调用接口emedia.mgr.grantRole将角色Audience更改为Speaker | + | |
- | + | ||
- | <code javascript> | + | |
- | emedia.mgr.grantRole(confr, [memberName1, memberName2], emedia.mgr.Role.TALKER) | + | |
- | </code> | + | |
- | + | ||
- | 成员角色改变后,被改变的成员会收到回调 | + | |
- | + | ||
- | <code javascript> | + | |
- | emedia.mgr.onRoleChanged = function (role) { | + | |
- | + | ||
- | }; | + | |
- | </code> | + | |
- | + | ||
- | 4. 角色从Audience变为Speaker,成员就可以发布数据流了 | + | |
- | + | ||
- | ===== 其他接口 ===== | + | |
- | ==== 获取加入会议ticket ==== | + | |
- | <code javascript> | + | |
- | emedia.mgr.getConferenceTkt(confrType, password).then(function(confr){ | + | |
- | + | ||
- | }).catch(function(error){ | + | |
- | + | ||
- | }) | + | |
- | </code> | + | |
- | + | ||
- | ==== 销毁会议 ==== | + | |
- | <code javascript> | + | |
- | emedia.mgr.destroyConference(confr).then(function(){ | + | |
- | + | ||
- | }).catch(function(error){ | + | |
- | + | ||
- | }) | + | |
- | </code> | + | |
- | ==== 踢人 ==== | + | |
- | <code javascript> | + | |
- | emedia.mgr.kickMembersById(confr, memberNames).then(function(){ | + | |
- | + | ||
- | }).catch(function(error){ | + | |
- | + | ||
- | }) | + | |
- | </code> | + | |
- | ==== 授权 ==== | + | |
- | <code javascript> | + | |
- | emedia.mgr.grantRole(confr, memberNames, role).then(function(){ | + | |
- | + | ||
- | }).catch(function(error){ | + | |
- | + | ||
- | }) | + | |
- | </code> | + | |
- | + | ||
- | ==== 使用用户名密码加入会议,可自定义ext ==== | + | |
- | <code javascript> | + | |
- | emedia.mgr.joinConference(confrId, password, ext).then(function(){ | + | |
- | + | ||
- | }).catch(function(error){ | + | |
- | + | ||
- | }) | + | |
- | </code> | + | |
- | + | ||
- | ==== 使用ticket加入会议,可自定义ext ==== | + | |
- | <code javascript> | + | |
- | emedia.mgr.joinConference(confrId, ticket, ext).then(function(){ | + | |
- | + | ||
- | }).catch(function(error){ | + | |
- | + | ||
- | }) | + | |
- | </code> | + | |
- | + | ||
- | ==== 退出会议 ==== | + | |
- | <code javascript> | + | |
- | emedia.mgr.exitConference(); | + | |
- | </code> | + | |
- | + | ||
- | ==== publish 媒体流 ==== | + | |
- | <code javascript> | + | |
- | /** | + | |
- | * constaints: {audio: true, video: true} | + | |
- | * videoTag 可缺失,如果有 此次publish的媒体数据将会在这个video上显示 将会与stream绑定 | + | |
- | * ext 用户自定义扩展,其他成员可以看到这个字段 | + | |
- | * | + | |
- | */ | + | |
- | emedia.mgr.publish(constaints, videoTag, ext).then(function(pushedStream){ | + | |
- | //stream 对象 | + | |
- | }).catch(function(error){ | + | |
- | + | ||
- | }); | + | |
- | + | ||
- | /** | + | |
- | * videoTag 可缺失时 | + | |
- | * | + | |
- | */ | + | |
- | emedia.mgr.publish(constaints, ext).then(function(pushedStream){ | + | |
- | //stream 对象 | + | |
- | //如果需要将这个stream对象 显示,需要 emedia.mgr.streamBindVideo(videoTag, pushedStream) | + | |
- | }).catch(function(error){ | + | |
- | + | ||
- | }); | + | |
- | </code> | + | |
- | + | ||
- | ==== 共享桌面,仅支持PC Chrome或electron平台 ==== | + | |
- | <code javascript> | + | |
- | /** | + | |
- | * videoConstaints {screenOptions: ['screen', 'window', 'tab']} or true | + | |
- | * withAudio: true 携带语音,false不携带 | + | |
- | * videoTag 可缺失,如果有 此次publish的媒体数据将会在这个video上显示 将会与stream绑定 | + | |
- | * ext 用户自定义扩展,其他成员可以看到这个字段 | + | |
- | * | + | |
- | */ | + | |
- | emedia.mgr.shareDesktopWithAudio(videoConstaints, withAudio, videoTag, ext).then(function(pushedStream){ | + | |
- | //stream 对象 | + | |
- | }).catch(function(error){ | + | |
- | + | ||
- | }); | + | |
- | + | ||
- | //electron平台 默认选择第一个屏幕,如果需要选择其他,需要重写方法 | + | |
- | emedia.chooseElectronDesktopMedia = function(sources, accessApproved){ | + | |
- | var firstSources = sources[0]; | + | |
- | accessApproved(firstSources); | + | |
- | } | + | |
- | </code> | + | |
- | + | ||
- | ==== 取消publish ==== | + | |
- | <code javascript> | + | |
- | emedia.mgr.unpublish(pushedStream); | + | |
- | 或 | + | |
- | emedia.mgr.hungup(pushedStream); | + | |
- | </code> | + | |
- | + | ||
- | ==== 订阅 ==== | + | |
- | <code javascript> | + | |
- | /** | + | |
- | * subSVideo 看视频 | + | |
- | * subSAudio 看音频 | + | |
- | * videoTag 可缺失,如果有 将会与stream绑定,并播放stream | + | |
- | */ | + | |
- | emedia.mgr.subscribe(member, stream, subSVideo, subSAudio, videoTag).then(function(){ | + | |
- | //stream 对象 | + | |
- | }).catch(function(error){ | + | |
- | + | ||
- | }); | + | |
- | emedia.mgr.triggerSubscribe(videoTag, subSVideo, subSAudio).then(function(){ | + | |
- | //stream 对象 | + | |
- | }).catch(function(error){ | + | |
- | + | ||
- | }); | + | |
- | 也可以 | + | |
- | //仅订阅音频 | + | |
- | emedia.mgr.triggerResumeAudio(videoTag).then(function(){ | + | |
- | }).catch(function(error){ | + | |
- | }); | + | |
- | //仅暂停订阅音频 | + | |
- | emedia.mgr.triggerPauseAudio(videoTag).then(function(){ | + | |
- | }).catch(function(error){ | + | |
- | }); | + | |
- | + | ||
- | //仅订阅视频 | + | |
- | emedia.mgr.triggerResumeVideo(videoTag).then(function(){ | + | |
- | }).catch(function(error){ | + | |
- | }); | + | |
- | //仅暂停订阅视频 | + | |
- | emedia.mgr.triggerPauseVideo(videoTag).then(function(){ | + | |
- | }).catch(function(error){ | + | |
- | }); | + | |
- | + | ||
- | </code> | + | |
- | + | ||
- | ==== stream video 绑定 ==== | + | |
- | <code javascript> | + | |
- | //stream 与 video绑定后,video才可以播放stream;并且可以通过触发/监听video上的事件,来达到对stream的便捷操作 | + | |
- | emedia.mgr.streamBindVideo(stream, videoTag); | + | |
- | </code> | + | |
- | + | ||
- | ==== 获取stream绑定的video ==== | + | |
- | <code javascript> | + | |
- | emedia.mgr.getBindVideoBy(stream); | + | |
- | </code> | + | |
- | + | ||
- | ==== 切换摄像头==== | + | |
- | <code javascript> | + | |
- | emedia.mgr.switchCamera().then(function(){ | + | |
- | + | ||
- | }).catch(function(){ | + | |
- | + | ||
- | }) | + | |
- | </code> | + | |
- | + | ||
- | ==== 暂停/恢复自己的视频 ==== | + | |
- | <code javascript> | + | |
- | emedia.mgr.pauseVideo(pubS).then(function(){ | + | |
- | + | ||
- | }).catch(function(){ | + | |
- | + | ||
- | }) | + | |
- | 等价于 | + | |
- | emedia.mgr.triggerResumeVideo(localVideoTag).then(function(){ | + | |
- | + | ||
- | }).catch(function(){ | + | |
- | + | ||
- | }) | + | |
- | </code> | + | |
- | <code javascript> | + | |
- | emedia.mgr.pauseVideo(pubS).then(function(){ | + | |
- | + | ||
- | }).catch(function(){ | + | |
- | + | ||
- | }) | + | |
- | 等价于 | + | |
- | emedia.mgr.triggerPauseVideo(localVideoTag).then(function(){ | + | |
- | + | ||
- | }).catch(function(){ | + | |
- | + | ||
- | }) | + | |
- | </code> | + | |
- | + | ||
- | ==== 抓取 video图像,并保存 ==== | + | |
- | <code javascript> | + | |
- | emedia.mgr.captureVideo(videoTag, true, filename) | + | |
- | 等价于 | + | |
- | emedia.mgr.triggerCaptureVideo(videoTag, true, filename); | + | |
- | </code> | + | |
- | + | ||
- | ==== 控制远程视频(手机端)定格 ==== | + | |
- | <code javascript> | + | |
- | emedia.mgr.freezeFrameRemote(stream); | + | |
- | 等价于 | + | |
- | emedia.mgr.triggerFreezeFrameRemote(videoTag).catch(function(){ | + | |
- | alert("定格失败"); | + | |
- | }); | + | |
- | </code> | + | |
- | + | ||
- | ==== 控制手机闪光灯打开/关闭 ==== | + | |
- | <code javascript> | + | |
- | /** | + | |
- | * torch true 打开,否则 关闭; 可缺失 | + | |
- | */ | + | |
- | emedia.mgr.torchRemote(stream, torch); | + | |
- | 等价于 | + | |
- | emedia.mgr.triggerTorchRemote(videoTag, torch).catch(function(){ | + | |
- | alert("Torch失败"); | + | |
- | }); | + | |
- | </code> | + | |
- | + | ||
- | ==== 控制手机截屏 ==== | + | |
- | <code javascript> | + | |
- | emedia.mgr.capturePictureRemote(stream); | + | |
- | 等价于 | + | |
- | emedia.mgr.triggerCapturePictureRemote(videoTag).catch(function(){ | + | |
- | alert("抓图失败"); | + | |
- | }); | + | |
- | </code> | + | |
- | + | ||
- | ==== 控制手机摄像头放大缩小 ==== | + | |
- | <code javascript> | + | |
- | emedia.mgr.zoomRemote(stream, multiples); | + | |
- | 等价于 | + | |
- | emedia.mgr.triggerZoomRemote(videoTag, multiples).catch(function(){ | + | |
- | alert("zoom失败"); | + | |
- | }); | + | |
- | </code> | + | |
- | + | ||
- | ==== 控制手机摄像头聚焦曝光 ==== | + | |
- | <code javascript> | + | |
- | /** | + | |
- | * clickEvent 为 videoTag的点击事件。通过event计算点击的坐标传给sdk进行控制 | + | |
- | * | + | |
- | */ | + | |
- | emedia.mgr.focusExpoRemote(stream, videoTag, clickEvent).catch(function(){ | + | |
- | alert("focusExpoRemote失败"); | + | |
- | }); | + | |
- | 等价于 | + | |
- | /** | + | |
- | * event string. 如点击 “click” | + | |
- | * fail 失败回调;success成功回调 | + | |
- | */ | + | |
- | emedia.mgr.onFocusExpoRemoteWhenClickVideo(videoTag, event, fail, success); | + | |
- | </code> | + | |
- | + | ||
- | ==== 取消在videoTag上的事件 ==== | + | |
- | <code javascript> | + | |
- | //用来对onFocusExpoRemoteWhenClickVideo的撤销 | + | |
- | 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 javascript> | + | |
- | //视频收发数据统计 | + | |
- | emedia.mgr.onMediaTransmission(videoTag, function notify(trackId, type, subtype, data) { | + | |
- | var $iceStatsShow = $div.find("#iceStatsShow"); | + | |
- | var $em = $iceStatsShow.find("#"+subtype); | + | |
- | if(!$em.length){ | + | |
- | $em = $("<em></em>").appendTo($iceStatsShow).attr("id", subtype); | + | |
- | } | + | |
- | + | ||
- | $em.text(subtype + ":" + (data*8/1000).toFixed(2)); | + | |
- | }); | + | |
- | </code> | + | |
- | + | ||
- | <code javascript> | + | |
- | //连接状态变化 | + | |
- | emedia.mgr.onIceStateChanged(videoTag, function (state) { | + | |
- | console.log(state); | + | |
- | }); | + | |
- | </code> | + | |
- | + | ||
- | + | ||
- | ---- | + | |
- | <WRAP group> | + | |
- | <WRAP half column> | + | |
- | 上一页:[[im:web:basics:videocall|实时通话]] | + | |
- | </WRAP> | + | |
- | + | ||
- | <WRAP half column> | + | |
- | 下一页:[[im:web:other:toolrelated|工具类说明]] | + | |
- | </WRAP> | + | |
- | </WRAP> | + |