Added WebRTC stuff - Needs Testing.

This commit is contained in:
2026-03-29 15:18:57 -04:00
parent 0bb3aa28b1
commit 8c6724038a
8 changed files with 417 additions and 170 deletions

View File

@@ -9,116 +9,190 @@
<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) {
var messageLog = document.getElementById("messageLog");
const messageLog = document.getElementById("messageLog");
messageLog.value += '\r\n' + msg;
}
window.addEventListener(
"HybridWebViewMessageReceived",
function (e) {
LogMessage("Raw message: " + e.detail.message);
async function ensurePeerConnection() {
if (peerConnection) return;
peerConnection = new RTCPeerConnection({
iceServers: [{ urls: "stun:stun.l.google.com:19302" }]
});
function AddNumbers(a, b) {
var result = {
"result": a + b,
"operationName": "Addition"
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);
};
return result;
}
var count = 0;
async function ensureLocalMedia() {
if (localStream) return;
async function EvaluateMeWithParamsAndAsyncReturn(s1, s2) {
const response = await fetch("/asyncdata.txt");
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
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;
}
var jsonData = await response.json();
jsonData[s1] = s2;
const msg = 'JSON data is available: ' + JSON.stringify(jsonData);
window.HybridWebView.SendRawMessage(msg)
return jsonData;
}
async function InvokeDoSyncWork() {
LogMessage("Invoking DoSyncWork");
await window.HybridWebView.InvokeDotNet('DoSyncWork');
LogMessage("Invoked DoSyncWork");
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 InvokeDoSyncWorkParams() {
LogMessage("Invoking DoSyncWorkParams");
await window.HybridWebView.InvokeDotNet('DoSyncWorkParams', [123, 'hello']);
LogMessage("Invoked DoSyncWorkParams");
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);
}
}
async function InvokeDoSyncWorkReturn() {
LogMessage("Invoking DoSyncWorkReturn");
const retValue = await window.HybridWebView.InvokeDotNet('DoSyncWorkReturn');
LogMessage("Invoked DoSyncWorkReturn, return value: " + retValue);
}
async function InvokeDoSyncWorkParamsReturn() {
LogMessage("Invoking DoSyncWorkParamsReturn");
const retValue = await window.HybridWebView.InvokeDotNet('DoSyncWorkParamsReturn', [123, 'hello']);
LogMessage("Invoked DoSyncWorkParamsReturn, return value: message=" + retValue.Message + ", value=" + retValue.Value);
}
async function InvokeDoAsyncWork() {
LogMessage("Invoking DoAsyncWork");
await window.HybridWebView.InvokeDotNet('DoAsyncWork');
LogMessage("Invoked DoAsyncWork");
}
async function InvokeDoAsyncWorkParams() {
LogMessage("Invoking DoAsyncWorkParams");
await window.HybridWebView.InvokeDotNet('DoAsyncWorkParams', [123, 'hello']);
LogMessage("Invoked DoAsyncWorkParams");
}
async function InvokeDoAsyncWorkReturn() {
LogMessage("Invoking DoAsyncWorkReturn");
const retValue = await window.HybridWebView.InvokeDotNet('DoAsyncWorkReturn');
LogMessage("Invoked DoAsyncWorkReturn, return value: " + retValue);
}
async function InvokeDoAsyncWorkParamsReturn() {
LogMessage("Invoking DoAsyncWorkParamsReturn");
const retValue = await window.HybridWebView.InvokeDotNet('DoAsyncWorkParamsReturn', [123, 'hello']);
LogMessage("Invoked DoAsyncWorkParamsReturn, return value: message=" + retValue.Message + ", value=" + retValue.Value);
}
window.handleRtcSignal = handleRtcSignal;
window.addEventListener("HybridWebViewMessageReceived", function (e) {
LogMessage("Raw message: " + e.detail.message);
});
</script>
</head>
<body>
<div>
Hybrid sample!
</div>
<div>
<button onclick="window.HybridWebView.SendRawMessage('Message from JS! ' + (count++))">Send message to C#</button>
</div>
<div>
<button onclick="InvokeDoSyncWork()">Call C# sync method (no params)</button>
<button onclick="InvokeDoSyncWorkParams()">Call C# sync method (params)</button>
<button onclick="InvokeDoSyncWorkReturn()">Call C# method (no params) and get simple return value</button>
<button onclick="InvokeDoSyncWorkParamsReturn()">Call C# method (params) and get complex return value</button>
</div>
<div>
<button onclick="InvokeDoAsyncWork()">Call C# async method (no params)</button>
<button onclick="InvokeDoAsyncWorkParams()">Call C# async method (params)</button>
<button onclick="InvokeDoAsyncWorkReturn()">Call C# async method (no params) and get simple return value</button>
<button onclick="InvokeDoAsyncWorkParamsReturn()">Call C# async method (params) and get complex return value</button>
</div>
<div>
Log: <textarea readonly id="messageLog" style="width: 80%; height: 10em;"></textarea>
</div>
<div>
Consider checking out this PDF: <a href="docs/sample.pdf">sample.pdf</a>
</div>
</body>
<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>