예제 #1
0
        private void SpeakWithMicrosoftSpeechLibrary(string textToSpeak, Action onComplete, int?volume, int?rate, string voice)
        {
            var voiceToUse = voice ?? Settings.Default.SpeechVoice;

            if (!string.IsNullOrWhiteSpace(voiceToUse))
            {
                if (!useLegacyMicrosoftSpeechForVoices.Contains(voiceToUse))
                {
                    try
                    {
                        speechSynthesiser.SelectVoice(voiceToUse);
                        speechSynthesiser.Rate   = rate ?? Settings.Default.SpeechRate;
                        speechSynthesiser.Volume = volume ?? Settings.Default.SpeechVolume;
                    }
                    catch //(Exception exception)
                    {
                        //Commenting out the raising of an error notification for now
                        //var customException = new ApplicationException(string.Format(Resources.UNABLE_TO_SET_VOICE_WARNING,
                        //    voiceToUse, voice == null ? Resources.VOICE_COMES_FROM_SETTINGS : null), exception);
                        //PublishError(this, customException);

                        Log.Warn($"Unable to speak using SpeechSynthesizer and voice '{voiceToUse}'. Switching to legacy speech mode and trying again...");
                        useLegacyMicrosoftSpeechForVoices.Add(voiceToUse);
                    }
                }

                if (useLegacyMicrosoftSpeechForVoices.Contains(voiceToUse))
                {
                    Log.Info("Attempting speech using legacy mode.");
                    try
                    {
                        if (legacySpeechSynthesiser == null)
                        {
                            //Lazy instantiate legacy speech synthesiser
                            legacySpeechSynthesiser = new SpVoice();
                        }

                        var availableVoices = legacySpeechSynthesiser.GetVoices(string.Empty, string.Empty);
                        if (legacyMicrosoftSpeechVoiceToTokenIndexLookup.ContainsKey(voiceToUse))
                        {
                            int voiceIndex = legacyMicrosoftSpeechVoiceToTokenIndexLookup[voiceToUse];
                            Log.InfoFormat($"{voiceToUse} voice token exists at index {voiceIndex}. Setting voice on legacy speech synthesiser.");
                            legacySpeechSynthesiser.Voice = availableVoices.Item(voiceIndex);
                            Log.Info("Voice token set.");
                        }
                        else
                        {
                            for (int voiceIndex = 0; voiceIndex < availableVoices.Count; voiceIndex++)
                            {
                                var voiceToken = availableVoices.Item(voiceIndex);
                                if (voiceToken.GetDescription() == voiceToUse)
                                {
                                    Log.InfoFormat($"{voiceToUse} voice token found at index {voiceIndex}. Setting voice on legacy speech synthesiser.");
                                    legacyMicrosoftSpeechVoiceToTokenIndexLookup.Add(voiceToUse, voiceIndex);
                                    legacySpeechSynthesiser.Voice = voiceToken;
                                    Log.Info("Voice token set.");
                                    break;
                                }
                            }
                        }
                    }
                    catch (Exception exception)
                    {
                        var customException = new ApplicationException(string.Format(Resources.UNABLE_TO_SET_VOICE_WARNING,
                                                                                     voiceToUse, voice == null ? Resources.VOICE_COMES_FROM_SETTINGS : null), exception);
                        PublishError(this, customException);
                    }
                }
            }

            //Speak
            if (!useLegacyMicrosoftSpeechForVoices.Contains(voiceToUse))
            {
                onSpeakCompleted = (sender, args) =>
                {
                    lock (speakCompletedLock)
                    {
                        if (onSpeakCompleted != null)
                        {
                            speechSynthesiser.SpeakCompleted -= onSpeakCompleted;
                            onSpeakCompleted = null;
                        }

                        if (onComplete != null)
                        {
                            onComplete();
                        }
                    }
                };
                speechSynthesiser.SpeakCompleted += onSpeakCompleted;
                speechSynthesiser.SpeakAsync(textToSpeak);
            }
            else
            {
                //Legacy speech mode
                if (legacySpeechSynthesiser != null)
                {
                    legacySpeechSynthesiser.Speak(textToSpeak, SpeechVoiceSpeakFlags.SVSFIsNotXML | SpeechVoiceSpeakFlags.SVSFlagsAsync);
                    var speechHandle    = legacySpeechSynthesiser.SpeakCompleteEvent();
                    var speechHandlePtr = new IntPtr(speechHandle);
                    if (speechHandlePtr != IntPtr.Zero)
                    {
                        var autoResetEvent = new AutoResetEvent(false)
                        {
                            SafeWaitHandle = new SafeWaitHandle(speechHandlePtr, false)
                        };
                        var uiThreadDispatcher = Dispatcher.CurrentDispatcher;
                        legacySpeakCompleted = (state, timedOut) =>
                        {
                            if (onComplete != null)
                            {
                                uiThreadDispatcher.Invoke(onComplete);
                            }
                            autoResetEvent.Dispose();
                            legacySpeakCompleted = null;
                        };
                        ThreadPool.RegisterWaitForSingleObject(autoResetEvent, legacySpeakCompleted, null, 30000, true);
                    }
                }
            }
        }