1

As I described here:

I have a method async SpeakAsync(string language, string text):

 var synth = new SpeechSynthesizer();
 var player = new MediaPlayer();
 SetVoice(language, ref synth);
 var source = await synth.SynthesizeTextToStreamAsync(text);
 player.SetStreamSource(source);
 synth.Dispose();
 player.MediaEnded += (_, _) => { source.Dispose(); player.Dispose(); }
 player.Play();

If I call this method twice with .Wait() followed, my app will stuck at var source = await synth.SynthesizeTextToStreamAsync(text); forever for the second call (the first call runs perfectly).

I did what @DarranRowe said with storing a MediaPlayer instance and a SpeechSynthesisStream instance in a field of my class. I set the SpeechSynthesisStream instance to null at every time the method got called. But the problem still exists, and I don't know why this would solve my problem.

Please comment or answer here, the GitHub discussion I referenced above is not a place for this question.

AkiraVoid
  • 61
  • 8

1 Answers1

1

The problem has nothing to do with the SpeechSynthetizer, but is related to the code you're using to call your method:

private void OnClick(object _sender, RoutedEventArgs _e)
{
    SpeakAsync("en-US", "Test 1").Wait();
    SpeakAsync("en-US", "Test 2").Wait();
}

It's using an async method with task Wait() from a UI thread which causes a deadlock.

This is a classic mistake (same as with Winforms or WPF), see this How to avoid WinForm freezing using Task.Wait or Winforms call to async method hangs up program on this site or Don't Block on Async Code for a more detailed answer.

So the solution is just to do this instead:

private async void OnClick(object _sender, RoutedEventArgs _e)
{
    await SpeakAsync("en-US", "Test 1");
    await SpeakAsync("en-US", "Test 2");
}

Note with existing code, both phrases will play together, here's a version that can optionally wait for the end of play:

private Task SpeakAsync(string language, string text, bool waitForEnd = true)
{
    if (waitForEnd)
    {
        var tsc = new TaskCompletionSource();
        Task.Run(() => Do(tsc));
        return tsc.Task;
    }
    return Do(null);

    async Task Do(TaskCompletionSource tsc)
    {
        var player = new MediaPlayer();
        using var synth = new SpeechSynthesizer();
        synth.Voice = SpeechSynthesizer.AllVoices.FirstOrDefault(v => v.Language == language) ?? SpeechSynthesizer.DefaultVoice;
        var source = await synth.SynthesizeTextToStreamAsync(text);
        player.MediaEnded += (sender, _) =>
        {
            source.Dispose();
            tsc?.SetResult();
        };
        player.SetStreamSource(source);
        player.Play();
    }
}
Simon Mourier
  • 132,049
  • 21
  • 248
  • 298