Compare commits
2 Commits
687387b105
...
f77a5eb823
| Author | SHA1 | Date | |
|---|---|---|---|
| f77a5eb823 | |||
| d6ecb63b5f |
@@ -213,75 +213,6 @@ public partial class MainPage : ContentPage
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
|
||||||
var notificationChannelId = rtcNotification.ChannelId ?? string.Empty;
|
|
||||||
|
|
||||||
if (notificationChannelId != _currentChannelId)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// SafeSendRawToWebView("RTC notification received: " + notificationType + " for " + notificationChannelId);
|
|
||||||
|
|
||||||
MainThread.BeginInvokeOnMainThread(async () =>
|
|
||||||
{
|
|
||||||
switch (notificationType)
|
|
||||||
{
|
|
||||||
case SignalType.OfferUpdated:
|
|
||||||
{
|
|
||||||
if (rtcNotification.Username == _username)
|
|
||||||
break;
|
|
||||||
|
|
||||||
var offer = await GetRtcOffer();
|
|
||||||
await SendRtcSignalToJsAsync(offer);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SignalType.AnswerUpdated:
|
|
||||||
{
|
|
||||||
var answer = await ServerAPI.GetAnswerForChannelAsync(_currentChannelId);
|
|
||||||
if (answer is not null)
|
|
||||||
{
|
|
||||||
await AnswerCallback(answer);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
SafeSendRawToWebView($"Candidate rejected: {ex.Message}");
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SignalType.CallLeft:
|
|
||||||
{
|
|
||||||
SafeSendRawToWebView("RTC call left notification received.");
|
|
||||||
RtcLeaveCallback();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type != SignalType.EncryptedChat)
|
if (type != SignalType.EncryptedChat)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -368,7 +299,7 @@ public partial class MainPage : ContentPage
|
|||||||
if (channel.Type == ChannelType.Voice)
|
if (channel.Type == ChannelType.Voice)
|
||||||
{
|
{
|
||||||
SwapView();
|
SwapView();
|
||||||
// JoinRtcChannel(); //TODO: Join voice calls when clicking channel rather than a separate button
|
_ = JoinRtcChannel(); //TODO: Join voice calls when clicking channel rather than a separate button
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -447,26 +378,21 @@ public partial class MainPage : ContentPage
|
|||||||
ViewSwapped.Text = "Swap to Message View";
|
ViewSwapped.Text = "Swap to Message View";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SwapView_OnClicked(object? sender, EventArgs e)
|
private void SwapView_OnClicked(object? sender, EventArgs e)
|
||||||
{
|
{
|
||||||
SwapView();
|
SwapView();
|
||||||
}
|
}
|
||||||
|
|
||||||
#region RTC Functions
|
#region RTC Functions
|
||||||
public async Task JoinRtcChannel()
|
|
||||||
|
public Task JoinRtcChannel()
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(_currentChannelId))
|
if (string.IsNullOrWhiteSpace(_currentChannelId))
|
||||||
return; //false;
|
return Task.CompletedTask;
|
||||||
|
|
||||||
_wsc.Send($"RTC_JOIN_CHANNEL|{_username}|{_currentChannelId}");
|
_wsc.Send($"RTC_JOIN_CHANNEL|{_username}|{_currentChannelId}");
|
||||||
|
return Task.CompletedTask;
|
||||||
// SafeSendRawToWebView($"Attempting to join RTC Channel {_currentChannelName} | {_currentChannelId} ");
|
|
||||||
|
|
||||||
//bool active = await ServerAPI.GetIsChannelActiveAsync(_currentChannelId);
|
|
||||||
|
|
||||||
//SafeSendRawToWebView($"Rtc Channel {_currentChannelName} | {_currentChannelId} is active: {active}");
|
|
||||||
|
|
||||||
return; //active;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LeaveRtcChannel()
|
public void LeaveRtcChannel()
|
||||||
@@ -477,150 +403,8 @@ public partial class MainPage : ContentPage
|
|||||||
_wsc.Send($"RTC_LEAVE_CHANNEL|{_username}|{_currentChannelId}");
|
_wsc.Send($"RTC_LEAVE_CHANNEL|{_username}|{_currentChannelId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void WriteRtcOffer(string json)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
RtcDescription? description = JsonSerializer.Deserialize<RtcDescription>(json);
|
|
||||||
DBOffer offer = new DBOffer
|
|
||||||
{
|
|
||||||
ChannelId = _currentChannelId,
|
|
||||||
Username = _username,
|
|
||||||
SessionDescription = description
|
|
||||||
};
|
|
||||||
var response = await ServerAPI.PostOfferAsync(offer);
|
|
||||||
SafeSendRawToWebView(response.ToString());
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
SafeSendRawToWebView($"WriteRtcOffer failed: {ex.Message}");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
public async Task<string> GetRtcOffer()
|
|
||||||
{
|
|
||||||
RtcDescription? offer = await ServerAPI.GetOffersForChannelAsync(_currentChannelId);
|
|
||||||
return JsonSerializer.Serialize(offer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async void WriteRtcAnswer(string json)
|
|
||||||
{
|
|
||||||
// SafeSendRawToWebView("WriteRtcAnswer entered with: " + json);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
RtcDescription? description = JsonSerializer.Deserialize<RtcDescription>(json);
|
|
||||||
DBOffer answer = new DBOffer
|
|
||||||
{
|
|
||||||
ChannelId = _currentChannelId,
|
|
||||||
Username = _username,
|
|
||||||
SessionDescription = description
|
|
||||||
};
|
|
||||||
await ServerAPI.PostAnswerAsync(answer);
|
|
||||||
SafeSendRawToWebView("WriteRtcAnswer posted successfully");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
SafeSendRawToWebView("WriteRtcAnswer failed: " + ex.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async void WriteIceCandidate(string json)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
IceCandidate? candidate = JsonSerializer.Deserialize<IceCandidate>(json);
|
|
||||||
DBIceCandidate DBCandidate = new DBIceCandidate
|
|
||||||
{
|
|
||||||
ChannelId = _currentChannelId,
|
|
||||||
Username = _username,
|
|
||||||
Candidate = candidate
|
|
||||||
};
|
|
||||||
if (candidate == null) return;
|
|
||||||
await ServerAPI.PostIceCandidateAsync(DBCandidate);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
SafeSendRawToWebView("WriteIceCandidate failed: " + ex.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async void IceCandidateCallback(IceCandidate candidate)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await hybridWebView.InvokeJavaScriptAsync("IceCandidateAdded", [candidate], [HybridJSType.Default.IceCandidate]);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
SafeSendRawToWebView("WriteIceCandidate failed: " + ex.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public async Task AnswerCallback(RtcDescription answer)
|
|
||||||
{
|
|
||||||
answer.sdp = answer.sdp.Replace("\r\n", "(rn)");
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await hybridWebView.InvokeJavaScriptAsync("AnswerCallbackJS", [answer], [HybridJSType.Default.RtcDescription]);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
SafeSendRawToWebView("AnswerCallback failed: " + ex.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async void RtcLeaveCallback()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await hybridWebView.InvokeJavaScriptAsync("RtcLeaveCall", [], []);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
SafeSendRawToWebView("RtcLeaveCallback failed: " + ex.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task SendRtcSignalToJsAsync(string rawJson)
|
|
||||||
{
|
|
||||||
MainThread.BeginInvokeOnMainThread(async () =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
SafeSendRawToWebView("Dispatching RTC signal to JS");
|
|
||||||
|
|
||||||
var jsArg = JsonSerializer.Serialize(rawJson);
|
|
||||||
|
|
||||||
await hybridWebView.EvaluateJavaScriptAsync(
|
|
||||||
$"window.RelaySocket.receiveRtcSignal({jsArg})"
|
|
||||||
);
|
|
||||||
|
|
||||||
SafeSendRawToWebView("RTC signal dispatched to JS");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
SafeSendRawToWebView("SendRtcSignalToJsAsync failed: " + ex.Message);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
} //Remove?
|
|
||||||
|
|
||||||
private async Task PushRtcContextToJsAsync()
|
|
||||||
{
|
|
||||||
var usernameJson = JsonSerializer.Serialize(_username);
|
|
||||||
var channelIdJson = JsonSerializer.Serialize(_currentChannelId);
|
|
||||||
|
|
||||||
await hybridWebView.EvaluateJavaScriptAsync($"window.setUsername({usernameJson})");
|
|
||||||
await hybridWebView.EvaluateJavaScriptAsync($"window.setChannelId({channelIdJson})");
|
|
||||||
|
|
||||||
Console.WriteLine($"[{_username}] pushed RTC context into HybridWebView.");
|
|
||||||
} //Remove?
|
|
||||||
|
|
||||||
public void SendRtcSignal(string json)
|
public void SendRtcSignal(string json)
|
||||||
{
|
{
|
||||||
SafeSendRawToWebView("SendRtcSignal entered: " + json);
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(_serverPublicKey))
|
if (string.IsNullOrWhiteSpace(_serverPublicKey))
|
||||||
{
|
{
|
||||||
SafeSendRawToWebView("SendRtcSignal failed: server public key not loaded.");
|
SafeSendRawToWebView("SendRtcSignal failed: server public key not loaded.");
|
||||||
@@ -640,20 +424,25 @@ public partial class MainPage : ContentPage
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (rtcSignal is null)
|
if (rtcSignal is null)
|
||||||
{
|
|
||||||
SafeSendRawToWebView("SendRtcSignal failed: rtcSignal was null.");
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
if (string.IsNullOrWhiteSpace(rtcSignal.ChannelId))
|
||||||
|
rtcSignal.ChannelId = _currentChannelId;
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(rtcSignal.From))
|
||||||
|
rtcSignal.From = _username;
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(rtcSignal.ChannelId))
|
if (string.IsNullOrWhiteSpace(rtcSignal.ChannelId))
|
||||||
{
|
{
|
||||||
SafeSendRawToWebView("SendRtcSignal failed: channelId was empty.");
|
SafeSendRawToWebView("SendRtcSignal failed: missing channel id.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var outgoingJson = JsonSerializer.Serialize(rtcSignal);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var encrypted = E2EeHelper.EncryptForRecipient(json, _serverPublicKey);
|
var encrypted = E2EeHelper.EncryptForRecipient(outgoingJson, _serverPublicKey);
|
||||||
|
|
||||||
var payload = new SocketRtcSignalMessage
|
var payload = new SocketRtcSignalMessage
|
||||||
{
|
{
|
||||||
@@ -666,29 +455,71 @@ public partial class MainPage : ContentPage
|
|||||||
EncryptedKey = encrypted.EncryptedKey
|
EncryptedKey = encrypted.EncryptedKey
|
||||||
};
|
};
|
||||||
|
|
||||||
var socketJson = JsonSerializer.Serialize(payload);
|
_wsc.Send(JsonSerializer.Serialize(payload));
|
||||||
_wsc.Send(socketJson);
|
|
||||||
|
|
||||||
SafeSendRawToWebView($"SendRtcSignal sent: {rtcSignal.Type} -> {rtcSignal.ChannelId}");
|
SafeSendRawToWebView($"SendRtcSignal sent: {rtcSignal.Type} -> {rtcSignal.To}");
|
||||||
Console.WriteLine($"[{_username}] sent RTC signal: {rtcSignal.Type} -> {rtcSignal.ChannelId}");
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
SafeSendRawToWebView("SendRtcSignal websocket/encrypt failed: " + ex.Message);
|
SafeSendRawToWebView("SendRtcSignal failed: " + ex.Message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} //Remove?
|
|
||||||
|
|
||||||
public async Task<string> GetRtcParticipants()
|
public async Task<string> GetRtcParticipants()
|
||||||
{
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(_currentChannelId))
|
||||||
|
return "[]";
|
||||||
|
|
||||||
var participants = await ServerAPI.GetRtcParticipantsAsync(_currentChannelId);
|
var participants = await ServerAPI.GetRtcParticipantsAsync(_currentChannelId);
|
||||||
return JsonSerializer.Serialize(participants);
|
return JsonSerializer.Serialize(participants ?? []);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task SendRtcSignalToJsAsync(string rawJson)
|
||||||
|
{
|
||||||
|
MainThread.BeginInvokeOnMainThread(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var jsArg = JsonSerializer.Serialize(rawJson);
|
||||||
|
|
||||||
|
await hybridWebView.EvaluateJavaScriptAsync($@"
|
||||||
|
try {{
|
||||||
|
window.HybridWebView.SendRawMessage('C# eval entered');
|
||||||
|
|
||||||
|
if (!window.RelaySocket) {{
|
||||||
|
window.HybridWebView.SendRawMessage('window.RelaySocket missing');
|
||||||
|
}} else if (typeof window.RelaySocket.receiveRtcSignal !== 'function') {{
|
||||||
|
window.HybridWebView.SendRawMessage('RelaySocket.receiveRtcSignal missing');
|
||||||
|
}} else {{
|
||||||
|
window.HybridWebView.SendRawMessage('Calling RelaySocket.receiveRtcSignal');
|
||||||
|
window.RelaySocket.receiveRtcSignal({jsArg});
|
||||||
|
}}
|
||||||
|
}} catch (err) {{
|
||||||
|
window.HybridWebView.SendRawMessage('RTC JS dispatch failed: ' + err);
|
||||||
|
}}
|
||||||
|
");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
SafeSendRawToWebView("SendRtcSignalToJsAsync failed: " + ex.Message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task PushRtcContextToJsAsync()
|
||||||
|
{
|
||||||
|
var usernameJson = JsonSerializer.Serialize(_username);
|
||||||
|
var channelIdJson = JsonSerializer.Serialize(_currentChannelId);
|
||||||
|
|
||||||
|
await hybridWebView.EvaluateJavaScriptAsync($"window.setUsername({usernameJson})");
|
||||||
|
await hybridWebView.EvaluateJavaScriptAsync($"window.setChannelId({channelIdJson})");
|
||||||
|
|
||||||
|
Console.WriteLine($"[{_username}] pushed RTC context into HybridWebView.");
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
private void OnSendMessageButtonClicked(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
SafeSendRawToWebView($"Hello from C#!");
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void OnHybridWebViewRawMessageReceived(object sender, HybridWebViewRawMessageReceivedEventArgs e)
|
private async void OnHybridWebViewRawMessageReceived(object sender, HybridWebViewRawMessageReceivedEventArgs e)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user