From b1084891961232e3c697ea9fc52f127cdccffb6b Mon Sep 17 00:00:00 2001 From: liusuyi <1951119284@qq.com> Date: 星期四, 11 七月 2024 17:28:44 +0800 Subject: [PATCH] 优化:流媒体 --- ard-work/src/main/resources/templates/test.html | 1336 ++++++++++++++++++++++++++++++++++++++++++--------------- 1 files changed, 976 insertions(+), 360 deletions(-) diff --git a/ard-work/src/main/resources/templates/test.html b/ard-work/src/main/resources/templates/test.html index f9c520f..e805ee4 100644 --- a/ard-work/src/main/resources/templates/test.html +++ b/ard-work/src/main/resources/templates/test.html @@ -4,148 +4,147 @@ <meta charset="UTF-8"> <title>娴嬭瘯椤�</title> <script th:src="@{/js/jquery-3.6.4.min.js}"></script> - <script th:src="@{/js/adapter.min.js}"></script> - <script th:src="@{/js/webrtcstreamer.js}"></script> <link rel="stylesheet" th:href="@{/css/bootstrap.css}"/> <script th:src="@{/js/bootstrap.js}"></script> <style> - .top-buffer { margin-top:10px; } + .top-buffer { + margin-top: 10px; + } + .container { + border: 2px solid #1b6d85; + padding: 15px; + } </style> <body> <div class="container"> - <div class="row "> - <div class="dropdown"> - 鐩告満id锛� - <select id="select"> - </select> + <div class="row"> + <div class="col-md-5"> + <div class="row top-buffer"> + 璁惧锛�<select id="selectDev" style="width: 330px;"> + </select> </div> - </div> - <div class="row top-buffer"> - <div class="col-md-1 col-md-offset-1"> - <button id="up" type="button" class="btn btn-primary">涓�</button> + <div class="row top-buffer"> + 閫氶亾锛�<select id="selectChn" style="width: 330px;"> + </select> </div> - <div class="col-md-4 col-md-offset-3"> - <div class="btn-group" role="group"> - <button id="controlZoomIn" type="button" class="btn btn-primary">璋冪劍-</button> - <button id="controlZoomOut" type="button" class="btn btn-primary">璋冪劍+</button> + <div class="row top-buffer"> + <div class="col-md-1 col-md-offset-1"> + <button id="up" type="button" class="btn btn-primary">涓�</button> + </div> + <div class="col-md-6 col-md-offset-2"> + <div class="btn-group" role="group"> + <button id="controlZoomIn" type="button" class="btn btn-primary">璋冪劍-</button> + <button id="controlZoomOut" type="button" class="btn btn-primary">璋冪劍+</button> + </div> + </div> + </div> + <div class="row "> + <div class="col-md-1"> + <button id="left" type="button" class="btn btn-primary">宸�</button> + </div> + <div class="col-md-1 col-md-offset-1"> + <button id="right" type="button" class="btn btn-primary">鍙�</button> + </div> + <div class="col-md-6 col-md-offset-1"> + <div class="btn-group" role="group"> + <button id="controlFocusNear" type="button" class="btn btn-primary">鑱氱劍-</button> + <button id="controlFocusFar" type="button" class="btn btn-primary">鑱氱劍+</button> + </div> + </div> + </div> + <div class="row "> + <div class="col-md-1 col-md-offset-1"> + <button id="down" type="button" class="btn btn-primary">涓�</button> + </div> + <div class="col-md-6 col-md-offset-2"> + <div class="btn-group" role="group"> + <button id="controlIrisOpen" type="button" class="btn btn-primary">鍏夊湀-</button> + <button id="controlIrisClose" type="button" class="btn btn-primary">鍏夊湀+</button> + </div> + </div> + </div> + <div class="row "> + <div class="col-md-10"> + <div class="row top-buffer"> + <div class="input-group"> + <span class="input-group-addon">鐩殑鍧愭爣鍊硷細</span> + <input id="targetPostion" class="form-control" placeholder="鐩殑鍧愭爣"/> + <button id="setTargetPostion" type="button" class="btn btn-default">鎸囧悜鍧愭爣</button> + </div> + <div class="input-group"> + <span class="input-group-addon">P鍊硷細</span> + <input id="p" class="form-control" placeholder="璇疯緭鍏鍊�"/> + </div> + <div class="input-group"> + <span class="input-group-addon">T鍊硷細</span> + <input id="t" class="form-control" placeholder="璇疯緭鍏鍊�"/> + </div> + <div class="input-group"> + <span class="input-group-addon">Z鍊硷細</span> + <input id="z" class="form-control" placeholder="璇疯緭鍏鍊�"/> + </div> + </div> + <div class="row top-buffer"> + <div class="btn-group" role="group"> + <button id="getPTZ" type="button" class="btn btn-default">鑾峰彇ptz</button> + <button id="setPTZ" type="button" class="btn btn-default">璁剧疆ptz</button> + <button id="setPreset" type="button" class="btn btn-default">璁鹃缃偣</button> + <button id="gotoPreset" type="button" class="btn btn-default">璋冮缃偣</button> + <button id="setZeroPTZ" type="button" class="btn btn-default">璁剧疆闆舵柟浣嶈</button> + </div> + </div> + <div class="row top-buffer"> + <div class="btn-group" role="group"> + <button id="FocusMode" type="button" class="btn btn-default">鎵嬪姩鑱氱劍</button> + <div id="focusDiv" class="input-group"> + <span class="input-group-addon">鑱氱劍鍊硷細</span> + <input id="focus" class="form-control" placeholder="鑱氱劍鍊�"/> + </div> + <button id="getFocusPos" type="button" class="btn btn-default">鑾峰彇鑱氱劍鍊�</button> + <button id="setFocusPos" type="button" class="btn btn-default">璁剧疆鑱氱劍鍊�</button> + </div> + </div> + <div class="row top-buffer"> + <div class="btn-group" role="group"> + <button id="WiperPwron" type="button" class="btn btn-default">寮�鍚洦鍒�</button> + <button id="Defogcfg" type="button" class="btn btn-default">寮�鍚�忛浘</button> + <button id="Infrarecfg" type="button" class="btn btn-default">寮�鍚孩澶�</button> + <button id="HeateRpwron" type="button" class="btn btn-default">寮�鍚簯鍙板姞鐑�</button> + <button id="CameraDeicing" type="button" class="btn btn-default">寮�鍚暅澶村姞鐑�</button> + </div> + </div> + <div class="row top-buffer"> + <div class="btn-group" role="group"> + <button id="voice" type="button" class="btn btn-default">寮�濮嬭闊冲璁�</button> + <button id="record" type="button" class="btn btn-default">寮�濮嬪綍鍍�</button> + <button id="saveCutPic" type="button" class="btn btn-default">瀛樺偍鎶撳浘</button> + </div> + </div> </div> </div> </div> - <div class="row "> - <div class="col-md-1"> - <button id="left" type="button" class="btn btn-primary">宸�</button> - </div> - <div class="col-md-1 col-md-offset-1"> - <button id="right" type="button" class="btn btn-primary">鍙�</button> - </div> - <div class="col-md-4 col-md-offset-2"> - <div class="btn-group" role="group"> - <button id="controlFocusNear" type="button" class="btn btn-primary">鑱氱劍-</button> - <button id="controlFocusFar" type="button" class="btn btn-primary">鑱氱劍+</button> + <div class="col-md-6"> + <div class="row"> + <div class="row top-buffer"> + <button id="preview" type="button" class="btn btn-primary">棰勮</button> + <button id="previewStop" type="button" class="btn btn-primary">鍋滄</button> </div> - </div> - </div> - <div class="row "> - <div class="col-md-1 col-md-offset-1"> - <button id="down" type="button" class="btn btn-primary">涓�</button> - </div> - <div class="col-md-4 col-md-offset-3"> - <div class="btn-group" role="group"> - <button id="controlIrisOpen" type="button" class="btn btn-primary">鍏夊湀-</button> - <button id="controlIrisClose" type="button" class="btn btn-primary">鍏夊湀+</button> + <div class="row top-buffer"> + <video id="video" muted autoplay loop controls + style="width: 100%; height: 360px; object-fit: fill; border: 2px solid #3498db;"/> </div> - </div> - </div> - <div class="row top-buffer"> - <div class="input-group"> - <span class="input-group-addon">P鍊硷細</span> - <input id="p" class="form-control" placeholder="璇疯緭鍏鍊�"/> - </div> - <div class="input-group"> - <span class="input-group-addon">T鍊硷細</span> - <input id="t" class="form-control" placeholder="璇疯緭鍏鍊�"/> - </div> - <div class="input-group"> - <span class="input-group-addon">Z鍊硷細</span> - <input id="z" class="form-control" placeholder="璇疯緭鍏鍊�"/> - </div> - </div> - <div class="row top-buffer"> - <div class="btn-group" role="group"> - <button id="getPTZ" type="button" class="btn btn-default">鑾峰彇ptz</button> - <button id="setPTZ" type="button" class="btn btn-default">璁剧疆ptz</button> - <button id="setPreset" type="button" class="btn btn-default">璁鹃缃偣</button> - <button id="gotoPreset" type="button" class="btn btn-default">璋冮缃偣</button> - <button id="getZeroPTZ" type="button" class="btn btn-default">璋冪敤闆舵柟浣嶈</button> - <button id="setZeroPTZ" type="button" class="btn btn-default">璁剧疆闆舵柟浣嶈</button> - </div> - </div> - <div class="row top-buffer"> - <div class="btn-group" role="group"> - <button id="FocusMode" type="button" class="btn btn-default">鎵嬪姩鑱氱劍</button> - <div id="focusDiv" class="input-group"> - <span class="input-group-addon">鑱氱劍鍊硷細</span> - <input id="focus" class="form-control" placeholder="鑱氱劍鍊�"/> + <div class="row"> + <img class="thumbnail" id="imgContainer" + style="width: 100%; height: 360px; border: 2px solid #3498db;"/> </div> - <button id="getFocusPos" type="button" class="btn btn-default">鑾峰彇鑱氱劍鍊�</button> - <button id="setFocusPos" type="button" class="btn btn-default">璁剧疆鑱氱劍鍊�</button> - </div> - </div> - <div class="row top-buffer"> - <div class="btn-group" role="group"> - <button id="WiperPwron" type="button" class="btn btn-default">寮�鍚洦鍒�</button> - <button id="Defogcfg" type="button" class="btn btn-default">寮�鍚�忛浘</button> - <button id="Infrarecfg" type="button" class="btn btn-default">寮�鍚孩澶�</button> - <button id="HeateRpwron" type="button" class="btn btn-default">寮�鍚簯鍙板姞鐑�</button> - <button id="CameraDeicing" type="button" class="btn btn-default">寮�鍚暅澶村姞鐑�</button> - </div> - </div> - <div class="row top-buffer"> - <div class="btn-group" role="group"> - <button id="voice" type="button" class="btn btn-default">寮�濮嬭闊冲璁�</button> - <button id="record" type="button" class="btn btn-default">寮�濮嬪綍鍍�</button> - <button id="realCutPic" type="button" class="btn btn-default">瀹炴椂鎶撳浘</button> - <button id="saveCutPic" type="button" class="btn btn-default">瀛樺偍鎶撳浘</button> - </div> - </div> - <div class="row top-buffer"> - <div class="col-md-6"> - <img class="thumbnail" id="imgContainer" style="width: 500px; height: 400px;padding: 5px 5px;"/> - </div> - <div class="col-md-6"> - <video id="video" muted autoplay loop controls style="width: 800px; height: 100%; object-fit: fill" /> </div> </div> </div> -</body> +</div> <script th:inline="javascript"> - var cameraId, opt, token; + var cameraId, chanNo,opt, optOpen, optClose, token; window.onload = function () { - $.ajax({ - url: "../hik/list", - type: "get", - success: function (data) { - console.log(data); - var arr = data.data; - for (var i = 0; i < arr.length; i++) { - console.log(arr[i].id); - var camera = { - type: arr[i].type, - ipaddr: arr[i].ip, - username: arr[i].username, - password: arr[i].password, - port: 554 - }; - cameraMap.set(arr[i].id, camera); - //鍏堝垱寤哄ソselect閲岄潰鐨刼ption鍏冪礌 - var option = document.createElement("option"); - //缁檕ption鐨則ext璧嬪��,杩欏氨鏄綘鐐瑰紑涓嬫媺妗嗚兘澶熺湅鍒扮殑涓滆タ - $(option).text(arr[i].id); - //鑾峰彇select 涓嬫媺妗嗗璞�,骞跺皢option娣诲姞杩泂elect - $('#select').append(option); - } - } - }) + console.log(RTCRtpReceiver.getCapabilities('video').codecs) opt = {"username": "admin", "password": "admin123"}; $.ajax({ headers: { @@ -157,149 +156,255 @@ dataType: "json", data: JSON.stringify(opt), success: function (data) { - console.log(data); token = data.token; + getDeviceList();// 鑾峰彇璁惧鍒楄〃 } }) // 鍒濆鍖栧唴瀹� console.log(cameraMap); } - //浜戝彴涓婁笅宸﹀彸 - $("#up").mousedown(function () { - var url = "../hik/PTZControlWithSpeed"; - var code = 2; - var enable = true; - commondMethod(url, code, enable); - }) - $("#up").mouseup(function () { - var url = "../hik/PTZControlWithSpeed"; - var code = 2; - var enable = false; - commondMethod(url, code, enable); - }) - $("#down").mousedown(function () { - var url = "../hik/PTZControlWithSpeed"; - var code = 8; - var enable = true; - commondMethod(url, code, enable); - }) - $("#down").mouseup(function () { - var url = "../hik/PTZControlWithSpeed"; - var code = 8; - var enable = false; - commondMethod(url, code, enable); - }) - $("#left").mousedown(function () { - var url = "../hik/PTZControlWithSpeed"; - var code = 4; - var enable = true; - commondMethod(url, code, enable); - }) - $("#left").mouseup(function () { - var url = "../hik/PTZControlWithSpeed"; - var code = 4; - var enable = false; - commondMethod(url, code, enable); - }) - $("#right").mousedown(function () { - var url = "../hik/PTZControlWithSpeed"; - var code = 6; - var enable = true; - commondMethod(url, code, enable); - }) - $("#right").mouseup(function () { - var url = "../hik/PTZControlWithSpeed"; - var code = 6; - var enable = false; - commondMethod(url, code, enable); - }) - //鍙樺�� - $("#controlZoomIn").mousedown(function () { - var url = "../hik/PTZControlWithSpeed"; - var code = 10; - var enable = true; - commondMethod(url, code, enable); - }) - $("#controlZoomIn").mouseup(function () { - var url = "../hik/PTZControlWithSpeed"; - var code = 10; - var enable = false; - commondMethod(url, code, enable); - }) - $("#controlZoomOut").mousedown(function () { - var url = "../hik/PTZControlWithSpeed"; - var code = 11; - var enable = true; - commondMethod(url, code, enable); - }) - $("#controlZoomOut").mouseup(function () { - var url = "../hik/PTZControlWithSpeed"; - var code = 11; - var enable = false; - commondMethod(url, code, enable); - }) - //鍙樼劍 - $("#controlFocusNear").mousedown(function () { - var url = "../hik/PTZControlWithSpeed"; - var code = 12; - var enable = true; - commondMethod(url, code, enable); - }) - $("#controlFocusNear").mouseup(function () { - var url = "../hik/PTZControlWithSpeed"; - var code = 12; - var enable = false; - commondMethod(url, code, enable); - }) - $("#controlFocusFar").mousedown(function () { - var url = "../hik/PTZControlWithSpeed"; - var code = 13; - var enable = true; - commondMethod(url, code, enable); - }) - $("#controlFocusFar").mouseup(function () { - var url = "../hik/PTZControlWithSpeed"; - var code = 13; - var enable = false; - commondMethod(url, code, enable); - }) - //鍏夊湀 - $("#controlIrisOpen").mousedown(function () { - var url = "../hik/PTZControlWithSpeed"; - var code = 14; - var enable = true; - commondMethod(url, code, enable); - }) - $("#controlIrisOpen").mouseup(function () { - var url = "../hik/PTZControlWithSpeed"; - var code = 14; - var enable = false; - commondMethod(url, code, enable); - }) - $("#controlIrisClose").mousedown(function () { - var url = "../hik/PTZControlWithSpeed"; - var code = 15; - var enable = true; - commondMethod(url, code, enable); - }) - $("#controlIrisClose").mouseup(function () { - var url = "../hik/PTZControlWithSpeed"; - var code = 15; - var enable = false; - commondMethod(url, code, enable); - }) + //鑾峰彇璁惧 + function getDeviceList() { + $.ajax({ + url: "../cameraSdk/list", + type: "get", + success: function (data) { + console.log(data); + var arr = data.data; + for (var i = 0; i < arr.length; i++) { + console.log(arr[i].id); + console.log(arr[i].name) + var camera = { + name: arr[i].name, + factory: arr[i].factory, + ipaddr: arr[i].ip, + username: arr[i].username, + password: arr[i].password, + port: arr[i].rtspPort, + longitude: arr[i].longitude, + latitude: arr[i].latitude, + altitude: arr[i].altitude + }; + cameraMap.set(arr[i].id, camera); + //鍏堝垱寤哄ソselect閲岄潰鐨刼ption鍏冪礌 + var option = $("<option>"); + //缁檕ption鐨則ext璧嬪��,杩欏氨鏄綘鐐瑰紑涓嬫媺妗嗚兘澶熺湅鍒扮殑涓滆タ + $(option).val(arr[i].id); + $(option).text(arr[i].name); + //鑾峰彇select 涓嬫媺妗嗗璞�,骞跺皢option娣诲姞杩泂elect + $('#selectDev').append(option); + } + $("#selectDev").trigger("change"); + } + }) + } - $("#setPreset").click(function () { - cameraId = $('#select option:selected').val(); - opt = {"cameraId": cameraId, "channelNum": 1, "speed": 8, "presetIndex": 1}; + //閫夋嫨璁惧 + $("#selectDev").change(function () { + // 鍦ㄨ繖閲屽鐞嗛�夋嫨浜嬩欢 + var cameraId = $(this).find("option:selected").val(); + var name = $(this).find("option:selected").text(); + getChannelList(cameraId); + console.log("閫夋嫨浜嗭細" + cameraId + "---" + name); + }); + + //鑾峰彇閫氶亾 + function getChannelList(cameraId) { + console.log(cameraId) + var myEntity = { + deviceId: cameraId, + pageNum: 1, + pageSize: 64 + } + var queryString = $.param(myEntity); $.ajax({ headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', 'Authorization': token }, - url: "../hik/setPreset", + url: "../device/channel/list?" + queryString, + type: "get", + success: function (data) { + console.log(data); + var arr = data.rows; + $('#selectChn').empty(); + for (var i = 0; i < arr.length; i++) { + console.log(arr[i].chanNo); + console.log(arr[i].name); + //鍏堝垱寤哄ソselect閲岄潰鐨刼ption鍏冪礌 + var option = document.createElement("option"); + //缁檕ption鐨則ext璧嬪��,杩欏氨鏄綘鐐瑰紑涓嬫媺妗嗚兘澶熺湅鍒扮殑涓滆タ + $(option).text(arr[i].name); + $(option).val(arr[i].chanNo); + //鑾峰彇select 涓嬫媺妗嗗璞�,骞跺皢option娣诲姞杩泂elect + $('#selectChn').append(option); + } + } + }) + } + + //棰勮 + $('#preview').click(() => { + var cameraId = $('#selectDev option:selected').val(); + var chanNo = $('#selectChn option:selected').val(); + console.log(cameraId + " " + chanNo) + $.ajax({ + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': token + }, + url: "../vtdu/media/" + cameraId + "_" + chanNo, + type: "get", + dataType: "json", + success: function (data) { + realView(data.data.webrtcUrl + "/", "video"); + } + }) + }); + //鍋滄 + $('#previewStop').click(() => { + webrtcClient.stop(); + }); + //浜戝彴涓婁笅宸﹀彸 + $("#up").mousedown(function () { + var url = "../cameraSdk/PTZControlWithSpeed"; + var code = 2; + var enable = true; + commondMethod(url, code, enable); + + }) + $("#up").mouseup(function () { + var url = "../cameraSdk/PTZControlWithSpeed"; + var code = 2; + var enable = false; + commondMethod(url, code, enable); + }) + $("#down").mousedown(function () { + var url = "../cameraSdk/PTZControlWithSpeed"; + var code = 8; + var enable = true; + commondMethod(url, code, enable); + }) + $("#down").mouseup(function () { + var url = "../cameraSdk/PTZControlWithSpeed"; + var code = 8; + var enable = false; + commondMethod(url, code, enable); + }) + $("#left").mousedown(function () { + var url = "../cameraSdk/PTZControlWithSpeed"; + var code = 4; + var enable = true; + commondMethod(url, code, enable); + }) + $("#left").mouseup(function () { + var url = "../cameraSdk/PTZControlWithSpeed"; + var code = 4; + var enable = false; + commondMethod(url, code, enable); + }) + $("#right").mousedown(function () { + var url = "../cameraSdk/PTZControlWithSpeed"; + var code = 6; + var enable = true; + commondMethod(url, code, enable); + }) + $("#right").mouseup(function () { + var url = "../cameraSdk/PTZControlWithSpeed"; + var code = 6; + var enable = false; + commondMethod(url, code, enable); + }) + //鍙樺�� + $("#controlZoomIn").mousedown(function () { + var url = "../cameraSdk/PTZControlWithSpeed"; + var code = 10; + var enable = true; + commondMethod(url, code, enable); + }) + $("#controlZoomIn").mouseup(function () { + var url = "../cameraSdk/PTZControlWithSpeed"; + var code = 10; + var enable = false; + commondMethod(url, code, enable); + }) + $("#controlZoomOut").mousedown(function () { + var url = "../cameraSdk/PTZControlWithSpeed"; + var code = 11; + var enable = true; + commondMethod(url, code, enable); + }) + $("#controlZoomOut").mouseup(function () { + var url = "../cameraSdk/PTZControlWithSpeed"; + var code = 11; + var enable = false; + commondMethod(url, code, enable); + }) + //鍙樼劍 + $("#controlFocusNear").mousedown(function () { + var url = "../cameraSdk/PTZControlWithSpeed"; + var code = 12; + var enable = true; + commondMethod(url, code, enable); + }) + $("#controlFocusNear").mouseup(function () { + var url = "../cameraSdk/PTZControlWithSpeed"; + var code = 12; + var enable = false; + commondMethod(url, code, enable); + }) + $("#controlFocusFar").mousedown(function () { + var url = "../cameraSdk/PTZControlWithSpeed"; + var code = 13; + var enable = true; + commondMethod(url, code, enable); + }) + $("#controlFocusFar").mouseup(function () { + var url = "../cameraSdk/PTZControlWithSpeed"; + var code = 13; + var enable = false; + commondMethod(url, code, enable); + }) + //鍏夊湀 + $("#controlIrisOpen").mousedown(function () { + var url = "../cameraSdk/PTZControlWithSpeed"; + var code = 14; + var enable = true; + commondMethod(url, code, enable); + }) + $("#controlIrisOpen").mouseup(function () { + var url = "../cameraSdk/PTZControlWithSpeed"; + var code = 14; + var enable = false; + commondMethod(url, code, enable); + }) + $("#controlIrisClose").mousedown(function () { + var url = "../cameraSdk/PTZControlWithSpeed"; + var code = 15; + var enable = true; + commondMethod(url, code, enable); + }) + $("#controlIrisClose").mouseup(function () { + var url = "../cameraSdk/PTZControlWithSpeed"; + var code = 15; + var enable = false; + commondMethod(url, code, enable); + }) + + $("#setPreset").click(function () { + cameraId = $('#selectDev option:selected').val(); + chanNo = $('#selectChn option:selected').val(); + opt = {"cameraId": cameraId, "chanNo": chanNo, "speed": 8, "presetIndex": 1}; + $.ajax({ + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': token + }, + url: "../cameraSdk/setPreset", type: "post", dataType: "json", data: JSON.stringify(opt), @@ -309,15 +414,16 @@ }) }) $("#gotoPreset").click(function () { - cameraId = $('#select option:selected').val(); - opt = {"cameraId": cameraId, "channelNum": 1, "speed": 8, "presetIndex": 1}; + cameraId = $('#selectDev option:selected').val(); + chanNo = $('#selectChn option:selected').val(); + opt = {"cameraId": cameraId, "chanNo": chanNo, "speed": 8, "presetIndex": 1}; $.ajax({ headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', 'Authorization': token }, - url: "../hik/gotoPreset", + url: "../cameraSdk/gotoPreset", type: "post", dataType: "json", data: JSON.stringify(opt), @@ -327,15 +433,16 @@ }) }) $("#getPTZ").click(function () { - cameraId = $('#select option:selected').val(); - opt = {"cameraId": cameraId, "channelNum": 1}; + cameraId = $('#selectDev option:selected').val(); + chanNo = $('#selectChn option:selected').val(); + opt = {"cameraId": cameraId, "chanNo": chanNo}; $.ajax({ headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', 'Authorization': token }, - url: "../hik/getPTZ", + url: "../cameraSdk/getPTZ", type: "post", dataType: "json", data: JSON.stringify(opt), @@ -348,13 +455,14 @@ }) }) $("#setPTZ").click(function () { - cameraId = $('#select option:selected').val(); + cameraId = $('#selectDev option:selected').val(); + chanNo = $('#selectChn option:selected').val(); var p = $('#p').val(); var t = $('#t').val(); var z = $('#z').val(); //瀹氫箟涓�涓甫鏈塎ap瀛楁鐨勫疄浣撳璞� var myEntity = { - channelNum: 1, + chanNo: chanNo, cameraId: cameraId, ptzMap: { p: p, @@ -369,7 +477,37 @@ 'Content-Type': 'application/json', 'Authorization': token }, - url: "../hik/setPTZ", + url: "../cameraSdk/setPTZ", + type: "post", + dataType: "json", + data: JSON.stringify(myEntity), + success: function (data) { + console.log(data); + } + }) + }) + $("#setTargetPostion").click(function () { + cameraId = $('#selectDev option:selected').val(); + chanNo = $('#selectChn option:selected').val(); + var camera = cameraMap.get(cameraId); + var camP = camera.longitude + ',' + camera.latitude + ',' + camera.altitude; + var targetP = $('#targetPostion').val(); + var arr = targetP.split(","); + arr = arr.map(item => parseFloat(item)); + //瀹氫箟涓�涓甫鏈塎ap瀛楁鐨勫疄浣撳璞� + var myEntity = { + chanNo: chanNo, + cameraId: cameraId, + targetPosition: arr + }; + console.log(myEntity) + $.ajax({ + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': token + }, + url: "../cameraSdk/setTargetPosition", type: "post", dataType: "json", data: JSON.stringify(myEntity), @@ -379,15 +517,16 @@ }) }) $("#setZeroPTZ").click(function () { - cameraId = $('#select option:selected').val(); - opt = {"cameraId": cameraId, "channelNum": 1}; + cameraId = $('#selectDev option:selected').val(); + chanNo = $('#selectChn option:selected').val(); + opt = {"cameraId": cameraId, "chanNo": chanNo}; $.ajax({ headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', 'Authorization': token }, - url: "../hik/setZeroPTZ", + url: "../cameraSdk/setZeroPTZ", type: "post", dataType: "json", data: JSON.stringify(opt), @@ -397,15 +536,16 @@ }) }) $("#WiperPwron").click(function () { - cameraId = $('#select option:selected').val(); - opt = {"cameraId": cameraId, "channelNum": 1, "speed": 8, "enable": true, "code": 16}; + cameraId = $('#selectDev option:selected').val(); + chanNo = $('#selectChn option:selected').val(); + opt = {"cameraId": cameraId, "chanNo": chanNo, "speed": 8, "enable": true, "code": 16}; $.ajax({ headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', 'Authorization': token }, - url: "../hik/PTZControlWithSpeed", + url: "../cameraSdk/PTZControlWithSpeed", type: "post", dataType: "json", data: JSON.stringify(opt), @@ -416,9 +556,10 @@ }) var defogflag = true; $("#Defogcfg").click(function () { - cameraId = $('#select option:selected').val(); - optOpen = {"cameraId": cameraId, "channelNum": 1, "enable": true}; - optClose = {"cameraId": cameraId, "channelNum": 1, "enable": false}; + cameraId = $('#selectDev option:selected').val(); + chanNo = $('#selectChn option:selected').val(); + optOpen = {"cameraId": cameraId, "chanNo": chanNo, "enable": true}; + optClose = {"cameraId": cameraId, "chanNo": chanNo, "enable": false}; if (defogflag) { $(this).text("鍏抽棴閫忛浘"); defogflag = false; @@ -428,7 +569,7 @@ 'Content-Type': 'application/json', 'Authorization': token }, - url: "../hik/defogcfg", + url: "../cameraSdk/defogcfg", type: "post", dataType: "json", data: JSON.stringify(optOpen), @@ -445,7 +586,7 @@ 'Content-Type': 'application/json', 'Authorization': token }, - url: "../hik/defogcfg", + url: "../cameraSdk/defogcfg", type: "post", dataType: "json", data: JSON.stringify(optClose), @@ -458,9 +599,10 @@ }) var infrareflag = true; $("#Infrarecfg").click(function () { - cameraId = $('#select option:selected').val(); - optOpen = {"cameraId": cameraId, "channelNum": 1, "enable": true}; - optClose = {"cameraId": cameraId, "channelNum": 1, "enable": false}; + cameraId = $('#selectDev option:selected').val(); + chanNo = $('#selectChn option:selected').val(); + optOpen = {"cameraId": cameraId, "chanNo": chanNo, "enable": true}; + optClose = {"cameraId": cameraId, "chanNo": chanNo, "enable": false}; if (infrareflag) { $(this).text("鍏抽棴绾㈠"); infrareflag = false; @@ -470,7 +612,7 @@ 'Content-Type': 'application/json', 'Authorization': token }, - url: "../hik/infrarecfg", + url: "../cameraSdk/infrarecfg", type: "post", dataType: "json", data: JSON.stringify(optOpen), @@ -488,7 +630,7 @@ 'Content-Type': 'application/json', 'Authorization': token }, - url: "../hik/infrarecfg", + url: "../cameraSdk/infrarecfg", type: "post", dataType: "json", data: JSON.stringify(optClose), @@ -500,9 +642,10 @@ }) var focusModeflag = true; $("#FocusMode").click(function () { - cameraId = $('#select option:selected').val(); - optOpen = {"cameraId": cameraId, "channelNum": 1, "enable": true}; - optClose = {"cameraId": cameraId, "channelNum": 1, "enable": false}; + cameraId = $('#selectDev option:selected').val(); + chanNo = $('#selectChn option:selected').val(); + optOpen = {"cameraId": cameraId, "chanNo": chanNo, "enable": true}; + optClose = {"cameraId": cameraId, "chanNo": chanNo, "enable": false}; if (focusModeflag) { $(this).text("鑷姩鑱氱劍"); focusModeflag = false; @@ -512,7 +655,7 @@ 'Content-Type': 'application/json', 'Authorization': token }, - url: "../hik/focusMode", + url: "../cameraSdk/focusMode", type: "post", dataType: "json", data: JSON.stringify(optOpen), @@ -529,7 +672,7 @@ 'Content-Type': 'application/json', 'Authorization': token }, - url: "../hik/focusMode", + url: "../cameraSdk/focusMode", type: "post", dataType: "json", data: JSON.stringify(optClose), @@ -539,11 +682,32 @@ }) } }) + $("#getFocusPos").click(function () { + cameraId = $('#selectDev option:selected').val(); + chanNo = $('#selectChn option:selected').val(); + opt = {"cameraId": cameraId, "chanNo": chanNo}; + $.ajax({ + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': token + }, + url: "../cameraSdk/getFocusPos", + type: "post", + dataType: "json", + data: JSON.stringify(opt), + success: function (datas) { + console.log(datas); + $("#focus").val(datas.data); + } + }) + }) var heateRpwronflag = true; $("#HeateRpwron").click(function () { - cameraId = $('#select option:selected').val(); - optOpen = {"cameraId": cameraId, "channelNum": 1, "enable": true}; - optClose = {"cameraId": cameraId, "channelNum": 1, "enable": false}; + cameraId = $('#selectDev option:selected').val(); + chanNo = $('#selectChn option:selected').val(); + optOpen = {"cameraId": cameraId, "chanNo": chanNo, "enable": true}; + optClose = {"cameraId": cameraId, "chanNo": chanNo, "enable": false}; if (heateRpwronflag) { $(this).text("鍏抽棴浜戝彴鍔犵儹"); heateRpwronflag = false; @@ -553,7 +717,7 @@ 'Content-Type': 'application/json', 'Authorization': token }, - url: "../hik/heateRpwron", + url: "../cameraSdk/heateRpwron", type: "post", dataType: "json", data: JSON.stringify(optOpen), @@ -570,7 +734,7 @@ 'Content-Type': 'application/json', 'Authorization': token }, - url: "../hik/heateRpwron", + url: "../cameraSdk/heateRpwron", type: "post", dataType: "json", data: JSON.stringify(optClose), @@ -582,18 +746,20 @@ }) var CameraDeicingflag = true; $("#CameraDeicing").click(function () { - cameraId = $('#select option:selected').val(); - optOpen = {"cameraId": cameraId, "channelNum": 1, "enable": true}; - optClose = {"cameraId": cameraId, "channelNum": 1, "enable": false}; + cameraId = $('#selectDev option:selected').val(); + chanNo = $('#selectChn option:selected').val(); + optOpen = {"cameraId": cameraId, "chanNo": chanNo, "enable": true}; + optClose = {"cameraId": cameraId, "chanNo": chanNo, "enable": false}; if (CameraDeicingflag) { $(this).text("鍏抽棴闀滃ご鍔犵儹"); CameraDeicingflag = false; $.ajax({ headers: { 'Accept': 'application/json', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', + 'Authorization': token }, - url: "../hik/cameraDeicing", + url: "../cameraSdk/cameraDeicing", type: "post", dataType: "json", data: JSON.stringify(optOpen), @@ -610,7 +776,7 @@ 'Content-Type': 'application/json', 'Authorization': token }, - url: "../hik/cameraDeicing", + url: "../cameraSdk/cameraDeicing", type: "post", dataType: "json", data: JSON.stringify(optClose), @@ -621,48 +787,54 @@ } }) $("#realCutPic").click(function () { - cameraId = $('#select option:selected').val(); - opt = {"cameraId": cameraId, "channelNum": 1}; + cameraId = $('#selectDev option:selected').val(); + chanNo = $('#selectChn option:selected').val(); + opt = {"cameraId": cameraId, "chanNo": chanNo}; $.ajax({ headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', 'Authorization': token }, - url: "../hik/captureJPEGPicture", + url: "../cameraSdk/captureJPEGPicture", type: "post", dataType: "json", data: JSON.stringify(opt), success: function (data) { console.log(data.data); - $("#imgContainer").attr("src","data:image/png;base64,"+data.data); + $("#imgContainer").attr("src", "data:image/png;base64," + data.data); } }) }) $("#saveCutPic").click(function () { - cameraId = $('#select option:selected').val(); - opt = {"cameraId": cameraId, "channelNum": 1}; + cameraId = $('#selectDev option:selected').val(); + chanNo = $('#selectChn option:selected').val(); + opt = {"cameraId": cameraId, "chanNo": chanNo}; $.ajax({ headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', 'Authorization': token }, - url: "../hik/picCutCate", + url: "../cameraSdk/picCutCate", type: "post", dataType: "json", data: JSON.stringify(opt), success: function (data) { console.log(data.data); - $('#imgContainer').attr('src', data.data); + setTimeout(() => { + $('#imgContainer').attr('src', data.data); + }, 1000) + } }) }) var recordflag = true; $("#record").click(function () { - cameraId = $('#select option:selected').val(); - optOpen = {"cameraId": cameraId, "channelNum": 1, "enable": true}; - optClose = {"cameraId": cameraId, "channelNum": 1, "enable": false}; + cameraId = $('#selectDev option:selected').val(); + chanNo = $('#selectChn option:selected').val(); + optOpen = {"cameraId": cameraId, "chanNo": chanNo, "enable": true}; + optClose = {"cameraId": cameraId, "chanNo": chanNo, "enable": false}; if (recordflag) { $(this).text("鍋滄褰曞儚"); recordflag = false; @@ -672,7 +844,7 @@ 'Content-Type': 'application/json', 'Authorization': token }, - url: "../hik/record", + url: "../cameraSdk/record", type: "post", dataType: "json", data: JSON.stringify(optOpen), @@ -689,7 +861,7 @@ 'Content-Type': 'application/json', 'Authorization': token }, - url: "../hik/record", + url: "../cameraSdk/record", dataType: "json", data: JSON.stringify(optClose), type: "post", @@ -699,12 +871,14 @@ }) } }) + var cameraMap = new Map(); /*浜戝彴鍏叡鏂规硶*/ function commondMethod(url, code, enable) { - cameraId = $('#select option:selected').val(); - opt = {"cameraId": cameraId, "channelNum": 1, "speed": 8, "enable": enable, "code": code}; + cameraId = $('#selectDev option:selected').val(); + chanNo = $('#selectChn option:selected').val(); + opt = {"cameraId": cameraId, "chanNo": chanNo, "speed": 4, "enable": enable, "code": code}; $.ajax({ headers: { 'Accept': 'application/json', @@ -721,67 +895,509 @@ }) } - let webRtcServer = null; - let videoMap = new Map(); $('video').click(function (e) { - let ID = e.target.id;//鑾峰彇褰撳墠鐐瑰嚮浜嬩欢鐨勫厓绱� - console.log(ID); - if (videoMap.get(ID) != null) { - closeVideo(ID, videoMap.get(ID)); - } else { - var cameraId = $('#select option:selected').val(); - let camera = cameraMap.get(cameraId); - console.log(camera); - if (camera.type == "ys") { - realViewYs("127.0.0.1", ID, camera.username, camera.password, camera.ipaddr, camera.port); - } else if (camera.type == "dh") { - realViewDh("127.0.0.1", ID, camera.username, camera.password, camera.ipaddr, camera.port); - } else { - realViewHik("192.168.1.15", ID, camera.username, camera.password, camera.ipaddr, "21500"); + var cameraId = $('#selectDev option:selected').val(); + var chanNo = $('#selectChn option:selected').val(); + console.log(cameraId + " " + chanNo) + $.ajax({ + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': token + }, + url: "../vtdu/media/" + cameraId + "_" + chanNo, + type: "get", + dataType: "json", + success: function (data) { + realView(data.data.webrtcUrl + "/", e.target.id); } - } + }) }); + let webrtcClient; + //whep鎿嶄綔鏂规硶 + const retryPause = 2000; - //棰勮娴峰悍鐩告満 - function realViewHik(serverip, elem, username, password, ipaddr, port) { - webRtcServer = new WebRtcStreamer(elem, "http://" + serverip + ":8000"); - let rtspUrl = "rtsp://" + username + ":" + password + "@" + ipaddr + ":" + port + "/ch1/main/av_stream"; - let option = "rtptransport=tcp"; - console.log("rtsp鍦板潃锛�" + rtspUrl); - webRtcServer.connect(rtspUrl, null, option, null); - videoMap.set(elem, webRtcServer); - } + const video = document.getElementById('video'); + const message = document.getElementById('message'); - //棰勮澶у崕鐩告満 - function realViewDh(serverip, elem, username, password, ipaddr, port) { - webRtcServer = new WebRtcStreamer(elem, "http://" + serverip + ":8000"); - let rtspUrl = "rtsp://" + username + ":" + password + "@" + ipaddr + ":" + port + "/cam/realmonitor?channel=1&subtype=0"; - let option = "rtptransport=tcp"; - console.log("rtsp鍦板潃锛�" + rtspUrl); + let nonAdvertisedCodecs = []; + let pc = null; + let restartTimeout = null; + let sessionUrl = ''; + let offerData = ''; + let queuedCandidates = []; + let defaultControls = false; - webRtcServer.connect(rtspUrl, null, option, null); - videoMap.set(elem, webRtcServer); - } + const setMessage = (str) => { + if (str !== '') { + video.controls = false; + } else { + video.controls = defaultControls; + } + message.innerText = str; + }; - //棰勮瀹囪鐩告満 - function realViewYs(serverip, elem, username, password, ipaddr, port) { - webRtcServer = new WebRtcStreamer(elem, "http://" + serverip + ":8000"); - let rtspUrl = "rtsp://" + username + ":" + password + "@" + ipaddr + ":" + port + "/media/video1/multicast"; - console.log("rtsp鍦板潃锛�" + rtspUrl); - let option = "rtptransport=tcp"; - webRtcServer.connect(rtspUrl, null, option, null); - videoMap.set(elem, webRtcServer); - } + const unquoteCredential = (v) => ( + JSON.parse(`"${v}"`) + ); - function closeVideo(id, webrtc) { - webrtc.disconnect(); - videoMap.delete(id); - } + const linkToIceServers = (links) => ( + (links !== null) ? links.split(', ').map((link) => { + const m = link.match(/^<(.+?)>; rel="ice-server"(; username="(.*?)"; credential="(.*?)"; credential-type="password")?/i); + const ret = { + urls: [m[1]], + }; - //椤甸潰閫�鍑烘椂閿�姣� - window.onbeforeunload = function () { - webRtcServer.disconnect(); + if (m[3] !== undefined) { + ret.username = unquoteCredential(m[3]); + ret.credential = unquoteCredential(m[4]); + ret.credentialType = 'password'; + } + + return ret; + }) : [] + ); + + const parseOffer = (sdp) => { + const ret = { + iceUfrag: '', + icePwd: '', + medias: [], + }; + + for (const line of sdp.split('\r\n')) { + if (line.startsWith('m=')) { + ret.medias.push(line.slice('m='.length)); + } else if (ret.iceUfrag === '' && line.startsWith('a=ice-ufrag:')) { + ret.iceUfrag = line.slice('a=ice-ufrag:'.length); + } else if (ret.icePwd === '' && line.startsWith('a=ice-pwd:')) { + ret.icePwd = line.slice('a=ice-pwd:'.length); + } + } + + return ret; + }; + + const enableStereoPcmau = (section) => { + let lines = section.split('\r\n'); + + lines[0] += ' 118'; + lines.splice(lines.length - 1, 0, 'a=rtpmap:118 PCMU/8000/2'); + lines.splice(lines.length - 1, 0, 'a=rtcp-fb:118 transport-cc'); + + lines[0] += ' 119'; + lines.splice(lines.length - 1, 0, 'a=rtpmap:119 PCMA/8000/2'); + lines.splice(lines.length - 1, 0, 'a=rtcp-fb:119 transport-cc'); + + return lines.join('\r\n'); + }; + + const enableMultichannelOpus = (section) => { + let lines = section.split('\r\n'); + + lines[0] += " 112"; + lines.splice(lines.length - 1, 0, "a=rtpmap:112 multiopus/48000/3"); + lines.splice(lines.length - 1, 0, "a=fmtp:112 channel_mapping=0,2,1;num_streams=2;coupled_streams=1"); + lines.splice(lines.length - 1, 0, "a=rtcp-fb:112 transport-cc"); + + lines[0] += " 113"; + lines.splice(lines.length - 1, 0, "a=rtpmap:113 multiopus/48000/4"); + lines.splice(lines.length - 1, 0, "a=fmtp:113 channel_mapping=0,1,2,3;num_streams=2;coupled_streams=2"); + lines.splice(lines.length - 1, 0, "a=rtcp-fb:113 transport-cc"); + + lines[0] += " 114"; + lines.splice(lines.length - 1, 0, "a=rtpmap:114 multiopus/48000/5"); + lines.splice(lines.length - 1, 0, "a=fmtp:114 channel_mapping=0,4,1,2,3;num_streams=3;coupled_streams=2"); + lines.splice(lines.length - 1, 0, "a=rtcp-fb:114 transport-cc"); + + lines[0] += " 115"; + lines.splice(lines.length - 1, 0, "a=rtpmap:115 multiopus/48000/6"); + lines.splice(lines.length - 1, 0, "a=fmtp:115 channel_mapping=0,4,1,2,3,5;num_streams=4;coupled_streams=2"); + lines.splice(lines.length - 1, 0, "a=rtcp-fb:115 transport-cc"); + + lines[0] += " 116"; + lines.splice(lines.length - 1, 0, "a=rtpmap:116 multiopus/48000/7"); + lines.splice(lines.length - 1, 0, "a=fmtp:116 channel_mapping=0,4,1,2,3,5,6;num_streams=4;coupled_streams=4"); + lines.splice(lines.length - 1, 0, "a=rtcp-fb:116 transport-cc"); + + lines[0] += " 117"; + lines.splice(lines.length - 1, 0, "a=rtpmap:117 multiopus/48000/8"); + lines.splice(lines.length - 1, 0, "a=fmtp:117 channel_mapping=0,6,1,4,5,2,3,7;num_streams=5;coupled_streams=4"); + lines.splice(lines.length - 1, 0, "a=rtcp-fb:117 transport-cc"); + + return lines.join('\r\n'); + }; + + const enableL16 = (section) => { + let lines = section.split('\r\n'); + + lines[0] += " 120"; + lines.splice(lines.length - 1, 0, "a=rtpmap:120 L16/8000/2"); + lines.splice(lines.length - 1, 0, "a=rtcp-fb:120 transport-cc"); + + lines[0] += " 121"; + lines.splice(lines.length - 1, 0, "a=rtpmap:121 L16/16000/2"); + lines.splice(lines.length - 1, 0, "a=rtcp-fb:121 transport-cc"); + + lines[0] += " 122"; + lines.splice(lines.length - 1, 0, "a=rtpmap:122 L16/48000/2"); + lines.splice(lines.length - 1, 0, "a=rtcp-fb:122 transport-cc"); + + return lines.join('\r\n'); + }; + + const enableStereoOpus = (section) => { + let opusPayloadFormat = ''; + let lines = section.split('\r\n'); + + for (let i = 0; i < lines.length; i++) { + if (lines[i].startsWith('a=rtpmap:') && lines[i].toLowerCase().includes('opus/')) { + opusPayloadFormat = lines[i].slice('a=rtpmap:'.length).split(' ')[0]; + break; + } + } + + if (opusPayloadFormat === '') { + return section; + } + + for (let i = 0; i < lines.length; i++) { + if (lines[i].startsWith('a=fmtp:' + opusPayloadFormat + ' ')) { + if (!lines[i].includes('stereo')) { + lines[i] += ';stereo=1'; + } + if (!lines[i].includes('sprop-stereo')) { + lines[i] += ';sprop-stereo=1'; + } + } + } + + return lines.join('\r\n'); + }; + + const editOffer = (sdp) => { + const sections = sdp.split('m='); + + for (let i = 0; i < sections.length; i++) { + if (sections[i].startsWith('audio')) { + sections[i] = enableStereoOpus(sections[i]); + + if (nonAdvertisedCodecs.includes('pcma/8000/2')) { + sections[i] = enableStereoPcmau(sections[i]); + } + + if (nonAdvertisedCodecs.includes('multiopus/48000/6')) { + sections[i] = enableMultichannelOpus(sections[i]); + } + + if (nonAdvertisedCodecs.includes('L16/48000/2')) { + sections[i] = enableL16(sections[i]); + } + + break; + } + } + + return sections.join('m='); + }; + + const generateSdpFragment = (od, candidates) => { + const candidatesByMedia = {}; + for (const candidate of candidates) { + const mid = candidate.sdpMLineIndex; + if (candidatesByMedia[mid] === undefined) { + candidatesByMedia[mid] = []; + } + candidatesByMedia[mid].push(candidate); + } + + let frag = 'a=ice-ufrag:' + od.iceUfrag + '\r\n' + + 'a=ice-pwd:' + od.icePwd + '\r\n'; + + let mid = 0; + + for (const media of od.medias) { + if (candidatesByMedia[mid] !== undefined) { + frag += 'm=' + media + '\r\n' + + 'a=mid:' + mid + '\r\n'; + + for (const candidate of candidatesByMedia[mid]) { + frag += 'a=' + candidate.candidate + '\r\n'; + } + } + mid++; + } + + return frag; + }; + + const loadStream = () => { + requestICEServers(); + }; + + const supportsNonAdvertisedCodec = (codec, fmtp) => ( + new Promise((resolve, reject) => { + const pc = new RTCPeerConnection({ iceServers: [] }); + pc.addTransceiver('audio', { direction: 'recvonly' }); + pc.createOffer() + .then((offer) => { + if (offer.sdp.includes(' ' + codec)) { // codec is advertised, there's no need to add it manually + resolve(false); + return; + } + const sections = offer.sdp.split('m=audio'); + const lines = sections[1].split('\r\n'); + lines[0] += ' 118'; + lines.splice(lines.length - 1, 0, 'a=rtpmap:118 ' + codec); + if (fmtp !== undefined) { + lines.splice(lines.length - 1, 0, 'a=fmtp:118 ' + fmtp); + } + sections[1] = lines.join('\r\n'); + offer.sdp = sections.join('m=audio'); + return pc.setLocalDescription(offer); + }) + .then(() => { + return pc.setRemoteDescription(new RTCSessionDescription({ + type: 'answer', + sdp: 'v=0\r\n' + + 'o=- 6539324223450680508 0 IN IP4 0.0.0.0\r\n' + + 's=-\r\n' + + 't=0 0\r\n' + + 'a=fingerprint:sha-256 0D:9F:78:15:42:B5:4B:E6:E2:94:3E:5B:37:78:E1:4B:54:59:A3:36:3A:E5:05:EB:27:EE:8F:D2:2D:41:29:25\r\n' + + 'm=audio 9 UDP/TLS/RTP/SAVPF 118\r\n' + + 'c=IN IP4 0.0.0.0\r\n' + + 'a=ice-pwd:7c3bf4770007e7432ee4ea4d697db675\r\n' + + 'a=ice-ufrag:29e036dc\r\n' + + 'a=sendonly\r\n' + + 'a=rtcp-mux\r\n' + + 'a=rtpmap:118 ' + codec + '\r\n' + + ((fmtp !== undefined) ? 'a=fmtp:118 ' + fmtp + '\r\n' : ''), + })); + }) + .then(() => { + resolve(true); + }) + .catch((err) => { + resolve(false); + }) + .finally(() => { + pc.close(); + }); + }) + ); + + const getNonAdvertisedCodecs = () => { + Promise.all([ + ['pcma/8000/2'], + ['multiopus/48000/6', 'channel_mapping=0,4,1,2,3,5;num_streams=4;coupled_streams=2'], + ['L16/48000/2'] + ].map((c) => supportsNonAdvertisedCodec(c[0], c[1]).then((r) => (r) ? c[0] : false))) + .then((c) => c.filter((e) => e !== false)) + .then((codecs) => { + nonAdvertisedCodecs = codecs; + loadStream(); + }); + }; + + const onError = (err) => { + if (restartTimeout === null) { + setMessage(err + ', retrying in some seconds'); + + if (pc !== null) { + pc.close(); + pc = null; + } + + restartTimeout = window.setTimeout(() => { + restartTimeout = null; + loadStream(); + }, retryPause); + + if (sessionUrl) { + fetch(sessionUrl, { + method: 'DELETE', + }); + } + sessionUrl = ''; + + queuedCandidates = []; + } + }; + + const sendLocalCandidates = (candidates) => { + fetch(sessionUrl + window.location.search, { + method: 'PATCH', + headers: { + 'Content-Type': 'application/trickle-ice-sdpfrag', + 'If-Match': '*', + }, + body: generateSdpFragment(offerData, candidates), + }) + .then((res) => { + switch (res.status) { + case 204: + break; + case 404: + throw new Error('stream not found'); + default: + throw new Error(`bad status code ${res.status}`); + } + }) + .catch((err) => { + onError(err.toString()); + }); + }; + + const onLocalCandidate = (evt) => { + if (restartTimeout !== null) { + return; + } + + if (evt.candidate !== null) { + if (sessionUrl === '') { + queuedCandidates.push(evt.candidate); + } else { + sendLocalCandidates([evt.candidate]) + } + } + }; + + const onRemoteAnswer = (sdp) => { + if (restartTimeout !== null) { + return; + } + + pc.setRemoteDescription(new RTCSessionDescription({ + type: 'answer', + sdp, + })) + .then(() => { + if (queuedCandidates.length !== 0) { + sendLocalCandidates(queuedCandidates); + queuedCandidates = []; + } + }) + .catch((err) => { + onError(err.toString()); + }); + }; + + const sendOffer = (offer) => { + fetch(new URL('whep', window.location.href) + window.location.search, { + method: 'POST', + headers: { + 'Content-Type': 'application/sdp', + }, + body: offer.sdp, + }) + .then((res) => { + switch (res.status) { + case 201: + break; + case 404: + throw new Error('stream not found'); + case 400: + return res.json().then((e) => { throw new Error(e.error); }); + default: + throw new Error(`bad status code ${res.status}`); + } + + sessionUrl = new URL(res.headers.get('location'), window.location.href).toString(); + + return res.text() + .then((sdp) => onRemoteAnswer(sdp)); + }) + .catch((err) => { + onError(err.toString()); + }); + }; + + const createOffer = () => { + pc.createOffer() + .then((offer) => { + offer.sdp = editOffer(offer.sdp); + offerData = parseOffer(offer.sdp); + pc.setLocalDescription(offer) + .then(() => { + sendOffer(offer); + }) + .catch((err) => { + onError(err.toString()); + }); + }) + .catch((err) => { + onError(err.toString()); + }); + }; + + const onConnectionState = () => { + if (restartTimeout !== null) { + return; + } + + if (pc.iceConnectionState === 'disconnected') { + onError('peer connection closed'); + } + }; + + const onTrack = (evt) => { + setMessage(''); + video.srcObject = evt.streams[0]; + }; + + const requestICEServers = () => { + fetch(new URL('whep', window.location.href) + window.location.search, { + method: 'OPTIONS', + }) + .then((res) => { + pc = new RTCPeerConnection({ + iceServers: linkToIceServers(res.headers.get('Link')), + // https://webrtc.org/getting-started/unified-plan-transition-guide + sdpSemantics: 'unified-plan', + }); + + const direction = 'sendrecv'; + pc.addTransceiver('video', { direction }); + pc.addTransceiver('audio', { direction }); + + pc.onicecandidate = (evt) => onLocalCandidate(evt); + pc.oniceconnectionstatechange = () => onConnectionState(); + pc.ontrack = (evt) => onTrack(evt); + + createOffer(); + }) + .catch((err) => { + onError(err.toString()); + }); + }; + + const parseBoolString = (str, defaultVal) => { + str = (str || ''); + + if (['1', 'yes', 'true'].includes(str.toLowerCase())) { + return true; + } + if (['0', 'no', 'false'].includes(str.toLowerCase())) { + return false; + } + return defaultVal; + }; + + const loadAttributesFromQuery = () => { + const params = new URLSearchParams(window.location.search); + video.controls = parseBoolString(params.get('controls'), true); + video.muted = parseBoolString(params.get('muted'), true); + video.autoplay = parseBoolString(params.get('autoplay'), true); + video.playsInline = parseBoolString(params.get('playsinline'), true); + defaultControls = video.controls; + }; + + + function realView(whepUrl, videoId) { + console.log(whepUrl) + webrtcClient = new WHEPClient(whepUrl, videoId); } </script> -</html> \ No newline at end of file +</body> +</html> -- Gitblit v1.9.3