fix(amap):集成webrtc 到自有代码

This commit is contained in:
wang_yp 2024-11-14 22:31:30 +08:00
parent 210df9fa06
commit 32c9bd2381
12 changed files with 301 additions and 145 deletions

View File

@ -81,7 +81,7 @@ export const items = [
{ label: `部门管理`, key: "/admin/dep" }, { label: `部门管理`, key: "/admin/dep" },
{ label: "系统设置", key: "/admin/sys/setting" }, { label: "系统设置", key: "/admin/sys/setting" },
{ label: "光荣牌审核", key: "/admin/sys/gp" }, { label: "光荣牌审核", key: "/admin/sys/gp" },
{ label: "评优审核", key: "/admin/sys/gp" }, { label: "评优审核", key: "/admin/sys/exce_compet" },
], ],
}, },
]; ];

View File

@ -10,6 +10,7 @@ class MapUtl {
static addMaker(data: any) { static addMaker(data: any) {
const { lng, lat, title, users } = data; const { lng, lat, title, users } = data;
if (MapUtl.loadMap === null) return;
const marker = new MapUtl.loadMap.Marker({ const marker = new MapUtl.loadMap.Marker({
position: new MapUtl.loadMap.LngLat(lng, lat), position: new MapUtl.loadMap.LngLat(lng, lat),
title: title, title: title,

View File

@ -0,0 +1,53 @@
import BTable from "@/components/b_table";
import { UserDataType } from "@/model/userModel";
import { Button } from "antd";
import { Store } from "antd/es/form/interface";
import { ColumnsType } from "antd/lib/table";
import { inject, observer } from "mobx-react";
import { useEffect } from "react";
const ExceCompet = (props: Store) => {
const { exceCompetStore } = props;
useEffect(() => {
exceCompetStore.getlist();
}, [exceCompetStore]);
const columns: ColumnsType<UserDataType> = [
{ title: "评优标题", dataIndex: "title" },
{ title: "内容", dataIndex: "content" },
{
title: "评优申请人",
dataIndex: "users",
render: (users) => <span>{users?.user_name}</span>
},
{ title: "申请积分", dataIndex: "reviewer_score" },
{ title: "申请时间", dataIndex: "created_at" },
{ title: "描述", dataIndex: "desc" },
{ title: "审核状态", dataIndex: "status" },
{ title: "审核人", dataIndex: "reviewer_identity" },
{
title: "操作",
dataIndex: "id",
render: (any, record) => (
<Button
type="dashed"
size="small"
onClick={() => {
// edit(record);
}}
>
</Button>
),
},
];
return (
<div>
<BTable
store={exceCompetStore}
columns={columns}
dataSource={exceCompetStore.list}
/>
</div>
);
};
export default inject("exceCompetStore")(observer(ExceCompet));

View File

@ -48,7 +48,7 @@ const Home = observer(() => {
</div> </div>
<MapContainer /> <MapContainer />
<div className="map_video_container"> <div className="map_video_container">
<Video /> {/* <Video /> */}
</div> </div>
<div className="map_container_r"> <div className="map_container_r">
<HomeRight /> <HomeRight />

View File

@ -20,9 +20,7 @@ const Ec = (props: Store) => {
console.log(error); console.log(error);
} }
}; };
const callphone = (record: any) => {
webRTC.calls(record.value);
};
const [value, setValue] = useState<UserValue[]>([]); const [value, setValue] = useState<UserValue[]>([]);
async function fetchUserList(username: string): Promise<UserValue[]> { async function fetchUserList(username: string): Promise<UserValue[]> {
return usrStore.serchUser(username).then((res) => { return usrStore.serchUser(username).then((res) => {
@ -73,8 +71,8 @@ const Ec = (props: Store) => {
<PhoneTwoTone <PhoneTwoTone
style={{ fontSize: "20px" }} style={{ fontSize: "20px" }}
onClick={(items) => { onClick={(items) => {
webRTC.init(); webRTC.init(item.key);
callphone(item); webRTC.calls();
}} }}
/> />
</div> </div>

View File

@ -10,7 +10,7 @@ const videoJsOptions = {
fluid: true, fluid: true,
sources: [ sources: [
{ {
src: "http://183.221.86.205:18000/hls/stream_1_0/playlist.m3u8", src: "https://sprh.hswzct.cn:4443/hls/stream_1_0/playlist.m3u8",
type: "application/x-mpegURL", type: "application/x-mpegURL",
}, },
], ],

View File

@ -26,6 +26,7 @@ import GloryPlaque from "@/pages/glory_plaque";
import Grid from "@/pages/grid"; import Grid from "@/pages/grid";
import Community from "@/pages/community"; import Community from "@/pages/community";
import PatrolBrigade from "@/pages/patrolBrigade"; import PatrolBrigade from "@/pages/patrolBrigade";
import ExceCompet from "@/pages/exce_compet";
export const homeRouter = [ export const homeRouter = [
{ {
path: "/", path: "/",
@ -148,6 +149,7 @@ export const homeRouter = [
index: true, index: true,
element: <Training />, element: <Training />,
}, },
{ {
path: "/admin/whse", path: "/admin/whse",
element: <WhseMgmtRoute />, element: <WhseMgmtRoute />,
@ -178,6 +180,11 @@ export const homeRouter = [
index: true, index: true,
element: <GloryPlaque />, element: <GloryPlaque />,
}, },
{
path: "/admin/sys/exce_compet",
index: true,
element: <ExceCompet />,
},
], ],
}, },
], ],

26
src/store/exce_compet.ts Normal file
View File

@ -0,0 +1,26 @@
import { action, makeObservable } from "mobx";
// 档案
import BaseStore from "./baseStore";
import { TagDataType } from "@/model/userModel";
import baseHttp from "@/service/base";
class ExceCompetConfig {
static LIST: string = "exceCompet/list"
static ADD: string = "exceCompet"
static DELETE: string = "exceCompet"
static EDIT: string = "exceCompet"
}
class ExceCompetStore extends BaseStore<TagDataType> {
constructor() {
super(ExceCompetConfig)
makeObservable(this, {
save: action
})
}
async save(id: string, list: Array<any>) {
return await baseHttp.post(ExceCompetConfig.ADD +"/"+ id, {"list":list});
}
}
export const exceCompetStore = new ExceCompetStore()

View File

@ -25,6 +25,7 @@ import gpStore from './gp';
import { communityStore } from './community'; import { communityStore } from './community';
import { gridStore } from './grid'; import { gridStore } from './grid';
import { patrolBrigadeStore } from './patrol_brigade'; import { patrolBrigadeStore } from './patrol_brigade';
import { exceCompetStore } from './exce_compet';
@ -55,7 +56,8 @@ const store = {
gpStore, gpStore,
gridStore, gridStore,
communityStore, communityStore,
patrolBrigadeStore patrolBrigadeStore,
exceCompetStore
}; };
export default store; export default store;

View File

@ -25,11 +25,11 @@
</body> </body>
<script> <script>
let ws; let ws, pc, configuration,
let pc; url =
let configuration; 'https://rw.quwanya.cn/v1/public/webRtcConfig?service=turn&username=flutter-webrtc',
var url = formId = "admin",
'http://127.0.0.1:12214/v1/public/webRtcConfig?service=turn&username=flutter-webrtc'; toId = "01J9T8MP541EJ54KY4505C0S4Y";
fetch(url) fetch(url)
.then(response => response.json()) .then(response => response.json())
.then(data => { .then(data => {
@ -45,6 +45,123 @@
} }
}) })
const call = () => { 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 }) navigator.mediaDevices.getUserMedia({ video: true, audio: true })
.then(stream => { .then(stream => {
pc = new RTCPeerConnection(configuration) pc = new RTCPeerConnection(configuration)
@ -72,76 +189,31 @@
if (!e.candidate) { if (!e.candidate) {
return return
} }
ws.send(JSON.stringify({ type: 'candidate', data: e }))
}
pc?.createOffer().then(function (offer) {
pc?.setLocalDescription(offer);
ws.send(JSON.stringify({ ws.send(JSON.stringify({
type: "offer", "data": { type: 'candidate',
"to": "31283192", data: {
"from": "31283191", "to": toId,
"description": offer, "from": formId,
"description": e,
"media": "video", "media": "video",
"session_id": "31283192-31283191", "session_id": toId + "-" + formId,
} }
})) }))
// socketService.send({ type: 'offer', data: offer })
}).catch(function (error) {
// 错误处理
console.error(error);
});
}).catch((e) => {
console.log(e);
})
} }
// wss://rw.quwanya.cn/ws
initSocket = () => {
ws = new WebSocket("ws://127.0.0.1:12214/wsadmin?id=31283192")
ws.addEventListener('open', function (event) {
ws.send(JSON.stringify({ ws.send(JSON.stringify({
type: "peerRoot", "data": { type: "read", "data": {
"name": "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36 )", "to": toId,
"id": "31283192", "from": formId,
"user_agent": "flutter-webrtc/js" "description": "read",
"media": "video",
"session_id": toId + "-" + formId,
} }
})) }))
});
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')
}
console.log(msg);
switch (msg.type) {
case 'offer':
let offer = msg.data.description
pc.setRemoteDescription(offer)
pc.createAnswer().then(answer => {
pc.setLocalDescription(answer)
ws.send(JSON.stringify({
type: 'answer', data: {
'to': msg.data.from,
'from': "31283192",
'description': { 'sdp': answer.sdp, 'type': answer.type },
'session_id': msg.data.from + "-31283192",
}
}))
}) })
return return
case 'candidate':
let candidate = msg.content.body
if (!candidate) {
return console.log('failed to parse candidate')
}
pc.addIceCandidate(candidate)
case "answer": case "answer":
pc?.setRemoteDescription(msg.data.description) pc?.setRemoteDescription(msg.content.body.description)
} }
} }
@ -150,6 +222,7 @@
} }
} }
initSocket() initSocket()
</script> </script>
</html> </html>

View File

@ -61,7 +61,7 @@ export type AutoReconnectOptions = boolean | {
} }
} }
public hert(){ public hert(){
this.times = setInterval(() => this.send({"type":"heartbeat"}), 3000) this.times = setInterval(() => this.send({"type":"heartbeat","data":{}}), 10000)
} }
private shouldReconnect(): boolean { private shouldReconnect(): boolean {
if (typeof this.autoReconnect === 'boolean') { if (typeof this.autoReconnect === 'boolean') {

View File

@ -1,5 +1,6 @@
import SocketService from "./socket"; import SocketService from "./socket";
import baseHttp from "@/service/base";
class WebRtc { class WebRtc {
private mediaStream: MediaStream | Blob | null = null; private mediaStream: MediaStream | Blob | null = null;
@ -7,167 +8,162 @@ class WebRtc {
private ws: SocketService | null = null; private ws: SocketService | null = null;
private video: HTMLVideoElement | null = null; private video: HTMLVideoElement | null = null;
private userToId: string = ""; private userToId: string = "";
open = () => { async init(userId) {
this.ws?.send(JSON.stringify({ this.userToId = userId
type: "new", "data": {
"name": "admin",
"id": "31283192",
"user_agent": "flutter-webrtc/js"
}
}))
}
async init() {
this.ws = SocketService.getInstance(); this.ws = SocketService.getInstance();
this.ws.on("message", this.onMessage); this.ws.on("message", this.onMessage);
this.createOffer()
} }
onMessage = (e: any) => { onMessage = (e: any) => {
let that = this; let msg = JSON.parse(e)
let msg = JSON.parse(e.data)
if (!msg) { if (!msg) {
return console.log('failed to parse msg') return console.log('failed to parse msg')
} }
switch (msg.type) { switch (msg.type) {
case 'offer': case 'offer':
let offer = msg.data.description let offer = msg.content.body.description;
that.pee?.setRemoteDescription(offer) this.pee?.setRemoteDescription(offer)
that.pee?.createAnswer().then(answer => { this.pee?.createAnswer().then(answer => {
that.pee?.setLocalDescription(answer) this.pee?.setLocalDescription(answer)
that.ws?.send(JSON.stringify({ this.ws?.send({
type: 'answer', data: { type: 'answer',
'to': msg.data.from, data: {
'from': "31283192", to: msg.content.body.from,
'description': { 'sdp': answer.sdp, 'type': answer.type }, from: "admin",
'session_id': msg.data.from + "-31283192", description: { 'sdp': answer.sdp, 'type': answer.type },
session_id: msg.content.body.from + "-admin",
} }
}))
}) })
return })
break;
case "read":
this.sendOffer()
break;
case 'candidate': case 'candidate':
let candidate = msg.data.candidate let candidate = msg.content.body.description
if (!candidate) { if (!candidate) {
return console.log('failed to parse candidate') return console.log('failed to parse candidate')
} }
that.pee?.addIceCandidate(candidate) this.pee?.addIceCandidate(candidate)
break; break;
case "answer": case "answer":
that.pee?.setRemoteDescription(msg.data.description) this.pee?.setRemoteDescription(msg.content.body.description)
break; break;
case "bye": case "bye":
that.pee?.close() this.close()
that.close()
break; break;
} }
} }
async createOffer() { async createOffer() {
var url = let basData =await baseHttp.get('/public/webRtcConfig', { service: "11", username: "admin" })
'http://rw.quwanya.cn:12217/api/turn?service=turn&username=flutter-webrtc';
fetch(url)
.then(response => response.json())
.then(data => {
const configuration = { const configuration = {
iceServers: [ iceServers: [
{ {
urls: data.uris[0], urls: basData.data.credential.uris,
"username": data.username, username: basData.data.credential.username,
"credential": data.password credential: basData.data.credential.password,
ttl:basData.data.credential.ttl
}, },
] ]
} }
this.gets(configuration) this.gets(configuration)
})
try {
} catch (error) {
console.log(error);
}
} }
async gets(configuration) { async gets(configuration) {
console.log(configuration); this.pee = new RTCPeerConnection(configuration);
const peerConnection = new RTCPeerConnection(configuration);
this.pee = peerConnection
// 获取远方流添加到页面播放 // 获取远方流添加到页面播放
peerConnection.ontrack = event => { this.pee.ontrack = event => {
const remoteVideo = document.querySelector('#remoteVideo') as HTMLVideoElement; const re = document.querySelector('#remoteVideo') as HTMLVideoElement;
remoteVideo.autoplay = true re.autoplay = true
remoteVideo.controls = true re.controls = true
remoteVideo.srcObject = event.streams[0]; console.log(event.streams[0])
console.log(event); re.srcObject = event.streams[0];
event.track.onmute = function (event) {
event.track.onmute = function () { re.play()
remoteVideo.play() }
event.streams[0].onremovetrack = ({ track }) => {
if (re.parentNode) {
re.parentNode.removeChild(re)
}
} }
}; };
await this.getMedia(peerConnection) this.pee.onicecandidate = e => {
peerConnection.onicecandidate = e => {
if (!e.candidate) { if (!e.candidate) {
return return
} }
this.ws?.send(JSON.stringify({ type: 'candidate', data: e })) this.ws?.send({
type: "candidate", data: {
to: this.userToId,
from: "admin",
description: e.candidate,
media: "video",
session_id: this.userToId + "-admin",
} }
})
} }
sendOffer(userId) { this.ws?.send({
type: "call",
data: {
to: this.userToId,
from: "admin",
description: "call",
media: "video",
session_id: this.userToId + "-admin",
}
})
}
sendOffer() {
let that = this; let that = this;
that.userToId = userId;
that.video = document.getElementById('rtcVideo') as HTMLVideoElement;
if (that.pee?.connectionState === "closed") {
that.createOffer()
}
that.pee?.createOffer().then(function (offer) { that.pee?.createOffer().then(function (offer) {
that.pee?.setLocalDescription(offer); that.pee?.setLocalDescription(offer);
that.ws?.send(JSON.stringify({ that.ws?.send({
type: "offer", "data": { type: "offer",
"to": userId, data: {
"from": "31283192", to: that.userToId,
"description": offer, from: "admin",
"media": "video", description: offer,
"session_id": userId + "-31283192", media: "video",
session_id: that.userToId + "-admin",
} }
})) })
}).catch(function (error) { }).catch(function (error) {
// 错误处理 // 错误处理
console.error(error); console.error(error);
}); });
} }
addIceCandidate(candidate) { async getMedia() {
this.pee?.addIceCandidate(candidate)
}
async getMedia(pee: RTCPeerConnection) {
try { try {
this.video = document.getElementById('rtcVideo') as HTMLVideoElement;
const stream = await navigator.mediaDevices.getUserMedia({ const stream = await navigator.mediaDevices.getUserMedia({
video: true, video: true,
audio: true audio: true
}); });
this.mediaStream = stream; this.mediaStream = stream;
stream.getTracks().forEach(track => pee.addTrack(track, stream)) stream.getTracks().forEach(track => this.pee?.addTrack(track, stream))
} catch (error) {
console.log(error);
}
}
calls(userId) {
this.sendOffer(userId)
if (this.video) { if (this.video) {
this.video.srcObject = this.mediaStream; this.video.srcObject = this.mediaStream;
this.video.autoplay = true; this.video.autoplay = true;
} }
} catch (error) {
console.log(error);
}
}
async calls() {
await this.createOffer()
await this.getMedia()
} }
close() { close() {
this.video?.pause(); this.video?.pause();
this.pee?.close(); this.pee?.close();
this.ws?.send(JSON.stringify({ // this.ws?.send({
"type": "bye", "data": { // type: "bye",
"session_id": this.userToId + "31283192", // data: {
"to": this.userToId // session_id: this.userToId + "admin",
} // to: this.userToId,
} // from: "admin"
)); // }
// });
(this.mediaStream as MediaStream)?.getTracks().forEach(track => track.stop()); (this.mediaStream as MediaStream)?.getTracks().forEach(track => track.stop());
this.ws?.close()
} }
} }