InputChannelA Channel that receives its signal from an audio input device, such as a microphone or line-in, or from an existing MediaStream, such as the voice of another player received over WebRTC.
Because it extends Channel, effects, volume, panning and sends work exactly the same as on a normal channel. The input device can be switched at any time with setInputDevice(), without rebuilding the channel, its effects or its sends.
Extends Channel.
import { listAudioInputDevices, Compressor } from "@fluex/fluexgl-dsp";
const microphone = await audioDevice.createInputChannel(null, "Microphone");
microphone.addEffect(new Compressor({ threshold: -24, ratio: 4 }));
microphone.send(audioDevice.getMasterChannel());
// Later on, switch to another microphone without rebuilding anything.
const inputs = await listAudioInputDevices();
await microphone.setInputDevice(inputs[1]);
input device / MediaStream -> MediaStreamAudioSourceNode -> input -> [effects] -> panner -> analyser -> gain -> output
Everything from input onwards is the regular Channel chain. Switching the device only replaces the MediaStreamAudioSourceNode.
The channel is not connected to anything by default. Call send() to hear it. Monitoring a microphone through speakers can cause feedback, so use headphones while testing.
Constructs a new input channel. No device is opened yet: call setInputDevice() or setMediaStream() afterwards. audioDevice.createInputChannel() does both in one call.
new InputChannel(context: AudioContext, label?: string, options?: Partial<InputChannelOptions>): InputChannel;
context: AudioContext - The AudioContext used to create the audio nodes. Use the context of your AudioDevice.label?: string - Optional label. Defaults to "Input".options?: Partial<InputChannelOptions> - Capture options. Echo cancellation, noise suppression and automatic gain control are disabled by default, so effects receive the unprocessed signal.All properties of Channel, plus:
stream: MediaStream | nullThe stream this channel currently receives audio from. null when closed.
sourceNode: MediaStreamAudioSourceNode | nullThe node that feeds stream into input. null when closed.
deviceInfo: MediaDeviceInfo | nullThe input device that is currently open. null when closed, when the browser does not expose the device, or when an external stream is used (setMediaStream()).
options: InputChannelOptionsThe resolved capture options. Changes are applied the next time a device is opened. See InputChannelOptions.
All methods of Channel, plus:
setInputDevice(device?: MediaDeviceInfo | string | null): Promise<boolean>Opens (or switches to) the given input device. Passing nothing, null or "default" uses the system's default input device. The new device is opened before the old one is released, so the gap is as short as possible. Fires input-device-changed on success.
When this method is called again before the previous call finished, only the last call wins; earlier streams are stopped right away.
device?: MediaDeviceInfo | string | null - The input device (from listAudioInputDevices()), or its deviceId.boolean - true when the device has been opened, otherwise false.ERROR:FLUEXGL-DSP@0014 (ErrorCodes.CHANNEL_NOT_INITIALIZED) - The channel has no audio nodes.ERROR:FLUEXGL-DSP@0023 (ErrorCodes.INPUT_DEVICE_UNAVAILABLE) - Permission was denied, the device does not exist (anymore), or the stream could not be connected to the AudioContext (Firefox does not support input devices with a different sample rate than the context).open(device?: MediaDeviceInfo | string | null): Promise<boolean>Alias for setInputDevice(device).
setMediaStream(stream: MediaStream): booleanUses an existing MediaStream as input instead of opening an input device. Use this for audio that does not come from a local device, such as the voice of another player received over WebRTC. Combined with SpatialAudioSource.attachChannel() this gives positioned voice chat (proximity chat). Fires input-device-changed with current: null.
close() does not stop its tracks.input-device-lost is fired, but the channel never falls back to the local microphone.<audio> element.setInputDevice() calls.stream: MediaStream - A stream with at least one audio track.boolean - true when the stream is connected, otherwise false.ERROR:FLUEXGL-DSP@0014 (ErrorCodes.CHANNEL_NOT_INITIALIZED) - The channel has no audio nodes.ERROR:FLUEXGL-DSP@0023 (ErrorCodes.INPUT_DEVICE_UNAVAILABLE) - The stream has no audio tracks, or could not be connected to the AudioContext.close(): voidStops capturing. Tracks of a device opened by this channel are stopped (which turns off the browser's recording indicator); tracks of an external stream are left alone. The channel itself, its effects and its sends stay intact, so it can be opened again later.
No arguments
voidsetMuted(muted: boolean): InputChannelMutes or unmutes the input without closing it, by disabling the audio tracks.
muted: booleanInputChannel - The same channel.addEventListener(event, callback): () => voidRegisters a callback for one of the events below.
event: keyof InputChannelEventMap - "input-device-changed" or "input-device-lost".callback: InputChannelEventMap[event] - See InputChannelEventMap.() => void - A function that removes the listener again.removeEventListener(event, callback): InputChannelRemoves a previously registered callback.
InputChannel - The same channel.Registered with addEventListener(). See InputChannelEventMap.
| Event | Payload | Fired when |
|---|---|---|
| "input-device-changed" | AudioDeviceChangedEvent | A device was opened with setInputDevice(), or a stream was connected with setMediaStream(). |
| "input-device-lost" | AudioDeviceLostEvent | The device was unplugged, permission was revoked, or an external stream ended. Logs WARNING:FLUEXGL-DSP@0004 (WarningCodes.INPUT_DEVICE_LOST). For a local device with fallbackToDefault enabled, the default input device is opened afterwards. |
get isOpen(): booleanWhether the channel is currently receiving audio from a device or stream.
import { listAudioInputDevices, watchAudioDevices } from "@fluex/fluexgl-dsp";
const microphone = await audioDevice.createInputChannel(null, "Microphone");
microphone.send(audioDevice.getMasterChannel());
const select = document.querySelector("select")!;
function render(inputs: MediaDeviceInfo[]) {
select.replaceChildren(...inputs.map(input => new Option(input.label, input.deviceId)));
select.value = microphone.deviceInfo?.deviceId ?? "";
}
render(await listAudioInputDevices());
select.addEventListener("change", () => microphone.setInputDevice(select.value));
watchAudioDevices(({ inputs }) => render(inputs));
Echo cancellation, noise suppression and automatic gain control are disabled by default, which is what you want for music and effects. For speech, turn them on:
const voice = await audioDevice.createInputChannel(null, "Voice", {
echoCancellation: true,
noiseSuppression: true,
autoGainControl: true
});
import { InputChannel } from "@fluex/fluexgl-dsp";
peerConnection.addEventListener("track", (event) => {
const voice = new InputChannel(audioDevice.getContext(), "Player 2");
voice.setMediaStream(event.streams[0]);
voice.send(audioDevice.getMasterChannel());
voice.addEventListener("input-device-lost", () => {
voice.unsendFromAll();
});
});
See Example 11: Proximity voice chat for positioning voices in a game world.