using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Threading; using FragLabs.Audio.Codecs; using FragLabs.Audio.Codecs.Opus; using Global.Util; using Sandbox.Game.VoiceChat; using Torch.API; using Torch.Managers; using Torch.Utils; using VRage.Library.Collections; using VRage.Network; namespace Global { public class AudioSendManager : Manager { [ReflectedMethodInfo(typeof(MyVoiceChatSessionComponent), "SendVoicePlayer")] private static readonly MethodInfo _sendVoiceMethod; private readonly LegacyConfig _configData; private readonly object _lock = new object(); private readonly Dictionary _plays = new Dictionary(); private readonly SendBuffer _sendBuffer = new SendBuffer(); private readonly Thread _thread; private byte[] _buffer = Array.Empty(); private OpusEncoder _encoder; public AudioSendManager(ITorchBase torchInstance, LegacyConfig configData) : base(torchInstance) { _configData = configData; _thread = new Thread(UpdateProc); } public override void Attach() { base.Attach(); _encoder = OpusEncoder.Create(24000, 1, Application.Restricted_LowLatency); _thread.Start(); } public override void Detach() { base.Detach(); _encoder.Dispose(); _thread.Join(1); } private void UpdateProc() { while (true) { lock (_lock) { foreach (var (player, stream) in _plays) { // if stream can read and is not at the end if (stream.CanRead && stream.Position < stream.Length) { ArrayExtensions.EnsureCapacity(ref _buffer, _configData.SendDataMs * 48); var sampleLength = stream.Read(_buffer, 0, _configData.SendDataMs * 48); if (sampleLength == 0) continue; _sendBuffer.SenderUserId = (long)player; _sendBuffer.VoiceDataBuffer = _encoder.Encode(_buffer, sampleLength, out var encodedLength); _sendBuffer.NumElements = encodedLength; NetworkManager.RaiseStaticEvent(_sendVoiceMethod, 0UL, _sendBuffer, new EndpointId(player)); } else { stream.Dispose(); _plays.Remove(player); } } Thread.Sleep(1); } } } } }