diff --git a/src/client/media/viewer-presentation.ts b/src/client/media/viewer-presentation.ts index ed0c014..e12d8b7 100644 --- a/src/client/media/viewer-presentation.ts +++ b/src/client/media/viewer-presentation.ts @@ -219,6 +219,11 @@ export function reduceViewerPresentation( : state.autoplayBlockedGeneration, retainedFrame: state.retainedFrame || (revisionChanged && currentFrame), + connection: revisionChanged + ? action.kind === "none" + ? "idle" + : "connecting" + : state.connection, failure: revisionChanged && (state.failure === "ROUTE_EXHAUSTED" || @@ -478,7 +483,8 @@ export function deriveViewerPresentation( if ( state.media && state.media.revision === state.revision && - state.autoplayBlockedGeneration === state.media.generation + state.autoplayBlockedGeneration === state.media.generation && + state.connection === "connected" ) { return { ...presentation("needs-play", "需要点击播放", "blocking", state), diff --git a/src/client/sfu/publisher.ts b/src/client/sfu/publisher.ts index 2e94acd..cf50fc0 100644 --- a/src/client/sfu/publisher.ts +++ b/src/client/sfu/publisher.ts @@ -1241,6 +1241,7 @@ function audioPublishOptions( audioPreset, forceStereo: true, dtx: false, + red: false, }; } diff --git a/tests/sfu-client.test.ts b/tests/sfu-client.test.ts index 894af8d..4c1efdb 100644 --- a/tests/sfu-client.test.ts +++ b/tests/sfu-client.test.ts @@ -677,6 +677,7 @@ describe("SfuPublisher", () => { audioPreset: { maxBitrate: 128_000 }, forceStereo: true, dtx: false, + red: false, }); expect(sender.setParameters).toHaveBeenCalledOnce(); expect(sender.parameters.encodings).toEqual([ @@ -734,6 +735,7 @@ describe("SfuPublisher", () => { audioPreset: { maxBitrate: bitrate }, forceStereo: true, dtx: false, + red: false, }); }); @@ -824,6 +826,7 @@ describe("SfuPublisher", () => { audioPreset: { maxBitrate: 256_000 }, forceStereo: true, dtx: false, + red: false, }); expect(publisher.getAudioSenderParameters()).toEqual({ requestedMaxBitrate: 256_000, @@ -837,6 +840,7 @@ describe("SfuPublisher", () => { audioPreset: { maxBitrate: 256_000 }, forceStereo: true, dtx: false, + red: false, }); }); @@ -1392,6 +1396,7 @@ describe("SfuPublisher", () => { audioPreset: { maxBitrate: 256_000 }, forceStereo: true, dtx: false, + red: false, }); }); diff --git a/tests/viewer-presentation.test.ts b/tests/viewer-presentation.test.ts index 3c44e87..83ad472 100644 --- a/tests/viewer-presentation.test.ts +++ b/tests/viewer-presentation.test.ts @@ -58,6 +58,7 @@ describe("Viewer presentation reducer", () => { { type: "route", revision: 2, phase: "active", kind: "sfu" }, { type: "media-bound", generation: 4, revision: 2 }, { type: "autoplay-blocked", generation: 4, revision: 2 }, + { type: "connection", revision: 2, connection: "connected" }, ); expect(deriveViewerPresentation(blocked)).toMatchObject({ stage: "needs-play", @@ -81,6 +82,46 @@ describe("Viewer presentation reducer", () => { }); }); + it("waits for the current media connection before showing Play", () => { + const blockedWhileConnecting = apply( + { type: "access", access: "ready" }, + { type: "host", host: "online" }, + { type: "route", revision: 2, phase: "active", kind: "p2p" }, + { type: "media-bound", generation: 4, revision: 2 }, + { type: "autoplay-blocked", generation: 4, revision: 2 }, + ); + expect(deriveViewerPresentation(blockedWhileConnecting)).toMatchObject({ + stage: "receiving", + showPlay: false, + }); + + const connected = reduceViewerPresentation(blockedWhileConnecting, { + type: "connection", + revision: 2, + connection: "connected", + }); + expect(deriveViewerPresentation(connected)).toMatchObject({ + stage: "needs-play", + showPlay: true, + }); + }); + + it("does not reuse a connected fact after the route revision advances", () => { + const connected = apply( + { type: "access", access: "ready" }, + { type: "host", host: "online" }, + { type: "route", revision: 2, phase: "active", kind: "p2p" }, + { type: "connection", revision: 2, connection: "connected" }, + ); + const nextRoute = reduceViewerPresentation(connected, { + type: "route", + revision: 3, + phase: "prepare", + kind: "sfu", + }); + expect(nextRoute.connection).toBe("connecting"); + }); + it("ignores a late playback failure from a replaced media binding", () => { const rebound = apply( { type: "access", access: "ready" },