Compare commits

...

2 Commits

Author SHA1 Message Date
68a905a292 Update 2026-04-06 20:46:55 -04:00
df438e265b Revert "It's still broken, but I made a bit of progress."
This reverts commit 9b666ee109.
2026-04-06 20:43:03 -04:00
3 changed files with 87 additions and 153 deletions

View File

@@ -1,4 +1,4 @@
using RelayClient.Crypto; using RelayClient.Crypto;
using RelayClient.Models; using RelayClient.Models;
using WebSocketSharp; using WebSocketSharp;
using System.Text.Json; using System.Text.Json;
@@ -109,7 +109,7 @@ public partial class MainPage : ContentPage
SafeSendRawToWebView($"[{_username}] RAW WS DATA: {e.Data}"); SafeSendRawToWebView($"[{_username}] RAW WS DATA: {e.Data}");
//Console.WriteLine($"[{_username}] RAW WS DATA: {e.Data}"); Console.WriteLine($"[{_username}] RAW WS DATA: {e.Data}");
try try
{ {
@@ -198,8 +198,8 @@ public partial class MainPage : ContentPage
return; return;
} }
if (type is "rtc_offer_updated" or "rtc_answer_updated" or "rtc_candidate_added" or "rtc_call_left") if (type == "rtc_offer_updated" || type == "rtc_answer_updated" || type == "rtc_candidate_added" || type == "rtc_call_left")
{ {
var rtcNotification = JsonSerializer.Deserialize<RtcNotificationMessage>(e.Data); var rtcNotification = JsonSerializer.Deserialize<RtcNotificationMessage>(e.Data);
if (rtcNotification is null) if (rtcNotification is null)
@@ -213,10 +213,40 @@ public partial class MainPage : ContentPage
SafeSendRawToWebView("RTC notification received: " + notificationType + " for " + notificationChannelId); SafeSendRawToWebView("RTC notification received: " + notificationType + " for " + notificationChannelId);
_ = MainThread.InvokeOnMainThreadAsync(() => HandleRtcNotificationAsync(notificationType)); MainThread.BeginInvokeOnMainThread(async () =>
{
switch (notificationType)
{
case "rtc_offer_updated":
{
var offer = await GetRtcOffer();
await SendRtcSignalToJsAsync(offer);
break;
}
case "rtc_answer_updated":
{
var answer = await ServerAPI.GetAnswerForChannelAsync(_currentChannelId);
if (answer is not null)
{
await AnswerCallback(answer);
}
break;
}
case "rtc_candidate_added":
{
break;
}
case "rtc_call_left":
{
SafeSendRawToWebView("RTC call left notification received.");
break;
}
}
});
return; return;
} }
if (type != "encrypted_chat") if (type != "encrypted_chat")
return; return;
@@ -447,22 +477,23 @@ public partial class MainPage : ContentPage
} }
} }
//public async Task AnswerCallback(RtcDescription answer) public async Task AnswerCallback(RtcDescription answer)
//{ {
// string json = JsonSerializer.Serialize(answer); string json = JsonSerializer.Serialize(answer);
// SafeSendRawToWebView("WriteRtcAnswer answered with: " + json); SafeSendRawToWebView("WriteRtcAnswer answered with: " + json);
try
// try {
// { SafeSendRawToWebView("Pre");
// SafeSendRawToWebView("Pre Evaluate"); // await hybridWebView.InvokeJavaScriptAsync("CSharpCallTest", ["value from C#"], [HybridJSTypeString.Default.String]);
// await hybridWebView.EvaluateJavaScriptAsync($"window.AnswerCallback({json})"); // SafeSendRawToWebView("Mid");
// SafeSendRawToWebView("Post Evaluate"); await hybridWebView.InvokeJavaScriptAsync("AnswerCallback", [json], [HybridJSTypeString.Default.String]);
// } SafeSendRawToWebView("End");
// catch (Exception ex) }
// { catch (Exception ex)
// SafeSendRawToWebView("WriteRtcAnswer failed: " + ex.Message); {
// } SafeSendRawToWebView("WriteRtcAnswer failed: " + ex.Message);
//} }
}
private void OnSendMessageButtonClicked(object sender, EventArgs e) private void OnSendMessageButtonClicked(object sender, EventArgs e)
{ {
@@ -477,8 +508,7 @@ public partial class MainPage : ContentPage
return; return;
} }
Console.WriteLine($"[{_username}] JS RAW -> C#: {e.Message}"); await DisplayAlertAsync("Raw Message Received", e.Message, "OK");
SafeSendRawToWebView($"JS RAW -> C#: {e.Message}");
} }
public void SendRtcSignal(string json) public void SendRtcSignal(string json)
@@ -522,12 +552,8 @@ public partial class MainPage : ContentPage
private async Task SendRtcSignalToJsAsync(string rawJson) private async Task SendRtcSignalToJsAsync(string rawJson)
{ {
SafeSendRawToWebView("Before Evaluate dispatchRtcSignal");
var jsArg = JsonSerializer.Serialize(rawJson); var jsArg = JsonSerializer.Serialize(rawJson);
await hybridWebView.EvaluateJavaScriptAsync($"window.dispatchRtcSignal({jsArg})"); await hybridWebView.EvaluateJavaScriptAsync($"window.handleRtcSignal({jsArg})");
SafeSendRawToWebView("After Evaluate dispatchRtcSignal");
} }
private async Task PushRtcContextToJsAsync() private async Task PushRtcContextToJsAsync()
@@ -571,65 +597,4 @@ public partial class MainPage : ContentPage
// for trimmed builds. // for trimmed builds.
} }
private async Task HandleRtcNotificationAsync(string notificationType)
{
try
{
switch (notificationType)
{
case "rtc_offer_updated":
{
var offer = await ServerAPI.GetOffersForChannelAsync(_currentChannelId);
if (offer is not null)
{
var signal = new
{
type = "rtc_offer",
from = "server",
channelId = _currentChannelId,
sdp = offer.sdp
};
SafeSendRawToWebView("Dispatching rtc_offer to JS");
await SendRtcSignalToJsAsync(JsonSerializer.Serialize(signal));
}
break;
}
case "rtc_answer_updated":
{
var answer = await ServerAPI.GetAnswerForChannelAsync(_currentChannelId);
if (answer is not null)
{
var signal = new
{
type = "rtc_answer",
from = "server",
channelId = _currentChannelId,
sdp = answer.sdp
};
SafeSendRawToWebView("Dispatching rtc_answer to JS");
await SendRtcSignalToJsAsync(JsonSerializer.Serialize(signal));
}
break;
}
case "rtc_candidate_added":
{
break;
}
case "rtc_call_left":
{
SafeSendRawToWebView("RTC call left notification received.");
break;
}
}
}
catch (Exception ex)
{
SafeSendRawToWebView("RTC notification handler failed: " + ex.Message);
}
}
} }

View File

@@ -85,5 +85,5 @@ textarea::-webkit-scrollbar-thumb {
background: #1F1A24; background: #1F1A24;
border: 1px solid #332940; border: 1px solid #332940;
border-radius: 10px; border-radius: 10px;
padding: 12px; padding: 11px;
} }

View File

@@ -1,4 +1,4 @@
let peerConnection = null; let peerConnection = null;
let localStream = null; let localStream = null;
let currentUsername = null; let currentUsername = null;
let currentChannelId = null; let currentChannelId = null;
@@ -26,30 +26,6 @@ window.setChannelId = function(channelId) {
LogMessage("Channel set to: " + currentChannelId); LogMessage("Channel set to: " + currentChannelId);
}; };
//window.AnswerCallback = async function(answer) {
// try {
// LogMessage("AnswerCallback called with: " + JSON.stringify(answer));
//
// if (!peerConnection) {
// await ensurePeerConnection2();
// }
//
// if (!answer || !answer.type || !answer.sdp) {
// LogMessage("AnswerCallback received invalid answer");
// return;
// }
//
// await peerConnection.setRemoteDescription({
// type: answer.type,
// sdp: answer.sdp
// });
//
// LogMessage("Remote answer applied");
// } catch (err) {
// LogMessage("AnswerCallback failed: " + err);
// }
//};
function LogMessage(msg) { function LogMessage(msg) {
const messageLog = document.getElementById("messageLog"); const messageLog = document.getElementById("messageLog");
messageLog.value += '\r\n' + msg; messageLog.value += '\r\n' + msg;
@@ -242,21 +218,16 @@ async function ensurePeerConnection2()
`ICE connection state change: ${peerConnection.iceConnectionState}`); `ICE connection state change: ${peerConnection.iceConnectionState}`);
}); });
} }
async function channelCallJoin(activeCall) async function channelCallJoin(activeCall)
{ {
LogMessage("Active call: " + activeCall); LogMessage("Active call: " + activeCall);
await ensurePeerConnection2(); await ensurePeerConnection2();
await ensureLocalMedia();
if (activeCall) if (activeCall)
{ {
const rawJson = await window.HybridWebView.InvokeDotNet("GetRtcOffer"); const rawJson = await window.HybridWebView.InvokeDotNet("GetRtcOffer");
const offer = typeof rawJson === "string" ? JSON.parse(rawJson) : rawJson; const offer = typeof rawJson === "string" ? JSON.parse(rawJson) : rawJson;
await peerConnection.setRemoteDescription(offer); await peerConnection.setRemoteDescription(offer);
const answer = await peerConnection.createAnswer(); const answer = await peerConnection.createAnswer();
await peerConnection.setLocalDescription(answer); await peerConnection.setLocalDescription(answer);
@@ -270,9 +241,21 @@ async function channelCallJoin(activeCall)
{ {
const offer = await peerConnection.createOffer(); const offer = await peerConnection.createOffer();
await peerConnection.setLocalDescription(offer); await peerConnection.setLocalDescription(offer);
await window.HybridWebView.InvokeDotNet("WriteRtcOffer", [JSON.stringify(offer)]); await window.HybridWebView.InvokeDotNet("WriteRtcOffer", [JSON.stringify(offer)]);
LogMessage("Joining call with media offer: " + JSON.stringify(offer)); LogMessage(`Joining call with media offer: ${JSON.stringify(offer)}`);
localStream.getTracks().forEach(track => {
peerConnection.addTrack(track, localStream);
});
peerConnection.addEventListener('track', event => {
LogMessage("Received track: " + event.streams[0]);
event.streams[0].getTracks().forEach(track => {
LogMessage(`Add a track to the remoteStream: ${track}`);
remoteStream.addTrack(track);
});
});
} }
} }
@@ -280,20 +263,20 @@ async function CSharpCallTest(value)
{ {
LogMessage("Called from C#: " + value); LogMessage("Called from C#: " + value);
} }
//async function AnswerCallback(answer) async function AnswerCallback(answer)
//{ {
// LogMessage("Answer: " + answer); LogMessage("Answer: " + answer);
//
// let callBack = JSON.parse(answer); let callBack = JSON.parse(answer);
// LogMessage("Call Back: " + callBack); LogMessage("Call Back: " + callBack);
//
// if (!peerConnection.currentRemoteDescription && callBack) if (!peerConnection.currentRemoteDescription && callBack)
// { {
// LogMessage("Current answer: " + callBack); LogMessage("Current answer: " + callBack);
// const desc = new RTCSessionDescription(answer); const desc = new RTCSessionDescription(answer);
// await peerConnection.setRemoteDescription(desc); await peerConnection.setRemoteDescription(desc);
// } }
//} }
async function CollectIceCandidates() async function CollectIceCandidates()
{ {
@@ -301,8 +284,6 @@ async function CollectIceCandidates()
} }
async function handleRtcSignal(rawJson) { async function handleRtcSignal(rawJson) {
try { try {
LogMessage("handleRtcSignal raw: " + JSON.stringify(rawJson));
const msg = typeof rawJson === "string" ? JSON.parse(rawJson) : rawJson; const msg = typeof rawJson === "string" ? JSON.parse(rawJson) : rawJson;
LogMessage("Received signal: " + msg.type + " from " + msg.from + " in " + msg.channelId); LogMessage("Received signal: " + msg.type + " from " + msg.from + " in " + msg.channelId);
@@ -455,15 +436,8 @@ async function waitForIceGatheringComplete(pc) {
}); });
} }
function dispatchRtcSignal(rawJson) {
handleRtcSignal(rawJson);
return "ok";
}
window.handleRtcSignal = handleRtcSignal; window.handleRtcSignal = handleRtcSignal;
window.dispatchRtcSignal = dispatchRtcSignal;
window.addEventListener("HybridWebViewMessageReceived", function (e) { window.addEventListener("HybridWebViewMessageReceived", function (e) {
LogMessage("Raw message: " + e.detail.message); LogMessage("Raw message: " + e.detail.message);
}); });
@@ -472,9 +446,4 @@ window.addEventListener("load", async () => {
LogMessage("RTC page loaded"); LogMessage("RTC page loaded");
window.HybridWebView.SendRawMessage("rtc_page_ready"); window.HybridWebView.SendRawMessage("rtc_page_ready");
await loadDevices(); await loadDevices();
}); });
window.dispatchRtcSignal = function(rawJson) {
handleRtcSignal(rawJson);
return "ok";
};