Skip to main content

ASR 服务开发接入指引

1. 接入前准备

1.1 前提条件

  • 已注册 Player Network 控制台,并完成业务项目创建。
  • 若采用 SDK 接入,客户端 Player Network SDK 版本需为 1.32 及以上

1.2 接入方式选择

接入方式适用场景接入特点安全注意事项
SDK 接入(推荐)业务已接入 Player Network SDK,客户端可直接调用 SDK 能力。开发链路较短,适合游戏内实时功能。客户端只使用 SDK 所需参数,不应保存 secret
API 接入仅接入 ASR 服务,或由游戏后端统一代理调用。便于统一鉴权、限流、日志审计和业务封装。secret 仅保存在可信后端或密钥管理系统。

1.3 音频与语言准备

准备项说明建议
语言代码ASR 识别语种,如 zhen按玩家当前语言或业务场景设置;不确定时由后端/管理端明确配置。
PCM 参数application/json 协议传入裸 PCM 数据;当前示例采用 16 kHz、16-bit、单声道。采集端必须保证实际 PCM 参数与服务要求一致,再进行 base64 编码。
音频格式支持 WAV 与 GVoice Opus。audioFormat1-WAV2-GVoice Opus客户端录音格式必须与 audioFormat 一致。
音频路径/文件SDK 侧使用本地 VoicePath;API 文件上传使用 data Part。上传前校验文件存在、可读取、大小和时长合理。
时间戳application/json 协议需传 JSON 字符串格式的 timeStamp,其中包含 start/endstart 为 Unix 秒级时间戳,end 可按 start + 音频时长 计算。

2. 管理端操作

  1. 首次进入 ASR 服务,点击「立即免费体验」完成 ASR 服务功能初始化。

ASR 服务功能初始化入口

  1. API 接入时,按照以下说明完成管理端配置:
配置项操作说明
功能入口前往「项目信息」,选择「AI 语音识别」。
获取参数在「API 参数」区域获取 APPID(appId)AppSecret(secret),用于签发请求鉴权所需的 JWT Token。具体要求见「3.2.1 JWT Token 生成要求」。
白名单配置在「白名单配置」区域填写游戏后端出口 IP,确认无误后保存。

ASR 服务 API 白名单 / 场景配置入口

3. 后台 API 接入

3.1 协议选择

协议Content-Type音频传入方式适用场景注意事项
协议 1application/jsonaudioFile 字段传 base64 编码的裸 PCM 音频数据。电竞直播场景。示例 PCM 参数为 16 kHz、16-bit、单声道;需要传 appIdaudioFilegameCodesrcLangtimeStamptraceId
协议 2(推荐)multipart/form-datameta Part 传 JSON 配置;data Part 传音频二进制文件。玩家游戏内场景的语音识别、客户端上传 WAV/GVoice Opus 文件。metadata 两个 Part 的 Content-Type 会被检查,必须按要求填写。
协议说明

协议 1 仅支持通过后台 API 接入;协议 2 除支持后台 API 接入外,还可通过客户端 SDK 接入。SDK 接入方式请参考「4. 客户端 SDK 接入」。

3.2 接口信息

后台调用 ASR 服务 API 时,请根据当前部署环境选择对应完整地址;接口路径为 /api/v2/speechai/asr

IP 白名单

调用接口前,需要在 Player Network 管理端配置游戏后端出口 IP 白名单,否则接口无法成功调用。配置方式请参考「2. 管理端操作」。

环境完整调用地址说明
腾讯云 test 环境https://asr-test.intlgame.com/api/v2/speechai/asr腾讯云测试环境使用。
项目说明
接口路径POST <API域名>/api/v2/speechai/asr
Content-Typemultipart/form-dataapplication/json
AuthorizationBearer <token>
鉴权方式JWT,签名算法 HS256;payload.data.accountappId 保持一致。
能力说明语音识别接口,统一支持 base64 编码的 PCM 音频数据和文件上传音频。

3.2.1 JWT Token 生成要求

  • appIdsecret 从管理端获取,具体操作见「查看参数获取方式」;secret 仅保存在可信后端或密钥管理系统中。
  • 使用 secret 作为 HS256 签名密钥。
  • JWT payload.data.account 必须等于请求中的 appId
  • JWT payload.exp 使用 Unix 秒级过期时间;后端示例设置为签发后 300 秒过期。
  • 请求头使用 Authorization: Bearer <token>

3.3 application/json 请求参数

参数类型必填说明
appIdstring管理员分配的 appId
audioFilestring裸 PCM 音频字节经 base64 编码后的字符串;示例参数为 16 kHz、16-bit、单声道。
gameCodestring业务代码,标识业务场景;错填会报错。
srcLangstring目标语音识别语言代码,如 zhen
timeStampjson stringJSON 字符串,包含 Unix 秒级 startend;注意不是嵌套 JSON 对象。
traceIdstring唯一请求 ID,用于跟踪请求。
gameLangstring玩家游戏语言,无玩家时可不传。
systemLangstring玩家系统语言,无玩家时可不传。
openIdstring用户 ID,暂未用到。
sessionIdstring会话 ID,暂未用到。

timeStamp 字段

字段类型必填说明
startfloat64音频片段开始时间,Unix 秒级时间戳。
endfloat64音频片段结束时间,Unix 秒级时间戳;可使用 start + 音频字节数 / (采样率 × 每样本字节数 × 声道数) 计算。

例如,16 kHz、16-bit、单声道 PCM 的音频时长计算方式为:

duration = len(pcm_bytes) / (16000 * (16 // 8) * 1)
application/json 请求示例
POST /api/v2/speechai/asr HTTP/1.1
Content-Type: application/json
Authorization: Bearer <token>

{
"appId": "<app-id>",
"audioFile": "<base64编码的PCM音频数据>",
"traceId": "asr-json-001",
"srcLang": "zh",
"gameCode": "<game-code>",
"timeStamp": "{\"start\": 1672531200, \"end\": 1672531260.0}"
}

完整的 Python 调用示例见「附录:后端接入伪代码」中的“协议 1”。

3.4 multipart/form-data 请求参数

Part 名称Content-Type必填说明
metaapplication/jsonJSON 配置,描述 appIdaudioFormatgameCode、语言、traceId 等基本信息。
dataapplication/octet-stream音频二进制文件,目前支持 WAV 和 GVoice Opus。

meta 参数

参数类型必填说明
appIdstring管理员分配的 appId
audioFormatint音频格式:1-WAV2-GVoice Opus
gameCodestring业务代码,标识业务场景。
traceIdstring唯一请求 ID,用于跟踪请求。
srcLangstring目标语音识别语言,如 zhen;游戏内场景通常可不传,更多用于电竞直播。
gameLangstring玩家游戏语言。
systemLangstring玩家系统语言。
openIdstring用户 ID,暂未用到。
sessionIdstring会话 ID,暂未用到。
timeStampjson string时间戳信息,包含 startend
multipart/form-data 请求示例
POST /api/v2/speechai/asr HTTP/1.1
Content-Type: multipart/form-data; boundary=----boundary
Authorization: Bearer <token>

------boundary
Content-Disposition: form-data; name="meta"
Content-Type: application/json

{
"appId": "<app-id>",
"audioFormat": 1,
"traceId": "asr-file-001",
"srcLang": "en",
"gameLang": "en",
"systemLang": "en",
"gameCode": "<game-code>"
}
------boundary
Content-Disposition: form-data; name="data"; filename="voice.wav"
Content-Type: application/octet-stream

(binary)
------boundary--

实际接入时建议由 HTTP 客户端自动生成 multipart boundary,不要手工固定请求头中的 boundary。完整的 Python 调用示例见「附录:后端接入伪代码」中的“协议 2”。

3.5 响应处理

响应字段类型说明处理建议
retCodeint返回码,0 表示成功。非 0 时进入错误处理和日志上报。
messagestring返回消息。日志记录,不建议原样展示给玩家。
traceIdstring请求跟踪 ID。问题排查时提供给 PNT 支持。
resultobjectASR 识别结果,仅成功时返回。读取 result.text 作为完整识别文本。
result.startfloat64音频片段开始时间。流媒体或分片识别场景可使用。
result.endfloat64音频片段结束时间。流媒体或分片识别场景可使用。
result.textstring识别出的完整文本内容。展示或进入后续翻译/审核流程。
result.words[]Word单词级详细信息列表。用于字幕时间轴、置信度或说话人展示;为空时忽略。
Word 参数字段类型说明
textstring单个单词的文本内容。
startfloat64单词在音频中的开始时间(秒)。
endfloat64单词在音频中的结束时间(秒)。
scorefloat64单词识别的置信度分数。
speakerstring说话人标识,用于区分不同说话人。
成功响应示例
{
"retCode": 0,
"message": "success",
"traceId": "29d7b34e-3521-4f16-9c5a-12b36c466382",
"result": {
"start": 1770780974,
"end": 1770780980.017,
"text": "Hello World!",
"words": null
}
}

3.6 错误处理建议

错误类型可能原因处理建议
鉴权失败token 过期、签名错误、appId 与 token account 不一致。重新生成 token;检查 appId/secret;确认 Authorization 头格式。
参数错误缺少 appIdgameCodetraceIdaudioFileaudioFormat 不支持;meta/data Part Content-Type 不正确。按协议校验必填字段;multipart 请求需明确设置 Part Content-Type。
音频格式错误音频不是 WAV/GVoice Opus,或 base64 解码失败。客户端上传前校验格式;服务端记录文件类型和大小。
音频时长异常音频为空、过短、过长或 duration 不符合服务要求。客户端限制录音时长;后端添加预校验。
识别为空或噪声音频噪声过大、无人声或触发噪声过滤。前端提示玩家重新录制;必要时降噪或限制环境噪声。
服务内部错误ASR 服务或依赖异常。短暂重试;仍失败时联系 PNT 支持并提供 traceId

4. 客户端 SDK 接入

版本要求

SDK 接入 ASR 服务能力需使用 Player Network SDK 1.32 及以上版本。低于 1.32 的版本不支持相关能力,需先完成 SDK 升级。

4.1 调用流程

  1. 确认客户端已接入 Player Network SDK,并完成登录态初始化。
  2. 录制或获取本地音频文件,确保格式为 WAV 或 GVoice Opus。
  3. 构造 INTLTranslatorVoiceV2Req 请求结构体,填入 VoicePathAudioFormatGameCodeTraceId 等字段。
  4. 调用 SDK 已封装的音频翻译/ASR 接口提交请求。实际方法名以当前 SDK 版本文档为准。
  5. INTLTranslatorResult 回调中读取 asrRsp,优先按 ASR V2 结构解析 result.text
  6. 展示识别文本,或继续进入文本翻译、敏感词审核、聊天发送等业务流程。

4.2 INTLTranslatorVoiceV2Req 字段说明

字段类型必填说明填写建议
VoicePathString音频文件路径。确保文件存在且客户端有读取权限。
AudioFormatInteger目前支持 WAV 和 GVoice Opus:1-WAV2-GVoice Opus按实际文件格式填写,不能混填。
GameCodeStringAI 翻译服务为游戏分配的 gameCode使用管理端场景切换获取的值。
SessionIdString流式 ASR 的会话 ID。非流式/普通文件识别可不填。
GameLanguageString游戏语言设置。可填玩家当前游戏语言。
ExtInfoString额外信息。可填 JSON 字符串。
TraceIdString用于跟踪的唯一请求 ID。建议每次请求生成唯一 UUID。
客户端 ASR V2 请求结构示例(伪代码,方法名以 SDK 实际版本为准)
INTLTranslatorVoiceV2Req req;
req.VoicePath = "<local-voice-file.wav>";
req.AudioFormat = 1; // 1-WAV, 2-GVoice Opus
req.GameCode = "<game-code>";
req.SessionId = "";
req.GameLanguage = "zh";
req.ExtInfo = "";
req.TraceId = "client-asr-trace-001";

// SDK.AudioTranslateV2(req, OnTranslatorResult);

4.3 asrRsp 回调处理

  • ASR 结果在 asrRsp 中返回,游戏侧需要自行解析。
  • ASR V2 推荐读取 asr_rsp.result.text 作为识别结果。
  • startendwords 主要用于流媒体或字幕类场景,普通游戏内语音转文字可忽略。
  • 回调 retCode 为 0 时才展示识别文本;非 0 时提示重新录制或稍后再试。
asrRsp V2 核心结构示例
{
"ret": 0,
"msg": "success",
"translator_rsp": "",
"asr_rsp": {
"retCode": 0,
"message": "success",
"traceId": "traceId",
"result": {
"text": "Hello World!",
"start": 0,
"end": 0,
"words": null
}
}
}

5. 联调与验收

5.1 验收清单

检查项通过标准问题定位字段
功能初始化管理端已完成 ASR 服务初始化。项目 ID、appId
gameCode传入 gameCode 与管理端场景一致。gameCodetraceId
协议选择base64 使用 application/json;文件上传使用 multipart/form-dataContent-Type、请求体
PCM 参数协议 1 的 PCM 采样率、位深、声道数与服务要求一致,且 base64 编码前为原始音频字节。PCM 参数、解码后字节数
timeStamp协议 1 传入包含 start/end 的 JSON 字符串,时间跨度与音频时长一致。timeStamp、音频时长
音频格式WAV/GVoice Opus 与 audioFormat 一致。audioFormat、文件后缀、音频头
multipart Partmetaapplication/jsondataapplication/octet-streamPart Content-Type
识别结果成功时 result.textasr_rsp.result.text 有内容。retCodemessagetraceId
空音频/噪声无人声或噪声场景能提示重新录制。retCode、音频时长、traceId
异常兜底鉴权、参数、格式、服务异常均有业务提示。retCodemessagetraceId

5.2 上线前确认

  • 生产域名、白名单、限流配置已确认。
  • 后端 token 过期时间合理,具备自动刷新能力。
  • 日志中不打印 secret、完整 token 和完整音频内容。
  • 客户端具备录音失败、识别失败、重新录制等兜底流程。
  • 关键错误码和 traceId 已接入监控告警或问题上报。
客户端体验建议

录音前提示玩家保持安静环境;录音中展示时长;上传识别中显示 loading;失败时提供“重新录制”入口。

ASR 识别文本建议在发送前展示给玩家确认,避免误识别内容直接发送。

6. 常见问题与排障建议

问题可能原因解决方案
ASR 上传文件后报参数错误multipart 的 meta/data Part 名称或 Content-Type 不正确。确认 meta=application/jsondata=application/octet-stream
JSON 协议参数错误timeStamp 被传成嵌套对象而非 JSON 字符串,或 PCM 参数与服务要求不一致。使用 json.dumps({"start": ..., "end": ...});检查采样率、位深和声道数。
ASR 识别为空音频无有效人声、噪声过大或录音权限异常。客户端先本地校验录音文件大小/时长;提示玩家重新录制。
ASR 音频格式错误上传格式与 audioFormat 不一致,或不是 WAV/GVoice Opus。统一录音编码;WAV 传 audioFormat=1,GVoice Opus 传 audioFormat=2
鉴权失败token 缺失、过期、签名错误,或请求体 appId 与 token account 不一致。重新生成 token;检查 secret;确认 Authorization: Bearer <token> 格式。
SDK 回调 invalid config / ret 91002后台配置缺失。联系 Player Network 助手补充配置。

附录:后端接入伪代码

app_idsecret 用于签发 JWT token,token 通过 Authorization 请求头用于接口鉴权。生产环境中请从安全配置或密钥管理系统读取凭据,不要将其硬编码到代码仓库。

协议 1:application/json

该协议将裸 PCM 音频字节编码为 base64 字符串。以下示例采用 16 kHz、16-bit、单声道 PCM,并根据音频字节数计算时长。

Python 伪代码:application/json 调用 ASR
import base64
import json
import time
import uuid

import jwt
import requests

# app_id 和 secret 从管理端获取,用于签发 JWT token。
app_id = "<app_id>" # AppID
secret = "<secret>" # AppSecret
api_url = "https://<api-domain>/api/v2/speechai/asr"

token = jwt.encode(
{
"data": {"account": app_id},
"exp": int(time.time()) + 300,
},
secret,
algorithm="HS256",
)

sample_rate = 16000
bit_depth = 16
num_channels = 1

pcm_bytes: bytes = ... # 从语音 SDK 等来源获取的裸 PCM 音频字节

base64_pcm_audio = base64.b64encode(pcm_bytes).decode("utf-8")
duration = len(pcm_bytes) / (
sample_rate * (bit_depth // 8) * num_channels
)

ts = int(time.time())
body = {
"appId": app_id,
"audioFile": base64_pcm_audio,
"gameCode": "<game-code>",
"srcLang": "<src-lang>",
"timeStamp": json.dumps({"start": ts, "end": ts + duration}),
"traceId": str(uuid.uuid4()),
}

resp = requests.post(
api_url,
json=body,
headers={"Authorization": f"Bearer {token}"},
timeout=30,
)
resp.raise_for_status()
print(json.dumps(resp.json(), indent=4, ensure_ascii=False))

协议 2:multipart/form-data

该协议通过 meta Part 传入 JSON 配置,通过 data Part 上传 WAV 或 GVoice Opus 音频文件。audioFormat 必须与文件的实际编码一致。

Python 伪代码:multipart/form-data 调用 ASR
import json
import time
import uuid
from pathlib import Path

import jwt
import requests

# app_id 和 secret 从管理端获取,用于签发 JWT token。
app_id = "<app_id>" # AppID
secret = "<secret>" # AppSecret
api_url = "https://<api-domain>/api/v2/speechai/asr"

token = jwt.encode(
{
"data": {"account": app_id},
"exp": int(time.time()) + 300,
},
secret,
algorithm="HS256",
)

meta = {
"appId": app_id,
"audioFormat": 1, # 1-WAV,2-GVoice Opus
"traceId": str(uuid.uuid4()),
"gameLang": "<player-game-lang>",
"systemLang": "<player-system-lang>",
"gameCode": "<game-code>",
}

audio_path = Path("<audio-file-path>")

with audio_path.open("rb") as f:
files = {
"meta": (None, json.dumps(meta), "application/json"),
"data": (audio_path.name, f, "application/octet-stream"),
}
resp = requests.post(
api_url,
files=files,
headers={"Authorization": f"Bearer {token}"},
timeout=30,
)

resp.raise_for_status()
print(json.dumps(resp.json(), indent=4, ensure_ascii=False))