zby-live-sdk
Version:
This is a live SDK for weclassroom.
712 lines (657 loc) • 19 kB
JavaScript
/**
* @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
};