一、項目中一直用到了文字轉語音的功能,需求也比較簡單,就是將一段報警信息通過語音的方式播放出來,之前一直採用CS客戶端,利用微軟自帶的Speech語音播放庫就可以完成, 1.1 封裝winSpedk類代碼如下: namespace Speak { using System; using System ...
一、項目中一直用到了文字轉語音的功能,需求也比較簡單,就是將一段報警信息通過語音的方式播放出來,之前一直採用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); } } } }View Code
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) { } }View Code
二、 最近客戶提出需求需要在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(); } }View Code
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; } }View Code
註意:返回的必須為非同步( async Task)不然會報錯,因為文字音頻轉換涉及到非同步調用
2.4 前端展示
2.5 運行截圖如下:
BS實現文字音頻調用demo地址如下:
https://github.com/lxshwyan/SpeechBSDemo.git