一、项目中一直用到了文字转语音的功能,需求也比较简单,就是将一段报警信息通过语音的方式播放出来,之前一直采用cs客户端,利用微软自带的speech语音播放库就可以完成,

       1.1 封装winspedk类代码如下:

namespace speak
{
    using system;
    using system.runtime.compilerservices;
    using system.speech.synthesis;
    using system.threading;
    using speechlib;

    public class winspeak
    {
        #region 属性
        private speechsynthesizer speak;
        public event errorinfo errorinfoevent;
        private thread thvoice;
        private string strvoicemsg;
        spvoice voice = null;
        private static winspeak _intence;
        #endregion

        private winspeak()
        {
            voice = new spvoice();
        }

        #region 方法
        public static winspeak _init()
        {
            if (_intence == null)
                _intence = new winspeak();

            return _intence;
        }
        /// <summary>
        /// 读语音
        /// </summary>
        private void speakm()
        {
            try
            {
                if (speak != null)
                {
                    this.speak.speakasync(strvoicemsg);
                }
            }
            catch (exception exception)
            {
                this.errinfo(exception);
            }
        }
        /// <summary>
        /// 异步播放文本语音
        /// </summary>
        /// <param name="msg"></param>
        public void beginspeaktext(string msg)
        {
            try
            {
                if (speak != null)
                {
                    speak.speakasynccancelall();
                    speak.dispose();
                }

                if (thvoice != null && thvoice.threadstate == threadstate.running)
                {
                    thvoice.abort();
                }

                speak = new speechsynthesizer();
                speak.setoutputtodefaultaudiodevice();

                strvoicemsg = msg;

                //thvoice = new thread(new threadstart(speakm));
                //thvoice.start();
                speak.speakasync(msg);

                gc.collect();
                gc.waitforpendingfinalizers();
            }
            catch (exception exception)
            {
                this.errinfo(exception);
            }
        }
        /// <summary>
        /// 播放文本语音
        /// </summary>
        /// <param name="msg"></param>
        public void speaktext(string msg)
        {
            try
            {
                this.speak = new speechsynthesizer();
                this.speak.speak(msg);
                this.speak.setoutputtonull();
                this.speak.dispose();
            }
            catch (exception exception)
            {
                this.errinfo(exception);
            }
        }
        /// <summary>
        /// speech播放文本合成语音
        /// </summary>
        /// <param name="msg"></param>
        public void speech_speaktext(string msg)
        {
            try
            {
                if (voice != null)
                {
                    voice.speak(null, speechvoicespeakflags.svsfpurgebeforespeak);
                    voice.speak(msg, speechvoicespeakflags.svsflagsasync);
                }
            }
            catch (exception ex)
            {
                this.errinfo(ex);
            }
        }
        /// <summary>
        /// 关闭语音释放资源
        /// </summary>
        public void speakclose()
        {
            try
            {
                if (speak != null)
                {
                    this.speak.speakasynccancelall();
                    this.speak.dispose();
                }

                if (voice != null)
                {
                    voice.speak(null, speechvoicespeakflags.svsfpurgebeforespeak);
                }
            }
            catch (exception ex)
            {
                cglobe_log.error(cglobe_log.getmethodinfo() + ex.message);
            }
        }
        /// <summary>
        /// 获取错误信息
        /// </summary>
        /// <param name="str"></param>
        private void errinfo(exception str)
        {
            if (this.errorinfoevent != null)
            {
                this.errorinfoevent(str);
            }
        }
        #endregion

        ~winspeak()
        {
            try
            {
                if (speak != null)
                {
                    this.speak.speakasynccancelall();
                    this.speak.dispose();
                }
            }
            catch (exception exception)
            {
                //this.errinfo(exception);
            }
        }
    }
}

      1.2  调用如下(一个同步播放、一个异步播放):  

   private void btntest_click(object sender, eventargs e)
        {
            try
            {
                string strsep = txtword.text;
                sfbr.winspeak._init().speech_speaktext(strsep);
            }
            catch (exception ex)
            { }
        }

        private void button1_click(object sender, eventargs e)
        {
            try
            {
                string strsep = txtword.text;
                sfbr.winspeak._init().beginspeaktext(strsep);
            }
            catch (exception ex)
            { }
        }

   二、 最近客户提出需求需要在bs系统实现文字语音播放的功能,因不能接入外网不能调用第三方服务等,最后想到了一个解决方案:先把文字转化为音频文件,再把音频文件以流的形式推送到bs端进行播放;

       2.1  同样可以利用微软自带的speech语音播放库将一段文本转化为音频文件:

       2.2 封装 speechservice文字转换音频文件类

    public class speechservice
    {
        private static speechsynthesizer synth = null;
        /// <summary>
        /// 返回一个speechsynthesizer对象
        /// </summary>
        /// <returns></returns>
        private static speechsynthesizer getspeechsynthesizerinstance()
        {
            if (synth == null)
            {
                synth = new speechsynthesizer();
            }
            return synth;
        }
        /// <summary>
        /// 保存语音文件
        /// </summary>
        /// <param name="text"></param>
        public static void savemp3(string strfilename,string sptext)
        {    
            synth = getspeechsynthesizerinstance();
            synth.rate = 1;
            synth.volume = 100;      
            synth.setoutputtowavefile(strfilename);
            synth.speak(sptext);
            synth.setoutputtonull();
        }  
    }

       2.3  接下来就是将音频文件以文件流的形式推送到前端播放:

  public async task<actionresult> playwav(string id,string sptext)
        {    
            string strpath = server.mappath("~\\mp4\\" + id + ".wav");
            speechservice.savemp3(strpath, sptext);
            try
            {     
                using (filestream filestream = new filestream(strpath, filemode.open))
                {
                    byte[] filebyte = new byte[filestream.length];
                    filestream.seek(0, seekorigin.begin);
                    filestream.read(filebyte, 0, (int)filestream.length);
                    long fsize = filestream.length;
                    long startbyte = 0;
                    long endbyte = fsize - 1;
                    int statuscode = 200;
                    if ((request.headers["range"] != null))
                    {
                        //get the actual byte range from the range header string, and set the starting byte.
                        string[] range = request.headers["range"].split(new char[] { '=', '-' });
                        startbyte = convert.toint64(range[1]);
                        if (range.length > 2 && range[2] != "") endbyte = convert.toint64(range[2]);
                        //if the start byte is not equal to zero, that means the user is requesting partial content.
                        if (startbyte != 0 || endbyte != fsize - 1 || range.length > 2 && range[2] == "")
                        { statuscode = 206; }//set the status code of the response to 206 (partial content) and add a content range header.                                    
                    }
                    long dessize = endbyte - startbyte + 1;
                    //headers
                    response.statuscode = statuscode;
                    response.contenttype = "audio/mpeg";
                    response.addheader("content-accept", response.contenttype);
                    response.addheader("content-length", dessize.tostring());
                    response.addheader("content-range", string.format("bytes {0}-{1}/{2}", startbyte, endbyte, fsize));
                    return file(filebyte, response.contenttype);
               
                }
            }
            catch (exception ex)
            {
                throw;
            }
        }

    注意:返回的必须为异步( async task)不然会报错,因为文字音频转换涉及到异步调用

       2.4 前端展示

   

       2.5  运行截图如下:

 bs实现文字音频调用demo地址如下:

  https://github.com/lxshwyan/speechbsdemo.git