Add logs to debug missing spatial audio
And potentially fix it, by recreating the source node when the stream changes.
This commit is contained in:
parent
85959046a5
commit
0a5701b9fa
2 changed files with 62 additions and 51 deletions
|
@ -71,8 +71,8 @@ export function VideoTileContainer({
|
||||||
stream ?? null,
|
stream ?? null,
|
||||||
audioContext,
|
audioContext,
|
||||||
audioDestination,
|
audioDestination,
|
||||||
isLocal,
|
localVolume,
|
||||||
localVolume
|
isLocal
|
||||||
);
|
);
|
||||||
const {
|
const {
|
||||||
modalState: videoTileSettingsModalState,
|
modalState: videoTileSettingsModalState,
|
||||||
|
|
|
@ -20,6 +20,7 @@ import {
|
||||||
acquireContext,
|
acquireContext,
|
||||||
releaseContext,
|
releaseContext,
|
||||||
} from "matrix-js-sdk/src/webrtc/audioContext";
|
} from "matrix-js-sdk/src/webrtc/audioContext";
|
||||||
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
|
|
||||||
import { useSpatialAudio } from "../settings/useSetting";
|
import { useSpatialAudio } from "../settings/useSetting";
|
||||||
import { useEventTarget } from "../useEvents";
|
import { useEventTarget } from "../useEvents";
|
||||||
|
@ -213,10 +214,10 @@ export const useSpatialMediaStream = (
|
||||||
stream: MediaStream | null,
|
stream: MediaStream | null,
|
||||||
audioContext: AudioContext,
|
audioContext: AudioContext,
|
||||||
audioDestination: AudioNode,
|
audioDestination: AudioNode,
|
||||||
mute = false,
|
localVolume: number,
|
||||||
localVolume?: number
|
mute = false
|
||||||
): [RefObject<HTMLDivElement>, RefObject<MediaElement>] => {
|
): [RefObject<HTMLDivElement>, RefObject<MediaElement>] => {
|
||||||
const tileRef = useRef<HTMLDivElement>();
|
const tileRef = useRef<HTMLDivElement | null>(null);
|
||||||
const [spatialAudio] = useSpatialAudio();
|
const [spatialAudio] = useSpatialAudio();
|
||||||
// We always handle audio separately form the video element
|
// We always handle audio separately form the video element
|
||||||
const mediaRef = useMediaStream(stream, null, true);
|
const mediaRef = useMediaStream(stream, null, true);
|
||||||
|
@ -227,53 +228,63 @@ export const useSpatialMediaStream = (
|
||||||
const sourceRef = useRef<MediaStreamAudioSourceNode>();
|
const sourceRef = useRef<MediaStreamAudioSourceNode>();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (spatialAudio && tileRef.current && !mute && audioTrackCount > 0) {
|
if (spatialAudio) {
|
||||||
if (!pannerNodeRef.current) {
|
if (tileRef.current && !mute && audioTrackCount > 0) {
|
||||||
pannerNodeRef.current = new PannerNode(audioContext, {
|
logger.debug(`Rendering spatial audio for ${stream!.id}`);
|
||||||
panningModel: "HRTF",
|
|
||||||
refDistance: 3,
|
if (!pannerNodeRef.current) {
|
||||||
});
|
pannerNodeRef.current = new PannerNode(audioContext, {
|
||||||
|
panningModel: "HRTF",
|
||||||
|
refDistance: 3,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!gainNodeRef.current) {
|
||||||
|
gainNodeRef.current = new GainNode(audioContext, {
|
||||||
|
gain: localVolume,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!sourceRef.current || sourceRef.current.mediaStream !== stream!) {
|
||||||
|
sourceRef.current = audioContext.createMediaStreamSource(stream!);
|
||||||
|
}
|
||||||
|
|
||||||
|
const tile = tileRef.current;
|
||||||
|
const source = sourceRef.current;
|
||||||
|
const gainNode = gainNodeRef.current;
|
||||||
|
const pannerNode = pannerNodeRef.current;
|
||||||
|
|
||||||
|
const updatePosition = () => {
|
||||||
|
const bounds = tile.getBoundingClientRect();
|
||||||
|
const windowSize = Math.max(window.innerWidth, window.innerHeight);
|
||||||
|
// Position the source relative to its placement in the window
|
||||||
|
pannerNodeRef.current!.positionX.value =
|
||||||
|
(bounds.x + bounds.width / 2) / windowSize - 0.5;
|
||||||
|
pannerNodeRef.current!.positionY.value =
|
||||||
|
(bounds.y + bounds.height / 2) / windowSize - 0.5;
|
||||||
|
// Put the source in front of the listener
|
||||||
|
pannerNodeRef.current!.positionZ.value = -2;
|
||||||
|
};
|
||||||
|
|
||||||
|
gainNode.gain.value = localVolume;
|
||||||
|
updatePosition();
|
||||||
|
source.connect(gainNode).connect(pannerNode).connect(audioDestination);
|
||||||
|
// HACK: We abuse the CSS transitionrun event to detect when the tile
|
||||||
|
// moves, because useMeasure, IntersectionObserver, etc. all have no
|
||||||
|
// ability to track changes in the CSS transform property
|
||||||
|
tile.addEventListener("transitionrun", updatePosition);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
tile.removeEventListener("transitionrun", updatePosition);
|
||||||
|
source.disconnect();
|
||||||
|
gainNode.disconnect();
|
||||||
|
pannerNode.disconnect();
|
||||||
|
};
|
||||||
|
} else if (stream) {
|
||||||
|
logger.debug(
|
||||||
|
`Not rendering spatial audio for ${stream.id} (tile ref ${Boolean(
|
||||||
|
tileRef.current
|
||||||
|
)}, mute ${mute}, track count ${audioTrackCount})`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (!gainNodeRef.current) {
|
|
||||||
gainNodeRef.current = new GainNode(audioContext, {
|
|
||||||
gain: localVolume,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (!sourceRef.current) {
|
|
||||||
sourceRef.current = audioContext.createMediaStreamSource(stream!);
|
|
||||||
}
|
|
||||||
|
|
||||||
const tile = tileRef.current;
|
|
||||||
const source = sourceRef.current;
|
|
||||||
const gainNode = gainNodeRef.current;
|
|
||||||
const pannerNode = pannerNodeRef.current;
|
|
||||||
|
|
||||||
const updatePosition = () => {
|
|
||||||
const bounds = tile.getBoundingClientRect();
|
|
||||||
const windowSize = Math.max(window.innerWidth, window.innerHeight);
|
|
||||||
// Position the source relative to its placement in the window
|
|
||||||
pannerNodeRef.current!.positionX.value =
|
|
||||||
(bounds.x + bounds.width / 2) / windowSize - 0.5;
|
|
||||||
pannerNodeRef.current!.positionY.value =
|
|
||||||
(bounds.y + bounds.height / 2) / windowSize - 0.5;
|
|
||||||
// Put the source in front of the listener
|
|
||||||
pannerNodeRef.current!.positionZ.value = -2;
|
|
||||||
};
|
|
||||||
|
|
||||||
gainNode.gain.value = localVolume;
|
|
||||||
updatePosition();
|
|
||||||
source.connect(gainNode).connect(pannerNode).connect(audioDestination);
|
|
||||||
// HACK: We abuse the CSS transitionrun event to detect when the tile
|
|
||||||
// moves, because useMeasure, IntersectionObserver, etc. all have no
|
|
||||||
// ability to track changes in the CSS transform property
|
|
||||||
tile.addEventListener("transitionrun", updatePosition);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
tile.removeEventListener("transitionrun", updatePosition);
|
|
||||||
source.disconnect();
|
|
||||||
gainNode.disconnect();
|
|
||||||
pannerNode.disconnect();
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
stream,
|
stream,
|
||||||
|
|
Loading…
Add table
Reference in a new issue