tiny-server-essentials
Version:
A good utility toolkit to unify Express v5 and Socket.IO v4 into a seamless development experience with modular helpers, server wrappers, and WebSocket tools.
662 lines • 28.7 kB
text/typescript
/** @typedef {'mic'|'cam'|'screen'} StreamTypes */
/** @typedef {'Mic'|'Cam'|'Screen'} StreamEventTypes */
/** @typedef {import('./TinyMediaReceiver.mjs').ReceiverTags} ReceiverTags */
/**
* @typedef {Object} StreamConfig
* @property {string} mimeType - A valid MIME type for MediaRecorder.
* @property {number} timeslice - Interval in milliseconds for emitting data chunks.
* @property {string|null} audioCodec - Audio codec that can be used
* @property {string|null} videoCodec - Video codec that can be used
*/
/**
* @typedef {Object} MandatoryConstraints
* @property {'screen'|'window'|'application'|'desktop'} [chromeMediaSource]
* Capture source for Chrome/Electron.
* @property {string} [chromeMediaSourceId]
* Specific ID of the capture source (usually obtained via desktopCapturer).
* @property {number} [maxWidth]
* Maximum width of the capture.
* @property {number} [maxHeight]
* Maximum height of the capture.
* @property {number} [maxFrameRate]
* Maximum frame rate.
* @property {number} [minWidth]
* Minimum width of the capture.
* @property {number} [minHeight]
* Minimum height of the capture.
* @property {number} [minFrameRate]
* Minimum frame rate.
* @property {boolean} [googLeakyBucket]
* Experimental setting used in some Chromium versions.
* @property {boolean} [googTemporalLayeredScreencast]
* Experimental setting for temporal layers in screen capture.
*/
/**
* @typedef {Object} AdvancedScreenVideoConstraints
* @property {'screen'|'window'|'application'|'browser'|'monitor'} [mediaSource]
* Capture source, useful in Electron and Firefox.
* @property {string} [chromeMediaSource]
* Used in older versions of Chrome/Electron. Usually 'desktop'.
* @property {string} [chromeMediaSourceId]
* Used in Electron to select a specific screen or window.
* @property {number} [frameRate]
* Desired capture frame rate (e.g., 30 or 60).
* @property {number} [width]
* Ideal capture width.
* @property {number} [height]
* Ideal capture height.
* @property {MandatoryConstraints} [mandatory]
* Allows configuring advanced fields in Electron/Chrome (like `chromeMediaSource`).
*/
/**
* @typedef {Object} ScreenShareConstraints
* @property {boolean|MediaTrackConstraints} [audio]
* @property {boolean|AdvancedScreenVideoConstraints|MediaTrackConstraints} video
* Constraints for screen capture, can be simple (true) or detailed.
*/
/**
* Manages media streams (microphone, camera, screen) with flexible device constraints,
* socket emission support, and audio volume metering.
*
* This class:
* - Allows starting and managing media input streams (mic, cam, screen).
* - Supports custom constraints and device targeting via deviceId or full constraint objects.
* - Emits media streams to a socket or handler using predefined labels (mic, cam, screen, etc.).
* - Provides audio volume metering for microphone and screen when audio is available.
* - Supports Electron-specific constraints when applicable.
*
* Events emitted:
* - `"Mic"`: Audio stream from microphone.
* - `"MicMeter"`: Volume level from microphone.
* - `"Cam"`: Video stream from webcam.
* - `"Screen"`: Video stream from screen capture.
* - `"ScreenMeter"`: Volume level from screen audio.
*
* Internally uses:
* - `navigator.mediaDevices.getUserMedia` for mic/cam.
* - `navigator.mediaDevices.getDisplayMedia` for screen sharing.
* - Optional support for `chromeMediaSource` and related properties in Electron environments.
*
* @class
* @beta
*/
export class TinyStreamManager {
/**
* Event labels used internally and externally for stream control and monitoring.
* These events are emitted or listened to over socket or internal dispatch.
* @readonly
*/
readonly Events: {
/**
* Event name emitted when the instance is destroyed.
* This constant can be used to subscribe to the destruction event of the instance.
* @type {'Destroyed'}
*/
Destroyed: "Destroyed";
/**
* Emitted when a media data receiver (e.g., WebSocket, PeerConnection, etc.) has been removed.
* This may happen when a connection is closed or explicitly terminated.
* @type {'ReceiverDeleted'}
*/
ReceiverDeleted: "ReceiverDeleted";
/**
* Emitted when a new media data receiver has been added to the stream.
* Useful for dynamic systems where receivers can join at runtime.
* @type {'ReceiverAdded'}
*/
ReceiverAdded: "ReceiverAdded";
/**
* Event emitted to request starting the webcam stream.
* @type {'StartCam'}
*/
StartCam: "StartCam";
/**
* Event emitted to request starting the microphone stream.
* @type {'StartMic'}
*/
StartMic: "StartMic";
/**
* Event emitted to request starting the screen sharing stream.
* @type {'StartScreen'}
*/
StartScreen: "StartScreen";
/**
* Event emitted to request stopping the webcam stream.
* @type {'StopCam'}
*/
StopCam: "StopCam";
/**
* Event emitted to request stopping the microphone stream.
* @type {'StopMic'}
*/
StopMic: "StopMic";
/**
* Event emitted to request stopping the screen sharing stream.
* @type {'StopScreen'}
*/
StopScreen: "StopScreen";
/**
* Event emitted when the webcam stream is transmitted.
* @type {'Cam'}
*/
Cam: "Cam";
/**
* Event emitted when the microphone stream is transmitted.
* @type {'Mic'}
*/
Mic: "Mic";
/**
* Event emitted when the screen sharing stream is transmitted.
* @type {'Screen'}
*/
Screen: "Screen";
/**
* Event emitted periodically with screen audio volume data.
* @type {'ScreenMeter'}
*/
ScreenMeter: "ScreenMeter";
/**
* Event emitted periodically with microphone audio volume data.
* @type {'MicMeter'}
*/
MicMeter: "MicMeter";
};
/**
* Checks whether a given event name is defined in the Events map.
*
* This method verifies if the provided string matches one of the predefined
* event labels (e.g., "Mic", "Cam", "Screen", "MicMeter", "ScreenMeter").
*
* @param {string} name - The name of the event to check.
* @returns {boolean} Returns `true` if the event exists in the Events map, otherwise `false`.
*/
existsEvent(name: string): boolean;
/**
* Provides access to a secure internal EventEmitter for subclass use only.
*
* This method exposes a dedicated EventEmitter instance intended specifically for subclasses
* that extend the main class. It prevents subclasses from accidentally or intentionally using
* the primary class's public event system (`emit`), which could lead to unpredictable behavior
* or interference in the base class's event flow.
*
* For security and consistency, this method is designed to be accessed only once.
* Multiple accesses are blocked to avoid leaks or misuse of the internal event bus.
*
* @returns {EventEmitter} A special internal EventEmitter instance for subclass use.
* @throws {Error} If the method is called more than once.
*/
getSysEvents(): EventEmitter;
/**
* @typedef {(...args: any[]) => void} ListenerCallback
* A generic callback function used for event listeners.
*/
/**
* Sets the maximum number of listeners for the internal event emitter.
*
* @param {number} max - The maximum number of listeners allowed.
*/
setMaxListeners(max: number): void;
/**
* Emits an event with optional arguments.
* @param {string | symbol} event - The name of the event to emit.
* @param {...any} args - Arguments passed to event listeners.
* @returns {boolean} `true` if the event had listeners, `false` otherwise.
*/
emit(event: string | symbol, ...args: any[]): boolean;
/**
* Registers a listener for the specified event.
* @param {string | symbol} event - The name of the event to listen for.
* @param {ListenerCallback} listener - The callback function to invoke.
* @returns {this} The current class instance (for chaining).
*/
on(event: string | symbol, listener: (...args: any[]) => void): this;
/**
* Registers a one-time listener for the specified event.
* @param {string | symbol} event - The name of the event to listen for once.
* @param {ListenerCallback} listener - The callback function to invoke.
* @returns {this} The current class instance (for chaining).
*/
once(event: string | symbol, listener: (...args: any[]) => void): this;
/**
* Removes a listener from the specified event.
* @param {string | symbol} event - The name of the event.
* @param {ListenerCallback} listener - The listener to remove.
* @returns {this} The current class instance (for chaining).
*/
off(event: string | symbol, listener: (...args: any[]) => void): this;
/**
* Alias for `on`.
* @param {string | symbol} event - The name of the event.
* @param {ListenerCallback} listener - The callback to register.
* @returns {this} The current class instance (for chaining).
*/
addListener(event: string | symbol, listener: (...args: any[]) => void): this;
/**
* Alias for `off`.
* @param {string | symbol} event - The name of the event.
* @param {ListenerCallback} listener - The listener to remove.
* @returns {this} The current class instance (for chaining).
*/
removeListener(event: string | symbol, listener: (...args: any[]) => void): this;
/**
* Removes all listeners for a specific event, or all events if no event is specified.
* @param {string | symbol} [event] - The name of the event. If omitted, all listeners from all events will be removed.
* @returns {this} The current class instance (for chaining).
*/
removeAllListeners(event?: string | symbol): this;
/**
* Returns the number of times the given `listener` is registered for the specified `event`.
* If no `listener` is passed, returns how many listeners are registered for the `event`.
* @param {string | symbol} eventName - The name of the event.
* @param {Function} [listener] - Optional listener function to count.
* @returns {number} Number of matching listeners.
*/
listenerCount(eventName: string | symbol, listener?: Function): number;
/**
* Adds a listener function to the **beginning** of the listeners array for the specified event.
* The listener is called every time the event is emitted.
* @param {string | symbol} eventName - The event name.
* @param {ListenerCallback} listener - The callback function.
* @returns {this} The current class instance (for chaining).
*/
prependListener(eventName: string | symbol, listener: (...args: any[]) => void): this;
/**
* Adds a **one-time** listener function to the **beginning** of the listeners array.
* The next time the event is triggered, this listener is removed and then invoked.
* @param {string | symbol} eventName - The event name.
* @param {ListenerCallback} listener - The callback function.
* @returns {this} The current class instance (for chaining).
*/
prependOnceListener(eventName: string | symbol, listener: (...args: any[]) => void): this;
/**
* Returns an array of event names for which listeners are currently registered.
* @returns {(string | symbol)[]} Array of event names.
*/
eventNames(): (string | symbol)[];
/**
* Gets the current maximum number of listeners allowed for any single event.
* @returns {number} The max listener count.
*/
getMaxListeners(): number;
/**
* Returns a copy of the listeners array for the specified event.
* @param {string | symbol} eventName - The event name.
* @returns {Function[]} An array of listener functions.
*/
listeners(eventName: string | symbol): Function[];
/**
* Returns a copy of the internal listeners array for the specified event,
* including wrapper functions like those used by `.once()`.
* @param {string | symbol} eventName - The event name.
* @returns {Function[]} An array of raw listener functions.
*/
rawListeners(eventName: string | symbol): Function[];
/** @type {VolumeMeter|null} */
micMeter: VolumeMeter | null;
/** @type {VolumeMeter|null} */
screenMeter: VolumeMeter | null;
/** @type {MediaStream|null} */
micStream: MediaStream | null;
/** @type {MediaStream|null} */
camStream: MediaStream | null;
/** @type {MediaStream|null} */
screenStream: MediaStream | null;
/**
* Updates the configuration for a specific media source.
*
* @param {StreamTypes} target - The config to update.
* @param {{ mimeType?: string, timeslice?: number }} updates - The new configuration values.
*
* @throws {Error} If the target is invalid.
* @throws {Error} If the mimeType is invalid or unsupported.
* @throws {Error} If the timeslice is not a positive finite number.
*/
updateMediaConfig(target: StreamTypes, updates?: {
mimeType?: string;
timeslice?: number;
}): void;
/**
* Returns the current microphone stream if it is a valid MediaStream.
*
* @returns {MediaStream} The active microphone stream.
* @throws {Error} If the microphone stream is not a valid MediaStream.
*/
getMicStream(): MediaStream;
/**
* Returns the current webcam stream if it is a valid MediaStream.
*
* @returns {MediaStream} The active webcam stream.
* @throws {Error} If the webcam stream is not a valid MediaStream.
*/
getCamStream(): MediaStream;
/**
* Returns the current screen sharing stream if it is a valid MediaStream.
*
* @returns {MediaStream} The active screen sharing stream.
* @throws {Error} If the screen stream is not a valid MediaStream.
*/
getScreenStream(): MediaStream;
/**
* Returns the current microphone volume meter if it is a valid VolumeMeter instance.
*
* @returns {VolumeMeter} The active microphone volume meter.
* @throws {Error} If the microphone meter is not a valid VolumeMeter instance.
*/
getMicMeter(): VolumeMeter;
/**
* Returns the current screen volume meter if it is a valid VolumeMeter instance.
*
* @returns {VolumeMeter} The active screen volume meter.
* @throws {Error} If the screen meter is not a valid VolumeMeter instance.
*/
getScreenMeter(): VolumeMeter;
/**
* Checks if the microphone volume meter exists and is a valid VolumeMeter instance.
*
* @returns {boolean} True if micMeter exists and is valid, false otherwise.
*/
hasMicMeter(): boolean;
/**
* Checks if the screen volume meter exists and is a valid VolumeMeter instance.
*
* @returns {boolean} True if screenMeter exists and is valid, false otherwise.
*/
hasScreenMeter(): boolean;
/**
* Updates the internal list of available media devices.
*
* This method queries the user's system for media input and output devices using
* `navigator.mediaDevices.enumerateDevices()` and categorizes them into three groups:
* video inputs, audio inputs, and audio outputs (speakers). The result is stored in the
* `this.devices` object and also returned for immediate use.
*
* If the device list cannot be retrieved, it falls back to setting all categories as empty arrays.
*
* @returns {Promise<{ video: MediaDeviceInfo[], audio: MediaDeviceInfo[], speaker: MediaDeviceInfo[] }>}
* A promise resolving to an object containing categorized media devices.
*/
updateDeviceList(): Promise<{
video: MediaDeviceInfo[];
audio: MediaDeviceInfo[];
speaker: MediaDeviceInfo[];
}>;
/**
* Retrieves a list of media devices filtered by the specified kind.
*
* This method strictly enforces the kind to be one of: 'audio', 'video', or 'speaker'.
* It throws an error if the input is not a string, not one of the allowed kinds,
* or if no devices are available for the given kind.
*
* @param {'audio' | 'video' | 'speaker'} kind - The type of device to retrieve.
* @returns {MediaDeviceInfo[]} An array of media devices matching the specified kind.
* @throws {Error} If the input is not a string.
* @throws {RangeError} If the input is not one of the accepted device kinds.
* @throws {Error} If no devices are found for the given kind.
*/
getDevicesByKind(kind: "audio" | "video" | "speaker"): MediaDeviceInfo[];
/**
* Returns an array containing all available audio, video, and speaker devices.
*
* This method throws an error if the manager is not yet initialized.
*
* @returns {MediaDeviceInfo[]} An array of all available media devices.
* @throws {Error} If the manager is not yet initialized.
*/
getAllDevices(): MediaDeviceInfo[];
/**
* Starts capturing audio from the microphone with flexible constraints.
*
* If a deviceId is provided, it targets a specific microphone. You can also pass in
* a full MediaTrackConstraints object to fine-tune behavior (e.g., noise suppression, echo cancellation).
*
* This method:
* - Emits the audio stream over the socket under the label `"mic"`.
* - Starts volume monitoring and emits microphone volume under the label `"micMeter"`.
*
* @param {string|MediaTrackConstraints|null} options - Either a deviceId string, a full constraints object, or null for defaults.
* @param {boolean} hearVoice - `true` = Hear your voice.
* @returns {Promise<MediaStream>} A promise resolving to the active audio stream.
* @throws {Error} If the deviceId is invalid or if no audio track is found in the stream.
*/
startMic(options?: string | MediaTrackConstraints | null, hearVoice?: boolean): Promise<MediaStream>;
/**
* Starts capturing video from the webcam with flexible constraints.
*
* Accepts a deviceId string for a specific webcam, or a full MediaTrackConstraints
* object to customize video input (resolution, frameRate, etc.).
*
* This method:
* - Emits the video stream over the socket under the label `"cam"`.
*
* @param {string|MediaTrackConstraints|null} options - Either a deviceId string, a full constraints object, or null for defaults.
* @returns {Promise<MediaStream>} A promise resolving to the active video stream.
* @throws {Error} If the deviceId is invalid.
*/
startCam(options?: string | MediaTrackConstraints | null): Promise<MediaStream>;
/**
* Starts screen sharing with customizable audio and video constraints.
*
* You can pass a boolean to enable or disable audio,
* or an object to define custom `audio` and `video` constraints.
*
* This method:
* - Emits the screen stream over the socket under the label `"screen"`.
* - If audio is present, starts volume monitoring and emits under the label `"screenMeter"`.
*
* @param {boolean|ScreenShareConstraints} options - `true` = enable audio, `false` = no audio, or an object with audio/video constraints.
* @param {boolean} hearScreen - `true` = Hear your screen audio (**Your ear will be destroyed!!!**).
* @returns {Promise<MediaStream>} A promise resolving to the active screen capture stream.
* @throws {Error} If the options are invalid.
*/
startScreen(options?: boolean | ScreenShareConstraints, hearScreen?: boolean): Promise<MediaStream>;
/**
* Stops the microphone stream if active.
*
* Stops all tracks from the current microphone stream and clears its reference.
* Throws an error if the microphone stream is not set or invalid.
*
* @throws {Error} If the microphone stream is not active or invalid.
*/
stopMic(): void;
/**
* Stops the webcam stream if active.
*
* Stops all tracks from the current webcam stream and clears its reference.
* Throws an error if the webcam stream is not set or invalid.
*
* @throws {Error} If the webcam stream is not active or invalid.
*/
stopCam(): void;
/**
* Stops the screen sharing stream if active.
*
* Stops all tracks from the current screen stream and clears its reference.
* Throws an error if the screen stream is not set or invalid.
*
* @throws {Error} If the screen sharing stream is not active or invalid.
*/
stopScreen(): void;
/**
* Stops all active media streams (microphone, webcam, and screen share).
*
* This method calls the individual stop methods to ensure each stream is safely terminated.
* Use this when you want to stop all media input/output at once.
*/
stopAll(): void;
/**
* Generates a unique media identifier string based on the given parameters.
*
* @param {string} userId - The ID of the user.
* @param {string} type - The type/category of the media.
* @param {string} mime - The MIME type of the media.
* @param {ReceiverTags} element - The name of the media element.
* @returns {string} A concatenated string uniquely identifying the media.
*/
getMediaId(userId: string, type: string, mime: string, element: ReceiverTags): string;
/**
* Checks if a media receiver exists for the given stream parameters.
*
* @param {string} userId - The user id to attach the stream.
* @param {string} type - The stream type, e.g., 'mic'.
* @param {string} mime - The mime type, e.g., 'audio/webm;codecs=opus'.
* @param {ReceiverTags} element - The tag name needs to be `audio` or `video` to attach the stream.
* @returns {boolean}
*/
hasReceiver(userId: string, type: string, mime: string, element: ReceiverTags): boolean;
/**
* Deletes a media receiver.
*
* @param {string} userId - The user id to attach the stream.
* @param {string} type - The stream type, e.g., 'mic'.
* @param {string} mime - The mime type, e.g., 'audio/webm;codecs=opus'.
* @param {ReceiverTags} element - The tag name needs to be `audio` or `video` to attach the stream.
*/
deleteReceiver(userId: string, type: string, mime: string, element: ReceiverTags): void;
/**
* Gets a media player for continuous streaming from received chunks.
*
* @param {string} userId - The user id to attach the stream.
* @param {string} type - The stream type, e.g., 'mic'.
* @param {string} mime - The mime type, e.g., 'audio/webm;codecs=opus'.
* @param {ReceiverTags} element - The tag name needs to be `audio` or `video` to attach the stream.
* @returns {TinyMediaReceiver} - If the instance has not yet been created, it will be created automatically.
* @throws {Error} If no media receiver exists for the given parameters.
*/
getReceiver(userId: string, type: string, mime: string, element: ReceiverTags): TinyMediaReceiver;
/**
* Initializes a media player for continuous streaming from received chunks.
*
* @param {string} userId - The user id to attach the stream.
* @param {StreamTypes} type - The stream type, e.g., 'mic'.
* @param {string} mimeType - The mime type, e.g., 'audio/webm;codecs=opus'.
* @param {ReceiverTags} element - The tag name needs to be `audio` or `video` to attach the stream.
* @param {Object} [options={}]
* @param {number} [options.maxBufferBack=10] - Maximum buffer (in seconds) back to keep in the buffer behind the current time.
* @param {number} [options.cleanupTime] - Interval time in milliseconds to perform buffer cleanup. Must be a positive number.
* @param {number} [options.bufferTolerance] - Tolerance value (in seconds) used when comparing buffer ranges. Must be a positive number.
* @returns {TinyMediaReceiver} - If the instance has not yet been created, it will be created automatically.
*/
initReceiver(userId: string, type: StreamTypes, mimeType: string, element: ReceiverTags, { maxBufferBack, cleanupTime, bufferTolerance }?: {
maxBufferBack?: number | undefined;
cleanupTime?: number | undefined;
bufferTolerance?: number | undefined;
}): TinyMediaReceiver;
/**
* Destroys the instance by terminating all active streams, stopping processes, and removing all event listeners.
*
* This method performs a full cleanup of the instance. It first iterates through all entries in `#streams` and calls
* their `destroy()` methods to properly dispose of any underlying resources (e.g., sockets, file handles, etc.). After that,
* it clears the `#streams` map entirely. It also calls `stopAll()` to terminate any ongoing operations or processes,
* and finally removes all listeners from both `#events` and `#sysEvents` to avoid memory leaks or unintended side effects.
*
* Call this method when the instance is no longer needed or before disposing of it.
*
* @returns {void}
*/
destroy(): void;
#private;
}
export type StreamTypes = "mic" | "cam" | "screen";
export type StreamEventTypes = "Mic" | "Cam" | "Screen";
export type ReceiverTags = import("./TinyMediaReceiver.mjs").ReceiverTags;
export type StreamConfig = {
/**
* - A valid MIME type for MediaRecorder.
*/
mimeType: string;
/**
* - Interval in milliseconds for emitting data chunks.
*/
timeslice: number;
/**
* - Audio codec that can be used
*/
audioCodec: string | null;
/**
* - Video codec that can be used
*/
videoCodec: string | null;
};
export type MandatoryConstraints = {
/**
* Capture source for Chrome/Electron.
*/
chromeMediaSource?: "screen" | "window" | "application" | "desktop" | undefined;
/**
* Specific ID of the capture source (usually obtained via desktopCapturer).
*/
chromeMediaSourceId?: string | undefined;
/**
* Maximum width of the capture.
*/
maxWidth?: number | undefined;
/**
* Maximum height of the capture.
*/
maxHeight?: number | undefined;
/**
* Maximum frame rate.
*/
maxFrameRate?: number | undefined;
/**
* Minimum width of the capture.
*/
minWidth?: number | undefined;
/**
* Minimum height of the capture.
*/
minHeight?: number | undefined;
/**
* Minimum frame rate.
*/
minFrameRate?: number | undefined;
/**
* Experimental setting used in some Chromium versions.
*/
googLeakyBucket?: boolean | undefined;
/**
* Experimental setting for temporal layers in screen capture.
*/
googTemporalLayeredScreencast?: boolean | undefined;
};
export type AdvancedScreenVideoConstraints = {
/**
* Capture source, useful in Electron and Firefox.
*/
mediaSource?: "screen" | "window" | "application" | "browser" | "monitor" | undefined;
/**
* Used in older versions of Chrome/Electron. Usually 'desktop'.
*/
chromeMediaSource?: string | undefined;
/**
* Used in Electron to select a specific screen or window.
*/
chromeMediaSourceId?: string | undefined;
/**
* Desired capture frame rate (e.g., 30 or 60).
*/
frameRate?: number | undefined;
/**
* Ideal capture width.
*/
width?: number | undefined;
/**
* Ideal capture height.
*/
height?: number | undefined;
/**
* Allows configuring advanced fields in Electron/Chrome (like `chromeMediaSource`).
*/
mandatory?: MandatoryConstraints | undefined;
};
export type ScreenShareConstraints = {
audio?: boolean | MediaTrackConstraints | undefined;
/**
* Constraints for screen capture, can be simple (true) or detailed.
*/
video: boolean | AdvancedScreenVideoConstraints | MediaTrackConstraints;
};
import { EventEmitter } from 'events';
import VolumeMeter from './VolumeMeter.mjs';
import TinyMediaReceiver from './TinyMediaReceiver.mjs';
//# sourceMappingURL=TinyStreamManager.d.mts.map