Files
Relay/RelayClient/Resources/Raw/wwwroot/index.html

198 lines
6.9 KiB
HTML

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title></title>
<link rel="icon" href="data:,">
<link rel="stylesheet" href="styles/app.css">
<link rel="stylesheet" href="index.css">
<script src="_framework/hybridwebview.js"></script>
<script>
let peerConnection = null;
let localStream = null;
let currentTarget = null;
let currentUsername = null;
function LogMessage(msg) {
const messageLog = document.getElementById("messageLog");
messageLog.value += '\r\n' + msg;
}
async function ensurePeerConnection() {
if (peerConnection) return;
peerConnection = new RTCPeerConnection({
iceServers: [{ urls: "stun:stun.l.google.com:19302" }]
});
peerConnection.onicecandidate = async (event) => {
if (!event.candidate || !currentTarget || !currentUsername) return;
const payload = {
type: "rtc_ice_candidate",
from: currentUsername,
to: currentTarget,
candidate: event.candidate.candidate,
sdpMid: event.candidate.sdpMid,
sdpMLineIndex: event.candidate.sdpMLineIndex
};
LogMessage("Sending ICE candidate");
await window.HybridWebView.InvokeDotNet("SendRtcSignal", [JSON.stringify(payload)]);
};
peerConnection.ontrack = (event) => {
LogMessage("Remote track received");
const remoteVideo = document.getElementById("remoteVideo");
remoteVideo.srcObject = event.streams[0];
};
peerConnection.onconnectionstatechange = () => {
LogMessage("Connection state: " + peerConnection.connectionState);
};
peerConnection.oniceconnectionstatechange = () => {
LogMessage("ICE connection state: " + peerConnection.iceConnectionState);
};
peerConnection.onicegatheringstatechange = () => {
LogMessage("ICE gathering state: " + peerConnection.iceGatheringState);
};
}
async function ensureLocalMedia() {
if (localStream) return;
try {
localStream = await navigator.mediaDevices.getUserMedia({
video: true,
audio: true
});
const localVideo = document.getElementById("localVideo");
localVideo.srcObject = localStream;
for (const track of localStream.getTracks()) {
peerConnection.addTrack(track, localStream);
}
LogMessage("Local media initialized");
} catch (err) {
LogMessage("getUserMedia failed: " + err);
throw err;
}
}
async function startCall() {
try {
currentTarget = document.getElementById("targetUser").value;
if (!currentTarget) {
LogMessage("No target user set.");
return;
}
await ensurePeerConnection();
await ensureLocalMedia();
const offer = await peerConnection.createOffer();
await peerConnection.setLocalDescription(offer);
const payload = {
type: "rtc_offer",
from: currentUsername,
to: currentTarget,
sdp: offer.sdp
};
LogMessage("Sending offer to " + currentTarget);
await window.HybridWebView.InvokeDotNet("SendRtcSignal", [JSON.stringify(payload)]);
} catch (err) {
LogMessage("startCall failed: " + err);
}
}
async function handleRtcSignal(rawJson) {
try {
const msg = typeof rawJson === "string" ? JSON.parse(rawJson) : rawJson;
LogMessage("Received signal: " + msg.type + " from " + msg.from);
await ensurePeerConnection();
if (msg.type === "rtc_offer") {
currentTarget = msg.from;
LogMessage("Incoming call from " + msg.from);
await ensureLocalMedia();
await peerConnection.setRemoteDescription({
type: "offer",
sdp: msg.sdp
});
const answer = await peerConnection.createAnswer();
await peerConnection.setLocalDescription(answer);
const payload = {
type: "rtc_answer",
from: currentUsername,
to: msg.from,
sdp: answer.sdp
};
LogMessage("Sending answer to " + msg.from);
await window.HybridWebView.InvokeDotNet("SendRtcSignal", [JSON.stringify(payload)]);
return;
}
if (msg.type === "rtc_answer") {
await peerConnection.setRemoteDescription({
type: "answer",
sdp: msg.sdp
});
LogMessage("Remote answer applied");
return;
}
if (msg.type === "rtc_ice_candidate") {
await peerConnection.addIceCandidate({
candidate: msg.candidate,
sdpMid: msg.sdpMid,
sdpMLineIndex: msg.sdpMLineIndex
});
LogMessage("Remote ICE candidate applied");
}
} catch (err) {
LogMessage("handleRtcSignal failed: " + err);
}
}
window.handleRtcSignal = handleRtcSignal;
window.addEventListener("HybridWebViewMessageReceived", function (e) {
LogMessage("Raw message: " + e.detail.message);
});
</script>
</head>
<body>
<div>
<h3>Relay RTC Test</h3>
</div>
<div>
<label for="targetUser">Target User:</label>
<input id="targetUser" type="text" value="Ru_Kira" />
<button onclick="startCall()">Start Call</button>
</div>
<div style="margin-top: 10px;">
<video id="localVideo" autoplay playsinline muted style="width: 320px; height: 240px; background: #111;"></video>
<video id="remoteVideo" autoplay playsinline style="width: 320px; height: 240px; background: #111;"></video>
</div>
<div style="margin-top: 10px;">
<textarea readonly id="messageLog" style="width: 90%; height: 12em;"></textarea>
</div>
</body>
</html>