diff --git a/src/Discord.Net.Core/Audio/IAudioClient.cs b/src/Discord.Net.Core/Audio/IAudioClient.cs
index 746515fa7..c8e8de747 100644
--- a/src/Discord.Net.Core/Audio/IAudioClient.cs
+++ b/src/Discord.Net.Core/Audio/IAudioClient.cs
@@ -21,31 +21,27 @@ namespace Discord.Audio
/// Creates a new outgoing stream accepting Opus-encoded data.
///
/// Samples per frame. Must be 120, 240, 480, 960, 1920 or 2880, representing 2.5, 5, 10, 20, 40 or 60 milliseconds respectively.
- /// The size of the internal buffer used for encryption.
///
- Stream CreateOpusStream(int samplesPerFrame, int bufferSize = 4000);
+ Stream CreateOpusStream(int samplesPerFrame);
///
/// Creates a new outgoing stream accepting Opus-encoded data. This is a direct stream with no internal timer.
///
/// Samples per frame. Must be 120, 240, 480, 960, 1920 or 2880, representing 2.5, 5, 10, 20, 40 or 60 milliseconds respectively.
- /// The size of the internal buffer used for encryption.
///
- Stream CreateDirectOpusStream(int samplesPerFrame, int bufferSize = 4000);
+ Stream CreateDirectOpusStream(int samplesPerFrame);
///
/// Creates a new outgoing stream accepting PCM (raw) data.
///
/// Samples per frame. Must be 120, 240, 480, 960, 1920 or 2880, representing 2.5, 5, 10, 20, 40 or 60 milliseconds respectively.
///
- /// The size of the internal buffer used for encoding and encryption.
///
- Stream CreatePCMStream(int samplesPerFrame, int? bitrate = null, int bufferSize = 4000);
+ Stream CreatePCMStream(int samplesPerFrame, int channels = 2, int? bitrate = null);
///
/// Creates a new direct outgoing stream accepting PCM (raw) data. This is a direct stream with no internal timer.
///
/// Samples per frame. Must be 120, 240, 480, 960, 1920 or 2880, representing 2.5, 5, 10, 20, 40 or 60 milliseconds respectively.
///
- /// The size of the internal buffer used for encoding and encryption.
///
- Stream CreateDirectPCMStream(int samplesPerFrame, int? bitrate = null, int bufferSize = 4000);
+ Stream CreateDirectPCMStream(int samplesPerFrame, int channels = 2, int? bitrate = null);
}
}
diff --git a/src/Discord.Net.WebSocket/Audio/AudioClient.cs b/src/Discord.Net.WebSocket/Audio/AudioClient.cs
index 2d11baaec..0f5079caa 100644
--- a/src/Discord.Net.WebSocket/Audio/AudioClient.cs
+++ b/src/Discord.Net.WebSocket/Audio/AudioClient.cs
@@ -169,29 +169,29 @@ namespace Discord.Audio
await _disconnectedEvent.InvokeAsync(ex).ConfigureAwait(false);
}
- public Stream CreateOpusStream(int samplesPerFrame, int bufferSize = 4000)
+ public Stream CreateOpusStream(int samplesPerFrame)
{
CheckSamplesPerFrame(samplesPerFrame);
var target = new BufferedAudioTarget(ApiClient, samplesPerFrame, _cancelTokenSource.Token);
- return new RTPWriteStream(target, _secretKey, samplesPerFrame, _ssrc, bufferSize = 4000);
+ return new RTPWriteStream(target, _secretKey, samplesPerFrame, _ssrc);
}
- public Stream CreateDirectOpusStream(int samplesPerFrame, int bufferSize = 4000)
+ public Stream CreateDirectOpusStream(int samplesPerFrame)
{
CheckSamplesPerFrame(samplesPerFrame);
var target = new DirectAudioTarget(ApiClient);
- return new RTPWriteStream(target, _secretKey, samplesPerFrame, _ssrc, bufferSize = 4000);
+ return new RTPWriteStream(target, _secretKey, samplesPerFrame, _ssrc);
}
- public Stream CreatePCMStream(int samplesPerFrame, int? bitrate = null, int bufferSize = 4000)
+ public Stream CreatePCMStream(int samplesPerFrame, int channels = 2, int? bitrate = null)
{
CheckSamplesPerFrame(samplesPerFrame);
var target = new BufferedAudioTarget(ApiClient, samplesPerFrame, _cancelTokenSource.Token);
- return new OpusEncodeStream(target, _secretKey, samplesPerFrame, _ssrc, bitrate, bufferSize);
+ return new OpusEncodeStream(target, _secretKey, channels, samplesPerFrame, _ssrc, bitrate);
}
- public Stream CreateDirectPCMStream(int samplesPerFrame, int? bitrate = null, int bufferSize = 4000)
+ public Stream CreateDirectPCMStream(int samplesPerFrame, int channels = 2, int? bitrate = null)
{
CheckSamplesPerFrame(samplesPerFrame);
var target = new DirectAudioTarget(ApiClient);
- return new OpusEncodeStream(target, _secretKey, samplesPerFrame, _ssrc, bitrate, bufferSize);
+ return new OpusEncodeStream(target, _secretKey, channels, samplesPerFrame, _ssrc, bitrate);
}
private void CheckSamplesPerFrame(int samplesPerFrame)
{
diff --git a/src/Discord.Net.WebSocket/Audio/Streams/OpusEncodeStream.cs b/src/Discord.Net.WebSocket/Audio/Streams/OpusEncodeStream.cs
index f86901ef1..d207e3cf7 100644
--- a/src/Discord.Net.WebSocket/Audio/Streams/OpusEncodeStream.cs
+++ b/src/Discord.Net.WebSocket/Audio/Streams/OpusEncodeStream.cs
@@ -1,16 +1,22 @@
-namespace Discord.Audio
+using System;
+
+namespace Discord.Audio
{
internal class OpusEncodeStream : RTPWriteStream
{
- public int SampleRate = 48000;
- public int Channels = 2;
-
+ public const int SampleRate = 48000;
+ private int _frameSize;
+ private byte[] _partialFrameBuffer;
+ private int _partialFramePos;
+
private readonly OpusEncoder _encoder;
- internal OpusEncodeStream(IAudioTarget target, byte[] secretKey, int samplesPerFrame, uint ssrc, int? bitrate = null, int bufferSize = 4000)
- : base(target, secretKey, samplesPerFrame, ssrc, bufferSize)
+ internal OpusEncodeStream(IAudioTarget target, byte[] secretKey, int channels, int samplesPerFrame, uint ssrc, int? bitrate = null)
+ : base(target, secretKey, samplesPerFrame, ssrc)
{
- _encoder = new OpusEncoder(SampleRate, Channels);
+ _encoder = new OpusEncoder(SampleRate, channels);
+ _frameSize = samplesPerFrame * channels * 2;
+ _partialFrameBuffer = new byte[_frameSize];
_encoder.SetForwardErrorCorrection(true);
if (bitrate != null)
@@ -19,8 +25,27 @@
public override void Write(byte[] buffer, int offset, int count)
{
- count = _encoder.EncodeFrame(buffer, offset, count, _buffer, 0);
- base.Write(_buffer, 0, count);
+ //Assume threadsafe
+ while (count > 0)
+ {
+ if (_partialFramePos + count >= _frameSize)
+ {
+ int partialSize = _frameSize - _partialFramePos;
+ Buffer.BlockCopy(buffer, offset, _partialFrameBuffer, _partialFramePos, partialSize);
+ offset += partialSize;
+ count -= partialSize;
+ _partialFramePos = 0;
+
+ int encFrameSize = _encoder.EncodeFrame(_partialFrameBuffer, 0, _frameSize, _buffer, 0);
+ base.Write(_buffer, 0, encFrameSize);
+ }
+ else
+ {
+ Buffer.BlockCopy(buffer, offset, _partialFrameBuffer, _partialFramePos, count);
+ _partialFramePos += count;
+ break;
+ }
+ }
}
protected override void Dispose(bool disposing)
diff --git a/src/Discord.Net.WebSocket/Audio/Streams/RTPWriteStream.cs b/src/Discord.Net.WebSocket/Audio/Streams/RTPWriteStream.cs
index 5ea0d2473..217555052 100644
--- a/src/Discord.Net.WebSocket/Audio/Streams/RTPWriteStream.cs
+++ b/src/Discord.Net.WebSocket/Audio/Streams/RTPWriteStream.cs
@@ -16,13 +16,13 @@ namespace Discord.Audio
public override bool CanSeek => false;
public override bool CanWrite => true;
- internal RTPWriteStream(IAudioTarget target, byte[] secretKey, int samplesPerFrame, uint ssrc, int bufferSize = 4000)
+ internal RTPWriteStream(IAudioTarget target, byte[] secretKey, int samplesPerFrame, uint ssrc)
{
_target = target;
_secretKey = secretKey;
_samplesPerFrame = samplesPerFrame;
_ssrc = ssrc;
- _buffer = new byte[bufferSize];
+ _buffer = new byte[4000];
_nonce = new byte[24];
_nonce[0] = 0x80;
_nonce[1] = 0x78;
diff --git a/src/Discord.Net.WebSocket/Audio/Targets/BufferedAudioTarget.cs b/src/Discord.Net.WebSocket/Audio/Targets/BufferedAudioTarget.cs
index 19bdee245..848a77131 100644
--- a/src/Discord.Net.WebSocket/Audio/Targets/BufferedAudioTarget.cs
+++ b/src/Discord.Net.WebSocket/Audio/Targets/BufferedAudioTarget.cs
@@ -75,4 +75,4 @@ namespace Discord.Audio
Dispose(true);
}
}
-}
+}
\ No newline at end of file