-
-
Notifications
You must be signed in to change notification settings - Fork 120
/
VOIPPacketHandler.cs
151 lines (121 loc) · 5.44 KB
/
VOIPPacketHandler.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using Ciribob.DCS.SimpleRadio.Standalone.Common;
using DotNetty.Transport.Channels.Groups;
using NLog;
using Xceed.Wpf.Toolkit.Converters;
namespace Ciribob.DCS.SimpleRadio.Standalone.Server.Network
{
using System;
using System.Collections.Concurrent;
using System.Text;
using DotNetty.Buffers;
using DotNetty.Transport.Channels;
public class VOIPPacketHandler : ChannelHandlerAdapter
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
static volatile IChannelGroup group;
private ConcurrentDictionary<string, SRClient> _clientsList;
private readonly ServerSettings _serverSettings = ServerSettings.Instance;
public VOIPPacketHandler(ConcurrentDictionary<string, SRClient> clientsList)
{
_clientsList = clientsList;
}
public override void ChannelActive(IChannelHandlerContext contex)
{
IChannelGroup g = group;
if (g == null)
{
lock (this)
{
if (group == null)
{
g = group = new DefaultChannelGroup(contex.Executor);
}
}
}
g.Add(contex.Channel);
}
class AllMatchingChannels : IChannelMatcher
{
private HashSet<string> matchingClients;
public AllMatchingChannels(HashSet<string> matchingClients)
{
this.matchingClients = matchingClients;
}
public bool Matches(IChannel channel)
{
return matchingClients.Contains(channel.Id.AsShortText());
}
}
public override void ChannelRead(IChannelHandlerContext context, object message)
{
var byteBuffer = message as IByteBuffer;
if (byteBuffer != null)
{
byte[] udpData = new byte[byteBuffer.ReadableBytes];
byteBuffer.GetBytes(0, udpData);
var decodedPacket = UDPVoicePacket.DecodeVoicePacket(udpData, false);
SRClient srClient;
if (_clientsList.TryGetValue(decodedPacket.Guid, out srClient))
{
srClient.ClientChannelId = context.Channel.Id.AsShortText();
var spectatorAudioDisabled =
_serverSettings.ServerSetting[(int) ServerSettingType.SPECTATORS_AUDIO_DISABLED];
if ((srClient.Coalition == 0) && spectatorAudioDisabled)
{
return;
}
else
{
HashSet<string> matchingClients = new HashSet<string>();
if (decodedPacket.Modulation != 4)
//magical ignore message 4 - just used for ping
{
var coalitionSecurity =
_serverSettings.ServerSetting[(int) ServerSettingType.COALITION_AUDIO_SECURITY];
foreach (KeyValuePair<string, SRClient> _client in _clientsList)
{
//dont send to receiver
if (_client.Value.ClientGuid != decodedPacket.Guid)
{
//check frequencies
if ((!coalitionSecurity || (_client.Value.Coalition == srClient.Coalition)))
{
var radioInfo = _client.Value.RadioInfo;
if (radioInfo != null)
{
RadioReceivingState radioReceivingState = null;
var receivingRadio = radioInfo.CanHearTransmission(decodedPacket.Frequency,
(RadioInformation.Modulation) decodedPacket.Modulation,
decodedPacket.UnitId, out radioReceivingState);
//only send if we can hear!
if (receivingRadio != null)
matchingClients.Add(_client.Value.ClientChannelId);
}
}
}
}
//send to other connected clients
if (matchingClients.Count > 0)
{
group.WriteAndFlushAsync(message, new AllMatchingChannels(matchingClients));
}
}
}
}
}
}
public override void ChannelReadComplete(IChannelHandlerContext context) => context.Flush();
public override void ExceptionCaught(IChannelHandlerContext context, Exception exception)
{
Logger.Log(LogLevel.Error,exception,"Exception processing voip: "+exception.Message);
context.CloseAsync();
}
public override bool IsSharable => true;
}
}