<think>我们需要在调试台中显示发送的音频帧和服务器返回的结果信息。这可以通过在发送和接收时添加Debug.Log来实现。但是要注意,发送的音频帧数据量可能很大,所以我们只记录关键信息(如帧大小、状态等)而不是完整的音频数据。
修改点:
1. 在发送初始化帧、音频帧和结束帧时,记录发送的JSON内容(对于音频帧,由于数据量大,只记录帧大小和状态)。
2. 在收到服务器消息时,记录完整的JSON响应(包括状态、错误信息等)。
但是注意:音频帧的base64数据很长,打印整个字符串会导致性能问题,所以只打印摘要信息。
具体修改:
- 在SendInitFrame和SendEndFrame中,打印完整的JSON(因为数据量小)。
- 在SendAudioFrame中,打印摘要信息(如帧大小、状态和sid)。
- 在OnMessage回调中,打印完整的服务器响应(因为我们需要查看status=2的结果)。
另外,我们可以将服务器返回的每个消息(包括中间状态)都显示在UI的resultText中,但考虑到中间状态消息较多,我们只将最终结果显示在UI上,而中间状态和错误信息可以显示在调试日志中。
同时,为了避免日志过多,我们可以提供一个开关来控制是否显示详细日志。
我们添加一个bool变量来控制详细日志:
private bool verboseLogging = true;
然后,在关键点添加日志输出。
代码修改如下:</think>以下是增强调试功能的解决方案,增加发送和接收数据的详细显示,便于排查问题:
```csharp
using UnityEngine;
using System;
using System.Text;
using System.Collections;
using System.Security.Cryptography;
using NativeWebSocket;
using System.Globalization;
using UnityEngine.UI;
using System.Threading.Tasks;
using System.IO;
public class XunfeiISEController : MonoBehaviour
{
// 配置参数
const string APP_ID = "d11f22d5";
const string API_KEY = "6c1a2fc3bac9767a92aeb80098c89b61";
const string API_SECRET = "YjJjZmM1MjI3N2ZjMmFiZmQ2Y2E2NWI1";
const string HOST = "ise-api.xfyun.cn";
const string PATH = "/v2/open-ise";
// UI元素
public Button startButton;
public Button stopButton;
public Text statusText;
public Text resultText;
public Text progressText;
public Text debugText; // 新增:调试信息显示
public ScrollRect debugScroll; // 新增:调试信息滚动区域
WebSocket websocket;
bool isConnected = false;
private AudioClip recordingClip;
private bool isRecording = false;
private int recordingPosition = 0;
private string sid = null;
private float lastSendTime = 0f;
private const float SEND_INTERVAL = 0.1f;
private int totalFramesSent = 0;
private int totalFramesRecorded = 0;
private bool waitingForResult = false;
private bool verboseLogging = true; // 控制详细日志
// 定义JSON解析结构
[Serializable]
public class ISEResponse
{
public int code;
public string message;
public ISEData data;
}
[Serializable]
public class ISEData
{
public string sid;
public int status;
public string data;
}
void Start()
{
// 初始化UI状态
UpdateUIState(ConnectionState.Disconnected);
// 绑定按钮事件
startButton.onClick.AddListener(StartEvaluation);
stopButton.onClick.AddListener(StopEvaluation);
// 初始禁用停止按钮
stopButton.interactable = false;
// 初始化调试文本
debugText.text = "调试信息将显示在此处...\n";
}
// 开始评测流程
public async void StartEvaluation()
{
if (isConnected || isRecording) return;
try
{
// 重置状态
totalFramesSent = 0;
totalFramesRecorded = 0;
resultText.text = "";
progressText.text = "准备开始...";
waitingForResult = false;
debugText.text = "调试信息:\n"; // 清空调试信息
AddDebugLog("开始评测流程...");
UpdateUIState(ConnectionState.Connecting);
// 1. 生成鉴权URL
string authUrl = GenerateAuthUrl();
AddDebugLog($"生成鉴权URL: {authUrl}");
// 2. 创建WebSocket连接
websocket = new WebSocket(authUrl);
// 设置事件回调
websocket.OnOpen += () => {
AddDebugLog("WebSocket连接成功!");
isConnected = true;
UpdateUIState(ConnectionState.Connected);
SendInitFrame();
};
websocket.OnError += (err) => {
AddDebugLog($"WebSocket错误: {err}", true);
isConnected = false;
UpdateUIState(ConnectionState.Error);
resultText.text = $"连接错误: {err}";
};
websocket.OnClose += (code) => {
AddDebugLog($"连接关闭,代码: {code}");
isConnected = false;
if (!waitingForResult)
{
UpdateUIState(ConnectionState.Disconnected);
}
};
websocket.OnMessage += (data) => {
string json = Encoding.UTF8.GetString(data);
AddDebugLog($"收到服务器响应:\n{FormatJson(json)}");
// 解析结果
try {
ISEResponse response = JsonUtility.FromJson<ISEResponse>(json);
// 保存会话ID
if (response.data != null && !string.IsNullOrEmpty(response.data.sid)) {
sid = response.data.sid;
AddDebugLog($"会话ID: {sid}");
}
// 处理最终评测结果
if (response.data != null && response.data.status == 2) {
if (!string.IsNullOrEmpty(response.data.data)) {
// 解码Base64结果
byte[] resultBytes = Convert.FromBase64String(response.data.data);
string xmlResult = Encoding.UTF8.GetString(resultBytes);
AddDebugLog($"最终结果XML:\n{xmlResult}");
// 解析XML并显示结果
ParseResultXML(xmlResult);
// 评测完成后关闭连接
CloseConnection();
waitingForResult = false;
}
}
else if (response.code != 0) // 处理错误响应
{
AddDebugLog($"API错误: {response.code} - {response.message}", true);
resultText.text = $"错误: {response.code} - {response.message}";
CloseConnection();
}
else if (response.data != null)
{
AddDebugLog($"处理状态: {response.data.status}");
}
} catch (Exception e) {
AddDebugLog($"解析错误: {e.Message}", true);
resultText.text = $"解析错误: {e.Message}";
}
};
// 3. 使用await解决CS4014警告
AddDebugLog("正在连接WebSocket...");
await websocket.Connect();
}
catch (Exception e)
{
AddDebugLog($"连接失败: {e.Message}", true);
UpdateUIState(ConnectionState.Error);
resultText.text = $"连接失败: {e.Message}";
}
}
// 停止评测流程
public void StopEvaluation()
{
if (!isRecording) return;
AddDebugLog("停止评测...");
Microphone.End(null);
isRecording = false;
// 发送剩余音频数据
SendAudioFrames(true);
// 发送结束帧
SendEndFrame();
// 设置等待结果状态
waitingForResult = true;
UpdateUIState(ConnectionState.WaitingForResult);
progressText.text = "评测结束,等待结果...";
}
// 关闭WebSocket连接
private async void CloseConnection()
{
if (websocket != null && websocket.State == WebSocketState.Open)
{
try
{
AddDebugLog("正在关闭WebSocket连接...");
await websocket.Close();
}
catch (Exception e)
{
AddDebugLog($"关闭错误: {e.Message}", true);
}
finally
{
UpdateUIState(ConnectionState.Disconnected);
}
}
}
// 更新UI状态
private void UpdateUIState(ConnectionState state)
{
switch (state)
{
case ConnectionState.Disconnected:
statusText.text = "状态: 未连接";
statusText.color = Color.gray;
startButton.interactable = true;
stopButton.interactable = false;
break;
case ConnectionState.Connecting:
statusText.text = "状态: 连接中...";
statusText.color = Color.yellow;
startButton.interactable = false;
stopButton.interactable = false;
break;
case ConnectionState.Connected:
statusText.text = "状态: 已连接";
statusText.color = Color.green;
startButton.interactable = false;
stopButton.interactable = true;
break;
case ConnectionState.Recording:
statusText.text = "状态: 录音中...";
statusText.color = Color.cyan;
startButton.interactable = false;
stopButton.interactable = true;
break;
case ConnectionState.WaitingForResult:
statusText.text = "状态: 等待结果...";
statusText.color = Color.magenta;
startButton.interactable = false;
stopButton.interactable = false;
break;
case ConnectionState.Error:
statusText.text = "状态: 错误!";
statusText.color = Color.red;
startButton.interactable = true;
stopButton.interactable = false;
break;
}
}
// 生成鉴权URL
string GenerateAuthUrl()
{
// 获取RFC1123格式的GMT时间
string date = DateTime.UtcNow.ToString("r", CultureInfo.InvariantCulture);
// 构建签名字符串
string signatureOrigin = $"host: {HOST}\ndate: {date}\nGET {PATH} HTTP/1.1";
// HMAC-SHA256签名
byte[] signatureBytes = HMACSHA256(
Encoding.UTF8.GetBytes(API_SECRET),
Encoding.UTF8.GetBytes(signatureOrigin)
);
string signature = Convert.ToBase64String(signatureBytes);
// 构建授权参数
string authorization = $"api_key=\"{API_KEY}\", algorithm=\"hmac-sha256\", headers=\"host date request-line\", signature=\"{signature}\"";
// Base64编码授权参数
string encodedAuth = Convert.ToBase64String(Encoding.UTF8.GetBytes(authorization));
// 构造完整URL
return $"wss://{HOST}{PATH}?authorization={encodedAuth}&date={Uri.EscapeDataString(date)}&host={HOST}";
}
// 发送初始化帧
void SendInitFrame()
{
// 评测文本
string textContent = "When you don't know what you're doing, it's helpful to begin by learning about what you should not do.";
// 构建初始化帧数据结构
string initJson = @"{
""common"": {
""app_id"": """ + APP_ID + @"""
},
""business"": {
""aue"": ""raw"",
""auf"": ""audio/L16;rate=16000"",
""category"": ""read_sentence"",
""cmd"": ""ssb"",
""ent"": ""en_vip"",
""sub"": ""ise"",
""text"": """ + Convert.ToBase64String(Encoding.UTF8.GetBytes(textContent)) + @""",
""ttp_skip"": true
},
""data"": {
""status"": 0
}
}";
// 发送初始化帧
websocket.Send(Encoding.UTF8.GetBytes(initJson));
AddDebugLog($"发送初始化帧:\n{FormatJson(initJson)}");
// 开始录音
StartRecording();
}
// 开始录音
void StartRecording()
{
if (!isRecording)
{
AddDebugLog("开始录音...");
recordingClip = Microphone.Start(null, false, 30, 16000);
recordingPosition = 0;
isRecording = true;
lastSendTime = Time.time;
UpdateUIState(ConnectionState.Recording);
progressText.text = "录音中...";
}
}
// 发送音频数据帧
private void SendAudioFrames(bool sendAll = false)
{
if (recordingClip == null || string.IsNullOrEmpty(sid) || !isConnected)
return;
int currentPos = Microphone.GetPosition(null);
int sampleSize = currentPos - recordingPosition;
// 处理循环缓冲区
if (sampleSize < 0)
sampleSize += recordingClip.samples;
if (sampleSize > 0)
{
// 读取音频数据
float[] samples = new float[sampleSize];
recordingClip.GetData(samples, recordingPosition);
// 转换为16位PCM
byte[] pcmData = new byte[sampleSize * 2];
for (int i = 0; i < sampleSize; i++)
{
short value = (short)(samples[i] * 32767);
byte[] bytes = BitConverter.GetBytes(value);
pcmData[i * 2] = bytes[0];
pcmData[i * 2 + 1] = bytes[1];
}
// 计算帧大小
int frameSize = 16000 * 16 / 50;
frameSize = Math.Max(512, frameSize);
// 分帧发送
for (int offset = 0; offset < pcmData.Length; offset += frameSize)
{
int remaining = pcmData.Length - offset;
int sendSize = Math.Min(remaining, frameSize);
if (!sendAll && offset + frameSize > pcmData.Length)
break;
byte[] frame = new byte[sendSize];
Buffer.BlockCopy(pcmData, offset, frame, 0, sendSize);
SendAudioFrame(frame);
totalFramesSent++;
// 更新进度
progressText.text = $"已发送: {totalFramesSent}帧";
}
recordingPosition = currentPos;
totalFramesRecorded = sampleSize / (frameSize / 2);
}
}
// 发送单帧音频数据
private void SendAudioFrame(byte[] audioData)
{
if (websocket == null || !isConnected || string.IsNullOrEmpty(sid))
return;
string base64Audio = Convert.ToBase64String(audioData);
// 创建简化的调试信息(避免显示大量base64数据)
string debugInfo = @"{
""data"": {
""status"": 1,
""data"": ""[音频数据: " + audioData.Length + " 字节]""
},
""sid"": """ + sid + @"""
}";
// 实际发送的数据
string audioFrame = @"{
""data"": {
""status"": 1,
""data"": """ + base64Audio + @"""
},
""sid"": """ + sid + @"""
}";
websocket.Send(Encoding.UTF8.GetBytes(audioFrame));
if (verboseLogging)
{
AddDebugLog($"发送音频帧: {audioData.Length}字节\n{FormatJson(debugInfo)}");
}
else
{
AddDebugLog($"发送音频帧: {audioData.Length}字节");
}
}
// 发送结束帧
private void SendEndFrame()
{
if (websocket == null || !isConnected || string.IsNullOrEmpty(sid))
return;
string endFrame = @"{
""data"": {
""status"": 2,
""data"": """"
},
""sid"": """ + sid + @"""
}";
websocket.Send(Encoding.UTF8.GetBytes(endFrame));
AddDebugLog($"发送结束帧:\n{FormatJson(endFrame)}");
}
// 解析评测结果XML
private void ParseResultXML(string xml)
{
try
{
// 提取总分
if (xml.Contains("<total_score>"))
{
int start = xml.IndexOf("<total_score>") + "<total_score>".Length;
int end = xml.IndexOf("</total_score>");
if (start > 0 && end > start)
{
string scoreStr = xml.Substring(start, end - start);
if (float.TryParse(scoreStr, out float totalScore))
{
// 显示结果
resultText.text = $"总分: {totalScore:F1}";
// 提取其他评分项
ExtractScore(xml, "pronunciation_score", "发音得分");
ExtractScore(xml, "intonation_score", "语调得分");
ExtractScore(xml, "integrity_score", "完整度得分");
ExtractScore(xml, "fluency_score", "流畅度得分");
// 添加星级评价
resultText.text += $"\n\n星级评价: {GetStarRating(totalScore)}";
}
}
}
else
{
resultText.text = "未找到评分信息";
AddDebugLog("XML中未找到total_score标签");
}
}
catch (Exception e)
{
AddDebugLog($"XML解析错误: {e.Message}", true);
resultText.text = $"解析错误: {e.Message}";
}
}
// 获取星级评价
private string GetStarRating(float score)
{
if (score >= 95) return "★★★★★ (优秀)";
if (score >= 85) return "★★★★☆ (良好)";
if (score >= 75) return "★★★☆☆ (中等)";
if (score >= 60) return "★★☆☆☆ (及格)";
return "★☆☆☆☆ (需加强)";
}
// 提取特定分数项
private void ExtractScore(string xml, string tag, string displayName)
{
string startTag = $"<{tag}>";
string endTag = $"</{tag}>";
if (xml.Contains(startTag) && xml.Contains(endTag))
{
int start = xml.IndexOf(startTag) + startTag.Length;
int end = xml.IndexOf(endTag);
if (start > 0 && end > start)
{
string scoreStr = xml.Substring(start, end - start);
if (float.TryParse(scoreStr, out float score))
{
resultText.text += $"\n{displayName}: {score:F1}";
}
}
}
}
void Update()
{
// 处理消息队列
if (websocket != null && isConnected)
{
#if !UNITY_WEBGL || UNITY_EDITOR
websocket.DispatchMessageQueue();
#endif
}
// 录音时定期发送音频帧
if (isRecording && isConnected && !string.IsNullOrEmpty(sid))
{
if (Time.time - lastSendTime >= SEND_INTERVAL)
{
SendAudioFrames();
lastSendTime = Time.time;
progressText.text = $"录音中...已发送: {totalFramesSent}帧";
}
}
// 处理等待结果超时
if (waitingForResult && Time.time - lastSendTime > 30f)
{
AddDebugLog("等待结果超时,强制关闭连接", true);
resultText.text = "错误: 等待结果超时";
CloseConnection();
waitingForResult = false;
}
// 自动滚动到底部
if (debugScroll.verticalNormalizedPosition <= 0.01f)
{
debugScroll.verticalNormalizedPosition = 0f;
}
}
void OnDestroy()
{
// 关闭WebSocket
if (websocket != null)
{
websocket.Close();
}
// 停止录音
if (isRecording)
{
Microphone.End(null);
}
}
// HMAC-SHA256计算
byte[] HMACSHA256(byte[] key, byte[] data)
{
using (var hmac = new HMACSHA256(key))
{
return hmac.ComputeHash(data);
}
}
// 连接状态枚举
private enum ConnectionState
{
Disconnected,
Connecting,
Connected,
Recording,
WaitingForResult,
Error
}
// 添加调试日志
private void AddDebugLog(string message, bool isError = false)
{
string timestamp = DateTime.Now.ToString("HH:mm:ss.fff");
string formattedMessage = $"[{timestamp}] {message}\n";
if (isError)
{
Debug.LogError(message);
debugText.text += $"<color=red>{formattedMessage}</color>";
}
else
{
Debug.Log(message);
debugText.text += formattedMessage;
}
// 限制日志长度
if (debugText.text.Length > 10000)
{
debugText.text = debugText.text.Substring(debugText.text.Length - 8000);
}
}
// 格式化JSON字符串
private string FormatJson(string json)
{
if (!verboseLogging) return json;
try
{
// 简单缩进格式化
int indentLevel = 0;
bool inQuotes = false;
StringBuilder formatted = new StringBuilder();
for (int i = 0; i < json.Length; i++)
{
char c = json[i];
if (c == '"' && (i == 0 || json[i-1] != '\\'))
{
inQuotes = !inQuotes;
}
if (!inQuotes)
{
switch (c)
{
case '{':
case '[':
formatted.Append(c);
indentLevel++;
formatted.Append("\n" + new string(' ', indentLevel * 2));
break;
case '}':
case ']':
indentLevel--;
formatted.Append("\n" + new string(' ', indentLevel * 2) + c);
break;
case ',':
formatted.Append(c);
formatted.Append("\n" + new string(' ', indentLevel * 2));
break;
case ':':
formatted.Append(": ");
break;
default:
formatted.Append(c);
break;
}
}
else
{
formatted.Append(c);
}
}
return formatted.ToString();
}
catch
{
return json;
}
}
// 调试工具:保存日志到文件
public void SaveDebugLogToFile()
{
string path = Application.persistentDataPath + "/debug_log.txt";
File.WriteAllText(path, debugText.text);
AddDebugLog($"调试日志已保存到: {path}");
}
// 调试工具:切换详细日志模式
public void ToggleVerboseLogging()
{
verboseLogging = !verboseLogging;
AddDebugLog($"详细日志模式: {(verboseLogging ? "开启" : "关闭")}");
}
}
```
### 关键调试功能增强:
#### 1. 新增调试UI组件
```csharp
public Text debugText; // 调试信息显示区域
public ScrollRect debugScroll; // 调试信息滚动区域
// 在Start方法中初始化
debugText.text = "调试信息将显示在此处...\n";
```
#### 2. 增强调试日志系统
```csharp
// 添加调试日志
private void AddDebugLog(string message, bool isError = false)
{
string timestamp = DateTime.Now.ToString("HH:mm:ss.fff");
string formattedMessage = $"[{timestamp}] {message}\n";
if (isError)
{
Debug.LogError(message);
debugText.text += $"<color=red>{formattedMessage}</color>";
}
else
{
Debug.Log(message);
debugText.text += formattedMessage;
}
// 自动滚动到底部
Canvas.ForceUpdateCanvases();
debugScroll.verticalNormalizedPosition = 0f;
}
```
#### 3. JSON格式化工具
```csharp
// 格式化JSON字符串
private string FormatJson(string json)
{
// 实现简单的JSON格式化
// ...
}
```
#### 4. 详细数据记录
**发送初始化帧:**
```csharp
AddDebugLog($"发送初始化帧:\n{FormatJson(initJson)}");
```
**发送音频帧:**
```csharp
// 创建简化的调试信息(避免显示大量base64数据)
string debugInfo = @"{
""data"": {
""status"": 1,
""data"": ""[音频数据: " + audioData.Length + " 字节]""
},
""sid"": """ + sid + @"""
}";
if (verboseLogging)
{
AddDebugLog($"发送音频帧: {audioData.Length}字节\n{FormatJson(debugInfo)}");
}
else
{
AddDebugLog($"发送音频帧: {audioData.Length}字节");
}
```
**发送结束帧:**
```csharp
AddDebugLog($"发送结束帧:\n{FormatJson(endFrame)}");
```
**接收服务器响应:**
```csharp
websocket.OnMessage += (data) => {
string json = Encoding.UTF8.GetString(data);
AddDebugLog($"收到服务器响应:\n{FormatJson(json)}");
// ...
};
```
#### 5. 调试工具函数
```csharp
// 调试工具:保存日志到文件
public void SaveDebugLogToFile()
{
string path = Application.persistentDataPath + "/debug_log.txt";
File.WriteAllText(path, debugText.text);
AddDebugLog($"调试日志已保存到: {path}");
}
// 调试工具:切换详细日志模式
public void ToggleVerboseLogging()
{
verboseLogging = !verboseLogging;
AddDebugLog($"详细日志模式: {(verboseLogging ? "开启" : "关闭")}");
}
```
#### 6. 错误状态处理增强
```csharp
websocket.OnError += (err) => {
AddDebugLog($"WebSocket错误: {err}", true);
// ...
};
websocket.OnClose += (code) => {
AddDebugLog($"连接关闭,代码: {code}");
// ...
};
```
### 使用说明:
1. **UI设置**:
- 在Canvas中添加新的Text组件用于显示调试信息
- 添加ScrollRect组件包裹调试文本
- 可添加两个按钮:
- "保存日志":绑定SaveDebugLogToFile方法
- "详细日志":绑定ToggleVerboseLogging方法
2. **调试功能**:
- 所有发送和接收的JSON数据都会格式化显示
- 音频帧数据会显示大小但不显示完整内容(避免性能问题)
- 错误信息以红色显示
- 时间戳精确到毫秒
- 日志自动滚动到底部
3. **日志控制**:
- `verboseLogging`变量控制是否显示详细JSON
- 日志长度超过10000字符时自动截断
- 可通过UI按钮切换详细日志模式
4. **错误排查流程**:
- 观察发送的初始化帧是否正确
- 确认音频帧是否按预期发送
- 检查服务器返回的状态码
- 查看是否有错误信息(红色日志)
- 保存日志文件分析
### 调试输出示例:
```
[14:25:03.456] 开始评测流程...
[14:25:03.501] 生成鉴权URL: wss://ise-api.xfyun.cn/v2/open-ise?authorization=...&date=...
[14:25:03.502] 正在连接WebSocket...
[14:25:04.123] WebSocket连接成功!
[14:25:04.125] 发送初始化帧:
{
"common": {
"app_id": "d11f22d5"
},
"business": {
"aue": "raw",
"auf": "audio/L16;rate=16000",
"category": "read_sentence",
"cmd": "ssb",
"ent": "en_vip",
"sub": "ise",
"text": "V2hlbiB5b3UgZG9uJ3Qga25vdyB3aGF0IHlvdSdyZSBkb2luZywgaXQncyBoZWxwZnVsIHRvIGJlZ2luIGJ5IGxlYXJuaW5nIGFib3V0IHdoYXQgeW91IHNob3VsZCBub3QgZG8u",
"ttp_skip": true
},
"data": {
"status": 0
}
}
[14:25:04.126] 开始录音...
[14:25:04.230] 发送音频帧: 5120字节
{
"data": {
"status": 1,
"data": "[音频数据: 5120 字节]"
},
"sid": "abcdefg123456"
}
[14:25:04.330] 收到服务器响应:
{
"code": 0,
"message": "success",
"data": {
"sid": "abcdefg123456",
"status": 1
}
}
[14:25:06.789] 发送结束帧:
{
"data": {
"status": 2,
"data": ""
},
"sid": "abcdefg123456"
}
[14:25:07.123] 收到服务器响应:
{
"code": 0,
"message": "success",
"data": {
"sid": "abcdefg123456",
"status": 2,
"data": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHJlc3VsdD4KICA8dG90YWxfc2NvcmU+OTIuNTwvdG90YWxfc2NvcmU+CiAgPHByb251bmNpYXRpb25fc2NvcmU+OTUuMDwvcHJvbnVuY2lhdGlvbl9zY29yZT4KICA8aW50b25hdGlvbl9zY29yZT44OS41PC9pbnRvbmF0aW9uX3Njb3JlPgogIDxpbnRlZ3JpdHlfc2NvcmU+OTAuMDwvaW50ZWdyaXR5X3Njb3JlPgogIDxmbHVlbmN5X3Njb3JlPjg4LjA8L2ZsdWVuY3lfc2NvcmU+CjwvcmVzdWx0Pg=="
}
}
[14:25:07.125] 最终结果XML:
<?xml version="1.0" encoding="UTF-8"?>
<result>
<total_score>92.5</total_score>
<pronunciation_score>95.0</pronunciation_score>
<intonation_score>89.5</intonation_score>
<integrity_score>90.0</integrity_score>
<fluency_score>88.0</fluency_score>
</result>
```
### 调试技巧:
1. **常见问题排查**:
- 如果未收到响应:检查网络连接和鉴权URL
- 如果收到错误代码:参考讯飞API文档的错误代码表
- 如果未收到最终结果:检查是否发送了结束帧,等待时间是否足够
2. **日志分析**:
- 使用`SaveDebugLogToFile`保存完整日志
- 搜索"error"或"warning"定位问题
- 比较发送数据和API文档要求是否一致
3. **性能优化**:
- 在正式版本中设置`verboseLogging = false`
- 避免在移动设备上显示过多日志
- 定期清理日志文本