@norskvideo/norsk-sdk 1.0.384 → 1.0.386

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "license": "MIT",
3
3
  "name": "@norskvideo/norsk-sdk",
4
- "version": "1.0.384",
4
+ "version": "1.0.386",
5
5
  "dependencies": {
6
6
  "@bufbuild/protobuf": "^0.3.0",
7
7
  "@grpc/grpc-js": "^1.2.2",
8
- "@norskvideo/norsk-api": "1.0.384",
8
+ "@norskvideo/norsk-api": "1.0.386",
9
9
  "lodash": "^4.17.21",
10
10
  "typescript-nullable": "^0.6.0"
11
11
  },
@@ -636,6 +636,10 @@ export interface AudioSignalGeneratorSettings extends SourceNodeSettings<AudioSi
636
636
  sampleFormat?: SampleFormat;
637
637
  /** The language tag to use. Defaults to no language */
638
638
  language?: string;
639
+ /** Number of audio samples per frame. Defaults to 1024 */
640
+ numSamplesPerFrame?: number;
641
+ /** Number of frames to output. Defaults to infinite */
642
+ numFrames?: number;
639
643
  /**
640
644
  * Waveform - create one with {@link mkSine}
641
645
  * */
@@ -764,6 +768,23 @@ export declare class FileMp4InputNode extends SourceMediaNode {
764
768
  /** Seek to a given point, without starting playback. When the stream is played/resumed, it will start from (about) this offset */
765
769
  seek(offsetMs: number): void;
766
770
  }
771
+ /**
772
+ * @public
773
+ * Settings for an File Based WAV Input
774
+ * see: {@link NorskInput.fileWav}
775
+ */
776
+ export interface FileWavInputSettings extends SourceNodeSettings<FileWavInputNode> {
777
+ /** The source name to set in the stream key of the outgoing stream */
778
+ sourceName: string;
779
+ /** Path to the WAV file to read */
780
+ fileName: string;
781
+ }
782
+ /**
783
+ * @public
784
+ * see: {@link NorskInput.fileWav}
785
+ */
786
+ export declare class FileWavInputNode extends SourceMediaNode {
787
+ }
767
788
  /**
768
789
  * @public
769
790
  * Methods that allow you to ingest media into your application
@@ -830,6 +851,11 @@ export interface NorskInput {
830
851
  * @param settings - Configuration for the file input
831
852
  */
832
853
  fileMp4(settings: FileMp4InputSettings): Promise<FileMp4InputNode>;
854
+ /**
855
+ * Read a WAV file with PCM audio with realtime playback.
856
+ * @param settings - Configuration for the file input
857
+ */
858
+ fileWav(settings: FileWavInputSettings): Promise<FileWavInputNode>;
833
859
  /**
834
860
  * Stream from a remote RTP source
835
861
  *
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.FileMp4InputNode = exports.FileImageInputNode = exports.VideoTestcardGeneratorNode = exports.AudioSignalGeneratorNode = exports.BrowserInputNode = exports.M3u8InputNode = exports.UdpTsInputNode = exports.SrtInputNode = exports.FileTsInputNode = exports.StreamWebVttInputNode = exports.FileWebVttInputNode = exports.WhipInputNode = exports.DeltacastInputNode = exports.DeckLinkInputNode = exports.RtmpServerInputNode = exports.RtpInputNode = void 0;
3
+ exports.FileWavInputNode = exports.FileMp4InputNode = exports.FileImageInputNode = exports.VideoTestcardGeneratorNode = exports.AudioSignalGeneratorNode = exports.BrowserInputNode = exports.M3u8InputNode = exports.UdpTsInputNode = exports.SrtInputNode = exports.FileTsInputNode = exports.StreamWebVttInputNode = exports.FileWebVttInputNode = exports.WhipInputNode = exports.DeltacastInputNode = exports.DeckLinkInputNode = exports.RtmpServerInputNode = exports.RtpInputNode = void 0;
4
4
  const media_pb_1 = require("@norskvideo/norsk-api/lib/media_pb");
5
5
  const types_1 = require("./types");
6
6
  const types_2 = require("../types");
@@ -1128,7 +1128,9 @@ class AudioSignalGeneratorNode extends common_1.SourceMediaNode {
1128
1128
  sampleFormat: (0, types_1.toSampleFormat)(settings.sampleFormat ? settings.sampleFormat : "fltp"),
1129
1129
  sampleRate: (0, types_1.toSampleRate)(settings.sampleRate),
1130
1130
  channelLayout: (0, types_1.toChannelLayout)(settings.channelLayout),
1131
- language: (0, types_1.toOptString)(settings.language)
1131
+ language: (0, types_1.toOptString)(settings.language),
1132
+ samplesPerFrame: (0, types_1.toOptInt)(settings.numSamplesPerFrame),
1133
+ outputFrameCount: (0, types_1.toOptInt)(settings.numFrames)
1132
1134
  });
1133
1135
  this.grpcStream = this.client.media.createInputAudioSignalGenerator(config);
1134
1136
  this.initialised = new Promise((resolve, reject) => {
@@ -1412,4 +1414,51 @@ class FileMp4InputNode extends common_1.SourceMediaNode {
1412
1414
  }
1413
1415
  }
1414
1416
  exports.FileMp4InputNode = FileMp4InputNode;
1417
+ /**
1418
+ * @public
1419
+ * see: {@link NorskInput.fileWav}
1420
+ */
1421
+ class FileWavInputNode extends common_1.SourceMediaNode {
1422
+ /** @internal */
1423
+ constructor(settings, client, unregisterNode) {
1424
+ super(client, settings.onOutboundContextChange);
1425
+ const config = (0, utils_1.provideFull)(media_pb_1.FileWavInputConfiguration, {
1426
+ ...settings,
1427
+ id: settings.id
1428
+ ? (0, utils_1.provideFull)(media_pb_1.MediaNodeId, { id: settings.id })
1429
+ : undefined,
1430
+ });
1431
+ this.grpcStream = this.client.media.createInputFileWav(config);
1432
+ this.initialised = new Promise((resolve, reject) => {
1433
+ this.grpcStream.on("data", (data) => {
1434
+ const messageCase = data.message.case;
1435
+ switch (messageCase) {
1436
+ case undefined:
1437
+ break;
1438
+ case "nodeId": {
1439
+ this.id = data.message.value.id;
1440
+ settings.onCreate && settings.onCreate(this);
1441
+ resolve();
1442
+ break;
1443
+ }
1444
+ case "outboundContext": {
1445
+ const context = data.message.value;
1446
+ this.outboundContextChange(context);
1447
+ break;
1448
+ }
1449
+ default:
1450
+ (0, utils_1.exhaustiveCheck)(messageCase);
1451
+ }
1452
+ });
1453
+ (0, common_1.registerStreamHandlers)(this.grpcStream, () => unregisterNode(this), "mp4file", reject, settings);
1454
+ });
1455
+ }
1456
+ /** @internal */
1457
+ static async create(settings, client, unregisterNode) {
1458
+ const node = new FileWavInputNode(settings, client, unregisterNode);
1459
+ await node.initialised;
1460
+ return node;
1461
+ }
1462
+ }
1463
+ exports.FileWavInputNode = FileWavInputNode;
1415
1464
  //# sourceMappingURL=input.js.map
@@ -322,6 +322,7 @@ class MediaStoreAsset {
322
322
  this.closed = false;
323
323
  this.client = client;
324
324
  this.settings = settings;
325
+ this._complete = false;
325
326
  this.grpcStream = this.client.media.createMediaStoreAsset((0, common_1.provideFull)(media_pb_1.MediaStoreAssetSettings, {
326
327
  mediaStoreName: settings.name,
327
328
  assetSource: (0, common_1.provideFull)(media_pb_1.MediaStoreAssetSource, settings.source ?
@@ -343,8 +344,12 @@ class MediaStoreAsset {
343
344
  }));
344
345
  this._ready = new Promise((resolve, reject) => {
345
346
  this.grpcStream.on("error", (err) => reject(err));
346
- this.grpcStream.on("close", () => console.log("CLOSE"));
347
- this.grpcStream.on("end", () => console.log("END"));
347
+ this.grpcStream.on("close", () => { if (!this._complete) {
348
+ reject("Close before import complete");
349
+ } });
350
+ this.grpcStream.on("end", () => { if (!this._complete) {
351
+ reject("End before import complete");
352
+ } });
348
353
  this.grpcStream.on("data", (data) => {
349
354
  const messageCase = data.message.case;
350
355
  switch (messageCase) {
@@ -355,6 +360,7 @@ class MediaStoreAsset {
355
360
  break;
356
361
  }
357
362
  case "importComplete": {
363
+ this._complete = true;
358
364
  this.durationMs = data.message.value.durationMs;
359
365
  this.size = data.message.value.size;
360
366
  const metadataFn = util
@@ -1,6 +1,6 @@
1
1
  import * as grpc from "@grpc/grpc-js";
2
2
  import { CmafAudioMessage, CmafMultiVariantMessage, CmafVideoMessage, CmafWebVttMessage, HlsOutputEvent, HlsTsAudioMessage, HlsTsCombinedPushMessage, HlsTsVideoMessage, Subscription, HlsTsMultiVariantMessage } from "@norskvideo/norsk-api/lib/media_pb";
3
- import { AwsCredentials, EncryptionSettings, IceServerSettings, SrtMode, StreamMetadata, Scte35SpliceInfoSection } from "./types";
3
+ import { AwsCredentials, EncryptionSettings, IceServerSettings, SrtMode, StreamMetadata, Scte35SpliceInfoSection, AudioSegmentationStrategy, VideoSegmentationStrategy } from "./types";
4
4
  import { AutoProcessorMediaNode, ProcessorNodeSettings } from "./processor";
5
5
  import { AutoSinkMediaNode, MediaClient, MediaNodeState, SinkNodeSettings, StreamStatisticsMixin } from "./common";
6
6
  /**
@@ -60,6 +60,11 @@ export interface HlsTsVideoOutputSettings extends SinkNodeSettings<HlsTsVideoOut
60
60
  * to produce compliant segments that are less than or equal to this in duration
61
61
  */
62
62
  segmentDurationSeconds: number;
63
+ /**
64
+ * Optional stategy to be used in creating segments of the correct length
65
+ * care should be taken to not supply values that result in segments of an invalid length
66
+ */
67
+ segmentationStrategy?: VideoSegmentationStrategy;
63
68
  /**
64
69
  * A list of destinations {@link CmafDestinationSettings} for this stream to be published to
65
70
  */
@@ -98,6 +103,11 @@ export interface HlsTsAudioOutputSettings extends SinkNodeSettings<HlsTsAudioOut
98
103
  * without going over this target using the durations of the individual audio frames
99
104
  */
100
105
  segmentDurationSeconds: number;
106
+ /**
107
+ * Optional stategy to be used in creating segments of the correct length
108
+ * care should be taken to not supply values that result in segments of an invalid length
109
+ */
110
+ segmentationStrategy?: AudioSegmentationStrategy;
101
111
  /**
102
112
  * A list of destinations {@link CmafDestinationSettings} for this stream to be published to
103
113
  */
@@ -171,11 +181,16 @@ export interface UpdateCredentials {
171
181
  */
172
182
  export interface HlsTsCombinedPushOutputSettings extends SinkNodeSettings<HlsTsCombinedPushOutputNode> {
173
183
  /**
174
- * The target segment duration in seconds. Norsk will use the framerate of the video stream in order
184
+ * The target segment duration in seconds. By default, Norsk will use the framerate of the video stream in order
175
185
  * to produce compliant segments that are less than or equal to this in duration, with audio packaged alongside
176
186
  * using timestamps to line them up
177
187
  */
178
188
  segmentDurationSeconds: number;
189
+ /**
190
+ * Optional stategy to be used instead of the default in creating segments of the correct length
191
+ * care should be taken to not supply values that result in segments of an invalid length
192
+ */
193
+ segmentationStrategy?: VideoSegmentationStrategy;
179
194
  /**
180
195
  * The destination {@link CmafDestinationSettings} for this stream to be published to
181
196
  */
@@ -860,6 +875,23 @@ export declare class FileMp4OutputNode extends AutoSinkMediaNode<"audio" | "vide
860
875
  */
861
876
  writeFile(nonfragmentedFileName: string): void;
862
877
  }
878
+ /**
879
+ * @public
880
+ * Settings to control WAV file output
881
+ * see {@link NorskOutput.fileWav}
882
+ */
883
+ export interface FileWavOutputSettings extends SinkNodeSettings<FileWavOutputNode> {
884
+ /**
885
+ * Required: stream audio to this file.
886
+ */
887
+ fileName: string;
888
+ }
889
+ /**
890
+ * @public
891
+ * see: {@link NorskOutput.fileWav}
892
+ */
893
+ export declare class FileWavOutputNode extends AutoSinkMediaNode<"audio"> {
894
+ }
863
895
  /**
864
896
  * @public
865
897
  * Settings to control MP4 file output
@@ -1031,6 +1063,14 @@ export interface NorskOutput {
1031
1063
  * @param settings - Configuration for the MP4 output.
1032
1064
  */
1033
1065
  fileMp4(settings: FileMp4OutputSettings): Promise<FileMp4OutputNode>;
1066
+ /**
1067
+ * Output WAV files to disk. A WAV output cannot handle
1068
+ * context changes (for example, a change of sample rate),
1069
+ * so it is important that the upstream data is normalised.
1070
+ * The file being written to is finalised and closed when
1071
+ * the inbound context becomes empty.
1072
+ */
1073
+ fileWav(settings: FileWavOutputSettings): Promise<FileWavOutputNode>;
1034
1074
  /**
1035
1075
  * Output a WebVTT subtitle file to disk
1036
1076
  * @param settings - Configuration for the WebVTT output.
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.MoqOutputNode = exports.FileWebVttOutputNode = exports.FileMp4OutputNode = exports.FileTsOutputNode = exports.RtmpOutputNode = exports.RtmpConnectionFailureReason = exports.WhepOutputNode = exports.WhipOutputNode = exports.SrtOutputNode = exports.UdpTsOutputNode = exports.HlsTsMultiVariantOutputNode = exports.CmafMultiVariantOutputNode = exports.CmafWebVttOutputNode = exports.HlsTsCombinedPushOutputNode = exports.HlsTsAudioOutputNode = exports.HlsTsVideoOutputNode = exports.CmafAudioOutputNode = exports.CmafVideoOutputNode = exports.isScheduledTag = exports.isProgramDateTime = exports.isHlsTag = exports.isAdMarker = exports.isMediaSegment = void 0;
6
+ exports.MoqOutputNode = exports.FileWebVttOutputNode = exports.FileWavOutputNode = exports.FileMp4OutputNode = exports.FileTsOutputNode = exports.RtmpOutputNode = exports.RtmpConnectionFailureReason = exports.WhepOutputNode = exports.WhipOutputNode = exports.SrtOutputNode = exports.UdpTsOutputNode = exports.HlsTsMultiVariantOutputNode = exports.CmafMultiVariantOutputNode = exports.CmafWebVttOutputNode = exports.HlsTsCombinedPushOutputNode = exports.HlsTsAudioOutputNode = exports.HlsTsVideoOutputNode = exports.CmafAudioOutputNode = exports.CmafVideoOutputNode = exports.isScheduledTag = exports.isProgramDateTime = exports.isHlsTag = exports.isAdMarker = exports.isMediaSegment = void 0;
7
7
  const media_pb_1 = require("@norskvideo/norsk-api/lib/media_pb");
8
8
  const types_1 = require("./types");
9
9
  const common_pb_1 = require("@norskvideo/norsk-api/lib/shared/common_pb");
@@ -139,6 +139,7 @@ class CmafNodeBase extends processor_1.AutoProcessorMediaNode {
139
139
  break;
140
140
  case "nodeId":
141
141
  this.id = data.message.value.id;
142
+ settings.onCreate && settings.onCreate(this);
142
143
  resolve();
143
144
  break;
144
145
  case "inboundContext": {
@@ -563,7 +564,8 @@ class HlsTsVideoOutputNode extends CmafNodeWithPlaylist {
563
564
  bitrate: settings.bitrate || 0,
564
565
  name: (0, types_1.toOptString)(settings.name),
565
566
  pdtEverySegment: !!settings.pdtEverySegment,
566
- metrics: (0, types_1.toApiMetrics)(settings.metrics)
567
+ metrics: (0, types_1.toApiMetrics)(settings.metrics),
568
+ segmentationStrategy: settings.segmentationStrategy ? (0, types_1.toSegmentationStrategy)(settings.segmentationStrategy) : undefined
567
569
  });
568
570
  const hls = client.media.createOutputHlsTsVideo();
569
571
  hls.write((0, utils_1.provideFull)(media_pb_1.HlsTsVideoMessage, (0, utils_1.mkMessageCase)({ configuration: config })));
@@ -618,7 +620,8 @@ class HlsTsAudioOutputNode extends CmafNodeWithPlaylist {
618
620
  bitrate: settings.bitrate || 0,
619
621
  name: (0, types_1.toOptString)(settings.name),
620
622
  pdtEverySegment: !!settings.pdtEverySegment,
621
- metrics: (0, types_1.toApiMetrics)(settings.metrics)
623
+ metrics: (0, types_1.toApiMetrics)(settings.metrics),
624
+ segmentationStrategy: settings.segmentationStrategy ? (0, types_1.toSegmentationStrategy)(settings.segmentationStrategy) : undefined
622
625
  });
623
626
  const hls = client.media.createOutputHlsTsAudio();
624
627
  hls.write((0, utils_1.provideFull)(media_pb_1.HlsTsAudioMessage, (0, utils_1.mkMessageCase)({ configuration: config })));
@@ -676,7 +679,8 @@ class HlsTsCombinedPushOutputNode extends CmafNodeWithPlaylist {
676
679
  destination: mkCmafDestination(settings.destination),
677
680
  m3uAdditions: settings.m3uAdditions || "",
678
681
  name: (0, types_1.toOptString)(settings.name),
679
- pdtEverySegment: !!settings.pdtEverySegment
682
+ pdtEverySegment: !!settings.pdtEverySegment,
683
+ segmentationStrategy: settings.segmentationStrategy ? (0, types_1.toSegmentationStrategy)(settings.segmentationStrategy) : undefined
680
684
  });
681
685
  const hls = client.media.createOutputHlsTsCombinedPush();
682
686
  hls.write((0, utils_1.provideFull)(media_pb_1.HlsTsCombinedPushMessage, (0, utils_1.mkMessageCase)({ configuration: config })));
@@ -1332,6 +1336,57 @@ class FileMp4OutputNode extends common_1.AutoSinkMediaNode {
1332
1336
  }
1333
1337
  }
1334
1338
  exports.FileMp4OutputNode = FileMp4OutputNode;
1339
+ /**
1340
+ * @public
1341
+ * see: {@link NorskOutput.fileWav}
1342
+ */
1343
+ class FileWavOutputNode extends common_1.AutoSinkMediaNode {
1344
+ /** @internal */
1345
+ constructor(settings, client, unregisterNode) {
1346
+ super(client, () => this.grpcStream, async (subscription) => this.grpcStream.write((0, utils_1.provideFull)(media_pb_1.FileWavOutputMessage, (0, utils_1.mkMessageCase)({ subscription }))), settings.onSubscriptionError);
1347
+ const config = (0, utils_1.provideFull)(media_pb_1.FileWavOutputConfiguration, {
1348
+ ...settings,
1349
+ id: settings.id
1350
+ ? (0, utils_1.provideFull)(media_pb_1.MediaNodeId, { id: settings.id })
1351
+ : undefined,
1352
+ });
1353
+ this.grpcStream = this.client.media.createOutputFileWav();
1354
+ this.grpcStream.write((0, utils_1.provideFull)(media_pb_1.FileWavOutputMessage, (0, utils_1.mkMessageCase)({ configuration: config })));
1355
+ this.initialised = new Promise((resolve, reject) => {
1356
+ this.grpcStream.on("data", (data) => {
1357
+ const messageCase = data.message.case;
1358
+ switch (messageCase) {
1359
+ case undefined:
1360
+ break;
1361
+ case "subscriptionResponse":
1362
+ super.subscriptionResponse(data.message.value);
1363
+ break;
1364
+ case "nodeId": {
1365
+ this.id = data.message.value.id;
1366
+ settings.onCreate && settings.onCreate(this);
1367
+ resolve();
1368
+ break;
1369
+ }
1370
+ case "inboundContext": {
1371
+ const context = data.message.value;
1372
+ super.handleInboundContext(context);
1373
+ break;
1374
+ }
1375
+ default:
1376
+ (0, utils_1.exhaustiveCheck)(messageCase);
1377
+ }
1378
+ });
1379
+ (0, common_1.registerStreamHandlers)(this.grpcStream, () => unregisterNode(this), "fileMp4Output", reject, settings);
1380
+ });
1381
+ }
1382
+ /** @internal */
1383
+ static async create(settings, client, unregisterNode) {
1384
+ const node = new FileWavOutputNode(settings, client, unregisterNode);
1385
+ await node.initialised;
1386
+ return node;
1387
+ }
1388
+ }
1389
+ exports.FileWavOutputNode = FileWavOutputNode;
1335
1390
  /**
1336
1391
  * @public
1337
1392
  * see: {@link NorskOutput.fileWebVtt}
@@ -1,9 +1,9 @@
1
1
  /// <reference types="node" />
2
2
  import { PlainMessage } from "@bufbuild/protobuf";
3
- import { StreamStatisticsSampling, Subscription, SipEvent_Status } from "@norskvideo/norsk-api/lib/media_pb";
3
+ import { StreamStatisticsSampling, Subscription, SipEvent_Status, AudioWatermarkLicenseInformation, AudioWatermarkSnapEvent } from "@norskvideo/norsk-api/lib/media_pb";
4
4
  import { FrameRate, VancPayloadFormat, VancType2AncillaryId } from "../types";
5
5
  import { AutoSinkMediaNode, MediaClient, MediaNodeState, SinkNodeSettings, SourceMediaNode, SourceMediaNodeEvents, SourceNodeSettings, StreamStatisticsMixin } from "./common";
6
- import { AacProfile, AudioMeasureLevels, AwsCredentials, ChannelLayout, ComposeMissingStreamBehaviour, ComposeHardwareAcceleration, Db, IceServerSettings, LoganH264, LoganHevc, MultiStreamStatistics, NvidiaH264, NvidiaHevc, PixelFormat, QuadraH264, QuadraHevc, AmdU30H264, AmdU30Hevc, AmdMA35DH264, AmdMA35DHevc, Resolution, SampleAspectRatio, SampleRate, SentenceBuildMode, SimpleEasing, StabilizationMode, StreamKey, StreamMetadata, X264Codec, X265Codec, SubscriptionError, DeinterlaceSettings, Scte35SpliceInfoSection, Interval, SampleFormat, VideoStreamMetadata } from "./types";
6
+ import { AacProfile, AudioMeasureLevels, AwsCredentials, ChannelLayout, ComposeMissingStreamBehaviour, ComposeHardwareAcceleration, Db, IceServerSettings, LoganH264, LoganHevc, MultiStreamStatistics, NvidiaH264, NvidiaHevc, PixelFormat, QuadraH264, QuadraHevc, AmdU30H264, AmdU30Hevc, AmdMA35DH264, AmdMA35DHevc, Resolution, SampleAspectRatio, SampleRate, SentenceBuildMode, SimpleEasing, StabilizationMode, StreamKey, StreamMetadata, X264Codec, X265Codec, SubscriptionError, DeinterlaceSettings, Scte35SpliceInfoSection, Interval, SampleFormat, VideoStreamMetadata, QuadraAv1, AmdMA35DAv1 } from "./types";
7
7
  import { Writable, Readable } from 'stream';
8
8
  /** @public */
9
9
  export interface ProcessorMediaNode<Pins extends string> extends SourceMediaNode<SourceMediaNodeEvents>, AutoSinkMediaNode<Pins, SourceMediaNodeEvents> {
@@ -91,6 +91,10 @@ export interface StreamSwitchSmoothSettings<Pins extends string> extends Process
91
91
  */
92
92
  hardwareAcceleration?: ComposeHardwareAcceleration;
93
93
  }
94
+ export interface StreamSwitchSmoothSwitchOptions {
95
+ /** Duration to switch for this transition only (if omitted, the configured default shall be used, to suppress a transition specify this but as 0). */
96
+ transitionDurationMs?: number;
97
+ }
94
98
  /**
95
99
  * @public
96
100
  * see: {@link NorskControl.streamSwitchSmooth}
@@ -100,7 +104,7 @@ export declare class StreamSwitchSmoothNode<Pins extends string> extends Process
100
104
  * @public
101
105
  * Switches the source used for the current output of this node
102
106
  */
103
- switchSource(newSource: Pins): void;
107
+ switchSource(newSource: Pins, options?: StreamSwitchSmoothSwitchOptions): void;
104
108
  }
105
109
  /**
106
110
  * @public
@@ -472,6 +476,36 @@ export interface ComposePart<Pins> {
472
476
  */
473
477
  compose: <Pins extends string>(partStream: VideoStreamMetadata, settings: VideoComposeSettings<Pins>) => ComposeOperation;
474
478
  }
479
+ export interface AudioWatermarkOnlineLicense {
480
+ type: "online";
481
+ login: string;
482
+ password: string;
483
+ server?: string;
484
+ port?: number;
485
+ licenseId: bigint;
486
+ }
487
+ export interface AudioWatermarkOfflineLicense {
488
+ type: "offline";
489
+ kantarLicensePath: string;
490
+ audienceLicensePath: string;
491
+ channelName: string;
492
+ }
493
+ /**
494
+ * @public
495
+ * Settings for an Audio Watermark node
496
+ * see: {@link NorskTransform.audioWatermark}
497
+ * */
498
+ export interface AudioWatermarkSettings extends ProcessorNodeSettings<AudioWatermarkNode> {
499
+ license: AudioWatermarkOnlineLicense | AudioWatermarkOfflineLicense;
500
+ onLicenseInformation?: (info: AudioWatermarkLicenseInformation) => void;
501
+ onSnapEvent?: (event: AudioWatermarkSnapEvent) => void;
502
+ }
503
+ /**
504
+ * @public
505
+ * see: {@link NorskTransform.audioWatermakr}
506
+ */
507
+ export declare class AudioWatermarkNode extends AutoProcessorMediaNode<"audio"> {
508
+ }
475
509
  export declare type ComposeOperation = {
476
510
  /**
477
511
  * The area within the source picture to include. This may be the full picture
@@ -1025,7 +1059,7 @@ export interface VideoEncodeRung {
1025
1059
  * A ladder can use several different codecs across its various rungs and the
1026
1060
  * VideoEncode node will attempt to build a pipeline that uses the hardware efficently
1027
1061
  */
1028
- codec: X264Codec | X265Codec | NvidiaH264 | NvidiaHevc | LoganH264 | LoganHevc | QuadraH264 | QuadraHevc | AmdU30H264 | AmdU30Hevc | AmdMA35DH264 | AmdMA35DHevc;
1062
+ codec: X264Codec | X265Codec | NvidiaH264 | NvidiaHevc | LoganH264 | LoganHevc | QuadraH264 | QuadraHevc | QuadraAv1 | AmdU30H264 | AmdU30Hevc | AmdMA35DH264 | AmdMA35DHevc | AmdMA35DAv1;
1029
1063
  }
1030
1064
  /**
1031
1065
  * @public
@@ -1323,6 +1357,21 @@ export interface NorskTransform {
1323
1357
  * bitrate.
1324
1358
  */
1325
1359
  audioEncode(settings: AudioEncodeSettings): Promise<AudioEncodeNode>;
1360
+ /**
1361
+ * Embeds audio watermarks into the audio stream, using Kantar Media's SNAP
1362
+ * technology, see kantarmedia.com for details. Norsk supports both online
1363
+ * and offline licensing models, and the relevant license information is
1364
+ * provided to Norsk through the AudioWatermarkConfiguration message.
1365
+ * At runtime, notifications are returned through the stream of
1366
+ * AudioWatermarkEvent messages, which includes Kantar event information
1367
+ * and, for offline licenses, a notification of the number of days remaining.
1368
+ * Note that audio watermarking introduces around 50-60ms of delay to the
1369
+ * audio stream; Norsk will ensure that all related media streams (e.g.
1370
+ * video) are kept in sync.
1371
+ * @param settings - Settings for the watermark process, primarily
1372
+ * Kantar license information.
1373
+ */
1374
+ audioWatermark(settings: AudioWatermarkSettings): Promise<AudioWatermarkNode>;
1326
1375
  /**
1327
1376
  * Translate subtitles using the AWS Translate service.
1328
1377
  *
@@ -1459,7 +1508,6 @@ export declare class NorskProcessor {
1459
1508
  * Implements the {@link NorskTransform} interface
1460
1509
  */
1461
1510
  transform: NorskTransform;
1462
- close(): Promise<void>;
1463
1511
  constructor(client: MediaClient);
1464
1512
  }
1465
1513
  export {};
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.NorskProcessor = exports.SipNode = exports.WebRTCBrowserNode = exports.StreamChaosMonkeyNode = exports.VideoTransformNode = exports.VideoDecodeNode = exports.VideoEncodeNode = exports.AudioTranscribeWhisperNode = exports.AudioTranscribeAzureNode = exports.SubtitleConvertNode = exports.SubtitleTranslateAwsNode = exports.AudioTranscribeAwsNode = exports.AudioBuildMultichannelNode = exports.AudioSplitMultichannelNode = exports.AudioGainNode = exports.AudioMixMatrixNode = exports.AudioMixNode = exports.VideoComposeNode = exports.VideoComposeDefaults = exports.AudioEncodeNode = exports.MetadataCombineMode = exports.AncillaryNode = exports.StreamConditionNode = exports.StreamAlignNode = exports.StreamSyncNode = exports.JitterBufferNode = exports.StreamMetadataOverrideNode = exports.StreamKeyOverrideNode = exports.StreamTimestampNudgeNode = exports.AudioMeasureLevelsNode = exports.StreamStatisticsNode = exports.StreamSwitchSmoothNode = exports.StreamSwitchHardNode = exports.AutoProcessorMediaNode = exports.ProcessorMediaNode = void 0;
6
+ exports.NorskProcessor = exports.SipNode = exports.WebRTCBrowserNode = exports.StreamChaosMonkeyNode = exports.VideoTransformNode = exports.VideoDecodeNode = exports.VideoEncodeNode = exports.AudioTranscribeWhisperNode = exports.AudioTranscribeAzureNode = exports.SubtitleConvertNode = exports.SubtitleTranslateAwsNode = exports.AudioTranscribeAwsNode = exports.AudioBuildMultichannelNode = exports.AudioSplitMultichannelNode = exports.AudioGainNode = exports.AudioMixMatrixNode = exports.AudioMixNode = exports.VideoComposeNode = exports.VideoComposeDefaults = exports.AudioWatermarkNode = exports.AudioEncodeNode = exports.MetadataCombineMode = exports.AncillaryNode = exports.StreamConditionNode = exports.StreamAlignNode = exports.StreamSyncNode = exports.JitterBufferNode = exports.StreamMetadataOverrideNode = exports.StreamKeyOverrideNode = exports.StreamTimestampNudgeNode = exports.AudioMeasureLevelsNode = exports.StreamStatisticsNode = exports.StreamSwitchSmoothNode = exports.StreamSwitchHardNode = exports.AutoProcessorMediaNode = exports.ProcessorMediaNode = void 0;
7
7
  const events_1 = __importDefault(require("events"));
8
8
  const media_pb_1 = require("@norskvideo/norsk-api/lib/media_pb");
9
9
  const common_pb_1 = require("@norskvideo/norsk-api/lib/shared/common_pb");
@@ -220,10 +220,12 @@ class StreamSwitchSmoothNode extends ProcessorMediaNode {
220
220
  * @public
221
221
  * Switches the source used for the current output of this node
222
222
  */
223
- switchSource(newSource) {
223
+ switchSource(newSource, options) {
224
+ const transitionDurationMs = options?.transitionDurationMs;
224
225
  this.grpcStream.write((0, utils_1.provideFull)(media_pb_1.StreamSwitchSmoothMessage, (0, utils_1.mkMessageCase)({
225
226
  switchSource: (0, utils_1.provideFull)(media_pb_1.StreamSwitchSmoothSwitch, {
226
227
  newActiveSource: (0, utils_1.provideFull)(media_pb_1.InputPin, { inputPin: newSource }),
228
+ transitionDurationMs: transitionDurationMs !== undefined ? (0, utils_1.provideFull)(common_pb_1.OptionalFloat, { value: transitionDurationMs }) : undefined
227
229
  }),
228
230
  })));
229
231
  }
@@ -1088,6 +1090,89 @@ class AudioEncodeNode extends AutoProcessorMediaNode {
1088
1090
  }
1089
1091
  }
1090
1092
  exports.AudioEncodeNode = AudioEncodeNode;
1093
+ /**
1094
+ * @public
1095
+ * see: {@link NorskTransform.audioWatermakr}
1096
+ */
1097
+ class AudioWatermarkNode extends AutoProcessorMediaNode {
1098
+ /** @internal */
1099
+ constructor(settings, client, unregisterNode) {
1100
+ super(client, unregisterNode, () => this.grpcStream, async (subscription) => this.grpcStream.write((0, utils_1.provideFull)(media_pb_1.AudioWatermarkMessage, (0, utils_1.mkMessageCase)({ subscription }))));
1101
+ const license = (() => {
1102
+ const type = settings.license.type;
1103
+ switch (type) {
1104
+ case "online":
1105
+ return (0, utils_1.mkCase)({ onlineLicense: (0, utils_1.provideFull)(media_pb_1.AudioWatermarkConfiguration_OnlineLicense, { login: settings.license.login,
1106
+ password: settings.license.password,
1107
+ server: settings.license.server == undefined ? "" : settings.license.server,
1108
+ port: settings.license.port == undefined ? 0 : settings.license.port,
1109
+ licenseId: settings.license.licenseId,
1110
+ }) });
1111
+ case "offline":
1112
+ return (0, utils_1.mkCase)({ offlineLicense: (0, utils_1.provideFull)(media_pb_1.AudioWatermarkConfiguration_OfflineLicense, { audienceLicense: settings.license.audienceLicensePath,
1113
+ kantarLicense: settings.license.kantarLicensePath,
1114
+ channelName: settings.license.channelName
1115
+ }) });
1116
+ default:
1117
+ (0, utils_1.exhaustiveCheck)(type);
1118
+ }
1119
+ })();
1120
+ const config = new media_pb_1.AudioWatermarkConfiguration({
1121
+ id: settings.id
1122
+ ? (0, utils_1.provideFull)(media_pb_1.MediaNodeId, { id: settings.id })
1123
+ : undefined,
1124
+ license: license
1125
+ });
1126
+ this.grpcStream = this.client.media.createTransformAudioWatermark();
1127
+ this.grpcStream.write((0, utils_1.provideFull)(media_pb_1.AudioWatermarkMessage, (0, utils_1.mkMessageCase)({ initialConfig: config })));
1128
+ this.initialised = new Promise((resolve, reject) => {
1129
+ this.grpcStream.on("data", (data) => {
1130
+ const messageCase = data.message.case;
1131
+ switch (messageCase) {
1132
+ case undefined:
1133
+ break;
1134
+ case "subscriptionResponse":
1135
+ super.subscriptionResponse(data.message.value);
1136
+ break;
1137
+ case "nodeId": {
1138
+ this.id = data.message.value.id;
1139
+ settings.onCreate && settings.onCreate(this);
1140
+ resolve();
1141
+ break;
1142
+ }
1143
+ case "outboundContext": {
1144
+ const context = data.message.value;
1145
+ this.outboundContextChange(context);
1146
+ break;
1147
+ }
1148
+ case "inboundContext": {
1149
+ const context = data.message.value;
1150
+ super.handleInboundContext(context);
1151
+ break;
1152
+ }
1153
+ case "licenseInformation": {
1154
+ settings.onLicenseInformation && settings.onLicenseInformation(data.message.value);
1155
+ break;
1156
+ }
1157
+ case "snapEvent": {
1158
+ settings.onSnapEvent && settings.onSnapEvent(data.message.value);
1159
+ break;
1160
+ }
1161
+ default:
1162
+ (0, utils_1.exhaustiveCheck)(messageCase);
1163
+ }
1164
+ });
1165
+ (0, common_1.registerStreamHandlers)(this.grpcStream, () => unregisterNode(this), "audioWatermark", reject, settings);
1166
+ });
1167
+ }
1168
+ /** @internal */
1169
+ static async create(settings, client, unregisterNode) {
1170
+ const node = new AudioWatermarkNode(settings, client, unregisterNode);
1171
+ await node.initialised;
1172
+ return node;
1173
+ }
1174
+ }
1175
+ exports.AudioWatermarkNode = AudioWatermarkNode;
1091
1176
  exports.VideoComposeDefaults = {
1092
1177
  /**
1093
1178
  * Takes the whole input part and renders it over the whole output video, scaling it as required to fit
@@ -2104,6 +2189,12 @@ class VideoEncodeNode extends AutoProcessorMediaNode {
2104
2189
  value: (0, types_2.toQuadraHevc)(stream.codec),
2105
2190
  };
2106
2191
  break;
2192
+ case "quadra-av1":
2193
+ codec = {
2194
+ case: "quadraAv1",
2195
+ value: (0, types_2.toQuadraAv1)(stream.codec),
2196
+ };
2197
+ break;
2107
2198
  case "amdU30-h264":
2108
2199
  codec = {
2109
2200
  case: "amdU30H264",
@@ -2128,6 +2219,12 @@ class VideoEncodeNode extends AutoProcessorMediaNode {
2128
2219
  value: (0, types_2.toAmdMA35DHevc)(stream.codec),
2129
2220
  };
2130
2221
  break;
2222
+ case "amdMA35D-av1":
2223
+ codec = {
2224
+ case: "amdMA35DAv1",
2225
+ value: (0, types_2.toAmdMA35DAv1)(stream.codec),
2226
+ };
2227
+ break;
2131
2228
  default:
2132
2229
  (0, utils_1.exhaustiveCheck)(codecType);
2133
2230
  }
@@ -2604,6 +2701,7 @@ class NorskProcessor {
2604
2701
  audioBuildMultichannel: async (settings) => AudioBuildMultichannelNode.create(settings, client, unregisterNode).then(registerNode),
2605
2702
  audioSplitMultichannel: async (settings) => AudioSplitMultichannelNode.create(settings, client, unregisterNode).then(registerNode),
2606
2703
  audioEncode: async (settings) => AudioEncodeNode.create(settings, client, unregisterNode).then(registerNode),
2704
+ audioWatermark: async (settings) => AudioWatermarkNode.create(settings, client, unregisterNode).then(registerNode),
2607
2705
  subtitleTranslateAws: async (settings) => SubtitleTranslateAwsNode.create(settings, client, unregisterNode).then(registerNode),
2608
2706
  streamTimestampNudge: async (settings) => StreamTimestampNudgeNode.create(settings, client, unregisterNode).then(registerNode),
2609
2707
  streamKeyOverride: async (settings) => StreamKeyOverrideNode.create(settings, client, unregisterNode).then(registerNode),
@@ -2627,6 +2725,7 @@ class NorskProcessor {
2627
2725
  this.nodes = this.nodes.filter(n => n != node);
2628
2726
  node.finalise();
2629
2727
  }
2728
+ /** @internal */
2630
2729
  async close() {
2631
2730
  for (const n of this.nodes) {
2632
2731
  await n.close();