unity接入讯飞AIUI(Windows SDK)

这篇具有很好参考价值的文章主要介绍了unity接入讯飞AIUI(Windows SDK)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、什么是AIUI
AIUI 是一套人机交互解决方案,整合了语音唤醒、语音识别、语义理解、内容平台、语音合成(比普通的语音合成多一个发音人)等能力。
新用户有20个免费的装机量,每天有500交互次数

二、创建AIUI

  1. 在控制台→我的应用→创建新应用中来创建自己测试项目
    unity接入讯飞AIUI(Windows SDK),unity,windows,语音识别,ai
    三、进入AIUI控制台
    unity接入讯飞AIUI(Windows SDK),unity,windows,语音识别,ai
    unity接入讯飞AIUI(Windows SDK),unity,windows,语音识别,ai

点击服务管理进入AIUI的控制台

四、AIUI设置

unity接入讯飞AIUI(Windows SDK),unity,windows,语音识别,ai

默认自带有语音识别的,如果需要AIUI回答你,则需要开启语义理解,如果需要有声音则需要开启语音合成,否则调用SDK的时候是不会返回语义理解和语音合成的数据的

unity接入讯飞AIUI(Windows SDK),unity,windows,语音识别,ai
可以在上面的位置直接修改发音人,返回的语音合成数据也会改变

五、导入项目

1.下载SDK
unity接入讯飞AIUI(Windows SDK),unity,windows,语音识别,ai

2.我们需要将aiui.dll导入的Unity的Plugins文件夹中
unity接入讯飞AIUI(Windows SDK),unity,windows,语音识别,aiunity接入讯飞AIUI(Windows SDK),unity,windows,语音识别,ai

3.我们需要将AIUI文件夹放到StreamingAssets文件夹中,这里面保存的一些配置信息,比如APPID,语音合成等等,只需要在程序开始时读取配置文件进行了,就不需要像讯飞的语音合成,语音识别等模块一样需要登录和登出了。
unity接入讯飞AIUI(Windows SDK),unity,windows,语音识别,ai

4.这里有一些工具类,是对 aiui.dll 的扩展,使用的是官方的 c# 的 demo
unity接入讯飞AIUI(Windows SDK),unity,windows,语音识别,aiunity接入讯飞AIUI(Windows SDK),unity,windows,语音识别,ai
5.初始化配置

 void Start()
    {
        // 为每一个设备设置对应唯一的SN(最好使用设备硬件信息(mac地址,设备序列号等)生成)
        // 以便正确统计装机量,避免刷机或者应用卸载重装导致装机量重复计数
        AIUISetting.setSystemInfo(AIUIConstant.KEY_SERIAL_NUM, GetMac());
        string cfg = File.ReadAllText(Application.streamingAssetsPath + "\\AIUI\\cfg\\aiui.cfg");
        agent = IAIUIAgent.Create(cfg, onEvent);

        IAIUIMessage msg_start = IAIUIMessage.Create(AIUIConstant.CMD_START, 0, 0, "", IBuffer.Zero);
        agent.SendMessage(msg_start);
        msg_start.Destroy();
        msg_start = null;
    }

6.发送消息,这里是将麦克风录入的信息转换为byte[],然后发送的到SDK中

 public IEnumerator SendMassage(byte[] data)
    {
        //唤醒
        IAIUIMessage msg_wakeup = IAIUIMessage.Create(AIUIConstant.CMD_WAKEUP, 0, 0, "", IBuffer.Zero);
        agent.SendMessage(msg_wakeup);
        msg_wakeup.Destroy();
        msg_wakeup = null;
        yield return new WaitForSeconds(0.2f);
        print("wakeup");

        //开始录音
        IAIUIMessage msg_start_r = IAIUIMessage.Create(AIUIConstant.CMD_START_RECORD, 0, 0,
            "data_type=audio,interact_mode=oneshot", IBuffer.Zero);
        agent.SendMessage(msg_start_r);
        msg_start_r.Destroy();
        msg_start_r = null;

        //发送语音
        IBuffer buf_1 = IBuffer.FromData(data, data.Length);
        IAIUIMessage msg_write_audio = IAIUIMessage.Create(AIUIConstant.CMD_WRITE, 0, 0, "data_type=audio", buf_1);
        agent.SendMessage(msg_write_audio);
        msg_write_audio.Destroy();
        msg_write_audio = null;
        buf_1 = null;
        yield return new WaitForSeconds(0.04f);
    }

7.返回消息

private  void onEvent(IAIUIEvent ev)
    {
        switch (ev.GetEventType())
        {
            case AIUIConstant.EVENT_STATE:
                {
                    switch (ev.GetArg1())
                    {
                        case AIUIConstant.STATE_IDLE:
                            {
                                print("EVENT_STATE: IDLE");
                            }
                            break;

                        case AIUIConstant.STATE_READY:
                            {
                                print("EVENT_STATE: READY");
                            }
                            break;

                        case AIUIConstant.STATE_WORKING:
                            {
                                print("EVENT_STATE: WORKING");
                            }
                            break;
                    }
                }
                break;
            case AIUIConstant.EVENT_WAKEUP:
                {
                    Debug.LogFormat("EVENT_WAKEUP: {0}", ev.GetInfo());

                }
                break;
            case AIUIConstant.EVENT_SLEEP:
                {
                    Debug.LogFormat("EVENT_WAKEUP: arg1={0}", ev.GetArg1());
                }
                break;
            case AIUIConstant.EVENT_VAD:
                {
                    switch (ev.GetArg1())
                    {
                        case AIUIConstant.VAD_BOS:
                            {
                                print("EVENT_VAD: BOS");
                            }
                            break;

                        case AIUIConstant.VAD_EOS:
                            {
                                print("EVENT_VAD: EOS");
                            }
                            break;
                    }
                }
                break;

            case AIUIConstant.EVENT_RESULT://返回成功时传入的数据
                {
                    try
                    {
                        var info = JsonConvert.DeserializeObject<Dictionary<object, object>>(ev.GetInfo());
                         
                        var datas = info["data"] as JArray;
                        var data = datas[0] as JObject;
                        var param = data["params"] as JObject;
                        var contents = data["content"] as JArray;
                        var content = contents[0] as JObject;

                        string sub = param["sub"].ToString();
                        string cnt_id = content["cnt_id"].ToString();
                        int dataLen = 0;
                        byte[] buffer = ev.GetData().GetBinary(cnt_id, ref dataLen);
                        Debug.LogFormat("sub: {0} ,info: {1}", sub, ev.GetInfo());
                        switch (sub)
                        {                               
                            case "iat":
                                string jsonObject = Encoding.UTF8.GetString(buffer).Replace('\0', ' ');
                                JsonData deJson = JsonMapper.ToObject(jsonObject);

                                StringBuilder cont = new StringBuilder();
                                foreach (JsonData item in deJson["text"]["ws"])
                                {

                                    cont.Append(item["cw"][0]["w"]);
                                }
                                //切换的主线程
                                Loom.QueueOnMainThread(() => {
                                    sendText.text = cont.ToString();
                                });

                                break;
                            case "nlp":
                                string jsonObject1 = Encoding.UTF8.GetString(buffer).Replace('\0',' ');
                                JsonData deJson1 = JsonMapper.ToObject(jsonObject1);
                                //切换的主线程
                                Loom.QueueOnMainThread(() => {
                                    returnText.text = deJson1["intent"]["answer"]["text"].ToString();
                                });
 
                                break;
                            case "tts":
                                string jsonObject2 = ev.GetInfo().Replace('\0', ' ');
                                JsonData deJson2 = JsonMapper.ToObject(jsonObject2);
                                //复制数据
                                for (int i = 0; i < buffer.Length; i++)
                                {
                                    audioData.Add(buffer[i]);
                                }
                              
                                Debug.Log("音频数据长度:"+ buffer.Length +"   总长度:"+ audioData.Count);
                                //判断是否结束
                                if (int.Parse(deJson2["data"][0]["content"][0]["dts"].ToString()) == 2)
                                {
                                    Debug.Log(audioData.Count);
                                    //切换的主线程
                                    Loom.QueueOnMainThread(() => {
                                        Save();
                                        //audioData = new List<byte>();
                                        //语音合成
                                        //audioSource.clip = Clip(audioData.ToArray());
                                        //audioSource.loop = false;
                                        //audioSource.Play();

                                    });
                                }
                                break;
                            case "asr":
                                break;
                            default:
                                break;
                        }

                        datas = null;
                        data = null;
                        param = null;
                        contents = null;
                        content = null;
                        info = null;
                    }
                    catch (Exception e)
                    {

                        print(e.Message); ;
                    }


                }
                break;
            case AIUIConstant.EVENT_ERROR:
                Debug.LogFormat("EVENT_ERROR: {0} {1}", ev.GetArg1(), ev.GetInfo());
                break;

        }
    }

AIUIManager 全部代码

using aiui;
using LitJson;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Net.NetworkInformation;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using UnityEngine;
using UnityEngine.UI;

//讯飞AIUI
public class AIUIManager : MonoBehaviour
{
    public static AIUIManager Instance;
    private IAIUIAgent agent;
    public AudioSource audioSource;

    public Text returnText;
    public Text sendText;

    private void Awake()
    {
        Instance = this;
    }

    // Start is called before the first frame update
    void Start()
    {
        // 为每一个设备设置对应唯一的SN(最好使用设备硬件信息(mac地址,设备序列号等)生成)
        // 以便正确统计装机量,避免刷机或者应用卸载重装导致装机量重复计数
        AIUISetting.setSystemInfo(AIUIConstant.KEY_SERIAL_NUM, GetMac());
        string cfg = File.ReadAllText(Application.streamingAssetsPath + "\\AIUI\\cfg\\aiui.cfg");
        agent = IAIUIAgent.Create(cfg, onEvent);

        IAIUIMessage msg_start = IAIUIMessage.Create(AIUIConstant.CMD_START, 0, 0, "", IBuffer.Zero);
        agent.SendMessage(msg_start);
        msg_start.Destroy();
        msg_start = null;
    }

     public IEnumerator SendMassage(byte[] data)
    {
        //唤醒
        IAIUIMessage msg_wakeup = IAIUIMessage.Create(AIUIConstant.CMD_WAKEUP, 0, 0, "", IBuffer.Zero);
        agent.SendMessage(msg_wakeup);
        msg_wakeup.Destroy();
        msg_wakeup = null;
        yield return new WaitForSeconds(0.2f);
        print("wakeup");

        //开始录音
        IAIUIMessage msg_start_r = IAIUIMessage.Create(AIUIConstant.CMD_START_RECORD, 0, 0,
            "data_type=audio,interact_mode=oneshot", IBuffer.Zero);
        agent.SendMessage(msg_start_r);
        msg_start_r.Destroy();
        msg_start_r = null;

        //发送语音
        IBuffer buf_1 = IBuffer.FromData(data, data.Length);
        IAIUIMessage msg_write_audio = IAIUIMessage.Create(AIUIConstant.CMD_WRITE, 0, 0, "data_type=audio", buf_1);
        agent.SendMessage(msg_write_audio);
        msg_write_audio.Destroy();
        msg_write_audio = null;
        buf_1 = null;
        yield return new WaitForSeconds(0.04f);
    }

    public  string GetMac()
    {
        NetworkInterface[] interfaces = NetworkInterface.GetAllNetworkInterfaces();

        string mac = "";
        foreach (NetworkInterface ni in interfaces)
        {
            if (ni.NetworkInterfaceType != NetworkInterfaceType.Loopback)
            {
                mac += ni.GetPhysicalAddress().ToString();
            }
        }

        byte[] result = Encoding.Default.GetBytes(mac);
        result = new MD5CryptoServiceProvider().ComputeHash(result);

        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < result.Length; i++)
        {
            builder.Append(result[i].ToString("x2"));
        }

        return builder.ToString();
    }

    private void OnDisable()
    {
        agent.Destroy();
    }

    //返回事件
    private  void onEvent(IAIUIEvent ev)
    {
        switch (ev.GetEventType())
        {
            case AIUIConstant.EVENT_STATE:
                {
                    switch (ev.GetArg1())
                    {
                        case AIUIConstant.STATE_IDLE:
                            {
                                print("EVENT_STATE: IDLE");
                            }
                            break;

                        case AIUIConstant.STATE_READY:
                            {
                                print("EVENT_STATE: READY");
                            }
                            break;

                        case AIUIConstant.STATE_WORKING:
                            {
                                print("EVENT_STATE: WORKING");
                            }
                            break;
                    }
                }
                break;
            case AIUIConstant.EVENT_WAKEUP:
                {
                    Debug.LogFormat("EVENT_WAKEUP: {0}", ev.GetInfo());

                }
                break;
            case AIUIConstant.EVENT_SLEEP:
                {
                    Debug.LogFormat("EVENT_WAKEUP: arg1={0}", ev.GetArg1());
                }
                break;
            case AIUIConstant.EVENT_VAD:
                {
                    switch (ev.GetArg1())
                    {
                        case AIUIConstant.VAD_BOS:
                            {
                                print("EVENT_VAD: BOS");
                            }
                            break;

                        case AIUIConstant.VAD_EOS:
                            {
                                print("EVENT_VAD: EOS");
                            }
                            break;
                    }
                }
                break;

            case AIUIConstant.EVENT_RESULT:
                {
                    try
                    {
                        var info = JsonConvert.DeserializeObject<Dictionary<object, object>>(ev.GetInfo());
                         
                        var datas = info["data"] as JArray;
                        var data = datas[0] as JObject;
                        var param = data["params"] as JObject;
                        var contents = data["content"] as JArray;
                        var content = contents[0] as JObject;

                        string sub = param["sub"].ToString();
                        string cnt_id = content["cnt_id"].ToString();
                        int dataLen = 0;
                        byte[] buffer = ev.GetData().GetBinary(cnt_id, ref dataLen);
                        Debug.LogFormat("sub: {0} ,info: {1}", sub, ev.GetInfo());
                        switch (sub)
                        {                               
                            case "iat":
                                string jsonObject = Encoding.UTF8.GetString(buffer).Replace('\0', ' ');
                                JsonData deJson = JsonMapper.ToObject(jsonObject);

                                StringBuilder cont = new StringBuilder();
                                foreach (JsonData item in deJson["text"]["ws"])
                                {

                                    cont.Append(item["cw"][0]["w"]);
                                }
                                //切换的主线程
                                Loom.QueueOnMainThread(() => {
                                    sendText.text = cont.ToString();
                                });

                                break;
                            case "nlp":
                                string jsonObject1 = Encoding.UTF8.GetString(buffer).Replace('\0',' ');
                                JsonData deJson1 = JsonMapper.ToObject(jsonObject1);
                                //切换的主线程
                                Loom.QueueOnMainThread(() => {
                                    returnText.text = deJson1["intent"]["answer"]["text"].ToString();
                                });
 
                                break;
                            case "tts":
                                string jsonObject2 = ev.GetInfo().Replace('\0', ' ');
                                JsonData deJson2 = JsonMapper.ToObject(jsonObject2);

                                if (int.Parse(deJson2["data"][0]["content"][0]["dts"].ToString()) == 2)
                                {
                                    for (int i = 0; i < 44; i++)
                                    {
                                        audioData.Add(0);
                                    }
                                }

                                    //复制数据
                                for (int i = 0; i < buffer.Length; i++)
                                {
                                    audioData.Add(buffer[i]);
                                }
                              
                                Debug.Log("音频数据长度:"+ buffer.Length +"   总长度:"+ audioData.Count);
                                //判断是否结束
                                if (int.Parse(deJson2["data"][0]["content"][0]["dts"].ToString()) == 2)
                                {
                                    Debug.Log(audioData.Count);

                                    //写入wav头
                                    //创建wav文件头
                                    WAVE_Header header = getWave_Header(audioData.Count-44);
                                    //把文件头结构转化为字节数组                      
                                    byte[] headerByte = StructToBytes(header);
                                    for (int i = 0; i < headerByte.Length; i++)
                                    {
                                        audioData[i] = headerByte[i];
                                    }

                                    //切换的主线程
                                    Loom.QueueOnMainThread(() => {
                                        //Save();
                                       
                                        //语音合成
                                        audioSource.clip = Clip(audioData.ToArray());
                                        //audioSource.loop = false;
                                        audioSource.Play();
                                        audioData = new List<byte>();
                                    });
                                }
                                break;
                            case "asr":
                                break;
                            default:
                                break;
                        }

                        datas = null;
                        data = null;
                        param = null;
                        contents = null;
                        content = null;
                        info = null;
                    }
                    catch (Exception e)
                    {

                        print(e.Message); ;
                    }


                }
                break;
            case AIUIConstant.EVENT_ERROR:
                Debug.LogFormat("EVENT_ERROR: {0} {1}", ev.GetArg1(), ev.GetInfo());
                break;

        }
    }
    private List<byte> audioData = new List<byte>();

    /// <summary>
    /// 把结构体转化为字节序列
    /// </summary>
    /// <param name="structure">被转化的结构体</param>
    /// <returns>返回字节序列</returns>
    public static byte[] StructToBytes(object structure)
    {
        int size = Marshal.SizeOf(structure);
        IntPtr buffer = Marshal.AllocHGlobal(size);
        try
        {
            Marshal.StructureToPtr(structure, buffer, false);
            Byte[] bytes = new Byte[size];
            Marshal.Copy(buffer, bytes, 0, size);
            return bytes;
        }
        finally
        {
            Marshal.FreeHGlobal(buffer);
        }
    }

/// <summary>
/// 根据数据段的长度,生产文件头
/// </summary>
/// <param name="data_len">音频数据长度</param>
/// <returns>返回wav文件头结构体</returns>
public static WAVE_Header getWave_Header(int data_len)
    {
        WAVE_Header wav_Header = new WAVE_Header();
        wav_Header.RIFF_ID = 0x46464952;        //字符RIFF
        wav_Header.File_Size = data_len + 36;
        wav_Header.RIFF_Type = 0x45564157;      //字符WAVE

        wav_Header.FMT_ID = 0x20746D66;         //字符fmt
        wav_Header.FMT_Size = 16;
        wav_Header.FMT_Tag = 0x0001;
        wav_Header.FMT_Channel = 1;             //单声道
        wav_Header.FMT_SamplesPerSec = 16000;   //采样频率
        wav_Header.AvgBytesPerSec = 32000;      //每秒所需字节数
        wav_Header.BlockAlign = 2;              //每个采样1个字节
        wav_Header.BitsPerSample = 16;           //每个采样8bit

        wav_Header.DATA_ID = 0x61746164;        //字符data
        wav_Header.DATA_Size = data_len;

        return wav_Header;
    }
    /// <summary>
    /// wave文件头
    /// </summary>
    public struct WAVE_Header
    {
        public int RIFF_ID;           //4 byte , 'RIFF'
        public int File_Size;         //4 byte , 文件长度
        public int RIFF_Type;         //4 byte , 'WAVE'

        public int FMT_ID;            //4 byte , 'fmt'
        public int FMT_Size;          //4 byte , 数值为16或18,18则最后又附加信息
        public short FMT_Tag;         //2 byte , 编码方式,一般为0x0001
        public ushort FMT_Channel;    //2 byte , 声道数目,1--单声道;2--双声道
        public int FMT_SamplesPerSec; //4 byte , 采样频率
        public int AvgBytesPerSec;    //4 byte , 每秒所需字节数,记录每秒的数据量
        public ushort BlockAlign;     //2 byte , 数据块对齐单位(每个采样需要的字节数)
        public ushort BitsPerSample;  //2 byte , 每个采样需要的bit数

        public int DATA_ID;           //4 byte , 'data'
        public int DATA_Size;         //4 byte , 
    }

    #region 播放录音
    public static AudioClip Clip(byte[] fileBytes, int offsetSamples = 0, string name = "ifly")
    {
        //string riff = Encoding.ASCII.GetString (fileBytes, 0, 4);
        //string wave = Encoding.ASCII.GetString (fileBytes, 8, 4);
        int subchunk1 = BitConverter.ToInt32(fileBytes, 16);
        ushort audioFormat = BitConverter.ToUInt16(fileBytes, 20);

        // NB: Only uncompressed PCM wav files are supported.
        string formatCode = FormatCode(audioFormat);
        //Debug.AssertFormat(audioFormat == 1 || audioFormat == 65534, "Detected format code '{0}' {1}, but only PCM and WaveFormatExtensable uncompressed formats are currently supported.", audioFormat, formatCode);

        ushort channels = BitConverter.ToUInt16(fileBytes, 22);
        int sampleRate = BitConverter.ToInt32(fileBytes, 24);
        //int byteRate = BitConverter.ToInt32 (fileBytes, 28);
        //UInt16 blockAlign = BitConverter.ToUInt16 (fileBytes, 32);
        ushort bitDepth = BitConverter.ToUInt16(fileBytes, 34);

        int headerOffset = 16 + 4 + subchunk1 + 4;
        int subchunk2 = BitConverter.ToInt32(fileBytes, headerOffset);
        //Debug.LogFormat ("riff={0} wave={1} subchunk1={2} format={3} channels={4} sampleRate={5} byteRate={6} blockAlign={7} bitDepth={8} headerOffset={9} subchunk2={10} filesize={11}", riff, wave, subchunk1, formatCode, channels, sampleRate, byteRate, blockAlign, bitDepth, headerOffset, subchunk2, fileBytes.Length);

        //Log.Info(bitDepth);

        float[] data;
        switch (bitDepth)
        {
            case 8:
                data = Convert8BitByteArrayToAudioClipData(fileBytes, headerOffset, subchunk2);
                break;
            case 16:
                data = Convert16BitByteArrayToAudioClipData(fileBytes, headerOffset, subchunk2);
                break;
            case 24:
                data = Convert24BitByteArrayToAudioClipData(fileBytes, headerOffset, subchunk2);
                break;
            case 32:
                data = Convert32BitByteArrayToAudioClipData(fileBytes, headerOffset, subchunk2);
                break;
            default:
                throw new Exception(bitDepth + " bit depth is not supported.");
        }

        AudioClip audioClip = AudioClip.Create(name, data.Length, channels, sampleRate, false);
        audioClip.SetData(data, 0);
        return audioClip;
    }

    private static string FormatCode(UInt16 code)
    {
        switch (code)
        {
            case 1:
                return "PCM";
            case 2:
                return "ADPCM";
            case 3:
                return "IEEE";
            case 7:
                return "μ-law";
            case 65534:
                return "WaveFormatExtensable";
            default:
                Debug.LogWarning("Unknown wav code format:" + code);
                return "";
        }
    }

    #region wav file bytes to Unity AudioClip conversion methods

    private static float[] Convert8BitByteArrayToAudioClipData(byte[] source, int headerOffset, int dataSize)
    {
        int wavSize = BitConverter.ToInt32(source, headerOffset);
        headerOffset += sizeof(int);
        Debug.AssertFormat(wavSize > 0 && wavSize == dataSize, "Failed to get valid 8-bit wav size: {0} from data bytes: {1} at offset: {2}", wavSize, dataSize, headerOffset);

        float[] data = new float[wavSize];

        sbyte maxValue = sbyte.MaxValue;

        int i = 0;
        while (i < wavSize)
        {
            data[i] = (float)source[i] / maxValue;
            ++i;
        }

        return data;
    }

    private static float[] Convert16BitByteArrayToAudioClipData(byte[] source, int headerOffset, int dataSize)
    {
        int wavSize = BitConverter.ToInt32(source, headerOffset);
        headerOffset += sizeof(int);
        Debug.AssertFormat(wavSize > 0 && wavSize == dataSize, "Failed to get valid 16-bit wav size: {0} from data bytes: {1} at offset: {2}", wavSize, dataSize, headerOffset);

        int x = sizeof(Int16); // block size = 2
        int convertedSize = wavSize / x;

        float[] data = new float[convertedSize];

        Int16 maxValue = Int16.MaxValue;

        int offset = 0;
        int i = 0;
        while (i < convertedSize)
        {
            offset = i * x + headerOffset;
            data[i] = (float)BitConverter.ToInt16(source, offset) / maxValue;
            ++i;
        }

        Debug.AssertFormat(data.Length == convertedSize, "AudioClip .wav data is wrong size: {0} == {1}", data.Length, convertedSize);

        return data;
    }

    private static float[] Convert24BitByteArrayToAudioClipData(byte[] source, int headerOffset, int dataSize)
    {
        int wavSize = BitConverter.ToInt32(source, headerOffset);
        headerOffset += sizeof(int);
        Debug.AssertFormat(wavSize > 0 && wavSize == dataSize, "Failed to get valid 24-bit wav size: {0} from data bytes: {1} at offset: {2}", wavSize, dataSize, headerOffset);

        int x = 3; // block size = 3
        int convertedSize = wavSize / x;

        int maxValue = Int32.MaxValue;

        float[] data = new float[convertedSize];

        byte[] block = new byte[sizeof(int)]; // using a 4 byte block for copying 3 bytes, then copy bytes with 1 offset

        int offset = 0;
        int i = 0;
        while (i < convertedSize)
        {
            offset = i * x + headerOffset;
            Buffer.BlockCopy(source, offset, block, 1, x);
            data[i] = (float)BitConverter.ToInt32(block, 0) / maxValue;
            ++i;
        }

        Debug.AssertFormat(data.Length == convertedSize, "AudioClip .wav data is wrong size: {0} == {1}", data.Length, convertedSize);

        return data;
    }

    private static float[] Convert32BitByteArrayToAudioClipData(byte[] source, int headerOffset, int dataSize)
    {
        int wavSize = BitConverter.ToInt32(source, headerOffset);
        headerOffset += sizeof(int);
        Debug.AssertFormat(wavSize > 0 && wavSize == dataSize, "Failed to get valid 32-bit wav size: {0} from data bytes: {1} at offset: {2}", wavSize, dataSize, headerOffset);

        int x = sizeof(float); //  block size = 4
        int convertedSize = wavSize / x;

        Int32 maxValue = Int32.MaxValue;

        float[] data = new float[convertedSize];

        int offset = 0;
        int i = 0;
        while (i < convertedSize)
        {
            offset = i * x + headerOffset;
            data[i] = (float)BitConverter.ToInt32(source, offset) / maxValue;
            ++i;
        }

        Debug.AssertFormat(data.Length == convertedSize, "AudioClip .wav data is wrong size: {0} == {1}", data.Length, convertedSize);

        return data;
    }

    #endregion

    #endregion

    #region 保存语音
    public void Save()
    {
        using (FileStream fs = CreateEmpty(Application.streamingAssetsPath + "/dd.wav"))
        {
            ConvertAndWrite(fs);
            WriteHeader(fs);

            Debug.Log("写入完成");
        }



    }
    private void ConvertAndWrite(FileStream fileStream)
    {

        var outData = audioData.ToArray();
        fileStream.Write(outData, 0, outData.Length);
    }
    private FileStream CreateEmpty(string filepath)
    {
        FileStream fileStream = new FileStream(filepath, FileMode.Create);
        byte emptyByte = new byte();

        for (int i = 0; i < 44; i++) //preparing the header
        {
            fileStream.WriteByte(emptyByte);
        }

        return fileStream;
    }

    private void WriteHeader(FileStream stream)
    {
        int hz = 16000;
        int channels = 1;
        int samples =audioData.Count;

        stream.Seek(0, SeekOrigin.Begin);

        Byte[] riff = System.Text.Encoding.UTF8.GetBytes("RIFF");
        stream.Write(riff, 0, 4);

        Byte[] chunkSize = BitConverter.GetBytes(stream.Length - 8);
        stream.Write(chunkSize, 0, 4);

        Byte[] wave = System.Text.Encoding.UTF8.GetBytes("WAVE");
        stream.Write(wave, 0, 4);

        Byte[] fmt = System.Text.Encoding.UTF8.GetBytes("fmt ");
        stream.Write(fmt, 0, 4);

        Byte[] subChunk1 = BitConverter.GetBytes(16);
        stream.Write(subChunk1, 0, 4);

        UInt16 two = 2;
        UInt16 one = 1;

        Byte[] audioFormat = BitConverter.GetBytes(one);
        stream.Write(audioFormat, 0, 2);

        Byte[] numChannels = BitConverter.GetBytes(channels);
        stream.Write(numChannels, 0, 2);

        Byte[] sampleRate = BitConverter.GetBytes(hz);
        stream.Write(sampleRate, 0, 4);

        Byte[] byteRate = BitConverter.GetBytes(hz * channels * 2); // sampleRate * bytesPerSample*number of channels, here 44100*2*2
        stream.Write(byteRate, 0, 4);

        UInt16 blockAlign = (ushort)(channels * 2);
        stream.Write(BitConverter.GetBytes(blockAlign), 0, 2);

        UInt16 bps = 16;
        Byte[] bitsPerSample = BitConverter.GetBytes(bps);
        stream.Write(bitsPerSample, 0, 2);

        Byte[] datastring = System.Text.Encoding.UTF8.GetBytes("data");
        stream.Write(datastring, 0, 4);

        Byte[] subChunk2 = BitConverter.GetBytes(samples * channels * 2);
        stream.Write(subChunk2, 0, 4);

    }
    #endregion
}

这里接收到消息时,是使用的其他线程,所以需要转换到主线程才能使用Unity的API,不然就会报错,我这里可以将传入的数据放在本地,也在内存中使用并播放(这里传输过来的数据是pcm,如果要在Unity中直接使用,需要写入WAV头才行)。语音合成的数据是多段传输的,所以需要整合在一起。

六、项目位置
链接:https://pan.baidu.com/s/1X83tzFAaRLFvPeleT2Pm0A
提取码:a1oj
unity接入讯飞AIUI(Windows SDK),unity,windows,语音识别,ai
只需要将SDK中的AIUI文件放在SteamingAssets文件夹中和替换aiui.dll文件即可。文章来源地址https://www.toymoban.com/news/detail-716928.html

到了这里,关于unity接入讯飞AIUI(Windows SDK)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java中实现在线语音识别(科大讯飞免费的SKD)、SDK下载和IDEA项目搭建、成功运行【完整代码】

    科大讯飞官网:https://www.xfyun.cn/ 首先登陆讯飞开放平台:https://passport.xfyun.cn/login,微信扫码关注登录 注册新账号 登陆后界面后,进入产品服务–实时语音转写栏目 点击个人免费套餐,下面的立即领取,它会提醒我们去实名认证 实名认证一下 提交完认证之后 可以看到认证

    2023年04月21日
    浏览(50)
  • 【第三方SDK接入汇总】Unity接入VuforiaAR(图片识别)

    目录 一.注册Vuforia账号 二.获取许可秘钥 三.获取Vuforia的SDK导入unity 四.搭建创建AR场景 五.打包到手机 注册地址:Engine Developer Portal 申请地址:https://developer.vuforia.com/vui/develop/licenses 方式一: 官网下载 下载地址:SDK Download | Engine Developer Portal  下载后把package包导入unity即可。

    2024年04月08日
    浏览(53)
  • 科大讯飞语音SDK下载及测试

    一、SDK 下载 进入讯飞开发平台官网http://www.xfyun.cn/,右上角进行注册登录,登录后点击进入SDK下载。            2.创建新应用               3.填入相关信息         4.创建完后提交后回到SDK下载页面,刷新页面,应用选择前面创建的应用,平台选择Linux,SDK选择

    2024年02月08日
    浏览(74)
  • vue使用科大讯飞的语音识别(语音听写)

    使用的是封装好的插件:voice-input-button2 真的很好使很好使 1、先使用npm下载插件 npm i voice-input-button2 -save -dev 2、在main.js中引入 import voiceInputButton from \\\'voice-input-button2\\\' Vue.use(voiceInputButton, { appId: \\\'xxx\\\', // 您申请的语音听写服务应用的ID apiKey: \\\'xxxxxxxxxxxxxxxxxxxxxxxxx\\\', // 您开通的语音

    2024年01月19日
    浏览(50)
  • 讯飞离线语音合成新版(Aikit)-android sdk合成 demo(Java版本)

    前言:科大讯飞的新版离线语音合成,由于官网demo是kt语言开发的,咱也看不懂kt,搜遍了全网也没看到一个java版的新版离线语音demo,现记录下,留给有缘人参考!!!!!毕竟咱在这上面遇到了不少的坑。如果能留言指正,那就更好了。 ​官网注册账号---》实名认证---》

    2024年02月11日
    浏览(63)
  • 科大讯飞语音离线命令识别

    准备工作 注册讯飞账号,做相关的认证,只有认证通过才能下载部分免费的资源。官网地址:https://console.xfyun.cn/ 创建我的应用后再在离线命令识别 操作前先查看一下这个官方文档Android 语音识别(Recognizer) | 讯飞开放平台文档中心 (xfyun.cn) 1、必要文件包复制到自己的项目目录

    2023年04月08日
    浏览(60)
  • python实现语音识别(讯飞开放平台)

    1.注册讯飞平台账号讯飞官网网址。 2.打开讯飞控制台。 3.点击“创建新应用”。 4.输入“应用名称”,“应用分类”,“应用功能描述”(这些都是自定义的)。 5.创建成功后,记住“APPID”,“APISecret”,“APIKey”这三个关键。 如果有没有的依赖库,通过pip在Anaconda的配置

    2024年02月13日
    浏览(60)
  • 技术解读 | 科大讯飞语音技术最新进展之二:语音识别与语音合成

    这一篇内容将围绕语音识别与合成方向,继续为大家带来相关技术解析。 “风物长宜放眼量”。面向人机交互更加自然流畅的未来,智能语音技术进展如何?该走向何方? 以下内容根据讯飞研究院杰出科学家潘嘉在NCMMSC 2022上的主题演讲《科大讯飞语音技术前沿进展》整理。

    2024年02月07日
    浏览(61)
  • OpenAI开源语音识别模型Whisper在Windows系统的安装详细过程

    Python的安装很简单,点击这里进行下载。 安装完成之后,输入python -V可以看到版本信息,说明已经安装成功了。 如果输入python -V命令没有看到上面的这样的信息,要么是安装失败,要么是安装好之后没有自动配置环境变量,如何配置环境变量可以从网上搜索。 Python的具体安

    2024年02月08日
    浏览(60)
  • GEC6818科大讯飞离线语音识别

    在下载SDK时需要注意选择Linux的版本!! 在官网下载离线语音的包,解压后可以得到下面的一些文件夹: 解压后你需要知道自己命令放在下面的文件夹中 关于Make file文件: 关于asr_offline_sample.c文件: asr_offline_sample.c 文件是我们更改为自己的逻辑的文件,但是也不需要都了解

    2024年01月17日
    浏览(56)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包