Reuse existing ChatHub consent and Podcast LibVLC capture for direct bidirectional H.264/AAC media, with embedded call controls and cleanup. Require HTTPS key exchange and reject IP-masking policies for this opt-in LAN/VPN transport. Add native SRTP, signaling and lifecycle tests; document setup and remaining physical-device validation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
61 lines
2.2 KiB
C#
61 lines
2.2 KiB
C#
#nullable enable
|
|
|
|
namespace Yavsc.Abstract.Chat.Calls;
|
|
|
|
public static class CallHubMethods
|
|
{
|
|
public const string Invite = "InviteCall";
|
|
public const string InviteLan = "InviteLanCall";
|
|
public const string Accept = "AcceptCall";
|
|
public const string End = "EndCall";
|
|
public const string Signal = "SendCallSignal";
|
|
public const string Invitation = "CallInvitation";
|
|
public const string Accepted = "CallAccepted";
|
|
public const string Ended = "CallEnded";
|
|
public const string SignalReceived = "CallSignal";
|
|
}
|
|
|
|
public sealed record CallSession(
|
|
Guid Id, string RoomName, string Caller, string Callee, bool RelayOnly,
|
|
DateTimeOffset ExpiresAt, string Transport = CallTransports.WebRtc);
|
|
|
|
public static class CallTransports
|
|
{
|
|
public const string WebRtc = "webrtc";
|
|
public const string LanSrtp = "lan-srtp";
|
|
}
|
|
|
|
public sealed record CallIceServer(string[] Urls, string? Username = null, string? Credential = null);
|
|
|
|
public sealed record CallAccepted(CallSession Session, CallIceServer[] IceServers);
|
|
|
|
public sealed record CallEnded(Guid CallId, string Reason);
|
|
|
|
public sealed record CallSignal(
|
|
string Kind, string? Sdp = null, string? Candidate = null,
|
|
string? SdpMid = null, int? SdpMLineIndex = null, LanCallEndpoint? Endpoint = null);
|
|
|
|
public sealed record LanCallEndpoint(string Address, int Port, string Key, string Salt)
|
|
{
|
|
public override string ToString() => "SRTP endpoint (credentials redacted)";
|
|
|
|
public bool IsValid() =>
|
|
LanCallNetwork.IsPrivateIPv4(Address) && Port is >= 1024 and <= 65534 && Port % 2 == 0 &&
|
|
Key is { Length: 32 } && Key.All(Uri.IsHexDigit) &&
|
|
Salt is { Length: 28 } && Salt.All(Uri.IsHexDigit);
|
|
}
|
|
|
|
public static class LanCallNetwork
|
|
{
|
|
public static bool IsPrivateIPv4(string address)
|
|
{
|
|
if (!System.Net.IPAddress.TryParse(address, out var ip) ||
|
|
ip.AddressFamily != System.Net.Sockets.AddressFamily.InterNetwork ||
|
|
ip.ToString() != address)
|
|
return false;
|
|
var bytes = ip.GetAddressBytes();
|
|
return bytes[0] == 10 || bytes[0] == 127 ||
|
|
(bytes[0] == 172 && bytes[1] is >= 16 and <= 31) ||
|
|
(bytes[0] == 192 && bytes[1] == 168);
|
|
}
|
|
}
|