@norskvideo/norsk-sdk 1.0.391 → 1.0.392

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.
@@ -8,6 +8,7 @@ import { CmafAudioMessage } from '@norskvideo/norsk-api/lib/media_pb';
8
8
  import { CmafMultiVariantMessage } from '@norskvideo/norsk-api/lib/media_pb';
9
9
  import { CmafVideoMessage } from '@norskvideo/norsk-api/lib/media_pb';
10
10
  import { CmafWebVttMessage } from '@norskvideo/norsk-api/lib/media_pb';
11
+ import { Context as Context_2 } from '@norskvideo/norsk-api/lib/media_pb';
11
12
  import { CurrentLoad } from '@norskvideo/norsk-api/lib/shared/common_pb';
12
13
  import EventEmitter from 'events';
13
14
  import { ExplicitChannel } from '@norskvideo/norsk-api/lib/media_pb';
@@ -38,7 +39,6 @@ import { TsInputEvent } from '@norskvideo/norsk-api/lib/media_pb';
38
39
  import { UdpTsInputMessage } from '@norskvideo/norsk-api/lib/media_pb';
39
40
  import { Version } from '@norskvideo/norsk-api/lib/shared/common_pb';
40
41
  import { VideoTransformConfiguration } from '@norskvideo/norsk-api/lib/media_pb';
41
- import { Wave } from '@norskvideo/norsk-api/lib/media_pb';
42
42
  import { Writable } from 'stream';
43
43
 
44
44
  /** @public */
@@ -572,6 +572,8 @@ export declare type AudioSegmentationStrategy = SegmentationStrategyExactFrameCo
572
572
  * see: {@link NorskInput.audioSignal}
573
573
  */
574
574
  export declare class AudioSignalGeneratorNode extends SourceMediaNode {
575
+ /** @public */
576
+ updateConfig(update: AudioSignalGeneratorSettingsUpdate): void;
575
577
  }
576
578
 
577
579
  /**
@@ -595,8 +597,17 @@ export declare interface AudioSignalGeneratorSettings extends SourceNodeSettings
595
597
  /** Number of frames to output. Defaults to infinite */
596
598
  numFrames?: number;
597
599
  /**
598
- * Waveform - create one with {@link mkSine}
599
- * */
600
+ * Waveform - construct a {@link Wave} directoy, or from DMTF digits via {@link mkDtmf}
601
+ *
602
+ * If unspecified an arbitrary default signal is generated
603
+ */
604
+ wave?: Wave;
605
+ }
606
+
607
+ export declare interface AudioSignalGeneratorSettingsUpdate {
608
+ /**
609
+ * Updated waveform. If unspecified the originally configured waveform is retained
610
+ */
600
611
  wave?: Wave;
601
612
  }
602
613
 
@@ -2821,6 +2832,14 @@ export declare interface MetadataSendMessage extends MetadataMessage {
2821
2832
  /** @public */
2822
2833
  export declare type MetadataType = 'klv' | 'id3' | 'other';
2823
2834
 
2835
+ /**
2836
+ * @public
2837
+ *
2838
+ * Construct a waveform representing a string of DTMF digits. This is of finite duration, you may wish to sequence silence afterwards
2839
+ *
2840
+ **/
2841
+ export declare function mkDtmf(digits: string): Wave;
2842
+
2824
2843
  /**
2825
2844
  * @public
2826
2845
  * Generate encryption parameters from from an encryption KeyID and Key,
@@ -2828,7 +2847,11 @@ export declare type MetadataType = 'klv' | 'id3' | 'other';
2828
2847
  */
2829
2848
  export declare function mkEncryption(encryption: string | undefined, pssh?: string | undefined): EncryptionSettings | undefined;
2830
2849
 
2831
- /** @public */
2850
+ /**
2851
+ * @public
2852
+ *
2853
+ * Provided for compatibilty, this is just e.g. `{ type: "sine", freq: 444 }`
2854
+ */
2832
2855
  export declare function mkSine(freq: number): Wave;
2833
2856
 
2834
2857
  /**
@@ -4045,6 +4068,24 @@ export declare type QuadraHevcProfile = "main" | "main10";
4045
4068
  /** @public */
4046
4069
  export declare type QuadraHevcTier = "main" | "high";
4047
4070
 
4071
+ /**
4072
+ * @public
4073
+ * Settings for influencing the encode pipeline built for a quadra rung within a ladder
4074
+ */
4075
+ export declare type QuadraPipelineHints = {
4076
+ type: 'quadra';
4077
+ rescaler?: QuadraRescalerAlgorithm;
4078
+ };
4079
+
4080
+ /**
4081
+ * @public
4082
+ * The algorithm used for rescales in quadra pipeline, in ffmpeg parlance this is
4083
+ * 0 = default
4084
+ * 1 = filterblit
4085
+ * 2 = bicubic
4086
+ */
4087
+ export declare type QuadraRescalerAlgorithm = "default" | "filterblit" | "bicubic";
4088
+
4048
4089
  /** @public */
4049
4090
  export declare type ReceiveFromAddress<Pins extends string> = {
4050
4091
  source: SourceMediaNode;
@@ -4780,6 +4821,8 @@ export declare class SourceMediaNode<Events extends SourceMediaNodeEvents = Sour
4780
4821
  outputStreams: StreamMetadata[];
4781
4822
  registerForContextChange(subscriber: SubscribeDestination): void;
4782
4823
  unregisterForContextChange(subscriber: SubscribeDestination): void;
4824
+ /** @private */
4825
+ _outboundContextChange(context: Context_2): Promise<void>;
4783
4826
  }
4784
4827
 
4785
4828
  export declare type SourceMediaNodeEvents = {
@@ -5397,7 +5440,7 @@ export declare class StreamTimestampReportNode extends AutoSinkMediaNode<string>
5397
5440
  * see {@link NorskOutput.fileMp4}
5398
5441
  */
5399
5442
  export declare interface StreamTimestampReportSettings extends SinkNodeSettings<StreamTimestampReportNode> {
5400
- onTimestamp?: (streamKey: StreamKey, timestamp: Interval) => Promise<void>;
5443
+ onTimestamp?: (streamKey: StreamKey, timestamp: Interval) => void;
5401
5444
  }
5402
5445
 
5403
5446
  /**
@@ -5822,6 +5865,10 @@ export declare interface VideoEncodeRung {
5822
5865
  * VideoEncode node will attempt to build a pipeline that uses the hardware efficently
5823
5866
  */
5824
5867
  codec: X264Codec | X265Codec | NvidiaH264 | NvidiaHevc | LoganH264 | LoganHevc | QuadraH264 | QuadraHevc | QuadraAv1 | AmdU30H264 | AmdU30Hevc | AmdMA35DH264 | AmdMA35DHevc | AmdMA35DAv1;
5868
+ /**
5869
+ * Extra options for influencing how the ladder gets constructed and what algorithms get used for certain operations
5870
+ */
5871
+ pipelineHints?: QuadraPipelineHints;
5825
5872
  }
5826
5873
 
5827
5874
  /**
@@ -5930,6 +5977,37 @@ export declare interface VideoTransformSettings extends ProcessorNodeSettings<Vi
5930
5977
  sar?: SampleAspectRatio;
5931
5978
  }
5932
5979
 
5980
+ /**
5981
+ * @public
5982
+ *
5983
+ * Describes a waveform for use by audio signal generator. Constructed from simple sine waves, silence and sequences, loops, combinations
5984
+ * of those. May be finite or infinite in duration, it may often make sense to follow a timed signal with silence.
5985
+ *
5986
+ * See {@link mkDtmf} to construct DTMF tones.
5987
+ */
5988
+ export declare type Wave = {
5989
+ type: "sine";
5990
+ /** The wave frequency */
5991
+ freq: number;
5992
+ /** Level of the wave. 0 (the default) representing a full-scale sine wave, value must be negative or 0. */
5993
+ db?: number;
5994
+ } | {
5995
+ type: "silence";
5996
+ } | {
5997
+ type: "compound";
5998
+ components: Wave[];
5999
+ } | {
6000
+ type: "sequence";
6001
+ components: Wave[];
6002
+ } | {
6003
+ type: "loop";
6004
+ component: Wave;
6005
+ } | {
6006
+ type: "timed";
6007
+ component: Wave;
6008
+ durationMs: number;
6009
+ };
6010
+
5933
6011
  /**
5934
6012
  * @public
5935
6013
  * see: {@link NorskDuplex.webRtcBrowser}
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.391",
4
+ "version": "1.0.392",
5
5
  "dependencies": {
6
6
  "@bufbuild/protobuf": "^0.3.0",
7
7
  "@grpc/grpc-js": "^1.2.2",
8
- "@norskvideo/norsk-api": "1.0.391",
8
+ "@norskvideo/norsk-api": "1.0.392",
9
9
  "lodash": "^4.17.21",
10
10
  "typescript-nullable": "^0.6.0"
11
11
  },
@@ -7,7 +7,7 @@ export type MediaClient = {
7
7
  media: MediaClientPB;
8
8
  subscriptions: grpc.ClientDuplexStream<SubscriptionChannelMessage, SubscriptionChannelResponse>;
9
9
  };
10
- import { StreamStatisticsSampling, GopStructure, SubscriptionChannelMessage, SubscriptionChannelResponse } from "@norskvideo/norsk-api/lib/media_pb";
10
+ import { Context as ContextPB, StreamStatisticsSampling, GopStructure, SubscriptionChannelMessage, SubscriptionChannelResponse } from "@norskvideo/norsk-api/lib/media_pb";
11
11
  import { Nullable } from "typescript-nullable";
12
12
  import { StreamKey, MediaNodeId, StreamMetadata, Context, MultiStreamStatistics, SubscriptionError } from "./types";
13
13
  export * from "../shared/utils";
@@ -110,6 +110,8 @@ export declare class SourceMediaNode<Events extends SourceMediaNodeEvents = Sour
110
110
  outputStreams: StreamMetadata[];
111
111
  registerForContextChange(subscriber: SubscribeDestination): void;
112
112
  unregisterForContextChange(subscriber: SubscribeDestination): void;
113
+ /** @private */
114
+ _outboundContextChange(context: ContextPB): Promise<void>;
113
115
  }
114
116
  /**
115
117
  * @public
@@ -141,7 +141,8 @@ class SourceMediaNode extends MediaNodeState {
141
141
  (0, utils_1.debuglog)("Checking context on %s: %O", this.id, context.blockingCallRef);
142
142
  if (pending.pendingSubscribes.length == 0 && pending.readyToAck) {
143
143
  (0, utils_1.debuglog)("Node '%s' acknowledging context %O", this.id, context.blockingCallRef);
144
- _ackContext(this.client.subscriptions, this.id, context);
144
+ // Really should be awaiting this? How far up the callstack does this go???
145
+ void _ackContext(this.client.subscriptions, this.id, context);
145
146
  this.pendingContextAcks.delete(context.blockingCallRef);
146
147
  }
147
148
  else {
@@ -149,7 +150,11 @@ class SourceMediaNode extends MediaNodeState {
149
150
  }
150
151
  }
151
152
  /** @internal */
152
- async outboundContextChange(context) {
153
+ outboundContextChange(context) {
154
+ void this._outboundContextChange(context);
155
+ }
156
+ /** @private */
157
+ async _outboundContextChange(context) {
153
158
  (0, utils_1.debuglog)("Node '%s' received new outbound context %O", this.id, debugFormatContext(context));
154
159
  this.outputStreams = context.streams.map(types_1.fromStreamMetadata);
155
160
  // The client can do something before we notify subscribers then unblock - e.g. maybe spinning up a new node and subscribing it
@@ -283,7 +288,7 @@ class SinkMediaNode extends MediaNodeState {
283
288
  else {
284
289
  this.subscriptionValidation = this.defaultSubscriptionValidation;
285
290
  }
286
- this.sourceContextChange(done || (() => { }));
291
+ void this.sourceContextChange(done || (() => { }));
287
292
  }
288
293
  async sourceContextChange(responseCallback) {
289
294
  const stream = this.getGrpcStream();
@@ -326,11 +331,11 @@ class SinkMediaNode extends MediaNodeState {
326
331
  return subscribed;
327
332
  }
328
333
  /** @internal */
329
- async subscriptionResponse(response) {
330
- await this.finaliseSubscription(response.id, response.error);
334
+ subscriptionResponse(response) {
335
+ void this.finaliseSubscription(response.id, response.error);
331
336
  }
332
337
  /** @internal */
333
- async finaliseSubscription(id, err) {
338
+ finaliseSubscription(id, err) {
334
339
  const callback = this.subscriptionResponseCallbacks.get(id);
335
340
  this.subscriptionResponseCallbacks.delete(id);
336
341
  if (callback) {
@@ -354,7 +359,7 @@ class SinkMediaNode extends MediaNodeState {
354
359
  }
355
360
  }
356
361
  /** @internal */
357
- async handleInboundContext(context) {
362
+ handleInboundContext(context) {
358
363
  const validationResponse = this.subscriptionValidation((0, types_1.fromContext)(context));
359
364
  this.client.subscriptions.write((0, utils_1.provideFull)(media_pb_1.SubscriptionChannelMessage, (0, utils_1.mkMessageCase)({
360
365
  validationResponse: new media_pb_1.ValidationResponse({
@@ -362,7 +367,7 @@ class SinkMediaNode extends MediaNodeState {
362
367
  result: this.toValidationResponse(validationResponse),
363
368
  })
364
369
  })));
365
- _ackContext(this.client.subscriptions, this.id, context);
370
+ void _ackContext(this.client.subscriptions, this.id, context);
366
371
  }
367
372
  /** @internal */
368
373
  toValidationResponse(response) {
@@ -462,10 +467,10 @@ function registerStreamHandlers(grpcStream, unregisterNode, tag, reject, setting
462
467
  settings.onError && settings.onError(error);
463
468
  rejectReason = error;
464
469
  });
465
- grpcStream.on("close", async () => {
470
+ grpcStream.on("close", () => {
466
471
  (0, utils_1.debuglog)(`${tag} node close`);
467
- settings.onClose && await settings.onClose();
468
472
  unregisterNode();
473
+ settings.onClose && void settings.onClose();
469
474
  reject(rejectReason);
470
475
  });
471
476
  }
@@ -6,7 +6,7 @@ import { Interval, StreamKey } from "./types";
6
6
  * see {@link NorskOutput.fileMp4}
7
7
  */
8
8
  export interface StreamTimestampReportSettings extends SinkNodeSettings<StreamTimestampReportNode> {
9
- onTimestamp?: (streamKey: StreamKey, timestamp: Interval) => Promise<void>;
9
+ onTimestamp?: (streamKey: StreamKey, timestamp: Interval) => void;
10
10
  }
11
11
  /**
12
12
  * @public
@@ -1,6 +1,6 @@
1
1
  import * as grpc from "@grpc/grpc-js";
2
- import { TsInputEvent, StreamKey as StreamKeyPB, Wave, FileTsInputMessage, UdpTsInputMessage, M3u8MediaInputMessage, TimestampProgramNudge, RtmpError_UnsupportedVideo, RtmpError_UnsupportedAudio } from "@norskvideo/norsk-api/lib/media_pb";
3
- import { BrowserEvent, ChannelLayout, RtmpServerInputStatus, RtpLinearPcmBitDepth, SampleFormat, SampleRate, SrtMode, SrtInputStatus, ImageFormat, IceServerSettings, PixelFormat } from "./types";
2
+ import { TsInputEvent, StreamKey as StreamKeyPB, FileTsInputMessage, UdpTsInputMessage, M3u8MediaInputMessage, TimestampProgramNudge, RtmpError_UnsupportedVideo, RtmpError_UnsupportedAudio } from "@norskvideo/norsk-api/lib/media_pb";
3
+ import { BrowserEvent, ChannelLayout, RtmpServerInputStatus, RtpLinearPcmBitDepth, SampleFormat, SampleRate, SrtMode, SrtInputStatus, ImageFormat, IceServerSettings, PixelFormat, Wave } from "./types";
4
4
  import { FrameRate } from "../types";
5
5
  import { DeckLinkPixelFormat, DeckLinkVideoConnection, DeckLinkDisplayModeId } from "../types";
6
6
  import { MediaNodeState, MediaClient, SourceMediaNode, SourceNodeSettings, StreamStatisticsMixin } from "./common";
@@ -641,8 +641,16 @@ export interface AudioSignalGeneratorSettings extends SourceNodeSettings<AudioSi
641
641
  /** Number of frames to output. Defaults to infinite */
642
642
  numFrames?: number;
643
643
  /**
644
- * Waveform - create one with {@link mkSine}
645
- * */
644
+ * Waveform - construct a {@link Wave} directoy, or from DMTF digits via {@link mkDtmf}
645
+ *
646
+ * If unspecified an arbitrary default signal is generated
647
+ */
648
+ wave?: Wave;
649
+ }
650
+ export interface AudioSignalGeneratorSettingsUpdate {
651
+ /**
652
+ * Updated waveform. If unspecified the originally configured waveform is retained
653
+ */
646
654
  wave?: Wave;
647
655
  }
648
656
  /**
@@ -650,6 +658,8 @@ export interface AudioSignalGeneratorSettings extends SourceNodeSettings<AudioSi
650
658
  * see: {@link NorskInput.audioSignal}
651
659
  */
652
660
  export declare class AudioSignalGeneratorNode extends SourceMediaNode {
661
+ /** @public */
662
+ updateConfig(update: AudioSignalGeneratorSettingsUpdate): void;
653
663
  }
654
664
  /**
655
665
  * @public
@@ -1136,9 +1136,11 @@ class AudioSignalGeneratorNode extends common_1.SourceMediaNode {
1136
1136
  channelLayout: (0, types_1.toChannelLayout)(settings.channelLayout),
1137
1137
  language: (0, types_1.toOptString)(settings.language),
1138
1138
  samplesPerFrame: (0, types_1.toOptInt)(settings.numSamplesPerFrame),
1139
- outputFrameCount: (0, types_1.toOptInt)(settings.numFrames)
1139
+ outputFrameCount: (0, types_1.toOptInt)(settings.numFrames),
1140
+ wave: settings.wave !== undefined ? (0, types_1.toWave)(settings.wave) : undefined
1140
1141
  });
1141
- this.grpcStream = this.client.media.createInputAudioSignalGenerator(config);
1142
+ this.grpcStream = this.client.media.createInputAudioSignalGenerator();
1143
+ this.grpcStream.write((0, utils_1.provideFull)(media_pb_1.AudioSignalGeneratorMessage, (0, utils_1.mkMessageCase)({ initialConfig: config })));
1142
1144
  this.initialised = new Promise((resolve, reject) => {
1143
1145
  this.grpcStream.on("data", (data) => {
1144
1146
  const messageCase = data.message.case;
@@ -1163,6 +1165,13 @@ class AudioSignalGeneratorNode extends common_1.SourceMediaNode {
1163
1165
  (0, common_1.registerStreamHandlers)(this.grpcStream, () => unregisterNode(this), "audiosignal", reject, settings);
1164
1166
  });
1165
1167
  }
1168
+ /** @public */
1169
+ updateConfig(update) {
1170
+ const config = (0, utils_1.provideFull)(media_pb_1.AudioSignalGeneratorConfigurationUpdate, {
1171
+ wave: update.wave !== undefined ? (0, types_1.toWave)(update.wave) : undefined
1172
+ });
1173
+ this.grpcStream.write((0, utils_1.provideFull)(media_pb_1.AudioSignalGeneratorMessage, (0, utils_1.mkMessageCase)({ updateConfig: config })));
1174
+ }
1166
1175
  }
1167
1176
  exports.AudioSignalGeneratorNode = AudioSignalGeneratorNode;
1168
1177
  function toPattern(p) {
@@ -3,7 +3,7 @@ import { PlainMessage } from "@bufbuild/protobuf";
3
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, QuadraAv1, AmdMA35DAv1 } 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, QuadraPipelineHints } 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> {
@@ -1069,6 +1069,10 @@ export interface VideoEncodeRung {
1069
1069
  * VideoEncode node will attempt to build a pipeline that uses the hardware efficently
1070
1070
  */
1071
1071
  codec: X264Codec | X265Codec | NvidiaH264 | NvidiaHevc | LoganH264 | LoganHevc | QuadraH264 | QuadraHevc | QuadraAv1 | AmdU30H264 | AmdU30Hevc | AmdMA35DH264 | AmdMA35DHevc | AmdMA35DAv1;
1072
+ /**
1073
+ * Extra options for influencing how the ladder gets constructed and what algorithms get used for certain operations
1074
+ */
1075
+ pipelineHints?: QuadraPipelineHints;
1072
1076
  }
1073
1077
  /**
1074
1078
  * @public
@@ -186,7 +186,7 @@ class StreamSwitchSmoothNode extends ProcessorMediaNode {
186
186
  }
187
187
  }
188
188
  const onChange = settings.onInboundContextChange ? settings.onInboundContextChange(ctxMap) : Promise.resolve();
189
- onChange.then(() => {
189
+ void onChange.then(() => {
190
190
  client.subscriptions.write((0, utils_1.provideFull)(media_pb_1.SubscriptionChannelMessage, (0, utils_1.mkMessageCase)({
191
191
  unblock: (0, utils_1.provideFull)(media_pb_1.BlockingCallRef, {
192
192
  mediaNodeId: (0, types_2.toMediaNodeId)(this.id),
@@ -2253,6 +2253,7 @@ class VideoEncodeNode extends AutoProcessorMediaNode {
2253
2253
  ? (0, utils_1.provideFull)(media_pb_1.SampleAspectRatio, stream.sar)
2254
2254
  : undefined,
2255
2255
  codec,
2256
+ hints: stream.pipelineHints ? { case: 'quadra', value: new media_pb_1.QuadraEncodeHints((0, types_2.toEncodeHint)(stream.pipelineHints)) } : { case: undefined }
2256
2257
  });
2257
2258
  return x;
2258
2259
  });
@@ -567,6 +567,22 @@ export type QuadraAv1Level = 1 | 2 | 2.1 | 3 | 3.1 | 4 | 4.1 | 5 | 5.1 | 5.2 | 6
567
567
  export type QuadraH264Level = 1 | 2 | 2.1 | 3 | 3.1 | 4 | 4.1 | 5 | 5.1 | 5.2 | 6 | 6.1 | 6.2;
568
568
  /** @public */
569
569
  export type QuadraHevcLevel = 1 | 2 | 2.1 | 3 | 3.1 | 4 | 4.1 | 5 | 5.1 | 5.2 | 6 | 6.1 | 6.2;
570
+ /**
571
+ * @public
572
+ * The algorithm used for rescales in quadra pipeline, in ffmpeg parlance this is
573
+ * 0 = default
574
+ * 1 = filterblit
575
+ * 2 = bicubic
576
+ */
577
+ export type QuadraRescalerAlgorithm = "default" | "filterblit" | "bicubic";
578
+ /**
579
+ * @public
580
+ * Settings for influencing the encode pipeline built for a quadra rung within a ladder
581
+ */
582
+ export type QuadraPipelineHints = {
583
+ type: 'quadra';
584
+ rescaler?: QuadraRescalerAlgorithm;
585
+ };
570
586
  /**
571
587
  * @public
572
588
  * Settings for a H264 Encode using Netint Quadra hardware
@@ -1441,4 +1457,41 @@ export type SegmentationStrategyExactIdrCount = {
1441
1457
  type: 'exact_idr_count';
1442
1458
  count: number;
1443
1459
  };
1460
+ /**
1461
+ * @public
1462
+ *
1463
+ * Describes a waveform for use by audio signal generator. Constructed from simple sine waves, silence and sequences, loops, combinations
1464
+ * of those. May be finite or infinite in duration, it may often make sense to follow a timed signal with silence.
1465
+ *
1466
+ * See {@link mkDtmf} to construct DTMF tones.
1467
+ */
1468
+ export type Wave = {
1469
+ type: "sine";
1470
+ /** The wave frequency */
1471
+ freq: number;
1472
+ /** Level of the wave. 0 (the default) representing a full-scale sine wave, value must be negative or 0. */
1473
+ db?: number;
1474
+ } | {
1475
+ type: "silence";
1476
+ } | {
1477
+ type: "compound";
1478
+ components: Wave[];
1479
+ } | {
1480
+ type: "sequence";
1481
+ components: Wave[];
1482
+ } | {
1483
+ type: "loop";
1484
+ component: Wave;
1485
+ } | {
1486
+ type: "timed";
1487
+ component: Wave;
1488
+ durationMs: number;
1489
+ };
1490
+ /**
1491
+ * @public
1492
+ *
1493
+ * Construct a waveform representing a string of DTMF digits. This is of finite duration, you may wish to sequence silence afterwards
1494
+ *
1495
+ **/
1496
+ export declare function mkDtmf(digits: string): Wave;
1444
1497
  //# sourceMappingURL=types.d.ts.map
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.toTrinary = exports.toAmdMA35DEncodeCommon = exports.toAmdMA35DH264Profile = exports.toAmdMA35DHevcProfile = exports.toAmdMA35DHevcTier = exports.toAmdMA35DAv1Profile = exports.toAmdMA35DAv1Tier = exports.toAmdU30Hevc = exports.toAmdU30H264 = exports.toAmdU30H264Profile = exports.toAmdU30HevcProfile = exports.toAmdU30HevcTier = exports.toQuadraAv1 = exports.toQuadraHevc = exports.toQuadraH264 = exports.toQuadraH264Profile = exports.toQuadraAv1Profile = exports.toQuadraHevcProfile = exports.toQuadraAv1Tier = exports.toQuadraHevcTier = exports.toLoganHevc = exports.toLoganH264 = exports.toLoganH264Profile = exports.toLoganHevcProfile = exports.toLoganHevcTier = exports.toNvidiaH264 = exports.toNvidiaHevc = exports.toNvidiaH264Profile = exports.toNvidiaHevcProfile = exports.toNvidiaHevcTier = exports.toNvidiaPreset = exports.toCabrMode = exports.toNvidiaRateControl = exports.toNvidiaRateControlMode = exports.toX265Codec = exports.toX265Tune = exports.toX264Codec = exports.toDeinterlaceSettings = exports.fromContext = exports.fromStreamMetadata = exports.metadataForStreamKey = exports.fromStreamKey = exports.mkStreamKey = exports.toMediaNodeId = exports.toOptString = exports.mkOptString = exports.toOptBool = exports.mkOptBool = exports.toOptInt = exports.mkOptInt = void 0;
4
- exports.toSegmentationStrategy = exports.fromScte35PB = exports.toScte35PB = exports.mkWebrtcServerSettings = exports.mkEncryptionSettings = exports.fromSourceSubscriptionError = exports.fromSubscriptionError = exports.fromStreamStatistics = exports.fromAudioMeasureLevels = exports.mkDb = exports.toInterval = exports.fromInterval = exports.addInterval = exports.fromChannelName = exports.toChannelName = exports.getAmountOfChannels = exports.fromChannelLayout = exports.toChannelLayout = exports.fromSampleRate = exports.toSampleRate = exports.toApiMetrics = exports.fromSampleFormat = exports.toSampleFormat = exports.toSsHardwareAcceleration = exports.toComposeHardwareAcceleration = exports.toComposeMissingStreamBehaviour = exports.toPixelFormat = exports.toSimpleEasing = exports.toAacProfile = exports.toImageFormat = exports.toStabilizationMode = exports.toSentenceBuildMode = exports.fromBrowserEvent = exports.toSrtMode = exports.fromSrtInputState = exports.fromRtmpServerInputState = exports.toBitDepth = exports.toAmdMA35DAv1 = exports.toAmdMA35DHevc = exports.toAmdMA35DH264 = void 0;
3
+ exports.toAmdMA35DEncodeCommon = exports.toAmdMA35DH264Profile = exports.toAmdMA35DHevcProfile = exports.toAmdMA35DHevcTier = exports.toAmdMA35DAv1Profile = exports.toAmdMA35DAv1Tier = exports.toAmdU30Hevc = exports.toAmdU30H264 = exports.toAmdU30H264Profile = exports.toAmdU30HevcProfile = exports.toAmdU30HevcTier = exports.toQuadraAv1 = exports.toQuadraHevc = exports.toQuadraH264 = exports.toEncodeHint = exports.toQuadraH264Profile = exports.toQuadraAv1Profile = exports.toQuadraHevcProfile = exports.toQuadraAv1Tier = exports.toQuadraHevcTier = exports.toLoganHevc = exports.toLoganH264 = exports.toLoganH264Profile = exports.toLoganHevcProfile = exports.toLoganHevcTier = exports.toNvidiaH264 = exports.toNvidiaHevc = exports.toNvidiaH264Profile = exports.toNvidiaHevcProfile = exports.toNvidiaHevcTier = exports.toNvidiaPreset = exports.toCabrMode = exports.toNvidiaRateControl = exports.toNvidiaRateControlMode = exports.toX265Codec = exports.toX265Tune = exports.toX264Codec = exports.toDeinterlaceSettings = exports.fromContext = exports.fromStreamMetadata = exports.metadataForStreamKey = exports.fromStreamKey = exports.mkStreamKey = exports.toMediaNodeId = exports.toOptString = exports.mkOptString = exports.toOptBool = exports.mkOptBool = exports.toOptInt = exports.mkOptInt = void 0;
4
+ exports.mkDtmf = exports.toWave = exports.toSegmentationStrategy = exports.fromScte35PB = exports.toScte35PB = exports.mkWebrtcServerSettings = exports.mkEncryptionSettings = exports.fromSourceSubscriptionError = exports.fromSubscriptionError = exports.fromStreamStatistics = exports.fromAudioMeasureLevels = exports.mkDb = exports.toInterval = exports.fromInterval = exports.addInterval = exports.fromChannelName = exports.toChannelName = exports.getAmountOfChannels = exports.fromChannelLayout = exports.toChannelLayout = exports.fromSampleRate = exports.toSampleRate = exports.toApiMetrics = exports.fromSampleFormat = exports.toSampleFormat = exports.toSsHardwareAcceleration = exports.toComposeHardwareAcceleration = exports.toComposeMissingStreamBehaviour = exports.toPixelFormat = exports.toSimpleEasing = exports.toAacProfile = exports.toImageFormat = exports.toStabilizationMode = exports.toSentenceBuildMode = exports.fromBrowserEvent = exports.toSrtMode = exports.fromSrtInputState = exports.fromRtmpServerInputState = exports.toBitDepth = exports.toAmdMA35DAv1 = exports.toAmdMA35DHevc = exports.toAmdMA35DH264 = exports.toTrinary = void 0;
5
5
  const media_pb_1 = require("@norskvideo/norsk-api/lib/media_pb");
6
6
  const common_pb_1 = require("@norskvideo/norsk-api/lib/shared/common_pb");
7
7
  const utils_1 = require("../shared/utils");
@@ -820,6 +820,28 @@ function toQuadraH264Profile(profile) {
820
820
  }
821
821
  exports.toQuadraH264Profile = toQuadraH264Profile;
822
822
  /** @internal */
823
+ function toEncodeHint(hint) {
824
+ const options = {
825
+ rescale: media_pb_1.QuadraEncodeHints_QuadraRescaleAlgorithm.QUADRA_RESCALE_DEFAULT
826
+ };
827
+ const rescale = hint.rescaler;
828
+ switch (rescale) {
829
+ case undefined:
830
+ case 'default':
831
+ break;
832
+ case 'filterblit':
833
+ options.rescale = media_pb_1.QuadraEncodeHints_QuadraRescaleAlgorithm.QUADRA_RESCALE_FILTERBLIT;
834
+ break;
835
+ case 'bicubic':
836
+ options.rescale = media_pb_1.QuadraEncodeHints_QuadraRescaleAlgorithm.QUADRA_RESCALE_BICUBIC;
837
+ break;
838
+ default:
839
+ (0, utils_1.exhaustiveCheck)(rescale);
840
+ }
841
+ return options;
842
+ }
843
+ exports.toEncodeHint = toEncodeHint;
844
+ /** @internal */
823
845
  function toQuadraH264(codec) {
824
846
  const codecOptions = {
825
847
  extraOpts: "",
@@ -2560,4 +2582,109 @@ function toSegmentationStrategy(strategy) {
2560
2582
  }
2561
2583
  }
2562
2584
  exports.toSegmentationStrategy = toSegmentationStrategy;
2585
+ /** @internal */
2586
+ function toWave(wave) {
2587
+ switch (wave.type) {
2588
+ case "sine":
2589
+ return (0, utils_1.provideFull)(media_pb_1.Wave, (0, utils_1.mkMessageCase)({ sine: (0, utils_1.provideFull)(media_pb_1.SineWave, { freq: wave.freq, db: wave.db || 0 }) }));
2590
+ case "silence":
2591
+ return (0, utils_1.provideFull)(media_pb_1.Wave, (0, utils_1.mkMessageCase)({ silence: (0, utils_1.provideFull)(media_pb_1.Silence, {}) }));
2592
+ case "compound":
2593
+ return (0, utils_1.provideFull)(media_pb_1.Wave, (0, utils_1.mkMessageCase)({ compound: (0, utils_1.provideFull)(media_pb_1.Compound, { components: wave.components.map(toWave) }) }));
2594
+ case "sequence":
2595
+ return (0, utils_1.provideFull)(media_pb_1.Wave, (0, utils_1.mkMessageCase)({ sequence: (0, utils_1.provideFull)(media_pb_1.Sequence, { components: wave.components.map(toWave) }) }));
2596
+ case "loop":
2597
+ return (0, utils_1.provideFull)(media_pb_1.Wave, (0, utils_1.mkMessageCase)({ loop: (0, utils_1.provideFull)(media_pb_1.Loop, { component: toWave(wave.component) }) }));
2598
+ case "timed":
2599
+ return (0, utils_1.provideFull)(media_pb_1.Wave, (0, utils_1.mkMessageCase)({ timed: (0, utils_1.provideFull)(media_pb_1.Timed, { component: toWave(wave.component), durationMs: wave.durationMs }) }));
2600
+ }
2601
+ }
2602
+ exports.toWave = toWave;
2603
+ /**
2604
+ * @public
2605
+ *
2606
+ * Construct a waveform representing a string of DTMF digits. This is of finite duration, you may wish to sequence silence afterwards
2607
+ *
2608
+ **/
2609
+ function mkDtmf(digits) {
2610
+ if (!digits) {
2611
+ digits = "";
2612
+ }
2613
+ return {
2614
+ type: "sequence",
2615
+ components: digits.split("").flatMap(mkDtmfDigit)
2616
+ };
2617
+ }
2618
+ exports.mkDtmf = mkDtmf;
2619
+ function mkDtmfDigit(digit) {
2620
+ if (!digit || digit.length !== 1) {
2621
+ throw new Error("Expected single digit");
2622
+ }
2623
+ let pair;
2624
+ switch (digit.toUpperCase()) {
2625
+ case "1":
2626
+ pair = [697.0, 1209.0];
2627
+ break;
2628
+ case "2":
2629
+ pair = [697.0, 1336.0];
2630
+ break;
2631
+ case "3":
2632
+ pair = [697.0, 1477.0];
2633
+ break;
2634
+ case "A":
2635
+ pair = [697.0, 1633.0];
2636
+ break;
2637
+ case "4":
2638
+ pair = [770.0, 1209.0];
2639
+ break;
2640
+ case "5":
2641
+ pair = [770.0, 1336.0];
2642
+ break;
2643
+ case "6":
2644
+ pair = [770.0, 1477.0];
2645
+ break;
2646
+ case "B":
2647
+ pair = [770.0, 1633.0];
2648
+ break;
2649
+ case "7":
2650
+ pair = [852.0, 1209.0];
2651
+ break;
2652
+ case "8":
2653
+ pair = [852.0, 1336.0];
2654
+ break;
2655
+ case "9":
2656
+ pair = [852.0, 1477.0];
2657
+ break;
2658
+ case "C":
2659
+ pair = [852.0, 1633.0];
2660
+ break;
2661
+ case "*":
2662
+ pair = [941.0, 1209.0];
2663
+ break;
2664
+ case "0":
2665
+ pair = [941.0, 1336.0];
2666
+ break;
2667
+ case "#":
2668
+ pair = [941.0, 1477.0];
2669
+ break;
2670
+ case "D":
2671
+ pair = [941.0, 1633.0];
2672
+ break;
2673
+ default:
2674
+ throw new Error("Unexpected digit: " + digit);
2675
+ }
2676
+ return [
2677
+ {
2678
+ type: "timed",
2679
+ durationMs: 250,
2680
+ component: {
2681
+ type: "compound", components: [
2682
+ { type: "sine", freq: pair[0], db: -5.0 },
2683
+ { type: "sine", freq: pair[1], db: -5.0 }
2684
+ ]
2685
+ }
2686
+ },
2687
+ { type: "timed", component: { type: "silence" }, durationMs: 250 }
2688
+ ];
2689
+ }
2563
2690
  //# sourceMappingURL=types.js.map
package/lib/src/sdk.d.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  import { Version, CurrentLoad } from "@norskvideo/norsk-api/lib/shared/common_pb";
2
- import { Wave, AmdMA35DLoad } from "@norskvideo/norsk-api/lib/media_pb";
2
+ import { AmdMA35DLoad } from "@norskvideo/norsk-api/lib/media_pb";
3
3
  import { PinToKey } from "./media_nodes/common";
4
4
  import { NorskInput } from "./media_nodes/input";
5
5
  import { Gain, NorskProcessor, NorskDuplex } from "./media_nodes/processor";
6
6
  import { NorskOutput } from "./media_nodes/output";
7
- import { EncryptionSettings, StreamKey, StreamMetadata, Context } from "./media_nodes/types";
7
+ import { EncryptionSettings, StreamKey, StreamMetadata, Context, Wave } from "./media_nodes/types";
8
8
  import { NorskSystem } from "./system";
9
9
  import { NorskDebug } from "./media_nodes/debug";
10
10
  import { NorskMediaStore } from "./media_nodes/mediaStore";
@@ -183,7 +183,11 @@ export declare function playlistStreamKeys(streams: readonly StreamMetadata[]):
183
183
  export declare function ancillaryStreamKeys(streams: readonly StreamMetadata[]): StreamKey[];
184
184
  /** @public */
185
185
  export declare function newSilentMatrix(rows: number, cols: number): Gain[][];
186
- /** @public */
186
+ /**
187
+ * @public
188
+ *
189
+ * Provided for compatibilty, this is just e.g. `{ type: "sine", freq: 444 }`
190
+ */
187
191
  export declare function mkSine(freq: number): Wave;
188
192
  /**
189
193
  * @public
package/lib/src/sdk.js CHANGED
@@ -30,7 +30,6 @@ exports.streamKeysAreEqual = exports.requireExactAV = exports.requireAV = export
30
30
  const grpc = __importStar(require("@grpc/grpc-js"));
31
31
  const media_grpc_pb_1 = require("@norskvideo/norsk-api/lib/media_grpc_pb");
32
32
  const common_pb_1 = require("@norskvideo/norsk-api/lib/shared/common_pb");
33
- const media_pb_1 = require("@norskvideo/norsk-api/lib/media_pb");
34
33
  const protobuf_1 = require("@bufbuild/protobuf");
35
34
  const utils_1 = require("./shared/utils");
36
35
  const input_1 = require("./media_nodes/input");
@@ -52,10 +51,10 @@ __exportStar(require("./media_nodes/common"), exports);
52
51
  __exportStar(require("./media_nodes/mediaStore"), exports);
53
52
  var common_pb_2 = require("@norskvideo/norsk-api/lib/shared/common_pb");
54
53
  Object.defineProperty(exports, "CurrentLoad", { enumerable: true, get: function () { return common_pb_2.CurrentLoad; } });
54
+ var media_pb_1 = require("@norskvideo/norsk-api/lib/media_pb");
55
+ Object.defineProperty(exports, "AmdMA35DLoad", { enumerable: true, get: function () { return media_pb_1.AmdMA35DLoad; } });
55
56
  var media_pb_2 = require("@norskvideo/norsk-api/lib/media_pb");
56
- Object.defineProperty(exports, "AmdMA35DLoad", { enumerable: true, get: function () { return media_pb_2.AmdMA35DLoad; } });
57
- var media_pb_3 = require("@norskvideo/norsk-api/lib/media_pb");
58
- Object.defineProperty(exports, "AudioCodec", { enumerable: true, get: function () { return media_pb_3.AudioCodec; } });
57
+ Object.defineProperty(exports, "AudioCodec", { enumerable: true, get: function () { return media_pb_2.AudioCodec; } });
59
58
  __exportStar(require("./system"), exports);
60
59
  var common_pb_3 = require("@norskvideo/norsk-api/lib/shared/common_pb");
61
60
  Object.defineProperty(exports, "Version", { enumerable: true, get: function () { return common_pb_3.Version; } });
@@ -73,7 +72,7 @@ class Norsk {
73
72
  registerNode(node) {
74
73
  this.nodes.push(node);
75
74
  if (this.closing) {
76
- node.close();
75
+ void node.close();
77
76
  }
78
77
  return node;
79
78
  }
@@ -485,9 +484,13 @@ function newSilentMatrix(rows, cols) {
485
484
  return new Array(rows).fill(0).map(() => new Array(cols).fill(null));
486
485
  }
487
486
  exports.newSilentMatrix = newSilentMatrix;
488
- /** @public */
487
+ /**
488
+ * @public
489
+ *
490
+ * Provided for compatibilty, this is just e.g. `{ type: "sine", freq: 444 }`
491
+ */
489
492
  function mkSine(freq) {
490
- return new media_pb_1.Wave({ message: { case: "sine", value: new media_pb_1.SineWave({ freq }) } });
493
+ return { type: "sine", freq };
491
494
  }
492
495
  exports.mkSine = mkSine;
493
496
  /**
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "license": "MIT",
3
3
  "name": "@norskvideo/norsk-sdk",
4
- "version": "1.0.391",
4
+ "version": "1.0.392",
5
5
  "dependencies": {
6
6
  "@bufbuild/protobuf": "^0.3.0",
7
7
  "@grpc/grpc-js": "^1.2.2",
8
- "@norskvideo/norsk-api": "1.0.391",
8
+ "@norskvideo/norsk-api": "1.0.392",
9
9
  "lodash": "^4.17.21",
10
10
  "typescript-nullable": "^0.6.0"
11
11
  },
package/src/sdk.ts CHANGED
@@ -6,9 +6,7 @@ import {
6
6
  Log_Level,
7
7
  } from "@norskvideo/norsk-api/lib/shared/common_pb";
8
8
  import {
9
- Wave,
10
9
  NorskStatusEvent,
11
- SineWave,
12
10
  AmdMA35DLoad,
13
11
  SubscriptionChannelResponse
14
12
  } from "@norskvideo/norsk-api/lib/media_pb";
@@ -99,7 +97,7 @@ import {
99
97
  WhipOutputNode,
100
98
  WhipOutputSettings,
101
99
  } from "./media_nodes/output";
102
- import { EncryptionSettings, StreamKey, StreamMetadata, Context } from "./media_nodes/types";
100
+ import { EncryptionSettings, StreamKey, StreamMetadata, Context, Wave } from "./media_nodes/types";
103
101
  import { hardwareInfo, NorskSystem } from "./system";
104
102
  import { NorskDebug, StreamTimestampReportNode, StreamTimestampReportSettings } from "./media_nodes/debug";
105
103
  import {
@@ -268,7 +266,7 @@ export class Norsk {
268
266
  registerNode<N extends MediaNodeState>(node: N): N {
269
267
  this.nodes.push(node);
270
268
  if (this.closing) {
271
- node.close();
269
+ void node.close();
272
270
  }
273
271
  return node;
274
272
  }
@@ -631,7 +629,7 @@ export class Norsk {
631
629
  this.duplex = {
632
630
  webRtcBrowser: async (settings: WebRTCBrowserSettings) =>
633
631
  WebRTCBrowserNode.create(settings, this._client(), unregisterNode).then(registerNode),
634
- sip: async (settings: SipSettings) =>
632
+ sip: async (settings: SipSettings) =>
635
633
  SipNode.create(settings, this._client(), unregisterNode).then(registerNode)
636
634
  };
637
635
  }
@@ -773,9 +771,13 @@ export function newSilentMatrix(rows: number, cols: number): Gain[][] {
773
771
  return new Array(rows).fill(0).map(() => new Array(cols).fill(null));
774
772
  }
775
773
 
776
- /** @public */
777
- export function mkSine(freq: number) {
778
- return new Wave({ message: { case: "sine", value: new SineWave({ freq }) } });
774
+ /**
775
+ * @public
776
+ *
777
+ * Provided for compatibilty, this is just e.g. `{ type: "sine", freq: 444 }`
778
+ */
779
+ export function mkSine(freq: number): Wave {
780
+ return { type: "sine", freq }
779
781
  }
780
782
 
781
783
  /**