@observertc/observer-js 0.9.27-beta → 0.30.0-beta

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.
Files changed (298) hide show
  1. package/lib/ObservedCall.d.ts +54 -0
  2. package/lib/ObservedCall.d.ts.map +1 -0
  3. package/lib/ObservedCall.js +166 -0
  4. package/lib/ObservedClient.d.ts +73 -0
  5. package/lib/ObservedClient.d.ts.map +1 -0
  6. package/lib/ObservedClient.js +487 -0
  7. package/lib/ObservedInboundTrack.d.ts +65 -0
  8. package/lib/ObservedInboundTrack.d.ts.map +1 -0
  9. package/lib/ObservedInboundTrack.js +192 -0
  10. package/lib/ObservedOutboundTrack.d.ts +55 -0
  11. package/lib/ObservedOutboundTrack.d.ts.map +1 -0
  12. package/lib/ObservedOutboundTrack.js +166 -0
  13. package/lib/ObservedPeerConnection.d.ts +57 -0
  14. package/lib/ObservedPeerConnection.d.ts.map +1 -0
  15. package/lib/ObservedPeerConnection.js +217 -0
  16. package/lib/Observer.d.ts +26 -1465
  17. package/lib/Observer.d.ts.map +1 -1
  18. package/lib/Observer.js +53 -605
  19. package/lib/{sinks/ObserverSink.d.ts → ReportsCollector.d.ts} +7 -23
  20. package/lib/ReportsCollector.d.ts.map +1 -0
  21. package/lib/{sinks/ObserverSink.js → ReportsCollector.js} +27 -85
  22. package/lib/common/ReportsCollector.d.ts +21 -24
  23. package/lib/common/ReportsCollector.d.ts.map +1 -1
  24. package/lib/common/ReportsCollector.js +24 -0
  25. package/lib/common/SingleExecutor.d.ts +3 -0
  26. package/lib/common/SingleExecutor.d.ts.map +1 -0
  27. package/lib/common/SingleExecutor.js +31 -0
  28. package/lib/common/TypedEventEmitter.d.ts +22 -0
  29. package/lib/common/TypedEventEmitter.d.ts.map +1 -0
  30. package/lib/common/TypedEventEmitter.js +11 -0
  31. package/lib/common/callEventReports.d.ts.map +1 -0
  32. package/lib/common/logger.d.ts +3 -9
  33. package/lib/common/logger.d.ts.map +1 -1
  34. package/lib/common/logger.js +58 -141
  35. package/lib/common/types.d.ts +2 -14
  36. package/lib/common/types.d.ts.map +1 -1
  37. package/lib/common/utils.d.ts +1 -0
  38. package/lib/common/utils.d.ts.map +1 -1
  39. package/lib/common/utils.js +6 -1
  40. package/lib/index.d.ts +8 -19
  41. package/lib/index.d.ts.map +1 -1
  42. package/lib/index.js +7 -2
  43. package/package.json +1 -1
  44. package/src/ObservedCall.ts +201 -0
  45. package/src/ObservedClient.ts +681 -0
  46. package/src/ObservedInboundTrack.ts +238 -0
  47. package/src/ObservedOutboundTrack.ts +205 -0
  48. package/src/ObservedPeerConnection.ts +249 -0
  49. package/src/Observer.ts +86 -442
  50. package/src/{sinks/ObserverSink.ts → ReportsCollector.ts} +29 -94
  51. package/src/common/ReportsCollector.ts +48 -23
  52. package/src/common/SingleExecutor.ts +36 -0
  53. package/src/common/TypedEventEmitter.ts +32 -0
  54. package/src/common/logger.ts +58 -161
  55. package/src/common/types.ts +4 -24
  56. package/src/common/utils.ts +6 -0
  57. package/src/index.ts +12 -23
  58. package/lib/Evaluator.d.ts +0 -43
  59. package/lib/Evaluator.d.ts.map +0 -1
  60. package/lib/Evaluator.js +0 -171
  61. package/lib/common/Semaphore.d.ts +0 -31
  62. package/lib/common/Semaphore.d.ts.map +0 -1
  63. package/lib/common/Semaphore.js +0 -16
  64. package/lib/entries/CallEntry.d.ts +0 -619
  65. package/lib/entries/CallEntry.d.ts.map +0 -1
  66. package/lib/entries/CallEntry.js +0 -75
  67. package/lib/entries/ClientEntry.d.ts +0 -478
  68. package/lib/entries/ClientEntry.d.ts.map +0 -1
  69. package/lib/entries/ClientEntry.js +0 -114
  70. package/lib/entries/InboundTrackEntry.d.ts +0 -682
  71. package/lib/entries/InboundTrackEntry.d.ts.map +0 -1
  72. package/lib/entries/InboundTrackEntry.js +0 -76
  73. package/lib/entries/OutboundTrackEntry.d.ts +0 -682
  74. package/lib/entries/OutboundTrackEntry.d.ts.map +0 -1
  75. package/lib/entries/OutboundTrackEntry.js +0 -73
  76. package/lib/entries/PeerConnectionEntry.d.ts +0 -505
  77. package/lib/entries/PeerConnectionEntry.d.ts.map +0 -1
  78. package/lib/entries/PeerConnectionEntry.js +0 -144
  79. package/lib/entries/SfuEntry.d.ts +0 -150
  80. package/lib/entries/SfuEntry.d.ts.map +0 -1
  81. package/lib/entries/SfuEntry.js +0 -77
  82. package/lib/entries/SfuInboundRtpPadEntry.d.ts +0 -14
  83. package/lib/entries/SfuInboundRtpPadEntry.d.ts.map +0 -1
  84. package/lib/entries/SfuInboundRtpPadEntry.js +0 -49
  85. package/lib/entries/SfuOutboundRtpPadEntry.d.ts +0 -14
  86. package/lib/entries/SfuOutboundRtpPadEntry.d.ts.map +0 -1
  87. package/lib/entries/SfuOutboundRtpPadEntry.js +0 -47
  88. package/lib/entries/SfuSctpChannelEntry.d.ts +0 -12
  89. package/lib/entries/SfuSctpChannelEntry.d.ts.map +0 -1
  90. package/lib/entries/SfuSctpChannelEntry.js +0 -43
  91. package/lib/entries/SfuTransportEntry.d.ts +0 -82
  92. package/lib/entries/SfuTransportEntry.d.ts.map +0 -1
  93. package/lib/entries/SfuTransportEntry.js +0 -122
  94. package/lib/evaluators/SetClientsCoordinateEvaluator.d.ts +0 -9
  95. package/lib/evaluators/SetClientsCoordinateEvaluator.d.ts.map +0 -1
  96. package/lib/evaluators/SetClientsCoordinateEvaluator.js +0 -95
  97. package/lib/middlewares/CallOperationsContext.d.ts +0 -18
  98. package/lib/middlewares/CallOperationsContext.d.ts.map +0 -1
  99. package/lib/middlewares/CallOperationsContext.js +0 -27
  100. package/lib/middlewares/CallProcessor.d.ts +0 -6
  101. package/lib/middlewares/CallProcessor.d.ts.map +0 -1
  102. package/lib/middlewares/CallProcessor.js +0 -36
  103. package/lib/middlewares/CommitTransactionMiddleware.d.ts +0 -6
  104. package/lib/middlewares/CommitTransactionMiddleware.d.ts.map +0 -1
  105. package/lib/middlewares/CommitTransactionMiddleware.js +0 -179
  106. package/lib/middlewares/DeleteOutdatedCallEntries.d.ts +0 -6
  107. package/lib/middlewares/DeleteOutdatedCallEntries.d.ts.map +0 -1
  108. package/lib/middlewares/DeleteOutdatedCallEntries.js +0 -121
  109. package/lib/middlewares/DeleteOutdatedSfuEntries.d.ts +0 -6
  110. package/lib/middlewares/DeleteOutdatedSfuEntries.d.ts.map +0 -1
  111. package/lib/middlewares/DeleteOutdatedSfuEntries.js +0 -127
  112. package/lib/middlewares/Middleware.d.ts +0 -3
  113. package/lib/middlewares/Middleware.d.ts.map +0 -1
  114. package/lib/middlewares/Middleware.js +0 -21
  115. package/lib/middlewares/Processor.d.ts +0 -9
  116. package/lib/middlewares/Processor.d.ts.map +0 -1
  117. package/lib/middlewares/Processor.js +0 -54
  118. package/lib/middlewares/TransactionContext.d.ts +0 -35
  119. package/lib/middlewares/TransactionContext.d.ts.map +0 -1
  120. package/lib/middlewares/TransactionContext.js +0 -90
  121. package/lib/middlewares/TransactoinProcessor.d.ts +0 -6
  122. package/lib/middlewares/TransactoinProcessor.d.ts.map +0 -1
  123. package/lib/middlewares/TransactoinProcessor.js +0 -17
  124. package/lib/middlewares/VisitObservedCallsMiddleware.d.ts +0 -7
  125. package/lib/middlewares/VisitObservedCallsMiddleware.d.ts.map +0 -1
  126. package/lib/middlewares/VisitObservedCallsMiddleware.js +0 -96
  127. package/lib/middlewares/VisitObservedSfusMiddleware.d.ts +0 -6
  128. package/lib/middlewares/VisitObservedSfusMiddleware.d.ts.map +0 -1
  129. package/lib/middlewares/VisitObservedSfusMiddleware.js +0 -151
  130. package/lib/middlewares/visitors/visitClient.d.ts +0 -5
  131. package/lib/middlewares/visitors/visitClient.d.ts.map +0 -1
  132. package/lib/middlewares/visitors/visitClient.js +0 -174
  133. package/lib/middlewares/visitors/visitInboundAudioTrack.d.ts +0 -5
  134. package/lib/middlewares/visitors/visitInboundAudioTrack.d.ts.map +0 -1
  135. package/lib/middlewares/visitors/visitInboundAudioTrack.js +0 -93
  136. package/lib/middlewares/visitors/visitInboundVideoTrack.d.ts +0 -5
  137. package/lib/middlewares/visitors/visitInboundVideoTrack.d.ts.map +0 -1
  138. package/lib/middlewares/visitors/visitInboundVideoTrack.js +0 -94
  139. package/lib/middlewares/visitors/visitOutboundAudioTrack.d.ts +0 -5
  140. package/lib/middlewares/visitors/visitOutboundAudioTrack.d.ts.map +0 -1
  141. package/lib/middlewares/visitors/visitOutboundAudioTrack.js +0 -90
  142. package/lib/middlewares/visitors/visitOutboundVideoTarck.d.ts +0 -5
  143. package/lib/middlewares/visitors/visitOutboundVideoTarck.d.ts.map +0 -1
  144. package/lib/middlewares/visitors/visitOutboundVideoTarck.js +0 -90
  145. package/lib/middlewares/visitors/visitPeerConnection.d.ts +0 -5
  146. package/lib/middlewares/visitors/visitPeerConnection.d.ts.map +0 -1
  147. package/lib/middlewares/visitors/visitPeerConnection.js +0 -111
  148. package/lib/middlewares/visitors/visitSfu.d.ts +0 -5
  149. package/lib/middlewares/visitors/visitSfu.d.ts.map +0 -1
  150. package/lib/middlewares/visitors/visitSfu.js +0 -78
  151. package/lib/middlewares/visitors/visitSfuInboundRtpPad.d.ts +0 -5
  152. package/lib/middlewares/visitors/visitSfuInboundRtpPad.d.ts.map +0 -1
  153. package/lib/middlewares/visitors/visitSfuInboundRtpPad.js +0 -56
  154. package/lib/middlewares/visitors/visitSfuOutboundRtpPad.d.ts +0 -5
  155. package/lib/middlewares/visitors/visitSfuOutboundRtpPad.d.ts.map +0 -1
  156. package/lib/middlewares/visitors/visitSfuOutboundRtpPad.js +0 -56
  157. package/lib/middlewares/visitors/visitSfuSctpChannel.d.ts +0 -5
  158. package/lib/middlewares/visitors/visitSfuSctpChannel.d.ts.map +0 -1
  159. package/lib/middlewares/visitors/visitSfuSctpChannel.js +0 -55
  160. package/lib/middlewares/visitors/visitSfuTransport.d.ts +0 -5
  161. package/lib/middlewares/visitors/visitSfuTransport.d.ts.map +0 -1
  162. package/lib/middlewares/visitors/visitSfuTransport.js +0 -56
  163. package/lib/processes/closePeerConnectionProcess.d.ts +0 -10
  164. package/lib/processes/closePeerConnectionProcess.d.ts.map +0 -1
  165. package/lib/processes/closePeerConnectionProcess.js +0 -51
  166. package/lib/processes/detachClientProcess.d.ts +0 -14
  167. package/lib/processes/detachClientProcess.d.ts.map +0 -1
  168. package/lib/processes/detachClientProcess.js +0 -106
  169. package/lib/processes/findRemoteMatches.d.ts +0 -9
  170. package/lib/processes/findRemoteMatches.d.ts.map +0 -1
  171. package/lib/processes/findRemoteMatches.js +0 -96
  172. package/lib/processes/inboundTrackRemoved.d.ts +0 -9
  173. package/lib/processes/inboundTrackRemoved.d.ts.map +0 -1
  174. package/lib/processes/inboundTrackRemoved.js +0 -22
  175. package/lib/processes/joinClientProcess.d.ts +0 -11
  176. package/lib/processes/joinClientProcess.d.ts.map +0 -1
  177. package/lib/processes/joinClientProcess.js +0 -120
  178. package/lib/processes/outboundTrackRemoved.d.ts +0 -9
  179. package/lib/processes/outboundTrackRemoved.d.ts.map +0 -1
  180. package/lib/processes/outboundTrackRemoved.js +0 -22
  181. package/lib/samples/ObservedCall.d.ts +0 -17
  182. package/lib/samples/ObservedCall.d.ts.map +0 -1
  183. package/lib/samples/ObservedCall.js +0 -29
  184. package/lib/samples/ObservedCalls.d.ts +0 -19
  185. package/lib/samples/ObservedCalls.d.ts.map +0 -1
  186. package/lib/samples/ObservedCalls.js +0 -113
  187. package/lib/samples/ObservedClient.d.ts +0 -28
  188. package/lib/samples/ObservedClient.d.ts.map +0 -1
  189. package/lib/samples/ObservedClient.js +0 -110
  190. package/lib/samples/ObservedInboundAudioTrack.d.ts +0 -17
  191. package/lib/samples/ObservedInboundAudioTrack.d.ts.map +0 -1
  192. package/lib/samples/ObservedInboundAudioTrack.js +0 -17
  193. package/lib/samples/ObservedInboundVideoTrack.d.ts +0 -17
  194. package/lib/samples/ObservedInboundVideoTrack.d.ts.map +0 -1
  195. package/lib/samples/ObservedInboundVideoTrack.js +0 -17
  196. package/lib/samples/ObservedOutboundAudioTrack.d.ts +0 -16
  197. package/lib/samples/ObservedOutboundAudioTrack.d.ts.map +0 -1
  198. package/lib/samples/ObservedOutboundAudioTrack.js +0 -17
  199. package/lib/samples/ObservedOutboundVideoTrack.d.ts +0 -16
  200. package/lib/samples/ObservedOutboundVideoTrack.d.ts.map +0 -1
  201. package/lib/samples/ObservedOutboundVideoTrack.js +0 -17
  202. package/lib/samples/ObservedPeerConnection.d.ts +0 -47
  203. package/lib/samples/ObservedPeerConnection.d.ts.map +0 -1
  204. package/lib/samples/ObservedPeerConnection.js +0 -130
  205. package/lib/samples/ObservedSfu.d.ts +0 -27
  206. package/lib/samples/ObservedSfu.d.ts.map +0 -1
  207. package/lib/samples/ObservedSfu.js +0 -65
  208. package/lib/samples/ObservedSfuInboundRtpPad.d.ts +0 -15
  209. package/lib/samples/ObservedSfuInboundRtpPad.d.ts.map +0 -1
  210. package/lib/samples/ObservedSfuInboundRtpPad.js +0 -17
  211. package/lib/samples/ObservedSfuOutboundRtpPad.d.ts +0 -15
  212. package/lib/samples/ObservedSfuOutboundRtpPad.d.ts.map +0 -1
  213. package/lib/samples/ObservedSfuOutboundRtpPad.js +0 -17
  214. package/lib/samples/ObservedSfuSctpChannel.d.ts +0 -15
  215. package/lib/samples/ObservedSfuSctpChannel.d.ts.map +0 -1
  216. package/lib/samples/ObservedSfuSctpChannel.js +0 -17
  217. package/lib/samples/ObservedSfuTransport.d.ts +0 -30
  218. package/lib/samples/ObservedSfuTransport.d.ts.map +0 -1
  219. package/lib/samples/ObservedSfuTransport.js +0 -86
  220. package/lib/samples/ObservedSfus.d.ts +0 -16
  221. package/lib/samples/ObservedSfus.d.ts.map +0 -1
  222. package/lib/samples/ObservedSfus.js +0 -72
  223. package/lib/sinks/ObserverSink.d.ts.map +0 -1
  224. package/lib/sinks/callEventReports.d.ts.map +0 -1
  225. package/lib/sources/ObservedCallSource.d.ts +0 -18
  226. package/lib/sources/ObservedCallSource.d.ts.map +0 -1
  227. package/lib/sources/ObservedCallSource.js +0 -2
  228. package/lib/sources/ObservedClientSource.d.ts +0 -19
  229. package/lib/sources/ObservedClientSource.d.ts.map +0 -1
  230. package/lib/sources/ObservedClientSource.js +0 -2
  231. package/lib/sources/ObservedSfuSource.d.ts +0 -15
  232. package/lib/sources/ObservedSfuSource.d.ts.map +0 -1
  233. package/lib/sources/ObservedSfuSource.js +0 -2
  234. package/lib/sources/Sources.d.ts +0 -49
  235. package/lib/sources/Sources.d.ts.map +0 -1
  236. package/lib/sources/Sources.js +0 -213
  237. package/src/Evaluator.ts +0 -229
  238. package/src/common/Semaphore.ts +0 -45
  239. package/src/entries/CallEntry.ts +0 -62
  240. package/src/entries/ClientEntry.ts +0 -106
  241. package/src/entries/InboundTrackEntry.ts +0 -74
  242. package/src/entries/OutboundTrackEntry.ts +0 -72
  243. package/src/entries/PeerConnectionEntry.ts +0 -133
  244. package/src/entries/SfuEntry.ts +0 -62
  245. package/src/entries/SfuInboundRtpPadEntry.ts +0 -46
  246. package/src/entries/SfuOutboundRtpPadEntry.ts +0 -44
  247. package/src/entries/SfuSctpChannelEntry.ts +0 -39
  248. package/src/entries/SfuTransportEntry.ts +0 -109
  249. package/src/evaluators/SetClientsCoordinateEvaluator.ts +0 -78
  250. package/src/middlewares/CallOperationsContext.ts +0 -56
  251. package/src/middlewares/CallProcessor.ts +0 -38
  252. package/src/middlewares/CommitTransactionMiddleware.ts +0 -328
  253. package/src/middlewares/DeleteOutdatedCallEntries.ts +0 -159
  254. package/src/middlewares/DeleteOutdatedSfuEntries.ts +0 -168
  255. package/src/middlewares/Middleware.ts +0 -10
  256. package/src/middlewares/Processor.ts +0 -59
  257. package/src/middlewares/TransactionContext.ts +0 -176
  258. package/src/middlewares/TransactoinProcessor.ts +0 -28
  259. package/src/middlewares/VisitObservedCallsMiddleware.ts +0 -172
  260. package/src/middlewares/VisitObservedSfusMiddleware.ts +0 -203
  261. package/src/middlewares/visitors/visitClient.ts +0 -239
  262. package/src/middlewares/visitors/visitInboundAudioTrack.ts +0 -113
  263. package/src/middlewares/visitors/visitInboundVideoTrack.ts +0 -117
  264. package/src/middlewares/visitors/visitOutboundAudioTrack.ts +0 -100
  265. package/src/middlewares/visitors/visitOutboundVideoTarck.ts +0 -102
  266. package/src/middlewares/visitors/visitPeerConnection.ts +0 -151
  267. package/src/middlewares/visitors/visitSfu.ts +0 -70
  268. package/src/middlewares/visitors/visitSfuInboundRtpPad.ts +0 -52
  269. package/src/middlewares/visitors/visitSfuOutboundRtpPad.ts +0 -53
  270. package/src/middlewares/visitors/visitSfuSctpChannel.ts +0 -50
  271. package/src/middlewares/visitors/visitSfuTransport.ts +0 -50
  272. package/src/processes/closePeerConnectionProcess.ts +0 -54
  273. package/src/processes/detachClientProcess.ts +0 -136
  274. package/src/processes/findRemoteMatches.ts +0 -104
  275. package/src/processes/inboundTrackRemoved.ts +0 -22
  276. package/src/processes/joinClientProcess.ts +0 -138
  277. package/src/processes/outboundTrackRemoved.ts +0 -22
  278. package/src/samples/ObservedCall.ts +0 -49
  279. package/src/samples/ObservedCalls.ts +0 -143
  280. package/src/samples/ObservedClient.ts +0 -172
  281. package/src/samples/ObservedInboundAudioTrack.ts +0 -35
  282. package/src/samples/ObservedInboundVideoTrack.ts +0 -36
  283. package/src/samples/ObservedOutboundAudioTrack.ts +0 -35
  284. package/src/samples/ObservedOutboundVideoTrack.ts +0 -35
  285. package/src/samples/ObservedPeerConnection.ts +0 -227
  286. package/src/samples/ObservedSfu.ts +0 -115
  287. package/src/samples/ObservedSfuInboundRtpPad.ts +0 -35
  288. package/src/samples/ObservedSfuOutboundRtpPad.ts +0 -35
  289. package/src/samples/ObservedSfuSctpChannel.ts +0 -35
  290. package/src/samples/ObservedSfuTransport.ts +0 -142
  291. package/src/samples/ObservedSfus.ts +0 -95
  292. package/src/sources/ObservedCallSource.ts +0 -26
  293. package/src/sources/ObservedClientSource.ts +0 -28
  294. package/src/sources/ObservedSfuSource.ts +0 -19
  295. package/src/sources/Sources.ts +0 -301
  296. /package/lib/{sinks → common}/callEventReports.d.ts +0 -0
  297. /package/lib/{sinks → common}/callEventReports.js +0 -0
  298. /package/src/{sinks → common}/callEventReports.ts +0 -0
@@ -0,0 +1,681 @@
1
+ import { ClientSample, IceLocalCandidate } from '@observertc/sample-schemas-js';
2
+ import { ObservedCall } from './ObservedCall';
3
+ import * as Models from './models/Models';
4
+ import { StorageProvider } from './storages/StorageProvider';
5
+ import { EventEmitter } from 'events';
6
+ import { createSingleExecutor } from './common/SingleExecutor';
7
+ import { ObservedPeerConnection } from './ObservedPeerConnection';
8
+ import { createLogger } from './common/logger';
9
+ import { CallMetaType, createCallMetaReport } from './common/callMetaReports';
10
+ // eslint-disable-next-line camelcase
11
+ import { Samples_ClientSample_Browser, Samples_ClientSample_Engine, Samples_ClientSample_OperationSystem, Samples_ClientSample_Platform } from './models/samples_pb';
12
+ import { IceCandidatePairReport } from '@observertc/report-schemas-js';
13
+ import { isValidUuid } from './common/utils';
14
+
15
+ const logger = createLogger('ObservedClient');
16
+
17
+ export type ObservedClientConfig<AppData extends Record<string, unknown> = Record<string, unknown>> = {
18
+ callId: string;
19
+ clientId: string;
20
+ mediaUnitId: string;
21
+ appData: AppData;
22
+ overflowingProcessingThreshold?: number;
23
+ joined?: number,
24
+ };
25
+
26
+ export type ObservedClientEvents = {
27
+ update: [],
28
+ close: [],
29
+ 'processing-sample-overflow': [],
30
+ 'candidate-pair-change': [],
31
+ newpeerconnection: [ObservedPeerConnection],
32
+ };
33
+
34
+ export declare interface ObservedClient<AppData extends Record<string, unknown> = Record<string, unknown>> {
35
+ on<U extends keyof ObservedClientEvents>(event: U, listener: (...args: ObservedClientEvents[U]) => void): this;
36
+ off<U extends keyof ObservedClientEvents>(event: U, listener: (...args: ObservedClientEvents[U]) => void): this;
37
+ once<U extends keyof ObservedClientEvents>(event: U, listener: (...args: ObservedClientEvents[U]) => void): this;
38
+ emit<U extends keyof ObservedClientEvents>(event: U, ...args: ObservedClientEvents[U]): boolean;
39
+ readonly appData: AppData;
40
+ }
41
+
42
+ export class ObservedClient<AppData extends Record<string, unknown> = Record<string, unknown>> extends EventEmitter {
43
+ public static async create<T extends Record<string, unknown> = Record<string, unknown>>(
44
+ config: ObservedClientConfig<T>,
45
+ call: ObservedCall,
46
+ storageProvider: StorageProvider,
47
+ ) {
48
+ const { callId, clientId, mediaUnitId } = config;
49
+
50
+ const model = new Models.Client({
51
+ roomId: call.roomId,
52
+ serviceId: call.serviceId,
53
+ callId,
54
+ clientId,
55
+ mediaUnitId,
56
+ peerConnectionIds: [],
57
+ joined: BigInt(config.joined ?? Date.now()),
58
+ });
59
+
60
+ const result = new ObservedClient<T>(model, call, storageProvider, config.appData);
61
+
62
+ const alreadyInserted = await storageProvider.clientStorage.insert(clientId, model);
63
+
64
+ if (alreadyInserted) throw new Error(`Client with id ${clientId} already exists`);
65
+
66
+ result._overflowingProcessingThreshold = config.overflowingProcessingThreshold ?? 0;
67
+
68
+ return result;
69
+ }
70
+
71
+ private readonly _peerConnections = new Map<string, ObservedPeerConnection>();
72
+ private readonly _execute = createSingleExecutor();
73
+
74
+ private _overflowingProcessingThreshold = 0;
75
+ private _closed = false;
76
+ private _updated = Date.now();
77
+ private _acceptedSample = 0;
78
+ private _processingSample = 0;
79
+ private _iceLocalCandidate?: IceLocalCandidate;
80
+ private _iceRemoteCandidate?: IceLocalCandidate;
81
+
82
+ public readonly mediaDevices: string[] = [];
83
+ public readonly codecs: string[] = [];
84
+ public readonly userMediaErrors: string[] = [];
85
+
86
+ private constructor(
87
+ private readonly _model: Models.Client,
88
+ public readonly call: ObservedCall,
89
+ private readonly _storageProvider: StorageProvider,
90
+ public readonly appData: AppData
91
+ ) {
92
+ super();
93
+ }
94
+
95
+ public get joined(): number {
96
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
97
+ return Number(this._model.joined!);
98
+ }
99
+
100
+ public get clientId(): string {
101
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
102
+ return this._model.clientId!;
103
+ }
104
+
105
+ public get roomId() {
106
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
107
+ return this._model.roomId!;
108
+ }
109
+
110
+ public get serviceId() {
111
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
112
+ return this._model.serviceId!;
113
+ }
114
+
115
+ public get callId() {
116
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
117
+ return this._model.callId!;
118
+ }
119
+
120
+ public get mediaUnitId() {
121
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
122
+ return this._model.mediaUnitId!;
123
+ }
124
+
125
+ public get reports() {
126
+ return this.call.reports;
127
+ }
128
+
129
+ public get userId() {
130
+ return this._model.userId;
131
+ }
132
+
133
+ public get iceLocalCandidate() {
134
+ return this._iceLocalCandidate;
135
+ }
136
+
137
+ public get iceRemoteCandidate() {
138
+ return this._iceRemoteCandidate;
139
+ }
140
+
141
+ public get marker() {
142
+ return this._model.marker;
143
+ }
144
+
145
+ public get browser() {
146
+ return this._model.browser;
147
+ }
148
+
149
+ public get engine() {
150
+ return this._model.engine;
151
+ }
152
+
153
+ public get operationSystem() {
154
+ return this._model.operationSystem;
155
+ }
156
+
157
+ public get platform() {
158
+ return this._model.platform;
159
+ }
160
+
161
+ public get acceptedSample() {
162
+ return this._acceptedSample;
163
+ }
164
+
165
+ public get updated() {
166
+ return this._updated;
167
+ }
168
+
169
+ public get closed() {
170
+ return this._closed;
171
+ }
172
+
173
+ public get peerConnections(): ReadonlyMap<string, ObservedPeerConnection> {
174
+ return this._peerConnections;
175
+ }
176
+
177
+ public close() {
178
+ if (this._closed) return;
179
+ this._closed = true;
180
+
181
+ Array.from(this._peerConnections.values()).forEach((peerConnection) => peerConnection.close());
182
+
183
+ this._execute(() => this._storageProvider.clientStorage.remove(this.clientId))
184
+ .catch(() => void 0)
185
+ .finally(() => this.emit('close'));
186
+ }
187
+
188
+ public async accept(sample: ClientSample): Promise<void> {
189
+ if (this._closed) throw new Error(`Client ${this.clientId} is closed`);
190
+ if (sample.clientId && sample.clientId !== 'NULL' && sample.clientId !== this.clientId) {
191
+ throw new Error(`Sample client id (${sample.clientId}) does not match the client id of the observed client (${this.clientId})`);
192
+ }
193
+ ++this._acceptedSample;
194
+ ++this._processingSample;
195
+
196
+ if (0 < this._overflowingProcessingThreshold && this._overflowingProcessingThreshold < this._processingSample) {
197
+ this.emit('processing-sample-overflow');
198
+ }
199
+
200
+ return this._execute(async () => {
201
+ let executeSave = false;
202
+
203
+ if (this.userId !== sample.userId) {
204
+ this._model.userId = sample.userId;
205
+ executeSave = true;
206
+ }
207
+ if (this._model.marker !== sample.marker) {
208
+ this._model.marker = sample.marker;
209
+ executeSave = true;
210
+ }
211
+
212
+ if (sample.os && (
213
+ this._model.operationSystem?.name !== sample.os.name ||
214
+ this._model.operationSystem?.version !== sample.os.version ||
215
+ this._model.operationSystem?.versionName !== sample.os.versionName
216
+ )) {
217
+ this._model.operationSystem = new Samples_ClientSample_OperationSystem({
218
+ ...sample.os,
219
+ });
220
+
221
+ const callMetaReport = createCallMetaReport(
222
+ this.serviceId,
223
+ this.mediaUnitId,
224
+ this.roomId,
225
+ this.callId,
226
+ this.clientId,
227
+ {
228
+ type: CallMetaType.OPERATION_SYSTEM,
229
+ payload: sample.os,
230
+ }, this.userId);
231
+
232
+ this.reports.addCallMetaReport(callMetaReport);
233
+ executeSave = true;
234
+ }
235
+
236
+ if (sample.engine && (
237
+ this._model.engine?.name !== sample.engine.name ||
238
+ this._model.engine?.version !== sample.engine.version
239
+ )) {
240
+ this._model.engine = new Samples_ClientSample_Engine({
241
+ ...sample.engine,
242
+ });
243
+
244
+ const callMetaReport = createCallMetaReport(
245
+ this.serviceId,
246
+ this.mediaUnitId,
247
+ this.roomId,
248
+ this.callId,
249
+ this.clientId,
250
+ {
251
+ type: CallMetaType.ENGINE,
252
+ payload: sample.engine,
253
+ }, this.userId);
254
+
255
+ this.reports.addCallMetaReport(callMetaReport);
256
+ executeSave = true;
257
+ }
258
+
259
+ if (sample.platform && (
260
+ this._model.platform?.model !== sample.platform.model ||
261
+ this._model.platform?.type !== sample.platform.type ||
262
+ this._model.platform?.vendor !== sample.platform.vendor
263
+ )) {
264
+ this._model.platform = new Samples_ClientSample_Platform({
265
+ ...sample.platform,
266
+ });
267
+
268
+ const callMetaReport = createCallMetaReport(
269
+ this.serviceId,
270
+ this.mediaUnitId,
271
+ this.roomId,
272
+ this.callId,
273
+ this.clientId,
274
+ {
275
+ type: CallMetaType.PLATFORM,
276
+ payload: sample.platform,
277
+ }, this.userId);
278
+
279
+ this.reports.addCallMetaReport(callMetaReport);
280
+ executeSave = true;
281
+ }
282
+
283
+ if (sample.browser && (
284
+ this._model.browser?.name !== sample.browser.name ||
285
+ this._model.browser?.version !== sample.browser.version
286
+ )) {
287
+ this._model.browser = new Samples_ClientSample_Browser({
288
+ ...sample.browser,
289
+ });
290
+
291
+ const callMetaReport = createCallMetaReport(
292
+ this.serviceId,
293
+ this.mediaUnitId,
294
+ this.roomId,
295
+ this.callId,
296
+ this.clientId,
297
+ {
298
+ type: CallMetaType.BROWSER,
299
+ payload: sample.browser,
300
+ }, this.userId);
301
+
302
+ this.reports.addCallMetaReport(callMetaReport);
303
+ executeSave = true;
304
+ }
305
+
306
+ for (const mediaConstraint of sample.mediaConstraints ?? []) {
307
+ const callMetaReport = createCallMetaReport(
308
+ this.serviceId,
309
+ this.mediaUnitId,
310
+ this.roomId,
311
+ this.callId,
312
+ this.clientId,
313
+ {
314
+ type: CallMetaType.MEDIA_CONSTRAINT,
315
+ payload: mediaConstraint,
316
+ }, this.userId);
317
+
318
+ this.reports.addCallMetaReport(callMetaReport);
319
+ }
320
+
321
+ for (const localSDP of sample.localSDPs ?? []) {
322
+ const callMetaReport = createCallMetaReport(
323
+ this.serviceId,
324
+ this.mediaUnitId,
325
+ this.roomId,
326
+ this.callId,
327
+ this.clientId,
328
+ {
329
+ type: CallMetaType.LOCAL_SDP,
330
+ payload: localSDP,
331
+ }, this.userId);
332
+
333
+ this.reports.addCallMetaReport(callMetaReport);
334
+ }
335
+
336
+ for (const extensionStats of sample.extensionStats ?? []) {
337
+ this.reports.addClientExtensionReport({
338
+ serviceId: this.serviceId,
339
+ mediaUnitId: this.mediaUnitId,
340
+ roomId: this.roomId,
341
+ callId: this.callId,
342
+ clientId: this.clientId,
343
+ userId: this.userId,
344
+ timestamp: Date.now(),
345
+ payload: extensionStats.payload,
346
+ extensionType: extensionStats.type,
347
+ });
348
+ }
349
+
350
+ for (const { timestamp = Date.now(), ...callEvent } of sample.customCallEvents ?? []) {
351
+ this.reports.addCallEventReport({
352
+ serviceId: this.serviceId,
353
+ mediaUnitId: this.mediaUnitId,
354
+ roomId: this.roomId,
355
+ callId: this.callId,
356
+ clientId: this.clientId,
357
+ userId: this.userId,
358
+ timestamp,
359
+ ...callEvent,
360
+ });
361
+ }
362
+
363
+ for (const userMediaError of sample.userMediaErrors ?? []) {
364
+ const callMetaReport = createCallMetaReport(
365
+ this.serviceId,
366
+ this.mediaUnitId,
367
+ this.roomId,
368
+ this.callId,
369
+ this.clientId, {
370
+ type: CallMetaType.USER_MEDIA_ERROR,
371
+ payload: userMediaError,
372
+ }, this.userId);
373
+
374
+ this.reports.addCallMetaReport(callMetaReport);
375
+ this.userMediaErrors.push(userMediaError);
376
+ }
377
+
378
+ for (const certificate of sample.certificates ?? []) {
379
+ const callMetaReport = createCallMetaReport(
380
+ this.serviceId,
381
+ this.mediaUnitId,
382
+ this.roomId,
383
+ this.callId,
384
+ this.clientId, {
385
+ type: CallMetaType.CERTIFICATE,
386
+ payload: certificate,
387
+ }, this.userId);
388
+
389
+ this.reports.addCallMetaReport(callMetaReport);
390
+ }
391
+
392
+ for (const codec of sample.codecs ?? []) {
393
+ const callMetaReport = createCallMetaReport(
394
+ this.serviceId,
395
+ this.mediaUnitId,
396
+ this.roomId,
397
+ this.callId,
398
+ this.clientId, {
399
+ type: CallMetaType.CODEC,
400
+ payload: codec,
401
+ }, this.userId);
402
+
403
+ this.reports.addCallMetaReport(callMetaReport);
404
+ codec.mimeType && this.codecs.push(codec.mimeType);
405
+ }
406
+
407
+ for (const iceServer of sample.iceServers ?? []) {
408
+ const callMetaReport = createCallMetaReport(
409
+ this.serviceId,
410
+ this.mediaUnitId,
411
+ this.roomId,
412
+ this.callId,
413
+ this.clientId, {
414
+ type: CallMetaType.ICE_SERVER,
415
+ payload: iceServer,
416
+ }, this.userId);
417
+
418
+ this.reports.addCallMetaReport(callMetaReport);
419
+ }
420
+
421
+ for (const mediaDevice of sample.mediaDevices ?? []) {
422
+ const callMetaReport = createCallMetaReport(
423
+ this.serviceId,
424
+ this.mediaUnitId,
425
+ this.roomId,
426
+ this.callId,
427
+ this.clientId, {
428
+ type: CallMetaType.MEDIA_DEVICE,
429
+ payload: mediaDevice,
430
+ }, this.userId);
431
+
432
+ this.reports.addCallMetaReport(callMetaReport);
433
+ mediaDevice.label && this.mediaDevices.push(mediaDevice.label);
434
+ }
435
+
436
+ for (const mediaSource of sample.mediaSources ?? []) {
437
+ const callMetaReport = createCallMetaReport(
438
+ this.serviceId,
439
+ this.mediaUnitId,
440
+ this.roomId,
441
+ this.callId,
442
+ this.clientId, {
443
+ type: CallMetaType.MEDIA_SOURCE,
444
+ payload: mediaSource,
445
+ }, this.userId);
446
+
447
+ this.reports.addCallMetaReport(callMetaReport);
448
+ }
449
+ let selectedLocalCandidateId: string | undefined;
450
+ let selectedRemoteCandidateId: string | undefined;
451
+
452
+ for (const candidatePair of sample.iceCandidatePairs ?? []) {
453
+ if (candidatePair.nominated) {
454
+ if (!selectedLocalCandidateId) selectedLocalCandidateId = candidatePair.localCandidateId;
455
+ if (!selectedRemoteCandidateId) selectedRemoteCandidateId = candidatePair.remoteCandidateId;
456
+ }
457
+
458
+ const report: IceCandidatePairReport = {
459
+ serviceId: this.serviceId,
460
+ mediaUnitId: this.mediaUnitId,
461
+ roomId: this.roomId,
462
+ callId: this.callId,
463
+ clientId: this.clientId,
464
+ userId: this.userId,
465
+ timestamp: sample.timestamp,
466
+ ...candidatePair,
467
+ sampleSeq: -1, // deprecated
468
+ };
469
+
470
+ this.reports.addIceCandidatePairReport(report);
471
+ }
472
+
473
+ let changeIceCandidatePair = false;
474
+
475
+ for (const iceLocalCandidate of sample.iceLocalCandidates ?? []) {
476
+ if (
477
+ iceLocalCandidate.id && selectedLocalCandidateId &&
478
+ iceLocalCandidate.id === selectedLocalCandidateId &&
479
+ this._iceLocalCandidate?.id !== iceLocalCandidate.id
480
+ ) {
481
+ this._iceLocalCandidate = iceLocalCandidate;
482
+ changeIceCandidatePair = true;
483
+ }
484
+ const callMetaReport = createCallMetaReport(
485
+ this.serviceId,
486
+ this.mediaUnitId,
487
+ this.roomId,
488
+ this.callId,
489
+ this.clientId, {
490
+ type: CallMetaType.ICE_LOCAL_CANDIDATE,
491
+ payload: iceLocalCandidate,
492
+ }, this.userId);
493
+
494
+ this.reports.addCallMetaReport(callMetaReport);
495
+ }
496
+
497
+ for (const iceRemoteCandidate of sample.iceRemoteCandidates ?? []) {
498
+ if (
499
+ iceRemoteCandidate.id && selectedRemoteCandidateId &&
500
+ iceRemoteCandidate.id === selectedRemoteCandidateId &&
501
+ this._iceRemoteCandidate?.id !== iceRemoteCandidate.id
502
+ ) {
503
+ this._iceRemoteCandidate = iceRemoteCandidate;
504
+ changeIceCandidatePair = true;
505
+ }
506
+ const callMetaReport = createCallMetaReport(
507
+ this.serviceId,
508
+ this.mediaUnitId,
509
+ this.roomId,
510
+ this.callId,
511
+ this.clientId, {
512
+ type: CallMetaType.ICE_REMOTE_CANDIDATE,
513
+ payload: iceRemoteCandidate,
514
+ }, this.userId);
515
+
516
+ this.reports.addCallMetaReport(callMetaReport);
517
+ }
518
+
519
+ for (const transport of sample.pcTransports ?? []) {
520
+ try {
521
+ const peerConnection = this._peerConnections.get(transport.transportId) ?? await this._createPeerConnection(transport.peerConnectionId);
522
+
523
+ peerConnection.update(transport, sample.timestamp);
524
+ } catch (err) {
525
+ logger.error(`Error creating peer connection: ${(err as Error)?.message}`);
526
+ }
527
+
528
+ }
529
+
530
+ for (const track of sample.inboundAudioTracks ?? []) {
531
+ if (!track.peerConnectionId || !track.trackId) {
532
+ logger.warn(`InboundAudioTrack without peerConnectionId or trackId: ${JSON.stringify(track)}`);
533
+
534
+ continue;
535
+ }
536
+
537
+ try {
538
+ const peerConnection = this._peerConnections.get(track.peerConnectionId) ?? await this._createPeerConnection(track.peerConnectionId);
539
+
540
+ if (!peerConnection) continue;
541
+
542
+ const inboundAudioTrack = peerConnection.inboundAudioTracks.get(track.trackId) ?? await peerConnection.createInboundAudioTrack({
543
+ trackId: track.trackId,
544
+ sfuStreamId: track.sfuStreamId,
545
+ sfuSinkId: track.sfuSinkId,
546
+ });
547
+
548
+ await inboundAudioTrack.update(track, sample.timestamp);
549
+
550
+ const remoteOutboundTrack = this.call.sfuStreamIdToOutboundAudioTrack.get(track.sfuStreamId ?? '');
551
+
552
+ if (remoteOutboundTrack && inboundAudioTrack.sfuStreamId && !remoteOutboundTrack.remoteInboundTracks.has(inboundAudioTrack.sfuStreamId)) {
553
+ remoteOutboundTrack.connectInboundTrack(inboundAudioTrack);
554
+ }
555
+ } catch (err) {
556
+ logger.error(`Error creating inbound audio track: ${(err as Error)?.message}`);
557
+ }
558
+ }
559
+
560
+ for (const track of sample.inboundVideoTracks ?? []) {
561
+ if (!track.peerConnectionId || !track.trackId) {
562
+ logger.warn(`InboundVideoTrack without peerConnectionId or trackId: ${JSON.stringify(track)}`);
563
+
564
+ continue;
565
+ }
566
+ if (isValidUuid(track.trackId) === false) {
567
+ // mediasoup-probator trackId is not a valid UUID, no need to warn about it
568
+ if (track.trackId === 'probator') continue;
569
+ logger.warn(`InboundVideoTrack with invalid trackId: ${track.trackId}`);
570
+ continue;
571
+ }
572
+
573
+ try {
574
+ const peerConnection = this._peerConnections.get(track.peerConnectionId) ?? await this._createPeerConnection(track.peerConnectionId);
575
+
576
+ if (!peerConnection) continue;
577
+
578
+ const inboundVideoTrack = peerConnection.inboundVideoTracks.get(track.trackId) ?? await peerConnection.createInboundVideoTrack({
579
+ trackId: track.trackId,
580
+ sfuStreamId: track.sfuStreamId,
581
+ sfuSinkId: track.sfuSinkId,
582
+ });
583
+
584
+ await inboundVideoTrack.update(track, sample.timestamp);
585
+
586
+ const remoteOutboundTrack = this.call.sfuStreamIdToOutboundVideoTrack.get(inboundVideoTrack.sfuStreamId ?? '');
587
+
588
+ if (remoteOutboundTrack && inboundVideoTrack.sfuStreamId && !remoteOutboundTrack.remoteInboundTracks.has(inboundVideoTrack.sfuStreamId)) {
589
+ remoteOutboundTrack.connectInboundTrack(inboundVideoTrack);
590
+ }
591
+ } catch (err) {
592
+ logger.error(`Error creating inbound video track: ${(err as Error)?.message}`);
593
+ }
594
+ }
595
+
596
+ for (const track of sample.outboundAudioTracks ?? []) {
597
+ if (!track.peerConnectionId || !track.trackId) {
598
+ logger.warn(`OutboundAudioTrack without peerConnectionId or trackId: ${JSON.stringify(track)}`);
599
+
600
+ continue;
601
+ }
602
+
603
+ try {
604
+ const peerConnection = this._peerConnections.get(track.peerConnectionId) ?? await this._createPeerConnection(track.peerConnectionId);
605
+
606
+ if (!peerConnection) continue;
607
+
608
+ const outboundAudioTrack = peerConnection.outboundAudioTracks.get(track.trackId) ?? await peerConnection.createOutboundAudioTrack({
609
+ trackId: track.trackId,
610
+ sfuStreamId: track.sfuStreamId,
611
+ });
612
+
613
+ await outboundAudioTrack.update(track, sample.timestamp);
614
+ } catch (err) {
615
+ logger.error(`Error creating outbound audio track: ${(err as Error)?.message}`);
616
+ }
617
+
618
+ }
619
+
620
+ for (const track of sample.outboundVideoTracks ?? []) {
621
+ if (!track.peerConnectionId || !track.trackId) {
622
+ logger.warn(`OutboundVideoTrack without peerConnectionId or trackId: ${JSON.stringify(track)}`);
623
+
624
+ continue;
625
+ }
626
+
627
+ try {
628
+ const peerConnection = this._peerConnections.get(track.peerConnectionId) ?? await this._createPeerConnection(track.peerConnectionId);
629
+
630
+ if (!peerConnection) continue;
631
+
632
+ const outboundVideoTrack = peerConnection.outboundVideoTracks.get(track.trackId) ?? await peerConnection.createOutboundVideoTrack({
633
+ trackId: track.trackId,
634
+ sfuStreamId: track.sfuStreamId,
635
+ });
636
+
637
+ await outboundVideoTrack.update(track, sample.timestamp);
638
+
639
+ } catch (err) {
640
+ logger.error(`Error creating outbound video track: ${(err as Error)?.message}`);
641
+ }
642
+ }
643
+
644
+ if (changeIceCandidatePair) {
645
+ this.emit('candidate-pair-change');
646
+ }
647
+
648
+ if (executeSave) await this._save();
649
+
650
+ this._updated = sample.timestamp;
651
+ this.emit('update');
652
+ }).finally(() => {
653
+ --this._processingSample;
654
+ });
655
+ }
656
+
657
+ private async _createPeerConnection(peerConnectionId: string): Promise<ObservedPeerConnection> {
658
+ const result = await ObservedPeerConnection.create({
659
+ peerConnectionId,
660
+ }, this, this._storageProvider);
661
+
662
+ result.once('close', () => {
663
+ this._peerConnections.delete(peerConnectionId);
664
+ this._model.peerConnectionIds = this._model.peerConnectionIds.filter((id) => id !== peerConnectionId);
665
+ this._save().catch(() => void 0);
666
+ });
667
+ this._peerConnections.set(peerConnectionId, result);
668
+ this._model.peerConnectionIds.push(peerConnectionId);
669
+ await this._save();
670
+
671
+ this.emit('newpeerconnection', result);
672
+
673
+ return result;
674
+ }
675
+
676
+ private async _save() {
677
+ if (this._closed) throw new Error(`Client ${this.clientId} is closed`);
678
+
679
+ return this._storageProvider.clientStorage.set(this.clientId, this._model);
680
+ }
681
+ }