Update: Channel Based VC (Same Issues)

This commit is contained in:
2026-03-31 09:47:15 -04:00
parent 6fedad92b1
commit e9f96b7389
7 changed files with 69 additions and 54 deletions

View File

@@ -136,10 +136,11 @@ public partial class MainPage : ContentPage
_currentChannelId = defaultChannel.ChannelId; _currentChannelId = defaultChannel.ChannelId;
_currentChannelName = defaultChannel.Name; _currentChannelName = defaultChannel.Name;
MainThread.BeginInvokeOnMainThread(() => MainThread.BeginInvokeOnMainThread(async () =>
{ {
ChannelLabel.Text = $"#{_currentChannelName}"; ChannelLabel.Text = $"#{_currentChannelName}";
RenderChannelList(); RenderChannelList();
await PushRtcContextToJsAsync();
}); });
_wsc.Send($"GET_HISTORY|{_username}|{_currentChannelId}"); _wsc.Send($"GET_HISTORY|{_username}|{_currentChannelId}");
@@ -166,7 +167,10 @@ public partial class MainPage : ContentPage
if (payload is null) if (payload is null)
return; return;
if (payload.RecipientUsername != _username) if (payload.ChannelId != _currentChannelId)
return;
if (payload.SenderUsername == _username)
return; return;
var privateKey = KeyStorage.LoadPrivateKey(_username); var privateKey = KeyStorage.LoadPrivateKey(_username);
@@ -268,6 +272,11 @@ public partial class MainPage : ContentPage
_currentChannelId = channel.ChannelId; _currentChannelId = channel.ChannelId;
_currentChannelName = channel.Name; _currentChannelName = channel.Name;
MainThread.BeginInvokeOnMainThread(async () =>
{
await PushRtcContextToJsAsync();
});
ChannelLabel.Text = $"#{_currentChannelName}"; ChannelLabel.Text = $"#{_currentChannelName}";
RenderCurrentChannelMessages(); RenderCurrentChannelMessages();
@@ -353,7 +362,7 @@ public partial class MainPage : ContentPage
{ {
if (e.Message == "rtc_page_ready") if (e.Message == "rtc_page_ready")
{ {
await InitializeRtcPageAsync(); await PushRtcContextToJsAsync();
return; return;
} }
@@ -388,7 +397,7 @@ public partial class MainPage : ContentPage
{ {
Type = "encrypted_rtc_signal", Type = "encrypted_rtc_signal",
SenderUsername = _username, SenderUsername = _username,
RecipientUsername = rtcSignal.To, ChannelId = rtcSignal.ChannelId,
CipherText = encrypted.CipherText, CipherText = encrypted.CipherText,
Nonce = encrypted.Nonce, Nonce = encrypted.Nonce,
Tag = encrypted.Tag, Tag = encrypted.Tag,
@@ -396,7 +405,7 @@ public partial class MainPage : ContentPage
}; };
_wsc.Send(JsonSerializer.Serialize(payload)); _wsc.Send(JsonSerializer.Serialize(payload));
Console.WriteLine($"[{_username}] sent RTC signal: {rtcSignal.Type} -> {rtcSignal.To}"); Console.WriteLine($"[{_username}] sent RTC signal: {rtcSignal.Type} -> {rtcSignal.ChannelId}");
} }
private async Task SendRtcSignalToJsAsync(string rawJson) private async Task SendRtcSignalToJsAsync(string rawJson)
@@ -405,10 +414,14 @@ public partial class MainPage : ContentPage
await hybridWebView.EvaluateJavaScriptAsync($"window.handleRtcSignal({jsArg})"); await hybridWebView.EvaluateJavaScriptAsync($"window.handleRtcSignal({jsArg})");
} }
private async Task InitializeRtcPageAsync() private async Task PushRtcContextToJsAsync()
{ {
var usernameJson = JsonSerializer.Serialize(_username); var usernameJson = JsonSerializer.Serialize(_username);
var channelIdJson = JsonSerializer.Serialize(_currentChannelId);
await hybridWebView.EvaluateJavaScriptAsync($"window.setUsername({usernameJson})"); await hybridWebView.EvaluateJavaScriptAsync($"window.setUsername({usernameJson})");
Console.WriteLine($"[{_username}] pushed username into HybridWebView."); await hybridWebView.EvaluateJavaScriptAsync($"window.setChannelId({channelIdJson})");
Console.WriteLine($"[{_username}] pushed RTC context into HybridWebView.");
} }
} }

View File

@@ -2,9 +2,9 @@
public class RtcSignalMessage public class RtcSignalMessage
{ {
public required string Type { get; set; } // rtc_offer / rtc_answer / rtc_ice_candidate / rtc_call_request / rtc_call_accept / rtc_call_reject public required string Type { get; set; } // rtc_join / rtc_offer / rtc_answer / rtc_ice_candidate / rtc_leave
public required string From { get; set; } public required string From { get; set; }
public required string To { get; set; } public required string ChannelId { get; set; }
public string? Sdp { get; set; } public string? Sdp { get; set; }
public string? Candidate { get; set; } public string? Candidate { get; set; }

View File

@@ -4,7 +4,7 @@ public class SocketRtcSignalMessage
{ {
public required string Type { get; set; } // encrypted_rtc_signal public required string Type { get; set; } // encrypted_rtc_signal
public required string SenderUsername { get; set; } public required string SenderUsername { get; set; }
public required string RecipientUsername { get; set; } public required string ChannelId { get; set; }
public required string CipherText { get; set; } public required string CipherText { get; set; }
public required string Nonce { get; set; } public required string Nonce { get; set; }

View File

@@ -11,8 +11,8 @@
<script> <script>
let peerConnection = null; let peerConnection = null;
let localStream = null; let localStream = null;
let currentTarget = null;
let currentUsername = null; let currentUsername = null;
let currentChannelId = null;
let availableCameras = []; let availableCameras = [];
let availableMics = []; let availableMics = [];
@@ -21,6 +21,11 @@
LogMessage("Username set to: " + currentUsername); LogMessage("Username set to: " + currentUsername);
}; };
window.setChannelId = function(channelId) {
currentChannelId = channelId;
LogMessage("Channel set to: " + currentChannelId);
};
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;
@@ -43,12 +48,12 @@
}); });
peerConnection.onicecandidate = async (event) => { peerConnection.onicecandidate = async (event) => {
if (!event.candidate || !currentTarget || !currentUsername) return; if (!event.candidate || !currentChannelId || !currentUsername) return;
const payload = { const payload = {
type: "rtc_ice_candidate", type: "rtc_ice_candidate",
from: currentUsername, from: currentUsername,
to: currentTarget, channelId: currentChannelId,
candidate: event.candidate.candidate, candidate: event.candidate.candidate,
sdpMid: event.candidate.sdpMid, sdpMid: event.candidate.sdpMid,
sdpMLineIndex: event.candidate.sdpMLineIndex sdpMLineIndex: event.candidate.sdpMLineIndex
@@ -169,20 +174,20 @@
} }
} }
async function startCall() { async function joinChannelCall() {
LogMessage("Current username: " + currentUsername); LogMessage("Current username: " + currentUsername);
try { LogMessage("Current channel: " + currentChannelId);
currentTarget = document.getElementById("targetUser").value;
if (!currentTarget) { try {
LogMessage("No target user set."); if (!currentChannelId) {
LogMessage("No current channel set.");
return; return;
} }
await ensurePeerConnection(); await ensurePeerConnection();
await ensureLocalMedia(); await ensureLocalMedia();
LogMessage(`Starting call with media: audio=${hasAudioTrack()} video=${hasVideoTrack()}`); LogMessage(`Joining call with media: audio=${hasAudioTrack()} video=${hasVideoTrack()}`);
const offer = await peerConnection.createOffer(); const offer = await peerConnection.createOffer();
await peerConnection.setLocalDescription(offer); await peerConnection.setLocalDescription(offer);
@@ -190,14 +195,14 @@
const payload = { const payload = {
type: "rtc_offer", type: "rtc_offer",
from: currentUsername, from: currentUsername,
to: currentTarget, channelId: currentChannelId,
sdp: offer.sdp sdp: offer.sdp
}; };
LogMessage("Sending offer to " + currentTarget); LogMessage("Sending offer to channel " + currentChannelId);
await window.HybridWebView.InvokeDotNet("SendRtcSignal", [JSON.stringify(payload)]); await window.HybridWebView.InvokeDotNet("SendRtcSignal", [JSON.stringify(payload)]);
} catch (err) { } catch (err) {
LogMessage("startCall failed: " + err); LogMessage("joinChannelCall failed: " + err);
} }
} }
@@ -205,13 +210,12 @@
try { try {
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); LogMessage("Received signal: " + msg.type + " from " + msg.from + " in " + msg.channelId);
await ensurePeerConnection(); await ensurePeerConnection();
if (msg.type === "rtc_offer") { if (msg.type === "rtc_offer") {
currentTarget = msg.from; LogMessage("Incoming channel call offer from " + msg.from);
LogMessage("Incoming call from " + msg.from);
await ensureLocalMedia(); await ensureLocalMedia();
LogMessage(`Answering call with media: audio=${hasAudioTrack()} video=${hasVideoTrack()}`); LogMessage(`Answering call with media: audio=${hasAudioTrack()} video=${hasVideoTrack()}`);
@@ -228,11 +232,11 @@
const payload = { const payload = {
type: "rtc_answer", type: "rtc_answer",
from: currentUsername, from: currentUsername,
to: msg.from, channelId: msg.channelId,
sdp: answer.sdp sdp: answer.sdp
}; };
LogMessage("Sending answer to " + msg.from); LogMessage("Sending answer to channel " + msg.channelId);
await window.HybridWebView.InvokeDotNet("SendRtcSignal", [JSON.stringify(payload)]); await window.HybridWebView.InvokeDotNet("SendRtcSignal", [JSON.stringify(payload)]);
return; return;
} }
@@ -335,10 +339,8 @@
</div> </div>
<div> <div>
<label for="targetUser">Target User:</label>
<input id="targetUser" type="text" value="Ru_Kira" />
<button onclick="loadDevices()">Refresh Devices</button> <button onclick="loadDevices()">Refresh Devices</button>
<button onclick="startCall()">Start Call</button> <button onclick="joinChannelCall()">Join Call</button>
</div> </div>
<div style="margin-top: 8px;"> <div style="margin-top: 8px;">

View File

@@ -2,9 +2,9 @@
public class RtcSignalMessage public class RtcSignalMessage
{ {
public required string Type { get; set; } // rtc_offer / rtc_answer / rtc_ice_candidate / rtc_call_request / rtc_call_accept / rtc_call_reject public required string Type { get; set; } // rtc_join / rtc_offer / rtc_answer / rtc_ice_candidate / rtc_leave
public required string From { get; set; } public required string From { get; set; }
public required string To { get; set; } public required string ChannelId { get; set; }
public string? Sdp { get; set; } public string? Sdp { get; set; }
public string? Candidate { get; set; } public string? Candidate { get; set; }

View File

@@ -4,7 +4,7 @@ public class SocketRtcSignalMessage
{ {
public required string Type { get; set; } // encrypted_rtc_signal public required string Type { get; set; } // encrypted_rtc_signal
public required string SenderUsername { get; set; } public required string SenderUsername { get; set; }
public required string RecipientUsername { get; set; } public required string ChannelId { get; set; }
public required string CipherText { get; set; } public required string CipherText { get; set; }
public required string Nonce { get; set; } public required string Nonce { get; set; }

View File

@@ -384,23 +384,22 @@ public class ChatTest : WebSocketBehavior
return; return;
} }
var targetClient = Task.Run(async () => await ClientKeyService.GetByUsernameAsync(clientPayload.RecipientUsername)) var allKeys = Task.Run(async () => await ClientKeyService.GetAllAsync())
.GetAwaiter() .GetAwaiter()
.GetResult(); .GetResult();
if (targetClient is null) foreach (var client in allKeys)
{ {
Console.WriteLine($"No target RTC client key found for {clientPayload.RecipientUsername}"); if (client.Username == clientPayload.SenderUsername)
return; continue;
}
var encrypted = E2EeHelper.EncryptForRecipient(plainJson, targetClient.PublicKey); var encrypted = E2EeHelper.EncryptForRecipient(plainJson, client.PublicKey);
var outbound = new SocketRtcSignalMessage var outbound = new SocketRtcSignalMessage
{ {
Type = "encrypted_rtc_signal", Type = "encrypted_rtc_signal",
SenderUsername = clientPayload.SenderUsername, SenderUsername = clientPayload.SenderUsername,
RecipientUsername = clientPayload.RecipientUsername, ChannelId = clientPayload.ChannelId,
CipherText = encrypted.CipherText, CipherText = encrypted.CipherText,
Nonce = encrypted.Nonce, Nonce = encrypted.Nonce,
Tag = encrypted.Tag, Tag = encrypted.Tag,
@@ -410,3 +409,4 @@ public class ChatTest : WebSocketBehavior
Sessions.Broadcast(JsonSerializer.Serialize(outbound)); Sessions.Broadcast(JsonSerializer.Serialize(outbound));
} }
} }
}