zhzf/client/public/js/webrtc.js

390 lines
17 KiB
JavaScript
Raw Normal View History

2025-02-14 16:04:21 +08:00
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()
})
}
}
}