wip
This commit is contained in:
@@ -21,42 +21,45 @@ export function useAudioSource(
|
||||
>(new WeakMap());
|
||||
|
||||
useEffect(() => {
|
||||
if (!source) {
|
||||
setAudioSource(null);
|
||||
return;
|
||||
}
|
||||
// Build the source node (creating an AudioContext as needed) plus optional
|
||||
// teardown for contexts we own; the branches converge on one setState.
|
||||
let result: AudioSource | null = null;
|
||||
let cleanup: (() => void) | undefined;
|
||||
|
||||
if (source instanceof MediaStream) {
|
||||
const ctx = new AudioContext();
|
||||
ctx.resume();
|
||||
const sourceNode = ctx.createMediaStreamSource(source);
|
||||
setAudioSource({ sourceNode, ctx });
|
||||
|
||||
return () => {
|
||||
ctx.close();
|
||||
};
|
||||
result = { sourceNode, ctx };
|
||||
cleanup = () => ctx.close();
|
||||
} else if (source) {
|
||||
// HTMLAudioElement — createMediaElementSource can only be called once per
|
||||
// element, so reuse a cached context/node when we have one.
|
||||
const cached = elementSourceCache.current.get(source);
|
||||
if (cached) {
|
||||
cached.ctx.resume();
|
||||
result = cached;
|
||||
} else {
|
||||
const ctx = new AudioContext();
|
||||
ctx.resume();
|
||||
const sourceNode = ctx.createMediaElementSource(source);
|
||||
// Connect element source to destination so audio is still audible
|
||||
sourceNode.connect(ctx.destination);
|
||||
elementSourceCache.current.set(source, { sourceNode, ctx });
|
||||
result = { sourceNode, ctx };
|
||||
cleanup = () => {
|
||||
ctx.close();
|
||||
elementSourceCache.current.delete(source);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// HTMLAudioElement — createMediaElementSource can only be called once per element
|
||||
const cached = elementSourceCache.current.get(source);
|
||||
if (cached) {
|
||||
cached.ctx.resume();
|
||||
setAudioSource(cached);
|
||||
return;
|
||||
}
|
||||
// Publishing an imperatively-created Web Audio node — external-resource
|
||||
// sync, not a re-render cascade.
|
||||
// eslint-disable-next-line react-hooks/set-state-in-effect
|
||||
setAudioSource(result);
|
||||
|
||||
const ctx = new AudioContext();
|
||||
ctx.resume();
|
||||
const sourceNode = ctx.createMediaElementSource(source);
|
||||
// Connect element source to destination so audio is still audible
|
||||
sourceNode.connect(ctx.destination);
|
||||
elementSourceCache.current.set(source, { sourceNode, ctx });
|
||||
setAudioSource({ sourceNode, ctx });
|
||||
|
||||
return () => {
|
||||
ctx.close();
|
||||
elementSourceCache.current.delete(source);
|
||||
};
|
||||
return cleanup;
|
||||
}, [source]);
|
||||
|
||||
return audioSource;
|
||||
|
||||
@@ -23,16 +23,13 @@ export function ScreenSourcePicker({
|
||||
getSources().then((result) => {
|
||||
setSources(result);
|
||||
setLoading(false);
|
||||
// Auto-select if there's only one source.
|
||||
if (result.length === 1) {
|
||||
setSelectedId(result[0].id);
|
||||
}
|
||||
});
|
||||
}, [getSources]);
|
||||
|
||||
// Auto-select if there's only one source
|
||||
useEffect(() => {
|
||||
if (!loading && sources.length === 1) {
|
||||
setSelectedId(sources[0].id);
|
||||
}
|
||||
}, [loading, sources]);
|
||||
|
||||
const screens = sources.filter((s) => s.id.startsWith("screen:"));
|
||||
const windows = sources.filter((s) => s.id.startsWith("window:"));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user