livekit-client 2.17.3 → 2.18.1
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/livekit-client.e2ee.worker.js +1 -1
- package/dist/livekit-client.e2ee.worker.js.map +1 -1
- package/dist/livekit-client.e2ee.worker.mjs +8 -7
- package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
- package/dist/livekit-client.esm.mjs +7823 -5772
- package/dist/livekit-client.esm.mjs.map +1 -1
- package/dist/livekit-client.umd.js +1 -1
- package/dist/livekit-client.umd.js.map +1 -1
- package/dist/src/api/SignalClient.d.ts +12 -4
- package/dist/src/api/SignalClient.d.ts.map +1 -1
- package/dist/src/e2ee/constants.d.ts.map +1 -1
- package/dist/src/e2ee/types.d.ts +6 -0
- package/dist/src/e2ee/types.d.ts.map +1 -1
- package/dist/src/e2ee/utils.d.ts +2 -1
- package/dist/src/e2ee/utils.d.ts.map +1 -1
- package/dist/src/e2ee/worker/DataCryptor.d.ts.map +1 -1
- package/dist/src/e2ee/worker/FrameCryptor.d.ts.map +1 -1
- package/dist/src/index.d.ts +5 -4
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/room/PCTransport.d.ts +5 -0
- package/dist/src/room/PCTransport.d.ts.map +1 -1
- package/dist/src/room/PCTransportManager.d.ts +1 -1
- package/dist/src/room/PCTransportManager.d.ts.map +1 -1
- package/dist/src/room/RTCEngine.d.ts +27 -9
- package/dist/src/room/RTCEngine.d.ts.map +1 -1
- package/dist/src/room/Room.d.ts +13 -3
- package/dist/src/room/Room.d.ts.map +1 -1
- package/dist/src/room/data-stream/outgoing/OutgoingDataStreamManager.d.ts.map +1 -1
- package/dist/src/room/data-track/LocalDataTrack.d.ts +48 -0
- package/dist/src/room/data-track/LocalDataTrack.d.ts.map +1 -0
- package/dist/src/room/data-track/RemoteDataTrack.d.ts +46 -0
- package/dist/src/room/data-track/RemoteDataTrack.d.ts.map +1 -0
- package/dist/src/room/data-track/depacketizer.d.ts +6 -6
- package/dist/src/room/data-track/depacketizer.d.ts.map +1 -1
- package/dist/src/room/data-track/frame.d.ts +14 -0
- package/dist/src/room/data-track/frame.d.ts.map +1 -1
- package/dist/src/room/data-track/handle.d.ts +2 -2
- package/dist/src/room/data-track/handle.d.ts.map +1 -1
- package/dist/src/room/data-track/incoming/IncomingDataTrackManager.d.ts +104 -0
- package/dist/src/room/data-track/incoming/IncomingDataTrackManager.d.ts.map +1 -0
- package/dist/src/room/data-track/incoming/errors.d.ts +24 -0
- package/dist/src/room/data-track/incoming/errors.d.ts.map +1 -0
- package/dist/src/room/data-track/incoming/pipeline.d.ts +38 -0
- package/dist/src/room/data-track/incoming/pipeline.d.ts.map +1 -0
- package/dist/src/room/data-track/incoming/types.d.ts +20 -0
- package/dist/src/room/data-track/incoming/types.d.ts.map +1 -0
- package/dist/src/room/data-track/outgoing/OutgoingDataTrackManager.d.ts +63 -28
- package/dist/src/room/data-track/outgoing/OutgoingDataTrackManager.d.ts.map +1 -1
- package/dist/src/room/data-track/outgoing/errors.d.ts +20 -10
- package/dist/src/room/data-track/outgoing/errors.d.ts.map +1 -1
- package/dist/src/room/data-track/outgoing/pipeline.d.ts +9 -8
- package/dist/src/room/data-track/outgoing/pipeline.d.ts.map +1 -1
- package/dist/src/room/data-track/outgoing/types.d.ts +16 -7
- package/dist/src/room/data-track/outgoing/types.d.ts.map +1 -1
- package/dist/src/room/data-track/packet/errors.d.ts +2 -4
- package/dist/src/room/data-track/packet/errors.d.ts.map +1 -1
- package/dist/src/room/data-track/packet/extensions.d.ts +4 -4
- package/dist/src/room/data-track/packet/extensions.d.ts.map +1 -1
- package/dist/src/room/data-track/packet/index.d.ts +5 -5
- package/dist/src/room/data-track/packet/index.d.ts.map +1 -1
- package/dist/src/room/data-track/packet/serializable.d.ts +4 -4
- package/dist/src/room/data-track/packet/serializable.d.ts.map +1 -1
- package/dist/src/room/data-track/packetizer.d.ts +6 -6
- package/dist/src/room/data-track/packetizer.d.ts.map +1 -1
- package/dist/src/room/data-track/track-interfaces.d.ts +23 -0
- package/dist/src/room/data-track/track-interfaces.d.ts.map +1 -0
- package/dist/src/room/data-track/types.d.ts +15 -0
- package/dist/src/room/data-track/types.d.ts.map +1 -0
- package/dist/src/room/events.d.ts +24 -3
- package/dist/src/room/events.d.ts.map +1 -1
- package/dist/src/room/participant/LocalParticipant.d.ts +11 -1
- package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
- package/dist/src/room/participant/RemoteParticipant.d.ts +14 -1
- package/dist/src/room/participant/RemoteParticipant.d.ts.map +1 -1
- package/dist/src/room/token-source/TokenSource.d.ts +1 -1
- package/dist/src/room/token-source/TokenSource.d.ts.map +1 -1
- package/dist/src/room/token-source/types.d.ts +1 -0
- package/dist/src/room/token-source/types.d.ts.map +1 -1
- package/dist/src/room/utils.d.ts +2 -1
- package/dist/src/room/utils.d.ts.map +1 -1
- package/dist/src/utils/abort-signal-polyfill.d.ts +13 -0
- package/dist/src/utils/abort-signal-polyfill.d.ts.map +1 -0
- package/dist/src/utils/deferrable-map.d.ts +32 -0
- package/dist/src/utils/deferrable-map.d.ts.map +1 -0
- package/dist/src/utils/subscribeToEvents.d.ts +3 -0
- package/dist/src/utils/subscribeToEvents.d.ts.map +1 -1
- package/dist/ts4.2/api/SignalClient.d.ts +12 -4
- package/dist/ts4.2/e2ee/types.d.ts +6 -0
- package/dist/ts4.2/e2ee/utils.d.ts +2 -1
- package/dist/ts4.2/index.d.ts +5 -4
- package/dist/ts4.2/room/PCTransport.d.ts +5 -0
- package/dist/ts4.2/room/PCTransportManager.d.ts +1 -1
- package/dist/ts4.2/room/RTCEngine.d.ts +27 -9
- package/dist/ts4.2/room/Room.d.ts +13 -3
- package/dist/ts4.2/room/data-track/LocalDataTrack.d.ts +48 -0
- package/dist/ts4.2/room/data-track/RemoteDataTrack.d.ts +46 -0
- package/dist/ts4.2/room/data-track/depacketizer.d.ts +6 -6
- package/dist/ts4.2/room/data-track/frame.d.ts +14 -0
- package/dist/ts4.2/room/data-track/handle.d.ts +2 -2
- package/dist/ts4.2/room/data-track/incoming/IncomingDataTrackManager.d.ts +110 -0
- package/dist/ts4.2/room/data-track/incoming/errors.d.ts +24 -0
- package/dist/ts4.2/room/data-track/incoming/pipeline.d.ts +38 -0
- package/dist/ts4.2/room/data-track/incoming/types.d.ts +20 -0
- package/dist/ts4.2/room/data-track/outgoing/OutgoingDataTrackManager.d.ts +63 -29
- package/dist/ts4.2/room/data-track/outgoing/errors.d.ts +20 -10
- package/dist/ts4.2/room/data-track/outgoing/pipeline.d.ts +9 -8
- package/dist/ts4.2/room/data-track/outgoing/types.d.ts +16 -7
- package/dist/ts4.2/room/data-track/packet/errors.d.ts +2 -4
- package/dist/ts4.2/room/data-track/packet/extensions.d.ts +4 -4
- package/dist/ts4.2/room/data-track/packet/index.d.ts +5 -6
- package/dist/ts4.2/room/data-track/packet/serializable.d.ts +4 -4
- package/dist/ts4.2/room/data-track/packetizer.d.ts +6 -6
- package/dist/ts4.2/room/data-track/track-interfaces.d.ts +23 -0
- package/dist/ts4.2/room/data-track/types.d.ts +15 -0
- package/dist/ts4.2/room/events.d.ts +24 -3
- package/dist/ts4.2/room/participant/LocalParticipant.d.ts +11 -1
- package/dist/ts4.2/room/participant/RemoteParticipant.d.ts +14 -1
- package/dist/ts4.2/room/token-source/TokenSource.d.ts +1 -1
- package/dist/ts4.2/room/token-source/types.d.ts +1 -0
- package/dist/ts4.2/room/utils.d.ts +2 -1
- package/dist/ts4.2/utils/abort-signal-polyfill.d.ts +13 -0
- package/dist/ts4.2/utils/deferrable-map.d.ts +32 -0
- package/dist/ts4.2/utils/subscribeToEvents.d.ts +3 -0
- package/package.json +4 -2
- package/src/api/SignalClient.test.ts +9 -4
- package/src/api/SignalClient.ts +116 -9
- package/src/e2ee/constants.ts +1 -0
- package/src/e2ee/types.ts +6 -0
- package/src/e2ee/utils.ts +4 -3
- package/src/e2ee/worker/DataCryptor.ts +1 -4
- package/src/e2ee/worker/FrameCryptor.ts +1 -4
- package/src/e2ee/worker/ParticipantKeyHandler.ts +1 -1
- package/src/index.ts +6 -4
- package/src/room/PCTransport.ts +41 -1
- package/src/room/PCTransportManager.ts +1 -1
- package/src/room/RTCEngine.ts +274 -112
- package/src/room/Room.ts +152 -15
- package/src/room/data-stream/outgoing/OutgoingDataStreamManager.ts +9 -9
- package/src/room/data-track/LocalDataTrack.ts +126 -0
- package/src/room/data-track/RemoteDataTrack.ts +80 -0
- package/src/room/data-track/depacketizer.ts +23 -26
- package/src/room/data-track/frame.ts +28 -2
- package/src/room/data-track/handle.ts +2 -8
- package/src/room/data-track/incoming/IncomingDataTrackManager.test.ts +555 -0
- package/src/room/data-track/incoming/IncomingDataTrackManager.ts +589 -0
- package/src/room/data-track/incoming/errors.ts +57 -0
- package/src/room/data-track/incoming/pipeline.ts +121 -0
- package/src/room/data-track/incoming/types.ts +22 -0
- package/src/room/data-track/outgoing/OutgoingDataTrackManager.test.ts +240 -27
- package/src/room/data-track/outgoing/OutgoingDataTrackManager.ts +165 -84
- package/src/room/data-track/outgoing/errors.ts +40 -11
- package/src/room/data-track/outgoing/pipeline.ts +25 -23
- package/src/room/data-track/outgoing/types.ts +14 -6
- package/src/room/data-track/packet/errors.ts +2 -14
- package/src/room/data-track/packet/extensions.ts +21 -26
- package/src/room/data-track/packet/index.test.ts +22 -33
- package/src/room/data-track/packet/index.ts +4 -6
- package/src/room/data-track/packet/serializable.ts +4 -4
- package/src/room/data-track/packetizer.test.ts +2 -2
- package/src/room/data-track/packetizer.ts +7 -10
- package/src/room/data-track/track-interfaces.ts +53 -0
- package/src/room/data-track/types.ts +31 -0
- package/src/room/events.ts +26 -1
- package/src/room/participant/LocalParticipant.ts +57 -6
- package/src/room/participant/RemoteParticipant.ts +26 -1
- package/src/room/token-source/TokenSource.ts +8 -2
- package/src/room/token-source/types.ts +4 -0
- package/src/room/utils.ts +5 -1
- package/src/utils/abort-signal-polyfill.ts +63 -0
- package/src/utils/deferrable-map.ts +109 -0
- package/src/utils/subscribeToEvents.ts +18 -1
- package/dist/src/room/data-track/e2ee.d.ts +0 -12
- package/dist/src/room/data-track/e2ee.d.ts.map +0 -1
- package/dist/src/room/data-track/track.d.ts +0 -30
- package/dist/src/room/data-track/track.d.ts.map +0 -1
- package/dist/src/utils/throws.d.ts +0 -36
- package/dist/src/utils/throws.d.ts.map +0 -1
- package/dist/ts4.2/room/data-track/e2ee.d.ts +0 -12
- package/dist/ts4.2/room/data-track/track.d.ts +0 -30
- package/dist/ts4.2/utils/throws.d.ts +0 -39
- package/src/room/data-track/e2ee.ts +0 -14
- package/src/room/data-track/track.ts +0 -50
- package/src/utils/throws.ts +0 -42
|
@@ -1,25 +1,27 @@
|
|
|
1
1
|
import { EventEmitter } from 'events';
|
|
2
|
+
import type { Throws } from '@livekit/throws-transformer/throws';
|
|
2
3
|
import type TypedEmitter from 'typed-emitter';
|
|
4
|
+
import type { BaseE2EEManager } from '../../../e2ee/E2eeManager';
|
|
3
5
|
import { LoggerNames, getLogger } from '../../../logger';
|
|
4
|
-
import
|
|
6
|
+
import { abortSignalAny, abortSignalTimeout } from '../../../utils/abort-signal-polyfill';
|
|
5
7
|
import { Future } from '../../utils';
|
|
6
|
-
import
|
|
7
|
-
import type {
|
|
8
|
+
import LocalDataTrack from '../LocalDataTrack';
|
|
9
|
+
import type { DataTrackFrameInternal } from '../frame';
|
|
8
10
|
import { DataTrackHandle, DataTrackHandleAllocator } from '../handle';
|
|
9
|
-
import {
|
|
10
|
-
import { type DataTrackInfo, LocalDataTrack } from '../track';
|
|
11
|
+
import { type DataTrackInfo } from '../types';
|
|
11
12
|
import {
|
|
12
13
|
DataTrackPublishError,
|
|
13
|
-
DataTrackPublishErrorReason,
|
|
14
14
|
DataTrackPushFrameError,
|
|
15
15
|
DataTrackPushFrameErrorReason,
|
|
16
16
|
} from './errors';
|
|
17
17
|
import DataTrackOutgoingPipeline from './pipeline';
|
|
18
18
|
import {
|
|
19
19
|
type DataTrackOptions,
|
|
20
|
-
type
|
|
21
|
-
type
|
|
22
|
-
type
|
|
20
|
+
type EventPacketAvailable,
|
|
21
|
+
type EventSfuPublishRequest,
|
|
22
|
+
type EventSfuUnpublishRequest,
|
|
23
|
+
type EventTrackPublished,
|
|
24
|
+
type EventTrackUnpublished,
|
|
23
25
|
type SfuPublishResponseResult,
|
|
24
26
|
} from './types';
|
|
25
27
|
|
|
@@ -27,20 +29,15 @@ const log = getLogger(LoggerNames.DataTracks);
|
|
|
27
29
|
|
|
28
30
|
export type PendingDescriptor = {
|
|
29
31
|
type: 'pending';
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
| DataTrackPublishError<DataTrackPublishErrorReason.NotAllowed>
|
|
33
|
-
| DataTrackPublishError<DataTrackPublishErrorReason.DuplicateName>
|
|
34
|
-
| DataTrackPublishError<DataTrackPublishErrorReason.Timeout>
|
|
35
|
-
| DataTrackPublishError<DataTrackPublishErrorReason.LimitReached>
|
|
36
|
-
| DataTrackPublishError<DataTrackPublishErrorReason.Disconnected>
|
|
37
|
-
| DataTrackPublishError<DataTrackPublishErrorReason.Cancelled>
|
|
38
|
-
>;
|
|
32
|
+
/** Resolves when the descriptor is fully published. */
|
|
33
|
+
completionFuture: Future<void, DataTrackPublishError>;
|
|
39
34
|
};
|
|
40
35
|
export type ActiveDescriptor = {
|
|
41
36
|
type: 'active';
|
|
42
37
|
info: DataTrackInfo;
|
|
43
38
|
|
|
39
|
+
publishState: 'published' | 'republishing' | 'unpublished';
|
|
40
|
+
|
|
44
41
|
pipeline: DataTrackOutgoingPipeline;
|
|
45
42
|
|
|
46
43
|
/** Resolves when the descriptor is unpublished. */
|
|
@@ -55,11 +52,12 @@ export const Descriptor = {
|
|
|
55
52
|
completionFuture: new Future(),
|
|
56
53
|
};
|
|
57
54
|
},
|
|
58
|
-
active(info: DataTrackInfo,
|
|
55
|
+
active(info: DataTrackInfo, e2eeManager: BaseE2EEManager | null): ActiveDescriptor {
|
|
59
56
|
return {
|
|
60
57
|
type: 'active',
|
|
61
58
|
info,
|
|
62
|
-
|
|
59
|
+
publishState: 'published',
|
|
60
|
+
pipeline: new DataTrackOutgoingPipeline({ info, e2eeManager }),
|
|
63
61
|
unpublishingFuture: new Future(),
|
|
64
62
|
};
|
|
65
63
|
},
|
|
@@ -67,35 +65,39 @@ export const Descriptor = {
|
|
|
67
65
|
|
|
68
66
|
export type DataTrackOutgoingManagerCallbacks = {
|
|
69
67
|
/** Request sent to the SFU to publish a track. */
|
|
70
|
-
sfuPublishRequest: (event:
|
|
68
|
+
sfuPublishRequest: (event: EventSfuPublishRequest) => void;
|
|
71
69
|
/** Request sent to the SFU to unpublish a track. */
|
|
72
|
-
sfuUnpublishRequest: (event:
|
|
73
|
-
/**
|
|
74
|
-
|
|
70
|
+
sfuUnpublishRequest: (event: EventSfuUnpublishRequest) => void;
|
|
71
|
+
/** A serialized packet is ready to be sent over the transport. */
|
|
72
|
+
packetAvailable: (event: EventPacketAvailable) => void;
|
|
73
|
+
/** A new {@link LocalDataTrack} has been published */
|
|
74
|
+
trackPublished: (event: EventTrackPublished) => void;
|
|
75
|
+
/** A {@link LocalDataTrack} has been unpublished */
|
|
76
|
+
trackUnpublished: (event: EventTrackUnpublished) => void;
|
|
75
77
|
};
|
|
76
78
|
|
|
77
|
-
type
|
|
79
|
+
type OutgoingDataTrackManagerOptions = {
|
|
78
80
|
/**
|
|
79
81
|
* Provider to use for encrypting outgoing frame payloads.
|
|
80
82
|
*
|
|
81
|
-
* If
|
|
83
|
+
* If null, end-to-end encryption will be disabled for all published tracks.
|
|
82
84
|
*/
|
|
83
|
-
|
|
85
|
+
e2eeManager?: BaseE2EEManager;
|
|
84
86
|
};
|
|
85
87
|
|
|
86
88
|
/** How long to wait when attempting to publish before timing out. */
|
|
87
89
|
const PUBLISH_TIMEOUT_MILLISECONDS = 10_000;
|
|
88
90
|
|
|
89
91
|
export default class OutgoingDataTrackManager extends (EventEmitter as new () => TypedEmitter<DataTrackOutgoingManagerCallbacks>) {
|
|
90
|
-
private
|
|
92
|
+
private e2eeManager: BaseE2EEManager | null;
|
|
91
93
|
|
|
92
94
|
private handleAllocator = new DataTrackHandleAllocator();
|
|
93
95
|
|
|
94
96
|
private descriptors = new Map<DataTrackHandle, Descriptor>();
|
|
95
97
|
|
|
96
|
-
constructor(options?:
|
|
98
|
+
constructor(options?: OutgoingDataTrackManagerOptions) {
|
|
97
99
|
super();
|
|
98
|
-
this.
|
|
100
|
+
this.e2eeManager = options?.e2eeManager ?? null;
|
|
99
101
|
}
|
|
100
102
|
|
|
101
103
|
static withDescriptors(descriptors: Map<DataTrackHandle, Descriptor>) {
|
|
@@ -104,6 +106,18 @@ export default class OutgoingDataTrackManager extends (EventEmitter as new () =>
|
|
|
104
106
|
return manager;
|
|
105
107
|
}
|
|
106
108
|
|
|
109
|
+
/** @internal */
|
|
110
|
+
updateE2eeManager(e2eeManager: BaseE2EEManager | null) {
|
|
111
|
+
this.e2eeManager = e2eeManager;
|
|
112
|
+
|
|
113
|
+
// Propegate downwards to all pre-existing pipelines
|
|
114
|
+
for (const descriptor of this.descriptors.values()) {
|
|
115
|
+
if (descriptor.type === 'active') {
|
|
116
|
+
descriptor.pipeline.updateE2eeManager(e2eeManager);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
107
121
|
/**
|
|
108
122
|
* Used by attached {@link LocalDataTrack} instances to query their associated descriptor info.
|
|
109
123
|
* @internal
|
|
@@ -112,39 +126,35 @@ export default class OutgoingDataTrackManager extends (EventEmitter as new () =>
|
|
|
112
126
|
return this.descriptors.get(handle) ?? null;
|
|
113
127
|
}
|
|
114
128
|
|
|
115
|
-
createLocalDataTrack(handle: DataTrackHandle) {
|
|
116
|
-
const descriptor = this.getDescriptor(handle);
|
|
117
|
-
if (descriptor?.type !== 'active') {
|
|
118
|
-
return null;
|
|
119
|
-
}
|
|
120
|
-
return new LocalDataTrack(descriptor.info, this);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
129
|
/** Used by attached {@link LocalDataTrack} instances to broadcast data track packets to other
|
|
124
130
|
* subscribers.
|
|
125
131
|
* @internal
|
|
126
132
|
*/
|
|
127
|
-
tryProcessAndSend(
|
|
133
|
+
async tryProcessAndSend(
|
|
128
134
|
handle: DataTrackHandle,
|
|
129
|
-
|
|
130
|
-
):
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
135
|
+
frame: DataTrackFrameInternal,
|
|
136
|
+
): Promise<
|
|
137
|
+
Throws<
|
|
138
|
+
void,
|
|
139
|
+
| DataTrackPushFrameError<DataTrackPushFrameErrorReason.Dropped>
|
|
140
|
+
| DataTrackPushFrameError<DataTrackPushFrameErrorReason.TrackUnpublished>
|
|
141
|
+
>
|
|
134
142
|
> {
|
|
135
143
|
const descriptor = this.getDescriptor(handle);
|
|
136
144
|
if (descriptor?.type !== 'active') {
|
|
137
145
|
throw DataTrackPushFrameError.trackUnpublished();
|
|
138
146
|
}
|
|
139
147
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
148
|
+
if (descriptor.publishState === 'unpublished') {
|
|
149
|
+
throw DataTrackPushFrameError.trackUnpublished();
|
|
150
|
+
}
|
|
151
|
+
if (descriptor.publishState === 'republishing') {
|
|
152
|
+
throw DataTrackPushFrameError.dropped('Data track republishing');
|
|
153
|
+
}
|
|
144
154
|
|
|
145
155
|
try {
|
|
146
|
-
for (const packet of descriptor.pipeline.processFrame(frame)) {
|
|
147
|
-
this.emit('
|
|
156
|
+
for await (const packet of descriptor.pipeline.processFrame(frame)) {
|
|
157
|
+
this.emit('packetAvailable', { bytes: packet.toBinary() });
|
|
148
158
|
}
|
|
149
159
|
} catch (err) {
|
|
150
160
|
// NOTE: In the rust implementation this "dropped" error means something different (not enough room
|
|
@@ -153,15 +163,25 @@ export default class OutgoingDataTrackManager extends (EventEmitter as new () =>
|
|
|
153
163
|
}
|
|
154
164
|
}
|
|
155
165
|
|
|
156
|
-
/**
|
|
157
|
-
|
|
166
|
+
/**
|
|
167
|
+
* Client requested to publish a track.
|
|
168
|
+
*
|
|
169
|
+
* If the LiveKit server is too old and doesn't support data tracks, a
|
|
170
|
+
* {@link DataTrackPublishError#timeout} will be thrown.
|
|
171
|
+
*
|
|
172
|
+
* @internal
|
|
173
|
+
**/
|
|
174
|
+
async publishRequest(
|
|
175
|
+
options: DataTrackOptions,
|
|
176
|
+
signal?: AbortSignal,
|
|
177
|
+
): Promise<Throws<DataTrackHandle, DataTrackPublishError>> {
|
|
158
178
|
const handle = this.handleAllocator.get();
|
|
159
179
|
if (!handle) {
|
|
160
180
|
throw DataTrackPublishError.limitReached();
|
|
161
181
|
}
|
|
162
182
|
|
|
163
|
-
const timeoutSignal =
|
|
164
|
-
const combinedSignal = signal ?
|
|
183
|
+
const timeoutSignal = abortSignalTimeout(PUBLISH_TIMEOUT_MILLISECONDS);
|
|
184
|
+
const combinedSignal = signal ? abortSignalAny([signal, timeoutSignal]) : timeoutSignal;
|
|
165
185
|
|
|
166
186
|
if (this.descriptors.has(handle)) {
|
|
167
187
|
// @throws-transformer ignore - this should be treated as a "panic" and not be caught
|
|
@@ -191,21 +211,35 @@ export default class OutgoingDataTrackManager extends (EventEmitter as new () =>
|
|
|
191
211
|
);
|
|
192
212
|
}
|
|
193
213
|
};
|
|
214
|
+
if (combinedSignal.aborted) {
|
|
215
|
+
onAbort(); // NOTE: this rejects `completionFuture`; the next line just returns the rejection
|
|
216
|
+
return descriptor.completionFuture.promise.then(
|
|
217
|
+
() => handle /* no-op, makes typescript happy */,
|
|
218
|
+
);
|
|
219
|
+
}
|
|
194
220
|
combinedSignal.addEventListener('abort', onAbort);
|
|
195
221
|
|
|
196
222
|
this.emit('sfuPublishRequest', {
|
|
197
223
|
handle,
|
|
198
224
|
name: options.name,
|
|
199
|
-
usesE2ee: this.
|
|
225
|
+
usesE2ee: this.e2eeManager !== null,
|
|
200
226
|
});
|
|
201
227
|
|
|
202
|
-
|
|
228
|
+
await descriptor.completionFuture.promise;
|
|
203
229
|
combinedSignal.removeEventListener('abort', onAbort);
|
|
204
|
-
|
|
230
|
+
|
|
231
|
+
this.emit('trackPublished', {
|
|
232
|
+
track: LocalDataTrack.withExplicitHandle(options, this, handle),
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
return handle;
|
|
205
236
|
}
|
|
206
237
|
|
|
207
|
-
/**
|
|
208
|
-
|
|
238
|
+
/**
|
|
239
|
+
* Get information about all currently published tracks.
|
|
240
|
+
* @internal
|
|
241
|
+
**/
|
|
242
|
+
queryPublished() {
|
|
209
243
|
const descriptorInfos = Array.from(this.descriptors.values())
|
|
210
244
|
.filter((descriptor): descriptor is ActiveDescriptor => descriptor.type === 'active')
|
|
211
245
|
.map((descriptor) => descriptor.info);
|
|
@@ -213,7 +247,10 @@ export default class OutgoingDataTrackManager extends (EventEmitter as new () =>
|
|
|
213
247
|
return descriptorInfos;
|
|
214
248
|
}
|
|
215
249
|
|
|
216
|
-
/**
|
|
250
|
+
/**
|
|
251
|
+
* Client request to unpublish a track.
|
|
252
|
+
* @internal
|
|
253
|
+
**/
|
|
217
254
|
async unpublishRequest(handle: DataTrackHandle) {
|
|
218
255
|
const descriptor = this.descriptors.get(handle);
|
|
219
256
|
if (!descriptor) {
|
|
@@ -228,9 +265,14 @@ export default class OutgoingDataTrackManager extends (EventEmitter as new () =>
|
|
|
228
265
|
this.emit('sfuUnpublishRequest', { handle });
|
|
229
266
|
|
|
230
267
|
await descriptor.unpublishingFuture.promise;
|
|
268
|
+
|
|
269
|
+
this.emit('trackUnpublished', { sid: descriptor.info.sid });
|
|
231
270
|
}
|
|
232
271
|
|
|
233
|
-
/**
|
|
272
|
+
/**
|
|
273
|
+
* SFU responded to a request to publish a data track.
|
|
274
|
+
* @internal
|
|
275
|
+
**/
|
|
234
276
|
receivedSfuPublishResponse(handle: DataTrackHandle, result: SfuPublishResponseResult) {
|
|
235
277
|
const descriptor = this.descriptors.get(handle);
|
|
236
278
|
if (!descriptor) {
|
|
@@ -239,32 +281,41 @@ export default class OutgoingDataTrackManager extends (EventEmitter as new () =>
|
|
|
239
281
|
}
|
|
240
282
|
this.descriptors.delete(handle);
|
|
241
283
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
284
|
+
switch (descriptor.type) {
|
|
285
|
+
case 'pending': {
|
|
286
|
+
if (result.type === 'ok') {
|
|
287
|
+
const info = result.data;
|
|
288
|
+
const e2eeManager = info.usesE2ee ? this.e2eeManager : null;
|
|
289
|
+
this.descriptors.set(info.pubHandle, Descriptor.active(info, e2eeManager));
|
|
290
|
+
|
|
291
|
+
descriptor.completionFuture.resolve?.();
|
|
292
|
+
} else {
|
|
293
|
+
descriptor.completionFuture.reject?.(result.error);
|
|
294
|
+
}
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
case 'active': {
|
|
298
|
+
if (descriptor.publishState !== 'republishing') {
|
|
299
|
+
log.warn(`Track ${handle} already active`);
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
if (result.type === 'error') {
|
|
303
|
+
log.warn(`Republish failed for track ${handle}`);
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
log.debug(`Track ${handle} republished`);
|
|
308
|
+
descriptor.info.sid = result.data.sid;
|
|
309
|
+
descriptor.publishState = 'published';
|
|
310
|
+
this.descriptors.set(descriptor.info.pubHandle, descriptor);
|
|
259
311
|
}
|
|
260
|
-
|
|
261
|
-
descriptor.completionFuture.resolve?.(localDataTrack);
|
|
262
|
-
} else {
|
|
263
|
-
descriptor.completionFuture.reject?.(result.error);
|
|
264
312
|
}
|
|
265
313
|
}
|
|
266
314
|
|
|
267
|
-
/**
|
|
315
|
+
/**
|
|
316
|
+
* SFU notification that a track has been unpublished.
|
|
317
|
+
* @internal
|
|
318
|
+
**/
|
|
268
319
|
receivedSfuUnpublishResponse(handle: DataTrackHandle) {
|
|
269
320
|
const descriptor = this.descriptors.get(handle);
|
|
270
321
|
if (!descriptor) {
|
|
@@ -278,10 +329,40 @@ export default class OutgoingDataTrackManager extends (EventEmitter as new () =>
|
|
|
278
329
|
return;
|
|
279
330
|
}
|
|
280
331
|
|
|
332
|
+
descriptor.publishState = 'unpublished';
|
|
281
333
|
descriptor.unpublishingFuture.resolve?.();
|
|
282
334
|
}
|
|
283
335
|
|
|
284
|
-
/**
|
|
336
|
+
/** Republish all tracks.
|
|
337
|
+
*
|
|
338
|
+
* This must be sent after a full reconnect in order for existing publications
|
|
339
|
+
* to be recognized by the SFU. Each republished track will be assigned a new SID.
|
|
340
|
+
* @internal
|
|
341
|
+
*/
|
|
342
|
+
sfuWillRepublishTracks() {
|
|
343
|
+
for (const [handle, descriptor] of this.descriptors.entries()) {
|
|
344
|
+
switch (descriptor.type) {
|
|
345
|
+
case 'pending':
|
|
346
|
+
// TODO: support republish for pending publications
|
|
347
|
+
this.descriptors.delete(handle);
|
|
348
|
+
descriptor.completionFuture.reject?.(DataTrackPublishError.disconnected());
|
|
349
|
+
break;
|
|
350
|
+
case 'active':
|
|
351
|
+
descriptor.publishState = 'republishing';
|
|
352
|
+
|
|
353
|
+
this.emit('sfuPublishRequest', {
|
|
354
|
+
handle: descriptor.info.pubHandle,
|
|
355
|
+
name: descriptor.info.name,
|
|
356
|
+
usesE2ee: descriptor.info.usesE2ee,
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Shuts down the manager and all associated tracks.
|
|
364
|
+
* @internal
|
|
365
|
+
**/
|
|
285
366
|
async shutdown() {
|
|
286
367
|
for (const descriptor of this.descriptors.values()) {
|
|
287
368
|
switch (descriptor.type) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { LivekitReasonedError } from '../../errors';
|
|
2
|
-
import { DataTrackPacketizerError
|
|
2
|
+
import { DataTrackPacketizerError } from '../packetizer';
|
|
3
3
|
|
|
4
4
|
export enum DataTrackPublishErrorReason {
|
|
5
5
|
/**
|
|
@@ -23,10 +23,17 @@ export enum DataTrackPublishErrorReason {
|
|
|
23
23
|
|
|
24
24
|
// NOTE: this was introduced by web / there isn't a corresponding case in the rust version.
|
|
25
25
|
Cancelled = 5,
|
|
26
|
+
|
|
27
|
+
/** The name requested is not able to be used when creating the data track. */
|
|
28
|
+
InvalidName = 6,
|
|
29
|
+
|
|
30
|
+
/** There was an error publishing, but it was not something that could be sorted into a known
|
|
31
|
+
* category. */
|
|
32
|
+
Unknown = 7,
|
|
26
33
|
}
|
|
27
34
|
|
|
28
35
|
export class DataTrackPublishError<
|
|
29
|
-
Reason extends DataTrackPublishErrorReason,
|
|
36
|
+
Reason extends DataTrackPublishErrorReason = DataTrackPublishErrorReason,
|
|
30
37
|
> extends LivekitReasonedError<Reason> {
|
|
31
38
|
readonly name = 'DataTrackPublishError';
|
|
32
39
|
|
|
@@ -34,37 +41,59 @@ export class DataTrackPublishError<
|
|
|
34
41
|
|
|
35
42
|
reasonName: string;
|
|
36
43
|
|
|
37
|
-
|
|
44
|
+
/** Underling message from the SFU, if one was provided */
|
|
45
|
+
rawMessage?: string;
|
|
46
|
+
|
|
47
|
+
constructor(message: string, reason: Reason, options?: { rawMessage?: string; cause?: unknown }) {
|
|
38
48
|
super(21, message, options);
|
|
39
49
|
this.reason = reason;
|
|
40
50
|
this.reasonName = DataTrackPublishErrorReason[reason];
|
|
51
|
+
this.rawMessage = options?.rawMessage;
|
|
41
52
|
}
|
|
42
53
|
|
|
43
|
-
static notAllowed() {
|
|
54
|
+
static notAllowed(rawMessage?: string) {
|
|
44
55
|
return new DataTrackPublishError(
|
|
45
56
|
'Data track publishing unauthorized',
|
|
46
57
|
DataTrackPublishErrorReason.NotAllowed,
|
|
58
|
+
{ rawMessage },
|
|
47
59
|
);
|
|
48
60
|
}
|
|
49
61
|
|
|
50
|
-
static duplicateName() {
|
|
62
|
+
static duplicateName(rawMessage?: string) {
|
|
51
63
|
return new DataTrackPublishError(
|
|
52
64
|
'Track name already taken',
|
|
53
65
|
DataTrackPublishErrorReason.DuplicateName,
|
|
66
|
+
{ rawMessage },
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
static invalidName(rawMessage?: string) {
|
|
71
|
+
return new DataTrackPublishError(
|
|
72
|
+
'Track name is invalid',
|
|
73
|
+
DataTrackPublishErrorReason.InvalidName,
|
|
74
|
+
{ rawMessage },
|
|
54
75
|
);
|
|
55
76
|
}
|
|
56
77
|
|
|
57
78
|
static timeout() {
|
|
58
79
|
return new DataTrackPublishError(
|
|
59
|
-
'Publish data track timed-out',
|
|
80
|
+
'Publish data track timed-out. Does the LiveKit server support data tracks?',
|
|
60
81
|
DataTrackPublishErrorReason.Timeout,
|
|
61
82
|
);
|
|
62
83
|
}
|
|
63
84
|
|
|
64
|
-
static limitReached() {
|
|
85
|
+
static limitReached(rawMessage?: string) {
|
|
65
86
|
return new DataTrackPublishError(
|
|
66
87
|
'Data track publication limit reached',
|
|
67
88
|
DataTrackPublishErrorReason.LimitReached,
|
|
89
|
+
{ rawMessage },
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
static unknown(reason: number, message: string) {
|
|
94
|
+
return new DataTrackPublishError(
|
|
95
|
+
`Received RequestResponse for publishDataTrack, but reason was unrecognised (${reason}, ${message})`,
|
|
96
|
+
DataTrackPublishErrorReason.Unknown,
|
|
68
97
|
);
|
|
69
98
|
}
|
|
70
99
|
|
|
@@ -91,7 +120,7 @@ export enum DataTrackPushFrameErrorReason {
|
|
|
91
120
|
}
|
|
92
121
|
|
|
93
122
|
export class DataTrackPushFrameError<
|
|
94
|
-
Reason extends DataTrackPushFrameErrorReason,
|
|
123
|
+
Reason extends DataTrackPushFrameErrorReason = DataTrackPushFrameErrorReason,
|
|
95
124
|
> extends LivekitReasonedError<Reason> {
|
|
96
125
|
readonly name = 'DataTrackPushFrameError';
|
|
97
126
|
|
|
@@ -112,7 +141,7 @@ export class DataTrackPushFrameError<
|
|
|
112
141
|
);
|
|
113
142
|
}
|
|
114
143
|
|
|
115
|
-
static dropped(cause
|
|
144
|
+
static dropped(cause?: unknown) {
|
|
116
145
|
return new DataTrackPushFrameError('Frame was dropped', DataTrackPushFrameErrorReason.Dropped, {
|
|
117
146
|
cause,
|
|
118
147
|
});
|
|
@@ -125,7 +154,7 @@ export enum DataTrackOutgoingPipelineErrorReason {
|
|
|
125
154
|
}
|
|
126
155
|
|
|
127
156
|
export class DataTrackOutgoingPipelineError<
|
|
128
|
-
Reason extends DataTrackOutgoingPipelineErrorReason,
|
|
157
|
+
Reason extends DataTrackOutgoingPipelineErrorReason = DataTrackOutgoingPipelineErrorReason,
|
|
129
158
|
> extends LivekitReasonedError<Reason> {
|
|
130
159
|
readonly name = 'DataTrackOutgoingPipelineError';
|
|
131
160
|
|
|
@@ -139,7 +168,7 @@ export class DataTrackOutgoingPipelineError<
|
|
|
139
168
|
this.reasonName = DataTrackOutgoingPipelineErrorReason[reason];
|
|
140
169
|
}
|
|
141
170
|
|
|
142
|
-
static packetizer(cause: DataTrackPacketizerError
|
|
171
|
+
static packetizer(cause: DataTrackPacketizerError) {
|
|
143
172
|
return new DataTrackOutgoingPipelineError(
|
|
144
173
|
'Error packetizing frame',
|
|
145
174
|
DataTrackOutgoingPipelineErrorReason.Packetizer,
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import { type Throws } from '
|
|
2
|
-
import
|
|
3
|
-
import { type
|
|
1
|
+
import { type Throws } from '@livekit/throws-transformer/throws';
|
|
2
|
+
import type { BaseE2EEManager } from '../../../e2ee/E2eeManager';
|
|
3
|
+
import { type DataTrackFrameInternal } from '../frame';
|
|
4
4
|
import { DataTrackPacket } from '../packet';
|
|
5
5
|
import { DataTrackE2eeExtension } from '../packet/extensions';
|
|
6
6
|
import DataTrackPacketizer, { DataTrackPacketizerError } from '../packetizer';
|
|
7
|
-
import type { DataTrackInfo } from '../
|
|
7
|
+
import type { DataTrackInfo } from '../types';
|
|
8
8
|
import { DataTrackOutgoingPipelineError, DataTrackOutgoingPipelineErrorReason } from './errors';
|
|
9
9
|
|
|
10
10
|
type Options = {
|
|
11
11
|
info: DataTrackInfo;
|
|
12
|
-
|
|
12
|
+
e2eeManager: BaseE2EEManager | null;
|
|
13
13
|
};
|
|
14
14
|
|
|
15
15
|
/** Processes outgoing frames into final packets for distribution to the SFU. */
|
|
16
16
|
export default class DataTrackOutgoingPipeline {
|
|
17
|
-
private
|
|
17
|
+
private e2eeManager: BaseE2EEManager | null;
|
|
18
18
|
|
|
19
19
|
private packetizer: DataTrackPacketizer;
|
|
20
20
|
|
|
@@ -22,21 +22,21 @@ export default class DataTrackOutgoingPipeline {
|
|
|
22
22
|
private static TRANSPORT_MTU_BYTES = 16_000;
|
|
23
23
|
|
|
24
24
|
constructor(options: Options) {
|
|
25
|
-
this.
|
|
25
|
+
this.e2eeManager = options.e2eeManager;
|
|
26
26
|
this.packetizer = new DataTrackPacketizer(
|
|
27
27
|
options.info.pubHandle,
|
|
28
28
|
DataTrackOutgoingPipeline.TRANSPORT_MTU_BYTES,
|
|
29
29
|
);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
> {
|
|
39
|
-
const encryptedFrame = this.encryptIfNeeded(frame);
|
|
32
|
+
updateE2eeManager(e2eeManager: BaseE2EEManager | null) {
|
|
33
|
+
this.e2eeManager = e2eeManager;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async *processFrame(
|
|
37
|
+
frame: DataTrackFrameInternal,
|
|
38
|
+
): Throws<AsyncGenerator<DataTrackPacket>, DataTrackOutgoingPipelineError> {
|
|
39
|
+
const encryptedFrame = await this.encryptIfNeeded(frame);
|
|
40
40
|
|
|
41
41
|
try {
|
|
42
42
|
yield* this.packetizer.packetize(encryptedFrame);
|
|
@@ -48,19 +48,21 @@ export default class DataTrackOutgoingPipeline {
|
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
encryptIfNeeded(
|
|
52
|
-
frame:
|
|
53
|
-
):
|
|
54
|
-
|
|
55
|
-
|
|
51
|
+
async encryptIfNeeded(
|
|
52
|
+
frame: DataTrackFrameInternal,
|
|
53
|
+
): Promise<
|
|
54
|
+
Throws<
|
|
55
|
+
DataTrackFrameInternal,
|
|
56
|
+
DataTrackOutgoingPipelineError<DataTrackOutgoingPipelineErrorReason.Encryption>
|
|
57
|
+
>
|
|
56
58
|
> {
|
|
57
|
-
if (!this.
|
|
59
|
+
if (!this.e2eeManager) {
|
|
58
60
|
return frame;
|
|
59
61
|
}
|
|
60
62
|
|
|
61
|
-
let encryptedResult
|
|
63
|
+
let encryptedResult;
|
|
62
64
|
try {
|
|
63
|
-
encryptedResult = this.
|
|
65
|
+
encryptedResult = await this.e2eeManager.encryptData(frame.payload);
|
|
64
66
|
} catch (err) {
|
|
65
67
|
throw DataTrackOutgoingPipelineError.encryption(err);
|
|
66
68
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import type LocalDataTrack from '../LocalDataTrack';
|
|
1
2
|
import { type DataTrackHandle } from '../handle';
|
|
2
|
-
import { type DataTrackInfo } from '../
|
|
3
|
+
import { type DataTrackInfo, type DataTrackSid } from '../types';
|
|
3
4
|
import { type DataTrackPublishError, type DataTrackPublishErrorReason } from './errors';
|
|
4
5
|
|
|
5
6
|
/** Options for publishing a data track. */
|
|
@@ -15,23 +16,30 @@ export type SfuPublishResponseResult =
|
|
|
15
16
|
error:
|
|
16
17
|
| DataTrackPublishError<DataTrackPublishErrorReason.NotAllowed>
|
|
17
18
|
| DataTrackPublishError<DataTrackPublishErrorReason.DuplicateName>
|
|
19
|
+
| DataTrackPublishError<DataTrackPublishErrorReason.InvalidName>
|
|
18
20
|
| DataTrackPublishError<DataTrackPublishErrorReason.LimitReached>;
|
|
19
21
|
};
|
|
20
22
|
|
|
21
23
|
/** Request sent to the SFU to publish a track. */
|
|
22
|
-
export type
|
|
24
|
+
export type EventSfuPublishRequest = {
|
|
23
25
|
handle: DataTrackHandle;
|
|
24
26
|
name: string;
|
|
25
27
|
usesE2ee: boolean;
|
|
26
28
|
};
|
|
27
29
|
|
|
28
30
|
/** Request sent to the SFU to unpublish a track. */
|
|
29
|
-
export type
|
|
31
|
+
export type EventSfuUnpublishRequest = {
|
|
30
32
|
handle: DataTrackHandle;
|
|
31
33
|
};
|
|
32
34
|
|
|
33
|
-
/**
|
|
34
|
-
export type
|
|
35
|
+
/** A serialized packet is ready to be sent over the transport. */
|
|
36
|
+
export type EventPacketAvailable = {
|
|
35
37
|
bytes: Uint8Array;
|
|
36
|
-
signal?: AbortSignal;
|
|
37
38
|
};
|
|
39
|
+
|
|
40
|
+
/** A track has been created by a local participant and is available to be
|
|
41
|
+
* subscribed to. */
|
|
42
|
+
export type EventTrackPublished = { track: LocalDataTrack };
|
|
43
|
+
|
|
44
|
+
/** A track has been unpublished by a remote participant and can no longer be subscribed to. */
|
|
45
|
+
export type EventTrackUnpublished = { sid: DataTrackSid };
|