diff --git a/Deepgram.Microphone/Microphone.cs b/Deepgram.Microphone/Microphone.cs index bb0da3f7..d1492e7d 100644 --- a/Deepgram.Microphone/Microphone.cs +++ b/Deepgram.Microphone/Microphone.cs @@ -11,7 +11,7 @@ namespace Deepgram.Microphone; /// public class Microphone { - private Action _push_callback; + private Action _push_callback; private int _rate; private uint _chunk; @@ -27,7 +27,7 @@ public class Microphone /// Constructor for Microphone /// public Microphone( - Action push_callback, + Action push_callback, int rate = Defaults.RATE, uint chunkSize = Defaults.CHUNK_SIZE, int channels = Defaults.CHANNELS, @@ -120,7 +120,7 @@ private StreamCallbackResult _callback(nint input, nint output, uint frameCount, } // Push the data to the callback - _push_callback(buf); + _push_callback(buf, buf.Length); return StreamCallbackResult.Continue; } diff --git a/Deepgram/Clients/Interfaces/v1/Constants.cs b/Deepgram/Clients/Interfaces/v1/Constants.cs new file mode 100644 index 00000000..11b4de71 --- /dev/null +++ b/Deepgram/Clients/Interfaces/v1/Constants.cs @@ -0,0 +1,15 @@ +// Copyright 2024 Deepgram .NET SDK contributors. All Rights Reserved. +// Use of this source code is governed by a MIT license that can be found in the LICENSE file. +// SPDX-License-Identifier: MIT + +namespace Deepgram.Clients.Interfaces.v1; + +/// +/// Headers of interest in the return values from the Deepgram Speak API. +/// +public static class Constants +{ + // WS buffer size + public const int UseArrayLengthForSend = -1; +} + diff --git a/Deepgram/Clients/Interfaces/v1/IListenWebSocketClient.cs b/Deepgram/Clients/Interfaces/v1/IListenWebSocketClient.cs index c290b02b..1776aa38 100644 --- a/Deepgram/Clients/Interfaces/v1/IListenWebSocketClient.cs +++ b/Deepgram/Clients/Interfaces/v1/IListenWebSocketClient.cs @@ -71,32 +71,47 @@ public Task Connect(LiveSchema options, CancellationTokenSource? cancelToken = n #endregion #region Send Functions + /// + /// Sends a KeepAlive message to Deepgram + /// + public void SendKeepAlive(); + + /// + /// Sends a Finalize message to Deepgram + /// + public void SendFinalize(); + + /// + /// Sends a Close message to Deepgram + /// + public void SendClose(bool nullByte = false); + /// /// Sends a binary message over the WebSocket connection. /// /// The data to be sent over the WebSocket. - public void Send(byte[] data); + public void Send(byte[] data, int length = Constants.UseArrayLengthForSend); /// /// This method sends a binary message over the WebSocket connection. /// /// - public void SendBinary(byte[] data); + public void SendBinary(byte[] data, int length = Constants.UseArrayLengthForSend); /// /// This method sends a text message over the WebSocket connection. /// - public void SendMessage(byte[] data); + public void SendMessage(byte[] data, int length = Constants.UseArrayLengthForSend); /// /// This method sends a binary message over the WebSocket connection immediately without queueing. /// - public void SendBinaryImmediately(byte[] data); + public void SendBinaryImmediately(byte[] data, int length = Constants.UseArrayLengthForSend); /// /// This method sends a text message over the WebSocket connection immediately without queueing. /// - public void SendMessageImmediately(byte[] data); + public void SendMessageImmediately(byte[] data, int length = Constants.UseArrayLengthForSend); #endregion #region Helpers diff --git a/Deepgram/Clients/Interfaces/v1/ISpeakWebSocketClient.cs b/Deepgram/Clients/Interfaces/v1/ISpeakWebSocketClient.cs index 129261e6..3ef24916 100644 --- a/Deepgram/Clients/Interfaces/v1/ISpeakWebSocketClient.cs +++ b/Deepgram/Clients/Interfaces/v1/ISpeakWebSocketClient.cs @@ -109,7 +109,7 @@ public Task Connect(SpeakSchema options, CancellationTokenSource? cancelToken = /// Sends a binary message over the WebSocket connection. /// /// The data to be sent over the WebSocket. - public void Send(byte[] data); + public void Send(byte[] data, int length = Constants.UseArrayLengthForSend); ///// ///// This method sends a binary message over the WebSocket connection. @@ -120,7 +120,7 @@ public Task Connect(SpeakSchema options, CancellationTokenSource? cancelToken = /// /// This method sends a text message over the WebSocket connection. /// - public void SendMessage(byte[] data); + public void SendMessage(byte[] data, int length = Constants.UseArrayLengthForSend); ///// ///// This method sends a binary message over the WebSocket connection immediately without queueing. @@ -130,7 +130,7 @@ public Task Connect(SpeakSchema options, CancellationTokenSource? cancelToken = /// /// This method sends a text message over the WebSocket connection immediately without queueing. /// - public void SendMessageImmediately(byte[] data); + public void SendMessageImmediately(byte[] data, int length = Constants.UseArrayLengthForSend); #endregion #region Helpers diff --git a/Deepgram/Clients/Listen/v1/WebSocket/Client.cs b/Deepgram/Clients/Listen/v1/WebSocket/Client.cs index dba20455..690894e6 100644 --- a/Deepgram/Clients/Listen/v1/WebSocket/Client.cs +++ b/Deepgram/Clients/Listen/v1/WebSocket/Client.cs @@ -314,34 +314,59 @@ public void SendFinalize() SendMessageImmediately(data); } + /// + /// Sends a Close message to Deepgram + /// + public void SendClose(bool nullByte = false) + { + Log.Debug("SendFinalize", "Sending Close Message Immediately..."); + if (nullByte && _clientWebSocket != null) + { + // send a close to Deepgram + lock (_mutexSend) + { + _clientWebSocket.SendAsync(new ArraySegment([0]), WebSocketMessageType.Binary, true, _cancellationTokenSource.Token) + .ConfigureAwait(false); + } + return; + } + + byte[] data = Encoding.ASCII.GetBytes("{\"type\": \"CloseStream\"}"); + SendMessageImmediately(data); + } + /// /// Sends a binary message over the WebSocket connection. /// /// The data to be sent over the WebSocket. - public void Send(byte[] data) => SendBinary(data); + public void Send(byte[] data, int length = Constants.UseArrayLengthForSend) => SendBinary(data, length); /// /// This method sends a binary message over the WebSocket connection. /// /// - public void SendBinary(byte[] data) => - EnqueueSendMessage(new WebSocketMessage(data, WebSocketMessageType.Binary)); + public void SendBinary(byte[] data, int length = Constants.UseArrayLengthForSend) => + EnqueueSendMessage(new WebSocketMessage(data, WebSocketMessageType.Binary, length)); /// /// This method sends a text message over the WebSocket connection. /// - public void SendMessage(byte[] data) => - EnqueueSendMessage(new WebSocketMessage(data, WebSocketMessageType.Text)); + public void SendMessage(byte[] data, int length = Constants.UseArrayLengthForSend) => + EnqueueSendMessage(new WebSocketMessage(data, WebSocketMessageType.Text, length)); /// /// This method sends a binary message over the WebSocket connection immediately without queueing. /// - public void SendBinaryImmediately(byte[] data) + public void SendBinaryImmediately(byte[] data, int length = Constants.UseArrayLengthForSend) { lock (_mutexSend) { Log.Verbose("SendBinaryImmediately", "Sending binary message immediately.."); // TODO: dump this message - _clientWebSocket.SendAsync(new ArraySegment(data), WebSocketMessageType.Binary, true, _cancellationTokenSource.Token) + if (length == Constants.UseArrayLengthForSend) + { + length = data.Length; + } + _clientWebSocket.SendAsync(new ArraySegment(data, 0, length), WebSocketMessageType.Binary, true, _cancellationTokenSource.Token) .ConfigureAwait(false); } } @@ -349,12 +374,16 @@ public void SendBinaryImmediately(byte[] data) /// /// This method sends a text message over the WebSocket connection immediately without queueing. /// - public void SendMessageImmediately(byte[] data) + public void SendMessageImmediately(byte[] data, int length = Constants.UseArrayLengthForSend) { lock (_mutexSend) { Log.Verbose("SendBinaryImmediately", "Sending binary message immediately.."); // TODO: dump this message - _clientWebSocket.SendAsync(new ArraySegment(data), WebSocketMessageType.Text, true, _cancellationTokenSource.Token) + if (length == Constants.UseArrayLengthForSend) + { + length = data.Length; + } + _clientWebSocket.SendAsync(new ArraySegment(data, 0, length), WebSocketMessageType.Text, true, _cancellationTokenSource.Token) .ConfigureAwait(false); } } diff --git a/Deepgram/Clients/Listen/v1/WebSocket/Constants.cs b/Deepgram/Clients/Listen/v1/WebSocket/Constants.cs index 05f2cdcc..6da861b0 100644 --- a/Deepgram/Clients/Listen/v1/WebSocket/Constants.cs +++ b/Deepgram/Clients/Listen/v1/WebSocket/Constants.cs @@ -11,11 +11,13 @@ public static class Constants { // WS buffer size public const int BufferSize = 1024 * 16; + public const int UseArrayLengthForSend = -1; // Default timeout for connect/disconnect public const int DefaultConnectTimeout = 5000; public const int DefaultDisconnectTimeout = 5000; + // Default flush period public const int DefaultFlushPeriodInMs = 500; } diff --git a/Deepgram/Clients/Listen/v1/WebSocket/WebSocketMessage.cs b/Deepgram/Clients/Listen/v1/WebSocket/WebSocketMessage.cs index b70786f3..5fcd03d1 100644 --- a/Deepgram/Clients/Listen/v1/WebSocket/WebSocketMessage.cs +++ b/Deepgram/Clients/Listen/v1/WebSocket/WebSocketMessage.cs @@ -4,9 +4,30 @@ namespace Deepgram.Clients.Listen.v1.WebSocket; -internal readonly struct WebSocketMessage(byte[] message, WebSocketMessageType type) +internal readonly struct WebSocketMessage { - public ArraySegment Message { get; } = new ArraySegment(message); + public WebSocketMessage(byte[] message, WebSocketMessageType type) + : this(message, type, Constants.UseArrayLengthForSend) + { + } - public WebSocketMessageType MessageType { get; } = type; + public WebSocketMessage(byte[] message, WebSocketMessageType type, int length) + { + if (length != Constants.UseArrayLengthForSend || length < Constants.UseArrayLengthForSend) + { + Message = new ArraySegment(message, 0, length); + } + else + { + Message = new ArraySegment(message, 0, message.Length); + } + MessageType = type; + Length = length; + } + + public int Length { get; } + + public ArraySegment Message { get; } + + public WebSocketMessageType MessageType { get; } } diff --git a/Deepgram/Clients/Speak/v1/WebSocket/Client.cs b/Deepgram/Clients/Speak/v1/WebSocket/Client.cs index 4ba6f6af..8f1ff281 100644 --- a/Deepgram/Clients/Speak/v1/WebSocket/Client.cs +++ b/Deepgram/Clients/Speak/v1/WebSocket/Client.cs @@ -348,7 +348,7 @@ public void Close() /// Sends a binary message over the WebSocket connection. /// /// The data to be sent over the WebSocket. - public void Send(byte[] data) => SendMessage(data); + public void Send(byte[] data, int length = Constants.UseArrayLengthForSend) => SendMessage(data, length); ///// ///// This method sends a binary message over the WebSocket connection. @@ -361,7 +361,7 @@ public void Close() /// /// This method sends a text message over the WebSocket connection. /// - public void SendMessage(byte[] data) + public void SendMessage(byte[] data, int length = Constants.UseArrayLengthForSend) { // auto flush if (_deepgramClientOptions.InspectSpeakMessage()) @@ -384,7 +384,7 @@ public void SendMessage(byte[] data) } // send message - EnqueueSendMessage(new WebSocketMessage(data, WebSocketMessageType.Text)); + EnqueueSendMessage(new WebSocketMessage(data, WebSocketMessageType.Text, length)); } ///// ///// This method sends a binary message over the WebSocket connection immediately without queueing. @@ -403,7 +403,7 @@ public void SendMessage(byte[] data) /// /// This method sends a text message over the WebSocket connection immediately without queueing. /// - public void SendMessageImmediately(byte[] data) + public void SendMessageImmediately(byte[] data, int length = Constants.UseArrayLengthForSend) { // auto flush if (_deepgramClientOptions.InspectSpeakMessage()) @@ -428,7 +428,11 @@ public void SendMessageImmediately(byte[] data) lock (_mutexSend) { Log.Verbose("SendBinaryImmediately", "Sending text message immediately.."); // TODO: dump this message - _clientWebSocket.SendAsync(new ArraySegment(data), WebSocketMessageType.Text, true, _cancellationTokenSource.Token) + if (length == Constants.UseArrayLengthForSend) + { + length = data.Length; + } + _clientWebSocket.SendAsync(new ArraySegment(data, 0, length), WebSocketMessageType.Text, true, _cancellationTokenSource.Token) .ConfigureAwait(false); } } diff --git a/Deepgram/Clients/Speak/v1/WebSocket/Constants.cs b/Deepgram/Clients/Speak/v1/WebSocket/Constants.cs index a65f309e..8f21012a 100644 --- a/Deepgram/Clients/Speak/v1/WebSocket/Constants.cs +++ b/Deepgram/Clients/Speak/v1/WebSocket/Constants.cs @@ -11,6 +11,7 @@ public static class Constants { // WS buffer size public const int BufferSize = 1024 * 16; + public const int UseArrayLengthForSend = -1; // Default timeout for connect/disconnect public const int DefaultConnectTimeout = 5000; diff --git a/Deepgram/Clients/Speak/v1/WebSocket/WebSocketMessage.cs b/Deepgram/Clients/Speak/v1/WebSocket/WebSocketMessage.cs index 51fa8fbe..f9625bb7 100644 --- a/Deepgram/Clients/Speak/v1/WebSocket/WebSocketMessage.cs +++ b/Deepgram/Clients/Speak/v1/WebSocket/WebSocketMessage.cs @@ -4,9 +4,30 @@ namespace Deepgram.Clients.Speak.v1.WebSocket; -internal readonly struct WebSocketMessage(byte[] message, WebSocketMessageType type) +internal readonly struct WebSocketMessage { - public ArraySegment Message { get; } = new ArraySegment(message); + public WebSocketMessage(byte[] message, WebSocketMessageType type) + : this(message, type, Constants.UseArrayLengthForSend) + { + } - public WebSocketMessageType MessageType { get; } = type; + public WebSocketMessage(byte[] message, WebSocketMessageType type, int length) + { + if (length != Constants.UseArrayLengthForSend || length < Constants.UseArrayLengthForSend) + { + Message = new ArraySegment(message, 0, length); + } + else + { + Message = new ArraySegment(message, 0, message.Length); + } + MessageType = type; + Length = length; + } + + public int Length { get; } + + public ArraySegment Message { get; } + + public WebSocketMessageType MessageType { get; } }