public async Task SpeakAsync(string text, int max, SpeechOptions options, CancellationToken cancelToken) { await Initialize(); // Wait for any previous calls to finish up if (tcsUtterances?.Task != null) { await tcsUtterances.Task; } tcsUtterances = new TaskCompletionSource <bool>(); if (cancelToken != default) { cancelToken.Register(() => { try { tts?.Stop(); tcsUtterances?.TrySetResult(true); } catch { } }); } if (options?.Locale?.Language != null) { JavaLocale locale = null; if (!string.IsNullOrWhiteSpace(options?.Locale.Country)) { locale = new JavaLocale(options.Locale.Language, options.Locale.Country); } else { locale = new JavaLocale(options.Locale.Language); } tts.SetLanguage(locale); } else { SetDefaultLanguage(); } if (options?.Pitch.HasValue ?? false) { tts.SetPitch(options.Pitch.Value); } else { tts.SetPitch(TextToSpeechImplementation.PitchDefault); } tts.SetSpeechRate(1.0f); var parts = TextToSpeech.SplitSpeak(text, max); numExpectedUtterances = parts.Count; var guid = Guid.NewGuid().ToString(); for (var i = 0; i < parts.Count && !cancelToken.IsCancellationRequested; i++) { // We require the utterance id to be set if we want the completed listener to fire var map = new Dictionary <string, string> { { AndroidTextToSpeech.Engine.KeyParamUtteranceId, $"{guid}.{i}" } }; if (options != null && options.Volume.HasValue) { map.Add(AndroidTextToSpeech.Engine.KeyParamVolume, options.Volume.Value.ToString(CultureInfo.InvariantCulture)); } // We use an obsolete overload here so it works on older API levels at runtime // Flush on first entry and add (to not flush our own previous) subsequent entries #pragma warning disable CS0618 tts.Speak(parts[i], i == 0 ? QueueMode.Flush : QueueMode.Add, map); #pragma warning restore CS0618 } await tcsUtterances.Task; }
Task PlatformSpeakAsync(string text, SpeechOptions options, CancellationToken cancelToken) => throw ExceptionUtils.NotSupportedOrImplementedException;