-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
245 lines (209 loc) · 5.89 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
import {ok} from 'node:assert/strict'
import EventEmitter from 'node:events'
import mediasoupGetStatsFactory from '@mafalda-sfu/mediasoup-getstats-factory'
import mediasoup from 'mediasoup'
/**
* @see
* {@link
* https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/readyState#value}
*/
const OPEN = 1
/**
* @see
* {@link
* https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/readyState#value}
*/
const CLOSED = 3
/**
* Additional state to the WebSocket connection
* [readyState]{@link
* https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/readyState#value}
* property to indicate that the
* [Remote Mediasoup server]{@link https://mafalda.io/Remote-Mediasoup-server/}
* payload with its internal state has been received and sync'ed, and so the
* `Remote Mediasoup` connection has been fully established.
*
* @type {number}
*
* @constant
*
* @default
*/
const CONNECTED = 4
/**
* @summary Remote Mediasoup client mock class
*
* @class RemoteMediasoupClientMock
*
* @augments {EventEmitter}
*
* @date 30/04/2023
*
* @see
* {@link https://mafalda.io/Remote-Mediasoup-client/API#RemoteMediasoupClient
* Remote Mediasoup client}
*
* @export
*
* @author Jesús Leganés-Combarro 'piranna' <piranna@gmail.com>
*/
export default class RemoteMediasoupClientMock extends EventEmitter
{
/**
* @summary Creates an instance of {@link RemoteMediasoupClientMock}.
*
* @class
*
* @memberof RemoteMediasoupClientMock
*
* @param {string|object} [url] URL of the
* [Remote Mediasoup server](https://mafalda.io/Remote-Mediasoup-server/). If
* it's not provided, the {@link RemoteMediasoupClientMock} object will remain
* in closed state.
* @param {object} [WebSocket] WebSocket class to be used to create the
* connections with the
* [Remote Mediasoup server](https://mafalda.io/Remote-Mediasoup-server/)
*
* @date 30/04/2023
*
* @author Jesús Leganés-Combarro 'piranna' <piranna@gmail.com>
*/
constructor(url, WebSocket)
{
if(url && typeof url !== 'string') ({WebSocket, url} = url)
// eslint-disable-next-line no-console
if(WebSocket) console.debug('Websocket class not used in mock')
super()
if(url) this.open(url)
}
//
// Remote Mediasoup common interface
//
/**
* This object is API compatible with the
* [Mediasoup API](https://mediasoup.org/documentation/v3/mediasoup/api/)
* provided by the
* [`Mediasoup` package](https://www.npmjs.com/package/mediasoup).
*
* @summary Get a reference to the `mediasoup` package exported object.
*
* @readonly
* @memberof RemoteMediasoupClientMock
*
* @date 30/04/2023
*
* @see {@link https://mediasoup.org/documentation/v3/mediasoup/api/}
*
* @author Jesús Leganés-Combarro 'piranna' <piranna@gmail.com>
*/
get mediasoup()
{
return this.#connected ? mediasoup : undefined
}
/**
* In addition of the states defined for the WebSocket connection
* [readyState]{@link
* https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/readyState#value}
* property, this property can have a ['connected' state]{@link CONNECTED}
* to indicate that the
* [Remote Mediasoup server](https://mafalda.io/Remote-Mediasoup-server/)
* payload with its internal state has been received and sync'ed, and so the
* `Remote Mediasoup` connection has been fully established.
*
* @summary Get the current `readyState` of the client.
*
* @readonly
* @memberof RemoteMediasoupClientMock
*
* @date 30/04/2023
*
* @see
* {@link
* https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/readyState}
*
* @author Jesús Leganés-Combarro 'piranna' <piranna@gmail.com>
*/
get readyState()
{
if(this.#connected) return CONNECTED
return this.#closed ? CLOSED : OPEN
}
getStats = async () =>
{
ok(this.#mediasoupGetStats, 'Remote Mediasoup client is not connected')
return this.#mediasoupGetStats.getStats()
}
//
// Remote Mediasoup client API
//
/**
* If it's already closed, this method does nothing
*
* @summary Close the client.
*
* @memberof RemoteMediasoupClientMock
*
* @date 30/04/2023
*
* @author Jesús Leganés-Combarro 'piranna' <piranna@gmail.com>
*/
close()
{
if(this.#closed) return
this.#closed = true
this.#connected = false
this.#mediasoupGetStats.close()
this.#mediasoupGetStats = undefined
// Notify client is closed
this.emit('close')
// We don't emit the 'disconnected' and `websocketClose` events because it's
// us who are closing the client, not the server
}
/**
* If it's already open, it will throw an exception
*
* @summary Open the client to the given URL.
*
* @memberof RemoteMediasoupClientMock
*
* @param {string} [url] URL of the
* [Remote Mediasoup server](https://mafalda.io/Remote-Mediasoup-server/). If
* not provided, it will re-open the connection to the last provided URL, and
* if was not provided, it will throw an exception
*
* @returns {RemoteMediasoupClientMock}
*
* @date 30/04/2023
*
* @author Jesús Leganés-Combarro 'piranna' <piranna@gmail.com>
*/
open(url)
{
ok(this.#closed, `${this.constructor.name} is already open(ing)`)
// If `url` argument is not provided, allow to reopen the client to the same
// previous URL by default
url ??= this.#url
ok(url, 'url not defined')
setImmediate(this.#onOpen)
setImmediate(this.#onWebsocketOpen)
setImmediate(this.#onConnected)
this.#closed = false
this.#url = url
return this
}
//
// Private API
//
#closed = true
#connected = false
#mediasoupGetStats
#url
#onConnected = () =>
{
this.#connected = true
this.#mediasoupGetStats = mediasoupGetStatsFactory(mediasoup)
this.emit('connected')
}
#onOpen = this.emit.bind(this, 'open')
#onWebsocketOpen = this.emit.bind(this, 'websocketOpen')
}