import { checkBrowser } from './playerWasm/public.js'
import PlayerControl from './playerWasm/PlaySDKInterface.js'
const loadScript = (src, callback) => {
const dom = document.createElement('script')
dom.src = src
document.head.appendChild(dom)
var loaded = false
if (typeof callback === 'function') {
dom.onload = dom.onreadystatechange = function () {
if (!loaded && (!dom.readyState || /loaded|complete/.test(dom.readyState))) {
dom.onload = dom.onreadystatechange = null
loaded = true
callback()
}
}
}
}
let m_bClientInitialized = false
let m_nModuleInitialized = false
// Load multi-threaded PlaySDK library files
const loadLibPlaySDK = () => {
const libPath = '/static/WasmLib/MultiThread/libplay.js'
if (!isInclude('MultiThread/libplay.js')) {
loadScript(libPath, null)
}
}
// Load multi-threaded streaming library files
const loadLibStreamClient = () => {
let libPath = '/static/WasmLib/MultiThread/libStreamClient.js'
if (!isInclude('MultiThread/libStreamClient.js')) {
loadScript(libPath, () => {
// Initialize Streaming Module
Multi_Client_Module().then((instance) => {
window.SCModule = instance
// Multiple channels only need to be initialized once
window.SCModule._GLOBAL_Init()
m_bClientInitialized = true
})
})
}
}
// Load rendering engine files
const loadLibRenderEngine = () => {
let libPath = '/static/WasmLib/Common/libRenderEngine.js'
if (!isInclude('Common/libRenderEngine.js')) {
loadScript(libPath, () => {
// Initialize rendering engine module
RenderEngine_Module().then((instance) => {
window.REModule = instance
})
})
}
}
// Load IVSdrawer file
const loadLibIVSDrawer = () => {
let libPath = '/static/WasmLib/Common/libIVSDrawer.js'
if (!isInclude('Common/libIVSDrawer.js')) {
loadScript(libPath, () => {
// Initialize IVSDrawer Module
IVSDrawer_Module().then((instance) => {
window.IVSModule = instance
})
})
}
}
const loadLibASPLite = () => {
let libPath = '/static/WasmLib/Common/libmavasp_litepacket.js'
let dataPath = '/static/WasmLib/Common/libmavasp_litepacket.data'
if (!isInclude('Common/libmavasp_litepacket.js')) {
loadScript(libPath, () => {
// Set the path to the libmavasp_litepacket.data configuration file
ASPLite_Module['locateFile'] = function (path, prefix) {
if (path.endsWith('.data')) {
return dataPath
}
return prefix + path
}
// Initialize ASPLite Module
ASPLite_Module(ASPLite_Module).then((instance) => {
window.ASPLiteModule = instance
})
})
}
}
if (!window.Module) {
window.Module = {}
}
// PlaySDK wasm module loading and initialization completed callback
Module.onRuntimeInitialized = function () {
m_nModuleInitialized = true
}
// Reset font file path
Module.locateFile = function (path, prefix) {
if (path.endsWith('.data')) {
return '/static/WasmLib/MultiThread/libplay.data'
}
return prefix + path
}
const isInclude = (name) => {
var js = /js$/i.test(name)
var es = document.getElementsByTagName(js ? 'script' : 'link')
for (var i = 0; i < es.length; i++) {
if (es[i][js ? 'src' : 'href'].indexOf(name) != -1) return true
}
return false
}
const loadLibDHPlay = (bSupportMultiThread) => {
if (bSupportMultiThread) {
loadLibPlaySDK()
// Multi threaded version, using StreamClient wasm module for streaming
loadLibStreamClient()
}
if (!bSupportMultiThread) {
loadLibRenderEngine()
}
loadLibIVSDrawer()
// Load 3A algorithm library
loadLibASPLite()
let timer = null
return new Promise((resolve) => {
timer = setInterval(() => {
if (!bSupportMultiThread || (m_nModuleInitialized && m_bClientInitialized)) {
clearInterval(timer)
resolve()
}
})
})
}
class Player {
constructor(ids, callbacks) {
this.ids = ids || []
this.playControls = {}
this.nPorts = {}
this.volumes = {}
this.talkVolumes = {}
this.playStatus = {}
this.recordingStatus = {}
this.timers = {}
this.downloadTimers = {}
this.playError = callbacks.playError ? callbacks.playError : () => {}
this.playFileOver = callbacks.playFileOver ? callbacks.playFileOver : () => {}
this.captureCallback = callbacks.captureCallback ? callbacks.captureCallback : () => {}
this.playStart = callbacks.playStart ? callbacks.playStart : () => {}
this.playProgressUpdate = callbacks.playProgressUpdate ? callbacks.playProgressUpdate : () => {}
this.talkError = callbacks.talkError ? callbacks.talkError : () => {}
this.downloadError = callbacks.downloadError ? callbacks.downloadError : () => {}
this.downloadComplete = callbacks.downloadComplete ? callbacks.downloadComplete : () => {}
this.videoDownloadDuration = callbacks.videoDownloadDuration
? callbacks.videoDownloadDuration
: () => {}
this.downloadProgressUpdate = callbacks.downloadProgressUpdate
? callbacks.downloadProgressUpdate
: () => {}
this.runtimeInitializedCallBack = callbacks.runtimeInitializedCallBack
? callbacks.runtimeInitializedCallBack
: null
}
/**
* @param { Array } ids Play window id collection
*/
async init() {
if (!this.ids) return
if (!Array.isArray(this.ids)) this.ids = [this.ids]
this.ids.forEach((id) => {
this.playControls[id] = {}
this.drawVideoDom(id)
})
window.cPlusVisibleDecCallBack = (nPort, pBufY, pBufU, pBufV, nSize, pFrameInfo) => {
this.ids.forEach((id) => {
if (this.nPorts[id] && this.nPorts[id].playerPort == nPort) {
this.playControls[id].player &&
this.playControls[id].player.SetFrameData(
nPort,
pBufY,
pBufU,
pBufV,
nSize,
pFrameInfo,
this.volumes[id]
)
return true
} else if (this.nPorts[id] && this.nPorts[id].talkPort == nPort) {
this.playControls[id].talkPlayer &&
this.playControls[id].talkPlayer.SetFrameData(
nPort,
pBufY,
pBufU,
pBufV,
nSize,
pFrameInfo,
this.talkVolumes[id],
true
)
return true
} else if (this.nPorts[id] && this.nPorts[id].downloadPlayerPort == nPort) {
this.playControls[id].downloadPlayer &&
this.playControls[id].downloadPlayer.SetFrameData(
nPort,
pBufY,
pBufU,
pBufV,
nSize,
pFrameInfo,
0
)
return true
}
})
}
window.cDigitalSignCallBack = (nPort, nFrameID, bSuccess) => {
this.ids.forEach((id) => {
if (this.nPorts[id] && this.nPorts[id].playerPort == nPort) {
this.playControls[id].player &&
this.playControls[id].player.SetDecryptionResult(nPort, nFrameID, bSuccess)
} else if (this.nPorts[id] && this.nPorts[id].downloadPlayerPort == nPort) {
this.playControls[id].downloadPlayer &&
this.playControls[id].downloadPlayer.SetDecryptionResult(nPort, nFrameID, bSuccess)
}
})
}
window.cExtraDrawDataCallBack = (nPort, nDataType, pDrawData, nDataLen) => {
this.ids.forEach((id) => {
if (this.nPorts[id] && this.nPorts[id].playerPort == nPort) {
this.playControls[id].player &&
this.playControls[id].player.setIVSData(nPort, nDataType, pDrawData, nDataLen)
} else if (this.nPorts[id] && this.nPorts[id].downloadPlayerPort == nPort) {
this.playControls[id].downloadPlayer &&
this.playControls[id].downloadPlayer.setIVSData(nPort, nDataType, pDrawData, nDataLen)
}
})
}
window.cExtraDrawDrawCallBack = (nPort) => {
this.ids.forEach((id) => {
if (this.nPorts[id] && this.nPorts[id].playerPort == nPort) {
this.playControls[id].player && this.playControls[id].player.drawIVSData(nPort)
} else if (this.nPorts[id] && this.nPorts[id].downloadPlayerPort == nPort) {
this.playControls[id].downloadPlayer &&
this.playControls[id].downloadPlayer.drawIVSData(nPort)
}
})
}
window.cRecordDataCallBack = (nPort, pData, nDataLen, nOffset, pRecordFrameInfo) => {
this.ids.forEach((id) => {
if (this.nPorts[id] && this.nPorts[id].playerPort == nPort) {
this.playControls[id].player &&
this.playControls[id].player.SetRecordData(
nPort,
pData,
nDataLen,
nOffset,
pRecordFrameInfo
)
} else if (this.nPorts[id] && this.nPorts[id].downloadPlayerPort == nPort) {
this.playControls[id].downloadPlayer &&
this.playControls[id].downloadPlayer.SetRecordData(
nPort,
pData,
nDataLen,
nOffset,
pRecordFrameInfo
)
}
})
}
window.cIVSDrawDataCallBack = (nPort, buf, type, len, reallen) => {
this.ids.forEach((id) => {
if (this.nPorts[id] && this.nPorts[id].playerPort == nPort) {
this.playControls[id].player &&
this.playControls[id].player.SetIVSDrawData(nPort, buf, type, len, reallen)
} else if (this.nPorts[id] && this.nPorts[id].downloadPlayerPort == nPort) {
this.playControls[id].downloadPlayer &&
this.playControls[id].downloadPlayer.SetIVSDrawData(nPort, buf, type, len, reallen)
}
})
}
window.cPlusMediaFrameCallBack = (handle, index, pData, nDataLength) => {
this.ids.forEach((id) => {
if (this.nPorts[id] && this.nPorts[id].playerHandle == handle) {
this.playControls[id].player &&
this.playControls[id].player.InputDataEx(pData, nDataLength)
} else if (this.nPorts[id] && this.nPorts[id].talkHandle == handle) {
this.playControls[id].talkPlayer &&
this.playControls[id].talkPlayer.InputDataEx(pData, nDataLength)
} else if (this.nPorts[id] && this.nPorts[id].downloadHandle == handle) {
this.playControls[id].downloadPlayer &&
this.playControls[id].downloadPlayer.InputDataEx(pData, nDataLength)
}
})
}
window.cPlusRtspMsgCallBack = (handle, type, attach) => {
this.ids.forEach((id) => {
let playerHandle = null
let player = null
if (this.nPorts[id] && this.nPorts[id].playerHandle == handle) {
playerHandle = this.nPorts[id].playerHandle
player = this.playControls[id].player
} else if (this.nPorts[id] && this.nPorts[id].talkHandle == handle) {
playerHandle = this.nPorts[id].talkHandle
player = this.playControls[id].talkPlayer
} else if (this.nPorts[id] && this.nPorts[id].downloadHandle == handle) {
playerHandle = this.nPorts[id].downloadHandle
player = this.playControls[id].downloadPlayer
}
if (playerHandle && player) {
switch (type) {
// The module responsible for handling the RTSP protocol flow, if it fails during RTSP processing, sends the message to the message receiver
// Upon receiving this message, the recipient should call Close() to close the client. The attached parameter attach to the message is not used
case 0x1000:
player.StreamFailedCallback(attach)
player.StopPullStream()
player.StreamDisconnectCallback()
break
// Indicates that the client has completed the initialization and setup steps for the peer, and at this point, the user can obtain the SDP,
// The attached parameter attach to the message is not used.
// RTSP_PutStream can only be called after receiving this message in intercom services
case 0x1001:
break
// Indicates that all streams on the server have been received and the receiver should call Close() to clean up resources
// The attached parameter attach to the message is not used.
case 0x1004:
player.StreamFinishCallback()
break
// RTSP redirect message, when the client has configured clientConfigRedirDisable to enable, it will notify the upper layer of the message,
// Implement redirection function from the upper layer
case 0x1008:
player.StreamRedirectCallback(attach)
break
}
}
})
}
window.cPlusRtsvMsgCallBack = (handle, type) => {
this.ids.forEach((id) => {
let playerHandle = null
let player = null
if (this.nPorts[id] && this.nPorts[id].playerHandle == handle) {
playerHandle = this.nPorts[id].playerHandle
player = this.playControls[id].player
} else if (this.nPorts[id] && this.nPorts[id].talkHandle == handle) {
playerHandle = this.nPorts[id].talkHandle
player = this.playControls[id].talkPlayer
} else if (this.nPorts[id] && this.nPorts[id].downloadHandle == handle) {
playerHandle = this.nPorts[id].downloadHandle
player = this.playControls[id].downloadPlayer
}
if (playerHandle) {
switch (type) {
case 0x4001:
// Only after receiving this message in the intercom business can RTSV-PutStream be called
break
case 0x4002:
player.StreamFinishCallback()
break
}
}
})
}
Module.onRuntimeInitialized = function () {
m_nModuleInitialized = true
this.runtimeInitializedCallBack && this.runtimeInitializedCallBack()
}
const { bSupportMultiThread } = checkBrowser()
if (!isInclude('/libplay.js')) {
await loadLibDHPlay(bSupportMultiThread)
}
}
drawVideoDom(id) {
const dom = document.querySelector(`#${id}`)
let videoDom = `
`
if (dom) dom.innerHTML = videoDom
}
/**
* @description play
* @param { string } id play window id
* @param { object } options parameters to play
*/
play(id, options) {
if (!options.streamURL) return
if (this.playControls[id] && this.playControls[id].player) {
this.close(id)
}
const {
isPrivateProtocol,
wsURL,
stream,
sourceId,
deviceId,
userName,
password,
npt,
open3DPoint,
encryptMode,
isSandardPack,
volume
} = this.parameterProcessing(options)
this.volumes[id] = volume
const initParam = {
canvasElem: document.querySelector(`#can-${id}`),
videoElem: document.querySelector(`#video-${id}`),
ivsCanvasElem: document.querySelector(`#ivsCan-${id}`),
bPlayBack: options.isLive === false,
strDecodeFilePath: '/static/WasmLib/SingleThread'
}
const urlParam = {
strRtspvUri: wsURL,
strRtspvUrl: stream,
strPlayToken: '',
strPlayTokenKey: '',
strDeviceID: deviceId,
strSourceId: isPrivateProtocol ? sourceId : '',
strUserName: userName,
strPassWord: password,
bTalkService: false,
nRange: npt,
nShortTimeout: 3,
nRtspResponseTimeout: 8,
bStandardPack: isSandardPack
}
const { bSupportMultiThread } = checkBrowser()
if (!this.playControls[id]) this.playControls[id] = {}
if (!this.nPorts[id]) this.nPorts[id] = {}
this.playControls[id].player = new PlayerControl(bSupportMultiThread)
const player = this.playControls[id].player
const loadingElement = document.querySelector(`#loading-${id}`)
if (loadingElement) {
loadingElement.style.display = 'block'
}
player.SetCallBack('StreamPlayOver', () => {
if (this.playControls[id].player) {
setTimeout(() => {
this.close(id)
this.playFileOver(id)
}, 1)
}
})
player.SetCallBack('PlayStart', () => {
this.playStatus[id] = true
// Define the ID for easier reference
const elementId = `#can-${id}`
const ivsElementId = `#ivsCan-${id}`
const videoElementId = `#video-${id}`
const loadingElementId = `#loading-${id}`
// Check if the elements exist before applying styles
const canElement = document.querySelector(elementId)
const ivsCanElement = document.querySelector(ivsElementId)
const videoElement = document.querySelector(videoElementId)
const loadingElement = document.querySelector(loadingElementId)
if (canElement) {
canElement.style.visibility = 'visible'
}
if (ivsCanElement) {
ivsCanElement.style.visibility = 'visible'
}
if (videoElement) {
videoElement.style.visibility = 'visible'
}
if (loadingElement) {
loadingElement.style.display = 'none'
}
this.playStart()
})
player.SetCallBack('CapturePicDataCallBack', (blob) => {
this.captureCallback(id, blob)
})
player.SetCallBack('VideoFrameInfo', (e) => {
if (e.timeStamp) {
clearTimeout(this.timers[id])
this.timers[id] = setTimeout(() => {
this.playError(id, {
errorCode: '409',
errMsg: 'Rtsp Not Response.'
})
}, 10000)
}
const msg = {
frameRate: e.nFrameRate,
time: e.timeStamp,
utcTime: e.utcTimeStamp
}
this.playProgressUpdate(id, msg)
})
player.SetCallBack('DecodeStart', (e) => {
if (e.decodeMode === 'video') {
const canElement = document.querySelector(`#can-${id}`)
if (canElement) {
canElement.style.display = 'none'
}
const videoElement = document.querySelector(`#video-${id}`)
if (videoElement) {
videoElement.style.display = ''
}
} else {
const canElement = document.querySelector(`#can-${id}`)
if (canElement) {
canElement.style.display = ''
}
const videoElement = document.querySelector(`#video-${id}`)
if (videoElement) {
videoElement.style.display = 'none'
}
}
})
player.SetCallBack('Error', (e) => {
this.playStatus[id] = false
const elementId = `#can-${id}`
const ivsElementId = `#ivsCan-${id}`
const videoElementId = `#video-${id}`
const loadingElementId = `#loading-${id}`
// Check if the elements exist before applying styles
const canElement = document.querySelector(elementId)
const ivsCanElement = document.querySelector(ivsElementId)
const videoElement = document.querySelector(videoElementId)
const loadingElement = document.querySelector(loadingElementId)
if (canElement) {
canElement.style.visibility = 'hidden'
}
if (ivsCanElement) {
ivsCanElement.style.visibility = 'hidden'
}
if (videoElement) {
videoElement.style.visibility = 'hidden'
videoElement.style.display = 'none'
}
if (loadingElement && loadingElement.style.display == 'block') {
loadingElement.style.display = 'none'
}
this.playError(id, e)
})
player.SetCallBack('GetPlayPort', (port) => {
this.nPorts[id].playerPort = port
})
player.SetCallBack('GetOriginalKey', ({ nRet, outKey }) => {
if (nRet == 1) {
urlParam.strDeviceID = outKey
this.nPorts[id].playerHandle = player.StartPullStream(JSON.parse(JSON.stringify(urlParam)))
}
})
// player.SetPrintLogLevel(6)
player.Init(initParam)
player.SetSoundState(true)
player.SetVolume(this.volumes[id])
player.Set3DPoint(open3DPoint)
if (encryptMode) {
player.GetOriginalKey({
strPlayToken: '',
strPlayTokenKey: '',
strDeviceID: deviceId
})
} else {
this.nPorts[id].playerHandle = player.StartPullStream(JSON.parse(JSON.stringify(urlParam)))
}
}
/**
* @description download
* @param { string } id download window id
* @param { object } options parameters to download
* @param { string } fileName file name
* @param { number } speed download speed
*/
download(id, options, fileName, speed = 2) {
if (!options.streamURL) return
if (this.playControls[id] && this.playControls[id].downloadPlayer) {
this.playControls[id].downloadPlayer.StopRecord()
this.playControls[id].downloadPlayer.StopPullStream()
this.playControls[id].downloadPlayer.Stop()
this.playControls[id].downloadPlayer = null
} else {
if (!this.volumes[id] && this.volumes[id] !== 0) {
this.volumes[id] = 1
}
const {
isPrivateProtocol,
wsURL,
stream,
sourceId,
deviceId,
userName,
password,
npt,
open3DPoint,
encryptMode,
isSandardPack
} = this.parameterProcessing(options)
const initParam = {
canvasElem: document.querySelector(`#download-${id}`),
videoElem: document.querySelector(`#download-video-${id}`),
ivsCanvasElem: document.querySelector(`#downloadIvs-${id}`),
bPlayBack: options.isLive === false,
strDecodeFilePath: '/static/WasmLib/SingleThread'
}
const urlParam = {
strRtspvUri: wsURL,
strRtspvUrl: stream,
strPlayToken: '',
strPlayTokenKey: '',
strDeviceID: deviceId,
strSourceId: isPrivateProtocol ? sourceId : '',
strUserName: userName,
strPassWord: password,
bTalkService: false,
nRange: npt,
nShortTimeout: 3,
nRtspResponseTimeout: 8,
bStandardPack: isSandardPack
}
const { bSupportMultiThread } = checkBrowser()
if (!this.playControls[id]) this.playControls[id] = {}
if (!this.nPorts[id]) this.nPorts[id] = {}
let isSpeed = false
this.playControls[id].downloadPlayer = new PlayerControl(bSupportMultiThread)
let downloadPlayer = this.playControls[id].downloadPlayer
downloadPlayer.SetCallBack('Error', (e) => {
this.downloadError(id, e)
})
downloadPlayer.SetCallBack('StreamPlayOver', () => {
downloadPlayer.StopRecord()
this.downloadComplete(id)
this.playControls[id].downloadPlayer = null
})
downloadPlayer.SetCallBack('Disconnect', (e) => {
downloadPlayer.StopRecord()
this.downloadError(id, e)
this.playControls[id].downloadPlayer = null
})
downloadPlayer.SetCallBack('PlayBackStreamRange', (time) => {
this.videoDownloadDuration(id, time)
})
downloadPlayer.SetCallBack('RecordTimeStamp', (e) => {
if (!isSpeed && speed && e.timeStamp) {
isSpeed = true
downloadPlayer.SetSpeed(speed)
}
if (e.timeStamp) {
clearTimeout(this.downloadTimers[id])
this.downloadTimers[id] = setTimeout(() => {
this.downloadError(id, {
errorCode: '409',
errMsg: 'Rtsp Not Response.'
})
}, 10000)
}
const msg = {
size: e.size,
time: e.timeStamp,
utcTime: e.utcTimeStamp
}
this.downloadProgressUpdate(id, msg)
})
downloadPlayer.SetCallBack('GetPlayPort', (port) => {
this.nPorts[id].downloadPlayerPort = port
})
downloadPlayer.SetCallBack('GetOriginalKey', ({ nRet, outKey }) => {
if (nRet == 1) {
urlParam.strDeviceID = outKey
this.nPorts[id].downloadHandle = downloadPlayer.StartPullStream(
JSON.parse(JSON.stringify(urlParam))
)
downloadPlayer.StartRecord(5, 1000, fileName || Date.now() + '.mp4')
}
})
downloadPlayer.Init(initParam)
downloadPlayer.Set3DPoint(open3DPoint)
if (encryptMode) {
downloadPlayer.GetOriginalKey({
strPlayToken: '',
strPlayTokenKey: '',
strDeviceID: deviceId
})
} else {
this.nPorts[id].downloadHandle = downloadPlayer.StartPullStream(
JSON.parse(JSON.stringify(urlParam))
)
downloadPlayer.StartRecord(5, 1000, fileName || Date.now() + '.mp4')
}
}
}
/**
* @method downloadPause Pause download
*/
downloadPause = (id) => {
this.playControls[id].downloadPlayer && this.playControls[id].downloadPlayer.Pause(1)
clearTimeout(this.downloadTimers[id])
}
/**
* @method downloadStart Continue downloading
*/
downloadStart = (id) => {
this.playControls[id].downloadPlayer && this.playControls[id].downloadPlayer.Pause(0)
}
/**
* @method downloadClose Close Download
*/
downloadClose = (id) => {
this.playControls[id].downloadPlayer && this.playControls[id].downloadPlayer.StopPullStream()
this.playControls[id].downloadPlayer && this.playControls[id].downloadPlayer.Stop()
this.playControls[id].downloadPlayer.CancelRecord()
clearTimeout(this.downloadTimers[id])
this.playControls[id].downloadPlayer = null
}
/**
* @description turn on smart frame
* @param { string } id play window id
*/
openIVS(id) {
this.playControls[id].player && this.playControls[id].player.OpenIVS()
}
/**
* @description turn off smart frame
* @param { string } id play window id
*/
closeIVS(id) {
this.playControls[id].player && this.playControls[id].player.CloseIVS()
}
/**
* @description intercom
* @param { string } id play window id
* @param { object } options parameters to play
*/
talk(id, options) {
if (this.playControls[id]?.talkPlayer) {
this.playControls[id].talkPlayer.StopTalk()
this.playControls[id].talkPlayer.StopPullStream()
this.playControls[id].talkPlayer.Stop()
this.playControls[id].talkPlayer = null
} else if (options) {
const {
isPrivateProtocol,
wsURL,
stream,
sourceId,
deviceId,
userName,
password,
npt,
encryptMode,
isSandardPack,
volume
} = this.parameterProcessing(options)
this.talkVolumes[id] = volume
const initParam = {
canvasElem: document.querySelector(`#talk-${id}`),
videoElem: document.querySelector(`#talk-video-${id}`),
ivsCanvasElem: document.querySelector(`#talkIvs-${id}`),
bPlayBack: options.isLive === false,
strDecodeFilePath: '/static/WasmLib/SingleThread'
}
const urlParam = {
strRtspvUri: wsURL,
strRtspvUrl: stream,
strPlayToken: '',
strPlayTokenKey: '',
strDeviceID: deviceId,
strSourceId: isPrivateProtocol ? sourceId : '',
strUserName: userName,
strPassWord: password,
bTalkService: true,
nRange: npt,
nShortTimeout: 3,
nRtspResponseTimeout: 8,
bStandardPack: isSandardPack
}
if (!this.playControls[id]) this.playControls[id] = {}
if (!this.nPorts[id]) this.nPorts[id] = {}
const { bSupportMultiThread } = checkBrowser()
this.playControls[id].talkPlayer = new PlayerControl(bSupportMultiThread)
const talkPlayer = this.playControls[id].talkPlayer
// If the video is not played, it needs to be initialized first, if the video has been played first, it does not need to be initialized
talkPlayer.SetCallBack('Error', (e) => {
this.talkError(id, e)
})
talkPlayer.SetCallBack('GetPlayPort', (port) => {
this.nPorts[id].talkPort = port
})
talkPlayer.SetCallBack('GetOriginalKey', ({ nRet, outKey }) => {
if (nRet == 1) {
urlParam.strDeviceID = outKey
this.nPorts[id].talkHandle = talkPlayer.StartPullStream(
JSON.parse(JSON.stringify(urlParam))
)
talkPlayer.StartTalk(null, 0)
}
})
talkPlayer.Init(initParam)
talkPlayer.SetSoundState(true)
talkPlayer.SetVolume(this.talkVolumes[id])
if (encryptMode) {
talkPlayer.GetOriginalKey({
strPlayToken: '',
strPlayTokenKey: '',
strDeviceID: deviceId
})
} else {
this.nPorts[id].talkHandle = talkPlayer.StartPullStream(
JSON.parse(JSON.stringify(urlParam))
)
talkPlayer.StartTalk(null, 0)
}
}
}
talkMute(id) {
if (this.playControls[id]?.talkPlayer) {
this.playControls[id].talkPlayer.StopTalk()
}
}
talkEnabled(id) {
if (this.playControls[id]?.talkPlayer) {
this.playControls[id].talkPlayer.StartTalk(null, 0)
}
}
/**
* @description real time video
* @param { string } id play window id
* @param { String } fileName video file name
*/
record(id, fileName) {
if (!this.playControls[id] || !this.playControls[id].player) return
if (!this.recordingStatus[id]) {
this.recordingStatus[id] = true
this.playControls[id].player.StartRecord(5, 1000, fileName || Date.now() + '.mp4')
} else {
this.recordingStatus[id] = false
this.playControls[id].player.StopRecord()
}
}
/**
* @description screenshot
* @param { string } id play window id
*/
screenshot(id) {
this.playControls[id].player && this.playControls[id].player.CapturePic(null)
}
/**
* @description video off
* @param { string } id play window id
*/
close(id) {
if (this.playControls[id]?.talkPlayer) {
this.playControls[id].talkPlayer.StopTalk()
this.playControls[id].talkPlayer.StopPullStream()
this.playControls[id].talkPlayer.Stop()
this.playControls[id].talkPlayer = null
}
if (this.playControls[id]?.player) {
this.playControls[id].player.StopPullStream()
this.playControls[id].player.Stop()
}
this.playStatus[id] = false
clearTimeout(this.timers[id])
// Define the ID for easier reference
const elementId = `#can-${id}`
const ivsElementId = `#ivsCan-${id}`
const videoElementId = `#video-${id}`
const loadingElementId = `#loading-${id}`
// Check if the elements exist before applying styles
const canElement = document.querySelector(elementId)
const ivsCanElement = document.querySelector(ivsElementId)
const videoElement = document.querySelector(videoElementId)
const loadingElement = document.querySelector(loadingElementId)
if (canElement) {
canElement.style.visibility = 'hidden'
}
if (ivsCanElement) {
ivsCanElement.style.visibility = 'hidden'
}
if (videoElement) {
videoElement.style.visibility = 'hidden'
videoElement.style.display = 'none'
}
if (loadingElement) {
loadingElement.style.display = 'none'
}
if (this.playControls[id]) this.playControls[id].player = null
}
/**
* @description sound settings
* @param { string } id play window id
* @param { number } val volume
*/
setAudioVolume(id, val) {
if (!window.webAudioPlayer) {
let intervalId = setInterval(() => {
if (window.webAudioPlayer) {
window.webAudioPlayer.resume()
clearInterval(intervalId)
}
})
} else {
window.webAudioPlayer.resume()
}
this.volumes[id] = val
this.playControls[id].player && this.playControls[id].player.SetVolume(val)
}
/**
* @description sound settings
* @param { string } id play window id
* @param { number } val volume
*/
setTalkVolume(id, val) {
if (!window.webAudioPlayer) {
let intervalId = setInterval(() => {
if (window.webAudioPlayer) {
window.webAudioPlayer.resume()
clearInterval(intervalId)
}
})
} else {
window.webAudioPlayer.resume()
}
this.talkVolumes[id] = val
this.playControls[id].talkPlayer && this.playControls[id].talkPlayer.SetVolume(val)
}
/**
* @description pause
* @param { string } id play window id
*/
pause(id) {
this.playControls[id]?.player && this.playControls[id].player?.Pause(1)
clearTimeout(this.timers[id])
}
/**
* @description keep pulling
* @param { string } id play window id
*/
start(id) {
this.playControls[id]?.player && this.playControls[id].player?.Pause(0)
}
/**
* @description fast forward/rewind
* @param { string } id play window id
*/
playFF(id, speed) {
this.playControls[id]?.player && this.playControls[id].player?.SetSpeed(speed)
}
parameterProcessing(options, isTalk) {
const isPrivateProtocol = !options.streamURL.includes('rtsp://')
const { protocol } = location
const [wsIP] = options.streamURL.replace('rtsp://', '').split('/')
const wsURL = `${
protocol === 'http:' && !options.streamURL.includes('8556') ? 'ws' : 'wss'
}://${wsIP}`
const url = options.streamURL.includes('rtsp://')
? options.streamURL
: `rtsp://${options.streamURL}`
let stream = ''
if (isTalk) {
stream = !isPrivateProtocol
? url
: `/live/talk.xav?channel=${options.channelId}&subtype=${options.bitStream}`
} else {
stream = !isPrivateProtocol
? options.isLive
? url
: url.replace(
/&beginTime=\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}&endTime=\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/,
''
)
: options.isLive
? `/live/realmonitor.xav?channel=${options.channelId}&subtype=${options.bitStream}`
: `/vod/playback.xav?channel=${options.channelId}&subtype=${options.bitStream}`
}
if (isPrivateProtocol) {
const timeRangeArr =
/&beginTime=\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}&endTime=\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/.exec(
url
)
if (timeRangeArr) {
const timeRange = timeRangeArr[0].replace(
/(&beginTime=)(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})(&endTime=)(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/,
'&starttime=$2_$3_$4_$5_$6_$7&endtime_$9_$10_$11_$12_$13'
)
stream += timeRange
}
}
const sourceId = !isPrivateProtocol
? options.streamURL.replace('rtsp://', '').split('/')[1]
: options.streamURL
.replace('rtsp://', '')
.split('/')[1]
.replace(
/&beginTime=\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}&endTime=\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/,
''
)
const userName = options.userName || 'admin'
const password = options.password || 'admin123'
const deviceId = options.deviceId || ''
const encryptMode = options.encryptMode || 0
const npt = options.npt || 0
const panoAR = options.npt || 0
const open3DPoint = options.open3DPoint || 0
const isSandardPack = options.isSandardPack || false
const volume = options.volume || options.volume == 0 ? options.volume : 1
return {
isPrivateProtocol,
wsURL,
stream,
sourceId,
deviceId,
userName,
password,
encryptMode,
npt,
panoAR,
open3DPoint,
isSandardPack,
volume
}
}
}
export default Player