static void write_to_console(string text, USER_CONFIG user_config)
 {
     if (false == user_config.suppress_output_enabled)
     {
         Console.Write(text);
     }
 }
 static void write_to_console_or_file(string text, USER_CONFIG user_config)
 {
     if (false == user_config.suppress_output_enabled)
     {
         Console.Write(text);
     }
     if (true == user_config.output_file_enabled)
     {
         File.AppendAllText(user_config.output_file, text);
     }
 }
        static void initialize(USER_CONFIG user_config)
        {
            if (true == user_config.output_file_enabled && true == File.Exists(user_config.output_file))
            {
                File.Delete(user_config.output_file);
            }

            if (false == user_config.srt_enabled)
            {
                write_to_console_or_file(String.Format("WEBVTT{0}{0}", Environment.NewLine), user_config);
            }
        }
        static SpeechConfig user_config_to_speech_config(USER_CONFIG user_config)
        {
            Uri          endpoint      = new Uri(region_to_endpoint(user_config.region));
            SpeechConfig speech_config = SpeechConfig.FromEndpoint(endpoint, user_config.subscription_key);

/* Note: Dictation mode is only supported for continuous recognition.
 * See:
 * https://docs.microsoft.com/azure/cognitive-services/speech-service/get-started-speech-to-text?tabs=windowsinstall&pivots=programming-language-cpp#dictation-mode
 */
            if (true == user_config.dictation_enabled)
            {
                speech_config.EnableDictation();
            }

            if (true == user_config.language_id_enabled)
            {
/* Notes:
 * - Continuous language identification is supported only in C#, C++, and Python.
 * See:
 * https://docs.microsoft.com/azure/cognitive-services/Speech-Service/language-identification?tabs=once&pivots=programming-language-cpp#at-start-and-continuous-language-identification
 *
 * - Valid values are "Latency" and "Accuracy" (for standalone languageId).
 * See:
 * https://docs.microsoft.com/azure/cognitive-services/Speech-Service/language-identification?tabs=once&pivots=programming-language-cpp#accuracy-and-latency-prioritization
 */
                if (true == user_config.prioritize_accuracy_enabled)
                {
                    speech_config.SetProperty(PropertyId.SpeechServiceConnection_ContinuousLanguageIdPriority, "Accuracy");
                }
                else
                {
                    speech_config.SetProperty(PropertyId.SpeechServiceConnection_ContinuousLanguageIdPriority, "Latency");
                }
            }

            if (true == user_config.profanity_filter_enabled)
            {
                speech_config.SetProfanity(ProfanityOption.Removed);
            }

            if (true == user_config.stable_partial_result_threshold_enabled)
            {
                speech_config.SetProperty("StablePartialResultThreshold", user_config.stable_partial_result_threshold);
            }

            if (true == user_config.true_text_enabled)
            {
                speech_config.SetProperty("SpeechServiceResponse_PostProcessingOption", "TrueText");
            }

            return(speech_config);
        }
        static async Task <string?> recognize_continuous(SpeechRecognizer speech_recognizer, USER_CONFIG user_config)
        {
            var recognition_end = new TaskCompletionSource <string?>();
            int sequence_number = 0;

            speech_recognizer.Recognized += (object?sender, SpeechRecognitionEventArgs e) =>
            {
                if (ResultReason.RecognizedSpeech == e.Result.Reason && e.Result.Text.Length > 0)
                {
                    string?language = null;
                    if (true == user_config.language_id_enabled)
                    {
                        var language_id_result = AutoDetectSourceLanguageResult.FromResult(e.Result);
                        language = language_id_result.Language;
                    }

                    sequence_number++;
                    var    start_time = new DateTime(e.Result.OffsetInTicks);
                    var    end_time   = start_time.Add(e.Result.Duration);
                    string caption    = caption_time_to_caption(user_config.srt_enabled, sequence_number, start_time, end_time, e.Result.Text, language);
                    write_to_console_or_file(caption, user_config);
                }
                else if (ResultReason.NoMatch == e.Result.Reason)
                {
                    write_to_console(String.Format("NOMATCH: Speech could not be recognized.{0}", Environment.NewLine), user_config);
                }
            };

            speech_recognizer.Canceled += (object?sender, SpeechRecognitionCanceledEventArgs e) =>
            {
                if (CancellationReason.EndOfStream == e.Reason)
                {
                    write_to_console(String.Format("End of stream reached.{0}", Environment.NewLine), user_config);
                    recognition_end.TrySetResult(null);      // Notify to stop recognition.
                }
                else if (CancellationReason.CancelledByUser == e.Reason)
                {
                    write_to_console(String.Format("User canceled request.{0}", Environment.NewLine), user_config);
                    recognition_end.TrySetResult(null);      // Notify to stop recognition.
                }
                else if (CancellationReason.Error == e.Reason)
                {
                    var error = String.Format("Encountered error.{0}Error code: {1}{0}Error details: {2}{0}", Environment.NewLine, (int)e.ErrorCode, e.ErrorDetails);
                    recognition_end.TrySetResult(error);      // Notify to stop recognition.
                }
                else
                {
                    var error = String.Format("Request was cancelled for an unrecognized reason: {0}.{1}", (int)e.Reason, Environment.NewLine);
                    recognition_end.TrySetResult(error);      // Notify to stop recognition.
                }
            };

            speech_recognizer.SessionStopped += (object?sender, SessionEventArgs e) =>
            {
                write_to_console(String.Format("Session stopped.{0}", Environment.NewLine), user_config);
                recognition_end.TrySetResult(null);      // Notify to stop recognition.
            };

// Starts continuous recognition. Uses StopContinuousRecognitionAsync() to stop recognition.
            await speech_recognizer.StartContinuousRecognitionAsync().ConfigureAwait(false);

// Waits for recognition end.
            Task.WaitAll(new[] { recognition_end.Task });

// Stops recognition.
            await speech_recognizer.StopContinuousRecognitionAsync().ConfigureAwait(false);

            return(recognition_end.Task.Result);
        }
        static SpeechRecognizer user_config_to_speech_recognizer(SpeechConfig speech_config, AudioConfig audio_config, USER_CONFIG user_config)
        {
            SpeechRecognizer speech_recognizer;

            if (true == user_config.language_id_enabled)
            {
/* Note: Continuous language identification is supported only in C#, C++, and Python.
 * See:
 * https://docs.microsoft.com/azure/cognitive-services/speech-service/how-to-automatic-language-detection?pivots=programming-language-cpp#language-identification-with-speech-to-text
 */
                AutoDetectSourceLanguageConfig detect_language_config = AutoDetectSourceLanguageConfig.FromLanguages(user_config.language_id_languages);
                speech_recognizer = new SpeechRecognizer(speech_config, detect_language_config, audio_config);
            }
            else
            {
                speech_recognizer = new SpeechRecognizer(speech_config, audio_config);
            }

            if (true == user_config.phrase_list_enabled)
            {
                PhraseListGrammar grammar = PhraseListGrammar.FromRecognizer(speech_recognizer);
                grammar.AddPhrase(user_config.phrase_list);
            }

            return(speech_recognizer);
        }
        static USER_CONFIG args_to_user_config(string[] args)
        {
            bool prioritize_accuracy_enabled = false;
            bool dictation_enabled           = false;
            bool profanity_filter_enabled    = false;
            bool language_id_enabled         = false;

            string[] language_id_languages   = {};
            bool     output_file_enabled     = false;
            string   output_file             = "";
            bool     phrase_list_enabled     = false;
            string   phrase_list             = "";
            bool     suppress_output_enabled = false;
            bool     stable_partial_result_threshold_enabled = false;
            string   stable_partial_result_threshold         = "";
            bool     srt_enabled       = false;
            bool     true_text_enabled = false;
            string   subscription_key  = "";
            string   region            = "";

// Verify argc >= 3 (caption.exe, subscription_key, region)
            if (args.Length < 3)
            {
                throw new TOO_FEW_ARGUMENTS();
            }

            subscription_key = args[args.Length - 2];
            region           = args[args.Length - 1];

            prioritize_accuracy_enabled = cmd_option_exists(args, "-a");
            dictation_enabled           = cmd_option_exists(args, "-d");
            profanity_filter_enabled    = cmd_option_exists(args, "-f");

            if (get_cmd_option(args, "-l") is string language_id_languages_result)
            {
                language_id_enabled   = true;
                language_id_languages = language_id_languages_result.Split(',');
            }

            if (get_cmd_option(args, "-o") is string output_file_result)
            {
                output_file_enabled = true;
                output_file         = output_file_result;
            }

            if (get_cmd_option(args, "-p") is string phrase_list_result)
            {
                phrase_list_enabled = true;
                phrase_list         = phrase_list_result;
            }

            suppress_output_enabled = cmd_option_exists(args, "-q");

            if (get_cmd_option(args, "-r") is string stable_partial_result_threshold_result)
            {
                stable_partial_result_threshold_enabled = true;
                stable_partial_result_threshold         = stable_partial_result_threshold_result;
            }

            srt_enabled       = cmd_option_exists(args, "-s");
            true_text_enabled = cmd_option_exists(args, "-t");

            USER_CONFIG user_config = new USER_CONFIG(
                prioritize_accuracy_enabled,
                dictation_enabled,
                profanity_filter_enabled,
                language_id_enabled,
                language_id_languages,
                output_file_enabled,
                output_file,
                phrase_list_enabled,
                phrase_list,
                suppress_output_enabled,
                stable_partial_result_threshold_enabled,
                stable_partial_result_threshold,
                srt_enabled,
                true_text_enabled,
                subscription_key,
                region
                );

            return(user_config);
        }