提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

声纹识别(Voiceprint Recognition),是一项提取说话人声音特征和说话内容信息,自动核验说话人身份的技术。可以将说话人声纹信息与库中的已知用户声纹进行1:1比对验证和1:N的检索,当声纹匹配时即为验证/检索成功。

一、接口流程是什么?

科大讯飞控制台地址:https://passport.xfyun.cn/login
1.文档地址:https://www.xfyun.cn/doc/voiceservice/isv/API.html#%E6%8E%A5%E5%8F%A3%E8%B0%83%E7%94%A8%E6%B5%81%E7%A8%8B

2.要求
1、创建声纹特征库(必须)
2、添加音频特征(必须)
3、特征比对1:1(必须)
4、特征比对1:N(必须)
5、查询特征列表(非必须)
6、更新音频特征(非必须)
7、删除指定特征(非必须)
8、删除声纹特征库(非必须)
在这里插入图片描述
在这里插入图片描述

二、使用步骤

1.构建URL

using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using UnityEngine;

public class GenerateRequestUrl
{
    public const string APPID = "xxxx";
    public const string APISECRET = "xxxxxx";
    public const string APIKEY = "xxxxxx";

    public string AppId { get { return APPID; } }


    // 生成SHA256哈希并使用Base64编码  
    public string Sha256Base64(string data)
    {
        using (SHA256 sha256Hash = SHA256.Create())
        {
            byte[] bytes = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(data));
            return Convert.ToBase64String(bytes);
        }
    }

    // 解析URL以获取主机和路径  
    public void ParseUrl(string requestUrl, out string host, out string path)
    {
        int startIndex = requestUrl.IndexOf("://", StringComparison.Ordinal);
        if (startIndex == -1)
            throw new ArgumentException("Invalid request URL format.", nameof(requestUrl));

        string afterProtocol = requestUrl.Substring(startIndex + 3);
        int endIndex = afterProtocol.IndexOf('/', StringComparison.Ordinal);

        if (endIndex <= 0)
            throw new Exception("Invalid request URL: " + requestUrl);

        host = afterProtocol.Substring(0, endIndex);
        path = afterProtocol.Substring(endIndex);
    }

    // 组装WebSocket授权请求URL  
    public string AssembleWsAuthUrl(string requestUrl, string apiKey, string apiSecret, string method = "POST")
    {
        string host, path;
        ParseUrl(requestUrl, out host, out path);

        DateTime now = DateTime.UtcNow;
        string date = now.ToString("r"); // RFC1123 format, close enough to what format_date_time does in Python/WSGI  

        string signatureOrigin = $"host: {host}\ndate: {date}\n{method} {path} HTTP/1.1";
        byte[] secretBytes = Encoding.UTF8.GetBytes(apiSecret);
        byte[] signatureOriginBytes = Encoding.UTF8.GetBytes(signatureOrigin);

        using (HMACSHA256 hmac = new HMACSHA256(secretBytes))
        {
            byte[] signatureBytes = hmac.ComputeHash(signatureOriginBytes);
            string signatureSha = Convert.ToBase64String(signatureBytes);

            string authorizationOrigin = $"api_key=\"{apiKey}\", algorithm=\"hmac-sha256\", headers=\"host date request-line\", signature=\"{signatureSha}\"";
            string authorization = Convert.ToBase64String(Encoding.UTF8.GetBytes(authorizationOrigin));

            // Construct the final request URL with authorization parameters  
            string encodedAuthBase = WebUtility.UrlEncode(authorization);
            string encodedHost = WebUtility.UrlEncode(host);
            string encodedDate = WebUtility.UrlEncode(date);

            string finalUrl = $"{requestUrl}?authorization={encodedAuthBase}&host={encodedHost}&date={encodedDate}";
            return finalUrl;
        }
    }


    public string BuildRequestUrl(string requestUrl, string apiKey,string apiSecret)
    {
        try
        {
            // Replace ws or wss schema with http or https  
            string httpRequestUrl = requestUrl.Replace("ws://", "http://").Replace("wss://", "https://");
            Uri url = new Uri(httpRequestUrl);

            // Get current date and format it for HTTP header  
            string date = DateTime.UtcNow.ToString("r", CultureInfo.InvariantCulture); // ISO 8601 format  

            string host = url.Host;
            // Uncomment the following block if you need to include the port in the host header  
            // if (!((url.Scheme == "http" && url.Port == 80) || (url.Scheme == "https" && url.Port == 443)))  
            // {  
            //     host += $":{url.Port}";  
            // }  

            StringBuilder  sb = new StringBuilder();
            sb.Append("host: ").AppendLine(host);
            sb.Append("date: ").AppendLine(date);
            sb.Append("POST ").Append(url.AbsolutePath).Append(" HTTP/1.1");

            // Compute the HMACSHA256 signature  
            string sha = string.Empty;
            using (HMACSHA256 hmac = new HMACSHA256(Encoding.UTF8.GetBytes(apiSecret)))
            {
                byte[] signatureBytes = hmac.ComputeHash(Encoding.UTF8.GetBytes(sb.ToString()));
                 sha = Convert.ToBase64String(signatureBytes);
            }

            // Prepare the authorization header  
            string authorization = $"api_key=\"{apiKey}\", algorithm=\"hmac-sha256\", headers=\"host date request-line\", signature=\"{sha}\"";
            string authBase = Convert.ToBase64String(Encoding.UTF8.GetBytes(authorization));

            // Construct the final request URL with authorization parameters  
            string encodedAuthBase = WebUtility.UrlEncode(authBase);
            string encodedHost = WebUtility.UrlEncode(host);
            string encodedDate = WebUtility.UrlEncode(date);

            string finalUrl = $"{requestUrl}?authorization={encodedAuthBase}&host={encodedHost}&date={encodedDate}";
            Debug.Log($"finaUrl:{finalUrl}");
            return finalUrl;
        }
        catch (Exception ex)
        {
            throw new Exception("Error assembling request URL: " + ex.Message);
        }
    }


    /// <summary>
    /// 获取接口鉴权请求地址
    /// </summary>
    public string GetauthorizationUr(GenerateRequestUrl genReqUrl)
    {
        string apiKey = APIKEY;
        string apiSecret = APISECRET;
        string requestUrl = "https://api.xf-yun.com/v1/private/s782b4996";
        string authUrl = genReqUrl.AssembleWsAuthUrl(requestUrl, apiKey, apiSecret);
        return (authUrl);
    }
}

2.创建声纹特征库

using Newtonsoft.Json;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;

/// <summary>
/// 创建声纹特征库
/// </summary>
public class CreateGroup : MonoBehaviour
{
    private static string currentState = string.Empty;//当前识别状态
    public static string CurrentState { get => currentState; set => currentState = value; }


    private IEnumerator GenerateCreateGroup()
    {
        GenerateRequestUrl generateRequestUrl = new GenerateRequestUrl();
        CurrentState = string.Empty;
        string url = generateRequestUrl.GetauthorizationUr(generateRequestUrl);//构建URL
        Debug.Log($"url:{url}");
        var param = new JsonParse
        {
            header = new Header()
            {
                app_id = "xxxx",
                status = 3
            },
            parameter = new Parameter()
            {
                s782b4996 = new S782b4996()
                {
                    func = "createGroup",
                    groupId = "iFLYTEK_examples_groupId",
                    groupName= "iFLYTEK_examples_groupName",
                    groupInfo= "iFLYTEK_examples_groupInfo",
                    createGroupRes=new CreateGroupRes()
                    {
                       encoding = "utf8",
                       compress="raw",
                       format="json"
                    }              
               }       
             }

        };
        string paramsJson = JsonConvert.SerializeObject(param); // 假设这是你的参数构建方法,需要你自己实现。  
        byte[] bodyRaw = Encoding.UTF8.GetBytes(paramsJson);
        using (UnityWebRequest webRequest = UnityWebRequest.Post(url, paramsJson))
        {
            using (var uh = new UploadHandlerRaw(bodyRaw))
            {
                webRequest.uploadHandler.Dispose();
                webRequest.uploadHandler = uh;
                //webRequest.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
                webRequest.SetRequestHeader("Content-Type", "application/json");
                webRequest.SetRequestHeader("Accept", "*/*");
                yield return webRequest.SendWebRequest();
            }
            while (!webRequest.isDone) { yield return null; }
            if (webRequest.result == UnityWebRequest.Result.Success)
            {
                try
                {
                    // 在这里处理你的返回数据,比如解析JSON等。  
                    // 注意:由于这个方法是Coroutine,你不能直接从DoRequest返回结果。  
                    // 你可能需要调用另一个方法来处理这个返回的数据。  
                    string responseText = webRequest.downloadHandler.text;
                    Logging.Info($"Response: {responseText}");
                    var result = JsonConvert.DeserializeObject<PlayParamerter>(responseText);
                    string txt = result.payload.createGroupRes.text;
                    Logging.Info($"txt: {txt}");
                    byte[] decodedBytes = Convert.FromBase64String(txt);
                    string textBase64Decode = Encoding.UTF8.GetString(decodedBytes);

                    Debug.Log($"textBase64Decode:{textBase64Decode}");
                    if (textBase64Decode.Equals("success"))
                    {
                        print("创建库成功");
                    }
                    else
                    {
                        print("创建库失败");
                    }
                }
                catch (Exception ex)
                {
                    webRequest.Abort();
                    webRequest.Dispose();
                    Logging.Error($"创建声纹特征库失败:{ex.Message}");
                }
            }
            else if (webRequest.result == UnityWebRequest.Result.ConnectionError || webRequest.result == UnityWebRequest.Result.ProtocolError)
            {
                webRequest.Dispose();
            }
        }
    }



    [SerializeField]
    //Json解析
    public class JsonParse
    {
        public Header header { get; set;}

        public Parameter parameter { get; set; }

    }



    [SerializeField]
    public class  Parameter      
   {
        public S782b4996 s782b4996 { get; set; }
    }


    [SerializeField]
    public class Header
    {
        public string app_id { get; set; }
        public int status { get; set; }
    }

    [SerializeField]
    public class S782b4996
    {
        public string func { get; set; }

        public string groupId { get; set; }

        public string groupName { get; set; }

        public string groupInfo { get; set; }

        //根据model的取值不同,名字有所变动。
        public CreateGroupRes createGroupRes { get; set; }
    }

    [SerializeField]
    public class CreateGroupRes
    {
        public string compress { get; set; }
        public string encoding { get; set; }
        public string format { get; set; }

    }


    [SerializeField]
    public class Header2 
    {
        public int code { get; set; }

        public string message { get; set; }

        public string sid { get; set; }
    }


    [SerializeField]
    public class CreateGroupRes2
    {
        public string text { get; set; }
    }

    [SerializeField]
    public class Payload2 
    {
        public CreateGroupRes2 createGroupRes;
    }

    [SerializeField]
    public class PlayParamerter
    {
        public Header2 header { get; set; }
        public  Payload2  payload { get; set; }
    }


}

2.添加音频特征

代码如下(示例):

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Unity.Collections;
using UnityEngine;
using UnityEngine.Networking;

/// <summary>
/// 创建声纹特征库
/// </summary>
public class CreateFeature : MonoBehaviour
{
    private IEnumerator GenerateCreateFeature()
    {
        GenerateRequestUrl generateRequestUrl = new GenerateRequestUrl();
        // 音频文件路径
        string audioFilePath = Application.streamingAssetsPath + "/music/dd.mp3";
        // 读取音频文件为字节数组
        byte[] audioBytes = File.ReadAllBytes(audioFilePath);
        // 对音频字节数组进行Base64编码
        string base64StringAudio = Convert.ToBase64String(audioBytes);

        string url = generateRequestUrl.GetauthorizationUr(generateRequestUrl);//构建URL
        Debug.Log($"url:{url}");
        var param = new JsonParse
        {
            header = new Header()
            {
                app_id = "xxxx",
                status = 3
            },
            parameter = new Parameter()
            {
                s782b4996 = new S782b4996()
                {
                    func = "createFeature",
                    groupId = "iFLYTEK_examples_groupId",
                    featureId= "iFLYTEK_examples_featureId",
                    featureInfo = "iFLYTEK_examples_featureInfo",
                    createFeatureRes = new CreateFeatureRes()
                    {
                       encoding = "utf8",
                       compress="raw",
                       format="json"
                    }              
               }       
             },

            payload = new PayLoad()
            {
                resource = new Resource()
                {
                    encoding = "lame",
                    sample_rate = 16000,
                    channels=1,
                    bit_depth=16,
                    status=3,
                    audio= base64StringAudio
                }
            }
        };
        string paramsJson = JsonConvert.SerializeObject(param); // 假设这是你的参数构建方法,需要你自己实现。
        byte[] bodyRaw = Encoding.UTF8.GetBytes(paramsJson);
        using (UnityWebRequest webRequest =UnityWebRequest.Post(url, paramsJson))
        {             
            using (var uh = new UploadHandlerRaw(bodyRaw))
            {
                webRequest.uploadHandler.Dispose();
                webRequest.uploadHandler = uh;
                //webRequest.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
                webRequest.SetRequestHeader("Content-Type", "application/json");
                webRequest.SetRequestHeader("Accept", "*/*");
                yield return webRequest.SendWebRequest();
            }             
            while (!webRequest.isDone) { yield return null; }
            if (webRequest.result == UnityWebRequest.Result.Success)
            {
                try
                {
                    // 在这里处理你的返回数据,比如解析JSON等。  
                    // 注意:由于这个方法是Coroutine,你不能直接从DoRequest返回结果。  
                    // 你可能需要调用另一个方法来处理这个返回的数据。  
                    string responseText = webRequest.downloadHandler.text;
                    Debug.Log($"Response: {responseText}");
                    var result = JsonConvert.DeserializeObject<PlayParamerter>(responseText);
                    string txt = result.payload.createFeatureRes.text;

                    byte[] decodedBytes = Convert.FromBase64String(txt);
                    string textBase64Decode = Encoding.UTF8.GetString(decodedBytes);
                    if (result.header.message.Equals("success"))
                    {
                        
                        //识别成功
                    }
                    else
                    {
     
                        //识别失败
                    }
                    Logging.Debug($"textBase64Decode:{textBase64Decode}");
                }
                catch (Exception ex)
                {
                    Logging.Error($"创建声纹特征库失败:{ex.Message}");
                }
            }
            else if (webRequest.result == UnityWebRequest.Result.ConnectionError || webRequest.result == UnityWebRequest.Result.ProtocolError)
            {
                webRequest.Dispose();
            }        
        }   
    }



    [SerializeField]
    //Json解析
    public class JsonParse
    {
        public Header header { get; set;}

        public Parameter parameter { get; set; }


        public PayLoad payload { get; set; }

    }

    [SerializeField]
    public class  Parameter      
   {
        public S782b4996 s782b4996 { get; set; }
    }


    [SerializeField]
    public class Header
    {
        public string app_id { get; set; }
        public int status { get; set; }
    }

    [SerializeField]
    public class S782b4996
    {
        public string func { get; set; }

        public string groupId { get; set; }

        public string featureId { get; set; }

        public string featureInfo { get; set; }

        //根据model的取值不同,名字有所变动。
        public CreateFeatureRes createFeatureRes { get; set; }
    }

    [SerializeField]
    public class CreateFeatureRes
    {
        public string compress { get; set; }
        public string encoding { get; set; }
        public string format { get; set; }

    }


    [SerializeField]
    public class PayLoad
    {
        public Resource resource { get; set; }
    }


    [SerializeField]
    public class Resource 
    {
        public string encoding { get; set; }

        public int sample_rate { get; set; }

        public int channels { get; set; }

        public int bit_depth { get; set; }

        public int status { get; set; }

        public string audio { get; set; }


    }


    [SerializeField]
    public class Header2 
    {
        public int code { get; set; }

        public string message { get; set; }

        public string sid { get; set; }
    }


    [SerializeField]
    public class CreateFeatureRes2
    {
        public string text { get; set; }
    }

    [SerializeField]
    public class Payload2 
    {
        public CreateFeatureRes2 createFeatureRes;
    }

    [SerializeField]
    public class PlayParamerter
    {
        public Header2 header { get; set; }
        public  Payload2  payload { get; set; }
    }


}

3.特征比对1:1

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;

/// <summary>
///特征比对1:1
/// </summary>
public class SearchOneFeature :  MonoBehaviour
{
    /// <summary>
    /// 删除创建声纹特征库
    /// </summary>
    public void StartSearchOneFeature()
    {
        StartCoroutine("GenerateSearchOneFeature");
    }

    private IEnumerator GenerateSearchOneFeature()
    {
        GenerateRequestUrl generateRequestUrl = new GenerateRequestUrl();
        // 音频文件路径
        string audioFilePath = Application.streamingAssetsPath + "/music/dd.mp3";
        // 读取音频文件为字节数组
        byte[] audioBytes = File.ReadAllBytes(audioFilePath);
        // 对音频字节数组进行Base64编码
        string base64String = Convert.ToBase64String(audioBytes);
        string url = generateRequestUrl.GetauthorizationUr(generateRequestUrl);//构建URL
        Debug.Log($"url:{url}");
        var param = new JsonParse
        {
            header = new Header()
            {
                app_id = "xxxx",
                status = 3
            },
            parameter = new Parameter()
            {
                s782b4996 = new S782b4996()
                {
                    func = "searchScoreFea",
                    groupId = "iFLYTEK_examples_groupId",
                    dstFeatureId= "iFLYTEK_examples_featureId",
                    searchScoreFeaRes = new SearchScoreFeaRes()
                    {
                       encoding = "utf8",
                       compress="raw",
                       format="json"
                    }              
               }       
             },

            payload = new PayLoad()
            {
                resource = new Resource()
                {
                    encoding = "lame",
                    sample_rate = 16000,
                    channels=1,
                    bit_depth=16,
                    status=3,
                    audio= base64String
                }
            }
        };
        string paramsJson = JsonConvert.SerializeObject(param); // 假设这是你的参数构建方法,需要你自己实现。  
        byte[] bodyRaw = Encoding.UTF8.GetBytes(paramsJson);
        using (UnityWebRequest webRequest = new UnityWebRequest(url, "POST"))
        {
            webRequest.uploadHandler = (UploadHandler)new UploadHandlerRaw(bodyRaw);
            webRequest.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
            webRequest.SetRequestHeader("Content-Type", "application/json");
            webRequest.SetRequestHeader("Accept", "*/*");
            yield return webRequest.SendWebRequest();
            if (webRequest.result != UnityWebRequest.Result.ConnectionError || webRequest.result != UnityWebRequest.Result.ProtocolError)
            {
                try
                {
                    // 在这里处理你的返回数据,比如解析JSON等。  
                    // 注意:由于这个方法是Coroutine,你不能直接从DoRequest返回结果。  
                    // 你可能需要调用另一个方法来处理这个返回的数据。  
                    string responseText = webRequest.downloadHandler.text;
                    ConfigInfo configInfo = new ConfigInfo();
                    Debug.Log($"Response: {responseText}");
                    if (!string.IsNullOrEmpty(responseText))
                    {
                        var result = JsonConvert.DeserializeObject<PlayParamerter>(responseText);
                        string txt = result.payload.searchScoreFeaRes.text;
                        print($"result.header.code:{result.header.code}");
                        if (result.header.code.Equals(0))
                        {
                            byte[] decodedBytes = Convert.FromBase64String(txt);
                            string textBase64Decode = Encoding.UTF8.GetString(decodedBytes);
                            Logging.Debug($"textBase64Decode:{textBase64Decode}");
                            var result2 = JsonConvert.DeserializeObject<JsonTxt>(textBase64Decode);
                            if (result2.score >= 0.7)//权重值
                            {
                                Debug.Log("识别成功");
                            }
                            else
                            {
                                Debug.Log("识别失败");
                            }
                        }
                        else
                        {
                            Debug.Log("识别失败");
                        }
                    }
                    else 
                    {

                        Debug.Log("识别失败");
                    }
                }
                catch (Exception ex)
                {
                    Debug.Log("识别失败");               
                }
            }
            else
            {
                Debug.Log("Received: " + webRequest.downloadHandler.text);
               
            }
            webRequest.Dispose();
        }
    }



    [SerializeField]
    //Json解析
    public class JsonParse
    {
        public Header header { get; set;}

        public Parameter parameter { get; set; }


        public PayLoad payload { get; set; }

    }



    [SerializeField]
    public class  Parameter      
   {
        public S782b4996 s782b4996 { get; set; }
    }


    [SerializeField]
    public class Header
    {
        public string app_id { get; set; }
        public int status { get; set; }
    }

    [SerializeField]
    public class S782b4996
    {
        public string func { get; set; }

        public string groupId { get; set; }

        public string dstFeatureId { get; set; }


        //根据model的取值不同,名字有所变动。
        public SearchScoreFeaRes searchScoreFeaRes { get; set; }
    }

    [SerializeField]
    public class SearchScoreFeaRes
    {
        public string compress { get; set; }
        public string encoding { get; set; }
        public string format { get; set; }

    }


    [SerializeField]
    public class PayLoad
    {
        public Resource resource { get; set; }
    }


    [SerializeField]
    public class Resource 
    {
        public string encoding { get; set; }

        public int sample_rate { get; set; }

        public int channels { get; set; }

        public int bit_depth { get; set; }

        public int status { get; set; }

        public string audio { get; set; }


    }


    [SerializeField]
    public class Header2 
    {
        public int code { get; set; }

        public string message { get; set; }

        public string sid { get; set; }
    }


    [SerializeField]
    public class SearchScoreFeaRes2
    {
        public string text { get; set; }
    }

    [SerializeField]
    public class Payload2 
    {
        public SearchScoreFeaRes2 searchScoreFeaRes;
    }

    [SerializeField]
    public class PlayParamerter
    {
        public Header2 header { get; set; }
        public  Payload2  payload { get; set; }
    }


    [SerializeField]
    public class JsonTxt
    {
        public float  score { get; set; }

        public string featureInfo { get; set; }

        public string featureId { get; set; }
    }

}

总结

以上就是今天要讲的内容,本文仅仅简单介绍了科大讯飞声纹识别的使用,而科大讯飞提供了大量能使我们快速便捷地处理数据的接口,谢谢大家的观看,我们下期再见。

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐