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;
            }

            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(TextToSpeech.PitchDefault);
            }

            tts.SetSpeechRate(1.0f);

            var parts = text.SplitSpeak(max);

            numExpectedUtterances = parts.Count;
            tcsUtterances         = new TaskCompletionSource <bool>();

            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;
        }
 internal static Task PlatformSpeakAsync(string text, SpeechOptions options, CancellationToken cancelToken = default) =>
 throw ExceptionUtils.NotSupportedOrImplementedException;