tnblog
首页
视频
资源
登录

C#语音播放的崎岖之路

16630人阅读 2019/4/8 11:47 总访问:150281 评论:4 收藏:0 手机
分类: C#

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

开始崎岖之路

 BEGIEN:

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

  1. using EasyTeam.Problem.Web.Api.Models;
  2. using SpeechLib;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using System.Speech.Synthesis;
  7. using System.Web;
  8. using System.Web.Http;
  9. using System.Web.Mvc;
  10. using HttpGetAttribute = System.Web.Http.HttpGetAttribute;
  11. namespace EasyTeam.VoicePlay.Controllers
  12. {
  13.     public class VoicePlayController : ApiController
  14.     {
  15.         public OperationResult result = new OperationResult();
  16.         /// <summary>
  17.         /// 外部调用接口
  18.         /// </summary>
  19.         /// <param name="msg">消息体(文本内容)</param>
  20.         /// <returns></returns>
  21.         [HttpGet]
  22.         public OperationResult Index(string msg)
  23.         {
  24.             Paly(msg);
  25.             return result;
  26.         }
  27.         /// <summary>
  28.         /// 内部实现方法
  29.         /// </summary>
  30.         /// <param name="msg"></param>
  31.         private void Paly(string msg)
  32.         {
  33.             try
  34.             {
  35.                 //创建实例
  36.                 var reader = new SpeechSynthesizer();
  37.                 /*下面的代码为一些SpeechSynthesizer的属性,看实际情况是否需要使用*/
  38.                 //reader.Rate = -1; //设置语速,[-10,10]
  39.                 //reader.Volume = 100; //设置音量,[0,100]
  40.                 //reader.SpeakAsync("Hellow Word");  //播放指定的字符串,这是异步朗读
  41.                 //reader.Speak("Hellow Word");  //同步朗读
  42.                 //reader.Dispose();  //释放所有语音资源
  43.                 //reader.SpeakAsyncCancelAll();  //取消朗读
  44.                 //reader.Pause();  //暂停朗读
  45.                 //reader.Resume(); //继续朗读
  46.                 if (string.IsNullOrEmpty(msg))
  47.                 {
  48.                     result.Message = "Please enter some text";
  49.                     result.ResultType = OperationResultType.ValidError;
  50.                     result.Data = null;
  51.                     reader.Dispose();
  52.                 }
  53.                 else
  54.                 {
  55.                     //reader.SpeakAsync(msg);
  56.                     reader.Speak(msg);
  57.                     //回调(同步读文本时,不会进入此委托)
  58.                     reader.SpeakCompleted += new EventHandler<SpeakCompletedEventArgs>(reader_SpeakCompleted);
  59.                     reader.Dispose();
  60.                 }
  61.             }
  62.             catch (Exception e)
  63.             {
  64.                 result.Message = e.Message;
  65.                 result.ResultType = OperationResultType.Error;
  66.                 result.Data = null;
  67.             }
  68.         }
  69.         void reader_SpeakCompleted(object sender, SpeakCompletedEventArgs e)
  70.         {
  71.             var reader = (SpeechSynthesizer)sender;
  72.             result.Message = "成功!";
  73.             result.ResultType = OperationResultType.Success;
  74.         }
  75.     }
  76. }

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


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


what?f**k!

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

改一下Paly方法:

  1. private void Paly(string msg)
  2.         {
  3.             try
  4.             {
  5.                 //创建实例
  6.                 var reader = new SpeechSynthesizer();
  7.                 /*下面的代码为一些SpeechSynthesizer的属性,看实际情况是否需要使用*/
  8.                 //reader.Rate = -1; //设置语速,[-10,10]
  9.                 //reader.Volume = 100; //设置音量,[0,100]
  10.                 //reader.SpeakAsync("Hellow Word");  //播放指定的字符串,这是异步朗读
  11.                 //reader.Speak("Hellow Word");  //同步朗读
  12.                 //reader.Dispose();  //释放所有语音资源
  13.                 //reader.SpeakAsyncCancelAll();  //取消朗读
  14.                 //reader.Pause();  //暂停朗读
  15.                 //reader.Resume(); //继续朗读
  16.                 if (string.IsNullOrEmpty(msg))
  17.                 {
  18.                     result.Message = "Please enter some text";
  19.                     result.ResultType = OperationResultType.ValidError;
  20.                     result.Data = null;
  21.                     reader.Dispose();
  22.                 }
  23.                 else
  24.                 {
  25.                     //现在是异步
  26.                     reader.SpeakAsync(msg);
  27.                     //reader.Speak(msg);
  28.                     //回调
  29.                     reader.SpeakCompleted += new EventHandler<SpeakCompletedEventArgs>(reader_SpeakCompleted);
  30.                     reader.Dispose();
  31.                 }
  32.             }
  33.             catch (Exception e)
  34.             {
  35.                 result.Message = e.Message;
  36.                 result.ResultType = OperationResultType.Error;
  37.                 result.Data = null;
  38.             }
  39.         }

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

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

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

  1.         private void Paly(string msg)
  2.         {
  3.             try
  4.             {
  5.                 //创建实例
  6.                 var reader = new SpeechSynthesizer();
  7.                 /*下面的代码为一些SpeechSynthesizer的属性,看实际情况是否需要使用*/
  8.                 //reader.Rate = -1; //设置语速,[-10,10]
  9.                 //reader.Volume = 100; //设置音量,[0,100]
  10.                 //reader.SpeakAsync("Hellow Word");  //播放指定的字符串,这是异步朗读
  11.                 //reader.Speak("Hellow Word");  //同步朗读
  12.                 //reader.Dispose();  //释放所有语音资源
  13.                 //reader.SpeakAsyncCancelAll();  //取消朗读
  14.                 //reader.Pause();  //暂停朗读
  15.                 //reader.Resume(); //继续朗读
  16.                 if (string.IsNullOrEmpty(msg))
  17.                 {
  18.                     result.Message = "Please enter some text";
  19.                     result.ResultType = OperationResultType.ValidError;
  20.                     result.Data = null;
  21.                     reader.Dispose();
  22.                 }
  23.                 else
  24.                 {
  25.                     reader.SpeakAsync(msg);
  26.                     //reader.Speak(msg);
  27.                     //回调(同步读文本时,不会进入此委托)
  28.                     reader.SpeakCompleted += new EventHandler<SpeakCompletedEventArgs>(reader_SpeakCompleted);
  29.                 }
  30.             }
  31.             catch (Exception e)
  32.             {
  33.                 result.Message = e.Message;
  34.                 result.ResultType = OperationResultType.Error;
  35.                 result.Data = null;
  36.             }
  37.         }
  38.         void reader_SpeakCompleted(object sender, SpeakCompletedEventArgs e)
  39.         {
  40.             var reader = (SpeechSynthesizer)sender;
  41.             result.Message = "成功!";
  42.             result.ResultType = OperationResultType.Success;
  43.             reader.Dispose();//现在释放在这里
  44.         }

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

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


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

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

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

再试!!!发现还是不行

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

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


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

  1.         private void Paly1(string msg)
  2.         {
  3.             try
  4.             {
  5.                 if (string.IsNullOrEmpty(msg))
  6.                 {
  7.                     result.Message = "Please enter some text in the textbox";
  8.                     result.ResultType = OperationResultType.ValidError;
  9.                 }
  10.                 else
  11.                 {
  12.                     SpeechVoiceSpeakFlags flag = SpeechVoiceSpeakFlags.SVSFlagsAsync;
  13.                     SpVoice voice = new SpVoice();
  14.                     string voice_txt = msg;
  15.                     voice.Voice = voice.GetVoices(string.Empty, string.Empty).Item(0);
  16.                     int result = voice.Speak(voice_txt, flag);
  17.                 }
  18.                
  19.             }
  20.             catch (Exception e)
  21.             {
  22.                 result.Message = e.Message;
  23.                 result.ResultType = OperationResultType.Error;
  24.             }
  25.         }

然后调试调用:

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


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


END

评价

剑轩

2019/4/8 14:49:09

666这个必须点赞!!!就喜欢这种爱专研,一步一步解决问题的

瑾语

2019/4/20 18:56:29

点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞点赞

剑轩:@瑾语[汗][汗]你这个文字也太多了吧

2019/4/22 21:00:24 回复

2021/9/26 16:46:53

牛逼

Css弹性盒子,flex布局

css弹性盒子由于版本不同浏览器问题造成了一些不同的写法display:flexbox;在google浏览器中如果使用下面的写法就不行displa...

Css图片和文字对齐问题

文字和图片写到一排经常会出现对不齐的问题 这样感觉图片会上来一点没有和文字对齐,如下图 但是如果修改下html结...

GitHub 上传项目

补充简化方法:登录git创建项目--&gt;拉取刚刚创建的项目--&gt;复制需要的代码进去--&gt;上传提交即可先拉取项目在上传代码...

NET Core 使用 EF Code First

下面这些内容很老了看这篇:https://www.tnblog.net/aojiancc2/article/details/5365 项目使用多层,把数据库访问...

Windows平台分布式架构实践 - 负载均衡

原文地址: https://www.cnblogs.com/atree/p/windows_loadbalancer.html 概述  最近.NET的世界开始闹腾了,微软官方终...

Css实现简单矩形对话框

在前端做项目时,我们可能会遇到写对话框的需求,这次做视频会议页面就遇到了,记录下日后有个参照。//网页部分 &lt;divcla...

CAPS.NET 保存base64位格式的图片

publicvoidUpload() { //取出图片对应的base64位字符 stringimgBase=Request[&quot;imgBase&quot;]; //c#里边的base6...

使用OLEDB读取不同版本ExCel的连接字符串设置

使用OleBD读取excel的时候,excel不同的版本,连接字符串的写法也会不一样。///&lt;summary&gt; ///读取excel ///&lt;/su...

vs2017 对 COM 组件的调用返回了错误 HRESULT E_FAIL

vs2017添加引用报错 对 COM 组件的调用返回了错误 HRESULT E_FAIL 1.以管理员身份打开vs2017开发人员命令指示符 2...

分布式服务架构与微服务架构概念的区别与联系

分布式:分散压力。微服务:分散能力。当下理解分布式:不同模块部署在不同服务器上作用:分布式解决网站高并发带来问题集...

分布式-微服务-集群的区别

1.分布式将一个大的系统划分为多个业务模块,业务模块分别部署到不同的机器上,各个业务模块之间通过接口进行数据交互。区...

NPOI操作exCel 2007/2010版本

HSSFWorkbook:是操作Excel2003以前(包括2003)的版本,扩展名是.xlsXSSFWorkbook:是操作Excel2007的版本,扩展名是.xlsx先...

这样学英语三个月超过你过去学三年

本文作者三年间从四级勉强及格到高级口译笔试210,口试232。找工作面试时给其口试的老外考官听了一分钟就说你的英语不用考...

EasyUI弹窗批量修改Combogrid下拉框的值

JS方法//点击弹出批量修改框 UpdateLot:function(){ varrow=$(&quot;#dg&quot;).datagrid(&quot;getChecked&quot;); if(...

js与Controller中分割字符串的方法

js: varstr=OpenRule; varstrs=newArray(); strs=str.split(&quot;,&quot;); for(vari=0;i&lt;strs.length;i++){ $(&q...

如何修改CSS中存在的element.style内联样式

改腾讯地图的时候调整了下样式,发现样式一直存在问题,修改style里面的值,一点用都没有,html中这个值还找不到是在哪里出...
Decorating heart
排名
22
文章
14
粉丝
21
评论
27
腾讯防水墙
赖成龙 : 学长你有下载好的js文件吗
使用 JSON WEB TOKEN (jwt) 验证
饰心 : 由于最近换了新的工作环境,还在挖煤中。后续会增加博客更新频率。
腾讯防水墙
饰心 : @剑轩,快去给tnblog弄一个
使用select2实现下拉框中显示图片
剑轩 : 秀啊.....,飞常不错
使用select2实现下拉框中显示图片
饰心 : 嗯~刚好差不多下班
ICP备案 :渝ICP备18016597号-1
网站信息:2018-2025TNBLOG.NET
技术交流:群号656732739
联系我们:contact@tnblog.net
公网安备:50010702506256
欢迎加群交流技术
逸一时,误一世。