Client LuaCsForBarotrauma
VoipClient.cs
2 using Barotrauma.Sounds;
3 using Microsoft.Xna.Framework;
4 using System;
5 using System.Collections.Generic;
6 using System.Linq;
7 
8 namespace Barotrauma.Networking
9 {
10  class VoipClient : IDisposable
11  {
15  const float RangeNear = 0.4f;
16 
17  private readonly GameClient gameClient;
18  private readonly ClientPeer netClient;
19  private DateTime lastSendTime;
20  private readonly List<VoipQueue> queues;
21 
22  private UInt16 storedBufferID = 0;
23 
24  private static Rectangle[] voiceIconSheetRects;
25 
26  public VoipClient(GameClient gClient,ClientPeer nClient)
27  {
28  gameClient = gClient;
29  netClient = nClient;
30 
31  queues = new List<VoipQueue>();
32 
33  lastSendTime = DateTime.Now;
34  }
35 
36  public void RegisterQueue(VoipQueue queue)
37  {
38  if (queue == VoipCapture.Instance) { return; }
39  if (!queues.Contains(queue)) { queues.Add(queue); }
40  }
41 
42  public void UnregisterQueue(VoipQueue queue)
43  {
44  if (queues.Contains(queue)) { queues.Remove(queue); }
45  }
46 
47  public void SendToServer()
48  {
49  if (GameSettings.CurrentConfig.Audio.VoiceSetting == VoiceMode.Disabled)
50  {
51  if (VoipCapture.Instance != null)
52  {
53  storedBufferID = VoipCapture.Instance.LatestBufferID;
55  }
56  return;
57  }
58  else
59  {
60  try
61  {
62  if (VoipCapture.Instance == null) { VoipCapture.Create(GameSettings.CurrentConfig.Audio.VoiceCaptureDevice, storedBufferID); }
63  }
64  catch (Exception e)
65  {
66  DebugConsole.ThrowError($"VoipCature.Create failed: {e.Message} {e.StackTrace.CleanupStackTrace()}");
67  var config = GameSettings.CurrentConfig;
68  config.Audio.VoiceSetting = VoiceMode.Disabled;
69  GameSettings.SetCurrentConfig(config);
70  }
71  if (VoipCapture.Instance == null || VoipCapture.Instance.EnqueuedTotalLength <= 0) { return; }
72  }
73 
74  if (DateTime.Now >= lastSendTime + VoipConfig.SEND_INTERVAL)
75  {
76  IWriteMessage msg = new WriteOnlyMessage();
77 
78  msg.WriteByte((byte)ClientPacketHeader.VOICE);
81 
82  netClient.Send(msg, DeliveryMethod.Unreliable);
83 
84  lastSendTime = DateTime.Now;
85  }
86  }
87 
88  public void Read(IReadMessage msg)
89  {
90  byte queueId = msg.ReadByte();
91  float distanceFactor = msg.ReadRangedSingle(0.0f, 1.0f, 8);
92  VoipQueue queue = queues.Find(q => q.QueueID == queueId);
93 
94  if (queue == null)
95  {
96 #if DEBUG
97  DebugConsole.NewMessage("Couldn't find VoipQueue with id " + queueId.ToString() + "!", GUIStyle.Red);
98 #endif
99  return;
100  }
101 
102  Client client = gameClient.ConnectedClients.Find(c => c.VoipQueue == queue);
103  if (queue.Read(msg, discardData: client.Muted || client.MutedLocally))
104  {
105  if (client.Muted || client.MutedLocally) { return; }
106  if (client.VoipSound == null)
107  {
108  DebugConsole.Log("Recreating voipsound " + queueId);
109  client.VoipSound = new VoipSound(client, GameMain.SoundManager, client.VoipQueue);
110  }
112  client.RadioNoise = 0.0f;
113  if (client.Character != null && !client.Character.IsDead && !client.Character.Removed && client.Character.SpeechImpediment <= 100.0f)
114  {
115  float speechImpedimentMultiplier = 1.0f - client.Character.SpeechImpediment / 100.0f;
116  bool spectating = Character.Controlled == null;
117  float rangeMultiplier = spectating ? 2.0f : 1.0f;
118  WifiComponent senderRadio = null;
119  var messageType =
120  !client.VoipQueue.ForceLocal &&
121  ChatMessage.CanUseRadio(client.Character, out senderRadio) &&
122  ChatMessage.CanUseRadio(Character.Controlled, out var recipientRadio) &&
123  senderRadio.CanReceive(recipientRadio) ?
124  ChatMessageType.Radio : ChatMessageType.Default;
125  client.Character.ShowTextlessSpeechBubble(1.25f, ChatMessage.MessageColor[(int)messageType]);
126 
127  client.VoipSound.UseRadioFilter = messageType == ChatMessageType.Radio && !GameSettings.CurrentConfig.Audio.DisableVoiceChatFilters;
128  client.RadioNoise = 0.0f;
129  if (messageType == ChatMessageType.Radio)
130  {
131  client.VoipSound.UsingRadio = true;
132  client.VoipSound.SetRange(senderRadio.Range * RangeNear * speechImpedimentMultiplier * rangeMultiplier, senderRadio.Range * speechImpedimentMultiplier * rangeMultiplier);
133  if (distanceFactor > RangeNear && !spectating)
134  {
135  //noise starts increasing exponentially after 40% range
136  client.RadioNoise = MathF.Pow(MathUtils.InverseLerp(RangeNear, 1.0f, distanceFactor), 2);
137  }
138  }
139  else
140  {
141  client.VoipSound.UsingRadio = false;
142  client.VoipSound.SetRange(ChatMessage.SpeakRangeVOIP * RangeNear * speechImpedimentMultiplier * rangeMultiplier, ChatMessage.SpeakRangeVOIP * speechImpedimentMultiplier * rangeMultiplier);
143  }
144  client.VoipSound.UseMuffleFilter =
145  messageType != ChatMessageType.Radio && Character.Controlled != null && !GameSettings.CurrentConfig.Audio.DisableVoiceChatFilters &&
146  SoundPlayer.ShouldMuffleSound(Character.Controlled, client.Character.WorldPosition, ChatMessage.SpeakRangeVOIP, client.Character.CurrentHull);
147  }
148 
151 
152  if ((client.VoipSound.CurrentAmplitude * client.VoipSound.Gain * GameMain.SoundManager.GetCategoryGainMultiplier("voip")) > 0.1f) //TODO: might need to tweak
153  {
154  if (client.Character != null && !client.Character.Removed && !client.Character.IsDead)
155  {
156  Vector3 clientPos = new Vector3(client.Character.WorldPosition.X, client.Character.WorldPosition.Y, 0.0f);
157  Vector3 listenerPos = GameMain.SoundManager.ListenerPosition;
158  float attenuationDist = client.VoipSound.Near * 1.125f;
159  if (Vector3.DistanceSquared(clientPos, listenerPos) < attenuationDist * attenuationDist)
160  {
162  }
163  }
164  else
165  {
167  }
168  }
169  }
170  }
171 
172  public static void UpdateVoiceIndicator(GUIImage soundIcon, float voipAmplitude, float deltaTime)
173  {
174  if (voiceIconSheetRects == null)
175  {
176  var soundIconStyle = GUIStyle.GetComponentStyle("GUISoundIcon");
177  Rectangle sourceRect = soundIconStyle.Sprites.First().Value.First().Sprite.SourceRect;
178  var indexPieces = soundIconStyle.Element.GetAttribute("sheetindices").Value.Split(';');
179  voiceIconSheetRects = new Rectangle[indexPieces.Length];
180  for (int i = 0; i < indexPieces.Length; i++)
181  {
182  Point location = sourceRect.Location + XMLExtensions.ParsePoint(indexPieces[i].Trim()) * sourceRect.Size;
183  voiceIconSheetRects[i] = new Rectangle(location, sourceRect.Size);
184  }
185  }
186 
187  Pair<string, float> userdata = soundIcon.UserData as Pair<string, float>;
188  userdata.Second = Math.Max(voipAmplitude, userdata.Second - deltaTime);
189 
190  if (userdata.Second <= 0.0f)
191  {
192  soundIcon.Visible = false;
193  }
194  else
195  {
196  soundIcon.Visible = true;
197  int sheetIndex = (int)Math.Floor(userdata.Second * voiceIconSheetRects.Length);
198  sheetIndex = MathHelper.Clamp(sheetIndex, 0, voiceIconSheetRects.Length - 1);
199  soundIcon.SourceRect = voiceIconSheetRects[sheetIndex];
200  soundIcon.OverrideState = GUIComponent.ComponentState.None;
201  soundIcon.HoverColor = Color.White;
202  }
203  }
204 
205  public void Dispose()
206  {
208  }
209  }
210 }
void ShowTextlessSpeechBubble(float duration, Color color)
virtual Vector2 WorldPosition
Definition: Entity.cs:49
virtual Color HoverColor
ComponentState? OverrideState
Definition: GUIImage.cs:98
Rectangle SourceRect
Definition: GUIImage.cs:78
static GameSession?? GameSession
Definition: GameMain.cs:88
static NetLobbyScreen NetLobbyScreen
Definition: GameMain.cs:55
static Sounds.SoundManager SoundManager
Definition: GameMain.cs:80
const float SpeakRangeVOIP
This is shorter than the text chat speak range, because the voice chat is still intelligible (just qu...
static bool CanUseRadio(Character sender, bool ignoreJamming=false)
static void Create(string deviceName, UInt16? storedBufferID=null)
Definition: VoipCapture.cs:65
void RegisterQueue(VoipQueue queue)
Definition: VoipClient.cs:36
void Read(IReadMessage msg)
Definition: VoipClient.cs:88
static void UpdateVoiceIndicator(GUIImage soundIcon, float voipAmplitude, float deltaTime)
Definition: VoipClient.cs:172
VoipClient(GameClient gClient, ClientPeer nClient)
Definition: VoipClient.cs:26
void UnregisterQueue(VoipQueue queue)
Definition: VoipClient.cs:42
virtual bool Read(IReadMessage msg, bool discardData=false)
Definition: VoipQueue.cs:136
virtual void Write(IWriteMessage msg)
Definition: VoipQueue.cs:118
float GetCategoryGainMultiplier(string category, int index=-1)
void SetRange(float near, float far)
Definition: VoipSound.cs:99
Single ReadRangedSingle(Single min, Single max, int bitCount)