Skip to content

fix: resume audio context#915

Open
HardyNLee wants to merge 1 commit intoOpenWebGAL:devfrom
HardyNLee:fix/resume-audio-context
Open

fix: resume audio context#915
HardyNLee wants to merge 1 commit intoOpenWebGAL:devfrom
HardyNLee:fix/resume-audio-context

Conversation

@HardyNLee
Copy link
Contributor

介绍

Warning

AI CODED PULL REQUEAST

修复 web 构建产物,会因为玩家的浏览器的自动播放设置被拦截,导致 audioContext.state 为 suspended,导致语音不播放和口型没有被驱动

更改

  • 不在脚本初始化阶段就新建 audio context,而是按需创建
  • 若 audio context 的 state 为 suspended,则会尝试 resume, 若还是失败,则跳过口型驱动并 log warn,避免连带无法播放语音
  • 顺带修复了 audio threshold 没有被重置的问题

测试

  1. 一定要确保用 web 构建产物测试,yarn dev 时,用 webgal_terre 编辑时和导出为 electron 时是没有问题的
  2. 确保浏览器的媒体自动播放策略不为始终允许
  • 以 Edge 为例,将 媒体自动播放 设置为 限制(默认值)
  1. 测试如下代码
changeBg:bg.webp;
changeFigure:anon/casual/model.json -id=x;
测试对话:aaaaaaa -v1.wav -figureId=x;
;

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

此合并请求旨在解决 Web 构建中因浏览器自动播放策略导致 AudioContext 挂起,进而造成语音无法播放和口型不同步的问题。通过将音频上下文的初始化改为按需创建,并引入了在上下文挂起时尝试恢复的机制,同时增强了语音播放的错误处理能力。这些改进确保了在严格的浏览器自动播放环境下,语音功能能够正常运行,并正确重置音频阈值,从而提升了用户体验。

Highlights

  • 按需创建 AudioContext: 音频上下文 (AudioContext) 的创建现在改为按需进行,而非在脚本初始化阶段。
  • AudioContext 状态处理: 当音频上下文处于“挂起”状态时,会尝试恢复;如果恢复失败,则会跳过口型同步驱动并记录警告。
  • 修复音频阈值重置: 修复了 maxAudioLevel (音频阈值) 未被重置的问题。
  • 自动播放策略错误处理: 增加了对浏览器自动播放策略拦截语音播放的错误处理。
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

这个 PR 很好地解决了浏览器自动播放策略导致音频上下文(AudioContext)被挂起的问题。主要改动包括:

  1. AudioContext 的创建改为按需创建,而不是在脚本初始化时创建。
  2. 在播放语音前,通过新的 ensureAudioContextReady 函数确保 AudioContext 处于 'running' 状态,如果失败则会跳过口型同步并记录警告,避免阻塞语音播放。
  3. VocalControl.play() 添加了 Promise 的 catch 处理,以优雅地处理播放被浏览器阻止的情况。
  4. 通过 finishPerform 函数重构了演出结束的逻辑,提高了代码的复用性。
  5. 修复了 maxAudioLevel 没有被重置的问题。

这些改动增强了应用的鲁棒性。我提出了一些关于类型安全的小建议,请查看具体的评论。

Comment on lines +144 to +147
audioContextWrapper.source.connect(audioContextWrapper.analyser);
}

performMouthAnimation({
audioLevel,
OPEN_THRESHOLD,
HALF_OPEN_THRESHOLD,
currentMouthValue,
lerpSpeed,
key,
animationItem,
pos,
});
}, 50);
audioContextWrapper.analyser.connect(audioContextWrapper.audioContext.destination);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

audioContextWrapper.analyser 的类型是 AnalyserNode | undefined。虽然在前面的代码中已经对其进行了初始化,但 TypeScript 编译器可能无法在此处推断出其为非空。为了代码的健壮性和避免潜在的运行时错误,建议在调用 .connect 之前使用非空断言 !

Suggested change
audioContextWrapper.source.connect(audioContextWrapper.analyser);
}
performMouthAnimation({
audioLevel,
OPEN_THRESHOLD,
HALF_OPEN_THRESHOLD,
currentMouthValue,
lerpSpeed,
key,
animationItem,
pos,
});
}, 50);
audioContextWrapper.analyser.connect(audioContextWrapper.audioContext.destination);
audioContextWrapper.source.connect(audioContextWrapper.analyser!);
}
audioContextWrapper.analyser!.connect(audioContextWrapper.audioContext.destination);

dataArray: Uint8Array,
bufferLength: number,
): number => {
analyser.getByteFrequencyData(dataArray as any);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

在这里使用 as any 类型断言是不必要的,并且会降低代码的类型安全性。getAudioLevel 函数的签名已经明确指出 dataArray 的类型是 Uint8Array,这与 analyser.getByteFrequencyData 方法的参数类型相匹配。建议移除 as any

Suggested change
analyser.getByteFrequencyData(dataArray as any);
analyser.getByteFrequencyData(dataArray);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant