Update: Channel Based VC (Same Issues)
This commit is contained in:
@@ -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.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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; }
|
||||||
|
|||||||
@@ -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; }
|
||||||
|
|||||||
@@ -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;">
|
||||||
|
|||||||
@@ -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; }
|
||||||
|
|||||||
@@ -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; }
|
||||||
|
|||||||
@@ -384,29 +384,29 @@ 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, client.PublicKey);
|
||||||
|
|
||||||
|
var outbound = new SocketRtcSignalMessage
|
||||||
|
{
|
||||||
|
Type = "encrypted_rtc_signal",
|
||||||
|
SenderUsername = clientPayload.SenderUsername,
|
||||||
|
ChannelId = clientPayload.ChannelId,
|
||||||
|
CipherText = encrypted.CipherText,
|
||||||
|
Nonce = encrypted.Nonce,
|
||||||
|
Tag = encrypted.Tag,
|
||||||
|
EncryptedKey = encrypted.EncryptedKey
|
||||||
|
};
|
||||||
|
|
||||||
|
Sessions.Broadcast(JsonSerializer.Serialize(outbound));
|
||||||
}
|
}
|
||||||
|
|
||||||
var encrypted = E2EeHelper.EncryptForRecipient(plainJson, targetClient.PublicKey);
|
|
||||||
|
|
||||||
var outbound = new SocketRtcSignalMessage
|
|
||||||
{
|
|
||||||
Type = "encrypted_rtc_signal",
|
|
||||||
SenderUsername = clientPayload.SenderUsername,
|
|
||||||
RecipientUsername = clientPayload.RecipientUsername,
|
|
||||||
CipherText = encrypted.CipherText,
|
|
||||||
Nonce = encrypted.Nonce,
|
|
||||||
Tag = encrypted.Tag,
|
|
||||||
EncryptedKey = encrypted.EncryptedKey
|
|
||||||
};
|
|
||||||
|
|
||||||
Sessions.Broadcast(JsonSerializer.Serialize(outbound));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user