语音不是开关按钮
队伍语音在客户端里经常被压缩成一个麦克风按钮:点一下开,再点一下关。实际体验远比这复杂。玩家可能没给麦克风权限,系统可能占用音频设备,耳机突然断开,队友在静音,频道连接失败,弱网导致语音断续,后台切前台后音频会话丢失。
语音 UI 的目标不是展示技术细节,而是让玩家明确知道自己是否在说话、队友是否听得到、自己听不听得到队友、当前失败能不能恢复。状态如果不清楚,玩家会在团战前反复喊“能听见吗”。
stateDiagram-v2
[*] --> Disabled
Disabled --> PermissionRequest: 点击开启
PermissionRequest --> Connecting: 授权成功
PermissionRequest --> PermissionDenied: 授权拒绝
Connecting --> InChannel: 频道连接成功
Connecting --> Failed: 连接失败
InChannel --> Muted: 本地静音
Muted --> InChannel: 取消静音
InChannel --> Reconnecting: 网络波动
Reconnecting --> InChannel: 恢复
Reconnecting --> Failed: 超时
权限要在合适时机请求
麦克风权限不要在玩家首次进游戏时就弹。更自然的时机是玩家进入队伍、打开语音按钮或加入需要语音的玩法时。权限弹窗前,客户端可以用轻提示说明为什么需要麦克风。玩家拒绝后,按钮应显示“未授权”,并提供去系统设置的路径。
权限状态要缓存但不能永久相信。系统设置里可能被玩家改掉,应用回到前台时应重新检查。iOS 和 Android 的权限返回路径不同,客户端要把“拒绝一次”和“永久拒绝”区分开,文案也要不同。
不要用自定义弹窗假装系统权限。玩家需要看到平台真实权限提示。自定义说明只应在系统弹窗前或拒绝后出现。
频道连接和麦克风静音不同
很多 UI 把“未连接频道”和“本地静音”都显示成灰色麦克风,玩家无法理解。频道状态表示你是否在语音房间里,麦克风状态表示你是否把声音发出去,扬声器状态表示你是否能听到别人。这三个状态应该分开建模。
按钮可以简化,但详情状态要可见。例如麦克风图标旁边用小点表示频道连接,点击后弹出面板显示:频道已连接、本地麦克风开启、扬声器开启、当前输入设备。这样普通玩家不会被打扰,有问题时又能查看。
队友说话指示也很重要。头像旁的音量波形能让玩家知道谁在说话。弱网时如果语音包延迟,不要让波形乱闪。可以根据语音 SDK 的真实说话事件或能量值做平滑显示。
音频会话要和游戏声音协调
开启语音后,游戏背景音乐和音效可能需要压低,尤其在移动端扬声器外放时。压低比例要可配置,玩家也应该能设置语音音量和游戏音量。不要简单把背景音乐关掉,很多玩家仍然需要环境反馈。
耳机插拔会改变路由。耳机断开后,是否自动切到扬声器要谨慎,避免玩家隐私暴露。可以显示提示“耳机已断开,语音输出已切换”,或根据平台策略暂停麦克风。
后台切前台也要恢复。移动端进入后台后,音频会话可能被系统回收。回到游戏时,客户端应检查频道和设备状态,必要时重连,并给出状态变化提示。
弱网下优先保留可解释状态
语音弱网比普通网络请求更微妙。玩家能看到队友移动,却听不到声音,会以为是 UI 坏了。客户端应把语音网络状态单独显示:重连中、语音质量差、频道断开。不要只依赖全局网络图标。
重连期间可以保持按钮状态,但加上小转圈或提示。超时后切到失败状态,允许玩家手动重试。自动重试要有次数和间隔,避免电量和流量浪费。
如果语音 SDK 支持降码率,客户端可以在弱网时降级音质,而不是直接断开。UI 不需要展示技术细节,只要提示当前语音质量不佳。
隐私和举报要有入口
语音是社交功能,也可能产生骚扰。玩家需要能快速静音某个队友、关闭全队语音、举报语音行为。静音状态要本地立即生效,服务端或语音 SDK 后续确认。举报入口不应藏太深,尤其在多人匹配里。
录音和隐私提示要符合平台要求。如果游戏会为举报保留短时语音片段,必须在合适位置说明。客户端不要在没有明确规则时自行录音。
未成年人或特定地区可能有语音限制。客户端要根据账号状态隐藏或禁用语音入口,并显示合适文案,不要让玩家反复点失败。
小结
队伍语音的体验来自清晰状态,而不是一个漂亮麦克风图标。客户端把权限、频道、麦克风、扬声器、设备、弱网和隐私分开建模,再用简洁 UI 汇总,玩家才能相信语音功能在关键时刻可用。
语音联调时我会准备一个状态面板,显示权限、频道 ID、SDK 连接状态、本地静音、输出设备、最近重连次数和队友说话事件。线上问题通常不是“语音坏了”,而是某个状态被 UI 折叠后无人能看见。
语音联调时我会准备一个状态面板,显示权限、频道 ID、SDK 连接状态、本地静音、输出设备、最近重连次数和队友说话事件。线上问题通常不是“语音坏了”,而是某个状态被 UI 折叠后无人能看见。
语音联调时我会准备一个状态面板,显示权限、频道 ID、SDK 连接状态、本地静音、输出设备、最近重连次数和队友说话事件。线上问题通常不是“语音坏了”,而是某个状态被 UI 折叠后无人能看见。
语音联调时我会准备一个状态面板,显示权限、频道 ID、SDK 连接状态、本地静音、输出设备、最近重连次数和队友说话事件。线上问题通常不是“语音坏了”,而是某个状态被 UI 折叠后无人能看见。
语音联调时我会准备一个状态面板,显示权限、频道 ID、SDK 连接状态、本地静音、输出设备、最近重连次数和队友说话事件。线上问题通常不是“语音坏了”,而是某个状态被 UI 折叠后无人能看见。
语音联调时我会准备一个状态面板,显示权限、频道 ID、SDK 连接状态、本地静音、输出设备、最近重连次数和队友说话事件。线上问题通常不是“语音坏了”,而是某个状态被 UI 折叠后无人能看见。
语音联调时我会准备一个状态面板,显示权限、频道 ID、SDK 连接状态、本地静音、输出设备、最近重连次数和队友说话事件。线上问题通常不是“语音坏了”,而是某个状态被 UI 折叠后无人能看见。
语音联调时我会准备一个状态面板,显示权限、频道 ID、SDK 连接状态、本地静音、输出设备、最近重连次数和队友说话事件。线上问题通常不是“语音坏了”,而是某个状态被 UI 折叠后无人能看见。
语音联调时我会准备一个状态面板,显示权限、频道 ID、SDK 连接状态、本地静音、输出设备、最近重连次数和队友说话事件。线上问题通常不是“语音坏了”,而是某个状态被 UI 折叠后无人能看见。
语音联调时我会准备一个状态面板,显示权限、频道 ID、SDK 连接状态、本地静音、输出设备、最近重连次数和队友说话事件。线上问题通常不是“语音坏了”,而是某个状态被 UI 折叠后无人能看见。
语音联调时我会准备一个状态面板,显示权限、频道 ID、SDK 连接状态、本地静音、输出设备、最近重连次数和队友说话事件。线上问题通常不是“语音坏了”,而是某个状态被 UI 折叠后无人能看见。
语音联调时我会准备一个状态面板,显示权限、频道 ID、SDK 连接状态、本地静音、输出设备、最近重连次数和队友说话事件。线上问题通常不是“语音坏了”,而是某个状态被 UI 折叠后无人能看见。
语音联调时我会准备一个状态面板,显示权限、频道 ID、SDK 连接状态、本地静音、输出设备、最近重连次数和队友说话事件。线上问题通常不是“语音坏了”,而是某个状态被 UI 折叠后无人能看见。
语音联调时我会准备一个状态面板,显示权限、频道 ID、SDK 连接状态、本地静音、输出设备、最近重连次数和队友说话事件。线上问题通常不是“语音坏了”,而是某个状态被 UI 折叠后无人能看见。
语音联调时我会准备一个状态面板,显示权限、频道 ID、SDK 连接状态、本地静音、输出设备、最近重连次数和队友说话事件。线上问题通常不是“语音坏了”,而是某个状态被 UI 折叠后无人能看见。
语音联调时我会准备一个状态面板,显示权限、频道 ID、SDK 连接状态、本地静音、输出设备、最近重连次数和队友说话事件。线上问题通常不是“语音坏了”,而是某个状态被 UI 折叠后无人能看见。
语音联调时我会准备一个状态面板,显示权限、频道 ID、SDK 连接状态、本地静音、输出设备、最近重连次数和队友说话事件。线上问题通常不是“语音坏了”,而是某个状态被 UI 折叠后无人能看见。
语音联调时我会准备一个状态面板,显示权限、频道 ID、SDK 连接状态、本地静音、输出设备、最近重连次数和队友说话事件。线上问题通常不是“语音坏了”,而是某个状态被 UI 折叠后无人能看见。
语音联调时我会准备一个状态面板,显示权限、频道 ID、SDK 连接状态、本地静音、输出设备、最近重连次数和队友说话事件。线上问题通常不是“语音坏了”,而是某个状态被 UI 折叠后无人能看见。
语音联调时我会准备一个状态面板,显示权限、频道 ID、SDK 连接状态、本地静音、输出设备、最近重连次数和队友说话事件。线上问题通常不是“语音坏了”,而是某个状态被 UI 折叠后无人能看见。
语音联调时我会准备一个状态面板,显示权限、频道 ID、SDK 连接状态、本地静音、输出设备、最近重连次数和队友说话事件。线上问题通常不是“语音坏了”,而是某个状态被 UI 折叠后无人能看见。
语音联调时我会准备一个状态面板,显示权限、频道 ID、SDK 连接状态、本地静音、输出设备、最近重连次数和队友说话事件。线上问题通常不是“语音坏了”,而是某个状态被 UI 折叠后无人能看见。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。