Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@

<Capabilities>
<rescap:Capability Name="runFullTrust" />
<DeviceCapability Name="microphone"/>
</Capabilities>

</Package>
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,9 @@

namespace CommunityToolkit.Maui.Sample.ViewModels.Essentials;

public partial class SpeechToTextViewModel : BaseViewModel
public partial class SpeechToTextViewModel : BaseViewModel, IAsyncDisposable
{
const string defaultLanguage = "en-US";
const string defaultLanguage_android = "en";
const string defaultLanguage_tizen = "en_US";

readonly ITextToSpeech textToSpeech;
readonly ISpeechToText speechToText;
Expand Down Expand Up @@ -55,7 +53,7 @@ async Task SetLocales(CancellationToken token)
Locales.Add(locale);
}

CurrentLocale = Locales.FirstOrDefault(x => x.Language is defaultLanguage or defaultLanguage_android or defaultLanguage_tizen) ?? Locales.FirstOrDefault();
CurrentLocale = Locales.FirstOrDefault();
}

[RelayCommand]
Expand Down Expand Up @@ -148,4 +146,9 @@ void HandleLocalesCollectionChanged(object? sender, NotifyCollectionChangedEvent
{
OnPropertyChanged(nameof(CurrentLocale));
}

public async ValueTask DisposeAsync()
{
await speechToText.DisposeAsync();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,6 @@ public SpeechToTextState CurrentState
public ValueTask DisposeAsync()
{
InternalStopListening();

offlineSpeechRecognizer?.Dispose();
offlineSpeechRecognizer = null;
return ValueTask.CompletedTask;
}

Expand All @@ -39,7 +36,6 @@ Task InternalStartListening(SpeechToTextOptions options, CancellationToken token
Initialize(options);

offlineSpeechRecognizer.AudioStateChanged += OfflineSpeechRecognizer_StateChanged;
offlineSpeechRecognizer.LoadGrammar(new DictationGrammar());

offlineSpeechRecognizer.InitialSilenceTimeout = TimeSpan.MaxValue;
offlineSpeechRecognizer.BabbleTimeout = TimeSpan.MaxValue;
Expand All @@ -48,7 +44,12 @@ Task InternalStartListening(SpeechToTextOptions options, CancellationToken token

offlineSpeechRecognizer.RecognizeCompleted += OnRecognizeCompleted;
offlineSpeechRecognizer.SpeechRecognized += OnSpeechRecognized;
offlineSpeechRecognizer.RecognizeAsync(RecognizeMode.Multiple);

if (offlineSpeechRecognizer.AudioState == AudioState.Stopped)
{
offlineSpeechRecognizer.RecognizeAsync(RecognizeMode.Multiple);
}

return Task.CompletedTask;
}

Expand Down Expand Up @@ -81,19 +82,26 @@ void InternalStopListening()
{
try
{
if (offlineSpeechRecognizer is not null)
if (offlineSpeechRecognizer is not null && offlineSpeechRecognizer.AudioState != AudioState.Stopped)
{
offlineSpeechRecognizer.RecognizeAsyncStop();

offlineSpeechRecognizer.AudioStateChanged -= OfflineSpeechRecognizer_StateChanged;
offlineSpeechRecognizer.RecognizeCompleted -= OnRecognizeCompleted;
offlineSpeechRecognizer.SpeechRecognized -= OnSpeechRecognized;
}
}
catch
{
// ignored. Recording may be already stopped
}
finally
{
if (offlineSpeechRecognizer is not null)
{
offlineSpeechRecognizer.AudioStateChanged -= OfflineSpeechRecognizer_StateChanged;
offlineSpeechRecognizer.RecognizeCompleted -= OnRecognizeCompleted;
offlineSpeechRecognizer.SpeechRecognized -= OnSpeechRecognized;
offlineSpeechRecognizer?.Dispose();
offlineSpeechRecognizer = null;
}
}
}

[MemberNotNull(nameof(recognitionText), nameof(offlineSpeechRecognizer), nameof(speechToTextOptions))]
Expand All @@ -102,6 +110,7 @@ void Initialize(SpeechToTextOptions options)
speechToTextOptions = options;
recognitionText = string.Empty;
offlineSpeechRecognizer = new SpeechRecognitionEngine(options.Culture);
offlineSpeechRecognizer.LoadGrammarAsync(new DictationGrammar());
}

void OfflineSpeechRecognizer_StateChanged(object? sender, AudioStateChangedEventArgs e)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Speech.Recognition;
using Microsoft.Maui.ApplicationModel;
using Windows.Globalization;
using Windows.Media.SpeechRecognition;
Expand Down Expand Up @@ -35,8 +34,6 @@ public SpeechToTextState CurrentState
public async ValueTask DisposeAsync()
{
await StopRecording(CancellationToken.None);
speechRecognizer?.Dispose();
speechRecognizer = null;
}

async Task InternalStartListeningAsync(SpeechToTextOptions options, CancellationToken cancellationToken)
Expand All @@ -48,7 +45,10 @@ async Task InternalStartListeningAsync(SpeechToTextOptions options, Cancellation
speechRecognizer.ContinuousRecognitionSession.Completed += OnCompleted;
try
{
await speechRecognizer.ContinuousRecognitionSession.StartAsync().AsTask(cancellationToken);
if (speechRecognizer.State == SpeechRecognizerState.Idle)
{
await speechRecognizer.ContinuousRecognitionSession.StartAsync().AsTask(cancellationToken);
}
}
catch (Exception ex) when ((uint)ex.HResult is privacyStatementDeclinedCode)
{
Expand Down Expand Up @@ -88,12 +88,8 @@ async Task StopRecording(CancellationToken cancellationToken)
{
try
{
if (speechRecognizer is not null)
if (speechRecognizer is not null && speechRecognizer.State != SpeechRecognizerState.Idle)
{
speechRecognizer.StateChanged -= SpeechRecognizer_StateChanged;
speechRecognizer.ContinuousRecognitionSession.ResultGenerated -= ResultGenerated;
speechRecognizer.ContinuousRecognitionSession.Completed -= OnCompleted;

cancellationToken.ThrowIfCancellationRequested();
await speechRecognizer.ContinuousRecognitionSession.StopAsync().AsTask(cancellationToken);
}
Expand All @@ -102,6 +98,17 @@ async Task StopRecording(CancellationToken cancellationToken)
{
// ignored. Recording may be already stopped
}
finally
{
if (speechRecognizer is not null)
{
speechRecognizer.StateChanged -= SpeechRecognizer_StateChanged;
speechRecognizer.ContinuousRecognitionSession.ResultGenerated -= ResultGenerated;
speechRecognizer.ContinuousRecognitionSession.Completed -= OnCompleted;
speechRecognizer?.Dispose();
speechRecognizer = null;
}
}
}

[MemberNotNull(nameof(recognitionText), nameof(speechRecognizer), nameof(speechToTextOptions))]
Expand Down
Loading