228 lines
8.7 KiB
HTML
228 lines
8.7 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<!--
|
|
SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
|
|
SPDX-License-Identifier: MIT
|
|
-->
|
|
|
|
<head>
|
|
<meta charset="utf-8">
|
|
</head>
|
|
|
|
<body>
|
|
<h3> Local Video </h3>
|
|
<video id="localVideo" width="160" height="120" autoplay muted></video>
|
|
<br />
|
|
|
|
<h3> Remote Video </h3>
|
|
<div id="remoteVideos"></div>
|
|
<br />
|
|
|
|
<h3> Logs </h3>
|
|
<div id="logs"></div>
|
|
<button onclick="call()">呼叫</button>
|
|
|
|
</body>
|
|
|
|
<script>
|
|
let ws, pc, configuration,
|
|
url =
|
|
'https://rw.quwanya.cn/v1/public/webRtcConfig?service=turn&username=flutter-webrtc',
|
|
formId = "admin",
|
|
toId = "01J9T8MP541EJ54KY4505C0S4Y";
|
|
fetch(url)
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
let res = data.data.credential;
|
|
configuration = {
|
|
iceServers: [
|
|
{
|
|
urls: res.uris[0],
|
|
"username": res.username,
|
|
"credential": res.password
|
|
},
|
|
]
|
|
}
|
|
})
|
|
const call = () => {
|
|
navigator.mediaDevices.getUserMedia({ video: true, audio: true })
|
|
.then(stream => {
|
|
pc = new RTCPeerConnection(configuration)
|
|
pc.ontrack = function (event) {
|
|
console.log(event)
|
|
if (event.track.kind === 'audio') {
|
|
return
|
|
}
|
|
let el = document.createElement(event.track.kind)
|
|
el.srcObject = event.streams[0]
|
|
el.autoplay = true
|
|
el.controls = true
|
|
document.getElementById('remoteVideos').appendChild(el)
|
|
event.track.onmute = function (event) {
|
|
el.play()
|
|
}
|
|
event.streams[0].onremovetrack = ({ track }) => {
|
|
if (el.parentNode) {
|
|
el.parentNode.removeChild(el)
|
|
}
|
|
}
|
|
}
|
|
document.getElementById('localVideo').srcObject = stream
|
|
stream.getTracks().forEach(track => pc.addTrack(track, stream))
|
|
pc.onicecandidate = e => {
|
|
if (!e.candidate) {
|
|
return
|
|
}
|
|
ws.send(JSON.stringify({
|
|
type: "candidate", data: {
|
|
"to": toId,
|
|
"from": formId,
|
|
"description": e.candidate,
|
|
"media": "video",
|
|
"session_id": toId + "-" + formId,
|
|
}
|
|
}))
|
|
}
|
|
this.send({
|
|
type: "call",
|
|
"data": {
|
|
"to": toId,
|
|
"from": formId,
|
|
"description": "call",
|
|
"media": "video",
|
|
"session_id": toId + "-" + formId,
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
send = (data) => {
|
|
ws.send(JSON.stringify(data))
|
|
}
|
|
|
|
// wss://rw.quwanya.cn/ws
|
|
initSocket = () => {
|
|
ws = new WebSocket("wss://rw.quwanya.cn/wsadmin?id=" + formId)
|
|
ws.addEventListener('open', function (event) {
|
|
ws.send(JSON.stringify({
|
|
type: "peerRoot", "data": {
|
|
"name": "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36 )",
|
|
"id": formId,
|
|
"user_agent": "flutter-webrtc/js"
|
|
}
|
|
}))
|
|
});
|
|
ws.onclose = function (evt) {
|
|
console.log(evt);
|
|
}
|
|
ws.onmessage = function (evt) {
|
|
let msg = JSON.parse(evt.data)
|
|
if (!msg) {
|
|
return console.log('failed to parse msg')
|
|
}
|
|
switch (msg.type) {
|
|
case 'offer':
|
|
let offer = msg.content.body.description
|
|
pc.setRemoteDescription(offer)
|
|
pc.createAnswer().then(answer => {
|
|
pc.setLocalDescription(answer)
|
|
ws.send(JSON.stringify({
|
|
type: 'answer', data: {
|
|
'to': msg.content.body.from,
|
|
'from': formId,
|
|
'description': { 'sdp': answer.sdp, 'type': answer.type },
|
|
'session_id': msg.content.body.from + "-" + toId,
|
|
}
|
|
}))
|
|
})
|
|
return
|
|
case 'candidate':
|
|
let candidate = msg.content.body.description
|
|
console.log("candidate1111", msg.content)
|
|
if (!candidate) {
|
|
return console.log('failed to parse candidate')
|
|
}
|
|
pc.addIceCandidate(candidate)
|
|
return
|
|
case "read":
|
|
pc?.createOffer().then(function (offer) {
|
|
pc?.setLocalDescription(offer);
|
|
ws.send(JSON.stringify({
|
|
type: "offer", "data": {
|
|
"to": toId,//"31283192",
|
|
"from": formId,
|
|
"description": offer,
|
|
"media": "video",
|
|
"session_id": formId + "-" + toId,
|
|
}
|
|
}),)
|
|
}).catch(function (error) {
|
|
// 错误处理
|
|
console.error(error);
|
|
});
|
|
return
|
|
case "call": // 接收到call 初始化 然后发送消息 read
|
|
navigator.mediaDevices.getUserMedia({ video: true, audio: true })
|
|
.then(stream => {
|
|
pc = new RTCPeerConnection(configuration)
|
|
pc.ontrack = function (event) {
|
|
if (event.track.kind === 'audio') {
|
|
return
|
|
}
|
|
let el = document.createElement(event.track.kind)
|
|
el.srcObject = event.streams[0]
|
|
el.autoplay = true
|
|
el.controls = true
|
|
document.getElementById('remoteVideos').appendChild(el)
|
|
event.track.onmute = function (event) {
|
|
el.play()
|
|
}
|
|
event.streams[0].onremovetrack = ({ track }) => {
|
|
if (el.parentNode) {
|
|
el.parentNode.removeChild(el)
|
|
}
|
|
}
|
|
}
|
|
document.getElementById('localVideo').srcObject = stream
|
|
stream.getTracks().forEach(track => pc.addTrack(track, stream))
|
|
pc.onicecandidate = e => {
|
|
if (!e.candidate) {
|
|
return
|
|
}
|
|
ws.send(JSON.stringify({
|
|
type: 'candidate',
|
|
data: {
|
|
"to": toId,
|
|
"from": formId,
|
|
"description": e,
|
|
"media": "video",
|
|
"session_id": toId + "-" + formId,
|
|
}
|
|
}))
|
|
}
|
|
ws.send(JSON.stringify({
|
|
type: "read", "data": {
|
|
"to": toId,
|
|
"from": formId,
|
|
"description": "read",
|
|
"media": "video",
|
|
"session_id": toId + "-" + formId,
|
|
}
|
|
}))
|
|
|
|
})
|
|
return
|
|
case "answer":
|
|
pc?.setRemoteDescription(msg.content.body.description)
|
|
}
|
|
}
|
|
|
|
ws.onerror = function (evt) {
|
|
console.log("ERROR: " + evt.data)
|
|
}
|
|
}
|
|
initSocket()
|
|
|
|
</script>
|
|
|
|
</html> |