CS程序和BS程序文字转语音
一、项目中一直用到了文字转语音的功能,需求也比较简单,就是将一段报警信息通过语音的方式播放出来,之前一直采用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