Fixed all underlying issues with the "Answer" call.
This commit is contained in:
@@ -197,6 +197,55 @@ public partial class MainPage : ContentPage
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type == "rtc_offer_updated" || type == "rtc_answer_updated" || type == "rtc_candidate_added" || type == "rtc_call_left")
|
||||||
|
{
|
||||||
|
var rtcNotification = JsonSerializer.Deserialize<RtcNotificationMessage>(e.Data);
|
||||||
|
if (rtcNotification is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var notificationType = rtcNotification.Type ?? string.Empty;
|
||||||
|
var notificationChannelId = rtcNotification.ChannelId ?? string.Empty;
|
||||||
|
|
||||||
|
if (notificationChannelId != _currentChannelId)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SafeSendRawToWebView("RTC notification received: " + notificationType + " for " + notificationChannelId);
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
var json = JsonSerializer.Serialize(answer);
|
||||||
|
await hybridWebView.EvaluateJavaScriptAsync($"window.AnswerCallback({json})");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "rtc_candidate_added":
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "rtc_call_left":
|
||||||
|
{
|
||||||
|
SafeSendRawToWebView("RTC call left notification received.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (type != "encrypted_chat")
|
if (type != "encrypted_chat")
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -358,15 +407,28 @@ public partial class MainPage : ContentPage
|
|||||||
|
|
||||||
public async Task<bool> JoinRtcChannel()
|
public async Task<bool> JoinRtcChannel()
|
||||||
{
|
{
|
||||||
//TODO: get bool value for if channel ID has an active call
|
if (string.IsNullOrWhiteSpace(_currentChannelId))
|
||||||
//TODO: Join RTC using current channel ID
|
return false;
|
||||||
SafeSendRawToWebView($"Attempting to join RTC Channel {_currentChannelName}");
|
|
||||||
bool active = await ServerAPI.GetIsChannelActiveAsync(_currentChannelId);
|
|
||||||
SafeSendRawToWebView($"Rtc Channel {_currentChannelName} is active: {active}");
|
|
||||||
return active;
|
|
||||||
//await hybridWebView.EvaluateJavaScriptAsync($"window.channelCallJoin({active})");
|
|
||||||
|
|
||||||
|
_wsc.Send($"RTC_JOIN_CHANNEL|{_username}|{_currentChannelId}");
|
||||||
|
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(_currentChannelId))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_wsc.Send($"RTC_LEAVE_CHANNEL|{_username}|{_currentChannelId}");
|
||||||
|
}
|
||||||
|
|
||||||
public async void WriteRtcOffer(string json)
|
public async void WriteRtcOffer(string json)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -391,21 +453,33 @@ public partial class MainPage : ContentPage
|
|||||||
RtcDescription? offer = await ServerAPI.GetOffersForChannelAsync(_currentChannelId);
|
RtcDescription? offer = await ServerAPI.GetOffersForChannelAsync(_currentChannelId);
|
||||||
return JsonSerializer.Serialize(offer);
|
return JsonSerializer.Serialize(offer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void WriteRtcAnswer(string json)
|
public async void WriteRtcAnswer(string json)
|
||||||
{
|
{
|
||||||
RtcDescription? description = JsonSerializer.Deserialize<RtcDescription>(json);
|
SafeSendRawToWebView("WriteRtcAnswer entered with: " + json);
|
||||||
DBOffer answer = new DBOffer
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
ChannelId = _currentChannelId,
|
RtcDescription? description = JsonSerializer.Deserialize<RtcDescription>(json);
|
||||||
Username = _username,
|
DBOffer answer = new DBOffer
|
||||||
SessionDescription = description
|
{
|
||||||
};
|
ChannelId = _currentChannelId,
|
||||||
await ServerAPI.PostAnswerAsync(answer);
|
Username = _username,
|
||||||
|
SessionDescription = description
|
||||||
|
};
|
||||||
|
await ServerAPI.PostAnswerAsync(answer);
|
||||||
|
SafeSendRawToWebView("WriteRtcAnswer posted successfully");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
SafeSendRawToWebView("WriteRtcAnswer failed: " + ex.Message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void AnswerCallback(RtcDescription answer)
|
public async void AnswerCallback(RtcDescription answer)
|
||||||
{
|
{
|
||||||
await hybridWebView.EvaluateJavaScriptAsync($"window.AnswerCallback({answer})");
|
var json = JsonSerializer.Serialize(answer);
|
||||||
|
await hybridWebView.EvaluateJavaScriptAsync($"window.AnswerCallback({json})");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnSendMessageButtonClicked(object sender, EventArgs e)
|
private void OnSendMessageButtonClicked(object sender, EventArgs e)
|
||||||
|
|||||||
9
RelayClient/Models/RtcNotificationMessage.cs
Normal file
9
RelayClient/Models/RtcNotificationMessage.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
namespace RelayClient.Models;
|
||||||
|
|
||||||
|
public sealed class RtcNotificationMessage
|
||||||
|
{
|
||||||
|
public string? Type { get; set; }
|
||||||
|
public string? ChannelId { get; set; }
|
||||||
|
public string? Username { get; set; }
|
||||||
|
public string? Direction { get; set; }
|
||||||
|
}
|
||||||
@@ -231,8 +231,10 @@ async function channelCallJoin(activeCall)
|
|||||||
const answer = await peerConnection.createAnswer();
|
const answer = await peerConnection.createAnswer();
|
||||||
await peerConnection.setLocalDescription(answer);
|
await peerConnection.setLocalDescription(answer);
|
||||||
|
|
||||||
LogMessage(`Joining call with media answer: ${JSON.stringify(answer)}`);
|
LogMessage("Joining call with media answer: " + JSON.stringify(answer));
|
||||||
await window.HybridWebView.InvokeDotNet("WriteRtcAnswer", [JSON.stringify(roomAnswer)]);
|
LogMessage("Calling C# WriteRtcAnswer with: " + JSON.stringify(answer));
|
||||||
|
await window.HybridWebView.InvokeDotNet("WriteRtcAnswer", [JSON.stringify(answer)]);
|
||||||
|
LogMessage("C# WriteRtcAnswer invoked");
|
||||||
//TODO: Update offer in SurrealDB to include answer
|
//TODO: Update offer in SurrealDB to include answer
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -45,9 +45,14 @@ public class ServerAPI
|
|||||||
return offer;
|
return offer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<Uri> PostAnswerAsync(DBOffer answer)
|
public static async Task<Uri?> PostAnswerAsync(DBOffer answer)
|
||||||
{
|
{
|
||||||
HttpResponseMessage response = await client.PostAsJsonAsync("api/rtc/answer", answer);
|
HttpResponseMessage response = await client.PostAsJsonAsync("api/rtc/answer", answer);
|
||||||
|
var body = await response.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
|
Console.WriteLine("PostAnswerAsync status: " + response.StatusCode);
|
||||||
|
Console.WriteLine("PostAnswerAsync body: " + body);
|
||||||
|
|
||||||
response.EnsureSuccessStatusCode();
|
response.EnsureSuccessStatusCode();
|
||||||
return response.Headers.Location;
|
return response.Headers.Location;
|
||||||
}
|
}
|
||||||
@@ -94,6 +99,18 @@ public class ServerAPI
|
|||||||
return response.Headers.Location;
|
return response.Headers.Location;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async Task<RtcDescription?> GetAnswerForChannelAsync(string? channelId)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(channelId))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
HttpResponseMessage response = await client.GetAsync($"api/rtc/answer/{channelId}");
|
||||||
|
if (!response.IsSuccessStatusCode)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var json = await response.Content.ReadAsStringAsync();
|
||||||
|
return JsonSerializer.Deserialize<RtcDescription>(json);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class RtcDescription
|
public class RtcDescription
|
||||||
|
|||||||
@@ -49,15 +49,11 @@ public static class RtcEndpoints
|
|||||||
// Store a new SDP answer for the specified channel call.
|
// Store a new SDP answer for the specified channel call.
|
||||||
app.MapPost("/api/rtc/answer", async (RtcOffer request, RtcCallService rtcCallService) =>
|
app.MapPost("/api/rtc/answer", async (RtcOffer request, RtcCallService rtcCallService) =>
|
||||||
{
|
{
|
||||||
|
Console.WriteLine($"RTC answer received for channel {request.ChannelId} from {request.Username}");
|
||||||
|
|
||||||
await rtcCallService.WriteAnswerAsync(request.ChannelId, request.SessionDescription);
|
await rtcCallService.WriteAnswerAsync(request.ChannelId, request.SessionDescription);
|
||||||
//DON'T FUCKING HARDCODE STRINGS INTO API REQUESTS
|
|
||||||
// await rtcCallService.WriteAnswerAsync(
|
Console.WriteLine($"Broadcasting rtc_answer_updated for {request.ChannelId}");
|
||||||
// request.ChannelId,
|
|
||||||
// new RtcSessionDescription
|
|
||||||
// {
|
|
||||||
// Type = "answer",
|
|
||||||
// Sdp = request.Sdp
|
|
||||||
// });
|
|
||||||
|
|
||||||
RtcNotificationService.BroadcastToChannel(new RtcNotificationMessage
|
RtcNotificationService.BroadcastToChannel(new RtcNotificationMessage
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -124,13 +124,14 @@ public sealed class RtcCallService
|
|||||||
/// <returns>
|
/// <returns>
|
||||||
/// A list of answers for the channel ordered from oldest to newest.
|
/// A list of answers for the channel ordered from oldest to newest.
|
||||||
/// </returns>
|
/// </returns>
|
||||||
public async Task<List<RtcAnswer>> GetAnswersAsync(string channelId)
|
public async Task<List<RtcSessionDescription>> GetAnswersAsync(string channelId)
|
||||||
{
|
{
|
||||||
var answers = await _db.Select<RtcAnswer>("rtc_answers");
|
var activeCall = await GetActiveCallAsync(channelId);
|
||||||
return answers
|
|
||||||
.Where(x => x.ChannelId == channelId)
|
if (activeCall?.Answer is null)
|
||||||
.OrderBy(x => x.CreatedAt)
|
return [];
|
||||||
.ToList();
|
|
||||||
|
return [activeCall.Answer];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -140,13 +141,10 @@ public sealed class RtcCallService
|
|||||||
/// <returns>
|
/// <returns>
|
||||||
/// The newest answer for the channel, or null if no answer exists.
|
/// The newest answer for the channel, or null if no answer exists.
|
||||||
/// </returns>
|
/// </returns>
|
||||||
public async Task<RtcAnswer?> GetLatestAnswerAsync(string channelId)
|
public async Task<RtcSessionDescription?> GetLatestAnswerAsync(string channelId)
|
||||||
{
|
{
|
||||||
var answers = await _db.Select<RtcAnswer>("rtc_answers");
|
var activeCall = await GetActiveCallAsync(channelId);
|
||||||
return answers
|
return activeCall?.Answer;
|
||||||
.Where(x => x.ChannelId == channelId)
|
|
||||||
.OrderByDescending(x => x.CreatedAt)
|
|
||||||
.FirstOrDefault();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
Reference in New Issue
Block a user