Compare commits

..

3 Commits

Author SHA1 Message Date
b70189c619 Verify RTS Push to JS (fixes to application) 2026-04-17 16:47:30 -04:00
88c5d597d3 Removed useless button 2026-04-14 21:59:31 -04:00
4a8170c448 Removed File 2026-04-14 21:59:18 -04:00
5 changed files with 31 additions and 180 deletions

View File

@@ -62,8 +62,6 @@
<!-- <WebView Source="test.html"/> -->
<Grid RowDefinitions="Auto,*"
ColumnDefinitions="*">
<Button Text="Send message to JavaScript"
Clicked="OnSendMessageButtonClicked" />
<HybridWebView x:Name="hybridWebView"
RawMessageReceived="OnHybridWebViewRawMessageReceived"
Grid.Row="1" />

View File

@@ -198,13 +198,13 @@ public partial class MainPage : ContentPage
return;
}
if (type == SignalType.OfferUpdated || type == SignalType.AnswerUpdated || type == SignalType.CandidateAdded || type == SignalType.CallLeft)
if (type is SignalType.OfferUpdated or SignalType.AnswerUpdated or SignalType.CandidateAdded or SignalType.CallLeft)
{
var rtcNotification = JsonSerializer.Deserialize<RtcNotificationMessage>(e.Data);
if (rtcNotification is null)
return;
var notificationType = rtcNotification.Type ?? null;
var notificationType = rtcNotification.Type;
var notificationChannelId = rtcNotification.ChannelId ?? string.Empty;
if (notificationChannelId != _currentChannelId)
@@ -216,8 +216,11 @@ public partial class MainPage : ContentPage
{
switch (notificationType)
{
case SignalType.OfferUpdated :
case SignalType.OfferUpdated:
{
if (rtcNotification.Username == _username)
break;
var offer = await GetRtcOffer();
await SendRtcSignalToJsAsync(offer);
break;
@@ -233,9 +236,16 @@ public partial class MainPage : ContentPage
}
case SignalType.CandidateAdded:
{
if (rtcNotification.Username == _username)
break;
try
{
IceCandidate? iceCandidate = JsonSerializer.Deserialize<IceCandidate>(rtcNotification.Direction);
if (iceCandidate is null)
break;
IceCandidateCallback(iceCandidate);
}
catch (Exception ex)
@@ -600,6 +610,11 @@ public partial class MainPage : ContentPage
Console.WriteLine($"[{_username}] sent RTC signal: {rtcSignal.Type} -> {rtcSignal.ChannelId}");
} //Remove?
//public async Task<string> GetRtcParticipants() // TODO: UNCOMMENT AND ADD
//{
// var participants = await ServerAPI.GetRtcParticipantsAsync(_currentChannelId);
// return JsonSerializer.Serialize(participants);
//}
#endregion
private void OnSendMessageButtonClicked(object sender, EventArgs e)
@@ -615,7 +630,7 @@ public partial class MainPage : ContentPage
return;
}
await DisplayAlertAsync("Raw Message Received", e.Message, "OK");
SafeSendRawToWebView($"JS RAW -> C#: {e.Message}");
}
private void SafeSendRawToWebView(string message)

View File

@@ -1,4 +1,6 @@
let peerConnection = null;
let peerConnections = {};
let remoteStreams = {};
let localStream = null;
let currentUsername = null;
let currentChannelId = null;
@@ -241,7 +243,7 @@ async function joinChannelCall() {
// }
} //Combine with channelCallJoin
async function ensurePeerConnection2()
async function ensurePeerConnectionForUser(username)
{
if (peerConnection) return;
peerConnection = new RTCPeerConnection(configuration);
@@ -263,7 +265,7 @@ async function ensurePeerConnection2()
console.log(`Ice Candidate: ${JSON.stringify(event.candidate)}`);
// LogMessage(`Ice Candidate: ${JSON.stringify(event.candidate)}`);
await window.HybridWebView.InvokeDotNet("WriteIceCandidate", [JSON.stringify(event.candidate)]);
await IceCandidateAdded(event.candidate);
//await IceCandidateAdded(event.candidate);
};
peerConnection.ontrack = (event) => {
@@ -297,7 +299,7 @@ async function ensurePeerConnection2()
async function channelCallJoin(activeCall)
{
// LogMessage("Active call: " + activeCall);
await ensurePeerConnection2();
await ensurePeerConnectionForUser();
await ensureLocalMedia();
await applyLocalStreamToPeerConnection();
@@ -529,7 +531,7 @@ async function waitForIceGatheringComplete(pc) {
});
} //Remove?
// window.handleRtcSignal = handleRtcSignal;
window.handleRtcSignal = handleRtcSignal;
window.addEventListener("HybridWebViewMessageReceived", function (e) {
LogMessage("Raw message: " + e.detail.message);

View File

@@ -1,170 +0,0 @@
using System;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Microsoft.Maui.Dispatching;
using Microsoft.AspNetCore.SignalR.Client;
namespace RelayClient;
//TODO: Remove this file
public static class NativeWebRtc
{
[DllImport("webrtc_wrapper.dll")]
public static extern IntPtr CreatePeerConnection();
[DllImport("webrtc_wrapper.dll")]
public static extern string CreateOffer(IntPtr pc);
[DllImport("webrtc_wrapper.dll")]
public static extern string CreateAnswer(IntPtr pc);
[DllImport("webrtc_wrapper.dll")]
public static extern void SetLocalDescription(IntPtr pc, string type, string sdp);
[DllImport("webrtc_wrapper.dll")]
public static extern void SetRemoteDescription(IntPtr pc, string type, string sdp);
[DllImport("webrtc_wrapper.dll")]
public static extern void AddIceCandidate(IntPtr pc, string candidate);
}
public enum RTCSdpType { Offer, Answer }
public class RTCSessionDescription
{
public RTCSdpType Type { get; set; }
public string Sdp { get; set; }
}
public class RTCIceCandidate
{
public string Candidate { get; set; }
}
public class PeerConnection
{
private readonly IntPtr _nativeHandle;
public string RemoteId { get; set; }
public PeerConnection()
{
_nativeHandle = NativeWebRtc.CreatePeerConnection();
}
public Task CreateOffer(Action<RTCSessionDescription> onOfferCreated)
{
var sdp = NativeWebRtc.CreateOffer(_nativeHandle);
onOfferCreated?.Invoke(new RTCSessionDescription { Type = RTCSdpType.Offer, Sdp = sdp });
return Task.CompletedTask;
}
public Task CreateAnswer(Action<RTCSessionDescription> onAnswerCreated)
{
var sdp = NativeWebRtc.CreateAnswer(_nativeHandle);
onAnswerCreated?.Invoke(new RTCSessionDescription { Type = RTCSdpType.Answer, Sdp = sdp });
return Task.CompletedTask;
}
public Task SetLocalDescription(RTCSessionDescription desc)
{
NativeWebRtc.SetLocalDescription(_nativeHandle, desc.Type.ToString(), desc.Sdp);
return Task.CompletedTask;
}
public Task SetRemoteDescription(RTCSessionDescription desc)
{
NativeWebRtc.SetRemoteDescription(_nativeHandle, desc.Type.ToString(), desc.Sdp);
return Task.CompletedTask;
}
public Task AddIceCandidate(RTCIceCandidate candidate)
{
NativeWebRtc.AddIceCandidate(_nativeHandle, candidate.Candidate);
return Task.CompletedTask;
}
}
public class WebRtcClient
{
private readonly PeerConnection _peerConnection = new();
private readonly HubConnection _signal;
private string _myId;
public WebRtcClient(string serverUrl)
{
_signal = new HubConnectionBuilder()
.WithUrl($"{serverUrl}/webrtc")
.WithAutomaticReconnect()
.Build();
_signal.On<string, string>("ReceiveOffer", (fromId, sdp) =>
{
MainThread.BeginInvokeOnMainThread(async () =>
{
await HandleOffer(fromId, sdp);
});
});
_signal.On<string, string>("ReceiveAnswer", (fromId, sdp) =>
{
MainThread.BeginInvokeOnMainThread(async () =>
{
await HandleAnswer(sdp);
});
});
_signal.On<string, string>("ReceiveIceCandidate", (fromId, candidate) =>
{
MainThread.BeginInvokeOnMainThread(async () =>
{
await HandleIceCandidate(candidate);
});
});
}
public async Task ConnectAsync()
{
await _signal.StartAsync();
_myId = _signal.ConnectionId;
}
public async Task CallAsync(string targetId)
{
_peerConnection.RemoteId = targetId;
await _peerConnection.CreateOffer(async offer =>
{
await _peerConnection.SetLocalDescription(offer);
await _signal.InvokeAsync("SendOffer", targetId, offer.Sdp);
});
}
public async Task HandleOffer(string fromId, string sdp)
{
_peerConnection.RemoteId = fromId;
var remoteDesc = new RTCSessionDescription { Type = RTCSdpType.Offer, Sdp = sdp };
await _peerConnection.SetRemoteDescription(remoteDesc);
await _peerConnection.CreateAnswer(async answer =>
{
await _peerConnection.SetLocalDescription(answer);
await _signal.InvokeAsync("SendAnswer", fromId, answer.Sdp);
});
}
public async Task HandleAnswer(string sdp)
{
var remoteDesc = new RTCSessionDescription { Type = RTCSdpType.Answer, Sdp = sdp };
await _peerConnection.SetRemoteDescription(remoteDesc);
}
public async Task HandleIceCandidate(string candidate)
{
await _peerConnection.AddIceCandidate(new RTCIceCandidate { Candidate = candidate });
}
public async Task SendIceCandidate(string candidate)
{
if (!string.IsNullOrEmpty(_peerConnection.RemoteId))
{
await _signal.InvokeAsync("SendIceCandidate", _peerConnection.RemoteId, candidate);
}
}
}

View File

@@ -70,6 +70,12 @@ public static class RtcEndpoints
{
return Results.Ok(await rtcCallService.GetAnswersAsync(channelId));
});
//app.MapGet("/api/rtc/participants/{channelId}", (string channelId) => // TODO: UNCOMMENT AND ADD
//{
// var participants = RtcChannelPresenceService.GetUsernamesInChannel(channelId);
// return Results.Ok(participants);
//});
// Return the latest answer stored for the specified channel.
app.MapGet("/api/rtc/answer/{channelId}", async (string channelId, RtcCallService rtcCallService) =>