UNPKG

livstream-player

Version:

A lightweight livestream player SDK for React apps

959 lines 50.2 kB
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime"; import { ReloadOutlined } from '@ant-design/icons'; import { Col, Row, Tag, Tooltip } from 'antd'; import React, { useCallback, useEffect, useRef, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import IconCameraOnvif from '@assets/icons/camera_onvif.svg'; import IconCameraRtsp from '@assets/icons/camera_rtsp.svg'; import Info from '@assets/icons/info.svg'; import Info11 from '@assets/icons/info_11.svg'; import Info12 from '@assets/icons/info_12.svg'; import Info3 from '@assets/icons/info_3.svg'; import Info5 from '@assets/icons/info_5.svg'; import Info6 from '@assets/icons/info_6.svg'; import Info7 from '@assets/icons/info_7.svg'; import LiveIconOn from '@assets/icons/live-streaming-on.svg'; import OffStream from '@assets/icons/off_stream.svg'; import PlayIconNoActive from '@assets/icons/play-button-no-active.svg'; import PlayIcon from '@assets/icons/play-button.svg'; import Thumbnail from '@assets/images/thumbnail.jpg'; import * as SERVICE from '@constants/service.types.js'; import { ZOOM_STATE } from '@constants/system.keys.js'; import useWindowDimensions from '@hooks/useWindowDimensions.js'; import { changeDialPadData, getEndStreamReturn, getEndStreamUtraFastReturn, socketEmitEvent } from '@redux/actions.js'; import { calcPercentForVideo } from '@utils/css.js'; import PlayerComponent from '@components/Player/index.jsx'; import './index.scss'; import { editOffer, generateSdpFragment, parseOffer, supportsNonAdvertisedCodec } from './utils.js'; import { useLivestream } from '../../contexts/contexts.js'; const RETRY_PAUSE = 2000; const pc_config = { iceServers: [{ urls: 'stun:stun01.beex.vn:3478' }], bundlePolicy: 'balanced', rtcpMuxPolicy: 'negotiate', sdpSemantics: 'unified-plan' }; const pc_constraints = { optional: [{ DtlsSrtpKeyAgreement: true }] }; const ViewStreamComponent = ({ serial, gatewaySerial, name, typeCamera, state, resolution, iconSize, thumbnail, zoomState, serviceId, isViewAll, permission, isAllowStreaming, allScreen }) => { var _a, _b, _c; const [countRetryStream] = useState(1); const [isFullscreen, setIsFullscreen] = useState(false); const dispatch = useDispatch(); const { width: windowWidth, height: windowHeight } = useWindowDimensions(); const { streamInfo } = useLivestream(); const { namespace, listDeviceContact, streamToken = (_b = (_a = Object.fromEntries(new URLSearchParams(location.search))) === null || _a === void 0 ? void 0 : _a.streamToken) !== null && _b !== void 0 ? _b : streamInfo === null || streamInfo === void 0 ? void 0 : streamInfo.streamToken } = useSelector((state) => state); const peerConnection = useRef({}); const [streaming, setStreaming] = useState(); const [, setWaitForWatch] = useState(0); const [, setWaitForStart] = useState(0); const [streamSerial, setStreamSerial] = useState(serial); const [isConnected, setIsConnected] = useState(false); const [loading, setLoading] = useState(false); const refTryLoad = useRef(); const [tryLoadTimer, setTryLoadTimer] = useState(10); const [isLoadReload, setIsLoadReload] = useState(false); const [onPlay, setOnPlay] = useState(false); const [sourceObject, setSourceObject] = useState(); const [checkTransferZoomState] = useState(false); const [zoomStatePlayer, setZoomStatePlayer] = useState(); const [zoomStateDefault, setZoomStateDefault] = useState(); const [nonAdvertisedCodecs, setNonAdvertisedCodecs] = useState([]); const [queuedCandidates, setQueuedCandidates] = useState([]); const [sessionUrl, setSessionUrl] = useState(''); const [offerData, setOfferData] = useState(''); const [internal, setInternal] = useState(false); const refVideoStreamWS = useRef(null); const refVideoStreamPC = useRef(null); const restartTimeout = useRef(); const onError = useCallback((err) => { console.log('Error: ========>', err); if (!restartTimeout.current) { if (refVideoStreamPC.current !== null) { refVideoStreamPC.current.close(); refVideoStreamPC.current = null; } restartTimeout.current = window.setTimeout(() => { restartTimeout.current = null; loadStream(); }, RETRY_PAUSE); if (sessionUrl) { fetch(sessionUrl, { method: 'DELETE' }); } setSessionUrl(''); setQueuedCandidates([]); } }, // eslint-disable-next-line react-hooks/exhaustive-deps [sessionUrl]); useEffect(() => { (() => __awaiter(void 0, void 0, void 0, function* () { if (gatewaySerial) { try { const url = `https://${gatewaySerial}.ezcam.vn:9090/info`; const promise = yield fetch(url, { signal: AbortSignal.timeout(1000) }); const response = yield promise.json(); setInternal((response === null || response === void 0 ? void 0 : response.localMedia) === 'on'); } catch (error) { console.log('error', error); setInternal(false); } } }))(); }, [gatewaySerial]); useEffect(() => { if (zoomState) { setZoomStatePlayer(zoomState); } }, [zoomState]); const compare = (a, b) => { if (a.resolution > b.resolution) { return -1; } if (a.resolution < b.resolution) { return 1; } return 0; }; useEffect(() => { var _a, _b, _c, _d, _e, _f, _g, _h; const subSourcesTemp = (streaming === null || streaming === void 0 ? void 0 : streaming.subSources) ? JSON.parse(streaming === null || streaming === void 0 ? void 0 : streaming.subSources) : null; if ((subSourcesTemp === null || subSourcesTemp === void 0 ? void 0 : subSourcesTemp.length) > 0 && zoomStatePlayer && zoomState) { const dataArr = (_a = subSourcesTemp === null || subSourcesTemp === void 0 ? void 0 : subSourcesTemp.filter((item) => item.resolution >= 0 && item.zoomState >= 0)) === null || _a === void 0 ? void 0 : _a.sort(compare); let dataArrTemp = [...dataArr]; (_b = zoomState === null || zoomState === void 0 ? void 0 : zoomState.dataZoomStates) === null || _b === void 0 ? void 0 : _b.map((item) => { if (!(dataArrTemp === null || dataArrTemp === void 0 ? void 0 : dataArrTemp.find((item1) => (item1 === null || item1 === void 0 ? void 0 : item1.resolution) === (item === null || item === void 0 ? void 0 : item.resolution)))) { dataArrTemp.push(item); } }); const dataArrTemp1 = dataArrTemp === null || dataArrTemp === void 0 ? void 0 : dataArrTemp.sort(compare); if ((dataArrTemp1 === null || dataArrTemp1 === void 0 ? void 0 : dataArrTemp1.length) > 0) { if (((_c = streaming === null || streaming === void 0 ? void 0 : streaming.mainSource) === null || _c === void 0 ? void 0 : _c.resolution) >= 0 && ((_d = streaming === null || streaming === void 0 ? void 0 : streaming.mainSource) === null || _d === void 0 ? void 0 : _d.zoomState) >= 0) { setZoomStatePlayer((state) => { var _a, _b, _c, _d; return ({ resolution: (state === null || state === void 0 ? void 0 : state.resolution) || ((_a = streaming === null || streaming === void 0 ? void 0 : streaming.mainSource) === null || _a === void 0 ? void 0 : _a.resolution) || 720, zoomState: (_d = (_b = state === null || state === void 0 ? void 0 : state.zoomState) !== null && _b !== void 0 ? _b : (_c = streaming === null || streaming === void 0 ? void 0 : streaming.mainSource) === null || _c === void 0 ? void 0 : _c.zoomState) !== null && _d !== void 0 ? _d : ZOOM_STATE.FOUR, dataZoomStates: dataArrTemp1 === null || dataArrTemp1 === void 0 ? void 0 : dataArrTemp1.map((item) => ({ resolution: item === null || item === void 0 ? void 0 : item.resolution, zoomState: item === null || item === void 0 ? void 0 : item.zoomState })) }); }); setZoomStateDefault({ resolution: (state === null || state === void 0 ? void 0 : state.resolution) || ((_e = streaming === null || streaming === void 0 ? void 0 : streaming.mainSource) === null || _e === void 0 ? void 0 : _e.resolution) || 720, zoomState: (_h = (_f = state === null || state === void 0 ? void 0 : state.zoomState) !== null && _f !== void 0 ? _f : (_g = streaming === null || streaming === void 0 ? void 0 : streaming.mainSource) === null || _g === void 0 ? void 0 : _g.zoomState) !== null && _h !== void 0 ? _h : ZOOM_STATE.FOUR, dataZoomStates: dataArrTemp1 === null || dataArrTemp1 === void 0 ? void 0 : dataArrTemp1.map((item) => { var _a, _b; return ({ resolution: (_a = item === null || item === void 0 ? void 0 : item.resolution) !== null && _a !== void 0 ? _a : 720, zoomState: (_b = item === null || item === void 0 ? void 0 : item.zoomState) !== null && _b !== void 0 ? _b : ZOOM_STATE.FOUR }); }) }); } else { setZoomStatePlayer((state) => (Object.assign(Object.assign({}, state), { dataZoomStates: dataArrTemp1 === null || dataArrTemp1 === void 0 ? void 0 : dataArrTemp1.map((item) => ({ resolution: item === null || item === void 0 ? void 0 : item.resolution, zoomState: item === null || item === void 0 ? void 0 : item.zoomState })) }))); setZoomStateDefault(Object.assign(Object.assign({}, zoomState), { dataZoomStates: dataArrTemp1 === null || dataArrTemp1 === void 0 ? void 0 : dataArrTemp1.map((item) => { var _a, _b; return ({ resolution: (_a = item === null || item === void 0 ? void 0 : item.resolution) !== null && _a !== void 0 ? _a : 720, zoomState: (_b = item === null || item === void 0 ? void 0 : item.zoomState) !== null && _b !== void 0 ? _b : ZOOM_STATE.FOUR }); }) })); } } } }, [streaming]); const createStream = useCallback((dataBody) => { var _a, _b; const data = { serial: dataBody.serial, namespace: dataBody.namespace, type: dataBody.type, qualityLevel: (_b = (_a = dataBody.qualityLevel) !== null && _a !== void 0 ? _a : zoomState === null || zoomState === void 0 ? void 0 : zoomState.zoomState) !== null && _b !== void 0 ? _b : ZOOM_STATE.FOUR, retry: dataBody.retry, serviceId: dataBody.serviceId }; const requestId = new Date().getTime(); let dataObj = { appServiceType: SERVICE.START_STREAM_MONITOR, requestId, body: JSON.stringify(data) }; setWaitForWatch(requestId); dispatch(socketEmitEvent(dataObj)); }, [dispatch]); const createRtspStream = useCallback((dataBody) => { const requestId = new Date().getTime(); let dataObj = { appServiceType: SERVICE.CREATE_RTSP_STREAM, requestId, body: JSON.stringify(dataBody) }; dispatch(socketEmitEvent(dataObj)); }, [dispatch]); const watchStream = useCallback((dataBody) => { const requestId = new Date().getTime(); let dataObj = { appServiceType: SERVICE.WATCH_STREAM, requestId, body: JSON.stringify(dataBody) }; setWaitForWatch(0); setWaitForStart(requestId); dispatch(socketEmitEvent(dataObj)); }, [dispatch]); const handleTryLoad = () => { setIsLoadReload(true); refTryLoad.current = setInterval(() => { setTryLoadTimer((timer) => timer - 1); }, 1000); //Create stream on reload setStreamSerial(serial); let dataBody = { namespace, serial, type: internal ? 'internal' : 'external', serviceId, retry: 0 }; createStream(dataBody); }; useEffect(() => { if (isViewAll) { setOnPlay(true); } }, [isViewAll]); useEffect(() => { if (tryLoadTimer === 0) { setIsLoadReload(false); clearInterval(refTryLoad.current); setWaitForWatch(0); setTryLoadTimer(10); } }, [tryLoadTimer]); useEffect(() => { if (streaming && streaming.started && !isConnected) { clearInterval(refTryLoad.current); setIsConnected(true); } }, [isConnected, streaming]); useEffect(() => { const { serial, streamMonitorId, path, wsHost, wssPort, subSources, zoomState, resolution, protocol, hlsPort, version } = streamInfo; setTimeout(() => { setStreaming({ serial, streamMonitorId: Number(streamMonitorId), streamId: null, sdpOffer: null, started: false, status: null, path, wsHost, wssPort: Number(wssPort), subSources: JSON.parse(subSources), protocol, hlsPort: hlsPort === 'null' ? null : Number(hlsPort), version, mainSource: { zoomState: Number(zoomState), resolution: Number(resolution) } }); }); }, [streamInfo]); const updateStream = useCallback((requestId, dispatch, streamId, candidate, isDone) => { let dataBody = { namespace, streamId, candidate, isDone: isDone }; let dataObj = { appServiceType: SERVICE.UPDATE_STREAM, requestId, body: JSON.stringify(dataBody) }; dispatch(socketEmitEvent(dataObj)); }, [namespace]); // Create Stream useEffect(() => { if (onPlay && state && serial && serviceId) { setLoading(true); setStreamSerial(serial); let dataBody = { namespace, serial, type: internal ? 'internal' : 'external', serviceId, retry: 0 }; createStream(dataBody); } }, [createStream, internal, namespace, onPlay, serial, serviceId, state]); const onChangeHover = useCallback(() => { if (serial && namespace) { let dataBody = { namespace, serial }; let dataObj = { appServiceType: SERVICE.GET_DEVICE_CONTACT_INFO, requestId: new Date().getTime(), body: JSON.stringify(dataBody) }; dispatch(socketEmitEvent(dataObj)); } }, [serial, namespace, dispatch]); const restartCallBack = useCallback((dataObject) => { if (streaming && serial) { let refTimeOut; if (refTimeOut) { clearInterval(refTimeOut); } const { streamId, serial } = streaming; if (streamId) { dispatch(getEndStreamReturn(streamId)); } else { dispatch(getEndStreamUtraFastReturn(serial)); } refTimeOut = setTimeout(() => { let dataBody = { namespace, serial, type: internal ? 'internal' : 'external', serviceId, qualityLevel: dataObject === null || dataObject === void 0 ? void 0 : dataObject.qualityLevel, retry: 1 }; createStream(dataBody); }, 1000); } }, [createStream, dispatch, internal, namespace, serial, serviceId, streaming]); const restartLoadingCallBack = useCallback((dataObject) => { if (serial) { let refTimeOut; if (refTimeOut) { clearInterval(refTimeOut); } dispatch(getEndStreamUtraFastReturn(serial)); refTimeOut = setTimeout(() => { let dataBody = { namespace, serial, type: internal ? 'internal' : 'external', serviceId, qualityLevel: dataObject === null || dataObject === void 0 ? void 0 : dataObject.qualityLevel, retry: 1 }; createStream(dataBody); }, 1000); } }, [createStream, dispatch, internal, namespace, serial, serviceId]); const restartQualityCallBack = useCallback((dataObject) => { if (streaming && serial) { let refTimeOut; if (refTimeOut) { clearInterval(refTimeOut); } const { streamId, serial } = streaming; if (streamId) { dispatch(getEndStreamReturn(streamId)); } else { dispatch(getEndStreamUtraFastReturn(serial)); } refTimeOut = setTimeout(() => { let dataBody = { namespace, serial, type: internal ? 'internal' : 'external', serviceId, qualityLevel: dataObject === null || dataObject === void 0 ? void 0 : dataObject.qualityLevel, retry: 0 }; createStream(dataBody); }, 1000); } }, [createStream, dispatch, internal, namespace, serial, serviceId, streaming]); useEffect(() => { if (streaming && streaming.serial && !streaming.streamId && streaming.streamMonitorId && !streaming.sdpOffer && !streaming.started && !streaming.path && !streaming.wsHost && !streaming.wssPort) { let dataBody = { namespace, serial: streaming.serial, streamMonitorId: streaming.streamMonitorId, serviceId }; createRtspStream(dataBody); } }, [namespace, streaming, createRtspStream, serviceId]); const sendLocalCandidates = useCallback((candidates, url) => { if (url && offerData && streamToken) { fetch(url, { method: 'PATCH', headers: { 'Content-Type': 'application/trickle-ice-sdpfrag', 'If-Match': '*', Authorization: `BeeX a:${streamToken}` }, body: generateSdpFragment(offerData, candidates) }) .then((res) => { switch (res.status) { case 204: break; case 404: throw new Error('stream not found'); default: throw new Error(`bad status code ${res.status}`); } }) .catch((err) => { console.log('Error ===========> ', err); onError(err.toString()); }); } }, [sessionUrl, offerData, streamToken, onError]); const onLocalCandidate = useCallback((evt) => { if (restartTimeout.current) { return; } if (evt.candidate !== null) { if (sessionUrl === '') { setQueuedCandidates((prev) => [...prev, evt.candidate]); } else { sendLocalCandidates([evt.candidate]); } } }, [sendLocalCandidates, sessionUrl]); const onConnectionState = useCallback(() => { if (restartTimeout.current !== null) { return; } if (refVideoStreamPC.current.iceConnectionState === 'disconnected') { onError('peer connection closed'); } }, [onError]); const onTrack = (evt) => { setSourceObject(evt.streams[0]); }; const onRemoteAnswer = useCallback((sdp, sessionUrl) => { if (restartTimeout.current) { return; } refVideoStreamPC.current .setRemoteDescription(new RTCSessionDescription({ type: 'answer', sdp })) .then(() => { if (queuedCandidates.length !== 0) { sendLocalCandidates(queuedCandidates, sessionUrl); setQueuedCandidates([]); } }) .catch((err) => { console.log('Error ========>', err); onError(err.toString()); }); }, [onError, queuedCandidates, sendLocalCandidates]); const sendOffer = (offer) => { if (streaming && (streaming === null || streaming === void 0 ? void 0 : streaming.path) && (streaming === null || streaming === void 0 ? void 0 : streaming.wsHost) && (streaming === null || streaming === void 0 ? void 0 : streaming.wssPort)) { const baseEndpoint = `https://${streaming.wsHost}:${streaming.wssPort}`; fetch(`${baseEndpoint}${streaming.path}/whep`, { method: 'POST', headers: { 'Content-Type': 'application/sdp', Authorization: 'BeeX a:' + streamToken }, body: offer.sdp }) .then((res) => { switch (res.status) { case 201: break; case 404: throw new Error('stream not found'); case 400: return res.json().then((e) => { throw new Error(e.error); }); default: throw new Error(`bad status code ${res.status}`); } const sessionUrl = `${baseEndpoint}${res.headers.get('location')}`; setSessionUrl(`${baseEndpoint}${res.headers.get('location')}`); return res.text().then((sdp) => onRemoteAnswer(sdp, sessionUrl)); }) .catch((err) => { onError(err.toString()); }); } }; // eslint-disable-next-line react-hooks/exhaustive-deps const createOffer = () => { refVideoStreamPC.current .createOffer() .then((offer) => { offer.sdp = editOffer(offer.sdp, nonAdvertisedCodecs); setOfferData(parseOffer(offer.sdp)); refVideoStreamPC.current .setLocalDescription(offer) .then(() => { sendOffer(offer); }) .catch((err) => { onError(err.toString()); }); }) .catch((err) => { onError(err.toString()); }); }; const loadStream = useCallback(() => { // create peer connection webrtc refVideoStreamPC.current = new RTCPeerConnection(pc_config); const direction = 'sendrecv'; refVideoStreamPC.current.addTransceiver('video', { direction }); refVideoStreamPC.current.addTransceiver('audio', { direction }); refVideoStreamPC.current.onicecandidate = (evt) => onLocalCandidate(evt); refVideoStreamPC.current.oniceconnectionstatechange = () => onConnectionState(); refVideoStreamPC.current.ontrack = (evt) => onTrack(evt); createOffer(); }, [createOffer, onConnectionState, onLocalCandidate]); const getNonAdvertisedCodecs = useCallback(() => { Promise.all([ ['pcma/8000/2'], [ 'multiopus/48000/6', 'channel_mapping=0,4,1,2,3,5;num_streams=4;coupled_streams=2' ], ['L16/48000/2'] ].map((c) => supportsNonAdvertisedCodec(c[0], c[1]).then((r) => (r ? c[0] : false)))) .then((c) => c.filter((e) => e !== false)) .then((codecs) => { setNonAdvertisedCodecs(codecs); loadStream(); }); }, [loadStream]); useEffect(() => { if (streaming && streaming.serial && !streaming.streamId && streaming.streamMonitorId && !streaming.sdpOffer && !streaming.started && streaming.path && streaming.wsHost && streaming.wssPort && !streaming.hlsPort && countRetryStream) { const start = () => { const onRemoteCandidate = (msg) => { if (refVideoStreamPC.current === null) { return; } refVideoStreamPC.current.addIceCandidate(JSON.parse(msg.data)); }; const onRemoteDescription = (msg) => { if (refVideoStreamPC.current === null || refVideoStreamWS.current === null) { return; } if (refVideoStreamPC.current) { const d = JSON.parse(msg.data); if (d && d instanceof Array) { refVideoStreamPC.current = new RTCPeerConnection({ iceServers: d }); } else { refVideoStreamPC.current.setRemoteDescription(new RTCSessionDescription(JSON.parse(msg.data))); } } refVideoStreamWS.current.onmessage = (msg) => onRemoteCandidate(msg); }; const onIceCandidate = (evt) => { if (refVideoStreamWS.current === null) { return; } if (evt.candidate !== null) { if (evt.candidate.candidate !== '') { refVideoStreamWS.current.send(JSON.stringify(evt.candidate)); } } }; const onIceServers = (msg) => { if (refVideoStreamWS.current === null) { return; } const iceServers = JSON.parse(msg.data); refVideoStreamPC.current = new RTCPeerConnection({ iceServers }); refVideoStreamWS.current.onmessage = (msg) => onRemoteDescription(msg); refVideoStreamPC.current.onicecandidate = (evt) => onIceCandidate(evt); refVideoStreamPC.current.oniceconnectionstatechange = () => { if (refVideoStreamPC.current === null) { return; } // should restart if (refVideoStreamPC.current.iceConnectionState === 'disconnected') { console.log('Retry connect when iceConnectionState is disconnected'); start(); } }; refVideoStreamPC.current.ontrack = (evt) => { setSourceObject(evt.streams[0]); }; const direction = 'sendrecv'; refVideoStreamPC.current.addTransceiver('video', { direction }); refVideoStreamPC.current.addTransceiver('audio', { direction }); refVideoStreamPC.current.createOffer().then((desc) => { if (refVideoStreamPC.current === null || refVideoStreamWS.current === null) { return; } refVideoStreamPC.current.setLocalDescription(desc); setWaitForStart(0); refVideoStreamWS.current.send(JSON.stringify(desc)); }); }; refVideoStreamWS.current = new WebSocket(`wss://${streaming.wsHost}:${streaming.wssPort}${streaming.path}/ws`); refVideoStreamWS.current.onerror = () => { if (refVideoStreamWS.current === null) { return; } if (refVideoStreamWS.current && refVideoStreamWS.current.readyState === 1) { refVideoStreamWS.current.close(); } refVideoStreamWS.current = null; console.log('Retry connect on error'); start(); }; refVideoStreamWS.current.onclose = () => { refVideoStreamWS.current = null; }; refVideoStreamWS.current.onmessage = (msg) => onIceServers(msg); refVideoStreamWS.current.onopen = () => { const data = { token: streamToken }; if (refVideoStreamWS === null || refVideoStreamWS === void 0 ? void 0 : refVideoStreamWS.current) { if (refVideoStreamWS.current.readyState === 1) { refVideoStreamWS.current.send(JSON.stringify(data)); } else { let timeoutRef = setTimeout(() => { refVideoStreamWS.current.send(JSON.stringify(data)); if (timeoutRef) { clearTimeout(timeoutRef); } }, 2000); } } }; }; const requestId = new Date().getTime(); setWaitForWatch(0); setWaitForStart(requestId); if ((streaming === null || streaming === void 0 ? void 0 : streaming.version) === 'v2') { // Handle with new method getNonAdvertisedCodecs(); } else { start(); } } }, [streaming, streamToken, countRetryStream]); useEffect(() => { if (streaming && streaming.serial && !streaming.streamId && streaming.streamMonitorId && !streaming.sdpOffer && !streaming.started && streaming.path && streaming.wsHost && streaming.wssPort && streaming.hlsPort && countRetryStream) { console.log('Streaming: ', streaming); setSourceObject({ mode: 'hls', link: (streaming === null || streaming === void 0 ? void 0 : streaming.version) === 'v2' ? `https://${streaming === null || streaming === void 0 ? void 0 : streaming.wsHost}:${streaming === null || streaming === void 0 ? void 0 : streaming.hlsPort}${streaming === null || streaming === void 0 ? void 0 : streaming.path}/index.m3u8?token=${streamToken}` : `https://${streaming === null || streaming === void 0 ? void 0 : streaming.wsHost}:${streaming === null || streaming === void 0 ? void 0 : streaming.hlsPort}/${streamToken}${streaming === null || streaming === void 0 ? void 0 : streaming.path}/index.m3u8` }); } }, [streaming, streamToken, countRetryStream]); // Watch Stream useEffect(() => { if (streaming && streaming.serial && streaming.streamId && !streaming.sdpOffer && !streaming.started) { let dataBody = { namespace, serial: streaming.serial, streamId: streaming.streamId }; watchStream(dataBody); } }, [namespace, streaming, watchStream]); useEffect(() => { if (streaming && streaming.sdpOffer && !streaming.started) { const offerOptions = { offerToReceiveAudio: true, offerToReceiveVideo: true }; if (peerConnection.current && peerConnection.current.connectionState) { peerConnection.current.close(); } peerConnection.current = new RTCPeerConnection(pc_config, pc_constraints); let sdpData = { type: 'offer', sdp: streaming.sdpOffer }; let remoteSessionDescription = new RTCSessionDescription(sdpData); if (peerConnection.current) { peerConnection.current .setRemoteDescription(remoteSessionDescription) .then(() => { peerConnection.current .createAnswer(offerOptions) .then((localDescription) => { peerConnection.current .setLocalDescription(localDescription) .then(() => { // start stream here let dataBody = { streamId: streaming.streamId, sdpAnswer: localDescription.sdp, namespace }; let dataObj = { appServiceType: SERVICE.START_STREAM, requestId: new Date().getTime(), body: JSON.stringify(dataBody) }; setWaitForStart(0); return dispatch(socketEmitEvent(dataObj)); }) .catch(() => { }); }) .catch(() => { }); }) .catch(() => { }); peerConnection.current.onicecandidate = (event) => { const requestId = new Date().getTime(); if (event.candidate) { peerConnection.current.addIceCandidate(event.candidate); // call update stream updateStream(requestId, dispatch, streaming.streamId, event.candidate.candidate, 0); } else { //call update stream updateStream(requestId, dispatch, streaming.streamId, '', 1); } }; peerConnection.current.ontrack = (event) => { if (event) { setSourceObject(event.streams[0]); } }; } } }, [dispatch, namespace, streaming, updateStream]); useEffect(() => { var _a; if (streaming && (zoomState === null || zoomState === void 0 ? void 0 : zoomState.zoomState) && streaming.started) { setLoading(false); let dataBody = { streamId: streaming.streamId, zoomState: (_a = zoomStatePlayer === null || zoomStatePlayer === void 0 ? void 0 : zoomStatePlayer.zoomState) !== null && _a !== void 0 ? _a : ZOOM_STATE.FOUR, namespace }; let dataObj = { appServiceType: SERVICE.ZOOM_STATE_STREAM, requestId: new Date().getTime(), body: JSON.stringify(dataBody) }; dispatch(socketEmitEvent(dataObj)); } }, [dispatch, streaming, namespace]); // Stop stream on exit useEffect(() => { return () => { if (streaming && streaming.started && streaming.status && streaming.status.length > 0) { const { streamId } = streaming; let dataBody = { streamId, namespace }; let dataObj = { appServiceType: SERVICE.STOP_STREAM, requestId: new Date().getTime(), body: JSON.stringify(dataBody) }; setStreaming(null); dispatch(socketEmitEvent(dataObj)); dispatch(getEndStreamReturn(streamId)); } }; }, [dispatch, namespace, streaming]); // Stop stream ultra fast on exit useEffect(() => { return () => { if (streaming && streaming.wsHost && streaming.wssPort && streaming.path && !streaming.hlsPort) { if (refVideoStreamWS.current && refVideoStreamWS.current.readyState === 1) { refVideoStreamWS.current.close(); } refVideoStreamWS.current = null; if (refVideoStreamPC.current) { refVideoStreamPC.current.close(); } refVideoStreamPC.current = null; setStreaming(null); dispatch(getEndStreamUtraFastReturn(streaming.serial)); } }; }, [dispatch, streaming]); // Stop stream hls fast on exit useEffect(() => { return () => { if (streaming && streaming.wsHost && streaming.wssPort && streaming.path && streaming.hlsPort) { setStreaming(null); setSourceObject(null); dispatch(getEndStreamUtraFastReturn(streaming.serial)); } }; }, [dispatch, streaming]); const onRotateCamera = useCallback((navigator) => { if (streaming === null || streaming === void 0 ? void 0 : streaming.serial) { let dataBody = { navigator, namespace, serial: streaming === null || streaming === void 0 ? void 0 : streaming.serial }; let dataObj = { appServiceType: SERVICE.ROTATE_VIEW_CAMERA, requestId: new Date().getTime(), body: JSON.stringify(dataBody) }; return dispatch(socketEmitEvent(dataObj)); } }, [dispatch, namespace, streaming]); const onZoomCamera = useCallback((zoom) => { if (streaming === null || streaming === void 0 ? void 0 : streaming.serial) { let dataBody = { zoom, namespace, serial: streaming === null || streaming === void 0 ? void 0 : streaming.serial }; let dataObj = { appServiceType: SERVICE.ZOOM_VIEW_CAMERA, requestId: new Date().getTime(), body: JSON.stringify(dataBody) }; return dispatch(socketEmitEvent(dataObj)); } }, [dispatch, namespace, streaming]); return (_jsxs("div", { className: 'view-stream-component', style: { height: '100%' }, children: [state === 1 || isConnected ? (!sourceObject && (_jsx("div", { className: 'icon-live-stream', children: _jsx("img", { width: iconSize ? iconSize : 26, height: iconSize ? iconSize : 26, className: 'icon', alt: 'live-stream-icon', src: LiveIconOn }) }))) : (_jsxs(_Fragment, { children: [_jsx("div", { className: 'name-camera', children: name }), _jsx("div", { className: 'icon-live-stream', children: _jsx("img", { width: iconSize ? iconSize : 26, height: iconSize ? iconSize : 26, className: 'icon', alt: 'live-stream-icon', src: OffStream }) })] })), !sourceObject && (_jsx("div", { className: 'icon-type-stream', children: _jsx("img", { width: iconSize ? iconSize : 26, height: iconSize ? iconSize : 26, className: 'icon', alt: 'live-stream-icon', src: typeCamera === 'onvif' ? IconCameraOnvif : IconCameraRtsp }) })), !sourceObject && (_jsx(Tooltip, { placement: 'left', mouseEnterDelay: 0.5, title: _jsx(_Fragment, { children: _jsxs(Row, { children: [_jsx(Col, { span: 24, children: _jsxs(Row, { style: { borderBottom: '1px solid #303030', paddingBottom: '10px' }, children: [_jsx(Col, { span: 18, style: { fontWeight: 'bold', fontSize: '13px', color: 'hsla(0,0%,100%,.85)' }, children: (listDeviceContact === null || listDeviceContact === void 0 ? void 0 : listDeviceContact.name) || '' }), _jsx(Col, { span: 6, children: (listDeviceContact === null || listDeviceContact === void 0 ? void 0 : listDeviceContact.state) === 1 ? (_jsx(Tag, { color: 'rgb(14, 147, 71)', children: "Online" })) : (_jsx(Tag, { color: 'rgb(79, 77, 77)', children: "Offline" })) })] }) }), (listDeviceContact === null || listDeviceContact === void 0 ? void 0 : listDeviceContact.note) && (_jsxs(Col, { span: 24, style: { color: 'hsla(0, 0%, 100%, 0.65)', marginTop: '10px', fontSize: '13px' }, children: [_jsx("img", { className: 'info-icon-stream', alt: 'live-stream-icon', style: { marginTop: '-2px' }, src: Info3 }), (listDeviceContact === null || listDeviceContact === void 0 ? void 0 : listDeviceContact.note) || ''] })), state === 0 && (_jsx(Col, { span: 24, children: _jsxs(Row, { children: [(listDeviceContact === null || listDeviceContact === void 0 ? void 0 : listDeviceContact.errorTime) && (_jsxs(Col, { span: 24, style: { color: 'hsla(0, 0%, 100%, 0.65)', marginTop: '5px', fontSize: '13px' }, children: [_jsx("img", { className: 'info-icon-stream', alt: 'live-stream-icon', style: { marginTop: '-2px' }, src: Info11 }), "Time:", ' ', _jsx("span", { style: { color: 'rgb(245, 47, 57)' }, children: (listDeviceContact === null || listDeviceContact === void 0 ? void 0 : listDeviceContact.errorTime) || '' })] })), (listDeviceContact === null || listDeviceContact === void 0 ? void 0 : listDeviceContact.errorMessage) && (_jsxs(Col, { span: 24, style: { color: 'hsla(0, 0%, 100%, 0.65)', marginTop: '5px', fontSize: '13px' }, children: [_jsx("img", { className: 'info-icon-stream', alt: 'live-stream-icon', style: { marginTop: '-2px' }, src: Info12 }), "Reason:", ' ', _jsx("span", { style: { color: 'rgb(245, 47, 57)' }, children: (listDeviceContact === null || listDeviceContact === void 0 ? void 0 : listDeviceContact.errorMessage) || '' })] }))] }) })), _jsxs(Col, { span: 24, style: { marginTop: '10px', fontSize: '13px' }, children: [_jsx("img", { className: 'info-icon-stream', alt: 'live-stream-icon', style: { marginTop: '-2px' }, src: Info5 }), _jsx("span", { style: { color: '#0E9347' }, children: "PERSON IN CHARGE" })] }), ((_c = listDeviceContact === null || listDeviceContact === void 0 ? void 0 : listDeviceContact.assigners) === null || _c === void 0 ? void 0 : _c.length) > 0 && listDeviceContact.assigners.map((item, index) => (_jsx(Col, { span: 24, children: _jsxs(Row, { children: [item.fullName && (_jsxs(Col, { span: 24, style: { color: 'hsla(0, 0%, 100%, 0.65)', marginTop: '5px', fontSize: '13px' }, children: [_jsx("img", { className: 'info-icon-stream', alt: 'live-stream-icon', style: { marginTop: '-2px' }, src: Info6 }), "H\u1ECD t\u00EAn: ", item.fullName || ''] })), item.phoneNumber && (_jsxs(Col, { span: 24, style: { color: 'hsla(0, 0%, 100%, 0.65)', marginTop: '5px', fontSize: '13px' }, children: [_jsx("img", { className: 'info-icon-stream', alt: 'live-stream-icon', style: { marginTop: '-2px' }, src: Info7 }), "Phone number:", ' ', _jsx("span", { style: { color: '#0E9347', textDecoration: 'underline', cursor: 'pointer' }, onClick: () => { dispatch(changeDialPadData({ show: true, phone: item.phoneNumber })); }, children: item.phoneNumber || '' })] }))] }) }, index)))] }) }), children: _jsx("div", { className: 'icon-info-stream', onMouseOver: () => onChangeHover(), children: _jsx("img", { width: iconSize ? iconSize : 26, height: iconSize ? iconSize : 26, className: 'icon', alt: 'live-stream-icon', src: Info }) }) })), state === 0 && !isConnected && permission && permission.split('_') && permission.split('_').find((item) => item === 'live') && (_jsxs(_Fragment, { children: [_jsx("div", { onClick: () => !isLoadReload && isAllowStreaming !== 0 && handleTryLoad(), className: 'preload-spinner reconnect', children: _jsx(ReloadOutlined, { className: isAllowStreaming === 0 ? 'no-active' : '', style: { fontSize: 48 }, spin: isLoadReload }) }), isAllowStreaming === 0 && (_jsx("div", { className: 'text-no-active', children: _jsx(Tag, { color: '#f50', children: "Not active" }) }))] })), onPlay ? (_jsx(PlayerComponent, { name: name, onvif: typeCamera === 'onvif', onRotate: onRotateCamera, onZoom: onZoomCamera, resolution: resolution, zoomStateProps: zoomStateDefault !== null && zoomStateDefault !== void 0 ? zoomStateDefault : zoomState, isFullscreenProps: isFullscreen, restartCallBack: restartCallBack, restartLoadingCallBack: restartLoadingCallBack, fullScreenCallBack: (isFull) => setIsFullscreen(isFull), status: streaming && streaming.status, type: 'streaming', loading: loading, sourceObject: sourceObject, poster: thumbnail && thumbnail.match(/http/g) ? thumbnail : Thumbnail, setOnPlay: setOnPlay, serial: serial, checkTransferZoomState: checkTransferZoomState, zoomStatePlayer: zoomStatePlayer, setZoomStatePlayer: setZoomStatePlayer, restartQualityCallBack: restartQualityCallBack, isHlsStreaming: !!(streaming === null || streaming === void 0 ? void 0 : streaming.hlsPort), allScreen: allScreen, protocol: streaming === null || streaming === void 0 ? void 0 : streaming.protocol })) : (_jsxs("div", { className: 'video-wrapper thumbnail', style: { paddingBottom: allScreen ? '56.25%' : `${calcPercentForVideo(windowHeight - 108, windowWidth - 324)}%` }, children: [state === 1 && permission && permission.split('_') && permission.split('_').find((item) => item === 'live') && (_jsxs(_Fragment, { children: [_jsx("img", { alt: 'play-icon', onClick: () => { if (isAllowStreaming !== 0) { setOnPlay(true); } }, src: isAllowStreaming === 0 ? PlayIconNoActive : PlayIcon }), isAllowStreaming === 0 && (_jsx("div", { className: 'text-no-active', children: _jsx