diff --git a/RelayClient/MainPage.xaml.cs b/RelayClient/MainPage.xaml.cs index 4b21af6..ec89dcc 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 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(e.Data); if (rtcNotification is null) @@ -213,10 +213,40 @@ public partial class MainPage : ContentPage 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; } - + if (type != "encrypted_chat") return; @@ -447,22 +477,23 @@ public partial class MainPage : ContentPage } } - //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); - // } - //} + 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); + } + } private void OnSendMessageButtonClicked(object sender, EventArgs e) { @@ -477,8 +508,7 @@ public partial class MainPage : ContentPage return; } - Console.WriteLine($"[{_username}] JS RAW -> C#: {e.Message}"); - SafeSendRawToWebView($"JS RAW -> C#: {e.Message}"); + await DisplayAlertAsync("Raw Message Received", e.Message, "OK"); } public void SendRtcSignal(string json) @@ -522,12 +552,8 @@ public partial class MainPage : ContentPage private async Task SendRtcSignalToJsAsync(string rawJson) { - SafeSendRawToWebView("Before Evaluate dispatchRtcSignal"); - var jsArg = JsonSerializer.Serialize(rawJson); - await hybridWebView.EvaluateJavaScriptAsync($"window.dispatchRtcSignal({jsArg})"); - - SafeSendRawToWebView("After Evaluate dispatchRtcSignal"); + await hybridWebView.EvaluateJavaScriptAsync($"window.handleRtcSignal({jsArg})"); } private async Task PushRtcContextToJsAsync() @@ -571,65 +597,4 @@ 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 fdade4b..18c7760 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,30 +26,6 @@ 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; @@ -242,21 +218,16 @@ 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); @@ -270,9 +241,21 @@ 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)); + 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); } -//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() { @@ -301,8 +284,6 @@ 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); @@ -455,15 +436,8 @@ 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); }); @@ -472,9 +446,4 @@ window.addEventListener("load", async () => { LogMessage("RTC page loaded"); window.HybridWebView.SendRawMessage("rtc_page_ready"); await loadDevices(); -}); - -window.dispatchRtcSignal = function(rawJson) { - handleRtcSignal(rawJson); - return "ok"; -}; \ No newline at end of file +}); \ No newline at end of file