zoukankan      html  css  js  c++  java
  • 自动语音播报系统

    与推送系统集成

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.Configuration;
    using System.Threading;
    using RepairerDispatch.SynthesisServer;
    using System.Media;
    using System.IO;
    using System.Diagnostics;
    using System.Collections.Concurrent;
    using System.Text.RegularExpressions;
    namespace RepairerDispatch
    {
        public partial class frmMain : Form
        {
    
            private Counter _Counter = new Counter();
            private PushClient _PushClient = null;
            protected SynchronizationContext SyncContext { get; set; }
            public ConcurrentQueue<NotifyInfo> NotifyQueue = new ConcurrentQueue<NotifyInfo>();
            public bool HandleEnable = false;
            public int MaxSendCount = int.Parse(ConfigurationManager.AppSettings["RepeatCount"]);
            public int RepeatInterval = int.Parse(ConfigurationManager.AppSettings["RepeatInterval"]);
            public bool MockMode = bool.Parse(ConfigurationManager.AppSettings["Mock"]);
            public bool Quietness = bool.Parse(ConfigurationManager.AppSettings["Quietness"]);
            public static int FirstSendDelay = int.Parse(ConfigurationManager.AppSettings["Delay"]);
            public frmMain()
            {
                InitializeComponent();
                SyncContext = SynchronizationContext.Current;
                this.MaximizeBox = false;
    
                this.StartPosition = FormStartPosition.CenterScreen;
         
    
                #region 配置推送
                _PushClient = new PushClient();
    
                _PushClient.UserId = ConfigurationManager.AppSettings["UserId"];
                _PushClient.OnPushReceived += this.HandleReceivePush;
                _PushClient.Start();
                #endregion
                #region 启动消息处理队列
                HandleEnable = true;
                ThreadPool.QueueUserWorkItem(o => { HandleNotifyQueue(); }, null);
                #endregion
                #region 统计信息
                var timer = new System.Windows.Forms.Timer();
                timer.Interval = 100;
                timer.Tick += (s, e) => 
                {
                    try
                    {
                        lbl1.Text = string.Format("{0}/{1}/{2}", _Counter.Received, _Counter.SendCount, _Counter.CancelCount);
                        lbl2.Text = string.Format("{0}/{1}", _Counter.SynthesisCount, _Counter.SynthesisedCount);
                        lbl3.Text = _Counter.QueueLength.ToString();
                    }
                    catch { }
                };
                timer.Start();
    
    
                #endregion
    
            }
            protected override void OnClosing(CancelEventArgs e)
            {
                if (MessageBox.Show("关闭窗体后将无法收到提示,确定关闭吗?", "警告!", MessageBoxButtons.YesNo,MessageBoxIcon.Warning) != System.Windows.Forms.DialogResult.Yes)
                {
                    e.Cancel = true;
                }
                base.OnClosing(e);
            }
            protected override void OnClosed(EventArgs e)
            {
    
                try
                {
                    HandleEnable = false;
                    if (_PushClient != null)
                    {
                        _PushClient.OnPushReceived -= this.HandleReceivePush;
                        _PushClient.Dispose();
                    }
                }
                finally { }
                base.OnClosed(e);
            }
            #region 处理推送消息
            private void HandleReceivePush(string msg)
            {
    
                if (this.InvokeRequired)
                {
               
                    SyncContext.Post((ox) => { HandleReceivePush(msg); }, null);
                }
                else
                {
                    try
                    {
                        Interlocked.Increment(ref _Counter.Received);
                        WriteInfo(msg.Replace(Environment.NewLine,""));
                        var info=  NotifyInfo.Create(msg);
                        if (info == null) return;
                        if (info.VoiceReady)
                        {
                            NotifyQueue.Enqueue(info);
                            _Counter.QueueLength ++;
                        }
                        else
                        {
                            SynthesisVoice(info);
                        }
                    }
                    catch (Exception ex)
                    {
                        WriteInfo(ex.Message);
                    }
                }
            }
    
            /// <summary>
            /// 处理队列里的消息
            /// </summary>
            private void HandleNotifyQueue()
            {
                try
                {
    
                    while (HandleEnable)
                    {
                        //WriteInfo("执行通知队列处理" + DateTime.Now);
                        var info=new NotifyInfo();
                        _Counter.QueueLength = NotifyQueue.Count;
                        if (NotifyQueue.TryDequeue(out info))
                        {
                            //符合播放条件
                            if (info.SendTime <= DateTime.Now )
                            {
                                #region 播放
                                using (var ctx = new JL_MFGEntities())
                                {
                                    var it = ctx.L_Conn_CallRepair.FirstOrDefault(ent => ent.ID == info.MsgId);
                                    if (it == null || it.TicketStatus != "呼叫" || !string.IsNullOrWhiteSpace(it.TakeOverEmpId))
                                    {
                                        if (!MockMode)//模拟模式
                                        {
                                            Interlocked.Increment(ref _Counter.CancelCount);
                                            continue;
                                        }
    
                                    }
    
                                }
                                Interlocked.Increment(ref _Counter.SendCount);
                                if (!Quietness)
                                {
                                    using (SoundPlayer soundPlayer = new SoundPlayer(info.WavFile))
                                    {
                                        soundPlayer.Stop();
                                        soundPlayer.PlaySync();
                                        Thread.Sleep(1000 * 6);
                                    }
                                }
                                info.SendCount++;
                                info.SendTime = info.SendTime.AddMinutes(RepeatInterval);
                                if (info.SendCount < MaxSendCount)
                                {
                                    NotifyQueue.Enqueue(info);
                                }
                                #endregion
    
                            }
                            else
                            {
                                NotifyQueue.Enqueue(info);
                            }
                        }
                        _Counter.QueueLength = NotifyQueue.Count;
                        if (NotifyQueue.Count <= 0)
                        {
                            Thread.Sleep(450);
                        }
    
                        Thread.Sleep(50);
                    }
                }
                catch (Exception ex)
                {
                    WriteInfo("错误" + ex.Message);
                }
                finally
                {
                    if (HandleEnable)
                    {
    
                        ThreadPool.QueueUserWorkItem(o => { HandleNotifyQueue(); }, null);
                    }
                }
            }
            private void SynthesisVoice(NotifyInfo info)
            {
             
                    try
                    {
                        #region 合成音频并排队
                        using (var svr = new SynthesisService())
                        {
                            WriteInfo(DateTime.Now + ":发起音频合成..." );
                            Interlocked.Increment(ref _Counter.SynthesisCount);
                            svr.Timeout = 1000 * 360;
                            svr.GetVoiceCompleted += (s, e) =>
                            {
                                try
                                {
                                    if (_Counter.SynthesisCount > 0)Interlocked.Decrement(ref _Counter.SynthesisCount);
                        
    
                                    if (e.Error != null) throw e.Error;
                                    if (e.Cancelled) return;
                                    if (e.Result.Code != 0) throw new Exception(e.Result.Msg);
                                    var filename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "VCache/" + info.Postion + ".wav");
                                    if(!Directory.Exists(Path.GetDirectoryName( filename)))
                                    {
                                        Directory.CreateDirectory(Path.GetDirectoryName(filename));
                                    }
                                    File.WriteAllBytes(filename, e.Result.Data);
                                    info.VoiceReady = true;
                                    NotifyQueue.Enqueue(info);
                                    Interlocked.Increment(ref _Counter.SynthesisedCount);
                                    _Counter.QueueLength ++;
                                    WriteInfo(DateTime.Now +":完成音频合成");
                                }
                                catch (Exception ex)
                                {
                                    WriteInfo(ex.Message);
                                }
    
    
                            };
                            svr.GetVoiceAsync(info.Msg, info);
    
    
                        }
                        #endregion
                    }
                    catch (Exception ex)
                    {
                        WriteInfo(ex.Message);
                    }
             
            }
    
    
            
            #endregion
    
            private void btnTest_Click(object sender, EventArgs e)
            {
                try
                {
                    btnTest.Enabled = false;
    
                    TestOnlineSynthesis();
    
                    #region 保持3秒
                    for (int i = 0; i < 30; i++)
                    {
                        Thread.Sleep(100);
                        Application.DoEvents();
                    }
                    #endregion
    
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
                finally
                {
                    btnTest.Enabled = true;
                }
            }
    
            private  void TestOnlineSynthesis()
            {
                Action act = () =>
                {
                    try
                    {
                        #region 在线合成测试
    
                        Stopwatch sw = new Stopwatch();
                        WriteInfo(DateTime.Now +":发起在线合成测试...");
                        Interlocked.Increment(ref _Counter.SynthesisCount);
                        sw.Start();
                        var svr = new SynthesisService();
                        svr.Timeout = 1000 * 360;
                        var msg = ConfigurationManager.AppSettings["TestText"];
                        var response = svr.GetVoice(msg);
                        //更新计数器
                        if (_Counter.SynthesisCount > 0) Interlocked.Decrement(ref _Counter.SynthesisCount);
                        if (response.Code != 0) throw new Exception(response.Msg);
                        Interlocked.Increment(ref _Counter.SynthesisedCount);
                        using (MemoryStream ms = new MemoryStream(response.Data))
                        {
                            using (SoundPlayer soundPlayer = new SoundPlayer(ms))
                            {
                                soundPlayer.Stop();
                                soundPlayer.Play();
    
                            }
                        }
                        sw.Stop();
                        
                        WriteInfo(string.Format("{0}:完成在线合成测试,用时{1}毫秒",DateTime.Now,sw.ElapsedMilliseconds));
                        #endregion
                    }
                    catch (Exception ex)
                    {
                        WriteInfo(ex.Message);
                    }
                };
                var ar = act.BeginInvoke(null, null);
            }
            private void  WriteInfo(string msg)
            {
    
                if (InvokeRequired)
                {
                    SyncContext.Post(o =>
                    {
                        WriteInfo(msg);
                    }, null);
                }
                else
                {
                    lblTips.Text = msg;
                    Console.WriteLine(msg);
                }
              
    
            }
            public class NotifyInfo
            {
                public long MsgId { get; set; }
                public String Postion { get; set; }
                public String Msg { get; set; }
                public String WavFile { get; set; }
                public DateTime AddTime { get; set; }
                public DateTime SendTime { get; set; }
                public int SendCount { get; set; }
                public bool VoiceReady { get; set; }
                public String EmpName { get; set; }
                public int EmpId { get; set; }
                public String Memo { get; set; }
                public String MachineType { get; set; }
                #region 机台编号对应表
                public static Dictionary<String, String> MachineTypeDic =
                    new Dictionary<string, string>()
            {
                    {"ZD","自动机"},
                    {"YJ","压接"},
                    {"ZJ","中间压接"},
                    {"DJ","冲床"},
                    {"XL","电脑剥线机"},
                    {"QD","扩孔机"},
                    {"JC","绞缠线"},
                    {"BJ","包胶机"},
                    {"RS","热缩机"},
                    {"YT","一体机"},
                    {"SC","超声波"}
    
            };
                #endregion
                public NotifyInfo()
                {
                    AddTime = DateTime.Now;
                    SendCount = 0;
                    WavFile = "";
                    VoiceReady = false;
                    SendTime = DateTime.Now;
                }
                
                public static NotifyInfo Create(String msg)
                {
                    var info = new NotifyInfo();
                    var MsgTemp = ConfigurationManager.AppSettings["MsgTemp"];
                    if (msg.IndexOf("呼叫机修通知") < 0) return null;
                    //呼叫机修通知:($RecId$)
    机台:$Position$
    员工:$EmpName$($EmpId$)
    备注:$Memo$
                    //呼叫机修通知:(5168)  机台:ZD062  员工:杜多婷(170062)  备注:
                    var m = Regex.Match(msg, @"^呼叫机修通知:(.*?)机台:(.*?)员工:(.*?)备注:(.*?)$",  RegexOptions.Singleline| RegexOptions.IgnoreCase);
                    if(!m.Success)return null;
                    info.AddTime = DateTime.Now;
                    info.SendTime = DateTime.Now.AddMinutes( frmMain.FirstSendDelay);
                    info.MsgId =long.Parse( m.Groups[1].Value.Replace("(", "").Replace(")",""));
                    info.Postion = m.Groups[2].Value.Trim().ToUpper();
                    //员工与工号
                    var empStr=m.Groups[3].Value;
                    var index=empStr.IndexOf("(");
                    info.EmpName = empStr.Substring(0, index);
                    var endIndex=empStr.IndexOf(")");
                    info.EmpId= int.Parse(empStr.Substring(index+1, endIndex-index-1));
                    info.Memo = m.Groups[4].Value.Trim();
                    
                    var m2 = Regex.Match(info.Postion, @"([a-zA-Z]*)d*", RegexOptions.Singleline | RegexOptions.IgnoreCase);
                    if (!m2.Success) return null;
                    info.MachineType = m2.Groups[1].Value.Trim();
                    var mNum = info.Postion.Replace(info.MachineType, "").TrimStart("0".ToCharArray()).Trim();
                    info.Msg =MsgTemp.Replace("$工序$",  MachineTypeDic[info.MachineType]).Replace("$编号$",info.Postion).Replace("$数字$",mNum);
    
                    var filename= Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "VCache/" + info.Postion + ".wav");
                    info.WavFile = filename;
                    info.VoiceReady=File.Exists(filename);
        
                    return info;
                }
            }
            public class Counter
            {
                public int SynthesisCount = 0; //正在合成数
                public int SynthesisedCount = 0; //已合成数
                public int Received = 0;
                public int SendCount = 0;
                public int CancelCount = 0;
                public int QueueLength = 0;
            }
        }
    }
    View Code

    服务端

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Services;
    using TTS;
    using System.Text;
    using System.IO;
    using System.Runtime.InteropServices;
    using System.Threading;
    using System.Configuration;
    namespace VoiceSynthesis
    {
        /// <summary>
        /// SynthesisService 的摘要说明
        /// </summary>
        [WebService(Namespace = "http://tempuri.org/")]
        [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
        [System.ComponentModel.ToolboxItem(false)]
        // 若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消对下行的注释。
        // [System.Web.Script.Services.ScriptService]
        public class SynthesisService : System.Web.Services.WebService
        {
            int ret = 0;
            IntPtr session_ID;
            [WebMethod]
            public string HelloWorld()
            {
                return "Hello World";
            }
    
            #region Core
            /// <summary>
            /// int>0 声音文件编号
            /// 科户端更具这个获取具体名称
            /// </summary>
            /// <param name="msg"></param>
            /// <returns></returns>
            [WebMethod]
            public ConvertResult GetVoice(string msg)
            {
                var response = new ConvertResult() { Code = 0, Msg = "", VoiceId = "" };
                try
                {
    
                    var vid=Path.GetRandomFileName()+".v";
                    var filename=Server.MapPath("/tmp/"+vid);
                    List<byte> outData;
                    lock (typeof(SynthesisService))
                    {
                         GenWave(filename, msg,out outData);
                    }
                    response.Data = outData;
                    response.VoiceId = vid;
                }
                catch (Exception ex)
                {
                    response.Code = -1;
                    response.Msg = ex.Message;
                }
                return response;
    
            }
            private void GenWave(string fname, string msg,out List<byte> fileBytes)
            {
                try
                {
                    fileBytes = null;
                    ///APPID请勿随意改动
                    string login_configs = "appid =    57f2ed75xx";//登录参数,自己注册后获取的appid
    
                    var text = msg;
    
                    string filename = fname; //合成的语音文件
                    uint audio_len = 0;
    
                    SynthStatus synth_status = SynthStatus.MSP_TTS_FLAG_STILL_HAVE_DATA;
                    ret = TTSDll.MSPLogin(string.Empty, string.Empty, login_configs);//第一个参数为用户名,第二个参数为密码,第三个参数是登录参数,用户名和密码需要在http://open.voicecloud.cn
                    //MSPLogin方法返回失败
                    if (ret != (int)ErrorCode.MSP_SUCCESS)
                    {
                        return;
                    }
    
                    //string parameter = "engine_type = local, voice_name=xiaoyan, tts_res_path =fo|res\tts\xiaoyan.jet;fo|res\tts\common.jet, sample_rate = 16000";
                    //string _params = "ssm=1,ent=sms16k,vcn=xiaoyan,spd=medium,aue=speex-wb;7,vol=x-loud,auf=audio/L16;rate=16000";
                    //许工,你妈妈喊你回家吃饭
                    string _params =ConfigurationManager.AppSettings["VSet"] ;
                    //string @params = "engine_type = local,voice_name=xiaoyan,speed=50,volume=50,pitch=50,rcn=1, text_encoding = UTF8, background_sound=1,sample_rate = 16000";
                    session_ID = TTSDll.QTTSSessionBegin(_params, ref ret);
                    //QTTSSessionBegin方法返回失败
                    if (ret != (int)ErrorCode.MSP_SUCCESS)
                    {
                        return;
                    }
                    ret = TTSDll.QTTSTextPut(Ptr2Str(session_ID), text, (uint)Encoding.Default.GetByteCount(text), string.Empty);
                    //QTTSTextPut方法返回失败
                    if (ret != (int)ErrorCode.MSP_SUCCESS)
                    {
                        return;
                    }
    
                    MemoryStream memoryStream = new MemoryStream();
                    memoryStream.Write(new byte[44], 0, 44);
                    while (true)
                    {
                        IntPtr source = TTSDll.QTTSAudioGet(Ptr2Str(session_ID), ref audio_len, ref synth_status, ref ret);
                        byte[] array = new byte[(int)audio_len];
                        if (audio_len > 0)
                        {
                            Marshal.Copy(source, array, 0, (int)audio_len);
                        }
                        memoryStream.Write(array, 0, array.Length);
                        Thread.Sleep(1000);
                        if (synth_status == SynthStatus.MSP_TTS_FLAG_DATA_END || ret != 0)
                            break;
                    }
                    WAVE_Header wave_Header = getWave_Header((int)memoryStream.Length - 44);
                    byte[] array2 = this.StructToBytes(wave_Header);
                    memoryStream.Position = 0L;
                    memoryStream.Write(array2, 0, array2.Length);
                    memoryStream.Position = 0L;
                    //SoundPlayer soundPlayer = new SoundPlayer(memoryStream);
                    //soundPlayer.Stop();
                    //soundPlayer.Play();
                    fileBytes = new List<byte>(memoryStream.ToArray());
                    if (filename != null)
                    {
                        FileStream fileStream = new FileStream(filename, FileMode.Create, FileAccess.Write);
                        memoryStream.WriteTo(fileStream);
                        memoryStream.Close();
                        fileStream.Close();
                    }
    
                }
                catch (Exception )
                {
                    throw;
                }
                finally
                {
                    ret = TTSDll.QTTSSessionEnd(Ptr2Str(session_ID), "");
                    ret = TTSDll.MSPLogout();//退出登录
                }
            }
    
            /// <summary>
            /// 结构体转字符串
            /// </summary>
            /// <param name="structure"></param>
            /// <returns></returns>
            private byte[] StructToBytes(object structure)
            {
                int num = Marshal.SizeOf(structure);
                IntPtr intPtr = Marshal.AllocHGlobal(num);
                byte[] result;
                try
                {
                    Marshal.StructureToPtr(structure, intPtr, false);
                    byte[] array = new byte[num];
                    Marshal.Copy(intPtr, array, 0, num);
                    result = array;
                }
                finally
                {
                    Marshal.FreeHGlobal(intPtr);
                }
                return result;
            }
            /// <summary>
            /// 结构体初始化赋值
            /// </summary>
            /// <param name="data_len"></param>
            /// <returns></returns>
            private WAVE_Header getWave_Header(int data_len)
            {
                return new WAVE_Header
                {
                    RIFF_ID = 1179011410,
                    File_Size = data_len + 36,
                    RIFF_Type = 1163280727,
                    FMT_ID = 544501094,
                    FMT_Size = 16,
                    FMT_Tag = 1,
                    FMT_Channel = 1,
                    FMT_SamplesPerSec = 16000,
                    AvgBytesPerSec = 32000,
                    BlockAlign = 2,
                    BitsPerSample = 16,
                    DATA_ID = 1635017060,
                    DATA_Size = data_len
                };
            }
            /// <summary>
            /// 语音音频头
            /// </summary>
            private struct WAVE_Header
            {
                public int RIFF_ID;
                public int File_Size;
                public int RIFF_Type;
                public int FMT_ID;
                public int FMT_Size;
                public short FMT_Tag;
                public ushort FMT_Channel;
                public int FMT_SamplesPerSec;
                public int AvgBytesPerSec;
                public ushort BlockAlign;
                public ushort BitsPerSample;
                public int DATA_ID;
                public int DATA_Size;
            }
            /// 指针转字符串
            /// </summary>
            /// <param name="p">指向非托管代码字符串的指针</param>
            /// <returns>返回指针指向的字符串</returns>
            public static string Ptr2Str(IntPtr p)
            {
                List<byte> lb = new List<byte>();
                while (Marshal.ReadByte(p) != 0)
                {
                    lb.Add(Marshal.ReadByte(p));
                    p = p + 1;
                }
                byte[] bs = lb.ToArray();
                return Encoding.Default.GetString(lb.ToArray());
            }
    
            public class ConvertResult
            {
                public int Code { get; set; }
                public String VoiceId { get; set; }
                public String Msg { get; set; }
                public List<Byte> Data { get; set; }
            }
    
            #endregion
        }
    }
    View Code

    IIS 7.0配置成32位模式,运行在LocalSystem下

      <appSettings>
        <add key="UserId" value="8999001" />
        <add key="MsgTemp" value="简讯!{0}:{1}呼叫机修,{0},{1}呼叫机修,完毕!"/>
        <add key="RepeatCount" value="3"/> <!-- 重复播放次数 -->
        <add key="RepeatInterval" value="3"/><!-- 重复间隔时间,单位分钟 -->
        <add key="TestText" value="喜讯!水工,你媳妇又生了,你妈叫你快些子回家,看看生了个啥子!"/>
        <add key="Mock" value="true"/>
      </appSettings>
    View Code

    配置

  • 相关阅读:
    线程---JDK查看线程
    如何处理js的跨域问题
    每日思考(2019/12/31)
    每日思考(2019/12/30)
    每日思考(2019/12/29)
    每日思考(2019/12/28)
    每日思考(2019/12/27)
    每日思考(2019/12/26)
    每日思考(2019/12/25)
    每日思考(2019/12/24)
  • 原文地址:https://www.cnblogs.com/wdfrog/p/5984410.html
Copyright © 2011-2022 走看看