Skip to content

Commit

Permalink
Small performance improvements
Browse files Browse the repository at this point in the history
- tiny performance improvement in the encoder
- added early chain abort check
- readded stall checker
  • Loading branch information
Splamy committed Feb 22, 2018
1 parent 7549fa3 commit 25b19d7
Show file tree
Hide file tree
Showing 35 changed files with 218 additions and 127 deletions.
25 changes: 18 additions & 7 deletions TS3AudioBot/Audio/CustomTargetPipe.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ namespace TS3AudioBot.Audio
using System.Collections.Generic;
using System.Linq;
using TS3Client;
using TS3Client.Audio;
using TS3Client.Full;
using TS3Client.Full.Audio;

internal class CustomTargetPipe : ITargetManager, IAudioPassiveConsumer
{
Expand All @@ -24,6 +24,23 @@ internal class CustomTargetPipe : ITargetManager, IAudioPassiveConsumer
public GroupWhisperType GroupWhisperType { get; set; }
public GroupWhisperTarget GroupWhisperTarget { get; set; }

public bool Active
{
get
{
switch (SendMode)
{
case TargetSendMode.None:
return false;
case TargetSendMode.Whisper:
UpdatedSubscriptionCache();
return channelSubscriptionsCache.Length > 0 || clientSubscriptionsCache.Length > 0;
default:
return true;
}
}
}

private readonly Dictionary<ulong, bool> channelSubscriptionsSetup;
private readonly List<ushort> clientSubscriptionsSetup;
private ulong[] channelSubscriptionsCache;
Expand Down Expand Up @@ -64,10 +81,6 @@ public void Write(Span<byte> data, Meta meta)
}
}

// TODO get this somehow to the front of the pipechain, to prevent further chain execution
// if (SendMode == TargetSendMode.Whisper)
// doSend &= channelSubscriptionsCache.Length > 0 || clientSubscriptionsCache.Length > 0;

#region ITargetManager

public void SetGroupWhisper(GroupWhisperType type, GroupWhisperTarget target, ulong targetId = 0)
Expand All @@ -79,8 +92,6 @@ public void SetGroupWhisper(GroupWhisperType type, GroupWhisperTarget target, ul

public void WhisperChannelSubscribe(ulong channel, bool temp)
{
// TODO move to requested channel
// TODO spawn new client
lock (subscriptionLockObj)
{
if (channelSubscriptionsSetup.TryGetValue(channel, out var subscriptionTemp))
Expand Down
2 changes: 1 addition & 1 deletion TS3AudioBot/Audio/FfmpegProducer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace TS3AudioBot.Audio
using System.Diagnostics;
using System.Globalization;
using System.Text.RegularExpressions;
using TS3Client.Full.Audio;
using TS3Client.Audio;

public class FfmpegProducer : IAudioPassiveProducer, ISampleInfo, IDisposable
{
Expand Down
64 changes: 64 additions & 0 deletions TS3AudioBot/Audio/StallCheckPipe.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// TS3AudioBot - An advanced Musicbot for Teamspeak 3
// Copyright (C) 2017 TS3AudioBot contributors
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the Open Software License v. 3.0
//
// You should have received a copy of the Open Software License along with this
// program. If not, see <https://opensource.org/licenses/OSL-3.0>.

namespace TS3AudioBot.Audio
{
using System;
using TS3Client.Audio;

public class StallCheckPipe : IAudioPipe
{
private const uint StallCountInterval = 10;
private const uint StallNoErrorCountMax = 5;

public bool Active => OutStream?.Active ?? false;
public IAudioPassiveConsumer OutStream { get; set; }

private bool isStall;
private uint stallCount;
private uint stallNoErrorCount;

public StallCheckPipe()
{
isStall = false;
stallCount = 0;
}

public void Write(Span<byte> data, Meta meta)
{
if (OutStream == null) return;

if (isStall)
{
// TODO maybe do time-cooldown instead of call-count-cooldown
if (++stallCount % StallCountInterval == 0)
{
stallNoErrorCount++;
if (stallNoErrorCount > StallNoErrorCountMax)
{
stallCount = 0;
isStall = false;
}
}
else
{
return;
}
}

OutStream?.Write(data, meta);
}

public void SetStall()
{
stallNoErrorCount = 0;
isStall = true;
}
}
}
1 change: 0 additions & 1 deletion TS3AudioBot/Bot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ public R InitializeBot()

if (!Injector.AllResolved())
{
// TODO detailed log + for inner if
Log.Warn("Cyclic bot module dependency");
Injector.ForceCyclicResolve();
if (!Injector.AllResolved())
Expand Down
2 changes: 1 addition & 1 deletion TS3AudioBot/Commands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ namespace TS3AudioBot
using System.Linq;
using System.Text;
using TS3Client;
using TS3Client.Full.Audio;
using TS3Client.Audio;
using TS3Client.Messages;
using Web.Api;

Expand Down
3 changes: 1 addition & 2 deletions TS3AudioBot/Core.cs
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ private R InitializeCore()
Log.Info("[=== Version: {0}", SystemData.AssemblyData);
Log.Info("[=== Platform: {0}", SystemData.PlattformData);
Log.Info("[=== Runtime: {0}", SystemData.RuntimeData.FullName);
Log.Info("[=== Opus: {0}", TS3Client.Full.Audio.Opus.NativeMethods.Info);
Log.Info("[=== Opus: {0}", TS3Client.Audio.Opus.NativeMethods.Info);
Log.Info("[==============================================]");
if (SystemData.RuntimeData.Runtime == Runtime.Mono)
{
Expand Down Expand Up @@ -207,7 +207,6 @@ private R InitializeCore()

if (!Injector.AllResolved())
{
// TODO detailed log + for inner if
Log.Debug("Cyclic core module dependency");
Injector.ForceCyclicResolve();
if (!Injector.AllResolved())
Expand Down
26 changes: 19 additions & 7 deletions TS3AudioBot/Dependency/DependencyRealm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ public DependencyRealm()
Util.Init(out modules);
}

// TODO doc
/// <summary>Will add the type to pool of registered types which can be injected into other dependencies.</summary>
/// <typeparam name="TModule">The type to add</typeparam>
public void RegisterType<TModule>() => RegisterType(typeof(TModule));

private void RegisterType(Type modType)
Expand All @@ -41,7 +42,13 @@ private void RegisterType(Type modType)
registeredTypes.Add(modType);
}

// TODO doc
/// <summary>Adds an object as a new module to the module pool.
/// The realm will inject all registered types into public propeties as soon as available.</summary>
/// <typeparam name="TMod">The type of the module to add</typeparam>
/// <param name="module">The object to add as a new module.</param>
/// <param name="onInit">An initialize method that gets called when all dependencies are inected into this module.
/// Note that declaring this param will force the realm to be more strict with this modul
/// and make cyclic dependencies harder to resolve.</param>
public void RegisterModule<TMod>(TMod module, Action<TMod> onInit = null) where TMod : class
{
var onInitObject = onInit != null ? new Action<object>(x => onInit((TMod)x)) : null;
Expand All @@ -54,7 +61,9 @@ private void RegisterModule(object module, Action<object> onInit = null)
DoQueueInitialize(false);
}

// TODO doc
/// <summary>Injects all dependencies into the passe object without registering it as a new module.</summary>
/// <param name="obj">The object to fill.</param>
/// <returns>True if all registered types were available and could be injected, false otherwise.</returns>
public bool TryInject(object obj) => TryResolve(obj, InitState.SetOnly, false);

// Maybe in future update child realm when parent gets updated
Expand All @@ -66,7 +75,7 @@ private void RegisterModule(object module, Action<object> onInit = null)
return child;
}

// TODO doc
/// <summary>Tries to initialize all modules while allowing undefined behaviour when resolving cyclic dependecies.</summary>
public void ForceCyclicResolve()
{
DoQueueInitialize(true);
Expand Down Expand Up @@ -144,15 +153,18 @@ private bool TryResolve(object obj, InitState state, bool force)
return true;
}

// TODO doc
public object GetModule<TModule>() where TModule : class => GetModule(typeof(TModule));
/// <summary>Gets a module assignable to the requested type.</summary>
/// <typeparam name="TModule">The type to get.</typeparam>
/// <returns>The object if found, null otherwiese.</returns>
public TModule GetModule<TModule>() where TModule : class => (TModule)GetModule(typeof(TModule));
public object GetModule(Type type) => FindInjectableModule(type, InitState.Done, false)?.Obj;

void IInjector.AddModule(object obj) => RegisterModule(obj);

public IEnumerable<object> GetAllModules() => modules.Select(x => x.Obj);

// TODO doc
/// <summary>Checks if all module could get initialized.</summary>
/// <returns>True if all are initialized, false otherwise.</returns>
public bool AllResolved() => modules.All(x => x.Status == InitState.Done);

public void Unregister(Type type)
Expand Down
2 changes: 1 addition & 1 deletion TS3AudioBot/ITargetManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
namespace TS3AudioBot
{
using TS3Client;
using TS3Client.Full.Audio;
using TS3Client.Audio;

/// <summary>Used to specify playing mode and active targets to send to.</summary>
public interface ITargetManager
Expand Down
2 changes: 1 addition & 1 deletion TS3AudioBot/Plugins/Plugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ public PluginResponse Start(Bot bot)
return PluginResponse.UnknownError;

case PluginStatus.NotAvailable:
return PluginResponse.MissingContext; // TODO
return PluginResponse.MissingContext;

default:
throw new ArgumentOutOfRangeException();
Expand Down
1 change: 1 addition & 0 deletions TS3AudioBot/TS3AudioBot.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
<Compile Include="Algorithm\LinearFeedbackShiftRegister.cs" />
<Compile Include="Audio\CustomTargetPipe.cs" />
<Compile Include="Audio\FfmpegProducer.cs" />
<Compile Include="Audio\StallCheckPipe.cs" />
<Compile Include="BotManager.cs" />
<Compile Include="Commands.cs" />
<Compile Include="CommandSystem\Ast\AstCommand.cs" />
Expand Down
56 changes: 7 additions & 49 deletions TS3AudioBot/Ts3Full.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ namespace TS3AudioBot
using System.Linq;
using System.Reflection;
using TS3Client;
using TS3Client.Audio;
using TS3Client.Full;
using TS3Client.Full.Audio;
using TS3Client.Helper;
using TS3Client.Messages;

Expand All @@ -28,8 +28,6 @@ internal sealed class Ts3Full : TeamspeakControl, IPlayerConnection
private ClientData self;

private const Codec SendCodec = Codec.OpusMusic;
private const uint StallCountInterval = 10;
private const uint StallNoErrorCountMax = 5;
private static readonly string[] QuitMessages = {
"I'm outta here", "You're boring", "Have a nice day", "Bye", "Good night",
"Nothing to do here", "Taking a break", "Lorem ipsum dolor sit amet…",
Expand All @@ -45,11 +43,10 @@ internal sealed class Ts3Full : TeamspeakControl, IPlayerConnection

private readonly Ts3FullClientData ts3FullClientData;

private bool isStall;
private uint stallCount;
private uint stallNoErrorCount;
private IdentityData identity;

private readonly StallCheckPipe stallCheckPipe;
private readonly ActiveCheckPipe activeCheckPipe;
private readonly VolumePipe volumePipe;
private readonly FfmpegProducer ffmpegProducer;
private readonly PreciseTimedPipe timePipe;
Expand All @@ -64,17 +61,17 @@ public Ts3Full(Ts3FullClientData tfcd) : base(ClientType.Full)
tfcd.PropertyChanged += Tfcd_PropertyChanged;

ffmpegProducer = new FfmpegProducer(tfcd);
stallCheckPipe = new StallCheckPipe();
activeCheckPipe = new ActiveCheckPipe();
volumePipe = new VolumePipe();
encoderPipe = new EncoderPipe(SendCodec) { Bitrate = ts3FullClientData.AudioBitrate * 1000 };
timePipe = new PreciseTimedPipe { ReadBufferSize = encoderPipe.PacketSize };
timePipe.Initialize(encoderPipe);
TargetPipe = new CustomTargetPipe(tsFullClient);

timePipe.InStream = ffmpegProducer;
timePipe.Chain(volumePipe).Chain(encoderPipe).Chain(TargetPipe);
timePipe.Chain(activeCheckPipe).Chain(stallCheckPipe).Chain(volumePipe).Chain(encoderPipe).Chain(TargetPipe);

isStall = false;
stallCount = 0;
identity = null;
}

Expand Down Expand Up @@ -188,8 +185,7 @@ private void TsFullClient_OnErrorEvent(object sender, CommandError error)
switch (error.Id)
{
case Ts3ErrorCode.whisper_no_targets:
stallNoErrorCount = 0;
isStall = true;
stallCheckPipe.SetStall();
break;

default:
Expand Down Expand Up @@ -264,44 +260,6 @@ public override R<ClientData> GetSelf()
return cd;
}

private void AudioSend()
{
// TODO Make a pipe for this
// Save cpu when we know there is noone to send to
bool doSend = true;

var SendMode = TargetSendMode.None;
switch (SendMode)
{
case TargetSendMode.None:
doSend = false;
break;
case TargetSendMode.Voice:
break;
case TargetSendMode.Whisper:
case TargetSendMode.WhisperGroup:
if (isStall)
{
if (++stallCount % StallCountInterval == 0)
{
stallNoErrorCount++;
if (stallNoErrorCount > StallNoErrorCountMax)
{
stallCount = 0;
isStall = false;
}
}
else
{
doSend = false;
}
}
break;
default:
throw new InvalidOperationException();
}
}

#region IPlayerConnection

public event EventHandler OnSongEnd
Expand Down
27 changes: 27 additions & 0 deletions TS3Client/Audio/ActiveCheckPipe.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// TS3Client - A free TeamSpeak3 client implementation
// Copyright (C) 2017 TS3Client contributors
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the Open Software License v. 3.0
//
// You should have received a copy of the Open Software License along with this
// program. If not, see <https://opensource.org/licenses/OSL-3.0>.

namespace TS3Client.Audio
{
using System;

public class ActiveCheckPipe : IAudioPipe
{
public bool Active => OutStream?.Active ?? false;
public IAudioPassiveConsumer OutStream { get; set; }

public void Write(Span<byte> data, Meta meta)
{
if (OutStream == null || !Active)
return;

OutStream?.Write(data, meta);
}
}
}
Loading

0 comments on commit 25b19d7

Please sign in to comment.