@norskvideo/norsk-sdk 1.0.350 → 1.0.351
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/dist/norsk-sdk.d.ts +148 -10
- package/lib/src/media_nodes/common.d.ts +3 -1
- package/lib/src/media_nodes/common.js +36 -20
- package/lib/src/media_nodes/input.d.ts +1 -7
- package/lib/src/media_nodes/input.js +7 -7
- package/lib/src/media_nodes/output.d.ts +37 -1
- package/lib/src/media_nodes/output.js +67 -5
- package/lib/src/media_nodes/processor.d.ts +33 -1
- package/lib/src/media_nodes/processor.js +81 -10
- package/lib/src/media_nodes/types.d.ts +34 -4
- package/lib/src/media_nodes/types.js +34 -4
- package/lib/src/sdk.d.ts +38 -4
- package/lib/src/sdk.js +45 -5
- package/lib/src/shared/utils.js +6 -1
- package/package.json +2 -2
- package/src/sdk.ts +44 -4
package/dist/norsk-sdk.d.ts
CHANGED
|
@@ -102,6 +102,7 @@ export declare class AudioBuildMultichannelNode extends AutoProcessorMediaNode<"
|
|
|
102
102
|
export declare interface AudioBuildMultichannelSettings extends ProcessorNodeSettings<AudioBuildMultichannelNode> {
|
|
103
103
|
/** The channel layout of the built outgoing stream */
|
|
104
104
|
channelLayout: ChannelLayout;
|
|
105
|
+
sampleRate: SampleRate;
|
|
105
106
|
/**
|
|
106
107
|
* Stream keys specifying the source for each channel, where the order is
|
|
107
108
|
* significant. The streams must all have the same sample format and sample
|
|
@@ -452,8 +453,13 @@ export declare interface AudioTranscribeWhisperSettings extends ProcessorNodeSet
|
|
|
452
453
|
noFallback?: boolean;
|
|
453
454
|
numThreads?: number;
|
|
454
455
|
useGpu?: boolean;
|
|
455
|
-
language
|
|
456
|
+
language?: string;
|
|
456
457
|
model: string;
|
|
458
|
+
translate?: boolean;
|
|
459
|
+
tinyDiarize?: boolean;
|
|
460
|
+
initialPrompt?: string;
|
|
461
|
+
suppressNonSpeechTokens?: boolean;
|
|
462
|
+
samplingStrategy?: WhisperSamplingStrategy;
|
|
457
463
|
}
|
|
458
464
|
|
|
459
465
|
export declare interface AutoProcessorMediaNode<Pins extends string> extends SourceMediaNode, AutoSinkMediaNode<Pins> {
|
|
@@ -1348,6 +1354,8 @@ export declare class FileTsOutputNode extends AutoSinkMediaNode<"audio" | "video
|
|
|
1348
1354
|
export declare interface FileTsOutputSettings extends SinkNodeSettings<FileTsOutputNode>, StreamStatisticsMixin {
|
|
1349
1355
|
/** The file to write - this will be truncated if it already exist */
|
|
1350
1356
|
fileName: string;
|
|
1357
|
+
/** 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 */
|
|
1358
|
+
avDelayMs?: number;
|
|
1351
1359
|
}
|
|
1352
1360
|
|
|
1353
1361
|
/**
|
|
@@ -1363,12 +1371,40 @@ export declare interface FrameRate {
|
|
|
1363
1371
|
seconds: number;
|
|
1364
1372
|
}
|
|
1365
1373
|
|
|
1374
|
+
/** @public */
|
|
1366
1375
|
export declare type FrameStoreCut = {
|
|
1367
1376
|
startDateTime: Date;
|
|
1368
1377
|
durationMs: number;
|
|
1369
1378
|
sessionNum?: number;
|
|
1370
1379
|
};
|
|
1371
1380
|
|
|
1381
|
+
/** @public */
|
|
1382
|
+
export declare type FrameStoreCutRequest = {
|
|
1383
|
+
fileFormat: "mp4";
|
|
1384
|
+
id: string;
|
|
1385
|
+
streamSelection: FrameStoreStreamSelection;
|
|
1386
|
+
cuts: FrameStoreCut[];
|
|
1387
|
+
trimPartialSegments: boolean;
|
|
1388
|
+
fileName: string;
|
|
1389
|
+
progressCb: (progress: number) => void;
|
|
1390
|
+
completeCb: (size: bigint) => void;
|
|
1391
|
+
};
|
|
1392
|
+
|
|
1393
|
+
/** @public */
|
|
1394
|
+
export declare type FrameStoreExpireBySize = {
|
|
1395
|
+
expire: "bySize";
|
|
1396
|
+
size: number;
|
|
1397
|
+
};
|
|
1398
|
+
|
|
1399
|
+
/** @public */
|
|
1400
|
+
export declare type FrameStoreExpireByTime = {
|
|
1401
|
+
expire: "byTime";
|
|
1402
|
+
durationS: number;
|
|
1403
|
+
};
|
|
1404
|
+
|
|
1405
|
+
/** @public */
|
|
1406
|
+
export declare type FrameStoreExpiry = FrameStoreExpireBySize | FrameStoreExpireByTime;
|
|
1407
|
+
|
|
1372
1408
|
/**
|
|
1373
1409
|
* @public
|
|
1374
1410
|
* see: {@link NorskInput.frameStorePlayer}
|
|
@@ -1407,6 +1443,7 @@ export declare interface FrameStorePlayerSettings extends InputSettings<FrameSto
|
|
|
1407
1443
|
* see: {@link NorskOutput.frameStoreRecording}
|
|
1408
1444
|
*/
|
|
1409
1445
|
export declare class FrameStoreRecorderNode extends AutoSinkMediaNode<"audio" | "video"> {
|
|
1446
|
+
makeCut(request: FrameStoreCutRequest): void;
|
|
1410
1447
|
}
|
|
1411
1448
|
|
|
1412
1449
|
/**
|
|
@@ -1427,8 +1464,13 @@ export declare interface FrameStoreRecorderSettings extends SinkNodeSettings<Fra
|
|
|
1427
1464
|
* Required: Duration of the frame store chunk files
|
|
1428
1465
|
*/
|
|
1429
1466
|
chunkFileDurationSeconds: number;
|
|
1467
|
+
/**
|
|
1468
|
+
* Optional: Expiry settings - if not supplied, then data will *not* get expired so on long-running events you may exhaust available disk space
|
|
1469
|
+
*/
|
|
1470
|
+
expiry?: FrameStoreExpiry;
|
|
1430
1471
|
}
|
|
1431
1472
|
|
|
1473
|
+
/** @public */
|
|
1432
1474
|
export declare type FrameStoreStreamSelection = "all" | StreamKey[];
|
|
1433
1475
|
|
|
1434
1476
|
export declare function fromVancPayloadFormat(format: VancPayloadFormat_2): VancPayloadFormat;
|
|
@@ -1962,6 +2004,14 @@ export declare interface MediaSegment {
|
|
|
1962
2004
|
number?: number;
|
|
1963
2005
|
}
|
|
1964
2006
|
|
|
2007
|
+
export declare class MetadataCombineMode extends AutoProcessorMediaNode<"ancillary"> {
|
|
2008
|
+
}
|
|
2009
|
+
|
|
2010
|
+
export declare interface MetadataCombineSettings extends ProcessorNodeSettings<MetadataCombineMode> {
|
|
2011
|
+
outputStreamKey: StreamKey;
|
|
2012
|
+
maxSyncDelta?: number;
|
|
2013
|
+
}
|
|
2014
|
+
|
|
1965
2015
|
/**
|
|
1966
2016
|
* @public
|
|
1967
2017
|
* Generate encryption parameters from from an encryption KeyID and Key,
|
|
@@ -2577,7 +2627,15 @@ export declare interface NorskTransform {
|
|
|
2577
2627
|
* hundred milliseconds
|
|
2578
2628
|
*/
|
|
2579
2629
|
streamAlign(settings: StreamAlignSettings): Promise<StreamAlignNode>;
|
|
2630
|
+
/**
|
|
2631
|
+
* Observe, modify or inject ancillary data such as SCTE-35
|
|
2632
|
+
*/
|
|
2580
2633
|
ancillary(settings: AncillarySettings): Promise<AncillaryNode>;
|
|
2634
|
+
/**
|
|
2635
|
+
* Combine compatible streams of metadata (this refers to ancillary streams of metadata messages, such as that
|
|
2636
|
+
* carried in an MPEG-TS PES metadata stream (e.g. KLV), unrelated to operations on the metadata of audio/video/etc streams.
|
|
2637
|
+
*/
|
|
2638
|
+
metadataCombine(settings: MetadataCombineSettings): Promise<MetadataCombineMode>;
|
|
2581
2639
|
}
|
|
2582
2640
|
|
|
2583
2641
|
/** @public */
|
|
@@ -3043,6 +3101,8 @@ export declare interface RtmpOutputSettings extends SinkNodeSettings<RtmpOutputN
|
|
|
3043
3101
|
url: string;
|
|
3044
3102
|
/** Jitter buffer delay in milliseconds */
|
|
3045
3103
|
bufferDelayMs?: number;
|
|
3104
|
+
/** A/V delay in milliseconds (to allow embedded captions to be added) */
|
|
3105
|
+
avDelayMs?: number;
|
|
3046
3106
|
/** Called when the RTMP output succesfully connects to a server and starts publishing data */
|
|
3047
3107
|
onPublishStart?: () => void;
|
|
3048
3108
|
/** Called when the connection to the RTMP server fails */
|
|
@@ -3467,7 +3527,28 @@ export declare type Scte35TimeSignalCommand = {
|
|
|
3467
3527
|
spliceTime: Scte35SpliceTime;
|
|
3468
3528
|
};
|
|
3469
3529
|
|
|
3470
|
-
/**
|
|
3530
|
+
/**
|
|
3531
|
+
* @public
|
|
3532
|
+
* Select all the streams from the input
|
|
3533
|
+
* @param streams - The streams from the inbound Context
|
|
3534
|
+
* @returns Array of selected StreamKeys
|
|
3535
|
+
*/
|
|
3536
|
+
export declare function selectAll(streams: readonly StreamMetadata[]): StreamKey[];
|
|
3537
|
+
|
|
3538
|
+
/**
|
|
3539
|
+
* @public
|
|
3540
|
+
* Select all the ancillary data streams from the input
|
|
3541
|
+
* @param streams - The streams from the inbound Context
|
|
3542
|
+
* @returns Array of selected StreamKeys
|
|
3543
|
+
*/
|
|
3544
|
+
export declare function selectAncillary(streams: readonly StreamMetadata[]): StreamKey[];
|
|
3545
|
+
|
|
3546
|
+
/**
|
|
3547
|
+
* @public
|
|
3548
|
+
* Select all the audio streams from the input
|
|
3549
|
+
* @param streams - The streams from the inbound Context
|
|
3550
|
+
* @returns Array of selected StreamKeys
|
|
3551
|
+
*/
|
|
3471
3552
|
export declare function selectAudio(streams: readonly StreamMetadata[]): StreamKey[];
|
|
3472
3553
|
|
|
3473
3554
|
/**
|
|
@@ -3484,13 +3565,28 @@ export declare function selectExactKey(key: StreamKey): (streams: readonly Strea
|
|
|
3484
3565
|
/** @public */
|
|
3485
3566
|
export declare function selectPlaylist(streams: readonly StreamMetadata[]): StreamKey[];
|
|
3486
3567
|
|
|
3487
|
-
/**
|
|
3568
|
+
/**
|
|
3569
|
+
* @public
|
|
3570
|
+
* Select all the subtitle streams from the input
|
|
3571
|
+
* @param streams - The streams from the inbound Context
|
|
3572
|
+
* @returns Array of selected StreamKeys
|
|
3573
|
+
*/
|
|
3488
3574
|
export declare function selectSubtitles(streams: readonly StreamMetadata[]): StreamKey[];
|
|
3489
3575
|
|
|
3490
|
-
/**
|
|
3576
|
+
/**
|
|
3577
|
+
* @public
|
|
3578
|
+
* Select all the video streams from the input
|
|
3579
|
+
* @param streams - The streams from the inbound Context
|
|
3580
|
+
* @returns Array of selected StreamKeys
|
|
3581
|
+
*/
|
|
3491
3582
|
export declare function selectVideo(streams: readonly StreamMetadata[]): StreamKey[];
|
|
3492
3583
|
|
|
3493
|
-
/**
|
|
3584
|
+
/**
|
|
3585
|
+
* @public
|
|
3586
|
+
* Create a selector selecting all the video streams from the input with the specified rendition name
|
|
3587
|
+
* @param renditionName - The streams from the inbound Context
|
|
3588
|
+
* @returns Array of selected StreamKeys
|
|
3589
|
+
*/
|
|
3494
3590
|
export declare function selectVideoRendition(renditionName: string): (streams: readonly StreamMetadata[]) => StreamKey[];
|
|
3495
3591
|
|
|
3496
3592
|
/** @public */
|
|
@@ -3715,6 +3811,8 @@ export declare interface SrtOutputSettings extends SinkNodeSettings<SrtOutputNod
|
|
|
3715
3811
|
port: number;
|
|
3716
3812
|
/** Jitter buffer delay in milliseconds */
|
|
3717
3813
|
bufferDelayMs?: number;
|
|
3814
|
+
/** 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 */
|
|
3815
|
+
avDelayMs?: number;
|
|
3718
3816
|
/**
|
|
3719
3817
|
* On connect callback, notifying that a new caller has connected (in listener mode) and providing the stream_id that was set on the socket
|
|
3720
3818
|
* @eventProperty
|
|
@@ -3958,6 +4056,17 @@ export declare interface StreamSwitchHardSettings<Pins extends string> extends P
|
|
|
3958
4056
|
outputSource: string;
|
|
3959
4057
|
}
|
|
3960
4058
|
|
|
4059
|
+
/** @public */
|
|
4060
|
+
export declare type StreamSwitchSmoothHardwareAcceleration =
|
|
4061
|
+
/**
|
|
4062
|
+
* Use the quadra overlay functionality to perform the compose
|
|
4063
|
+
*/
|
|
4064
|
+
"quadra"
|
|
4065
|
+
/**
|
|
4066
|
+
* Use an nvidia CUDA kernel to perform the compose
|
|
4067
|
+
*/
|
|
4068
|
+
| "nvidia";
|
|
4069
|
+
|
|
3961
4070
|
/**
|
|
3962
4071
|
* @public
|
|
3963
4072
|
* see: {@link NorskControl.streamSwitchSmooth}
|
|
@@ -4014,6 +4123,10 @@ export declare interface StreamSwitchSmoothSettings<Pins extends string> extends
|
|
|
4014
4123
|
* @param allStreams The collection of input contexts received over all input pins
|
|
4015
4124
|
*/
|
|
4016
4125
|
onInboundContextChange?: (allStreams: Map<Pins, StreamMetadata[]>) => Promise<void>;
|
|
4126
|
+
/**
|
|
4127
|
+
* Optionally attempt to perform the compose operation on hardware
|
|
4128
|
+
*/
|
|
4129
|
+
hardwareAcceleration?: ComposeHardwareAcceleration;
|
|
4017
4130
|
}
|
|
4018
4131
|
|
|
4019
4132
|
/**
|
|
@@ -4108,8 +4221,10 @@ export declare type SubscriptionError = {
|
|
|
4108
4221
|
* - false/deny: Deny the incoming context, if no context has been accepted, then queue data until one is
|
|
4109
4222
|
* - accept_and_terminate: Allow the incoming context, then deny further data, flush and shut down the node
|
|
4110
4223
|
* this is useful for cleanly terminating outputs when the context is empty
|
|
4224
|
+
* - deny_and_queue: Deny the incoming context, and revert to the original queueing behaviour as if no context has been accepted
|
|
4225
|
+
* this is useful when switching from one full context to another, avoiding any "in-between"
|
|
4111
4226
|
* */
|
|
4112
|
-
export declare type SubscriptionValidationResponse = true | false | "accept" | "deny" | "accept_and_terminate";
|
|
4227
|
+
export declare type SubscriptionValidationResponse = true | false | "accept" | "deny" | "accept_and_terminate" | "deny_and_queue";
|
|
4113
4228
|
|
|
4114
4229
|
/** @public */
|
|
4115
4230
|
export declare function subtitlesToPin<Pins extends string>(pin: Pins): (streams: StreamMetadata[]) => PinToKey<Pins>;
|
|
@@ -4203,6 +4318,8 @@ export declare interface UdpTsOutputSettings extends SinkNodeSettings<UdpTsOutpu
|
|
|
4203
4318
|
port: number;
|
|
4204
4319
|
/** Jitter buffer delay in milliseconds */
|
|
4205
4320
|
bufferDelayMs?: number;
|
|
4321
|
+
/** 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 */
|
|
4322
|
+
avDelayMs?: number;
|
|
4206
4323
|
/** Whether to encapsulate in RTP via RFC 2250 (default: false) */
|
|
4207
4324
|
rtpEncapsulate?: boolean;
|
|
4208
4325
|
}
|
|
@@ -4558,6 +4675,14 @@ export declare interface WhipOutputSettings extends SinkNodeSettings<WhipOutputN
|
|
|
4558
4675
|
bufferDelayMs?: number;
|
|
4559
4676
|
}
|
|
4560
4677
|
|
|
4678
|
+
declare type WhisperSamplingStrategy = {
|
|
4679
|
+
strategy: 'greedy';
|
|
4680
|
+
bestOf?: number;
|
|
4681
|
+
} | {
|
|
4682
|
+
strategy: "beam_search";
|
|
4683
|
+
beam_size?: number;
|
|
4684
|
+
};
|
|
4685
|
+
|
|
4561
4686
|
/** @public */
|
|
4562
4687
|
export declare interface X264Codec {
|
|
4563
4688
|
type: "x264";
|
|
@@ -4768,9 +4893,9 @@ export declare type X265Tune = "psnr" | "ssim" | "grain" | "zerolatency" | "fast
|
|
|
4768
4893
|
|
|
4769
4894
|
/**
|
|
4770
4895
|
* @public
|
|
4771
|
-
* Settings for a H264 Encode using
|
|
4896
|
+
* Settings for a H264 Encode using Xilinx hardware
|
|
4772
4897
|
* A detailed description of these params can be found
|
|
4773
|
-
* on the
|
|
4898
|
+
* on the Xilinx Encoder Documentation
|
|
4774
4899
|
*
|
|
4775
4900
|
* These fields have deliberately been written to maintain the same semantics as the
|
|
4776
4901
|
* Xilinx documentation where possible.
|
|
@@ -4781,6 +4906,13 @@ export declare interface XilinxH264 {
|
|
|
4781
4906
|
type: "xilinx-h264";
|
|
4782
4907
|
profile?: XilinxH264Profile;
|
|
4783
4908
|
level?: XilinxH264Level;
|
|
4909
|
+
rateControl?: XilinxRateControl;
|
|
4910
|
+
lookaheadDepth?: number;
|
|
4911
|
+
idrPeriod?: number;
|
|
4912
|
+
bframes?: number;
|
|
4913
|
+
gopSize?: number;
|
|
4914
|
+
minQp?: number;
|
|
4915
|
+
maxQp?: number;
|
|
4784
4916
|
}
|
|
4785
4917
|
|
|
4786
4918
|
/** @public */
|
|
@@ -4791,9 +4923,9 @@ export declare type XilinxH264Profile = "baseline" | "main" | "extended" | "high
|
|
|
4791
4923
|
|
|
4792
4924
|
/**
|
|
4793
4925
|
* @public
|
|
4794
|
-
* Settings for a HEVC Encode using
|
|
4926
|
+
* Settings for a HEVC Encode using Xilinx hardware
|
|
4795
4927
|
* A detailed description of these params can be found
|
|
4796
|
-
* on the
|
|
4928
|
+
* on the Xilinx Encoder Documentation
|
|
4797
4929
|
*
|
|
4798
4930
|
* These fields have deliberately been written to maintain the same semantics as the
|
|
4799
4931
|
* Xilinx documentation where possible.
|
|
@@ -4816,4 +4948,10 @@ export declare type XilinxHevcProfile = "main" | "main10";
|
|
|
4816
4948
|
/** @public */
|
|
4817
4949
|
export declare type XilinxHevcTier = "main" | "high";
|
|
4818
4950
|
|
|
4951
|
+
/** @public */
|
|
4952
|
+
export declare interface XilinxRateControl {
|
|
4953
|
+
value: number;
|
|
4954
|
+
mode: "constQp" | "cbr" | "vbr" | "lowLatency";
|
|
4955
|
+
}
|
|
4956
|
+
|
|
4819
4957
|
export { }
|
|
@@ -94,8 +94,10 @@ export declare class SourceMediaNode extends MediaNodeState {
|
|
|
94
94
|
* - false/deny: Deny the incoming context, if no context has been accepted, then queue data until one is
|
|
95
95
|
* - accept_and_terminate: Allow the incoming context, then deny further data, flush and shut down the node
|
|
96
96
|
* this is useful for cleanly terminating outputs when the context is empty
|
|
97
|
+
* - deny_and_queue: Deny the incoming context, and revert to the original queueing behaviour as if no context has been accepted
|
|
98
|
+
* this is useful when switching from one full context to another, avoiding any "in-between"
|
|
97
99
|
* */
|
|
98
|
-
export declare type SubscriptionValidationResponse = true | false | "accept" | "deny" | "accept_and_terminate";
|
|
100
|
+
export declare type SubscriptionValidationResponse = true | false | "accept" | "deny" | "accept_and_terminate" | "deny_and_queue";
|
|
99
101
|
/** @public */
|
|
100
102
|
export declare class SinkMediaNode<Pins extends string> extends MediaNodeState implements SubscribeDestination {
|
|
101
103
|
permissiveSubscriptionValidation(_context: Context): SubscriptionValidationResponse;
|
|
@@ -114,22 +114,37 @@ class SourceMediaNode extends MediaNodeState {
|
|
|
114
114
|
/** @internal */
|
|
115
115
|
subscriptionComplete(context, subscriber) {
|
|
116
116
|
return () => {
|
|
117
|
-
const pending = this.pendingContextAcks.get(context);
|
|
118
|
-
if (pending === undefined)
|
|
117
|
+
const pending = this.pendingContextAcks.get(context.blockingCallRef);
|
|
118
|
+
if (pending === undefined) {
|
|
119
|
+
// Subscription completed before even adding it!!
|
|
120
|
+
// should never happen now
|
|
121
|
+
(0, utils_1.errorlog)("No pending subscription found for ref %s on %s, something went horribly wrong", context.blockingCallRef, this.id);
|
|
119
122
|
return;
|
|
120
|
-
(0, utils_1.debuglog)("Checking context on %s: %O", this.id, context.blockingCallRef);
|
|
121
|
-
if (pending.length == 1) {
|
|
122
|
-
(0, utils_1.debuglog)("Node '%s' acknowledging context %O", this.id, context.blockingCallRef);
|
|
123
|
-
_ackContext(this.client, this.id, context);
|
|
124
|
-
this.pendingContextAcks.delete(context);
|
|
125
|
-
}
|
|
126
|
-
else {
|
|
127
|
-
let index = pending.indexOf(subscriber); // should error if not null?
|
|
128
|
-
this.pendingContextAcks.set(context, pending.splice(index, 1));
|
|
129
123
|
}
|
|
124
|
+
;
|
|
125
|
+
let index = pending.pendingSubscribes.indexOf(subscriber);
|
|
126
|
+
pending.pendingSubscribes.splice(index, 1);
|
|
127
|
+
this.maybeAckPendingContext(context);
|
|
130
128
|
};
|
|
131
129
|
}
|
|
132
130
|
/** @internal */
|
|
131
|
+
maybeAckPendingContext(context) {
|
|
132
|
+
const pending = this.pendingContextAcks.get(context.blockingCallRef);
|
|
133
|
+
if (!pending) {
|
|
134
|
+
(0, utils_1.errorlog)("No pending subscription found for ref %s on %s, something went horribly wrong", context.blockingCallRef, this.id);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
(0, utils_1.debuglog)("Checking context on %s: %O", this.id, context.blockingCallRef);
|
|
138
|
+
if (pending.pendingSubscribes.length == 0 && pending.readyToAck) {
|
|
139
|
+
(0, utils_1.debuglog)("Node '%s' acknowledging context %O", this.id, context.blockingCallRef);
|
|
140
|
+
_ackContext(this.client, this.id, context);
|
|
141
|
+
this.pendingContextAcks.delete(context.blockingCallRef);
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
(0, utils_1.debuglog)("Node '%s' not acknowledging context yet, pending: %d %O", this.id, pending.pendingSubscribes.length, context.blockingCallRef);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/** @internal */
|
|
133
148
|
outboundContextChange(context) {
|
|
134
149
|
return __awaiter(this, void 0, void 0, function* () {
|
|
135
150
|
(0, utils_1.debuglog)("Node '%s' received new outbound context %O", this.id, debugFormatContext(context));
|
|
@@ -138,23 +153,22 @@ class SourceMediaNode extends MediaNodeState {
|
|
|
138
153
|
if (this.onOutboundContextChange) {
|
|
139
154
|
yield this.onOutboundContextChange(this.outputStreams);
|
|
140
155
|
}
|
|
141
|
-
let pending = [];
|
|
156
|
+
let pending = { pendingSubscribes: [], readyToAck: false };
|
|
157
|
+
this.pendingContextAcks.set(context.blockingCallRef, pending);
|
|
142
158
|
for (let [subscriber, _] of this.subscribers) {
|
|
159
|
+
// Okay, this is async
|
|
160
|
+
// which means that while one is executing, another can complete
|
|
161
|
+
// and that just messes the whole world up beause we haven't stashed it away yet!
|
|
143
162
|
const alive = yield subscriber.sourceContextChange(this.subscriptionComplete(context, subscriber));
|
|
144
163
|
if (alive) {
|
|
145
|
-
pending.push(subscriber);
|
|
164
|
+
pending.pendingSubscribes.push(subscriber);
|
|
146
165
|
}
|
|
147
166
|
else {
|
|
148
167
|
(0, utils_1.debuglog)("Skipping updating subscription to closed node %s", subscriber.id);
|
|
149
168
|
}
|
|
150
169
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
}
|
|
154
|
-
else {
|
|
155
|
-
(0, utils_1.debuglog)("Node '%s' acknowledging context immediately %O", this.id, context.blockingCallRef);
|
|
156
|
-
_ackContext(this.client, this.id, context);
|
|
157
|
-
}
|
|
170
|
+
pending.readyToAck = true;
|
|
171
|
+
this.maybeAckPendingContext(context);
|
|
158
172
|
});
|
|
159
173
|
}
|
|
160
174
|
}
|
|
@@ -365,6 +379,8 @@ class SinkMediaNode extends MediaNodeState {
|
|
|
365
379
|
return media_pb_1.ValidationResponse_ContextValidationResponse.CONTEXT_VALIDATION_DENY;
|
|
366
380
|
case "accept_and_terminate":
|
|
367
381
|
return media_pb_1.ValidationResponse_ContextValidationResponse.CONTEXT_VALIDATION_ALLOW_AND_TERMINATE;
|
|
382
|
+
case "deny_and_queue":
|
|
383
|
+
return media_pb_1.ValidationResponse_ContextValidationResponse.CONTEXT_VALIDATION_DENY_AND_QUEUE;
|
|
368
384
|
default:
|
|
369
385
|
(0, utils_1.exhaustiveCheck)(response);
|
|
370
386
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as grpc from "@grpc/grpc-js";
|
|
2
2
|
import { MediaClient } from "@norskvideo/norsk-api/lib/media_grpc_pb";
|
|
3
3
|
import { TsInputEvent, StreamKey as StreamKeyPB, Wave, FileTsInputMessage, UdpTsInputMessage, TimestampProgramNudge, RtmpError_UnsupportedVideo, RtmpError_UnsupportedAudio } from "@norskvideo/norsk-api/lib/media_pb";
|
|
4
|
-
import { BrowserEvent, ChannelLayout, RtmpServerInputStatus, RtpLinearPcmBitDepth, SampleFormat, SampleRate, SrtMode, SrtInputStatus, ImageFormat, IceServerSettings,
|
|
4
|
+
import { BrowserEvent, ChannelLayout, RtmpServerInputStatus, RtpLinearPcmBitDepth, SampleFormat, SampleRate, SrtMode, SrtInputStatus, ImageFormat, IceServerSettings, FrameStoreStreamSelection, FrameStoreCut } from "./types";
|
|
5
5
|
import { FrameRate } from "../types";
|
|
6
6
|
import { DeckLinkPixelFormat, DeckLinkVideoConnection, DeckLinkDisplayModeId } from "../types";
|
|
7
7
|
import { MediaNodeState, SourceMediaNode, SourceNodeSettings, StreamStatisticsMixin } from "./common";
|
|
@@ -602,12 +602,6 @@ export declare class FileMp4InputNode extends SourceMediaNode {
|
|
|
602
602
|
nudge(nudge: number): void;
|
|
603
603
|
updateSettings(settings: FileMp4InputSettingsUpdate): void;
|
|
604
604
|
}
|
|
605
|
-
export declare type FrameStoreStreamSelection = "all" | StreamKey[];
|
|
606
|
-
export declare type FrameStoreCut = {
|
|
607
|
-
startDateTime: Date;
|
|
608
|
-
durationMs: number;
|
|
609
|
-
sessionNum?: number;
|
|
610
|
-
};
|
|
611
605
|
/**
|
|
612
606
|
* @public
|
|
613
607
|
* Settings for Frame Store playback
|
|
@@ -1246,13 +1246,13 @@ class FrameStorePlayerNode extends common_1.SourceMediaNode {
|
|
|
1246
1246
|
durationMs,
|
|
1247
1247
|
sessionNum: sessionNum ? (0, utils_1.provideFull)(common_pb_1.OptionalInt, { value: sessionNum }) : undefined
|
|
1248
1248
|
})),
|
|
1249
|
-
streamSelection: (settings.streamSelection == "all") ?
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1249
|
+
streamSelection: (0, utils_1.provideFull)(media_pb_1.StreamSelection, { streamSelection: (settings.streamSelection == "all") ?
|
|
1250
|
+
(0, utils_1.mkCase)({ all: (0, utils_1.provideFull)(media_pb_1.StreamSelection_All, {}) }) :
|
|
1251
|
+
(0, utils_1.mkCase)({
|
|
1252
|
+
subset: (0, utils_1.provideFull)(media_pb_1.StreamSelection_Subset, {
|
|
1253
|
+
streamList: settings.streamSelection.map(types_1.mkStreamKey)
|
|
1254
|
+
})
|
|
1255
|
+
}) }),
|
|
1256
1256
|
trimPartialSegments: settings.trimPartialSegments
|
|
1257
1257
|
});
|
|
1258
1258
|
this.grpcStream = client.createInputFrameStorePlayer();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as grpc from "@grpc/grpc-js";
|
|
2
2
|
import { MediaClient } from "@norskvideo/norsk-api/lib/media_grpc_pb";
|
|
3
3
|
import { CmafAudioMessage, CmafMultiVariantMessage, CmafVideoMessage, CmafWebVttMessage, HlsOutputEvent, HlsTsAudioMessage, HlsTsCombinedPushMessage, HlsTsVideoMessage, Subscription, HlsTsMultiVariantMessage } from "@norskvideo/norsk-api/lib/media_pb";
|
|
4
|
-
import { AwsCredentials, EncryptionSettings, IceServerSettings, SrtMode, StreamMetadata, Scte35SpliceInfoSection } from "./types";
|
|
4
|
+
import { AwsCredentials, EncryptionSettings, IceServerSettings, SrtMode, StreamMetadata, Scte35SpliceInfoSection, FrameStoreStreamSelection, FrameStoreCut } from "./types";
|
|
5
5
|
import { AutoProcessorMediaNode, ProcessorNodeSettings } from "./processor";
|
|
6
6
|
import { AutoSinkMediaNode, MediaNodeState, SinkNodeSettings, StreamStatisticsMixin } from "./common";
|
|
7
7
|
/**
|
|
@@ -616,6 +616,8 @@ export interface UdpTsOutputSettings extends SinkNodeSettings<UdpTsOutputNode>,
|
|
|
616
616
|
port: number;
|
|
617
617
|
/** Jitter buffer delay in milliseconds */
|
|
618
618
|
bufferDelayMs?: number;
|
|
619
|
+
/** 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 */
|
|
620
|
+
avDelayMs?: number;
|
|
619
621
|
/** Whether to encapsulate in RTP via RFC 2250 (default: false) */
|
|
620
622
|
rtpEncapsulate?: boolean;
|
|
621
623
|
}
|
|
@@ -653,6 +655,8 @@ export interface SrtOutputSettings extends SinkNodeSettings<SrtOutputNode>, Stre
|
|
|
653
655
|
port: number;
|
|
654
656
|
/** Jitter buffer delay in milliseconds */
|
|
655
657
|
bufferDelayMs?: number;
|
|
658
|
+
/** 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 */
|
|
659
|
+
avDelayMs?: number;
|
|
656
660
|
/**
|
|
657
661
|
* On connect callback, notifying that a new caller has connected (in listener mode) and providing the stream_id that was set on the socket
|
|
658
662
|
* @eventProperty
|
|
@@ -731,6 +735,8 @@ export interface RtmpOutputSettings extends SinkNodeSettings<RtmpOutputNode>, St
|
|
|
731
735
|
url: string;
|
|
732
736
|
/** Jitter buffer delay in milliseconds */
|
|
733
737
|
bufferDelayMs?: number;
|
|
738
|
+
/** A/V delay in milliseconds (to allow embedded captions to be added) */
|
|
739
|
+
avDelayMs?: number;
|
|
734
740
|
/** Called when the RTMP output succesfully connects to a server and starts publishing data */
|
|
735
741
|
onPublishStart?: () => void;
|
|
736
742
|
/** Called when the connection to the RTMP server fails */
|
|
@@ -758,6 +764,8 @@ export declare class RtmpOutputNode extends AutoSinkMediaNode<"audio" | "video">
|
|
|
758
764
|
export interface FileTsOutputSettings extends SinkNodeSettings<FileTsOutputNode>, StreamStatisticsMixin {
|
|
759
765
|
/** The file to write - this will be truncated if it already exist */
|
|
760
766
|
fileName: string;
|
|
767
|
+
/** 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 */
|
|
768
|
+
avDelayMs?: number;
|
|
761
769
|
}
|
|
762
770
|
/**
|
|
763
771
|
* @public
|
|
@@ -806,6 +814,29 @@ export declare class FileMp4OutputNode extends AutoSinkMediaNode<"audio" | "vide
|
|
|
806
814
|
*/
|
|
807
815
|
writeFile(nonfragmentedFileName: string): void;
|
|
808
816
|
}
|
|
817
|
+
/** @public */
|
|
818
|
+
export declare type FrameStoreExpireByTime = {
|
|
819
|
+
expire: "byTime";
|
|
820
|
+
durationS: number;
|
|
821
|
+
};
|
|
822
|
+
/** @public */
|
|
823
|
+
export declare type FrameStoreExpireBySize = {
|
|
824
|
+
expire: "bySize";
|
|
825
|
+
size: number;
|
|
826
|
+
};
|
|
827
|
+
/** @public */
|
|
828
|
+
export declare type FrameStoreExpiry = FrameStoreExpireBySize | FrameStoreExpireByTime;
|
|
829
|
+
/** @public */
|
|
830
|
+
export declare type FrameStoreCutRequest = {
|
|
831
|
+
fileFormat: "mp4";
|
|
832
|
+
id: string;
|
|
833
|
+
streamSelection: FrameStoreStreamSelection;
|
|
834
|
+
cuts: FrameStoreCut[];
|
|
835
|
+
trimPartialSegments: boolean;
|
|
836
|
+
fileName: string;
|
|
837
|
+
progressCb: (progress: number) => void;
|
|
838
|
+
completeCb: (size: bigint) => void;
|
|
839
|
+
};
|
|
809
840
|
/**
|
|
810
841
|
* @public
|
|
811
842
|
* Settings to configure a frame store recorder
|
|
@@ -824,12 +855,17 @@ export interface FrameStoreRecorderSettings extends SinkNodeSettings<FrameStoreR
|
|
|
824
855
|
* Required: Duration of the frame store chunk files
|
|
825
856
|
*/
|
|
826
857
|
chunkFileDurationSeconds: number;
|
|
858
|
+
/**
|
|
859
|
+
* Optional: Expiry settings - if not supplied, then data will *not* get expired so on long-running events you may exhaust available disk space
|
|
860
|
+
*/
|
|
861
|
+
expiry?: FrameStoreExpiry;
|
|
827
862
|
}
|
|
828
863
|
/**
|
|
829
864
|
* @public
|
|
830
865
|
* see: {@link NorskOutput.frameStoreRecording}
|
|
831
866
|
*/
|
|
832
867
|
export declare class FrameStoreRecorderNode extends AutoSinkMediaNode<"audio" | "video"> {
|
|
868
|
+
makeCut(request: FrameStoreCutRequest): void;
|
|
833
869
|
}
|
|
834
870
|
/**
|
|
835
871
|
* @public
|