fix(conversation): 修复实时会话 TTS/回复被离屏 WS 抢占
- 列表预热仅预取消息缓存,避免后台 WebSocket 覆盖服务端连接 - RealtimeSession UI 回调按 owner 独占,防止 offscreen 覆盖聊天页 - 列表页聚焦时再 prewarm,会话页 TTS 入队优先 base64 - 管线下发 TTS 同时带 audio_base64 与 audio_url;协议说明同步 - 移除 TTS 排查用前后端调试日志,保留错误/告警 - 补充 WS / RealtimeSession / entry-warmup / 播放器相关单测 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -37,6 +37,7 @@ describe('usePlayer', () => {
|
||||
});
|
||||
jest.mocked(audioFocus.acquireForPlayback).mockResolvedValue(true);
|
||||
jest.mocked(audioFocus.releaseIfOwnedBy).mockResolvedValue(undefined);
|
||||
jest.mocked(audioFocus.onOwnerChange).mockImplementation(() => jest.fn());
|
||||
});
|
||||
|
||||
test('keeps the native audio session active while app-level audio focus owns teardown', () => {
|
||||
@@ -127,4 +128,43 @@ describe('usePlayer', () => {
|
||||
expect(pause).not.toHaveBeenCalled();
|
||||
expect(result.current.status).toBe('idle');
|
||||
});
|
||||
|
||||
test('retries queued audio after acquire fails once then audio focus frees', async () => {
|
||||
const acquire = jest.mocked(audioFocus.acquireForPlayback);
|
||||
acquire.mockResolvedValueOnce(false).mockResolvedValue(true);
|
||||
|
||||
let ownerListener: ((owner: null | string) => void) | undefined;
|
||||
jest.mocked(audioFocus.onOwnerChange).mockImplementation((cb) => {
|
||||
ownerListener = cb as (owner: null | string) => void;
|
||||
return jest.fn();
|
||||
});
|
||||
|
||||
mockUseAudioPlayerStatus.mockReturnValue({
|
||||
isLoaded: true,
|
||||
playing: false,
|
||||
currentTime: 0,
|
||||
duration: 10,
|
||||
});
|
||||
const play = jest.fn();
|
||||
mockUseAudioPlayer.mockReturnValue({ pause: jest.fn(), play });
|
||||
|
||||
const { result } = renderHook(() => usePlayer());
|
||||
|
||||
await act(async () => {
|
||||
await result.current.enqueue({
|
||||
uri: 'file:///queued.mp3',
|
||||
kind: 'tts_auto',
|
||||
});
|
||||
});
|
||||
|
||||
expect(acquire).toHaveBeenCalledTimes(1);
|
||||
expect(result.current.status).toBe('idle');
|
||||
|
||||
await act(async () => {
|
||||
ownerListener?.(null);
|
||||
});
|
||||
|
||||
expect(acquire).toHaveBeenCalledTimes(2);
|
||||
expect(play).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user