import * as grpc from "@grpc/grpc-js"; import { CmafAudioMessage, CmafMultiVariantMessage, CmafVideoMessage, CmafWebVttMessage, CmafTtmlMessage, HlsOutputEvent, HlsTsAudioMessage, HlsTsCombinedPushMessage, HlsTsVideoMessage, Subscription, HlsTsMultiVariantMessage } from "@norskvideo/norsk-api/lib/media_pb"; import { AwsCredentials, C2paSigningSettings, EncryptionSettings, IceServerSettings, SrtMode, StreamMetadata, TcpMode, Scte35SpliceInfoSection, AudioSegmentationStrategy, VideoSegmentationStrategy, Resolution, WebRtcStatsMessage, JitterBufferConfig, Interval, SourceTime, StreamKey, HttpAuth, Cta708CharsetSetting } from "./types"; import { DeckLinkVideoConnection, DeckLinkPixelFormat, DeckLinkKeyingMode, DeckLinkProfileId, DeckLinkDisplayModeId } from "../types"; import { AutoProcessorMediaNode, ProcessorNodeSettings } from "./common"; import { MqaConfig } from "./mqa"; import { AutoSinkMediaNode, MediaClient, MediaNodeState, MediaNodeStateEvents, SinkNodeSettings, StreamStatisticsMixin } from "./common"; /** * @public * What is the source of program-date-time in HLS/Dash outputs? */ export type PdtSource = "norskTimestamp" | "preferSourceTimestamp"; /** * @public * How should the system handle discontinuities in media playlists? */ export type PlaylistDiscontinuityMode = "gap" | "discontinuity"; /** * @public * Which flavour of SCTE-35 marker tags to emit into HLS media playlists. * * - `standard` (default): RFC 8216 `EXT-X-DATERANGE` with `SCTE35-OUT/IN/CMD` * attributes — the only Apple-supported carriage. * - `legacy`: the pre-standard "Elemental / Adobe Primetime" convention — * `EXT-X-CUE-OUT`/`EXT-X-CUE-IN`, `EXT-OATCLS-SCTE35` and `EXT-X-ASSET:CAID`. * Not in any formal standard but widely parsed across the SSAI ecosystem. * - `both`: emit the standard DATERANGE and the legacy tags together. */ export type Scte35MarkerMode = "standard" | "legacy" | "both"; /** * @public * Settings for a CMAF Audio and Video Outputs * see {@link NorskOutput.cmafAudio}, {@link NorskOutput.cmafVideo} */ export interface CmafOutputSettings extends SinkNodeSettings { /** * The target segment duration in seconds. Norsk will make the largest segments it can * without going over this target */ segmentDurationSeconds: number; /** * The target part duration in seconds. Norsk will make the largest parts it can * without going over this target */ partDurationSeconds: number; /** * Settings for encrypting the content. */ encryption?: EncryptionSettings; /** * Settings for C2PA (Content Provenance and Authenticity) signing * of the CMAF segments produced by this output. When set, every * init and media segment is signed before being pushed to each * destination. */ c2paSigning?: C2paSigningSettings; /** * A list of destinations {@link CmafDestinationSettings} for this stream to be published to */ destinations: CmafDestinationSettings[]; /** * Directives to add to the m3u media playlist */ m3uAdditions?: string; /** * XML fragment to add to the mpd Representation element */ mpdAdditions?: string; /** * Optional bitrate for the {@link NorskOutput.cmafMultiVariant} playlist. This field * is only used if the stream bitrate is unknown, which is typically only the case * in a passthrough scenario. The bitrate can be set through an explicit encode, * or set or overriden with a streamKeyOverride node */ bitrate?: number; /** * The name to use for the playlist in a multivariant playlist */ name?: string; /** * Whether to insert a program date-time directive on every segment. Not required to produce spec-compliant playlists, * but may be useful for inspection or playlist manipulation */ pdtEverySegment?: boolean; /** * What source to use for the program-date-time */ pdtSource?: PdtSource; /** * Whether to use integral (rounded) rather than fractional segment durations. Integral durations are mostly * a legacy form but still permitted in later compatibility versions, not recommended by the spec but in some * cases may make certain players happier in the case where segments durations can't be round or consistent values. */ integralSegmentDuration?: boolean; /** * When generating LL-HLS playlists, include rendition reports for all streams that share this renditionGroupId */ renditionGroupId?: string; /** * Playlist format(s) to generate */ playlistFormat?: CmafPlaylistFormat; /** * How to handle discontinuities in the media playlist. When set to "discontinuity", honours any discontinuities * present in the stream by generating EXT-X-DISCONTINUITY tags. When set to "gap" (default), ignores * discontinuities and uses EXT-X-GAP tags instead. Only set to "discontinuity" when all streams in a * multi-variant playlist have been processed through StreamSync or come from the same source to ensure * synchronized discontinuities across all renditions. */ discontinuityMode?: PlaylistDiscontinuityMode; /** * Which flavour of SCTE-35 marker tags to emit into the HLS media * playlist. Defaults to "standard" (EXT-X-DATERANGE). See * {@link Scte35MarkerMode}. */ scte35MarkerMode?: Scte35MarkerMode; /** * Arrange for CMAF segments to be created in a consistent manner across multiple encoders; used for primary/backup systems * to enable seamless player switching. If you want this, then you should set this to 'true' for every run that is being used * in your ABR ladder, and to also set the corresponding 'consistentGops' flag on the VideoEncode node. */ consistentSegments?: boolean; /** Optional MQA quality-metric aggregation weights. When omitted, server defaults are used. */ mqaConfig?: MqaConfig; } /** * @public * Settings for a CMAF Video Output * see {@link NorskOutput.cmafVideo} */ export interface CmafVideoOutputSettings extends CmafOutputSettings { /** * Optional stategy to be used in creating segments of the correct length * care should be taken to not supply values that result in segments of an invalid length */ segmentationStrategy?: VideoSegmentationStrategy; } /** * @public * Settings for a CMAF Audio Output * see {@link NorskOutput.cmafAudio} */ export interface CmafAudioOutputSettings extends CmafOutputSettings { /** * Optional stategy to be used in creating segments of the correct length * care should be taken to not supply values that result in segments of an invalid length */ segmentationStrategy?: AudioSegmentationStrategy; } /** * @public * Settings for a HLS TS Video Output * see {@link NorskOutput.hlsTsVideo} */ export interface HlsTsVideoOutputSettings extends SinkNodeSettings { /** * The target segment duration in seconds. Norsk will use the framerate of the stream in order * to produce compliant segments that are less than or equal to this in duration */ segmentDurationSeconds: number; /** * Optional stategy to be used in creating segments of the correct length * care should be taken to not supply values that result in segments of an invalid length */ segmentationStrategy?: VideoSegmentationStrategy; /** * A list of destinations {@link CmafDestinationSettings} for this stream to be published to */ destinations: CmafDestinationSettings[]; /** * Directives to add to the m3u media playlist */ m3uAdditions?: string; /** * XML fragment to add to the mpd Representation element */ mpdAdditions?: string; /** * Video bitrate for the {@link NorskOutput.hlsTsMultiVariant} playlist */ bitrate?: number; /** * The name to use for the playlist in a multivariant playlist */ name?: string; /** * Whether to insert a program date-time directive on every segment. Not required to produce spec-compliant playlists, * but may be useful for inspection or playlist manipulation */ pdtEverySegment?: boolean; metrics?: "enabled" | "minimal" | "none"; /** * What source to use for the program-date-time */ pdtSource?: PdtSource; /** * How to handle discontinuities in the media playlist. When set to "discontinuity", honours any discontinuities * present in the stream by generating EXT-X-DISCONTINUITY tags. When set to "gap" (default), ignores * discontinuities and uses EXT-X-GAP tags instead. Only set to "discontinuity" when all streams in a * multi-variant playlist have been processed through StreamSync or come from the same source to ensure * synchronized discontinuities across all renditions. */ discontinuityMode?: PlaylistDiscontinuityMode; /** * Which flavour of SCTE-35 marker tags to emit into the HLS media * playlist. Defaults to "standard" (EXT-X-DATERANGE). See * {@link Scte35MarkerMode}. */ scte35MarkerMode?: Scte35MarkerMode; /** Optional MQA quality-metric aggregation weights. When omitted, server defaults are used. */ mqaConfig?: MqaConfig; } /** * @public * Settings for a HLS TS Audio Output * see {@link NorskOutput.hlsTsAudio} */ export interface HlsTsAudioOutputSettings extends SinkNodeSettings { /** * The target segment duration in seconds. Norsk will make the largest segments it can * without going over this target using the durations of the individual audio frames */ segmentDurationSeconds: number; /** * Optional stategy to be used in creating segments of the correct length * care should be taken to not supply values that result in segments of an invalid length */ segmentationStrategy?: AudioSegmentationStrategy; /** * A list of destinations {@link CmafDestinationSettings} for this stream to be published to */ destinations: CmafDestinationSettings[]; /** * Directives to add to the m3u media playlist */ m3uAdditions?: string; /** * XML fragment to add to the mpd Representation element */ mpdAdditions?: string; /** * Audio bitrate for the {@link NorskOutput.hlsTsMultiVariant} playlist */ bitrate?: number; /** * The name to use for the playlist in a multivariant playlist */ name?: string; /** * Whether to insert a program date-time directive on every segment. Not required to produce spec-compliant playlists, * but may be useful for inspection or playlist manipulation */ pdtEverySegment?: boolean; metrics?: "enabled" | "minimal" | "none"; /** * What source to use for the program-date-time */ pdtSource?: PdtSource; /** * How to handle discontinuities in the media playlist. When set to "discontinuity", honours any discontinuities * present in the stream by generating EXT-X-DISCONTINUITY tags. When set to "gap" (default), ignores * discontinuities and uses EXT-X-GAP tags instead. Only set to "discontinuity" when all streams in a * multi-variant playlist have been processed through StreamSync or come from the same source to ensure * synchronized discontinuities across all renditions. */ discontinuityMode?: PlaylistDiscontinuityMode; /** * Which flavour of SCTE-35 marker tags to emit into the HLS media * playlist. Defaults to "standard" (EXT-X-DATERANGE). See * {@link Scte35MarkerMode}. */ scte35MarkerMode?: Scte35MarkerMode; /** Optional MQA quality-metric aggregation weights. When omitted, server defaults are used. */ mqaConfig?: MqaConfig; } /** * @public * Settings for a CMAF WebVTT Output * see {@link NorskOutput.cmafWebVtt} */ export interface CmafWebVttOutputSettings extends SinkNodeSettings { /** * The target segment duration in seconds, Norsk will split subtitles over multiple segments * in a compliant manner if necessary */ segmentDurationSeconds: number; /** * A list of destinations {@link CmafDestinationSettings} for this stream to be published to */ destinations: CmafDestinationSettings[]; /** * The name to use for the playlist in a multivariant playlist */ name?: string; /** * Whether to insert a program date-time directive on every segment. Not required to produce spec-compliant playlists, * but may be useful for inspection or playlist manipulation */ pdtEverySegment?: boolean; /** * Maximum elapsed duration since last playlist push before initiating a new playlist push with the existing playlist data. * This can be used to ensure a remote system views the playlist as "alive" though no data may be flowing due to intermittent media. * The actual gap may be longer if a segment push occurs when a playlist would be pushed. * Default: No playlists re-pushed ever. */ maximumPlaylistPushIntervalMs?: number; /** * How far behind live the subtitle "forcing timer" keeps its finalisation * watermark when no cues are flowing, so that cues arriving late relative to * their media timestamp (e.g. a transcriber holding a caption until an * utterance ends) are not stranded in an already-finalised segment. Raise this * if captioning for a stream is very stop-start / delayed. Default: one segment. */ cueLatencyToleranceMs?: number; /** * What source to use for the program-date-time */ pdtSource?: PdtSource; /** * When generating LL-HLS playlists, include rendition reports for all streams that share this renditionGroupId */ renditionGroupId?: string; /** * Playlist format(s) to generate */ playlistFormat?: CmafPlaylistFormat; /** * How to handle discontinuities in the media playlist. When set to "discontinuity", honours any discontinuities * present in the stream by generating EXT-X-DISCONTINUITY tags. When set to "gap" (default), ignores * discontinuities and uses EXT-X-GAP tags instead. Only set to "discontinuity" when all streams in a * multi-variant playlist have been processed through StreamSync or come from the same source to ensure * synchronized discontinuities across all renditions. */ discontinuityMode?: PlaylistDiscontinuityMode; /** Optional MQA quality-metric aggregation weights. When omitted, server defaults are used. */ mqaConfig?: MqaConfig; } /** * @public * Settings for a CMAF TTML Output. * * TTML subtitles (ISO/IEC 14496-30, `stpp`) are carried as fragmented-MP4 * segments for both HLS and DASH (unlike WebVTT, which uses raw `.vtt` for HLS). * see {@link NorskOutput.cmafTtml} */ export interface CmafTtmlOutputSettings extends SinkNodeSettings { /** The target segment duration in seconds */ segmentDurationSeconds: number; /** A list of destinations {@link CmafDestinationSettings} for this stream to be published to */ destinations: CmafDestinationSettings[]; /** The name to use for the playlist in a multivariant playlist */ name?: string; /** Whether to insert a program date-time directive on every segment */ pdtEverySegment?: boolean; /** Maximum elapsed duration since last playlist push before initiating a new push (ms) */ maximumPlaylistPushIntervalMs?: number; /** * How far behind live the subtitle "forcing timer" keeps its finalisation * watermark when no cues are flowing, so that cues arriving late relative to * their media timestamp (e.g. a transcriber holding a caption until an * utterance ends) are not stranded in an already-finalised segment. Raise this * if captioning for a stream is very stop-start / delayed. Default: one segment. */ cueLatencyToleranceMs?: number; /** What source to use for the program-date-time */ pdtSource?: PdtSource; /** When generating LL-HLS playlists, include rendition reports for all streams sharing this renditionGroupId */ renditionGroupId?: string; /** Playlist format(s) to generate */ playlistFormat?: CmafPlaylistFormat; /** How to handle discontinuities in the media playlist */ discontinuityMode?: PlaylistDiscontinuityMode; /** Optional MQA quality-metric aggregation weights. When omitted, server defaults are used. */ mqaConfig?: MqaConfig; } /** * @public * An update request for credentials on a CMAF output */ export interface UpdateCredentials { /** * The id of the destination that is to be updated (see {@link HlsPushDestinationSettings.id}) */ destinationId: string; /** * the new credentials to be used by the destination */ awsCredentials: AwsCredentials; } /** * @public * Settings for a HLS Transport Stream Combined Push Output * see {@link NorskOutput.hlsTsCombinedPush} */ export interface HlsTsCombinedPushOutputSettings extends SinkNodeSettings { /** * The target segment duration in seconds. By default, Norsk will use the framerate of the video stream in order * to produce compliant segments that are less than or equal to this in duration, with audio packaged alongside * using timestamps to line them up */ segmentDurationSeconds: number; /** * Optional stategy to be used instead of the default in creating segments of the correct length * care should be taken to not supply values that result in segments of an invalid length */ segmentationStrategy?: VideoSegmentationStrategy; /** * The destination {@link CmafDestinationSettings} for this stream to be published to */ destination: CmafDestinationSettings; /** * The name of this media playlist (.m3u8 will be added onto this field to generate a filename) */ playlistName: string; /** * Directives to add to the m3u media playlists */ m3uAdditions?: string; /** * The name to use for the playlist in a multivariant playlist */ name?: string; /** * Whether to insert a program date-time directive on every segment. Not required to produce spec-compliant playlists, * but may be useful for inspection or playlist manipulation */ pdtEverySegment?: boolean; /** * What source to use for the program-date-time */ pdtSource?: PdtSource; /** * How to handle discontinuities in the media playlist. When set to "discontinuity", honours any discontinuities * present in the stream by generating EXT-X-DISCONTINUITY tags. When set to "gap" (default), ignores * discontinuities and uses EXT-X-GAP tags instead. Only set to "discontinuity" when all streams in a * multi-variant playlist have been processed through StreamSync or come from the same source to ensure * synchronized discontinuities across all renditions. */ discontinuityMode?: PlaylistDiscontinuityMode; /** * Which flavour of SCTE-35 marker tags to emit into the HLS media * playlist. Defaults to "standard" (EXT-X-DATERANGE). See * {@link Scte35MarkerMode}. */ scte35MarkerMode?: Scte35MarkerMode; /** Optional MQA quality-metric aggregation weights. When omitted, server defaults are used. */ mqaConfig?: MqaConfig; } export type CmafPlaylistFormat = "hls" | "hls_dash" | "dash"; /** * @public * Settings for a CMAF Multi Variant Playlist * see {@link NorskOutput.cmafMultiVariant} */ export interface CmafMultiVariantOutputSettings extends SinkNodeSettings { /** * The name of this multi variant playlist (.m3u8 will be added onto this field to generate a filename) */ playlistName: string; /** * A list of destinations {@link CmafDestinationSettings} for this stream to be published to */ destinations: CmafDestinationSettings[]; /** * Directives to add to the m3u multi variant playlist */ m3uAdditions?: string; /** * XML fragment to add to the (top-level) MPD element */ mpdAdditions?: string; /** * A callback invoked every time a CMAF multi variant playlist is changed */ onPlaylistChange?: (destinationId: DestinationId, playlist: CmafMultiVariantPlaylistData) => CmafMultiVariantPlaylistData; /** * Playlist format(s) to generate */ playlistFormat?: CmafPlaylistFormat; } /** * @public * Settings for a Hls Ts Multivariant Playlist * see {@link NorskOutput.hlsTsMultiVariant} */ export interface HlsTsMultiVariantOutputSettings extends SinkNodeSettings { /** * The name of this multi variant playlist (.m3u8 will be added onto this field to generate a filename) */ playlistName: string; /** * A list of destinations {@link CmafDestinationSettings} for this stream to be published to */ destinations: CmafDestinationSettings[]; /** * Directives to add to the m3u multi variant playlist */ m3uAdditions?: string; /** * A callback invoked every time a TS multi variant playlist is changed */ onPlaylistChange?: (destinationId: DestinationId, playlist: string) => string; } /** * @public * Configuration for pushing a segmented media stream directly to a generic http server * */ export interface HlsPushDestinationSettings { type: "generic"; /** The hostname of the web server being pushed to. * This will be used to re-resolve the IP address on failures * */ host: string; /** the port of the web server being pushed to. */ port: number; /** the path under which segments and playlists will be pushed to */ pathPrefix: string; /** * Optionally supply a string that will be inserted into the path structure for segments published in this stream * * This is useful for stream restarts or republishing when duplicate segment IDs would be generated causing problems with * cacheing directives */ sessionId?: string; /** * A unique identifier for this destination * * This can be used for supplying updates to configuration to this destination specifically * see: {@link UpdateCredentials} */ id: DestinationId; /** * Informs the playlist generation how long segments will be retained for on the remote server * in order to generate an accurate playlist */ retentionPeriodSeconds: number; /** * In the absence of a HLS_SKIP query parameter, how many segments should be served in a playlist * this effectively controls how far back in time a player can seek from first load (as long as the data exists) */ defaultSegmentCount?: number; /** Server control directive, informs the client how far back in the stream (in seconds) it should attempt to play this should take into account the end to end latency from source capture, to the segment and playlist being published */ holdBackSeconds?: number; /** Server control directive, informs the client how far back in the stream (in seconds) it should attempt to play when using the lower latency parts this should take into account the end to end latency from source capture, to the part and playlist being published */ partHoldBackSeconds?: number; /** Whether the server supports gzip *request* compression for PUT/POST requests */ supportsGzip?: boolean; /** Whether to use TLS or plain TCP transport, by default TLS used if port is 443 */ tlsTransport?: boolean; /** Add Common Media Server Data headers to the POST requests */ addCmsdHeaders?: boolean; /** Custom headers to add to the POST requests */ customHeaders?: { name: string; value: string; }[]; /** If specified: generate a Delta Playlist update with this playlist name (and appropriate CAN-SKIP-UNTIL tags in the main playlist). * Not supported with client-side playlist rewriting. */ deltaPlaylist?: string; /** * Segment and init segment path naming convention. All CMAF conventions use HTTP PUT * with CMAF file extensions (.cmfv for video, .cmfa for audio, .cmft for text) and * do not push HLS/DASH playlists — the receiving origin generates those. * * - `"standard"` — Norsk default. Uses HTTP POST with .mp4/.m4s extensions and full * path routing: `/{sourceName}/{programNumber}/{streamId}/{renditionName}/{segmentNumber}.mp4`. * Playlists (.m3u8/.mpd) are also pushed. Use this with Norsk's own HTTP server or * CDNs that expect HLS push. * * - `"cmaf-long"` — Each track gets its own URL path prefix. Init and media segments * have distinct URLs: * - Init: `{prefix}/{representationId}/init.cmfv` * - Media: `{prefix}/{representationId}/{segmentNumber}.cmfv` * Compatible with DASH-IF Live Media Ingest Interface 1 receivers. * * - `"cmaf-ism"` — ISM/Smooth Streaming style. Uses `Streams()` wrapper with sub-paths * for init and each segment: * - Init: `{prefix}/Streams({name}.cmfv)/InitializationSegment` * - Media: `{prefix}/Streams({name}.cmfv)/Segment({number})` * Compatible with Unified Streaming Origin and similar ISM-based origins. * * - `"cmaf-short"` — DASH-IF short form. All segments (including init) for a track are * PUT to the same URL — the receiver identifies segments by parsing the MP4 boxes: * - Init + Media: `{prefix}/Streams({name}.cmfv)` * Compatible with DASH-IF Live Media Ingest Interface 1 receivers that support the * short `Streams()` URL form. * * @defaultValue "standard" */ namingConvention?: "standard" | "cmaf-long" | "cmaf-ism" | "cmaf-short"; /** * Send HTTP DELETE for segments that have expired past the retention period. * @defaultValue false */ deleteExpiredSegments?: boolean; } /** * @public * Configuration for pushing a segmented media stream directly to AWS S3 * */ export interface AwsS3PushDestinationSettings { type: "s3"; /** The hostname of the s3 server being pushed to. */ host: string; /** the port of the s3 server being pushed to. */ port: number; /** the path under which segments and playlists will be pushed to */ pathPrefix: string; /** * Optionally supply a string that will be inserted into the path structure for segments published in this stream * * This is useful for stream restarts or republishing when duplicate segment IDs would be generated causing problems with * cacheing directives */ sessionId?: string; /** * A unique identifier for this destination * * This can be used for supplying updates to configuration to this destination specifically * see: {@link UpdateCredentials} */ id: DestinationId; /** * The AWS region being pushed to */ awsRegion: string; /** * AWS credentials to be used for connecting to S3 * Standard environment variables will be read if these are not provided */ awsCredentials?: AwsCredentials; /** * Informs the playlist generation how long segments will be retained for on the remote server * in order to generate an accurate playlist */ retentionPeriodSeconds: number; /** * In the absence of a HLS_SKIP query parameter, how many segments should be served in a playlist * this effectively controls how far back in time a player can seek from first load (as long as the data exists) */ defaultSegmentCount?: number; /** Server control directive, informs the client how far back in the stream (in seconds) it should attempt to play this should take into account the end to end latency from source capture, to the segment and playlist being published */ holdBackSeconds?: number; /** Server control directive, informs the client how far back in the stream (in seconds) it should attempt to play when using the lower latency parts this should take into account the end to end latency from source capture, to the part and playlist being published */ partHoldBackSeconds?: number; /** If specified: generate a Delta Playlist update with this playlist name (and appropriate CAN-SKIP-UNTIL tags in the main playlist). * Not supported with client-side playlist rewriting. */ deltaPlaylist?: string; } /** * @public * Configuration for the serving of segments and playlists directly from the Norsk Web Server * Note: While this is both useful for local testing and for sitting behind a reverse caching proxy / CDN * it is not expected that Norsk serve as the edge server in most scenarios * */ export interface LocalPullDestinationSettings { type: "local"; /** * A unique identifier for this destination */ id: DestinationId; /** * Optionally supply a string that will be inserted into the path structure for segments published in this stream * * This is useful for stream restarts or republishing when duplicate segment IDs would be generated causing problems with * cacheing directives */ sessionId?: string; /** * Informs the playlist generation how long segments will be retained for * and informs the local web server how long to retain those segments */ retentionPeriodSeconds: number; /** * In the absence of a HLS_SKIP query parameter, how many segments should be served in a playlist * this effectively controls how far back in time a player can seek from first load (as long as the data exists) */ defaultSegmentCount?: number; /** Server control directive, informs the client how far back in the stream (in seconds) it should attempt to play this should take into account the end to end latency from source capture, to the segment and playlist being published */ holdBackSeconds?: number; /** Server control directive, informs the client how far back in the stream (in seconds) it should attempt to play when using the lower latency parts this should take into account the end to end latency from source capture, to the part and playlist being published */ partHoldBackSeconds?: number; /** Add Common Media Server Data headers to add to GET responses */ addCmsdHeaders?: boolean; /** Custom headers to add to GET responses */ customHeaders?: { name: string; value: string; }[]; } /** @public */ export type MediaPlaylistPart = MediaSegment | AdMarker | HlsTag | ProgramDateTime | ScheduledTag; /** @public */ export type HlsPlaylist = { hlsFilePartPlaylist: MediaPlaylistPart[]; hlsByteRangePlaylist: MediaPlaylistPart[]; hlsStandardPlaylist: MediaPlaylistPart[]; programDateTime?: Date; }; /** @public */ export type HlsPlaylistAdditions = HlsPlaylist; /** @public */ export type TsPlaylist = MediaPlaylistPart[]; /** @public */ export type TsPlaylistAdditions = [MediaPlaylistPart[], Date]; /** @public */ export interface CmafMultiVariantPlaylistData { hls: string; dash: string; } /** @public */ export interface MediaSegment { uri: string; duration: number; title: string; number: bigint; } /** @public */ export interface AdMarker { id: string; startDate: Date; durationSeconds: number; scte35: Scte35SpliceInfoSection; } /** @public */ export interface HlsTag { tag: string; } /** @public */ export interface ProgramDateTime { programDateTime: Date; } /** @public */ export declare function isMediaSegment(seg: MediaPlaylistPart): seg is MediaSegment; /** @public */ export declare function isAdMarker(seg: MediaPlaylistPart): seg is AdMarker; /** @public */ export declare function isHlsTag(seg: MediaPlaylistPart): seg is HlsTag; /** @public */ export declare function isProgramDateTime(seg: MediaPlaylistPart): seg is ProgramDateTime; /** @public */ export declare function isScheduledTag(seg: MediaPlaylistPart): seg is ScheduledTag; /** @public */ export type PlaylistOnChangeFn = { cmafMediaPlaylist?: (grpcStream: grpc.ClientDuplexStream, destinationId: DestinationId, additions: HlsPlaylistAdditions, playlistWithAdditions: HlsPlaylist) => void; tsMediaPlaylist?: (grpcStream: grpc.ClientDuplexStream, destinationId: DestinationId, additions: TsPlaylistAdditions, playlistWithAdditions: MediaPlaylistPart[]) => void; cmafMultiVariantPlaylist?: (grpcStream: grpc.ClientDuplexStream, destinationId: DestinationId, playlist: CmafMultiVariantPlaylistData) => void; hlsTsMultiVariantPlaylist?: (grpcStream: grpc.ClientDuplexStream, destinationId: DestinationId, playlist: string) => void; }; /** * @public * Possible destinations for a segmented media stream * - {@link HlsPushDestinationSettings}: Push to a generic HTTP server * - {@link AwsS3PushDestinationSettings}: Push to Amazon S3 * - {@link LocalPullDestinationSettings}: Serve directly from the Norsk Web Server * */ export type CmafDestinationSettings = HlsPushDestinationSettings | AwsS3PushDestinationSettings | LocalPullDestinationSettings; type HlsPlaylistDestination = { [destination: DestinationId]: HlsPlaylist; }; type HlsTsPlaylistDestination = { [destination: DestinationId]: MediaPlaylistPart[]; }; declare class CmafNodeBase extends AutoProcessorMediaNode { playlists: HlsPlaylistDestination; destinations: DestinationId[]; scheduledTags: ScheduledTag[]; constructor(client: MediaClient, unregisterNode: (node: MediaNodeState) => void, settings: ProcessorNodeSettings & StreamStatisticsMixin, grpcInit: () => grpc.ClientDuplexStream, subscribeFn: (subscription: Subscription) => Promise, onPlaylistAddition: PlaylistOnChangeFn, destinations: DestinationId[], subscribedStreamsChangedFn?: (streams: StreamMetadata[]) => void); scheduleTag(tag: MediaPlaylistPart, scheduleAt: Date, destinationId?: DestinationId): ScheduledTag; removeScheduledTag(tagId: number): void; } /** @public */ export type ScheduledTag = [number, MediaPlaylistPart, Date, DestinationId?]; /** @public */ export type DestinationId = string; declare class CmafNodeWithPlaylist extends CmafNodeBase { /** * @public * Returns the URL to the HLS playlist entry. Note this can only be evaluated once the stream is active as it * varies with the stream subscribed to. Useful during development, but you probably want to * use {@link NorskOutput.cmafMultiVariant} for production. */ url(): Promise; } /** * @public * see: {@link NorskOutput.cmafVideo} */ export declare class CmafVideoOutputNode extends CmafNodeWithPlaylist { /** @public*/ get onPlaylistAddition(): ((destinationId: DestinationId, pl: HlsPlaylistAdditions) => HlsPlaylist) | undefined; set onPlaylistAddition(c: ((destinationId: DestinationId, pl: HlsPlaylistAdditions) => HlsPlaylist) | undefined); /** * @public * Updates the credentials for a specific destination within this output by id * see: {@link UpdateCredentials} * see: {@link CmafDestinationSettings} */ updateCredentials(settings: UpdateCredentials): void; } /** * @public * see: {@link NorskOutput.cmafAudio} */ export declare class CmafAudioOutputNode extends CmafNodeWithPlaylist { /** @public*/ get onPlaylistAddition(): ((destinationId: DestinationId, pl: HlsPlaylistAdditions) => HlsPlaylist) | undefined; set onPlaylistAddition(c: ((destinationId: DestinationId, pl: HlsPlaylistAdditions) => HlsPlaylist) | undefined); /** * @public * Updates the credentials for a specific destination within this output by id * see: {@link UpdateCredentials} * see: {@link CmafDestinationSettings} */ updateCredentials(settings: UpdateCredentials): void; } /** * @public * see: {@link NorskOutput.hlsTsVideo} */ export declare class HlsTsVideoOutputNode extends CmafNodeWithPlaylist { /** @public */ get onPlaylistAddition(): ((destinationId: DestinationId, pl: TsPlaylistAdditions) => TsPlaylist) | undefined; set onPlaylistAddition(c: ((destinationId: DestinationId, pl: TsPlaylistAdditions) => TsPlaylist) | undefined); get playlist(): HlsTsPlaylistDestination; /** * @public * Updates the credentials for a specific destination within this output by id * see: {@link UpdateCredentials} * see: {@link CmafDestinationSettings} */ updateCredentials(settings: UpdateCredentials): void; } /** * @public * see: {@link NorskOutput.hlsTsAudio} */ export declare class HlsTsAudioOutputNode extends CmafNodeWithPlaylist { /** @public */ get onPlaylistAddition(): ((destinationId: DestinationId, pl: TsPlaylistAdditions) => TsPlaylist) | undefined; set onPlaylistAddition(c: ((destinationId: DestinationId, pl: TsPlaylistAdditions) => TsPlaylist) | undefined); get playlist(): HlsTsPlaylistDestination; /** * @public * Updates the credentials for a specific destination within this output by id * see: {@link UpdateCredentials} * see: {@link CmafDestinationSettings} */ updateCredentials(settings: UpdateCredentials): void; } /** * @public * see: {@link NorskOutput.hlsTsCombinedPush} */ export declare class HlsTsCombinedPushOutputNode extends CmafNodeWithPlaylist { } /** * @public * see: {@link NorskOutput.cmafWebVtt} */ export declare class CmafWebVttOutputNode extends CmafNodeWithPlaylist { /** @public */ onPlaylistAddition?: (destinationId: DestinationId, pl: HlsPlaylistAdditions) => HlsPlaylist; /** * @public * Updates the credentials for a specific destination within this output by id * see: {@link UpdateCredentials} * see: {@link CmafDestinationSettings} */ updateCredentials(settings: UpdateCredentials): void; } /** * @public * A CMAF TTML output node (TTML subtitles as `stpp` fragmented-MP4, for both HLS and DASH). * see: {@link NorskOutput.cmafTtml} */ export declare class CmafTtmlOutputNode extends CmafNodeWithPlaylist { /** @public */ onPlaylistAddition?: (destinationId: DestinationId, pl: HlsPlaylistAdditions) => HlsPlaylist; /** * @public * Updates the credentials for a specific destination within this output by id */ updateCredentials(settings: UpdateCredentials): void; } /** * @public * see: {@link NorskOutput.cmafMultiVariant} */ export declare class CmafMultiVariantOutputNode extends CmafNodeBase { /** @public The URL of the file based multi variant playlist */ url: string; /** @public The URL of the file based DASH manifest */ dashUrl: string; /** * @public * Updates the credentials for a specific destination within this output by id * see: {@link UpdateCredentials} * see: {@link CmafDestinationSettings} */ updateCredentials(settings: UpdateCredentials): void; } /** * @public * see: {@link NorskOutput.hlsTsMultiVariant} */ export declare class HlsTsMultiVariantOutputNode extends CmafNodeBase { /** @public The URL of the file based multi variant playlist */ url: string; /** * @public * Updates the credentials for a specific destination within this output by id * see: {@link UpdateCredentials} * see: {@link CmafDestinationSettings} */ updateCredentials(settings: UpdateCredentials): void; } export interface TamsFlowCommonOutputSettings { /** URL of the TAMS service, eg http://example.com:12345/shiny-tams-api/ */ url: string; /** HTTP authentication scheme to use */ auth?: HttpAuth; /** * Container/wrapping format for the written flow segments. * "ts" = MPEG-TS (default), "mp4" = fragmented MP4 with init segments. */ container?: "ts" | "mp4"; } export interface TamsVideoFlowOutputSettings extends TamsFlowCommonOutputSettings, SinkNodeSettings { } export declare class TamsVideoFlowOutputNode extends AutoSinkMediaNode<"video"> { } export interface TamsAudioFlowOutputSettings extends TamsFlowCommonOutputSettings, SinkNodeSettings { } export declare class TamsAudioFlowOutputNode extends AutoSinkMediaNode<"Audio"> { } export type TsBroadcastEncoderSettings = { type: "broadcast"; /** * Overall transport stream bitrate (bits per second) */ bitrate: number; /** * PCR spacing in milliseconds. If unspecified: default 50ms. * * Lower number might be specified to pass legacy validation (40ms), per DVB standards this should be <100ms. */ pcrIntervalMs?: number; /** * PAT/PMT table spacing in milliseconds. Default 100ms (ETSI TS 101 154 recommendation), should be < 0.5s (ETSI TR 101 290). */ tableIntervalMs?: number; /** * PCR-DTS delay in milliseconds - note if this is insufficient the stream will be invalid, beware. Default value if omitted is presently 500ms */ pcrDelayMs?: number; }; export type TsSimpleEncoderSettings = { type: "simple"; /** * PCR-DTS delay in milliseconds - note if this is insufficient the stream will be invalid, beware. Default value if omitted is presently 500ms */ pcrDelayMs?: number; }; export type TsEncoderSettings = TsSimpleEncoderSettings | TsBroadcastEncoderSettings; export interface TsOutputSettings { /** * TS encoder settings. A broadcast encode specifies a bitrate and will produce a stream with accurate PCR spacing, null padding etc. * A simple encode (default) is acceptable for many use cases. */ encoder?: TsEncoderSettings; /** * Pid to assign as PMT pid (for the first program, if there are multiple), if unspecified a default pid will be chosen */ pmtPid?: number; /** * PES packing of audio frames (where applicable). Lower values reduce audio latency, but increase * bandwidth due to encapsulation overhead - interplay with PCR delay applies for larger values. Minimum 1, applicable maximum * bounded by byte size of PES packets. If omitted a default packing value will apply, currently default is 16. */ audioFramesPerPes?: number; /** * Character set used when emitting CTA-708 **P16** (16-bit) captions — for * producing East-Asian captions in a legacy DBCS rather than Unicode. Does * not affect Latin/ASCII text. Defaults to `'unicode'`. */ cta708Charset?: Cta708CharsetSetting; } /** * @public * The settings for an output Transport Stream over UDP * see: {@link NorskOutput.udpTs} */ export interface UdpTsOutputSettings extends SinkNodeSettings, StreamStatisticsMixin { /** * The IP address or hostname to publish to * The Ip address can be multicast, unicast or broadcast */ destinationHost: string; /** * The interface to bind to for publishing * This can be 'any', 'loopback' or any named interface on the machine * Note: If running inside docker this may be different to expected */ interface: string; /** The port to send to */ port: number; /** Jitter buffer configuration */ jitterBuffer?: JitterBufferConfig; /** A/V delay in milliseconds - to allow inclusion of subtitles, metadata and other ancillary data. May be set to 0 if these are not present to reduce latency */ avDelayMs?: number; /** Whether to encapsulate in RTP via RFC 2250 (default: false) */ rtpEncapsulate?: boolean; /** * Maximum duration to hold any stream in the case that one or more are running behind. In the case the late * stream is delayed rather than having a large gap, this will result in discarded input frames. */ maxQueueMs?: number; ts?: TsOutputSettings; } /** * @public * see: {@link NorskOutput.udpTs} */ export declare class UdpTsOutputNode extends AutoSinkMediaNode<"audio" | "video"> { } /** * @public * The settings for an output Transport Stream over TCP. Norsk acts as the TCP * client, connecting to the destination host/port and reconnecting on failure. * see: {@link NorskOutput.tcpTs} */ export interface TcpTsOutputSettings extends SinkNodeSettings, StreamStatisticsMixin { /** * Whether Norsk connects out to the remote ("caller", the default) or binds * and accepts an incoming connection ("listener"). */ mode?: TcpMode; /** * In caller mode the IP address or hostname to connect to; in listener mode * the local address to bind ("0.0.0.0" for all interfaces). */ destinationHost: string; /** In caller mode the port to connect to; in listener mode the port to bind */ port: number; /** Jitter buffer configuration */ jitterBuffer?: JitterBufferConfig; /** A/V delay in milliseconds - to allow inclusion of subtitles, metadata and other ancillary data. May be set to 0 if these are not present to reduce latency */ avDelayMs?: number; /** * Maximum duration to hold any stream in the case that one or more are running behind. In the case the late * stream is delayed rather than having a large gap, this will result in discarded input frames. */ maxQueueMs?: number; ts?: TsOutputSettings; } /** * @public * see: {@link NorskOutput.tcpTs} */ export declare class TcpTsOutputNode extends AutoSinkMediaNode<"audio" | "video"> { } /** * @public */ export type RolloverSettings = { type: 'bytes'; value: number; } | { type: 'ms'; value: number; }; /** * @public */ export type WriteThroughFile = { fileName: string; rollover?: RolloverSettings; }; /** * @public * The settings for an SRT output * see: {@link NorskOutput.srt} * */ export interface SrtOutputSettings extends SinkNodeSettings, StreamStatisticsMixin { /** * Passphrase for encryption */ passphrase?: string; /** * Stream ID to set on the socket when acting in caller mode */ streamId?: string; /** * The latency value in the receiving direction of the socket (SRTO_RCVLATENCY) */ receiveLatency?: number; /** * The latency value provided by the sender side as a minimum value for the receiver (SRTO_PEERLATENCY) */ peerLatency?: number; /** * Input bandwidth (SRTO_INPUTBW) */ inputBandwidth?: number; /** * Overhead bandwidth (SRTO_OHEADBW) */ overheadBandwidth?: number; /** * Max bandwidth (SRTO_MAXBW) */ maxBandwidth?: number; /** * Whether to enable the too-late-packet-drop mechanism (SRTO_TLPKTDROP) - default true. On a sender this means dropping packets which have no chance to be delivered. Enabled by default when the receiver supports it. */ tlpktdrop?: boolean; /** * The mode to act in (see {@link SrtMode}) */ mode: SrtMode; /** * The IP address or hostname to listen on in listener mode, or to connect to in caller mode */ host: string; /** * The port to listen on in listener mode, or to connect to in caller mode * * In listener mode the port may be given as 0 to bind to an automatically assigned port, which can be retrieved in `onBind`. */ port: number; /** Jitter buffer configuration */ jitterBuffer?: JitterBufferConfig; /** A/V delay in milliseconds - to allow inclusion of subtitles, metadata and other ancillary data. May be set to 0 if these are not present to reduce latency */ avDelayMs?: number; /** * Maximum duration to hold any stream in the case that one or more are running behind. In the case the late * stream is delayed rather than having a large gap, this will result in discarded input frames. */ maxQueueMs?: number; ts?: TsOutputSettings; /** * Called when a listener-mode SRT output binds to the interface */ onBind?: (info: { port: number; }) => void; /** * File to write through all data to (this will be read from in order to produce the final SRT stream, useful for compliance purposes) * NB: This will rollover automatically, but no expiry will take place, it is assumed that infrastructure will take care of this */ writeThroughFile?: WriteThroughFile; /** * On connect callback, notifying that a connection has been established. In caller mode this is raised for the single outbound caller, while * in listener mode this means a new caller has connected (possibly one of many) and provides the stream_id that was set on the socket * @eventProperty */ onConnection?: ( /** The stream_id sent on the SRT socket (or empty if none was set) */ streamId: string, /** The stream index (count of connections that have been made) */ streamIndex: number, /** The remote host address */ remoteHost: string) => void; /** * On disconnect callback, notifying that an individual client connection has disconnected. This will be followed by a retry in caller mode, while in * listener mode is relevant to an individual client (per the provided metadata), while the remaining clients remain connected. */ onDisconnect?: (info: { /** The stream index (as returned on connect) */ streamIndex: number; }) => void; /** * Interval in milliseconds at which to poll the underlying SRT socket for connection status changes (driving {@link SrtOutputSettings.onConnection}-related events). When unspecified a default is used. */ statusPollIntervalMs?: number; /** * Interval in milliseconds at which to sample SRT socket statistics. Stats feed metrics, so tune this to the rate at which you want metric updates. When unspecified a default is used. */ statsPollIntervalMs?: number; } /** * @public * see: {@link NorskOutput.srt} */ export declare class SrtOutputNode extends AutoSinkMediaNode<"audio" | "video"> { } /** * @public * The settings for a WebRTC Whip Output * see {@link NorskOutput.whip} */ export interface WhipOutputSettings extends SinkNodeSettings, StreamStatisticsMixin { /** * The URI to make the initial publish request to (as per the WHIP protocol) */ uri: string; /** The auth header to supply (for example: 'Bearer: mybearertoken') */ authHeader: string; /** Jitter buffer configuration */ jitterBuffer?: JitterBufferConfig; /** * Maximum duration to hold any stream in the case that one or more are running behind. In the case the late * stream is delayed rather than having a large gap, this will result in discarded input frames. */ maxQueueMs?: number; } /** * @public * see: {@link NorskOutput.whip} */ export declare class WhipOutputNode extends AutoSinkMediaNode<"audio" | "video"> { } /** * @public * The settings for a WebRTC WHEP Output * see {@link NorskOutput.whep} */ export interface WhepOutputSettings extends SinkNodeSettings, StreamStatisticsMixin { /** List of ice servers to use as part of session negotiation */ iceServers?: IceServerSettings[]; /** Internal addresses for the ice servers (defaults to iceServers) */ reportedIceServers?: IceServerSettings[]; name: string; /** * List of IPs to advertise as your host address - useful e.g. when on a cloud server * so that the public rather than private IP is used. */ hostIps?: string[]; /** * Similar to hostIps, but a list of server reflexive candidates so that ICE negotiations can be * sped up */ serverReflexiveIps?: string[]; /** Jitter buffer configuration */ jitterBuffer?: JitterBufferConfig; /** * Maximum duration to hold any media stream in the case that one or more are running behind. In the case the late * stream is delayed rather than having a large gap, this will result in discarded input frames. * Should not be required in general, could be useful to ensure low latency when there are gaps in input (eg few seconds of decode error) */ maxQueueMs?: number; /** Callback to signify the WHEP output is publishing media and ready for client connection */ onPublishStart?: () => void; /** Callback to signify the WHEP output has stopped publishing media and will reject client connections * * i.e. A WHEP output which has previously been usable, and has now had its source turned off, but may * become usable in the future if a new source appears. */ onPublishStop?: () => void; /** * Callback giving stats from the WebRTC stack for an individual client session */ onStats?: (stats: WebRtcStatsMessage) => void; } /** * @public * see: {@link NorskOutput.whep} */ export declare class WhepOutputNode extends AutoSinkMediaNode<"audio" | "video"> { /** @public The URL of the local player */ playerUrl: string; /** @public The URL of the WHEP endpoint */ endpointUrl: string; } export interface ImagePreviewPublishedInfo { file: string; utc: Date; sourceUtc?: Date; } /** * @public * The settings for a Image Preview Output * see {@link NorskOutput.imagePreview} */ export interface ImagePreviewOutputSettings extends SinkNodeSettings, StreamStatisticsMixin { frequency: number; keep: number; quality: number; resolution: Resolution; /** Invoked when a new image is created on the server this filename can be appended to baseUrl to get the full location */ onImagePublished?: (info: ImagePreviewPublishedInfo) => void; } /** * @public * see: {@link NorskOutput.whep} */ export declare class ImagePreviewOutputNode extends AutoSinkMediaNode<"video", { "image-published": (info: ImagePreviewPublishedInfo) => void; } & MediaNodeStateEvents> { /** @public The URL where published files can be found */ baseUrl: string; } /** @public */ export declare enum RtmpConnectionFailureReason { RtmpConnectionFailedRetry = "RtmpConnectionFailedRetry" } /** * @public * The settings for an RTMP output * see: {@link NorskOutput.rtmp} * */ export interface RtmpOutputSettings extends SinkNodeSettings, StreamStatisticsMixin { /** * The URL of the remote RTMP server to connect to, including the full stream path and credentials */ url: string; /** Jitter buffer configuration */ jitterBuffer?: JitterBufferConfig; /** A/V delay in milliseconds (to allow embedded captions to be added) */ avDelayMs?: number; /** * Maximum duration to hold any stream in the case that one or more are running behind. In the case the late * stream is delayed rather than having a large gap, this will result in discarded input frames. */ maxQueueMs?: number; /** RTMP Chunksize in bytes */ chunkSize?: number; /** Called when the RTMP output succesfully connects to a server and is about to start publishing media */ onPublishStart?: () => void; /** Called when the connection to the RTMP server fails */ onConnectionFailure?: (failureReason: RtmpConnectionFailureReason) => void; /** Called when the RTMP output sends the first media frame after connecting to a server (base t0 is established for the RTMP connection) */ onSourceTimeUpdate?: (streamKey: StreamKey, timestamp: Interval, sourceTime: SourceTime | undefined) => void; /** * Number of seconds to wait until a retry is attempted to the RTMP server. * Defaults to five seconds */ retryConnectionTimeout?: number; sslOptions?: { verifyPeerCert?: boolean; }; } /** * @public * see: {@link NorskOutput.rtmp} */ export declare class RtmpOutputNode extends AutoSinkMediaNode<"audio" | "video"> { } /** * @public * The settings for an output Transport Stream written to file * see: {@link NorskOutput.fileTs} */ export interface FileTsOutputSettings extends SinkNodeSettings, StreamStatisticsMixin { /** The file to write - this will be truncated if it already exist */ fileName: string; /** Rollover */ rollver?: RolloverSettings; /** A/V delay in milliseconds - to allow inclusion of subtitles, metadata and other ancillary data. May be set to 0 if these are not present to reduce latency */ avDelayMs?: number; } /** * @public * see: {@link NorskOutput.fileTs} */ export declare class FileTsOutputNode extends AutoSinkMediaNode<"audio" | "video"> { } /** * @public * Settings to control MP4 file output * see {@link NorskOutput.fileMp4} */ export interface FileMp4OutputSettings extends SinkNodeSettings, StreamStatisticsMixin { /** * stream fragmented MP4 to this file. */ fragmentedFileName?: string; /** * Write non-fragmented MP4 to this file on close, creates a `.tmp` file to * store the frame data. */ nonfragmentedFileName?: string; /** * Serve the fragmented MP4 from this filename */ httpFileName?: string; /** * Settings for encrypting the audio track. */ audioEncryption?: EncryptionSettings; /** * Settings for encrypting the video track. */ videoEncryption?: EncryptionSettings; /** * Enable "incremental" write mode of non-fragmented mp4 output file. This periodically updates the file header (the moov) to * reflect the latest data that has been written, so that the file can be loaded/reloaded in some player while it is being written. * You must set {@link expectedMaxFileDurationS} to ensure an appropriate space can be reserved for the header or the file will no longer * update incrementally */ enableIncrementalMp4Write?: boolean; /** * Maximum duration that the file is expected to last. This should be a conservative estimate according to the use case, so that you never * expect to hit the limit, but there is some file size cost to a larger value (so if the file is going to be 10 seconds, setting 2 hours would be a bad idea). */ incrementalWriteIntervalMs?: number; expectedMaxFileDurationS?: number; } /** * @public * see: {@link NorskOutput.fileMp4} */ export declare class FileMp4OutputNode extends AutoSinkMediaNode<"audio" | "video" | "subtitle", { "http_stream_available": () => void; } & MediaNodeStateEvents> { settings: FileMp4OutputSettings; private _url; pendingUrlRequests: ((url: string) => void)[]; url(): Promise; /** * @public * Writes a non-fragmented MP4 file containing the data received so far to the * supplied filename */ writeFile(nonfragmentedFileName: string): void; } /** * @public * Settings to control WAV file output * see {@link NorskOutput.fileWav} */ export interface FileWavOutputSettings extends SinkNodeSettings { /** * Required: stream audio to this file. */ fileName: string; } /** * @public * see: {@link NorskOutput.fileWav} */ export declare class FileWavOutputNode extends AutoSinkMediaNode<"audio"> { } /** * @public * Settings for the local audio monitor output * see {@link NorskOutput.localAudioMonitor} */ export interface LocalAudioMonitorSettings extends SinkNodeSettings { /** * Output device name, as enumerated by hardware info's `audioDevices`. * Omit for the platform's default output device. In containers the device * must be passed through (`/dev/snd` for ALSA on Linux). */ deviceName?: string; } /** * @public * see: {@link NorskOutput.localAudioMonitor} */ export declare class LocalAudioMonitorNode extends AutoSinkMediaNode<"audio"> { } /** * @public * Settings to control MP4 file output * see {@link NorskOutput.fileMp4} */ export interface FileWebVttOutputSettings extends SinkNodeSettings { /** * Stream WebVTT cues to this file */ fileName: string; /** * Whether to output cues corresponding to partial rather than complete transcription utterances. Default: false (complete), * irrelevant for non-transcription sources. Partial transcriptions may be used for monitoring live output rather than post-event summary. */ partial?: boolean; } /** * @public * see: {@link NorskOutput.fileWebVtt} */ export declare class FileWebVttOutputNode extends AutoSinkMediaNode<"subtitle"> { } /** * @public * Settings for starting a QUIC listener for direct MoQT subscriber connections. * Multiple egests on the same port share a single listener via the listener pool. */ export interface MoqOutputListenerSettings { /** * Disable verification of remote server's TLS certificate * (for development use ONLY, not for production) */ disableTlsVerify: boolean; /** * QUIC listener port for direct MoQT subscriber connections (e.g. from another Norsk instance). * Multiple egests on the same port share a single listener via the listener pool. */ quicServerPort?: number; /** * WebTransport listener port for browser-based subscribers (e.g. moq-js). * Must be a different port from quicServerPort. */ webTransportPort?: number; /** * TLS certificate file path (required when quicServerPort or webTransportPort is set) */ quicServerCert?: string; /** * TLS private key file path (required when quicServerPort or webTransportPort is set) */ quicServerKey?: string; /** * Also accept subscribers over the shared per-instance iroh endpoint * (see norsk.system.iroh): the namespace routes on the endpoint's * NodeId, so remote peers can subscribe via `iroh://` with no * port, cert or firewall hole. Peers must be on the endpoint's * allow-list. */ iroh?: boolean; /** * Or accept over a DEDICATED iroh identity for this output alone — * its own key, allow-list and relay mode on its own endpoint * (advanced/multi-tenant; most users want `iroh: true`). */ irohDedicated?: IrohDedicatedListenerSettings; } /** * A dedicated iroh listener identity (own key/allow-list/relay mode on * its own endpoint) for a single MoQ input/output. Note the * default-closed policy: relayMode 'default' (publicly reachable) with * no allow-list refuses to start. * @public */ export interface IrohDedicatedListenerSettings { /** * Pool slot (>= 1; 0 is reserved for the shared endpoint). Inputs/ * outputs naming the same slot share the listener (first configuration * wins; later mismatching configs are rejected). */ slot: number; /** * Identity key file (load-or-generate, mode 0600) — a stable NodeId * across restarts. Omitted: fresh unpersisted identity per start. */ secretKeyFile?: string; /** 'default' (relays + discovery) or 'disabled' (direct paths only). */ relayMode?: 'default' | 'disabled'; /** Verified remote NodeIds (64-char hex) allowed to connect. */ allowedPeers?: string[]; /** Explicit opt-in to accept ANY peer. */ allowAnyPeer?: boolean; /** Allow-list file (one hex NodeId per line, # comments). */ allowedPeersFile?: string; /** * Self-hosted relay server URLs (https) — uses YOUR relays and disables * n0's discovery. Mutually exclusive with relayMode 'disabled'. */ relayUrls?: string[]; } /** * @public * Settings for connecting to a MoQT relay (e.g. CDN primary or backup). */ export interface MoqOutputRelaySettings { /** * The URL of the MoQT relay to connect to and publish tracks for */ relayUrl: string; /** * Optional namespace override for this relay, as a list of segments * (the on-the-wire MoQT tuple). If not provided, the main namespace * is used. */ namespace?: string[]; /** * When true, skip TLS certificate verification for this relay. * Required for self-signed certificates (e.g. local testing). */ disableTlsVerify?: boolean; } /** * @public * Settings to configure a Moq Egest * see {@link NorskOutput.moq} */ export interface MoqOutputSettings extends SinkNodeSettings, StreamStatisticsMixin { /** * The namespace to publish tracks within, as a list of segments * (the on-the-wire MoQT tuple). For example, the namespace * `<"stage", "primary">` is `["stage", "primary"]`. */ namespace: string[]; /** * MoQT relays to connect to and publish tracks for (e.g. CDN primary and backup) */ relays?: MoqOutputRelaySettings[]; /** * Optional: start a QUIC listener for direct MoQT subscriber connections. */ listener?: MoqOutputListenerSettings; /** * Called when a new subscriber connects via QUIC or WebTransport. * Return accept with a sourceName, or reject to deny the connection. */ onConnection?: (connectionIndex: number, remoteHost: string) => MoqConnectionResult; /** * Called when a connection status changes (connected, disconnected) */ onConnectionStatusChange?: (connectionIndex: number, state: string) => void; /** * Called whenever an upstream relay this egest is publishing to * transitions through one of the lifecycle states. Use this to * surface connection / announce / ready / failure events to the * application UI. The `relayUrl` lets you correlate events when * multiple relays are configured. * * Sequence (per relay): * * "connecting" → "announcing" → "connected" → "ready" * ↓ (on retry) * "announceFailed" { reason, retryMs } → loops back to "announcing" * * At any time after "connecting": * "disconnected" { reason } * * "connected" and "ready" are deliberately separate so a UI can * distinguish "we have a session, but the namespace hasn't been * accepted yet" from "the relay is publishing-ready". */ onRelayStateChange?: (event: MoqRelayStateEvent) => void; /** * If set, a PRFT (Producer Reference Time) box is prepended to each * CMAF media segment carrying an NTP wall-clock timestamp. The * PdtSource controls how the timestamp is derived. * By default, PRFT is only emitted on keyframe fragments. */ outputTimecode?: PdtSource; /** * When true, emit PRFT on every fragment. Default: false (keyframes only). */ outputTimecodeOnAllFrames?: boolean; /** * Optional jitter buffer configuration for smoothing output timing. */ jitterBuffer?: JitterBufferConfig; /** * Settings for C2PA (Content Provenance and Authenticity) signing * of MoQ output. When set, the init segment and every fragment of * each published track is signed before being broadcast. */ c2paSigning?: C2paSigningSettings; /** * Advertised (maximum) video bitrate in bits per second, published in the * catalog. Only needed when the stream bitrate is otherwise unknown — * typically a pass-through scenario; when encoding, the bitrate comes from the * encode. MSF-format catalogs require a bitrate for audio/video tracks. */ videoBitrate?: number; /** * Advertised (maximum) audio bitrate in bits per second, published in the * catalog. See {@link MoqOutputSettings.videoBitrate}. */ audioBitrate?: number; /** * Pin the MoQT transport draft this egest speaks, instead of auto-negotiating * the newest one. Omit (or "auto") to negotiate. Mainly useful for tests that * want to exercise a specific version. */ moqProtocolVersion?: "auto" | "draft14" | "draft16" | "draft18"; /** * Packaging format published by this egest. Defaults to `"cmaf"` * (fragmented MP4). `"loc"` publishes raw NAL payloads per object with the * codec init advertised inline in the catalog (Low Overhead Container). */ outputFormat?: "cmaf" | "loc"; /** * Per-object forwarding preference. Defaults to `"subgroup"` (reliable * unidirectional streams). `"datagram"` sends each media object as an * unreliable OBJECT_DATAGRAM for lower latency (catalog and codec init still * go reliably) — best paired with `outputFormat: "loc"`. */ forwardingPreference?: "subgroup" | "datagram"; } /** * @public * Result of a MoQ connection callback */ export type MoqConnectionResult = { accept: true; sourceName: string; } | { accept: false; }; /** * @public * Lifecycle event for a single upstream MoQT relay an egest is * publishing to. See {@link MoqOutputSettings.onRelayStateChange}. */ export type MoqRelayStateEvent = { relayUrl: string; state: "connecting"; } | { relayUrl: string; state: "announcing"; } | { relayUrl: string; state: "announceFailed"; reason: string; retryMs: number; } | { relayUrl: string; state: "connected"; } | { relayUrl: string; state: "ready"; } | { relayUrl: string; state: "disconnected"; reason: string; }; /** * @public * see: {@link NorskOutput.moq} */ export declare class MoqOutputNode extends AutoSinkMediaNode<"audio" | "video"> { /** * Close a specific subscriber connection. */ closeStream(connectionIndex: number): void; /** * Dynamically add an outbound MoQT relay to this egest. The egest * will spawn a relay manager that connects to `relay.relayUrl` and * starts publishing all live tracks to it. Repeated calls with the * same URL are no-ops — use {@link removeRelay} first if you want * to reconnect. */ addRelay(relay: MoqOutputRelaySettings): void; /** * Dynamically remove a previously-added outbound MoQT relay. The * relay manager for the matching URL is asked to shut down. If no * relay is currently registered for the URL the call is a no-op. */ removeRelay(relayUrl: string): void; } /** * @public * Settings to configure a Ndi Egest * see {@link NorskOutput.ndi} */ /** * @public * Configuration for a single MXL output flow (becomes an input pin on the node). */ export interface MxlOutputFlow { /** Pin name — used with subscribeToPins / videoToPin / audioToPin */ label: Pins; /** NMOS grouphint tag for flow discovery by downstream consumers */ groupHint: string; /** Media type: determines format conversion (v210 for video, float32 for audio) */ mediaType: "video" | "audio"; } /** * @public * Settings to configure an MXL (Media eXchange Layer) output. * Writes v210 video and float32 audio to an MXL domain for consumption by other MXL-enabled applications. * see: {@link NorskOutput.mxl} */ export interface MxlOutputSettings extends SinkNodeSettings>, StreamStatisticsMixin { /** MXL domain path (e.g. "/dev/shm/mxl") */ domain: string; /** Flow definitions — each becomes an input pin on the node */ flows: MxlOutputFlow[]; /** Jitter buffer configuration */ jitterBuffer?: JitterBufferConfig; } /** * @public * MXL Output Node - writes media to an MXL shared memory domain. * see: {@link NorskOutput.mxl} */ export declare class MxlOutputNode extends AutoSinkMediaNode { } export interface NdiOutputSettings extends SinkNodeSettings, StreamStatisticsMixin { /** * The NDI name to announce * */ name: string; /** * The NDI groups to announce to * */ groups?: string; /** Jitter buffer configuration */ jitterBuffer?: JitterBufferConfig; /** * Maximum duration to hold any stream in the case that one or more are running behind. In the case the late * stream is delayed rather than having a large gap, this will result in discarded input frames. */ maxQueueMs?: number; } /** * @public * see: {@link NorskOutput.ndi} */ export declare class NdiOutputNode extends AutoSinkMediaNode<"audio" | "video"> { } /** * @public * Status of a DeckLink output */ export type DeckLinkOutputStatus = "active" | "no_display_mode" | "no_host" | "start_failed"; /** * @public * Settings to configure a DeckLink (BlackMagic) output for SDI/HDMI playback * see {@link NorskOutput.deckLink} */ export interface DeckLinkOutputSettings extends SinkNodeSettings, StreamStatisticsMixin { /** The DeckLink card index (0-based) */ cardIndex: number; /** SDI or HDMI output */ videoConnection: DeckLinkVideoConnection; /** Pixel format for output */ pixelFormat: DeckLinkPixelFormat; /** Number of audio channels to output */ numAudioChannels: number; /** Keying mode (none, internal, or external) */ keyingMode?: DeckLinkKeyingMode; /** Jitter buffer configuration */ jitterBuffer?: JitterBufferConfig; /** Hardware profile to activate on the card before starting playback. * Only relevant for cards that support multiple profiles (e.g. DeckLink Duo 2, Quad 2). * If the card is already in the requested profile, this is a no-op. * If omitted, the card's current profile is used as-is. */ profileId?: DeckLinkProfileId; /** Typically left undefined: the output display mode is derived from the * incoming frames' resolution and frame rate, preferring progressive (so * e.g. 1080p25 content is emitted as 1080p25, not 1080i50). Set a specific * {@link DeckLinkDisplayModeId} only for the rare case where a particular SDI * timing is required that auto-selection wouldn't pick. */ displayModeId?: DeckLinkDisplayModeId; /** Called when the output status changes (e.g. playback started, display mode not found) */ onOutputStatus?: (status: DeckLinkOutputStatus) => void; } /** * @public * see: {@link NorskOutput.deckLink} */ export declare class DeckLinkOutputNode extends AutoSinkMediaNode<"audio" | "video" | "subtitle" | "ancillary"> { } /** * @public * Settings to control WebSocket output * see {@link NorskOutput.webSocket} */ export interface WebSocketOutputSettings extends SinkNodeSettings { /** * Required: name to determine the websocket url */ name: string; } /** * @public * see: {@link NorskOutput.webSocket} */ export declare class WebSocketOutputNode extends AutoSinkMediaNode<"audio"> { url(): string; } /** * @public * Methods that allow you to egest media from your application */ export interface NorskOutput { /** * Produces video segments with the supplied settings for use in * HLS or DASH manifests. * * These can optionally be served the Norsk web server or be pushed * to other locations - see {@link CmafDestinationSettings} * * @param settings - Configuration for the CMAF Video Stream */ cmafVideo(settings: CmafVideoOutputSettings): Promise; /** * Produces audio segments with the supplied settings for use in * HLS or DASH manifests. * * These can optionally be served via the Norsk web server or be pushed * to other locations - see {@link CmafDestinationSettings} * * @param settings - Configuration for the CMAF Audio Stream */ cmafAudio(settings: CmafAudioOutputSettings): Promise; /** * Produces WebVTT segments with the supplied settings for use in * HLS or DASH manifests. These are served via the Norsk web server * * @param settings - Configuration for the CMAF WebVTT Stream */ cmafWebVtt(settings: CmafWebVttOutputSettings): Promise; /** * Produces TTML subtitle segments (ISO/IEC 14496-30 `stpp`, fragmented MP4) * with the supplied settings for use in HLS or DASH manifests. Both HLS and * DASH reference the same fragmented-MP4 segments. * * @param settings - Configuration for the CMAF TTML Stream */ cmafTtml(settings: CmafTtmlOutputSettings): Promise; /** * Produces a multi variant (used to be known as master) hls and/or dash manifest for a collection of media streams * * This can optionally be served via the Norsk web server or be pushed * to other locations - see {@link CmafDestinationSettings} * * @param settings - Configuration for the CMAF Multi Variant Manifest */ cmafMultiVariant(settings: CmafMultiVariantOutputSettings): Promise; /** * Produces Transport Stream video segments with the supplied settings for use in * HLS manifests and builds a playlist served locally from the Norsk Web Server * or from other locations - see {@link CmafDestinationSettings} * * @param settings - Configuration for the HLS TS Stream */ hlsTsVideo(settings: HlsTsVideoOutputSettings): Promise; /** * Produces Transport Stream audio segments with the supplied settings for use in * HLS manifests and builds a playlist served locally from the Norsk Web Server * or from other locations - see {@link CmafDestinationSettings} * * @param settings - Configuration for the HLS TS Stream */ hlsTsAudio(settings: HlsTsAudioOutputSettings): Promise; /** * Produces Transport Stream segments containing both video and audio with the supplied settings for use in * HLS manifests and pushes them to the configured location (see {@link CmafDestinationSettings}) * * @param settings - Configuration for the HLS TS Stream */ hlsTsCombinedPush(settings: HlsTsCombinedPushOutputSettings): Promise; /** * Produces a multi variant HLS TS manifest for a collection of media streams * * This can optionally be served via the Norsk web server or be pushed * to other locations - see {@link CmafDestinationSettings} * * @param settings - Configuration for the Hls Ts Multivariant Playlist */ hlsTsMultiVariant(settings: HlsTsMultiVariantOutputSettings): Promise; /** * Produces Transport Stream video segments with the supplied settings and pushes a TAMS flow * and and these segments to a remote server via the TAMS write API * * @param settings - Configuration for the HLS TS Stream */ tamsVideoFlowPush(settings: TamsVideoFlowOutputSettings): Promise; /** * Produces Transport Stream audio segments with the supplied settings and pushes a TAMS flow * and and these segments to a remote server via the TAMS write API * @param settings - Configuration for the HLS TS Stream */ tamsAudioFlowPush(settings: TamsAudioFlowOutputSettings): Promise; /** * Produces a Transport Stream optionally containing both video and audio * and sends it out over UDP * * @param settings - Configuration for the TS Stream */ udpTs(settings: UdpTsOutputSettings): Promise; /** * Produces a Transport Stream optionally containing both video and audio * and sends it out over TCP. Norsk acts as the TCP client, connecting to * the destination host/port and reconnecting on failure. * * @param settings - Configuration for the TS Stream */ tcpTs(settings: TcpTsOutputSettings): Promise; /** * Produces a Transport Stream, and allows Norsk to either connect to an existing * SRT server or act as an SRT server itself * * @param settings - Configuration for the SRT Stream */ srt(settings: SrtOutputSettings): Promise; /** * Connects and sends media to a remote server via WebRTC using the WHIP standard. * * Here Norsk acts as the WHIP client sending to a remote Media Server; to * have Norsk act as the Media Server ingesting from some other WHIP client, see * {@link NorskInput.whip} * * @param settings - Configuration for the WebRTC Stream */ whip(settings: WhipOutputSettings): Promise; /** * Hosts media for clients connecting via WebRTC using the WHEP standard. * * To send media to a remote Media Server via WebRTC see {@link NorskOutput.whip}. * See also {@link NorskInput.whip}, {@link NorskDuplex.webRtcBrowser}. * * @param settings - Configuration for the WebRTC Stream */ whep(settings: WhepOutputSettings): Promise; /** * Outputs snapshots as images from a video stream to disk, and provides an endpoint for retrieving them * @param settings - Configuration for the Preview Stream */ imagePreview(settings: ImagePreviewOutputSettings): Promise; /** * Connects and sends media to a remote RTMP server * * @param settings - Configuration for the WebRTC Stream */ rtmp(settings: RtmpOutputSettings): Promise; /** * Stream to a Transport Stream file. * * @param settings - Configuration for the Transport Stream output */ fileTs(settings: FileTsOutputSettings): Promise; /** * Output MP4 files to disk, both fragmented and non-fragmented. * * The fragmented output is required. * * The optional non-fragmented filename will be written when calling * close and will be fully written by the time * {@link NodeSettings.onClose} is called. This sets up a temp file to * store the frame data by appending the extension `.tmp`. * * A non-fragmented MP4 file can be written on request with * {@link FileMp4OutputNode.writeFile}, which uses the frame data store if * {@link FileMp4OutputSettings.nonfragmentedFileName} was given or reads * back the fragmented mp4 if there is no non-fragmented file. * * @param settings - Configuration for the MP4 output. */ fileMp4(settings: FileMp4OutputSettings): Promise; /** * Output WAV files to disk. A WAV output cannot handle * context changes (for example, a change of sample rate), * so it is important that the upstream data is normalised. * The file being written to is finalised and closed when * the inbound context becomes empty. */ fileWav(settings: FileWavOutputSettings): Promise; /** * Play the subscribed audio on a local audio device (operator monitoring, * essentially latency-free). The input is converted to stereo/48 kHz; pick a * device by name from hardware info's `audioDevices`, or omit for the * default output device. */ localAudioMonitor(settings: LocalAudioMonitorSettings): Promise; /** * Output a WebVTT subtitle file to disk * @param settings - Configuration for the WebVTT output. */ fileWebVtt(settings: FileWebVttOutputSettings): Promise; /** * EXPERIMENTAL Connects and sends output to a remote Media over QUIC endpoint * * Here Norsk acts as a Media over QUIC Transport (MoQT) client publisher * and connects to a MoQT server subscriber (e.g. a relay) and publishes a * catalog and a video track into the configured namespace. * * Warning: experimental! Expect bugs and missing features. * * The MoQT specification is still a work in progress and this exeperimental * implementation serves to inform further specification changes * * Current target specification: \ * * The catalog track is named '.catalog' and describes the available * video track(s) within the namespace * * Video is currently configured to publish as fragmented MP4 (fMP4) * * @param settings - Configuration for the MoQ Output */ moq(settings: MoqOutputSettings): Promise; /** * Output to an NDI stream * @param settings - Configuration for the NDI output. */ ndi(settings: NdiOutputSettings): Promise; /** * Write media to an MXL (Media eXchange Layer) shared memory domain. * Accepts v210 video and float32 planar audio (auto-converts from other formats). * @param settings - Configuration for the MXL output */ mxl(settings: MxlOutputSettings): Promise>; /** * Output to a DeckLink (BlackMagic) card for SDI/HDMI playback * @param settings - Configuration for the DeckLink output. */ deckLink(settings: DeckLinkOutputSettings): Promise; /** * Output media frames to a websocket (select content/codecs only) */ webSocket(settings: WebSocketOutputSettings): Promise; } export {}; //# sourceMappingURL=output.d.ts.map