diff --git a/RelayClient/MainPage.xaml.cs b/RelayClient/MainPage.xaml.cs index ec89dcc..4b21af6 100644 --- a/RelayClient/MainPage.xaml.cs +++ b/RelayClient/MainPage.xaml.cs @@ -1,4 +1,4 @@ -using RelayClient.Crypto; +using RelayClient.Crypto; using RelayClient.Models; using WebSocketSharp; using System.Text.Json; @@ -109,7 +109,7 @@ public partial class MainPage : ContentPage SafeSendRawToWebView($"[{_username}] RAW WS DATA: {e.Data}"); - Console.WriteLine($"[{_username}] RAW WS DATA: {e.Data}"); + //Console.WriteLine($"[{_username}] RAW WS DATA: {e.Data}"); try { @@ -198,8 +198,8 @@ public partial class MainPage : ContentPage return; } - - if (type == "rtc_offer_updated" || type == "rtc_answer_updated" || type == "rtc_candidate_added" || type == "rtc_call_left") + + if (type is "rtc_offer_updated" or "rtc_answer_updated" or "rtc_candidate_added" or "rtc_call_left") { var rtcNotification = JsonSerializer.Deserialize(e.Data); if (rtcNotification is null) @@ -213,40 +213,10 @@ public partial class MainPage : ContentPage SafeSendRawToWebView("RTC notification received: " + notificationType + " for " + notificationChannelId); - 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; - } - } - }); - + _ = MainThread.InvokeOnMainThreadAsync(() => HandleRtcNotificationAsync(notificationType)); return; } - + if (type != "encrypted_chat") return; @@ -477,23 +447,22 @@ public partial class MainPage : ContentPage } } - public async Task AnswerCallback(RtcDescription answer) - { - string json = JsonSerializer.Serialize(answer); - SafeSendRawToWebView("WriteRtcAnswer answered with: " + json); - try - { - SafeSendRawToWebView("Pre"); - // await hybridWebView.InvokeJavaScriptAsync("CSharpCallTest", ["value from C#"], [HybridJSTypeString.Default.String]); - // SafeSendRawToWebView("Mid"); - await hybridWebView.InvokeJavaScriptAsync("AnswerCallback", [json], [HybridJSTypeString.Default.String]); - SafeSendRawToWebView("End"); - } - catch (Exception ex) - { - SafeSendRawToWebView("WriteRtcAnswer failed: " + ex.Message); - } - } + //public async Task AnswerCallback(RtcDescription answer) + //{ + // string json = JsonSerializer.Serialize(answer); + // SafeSendRawToWebView("WriteRtcAnswer answered with: " + json); + + // try + // { + // SafeSendRawToWebView("Pre Evaluate"); + // await hybridWebView.EvaluateJavaScriptAsync($"window.AnswerCallback({json})"); + // SafeSendRawToWebView("Post Evaluate"); + // } + // catch (Exception ex) + // { + // SafeSendRawToWebView("WriteRtcAnswer failed: " + ex.Message); + // } + //} private void OnSendMessageButtonClicked(object sender, EventArgs e) { @@ -508,7 +477,8 @@ public partial class MainPage : ContentPage return; } - await DisplayAlertAsync("Raw Message Received", e.Message, "OK"); + Console.WriteLine($"[{_username}] JS RAW -> C#: {e.Message}"); + SafeSendRawToWebView($"JS RAW -> C#: {e.Message}"); } public void SendRtcSignal(string json) @@ -552,8 +522,12 @@ public partial class MainPage : ContentPage private async Task SendRtcSignalToJsAsync(string rawJson) { + SafeSendRawToWebView("Before Evaluate dispatchRtcSignal"); + var jsArg = JsonSerializer.Serialize(rawJson); - await hybridWebView.EvaluateJavaScriptAsync($"window.handleRtcSignal({jsArg})"); + await hybridWebView.EvaluateJavaScriptAsync($"window.dispatchRtcSignal({jsArg})"); + + SafeSendRawToWebView("After Evaluate dispatchRtcSignal"); } private async Task PushRtcContextToJsAsync() @@ -597,4 +571,65 @@ public partial class MainPage : ContentPage // 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); + } + } } \ No newline at end of file diff --git a/RelayClient/Resources/Raw/wwwroot/index.js b/RelayClient/Resources/Raw/wwwroot/index.js index 18c7760..fdade4b 100644 --- a/RelayClient/Resources/Raw/wwwroot/index.js +++ b/RelayClient/Resources/Raw/wwwroot/index.js @@ -1,4 +1,4 @@ -let peerConnection = null; +let peerConnection = null; let localStream = null; let currentUsername = null; let currentChannelId = null; @@ -26,6 +26,30 @@ window.setChannelId = function(channelId) { 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) { const messageLog = document.getElementById("messageLog"); messageLog.value += '\r\n' + msg; @@ -218,16 +242,21 @@ async function ensurePeerConnection2() `ICE connection state change: ${peerConnection.iceConnectionState}`); }); } + async function channelCallJoin(activeCall) { LogMessage("Active call: " + activeCall); + await ensurePeerConnection2(); - + await ensureLocalMedia(); + if (activeCall) { const rawJson = await window.HybridWebView.InvokeDotNet("GetRtcOffer"); const offer = typeof rawJson === "string" ? JSON.parse(rawJson) : rawJson; + await peerConnection.setRemoteDescription(offer); + const answer = await peerConnection.createAnswer(); await peerConnection.setLocalDescription(answer); @@ -241,21 +270,9 @@ async function channelCallJoin(activeCall) { const offer = await peerConnection.createOffer(); await peerConnection.setLocalDescription(offer); - + await window.HybridWebView.InvokeDotNet("WriteRtcOffer", [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); - }); - }); + LogMessage("Joining call with media offer: " + JSON.stringify(offer)); } } @@ -263,20 +280,20 @@ async function CSharpCallTest(value) { LogMessage("Called from C#: " + value); } -async function AnswerCallback(answer) -{ - LogMessage("Answer: " + answer); - - let callBack = JSON.parse(answer); - LogMessage("Call Back: " + callBack); - - if (!peerConnection.currentRemoteDescription && callBack) - { - LogMessage("Current answer: " + callBack); - const desc = new RTCSessionDescription(answer); - await peerConnection.setRemoteDescription(desc); - } -} +//async function AnswerCallback(answer) +//{ +// LogMessage("Answer: " + answer); +// +// let callBack = JSON.parse(answer); +// LogMessage("Call Back: " + callBack); +// +// if (!peerConnection.currentRemoteDescription && callBack) +// { +// LogMessage("Current answer: " + callBack); +// const desc = new RTCSessionDescription(answer); +// await peerConnection.setRemoteDescription(desc); +// } +//} async function CollectIceCandidates() { @@ -284,6 +301,8 @@ async function CollectIceCandidates() } async function handleRtcSignal(rawJson) { try { + LogMessage("handleRtcSignal raw: " + JSON.stringify(rawJson)); + const msg = typeof rawJson === "string" ? JSON.parse(rawJson) : rawJson; LogMessage("Received signal: " + msg.type + " from " + msg.from + " in " + msg.channelId); @@ -436,8 +455,15 @@ async function waitForIceGatheringComplete(pc) { }); } +function dispatchRtcSignal(rawJson) { + handleRtcSignal(rawJson); + return "ok"; +} + window.handleRtcSignal = handleRtcSignal; +window.dispatchRtcSignal = dispatchRtcSignal; + window.addEventListener("HybridWebViewMessageReceived", function (e) { LogMessage("Raw message: " + e.detail.message); }); @@ -446,4 +472,9 @@ window.addEventListener("load", async () => { LogMessage("RTC page loaded"); window.HybridWebView.SendRawMessage("rtc_page_ready"); await loadDevices(); -}); \ No newline at end of file +}); + +window.dispatchRtcSignal = function(rawJson) { + handleRtcSignal(rawJson); + return "ok"; +}; \ No newline at end of file