fix(录音): gameui_play_voice/stop_voice 对齐 Android play() 时机
play_voice 改为进入 mediaTypeAudio 即立刻同步回调(对齐 Android play()在播放前调), 不再等 AVPlayer prepared(网络AMR延迟致动画起得晚/疑似没调);打断旧语音补发旧 user 的 stop_voice;创建失败也补 stop_voice;抽出 endVoice 统一收尾(完成/出错)防重复。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
7ae58e90ca
commit
64c0c621bc
@@ -134,14 +134,21 @@ export class AudioProvider implements CapabilityProvider {
|
||||
return;
|
||||
}
|
||||
const user: string = req.user;
|
||||
// 打断正在播的旧语音:先通知 H5 停旧座位动画,再释放(对齐"同一时刻只播一条")。
|
||||
if (this.voicePlayer !== undefined && this.currentVoiceUser !== '') {
|
||||
this.bridge?.callHandler(OutboundHandlers.GameUiStopVoice, this.currentVoiceUser);
|
||||
}
|
||||
this.releaseVoice();
|
||||
// 对齐 Android play():进入即立刻同步通知 H5 开始播放(座位说话动画),再创建播放器;
|
||||
// 不等到 prepared 才报——网络 AMR 加载可能延迟数百 ms,晚报会被认为"没调/动画起得晚"。
|
||||
this.currentVoiceUser = user;
|
||||
this.bridge?.callHandler(OutboundHandlers.GameUiPlayVoice, user);
|
||||
media.createAVPlayer().then((player: media.AVPlayer) => {
|
||||
if (this.disposed) {
|
||||
player.release(); // 创建期间已销毁:直接释放,勿播放/勿挂回调(防泄漏 + 打已弃桥)
|
||||
if (this.disposed || this.currentVoiceUser !== user) {
|
||||
player.release(); // 创建期间已销毁或已被新语音取代:释放孤儿播放器(旧 user 的 stop 已发)
|
||||
return;
|
||||
}
|
||||
this.voicePlayer = player;
|
||||
this.currentVoiceUser = user;
|
||||
player.on('stateChange', (state: string) => {
|
||||
if (state === 'initialized') {
|
||||
player.prepare();
|
||||
@@ -149,19 +156,28 @@ export class AudioProvider implements CapabilityProvider {
|
||||
player.loop = false;
|
||||
player.setVolume(this.effVolume());
|
||||
player.play();
|
||||
this.bridge?.callHandler(OutboundHandlers.GameUiPlayVoice, user);
|
||||
} else if (state === 'completed') {
|
||||
this.bridge?.callHandler(OutboundHandlers.GameUiStopVoice, user);
|
||||
this.releaseVoice();
|
||||
this.endVoice(user); // 播放完成:gameui_stop_voice + 释放
|
||||
}
|
||||
});
|
||||
player.on('error', (e: BusinessError) => {
|
||||
this.log.w(`voice play error: ${e.code} ${e.message}`);
|
||||
this.bridge?.callHandler(OutboundHandlers.GameUiStopVoice, user);
|
||||
this.releaseVoice();
|
||||
this.endVoice(user);
|
||||
});
|
||||
player.url = req.audiourl;
|
||||
}).catch((e: BusinessError) => this.log.w(`createAVPlayer(voice) failed: ${e.message}`));
|
||||
}).catch((e: BusinessError) => {
|
||||
this.log.w(`createAVPlayer(voice) failed: ${e.message}`);
|
||||
this.endVoice(user); // 创建失败也补 stop_voice,避免座位动画卡在"说话中"
|
||||
});
|
||||
}
|
||||
|
||||
/** 语音播放完成/出错:通知 H5 停座位动画(gameui_stop_voice) + 释放播放器。一次性,防重复。 */
|
||||
private endVoice(user: string): void {
|
||||
if (this.currentVoiceUser !== user) {
|
||||
return; // 已被新语音取代或已结束
|
||||
}
|
||||
this.bridge?.callHandler(OutboundHandlers.GameUiStopVoice, user);
|
||||
this.releaseVoice();
|
||||
}
|
||||
|
||||
/** 播放本地音效/背景乐:<urlpath>/<gameContentDir>/assets/wav/<src>。isloop<0 停止该 src。 */
|
||||
|
||||
Reference in New Issue
Block a user