最近做微信小程序的录音搜索功能,具体思路是将小程序的录音上传到服务器,再调用第三方api(这里用的是百度的),返回语音文本,遇到如下问题:
1.微信小程序的录音文件时silk,而百度的语音转文本api支持:pcm(不压缩)、wav(不压缩,pcm编码)、amr(压缩格式)。因此需要转换格式 ,网上找了些资料,后来用silk-v3-decoder 转换成功
2.在转换的过程中,遇到了一点问题,下载好silk-v3-decoder 后,执行silk2mp3.exe主程序,我们可以用此用户交互界面进行解码转码
3.代码解码转码,由于是需要客户端上传到服务器并且在后台播放,所以肯定需要用代码的方式实现解码转码咯. 代码方式也很简单,其实本质就是调用这个程序,传几个参数而已.
代码附上:
/// <summary>
/// 执行CMD语句
/// </summary>
/// <param name="path">执行文件目录</param>
/// <param name="cmd">要执行的CMD命令</param>
public string RunCmd(string path,string cmd)
{
proc.StartInfo.CreateNoWindow = true;
proc.StartInfo.FileName = "cmd.exe";
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.RedirectStandardError = true;
proc.StartInfo.RedirectStandardInput = true;
proc.StartInfo.RedirectStandardOutput = true;
proc.Start();
proc.StandardInput.WriteLine("cd " + path);
proc.StandardInput.WriteLine(cmd);
proc.StandardInput.WriteLine("exit");
string outStr = proc.StandardOutput.ReadToEnd();
proc.Close();
return outStr;
}
3.后台文件转换以及调用百度api
/// <summary>
/// 上传录音文件
/// </summary>
/// <returns></returns>
public object PostUploadFile()
{
string result = string.Empty;
string picUrl = string.Empty;
string strPath = string.Empty;
try
{
HttpPostedFile file = System.Web.HttpContext.Current.Request.Files[0];
if (file != null && file.ContentLength > 0)
{
if (string.IsNullOrEmpty(file.FileName) == false)
{
strPath = System.Web.HttpContext.Current.Request.MapPath("\\voice");
//保存文件到目录
if (!Directory.Exists(strPath))
{
//当前目录不存在,则创建
Directory.CreateDirectory(strPath);
}
picUrl = strPath + "\\" + file.FileName;
//这里遇到个大坑,安卓微信端上传的文件名称始终是wx-file.silk,而我们是文件先上传到服务器的,所以每次录音上传时,这个文件(wx-file.silk)已经被占用(至于为啥,还没查出来),
//在转换读取文件的过程中,就一直报文件被占用不能读取的错误,而ios微信端可以读取完成的文件名,这个问题找了好一会,后来才发现是文件名的问题
改正后为:picUrl = strPath + "\\" +DateTime.Now.ToString("yyyyMMddHHmmss") + ".silk"; //用时间作文件名就避免文件被占用啦!
BinaryReader br = new BinaryReader(file.InputStream);
int lenth = Convert.ToInt32(br.BaseStream.Length);
byte[] bytes = br.ReadBytes(lenth);
using (FileStream fs1 = new FileStream(picUrl, FileMode.Create))
{
BinaryWriter bw = new BinaryWriter(fs1);
for (int i = 0; i < bytes.Length; i++)
{
bw.Write(bytes[i]);
}
bw.Close();
}
br.Close();
}
string pcmPath = picUrl.Replace("silk", "pcm");
CmdHelper cmdHelper = new CmdHelper();
cmdHelper.RunCmd(System.Web.HttpContext.Current.Request.MapPath("\\silk2mp3"), "silk_v3_decoder.exe " + picUrl + " " + pcmPath);
if (File.Exists(pcmPath))
{
SpeechDemo demo = new SpeechDemo();
result = demo.AsrData(pcmPath);
}
//删除临时silk文件
if (File.Exists(picUrl))
{
FileInfo fi = new FileInfo(picUrl);
if (fi.Attributes.ToString().IndexOf("ReadOnly") != -1)
fi.Attributes = FileAttributes.Normal;
File.Delete(picUrl);
}
}
}catch(Exception ex)
{
result = ex.Message;
throw ex;
}
return new { SearchText = result };
}
4.百度的语音转文件api说明以及demo可以去百度api文档查看,有具体的demo,很简单
地址:http://ai.baidu.com/docs#/ASR-Online-Csharp-SDK/top
5.后期测试中发现一个问题,当微信端录音一直按住不说话时,上传后,服务端一直没反应,也不报错,后来经过调试发现是cmd命令silk文件转pcm文件的问题,
cmd执行程序好像卡住了,既不返回值,也不报错,导致客户端搜索一直停留在搜索中状态,查了好些资料,试了好多种方法,
最后在cmd执行命令中去掉proc.StartInfo.RedirectStandardError = true;然后就正常了.