使用AudioConfig和PushAudioOutputStreamCallback

时间:2019-06-21 14:39:25

标签: c# naudio microsoft-cognitive azure-cognitive-services speech-synthesis

我正在制作一个工具,它使用MS认知语音服务和Naudio来合成文本语音并在指定的音频设备上播放。我使用PushAudioOutputStreamCallback将音频数据从天蓝色写入Naudio的wave提供程序。但是,调用SpeakTextAsync时会引发异常“对垃圾收集的委托进行了回调” 。如何解决?

此代码将在 等待演讲者时抛出异常。SpeakTextAsync(txtSpeech.Text)

public partial class MainWindow : Window
    {
        WaveOut device;
        BufferedWaveProvider playback;
        SpeechSynthesizer speecher;
        PushNAudio push;

        public MainWindow()
        {
            InitializeComponent();

            var fmt = new WaveFormat();
            fmt = fmt.AsStandardWaveFormat();
            playback = new BufferedWaveProvider(fmt);

            var cfg = SpeechConfig.FromSubscription("xxxxx", "xxxxx");
            var asfmt = AudioStreamFormat.GetWaveFormatPCM((uint)fmt.SampleRate, (byte)fmt.BitsPerSample, (byte)fmt.Channels);
            push = new PushNAudio(playback);
            AudioConfig acfg = AudioConfig.FromStreamOutput(push, asfmt);
            speecher = new SpeechSynthesizer (cfg, acfg);

            device = new WaveOut();
            device.DeviceNumber = 1;
            device.Init(playback);
            device.Play();
        }

        public class PushNAudio : PushAudioOutputStreamCallback
        {
            private BufferedWaveProvider _provider;
            public PushNAudio(BufferedWaveProvider provider)
            {
                _provider = provider;
            }
            public override uint Write(byte[] dataBuffer)
            {
                _provider.AddSamples(dataBuffer, 0, dataBuffer.Length);
                return (uint)dataBuffer.Length;
            }
        }

        private async void DoSpeech()
        {
            if (string.IsNullOrWhiteSpace(txtSpeech.Text))
                return;

            /*Exception*/
            var result = await speecher.SpeakTextAsync(txtSpeech.Text);
            if (result.Reason == ResultReason.Canceled)
            {
                var details = SpeechSynthesisCancellationDetails.FromResult(result);
            }

        }

        private void TxtSpeech_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                DoSpeech();
                e.Handled = true;
            }
        }

此例外:

对类型为“ Microsoft.CognitiveServices.Speech.csharp!Microsoft.CognitiveServices.Speech.Internal.PushAudioStreamWriteDelegate :: Invoke”的垃圾收集委托进行了回调。这可能会导致应用程序崩溃,损坏和数据丢失。将委托传递给非托管代码时,托管应用程序必须使它们保持活动状态,直到确保永远不会调用它们为止。

堆栈:

Microsoft.CognitiveServices.Speech.csharp.dll!Microsoft.CognitiveServices.Speech.SpeechSynthesizer.SpeakTextAsync.AnonymousMethod__1() Microsoft.CognitiveServices.Speech.csharp.dll!Microsoft.CognitiveServices.Speech.SpeechSynthesizer.DoAsyncSynthesisAction(System.Action synthImplAction) Microsoft.CognitiveServices.Speech.csharp.dll!Microsoft.CognitiveServices.Speech.SpeechSynthesizer.SpeakTextAsync.AnonymousMethod__0() mscorlib.dll!System.Threading.Tasks.Task.InnerInvoke() mscorlib.dll!System.Threading.Tasks.Task.Execute() mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executeContext,System.Threading.ContextCallback回调,对象状态,布尔类型saveSyncCtx) mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContextexecutionContext,System.Threading.ContextCallback回调,对象状态,bool keepSyncCtx) mscorlib.dll!System.Threading.Tasks.Task.ExecuteWithThreadLocal(参考System.Threading.Tasks.Task currentTaskSlot) mscorlib.dll!System.Threading.Tasks.Task.ExecuteEntry(bool bPreventDoubleExecution) mscorlib.dll!System.Threading.ThreadPoolWorkQueue.Dispatch()

1 个答案:

答案 0 :(得分:0)

经过多次尝试,我发现这些代码在目标.net核心时可以正常工作。我认为Microsoft.CognitiveServices.Speech可能尚未在.net框架下经过全面测试。