tnblog
首页

C#语音播放的崎岖之路

191人阅读 2019/4/8 11:47 评论:3 手机浏览 收藏
分类: C#

最近由于工作中需要语音读取消息文本,达到现场通知效果,故而研究了下C#语音播放功能:

开始崎岖之路

 BEGIEN:

首先测试,写一个接口,按照同步方式读文本

using EasyTeam.Problem.Web.Api.Models;
using SpeechLib;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Speech.Synthesis;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using HttpGetAttribute = System.Web.Http.HttpGetAttribute;

namespace EasyTeam.VoicePlay.Controllers
{
    public class VoicePlayController : ApiController
    {

        public OperationResult result = new OperationResult();

        /// <summary>
        /// 外部调用接口
        /// </summary>
        /// <param name="msg">消息体(文本内容)</param>
        /// <returns></returns>
        [HttpGet]
        public OperationResult Index(string msg)
        {

            Paly(msg);

            return result;
        }

        /// <summary>
        /// 内部实现方法
        /// </summary>
        /// <param name="msg"></param>
        private void Paly(string msg)
        {
            try
            {
                //创建实例
                var reader = new SpeechSynthesizer();

                /*下面的代码为一些SpeechSynthesizer的属性,看实际情况是否需要使用*/
                //reader.Rate = -1; //设置语速,[-10,10]
                //reader.Volume = 100; //设置音量,[0,100]
                //reader.SpeakAsync("Hellow Word");  //播放指定的字符串,这是异步朗读
                //reader.Speak("Hellow Word");  //同步朗读
                //reader.Dispose();  //释放所有语音资源
                //reader.SpeakAsyncCancelAll();  //取消朗读
                //reader.Pause();  //暂停朗读
                //reader.Resume(); //继续朗读

                if (string.IsNullOrEmpty(msg))
                {
                    result.Message = "Please enter some text";
                    result.ResultType = OperationResultType.ValidError;
                    result.Data = null;

                    reader.Dispose();
                }
                else
                {
                    //reader.SpeakAsync(msg);

                    reader.Speak(msg);
                    //回调(同步读文本时,不会进入此委托)
                    reader.SpeakCompleted += new EventHandler<SpeakCompletedEventArgs>(reader_SpeakCompleted);
                    reader.Dispose();
                }

            }
            catch (Exception e)
            {
                result.Message = e.Message;
                result.ResultType = OperationResultType.Error;
                result.Data = null;
            }
        }


        void reader_SpeakCompleted(object sender, SpeakCompletedEventArgs e)
        {
            var reader = (SpeechSynthesizer)sender;
            result.Message = "成功!";
            result.ResultType = OperationResultType.Success;
        }
    }
}

嗯。。。 跑一下。。。默默的带上耳机,希望有声音。


哇撒 ,进断点了,哇撒,有声音了,看来有戏


what?f**k!

都跑完了,为啥还在Loading?难道没释放资源?但是确实有写Dispose(),那换个异步读试试。

改一下Paly方法:

private void Paly(string msg)
        {
            try
            {
                //创建实例
                var reader = new SpeechSynthesizer();

                /*下面的代码为一些SpeechSynthesizer的属性,看实际情况是否需要使用*/
                //reader.Rate = -1; //设置语速,[-10,10]
                //reader.Volume = 100; //设置音量,[0,100]
                //reader.SpeakAsync("Hellow Word");  //播放指定的字符串,这是异步朗读
                //reader.Speak("Hellow Word");  //同步朗读
                //reader.Dispose();  //释放所有语音资源
                //reader.SpeakAsyncCancelAll();  //取消朗读
                //reader.Pause();  //暂停朗读
                //reader.Resume(); //继续朗读

                if (string.IsNullOrEmpty(msg))
                {
                    result.Message = "Please enter some text";
                    result.ResultType = OperationResultType.ValidError;
                    result.Data = null;

                    reader.Dispose();
                }
                else
                {
                    //现在是异步
                    reader.SpeakAsync(msg);

                    //reader.Speak(msg);
                    //回调
                    reader.SpeakCompleted += new EventHandler<SpeakCompletedEventArgs>(reader_SpeakCompleted);
                    reader.Dispose();
                }

            }
            catch (Exception e)
            {
                result.Message = e.Message;
                result.ResultType = OperationResultType.Error;
                result.Data = null;
            }
        }

再跑一下,嗯 ,异步能进入到委托中。

但是,牙刷,直接没声了,再检查下代码,想了想,考虑到异步,会不会是还没开始读,资源就被释放了?

再改一下代码,把 reader.Dispose()放到读完后的委托中:

        private void Paly(string msg)
        {
            try
            {
                //创建实例
                var reader = new SpeechSynthesizer();

                /*下面的代码为一些SpeechSynthesizer的属性,看实际情况是否需要使用*/
                //reader.Rate = -1; //设置语速,[-10,10]
                //reader.Volume = 100; //设置音量,[0,100]
                //reader.SpeakAsync("Hellow Word");  //播放指定的字符串,这是异步朗读
                //reader.Speak("Hellow Word");  //同步朗读
                //reader.Dispose();  //释放所有语音资源
                //reader.SpeakAsyncCancelAll();  //取消朗读
                //reader.Pause();  //暂停朗读
                //reader.Resume(); //继续朗读

                if (string.IsNullOrEmpty(msg))
                {
                    result.Message = "Please enter some text";
                    result.ResultType = OperationResultType.ValidError;
                    result.Data = null;

                    reader.Dispose();
                }
                else
                {
                    reader.SpeakAsync(msg);

                    //reader.Speak(msg);
                    //回调(同步读文本时,不会进入此委托)
                    reader.SpeakCompleted += new EventHandler<SpeakCompletedEventArgs>(reader_SpeakCompleted);
                }

            }
            catch (Exception e)
            {
                result.Message = e.Message;
                result.ResultType = OperationResultType.Error;
                result.Data = null;
            }
        }


        void reader_SpeakCompleted(object sender, SpeakCompletedEventArgs e)
        {
            var reader = (SpeechSynthesizer)sender;
            result.Message = "成功!";
            result.ResultType = OperationResultType.Success;
            reader.Dispose();//现在释放在这里

        }

再跑一下,嗯。。有声音,但是还是没有返回结果!!!

问题还是没解决,此时,就触及到我的知识盲区了,百度。。百度


然后找到一篇文章:https://blog.csdn.net/lphbtm/article/details/19475093 一直稀里糊涂看下去,然后。。what?文章末尾说了句 无解!!!

哎,人家说不行,咱也得试试再说,用GC释放下,看看行不行,再改,在内部方法和回调方法上都加上GC.Collect()释放资源:

有关GC的介绍:https://www.cnblogs.com/yunfeifei/p/3995342.html

再试!!!发现还是不行

--------------------

然后,通过各种自己的调试,改代码,百度都没找到解决方法


既然这条路走不通,不如考虑换个实现方式,终于,让我找到了一个替代方法。用SpVoice实现,代码如下:

        private void Paly1(string msg)
        {
            try
            {
                if (string.IsNullOrEmpty(msg))
                {
                    result.Message = "Please enter some text in the textbox";
                    result.ResultType = OperationResultType.ValidError;
                }
                else
                {
                    SpeechVoiceSpeakFlags flag = SpeechVoiceSpeakFlags.SVSFlagsAsync;
                    SpVoice voice = new SpVoice();
                    string voice_txt = msg;
                    voice.Voice = voice.GetVoices(string.Empty, string.Empty).Item(0);
                    int result = voice.Speak(voice_txt, flag);
                }
               
            }
            catch (Exception e)
            {
                result.Message = e.Message;
                result.ResultType = OperationResultType.Error;
            }
        }

然后调试调用:

Nice!!有声音,终于看到这个画面了!


大半天时间就过去了,爱研究的童鞋,可以研究下上面无法释放那个问题,mark一下,分享分享!


END

评价
Decorating heart
文章
6
评论
8
分类
16
关注
16
{{item.ArticleTitle}}
{{item.BlogName}} : {{item.Content}}