手持设备的视频对接 调试成功、以及项目文件路径的优化

手持设备的视频对接 调试成功、以及项目文件路径的优化
This commit is contained in:
TimSpan 2024-07-31 17:04:12 +08:00
parent 7edfd5275f
commit 98b7b2d5d2
63 changed files with 8873 additions and 4467 deletions

View File

@ -6,6 +6,8 @@ VITE_DROP_CONSOLE=true
# axios
VITE_APP_BASE_API=/api
VITE_APP_PROXY_URL=http://175.6.124.250:8083
# VITE_APP_PROXY_URL=https://www.hndyjqrh.cn
#crypto js 前后端需保持一致
VITE_APP_CRYPTO_JS_SECRET_KEY=f0234d57c311beb2

File diff suppressed because one or more lines are too long

View File

@ -13,10 +13,9 @@
<div id="app"></div>
<script
src="https://webapi.amap.com/maps?v=1.4.15&key=8910226d8d36a41d856262b1a588850c&plugin=AMap.MarkerClusterer"></script>
<!-- <script src="./public/jquery-3.4.1.min.js"></script>
<script src="./public/h5player.min.js"></script> -->
<script src="./jquery-3.4.1.min.js"></script>
<script src="./h5player.min.js"></script>
<script src="/haikang/h5player.min.js"></script>
<script type="module" src="/src/main.ts">
</script>

3
public/rtc/.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"liveServer.settings.port": 5501
}

File diff suppressed because one or more lines are too long

9
public/rtc/config/url.js Normal file
View File

@ -0,0 +1,9 @@
export const mqttUrl = ''
// export const mqttUrl = 'http://localhost:9527/api/multialarm/video/keep'
// export const mqttUrl = 'https://www.hndyjqrh.cn/multialarm/video/keep'
// export const mqttUrl = 'https://www.hnjinglian.cn:2563/api_8083/firectrl/client/notice/sendmqtt'

View File

@ -0,0 +1,286 @@
html,body{
width:100%;
height:100%;
background:#000;
overflow: hidden;
}
#video{
float:left;
width:100%;
height:100%;
position: absolute;
background-image:url("../walkBgVideo.png");
background-repeat:no-repeat;
background-size:100% 100%;
z-index:100;
}
#agora_local,
.player{
width:100%;
height:100%;
}
#video>p{
width:360px;
height:120px;
color:#fff;
font-size:32px;
position:absolute;
left:50%;
top:50%;
margin-left:-180px;
margin-top:-100px;
}
#video>p:hover{
cursor: pointer;
}
#video>p>span{
display: block;
width:100%;
height:45px;
line-height:45px;
}
#video>p>img{
display:block;
width:60px;
height:60px;
margin:8px 120px;
}
body:hover .videoNav{
display: block;
}
.videoNav{
display: none;
}
.videoNav{
position:absolute;
width:100%;
bottom:0px;
left:0;
z-index:9999999;
}
.videoNav>p{
float:left;
height:30px;
line-height:30px;
background:rgba(0, 0, 0, 0.44);
width:100%;
}
.videoNav>p>img{
height:18px;
padding:3px 5px;
border-radius: 3px;
border:1px solid #ccc;
}
.videoNav>p>img:last-child{
margin:7px;
padding:2px;
float:right;
}
.videoNav>p>img:first-child{
margin-left:5px;
}
.videoNav>p:last-child>img{
border:0;
padding:0;
}
.videoNav>p:last-child>span{
color:#fff;
}
.layui-slider{
float:left;
width:70px;
margin-top:18px;
}
.layui-slider-bar{
background-color:#1296DB !important;
}
.layui-slider-wrap-btn{
vertical-align: baseline;
}
.canvasImg{
display: none;
position: absolute;
width: 100%;
height:100%;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 1000000;
background: rgba(0, 0, 0, 0.44);
}
.canvasImgBox{
position: absolute;
background: #000;
right:10px;
bottom:90px;
font-size: 14px;
}
canvas{
width:100%;
height:100%;
}
.canvasImgBox>p{
height:40px;
line-height:40px;
}
.canvasImgBox>p>a,
.canvasImgBox>p>button{
display: inline-block;
height:36px;
line-height:36px;
border:1px solid #ccc;
color:#fff;
border-radius: 2px;
padding:0 16px;
background-color: #000;
}
.inTheVideo{
width:100px;
height:40px;
z-index:99999999;
right:10px;
top:10px;
position:absolute;
line-height:40px;
color:#000;
font-size:20px;
animation:mymove 6s infinite;
display:none;
background:#fff;
padding:0px 10px;
border-radius: 6px;
}
.inTheVideo>img{
width:22px;
height:22px;
float:left;
margin:9px 5px;
}
@keyframes mymove
{
0% {opacity:0;}
25% {opacity:0.5;}
50% {opacity:1;}
75% {opacity:0.5;}
100% {opacity:0;}
}
.videoRotate{
position:absolute;
z-index:9999999999999999999;
width:200px;
height:90px;
right:0%;
top:0%;
margin-top:0px;
margin-left:-70px;
font-size:14px;
border-radius:4px;
color:#000;
text-align: center;
}
.videoRotate>p{
line-height:40px;
height:40px;
margin:10px 0;
}
.videoRotate>p>button{
padding:5px 10px;
margin:0 5px;
border:0;
}
.videoRotate>p>button:hover{
cursor: pointer;
}
.videoRotate>p:nth-child(2)>button:nth-child(2){
width:40px;
height:40px;
border-radius:50%;
}
.videoRotate>p>.bgColor{
color:#fff;
background:#003c71;
}
.videoTitle{
position:absolute;
z-index:9999999999999999999;
background:#ccc;
width:300px;
height:140px;
left:50%;
top:50%;
margin-top:-70px;
margin-left:-150px;
font-size:14px;
border-radius:4px;
border:1px solid #fff;
display:none;
}
.videoTitle>p{
text-align:center;
}
.videoTitle>p:nth-child(1){
border-radius:4px 4px 0 0;
height:30px;
line-height:30px;
text-align: center;
background:#ccc;
font-size:16px;
font-weight: bold;
border-bottom:1px solid #fff;
}
.videoTitle>p:nth-child(2){
height:50px;
line-height:50px;
}
.videoTitle>p:nth-child(3)>button{
height:32px;
line-height:28px;
padding:0 12px;
color:#000;
border:0;
font-size:14px;
margin-right:5px;
}
.videoInfo,
#qrcode{
display:none;
width:100%;
z-index:99999999;
bottom:0px;
position:absolute;
color:#fff;
font-size:14px;
background:#000;
opacity:0.6;
}
.videoInfo{
left:0px;
}
#qrcode{
width:150px;
height:150px;
border:1px solid #ccc;
right:0px !important;
opacity:1;
}
.videoInfo>p{
float:left;
height:36px;
line-height:36px;
margin-left:10px;
}

View File

@ -0,0 +1,281 @@
html,body{
width:100%;
height:100%;
background:#000;
overflow: hidden;
}
#video{
float:left;
width:100%;
height:720px;
position: absolute;
background-image:url("../walkBgVideo.png");
background-repeat:no-repeat;
background-size:100% 100%;
z-index:100;
}
#agora_local,
.player{
width:100%;
height:100%;
}
#video>p{
width:360px;
height:120px;
color:#fff;
font-size:32px;
position:absolute;
left:50%;
top:50%;
margin-left:-180px;
margin-top:-100px;
}
#video>p:hover{
cursor: pointer;
}
#video>p>span{
display: block;
width:100%;
height:45px;
line-height:45px;
}
#video>p>img{
display:block;
width:60px;
height:60px;
margin:8px 120px;
}
.videoNav{
position:absolute;
width:100%;
height:40px;
line-height:40px;
bottom:0px;
left:0;
background:#000;
z-index:9999999;
}
.videoNav>p{
float:left;
height:40px;
line-height:40px;
margin-right:10px;
}
.videoNav>p>img{
height:24px;
padding:3px 5px;
border-radius: 3px;
border:1px solid #ccc;
}
.videoNav>p>img:last-child{
margin-right:10px;
padding:2px;
}
.videoNav>p:last-child{
margin-left:5px;
}
.videoNav>p>img:first-child{
margin-left:5px;
}
.videoNav>p:last-child>img{
border:0;
padding:0;
margin-top:-2px;
}
.videoNav>p:last-child>span{
color:#fff;
}
.layui-slider{
float:left;
width:70px;
margin-top:18px;
}
.layui-slider-bar{
background-color:#1296DB !important;
}
.layui-slider-wrap-btn{
vertical-align: baseline;
}
.canvasImg{
display: none;
position: absolute;
width: 100%;
height:100%;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 1000000;
background: rgba(0, 0, 0, 0.44);
}
.canvasImgBox{
position: absolute;
background: #000;
right:10px;
bottom:90px;
font-size: 14px;
}
canvas{
width:100%;
height:100%;
}
.canvasImgBox>p{
height:40px;
line-height:40px;
}
.canvasImgBox>p>a,
.canvasImgBox>p>button{
display: inline-block;
height:36px;
line-height:36px;
border:1px solid #ccc;
color:#fff;
border-radius: 2px;
padding:0 16px;
background-color: #000;
}
.inTheVideo{
width:100px;
height:40px;
z-index:99999999;
right:10px;
top:10px;
position:absolute;
line-height:40px;
color:#000;
font-size:20px;
animation:mymove 6s infinite;
display:none;
background:#fff;
padding:0px 10px;
border-radius: 6px;
}
.inTheVideo>img{
width:22px;
height:22px;
float:left;
margin:9px 5px;
}
@keyframes mymove
{
0% {opacity:0;}
25% {opacity:0.5;}
50% {opacity:1;}
75% {opacity:0.5;}
100% {opacity:0;}
}
.videoRotate{
position:absolute;
z-index:9999999999999999999;
width:200px;
height:90px;
right:0%;
top:0%;
margin-top:0px;
margin-left:-70px;
font-size:14px;
border-radius:4px;
color:#000;
text-align: center;
}
.videoRotate>p{
line-height:40px;
height:40px;
margin:10px 0;
}
.videoRotate>p>button{
padding:5px 10px;
margin:0 5px;
border:0;
}
.videoRotate>p>button:hover{
cursor: pointer;
}
.videoRotate>p:nth-child(2)>button:nth-child(2){
width:40px;
height:40px;
border-radius:50%;
}
.videoRotate>p>.bgColor{
color:#fff;
background:#003c71;
}
.videoTitle{
position:absolute;
z-index:9999999999999999999;
background:#ccc;
width:300px;
height:140px;
left:50%;
top:50%;
margin-top:-70px;
margin-left:-150px;
font-size:14px;
border-radius:4px;
border:1px solid #fff;
display:none;
}
.videoTitle>p{
text-align:center;
}
.videoTitle>p:nth-child(1){
border-radius:4px 4px 0 0;
height:30px;
line-height:30px;
text-align: center;
background:#ccc;
font-size:16px;
font-weight: bold;
border-bottom:1px solid #fff;
}
.videoTitle>p:nth-child(2){
height:50px;
line-height:50px;
}
.videoTitle>p:nth-child(3)>button{
height:32px;
line-height:28px;
padding:0 12px;
color:#000;
border:0;
font-size:14px;
margin-right:5px;
}
.videoInfo,
#qrcode{
display:none;
width:100%;
z-index:99999999;
bottom:0px;
position:absolute;
color:#fff;
font-size:14px;
background:#000;
opacity:0.6;
}
.videoInfo{
left:0px;
}
#qrcode{
width:150px;
height:150px;
border:1px solid #ccc;
right:0px !important;
opacity:1;
}
.videoInfo>p{
float:left;
height:36px;
line-height:36px;
margin-left:10px;
}

View File

@ -0,0 +1,281 @@
html,body{
width:100%;
height:100%;
background:#000;
overflow: hidden;
}
#video{
float:left;
width:100%;
height:720px;
position: absolute;
background-image:url("../walkBgVideo.png");
background-repeat:no-repeat;
background-size:100% 100%;
z-index:100;
}
#agora_local,
.player{
width:100%;
height:100%;
}
#video>p{
width:360px;
height:120px;
color:#fff;
font-size:32px;
position:absolute;
left:50%;
top:50%;
margin-left:-180px;
margin-top:-100px;
}
#video>p:hover{
cursor: pointer;
}
#video>p>span{
display: block;
width:100%;
height:45px;
line-height:45px;
}
#video>p>img{
display:block;
width:60px;
height:60px;
margin:8px 120px;
}
.videoNav{
position:absolute;
width:100%;
height:40px;
line-height:40px;
bottom:0px;
left:0;
background:#000;
z-index:9999999;
}
.videoNav>p{
float:left;
height:40px;
line-height:40px;
margin-right:10px;
}
.videoNav>p>img{
height:24px;
padding:3px 5px;
border-radius: 3px;
border:1px solid #ccc;
}
.videoNav>p>img:last-child{
margin-right:10px;
padding:2px;
}
.videoNav>p:last-child{
margin-left:5px;
}
.videoNav>p>img:first-child{
margin-left:5px;
}
.videoNav>p:last-child>img{
border:0;
padding:0;
margin-top:-2px;
}
.videoNav>p:last-child>span{
color:#fff;
}
.layui-slider{
float:left;
width:70px;
margin-top:18px;
}
.layui-slider-bar{
background-color:#1296DB !important;
}
.layui-slider-wrap-btn{
vertical-align: baseline;
}
.canvasImg{
display: none;
position: absolute;
width: 100%;
height:100%;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 1000000;
background: rgba(0, 0, 0, 0.44);
}
.canvasImgBox{
position: absolute;
background: #000;
right:10px;
bottom:90px;
font-size: 14px;
}
canvas{
width:100%;
height:100%;
}
.canvasImgBox>p{
height:40px;
line-height:40px;
}
.canvasImgBox>p>a,
.canvasImgBox>p>button{
display: inline-block;
height:36px;
line-height:36px;
border:1px solid #ccc;
color:#fff;
border-radius: 2px;
padding:0 16px;
background-color: #000;
}
.inTheVideo{
width:100px;
height:40px;
z-index:99999999;
right:10px;
top:10px;
position:absolute;
line-height:40px;
color:#000;
font-size:20px;
animation:mymove 6s infinite;
display:none;
background:#fff;
padding:0px 10px;
border-radius: 6px;
}
.inTheVideo>img{
width:22px;
height:22px;
float:left;
margin:9px 5px;
}
@keyframes mymove
{
0% {opacity:0;}
25% {opacity:0.5;}
50% {opacity:1;}
75% {opacity:0.5;}
100% {opacity:0;}
}
.videoRotate{
position:absolute;
z-index:9999999999999999999;
width:200px;
height:90px;
right:0%;
top:0%;
margin-top:0px;
margin-left:-70px;
font-size:14px;
border-radius:4px;
color:#000;
text-align: center;
}
.videoRotate>p{
line-height:40px;
height:40px;
margin:10px 0;
}
.videoRotate>p>button{
padding:5px 10px;
margin:0 5px;
border:0;
}
.videoRotate>p>button:hover{
cursor: pointer;
}
.videoRotate>p:nth-child(2)>button:nth-child(2){
width:40px;
height:40px;
border-radius:50%;
}
.videoRotate>p>.bgColor{
color:#fff;
background:#003c71;
}
.videoTitle{
position:absolute;
z-index:9999999999999999999;
background:#ccc;
width:300px;
height:140px;
left:50%;
top:50%;
margin-top:-70px;
margin-left:-150px;
font-size:14px;
border-radius:4px;
border:1px solid #fff;
display:none;
}
.videoTitle>p{
text-align:center;
}
.videoTitle>p:nth-child(1){
border-radius:4px 4px 0 0;
height:30px;
line-height:30px;
text-align: center;
background:#ccc;
font-size:16px;
font-weight: bold;
border-bottom:1px solid #fff;
}
.videoTitle>p:nth-child(2){
height:50px;
line-height:50px;
}
.videoTitle>p:nth-child(3)>button{
height:32px;
line-height:28px;
padding:0 12px;
color:#000;
border:0;
font-size:14px;
margin-right:5px;
}
.videoInfo,
#qrcode{
display:none;
width:100%;
z-index:99999999;
bottom:0px;
position:absolute;
color:#fff;
font-size:14px;
background:#000;
opacity:0.6;
}
.videoInfo{
left:0px;
}
#qrcode{
width:150px;
height:150px;
border:1px solid #ccc;
right:0px !important;
opacity:1;
}
.videoInfo>p{
float:left;
height:36px;
line-height:36px;
margin-left:10px;
}

View File

@ -0,0 +1,58 @@
<!DOCTYPE html>
<html>
<head>
<title>视频查看</title>
<meta charset="UTF-8"/>
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate"/>
<meta http-equiv="Cache" content="no-cache">
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<link rel="stylesheet" href="./layui.css">
<script src="AgoraRTC_N-4.11.0.js"></script>
<script src="./jquery-3.4.1.min.js"></script>
<script src="./layui.js"></script>
<!--给录像文件添加时间进度条-->
<script src="fix-webm-duration.js"></script>
</head>
<body>
<div id="video">
<div id="qrcode"></div>
<div id="agora_local"></div>
</div>
<!--视频操作-->
<div class="videoNav">
<p class="nav">
<img src="images/videoExit.png" alt="" class="videoExit" title="退出"/>
<img src="images/closeMute.png" alt="" title="静音" mute="close" class="closeMute"/>
<img src="images/videoFullscreen.png" alt="" title="全屏" model="exitfullScreen" class="videoFullscreen"/>
</p>
</div>
<!--当js文件发生变化的时候自动清除浏览器缓存,只要标签后面的v每次不一样浏览器就更新了阿-->
<script>
//创建一个script标签
function loadScriptString() {
var timeStamp=new Date().getTime();
var script = document.createElement("script"); //创建一个script标签
script.type = "module";
script.src=`js/deviceAlarmVideo.js?v=${timeStamp}`;
document.getElementsByTagName('head')[0].appendChild(script);
}
//创建一个link标签
function loadLinkString(){
var timeStamp=new Date().getTime();
var css = document.createElement("link"); //创建一个script标签
css.rel = "stylesheet";
css.href=`css/deviceAlarmVideo.css?v=${timeStamp}`
document.getElementsByTagName('head')[0].appendChild(css);
}
loadScriptString();
loadLinkString();
</script>
</body>
</html>

View File

@ -0,0 +1,487 @@
(function (name, definition) {
if (typeof define === 'function' && define.amd) { // RequireJS / AMD
define(definition);
} else if (typeof module !== 'undefined' && module.exports) { // CommonJS / Node.js
module.exports = definition();
} else { // Direct include
window.ysFixWebmDuration = definition();
}
})('fix-webm-duration', function () {
/*
* This is the list of possible WEBM file sections by their IDs.
* Possible types: Container, Binary, Uint, Int, String, Float, Date
*/
var sections = {
0xa45dfa3: { name: 'EBML', type: 'Container' },
0x286: { name: 'EBMLVersion', type: 'Uint' },
0x2f7: { name: 'EBMLReadVersion', type: 'Uint' },
0x2f2: { name: 'EBMLMaxIDLength', type: 'Uint' },
0x2f3: { name: 'EBMLMaxSizeLength', type: 'Uint' },
0x282: { name: 'DocType', type: 'String' },
0x287: { name: 'DocTypeVersion', type: 'Uint' },
0x285: { name: 'DocTypeReadVersion', type: 'Uint' },
0x6c: { name: 'Void', type: 'Binary' },
0x3f: { name: 'CRC-32', type: 'Binary' },
0xb538667: { name: 'SignatureSlot', type: 'Container' },
0x3e8a: { name: 'SignatureAlgo', type: 'Uint' },
0x3e9a: { name: 'SignatureHash', type: 'Uint' },
0x3ea5: { name: 'SignaturePublicKey', type: 'Binary' },
0x3eb5: { name: 'Signature', type: 'Binary' },
0x3e5b: { name: 'SignatureElements', type: 'Container' },
0x3e7b: { name: 'SignatureElementList', type: 'Container' },
0x2532: { name: 'SignedElement', type: 'Binary' },
0x8538067: { name: 'Segment', type: 'Container' },
0x14d9b74: { name: 'SeekHead', type: 'Container' },
0xdbb: { name: 'Seek', type: 'Container' },
0x13ab: { name: 'SeekID', type: 'Binary' },
0x13ac: { name: 'SeekPosition', type: 'Uint' },
0x549a966: { name: 'Info', type: 'Container' },
0x33a4: { name: 'SegmentUID', type: 'Binary' },
0x3384: { name: 'SegmentFilename', type: 'String' },
0x1cb923: { name: 'PrevUID', type: 'Binary' },
0x1c83ab: { name: 'PrevFilename', type: 'String' },
0x1eb923: { name: 'NextUID', type: 'Binary' },
0x1e83bb: { name: 'NextFilename', type: 'String' },
0x444: { name: 'SegmentFamily', type: 'Binary' },
0x2924: { name: 'ChapterTranslate', type: 'Container' },
0x29fc: { name: 'ChapterTranslateEditionUID', type: 'Uint' },
0x29bf: { name: 'ChapterTranslateCodec', type: 'Uint' },
0x29a5: { name: 'ChapterTranslateID', type: 'Binary' },
0xad7b1: { name: 'TimecodeScale', type: 'Uint' },
0x489: { name: 'Duration', type: 'Float' },
0x461: { name: 'DateUTC', type: 'Date' },
0x3ba9: { name: 'Title', type: 'String' },
0xd80: { name: 'MuxingApp', type: 'String' },
0x1741: { name: 'WritingApp', type: 'String' },
// 0xf43b675: { name: 'Cluster', type: 'Container' },
0x67: { name: 'Timecode', type: 'Uint' },
0x1854: { name: 'SilentTracks', type: 'Container' },
0x18d7: { name: 'SilentTrackNumber', type: 'Uint' },
0x27: { name: 'Position', type: 'Uint' },
0x2b: { name: 'PrevSize', type: 'Uint' },
0x23: { name: 'SimpleBlock', type: 'Binary' },
0x20: { name: 'BlockGroup', type: 'Container' },
0x21: { name: 'Block', type: 'Binary' },
0x22: { name: 'BlockVirtual', type: 'Binary' },
0x35a1: { name: 'BlockAdditions', type: 'Container' },
0x26: { name: 'BlockMore', type: 'Container' },
0x6e: { name: 'BlockAddID', type: 'Uint' },
0x25: { name: 'BlockAdditional', type: 'Binary' },
0x1b: { name: 'BlockDuration', type: 'Uint' },
0x7a: { name: 'ReferencePriority', type: 'Uint' },
0x7b: { name: 'ReferenceBlock', type: 'Int' },
0x7d: { name: 'ReferenceVirtual', type: 'Int' },
0x24: { name: 'CodecState', type: 'Binary' },
0x35a2: { name: 'DiscardPadding', type: 'Int' },
0xe: { name: 'Slices', type: 'Container' },
0x68: { name: 'TimeSlice', type: 'Container' },
0x4c: { name: 'LaceNumber', type: 'Uint' },
0x4d: { name: 'FrameNumber', type: 'Uint' },
0x4b: { name: 'BlockAdditionID', type: 'Uint' },
0x4e: { name: 'Delay', type: 'Uint' },
0x4f: { name: 'SliceDuration', type: 'Uint' },
0x48: { name: 'ReferenceFrame', type: 'Container' },
0x49: { name: 'ReferenceOffset', type: 'Uint' },
0x4a: { name: 'ReferenceTimeCode', type: 'Uint' },
0x2f: { name: 'EncryptedBlock', type: 'Binary' },
0x654ae6b: { name: 'Tracks', type: 'Container' },
0x2e: { name: 'TrackEntry', type: 'Container' },
0x57: { name: 'TrackNumber', type: 'Uint' },
0x33c5: { name: 'TrackUID', type: 'Uint' },
0x3: { name: 'TrackType', type: 'Uint' },
0x39: { name: 'FlagEnabled', type: 'Uint' },
0x8: { name: 'FlagDefault', type: 'Uint' },
0x15aa: { name: 'FlagForced', type: 'Uint' },
0x1c: { name: 'FlagLacing', type: 'Uint' },
0x2de7: { name: 'MinCache', type: 'Uint' },
0x2df8: { name: 'MaxCache', type: 'Uint' },
0x3e383: { name: 'DefaultDuration', type: 'Uint' },
0x34e7a: { name: 'DefaultDecodedFieldDuration', type: 'Uint' },
0x3314f: { name: 'TrackTimecodeScale', type: 'Float' },
0x137f: { name: 'TrackOffset', type: 'Int' },
0x15ee: { name: 'MaxBlockAdditionID', type: 'Uint' },
0x136e: { name: 'Name', type: 'String' },
0x2b59c: { name: 'Language', type: 'String' },
0x6: { name: 'CodecID', type: 'String' },
0x23a2: { name: 'CodecPrivate', type: 'Binary' },
0x58688: { name: 'CodecName', type: 'String' },
0x3446: { name: 'AttachmentLink', type: 'Uint' },
0x1a9697: { name: 'CodecSettings', type: 'String' },
0x1b4040: { name: 'CodecInfoURL', type: 'String' },
0x6b240: { name: 'CodecDownloadURL', type: 'String' },
0x2a: { name: 'CodecDecodeAll', type: 'Uint' },
0x2fab: { name: 'TrackOverlay', type: 'Uint' },
0x16aa: { name: 'CodecDelay', type: 'Uint' },
0x16bb: { name: 'SeekPreRoll', type: 'Uint' },
0x2624: { name: 'TrackTranslate', type: 'Container' },
0x26fc: { name: 'TrackTranslateEditionUID', type: 'Uint' },
0x26bf: { name: 'TrackTranslateCodec', type: 'Uint' },
0x26a5: { name: 'TrackTranslateTrackID', type: 'Binary' },
0x60: { name: 'Video', type: 'Container' },
0x1a: { name: 'FlagInterlaced', type: 'Uint' },
0x13b8: { name: 'StereoMode', type: 'Uint' },
0x13c0: { name: 'AlphaMode', type: 'Uint' },
0x13b9: { name: 'OldStereoMode', type: 'Uint' },
0x30: { name: 'PixelWidth', type: 'Uint' },
0x3a: { name: 'PixelHeight', type: 'Uint' },
0x14aa: { name: 'PixelCropBottom', type: 'Uint' },
0x14bb: { name: 'PixelCropTop', type: 'Uint' },
0x14cc: { name: 'PixelCropLeft', type: 'Uint' },
0x14dd: { name: 'PixelCropRight', type: 'Uint' },
0x14b0: { name: 'DisplayWidth', type: 'Uint' },
0x14ba: { name: 'DisplayHeight', type: 'Uint' },
0x14b2: { name: 'DisplayUnit', type: 'Uint' },
0x14b3: { name: 'AspectRatioType', type: 'Uint' },
0xeb524: { name: 'ColourSpace', type: 'Binary' },
0xfb523: { name: 'GammaValue', type: 'Float' },
0x383e3: { name: 'FrameRate', type: 'Float' },
0x61: { name: 'Audio', type: 'Container' },
0x35: { name: 'SamplingFrequency', type: 'Float' },
0x38b5: { name: 'OutputSamplingFrequency', type: 'Float' },
0x1f: { name: 'Channels', type: 'Uint' },
0x3d7b: { name: 'ChannelPositions', type: 'Binary' },
0x2264: { name: 'BitDepth', type: 'Uint' },
0x62: { name: 'TrackOperation', type: 'Container' },
0x63: { name: 'TrackCombinePlanes', type: 'Container' },
0x64: { name: 'TrackPlane', type: 'Container' },
0x65: { name: 'TrackPlaneUID', type: 'Uint' },
0x66: { name: 'TrackPlaneType', type: 'Uint' },
0x69: { name: 'TrackJoinBlocks', type: 'Container' },
0x6d: { name: 'TrackJoinUID', type: 'Uint' },
0x40: { name: 'TrickTrackUID', type: 'Uint' },
0x41: { name: 'TrickTrackSegmentUID', type: 'Binary' },
0x46: { name: 'TrickTrackFlag', type: 'Uint' },
0x47: { name: 'TrickMasterTrackUID', type: 'Uint' },
0x44: { name: 'TrickMasterTrackSegmentUID', type: 'Binary' },
0x2d80: { name: 'ContentEncodings', type: 'Container' },
0x2240: { name: 'ContentEncoding', type: 'Container' },
0x1031: { name: 'ContentEncodingOrder', type: 'Uint' },
0x1032: { name: 'ContentEncodingScope', type: 'Uint' },
0x1033: { name: 'ContentEncodingType', type: 'Uint' },
0x1034: { name: 'ContentCompression', type: 'Container' },
0x254: { name: 'ContentCompAlgo', type: 'Uint' },
0x255: { name: 'ContentCompSettings', type: 'Binary' },
0x1035: { name: 'ContentEncryption', type: 'Container' },
0x7e1: { name: 'ContentEncAlgo', type: 'Uint' },
0x7e2: { name: 'ContentEncKeyID', type: 'Binary' },
0x7e3: { name: 'ContentSignature', type: 'Binary' },
0x7e4: { name: 'ContentSigKeyID', type: 'Binary' },
0x7e5: { name: 'ContentSigAlgo', type: 'Uint' },
0x7e6: { name: 'ContentSigHashAlgo', type: 'Uint' },
0xc53bb6b: { name: 'Cues', type: 'Container' },
0x3b: { name: 'CuePoint', type: 'Container' },
0x33: { name: 'CueTime', type: 'Uint' },
0x37: { name: 'CueTrackPositions', type: 'Container' },
0x77: { name: 'CueTrack', type: 'Uint' },
0x71: { name: 'CueClusterPosition', type: 'Uint' },
0x70: { name: 'CueRelativePosition', type: 'Uint' },
0x32: { name: 'CueDuration', type: 'Uint' },
0x1378: { name: 'CueBlockNumber', type: 'Uint' },
0x6a: { name: 'CueCodecState', type: 'Uint' },
0x5b: { name: 'CueReference', type: 'Container' },
0x16: { name: 'CueRefTime', type: 'Uint' },
0x17: { name: 'CueRefCluster', type: 'Uint' },
0x135f: { name: 'CueRefNumber', type: 'Uint' },
0x6b: { name: 'CueRefCodecState', type: 'Uint' },
0x941a469: { name: 'Attachments', type: 'Container' },
0x21a7: { name: 'AttachedFile', type: 'Container' },
0x67e: { name: 'FileDescription', type: 'String' },
0x66e: { name: 'FileName', type: 'String' },
0x660: { name: 'FileMimeType', type: 'String' },
0x65c: { name: 'FileData', type: 'Binary' },
0x6ae: { name: 'FileUID', type: 'Uint' },
0x675: { name: 'FileReferral', type: 'Binary' },
0x661: { name: 'FileUsedStartTime', type: 'Uint' },
0x662: { name: 'FileUsedEndTime', type: 'Uint' },
0x43a770: { name: 'Chapters', type: 'Container' },
0x5b9: { name: 'EditionEntry', type: 'Container' },
0x5bc: { name: 'EditionUID', type: 'Uint' },
0x5bd: { name: 'EditionFlagHidden', type: 'Uint' },
0x5db: { name: 'EditionFlagDefault', type: 'Uint' },
0x5dd: { name: 'EditionFlagOrdered', type: 'Uint' },
0x36: { name: 'ChapterAtom', type: 'Container' },
0x33c4: { name: 'ChapterUID', type: 'Uint' },
0x1654: { name: 'ChapterStringUID', type: 'String' },
0x11: { name: 'ChapterTimeStart', type: 'Uint' },
0x12: { name: 'ChapterTimeEnd', type: 'Uint' },
0x18: { name: 'ChapterFlagHidden', type: 'Uint' },
0x598: { name: 'ChapterFlagEnabled', type: 'Uint' },
0x2e67: { name: 'ChapterSegmentUID', type: 'Binary' },
0x2ebc: { name: 'ChapterSegmentEditionUID', type: 'Uint' },
0x23c3: { name: 'ChapterPhysicalEquiv', type: 'Uint' },
0xf: { name: 'ChapterTrack', type: 'Container' },
0x9: { name: 'ChapterTrackNumber', type: 'Uint' },
0x0: { name: 'ChapterDisplay', type: 'Container' },
0x5: { name: 'ChapString', type: 'String' },
0x37c: { name: 'ChapLanguage', type: 'String' },
0x37e: { name: 'ChapCountry', type: 'String' },
0x2944: { name: 'ChapProcess', type: 'Container' },
0x2955: { name: 'ChapProcessCodecID', type: 'Uint' },
0x50d: { name: 'ChapProcessPrivate', type: 'Binary' },
0x2911: { name: 'ChapProcessCommand', type: 'Container' },
0x2922: { name: 'ChapProcessTime', type: 'Uint' },
0x2933: { name: 'ChapProcessData', type: 'Binary' },
0x254c367: { name: 'Tags', type: 'Container' },
0x3373: { name: 'Tag', type: 'Container' },
0x23c0: { name: 'Targets', type: 'Container' },
0x28ca: { name: 'TargetTypeValue', type: 'Uint' },
0x23ca: { name: 'TargetType', type: 'String' },
0x23c5: { name: 'TagTrackUID', type: 'Uint' },
0x23c9: { name: 'TagEditionUID', type: 'Uint' },
0x23c4: { name: 'TagChapterUID', type: 'Uint' },
0x23c6: { name: 'TagAttachmentUID', type: 'Uint' },
0x27c8: { name: 'SimpleTag', type: 'Container' },
0x5a3: { name: 'TagName', type: 'String' },
0x47a: { name: 'TagLanguage', type: 'String' },
0x484: { name: 'TagDefault', type: 'Uint' },
0x487: { name: 'TagString', type: 'String' },
0x485: { name: 'TagBinary', type: 'Binary' }
};
function doInherit(newClass, baseClass) {
newClass.prototype = Object.create(baseClass.prototype);
newClass.prototype.constructor = newClass;
}
function WebmBase(name, type) {
this.name = name || 'Unknown';
this.type = type || 'Unknown';
}
WebmBase.prototype.updateBySource = function() { };
WebmBase.prototype.setSource = function(source) {
this.source = source;
this.updateBySource();
};
WebmBase.prototype.updateByData = function() { };
WebmBase.prototype.setData = function(data) {
this.data = data;
this.updateByData();
};
function WebmUint(name, type) {
WebmBase.call(this, name, type || 'Uint');
}
doInherit(WebmUint, WebmBase);
function padHex(hex) {
return hex.length % 2 === 1 ? '0' + hex : hex;
}
WebmUint.prototype.updateBySource = function() {
// use hex representation of a number instead of number value
this.data = '';
for (var i = 0; i < this.source.length; i++) {
var hex = this.source[i].toString(16);
this.data += padHex(hex);
}
};
WebmUint.prototype.updateByData = function() {
var length = this.data.length / 2;
this.source = new Uint8Array(length);
for (var i = 0; i < length; i++) {
var hex = this.data.substr(i * 2, 2);
this.source[i] = parseInt(hex, 16);
}
};
WebmUint.prototype.getValue = function() {
return parseInt(this.data, 16);
};
WebmUint.prototype.setValue = function(value) {
this.setData(padHex(value.toString(16)));
};
function WebmFloat(name, type) {
WebmBase.call(this, name, type || 'Float');
}
doInherit(WebmFloat, WebmBase);
WebmFloat.prototype.getFloatArrayType = function() {
return this.source && this.source.length === 4 ? Float32Array : Float64Array;
};
WebmFloat.prototype.updateBySource = function() {
var byteArray = this.source.reverse();
var floatArrayType = this.getFloatArrayType();
var floatArray = new floatArrayType(byteArray.buffer);
this.data = floatArray[0];
};
WebmFloat.prototype.updateByData = function() {
var floatArrayType = this.getFloatArrayType();
var floatArray = new floatArrayType([ this.data ]);
var byteArray = new Uint8Array(floatArray.buffer);
this.source = byteArray.reverse();
};
WebmFloat.prototype.getValue = function() {
return this.data;
};
WebmFloat.prototype.setValue = function(value) {
this.setData(value);
};
function WebmContainer(name, type) {
WebmBase.call(this, name, type || 'Container');
}
doInherit(WebmContainer, WebmBase);
WebmContainer.prototype.readByte = function() {
return this.source[this.offset++];
};
WebmContainer.prototype.readUint = function() {
var firstByte = this.readByte();
var bytes = 8 - firstByte.toString(2).length;
var value = firstByte - (1 << (7 - bytes));
for (var i = 0; i < bytes; i++) {
// don't use bit operators to support x86
value *= 256;
value += this.readByte();
}
return value;
};
WebmContainer.prototype.updateBySource = function() {
this.data = [];
for (this.offset = 0; this.offset < this.source.length; this.offset = end) {
var id = this.readUint();
var len = this.readUint();
var end = Math.min(this.offset + len, this.source.length);
var data = this.source.slice(this.offset, end);
var info = sections[id] || { name: 'Unknown', type: 'Unknown' };
var ctr = WebmBase;
switch (info.type) {
case 'Container':
ctr = WebmContainer;
break;
case 'Uint':
ctr = WebmUint;
break;
case 'Float':
ctr = WebmFloat;
break;
}
var section = new ctr(info.name, info.type);
section.setSource(data);
this.data.push({
id: id,
idHex: id.toString(16),
data: section
});
}
};
WebmContainer.prototype.writeUint = function(x, draft) {
for (var bytes = 1, flag = 0x80; x >= flag && bytes < 8; bytes++, flag *= 0x80) { }
if (!draft) {
var value = flag + x;
for (var i = bytes - 1; i >= 0; i--) {
// don't use bit operators to support x86
var c = value % 256;
this.source[this.offset + i] = c;
value = (value - c) / 256;
}
}
this.offset += bytes;
};
WebmContainer.prototype.writeSections = function(draft) {
this.offset = 0;
for (var i = 0; i < this.data.length; i++) {
var section = this.data[i],
content = section.data.source,
contentLength = content.length;
this.writeUint(section.id, draft);
this.writeUint(contentLength, draft);
if (!draft) {
this.source.set(content, this.offset);
}
this.offset += contentLength;
}
return this.offset;
};
WebmContainer.prototype.updateByData = function() {
// run without accessing this.source to determine total length - need to know it to create Uint8Array
var length = this.writeSections('draft');
this.source = new Uint8Array(length);
// now really write data
this.writeSections();
};
WebmContainer.prototype.getSectionById = function(id) {
for (var i = 0; i < this.data.length; i++) {
var section = this.data[i];
if (section.id === id) {
return section.data;
}
}
return null;
};
function WebmFile(source) {
WebmContainer.call(this, 'File', 'File');
this.setSource(source);
}
doInherit(WebmFile, WebmContainer);
WebmFile.prototype.fixDuration = function(duration) {
var segmentSection = this.getSectionById(0x8538067);
if (!segmentSection) {
console.log('[fix-webm-duration] Segment section is missing');
return false;
}
var infoSection = segmentSection.getSectionById(0x549a966);
if (!infoSection) {
console.log('[fix-webm-duration] Info section is missing');
return false;
}
var timeScaleSection = infoSection.getSectionById(0xad7b1);
if (!timeScaleSection) {
console.log('[fix-webm-duration] TimecodeScale section is missing');
return false;
}
var durationSection = infoSection.getSectionById(0x489);
if (durationSection) {
if (durationSection.getValue() <= 0) {
console.log('[fix-webm-duration] Duration section is present, but the value is empty');
durationSection.setValue(duration);
} else {
console.log('[fix-webm-duration] Duration section is present');
return false;
}
} else {
console.log('[fix-webm-duration] Duration section is missing');
// append Duration section
durationSection = new WebmFloat('Duration', 'Float');
durationSection.setValue(duration);
infoSection.data.push({
id: 0x489,
data: durationSection
});
}
// set default time scale to 1 millisecond (1000000 nanoseconds)
timeScaleSection.setValue(1000000);
infoSection.updateByData();
segmentSection.updateByData();
this.updateByData();
return true;
};
WebmFile.prototype.toBlob = function() {
return new Blob([this.source.buffer], { type: 'video/webm;codecs=vp8,opus' });
};
return function(blob, duration, callback) {
try {
var reader = new FileReader();
reader.onloadend = function() {
try {
var file = new WebmFile(new Uint8Array(reader.result));
if (file.fixDuration(duration)) {
blob = file.toBlob();
}
} catch (ex) {
// ignore
}
callback(blob);
};
reader.readAsArrayBuffer(blob);
} catch (ex) {
callback(blob);
}
};
});

View File

@ -0,0 +1,48 @@
<!DOCTYPE html>
<html>
<head>
<title>视频查看</title>
<meta charset="UTF-8"/>
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate"/>
<meta http-equiv="Cache" content="no-cache">
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<link rel="stylesheet" href="./layui.css">
<script src="AgoraRTC_N-4.11.0.js"></script>
<script src="./jquery-3.4.1.min.js"></script>
<script src="./layui.js"></script>
<!--给录像文件添加时间进度条-->
<script src="fix-webm-duration.js"></script>
</head>
<body>
<!--视频显示-->
<div id="video">
<div id="agora_local"></div>
</div>
<!--当js文件发生变化的时候自动清除浏览器缓存,只要标签后面的v每次不一样浏览器就更新了阿-->
<script>
//创建一个script标签
function loadScriptString() {
var timeStamp=new Date().getTime();
var script = document.createElement("script"); //创建一个script标签
script.type = "module";
script.src=`js/fullScreenVideo.js?v=${timeStamp}`;
document.getElementsByTagName('head')[0].appendChild(script);
}
//创建一个link标签
function loadLinkString(){
var timeStamp=new Date().getTime();
var css = document.createElement("link"); //创建一个script标签
css.rel = "stylesheet";
css.href=`css/fullScreenVideo.css?v=${timeStamp}`
document.getElementsByTagName('head')[0].appendChild(css);
$("#video").css("height","720px");
}
loadScriptString();
loadLinkString();
</script>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

BIN
public/rtc/images/share.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 961 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -0,0 +1,806 @@
import {timestampFormat,getParams} from "./timestampFormat.js";
import { mqttUrl } from "../config/url.js";
window.onload=function(){
var slider,sliderInit,layer;
layui.use(['slider','layer'], function(){
slider= layui.slider;
layer = layui.layer;
});
var sizeLevel=0;//放大等级
var videotapeStartTime="";//录像开始时间
var videotapeEndTime="";//录像结束时间
var startTimeStamp="";
var endTimeStamp="";
var bApplySign = false;
var applyPage=false;
var keyCode = 32;
var videoTime=60000*10;
var cdTimeCountFlag="video";//video跟videotape
var cdTimeCount=videoTime;
var countDownTimer=null;
var channelValue=decodeURI(getParams("id"));
var mdDeviceName=decodeURI(getParams("mdDeviceName"));
var station=decodeURI(getParams("station"));
var title=decodeURI(getParams("mdDeviceName"));
var loginUserName=decodeURI(getParams("username"));
var power=decodeURI(getParams("power"));
var rtmName=channelValue;
var client=null;
var buffer=[];
var mediaRecorder =null;
var videoTimer=null;
var options = {
appid: "78846e9910a846688ab959e0f87034e5",
channel: channelValue,
uid: '',
token: null
};
var client=AgoraRTC.createClient({mode: 'live',codec: "vp8"});
var remoteUsers = {};
let localTracks = {
audioTrack: true
};
var videowatchingTimer=null;
$("html>head>title").html(title);
videoJoin();
setPower(power);
function setPower(power){
if(power=="null"){
power=0;
}
if(power>=90){
var img="images/power100.png";
}else if(power>=70){
var img="images/power80.png";
}else if(power>=50){
var img="images/power60.png";
}else if(power>=30){
var img="images/power40.png";
}else if(power>=10){
var img="images/power20.png";
}else{
var img="images/power0.png";
}
$(".power>span").html(power+"%");
$(".power>img").attr("src",img);
}
function closePage(){
leaveChannel();//我先离开频道
var obj=getRtmData("videoclose","");//在去关闭
sendMqttData(obj);
window.close();
}
async function leaveChannel() {
// leave the channel
await client.leave();
if(videowatchingTimer!=null){
clearInterval(videowatchingTimer);
videowatchingTimer=null;
}
}
//关闭并退出
$(".videoNav>.nav>img:nth-child(1)").on('click',function(){
resetParentPlayPage();
})
//重置父页面的播放页面
function resetParentPlayPage(){
var param = {
"sender":"children",
"receiver":"parent",
"deviceid":channelValue,
"cmd":"closePage"
};
window.parent.postMessage(param,'*');
closePage();
}
window.addEventListener('message', function(e) {
var data=e.data
var cmd=data["cmd"];
var deviceid=data["deviceid"]
if(cmd=="videoclose"){
if(channelValue==deviceid){
closePage();
}
}
})
//如果在全屏
function confClosePage(){
var url=window.location.href;
if(url.indexOf("fullScreenVideo")==-1){
closePage();
}
}
window.onresize = function () {
var w=parseFloat(window.innerWidth);
var h=parseFloat(window.innerHeight - 40);
switch(sizeLevel){
case 1:
setVideoSize1280(w,h);
break;
case 2:
setVideoSize720(w,h);
break;
case 3:
setVideoSize480(w,h);
break;
case 4:
setVideoSize640(w,h);
break;
default:
break;
}
}
//1280*720
function setVideoSize1280(w,h){
var f=parseFloat(h/w);
if(f >= 0.5625){
var width=w;
var height=width*0.5625;
var x= 0;
var y=parseFloat(h-height)/2;
}else{
var height=h;
var width=(height*16)/9;
var x=parseFloat(w-width)/2;
var y= 0;
}
setPageSize(x,y,width,height)
}
//720*1280
function setVideoSize720(w,h){
var f=parseFloat(w/h);
if(f>=0.5625){
var height=h;
var width=h*0.5625;
var x=parseFloat(w-width)/2;
var y=0;
}else{
var width=w;
var height=(w*16)/9;
var x=0;
var y=parseFloat(h-height)/2;;
}
setPageSize(x,y,width,height)
}
//480*640
function setVideoSize480(w,h){//宽度是480px;height:640px;
var f=parseFloat(w/h);
if(f>=0.75){
var height=h;
var width=h*0.75;
var x=parseFloat(w-width)/2;
var y=0;
}else{
var width=w;
var height=(w*4)/3;
var x=0;
var y=parseFloat(h-height)/2;;
}
setPageSize(0,0,120,160)
}
//640*480
function setVideoSize640(w,h){
var f=parseFloat(h/w);
if(f >= 0.75){
var width=w;
var height=width*0.75;
var x= 0;
var y=parseFloat(h-height)/2;
}else{
var height=h;
var width=(height*4)/3;
var x=parseFloat(w-width)/2;
var y= 0;
}
setPageSize(x,y,width,height)
}
function setPageSize(x,y,width,height){
$("#video").css("width",width+"px");
$("#video").css("height",height+"px");
$("#video").css("left",x);
$("#video").css("top",y);
}
$(".videoFullscreen").unbind('click');
$(".videoFullscreen").click(function(){
//投一个新的屏幕出去
var width=1280;
var height=720;
window.open("fullScreenVideo.html?id="+encodeURI(channelValue)+"&power="+encodeURI(power)+"&mdDeviceName="+encodeURI(encodeURI(mdDeviceName))+"&station="+encodeURI(encodeURI(station))+"&title="+encodeURI(encodeURI(title))+"&username="+loginUserName,"","width="+width+",height="+height+",top=0,left=0");
})
//打开声音
function openMute(select){
$(select).attr("src","images/openMute.png");
$(select).attr("title","音量");
$(select).attr("mute","open");
}
//关闭声音
function closeMute(select){
$(select).attr("src","images/closeMute.png");
$(select).attr("title","静音");
$(select).attr("mute","close");
}
//初始化声音
function videoSlideInit(){
sliderInit=slider.render({
elem: '#slideTest1',
change: function(value){
var select=$(".closeMute");
if(value==0){
closeMute(select);
}else{
openMute(select);
}
setRemoteUserMute(value*10);
}
});
}
function setRemoteUserMute(value){
for(var user in remoteUsers){
remoteUsers[user].audioTrack.setVolume(value);
}
}
let cameraid=0;
let rotateid=0;
//摄像图的操作
$(".carmeOper").on('click',function(){
rotateid=parseInt($(this).attr("rotate"));
$(".carmeOper").removeClass("bgColor");
$(this).addClass("bgColor")
sendCarmeOper();
})
//摄像头的方向调整
$(".carmeDir").on('click',function(){
let dir=$(this).attr("dir");
cameraid=dir;
if(dir=="0"){
$(this).attr("dir","1");
$(this).html("后");
}else{
$(this).attr("dir","0");
$(this).html("前");
}
sendCarmeOper();
})
function sendCarmeOper(){
var obj=getRtmData("videoclose","");
sendMqttData(obj);
setTimeout(()=>{
let data={
"rtmpflag":0,
"camera":cameraid,
"rotation":rotateid
}
var obj=getRtmData("videocall",JSON.stringify(data));
sendMqttData(obj);
videoInfoWind();
},4000)
}
//调节音量大小
$(".closeMute").click(function(){
var mute=$(this).attr("mute");
if(mute=="open"){
setRemoteUserMute(0)
sliderInit.setValue(0) //设置开始值
closeMute(this);
}else{
setRemoteUserMute(1000)
sliderInit.setValue(100) //设置开始值
openMute(this);
}
})
async function videoJoin() {
//订阅用户推送流
client.on("user-published", handleUserPublished);
//订阅用户取消推流
client.on("user-unpublished", handleUserUnpublished);
try {
// join a channel and create local tracks, we can use Promise.all to run them concurrently
[ options.uid] = await Promise.all([
// join the channel
client.join(options.appid, options.channel, options.token || null),
]);
} catch (e) {
console.log("加入频道失败", e);
}
// 使用 Web SDK 4.x,服务器频道禁用以后,客服端需要退出页面跟频道
client.on("connection-state-change", (curState, prevState) => {
closePage();
});
}
async function subscribe(user, mediaType) {
const uid = user.uid;
// subscribe to a remote user
await client.subscribe(user, mediaType);
if (mediaType === 'video') {
const player = $(`
<div id="player-${uid}" class="player"></div>
`);
$("#agora_local").append(player);
user.videoTrack.play(`player-${uid}`);
//设置视频数据
setVideoData();
//初始化视频的尺寸
videoInfoWind();
if(videowatchingTimer==null){
setInterval(function(){
var obj=getRtmData("videowatching","");
sendMqttData(obj)
//每隔1分钟发送发送1个不关闭视频的指令
},60000)
}
}
if(mediaType === 'audio'){
setRemoteUserMute(0);
//初始化音量
videoSlideInit();
user.audioTrack.play();
}
}
function handleUserPublished(user, mediaType) {
const id = user.uid;
remoteUsers[id] = user;
subscribe(user, mediaType);
}
function handleUserUnpublished(user) {
const id = user.uid;
delete remoteUsers[id];
$(`#player-wrapper-${id}`).remove();
resetParentPlayPage();
}
function setVideoData(){
setInterval(()=>{
var evt=client.getRemoteVideoStats();
if(JSON.stringify(evt)!="{}"){
for(var j in evt){
var packetLossRate=evt[j]["packetLossRate"]
var receiveBitrate=parseFloat(evt[j]["receiveBitrate"]/1024).toFixed(2);
var receiveFrameRate=evt[j]["receiveFrameRate"]
var totalDuration=evt[j]["totalDuration"]
var totalFreezeTime=evt[j]["totalFreezeTime"]
var transportDelay=evt[j]["transportDelay"]
$(".PacketLossRate").html(packetLossRate);
$(".RecvBitrate").html(receiveBitrate);
$(".RenderFrameRate").html(receiveFrameRate);
$(".TotalPlayDuration").html(totalDuration);
$(".TotalFreezeTime").html(totalFreezeTime);
$(".TransportDelay").html(transportDelay);
}
}
},1000)
}
function videoInfoWind(){
videoTimer=setInterval(() => {
var evt=client.getRemoteVideoStats();
if(JSON.stringify(evt)!="{}"){
for(var i in evt){
if("receiveResolutionHeight" in evt[i]){
var RecvResolutionHeight=evt[i]["receiveResolutionHeight"];
}
if("receiveResolutionWidth" in evt[i]){
var RecvResolutionWidth=evt[i]["receiveResolutionWidth"];
}
if((RecvResolutionWidth!="0"&&RecvResolutionHeight!="0")&&(RecvResolutionWidth!=undefined&&RecvResolutionHeight!=undefined)){
clearInterval(videoTimer);
var width=RecvResolutionWidth;
var height=parseFloat(RecvResolutionHeight);
if(RecvResolutionWidth=="1280"&&RecvResolutionHeight=="720"){
sizeLevel=1;
}else if(RecvResolutionWidth=="720"&&RecvResolutionHeight=="1280"){
if(window.screen.height+200<=height){
width=width*0.8;
height=height*0.8;
}
sizeLevel=2;
window.resizeTo(width,height);
}else if(RecvResolutionWidth=="480"&&RecvResolutionHeight=="640"){
sizeLevel=3;
window.resizeTo("480","640");
}else if(RecvResolutionWidth=="640"&&RecvResolutionHeight=="480"){
sizeLevel=4;
window.resizeTo(RecvResolutionWidth,RecvResolutionHeight);
}
var param={
"deviceid":channelValue,
"cmd":"videoloadedSuccess",
"data":{
w:width,
h:height
}
}
console.log(param);
parent.postMessage(param,'*');
//启动倒计时
downTime30();
}
}
}
},1000)
}
//设置stream
function setRecStream(){
let mediaStream = new MediaStream();
console.log(mediaStream);
for(var user in remoteUsers){
mediaStream.addTrack(remoteUsers[user].videoTrack.getMediaStreamTrack())
mediaStream.addTrack(remoteUsers[user].audioTrack.getMediaStreamTrack())
}
window.stream=mediaStream;
}
//开启远程录像
$(".startRecording").unbind();
$(".startRecording").click(function(){
var recordState=$(this).attr("state");
if(recordState=="open"){
setRecStream();
startRecord();
startTimeStamp=new Date().getTime();
videotapeStartTime=timestampFormat();
$(this).attr("state","close");
$(this).attr("src","images/endRecording.png");
$(this).attr("title","结束录像");
layer.msg("录像开启成功");
$(".inTheVideo").css("display","block");
cdTimeCountFlag="videotape";
downTime30();
}else{
endTimeStamp=new Date().getTime();
videotapeEndTime=timestampFormat();
stopRecord();
cdTimeCount=videoTime;
clearInterval(countDownTimer);
countDownTimer=null;
cdTimeCountFlag="video";
}
})
//视频信息
$(".videoReInfo").on('click',function(){
var state=$(this).attr("state");
if(state=="close"){
$(this).attr("state","open");
$(".videoInfo").css("display","block");
}else{
$(this).attr("state","close");
$(".videoInfo").css("display","none");
}
})
//分享
$(".videoShare").on('click',function(){
var state=$(this).attr("state");
if(state=="close"){
$(this).attr("state","open");
$("#qrcode").css("display","block");
}else{
$(this).attr("state","close");
$("#qrcode").css("display","none");
}
})
async function setClientHost(){
//设置成主播
await client.setClientRole("host");
try {
// join a channel and create local tracks, we can use Promise.all to run them concurrently
[localTracks.audioTrack] = await Promise.all([
// create local tracks, using microphone and camera
AgoraRTC.createMicrophoneAudioTrack()
]);
await client.publish(Object.values(localTracks));
} catch (e) {
console.log("加入频道失败", e);
}
}
async function setClientAudience(){
//先调用取消发布,在设置成观众
await client.unpublish(Object.values(localTracks));
await client.setClientRole("audience");
}
//开启对讲
$(".videoWalk").unbind();
$(".videoWalk").click(function(){
var state=$(this).attr("state");
if(state=="close"){
//开启
$(this).attr("state","open");
$(this).attr("src","images/videoWalkOnline.png");
applyPage=true;
bApplySign=true;
setClientHost();
}else{
applyPage=false;
bApplySign=false;
//关闭
$(this).attr("state","close");
$(this).attr("src","images/videoWalk.png");
setClientAudience();
}
})
//键盘松开
document.onkeyup = function (event) {
var e = event || window.event || arguments.callee.caller.arguments[0];
if(applyPage){
if(e && e.keyCode == keyCode&&!bApplySign) {
bApplySign = true;
//关闭麦克风
localTracks.audioTrack.setEnabled(false);
//开启远程的声音
setRemoteUserMute(100);
var select=$(".closeMute");
openMute(select);
sliderInit.setValue(100) //设置开始值
}
}
}
//键盘按下
document.onkeydown = function (event) {
var e = event || window.event || arguments.callee.caller.arguments[0];
if(applyPage){
if(e && e.keyCode == keyCode&&bApplySign) {
bApplySign = false;
//启用麦克风
localTracks.audioTrack.setEnabled(true);
//关闭远程的声音
setRemoteUserMute(0);
//页面状态改变
sliderInit.setValue(0) //设置开始值
var select=$(".closeMute");
closeMute(select);
}
}
}
//截图,并且把图片保存在云端
$(".videoImg").click(function(){
var video=document.querySelector(".agora_video_player");
var canvas=document.getElementById('canvas');
if(video!=null){
$(".canvasImg").css("display","block");
canvas.width=video.videoWidth;
canvas.height=video.videoHeight;
canvas.getContext('2d').drawImage(video,0,0,canvas.width,canvas.height);
var image = canvas . toDataURL ("image/png") ;
$(".canvasImgBox").css("width",canvas.width*0.3+"px");
$(".canvasImgBox").css("height",canvas.height*0.3+"px");
document.getElementById("save").href=image;
document.getElementById("save").download=mdDeviceName+".jpg";
document.getElementById('save').onclick=function(){
$(".canvasImg").css("display","none");
}
document.getElementById('cancel').onclick=function(){
$(".canvasImg").css("display","none");
}
}else{
layer.msg("用户已离开,无法截图");
}
})
function closeVideoStream(){
var obj=getRtmData("videoclose","");//在去关闭
sendMqttData(obj);
}
//倒计时30分钟以后关闭录像告诉用户,录像已经完成
/*************************观看视频为5分钟1次如果不点击确定就会关闭***********************************/
function downTime30(){
if(countDownTimer!=null){
clearInterval(countDownTimer);
}else{
countDownTimer=setInterval(function(){
cdTimeCount-=1000;
if(cdTimeCount<=0){
clearInterval(countDownTimer);
countDownTimer=null;
if(cdTimeCountFlag=="videotape"){
endTimeStamp=new Date().getTime();
videotapeEndTime=timestampFormat();
stopRecord();
}else{
//倒计时
showCountDownTimer();
}
}
},1000);
}
}
//倒计时*******************************************
var closeTime=10;//倒计时
var closePageTimer=null;
function showCountDownTimer(){
$(".videoTitle").css("display","block");
$(".close_ing_time").html(closeTime);
videoTitleEvent();
closePageTimer=setInterval(function(){
closeTime--;
$(".close_ing_time").html(closeTime);
if(closeTime<=0){
closeVideoStream();//发送关闭指令
leaveChannel();//离开频道
clearInterval(closePageTimer);//退出定时器
}
},1000);
}
function videoTitleEvent(){
$(".videoTitle>p:last-child>button:nth-child(1)").on('click',function(){
var obj=getRtmData("videocall","");//在去关闭
sendMqttData(obj);
$(".videoTitle").css("display","none");
clearInterval(closePageTimer);
closePageTimer=null;
closeTime=10;
cdTimeCount=videoTime;
//再次加入频道
videoJoin()
downTime30()
})
$(".videoTitle>p:last-child>button:nth-child(2)").on('click',function(){
closePage();
})
}
function handleDataAvailable(e){ // 5、获取数据的事件函数 当我们点击录制之后,数据就会源源不断的从这个事件函数中获取到
if(e && e.data && e.data.size > 0){
console.log(e.data);
buffer.push(e.data); // 将e.data放入二进制数组里面
// 这个buffer应该是我们在开始录制的时候创建这个buffer
}
}
//开始录像
function startRecord(){
buffer = []; // 定义数组
if (typeof MediaRecorder.isTypeSupported == 'function') {
if (MediaRecorder.isTypeSupported('video/webm;codecs=vp8')) {
var options = {
mimeType: 'video/webm;codecs=vp9,opus'
}
} else if (MediaRecorder.isTypeSupported('video/webm;codecs=vp9')) {
var options = {
mimeType:'video/webm;codecs=vp9,opus'
};
} else if (MediaRecorder.isTypeSupported('video/webm;codecs=h264')) {
var options = {
mimeType:'video/webm;codecs=h264,opus'
};
}
}
if(!MediaRecorder.isTypeSupported(options.mimeType)){ // 判断录制的视频 mimeType 格式浏览器是否支持
return;
}
try{ // 防止录制异常
// 5、先在上面定义全局对象mediaRecorder以便于后面停止录制的时候可以用到
mediaRecorder = new MediaRecorder(window.stream, options); // 调用录制API // window.stream在gotMediaStream中获取
//4、调用事件 这个事件处理函数里面就会收到我们录制的那块数据 当我们收集到这个数据之后我们应该把它存储起来
mediaRecorder.ondataavailable = handleDataAvailable;
mediaRecorder.start(10); // start方法里面传入一个时间片每隔一个 时间片存储 一块数据
}catch(e){
console.error(e);
return;
}
}
//停止录制
function stopRecord(){
//6、调用停止录制
try{
mediaRecorder.stop();
}catch(e){
console.error(e);
}
$(".startRecording").attr("state","open");
$(".startRecording").attr("src","images/startRecording.png");
$(this).attr("title","开始录像");
layer.msg('录像已保存', {
time: false, //20s后自动关闭
btn: ['知道了']
});
$(".inTheVideo").css("display","none");
var tmpBlob = new Blob(buffer, {type: 'video/webm'});
var duration=endTimeStamp-startTimeStamp;
//调用设置时长代码。该函数基于fix-webm-duration.js
ysFixWebmDuration(tmpBlob, duration, function (fixedBlob) {
var recorderFile = fixedBlob;
let name =`${mdDeviceName}(${videotapeStartTime}---${videotapeEndTime}).mp4`;
var url = window.URL.createObjectURL(recorderFile);
var a = document.createElement('a');
a.href = url;
a.style.display = 'none';
a.download = name;
a.click();
});
}
//构建rtm发送对象
function getRtmData(title,data){
return {
"title":title,
"sender":loginUserName,
"department":"",
"scope":"",
"receiver":[rtmName],
"video":"",
"rtm":(new Date().getTime()).toString(),
"data":data,
"userScope":"",
"userBragide":"",
"userDetachchment":"",
"userBorough":"",
"name":"",
}
}
//发送mqqt接口数据
function sendMqttData(obj){
var mqttObj={
"topic":`${station}/ter_cmd`,
"message":JSON.stringify(obj)
}
$.ajax({
url: mqttUrl,
type: "post",
dataType: "json",
headers: {
"Content-Type": "application/json;charset=utf-8"
},
data: JSON.stringify(mqttObj),
success: function(d) {
//console.error(d);
}
})
}
}

View File

@ -0,0 +1,798 @@
import {timestampFormat,getParams,fullScreen,exitFullscreen} from "./timestampFormat.js";
import { mqttUrl } from "../config/url.js";
window.onload=function(){
var locationUrl=window.location.href;
var slider,sliderInit,layer;
layui.use(['slider','layer'], function(){
slider= layui.slider;
layer = layui.layer;
});
var sizeLevel=0;//放大等级
var videotapeStartTime="";//录像开始时间
var videotapeEndTime="";//录像结束时间
var startTimeStamp="";
var endTimeStamp="";
var bApplySign = false;
var applyPage=false;
var keyCode = 32;
var videoTime=60000*12000;
var cdTimeCountFlag="video";//video跟videotape
var cdTimeCount=videoTime;
var countDownTimer=null;
var channelValue=decodeURI(getParams("id"));
var mdDeviceName=decodeURI(getParams("mdDeviceName"));
var station=decodeURI(getParams("station"));
var title=decodeURI(getParams("mdDeviceName"));
var loginUserName=decodeURI(getParams("username"));
var power=decodeURI(getParams("power"));
var rtmName=channelValue;
var client=null;
var buffer=[];
var mediaRecorder =null;
var videoTimer=null;
var options = {
appid: "78846e9910a846688ab959e0f87034e5",
channel: channelValue,
uid: '',
token: null
};
var client=AgoraRTC.createClient({mode: 'live',codec: "vp8"});
var remoteUsers = {};
let localTracks = {
audioTrack: true
};
$("html>head>title").html(title);
videoJoin();
setPower(power);
function setPower(power){
if(power=="null"){
power=0;
}
if(power>=90){
var img="images/power100.png";
}else if(power>=70){
var img="images/power80.png";
}else if(power>=50){
var img="images/power60.png";
}else if(power>=30){
var img="images/power40.png";
}else if(power>=10){
var img="images/power20.png";
}else{
var img="images/power0.png";
}
$(".power>span").html(power+"%");
$(".power>img").attr("src",img);
}
function closePage(){
leaveChannel();//我先离开频道
var obj=getRtmData("videoclose","");//在去关闭
sendMqttData(obj);
window.close();
}
async function leaveChannel() {
// leave the channel
await client.leave();
}
//关闭并退出
$(".videoNav>.nav>img:nth-child(1)").click(function(){
var param = {
"sender":"children",
"receiver":"parent",
"deviceid":channelValue,
"cmd":"closePage"
};
window.parent.postMessage(param,'*');
closePage();
})
window.addEventListener('message', function(e) {
var data=e.data
var cmd=data["cmd"];
var deviceid=data["deviceid"]
if(cmd=="videoclose"){
if(channelValue==deviceid){
closePage();
}
}
})
//如果在全屏
function confClosePage(){
var url=window.location.href;
if(url.indexOf("fullScreenVideo")==-1){
closePage();
}
}
window.onbeforeunload=function(e){
if(locationUrl.indexOf("videoMoitorShow")==-1){
confClosePage();
}
}
window.onresize = function () {
var w=parseFloat(window.innerWidth);
var h=parseFloat(window.innerHeight - 40);
switch(sizeLevel){
case 1:
setVideoSize1280(w,h);
break;
case 2:
setVideoSize720(w,h);
break;
case 3:
setVideoSize480(w,h);
break;
case 4:
setVideoSize640(w,h);
break;
default:
break;
}
}
//1280*720
function setVideoSize1280(w,h){
var f=parseFloat(h/w);
if(f >= 0.5625){
var width=w;
var height=width*0.5625;
var x= 0;
var y=parseFloat(h-height)/2;
}else{
var height=h;
var width=(height*16)/9;
var x=parseFloat(w-width)/2;
var y= 0;
}
setPageSize(x,y,width,height)
}
//720*1280
function setVideoSize720(w,h){
var f=parseFloat(w/h);
if(f>0.5625){
var height=h;
var width=h*0.5625;
var x=parseFloat(w-width)/2;
var y=0;
}else{
var width=w;
var height=(w*16)/9;
var x=0;
var y=parseFloat(h-height)/2;;
}
setPageSize(x,y,width,height)
}
//480*640
function setVideoSize480(w,h){//宽度是480px;height:640px;
var f=parseFloat(w/h);
if(f>0.75){
var height=h;
var width=h*0.75;
var x=parseFloat(w-width)/2;
var y=0;
}else{
var width=w;
var height=(w*4)/3;
var x=0;
var y=parseFloat(h-height)/2;;
}
setPageSize(x,y,width,height)
}
//640*480
function setVideoSize640(w,h){
var f=parseFloat(h/w);
if(f >= 0.75){
var width=w;
var height=width*0.75;
var x= 0;
var y=parseFloat(h-height)/2;
}else{
var height=h;
var width=(height*4)/3;
var x=parseFloat(w-width)/2;
var y= 0;
}
setPageSize(x,y,width,height)
}
function setPageSize(x,y,width,height){
$("#video").css("width",width+"px");
$("#video").css("height",height+"px");
$("#video").css("left",x);
$("#video").css("top",y);
}
$(".videoFullscreen").unbind('click');
$(".videoFullscreen").click(function(){
console.log(123456);
var url=window.location.href;
if(url.indexOf("alarmDeviceVideo")!=-1){
//投一个新的屏幕出去
var width=1280;
var height=760;
window.open("fullScreenVideo.html?id="+encodeURI(channelValue)+"&power="+encodeURI(power)+"&mdDeviceName="+encodeURI(encodeURI(mdDeviceName))+"&station="+encodeURI(encodeURI(station))+"&title="+encodeURI(encodeURI(title))+"&username="+loginUserName,"","width="+width+",height="+height+",top=0,left=0");
}else{
var model=$(this).attr("model");
if(model=="exitfullScreen"){
fullScreen()
$(this).attr("src","images/videoExitFullscreen.png").attr("model","fullScreen").attr("title","退出全屏")
}else{
exitFullscreen()
$(this).attr("src","images/videoFullscreen.png").attr("model","exitfullScreen").attr("title","全屏");
}
}
})
//打开声音
function openMute(select){
$(select).attr("src","images/openMute.png");
$(select).attr("title","音量");
$(select).attr("mute","open");
}
//关闭声音
function closeMute(select){
$(select).attr("src","images/closeMute.png");
$(select).attr("title","静音");
$(select).attr("mute","close");
}
//初始化声音
function videoSlideInit(){
sliderInit=slider.render({
elem: '#slideTest1',
change: function(value){
var select=$(".closeMute");
if(value==0){
closeMute(select);
}else{
openMute(select);
}
setRemoteUserMute(value*10);
}
});
}
function setRemoteUserMute(value){
for(var user in remoteUsers){
remoteUsers[user].audioTrack.setVolume(value);
}
}
let cameraid=0;
let rotateid=0;
//摄像图的操作
$(".carmeOper").on('click',function(){
rotateid=parseInt($(this).attr("rotate"));
$(".carmeOper").removeClass("bgColor");
$(this).addClass("bgColor")
sendCarmeOper();
})
//摄像头的方向调整
$(".carmeDir").on('click',function(){
let dir=$(this).attr("dir");
cameraid=dir;
if(dir=="0"){
$(this).attr("dir","1");
$(this).html("后");
}else{
$(this).attr("dir","0");
$(this).html("前");
}
sendCarmeOper();
})
function sendCarmeOper(){
var obj=getRtmData("videoclose","");
sendMqttData(obj);
setTimeout(()=>{
let data={
"rtmpflag":0,
"camera":cameraid,
"rotation":rotateid
}
var obj=getRtmData("videocall",JSON.stringify(data));
sendMqttData(obj);
videoInfoWind();
},4000)
}
//调节音量大小
$(".closeMute").click(function(){
var mute=$(this).attr("mute");
if(mute=="open"){
setRemoteUserMute(0)
sliderInit.setValue(0) //设置开始值
closeMute(this);
}else{
setRemoteUserMute(1000)
sliderInit.setValue(100) //设置开始值
openMute(this);
}
})
async function videoJoin() {
//订阅用户推送流
client.on("user-published", handleUserPublished);
//订阅用户取消推流
client.on("user-unpublished", handleUserUnpublished);
try {
// join a channel and create local tracks, we can use Promise.all to run them concurrently
[ options.uid] = await Promise.all([
// join the channel
client.join(options.appid, options.channel, options.token || null),
]);
} catch (e) {
console.log("加入频道失败", e);
}
// 使用 Web SDK 4.x,服务器频道禁用以后,客服端需要退出页面跟频道
client.on("connection-state-change", (curState, prevState) => {
closePage();
});
}
async function subscribe(user, mediaType) {
const uid = user.uid;
// subscribe to a remote user
await client.subscribe(user, mediaType);
if (mediaType === 'video') {
const player = $(`
<div id="player-${uid}" class="player"></div>
`);
$("#agora_local").append(player);
user.videoTrack.play(`player-${uid}`);
//设置视频数据
setVideoData();
//初始化视频的尺寸
videoInfoWind();
setInterval(function(){
var obj=getRtmData("videowatching","");
sendMqttData(obj)
//每隔1分钟发送发送1个不关闭视频的指令
},60000)
}
if(mediaType === 'audio'){
setRemoteUserMute(0);
//初始化音量
videoSlideInit();
user.audioTrack.play();
}
}
function handleUserPublished(user, mediaType) {
const id = user.uid;
remoteUsers[id] = user;
subscribe(user, mediaType);
}
function handleUserUnpublished(user) {
const id = user.uid;
delete remoteUsers[id];
$(`#player-wrapper-${id}`).remove();
}
function setVideoData(){
setInterval(()=>{
var evt=client.getRemoteVideoStats();
if(JSON.stringify(evt)!="{}"){
for(var j in evt){
var packetLossRate=evt[j]["packetLossRate"]
var receiveBitrate=parseFloat(evt[j]["receiveBitrate"]/1024).toFixed(2);
var receiveFrameRate=evt[j]["receiveFrameRate"]
var totalDuration=evt[j]["totalDuration"]
var totalFreezeTime=evt[j]["totalFreezeTime"]
var transportDelay=evt[j]["transportDelay"]
$(".PacketLossRate").html(packetLossRate);
$(".RecvBitrate").html(receiveBitrate);
$(".RenderFrameRate").html(receiveFrameRate);
$(".TotalPlayDuration").html(totalDuration);
$(".TotalFreezeTime").html(totalFreezeTime);
$(".TransportDelay").html(transportDelay);
}
}
},1000)
}
function videoInfoWind(){
videoTimer=setInterval(() => {
var evt=client.getRemoteVideoStats();
if(JSON.stringify(evt)!="{}"){
for(var i in evt){
if("receiveResolutionHeight" in evt[i]){
var RecvResolutionHeight=evt[i]["receiveResolutionHeight"];
}
if("receiveResolutionWidth" in evt[i]){
var RecvResolutionWidth=evt[i]["receiveResolutionWidth"];
}
if((RecvResolutionWidth!="0"&&RecvResolutionHeight!="0")&&(RecvResolutionWidth!=undefined&&RecvResolutionHeight!=undefined)){
clearInterval(videoTimer);
var width=RecvResolutionWidth;
var height=parseFloat(RecvResolutionHeight);
if(RecvResolutionWidth=="1280"&&RecvResolutionHeight=="720"){
sizeLevel=1;
setVideoSize1280(width*0.5,height*0.5);
window.resizeTo(width,height);
}else if(RecvResolutionWidth=="720"&&RecvResolutionHeight=="1280"){
if(window.screen.height+200<=height){
width=width*0.8;
height=height*0.8;
}
sizeLevel=2;
setVideoSize720(width*0.5,height*0.5);
window.resizeTo(width,height);
}else if(RecvResolutionWidth=="480"&&RecvResolutionHeight=="640"){
sizeLevel=3;
setVideoSize480(width*0.5,height*0.5);
window.resizeTo("496","750");
}else if(RecvResolutionWidth=="640"&&RecvResolutionHeight=="480"){
sizeLevel=4;
setVideoSize640(width*0.5,height*0.5);
window.resizeTo(RecvResolutionWidth,RecvResolutionHeight);
}
var param={
"deviceid":channelValue,
"cmd":"videoloadedSuccess"
}
parent.postMessage(param,'*');
//启动倒计时
downTime30();
}
}
}
},1000)
}
//设置stream
function setRecStream(){
let mediaStream = new MediaStream();
for(var user in remoteUsers){
mediaStream.addTrack(remoteUsers[user].videoTrack.getMediaStreamTrack())
mediaStream.addTrack(remoteUsers[user].audioTrack.getMediaStreamTrack())
}
window.stream=mediaStream;
}
//开启远程录像
$(".startRecording").unbind();
$(".startRecording").click(function(){
var recordState=$(this).attr("state");
if(recordState=="open"){
setRecStream();
startRecord();
startTimeStamp=new Date().getTime();
videotapeStartTime=timestampFormat();
$(this).attr("state","close");
$(this).attr("src","images/endRecording.png");
$(this).attr("title","结束录像");
layer.msg("录像开启成功");
$(".inTheVideo").css("display","block");
cdTimeCountFlag="videotape";
downTime30();
}else{
endTimeStamp=new Date().getTime();
videotapeEndTime=timestampFormat();
stopRecord();
cdTimeCount=videoTime;
clearInterval(countDownTimer);
countDownTimer=null;
cdTimeCountFlag="video";
}
})
//视频信息
$(".videoReInfo").on('click',function(){
var state=$(this).attr("state");
if(state=="close"){
$(this).attr("state","open");
$(".videoInfo").css("display","block");
}else{
$(this).attr("state","close");
$(".videoInfo").css("display","none");
}
})
async function setClientHost(){
//设置成主播
await client.setClientRole("host");
try {
// join a channel and create local tracks, we can use Promise.all to run them concurrently
[localTracks.audioTrack] = await Promise.all([
// create local tracks, using microphone and camera
AgoraRTC.createMicrophoneAudioTrack()
]);
await client.publish(Object.values(localTracks));
} catch (e) {
console.log("加入频道失败", e);
}
}
async function setClientAudience(){
//先调用取消发布,在设置成观众
await client.unpublish(Object.values(localTracks));
await client.setClientRole("audience");
}
//开启对讲
$(".videoWalk").unbind();
$(".videoWalk").click(function(){
var state=$(this).attr("state");
if(state=="close"){
//开启
$(this).attr("state","open");
$(this).attr("src","images/videoWalkOnline.png");
applyPage=true;
bApplySign=true;
setClientHost();
}else{
applyPage=false;
bApplySign=false;
//关闭
$(this).attr("state","close");
$(this).attr("src","images/videoWalk.png");
setClientAudience();
}
})
//键盘松开
document.onkeyup = function (event) {
var e = event || window.event || arguments.callee.caller.arguments[0];
if(applyPage){
if(e && e.keyCode == keyCode&&!bApplySign) {
bApplySign = true;
//关闭麦克风
localTracks.audioTrack.setEnabled(false);
//开启远程的声音
setRemoteUserMute(100);
var select=$(".closeMute");
openMute(select);
sliderInit.setValue(100) //设置开始值
}
}
}
//键盘按下
document.onkeydown = function (event) {
var e = event || window.event || arguments.callee.caller.arguments[0];
if(applyPage){
if(e && e.keyCode == keyCode&&bApplySign) {
bApplySign = false;
//启用麦克风
localTracks.audioTrack.setEnabled(true);
//关闭远程的声音
setRemoteUserMute(0);
//页面状态改变
sliderInit.setValue(0) //设置开始值
var select=$(".closeMute");
closeMute(select);
}
}
}
//截图,并且把图片保存在云端
$(".videoImg").click(function(){
var video=document.querySelector(".agora_video_player");
var canvas=document.getElementById('canvas');
if(video!=null){
$(".canvasImg").css("display","block");
canvas.width=video.videoWidth;
canvas.height=video.videoHeight;
canvas.getContext('2d').drawImage(video,0,0,canvas.width,canvas.height);
var image = canvas . toDataURL ("image/png") ;
$(".canvasImgBox").css("width",canvas.width*0.3+"px");
$(".canvasImgBox").css("height",canvas.height*0.3+"px");
document.getElementById("save").href=image;
document.getElementById("save").download=mdDeviceName+".jpg";
document.getElementById('save').onclick=function(){
$(".canvasImg").css("display","none");
}
document.getElementById('cancel').onclick=function(){
$(".canvasImg").css("display","none");
}
}else{
layer.msg("用户已离开,无法截图");
}
})
function closeVideoStream(){
var obj=getRtmData("videoclose","");//在去关闭
sendMqttData(obj);
}
//倒计时30分钟以后关闭录像告诉用户,录像已经完成
/*************************观看视频为5分钟1次如果不点击确定就会关闭***********************************/
function downTime30(){
if(countDownTimer!=null){
clearInterval(countDownTimer);
}else{
countDownTimer=setInterval(function(){
cdTimeCount-=1000;
if(cdTimeCount<=0){
clearInterval(countDownTimer);
countDownTimer=null;
if(cdTimeCountFlag=="videotape"){
endTimeStamp=new Date().getTime();
videotapeEndTime=timestampFormat();
stopRecord();
}else{
//倒计时
showCountDownTimer();
}
}
},1000);
}
}
//倒计时*******************************************
var closeTime=10;//倒计时
var closePageTimer=null;
function showCountDownTimer(){
$(".videoTitle").css("display","block");
$(".close_ing_time").html(closeTime);
videoTitleEvent();
closePageTimer=setInterval(function(){
closeTime--;
$(".close_ing_time").html(closeTime);
if(closeTime<=0){
closeVideoStream();//发送关闭指令
leaveChannel();//离开频道
clearInterval(closePageTimer);//退出定时器
}
},1000);
}
function videoTitleEvent(){
$(".videoTitle>p:last-child>button:nth-child(1)").on('click',function(){
var obj=getRtmData("videocall","");//在去关闭
sendMqttData(obj);
$(".videoTitle").css("display","none");
clearInterval(closePageTimer);
closePageTimer=null;
closeTime=10;
cdTimeCount=videoTime;
//再次加入频道
videoJoin()
downTime30()
})
$(".videoTitle>p:last-child>button:nth-child(2)").on('click',function(){
closePage();
})
}
function handleDataAvailable(e){ // 5、获取数据的事件函数 当我们点击录制之后,数据就会源源不断的从这个事件函数中获取到
if(e && e.data && e.data.size > 0){
console.log(e.data);
buffer.push(e.data); // 将e.data放入二进制数组里面
// 这个buffer应该是我们在开始录制的时候创建这个buffer
}
}
//开始录像
function startRecord(){
buffer = []; // 定义数组
if (typeof MediaRecorder.isTypeSupported == 'function') {
if (MediaRecorder.isTypeSupported('video/webm;codecs=vp8')) {
var options = {
mimeType: 'video/webm;codecs=vp9,opus'
}
} else if (MediaRecorder.isTypeSupported('video/webm;codecs=vp9')) {
var options = {
mimeType:'video/webm;codecs=vp9,opus'
};
} else if (MediaRecorder.isTypeSupported('video/webm;codecs=h264')) {
var options = {
mimeType:'video/webm;codecs=h264,opus'
};
}
}
if(!MediaRecorder.isTypeSupported(options.mimeType)){ // 判断录制的视频 mimeType 格式浏览器是否支持
return;
}
try{ // 防止录制异常
// 5、先在上面定义全局对象mediaRecorder以便于后面停止录制的时候可以用到
mediaRecorder = new MediaRecorder(window.stream, options); // 调用录制API // window.stream在gotMediaStream中获取
//4、调用事件 这个事件处理函数里面就会收到我们录制的那块数据 当我们收集到这个数据之后我们应该把它存储起来
mediaRecorder.ondataavailable = handleDataAvailable;
mediaRecorder.start(0); // start方法里面传入一个时间片每隔一个 时间片存储 一块数据
}catch(e){
console.error(e);
return;
}
}
//停止录制
function stopRecord(){
//6、调用停止录制
try{
mediaRecorder.stop();
}catch(e){
console.error(e);
}
$(".startRecording").attr("state","open");
$(".startRecording").attr("src","images/startRecording.png");
$(this).attr("title","开始录像");
layer.msg('录像已保存', {
time: false, //20s后自动关闭
btn: ['知道了']
});
$(".inTheVideo").css("display","none");
var tmpBlob = new Blob(buffer, {type: 'video/webm'});
var duration=endTimeStamp-startTimeStamp;
//调用设置时长代码。该函数基于fix-webm-duration.js
ysFixWebmDuration(tmpBlob, duration, function (fixedBlob) {
var recorderFile = fixedBlob;
let name =`${mdDeviceName}(${videotapeStartTime}---${videotapeEndTime}).mp4`;
var url = window.URL.createObjectURL(recorderFile);
var a = document.createElement('a');
a.href = url;
a.style.display = 'none';
a.download = name;
a.click();
});
}
//构建rtm发送对象
function getRtmData(title,data){
return {
"title":title,
"sender":loginUserName,
"department":"",
"scope":"",
"receiver":[rtmName],
"video":"",
"rtm":(new Date().getTime()).toString(),
"data":data,
"userScope":"",
"userBragide":"",
"userDetachchment":"",
"userBorough":"",
"name":"",
}
}
//发送mqqt接口数据
function sendMqttData(obj){
var mqttObj={
"topic":`${station}/ter_cmd`,
"message":JSON.stringify(obj)
}
$.ajax({
url: mqttUrl,
type: "post",
dataType: "json",
headers: {
"Content-Type": "application/json;charset=utf-8"
},
data: JSON.stringify(mqttObj),
success: function(d) {
//console.error(d);
}
})
}
}

View File

@ -0,0 +1,798 @@
import {timestampFormat,getParams,fullScreen,exitFullscreen} from "./timestampFormat.js";
import { mqttUrl } from "../config/url.js";
window.onload=function(){
var locationUrl=window.location.href;
var slider,sliderInit,layer;
layui.use(['slider','layer'], function(){
slider= layui.slider;
layer = layui.layer;
});
var sizeLevel=0;//放大等级
var videotapeStartTime="";//录像开始时间
var videotapeEndTime="";//录像结束时间
var startTimeStamp="";
var endTimeStamp="";
var bApplySign = false;
var applyPage=false;
var keyCode = 32;
var videoTime=60000*12000;
var cdTimeCountFlag="video";//video跟videotape
var cdTimeCount=videoTime;
var countDownTimer=null;
var channelValue=decodeURI(getParams("id"));
var mdDeviceName=decodeURI(getParams("mdDeviceName"));
var station=decodeURI(getParams("station"));
var title=decodeURI(getParams("mdDeviceName"));
var loginUserName=decodeURI(getParams("username"));
var power=decodeURI(getParams("power"));
var rtmName=channelValue;
var client=null;
var buffer=[];
var mediaRecorder =null;
var videoTimer=null;
var options = {
appid: "78846e9910a846688ab959e0f87034e5",
channel: channelValue,
uid: '',
token: null
};
var client=AgoraRTC.createClient({mode: 'live',codec: "vp8"});
var remoteUsers = {};
let localTracks = {
audioTrack: true
};
$("html>head>title").html(title);
videoJoin();
setPower(power);
function setPower(power){
if(power=="null"){
power=0;
}
if(power>=90){
var img="images/power100.png";
}else if(power>=70){
var img="images/power80.png";
}else if(power>=50){
var img="images/power60.png";
}else if(power>=30){
var img="images/power40.png";
}else if(power>=10){
var img="images/power20.png";
}else{
var img="images/power0.png";
}
$(".power>span").html(power+"%");
$(".power>img").attr("src",img);
}
function closePage(){
leaveChannel();//我先离开频道
var obj=getRtmData("videoclose","");//在去关闭
sendMqttData(obj);
window.close();
}
async function leaveChannel() {
// leave the channel
await client.leave();
}
//关闭并退出
$(".videoNav>.nav>img:nth-child(1)").click(function(){
var param = {
"sender":"children",
"receiver":"parent",
"deviceid":channelValue,
"cmd":"closePage"
};
window.parent.postMessage(param,'*');
closePage();
})
window.addEventListener('message', function(e) {
var data=e.data
var cmd=data["cmd"];
var deviceid=data["deviceid"]
if(cmd=="videoclose"){
if(channelValue==deviceid){
closePage();
}
}
})
//如果在全屏
function confClosePage(){
var url=window.location.href;
if(url.indexOf("fullScreenVideo")==-1){
closePage();
}
}
window.onbeforeunload=function(e){
if(locationUrl.indexOf("videoMoitorShow")==-1){
confClosePage();
}
}
window.onresize = function () {
var w=parseFloat(window.innerWidth);
var h=parseFloat(window.innerHeight - 40);
switch(sizeLevel){
case 1:
setVideoSize1280(w,h);
break;
case 2:
setVideoSize720(w,h);
break;
case 3:
setVideoSize480(w,h);
break;
case 4:
setVideoSize640(w,h);
break;
default:
break;
}
}
//1280*720
function setVideoSize1280(w,h){
var f=parseFloat(h/w);
if(f >= 0.5625){
var width=w;
var height=width*0.5625;
var x= 0;
var y=parseFloat(h-height)/2;
}else{
var height=h;
var width=(height*16)/9;
var x=parseFloat(w-width)/2;
var y= 0;
}
setPageSize(x,y,width,height)
}
//720*1280
function setVideoSize720(w,h){
var f=parseFloat(w/h);
if(f>0.5625){
var height=h;
var width=h*0.5625;
var x=parseFloat(w-width)/2;
var y=0;
}else{
var width=w;
var height=(w*16)/9;
var x=0;
var y=parseFloat(h-height)/2;;
}
setPageSize(x,y,width,height)
}
//480*640
function setVideoSize480(w,h){//宽度是480px;height:640px;
var f=parseFloat(w/h);
if(f>0.75){
var height=h;
var width=h*0.75;
var x=parseFloat(w-width)/2;
var y=0;
}else{
var width=w;
var height=(w*4)/3;
var x=0;
var y=parseFloat(h-height)/2;;
}
setPageSize(x,y,width,height)
}
//640*480
function setVideoSize640(w,h){
var f=parseFloat(h/w);
if(f >= 0.75){
var width=w;
var height=width*0.75;
var x= 0;
var y=parseFloat(h-height)/2;
}else{
var height=h;
var width=(height*4)/3;
var x=parseFloat(w-width)/2;
var y= 0;
}
setPageSize(x,y,width,height)
}
function setPageSize(x,y,width,height){
$("#video").css("width",width+"px");
$("#video").css("height",height+"px");
$("#video").css("left",x);
$("#video").css("top",y);
}
$(".videoFullscreen").unbind('click');
$(".videoFullscreen").click(function(){
console.log(123456);
var url=window.location.href;
if(url.indexOf("alarmDeviceVideo")!=-1){
//投一个新的屏幕出去
var width=1280;
var height=760;
window.open("fullScreenVideo.html?id="+encodeURI(channelValue)+"&power="+encodeURI(power)+"&mdDeviceName="+encodeURI(encodeURI(mdDeviceName))+"&station="+encodeURI(encodeURI(station))+"&title="+encodeURI(encodeURI(title))+"&username="+loginUserName,"","width="+width+",height="+height+",top=0,left=0");
}else{
var model=$(this).attr("model");
if(model=="exitfullScreen"){
fullScreen()
$(this).attr("src","images/videoExitFullscreen.png").attr("model","fullScreen").attr("title","退出全屏")
}else{
exitFullscreen()
$(this).attr("src","images/videoFullscreen.png").attr("model","exitfullScreen").attr("title","全屏");
}
}
})
//打开声音
function openMute(select){
$(select).attr("src","images/openMute.png");
$(select).attr("title","音量");
$(select).attr("mute","open");
}
//关闭声音
function closeMute(select){
$(select).attr("src","images/closeMute.png");
$(select).attr("title","静音");
$(select).attr("mute","close");
}
//初始化声音
function videoSlideInit(){
sliderInit=slider.render({
elem: '#slideTest1',
change: function(value){
var select=$(".closeMute");
if(value==0){
closeMute(select);
}else{
openMute(select);
}
setRemoteUserMute(value*10);
}
});
}
function setRemoteUserMute(value){
for(var user in remoteUsers){
remoteUsers[user].audioTrack.setVolume(value);
}
}
let cameraid=0;
let rotateid=0;
//摄像图的操作
$(".carmeOper").on('click',function(){
rotateid=parseInt($(this).attr("rotate"));
$(".carmeOper").removeClass("bgColor");
$(this).addClass("bgColor")
sendCarmeOper();
})
//摄像头的方向调整
$(".carmeDir").on('click',function(){
let dir=$(this).attr("dir");
cameraid=dir;
if(dir=="0"){
$(this).attr("dir","1");
$(this).html("后");
}else{
$(this).attr("dir","0");
$(this).html("前");
}
sendCarmeOper();
})
function sendCarmeOper(){
var obj=getRtmData("videoclose","");
sendMqttData(obj);
setTimeout(()=>{
let data={
"rtmpflag":0,
"camera":cameraid,
"rotation":rotateid
}
var obj=getRtmData("videocall",JSON.stringify(data));
sendMqttData(obj);
videoInfoWind();
},4000)
}
//调节音量大小
$(".closeMute").click(function(){
var mute=$(this).attr("mute");
if(mute=="open"){
setRemoteUserMute(0)
sliderInit.setValue(0) //设置开始值
closeMute(this);
}else{
setRemoteUserMute(1000)
sliderInit.setValue(100) //设置开始值
openMute(this);
}
})
async function videoJoin() {
//订阅用户推送流
client.on("user-published", handleUserPublished);
//订阅用户取消推流
client.on("user-unpublished", handleUserUnpublished);
try {
// join a channel and create local tracks, we can use Promise.all to run them concurrently
[ options.uid] = await Promise.all([
// join the channel
client.join(options.appid, options.channel, options.token || null),
]);
} catch (e) {
console.log("加入频道失败", e);
}
// 使用 Web SDK 4.x,服务器频道禁用以后,客服端需要退出页面跟频道
client.on("connection-state-change", (curState, prevState) => {
closePage();
});
}
async function subscribe(user, mediaType) {
const uid = user.uid;
// subscribe to a remote user
await client.subscribe(user, mediaType);
if (mediaType === 'video') {
const player = $(`
<div id="player-${uid}" class="player"></div>
`);
$("#agora_local").append(player);
user.videoTrack.play(`player-${uid}`);
//设置视频数据
setVideoData();
//初始化视频的尺寸
videoInfoWind();
setInterval(function(){
var obj=getRtmData("videowatching","");
sendMqttData(obj)
//每隔1分钟发送发送1个不关闭视频的指令
},60000)
}
if(mediaType === 'audio'){
setRemoteUserMute(0);
//初始化音量
videoSlideInit();
user.audioTrack.play();
}
}
function handleUserPublished(user, mediaType) {
const id = user.uid;
remoteUsers[id] = user;
subscribe(user, mediaType);
}
function handleUserUnpublished(user) {
const id = user.uid;
delete remoteUsers[id];
$(`#player-wrapper-${id}`).remove();
}
function setVideoData(){
setInterval(()=>{
var evt=client.getRemoteVideoStats();
if(JSON.stringify(evt)!="{}"){
for(var j in evt){
var packetLossRate=evt[j]["packetLossRate"]
var receiveBitrate=parseFloat(evt[j]["receiveBitrate"]/1024).toFixed(2);
var receiveFrameRate=evt[j]["receiveFrameRate"]
var totalDuration=evt[j]["totalDuration"]
var totalFreezeTime=evt[j]["totalFreezeTime"]
var transportDelay=evt[j]["transportDelay"]
$(".PacketLossRate").html(packetLossRate);
$(".RecvBitrate").html(receiveBitrate);
$(".RenderFrameRate").html(receiveFrameRate);
$(".TotalPlayDuration").html(totalDuration);
$(".TotalFreezeTime").html(totalFreezeTime);
$(".TransportDelay").html(transportDelay);
}
}
},1000)
}
function videoInfoWind(){
videoTimer=setInterval(() => {
var evt=client.getRemoteVideoStats();
if(JSON.stringify(evt)!="{}"){
for(var i in evt){
if("receiveResolutionHeight" in evt[i]){
var RecvResolutionHeight=evt[i]["receiveResolutionHeight"];
}
if("receiveResolutionWidth" in evt[i]){
var RecvResolutionWidth=evt[i]["receiveResolutionWidth"];
}
if((RecvResolutionWidth!="0"&&RecvResolutionHeight!="0")&&(RecvResolutionWidth!=undefined&&RecvResolutionHeight!=undefined)){
clearInterval(videoTimer);
var width=RecvResolutionWidth;
var height=parseFloat(RecvResolutionHeight);
if(RecvResolutionWidth=="1280"&&RecvResolutionHeight=="720"){
sizeLevel=1;
setVideoSize1280(width*0.5,height*0.5);
window.resizeTo(width,height);
}else if(RecvResolutionWidth=="720"&&RecvResolutionHeight=="1280"){
if(window.screen.height+200<=height){
width=width*0.8;
height=height*0.8;
}
sizeLevel=2;
setVideoSize720(width*0.5,height*0.5);
window.resizeTo(width,height);
}else if(RecvResolutionWidth=="480"&&RecvResolutionHeight=="640"){
sizeLevel=3;
setVideoSize480(width*0.5,height*0.5);
window.resizeTo("496","750");
}else if(RecvResolutionWidth=="640"&&RecvResolutionHeight=="480"){
sizeLevel=4;
setVideoSize640(width*0.5,height*0.5);
window.resizeTo(RecvResolutionWidth,RecvResolutionHeight);
}
var param={
"deviceid":channelValue,
"cmd":"videoloadedSuccess"
}
parent.postMessage(param,'*');
//启动倒计时
downTime30();
}
}
}
},1000)
}
//设置stream
function setRecStream(){
let mediaStream = new MediaStream();
for(var user in remoteUsers){
mediaStream.addTrack(remoteUsers[user].videoTrack.getMediaStreamTrack())
mediaStream.addTrack(remoteUsers[user].audioTrack.getMediaStreamTrack())
}
window.stream=mediaStream;
}
//开启远程录像
$(".startRecording").unbind();
$(".startRecording").click(function(){
var recordState=$(this).attr("state");
if(recordState=="open"){
setRecStream();
startRecord();
startTimeStamp=new Date().getTime();
videotapeStartTime=timestampFormat();
$(this).attr("state","close");
$(this).attr("src","images/endRecording.png");
$(this).attr("title","结束录像");
layer.msg("录像开启成功");
$(".inTheVideo").css("display","block");
cdTimeCountFlag="videotape";
downTime30();
}else{
endTimeStamp=new Date().getTime();
videotapeEndTime=timestampFormat();
stopRecord();
cdTimeCount=videoTime;
clearInterval(countDownTimer);
countDownTimer=null;
cdTimeCountFlag="video";
}
})
//视频信息
$(".videoReInfo").on('click',function(){
var state=$(this).attr("state");
if(state=="close"){
$(this).attr("state","open");
$(".videoInfo").css("display","block");
}else{
$(this).attr("state","close");
$(".videoInfo").css("display","none");
}
})
async function setClientHost(){
//设置成主播
await client.setClientRole("host");
try {
// join a channel and create local tracks, we can use Promise.all to run them concurrently
[localTracks.audioTrack] = await Promise.all([
// create local tracks, using microphone and camera
AgoraRTC.createMicrophoneAudioTrack()
]);
await client.publish(Object.values(localTracks));
} catch (e) {
console.log("加入频道失败", e);
}
}
async function setClientAudience(){
//先调用取消发布,在设置成观众
await client.unpublish(Object.values(localTracks));
await client.setClientRole("audience");
}
//开启对讲
$(".videoWalk").unbind();
$(".videoWalk").click(function(){
var state=$(this).attr("state");
if(state=="close"){
//开启
$(this).attr("state","open");
$(this).attr("src","images/videoWalkOnline.png");
applyPage=true;
bApplySign=true;
setClientHost();
}else{
applyPage=false;
bApplySign=false;
//关闭
$(this).attr("state","close");
$(this).attr("src","images/videoWalk.png");
setClientAudience();
}
})
//键盘松开
document.onkeyup = function (event) {
var e = event || window.event || arguments.callee.caller.arguments[0];
if(applyPage){
if(e && e.keyCode == keyCode&&!bApplySign) {
bApplySign = true;
//关闭麦克风
localTracks.audioTrack.setEnabled(false);
//开启远程的声音
setRemoteUserMute(100);
var select=$(".closeMute");
openMute(select);
sliderInit.setValue(100) //设置开始值
}
}
}
//键盘按下
document.onkeydown = function (event) {
var e = event || window.event || arguments.callee.caller.arguments[0];
if(applyPage){
if(e && e.keyCode == keyCode&&bApplySign) {
bApplySign = false;
//启用麦克风
localTracks.audioTrack.setEnabled(true);
//关闭远程的声音
setRemoteUserMute(0);
//页面状态改变
sliderInit.setValue(0) //设置开始值
var select=$(".closeMute");
closeMute(select);
}
}
}
//截图,并且把图片保存在云端
$(".videoImg").click(function(){
var video=document.querySelector(".agora_video_player");
var canvas=document.getElementById('canvas');
if(video!=null){
$(".canvasImg").css("display","block");
canvas.width=video.videoWidth;
canvas.height=video.videoHeight;
canvas.getContext('2d').drawImage(video,0,0,canvas.width,canvas.height);
var image = canvas . toDataURL ("image/png") ;
$(".canvasImgBox").css("width",canvas.width*0.3+"px");
$(".canvasImgBox").css("height",canvas.height*0.3+"px");
document.getElementById("save").href=image;
document.getElementById("save").download=mdDeviceName+".jpg";
document.getElementById('save').onclick=function(){
$(".canvasImg").css("display","none");
}
document.getElementById('cancel').onclick=function(){
$(".canvasImg").css("display","none");
}
}else{
layer.msg("用户已离开,无法截图");
}
})
function closeVideoStream(){
var obj=getRtmData("videoclose","");//在去关闭
sendMqttData(obj);
}
//倒计时30分钟以后关闭录像告诉用户,录像已经完成
/*************************观看视频为5分钟1次如果不点击确定就会关闭***********************************/
function downTime30(){
if(countDownTimer!=null){
clearInterval(countDownTimer);
}else{
countDownTimer=setInterval(function(){
cdTimeCount-=1000;
if(cdTimeCount<=0){
clearInterval(countDownTimer);
countDownTimer=null;
if(cdTimeCountFlag=="videotape"){
endTimeStamp=new Date().getTime();
videotapeEndTime=timestampFormat();
stopRecord();
}else{
//倒计时
showCountDownTimer();
}
}
},1000);
}
}
//倒计时*******************************************
var closeTime=10;//倒计时
var closePageTimer=null;
function showCountDownTimer(){
$(".videoTitle").css("display","block");
$(".close_ing_time").html(closeTime);
videoTitleEvent();
closePageTimer=setInterval(function(){
closeTime--;
$(".close_ing_time").html(closeTime);
if(closeTime<=0){
closeVideoStream();//发送关闭指令
leaveChannel();//离开频道
clearInterval(closePageTimer);//退出定时器
}
},1000);
}
function videoTitleEvent(){
$(".videoTitle>p:last-child>button:nth-child(1)").on('click',function(){
var obj=getRtmData("videocall","");//在去关闭
sendMqttData(obj);
$(".videoTitle").css("display","none");
clearInterval(closePageTimer);
closePageTimer=null;
closeTime=10;
cdTimeCount=videoTime;
//再次加入频道
videoJoin()
downTime30()
})
$(".videoTitle>p:last-child>button:nth-child(2)").on('click',function(){
closePage();
})
}
function handleDataAvailable(e){ // 5、获取数据的事件函数 当我们点击录制之后,数据就会源源不断的从这个事件函数中获取到
if(e && e.data && e.data.size > 0){
console.log(e.data);
buffer.push(e.data); // 将e.data放入二进制数组里面
// 这个buffer应该是我们在开始录制的时候创建这个buffer
}
}
//开始录像
function startRecord(){
buffer = []; // 定义数组
if (typeof MediaRecorder.isTypeSupported == 'function') {
if (MediaRecorder.isTypeSupported('video/webm;codecs=vp8')) {
var options = {
mimeType: 'video/webm;codecs=vp9,opus'
}
} else if (MediaRecorder.isTypeSupported('video/webm;codecs=vp9')) {
var options = {
mimeType:'video/webm;codecs=vp9,opus'
};
} else if (MediaRecorder.isTypeSupported('video/webm;codecs=h264')) {
var options = {
mimeType:'video/webm;codecs=h264,opus'
};
}
}
if(!MediaRecorder.isTypeSupported(options.mimeType)){ // 判断录制的视频 mimeType 格式浏览器是否支持
return;
}
try{ // 防止录制异常
// 5、先在上面定义全局对象mediaRecorder以便于后面停止录制的时候可以用到
mediaRecorder = new MediaRecorder(window.stream, options); // 调用录制API // window.stream在gotMediaStream中获取
//4、调用事件 这个事件处理函数里面就会收到我们录制的那块数据 当我们收集到这个数据之后我们应该把它存储起来
mediaRecorder.ondataavailable = handleDataAvailable;
mediaRecorder.start(0); // start方法里面传入一个时间片每隔一个 时间片存储 一块数据
}catch(e){
console.error(e);
return;
}
}
//停止录制
function stopRecord(){
//6、调用停止录制
try{
mediaRecorder.stop();
}catch(e){
console.error(e);
}
$(".startRecording").attr("state","open");
$(".startRecording").attr("src","images/startRecording.png");
$(this).attr("title","开始录像");
layer.msg('录像已保存', {
time: false, //20s后自动关闭
btn: ['知道了']
});
$(".inTheVideo").css("display","none");
var tmpBlob = new Blob(buffer, {type: 'video/webm'});
var duration=endTimeStamp-startTimeStamp;
//调用设置时长代码。该函数基于fix-webm-duration.js
ysFixWebmDuration(tmpBlob, duration, function (fixedBlob) {
var recorderFile = fixedBlob;
let name =`${mdDeviceName}(${videotapeStartTime}---${videotapeEndTime}).mp4`;
var url = window.URL.createObjectURL(recorderFile);
var a = document.createElement('a');
a.href = url;
a.style.display = 'none';
a.download = name;
a.click();
});
}
//构建rtm发送对象
function getRtmData(title,data){
return {
"title":title,
"sender":loginUserName,
"department":"",
"scope":"",
"receiver":[rtmName],
"video":"",
"rtm":(new Date().getTime()).toString(),
"data":data,
"userScope":"",
"userBragide":"",
"userDetachchment":"",
"userBorough":"",
"name":"",
}
}
//发送mqqt接口数据
function sendMqttData(obj){
var mqttObj={
"topic":`${station}/ter_cmd`,
"message":JSON.stringify(obj)
}
$.ajax({
url: mqttUrl,
type: "post",
dataType: "json",
headers: {
"Content-Type": "application/json;charset=utf-8"
},
data: JSON.stringify(mqttObj),
success: function(d) {
//console.error(d);
}
})
}
}

View File

@ -0,0 +1,68 @@
export function timestampFormat(){
var currentTime = new Date();
var year = currentTime.getFullYear();
var getMonth = (currentTime.getMonth()) + 1;
var getDate = currentTime.getDate();
var getHours = currentTime.getHours();
var getMinutes = currentTime.getMinutes();
var getSeconds = currentTime.getSeconds();
if(getMonth < 10) {
getMonth = "0" + getMonth;
}
if(getDate < 10) {
getDate = "0" + getDate;
}
if(getHours < 10) {
getHours = "0" + getHours;
}
if(getMinutes < 10) {
getMinutes = "0" + getMinutes;
}
if(getSeconds < 10) {
getSeconds = "0" + getSeconds;
}
return year + "年" + getMonth + "月" + getDate + "日" + getHours + "时" + getMinutes + "分" + getSeconds+"秒";
}
//接受url的值,进行解析
export function getParams(key) {
var reg = new RegExp("(^|&)" + key + "=([^&]*)(&|$)");
var r = window.location.search.substr(1).match(reg);
if (r != null) {
return unescape(r[2]);
}
return null;
};
//全屏
export function fullScreen() {
var element = document.documentElement;
if (element.requestFullscreen) {
element.requestFullscreen();
} else if (element.msRequestFullscreen) {
element.msRequestFullscreen();
} else if (element.mozRequestFullScreen) {
element.mozRequestFullScreen();
} else if (element.webkitRequestFullscreen) {
element.webkitRequestFullscreen();
}
}
//退出全屏
export function exitFullscreen() {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.msExitFullscreen) {
document.msExitFullscreen();
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
}
}

1
public/rtc/layui.css Normal file

File diff suppressed because one or more lines are too long

1
public/rtc/layui.js Normal file

File diff suppressed because one or more lines are too long

184
public/rtc/md5.js Normal file
View File

@ -0,0 +1,184 @@
function md5(string) {
function md5_RotateLeft(lValue, iShiftBits) {
return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits));
}
function md5_AddUnsigned(lX, lY) {
var lX4, lY4, lX8, lY8, lResult;
lX8 = (lX & 0x80000000);
lY8 = (lY & 0x80000000);
lX4 = (lX & 0x40000000);
lY4 = (lY & 0x40000000);
lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF);
if (lX4 & lY4) {
return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
}
if (lX4 | lY4) {
if (lResult & 0x40000000) {
return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
} else {
return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
}
} else {
return (lResult ^ lX8 ^ lY8);
}
}
function md5_F(x, y, z) {
return (x & y) | ((~x) & z);
}
function md5_G(x, y, z) {
return (x & z) | (y & (~z));
}
function md5_H(x, y, z) {
return (x ^ y ^ z);
}
function md5_I(x, y, z) {
return (y ^ (x | (~z)));
}
function md5_FF(a, b, c, d, x, s, ac) {
a = md5_AddUnsigned(a, md5_AddUnsigned(md5_AddUnsigned(md5_F(b, c, d), x), ac));
return md5_AddUnsigned(md5_RotateLeft(a, s), b);
};
function md5_GG(a, b, c, d, x, s, ac) {
a = md5_AddUnsigned(a, md5_AddUnsigned(md5_AddUnsigned(md5_G(b, c, d), x), ac));
return md5_AddUnsigned(md5_RotateLeft(a, s), b);
};
function md5_HH(a, b, c, d, x, s, ac) {
a = md5_AddUnsigned(a, md5_AddUnsigned(md5_AddUnsigned(md5_H(b, c, d), x), ac));
return md5_AddUnsigned(md5_RotateLeft(a, s), b);
};
function md5_II(a, b, c, d, x, s, ac) {
a = md5_AddUnsigned(a, md5_AddUnsigned(md5_AddUnsigned(md5_I(b, c, d), x), ac));
return md5_AddUnsigned(md5_RotateLeft(a, s), b);
};
function md5_ConvertToWordArray(string) {
var lWordCount;
var lMessageLength = string.length;
var lNumberOfWords_temp1 = lMessageLength + 8;
var lNumberOfWords_temp2 = (lNumberOfWords_temp1 - (lNumberOfWords_temp1 % 64)) / 64;
var lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16;
var lWordArray = Array(lNumberOfWords - 1);
var lBytePosition = 0;
var lByteCount = 0;
while (lByteCount < lMessageLength) {
lWordCount = (lByteCount - (lByteCount % 4)) / 4;
lBytePosition = (lByteCount % 4) * 8;
lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount) << lBytePosition));
lByteCount++;
}
lWordCount = (lByteCount - (lByteCount % 4)) / 4;
lBytePosition = (lByteCount % 4) * 8;
lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition);
lWordArray[lNumberOfWords - 2] = lMessageLength << 3;
lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;
return lWordArray;
};
function md5_WordToHex(lValue) {
var WordToHexValue = "", WordToHexValue_temp = "", lByte, lCount;
for (lCount = 0; lCount <= 3; lCount++) {
lByte = (lValue >>> (lCount * 8)) & 255;
WordToHexValue_temp = "0" + lByte.toString(16);
WordToHexValue = WordToHexValue + WordToHexValue_temp.substr(WordToHexValue_temp.length - 2, 2);
}
return WordToHexValue;
};
function md5_Utf8Encode(string) {
string = string.replace(/\r\n/g, "\n");
var utftext = "";
for (var n = 0; n < string.length; n++) {
var c = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
} else if ((c > 127) && (c < 2048)) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
} else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
}
return utftext;
};
var x = Array();
var k, AA, BB, CC, DD, a, b, c, d;
var S11 = 7, S12 = 12, S13 = 17, S14 = 22;
var S21 = 5, S22 = 9, S23 = 14, S24 = 20;
var S31 = 4, S32 = 11, S33 = 16, S34 = 23;
var S41 = 6, S42 = 10, S43 = 15, S44 = 21;
string = md5_Utf8Encode(string);
x = md5_ConvertToWordArray(string);
a = 0x67452301; b = 0xEFCDAB89; c = 0x98BADCFE; d = 0x10325476;
for (k = 0; k < x.length; k += 16) {
AA = a; BB = b; CC = c; DD = d;
a = md5_FF(a, b, c, d, x[k + 0], S11, 0xD76AA478);
d = md5_FF(d, a, b, c, x[k + 1], S12, 0xE8C7B756);
c = md5_FF(c, d, a, b, x[k + 2], S13, 0x242070DB);
b = md5_FF(b, c, d, a, x[k + 3], S14, 0xC1BDCEEE);
a = md5_FF(a, b, c, d, x[k + 4], S11, 0xF57C0FAF);
d = md5_FF(d, a, b, c, x[k + 5], S12, 0x4787C62A);
c = md5_FF(c, d, a, b, x[k + 6], S13, 0xA8304613);
b = md5_FF(b, c, d, a, x[k + 7], S14, 0xFD469501);
a = md5_FF(a, b, c, d, x[k + 8], S11, 0x698098D8);
d = md5_FF(d, a, b, c, x[k + 9], S12, 0x8B44F7AF);
c = md5_FF(c, d, a, b, x[k + 10], S13, 0xFFFF5BB1);
b = md5_FF(b, c, d, a, x[k + 11], S14, 0x895CD7BE);
a = md5_FF(a, b, c, d, x[k + 12], S11, 0x6B901122);
d = md5_FF(d, a, b, c, x[k + 13], S12, 0xFD987193);
c = md5_FF(c, d, a, b, x[k + 14], S13, 0xA679438E);
b = md5_FF(b, c, d, a, x[k + 15], S14, 0x49B40821);
a = md5_GG(a, b, c, d, x[k + 1], S21, 0xF61E2562);
d = md5_GG(d, a, b, c, x[k + 6], S22, 0xC040B340);
c = md5_GG(c, d, a, b, x[k + 11], S23, 0x265E5A51);
b = md5_GG(b, c, d, a, x[k + 0], S24, 0xE9B6C7AA);
a = md5_GG(a, b, c, d, x[k + 5], S21, 0xD62F105D);
d = md5_GG(d, a, b, c, x[k + 10], S22, 0x2441453);
c = md5_GG(c, d, a, b, x[k + 15], S23, 0xD8A1E681);
b = md5_GG(b, c, d, a, x[k + 4], S24, 0xE7D3FBC8);
a = md5_GG(a, b, c, d, x[k + 9], S21, 0x21E1CDE6);
d = md5_GG(d, a, b, c, x[k + 14], S22, 0xC33707D6);
c = md5_GG(c, d, a, b, x[k + 3], S23, 0xF4D50D87);
b = md5_GG(b, c, d, a, x[k + 8], S24, 0x455A14ED);
a = md5_GG(a, b, c, d, x[k + 13], S21, 0xA9E3E905);
d = md5_GG(d, a, b, c, x[k + 2], S22, 0xFCEFA3F8);
c = md5_GG(c, d, a, b, x[k + 7], S23, 0x676F02D9);
b = md5_GG(b, c, d, a, x[k + 12], S24, 0x8D2A4C8A);
a = md5_HH(a, b, c, d, x[k + 5], S31, 0xFFFA3942);
d = md5_HH(d, a, b, c, x[k + 8], S32, 0x8771F681);
c = md5_HH(c, d, a, b, x[k + 11], S33, 0x6D9D6122);
b = md5_HH(b, c, d, a, x[k + 14], S34, 0xFDE5380C);
a = md5_HH(a, b, c, d, x[k + 1], S31, 0xA4BEEA44);
d = md5_HH(d, a, b, c, x[k + 4], S32, 0x4BDECFA9);
c = md5_HH(c, d, a, b, x[k + 7], S33, 0xF6BB4B60);
b = md5_HH(b, c, d, a, x[k + 10], S34, 0xBEBFBC70);
a = md5_HH(a, b, c, d, x[k + 13], S31, 0x289B7EC6);
d = md5_HH(d, a, b, c, x[k + 0], S32, 0xEAA127FA);
c = md5_HH(c, d, a, b, x[k + 3], S33, 0xD4EF3085);
b = md5_HH(b, c, d, a, x[k + 6], S34, 0x4881D05);
a = md5_HH(a, b, c, d, x[k + 9], S31, 0xD9D4D039);
d = md5_HH(d, a, b, c, x[k + 12], S32, 0xE6DB99E5);
c = md5_HH(c, d, a, b, x[k + 15], S33, 0x1FA27CF8);
b = md5_HH(b, c, d, a, x[k + 2], S34, 0xC4AC5665);
a = md5_II(a, b, c, d, x[k + 0], S41, 0xF4292244);
d = md5_II(d, a, b, c, x[k + 7], S42, 0x432AFF97);
c = md5_II(c, d, a, b, x[k + 14], S43, 0xAB9423A7);
b = md5_II(b, c, d, a, x[k + 5], S44, 0xFC93A039);
a = md5_II(a, b, c, d, x[k + 12], S41, 0x655B59C3);
d = md5_II(d, a, b, c, x[k + 3], S42, 0x8F0CCC92);
c = md5_II(c, d, a, b, x[k + 10], S43, 0xFFEFF47D);
b = md5_II(b, c, d, a, x[k + 1], S44, 0x85845DD1);
a = md5_II(a, b, c, d, x[k + 8], S41, 0x6FA87E4F);
d = md5_II(d, a, b, c, x[k + 15], S42, 0xFE2CE6E0);
c = md5_II(c, d, a, b, x[k + 6], S43, 0xA3014314);
b = md5_II(b, c, d, a, x[k + 13], S44, 0x4E0811A1);
a = md5_II(a, b, c, d, x[k + 4], S41, 0xF7537E82);
d = md5_II(d, a, b, c, x[k + 11], S42, 0xBD3AF235);
c = md5_II(c, d, a, b, x[k + 2], S43, 0x2AD7D2BB);
b = md5_II(b, c, d, a, x[k + 9], S44, 0xEB86D391);
a = md5_AddUnsigned(a, AA);
b = md5_AddUnsigned(b, BB);
c = md5_AddUnsigned(c, CC);
d = md5_AddUnsigned(d, DD);
}
return (md5_WordToHex(a) + md5_WordToHex(b) + md5_WordToHex(c) + md5_WordToHex(d)).toLowerCase();
}

View File

@ -0,0 +1,102 @@
<!DOCTYPE html>
<html>
<head>
<title>视频查看</title>
<meta charset="UTF-8" />
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Cache" content="no-cache">
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<link rel="stylesheet" href="./layui.css">
<script src="./layui.js"></script>
<script src="./jquery-3.4.1.min.js"></script>
<script src="AgoraRTC_N-4.11.0.js"></script>
<!--给录像文件添加时间进度条-->
<script src="fix-webm-duration.js"></script>
</head>
<body>
<div id="video">
<div class="inTheVideo">
<img src="./images/inTheVideo.png" alt="" />
<span>REC</span>
</div>
<!--视频信息-->
<div class="videoInfo">
<p>丢包率:<span class="PacketLossRate">0</span>(%)</p>
<p>接收码率:<span class="RecvBitrate">0</span>(Kbps)</p>
<p>渲染帧率:<span class="RenderFrameRate">0</span>(fps)</p>
<p>播放总时间:<span class="TotalPlayDuration">0</span>(s)</p>
<p>卡顿总时间:<span class="TotalFreezeTime">0</span>(s)</p>
<p>传输延时:<span class="TransportDelay">0</span>(ms)</p>
</div>
<div id="qrcode"></div>
<div id="agora_local"></div>
</div>
<!--视频操作-->
<div class="videoNav">
<p class="nav">
<img src="images/videoExit.png" alt="" class="videoExit" title="退出" />
<img src="images/closeMute.png" alt="" title="静音" mute="close" class="closeMute" />
<img src="images/videoImg.png" alt="" title="截图" class="videoImg" />
<img src="images/startRecording.png" alt="" title="开始录像" class="startRecording" state="open" />
<img src="images/videoWalk.png" alt="" title="对讲" state="close" class="videoWalk" />
<img src="images/videoFullscreen.png" alt="" title="全屏" model="exitfullScreen" class="videoFullscreen" />
<img src="images/videoReInfo.png" alt="" title="视频信息" state="close" class="videoReInfo" />
</p>
<div id="slideTest1" class="demo-slider"></div>
<p class="power">
<img src="images/power100.png" alt="" title="电量" />
<span></span>
</p>
</div>
<!--倒计时-->
<div class="videoTitle">
<p>视频关闭中...</p>
<p>正在努力关闭视频中,还需<span class="close_ing_time"></span></p>
<p>
<button type="button" class="layui-btn layui-btn-primary">确认</button>
<button type="button" class="layui-btn layui-btn-primary">取消</button>
</p>
</div>
<!--截图-->
<div class="canvasImg">
<div class="canvasImgBox">
<canvas id="canvas"></canvas>
<p>
<a href="#" id="save" download=".png">保存</a>
<button id="cancel">取消</button>
</p>
</div>
</div>
<!--当js文件发生变化的时候自动清除浏览器缓存,只要标签后面的v每次不一样浏览器就更新了阿-->
<script>
//创建一个script标签
function loadScriptString() {
var timeStamp = new Date().getTime();
var script = document.createElement("script"); //创建一个script标签
script.type = "module";
script.src = `js/moveDeviceVideoOne.js?v=${timeStamp}`;
document.getElementsByTagName('head')[0].appendChild(script);
}
//创建一个link标签
function loadLinkString() {
var timeStamp = new Date().getTime();
var css = document.createElement("link"); //创建一个script标签
css.rel = "stylesheet";
css.href = `css/moveDeviceVideoOne.css?v=${timeStamp}`
document.getElementsByTagName('head')[0].appendChild(css);
$("#video").css("height", "720px");
}
loadScriptString();
loadLinkString();
</script>
</body>
</html>

View File

@ -0,0 +1,100 @@
<!DOCTYPE html>
<html>
<head>
<title>视频查看</title>
<meta charset="UTF-8"/>
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate"/>
<meta http-equiv="Cache" content="no-cache">
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<link rel="stylesheet" href="./layui.css">
<script src="./jquery-3.4.1.min.js"></script>
<script src="./layui.js"></script>
<script src="AgoraRTC_N-4.11.0.js"></script>
<!--给录像文件添加时间进度条-->
<script src="fix-webm-duration.js"></script>
</head>
<body
<!--视频显示-->
<div id="video">
<div class="inTheVideo">
<!-- <img src="../images/inTheVideo.png" alt="" /> -->
<span>REC</span>
</div>
<!--视频信息-->
<div class="videoInfo">
<p>丢包率:<span class="PacketLossRate">0</span>(%)</p>
<p>接收码率:<span class="RecvBitrate">0</span>(Kbps)</p>
<p>渲染帧率:<span class="RenderFrameRate">0</span>(fps)</p>
<p>播放总时间:<span class="TotalPlayDuration">0</span>(s)</p>
<p>卡顿总时间:<span class="TotalFreezeTime">0</span>(s)</p>
<p>传输延时:<span class="TransportDelay">0</span>(ms)</p>
</div>
<div id="agora_local"></div>
</div>
<!--视频操作-->
<div class="videoNav">
<p class="nav">
<img src="images/videoExit.png" alt="" class="videoExit" title="退出"/>
<img src="images/closeMute.png" alt="" title="静音" mute="close" class="closeMute"/>
<img src="images/videoImg.png" alt="" title="截图" class="videoImg"/>
<img src="images/startRecording.png" alt="" title="开始录像" class="startRecording" state="open"/>
<img src="images/videoWalk.png" alt="" title="对讲" state="close" class="videoWalk"/>
<img src="images/videoFullscreen.png" alt="" title="全屏" model="exitfullScreen" class="videoFullscreen"/>
<img src="images/videoReInfo.png" alt="" title="视频信息" state="close" class="videoReInfo"/>
</p>
<div id="slideTest1" class="demo-slider"></div>
<!--<p class="power">
<img src="images/power100.png" alt="" title="电量"/>
<span></span>
</p>-->
</div>
<!--倒计时-->
<div class="videoTitle">
<p>视频关闭中...</p>
<p>正在努力关闭视频中,还需<span class="close_ing_time"></span></p>
<p><button>确认</button><button>关闭</button></p>
</div>
<!--截图-->
<div class="canvasImg">
<div class="canvasImgBox">
<canvas id="canvas"></canvas>
<p>
<a href="#" id="save" download=".png">保存</a>
<button id="cancel">取消</button>
</p>
</div>
</div>
<!--当js文件发生变化的时候自动清除浏览器缓存,只要标签后面的v每次不一样浏览器就更新了阿-->
<script>
//创建一个script标签
function loadScriptString() {
var timeStamp=new Date().getTime();
var script = document.createElement("script"); //创建一个script标签
script.type = "module";
script.src=`js/moveDeviceVideoOne.js?v=${timeStamp}`;
document.getElementsByTagName('head')[0].appendChild(script);
}
//创建一个link标签
function loadLinkString(){
var timeStamp=new Date().getTime();
var css = document.createElement("link"); //创建一个script标签
css.rel = "stylesheet";
css.href=`css/moveDeviceVideoOne.css?v=${timeStamp}`
document.getElementsByTagName('head')[0].appendChild(css);
$("#video").css("height","720px");
}
loadScriptString();
loadLinkString();
</script>
</body>
</html>

BIN
public/rtc/walkBgVideo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

View File

@ -0,0 +1,25 @@
// import { userLoginInfo } from "../../view/index/js/index.js";
function createMqttData(deviceid: any, title: any, data: any, receiver: any) {
var openObj = {
"topic": deviceid + "_rtmtranfer",//设备号_rtmtranfer微站名/ter_cmd
"message": JSON.stringify({
"title": title,
// "sender": userLoginInfo["user_name"],
"sender": 'test05',
"department": "",
"scope": "",
"receiver": [receiver],
"video": "",
"rtm": (new Date().getTime()).toString(),
"data": data,
"userScope": "",
"userBragide": "",
"userDetachchment": "",
"userBorough": "",
"name": ""
})
}
return openObj;
}
export { createMqttData }

16
src/utils/sendMqtt.ts Normal file
View File

@ -0,0 +1,16 @@
// import axios from "axios";
// var url = 'https://www.hnjinglian.cn:2563/api_8083/firectrl/client/notice/sendmqtt'
// function sendMqtt(data: any) {
// return axios({
// method: 'post',
// url,
// data: data
// })
// }
// export { sendMqtt }
import api from '@/axios'
function sendMqtt(data: any) {
return api.post('/multialarm/video/keep', data)
}
export { sendMqtt }

View File

@ -36,7 +36,7 @@ onMounted(() => {
// iWidth: 600,
// iHeight: 400,
szId: 'player', //
szBasePath: './', // ,h5player.min.js
szBasePath: '/haikang', // ,h5player.min.js
iMaxSplit: 1, // 4*4
iCurrentSplit: IS_MOVE_DEVICE ? 1 : 2,
openDebug: true,
@ -45,11 +45,6 @@ onMounted(() => {
},
bSupporDoubleClickFull: true, //true
})
myPlugin
.JS_SetWindowControlCallback({
pluginErrorHandler: function (index: any, iErrorCode: any, oError: any) {},
})
.then((res: any) => {})
var controlIndex = 2
function playVideo() {

View File

@ -26,6 +26,8 @@
</el-form-item>
<!-- <el-input v-model="0"></el-input> -->
</div>
<!-- <button @click="stop">关闭</button> -->
<div style="padding: 0px 20px; height: 75%; overflow: auto" v-show="show3">
<a-tree
v-loading="loading"
@ -37,10 +39,10 @@
:tree-data="treedataall"
@select="selectA"
>
<template #title="{ title, level }">
<template #title="{ title }">
{{ title }}
</template>
<template #icon="{ level, deviceType, selected, title }">
<template #icon="{ level, deviceType, title }">
<img v-if="title == '湖南省'" style="" src="./indeximag/shu/一级.png" alt="" />
<img v-if="level == '1'" style="" src="./indeximag/shu/一级.png" alt="" />
<img v-if="level == '2'" style="" src="./indeximag/shu/二级.png" alt="" />
@ -344,12 +346,14 @@
</a-timeline>
</div>
<el-dialog title="视频" v-model="dialogVisible" width="30%">
<iframe style="width: 100%; height: 250px" :src="'https://www.jy-sh.com/h5sVideo/index.html?token=' + pointCode + '&autoplay=true'" frameborder="0"></iframe>
</el-dialog>
<div v-if="showIframe" class="iframe-container">
<iframe :src="videoUrl" frameborder="0"></iframe>
</div>
</div>
</template>
<script lang="ts" setup>
import { createMqttData } from '@/utils/createMqttData'
import { sendMqtt } from '@/utils/sendMqtt'
import { DownOutlined, SmileOutlined, FrownOutlined, FrownFilled } from '@ant-design/icons-vue'
import { useWebSocket } from '@vueuse/core'
import { wsUrl } from '@/utils/webSocket'
@ -369,7 +373,10 @@ import closeimag from './imag/infoClose.png'
import { Ref, ref, watch, onMounted, onBeforeMount, reactive, getCurrentInstance, nextTick } from 'vue'
// import AMapLoader from "@amap/amap-jsapi-loader";
import { Vue3SeamlessScroll } from 'vue3-seamless-scroll'
import { log } from 'util'
const showIframe = ref(false)
const videoUrl = ref('')
const { proxy } = getCurrentInstance() as any
const day = proxy.day
const size = ref('')
@ -377,7 +384,7 @@ const lodash = proxy.lodash
const value1 = ref('a1')
const zoom = ref('12')
const center = ref([121.59996, 31.197646])
const map = null
let map: any
const expandedKeys = ref([])
const selectedKeys = ref([])
const checkedKeys = ref([])
@ -413,7 +420,7 @@ const gbht = () => {
}
const isActive1 = ref('1')
const qhzty2 = (data) => {
const qhzty2 = (data: any) => {
isActive1.value = data
}
@ -434,7 +441,7 @@ const closee = () => {
visible.value = false
}
//
const jiesuo = (data) => {
const jiesuo = (data: any) => {
api
.post('/multialarm/client/alarm_event/unlock', {
eventId: data.multiAlarmId,
@ -465,7 +472,7 @@ const jiesuo = (data) => {
})
}
//
const lock = (data) => {
const lock = (data: any) => {
api
.post('/multialarm/client/alarm_event/lock', {
eventId: data.multiAlarmId,
@ -497,20 +504,20 @@ const lock = (data) => {
})
}
//
const printLeafs = (tree, jirearr) => {
const printLeafs = (tree: any, jirearr: any) => {
if (!tree.children) {
tree.children = []
jirearr.forEach((x) => {
jirearr.forEach((x: any) => {
if (tree.stationId == x.stationId) {
tree.children.push(x)
}
})
} else {
tree.children.forEach((child) => printLeafs(child, jirearr))
tree.children.forEach((child: any) => printLeafs(child, jirearr))
}
}
const isActive = ref('6')
const qhzty = (data) => {
const qhzty = (data: any) => {
isActive.value = data
switch (data) {
case '1':
@ -536,7 +543,7 @@ const qhzty = (data) => {
const loading = ref(false)
//
const treedataall = ref([])
const gettree4 = (data) => {
const gettree4 = (data: any) => {
loading.value = true
api
.post('/common/client/user/org/tree4', {
@ -565,7 +572,7 @@ const gettree4 = (data) => {
})
}
//
const close = (info) => {
const close = (info: any) => {
api
.post('/multialarm/client/alarm_event/close', {
eventId: info.multiAlarmId,
@ -609,7 +616,7 @@ const gridData = [
address: 'New York City',
},
]
const totypecn = (data) => {
const totypecn = (data: any) => {
if (data == '0') {
return '未核验'
} else if (data == '1') {
@ -618,7 +625,7 @@ const totypecn = (data) => {
return '核验为真'
}
}
const toCn = (data) => {
const toCn = (data: any) => {
if (data == 'report') {
return '信息上报'
} else if (data == 'modify.userinfo') {
@ -643,15 +650,15 @@ const num = ref(100)
const handleChange = (value: number) => {
// console.log(value)
}
const cz = (infoData, upstatuslist) => {
const cz = (infoData: any, upstatuslist: any) => {
let routeData = router.resolve({ path: '/index/communitymanage', query: { multiAlarmId: infoData.multiAlarmId, data: JSON.stringify(infoData), upstatuslist: JSON.stringify(upstatuslist) } })
window.open(routeData.href, '_blank')
}
;(window as any).cz2 = (infoData, upstatuslist) => {
;(window as any).cz2 = (infoData: any, upstatuslist: any) => {
let routeData = router.resolve({ path: '/index/communitymanage', query: { multiAlarmId: infoData.multiAlarmId, data: JSON.stringify(infoData), upstatuslist: JSON.stringify(upstatuslist) } })
window.open(routeData.href, '_blank')
}
const sendStationList = (rollCall_websocket, stationTempArr) => {
const sendStationList = (rollCall_websocket: any, stationTempArr: any) => {
var getIot = {
msgcode: 102,
msgname: 'station-sensor-list',
@ -661,7 +668,7 @@ const sendStationList = (rollCall_websocket, stationTempArr) => {
rollCall_websocket.send(msg)
}
const ingrssddata = ref()
const clickKz = (dat2a) => {
const clickKz = (dat2a: any) => {
api
.post('/multialarm/client/alarm_event/get_all_resource', {
range: 1000,
@ -701,8 +708,8 @@ const treedata = () => {
.then((res) => {
var gridSize = 60
// console.log('', res)
var points = []
res.data.map((x) => {
var points: any[]
res.data.map((x: any) => {
const marker = new AMap.Marker({
position: new AMap.LngLat(x.longitude == null ? 0 : x.longitude, x.latitude == null ? 0 : x.latitude),
offset: new AMap.Pixel(-15, -15),
@ -726,7 +733,7 @@ const treedata = () => {
})
var count = points.length
//
var _renderClusterMarker = function (context) {
var _renderClusterMarker = function (context: any) {
var factor = Math.pow(context.count / count, 1 / 18)
var div = document.createElement('div')
var Hue = 180 - factor * 180
@ -777,7 +784,7 @@ const getdayline = () => {
// console.log('', res)
jinbao.value = res.data
if (res.data.length > 0) {
res.data.map((x) => {
res.data.map((x: any) => {
if (x.state == 'close') {
const marker = new AMap.Marker({
position: new AMap.LngLat(x.longitude == null ? 0 : x.longitude, x.latitude == null ? 0 : x.latitude),
@ -881,7 +888,7 @@ const gettotal = () => {
}
//
let deviceInfoWindow = ref(null)
const selectA = (selectedKeys, e) => {
const selectA = (selectedKeys: any, e: any) => {
// console.log('selectedKeys',selectedKeys,e)
if (selectedKeys[0].length >= 13) {
let targetLangLat = [e.selectedNodes[0].longitude == null ? 0 : e.selectedNodes[0].longitude, e.selectedNodes[0].latitude == null ? 0 : e.selectedNodes[0].latitude]
@ -895,19 +902,19 @@ const selectA = (selectedKeys, e) => {
state.map.setZoomAndCenter(205, targetLangLat)
}
}
const selectB = (selectedKeys, e) => {
const selectB = (selectedKeys: any, e: any) => {
if (e.selectedNodes[0]) {
let targetLangLat = [e.selectedNodes[0].longitude == null ? 0 : e.selectedNodes[0].longitude, e.selectedNodes[0].latitude == null ? 0 : e.selectedNodes[0].latitude]
state.map.panTo(targetLangLat)
}
}
const selectC = (selectedKeys, e) => {
const selectC = (selectedKeys: any, e: any) => {
if (e.selectedNodes[0]) {
let targetLangLat = [e.selectedNodes[0].longitude == null ? 0 : e.selectedNodes[0].longitude, e.selectedNodes[0].latitude == null ? 0 : e.selectedNodes[0].latitude]
state.map.panTo(targetLangLat)
}
}
const createSubstanceInfowindow = (obj, type) => {
const createSubstanceInfowindow = (obj: any, type: any) => {
//
var mdinfoTop = document.createElement('div')
mdinfoTop.className = 'mapPopInfo'
@ -938,7 +945,7 @@ const createSubstanceInfowindow = (obj, type) => {
return mdinfoTop
}
const createSubstanceInfowindow1 = (obj, type) => {
const createSubstanceInfowindow1 = (obj: any, type: any) => {
//
var mdinfoTop = document.createElement('div')
mdinfoTop.className = 'mapPopInfo'
@ -969,7 +976,7 @@ const createSubstanceInfowindow1 = (obj, type) => {
return mdinfoTop
}
const createSubstanceInfowindow2 = (obj, type) => {
const createSubstanceInfowindow2 = (obj: any, type: any) => {
//
var mdinfoTop = document.createElement('div')
mdinfoTop.className = 'mapPopInfo'
@ -1001,7 +1008,7 @@ const createSubstanceInfowindow2 = (obj, type) => {
return mdinfoTop
}
const getSubstanceInfoWindowContent2 = (obj, type) => {
const getSubstanceInfoWindowContent2 = (obj: any, type: any) => {
console.log('🚀 ~ getSubstanceInfoWindowContent2 ~ obj, type:', obj, type)
var station = obj['station']
var nickname = ''
@ -1051,37 +1058,67 @@ const getSubstanceInfoWindowContent2 = (obj, type) => {
const dialogVisible = ref(false)
const pointCode = ref()
;(window as any).addrt = (a) => {
;(window as any).addrt = (a: any) => {
console.log('播放_______________', a)
// let routeData = router.resolve({ path: '/index/hkplay', query: { pointId: a.pointId } })
// window.open(routeData.href, '_blank')
if (a.deviceType == '00') {
if (a.alarmType == 'isc') {
try {
// router.push({ path: '/index/hkplay', query: { pointId: a.pointId } })
let routeData = router.resolve({ path: '/index/hkplay', query: { pointId: a.pointId } })
// console.log('routeData.href_____________________', routeData.href)
// routeData.href = 'index.html' + routeData.href
console.log('routeData.href_____________________', routeData.href)
// console.log('🚀 ~ routeData:', JSON.stringify(routeData))
// window.location.href = routeData.href
window.open(routeData.href, '_blank')
// window.open('http://172.10.10.161:9527/#/index/hkplay?pointId=43000000581314000013', '_blank') //token
// window.open('https://www.hndyjqrh.cn/#/index/hkplay?pointId=43000000581314000013', '_blank')
} catch (error) {
console.log('🚀 ~addrt error:', error)
}
} catch (error) {}
}
// window.open('https://www.jy-sh.com/h5sVideo/index.html?token=' + a.pointCode + '&autoplay=true')
} else {
window.open('https://www.jy-sh.com/webRtcVideo/moveDeviceVideoOne.html?id=' + a.deviceId)
//
var width = 1280
var height = 760
let deviceID = a.deviceId
let timeID_: ReturnType<typeof setTimeout>
function preview() {
api.post('/multialarm/video/preview', { pointId: a.pointId }).then((res) => {
console.log('🚀 ~ /multialarm/video/preview:', res)
if (res.code === 0) {
keep()
timeID_ = setInterval(() => {
console.log(111111)
keep()
}, 60000)
}
})
}
function keep() {
api.post('/multialarm/video/keep', { pointId: a.pointId }).then((res) => {
console.log('🚀 ~ /multialarm/video/keep:', res)
})
}
function close() {
api.post('/multialarm/video/close', { pointId: a.pointId }).then((res) => {
console.log('🚀 ~ /multialarm/video/close:', res)
})
}
var url = `/rtc/moveDeviceVideoOne.html?id=${deviceID}`
const newWindow = window.open(url, '', 'width=' + width + ',height=' + height + ",top=0,left=0,status='no',location='no',resizable='no',toolbar='no'")
preview()
const onWindowClosed = () => {
console.log('timerID, timeID', timerID, timeID_)
close()
clearInterval(timeID_)
clearInterval(timerID)
console.log('新窗口已关闭____成功')
}
let timerID: ReturnType<typeof setTimeout>
if (newWindow) {
timerID = setInterval(() => {
if (newWindow.closed) {
onWindowClosed()
clearInterval(timerID)
}
}, 500)
}
}
}
const getSubstanceInfoWindowContent = (obj, type) => {
const getSubstanceInfoWindowContent = (obj: any, type: any) => {
// console.log('obj', obj, type)
var station = obj['station']
var nickname = ''
@ -1170,7 +1207,7 @@ const getRealTimeAlarmSituation = () => {
// console.log('', res)
if (res.code == 0) {
listData.value = res.data.reverse()
res.data.map((x) => {
res.data.map((x: any) => {
const marker = new AMap.Marker({
position: new AMap.LngLat(x.longitude == null ? 0 : x.longitude, x.latitude == null ? 0 : x.latitude),
offset: new AMap.Pixel(-10, -10),
@ -1201,7 +1238,7 @@ const getRealTimeAlarmSituation = () => {
const infoData = ref({})
const upstatuslist = ref([])
const listindex = ref()
const toinfo = (item, index) => {
const toinfo = (item: any, index: number) => {
listindex.value = index
// dialogTableVisible.value = false;
nextTick(() => {
@ -1862,4 +1899,18 @@ const defaultProps = {
border: 1px solid #2081c1;
box-shadow: 0 0 3px 3px #244b68;
}
.iframe-container {
width: 80%;
height: 80%;
position: fixed;
top: 10%;
left: 10%;
border: 1px solid #ccc;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
background: #fff;
}
iframe {
width: 100%;
height: 100%;
}
</style>

View File

@ -1,12 +1,13 @@
import {defineConfig, loadEnv, UserConfigExport} from 'vite'
import { defineConfig, loadEnv, UserConfigExport } from 'vite'
import vueJsx from '@vitejs/plugin-vue-jsx'
import vue from '@vitejs/plugin-vue'
import * as path from "path";
import { resolve } from 'path';
import Components from 'unplugin-vue-components/vite';
import {AntDesignVueResolver} from 'unplugin-vue-components/resolvers';
import {visualizer} from 'rollup-plugin-visualizer'
import { AntDesignVueResolver } from 'unplugin-vue-components/resolvers';
import { visualizer } from 'rollup-plugin-visualizer'
// @ts-ignore
import {name, version, description, appName} from "./package.json";
import { name, version, description, appName } from "./package.json";
import dayjs from "dayjs";
const __APP_INFO__ = {
@ -20,7 +21,7 @@ const __APP_INFO__ = {
const pathSrc = path.resolve(__dirname, 'src');
// https://vitejs.dev/config/
export default ({mode}): UserConfigExport => {
export default ({ mode }): UserConfigExport => {
const env: Record<string, string> = loadEnv(mode, process.cwd(), '')
return defineConfig({
define: {
@ -32,7 +33,7 @@ export default ({mode}): UserConfigExport => {
vue(),
vueJsx(),
Components({
resolvers: [AntDesignVueResolver({importStyle: false})]
resolvers: [AntDesignVueResolver({ importStyle: false })]
}),
visualizer({
emitFile: false,
@ -57,7 +58,8 @@ export default ({mode}): UserConfigExport => {
changeOrigin: true,
rewrite: path => path.replace(RegExp(`^${env['VITE_APP_WS_API']}`), ''),
}
}
},
},
build: {
outDir: 'dist',
@ -75,6 +77,7 @@ export default ({mode}): UserConfigExport => {
comments: false
}
},
rollupOptions: {
output: {
manualChunks(id) {