fix(media): align SFU audio and playback state (#258)

This commit is contained in:
AAA authored and GitHub committed 2026-08-25 13:14:26 +08:00
1 parent 31d8b354c0
commit 52dca9a3aa
4 files changed
+54 -1

No files matched your search

+7 -1
View File
@@ -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),
+1
View File
@@ -1241,6 +1241,7 @@ function audioPublishOptions(
audioPreset,
forceStereo: true,
dtx: false,
red: false,
};
}
+5
View File
@@ -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,
});
});
+41
View File
@@ -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" },