UNPKG

zby-live-sdk

Version:

This is a live SDK for weclassroom.

712 lines (657 loc) 19 kB
/** * @File: Agora 音视频 SDK * @Author: xuyuanrui * @Email: raywhbxyr@163.com * @Date: 2018-08-06 11:00:29 **/ // 扩展标识 const extensionId = 'agora_ext'; // 端提供的 API 入口 const EM = window.EM; /** * @function 调用端提供的回调方法 * @param name:String 回调方法名,必选 * @param args:Object 回调参数,必选 * @return Promise | void */ const callMethod = (name, args) => { // EM 是寄宿于端的,浏览器中并不存在,为防止报错需要先进行能力检测 if (EM) { return new Promise((resolve, reject) => { EM.CallMethod( extensionId, name, JSON.stringify(args), (code, msg) => { console.log(`${name} Code: ${code}\nMessage: ${msg}`); resolve({ code, msg }); } ); }); } }; /** * @function 加载声网扩展 * @param extensionVersion:String 扩展版本号,必选 * @return Promise | void */ export const loadAgora = (extensionVersion) => { // EM 是寄宿于端的,浏览器中并不存在,为防止报错需要先进行能力检测 if (EM) { return new Promise((resolve, reject) => { EM.Load( extensionId, extensionVersion, false, (code, msg) => { console.log(`loadAgora Code: ${code}\nMessage: ${msg}`); resolve(); } ); }); } }; /** * @function 卸载声网扩展 * @return Promise | void */ export const unloadAgora = () => { // EM 是寄宿于端的,浏览器中并不存在,为防止报错需要先进行能力检测 if (EM) { return new Promise((resolve, reject) => { EM.UnLoad( extensionId, (code, msg) => { console.log(`unloadAgora Code: ${code}\nMessage: ${msg}`); resolve(); } ); }); } }; /** * @function 添加扩展监听机制 * @return void */ const addListener = () => { // EM 是寄宿于端的,浏览器中并不存在,为防止报错需要先进行能力检测 if (EM) { EM.AddListener(extensionId, (event, data) => { console.log(`AddListener Event: ${event}\nData: ${data}`); }); } }; /** * @function 创建 IRtcEngine 对象 * @param appId:String Agora 秘钥,必选 * @return Promise | void */ export const startEngine = (appId) => { return callMethod('StartEngine', { appId }); }; /** * @function 设置频道属性 * 该方法用于设置频道模式(profile), * Agora RtcEngine 需知道应用程序的使用场景(例如通信模式或直播模式), * 从而使用不同的优化手段。 * @param profile 频道模式,可选,默认 0,即使用通信模式, * 用于常见的一对一或群聊,频道中的任何用户可以自由说话 * @return Promise | void */ export const setChannelProfile = (profile) => { if (typeof profile === 'undefined') { profile = 0; } return callMethod('SetChannelProfile', { profile }); }; /** * @function 打开视频模式 * 可以在加入频道前或者通话中调用,在加入频道前调用, * 则自动开启视频模式,在通话中调用则由音频模式切换为视频模式。 * 调用 disableVideo() 方法可关闭视频模式。 * @return Promise | void */ export const enableVideo = () => { return callMethod('EnableVideo', {}); }; /** * @function 关闭视频模式 * 可以在加入频道前或者通话中调用,在加入频道前调用, * 则自动开启纯音频模式,在通话中调用则由视频模式切换为纯音频频模式。 * 调用 enableVideo() 方法可开启视频模式。 * @return Promise | void */ export const disableVideo = () => { return callMethod('DisableVideo', {}); }; /** * @function 设置本地视频显示属性 * @param userId:Number 用户 id * @return Promise | void */ export const setupLocalVideo = (userId) => { return callMethod('SetupLocalVideo', { uid: userId }); }; /** * @function 设置远端视频显示属性 * @param userId:Number 用户 id * @return Promise | void */ export const setupRemoteVideo = (userId) => { return callMethod('SetupRemoteVideo', { uid: userId }); }; /** * @function 设置本地视频编码属性 * 应在调用 enableVideo 后设置视频属性 * 应在调用 joinChannel/startPreview 前设置视频属性 * @param profile:Number 视频分辨率、帧率和码率,可选,默认 30 * @param swapWidthAndHeight:Boolean 是否交换宽和高,可选,默认 false * @return Promise | void */ export const setVideoProfile = (profile, swapWidthAndHeight) => { if (typeof profile === 'undefined') { profile = 30; } if (typeof swapWidthAndHeight === 'undefined') { swapWidthAndHeight = false; } return callMethod('SetVideoProfile', { profile, swapWidthAndHeight }); }; /** * @function 开启本地视频预览 * @return Promise | void */ export const startPreview = () => { return callMethod('StartPreview', {}); }; /** * @function 停止本地视频预览 * @return Promise | void */ export const stopPreview = () => { return callMethod('StopPreview', {}); }; /** * @function 加入频道 * @param userId:Number 用户 id,必选 * @param channelId:String 用课节 id 标识的频道号,必选 * @param token:String Agora 提供的 token,必选 * @return Promise | void */ export const joinChannel = (userId, channelId, token) => { return callMethod('JoinChannel', { uid: userId, channelId, token }); }; /** * @function 离开频道 * @return Promise | void */ export const leaveChannel = () => { return callMethod('LeaveChannel', {}); }; /** * @function 启用本地视频 * @param enabled:Boolean * @return Promise | void */ export const enableLocalVideo = (enabled) => { return callMethod('REPS.EnableLocalVideo', { enabled }); }; /** * @function 获取系统中所有的摄像头列表 * @return Promise | void */ export const enumerateVideoDevices = () => { return callMethod('IVDM.EnumerateVideoDevices', {}); }; /** * @function 指定使用的摄像头 * @param deviceId:String 摄像头 id * @return Promise | void */ export const setCameraDevice = (deviceId) => { return callMethod('IVDM.SetDevice', { deviceId }); }; /** * @function 静音/取消静音。暂停/开始发送音频流 * 将自己静音/取消静音,该方法用于禁止/允许往网络发送本地音频流 * @param mute:Boolean * @return Promise | void */ export const muteLocalAudioStream = (mute) => { return callMethod('REPS.MuteLocalAudioStream', { mute }); }; /** * @function 暂停/开始发送视频流 * 该方法不影响本地视频流获取,没有禁用摄像头。 * @param mute:Boolean * @return Promise | void */ export const muteLocalVideoStream = (mute) => { return callMethod('REPS.MuteLocalVideoStream', { mute }); }; /** * @function 打开音频 * @return Promise | void */ export const enableAudio = () => { return callMethod('EnableAudio', {}); }; /** * @function 关闭音频 * @return Promise | void */ export const disableAudio = () => { return callMethod('DisableAudio', {}); }; /** * @function 获取系统中所有的扬声器列表 * @return Promise | void */ export const enumeratePlaybackDevices = () => { return callMethod('IADM.EnumeratePlaybackDevices', {}); }; /** * @function 指定扬声器 * @param deviceId:String 扬声器的 Device ID,必选 * 可通过 enumeratePlaybackDevices() 获取 * 插拔设备不会影响 deviceId * @return Promise | void */ export const setPlaybackDevice = (deviceId) => { return callMethod('IADM.SetPlaybackDevice', { deviceId }); }; /** * @function 获取扬声器音量 * @return Promise | void */ export const getPlaybackDeviceVolume = () => { return callMethod('IADM.GetPlaybackDeviceVolume', {}); }; /** * @function 设置扬声器音量 * @param volume:Number 扬声器音量,取值 [0, 255],必选 * @return Promise | void */ export const setPlaybackDeviceVolume = (volume) => { return callMethod('IADM.SetPlaybackDeviceVolume', { volume }); }; /** * @function 控制扬声器是否静音 * @param mute:Boolean 必选 * @return Promise | void */ export const setPlaybackDeviceMute = (mute) => { return callMethod('IADM.SetPlaybackDeviceMute', { mute }); }; /** * @function 启动扬声器测试 * @param testAudioFilePath * @return Promise | void */ export const startPlaybackDeviceTest = (testAudioFilePath) => { return callMethod('IADM.StartPlaybackDeviceTest', { testAudioFilePath }); }; /** * @function 停止扬声器测试 * @return Promise | void */ export const stopPlaybackDeviceTest = () => { return callMethod('IADM.StopPlaybackDeviceTest', {}); }; /** * @function 获取 App 音量 * @return Promise | void */ export const getApplicationVolume = () => { return callMethod('IADC.GetApplicationVolume', {}); }; /** * @function 设置 App 音量 * @param volume 音量值,范围 [0, 255] * @return Promise | void */ export const setApplicationVolume = (volume) => { return callMethod('IADC.SetApplicationVolume', { volume }); }; /** * @function 设置 App 静音 * @param mute:Boolean * @return Promise | void */ export const setApplicationMute = (mute) => { return callMethod('IADC.SetApplicationMute', { mute }); }; /** * @function 获取系统中所有的麦克风列表 * @return Promise | void */ export const enumerateRecordingDevices = () => { return callMethod('IADM.EnumerateRecordingDevices', {}); }; /** * @function 指定麦克风 * @param deviceId:String 麦克风的 Device ID,必选 * 可通过 enumerateRecordingDevices() 获取 * 插拔设备不会影响 deviceId * @return Promise | void */ export const setRecordingDevice = (deviceId) => { return callMethod('IADM.SetRecordingDevice', { deviceId }); }; /** * @function 获取麦克风音量 * @return Promise | void */ export const getRecordingDeviceVolume = () => { return callMethod('IADM.GetRecordingDeviceVolume', {}); }; /** * @function 设置麦克风音量 * @param volume:Number 麦克风音量,取值 [0, 255],必选 * @return Promise | void */ export const setRecordingDeviceVolume = (volume) => { return callMethod('IADM.SetRecordingDeviceVolume', { volume }); }; /** * @function 静音麦克风 * @param mute:Boolean * @return Promise | void */ export const setRecordingDeviceMute = (mute) => { return callMethod('IADM.SetRecordingDeviceMute', { mute }); }; /** * @function 启动麦克风测试 * @param indicationInterval 向应用程序上报音量信息的时间间隔,推荐 500 * @return Promise | void */ export const startRecordingDeviceTest = (indicationInterval) => { return callMethod('IADM.StartRecordingDeviceTest', { indicationInterval }); }; /** * @function 停止麦克风测试 * @return Promise | void */ export const stopRecordingDeviceTest = () => { return callMethod('IADM.StopRecordingDeviceTest', {}); }; /** * @function 启用说话者音量提示 * 该方法允许 SDK 定期向应用程序反馈当前谁在说话以及说话者的音量。 * @param interval 指定音量提示的时间间隔 * <= 0: 禁用音量提示功能 * > 0: 提示间隔,单位为毫秒 * 建议设置到大于 200 毫秒 * @param smooth 平滑系数。默认可以设置为 3 * @return Promise | void */ export const enableAudioVolumeIndication = (interval, smooth) => { return callMethod('REPS.EnableAudioVolumeIndication', { interval, smooth }); }; /** * @function 开启本地或者远程的视频视图 * @param isLocal:Boolean 是否是本地的视频预览,必选 * @param streamId:String 要拉取的视频流的 id,可选,只有拉取远程的视频流的时候才是必选的 * @param domId:String <video> 标签的 id,可选 * 如果传了 domId,就把视频绑定到对应的 <video> 标签上 * @return Promise,可从 Promise 中获取 src,Promise.then((src) => {}) */ export const startLocalOrRemotePreview = (isLocal, streamId, domId) => { let playChannel = null; if (isLocal) { playChannel = window.zbyAVSDK_init_params.agora.userId; } else { playChannel = +(streamId.split('_')[2]); } const externalConstraints = { audio: false, video: { mandatory: { chromeMediaSource: 'external', chromeMediaSourceId: `ems://agora/${playChannel}` } } }; return new Promise((resolve, reject) => { const handleExternalSuccess = (stream) => { stream.oninactive = () => { console.log('Stream inactive'); }; const src = window.URL.createObjectURL(stream); if (domId) { document.querySelector(domId).src = src; } resolve(src); }; const handleExternalError = (error) => { if (error.name === 'ConstraintNotSatisfiedError') { console.error('ConstraintNotSatisfiedError'); // console.error(`The resolution ${cameraConstraints.video.width.exact}x${ // cameraConstraints.video.width.exact} px is not supported by your device.`); } else if (error.name === 'PermissionDeniedError') { console.error( 'Permissions have not been granted to use your camera and ' + 'microphone, you need to allow the page access to your devices in ' + 'order for the demo to work.' ); } console.error(`getUserMedia error: ${error.name}`, error); if (domId) { document.querySelector(domId).src = ''; } reject(''); }; if (navigator.webkitGetUserMedia) { navigator.webkitGetUserMedia( externalConstraints, handleExternalSuccess, handleExternalError ); } }); }; /** * @function 初始化 * @param args:Object * { * extensionVersion, // String,扩展版本号,必选 * appId, // String,Agora 秘钥,必选 * userId, // Number,用户 id,必选 * roomId, // String,频道号(房间号),必选 * token, // String,Agora 提供的 token,可选,默认与 appId 相同 * swapWidthAndHeight, // Boolean,是否交换宽和高,可选,默认 false * videoProfile, // Number,视频分辨率、帧率和码率,可选,默认 30 * channelProfile // Number,频道模式,可选,默认 0 * } * @return Promise */ export const init = async (args) => { await loadAgora(args.extensionVersion); addListener(); await startEngine(args.appId); await setChannelProfile(args.channelProfile); await enableVideo(); await setVideoProfile(args.videoProfile, args.swapWidthAndHeight); if (typeof args.token === 'undefined') { await joinChannel(args.userId, args.roomId, args.appId); } else { await joinChannel(args.userId, args.roomId, args.token); } await setupLocalVideo(args.userId); // 初始化的时候不推流 await muteLocalVideoStream(true); // 初始化的时候不打开麦克风 await muteLocalAudioStream(true); // 初始化的时候不打开摄像头 await enableLocalVideo(false); }; /** * @function 开始推流 * @return Promise */ export const startPushFlow = async () => { await muteLocalVideoStream(false); await muteLocalAudioStream(false); }; /** * @function 停止推流 * @return Promise */ export const stopPushFlow = async () => { await muteLocalVideoStream(true); await muteLocalAudioStream(true); }; /** * @function 初始化拉流 * @param streamId:String 被拉取的流的 id,必选 * @param domId:String <video> 标签的 id,可选 * 如果传了就把视频绑定到对应的 <video> 标签上 * @return src:String 视频预览地址 */ export const initPullFlow = async (streamId, domId) => { await setupRemoteVideo(+(streamId.split('_')[2])); return await startLocalOrRemotePreview(false, streamId, domId); }; /** * @function 恢复拉指定用户的流 * @param streamId:String 被拉取的流的 id,必选 * @return Promise */ export const startPullFlow = async (streamId) => { const userId = +(streamId.split('_')[2]); await muteRemoteVideoStream(userId, false); await muteRemoteAudioStream(userId, false); }; /** * @function 暂停拉指定用户的流 * @param streamId:String 被拉取的流的 id,必选 * @return Promise */ export const stopPullFlow = async (streamId) => { const userId = +(streamId.split('_')[2]); await muteRemoteVideoStream(userId, true); await muteRemoteAudioStream(userId, true); }; /** * @function 暂停指定远端视频流 * @param userId:Number 被拉取视频流的用户的 id,必选 * @param mute:Boolean 必选 * @return Promise | void */ export const muteRemoteVideoStream = (userId, mute) => { return callMethod('MuteRemoteVideoStream', { uid: userId, mute }); }; /** * @function 暂停指定远端音频流 * @param userId:Number 被拉取音频流的用户的 id,必选 * @param mute:Boolean 必选 * @return Promise | void */ export const muteRemoteAudioStream = (userId, mute) => { return callMethod('MuteRemoteAudioStream', { uid: userId, mute }); }; export default { loadAgora, unloadAgora, startEngine, setVideoProfile, setChannelProfile, joinChannel, leaveChannel, enumerateVideoDevices, setCameraDevice, enableAudio, disableAudio, enableVideo, disableVideo, muteLocalAudioStream, muteLocalVideoStream, startPreview, stopPreview, enableLocalVideo, setupLocalVideo, setupRemoteVideo, startLocalOrRemotePreview, enumeratePlaybackDevices, setPlaybackDevice, startPlaybackDeviceTest, stopPlaybackDeviceTest, getPlaybackDeviceVolume, setPlaybackDeviceVolume, setPlaybackDeviceMute, getApplicationVolume, setApplicationVolume, setApplicationMute, enumerateRecordingDevices, setRecordingDevice, getRecordingDeviceVolume, setRecordingDeviceVolume, setRecordingDeviceMute, startRecordingDeviceTest, stopRecordingDeviceTest, enableAudioVolumeIndication, init, startPushFlow, stopPushFlow, initPullFlow, startPullFlow, stopPullFlow, muteRemoteVideoStream, muteRemoteAudioStream };