videoPlay-js.js 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147
  1. import { checkBrowser } from './playerWasm/public.js'
  2. import PlayerControl from './playerWasm/PlaySDKInterface.js'
  3. const loadScript = (src, callback) => {
  4. const dom = document.createElement('script')
  5. dom.src = src
  6. document.head.appendChild(dom)
  7. var loaded = false
  8. if (typeof callback === 'function') {
  9. dom.onload = dom.onreadystatechange = function () {
  10. if (!loaded && (!dom.readyState || /loaded|complete/.test(dom.readyState))) {
  11. dom.onload = dom.onreadystatechange = null
  12. loaded = true
  13. callback()
  14. }
  15. }
  16. }
  17. }
  18. let m_bClientInitialized = false
  19. let m_nModuleInitialized = false
  20. // Load multi-threaded PlaySDK library files
  21. const loadLibPlaySDK = () => {
  22. const libPath = '/static/WasmLib/MultiThread/libplay.js'
  23. if (!isInclude('MultiThread/libplay.js')) {
  24. loadScript(libPath, null)
  25. }
  26. }
  27. // Load multi-threaded streaming library files
  28. const loadLibStreamClient = () => {
  29. let libPath = '/static/WasmLib/MultiThread/libStreamClient.js'
  30. if (!isInclude('MultiThread/libStreamClient.js')) {
  31. loadScript(libPath, () => {
  32. // Initialize Streaming Module
  33. Multi_Client_Module().then((instance) => {
  34. window.SCModule = instance
  35. // Multiple channels only need to be initialized once
  36. window.SCModule._GLOBAL_Init()
  37. m_bClientInitialized = true
  38. })
  39. })
  40. }
  41. }
  42. // Load rendering engine files
  43. const loadLibRenderEngine = () => {
  44. let libPath = '/static/WasmLib/Common/libRenderEngine.js'
  45. if (!isInclude('Common/libRenderEngine.js')) {
  46. loadScript(libPath, () => {
  47. // Initialize rendering engine module
  48. RenderEngine_Module().then((instance) => {
  49. window.REModule = instance
  50. })
  51. })
  52. }
  53. }
  54. // Load IVSdrawer file
  55. const loadLibIVSDrawer = () => {
  56. let libPath = '/static/WasmLib/Common/libIVSDrawer.js'
  57. if (!isInclude('Common/libIVSDrawer.js')) {
  58. loadScript(libPath, () => {
  59. // Initialize IVSDrawer Module
  60. IVSDrawer_Module().then((instance) => {
  61. window.IVSModule = instance
  62. })
  63. })
  64. }
  65. }
  66. const loadLibASPLite = () => {
  67. let libPath = '/static/WasmLib/Common/libmavasp_litepacket.js'
  68. let dataPath = '/static/WasmLib/Common/libmavasp_litepacket.data'
  69. if (!isInclude('Common/libmavasp_litepacket.js')) {
  70. loadScript(libPath, () => {
  71. // Set the path to the libmavasp_litepacket.data configuration file
  72. ASPLite_Module['locateFile'] = function (path, prefix) {
  73. if (path.endsWith('.data')) {
  74. return dataPath
  75. }
  76. return prefix + path
  77. }
  78. // Initialize ASPLite Module
  79. ASPLite_Module(ASPLite_Module).then((instance) => {
  80. window.ASPLiteModule = instance
  81. })
  82. })
  83. }
  84. }
  85. if (!window.Module) {
  86. window.Module = {}
  87. }
  88. // PlaySDK wasm module loading and initialization completed callback
  89. Module.onRuntimeInitialized = function () {
  90. m_nModuleInitialized = true
  91. }
  92. // Reset font file path
  93. Module.locateFile = function (path, prefix) {
  94. if (path.endsWith('.data')) {
  95. return '/static/WasmLib/MultiThread/libplay.data'
  96. }
  97. return prefix + path
  98. }
  99. const isInclude = (name) => {
  100. var js = /js$/i.test(name)
  101. var es = document.getElementsByTagName(js ? 'script' : 'link')
  102. for (var i = 0; i < es.length; i++) {
  103. if (es[i][js ? 'src' : 'href'].indexOf(name) != -1) return true
  104. }
  105. return false
  106. }
  107. const loadLibDHPlay = (bSupportMultiThread) => {
  108. if (bSupportMultiThread) {
  109. loadLibPlaySDK()
  110. // Multi threaded version, using StreamClient wasm module for streaming
  111. loadLibStreamClient()
  112. }
  113. if (!bSupportMultiThread) {
  114. loadLibRenderEngine()
  115. }
  116. loadLibIVSDrawer()
  117. // Load 3A algorithm library
  118. loadLibASPLite()
  119. let timer = null
  120. return new Promise((resolve) => {
  121. timer = setInterval(() => {
  122. if (!bSupportMultiThread || (m_nModuleInitialized && m_bClientInitialized)) {
  123. clearInterval(timer)
  124. resolve()
  125. }
  126. })
  127. })
  128. }
  129. class Player {
  130. constructor(ids, callbacks) {
  131. this.ids = ids || []
  132. this.playControls = {}
  133. this.nPorts = {}
  134. this.volumes = {}
  135. this.talkVolumes = {}
  136. this.playStatus = {}
  137. this.recordingStatus = {}
  138. this.timers = {}
  139. this.downloadTimers = {}
  140. this.playError = callbacks.playError ? callbacks.playError : () => {}
  141. this.playFileOver = callbacks.playFileOver ? callbacks.playFileOver : () => {}
  142. this.captureCallback = callbacks.captureCallback ? callbacks.captureCallback : () => {}
  143. this.playStart = callbacks.playStart ? callbacks.playStart : () => {}
  144. this.playProgressUpdate = callbacks.playProgressUpdate ? callbacks.playProgressUpdate : () => {}
  145. this.talkError = callbacks.talkError ? callbacks.talkError : () => {}
  146. this.downloadError = callbacks.downloadError ? callbacks.downloadError : () => {}
  147. this.downloadComplete = callbacks.downloadComplete ? callbacks.downloadComplete : () => {}
  148. this.videoDownloadDuration = callbacks.videoDownloadDuration
  149. ? callbacks.videoDownloadDuration
  150. : () => {}
  151. this.downloadProgressUpdate = callbacks.downloadProgressUpdate
  152. ? callbacks.downloadProgressUpdate
  153. : () => {}
  154. this.runtimeInitializedCallBack = callbacks.runtimeInitializedCallBack
  155. ? callbacks.runtimeInitializedCallBack
  156. : null
  157. }
  158. /**
  159. * @param { Array } ids Play window id collection
  160. */
  161. async init() {
  162. if (!this.ids) return
  163. if (!Array.isArray(this.ids)) this.ids = [this.ids]
  164. this.ids.forEach((id) => {
  165. this.playControls[id] = {}
  166. this.drawVideoDom(id)
  167. })
  168. window.cPlusVisibleDecCallBack = (nPort, pBufY, pBufU, pBufV, nSize, pFrameInfo) => {
  169. this.ids.forEach((id) => {
  170. if (this.nPorts[id] && this.nPorts[id].playerPort == nPort) {
  171. this.playControls[id].player &&
  172. this.playControls[id].player.SetFrameData(
  173. nPort,
  174. pBufY,
  175. pBufU,
  176. pBufV,
  177. nSize,
  178. pFrameInfo,
  179. this.volumes[id]
  180. )
  181. return true
  182. } else if (this.nPorts[id] && this.nPorts[id].talkPort == nPort) {
  183. this.playControls[id].talkPlayer &&
  184. this.playControls[id].talkPlayer.SetFrameData(
  185. nPort,
  186. pBufY,
  187. pBufU,
  188. pBufV,
  189. nSize,
  190. pFrameInfo,
  191. this.talkVolumes[id],
  192. true
  193. )
  194. return true
  195. } else if (this.nPorts[id] && this.nPorts[id].downloadPlayerPort == nPort) {
  196. this.playControls[id].downloadPlayer &&
  197. this.playControls[id].downloadPlayer.SetFrameData(
  198. nPort,
  199. pBufY,
  200. pBufU,
  201. pBufV,
  202. nSize,
  203. pFrameInfo,
  204. 0
  205. )
  206. return true
  207. }
  208. })
  209. }
  210. window.cDigitalSignCallBack = (nPort, nFrameID, bSuccess) => {
  211. this.ids.forEach((id) => {
  212. if (this.nPorts[id] && this.nPorts[id].playerPort == nPort) {
  213. this.playControls[id].player &&
  214. this.playControls[id].player.SetDecryptionResult(nPort, nFrameID, bSuccess)
  215. } else if (this.nPorts[id] && this.nPorts[id].downloadPlayerPort == nPort) {
  216. this.playControls[id].downloadPlayer &&
  217. this.playControls[id].downloadPlayer.SetDecryptionResult(nPort, nFrameID, bSuccess)
  218. }
  219. })
  220. }
  221. window.cExtraDrawDataCallBack = (nPort, nDataType, pDrawData, nDataLen) => {
  222. this.ids.forEach((id) => {
  223. if (this.nPorts[id] && this.nPorts[id].playerPort == nPort) {
  224. this.playControls[id].player &&
  225. this.playControls[id].player.setIVSData(nPort, nDataType, pDrawData, nDataLen)
  226. } else if (this.nPorts[id] && this.nPorts[id].downloadPlayerPort == nPort) {
  227. this.playControls[id].downloadPlayer &&
  228. this.playControls[id].downloadPlayer.setIVSData(nPort, nDataType, pDrawData, nDataLen)
  229. }
  230. })
  231. }
  232. window.cExtraDrawDrawCallBack = (nPort) => {
  233. this.ids.forEach((id) => {
  234. if (this.nPorts[id] && this.nPorts[id].playerPort == nPort) {
  235. this.playControls[id].player && this.playControls[id].player.drawIVSData(nPort)
  236. } else if (this.nPorts[id] && this.nPorts[id].downloadPlayerPort == nPort) {
  237. this.playControls[id].downloadPlayer &&
  238. this.playControls[id].downloadPlayer.drawIVSData(nPort)
  239. }
  240. })
  241. }
  242. window.cRecordDataCallBack = (nPort, pData, nDataLen, nOffset, pRecordFrameInfo) => {
  243. this.ids.forEach((id) => {
  244. if (this.nPorts[id] && this.nPorts[id].playerPort == nPort) {
  245. this.playControls[id].player &&
  246. this.playControls[id].player.SetRecordData(
  247. nPort,
  248. pData,
  249. nDataLen,
  250. nOffset,
  251. pRecordFrameInfo
  252. )
  253. } else if (this.nPorts[id] && this.nPorts[id].downloadPlayerPort == nPort) {
  254. this.playControls[id].downloadPlayer &&
  255. this.playControls[id].downloadPlayer.SetRecordData(
  256. nPort,
  257. pData,
  258. nDataLen,
  259. nOffset,
  260. pRecordFrameInfo
  261. )
  262. }
  263. })
  264. }
  265. window.cIVSDrawDataCallBack = (nPort, buf, type, len, reallen) => {
  266. this.ids.forEach((id) => {
  267. if (this.nPorts[id] && this.nPorts[id].playerPort == nPort) {
  268. this.playControls[id].player &&
  269. this.playControls[id].player.SetIVSDrawData(nPort, buf, type, len, reallen)
  270. } else if (this.nPorts[id] && this.nPorts[id].downloadPlayerPort == nPort) {
  271. this.playControls[id].downloadPlayer &&
  272. this.playControls[id].downloadPlayer.SetIVSDrawData(nPort, buf, type, len, reallen)
  273. }
  274. })
  275. }
  276. window.cPlusMediaFrameCallBack = (handle, index, pData, nDataLength) => {
  277. this.ids.forEach((id) => {
  278. if (this.nPorts[id] && this.nPorts[id].playerHandle == handle) {
  279. this.playControls[id].player &&
  280. this.playControls[id].player.InputDataEx(pData, nDataLength)
  281. } else if (this.nPorts[id] && this.nPorts[id].talkHandle == handle) {
  282. this.playControls[id].talkPlayer &&
  283. this.playControls[id].talkPlayer.InputDataEx(pData, nDataLength)
  284. } else if (this.nPorts[id] && this.nPorts[id].downloadHandle == handle) {
  285. this.playControls[id].downloadPlayer &&
  286. this.playControls[id].downloadPlayer.InputDataEx(pData, nDataLength)
  287. }
  288. })
  289. }
  290. window.cPlusRtspMsgCallBack = (handle, type, attach) => {
  291. this.ids.forEach((id) => {
  292. let playerHandle = null
  293. let player = null
  294. if (this.nPorts[id] && this.nPorts[id].playerHandle == handle) {
  295. playerHandle = this.nPorts[id].playerHandle
  296. player = this.playControls[id].player
  297. } else if (this.nPorts[id] && this.nPorts[id].talkHandle == handle) {
  298. playerHandle = this.nPorts[id].talkHandle
  299. player = this.playControls[id].talkPlayer
  300. } else if (this.nPorts[id] && this.nPorts[id].downloadHandle == handle) {
  301. playerHandle = this.nPorts[id].downloadHandle
  302. player = this.playControls[id].downloadPlayer
  303. }
  304. if (playerHandle && player) {
  305. switch (type) {
  306. // The module responsible for handling the RTSP protocol flow, if it fails during RTSP processing, sends the message to the message receiver
  307. // Upon receiving this message, the recipient should call Close() to close the client. The attached parameter attach to the message is not used
  308. case 0x1000:
  309. player.StreamFailedCallback(attach)
  310. player.StopPullStream()
  311. player.StreamDisconnectCallback()
  312. break
  313. // Indicates that the client has completed the initialization and setup steps for the peer, and at this point, the user can obtain the SDP,
  314. // The attached parameter attach to the message is not used.
  315. // RTSP_PutStream can only be called after receiving this message in intercom services
  316. case 0x1001:
  317. break
  318. // Indicates that all streams on the server have been received and the receiver should call Close() to clean up resources
  319. // The attached parameter attach to the message is not used.
  320. case 0x1004:
  321. player.StreamFinishCallback()
  322. break
  323. // RTSP redirect message, when the client has configured clientConfigRedirDisable to enable, it will notify the upper layer of the message,
  324. // Implement redirection function from the upper layer
  325. case 0x1008:
  326. player.StreamRedirectCallback(attach)
  327. break
  328. }
  329. }
  330. })
  331. }
  332. window.cPlusRtsvMsgCallBack = (handle, type) => {
  333. this.ids.forEach((id) => {
  334. let playerHandle = null
  335. let player = null
  336. if (this.nPorts[id] && this.nPorts[id].playerHandle == handle) {
  337. playerHandle = this.nPorts[id].playerHandle
  338. player = this.playControls[id].player
  339. } else if (this.nPorts[id] && this.nPorts[id].talkHandle == handle) {
  340. playerHandle = this.nPorts[id].talkHandle
  341. player = this.playControls[id].talkPlayer
  342. } else if (this.nPorts[id] && this.nPorts[id].downloadHandle == handle) {
  343. playerHandle = this.nPorts[id].downloadHandle
  344. player = this.playControls[id].downloadPlayer
  345. }
  346. if (playerHandle) {
  347. switch (type) {
  348. case 0x4001:
  349. // Only after receiving this message in the intercom business can RTSV-PutStream be called
  350. break
  351. case 0x4002:
  352. player.StreamFinishCallback()
  353. break
  354. }
  355. }
  356. })
  357. }
  358. Module.onRuntimeInitialized = function () {
  359. m_nModuleInitialized = true
  360. this.runtimeInitializedCallBack && this.runtimeInitializedCallBack()
  361. }
  362. const { bSupportMultiThread } = checkBrowser()
  363. if (!isInclude('/libplay.js')) {
  364. await loadLibDHPlay(bSupportMultiThread)
  365. }
  366. }
  367. drawVideoDom(id) {
  368. const dom = document.querySelector(`#${id}`)
  369. let videoDom = `
  370. <div class="video-player-context" style="width: 100%; height: 100%; position: relative;">
  371. <canvas
  372. id="download-${id}"
  373. class="kind-stream-canvas video-player-canvas"
  374. kind-channel-id="0"
  375. width="1920"
  376. height="1080"
  377. style="visibility: hidden; position: absolute; top: 0; width: 100%; height: 100%; object-fit: fill;"
  378. ></canvas>
  379. <canvas
  380. id="downloadIvs-${id}"
  381. class="kind-stream-canvas video-player-canvas"
  382. width="1920"
  383. height="1080"
  384. style="visibility: hidden; position: absolute; top: 0; width: 100%; height: 100%; object-fit: fill;"
  385. ></canvas>
  386. <canvas
  387. id="talk-${id}"
  388. class="kind-stream-canvas video-player-canvas"
  389. kind-channel-id="0"
  390. width="1920"
  391. height="1080"
  392. style="visibility: hidden; position: absolute; top: 0; width: 100%; height: 100%; object-fit: fill;"
  393. ></canvas>
  394. <canvas
  395. id="talkIvs-${id}"
  396. class="kind-stream-canvas video-player-canvas"
  397. width="1920"
  398. height="1080"
  399. style="visibility: hidden; position: absolute; top: 0; width: 100%; height: 100%; object-fit: fill;"
  400. ></canvas>
  401. <canvas
  402. id="can-${id}"
  403. class="kind-stream-canvas video-player-canvas"
  404. kind-channel-id="0"
  405. width="1920"
  406. height="1080"
  407. style="visibility: hidden; position: absolute; top: 0; width: 100%; height: 100%; object-fit: fill;"
  408. ></canvas>
  409. <canvas
  410. id="ivsCan-${id}"
  411. class="kind-stream-canvas video-player-canvas"
  412. width="1920"
  413. height="1080"
  414. style="visibility: hidden; position: absolute; top: 0; width: 100%; height: 100%; object-fit: fill;"
  415. ></canvas>
  416. <video
  417. id="video-${id}"
  418. class="kind-stream-canvas"
  419. kind-channel-id="0"
  420. width="1920"
  421. height="1080"
  422. style="visibility: hidden; width: 100%; height: 100%; top: 0; object-fit: fill;"
  423. ></video>
  424. <video
  425. id="download-video-${id}"
  426. class="kind-stream-canvas"
  427. kind-channel-id="0"
  428. width="1920"
  429. height="1080"
  430. style="visibility: hidden; width: 100%; height: 100%; top: 0; object-fit: fill;"
  431. ></video>
  432. <video
  433. id="talk-video-${id}"
  434. class="kind-stream-canvas"
  435. kind-channel-id="0"
  436. width="1920"
  437. height="1080"
  438. style="visibility: hidden; width: 100%; height: 100%; top: 0; object-fit: fill;"
  439. ></video>
  440. <img src="/static/360ARTagAsserts/loading.gif" id="loading-${id}" style="display: none; width: 286px; height: 180px; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);" />
  441. </div>
  442. `
  443. if (dom) dom.innerHTML = videoDom
  444. }
  445. /**
  446. * @description play
  447. * @param { string } id play window id
  448. * @param { object } options parameters to play
  449. */
  450. play(id, options) {
  451. if (!options.streamURL) return
  452. if (this.playControls[id] && this.playControls[id].player) {
  453. this.close(id)
  454. }
  455. const {
  456. isPrivateProtocol,
  457. wsURL,
  458. stream,
  459. sourceId,
  460. deviceId,
  461. userName,
  462. password,
  463. npt,
  464. open3DPoint,
  465. encryptMode,
  466. isSandardPack,
  467. volume
  468. } = this.parameterProcessing(options)
  469. this.volumes[id] = volume
  470. const initParam = {
  471. canvasElem: document.querySelector(`#can-${id}`),
  472. videoElem: document.querySelector(`#video-${id}`),
  473. ivsCanvasElem: document.querySelector(`#ivsCan-${id}`),
  474. bPlayBack: options.isLive === false,
  475. strDecodeFilePath: '/static/WasmLib/SingleThread'
  476. }
  477. const urlParam = {
  478. strRtspvUri: wsURL,
  479. strRtspvUrl: stream,
  480. strPlayToken: '',
  481. strPlayTokenKey: '',
  482. strDeviceID: deviceId,
  483. strSourceId: isPrivateProtocol ? sourceId : '',
  484. strUserName: userName,
  485. strPassWord: password,
  486. bTalkService: false,
  487. nRange: npt,
  488. nShortTimeout: 3,
  489. nRtspResponseTimeout: 8,
  490. bStandardPack: isSandardPack
  491. }
  492. const { bSupportMultiThread } = checkBrowser()
  493. if (!this.playControls[id]) this.playControls[id] = {}
  494. if (!this.nPorts[id]) this.nPorts[id] = {}
  495. this.playControls[id].player = new PlayerControl(bSupportMultiThread)
  496. const player = this.playControls[id].player
  497. const loadingElement = document.querySelector(`#loading-${id}`)
  498. if (loadingElement) {
  499. loadingElement.style.display = 'block'
  500. }
  501. player.SetCallBack('StreamPlayOver', () => {
  502. if (this.playControls[id].player) {
  503. setTimeout(() => {
  504. this.close(id)
  505. this.playFileOver(id)
  506. }, 1)
  507. }
  508. })
  509. player.SetCallBack('PlayStart', () => {
  510. this.playStatus[id] = true
  511. // Define the ID for easier reference
  512. const elementId = `#can-${id}`
  513. const ivsElementId = `#ivsCan-${id}`
  514. const videoElementId = `#video-${id}`
  515. const loadingElementId = `#loading-${id}`
  516. // Check if the elements exist before applying styles
  517. const canElement = document.querySelector(elementId)
  518. const ivsCanElement = document.querySelector(ivsElementId)
  519. const videoElement = document.querySelector(videoElementId)
  520. const loadingElement = document.querySelector(loadingElementId)
  521. if (canElement) {
  522. canElement.style.visibility = 'visible'
  523. }
  524. if (ivsCanElement) {
  525. ivsCanElement.style.visibility = 'visible'
  526. }
  527. if (videoElement) {
  528. videoElement.style.visibility = 'visible'
  529. }
  530. if (loadingElement) {
  531. loadingElement.style.display = 'none'
  532. }
  533. this.playStart()
  534. })
  535. player.SetCallBack('CapturePicDataCallBack', (blob) => {
  536. this.captureCallback(id, blob)
  537. })
  538. player.SetCallBack('VideoFrameInfo', (e) => {
  539. if (e.timeStamp) {
  540. clearTimeout(this.timers[id])
  541. this.timers[id] = setTimeout(() => {
  542. this.playError(id, {
  543. errorCode: '409',
  544. errMsg: 'Rtsp Not Response.'
  545. })
  546. }, 10000)
  547. }
  548. const msg = {
  549. frameRate: e.nFrameRate,
  550. time: e.timeStamp,
  551. utcTime: e.utcTimeStamp
  552. }
  553. this.playProgressUpdate(id, msg)
  554. })
  555. player.SetCallBack('DecodeStart', (e) => {
  556. if (e.decodeMode === 'video') {
  557. const canElement = document.querySelector(`#can-${id}`)
  558. if (canElement) {
  559. canElement.style.display = 'none'
  560. }
  561. const videoElement = document.querySelector(`#video-${id}`)
  562. if (videoElement) {
  563. videoElement.style.display = ''
  564. }
  565. } else {
  566. const canElement = document.querySelector(`#can-${id}`)
  567. if (canElement) {
  568. canElement.style.display = ''
  569. }
  570. const videoElement = document.querySelector(`#video-${id}`)
  571. if (videoElement) {
  572. videoElement.style.display = 'none'
  573. }
  574. }
  575. })
  576. player.SetCallBack('Error', (e) => {
  577. this.playStatus[id] = false
  578. const elementId = `#can-${id}`
  579. const ivsElementId = `#ivsCan-${id}`
  580. const videoElementId = `#video-${id}`
  581. const loadingElementId = `#loading-${id}`
  582. // Check if the elements exist before applying styles
  583. const canElement = document.querySelector(elementId)
  584. const ivsCanElement = document.querySelector(ivsElementId)
  585. const videoElement = document.querySelector(videoElementId)
  586. const loadingElement = document.querySelector(loadingElementId)
  587. if (canElement) {
  588. canElement.style.visibility = 'hidden'
  589. }
  590. if (ivsCanElement) {
  591. ivsCanElement.style.visibility = 'hidden'
  592. }
  593. if (videoElement) {
  594. videoElement.style.visibility = 'hidden'
  595. videoElement.style.display = 'none'
  596. }
  597. if (loadingElement && loadingElement.style.display == 'block') {
  598. loadingElement.style.display = 'none'
  599. }
  600. this.playError(id, e)
  601. })
  602. player.SetCallBack('GetPlayPort', (port) => {
  603. this.nPorts[id].playerPort = port
  604. })
  605. player.SetCallBack('GetOriginalKey', ({ nRet, outKey }) => {
  606. if (nRet == 1) {
  607. urlParam.strDeviceID = outKey
  608. this.nPorts[id].playerHandle = player.StartPullStream(JSON.parse(JSON.stringify(urlParam)))
  609. }
  610. })
  611. // player.SetPrintLogLevel(6)
  612. player.Init(initParam)
  613. player.SetSoundState(true)
  614. player.SetVolume(this.volumes[id])
  615. player.Set3DPoint(open3DPoint)
  616. if (encryptMode) {
  617. player.GetOriginalKey({
  618. strPlayToken: '',
  619. strPlayTokenKey: '',
  620. strDeviceID: deviceId
  621. })
  622. } else {
  623. this.nPorts[id].playerHandle = player.StartPullStream(JSON.parse(JSON.stringify(urlParam)))
  624. }
  625. }
  626. /**
  627. * @description download
  628. * @param { string } id download window id
  629. * @param { object } options parameters to download
  630. * @param { string } fileName file name
  631. * @param { number } speed download speed
  632. */
  633. download(id, options, fileName, speed = 2) {
  634. if (!options.streamURL) return
  635. if (this.playControls[id] && this.playControls[id].downloadPlayer) {
  636. this.playControls[id].downloadPlayer.StopRecord()
  637. this.playControls[id].downloadPlayer.StopPullStream()
  638. this.playControls[id].downloadPlayer.Stop()
  639. this.playControls[id].downloadPlayer = null
  640. } else {
  641. if (!this.volumes[id] && this.volumes[id] !== 0) {
  642. this.volumes[id] = 1
  643. }
  644. const {
  645. isPrivateProtocol,
  646. wsURL,
  647. stream,
  648. sourceId,
  649. deviceId,
  650. userName,
  651. password,
  652. npt,
  653. open3DPoint,
  654. encryptMode,
  655. isSandardPack
  656. } = this.parameterProcessing(options)
  657. const initParam = {
  658. canvasElem: document.querySelector(`#download-${id}`),
  659. videoElem: document.querySelector(`#download-video-${id}`),
  660. ivsCanvasElem: document.querySelector(`#downloadIvs-${id}`),
  661. bPlayBack: options.isLive === false,
  662. strDecodeFilePath: '/static/WasmLib/SingleThread'
  663. }
  664. const urlParam = {
  665. strRtspvUri: wsURL,
  666. strRtspvUrl: stream,
  667. strPlayToken: '',
  668. strPlayTokenKey: '',
  669. strDeviceID: deviceId,
  670. strSourceId: isPrivateProtocol ? sourceId : '',
  671. strUserName: userName,
  672. strPassWord: password,
  673. bTalkService: false,
  674. nRange: npt,
  675. nShortTimeout: 3,
  676. nRtspResponseTimeout: 8,
  677. bStandardPack: isSandardPack
  678. }
  679. const { bSupportMultiThread } = checkBrowser()
  680. if (!this.playControls[id]) this.playControls[id] = {}
  681. if (!this.nPorts[id]) this.nPorts[id] = {}
  682. let isSpeed = false
  683. this.playControls[id].downloadPlayer = new PlayerControl(bSupportMultiThread)
  684. let downloadPlayer = this.playControls[id].downloadPlayer
  685. downloadPlayer.SetCallBack('Error', (e) => {
  686. this.downloadError(id, e)
  687. })
  688. downloadPlayer.SetCallBack('StreamPlayOver', () => {
  689. downloadPlayer.StopRecord()
  690. this.downloadComplete(id)
  691. this.playControls[id].downloadPlayer = null
  692. })
  693. downloadPlayer.SetCallBack('Disconnect', (e) => {
  694. downloadPlayer.StopRecord()
  695. this.downloadError(id, e)
  696. this.playControls[id].downloadPlayer = null
  697. })
  698. downloadPlayer.SetCallBack('PlayBackStreamRange', (time) => {
  699. this.videoDownloadDuration(id, time)
  700. })
  701. downloadPlayer.SetCallBack('RecordTimeStamp', (e) => {
  702. if (!isSpeed && speed && e.timeStamp) {
  703. isSpeed = true
  704. downloadPlayer.SetSpeed(speed)
  705. }
  706. if (e.timeStamp) {
  707. clearTimeout(this.downloadTimers[id])
  708. this.downloadTimers[id] = setTimeout(() => {
  709. this.downloadError(id, {
  710. errorCode: '409',
  711. errMsg: 'Rtsp Not Response.'
  712. })
  713. }, 10000)
  714. }
  715. const msg = {
  716. size: e.size,
  717. time: e.timeStamp,
  718. utcTime: e.utcTimeStamp
  719. }
  720. this.downloadProgressUpdate(id, msg)
  721. })
  722. downloadPlayer.SetCallBack('GetPlayPort', (port) => {
  723. this.nPorts[id].downloadPlayerPort = port
  724. })
  725. downloadPlayer.SetCallBack('GetOriginalKey', ({ nRet, outKey }) => {
  726. if (nRet == 1) {
  727. urlParam.strDeviceID = outKey
  728. this.nPorts[id].downloadHandle = downloadPlayer.StartPullStream(
  729. JSON.parse(JSON.stringify(urlParam))
  730. )
  731. downloadPlayer.StartRecord(5, 1000, fileName || Date.now() + '.mp4')
  732. }
  733. })
  734. downloadPlayer.Init(initParam)
  735. downloadPlayer.Set3DPoint(open3DPoint)
  736. if (encryptMode) {
  737. downloadPlayer.GetOriginalKey({
  738. strPlayToken: '',
  739. strPlayTokenKey: '',
  740. strDeviceID: deviceId
  741. })
  742. } else {
  743. this.nPorts[id].downloadHandle = downloadPlayer.StartPullStream(
  744. JSON.parse(JSON.stringify(urlParam))
  745. )
  746. downloadPlayer.StartRecord(5, 1000, fileName || Date.now() + '.mp4')
  747. }
  748. }
  749. }
  750. /**
  751. * @method downloadPause Pause download
  752. */
  753. downloadPause = (id) => {
  754. this.playControls[id].downloadPlayer && this.playControls[id].downloadPlayer.Pause(1)
  755. clearTimeout(this.downloadTimers[id])
  756. }
  757. /**
  758. * @method downloadStart Continue downloading
  759. */
  760. downloadStart = (id) => {
  761. this.playControls[id].downloadPlayer && this.playControls[id].downloadPlayer.Pause(0)
  762. }
  763. /**
  764. * @method downloadClose Close Download
  765. */
  766. downloadClose = (id) => {
  767. this.playControls[id].downloadPlayer && this.playControls[id].downloadPlayer.StopPullStream()
  768. this.playControls[id].downloadPlayer && this.playControls[id].downloadPlayer.Stop()
  769. this.playControls[id].downloadPlayer.CancelRecord()
  770. clearTimeout(this.downloadTimers[id])
  771. this.playControls[id].downloadPlayer = null
  772. }
  773. /**
  774. * @description turn on smart frame
  775. * @param { string } id play window id
  776. */
  777. openIVS(id) {
  778. this.playControls[id].player && this.playControls[id].player.OpenIVS()
  779. }
  780. /**
  781. * @description turn off smart frame
  782. * @param { string } id play window id
  783. */
  784. closeIVS(id) {
  785. this.playControls[id].player && this.playControls[id].player.CloseIVS()
  786. }
  787. /**
  788. * @description intercom
  789. * @param { string } id play window id
  790. * @param { object } options parameters to play
  791. */
  792. talk(id, options) {
  793. if (this.playControls[id]?.talkPlayer) {
  794. this.playControls[id].talkPlayer.StopTalk()
  795. this.playControls[id].talkPlayer.StopPullStream()
  796. this.playControls[id].talkPlayer.Stop()
  797. this.playControls[id].talkPlayer = null
  798. } else if (options) {
  799. const {
  800. isPrivateProtocol,
  801. wsURL,
  802. stream,
  803. sourceId,
  804. deviceId,
  805. userName,
  806. password,
  807. npt,
  808. encryptMode,
  809. isSandardPack,
  810. volume
  811. } = this.parameterProcessing(options)
  812. this.talkVolumes[id] = volume
  813. const initParam = {
  814. canvasElem: document.querySelector(`#talk-${id}`),
  815. videoElem: document.querySelector(`#talk-video-${id}`),
  816. ivsCanvasElem: document.querySelector(`#talkIvs-${id}`),
  817. bPlayBack: options.isLive === false,
  818. strDecodeFilePath: '/static/WasmLib/SingleThread'
  819. }
  820. const urlParam = {
  821. strRtspvUri: wsURL,
  822. strRtspvUrl: stream,
  823. strPlayToken: '',
  824. strPlayTokenKey: '',
  825. strDeviceID: deviceId,
  826. strSourceId: isPrivateProtocol ? sourceId : '',
  827. strUserName: userName,
  828. strPassWord: password,
  829. bTalkService: true,
  830. nRange: npt,
  831. nShortTimeout: 3,
  832. nRtspResponseTimeout: 8,
  833. bStandardPack: isSandardPack
  834. }
  835. if (!this.playControls[id]) this.playControls[id] = {}
  836. if (!this.nPorts[id]) this.nPorts[id] = {}
  837. const { bSupportMultiThread } = checkBrowser()
  838. this.playControls[id].talkPlayer = new PlayerControl(bSupportMultiThread)
  839. const talkPlayer = this.playControls[id].talkPlayer
  840. // 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
  841. talkPlayer.SetCallBack('Error', (e) => {
  842. this.talkError(id, e)
  843. })
  844. talkPlayer.SetCallBack('GetPlayPort', (port) => {
  845. this.nPorts[id].talkPort = port
  846. })
  847. talkPlayer.SetCallBack('GetOriginalKey', ({ nRet, outKey }) => {
  848. if (nRet == 1) {
  849. urlParam.strDeviceID = outKey
  850. this.nPorts[id].talkHandle = talkPlayer.StartPullStream(
  851. JSON.parse(JSON.stringify(urlParam))
  852. )
  853. talkPlayer.StartTalk(null, 0)
  854. }
  855. })
  856. talkPlayer.Init(initParam)
  857. talkPlayer.SetSoundState(true)
  858. talkPlayer.SetVolume(this.talkVolumes[id])
  859. if (encryptMode) {
  860. talkPlayer.GetOriginalKey({
  861. strPlayToken: '',
  862. strPlayTokenKey: '',
  863. strDeviceID: deviceId
  864. })
  865. } else {
  866. this.nPorts[id].talkHandle = talkPlayer.StartPullStream(
  867. JSON.parse(JSON.stringify(urlParam))
  868. )
  869. talkPlayer.StartTalk(null, 0)
  870. }
  871. }
  872. }
  873. talkMute(id) {
  874. if (this.playControls[id]?.talkPlayer) {
  875. this.playControls[id].talkPlayer.StopTalk()
  876. }
  877. }
  878. talkEnabled(id) {
  879. if (this.playControls[id]?.talkPlayer) {
  880. this.playControls[id].talkPlayer.StartTalk(null, 0)
  881. }
  882. }
  883. /**
  884. * @description real time video
  885. * @param { string } id play window id
  886. * @param { String } fileName video file name
  887. */
  888. record(id, fileName) {
  889. if (!this.playControls[id] || !this.playControls[id].player) return
  890. if (!this.recordingStatus[id]) {
  891. this.recordingStatus[id] = true
  892. this.playControls[id].player.StartRecord(5, 1000, fileName || Date.now() + '.mp4')
  893. } else {
  894. this.recordingStatus[id] = false
  895. this.playControls[id].player.StopRecord()
  896. }
  897. }
  898. /**
  899. * @description screenshot
  900. * @param { string } id play window id
  901. */
  902. screenshot(id) {
  903. this.playControls[id].player && this.playControls[id].player.CapturePic(null)
  904. }
  905. /**
  906. * @description video off
  907. * @param { string } id play window id
  908. */
  909. close(id) {
  910. if (this.playControls[id]?.talkPlayer) {
  911. this.playControls[id].talkPlayer.StopTalk()
  912. this.playControls[id].talkPlayer.StopPullStream()
  913. this.playControls[id].talkPlayer.Stop()
  914. this.playControls[id].talkPlayer = null
  915. }
  916. if (this.playControls[id]?.player) {
  917. this.playControls[id].player.StopPullStream()
  918. this.playControls[id].player.Stop()
  919. }
  920. this.playStatus[id] = false
  921. clearTimeout(this.timers[id])
  922. // Define the ID for easier reference
  923. const elementId = `#can-${id}`
  924. const ivsElementId = `#ivsCan-${id}`
  925. const videoElementId = `#video-${id}`
  926. const loadingElementId = `#loading-${id}`
  927. // Check if the elements exist before applying styles
  928. const canElement = document.querySelector(elementId)
  929. const ivsCanElement = document.querySelector(ivsElementId)
  930. const videoElement = document.querySelector(videoElementId)
  931. const loadingElement = document.querySelector(loadingElementId)
  932. if (canElement) {
  933. canElement.style.visibility = 'hidden'
  934. }
  935. if (ivsCanElement) {
  936. ivsCanElement.style.visibility = 'hidden'
  937. }
  938. if (videoElement) {
  939. videoElement.style.visibility = 'hidden'
  940. videoElement.style.display = 'none'
  941. }
  942. if (loadingElement) {
  943. loadingElement.style.display = 'none'
  944. }
  945. if (this.playControls[id]) this.playControls[id].player = null
  946. }
  947. /**
  948. * @description sound settings
  949. * @param { string } id play window id
  950. * @param { number } val volume
  951. */
  952. setAudioVolume(id, val) {
  953. if (!window.webAudioPlayer) {
  954. let intervalId = setInterval(() => {
  955. if (window.webAudioPlayer) {
  956. window.webAudioPlayer.resume()
  957. clearInterval(intervalId)
  958. }
  959. })
  960. } else {
  961. window.webAudioPlayer.resume()
  962. }
  963. this.volumes[id] = val
  964. this.playControls[id].player && this.playControls[id].player.SetVolume(val)
  965. }
  966. /**
  967. * @description sound settings
  968. * @param { string } id play window id
  969. * @param { number } val volume
  970. */
  971. setTalkVolume(id, val) {
  972. if (!window.webAudioPlayer) {
  973. let intervalId = setInterval(() => {
  974. if (window.webAudioPlayer) {
  975. window.webAudioPlayer.resume()
  976. clearInterval(intervalId)
  977. }
  978. })
  979. } else {
  980. window.webAudioPlayer.resume()
  981. }
  982. this.talkVolumes[id] = val
  983. this.playControls[id].talkPlayer && this.playControls[id].talkPlayer.SetVolume(val)
  984. }
  985. /**
  986. * @description pause
  987. * @param { string } id play window id
  988. */
  989. pause(id) {
  990. this.playControls[id]?.player && this.playControls[id].player?.Pause(1)
  991. clearTimeout(this.timers[id])
  992. }
  993. /**
  994. * @description keep pulling
  995. * @param { string } id play window id
  996. */
  997. start(id) {
  998. this.playControls[id]?.player && this.playControls[id].player?.Pause(0)
  999. }
  1000. /**
  1001. * @description fast forward/rewind
  1002. * @param { string } id play window id
  1003. */
  1004. playFF(id, speed) {
  1005. this.playControls[id]?.player && this.playControls[id].player?.SetSpeed(speed)
  1006. }
  1007. parameterProcessing(options, isTalk) {
  1008. const isPrivateProtocol = !options.streamURL.includes('rtsp://')
  1009. const { protocol } = location
  1010. const [wsIP] = options.streamURL.replace('rtsp://', '').split('/')
  1011. const wsURL = `${
  1012. protocol === 'http:' && !options.streamURL.includes('8556') ? 'ws' : 'wss'
  1013. }://${wsIP}`
  1014. const url = options.streamURL.includes('rtsp://')
  1015. ? options.streamURL
  1016. : `rtsp://${options.streamURL}`
  1017. let stream = ''
  1018. if (isTalk) {
  1019. stream = !isPrivateProtocol
  1020. ? url
  1021. : `/live/talk.xav?channel=${options.channelId}&subtype=${options.bitStream}`
  1022. } else {
  1023. stream = !isPrivateProtocol
  1024. ? options.isLive
  1025. ? url
  1026. : url.replace(
  1027. /&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}/,
  1028. ''
  1029. )
  1030. : options.isLive
  1031. ? `/live/realmonitor.xav?channel=${options.channelId}&subtype=${options.bitStream}`
  1032. : `/vod/playback.xav?channel=${options.channelId}&subtype=${options.bitStream}`
  1033. }
  1034. if (isPrivateProtocol) {
  1035. const timeRangeArr =
  1036. /&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(
  1037. url
  1038. )
  1039. if (timeRangeArr) {
  1040. const timeRange = timeRangeArr[0].replace(
  1041. /(&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})/,
  1042. '&starttime=$2_$3_$4_$5_$6_$7&endtime_$9_$10_$11_$12_$13'
  1043. )
  1044. stream += timeRange
  1045. }
  1046. }
  1047. const sourceId = !isPrivateProtocol
  1048. ? options.streamURL.replace('rtsp://', '').split('/')[1]
  1049. : options.streamURL
  1050. .replace('rtsp://', '')
  1051. .split('/')[1]
  1052. .replace(
  1053. /&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}/,
  1054. ''
  1055. )
  1056. const userName = options.userName || 'admin'
  1057. const password = options.password || 'admin123'
  1058. const deviceId = options.deviceId || ''
  1059. const encryptMode = options.encryptMode || 0
  1060. const npt = options.npt || 0
  1061. const panoAR = options.npt || 0
  1062. const open3DPoint = options.open3DPoint || 0
  1063. const isSandardPack = options.isSandardPack || false
  1064. const volume = options.volume || options.volume == 0 ? options.volume : 1
  1065. return {
  1066. isPrivateProtocol,
  1067. wsURL,
  1068. stream,
  1069. sourceId,
  1070. deviceId,
  1071. userName,
  1072. password,
  1073. encryptMode,
  1074. npt,
  1075. panoAR,
  1076. open3DPoint,
  1077. isSandardPack,
  1078. volume
  1079. }
  1080. }
  1081. }
  1082. export default Player