From f2a25fe3ee193e4060b15fbacfe5c1f054587c5a Mon Sep 17 00:00:00 2001 From: RogueException Date: Tue, 24 Nov 2015 12:33:25 -0400 Subject: [PATCH 1/2] Added VoiceBitrate to configure the bitrate of the opus encoder --- src/Discord.Net/Audio/OpusEncoder.cs | 25 ++++++++++++++++--- src/Discord.Net/DiscordWSClientConfig.cs | 3 +++ .../Net/WebSockets/VoiceWebSocket.cs | 2 +- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/Discord.Net/Audio/OpusEncoder.cs b/src/Discord.Net/Audio/OpusEncoder.cs index c5e033a2b..fbb6a0729 100644 --- a/src/Discord.Net/Audio/OpusEncoder.cs +++ b/src/Discord.Net/Audio/OpusEncoder.cs @@ -8,7 +8,7 @@ namespace Discord.Audio private readonly IntPtr _ptr; /// Gets the bit rate of the encoder. - public const int BitRate = 16; + public const int BitsPerSample = 16; /// Gets the input sampling rate of the encoder. public int InputSamplingRate { get; private set; } /// Gets the number of channels of the encoder. @@ -21,6 +21,8 @@ namespace Discord.Audio public int SampleSize { get; private set; } /// Gets the bytes per frame. public int FrameSize { get; private set; } + /// Gets the bit rate in kbit/s. + public int? BitRate { get; private set; } /// Gets the coding mode of the encoder. public Opus.Application Application { get; private set; } @@ -28,9 +30,10 @@ namespace Discord.Audio /// Sampling rate of the input signal (Hz). Supported Values: 8000, 12000, 16000, 24000, or 48000. /// Number of channels (1 or 2) in input signal. /// Length, in milliseconds, that each frame takes. Supported Values: 2.5, 5, 10, 20, 40, 60 + /// Bitrate (kbit/s) used for this encoder. Supported Values: 1-512. Null will use the recommended bitrate. /// Coding mode. /// A new OpusEncoder - public OpusEncoder(int samplingRate, int channels, int frameLength, Opus.Application application) + public OpusEncoder(int samplingRate, int channels, int frameLength, int? bitrate, Opus.Application application) { if (samplingRate != 8000 && samplingRate != 12000 && samplingRate != 16000 && samplingRate != 24000 && @@ -38,14 +41,17 @@ namespace Discord.Audio throw new ArgumentOutOfRangeException(nameof(samplingRate)); if (channels != 1 && channels != 2) throw new ArgumentOutOfRangeException(nameof(channels)); + if (bitrate != null && (bitrate < 1 || bitrate > 512)) + throw new ArgumentOutOfRangeException(nameof(bitrate)); InputSamplingRate = samplingRate; InputChannels = channels; Application = application; FrameLength = frameLength; - SampleSize = (BitRate / 8) * channels; + SampleSize = (BitsPerSample / 8) * channels; SamplesPerFrame = samplingRate / 1000 * FrameLength; FrameSize = SamplesPerFrame * SampleSize; + BitRate = bitrate; Opus.Error error; _ptr = Opus.CreateEncoder(samplingRate, channels, (int)application, out error); @@ -53,6 +59,8 @@ namespace Discord.Audio throw new InvalidOperationException($"Error occured while creating encoder: {error}"); SetForwardErrorCorrection(true); + if (bitrate != null) + SetBitrate(bitrate.Value); } /// Produces Opus encoded audio from PCM samples. @@ -85,6 +93,17 @@ namespace Discord.Audio throw new Exception("Encoder error: " + ((Opus.Error)result).ToString()); } + /// Gets or sets whether Forward Error Correction is enabled. + public void SetBitrate(int value) + { + if (disposed) + throw new ObjectDisposedException(nameof(OpusEncoder)); + + var result = Opus.EncoderCtl(_ptr, Opus.Ctl.SetBitrateRequest, value * 1000); + if (result < 0) + throw new Exception("Encoder error: " + ((Opus.Error)result).ToString()); + } + #region IDisposable private bool disposed; public void Dispose() diff --git a/src/Discord.Net/DiscordWSClientConfig.cs b/src/Discord.Net/DiscordWSClientConfig.cs index 5e8a59d0b..9778cace4 100644 --- a/src/Discord.Net/DiscordWSClientConfig.cs +++ b/src/Discord.Net/DiscordWSClientConfig.cs @@ -30,6 +30,9 @@ namespace Discord /// Gets or sets the max buffer length (in milliseconds) for outgoing voice packets. This value is the target maximum but is not guaranteed, the buffer will often go slightly above this value. public int VoiceBufferLength { get { return _voiceBufferLength; } set { SetValue(ref _voiceBufferLength, value); } } private int _voiceBufferLength = 1000; + /// Gets or sets the bitrate used (in kbit/s, between 1 and 512) for outgoing voice packets. A null value will use default opus settings. + public int? VoiceBitrate { get { return _voiceBitrate; } set { SetValue(ref _voiceBitrate, value); } } + private int? _voiceBitrate = null; //Experimental Features /// (Experimental) Enables the voice websocket and UDP client and specifies how it will be used. Any option other than Disabled requires the opus .dll or .so be in the local lib/ folder. diff --git a/src/Discord.Net/Net/WebSockets/VoiceWebSocket.cs b/src/Discord.Net/Net/WebSockets/VoiceWebSocket.cs index 4402c4d03..fa416d038 100644 --- a/src/Discord.Net/Net/WebSockets/VoiceWebSocket.cs +++ b/src/Discord.Net/Net/WebSockets/VoiceWebSocket.cs @@ -53,7 +53,7 @@ namespace Discord.Net.WebSockets _targetAudioBufferLength = client.Config.VoiceBufferLength / 20; //20 ms frames _encodingBuffer = new byte[MaxOpusSize]; _ssrcMapping = new ConcurrentDictionary(); - _encoder = new OpusEncoder(48000, 1, 20, Opus.Application.Audio); + _encoder = new OpusEncoder(48000, 1, 20, client.Config.VoiceBitrate, Opus.Application.Audio); _sendBuffer = new VoiceBuffer((int)Math.Ceiling(client.Config.VoiceBufferLength / (double)_encoder.FrameLength), _encoder.FrameSize); } From d9b1779a3d2144fecb7fcd9682d8ff99d2b74b34 Mon Sep 17 00:00:00 2001 From: RogueException Date: Tue, 24 Nov 2015 15:09:59 -0400 Subject: [PATCH 2/2] Minor comment edit --- src/Discord.Net/DiscordWSClientConfig.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Discord.Net/DiscordWSClientConfig.cs b/src/Discord.Net/DiscordWSClientConfig.cs index 9778cace4..64c092d9c 100644 --- a/src/Discord.Net/DiscordWSClientConfig.cs +++ b/src/Discord.Net/DiscordWSClientConfig.cs @@ -30,7 +30,7 @@ namespace Discord /// Gets or sets the max buffer length (in milliseconds) for outgoing voice packets. This value is the target maximum but is not guaranteed, the buffer will often go slightly above this value. public int VoiceBufferLength { get { return _voiceBufferLength; } set { SetValue(ref _voiceBufferLength, value); } } private int _voiceBufferLength = 1000; - /// Gets or sets the bitrate used (in kbit/s, between 1 and 512) for outgoing voice packets. A null value will use default opus settings. + /// Gets or sets the bitrate used (in kbit/s, between 1 and 512 inclusively) for outgoing voice packets. A null value will use default Opus settings. public int? VoiceBitrate { get { return _voiceBitrate; } set { SetValue(ref _voiceBitrate, value); } } private int? _voiceBitrate = null;