using NAudio.Wave; using System; using System.Collections; using System.IO; using System.Text; using System.Text.RegularExpressions; using UnityEngine; using UnityEngine.Networking; public class ZXKTTS : TTS { public int maxRetries = 3; public string authorizationToken = "Bearer LB-krrBLcSkpWCqL8KmwU6ryg5Y4oNKKJcH26ZqSkgghsNLu7ea2EZv"; public string role = "longsanshu"; private UnityWebRequest currentRequest; private bool coroutineRunning = false; public override void StartSpeak(string _msg, Action _callback) { base.StartSpeak(_msg, _callback); StartCoroutine(CallAudioAPI(_msg, _callback)); } IEnumerator CallAudioAPI(string input,Action callBack) { CleanupCurrentRequest(); coroutineRunning = true; currentRequest = null; bool success = false; int retryCount = 0; // 创建请求体数据 StringBuilder requestData = new(); requestData.Append("{"); requestData.Append("\"appId\": \""+ Guid.NewGuid().ToString() +"\","); requestData.Append("\"input\": \"" + Regex.Replace(input, @"[\p{P}\p{S}]", "") + "\","); requestData.Append("\"ttsConfig\":"); requestData.Append("{\"type\":\" model \","); requestData.Append("\"model\":\"cosyvoice-v2\","); requestData.Append("\"voice\":\""+ role +"\"}}"); Debug.Log(requestData.ToString()); while (retryCount < maxRetries && !success) { currentRequest = new(m_PostURL, "POST"); currentRequest.timeout = 15; currentRequest.SetRequestHeader("Authorization", authorizationToken); currentRequest.SetRequestHeader("Content-Type", "application/json"); byte[] data = Encoding.UTF8.GetBytes(requestData.ToString()); currentRequest.uploadHandler = new UploadHandlerRaw(data); currentRequest.downloadHandler = new DownloadHandlerBuffer(); yield return currentRequest.SendWebRequest(); if (currentRequest.responseCode == 200 && coroutineRunning) { callBack?.Invoke(ConvertMp3ToAudioClip(currentRequest.downloadHandler.data)); success = true; } else if(coroutineRunning) { retryCount++; if (retryCount < maxRetries) { Debug.Log("正在重试,第 " + (retryCount + 1) + " 次..."); yield return new WaitForSeconds(1f); // 等待 1 秒后重试 } } // 清理当前请求 CleanupCurrentRequest(); } if (!success && coroutineRunning) { callBack?.Invoke(null); } //结束计时 stopwatch.Stop(); // 标记协程已结束 coroutineRunning = false; } AudioClip ConvertMp3ToAudioClip(byte[] mp3Data) { // 创建一个内存流来存储MP3数据 using (MemoryStream ms = new MemoryStream(mp3Data)) using (Mp3FileReader mp3Reader = new Mp3FileReader(ms)) using (WaveStream pcmStream = WaveFormatConversionStream.CreatePcmStream(mp3Reader)) { // 计算样本数量,假设是16位音频 int sampleCount = (int)(pcmStream.Length / 2); float[] samples = new float[sampleCount]; WaveBuffer waveBuffer = new WaveBuffer((int)pcmStream.Length); int bytesRead = pcmStream.Read(waveBuffer.ByteBuffer, 0, (int)pcmStream.Length); // 将短整型的PCM数据转换为-1到1之间的浮点数 for (int i = 0; i < sampleCount; i++) { short sample = (short)(waveBuffer.ShortBuffer[i]); samples[i] = sample / 32768f; } // 创建AudioClip对象 AudioClip audioClip = AudioClip.Create("DecodedAudio", sampleCount, pcmStream.WaveFormat.Channels, pcmStream.WaveFormat.SampleRate, false); audioClip.SetData(samples, 0); return audioClip; } } // 清理当前请求的方法 private void CleanupCurrentRequest() { if (currentRequest != null) { Debug.Log("CleanupCurrentRequest"); currentRequest.uploadHandler?.Dispose(); currentRequest.downloadHandler?.Dispose(); currentRequest.Dispose(); currentRequest = null; } } }