From f5643329bb21669b157c76873491f6e5385c9c7d Mon Sep 17 00:00:00 2001 From: dvonthenen Date: Wed, 3 Apr 2024 12:37:07 -0700 Subject: [PATCH] Add Subscribe Interface to Live Client --- Deepgram/Clients/Live/v1/Client.cs | 155 +++++++++++++----- Deepgram/LiveClient.cs | 1 + clean-up.ps1 | 16 -- clean-up.sh | 12 +- examples/manage/balances/Manage.csproj | 22 +++ examples/manage/balances/Program.cs | 79 +++++++++ examples/streaming/file/Program.cs | 8 +- examples/streaming/microphone/Program.cs | 48 +++--- tests/edge_cases/keepalive/Program.cs | 24 +-- .../exercise_timeout/Program.cs | 24 +-- 10 files changed, 273 insertions(+), 116 deletions(-) delete mode 100644 clean-up.ps1 create mode 100644 examples/manage/balances/Manage.csproj create mode 100644 examples/manage/balances/Program.cs diff --git a/Deepgram/Clients/Live/v1/Client.cs b/Deepgram/Clients/Live/v1/Client.cs index 76963872..2d14e3b7 100644 --- a/Deepgram/Clients/Live/v1/Client.cs +++ b/Deepgram/Clients/Live/v1/Client.cs @@ -2,6 +2,7 @@ // Use of this source code is governed by a MIT license that can be found in the LICENSE file. // SPDX-License-Identifier: MIT +using System.Threading; using Deepgram.Models.Authenticate.v1; using Deepgram.Models.Live.v1; @@ -17,6 +18,7 @@ public class Client : Attribute, IDisposable private ClientWebSocket? _clientWebSocket; private CancellationTokenSource? _cancellationTokenSource; + private readonly Mutex _mutex = new Mutex(); #endregion /// Required DeepgramApiKey @@ -35,18 +37,18 @@ public Client(string? apiKey = null, DeepgramWsClientOptions? options = null) Log.Verbose("LiveClient", "LEAVE"); } - #region Subscribe Events + #region Event Handlers /// /// Fires when an event is received from the Deepgram API /// - public event EventHandler? _openReceived; - public event EventHandler? _metadataReceived; - public event EventHandler? _resultsReceived; - public event EventHandler? _utteranceEndReceived; - public event EventHandler? _speechStartedReceived; - public event EventHandler? _closeReceived; - public event EventHandler? _unhandledReceived; - public event EventHandler? _errorReceived; + private event EventHandler? _openReceived; + private event EventHandler? _metadataReceived; + private event EventHandler? _resultsReceived; + private event EventHandler? _utteranceEndReceived; + private event EventHandler? _speechStartedReceived; + private event EventHandler? _closeReceived; + private event EventHandler? _unhandledReceived; + private event EventHandler? _errorReceived; #endregion /// @@ -161,36 +163,111 @@ void StartKeepAliveBackgroundThread() => _ = Task.Factory.StartNew( Log.Verbose("LiveClient.Connect", "LEAVE"); } - //// TODO: convienence method for subscribing to events - //public void On(T e, EventHandler eventHandler) { - // switch (e) - // { - // case OpenResponse open: - // OpenReceived += (sender, e) => eventHandler; - // break; - // case MetadataResponse metadata: - // MetadataReceived += (sender, e) => eventHandler; - // break; - // case ResultResponse result: - // ResultsReceived += (sender, e) => eventHandler; - // break; - // case UtteranceEndResponse utteranceEnd: - // UtteranceEndReceived += (sender, e) => eventHandler; - // break; - // case SpeechStartedResponse speechStarted: - // SpeechStartedReceived += (sender, e) => eventHandler; - // break; - // case CloseResponse close: - // CloseReceived += (sender, e) => eventHandler; - // break; - // case UnhandledResponse unhandled: - // UnhandledReceived += (sender, e) => eventHandler; - // break; - // case ErrorResponse error: - // ErrorReceived += (sender, e) => eventHandler; - // break; - // } - //} + #region Subscribe Event + /// + /// Subscribe to an Open event from the Deepgram API + /// + /// + /// True if successful + public bool Subscribe(EventHandler eventHandler) + { + lock (_mutex) + { + _openReceived += (sender, e) => eventHandler(sender, e); + } + + return true; + } + + /// + /// Subscribe to a Metadata event from the Deepgram API + /// + /// + /// True if successful + public bool Subscribe(EventHandler eventHandler) + { + lock (_mutex) + { + _metadataReceived += (sender, e) => eventHandler(sender, e); + } + return true; + } + + /// + /// Subscribe to a Results event from the Deepgram API + /// + /// True if successful + public bool Subscribe(EventHandler eventHandler) + { + lock (_mutex) + { + _resultsReceived += (sender, e) => eventHandler(sender, e); + } + return true; + } + + /// + /// Subscribe to an UtteranceEnd event from the Deepgram API + /// + /// True if successful + public bool Subscribe(EventHandler eventHandler) + { + lock (_mutex) + { + _utteranceEndReceived += (sender, e) => eventHandler(sender, e); + } + return true; + } + + /// + /// Subscribe to a SpeechStarted event from the Deepgram API + /// + /// True if successful + public bool Subscribe(EventHandler eventHandler) + { + _speechStartedReceived += (sender, e) => eventHandler(sender, e); + return true; + } + + /// + /// Subscribe to a Close event from the Deepgram API + /// + /// True if successful + public bool Subscribe(EventHandler eventHandler) + { + lock (_mutex) + { + _closeReceived += (sender, e) => eventHandler(sender, e); + } + return true; + } + + /// + /// Subscribe to an Unhandled event from the Deepgram API + /// + /// True if successful + public bool Subscribe(EventHandler eventHandler) + { + lock (_mutex) + { + _unhandledReceived += (sender, e) => eventHandler(sender, e); + } + return true; + } + + /// + /// Subscribe to an Error event from the Deepgram API + /// + /// True if successful + public bool Subscribe(EventHandler eventHandler) + { + lock (_mutex) + { + _errorReceived += (sender, e) => eventHandler(sender, e); + } + return true; + } + #endregion /// /// Sends a binary message over the WebSocket connection. diff --git a/Deepgram/LiveClient.cs b/Deepgram/LiveClient.cs index 2127c609..44987e33 100644 --- a/Deepgram/LiveClient.cs +++ b/Deepgram/LiveClient.cs @@ -4,6 +4,7 @@ using Deepgram.Clients.Live.v1; using Deepgram.Models.Authenticate.v1; +using Deepgram.Models.Live.v1; namespace Deepgram; diff --git a/clean-up.ps1 b/clean-up.ps1 deleted file mode 100644 index 59ac4527..00000000 --- a/clean-up.ps1 +++ /dev/null @@ -1,16 +0,0 @@ -Write-Output "Cleaning up the environment" - -# Deepgram -# Remove-Item -Recurse -Force -Remove-Item -Recurse -Force -LiteralPath "./.vs" -Remove-Item -Recurse -Force -LiteralPath "./dist" -Remove-Item -Recurse -Force -LiteralPath "./Deepgram/obj" -Remove-Item -Recurse -Force -LiteralPath "./Deepgram/bin" - -#Deepgram.Tests -Remove-Item -Recurse -Force -LiteralPath "./Deepgram.Tests/bin" -Remove-Item -Recurse -Force -LiteralPath "./Deepgram.Tests/obj" - -#Deepgram.Microphone -Remove-Item -Recurse -Force -LiteralPath "./Deepgram.Microphone/bin" -Remove-Item -Recurse -Force -LiteralPath "./Deepgram.Microphone/obj" diff --git a/clean-up.sh b/clean-up.sh index 280d2f5e..98fe9341 100644 --- a/clean-up.sh +++ b/clean-up.sh @@ -7,13 +7,7 @@ set -o xtrace rm -rf ./.vs rm -rf ./dist -rm -rf ./Deepgram/obj -rm -rf ./Deepgram/bin -# Deepgram.Tests -rm -rf ./Deepgram.Tests/bin -rm -rf ./Deepgram.Tests/obj - -# Deepgram.Microphone -rm -rf ./Deepgram.Microphone/bin -rm -rf ./Deepgram.Microphone/obj \ No newline at end of file +# delete all compile actifacts +find ./ -type d -iname obj -print0 | xargs -0 rm -rf +find ./ -type d -iname bin -print0 | xargs -0 rm -rf \ No newline at end of file diff --git a/examples/manage/balances/Manage.csproj b/examples/manage/balances/Manage.csproj new file mode 100644 index 00000000..33d8f4ee --- /dev/null +++ b/examples/manage/balances/Manage.csproj @@ -0,0 +1,22 @@ + + + + Exe + net6.0 + enable + enable + + + + + + + + + + + + + + + diff --git a/examples/manage/balances/Program.cs b/examples/manage/balances/Program.cs new file mode 100644 index 00000000..cbdc63cf --- /dev/null +++ b/examples/manage/balances/Program.cs @@ -0,0 +1,79 @@ +// 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 + +using System.Text.Json; + +using Deepgram.Logger; +using Deepgram.Models.Manage.v1; + +namespace SampleApp +{ + class Program + { + static async Task Main(string[] args) + { + // Initialize Library with default logging + // Normal logging is "Info" level + Library.Initialize(); + // OR very chatty logging + //Library.Initialize(LogLevel.Debug); // LogLevel.Default, LogLevel.Debug, LogLevel.Verbose + + // Set "DEEPGRAM_API_KEY" environment variable to your Deepgram API Key + var deepgramClient = new ManageClient(); + + var response = await deepgramClient.GetProjects(); + if (response == null) + { + Console.WriteLine("No projects found."); + return; + } + + Console.WriteLine(JsonSerializer.Serialize(response)); + + //var projectId = ""; + //foreach (var project in response.Projects) + //{ + // Console.WriteLine($"Project ID: {project.ProjectId}"); + // projectId = project.ProjectId; + // break; + //} + + //var balanacesResponse = deepgramClient.GetBalances(projectId); + //if (balanacesResponse == null || balanacesResponse.Balances == null) + //{ + // Console.WriteLine("No balance found."); + // return; + //} + + //Console.WriteLine("\n\nBalances:"); + //Console.WriteLine(JsonSerializer.Serialize(balanacesResponse)); + //Console.WriteLine("\n\n"); + + //string balanceId = ""; + //foreach (var balance in balanacesResponse.Balances) + //{ + // Console.WriteLine($"Balance ID: {balance.BalanceId}"); + // balanceId = balance.BalanceId; + // break; + //} + + //var balanaceResponse = deepgramClient.GetBalance(projectId, balanceId); + //if (balanaceResponse == null) + //{ + // Console.WriteLine("No balance found."); + // return; + //} + + //Console.WriteLine("\n\nBalances:"); + //Console.WriteLine(JsonSerializer.Serialize(balanacesResponse)); + //Console.WriteLine("\n\n"); + + Console.WriteLine("Press any key to exit."); + Console.ReadKey(); + + // Teardown Library + Library.Terminate(); + } + } +} \ No newline at end of file diff --git a/examples/streaming/file/Program.cs b/examples/streaming/file/Program.cs index 866a1855..9d82a6b9 100644 --- a/examples/streaming/file/Program.cs +++ b/examples/streaming/file/Program.cs @@ -21,16 +21,16 @@ static async Task Main(string[] args) var liveClient = new LiveClient(); // Subscribe to the EventResponseReceived event - liveClient._resultsReceived += (sender, e) => + liveClient.Subscribe(new EventHandler((sender, e) => { if (e.Channel.Alternatives[0].Transcript == "") { return; } - // Console.WriteLine("Transcription received: " + JsonSerializer.Serialize(e.Response.Transcription)); - Console.WriteLine($"Speaker: {e.Channel.Alternatives[0].Transcript}"); - }; + // Console.WriteLine("Transcription received: " + JsonSerializer.Serialize(e.Transcription)); + Console.WriteLine($"\n\n\n----> Speaker: {e.Channel.Alternatives[0].Transcript}\n\n\n"); + })); // Start the connection var liveSchema = new LiveSchema() diff --git a/examples/streaming/microphone/Program.cs b/examples/streaming/microphone/Program.cs index 17e2e26f..37f2dff6 100644 --- a/examples/streaming/microphone/Program.cs +++ b/examples/streaming/microphone/Program.cs @@ -32,15 +32,15 @@ static async Task Main(string[] args) //var liveClient = new LiveClienkt("set your DEEPGRAM_API_KEY here"); // Subscribe to the EventResponseReceived event - liveClient._openReceived += (sender, e) => + liveClient.Subscribe(new EventHandler((sender, e) => { - Console.WriteLine($"{e.Type} received"); - }; - liveClient._metadataReceived += (sender, e) => + Console.WriteLine($"----> {e.Type} received"); + })); + liveClient.Subscribe(new EventHandler((sender, e) => { - Console.WriteLine($"{e.Type} received: {JsonSerializer.Serialize(e)}"); - }; - liveClient._resultsReceived += (sender, e) => + Console.WriteLine($"----> {e.Type} received"); + })); + liveClient.Subscribe(new EventHandler((sender, e) => { if (e.Channel.Alternatives[0].Transcript == "") { @@ -48,28 +48,28 @@ static async Task Main(string[] args) } // Console.WriteLine("Transcription received: " + JsonSerializer.Serialize(e.Transcription)); - Console.WriteLine($"\n\n\nSpeaker: {e.Channel.Alternatives[0].Transcript}\n\n\n"); - }; - liveClient._speechStartedReceived += (sender, e) => + Console.WriteLine($"\n\n\n----> Speaker: {e.Channel.Alternatives[0].Transcript}\n\n\n"); + })); + liveClient.Subscribe(new EventHandler((sender, e) => { - Console.WriteLine($"{e.Type} received"); - }; - liveClient._utteranceEndReceived += (sender, e) => + Console.WriteLine($"----> {e.Type} received"); + })); + liveClient.Subscribe(new EventHandler((sender, e) => { - Console.WriteLine($"{e.Type} received"); - }; - liveClient._closeReceived += (sender, e) => + Console.WriteLine($"----> {e.Type} received"); + })); + liveClient.Subscribe(new EventHandler((sender, e) => { - Console.WriteLine($"{e.Type} received"); - }; - liveClient._unhandledReceived += (sender, e) => + Console.WriteLine($"----> {e.Type} received"); + })); + liveClient.Subscribe(new EventHandler((sender, e) => { - Console.WriteLine($"{e.Type} received. Raw: {e.Raw}"); - }; - liveClient._errorReceived += (sender, e) => + Console.WriteLine($"----> {e.Type} received"); + })); + liveClient.Subscribe(new EventHandler((sender, e) => { - Console.WriteLine($"{e.Type} received. Error: {e.Message}"); - }; + Console.WriteLine($"----> { e.Type} received. Error: {e.Message}"); + })); // my own cancellation token //var cancellationToken = new CancellationTokenSource(); diff --git a/tests/edge_cases/keepalive/Program.cs b/tests/edge_cases/keepalive/Program.cs index cbc4c3ae..9f2ad67e 100644 --- a/tests/edge_cases/keepalive/Program.cs +++ b/tests/edge_cases/keepalive/Program.cs @@ -25,11 +25,11 @@ static async Task Main(string[] args) var liveClient = new LiveClient("", options); // Subscribe to the EventResponseReceived event - liveClient._openReceived += (sender, e) => + liveClient.Subscribe(new EventHandler((sender, e) => { - Console.WriteLine($"{e.Type} received"); - }; - liveClient._resultsReceived += (sender, e) => + Console.WriteLine($"----> {e.Type} received"); + })); + liveClient.Subscribe(new EventHandler((sender, e) => { if (e.Channel.Alternatives[0].Transcript == "") { @@ -37,16 +37,16 @@ static async Task Main(string[] args) } // Console.WriteLine("Transcription received: " + JsonSerializer.Serialize(e.Transcription)); - Console.WriteLine($"\n\n\nSpeaker: {e.Channel.Alternatives[0].Transcript}\n\n\n"); - }; - liveClient._closeReceived += (sender, e) => + Console.WriteLine($"\n\n\n----> Speaker: {e.Channel.Alternatives[0].Transcript}\n\n\n"); + })); + liveClient.Subscribe(new EventHandler((sender, e) => { - Console.WriteLine($"{e.Type} received"); - }; - liveClient._errorReceived += (sender, e) => + Console.WriteLine($"----> {e.Type} received"); + })); + liveClient.Subscribe(new EventHandler((sender, e) => { - Console.WriteLine($"{e.Type} received. Error: {e.Message}"); - }; + Console.WriteLine($"----> {e.Type} received. Error: {e.Message}"); + })); // Start the connection var liveSchema = new LiveSchema() diff --git a/tests/expected_failures/exercise_timeout/Program.cs b/tests/expected_failures/exercise_timeout/Program.cs index c958d46d..7fedeb53 100644 --- a/tests/expected_failures/exercise_timeout/Program.cs +++ b/tests/expected_failures/exercise_timeout/Program.cs @@ -20,11 +20,11 @@ static async Task Main(string[] args) var liveClient = new LiveClient(); // Subscribe to the EventResponseReceived event - liveClient._openReceived += (sender, e) => + liveClient.Subscribe(new EventHandler((sender, e) => { - Console.WriteLine($"{e.Type} received"); - }; - liveClient._resultsReceived += (sender, e) => + Console.WriteLine($"----> {e.Type} received"); + })); + liveClient.Subscribe(new EventHandler((sender, e) => { if (e.Channel.Alternatives[0].Transcript == "") { @@ -32,16 +32,16 @@ static async Task Main(string[] args) } // Console.WriteLine("Transcription received: " + JsonSerializer.Serialize(e.Transcription)); - Console.WriteLine($"\n\n\nSpeaker: {e.Channel.Alternatives[0].Transcript}\n\n\n"); - }; - liveClient._closeReceived += (sender, e) => + Console.WriteLine($"\n\n\n----> Speaker: {e.Channel.Alternatives[0].Transcript}\n\n\n"); + })); + liveClient.Subscribe(new EventHandler((sender, e) => { - Console.WriteLine($"{e.Type} received"); - }; - liveClient._errorReceived += (sender, e) => + Console.WriteLine($"----> {e.Type} received"); + })); + liveClient.Subscribe(new EventHandler((sender, e) => { - Console.WriteLine($"{e.Type} received. Error: {e.Message}"); - }; + Console.WriteLine($"----> {e.Type} received. Error: {e.Message}"); + })); // Start the connection var liveSchema = new LiveSchema()