zhzf/client/public/js/webrtc.js

390 lines
17 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

class Webrtc {
/*******
* @name:
* @description:
* @param {object} InitialData 以下数据的对象
* @param {string} element 标签dom
* @param {boolean} debug 是否打印日志
* @param {string} zlmsdpUrl 流地址
* @param {boolean} simulcast 无线电和电视同步播放
* @param {boolean} useCamera 是否使用摄像头
* @param {boolean} audioEnable 音频数据
* @param {boolean} videoEnable 视频数据
* @param {boolean} recvOnly true是拉流 false是推流
* @param {object} resolution { w: 3840, h: 2160 } 分辨率
* @param {boolean} usedatachannel //数据通道
* @param {*} player webrtc实例
* @return {*}
* @author:
*/
/*
let InitialData = {
element:element,
debug:debug,
zlmsdpUrl:zlmsdpUrl,
simulcast:simulcast,
useCamera:useCamera,
audioEnable:audioEnable,
videoEnable:videoEnable,
recvOnly:recvOnly,
resolution:resolution,
usedatachannel:usedatachannel,
}
*/
constructor(InitialData) {
this.element = InitialData.element
this.debug = InitialData.debug
this.zlmsdpUrl = InitialData.zlmsdpUrl
this.simulcast = InitialData.simulcast
this.useCamera = InitialData.useCamera
this.audioEnable = InitialData.audioEnable
this.videoEnable = InitialData.videoEnable
this.recvOnly = InitialData.recvOnly
this.resolution = InitialData.resolution
this.usedatachannel = InitialData.usedatachannel
this.player = null
this.eventHandlers = {}
}
// 检测摄像头分辨率
detection() {
return new Promise((resolve, reject) => {
navigator.mediaDevices.enumerateDevices().then(devices => {
devices = devices.filter(d => d.kind === 'videoinput')
let creamData = devices[0].getCapabilities()
console.log(creamData, 'creamData')
let resolution = {}
resolution.w = creamData.width.max
resolution.h = creamData.height.max
resolve(resolution)
// this.resolution = resolution
}).catch((err) => {
console.log(err)
reject(err)
// this.resolution = resolution
})
})
}
// 拉流
start_play() {
return new Promise((resolve, reject) => {
let this_ = this
this.push_url = null
this.pull_url = null
let ZLMRTCClient = ZLMRTCClient_({})
if (this.useCamera) {
this.detection().then((resolution) => {
this.player = new ZLMRTCClient.Endpoint({
element: this.element,
debug: this.debug,
zlmsdpUrl: this.zlmsdpUrl,
simulcast: this.simulcast,
useCamera: this.useCamera,
audioEnable: this.audioEnable,
videoEnable: this.videoEnable,
recvOnly: this.recvOnly,
resolution: resolution,
usedatachannel: this.usedatachannel,
})
this.player.on(ZLMRTCClient.Events.WEBRTC_ICE_CANDIDATE_ERROR, function (e) { // ICE 协商出错
console.log('ICE 协商出错')
reject()
})
this.player.on(ZLMRTCClient.Events.WEBRTC_ON_REMOTE_STREAMS, function (e) { //获取到了远端流,可以播放
console.log('播放成功', e.streams, e, this_.zlmsdpUrl)
this_.pull_url = e.streams[0]
// resolve(e.streams[0])
})
this.player.on(ZLMRTCClient.Events.WEBRTC_OFFER_ANWSER_EXCHANGE_FAILED, function (e) { // offer anwser 交换失败
console.log('offer anwser 交换失败', e)
this_.stop_play(reject, 'offer anwser 交换失败')
})
// WEBRTC_IS_H265
this.player.on(ZLMRTCClient.Events.WEBRTC_IS_H265, function (e) { // offer anwser 交换失败
console.log('H265视频格式', e)
this_.stop_play(reject, '右上角设置打开插件模式以支持H265')
})
this.player.on(ZLMRTCClient.Events.WEBRTC_ON_LOCAL_STREAM, function (s) { // 获取到了本地流
console.log('获取到了本地流')
this_.push_url = s
// resolve(s)
})
this.player.on(ZLMRTCClient.Events.CAPTURE_STREAM_FAILED, function (s) { // 获取本地流失败
console.log('获取本地流失败', s)
this_.stop_play(reject, '获取本地流失败')
})
/**
*new表示刚创建一个新的 WebRTC 对象。
connecting表示正在建立连接。
connected表示已经成功建立连接。
disconnected表示连接已经中断。
failed表示连接失败。
closed表示连接已经关闭。
have-local-offer表示本地已经创建了一个 offer。
have-remote-offer表示远程端已经创建了一个 offer。
stable表示连接已经稳定。
have-local-pranswer表示本地已经创建了一个 pranswer。
have-remote-pranswer表示远程端已经创建了一个 pranswer。
* */
this.player.on(ZLMRTCClient.Events.WEBRTC_ON_CONNECTION_STATE_CHANGE, function (state) { // RTC 状态变化 ,详情参考 https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/connectionState
console.log('当前状态==>', state)
if (state == 'connected') {
if (this_.push_url) {
resolve(this_.push_url)
} else if (this_.pull_url) {
resolve(this_.pull_url)
}
} else {
this_.triggerEvent(state)
}
})
this.player.on(ZLMRTCClient.Events.WEBRTC_ON_DATA_CHANNEL_OPEN, function (event) {
console.log('rtc datachannel 打开 :', event)
})
this.player.on(ZLMRTCClient.Events.WEBRTC_ON_DATA_CHANNEL_MSG, function (event) {
console.log('rtc datachannel 消息 :', event.data)
})
this.player.on(ZLMRTCClient.Events.WEBRTC_ON_DATA_CHANNEL_ERR, function (event) {
console.log('rtc datachannel 错误 :', event)
})
this.player.on(ZLMRTCClient.Events.WEBRTC_ON_DATA_CHANNEL_CLOSE, function (event) {
console.log('rtc datachannel 关闭 :', event)
})
}).catch(() => {
this.player = new ZLMRTCClient.Endpoint({
element: this.element,
debug: this.debug,
zlmsdpUrl: this.zlmsdpUrl,
simulcast: this.simulcast,
useCamera: this.useCamera,
audioEnable: this.audioEnable,
videoEnable: this.videoEnable,
recvOnly: this.recvOnly,
resolution: this.resolution,
usedatachannel: this.usedatachannel,
})
this.player.on(ZLMRTCClient.Events.WEBRTC_ICE_CANDIDATE_ERROR, function (e) { // ICE 协商出错
console.log('ICE 协商出错')
reject()
})
this.player.on(ZLMRTCClient.Events.WEBRTC_ON_REMOTE_STREAMS, function (e) { //获取到了远端流,可以播放
console.log('播放成功', e.streams, e, this_.zlmsdpUrl)
this_.pull_url = e.streams[0]
// resolve(e.streams[0])
})
this.player.on(ZLMRTCClient.Events.WEBRTC_OFFER_ANWSER_EXCHANGE_FAILED, function (e) { // offer anwser 交换失败
console.log('offer anwser 交换失败', e)
this_.stop_play(reject, 'offer anwser 交换失败')
})
// WEBRTC_IS_H265
this.player.on(ZLMRTCClient.Events.WEBRTC_IS_H265, function (e) { // offer anwser 交换失败
console.log('H265视频格式', e)
this_.stop_play(reject, '右上角设置打开插件模式以支持H265')
})
this.player.on(ZLMRTCClient.Events.WEBRTC_ON_LOCAL_STREAM, function (s) { // 获取到了本地流
console.log('获取到了本地流')
this_.push_url = s
// resolve(s)
})
this.player.on(ZLMRTCClient.Events.CAPTURE_STREAM_FAILED, function (s) { // 获取本地流失败
console.log('获取本地流失败', s)
this_.stop_play(reject, '获取本地流失败')
})
/**
*new表示刚创建一个新的 WebRTC 对象。
connecting表示正在建立连接。
connected表示已经成功建立连接。
disconnected表示连接已经中断。
failed表示连接失败。
closed表示连接已经关闭。
have-local-offer表示本地已经创建了一个 offer。
have-remote-offer表示远程端已经创建了一个 offer。
stable表示连接已经稳定。
have-local-pranswer表示本地已经创建了一个 pranswer。
have-remote-pranswer表示远程端已经创建了一个 pranswer。
* */
this.player.on(ZLMRTCClient.Events.WEBRTC_ON_CONNECTION_STATE_CHANGE, function (state) { // RTC 状态变化 ,详情参考 https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/connectionState
console.log('当前状态==>', state)
if (state == 'connected') {
if (this_.push_url) {
resolve(this_.push_url)
} else if (this_.pull_url) {
resolve(this_.pull_url)
}
} else {
this_.triggerEvent(state)
}
})
this.player.on(ZLMRTCClient.Events.WEBRTC_ON_DATA_CHANNEL_OPEN, function (event) {
console.log('rtc datachannel 打开 :', event)
})
this.player.on(ZLMRTCClient.Events.WEBRTC_ON_DATA_CHANNEL_MSG, function (event) {
console.log('rtc datachannel 消息 :', event.data)
})
this.player.on(ZLMRTCClient.Events.WEBRTC_ON_DATA_CHANNEL_ERR, function (event) {
console.log('rtc datachannel 错误 :', event)
})
this.player.on(ZLMRTCClient.Events.WEBRTC_ON_DATA_CHANNEL_CLOSE, function (event) {
console.log('rtc datachannel 关闭 :', event)
})
})
} else {
this.player = new ZLMRTCClient.Endpoint({
element: this.element,
debug: this.debug,
zlmsdpUrl: this.zlmsdpUrl,
simulcast: this.simulcast,
useCamera: this.useCamera,
audioEnable: this.audioEnable,
videoEnable: this.videoEnable,
recvOnly: this.recvOnly,
resolution: this.resolution,
usedatachannel: this.usedatachannel,
})
this.player.on(ZLMRTCClient.Events.WEBRTC_ICE_CANDIDATE_ERROR, function (e) { // ICE 协商出错
console.log('ICE 协商出错')
reject()
})
this.player.on(ZLMRTCClient.Events.WEBRTC_ON_REMOTE_STREAMS, function (e) { //获取到了远端流,可以播放
console.log('播放成功', e.streams, e, this_.zlmsdpUrl)
this_.pull_url = e.streams[0]
// resolve(e.streams[0])
})
this.player.on(ZLMRTCClient.Events.WEBRTC_OFFER_ANWSER_EXCHANGE_FAILED, function (e) { // offer anwser 交换失败
console.log('offer anwser 交换失败', e)
this_.stop_play(reject, 'offer anwser 交换失败')
})
// WEBRTC_IS_H265
this.player.on(ZLMRTCClient.Events.WEBRTC_IS_H265, function (e) { // offer anwser 交换失败
console.log('H265视频格式', e)
this_.stop_play(reject, '右上角设置打开插件模式以支持H265')
})
this.player.on(ZLMRTCClient.Events.WEBRTC_ON_LOCAL_STREAM, function (s) { // 获取到了本地流
console.log('获取到了本地流')
this_.push_url = s
// resolve(s)
})
this.player.on(ZLMRTCClient.Events.CAPTURE_STREAM_FAILED, function (s) { // 获取本地流失败
console.log('获取本地流失败', s)
this_.stop_play(reject, '获取本地流失败')
})
/**
*new表示刚创建一个新的 WebRTC 对象。
connecting表示正在建立连接。
connected表示已经成功建立连接。
disconnected表示连接已经中断。
failed表示连接失败。
closed表示连接已经关闭。
have-local-offer表示本地已经创建了一个 offer。
have-remote-offer表示远程端已经创建了一个 offer。
stable表示连接已经稳定。
have-local-pranswer表示本地已经创建了一个 pranswer。
have-remote-pranswer表示远程端已经创建了一个 pranswer。
* */
this.player.on(ZLMRTCClient.Events.WEBRTC_ON_CONNECTION_STATE_CHANGE, function (state) { // RTC 状态变化 ,详情参考 https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/connectionState
console.log('当前状态==>', state)
if (state == 'connected') {
this_.player.pc.onjitterBuffer()
if (this_.push_url) {
resolve(this_.push_url)
} else if (this_.pull_url) {
resolve(this_.pull_url)
}
} else {
this_.triggerEvent(state)
}
})
this.player.on(ZLMRTCClient.Events.WEBRTC_ON_DATA_CHANNEL_OPEN, function (event) {
console.log('rtc datachannel 打开 :', event)
})
this.player.on(ZLMRTCClient.Events.WEBRTC_ON_DATA_CHANNEL_MSG, function (event) {
console.log('rtc datachannel 消息 :', event.data)
})
this.player.on(ZLMRTCClient.Events.WEBRTC_ON_DATA_CHANNEL_ERR, function (event) {
console.log('rtc datachannel 错误 :', event)
})
this.player.on(ZLMRTCClient.Events.WEBRTC_ON_DATA_CHANNEL_CLOSE, function (event) {
console.log('rtc datachannel 关闭 :', event)
})
}
})
}
// 拉流失败的回调
stop_play(reject, msg) {
if (this.player) {
this.player.close()
this.player = null
}
reject && reject(msg)
}
// 关闭拉流
close_play(remote1) {
return new Promise((resolve, reject) => {
console.log('关闭拉流或者推流')
if (this.player) {
this.player.close()
this.player = null
if (remote1) {
remote1.srcObject = null
remote1.load()
}
}
resolve()
})
}
on(eventName, eventHandler) {
if (!this.eventHandlers[eventName]) {
this.eventHandlers[eventName] = []
}
this.eventHandlers[eventName].push(eventHandler)
}
triggerEvent(eventName) {
const handlers = this.eventHandlers[eventName]
console.log(handlers)
if (handlers) {
handlers.forEach((handler) => {
handler()
})
}
}
}