MWSE/sdk/webrtc/MediaSources.js

99 lines
3.5 KiB
JavaScript

// Static factory methods for common media sources.
//
// All methods return a MediaStream so they can be passed directly to
// StreamManager.addStream(label, stream).
export const MediaSources = {
// Single camera (video only by default).
async camera(constraints = {}) {
return navigator.mediaDevices.getUserMedia({
video: constraints.video ?? true,
audio: constraints.audio ?? false
});
},
// Microphone (audio only).
async microphone(constraints = {}) {
return navigator.mediaDevices.getUserMedia({
audio: constraints.audio ?? true,
video: false
});
},
// Camera + microphone together.
async cameraAndMic(constraints = {}) {
return navigator.mediaDevices.getUserMedia({
video: constraints.video ?? true,
audio: constraints.audio ?? true
});
},
// Screen / window / tab sharing via getDisplayMedia.
async screen(constraints = {}) {
return navigator.mediaDevices.getDisplayMedia({
video: constraints.video ?? { cursor: 'always' },
audio: constraints.audio ?? false
});
},
// Enumerate available media devices.
async devices() {
const all = await navigator.mediaDevices.enumerateDevices();
return {
cameras: all.filter(d => d.kind === 'videoinput'),
microphones: all.filter(d => d.kind === 'audioinput'),
speakers: all.filter(d => d.kind === 'audiooutput')
};
},
// Play a pre-decoded AudioBuffer as a continuous MediaStream.
// Useful for replacing the live microphone with an audio file.
// Returns the MediaStream; the AudioContext is attached as ._ctx for cleanup.
fromAudioBuffer(audioBuffer, { loop = false } = {}) {
const ctx = new AudioContext();
const src = ctx.createBufferSource();
src.buffer = audioBuffer;
src.loop = loop;
const dest = ctx.createMediaStreamDestination();
src.connect(dest);
src.start();
const stream = dest.stream;
stream._ctx = ctx; // caller can close() to free resources
stream._src = src;
return stream;
},
// Capture a <canvas> or OffscreenCanvas as a video MediaStream.
fromCanvas(canvas, fps = 30) {
if (typeof canvas.captureStream === 'function') {
return canvas.captureStream(fps);
}
if (typeof canvas.transferControlToOffscreen === 'function') {
throw new Error(
'fromCanvas: pass the OffscreenCanvas, not the original canvas, ' +
'or use fromOffscreenCanvas()'
);
}
throw new Error('fromCanvas: captureStream() not supported on this element');
},
// Create an AudioContext-based mixing bus and capture its output as a
// MediaStream. Useful for compositing multiple audio sources before sending.
// Returns { ctx, dest, stream } — add nodes to ctx and connect to dest.
createAudioMix() {
const ctx = new AudioContext();
const dest = ctx.createMediaStreamDestination();
return { ctx, dest, stream: dest.stream };
},
// Fetch and decode an audio file URL into an AudioBuffer.
async loadAudioFile(url) {
const ctx = new AudioContext();
const resp = await fetch(url);
const ab = await resp.arrayBuffer();
const buf = await ctx.decodeAudioData(ab);
await ctx.close();
return buf; // pass to fromAudioBuffer()
}
};