Browse Source

Document some of the Audio stuff

pull/222/head
FiniteReality 8 years ago
parent
commit
be850f0824
11 changed files with 64 additions and 2 deletions
  1. +5
    -0
      src/Discord.Net/Audio/AudioMode.cs
  2. +7
    -0
      src/Discord.Net/Audio/IAudioClient.cs
  3. +7
    -0
      src/Discord.Net/Audio/Opus/OpusApplication.cs
  4. +2
    -0
      src/Discord.Net/Audio/Opus/OpusDecoder.cs
  5. +3
    -0
      src/Discord.Net/Audio/Opus/OpusEncoder.cs
  6. +3
    -1
      src/Discord.Net/Audio/Sodium/SecretBox.cs
  7. +3
    -0
      src/Discord.Net/Audio/Streams/OpusDecodeStream.cs
  8. +6
    -1
      src/Discord.Net/Audio/Streams/OpusEncodeStream.cs
  9. +11
    -0
      src/Discord.Net/Audio/Streams/RTPReadStream.cs
  10. +12
    -0
      src/Discord.Net/Audio/Streams/RTPWriteStream.cs
  11. +5
    -0
      src/Discord.Net/Entities/Channels/ChannelType.cs

+ 5
- 0
src/Discord.Net/Audio/AudioMode.cs View File

@@ -2,12 +2,17 @@

namespace Discord.Audio
{
/// <summary> Specifies an audio mode for Discord. </summary>
[Flags]
public enum AudioMode : byte
{
/// <summary> Audio send/receive is disabled. </summary>
Disabled = 0,
/// <summary> Audio can only be broadcasted by the client. </summary>
Outgoing = 1,
/// <summary> Audio can only be received by the client. </summary>
Incoming = 2,
/// <summary> Audio can be sent and received by the client. </summary>
Both = Outgoing | Incoming
}
}

+ 7
- 0
src/Discord.Net/Audio/IAudioClient.cs View File

@@ -5,19 +5,26 @@ namespace Discord.Audio
{
public interface IAudioClient
{
/// <summary> Fired when the client connects to Discord. </summary>
event Func<Task> Connected;
/// <summary> Fired when the client disconnects from Discord. </summary>
event Func<Exception, Task> Disconnected;
/// <summary> Fired in response to a heartbeat, providing the old and new latency. </summary>
event Func<int, int, Task> LatencyUpdated;

/// <summary> Gets the API client used for communicating with Discord. </summary>
DiscordVoiceAPIClient ApiClient { get; }
/// <summary> Gets the current connection state of this client. </summary>
ConnectionState ConnectionState { get; }
/// <summary> Gets the estimated round-trip latency, in milliseconds, to the gateway server. </summary>
int Latency { get; }

/// <summary> Disconnects the current client from Discord. </summary>
Task DisconnectAsync();

/// <summary> Creates an Opus stream for sending raw Opus-encoded data. </summary>
RTPWriteStream CreateOpusStream(int samplesPerFrame, int bufferSize = 4000);
/// <summary> Creates a PCM stream for sending unencoded PCM data. </summary>
OpusEncodeStream CreatePCMStream(int samplesPerFrame, int? bitrate = null, OpusApplication application = OpusApplication.MusicOrMixed, int bufferSize = 4000);
}
}

+ 7
- 0
src/Discord.Net/Audio/Opus/OpusApplication.cs View File

@@ -1,9 +1,16 @@
namespace Discord.Audio
{
/// <summary> The types of encoding which Opus supports during encoding. </summary>
public enum OpusApplication : int
{
/// <summary> Specifies that the <see cref="Discord.Audio.IAudioClient"/> uses
/// encoding to improve the quality of voice communication. </summary>
Voice = 2048,
/// <summary> Specifies that the <see cref="Discord.Audio.IAudioClient"/> uses
/// encoding to improve the overall quality of mixed-media audio transmission. </summary>
MusicOrMixed = 2049,
/// <summary> Specifies that the <see cref="Discord.Audio.IAudioClient"/> uses
/// encoding to reduce overall latency. </summary>
LowLatency = 2051
}
}

+ 2
- 0
src/Discord.Net/Audio/Opus/OpusDecoder.cs View File

@@ -24,7 +24,9 @@ namespace Discord.Audio
/// <summary> Produces PCM samples from Opus-encoded audio. </summary>
/// <param name="input">PCM samples to decode.</param>
/// <param name="inputOffset">Offset of the frame in input.</param>
/// <param name="inputCount">Number of bytes of the frame in input.</param>
/// <param name="output">Buffer to store the decoded frame.</param>
/// <param name="outputOffset">Zero-based offset for the output.</param>
public unsafe int DecodeFrame(byte[] input, int inputOffset, int inputCount, byte[] output, int outputOffset)
{
int result = 0;


+ 3
- 0
src/Discord.Net/Audio/Opus/OpusEncoder.cs View File

@@ -31,6 +31,9 @@ namespace Discord.Audio
/// <summary> Produces Opus encoded audio from PCM samples. </summary>
/// <param name="input">PCM samples to encode.</param>
/// <param name="output">Buffer to store the encoded frame.</param>
/// <param name="inputOffset">Offset of the frame in input.</param>
/// <param name="inputCount">Number of bytes of the frame in input.</param>
/// <param name="outputOffset">Zero-based offset for the output.</param>
/// <returns>Length of the frame contained in outputBuffer.</returns>
public unsafe int EncodeFrame(byte[] input, int inputOffset, int inputCount, byte[] output, int outputOffset)
{


+ 3
- 1
src/Discord.Net/Audio/Sodium/SecretBox.cs View File

@@ -3,13 +3,14 @@ using System.Runtime.InteropServices;

namespace Discord.Audio
{
public unsafe static class SecretBox
public unsafe static class SecretBox // TODO: should this be public?
{
[DllImport("libsodium", EntryPoint = "crypto_secretbox_easy", CallingConvention = CallingConvention.Cdecl)]
private static extern int SecretBoxEasy(byte* output, byte* input, long inputLength, byte[] nonce, byte[] secret);
[DllImport("libsodium", EntryPoint = "crypto_secretbox_open_easy", CallingConvention = CallingConvention.Cdecl)]
private static extern int SecretBoxOpenEasy(byte* output, byte* input, long inputLength, byte[] nonce, byte[] secret);

/// <summary> Encrypts a payload with the given nonce and secret. </summary>
public static int Encrypt(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset, byte[] nonce, byte[] secret)
{
fixed (byte* inPtr = input)
@@ -21,6 +22,7 @@ namespace Discord.Audio
return inputLength + 16;
}
}
/// <summary> Decrypts a payload with the given nonce and secret. </summary>
public static int Decrypt(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset, byte[] nonce, byte[] secret)
{
fixed (byte* inPtr = input)


+ 3
- 0
src/Discord.Net/Audio/Streams/OpusDecodeStream.cs View File

@@ -1,5 +1,6 @@
namespace Discord.Audio
{
/// <summary> A stream which decodes Opus frames as they are read. </summary>
public class OpusDecodeStream : RTPReadStream
{
private readonly byte[] _buffer;
@@ -13,12 +14,14 @@
_decoder = new OpusDecoder(samplingRate, channels);
}

/// <summary> Reads Opus-encoded frame from the stream, filling the buffer with PCM data </summary>
public override int Read(byte[] buffer, int offset, int count)
{
count = _decoder.DecodeFrame(buffer, offset, count, _buffer, 0);
return base.Read(_buffer, 0, count);
}

/// <inheritdoc/>
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);


+ 6
- 1
src/Discord.Net/Audio/Streams/OpusEncodeStream.cs View File

@@ -1,8 +1,11 @@
namespace Discord.Audio
{
/// <summary> A stream which encodes Opus frames as raw PCM data is written. </summary>
public class OpusEncodeStream : RTPWriteStream
{
public int SampleRate = 48000;
/// <summary> The sample rate of the Opus stream. </summary>
public int SampleRate = 48000; // TODO: shouldn't these be readonly?
/// <summary> The number of channels of the Opus stream. </summary>
public int Channels = 2;
private readonly OpusEncoder _encoder;
@@ -18,12 +21,14 @@
_encoder.SetBitrate(bitrate.Value);
}

/// <summary> Writes Opus-encoded PCM data to the stream. </summary>
public override void Write(byte[] buffer, int offset, int count)
{
count = _encoder.EncodeFrame(buffer, offset, count, _buffer, 0);
base.Write(_buffer, 0, count);
}

/// <inheritdoc/>
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);


+ 11
- 0
src/Discord.Net/Audio/Streams/RTPReadStream.cs View File

@@ -4,14 +4,18 @@ using System.IO;

namespace Discord.Audio
{
/// <summary> A stream used for reading raw audio data from Discord. </summary>
public class RTPReadStream : Stream
{
private readonly BlockingCollection<byte[]> _queuedData; //TODO: Replace with max-length ring buffer
private readonly AudioClient _audioClient;
private readonly byte[] _buffer, _nonce, _secretKey;

/// <inheritdoc/>
public override bool CanRead => true;
/// <inheritdoc/>
public override bool CanSeek => false;
/// <inheritdoc/>
public override bool CanWrite => true;

internal RTPReadStream(AudioClient audioClient, byte[] secretKey, int bufferSize = 4000)
@@ -23,12 +27,14 @@ namespace Discord.Audio
_nonce = new byte[24];
}

/// <inheritdoc/>
public override int Read(byte[] buffer, int offset, int count)
{
var queuedData = _queuedData.Take();
Buffer.BlockCopy(queuedData, 0, buffer, offset, Math.Min(queuedData.Length, count));
return queuedData.Length;
}
/// <inheritdoc/>
public override void Write(byte[] buffer, int offset, int count)
{
Buffer.BlockCopy(buffer, 0, _nonce, 0, 12);
@@ -38,16 +44,21 @@ namespace Discord.Audio
_queuedData.Add(newBuffer);
}

/// <inheritdoc/>
public override void Flush() { throw new NotSupportedException(); }

/// <inheritdoc/>
public override long Length { get { throw new NotSupportedException(); } }
/// <inheritdoc/>
public override long Position
{
get { throw new NotSupportedException(); }
set { throw new NotSupportedException(); }
}

/// <inheritdoc/>
public override void SetLength(long value) { throw new NotSupportedException(); }
/// <inheritdoc/>
public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); }
}
}

+ 12
- 0
src/Discord.Net/Audio/Streams/RTPWriteStream.cs View File

@@ -3,6 +3,7 @@ using System.IO;

namespace Discord.Audio
{
/// <summary> A stream used for writing raw audio data to Discord. </summary>
public class RTPWriteStream : Stream
{
private readonly AudioClient _audioClient;
@@ -10,10 +11,14 @@ namespace Discord.Audio
private int _samplesPerFrame;
private uint _ssrc, _timestamp = 0;

/// <summary> The current output buffer. </summary>
protected readonly byte[] _buffer;

/// <inheritdoc/>
public override bool CanRead => false;
/// <inheritdoc/>
public override bool CanSeek => false;
/// <inheritdoc/>
public override bool CanWrite => true;

internal RTPWriteStream(AudioClient audioClient, byte[] secretKey, int samplesPerFrame, uint ssrc, int bufferSize = 4000)
@@ -32,6 +37,7 @@ namespace Discord.Audio
_nonce[11] = (byte)(_ssrc >> 0);
}

/// <inheritdoc/>
public override void Write(byte[] buffer, int offset, int count)
{
unchecked
@@ -51,17 +57,23 @@ namespace Discord.Audio
_audioClient.Send(_buffer, count + 12);
}

/// <inheritdoc/>
public override void Flush() { }

/// <inheritdoc/>
public override long Length { get { throw new NotSupportedException(); } }
/// <inheritdoc/>
public override long Position
{
get { throw new NotSupportedException(); }
set { throw new NotSupportedException(); }
}

/// <inheritdoc/>
public override int Read(byte[] buffer, int offset, int count) { throw new NotSupportedException(); }
/// <inheritdoc/>
public override void SetLength(long value) { throw new NotSupportedException(); }
/// <inheritdoc/>
public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); }
}
}

+ 5
- 0
src/Discord.Net/Entities/Channels/ChannelType.cs View File

@@ -1,10 +1,15 @@
namespace Discord
{
/// <summary> Specifies the type of channel a message was sent to or eceived from. </summary>
public enum ChannelType
{
///<summary> A text channel </summary>
Text = 0,
///<summary> A direct-message text channel </summary>
DM = 1,
///<summary> A voice channel channel </summary>
Voice = 2,
///<summary> A group channel </summary>
Group = 3
}
}

Loading…
Cancel
Save