Files
QuartZ-dump/GlobalTorch/AudioSendManager.cs
2024-12-29 21:15:58 +01:00

90 lines
2.9 KiB
C#

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<ulong, Stream> _plays = new Dictionary<ulong, Stream>();
private readonly SendBuffer _sendBuffer = new SendBuffer();
private readonly Thread _thread;
private byte[] _buffer = Array.Empty<byte>();
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<ulong, BitReaderWriter>(_sendVoiceMethod, 0UL,
_sendBuffer,
new EndpointId(player));
}
else
{
stream.Dispose();
_plays.Remove(player);
}
}
Thread.Sleep(1);
}
}
}
}
}