mockrtc 0.1.0
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/.github/workflows/ci.yml +29 -0
- package/LICENSE +201 -0
- package/README.md +290 -0
- package/dist/admin-bin.d.ts +2 -0
- package/dist/admin-bin.js +67 -0
- package/dist/admin-bin.js.map +1 -0
- package/dist/client/mockrtc-client.d.ts +12 -0
- package/dist/client/mockrtc-client.js +67 -0
- package/dist/client/mockrtc-client.js.map +1 -0
- package/dist/client/mockrtc-remote-peer.d.ts +15 -0
- package/dist/client/mockrtc-remote-peer.js +246 -0
- package/dist/client/mockrtc-remote-peer.js.map +1 -0
- package/dist/control-channel.d.ts +8 -0
- package/dist/control-channel.js +11 -0
- package/dist/control-channel.js.map +1 -0
- package/dist/handling/handler-builder.d.ts +138 -0
- package/dist/handling/handler-builder.js +164 -0
- package/dist/handling/handler-builder.js.map +1 -0
- package/dist/handling/handler-step-definitions.d.ts +63 -0
- package/dist/handling/handler-step-definitions.js +123 -0
- package/dist/handling/handler-step-definitions.js.map +1 -0
- package/dist/handling/handler-steps.d.ts +48 -0
- package/dist/handling/handler-steps.js +218 -0
- package/dist/handling/handler-steps.js.map +1 -0
- package/dist/main-browser.d.ts +9 -0
- package/dist/main-browser.js +26 -0
- package/dist/main-browser.js.map +1 -0
- package/dist/main.d.ts +58 -0
- package/dist/main.js +67 -0
- package/dist/main.js.map +1 -0
- package/dist/mockrtc-admin-plugin.d.ts +56 -0
- package/dist/mockrtc-admin-plugin.js +151 -0
- package/dist/mockrtc-admin-plugin.js.map +1 -0
- package/dist/mockrtc-admin-server.d.ts +7 -0
- package/dist/mockrtc-admin-server.js +18 -0
- package/dist/mockrtc-admin-server.js.map +1 -0
- package/dist/mockrtc-client.d.ts +12 -0
- package/dist/mockrtc-client.js +64 -0
- package/dist/mockrtc-client.js.map +1 -0
- package/dist/mockrtc-handler-builder.d.ts +15 -0
- package/dist/mockrtc-handler-builder.js +24 -0
- package/dist/mockrtc-handler-builder.js.map +1 -0
- package/dist/mockrtc-peer.d.ts +147 -0
- package/dist/mockrtc-peer.js +7 -0
- package/dist/mockrtc-peer.js.map +1 -0
- package/dist/mockrtc-remote-peer.d.ts +15 -0
- package/dist/mockrtc-remote-peer.js +234 -0
- package/dist/mockrtc-remote-peer.js.map +1 -0
- package/dist/mockrtc-server-peer.d.ts +29 -0
- package/dist/mockrtc-server-peer.js +145 -0
- package/dist/mockrtc-server-peer.js.map +1 -0
- package/dist/mockrtc-server.d.ts +14 -0
- package/dist/mockrtc-server.js +53 -0
- package/dist/mockrtc-server.js.map +1 -0
- package/dist/mockrtc.d.ts +25 -0
- package/dist/mockrtc.js +7 -0
- package/dist/mockrtc.js.map +1 -0
- package/dist/package.json +52 -0
- package/dist/server/mockrtc-admin-plugin.d.ts +17 -0
- package/dist/server/mockrtc-admin-plugin.js +163 -0
- package/dist/server/mockrtc-admin-plugin.js.map +1 -0
- package/dist/server/mockrtc-admin-server.d.ts +7 -0
- package/dist/server/mockrtc-admin-server.js +18 -0
- package/dist/server/mockrtc-admin-server.js.map +1 -0
- package/dist/server/mockrtc-server-peer.d.ts +24 -0
- package/dist/server/mockrtc-server-peer.js +141 -0
- package/dist/server/mockrtc-server-peer.js.map +1 -0
- package/dist/server/mockrtc-server.d.ts +14 -0
- package/dist/server/mockrtc-server.js +53 -0
- package/dist/server/mockrtc-server.js.map +1 -0
- package/dist/src/main.d.ts +1 -0
- package/dist/src/main.js +24 -0
- package/dist/src/main.js.map +1 -0
- package/dist/src/mockrtc-peer.d.ts +0 -0
- package/dist/src/mockrtc-peer.js +2 -0
- package/dist/src/mockrtc-peer.js.map +1 -0
- package/dist/src/mockrtc.d.ts +0 -0
- package/dist/src/mockrtc.js +65 -0
- package/dist/src/mockrtc.js.map +1 -0
- package/dist/webrtc/control-channel.d.ts +8 -0
- package/dist/webrtc/control-channel.js +11 -0
- package/dist/webrtc/control-channel.js.map +1 -0
- package/dist/webrtc/datachannel-stream.d.ts +25 -0
- package/dist/webrtc/datachannel-stream.js +86 -0
- package/dist/webrtc/datachannel-stream.js.map +1 -0
- package/dist/webrtc/mediatrack-stream.d.ts +29 -0
- package/dist/webrtc/mediatrack-stream.js +109 -0
- package/dist/webrtc/mediatrack-stream.js.map +1 -0
- package/dist/webrtc/mockrtc-connection.d.ts +14 -0
- package/dist/webrtc/mockrtc-connection.js +147 -0
- package/dist/webrtc/mockrtc-connection.js.map +1 -0
- package/dist/webrtc/peer-connection.d.ts +16 -0
- package/dist/webrtc/peer-connection.js +81 -0
- package/dist/webrtc/peer-connection.js.map +1 -0
- package/dist/webrtc/rtc-connection.d.ts +47 -0
- package/dist/webrtc/rtc-connection.js +370 -0
- package/dist/webrtc/rtc-connection.js.map +1 -0
- package/dist/webrtc-hooks.d.ts +30 -0
- package/dist/webrtc-hooks.js +224 -0
- package/dist/webrtc-hooks.js.map +1 -0
- package/karma.conf.ts +89 -0
- package/ngi-eu-footer.png +0 -0
- package/package.json +86 -0
- package/src/admin-bin.ts +57 -0
- package/src/client/mockrtc-client.ts +79 -0
- package/src/client/mockrtc-remote-peer.ts +286 -0
- package/src/handling/handler-builder.ts +215 -0
- package/src/handling/handler-step-definitions.ts +142 -0
- package/src/handling/handler-steps.ts +254 -0
- package/src/main-browser.ts +44 -0
- package/src/main.ts +109 -0
- package/src/mockrtc-peer.ts +176 -0
- package/src/mockrtc.ts +36 -0
- package/src/server/mockrtc-admin-plugin.ts +196 -0
- package/src/server/mockrtc-admin-server.ts +17 -0
- package/src/server/mockrtc-server-peer.ts +159 -0
- package/src/server/mockrtc-server.ts +53 -0
- package/src/webrtc/control-channel.ts +13 -0
- package/src/webrtc/datachannel-stream.ts +102 -0
- package/src/webrtc/mediatrack-stream.ts +135 -0
- package/src/webrtc/mockrtc-connection.ts +164 -0
- package/src/webrtc/rtc-connection.ts +420 -0
- package/src/webrtc-hooks.ts +245 -0
- package/test/integration/close-steps.spec.ts +39 -0
- package/test/integration/connection-setup.spec.ts +230 -0
- package/test/integration/echo-steps.spec.ts +88 -0
- package/test/integration/proxy.spec.ts +526 -0
- package/test/integration/send-steps.spec.ts +76 -0
- package/test/integration/smoke-test.spec.ts +100 -0
- package/test/integration/wait-steps.spec.ts +225 -0
- package/test/start-test-admin-server.ts +12 -0
- package/test/test-setup.ts +136 -0
- package/test/tsconfig.json +11 -0
- package/tsconfig.json +14 -0
- package/typedoc.json +19 -0
- package/wallaby.js +41 -0
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* SPDX-FileCopyrightText: 2022 Tim Perry <tim@httptoolkit.tech>
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
7
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
8
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
9
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
10
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
11
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
12
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
13
|
+
});
|
|
14
|
+
};
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.RTCConnection = void 0;
|
|
17
|
+
const crypto_1 = require("crypto");
|
|
18
|
+
const events_1 = require("events");
|
|
19
|
+
const SDP = require("sdp-transform");
|
|
20
|
+
const NodeDataChannel = require("node-datachannel");
|
|
21
|
+
const datachannel_stream_1 = require("./datachannel-stream");
|
|
22
|
+
const mediatrack_stream_1 = require("./mediatrack-stream");
|
|
23
|
+
/**
|
|
24
|
+
* An RTC connection is a single connection. This base class defines the raw connection management and
|
|
25
|
+
* tracking logic for a generic connection. The MockRTCConnection subclass extends this and adds
|
|
26
|
+
* logic to support control channels, proxying and other MockRTC-specific additions.
|
|
27
|
+
*/
|
|
28
|
+
class RTCConnection extends events_1.EventEmitter {
|
|
29
|
+
constructor() {
|
|
30
|
+
super();
|
|
31
|
+
this.id = (0, crypto_1.randomUUID)();
|
|
32
|
+
// Set to null when the connection is closed, as otherwise calling any method (including checking
|
|
33
|
+
// the connection state) will segfault the process.
|
|
34
|
+
this.rawConn = new NodeDataChannel.PeerConnection("MockRTCConnection", { iceServers: [] });
|
|
35
|
+
this.trackedChannels = [];
|
|
36
|
+
this.trackedMediaTracks = [];
|
|
37
|
+
this.sessionApi = {
|
|
38
|
+
sessionId: this.id,
|
|
39
|
+
createOffer: (options = {}) => __awaiter(this, void 0, void 0, function* () {
|
|
40
|
+
if (options.mirrorSDP) {
|
|
41
|
+
return this.getMirroredLocalOffer(options.mirrorSDP, {
|
|
42
|
+
addDataStream: !!options.addDataStream
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
return this.getLocalDescription();
|
|
47
|
+
}
|
|
48
|
+
}),
|
|
49
|
+
completeOffer: (answer) => __awaiter(this, void 0, void 0, function* () {
|
|
50
|
+
this.setRemoteDescription(answer);
|
|
51
|
+
}),
|
|
52
|
+
answerOffer: (offer, options = {}) => __awaiter(this, void 0, void 0, function* () {
|
|
53
|
+
this.setRemoteDescription(offer);
|
|
54
|
+
if (options.mirrorSDP) {
|
|
55
|
+
return this.getMirroredLocalAnswer(options.mirrorSDP);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
return this.getLocalDescription();
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
};
|
|
62
|
+
this.rawConn.onDataChannel((channel) => {
|
|
63
|
+
if (!this.rawConn)
|
|
64
|
+
return; // https://github.com/murat-dogan/node-datachannel/issues/103
|
|
65
|
+
this.trackNewChannel(channel, { isLocal: false });
|
|
66
|
+
});
|
|
67
|
+
this.rawConn.onTrack((track) => {
|
|
68
|
+
if (!this.rawConn)
|
|
69
|
+
return; // https://github.com/murat-dogan/node-datachannel/issues/103
|
|
70
|
+
this.trackNewMediaTrack(track, { isLocal: false });
|
|
71
|
+
});
|
|
72
|
+
// Important to remember that only node-dc only allows one listener per event. To handle that,
|
|
73
|
+
// we reemit important events here to use normal node event methods instead:
|
|
74
|
+
this.rawConn.onStateChange((state) => {
|
|
75
|
+
this.emit('connection-state-changed', state);
|
|
76
|
+
});
|
|
77
|
+
this.on('connection-state-changed', (state) => {
|
|
78
|
+
if (state === 'closed')
|
|
79
|
+
this.emit('connection-closed');
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
get channels() {
|
|
83
|
+
return this.trackedChannels
|
|
84
|
+
.map(channel => channel.stream);
|
|
85
|
+
}
|
|
86
|
+
get localChannels() {
|
|
87
|
+
return this.trackedChannels
|
|
88
|
+
.filter(channel => channel.isLocal)
|
|
89
|
+
.map(channel => channel.stream);
|
|
90
|
+
}
|
|
91
|
+
get remoteChannels() {
|
|
92
|
+
return this.trackedChannels
|
|
93
|
+
.filter(channel => !channel.isLocal)
|
|
94
|
+
.map(channel => channel.stream);
|
|
95
|
+
}
|
|
96
|
+
get mediaTracks() {
|
|
97
|
+
return this.trackedMediaTracks
|
|
98
|
+
.map(track => track.stream);
|
|
99
|
+
}
|
|
100
|
+
get localMediaTracks() {
|
|
101
|
+
return this.trackedMediaTracks
|
|
102
|
+
.filter(track => track.isLocal)
|
|
103
|
+
.map(track => track.stream);
|
|
104
|
+
}
|
|
105
|
+
get remoteMediaTracks() {
|
|
106
|
+
return this.trackedMediaTracks
|
|
107
|
+
.filter(track => !track.isLocal)
|
|
108
|
+
.map(track => track.stream);
|
|
109
|
+
}
|
|
110
|
+
createDataChannel(label) {
|
|
111
|
+
if (!this.rawConn)
|
|
112
|
+
throw new Error("Can't create data channel after connection is closed");
|
|
113
|
+
const channel = this.rawConn.createDataChannel(label);
|
|
114
|
+
return this.trackNewChannel(channel, { isLocal: true });
|
|
115
|
+
}
|
|
116
|
+
trackNewChannel(channel, options) {
|
|
117
|
+
const channelStream = new datachannel_stream_1.DataChannelStream(channel);
|
|
118
|
+
this.trackedChannels.push({ stream: channelStream, isLocal: options.isLocal });
|
|
119
|
+
channelStream.on('close', () => {
|
|
120
|
+
const channelIndex = this.trackedChannels.findIndex(c => c.stream === channelStream);
|
|
121
|
+
if (channelIndex !== -1) {
|
|
122
|
+
this.trackedChannels.splice(channelIndex, 1);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
channelStream.on('error', (error) => {
|
|
126
|
+
console.error('Channel error:', error);
|
|
127
|
+
});
|
|
128
|
+
this.emit('channel-open', channelStream);
|
|
129
|
+
if (options.isLocal) {
|
|
130
|
+
this.emit('local-channel-open', channelStream);
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
this.emit('remote-channel-open', channelStream);
|
|
134
|
+
}
|
|
135
|
+
return channelStream;
|
|
136
|
+
}
|
|
137
|
+
trackNewMediaTrack(track, options) {
|
|
138
|
+
const trackStream = new mediatrack_stream_1.MediaTrackStream(track);
|
|
139
|
+
this.trackedMediaTracks.push({ stream: trackStream, isLocal: options.isLocal });
|
|
140
|
+
trackStream.on('close', () => {
|
|
141
|
+
const trackIndex = this.trackedMediaTracks.findIndex(c => c.stream === trackStream);
|
|
142
|
+
if (trackIndex !== -1) {
|
|
143
|
+
this.trackedChannels.splice(trackIndex, 1);
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
trackStream.on('error', (error) => {
|
|
147
|
+
console.error('Media track error:', error);
|
|
148
|
+
});
|
|
149
|
+
this.emit('track-open', trackStream);
|
|
150
|
+
if (options.isLocal) {
|
|
151
|
+
this.emit('local-track-open', trackStream);
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
this.emit('remote-track-open', trackStream);
|
|
155
|
+
}
|
|
156
|
+
return trackStream;
|
|
157
|
+
}
|
|
158
|
+
setRemoteDescription(description) {
|
|
159
|
+
if (!this.rawConn)
|
|
160
|
+
throw new Error("Can't set remote description after connection is closed");
|
|
161
|
+
this.remoteDescription = description;
|
|
162
|
+
const { type: offerType, sdp: offerSdp } = description;
|
|
163
|
+
if (!offerSdp)
|
|
164
|
+
throw new Error("Cannot set MockRTC peer description without providing an SDP");
|
|
165
|
+
this.rawConn.setRemoteDescription(offerSdp, offerType[0].toUpperCase() + offerType.slice(1));
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Gets the local description for this connection, waiting until gathering is complete to provide a
|
|
169
|
+
* full result. Because this waits for gathering, it will not resolve if no DataChannel, other
|
|
170
|
+
* tracks or remote description have been provided beforehand.
|
|
171
|
+
*/
|
|
172
|
+
getLocalDescription() {
|
|
173
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
174
|
+
if (!this.rawConn)
|
|
175
|
+
throw new Error("Can't get local description after connection is closed");
|
|
176
|
+
let setupChannel;
|
|
177
|
+
if (this.rawConn.gatheringState() === 'new') {
|
|
178
|
+
// We can't create an offer until we have something to negotiate, but we don't want to
|
|
179
|
+
// negotiate ourselves when we don't really know what's being negotiated here. To work
|
|
180
|
+
// around that, we create a channel to trigger gathering & get an offer, and then we
|
|
181
|
+
// remove it before the offer is delivered, so it's never visible remotely.
|
|
182
|
+
setupChannel = this.rawConn.createDataChannel('mockrtc.setup-channel');
|
|
183
|
+
}
|
|
184
|
+
yield new Promise((resolve) => {
|
|
185
|
+
this.rawConn.onGatheringStateChange((state) => {
|
|
186
|
+
if (state === 'complete')
|
|
187
|
+
resolve();
|
|
188
|
+
});
|
|
189
|
+
// Handle race conditions where gathering has already completed
|
|
190
|
+
if (this.rawConn.gatheringState() === 'complete')
|
|
191
|
+
resolve();
|
|
192
|
+
});
|
|
193
|
+
if (!this.rawConn)
|
|
194
|
+
throw new Error("Connection was closed while building local description");
|
|
195
|
+
const sessionDescription = this.rawConn.localDescription();
|
|
196
|
+
setupChannel === null || setupChannel === void 0 ? void 0 : setupChannel.close(); // Close the temporary setup channel, if we created one
|
|
197
|
+
return sessionDescription;
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
getRemoteDescription() {
|
|
201
|
+
if (!this.rawConn)
|
|
202
|
+
throw new Error("Can't get remote description after connection is closed");
|
|
203
|
+
return this.remoteDescription;
|
|
204
|
+
}
|
|
205
|
+
getMirroredLocalOffer(sdpToMirror, options = {}) {
|
|
206
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
207
|
+
if (!this.rawConn)
|
|
208
|
+
throw new Error("Can't get local description after connection is closed");
|
|
209
|
+
const offerToMirror = SDP.parse(sdpToMirror);
|
|
210
|
+
const mediaStreamsToMirror = offerToMirror.media.filter(media => media.type !== 'application');
|
|
211
|
+
const shouldMirrorDataStream = offerToMirror.media.some(media => media.type === 'application');
|
|
212
|
+
mediaStreamsToMirror.forEach((mediaToMirror) => {
|
|
213
|
+
var _a, _b;
|
|
214
|
+
// Skip media tracks that we already have
|
|
215
|
+
if (this.mediaTracks.find(({ mid }) => mid === mediaToMirror.mid))
|
|
216
|
+
return;
|
|
217
|
+
const mid = mediaToMirror.mid.toString();
|
|
218
|
+
const direction = sdpDirectionToNDCDirection(mediaToMirror.direction);
|
|
219
|
+
const media = mediaToMirror.type === 'video'
|
|
220
|
+
? new NodeDataChannel.Video(mid, direction)
|
|
221
|
+
: new NodeDataChannel.Audio(mid, direction);
|
|
222
|
+
// Copy SSRC data (awkward translation between per-attr and full-value structures)
|
|
223
|
+
const ssrcs = (_b = (_a = mediaToMirror.ssrcs) === null || _a === void 0 ? void 0 : _a.reduce((ssrcs, kv) => {
|
|
224
|
+
var _a;
|
|
225
|
+
ssrcs[_a = kv.id] || (ssrcs[_a] = {});
|
|
226
|
+
ssrcs[kv.id][kv.attribute] = kv.value;
|
|
227
|
+
return ssrcs;
|
|
228
|
+
}, {})) !== null && _b !== void 0 ? _b : {};
|
|
229
|
+
Object.keys(ssrcs).forEach((id) => {
|
|
230
|
+
var _a, _b;
|
|
231
|
+
const ssrcAttrs = ssrcs[id];
|
|
232
|
+
const [msid, trackId] = (_b = (_a = ssrcAttrs.msid) === null || _a === void 0 ? void 0 : _a.split(' ')) !== null && _b !== void 0 ? _b : [];
|
|
233
|
+
if (!msid) {
|
|
234
|
+
media.addSSRC(parseInt(id, 10), ssrcAttrs['cname']);
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
media.addSSRC(parseInt(id, 10), ssrcAttrs['cname'], msid, trackId);
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
const track = this.rawConn.addTrack(media);
|
|
241
|
+
this.trackNewMediaTrack(track, { isLocal: true });
|
|
242
|
+
});
|
|
243
|
+
let setupChannel;
|
|
244
|
+
const channelRequiredForDescription = this.rawConn.gatheringState() === 'new' &&
|
|
245
|
+
!mediaStreamsToMirror.length;
|
|
246
|
+
if (shouldMirrorDataStream || channelRequiredForDescription || options.addDataStream) {
|
|
247
|
+
// See getLocalDescription() above: if we want a description and we have no media, we
|
|
248
|
+
// need to make a stub channel to allow us to negotiate _something_.
|
|
249
|
+
// In addition, we might actually have data channels to mirror. In that case, we need
|
|
250
|
+
// to create a temporary data channel to force that negotiation (which will be closed
|
|
251
|
+
// again shortly, so that it never actually gets created).
|
|
252
|
+
setupChannel = this.rawConn.createDataChannel('mockrtc.setup-channel');
|
|
253
|
+
}
|
|
254
|
+
this.rawConn.setLocalDescription("Offer" /* Offer */);
|
|
255
|
+
yield new Promise((resolve) => {
|
|
256
|
+
this.rawConn.onGatheringStateChange((state) => {
|
|
257
|
+
if (state === 'complete')
|
|
258
|
+
resolve();
|
|
259
|
+
});
|
|
260
|
+
// Handle race conditions where gathering has already completed
|
|
261
|
+
if (this.rawConn.gatheringState() === 'complete')
|
|
262
|
+
resolve();
|
|
263
|
+
});
|
|
264
|
+
if (!this.rawConn)
|
|
265
|
+
throw new Error("Connection was closed while building the local description");
|
|
266
|
+
const localDesc = this.rawConn.localDescription();
|
|
267
|
+
setupChannel === null || setupChannel === void 0 ? void 0 : setupChannel.close(); // Close the temporary setup channel, if we created one
|
|
268
|
+
const offerSDP = SDP.parse(localDesc.sdp);
|
|
269
|
+
mirrorMediaParams(offerToMirror, offerSDP);
|
|
270
|
+
localDesc.sdp = SDP.write(offerSDP);
|
|
271
|
+
return localDesc;
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
getMirroredLocalAnswer(sdpToMirror) {
|
|
275
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
276
|
+
const localDesc = this.rawConn.localDescription();
|
|
277
|
+
const answerToMirror = SDP.parse(sdpToMirror);
|
|
278
|
+
const answerSDP = SDP.parse(localDesc.sdp);
|
|
279
|
+
mirrorMediaParams(answerToMirror, answerSDP);
|
|
280
|
+
localDesc.sdp = SDP.write(answerSDP);
|
|
281
|
+
return localDesc;
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
waitUntilConnected() {
|
|
285
|
+
return new Promise((resolve, reject) => {
|
|
286
|
+
if (!this.rawConn)
|
|
287
|
+
throw new Error("Connection closed while/before waiting until connected");
|
|
288
|
+
this.on('connection-state-changed', (state) => {
|
|
289
|
+
if (state === 'connected')
|
|
290
|
+
resolve();
|
|
291
|
+
if (state === 'failed') {
|
|
292
|
+
reject(new Error("Connection failed while waiting for connection"));
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
if (this.rawConn.state() === 'connected')
|
|
296
|
+
resolve();
|
|
297
|
+
if (this.rawConn.state() === 'failed') {
|
|
298
|
+
reject(new Error("Connection failed while waiting for connection"));
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
close() {
|
|
303
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
304
|
+
if (!this.rawConn)
|
|
305
|
+
return; // Already closed
|
|
306
|
+
const { rawConn } = this;
|
|
307
|
+
this.rawConn = null; // Drop the reference, so nothing tries to use it after close
|
|
308
|
+
if (rawConn.state() === 'closed')
|
|
309
|
+
return;
|
|
310
|
+
rawConn.close();
|
|
311
|
+
this.emit('connection-closed');
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
exports.RTCConnection = RTCConnection;
|
|
316
|
+
function sdpDirectionToNDCDirection(direction) {
|
|
317
|
+
if (direction === 'inactive')
|
|
318
|
+
return "Inactive" /* Inactive */;
|
|
319
|
+
else if ((direction === null || direction === void 0 ? void 0 : direction.length) === 8) {
|
|
320
|
+
return direction[0].toUpperCase() +
|
|
321
|
+
direction.slice(1, 4) +
|
|
322
|
+
direction[4].toUpperCase() +
|
|
323
|
+
direction.slice(5);
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
return "Unknown" /* Unknown */;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
;
|
|
330
|
+
/**
|
|
331
|
+
* Takes two parsed descriptions (typically a real description we want to mock, and our own current
|
|
332
|
+
* self-generated description) and modifies the target description sure that the media params for
|
|
333
|
+
* each stream in the source description match.
|
|
334
|
+
*
|
|
335
|
+
* In theory, this should guarantee that RTP packets generated by the source and forwarded through
|
|
336
|
+
* the target's connection can be interpreted by somebody connected to the target.
|
|
337
|
+
*/
|
|
338
|
+
function mirrorMediaParams(source, target) {
|
|
339
|
+
target.msidSemantic = source.msidSemantic;
|
|
340
|
+
const sourceMediaStreams = source.media.filter(m => m.type !== 'application');
|
|
341
|
+
sourceMediaStreams.forEach((sourceMedia) => {
|
|
342
|
+
const targetMedia = target.media
|
|
343
|
+
.find((targetMedia) => targetMedia.mid === sourceMedia.mid);
|
|
344
|
+
if (!targetMedia) {
|
|
345
|
+
throw new Error(`Missing mid ${sourceMedia.mid} in target when mirroring media params`);
|
|
346
|
+
}
|
|
347
|
+
if (sourceMedia.type !== targetMedia.type) {
|
|
348
|
+
throw new Error(`Unexpected media type (${targetMedia.type}) for mid ${targetMedia.mid} when mirroring media params`);
|
|
349
|
+
}
|
|
350
|
+
// Copy all the semantic parameters of the RTP & RTCP streams themselves, so that RTP packets
|
|
351
|
+
// can be forwarded correctly, but without copying the fingerprint or similar, so we can still
|
|
352
|
+
// act as a MitM to intercept the packets:
|
|
353
|
+
targetMedia.msid = sourceMedia.msid;
|
|
354
|
+
targetMedia.protocol = sourceMedia.protocol;
|
|
355
|
+
targetMedia.ext = sourceMedia.ext;
|
|
356
|
+
targetMedia.payloads = sourceMedia.payloads;
|
|
357
|
+
targetMedia.rtp = sourceMedia.rtp;
|
|
358
|
+
targetMedia.fmtp = sourceMedia.fmtp;
|
|
359
|
+
targetMedia.rtcp = sourceMedia.rtcp;
|
|
360
|
+
targetMedia.rtcpFb = sourceMedia.rtcpFb;
|
|
361
|
+
targetMedia.ssrcGroups = sourceMedia.ssrcGroups;
|
|
362
|
+
// SSRC info is especially important here: this is used to map RTP SSRCs to track mids, so if
|
|
363
|
+
// this is incorrect, the recipient track will not receive the data we're sending.
|
|
364
|
+
// Although in some cases we do already have some SSRC info here, for offers where we've already
|
|
365
|
+
// defined the tracks ourselves, libdatachannel doesn't support all params and it's best to copy
|
|
366
|
+
// the full definition itself directly to make sure they match:
|
|
367
|
+
targetMedia.ssrcs = sourceMedia.ssrcs;
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
//# sourceMappingURL=rtc-connection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rtc-connection.js","sourceRoot":"","sources":["../../src/webrtc/rtc-connection.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { MockRTCPeer } from "./mockrtc-peer";
|
|
2
|
+
/**
|
|
3
|
+
* Hooks a given RTCPeerConnection so that all connections it creates are automatically proxied
|
|
4
|
+
* through the given MockRTCPeer.
|
|
5
|
+
*
|
|
6
|
+
* This allows you to capture traffic without modifying your WebRTC code: you can create
|
|
7
|
+
* offers/answers and signal them to a remote client as normal, and both the local and remote
|
|
8
|
+
* connections will connect to MockRTC instead.
|
|
9
|
+
*
|
|
10
|
+
* What happens once they connect depends on the configuration of the given peer. This mocked
|
|
11
|
+
* local connection will follow the steps defined by the peer, so may receive mocked messages
|
|
12
|
+
* injected there, or delays, or anything else. The remote peer will receive nothing until
|
|
13
|
+
* a proxy step is reached (if ever), at which point the local & remote peers will be able to
|
|
14
|
+
* talking directly, although all traffic will still be proxied through MockRTC for logging
|
|
15
|
+
* and analysis/validation elsewhere.
|
|
16
|
+
*
|
|
17
|
+
* It is possible to proxy both real peers in a connection, potentially with different mock
|
|
18
|
+
* peers so that they experience different behaviours during the connection.
|
|
19
|
+
*
|
|
20
|
+
* @category API
|
|
21
|
+
*/
|
|
22
|
+
export declare function hookWebRTCConnection(conn: RTCPeerConnection, mockPeer: MockRTCPeer): void;
|
|
23
|
+
/**
|
|
24
|
+
* Modifies the global RTCPeerConnection constructor to hook all WebRTC connections
|
|
25
|
+
* created after this function is called, and redirect all their traffic to the
|
|
26
|
+
* provided MockRTCPeer.
|
|
27
|
+
*
|
|
28
|
+
* @category API
|
|
29
|
+
*/
|
|
30
|
+
export declare function hookAllWebRTC(mockPeer: MockRTCPeer): void;
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* SPDX-FileCopyrightText: 2022 Tim Perry <tim@httptoolkit.tech>
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
7
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
8
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
9
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
10
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
11
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
12
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
13
|
+
});
|
|
14
|
+
};
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.hookAllWebRTC = exports.hookWebRTCConnection = void 0;
|
|
17
|
+
const control_channel_1 = require("./webrtc/control-channel");
|
|
18
|
+
/*
|
|
19
|
+
* In this file, we define hooks which can automatically wrap an RTCPeerConnection so that the
|
|
20
|
+
* normal calls to initialize a connection instead proxy the connection through MockRTC.
|
|
21
|
+
*
|
|
22
|
+
* This is quite complicated and confusing! There's four connection endpoints to be aware of:
|
|
23
|
+
* - The original RTCPeerConnection that's being hooked here to connect to a mock ('internal')
|
|
24
|
+
* - A MockRTC connection with an associated MockRTCPeer that it will actually connect to ('mock')
|
|
25
|
+
* - The original remote peer that we're connecting to ('remote')
|
|
26
|
+
* - A MockRTC external connection that will connect to the remote peer ('external')
|
|
27
|
+
*
|
|
28
|
+
* The connection structure works like so:
|
|
29
|
+
* INTERNAL <--> MOCK <-?-> EXTERNAL <--> REMOTE
|
|
30
|
+
*
|
|
31
|
+
* Internal+Mock and External+Remote are connected via real WebRTC connections. Mock+External are
|
|
32
|
+
* connected within MockRTC once mockConnection.proxyTrafficTo(externalConnection) is called,
|
|
33
|
+
* which happens if/when a proxy step is reached (i.e. this depends on the configuration of the
|
|
34
|
+
* mock peer).
|
|
35
|
+
*
|
|
36
|
+
* Note that in extra complicated cases, both peers might be hooked, in which case REMOTE is
|
|
37
|
+
* actually the EXTERNAL for a second mirrored structure. We can mostly ignore this as it's
|
|
38
|
+
* handled implicitly.
|
|
39
|
+
*/
|
|
40
|
+
/**
|
|
41
|
+
* Hooks a given RTCPeerConnection so that all connections it creates are automatically proxied
|
|
42
|
+
* through the given MockRTCPeer.
|
|
43
|
+
*
|
|
44
|
+
* This allows you to capture traffic without modifying your WebRTC code: you can create
|
|
45
|
+
* offers/answers and signal them to a remote client as normal, and both the local and remote
|
|
46
|
+
* connections will connect to MockRTC instead.
|
|
47
|
+
*
|
|
48
|
+
* What happens once they connect depends on the configuration of the given peer. This mocked
|
|
49
|
+
* local connection will follow the steps defined by the peer, so may receive mocked messages
|
|
50
|
+
* injected there, or delays, or anything else. The remote peer will receive nothing until
|
|
51
|
+
* a proxy step is reached (if ever), at which point the local & remote peers will be able to
|
|
52
|
+
* talking directly, although all traffic will still be proxied through MockRTC for logging
|
|
53
|
+
* and analysis/validation elsewhere.
|
|
54
|
+
*
|
|
55
|
+
* It is possible to proxy both real peers in a connection, potentially with different mock
|
|
56
|
+
* peers so that they experience different behaviours during the connection.
|
|
57
|
+
*
|
|
58
|
+
* @category API
|
|
59
|
+
*/
|
|
60
|
+
function hookWebRTCConnection(conn, mockPeer) {
|
|
61
|
+
// Anything that creates signalling data (createOffer/createAnswer) needs to be hooked to
|
|
62
|
+
// return the params for the external connected.
|
|
63
|
+
// Anything that sets params (setLocal/RemoteDescription) needs to be hooked to send those
|
|
64
|
+
// params to the external connection, create new equivalent mock params for the mock connection
|
|
65
|
+
// and give those to the internal connection.
|
|
66
|
+
const _createOffer = conn.createOffer.bind(conn);
|
|
67
|
+
const _createAnswer = conn.createAnswer.bind(conn);
|
|
68
|
+
const _setLocalDescription = conn.setLocalDescription.bind(conn);
|
|
69
|
+
const _setRemoteDescription = conn.setRemoteDescription.bind(conn);
|
|
70
|
+
// The offers/answers we've generated, and the params needed to use them later:
|
|
71
|
+
let pendingCreatedOffers = {};
|
|
72
|
+
let pendingCreatedAnswers = {};
|
|
73
|
+
// The offer/answer we generated that we're actually using, once one is selected:
|
|
74
|
+
let selectedDescription;
|
|
75
|
+
// A mirrored offer from the mock conn to the internal conn, mirroring an incoming offer we
|
|
76
|
+
// received from the remote conn. This is stored so that when we pick an answer it can be
|
|
77
|
+
// completed, and so that createAnswer can wait until generation is complete before running.
|
|
78
|
+
let mockOffer;
|
|
79
|
+
// We create a control channel to communicate with MockRTC once the connection is set up.
|
|
80
|
+
// That's created immediately, so its in the initial SDP, to avoid later negotation.
|
|
81
|
+
const controlChannel = conn.createDataChannel(control_channel_1.MOCKRTC_CONTROL_CHANNEL);
|
|
82
|
+
new Promise((resolve) => {
|
|
83
|
+
controlChannel.onopen = () => resolve();
|
|
84
|
+
}).then(() => {
|
|
85
|
+
controlChannel.send(JSON.stringify({
|
|
86
|
+
type: 'attach-external',
|
|
87
|
+
id: selectedDescription.id
|
|
88
|
+
}));
|
|
89
|
+
});
|
|
90
|
+
conn.createOffer = ((options) => __awaiter(this, void 0, void 0, function* () {
|
|
91
|
+
const realOffer = yield _createOffer(options);
|
|
92
|
+
const externalOfferParams = yield mockPeer.createExternalOffer({
|
|
93
|
+
mirrorSDP: realOffer.sdp
|
|
94
|
+
});
|
|
95
|
+
const externalOffer = externalOfferParams.offer;
|
|
96
|
+
pendingCreatedOffers[externalOffer.sdp] = Object.assign(Object.assign({}, externalOfferParams), { realOffer });
|
|
97
|
+
return externalOffer;
|
|
98
|
+
}));
|
|
99
|
+
conn.createAnswer = ((options) => __awaiter(this, void 0, void 0, function* () {
|
|
100
|
+
yield mockOffer; // If we have a pending offer, wait for that first - we can't answer without it.
|
|
101
|
+
const realAnswer = yield _createAnswer(options);
|
|
102
|
+
const pendingAnswerParams = yield mockPeer.answerExternalOffer(conn.pendingRemoteDescription, {
|
|
103
|
+
mirrorSDP: realAnswer.sdp
|
|
104
|
+
});
|
|
105
|
+
const externalAnswer = pendingAnswerParams.answer;
|
|
106
|
+
pendingCreatedAnswers[externalAnswer.sdp] = Object.assign(Object.assign({}, pendingAnswerParams), { realAnswer });
|
|
107
|
+
return externalAnswer;
|
|
108
|
+
}));
|
|
109
|
+
// Mock all mutations of the connection description:
|
|
110
|
+
conn.setLocalDescription = ((localDescription) => __awaiter(this, void 0, void 0, function* () {
|
|
111
|
+
if (!localDescription) {
|
|
112
|
+
if (["stable", "have-local-offer", "have-remote-pranswer"].includes(conn.signalingState)) {
|
|
113
|
+
localDescription = yield conn.createOffer();
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
localDescription = yield conn.createAnswer();
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// When we set an offer or answer locally, it must be the external offer/answer we've
|
|
120
|
+
// generated to send to the other peer. We swap it back for a real equivalent that will
|
|
121
|
+
// connect us to the mock peer instead:
|
|
122
|
+
if (localDescription.type === 'offer') {
|
|
123
|
+
pendingLocalDescription = localDescription;
|
|
124
|
+
selectedDescription = pendingCreatedOffers[localDescription.sdp];
|
|
125
|
+
const { realOffer } = selectedDescription;
|
|
126
|
+
yield _setLocalDescription(realOffer);
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
selectedDescription = pendingCreatedAnswers[localDescription.sdp];
|
|
130
|
+
const { realAnswer } = selectedDescription;
|
|
131
|
+
yield Promise.all([
|
|
132
|
+
// Complete the mock side of the internal connection:
|
|
133
|
+
(yield mockOffer).setAnswer(realAnswer),
|
|
134
|
+
// Complete the internal side of the internal connection:
|
|
135
|
+
_setLocalDescription(realAnswer)
|
|
136
|
+
]);
|
|
137
|
+
currentLocalDescription = localDescription;
|
|
138
|
+
currentRemoteDescription = pendingRemoteDescription;
|
|
139
|
+
pendingLocalDescription = null;
|
|
140
|
+
pendingRemoteDescription = null;
|
|
141
|
+
}
|
|
142
|
+
}));
|
|
143
|
+
conn.setRemoteDescription = ((remoteDescription) => __awaiter(this, void 0, void 0, function* () {
|
|
144
|
+
if (remoteDescription.type === 'offer') {
|
|
145
|
+
// We have an offer! Remember it, so we can createAnswer shortly.
|
|
146
|
+
pendingRemoteDescription = remoteDescription;
|
|
147
|
+
// We persist the mock offer synchronously, so we can check for it in createAnswer
|
|
148
|
+
// and avoid race conditions where we fail to create an answer before this method
|
|
149
|
+
// hasn't yet completed.
|
|
150
|
+
mockOffer = mockPeer.createOffer({
|
|
151
|
+
mirrorSDP: remoteDescription.sdp,
|
|
152
|
+
addDataStream: true
|
|
153
|
+
});
|
|
154
|
+
yield _setRemoteDescription((yield mockOffer).offer);
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
// We have an answer - we must've sent an offer, complete & use that:
|
|
158
|
+
const { setAnswer, realOffer } = selectedDescription;
|
|
159
|
+
yield Promise.all([
|
|
160
|
+
// Complete the external <-> remote connection:
|
|
161
|
+
setAnswer(remoteDescription),
|
|
162
|
+
// Complete the internal <-> mock connection:
|
|
163
|
+
mockPeer.answerOffer(realOffer, {
|
|
164
|
+
mirrorSDP: remoteDescription.sdp
|
|
165
|
+
}).then(({ answer }) => _setRemoteDescription(answer))
|
|
166
|
+
]);
|
|
167
|
+
currentLocalDescription = pendingLocalDescription;
|
|
168
|
+
currentRemoteDescription = remoteDescription;
|
|
169
|
+
pendingLocalDescription = null;
|
|
170
|
+
pendingRemoteDescription = null;
|
|
171
|
+
}
|
|
172
|
+
}));
|
|
173
|
+
// Mock various props that expose the connection description:
|
|
174
|
+
let pendingLocalDescription = null;
|
|
175
|
+
Object.defineProperty(conn, 'pendingLocalDescription', {
|
|
176
|
+
get: () => pendingLocalDescription
|
|
177
|
+
});
|
|
178
|
+
let currentLocalDescription = null;
|
|
179
|
+
Object.defineProperty(conn, 'currentLocalDescription', {
|
|
180
|
+
get: () => currentLocalDescription
|
|
181
|
+
});
|
|
182
|
+
Object.defineProperty(conn, 'localDescription', {
|
|
183
|
+
get: () => { var _a; return (_a = conn.pendingLocalDescription) !== null && _a !== void 0 ? _a : conn.currentLocalDescription; }
|
|
184
|
+
});
|
|
185
|
+
let pendingRemoteDescription = null;
|
|
186
|
+
Object.defineProperty(conn, 'pendingRemoteDescription', {
|
|
187
|
+
get: () => pendingRemoteDescription
|
|
188
|
+
});
|
|
189
|
+
let currentRemoteDescription = null;
|
|
190
|
+
Object.defineProperty(conn, 'currentRemoteDescription', {
|
|
191
|
+
get: () => currentRemoteDescription
|
|
192
|
+
});
|
|
193
|
+
Object.defineProperty(conn, 'remoteDescription', {
|
|
194
|
+
get: () => { var _a; return (_a = conn.pendingRemoteDescription) !== null && _a !== void 0 ? _a : conn.currentRemoteDescription; }
|
|
195
|
+
});
|
|
196
|
+
Object.defineProperty(conn, 'onicecandidate', {
|
|
197
|
+
get: () => { },
|
|
198
|
+
set: () => { } // Ignore this completely - never call the callback
|
|
199
|
+
});
|
|
200
|
+
// For now we ignore incoming ice candidates. They're really intended for the external connection,
|
|
201
|
+
// not us, but also they're rarely necessary since we should be using local connections and MockRTC
|
|
202
|
+
// itself always waits rather than trickling candidates.
|
|
203
|
+
conn.addIceCandidate = () => Promise.resolve();
|
|
204
|
+
}
|
|
205
|
+
exports.hookWebRTCConnection = hookWebRTCConnection;
|
|
206
|
+
/**
|
|
207
|
+
* Modifies the global RTCPeerConnection constructor to hook all WebRTC connections
|
|
208
|
+
* created after this function is called, and redirect all their traffic to the
|
|
209
|
+
* provided MockRTCPeer.
|
|
210
|
+
*
|
|
211
|
+
* @category API
|
|
212
|
+
*/
|
|
213
|
+
function hookAllWebRTC(mockPeer) {
|
|
214
|
+
// The original constructor
|
|
215
|
+
const _RTCPeerConnection = window.RTCPeerConnection;
|
|
216
|
+
window.RTCPeerConnection = function () {
|
|
217
|
+
const connection = new _RTCPeerConnection(...arguments);
|
|
218
|
+
hookWebRTCConnection(connection, mockPeer);
|
|
219
|
+
return connection;
|
|
220
|
+
};
|
|
221
|
+
window.RTCPeerConnection.prototype = _RTCPeerConnection.prototype;
|
|
222
|
+
}
|
|
223
|
+
exports.hookAllWebRTC = hookAllWebRTC;
|
|
224
|
+
//# sourceMappingURL=webrtc-hooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webrtc-hooks.js","sourceRoot":"","sources":["../src/webrtc-hooks.ts"],"names":[],"mappings":"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"}
|