@observertc/observer-js 0.42.9 → 1.0.0-a1dd87c.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.
Files changed (303) hide show
  1. package/.prettierrc +6 -6
  2. package/README.md +493 -63
  3. package/lib/ObservedCall.d.ts +48 -43
  4. package/lib/ObservedCall.d.ts.map +1 -1
  5. package/lib/ObservedCall.js +164 -107
  6. package/lib/ObservedCallEventMonitor.d.ts +107 -0
  7. package/lib/ObservedCallEventMonitor.d.ts.map +1 -0
  8. package/lib/ObservedCallEventMonitor.js +321 -0
  9. package/lib/ObservedCallSummary.d.ts +18 -0
  10. package/lib/ObservedCallSummary.d.ts.map +1 -0
  11. package/lib/ObservedCertificate.d.ts +19 -0
  12. package/lib/ObservedCertificate.d.ts.map +1 -0
  13. package/lib/ObservedCertificate.js +38 -0
  14. package/lib/ObservedClient.d.ts +78 -145
  15. package/lib/ObservedClient.d.ts.map +1 -1
  16. package/lib/ObservedClient.js +661 -746
  17. package/lib/ObservedClientEventMonitor.d.ts +91 -0
  18. package/lib/ObservedClientEventMonitor.d.ts.map +1 -0
  19. package/lib/ObservedClientEventMonitor.js +254 -0
  20. package/lib/ObservedClientSummary.d.ts +23 -0
  21. package/lib/ObservedClientSummary.d.ts.map +1 -0
  22. package/lib/ObservedClientSummary.js +2 -0
  23. package/lib/ObservedCodec.d.ts +22 -0
  24. package/lib/ObservedCodec.d.ts.map +1 -0
  25. package/lib/ObservedCodec.js +45 -0
  26. package/lib/ObservedDataChannel.d.ts +25 -69
  27. package/lib/ObservedDataChannel.d.ts.map +1 -1
  28. package/lib/ObservedDataChannel.js +69 -109
  29. package/lib/ObservedIceCandidate.d.ts +29 -0
  30. package/lib/ObservedIceCandidate.d.ts.map +1 -0
  31. package/lib/ObservedIceCandidate.js +59 -0
  32. package/lib/ObservedIceCandidatePair.d.ts +45 -0
  33. package/lib/ObservedIceCandidatePair.d.ts.map +1 -0
  34. package/lib/ObservedIceCandidatePair.js +127 -0
  35. package/lib/ObservedIceTransport.d.ts +36 -0
  36. package/lib/ObservedIceTransport.d.ts.map +1 -0
  37. package/lib/ObservedIceTransport.js +93 -0
  38. package/lib/ObservedInboundRtp.d.ts +92 -0
  39. package/lib/ObservedInboundRtp.d.ts.map +1 -0
  40. package/lib/ObservedInboundRtp.js +193 -0
  41. package/lib/ObservedInboundTrack.d.ts +34 -0
  42. package/lib/ObservedInboundTrack.d.ts.map +1 -0
  43. package/lib/ObservedInboundTrack.js +92 -0
  44. package/lib/ObservedMediaPlayout.d.ts +22 -0
  45. package/lib/ObservedMediaPlayout.d.ts.map +1 -0
  46. package/lib/ObservedMediaPlayout.js +42 -0
  47. package/lib/ObservedMediaSource.d.ts +28 -0
  48. package/lib/ObservedMediaSource.d.ts.map +1 -0
  49. package/lib/ObservedMediaSource.js +55 -0
  50. package/lib/ObservedOutboundRtp.d.ts +62 -0
  51. package/lib/ObservedOutboundRtp.d.ts.map +1 -0
  52. package/lib/ObservedOutboundRtp.js +144 -0
  53. package/lib/ObservedOutboundTrack.d.ts +34 -0
  54. package/lib/ObservedOutboundTrack.d.ts.map +1 -0
  55. package/lib/ObservedOutboundTrack.js +65 -0
  56. package/lib/ObservedPeerConnection.d.ts +154 -80
  57. package/lib/ObservedPeerConnection.d.ts.map +1 -1
  58. package/lib/ObservedPeerConnection.js +724 -357
  59. package/lib/ObservedPeerConnectionTransport.d.ts +17 -0
  60. package/lib/ObservedPeerConnectionTransport.d.ts.map +1 -0
  61. package/lib/ObservedPeerConnectionTransport.js +34 -0
  62. package/lib/ObservedRemoteInboundRtp.d.ts +30 -0
  63. package/lib/ObservedRemoteInboundRtp.d.ts.map +1 -0
  64. package/lib/ObservedRemoteInboundRtp.js +60 -0
  65. package/lib/ObservedRemoteOutboundRtp.d.ts +30 -0
  66. package/lib/ObservedRemoteOutboundRtp.d.ts.map +1 -0
  67. package/lib/ObservedRemoteOutboundRtp.js +60 -0
  68. package/lib/ObservedTURN.d.ts +31 -0
  69. package/lib/ObservedTURN.d.ts.map +1 -0
  70. package/lib/ObservedTURN.js +58 -0
  71. package/lib/ObservedTurnServer.d.ts +25 -0
  72. package/lib/ObservedTurnServer.d.ts.map +1 -0
  73. package/lib/ObservedTurnServer.js +59 -0
  74. package/lib/Observer.d.ts +46 -54
  75. package/lib/Observer.d.ts.map +1 -1
  76. package/lib/Observer.js +131 -226
  77. package/lib/ObserverEventMonitor.d.ts +141 -0
  78. package/lib/ObserverEventMonitor.d.ts.map +1 -0
  79. package/lib/ObserverEventMonitor.js +440 -0
  80. package/lib/ObserverSummary.d.ts +13 -0
  81. package/lib/ObserverSummary.d.ts.map +1 -0
  82. package/lib/ObserverSummary.js +2 -0
  83. package/lib/Reports.d.ts +85 -0
  84. package/lib/Reports.d.ts.map +1 -0
  85. package/lib/Reports.js +2 -0
  86. package/lib/common/Middleware.d.ts +10 -1
  87. package/lib/common/Middleware.d.ts.map +1 -1
  88. package/lib/common/Middleware.js +55 -36
  89. package/lib/common/logger.d.ts +8 -4
  90. package/lib/common/logger.d.ts.map +1 -1
  91. package/lib/common/logger.js +44 -68
  92. package/lib/common/types.d.ts +0 -21
  93. package/lib/common/types.d.ts.map +1 -1
  94. package/lib/common/types.js +1 -0
  95. package/lib/common/utils.d.ts +3 -1
  96. package/lib/common/utils.d.ts.map +1 -1
  97. package/lib/common/utils.js +23 -3
  98. package/lib/detectors/Detector.d.ts +5 -0
  99. package/lib/detectors/Detector.d.ts.map +1 -0
  100. package/lib/detectors/Detector.js +3 -0
  101. package/lib/detectors/Detectors.d.ts +11 -0
  102. package/lib/detectors/Detectors.d.ts.map +1 -0
  103. package/lib/detectors/Detectors.js +34 -0
  104. package/lib/index.d.ts +27 -25
  105. package/lib/index.d.ts.map +1 -1
  106. package/lib/index.js +45 -41
  107. package/lib/mediasoup/ObservedMediaRouter.d.ts +10 -0
  108. package/lib/mediasoup/ObservedMediaRouter.d.ts.map +1 -0
  109. package/lib/mediasoup/ObservedMediaRouter.js +6 -0
  110. package/lib/monitors/TurnUsageMonitor.d.ts +0 -52
  111. package/lib/monitors/TurnUsageMonitor.d.ts.map +1 -1
  112. package/lib/monitors/TurnUsageMonitor.js +145 -120
  113. package/lib/schema/ClientEventTypes.d.ts +228 -0
  114. package/lib/schema/ClientEventTypes.d.ts.map +1 -0
  115. package/lib/schema/ClientEventTypes.js +41 -0
  116. package/lib/schema/ClientMetaTypes.d.ts +34 -0
  117. package/lib/schema/ClientMetaTypes.d.ts.map +1 -0
  118. package/lib/schema/ClientMetaTypes.js +16 -0
  119. package/lib/schema/ClientSample.d.ts +1333 -0
  120. package/lib/schema/ClientSample.d.ts.map +1 -0
  121. package/lib/schema/ClientSample.js +4 -0
  122. package/lib/scores/CalculatedScore.d.ts +6 -0
  123. package/lib/scores/CalculatedScore.d.ts.map +1 -0
  124. package/lib/scores/CalculatedScore.js +2 -0
  125. package/lib/scores/DefaultCallScoreCalculator.d.ts +7 -0
  126. package/lib/scores/DefaultCallScoreCalculator.d.ts.map +1 -0
  127. package/lib/scores/DefaultCallScoreCalculator.js +21 -0
  128. package/lib/scores/ScoreCalculator.d.ts +4 -0
  129. package/lib/scores/ScoreCalculator.d.ts.map +1 -0
  130. package/lib/scores/ScoreCalculator.js +2 -0
  131. package/lib/updaters/CallUpdater.d.ts +5 -0
  132. package/lib/updaters/CallUpdater.d.ts.map +1 -0
  133. package/lib/updaters/CallUpdater.js +2 -0
  134. package/lib/updaters/ObserverUpdater.d.ts +5 -0
  135. package/lib/updaters/ObserverUpdater.d.ts.map +1 -0
  136. package/lib/updaters/ObserverUpdater.js +2 -0
  137. package/lib/updaters/OnAllCallObserverUpdater.d.ts +15 -0
  138. package/lib/updaters/OnAllCallObserverUpdater.d.ts.map +1 -0
  139. package/lib/updaters/OnAllCallObserverUpdater.js +50 -0
  140. package/lib/updaters/OnAllClientCallUpdater.d.ts +15 -0
  141. package/lib/updaters/OnAllClientCallUpdater.d.ts.map +1 -0
  142. package/lib/updaters/OnAllClientCallUpdater.js +53 -0
  143. package/lib/updaters/OnAnyCallObserverUpdater.d.ts +12 -0
  144. package/lib/updaters/OnAnyCallObserverUpdater.d.ts.map +1 -0
  145. package/lib/updaters/OnAnyCallObserverUpdater.js +37 -0
  146. package/lib/updaters/OnAnyClientCallUpdater.d.ts +12 -0
  147. package/lib/updaters/OnAnyClientCallUpdater.d.ts.map +1 -0
  148. package/lib/updaters/OnAnyClientCallUpdater.js +36 -0
  149. package/lib/updaters/OnIntervalUpdater.d.ts +10 -0
  150. package/lib/updaters/OnIntervalUpdater.d.ts.map +1 -0
  151. package/lib/updaters/OnIntervalUpdater.js +17 -0
  152. package/lib/updaters/Updater.d.ts +6 -0
  153. package/lib/updaters/Updater.d.ts.map +1 -0
  154. package/lib/updaters/Updater.js +2 -0
  155. package/lib/utils/MediasoupRemoteTrackResolver.d.ts +25 -0
  156. package/lib/utils/MediasoupRemoteTrackResolver.d.ts.map +1 -0
  157. package/lib/utils/MediasoupRemoteTrackResolver.js +110 -0
  158. package/lib/utils/RemoteTrackResolver.d.ts +7 -0
  159. package/lib/utils/RemoteTrackResolver.d.ts.map +1 -0
  160. package/lib/utils/RemoteTrackResolver.js +2 -0
  161. package/package.json +4 -4
  162. package/src/ObservedCall.ts +243 -161
  163. package/src/ObservedCallEventMonitor.ts +402 -0
  164. package/src/ObservedCallSummary.ts +22 -0
  165. package/src/ObservedCertificate.ts +43 -0
  166. package/src/ObservedClient.ts +715 -1003
  167. package/src/ObservedClientEventMonitor.ts +309 -0
  168. package/src/ObservedClientSummary.ts +24 -0
  169. package/src/ObservedCodec.ts +49 -0
  170. package/src/ObservedDataChannel.ts +71 -181
  171. package/src/ObservedIceCandidate.ts +64 -0
  172. package/src/ObservedIceCandidatePair.ts +134 -0
  173. package/src/ObservedIceTransport.ts +99 -0
  174. package/src/ObservedInboundRtp.ts +205 -0
  175. package/src/ObservedInboundTrack.ts +105 -0
  176. package/src/ObservedMediaPlayout.ts +49 -0
  177. package/src/ObservedMediaSource.ts +60 -0
  178. package/src/ObservedOutboundRtp.ts +156 -0
  179. package/src/ObservedOutboundTrack.ts +82 -0
  180. package/src/ObservedPeerConnection.ts +933 -402
  181. package/src/ObservedPeerConnectionTransport.ts +38 -0
  182. package/src/ObservedRemoteInboundRtp.ts +64 -0
  183. package/src/ObservedRemoteOutboundRtp.ts +65 -0
  184. package/src/ObservedTURN.ts +86 -0
  185. package/src/ObservedTurnServer.ts +72 -0
  186. package/src/Observer.ts +183 -298
  187. package/src/ObserverEventMonitor.ts +561 -0
  188. package/src/ObserverSummary.ts +15 -0
  189. package/src/Reports.ts +87 -0
  190. package/src/common/Middleware.ts +70 -42
  191. package/src/common/logger.ts +60 -69
  192. package/src/common/types.ts +0 -42
  193. package/src/common/utils.ts +24 -2
  194. package/src/detectors/Detector.ts +6 -0
  195. package/src/detectors/Detectors.ts +38 -0
  196. package/src/index.ts +29 -90
  197. package/src/mediasoup/ObservedMediaRouter.ts +10 -0
  198. package/src/monitors/TurnUsageMonitor.ts +164 -164
  199. package/src/schema/ClientEventTypes.ts +280 -0
  200. package/src/schema/ClientMetaTypes.ts +41 -0
  201. package/src/schema/ClientSample.ts +1682 -0
  202. package/src/scores/CalculatedScore.ts +6 -0
  203. package/src/scores/DefaultCallScoreCalculator.ts +23 -0
  204. package/src/scores/ScoreCalculator.ts +3 -0
  205. package/src/updaters/CallUpdater.ts +5 -0
  206. package/src/updaters/ObserverUpdater.ts +5 -0
  207. package/src/updaters/OnAllCallObserverUpdater.ts +59 -0
  208. package/src/updaters/OnAllClientCallUpdater.ts +61 -0
  209. package/src/updaters/OnAnyCallObserverUpdater.ts +41 -0
  210. package/src/updaters/OnAnyClientCallUpdater.ts +39 -0
  211. package/src/updaters/OnIntervalUpdater.ts +19 -0
  212. package/src/updaters/Updater.ts +5 -0
  213. package/src/utils/MediasoupRemoteTrackResolver.ts +155 -0
  214. package/src/utils/RemoteTrackResolver.ts +12 -0
  215. package/tsconfig.json +3 -3
  216. package/lib/ObservedICE.d.ts +0 -64
  217. package/lib/ObservedICE.d.ts.map +0 -1
  218. package/lib/ObservedICE.js +0 -141
  219. package/lib/ObservedInboundAudioTrack.d.ts +0 -96
  220. package/lib/ObservedInboundAudioTrack.d.ts.map +0 -1
  221. package/lib/ObservedInboundAudioTrack.js +0 -217
  222. package/lib/ObservedInboundVideoTrack.d.ts +0 -101
  223. package/lib/ObservedInboundVideoTrack.d.ts.map +0 -1
  224. package/lib/ObservedInboundVideoTrack.js +0 -232
  225. package/lib/ObservedOutboundAudioTrack.d.ts +0 -87
  226. package/lib/ObservedOutboundAudioTrack.d.ts.map +0 -1
  227. package/lib/ObservedOutboundAudioTrack.js +0 -186
  228. package/lib/ObservedOutboundVideoTrack.d.ts +0 -91
  229. package/lib/ObservedOutboundVideoTrack.d.ts.map +0 -1
  230. package/lib/ObservedOutboundVideoTrack.js +0 -193
  231. package/lib/ObservedSfu.d.ts +0 -59
  232. package/lib/ObservedSfu.d.ts.map +0 -1
  233. package/lib/ObservedSfu.js +0 -157
  234. package/lib/ObservedSfuInboundRtpPad.d.ts +0 -42
  235. package/lib/ObservedSfuInboundRtpPad.d.ts.map +0 -1
  236. package/lib/ObservedSfuInboundRtpPad.js +0 -71
  237. package/lib/ObservedSfuOutboundRtpPad.d.ts +0 -42
  238. package/lib/ObservedSfuOutboundRtpPad.d.ts.map +0 -1
  239. package/lib/ObservedSfuOutboundRtpPad.js +0 -72
  240. package/lib/ObservedSfuSctpChannel.d.ts +0 -42
  241. package/lib/ObservedSfuSctpChannel.d.ts.map +0 -1
  242. package/lib/ObservedSfuSctpChannel.js +0 -57
  243. package/lib/ObservedSfuTransport.d.ts +0 -58
  244. package/lib/ObservedSfuTransport.d.ts.map +0 -1
  245. package/lib/ObservedSfuTransport.js +0 -120
  246. package/lib/RemoteTrackAssigner.d.ts +0 -14
  247. package/lib/RemoteTrackAssigner.d.ts.map +0 -1
  248. package/lib/RemoteTrackAssigner.js +0 -52
  249. package/lib/ReportsCollector.d.ts +0 -109
  250. package/lib/ReportsCollector.d.ts.map +0 -1
  251. package/lib/ReportsCollector.js +0 -207
  252. package/lib/common/CalculatedScore.d.ts +0 -80
  253. package/lib/common/CalculatedScore.d.ts.map +0 -1
  254. package/lib/common/CalculatedScore.js +0 -162
  255. package/lib/common/CallEventType.d.ts +0 -63
  256. package/lib/common/CallEventType.d.ts.map +0 -1
  257. package/lib/common/CallEventType.js +0 -39
  258. package/lib/common/CallMetaReports.d.ts +0 -42
  259. package/lib/common/CallMetaReports.d.ts.map +0 -1
  260. package/lib/common/CallMetaReports.js +0 -36
  261. package/lib/common/QualityScoreUtils.d.ts +0 -1
  262. package/lib/common/QualityScoreUtils.d.ts.map +0 -1
  263. package/lib/common/QualityScoreUtils.js +0 -1
  264. package/lib/common/TypedEventEmitter.d.ts +0 -22
  265. package/lib/common/TypedEventEmitter.d.ts.map +0 -1
  266. package/lib/common/TypedEventEmitter.js +0 -11
  267. package/lib/common/callEventReports.d.ts +0 -10
  268. package/lib/common/callEventReports.d.ts.map +0 -1
  269. package/lib/common/callEventReports.js +0 -112
  270. package/lib/monitors/CallSummary.d.ts +0 -37
  271. package/lib/monitors/CallSummary.d.ts.map +0 -1
  272. package/lib/monitors/CallSummaryMonitor.d.ts +0 -32
  273. package/lib/monitors/CallSummaryMonitor.d.ts.map +0 -1
  274. package/lib/monitors/CallSummaryMonitor.js +0 -152
  275. package/lib/monitors/ClientIssueMonitor.d.ts +0 -32
  276. package/lib/monitors/ClientIssueMonitor.d.ts.map +0 -1
  277. package/lib/monitors/ClientIssueMonitor.js +0 -49
  278. package/lib/monitors/SfuServerMonitor.d.ts +0 -79
  279. package/lib/monitors/SfuServerMonitor.d.ts.map +0 -1
  280. package/lib/monitors/SfuServerMonitor.js +0 -198
  281. package/src/ObservedICE.ts +0 -237
  282. package/src/ObservedInboundAudioTrack.ts +0 -344
  283. package/src/ObservedInboundVideoTrack.ts +0 -361
  284. package/src/ObservedOutboundAudioTrack.ts +0 -307
  285. package/src/ObservedOutboundVideoTrack.ts +0 -319
  286. package/src/ObservedSfu.ts +0 -231
  287. package/src/ObservedSfuInboundRtpPad.ts +0 -106
  288. package/src/ObservedSfuOutboundRtpPad.ts +0 -107
  289. package/src/ObservedSfuSctpChannel.ts +0 -103
  290. package/src/ObservedSfuTransport.ts +0 -185
  291. package/src/RemoteTrackAssigner.ts +0 -68
  292. package/src/ReportsCollector.ts +0 -336
  293. package/src/common/CalculatedScore.ts +0 -188
  294. package/src/common/CallEventType.ts +0 -69
  295. package/src/common/CallMetaReports.ts +0 -82
  296. package/src/common/QualityScoreUtils.ts +0 -0
  297. package/src/common/TypedEventEmitter.ts +0 -32
  298. package/src/common/callEventReports.ts +0 -178
  299. package/src/monitors/CallSummary.ts +0 -38
  300. package/src/monitors/CallSummaryMonitor.ts +0 -192
  301. package/src/monitors/ClientIssueMonitor.ts +0 -88
  302. package/src/monitors/SfuServerMonitor.ts +0 -285
  303. /package/lib/{monitors/CallSummary.js → ObservedCallSummary.js} +0 -0
package/.prettierrc CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
- "tabWidth": 2,
3
- "useTabs": true,
4
- "trailingComma": "es5",
5
- "singleQuote": true,
6
- "printWidth": 120
7
- }
2
+ "tabWidth": 2,
3
+ "useTabs": true,
4
+ "trailingComma": "es5",
5
+ "singleQuote": true,
6
+ "printWidth": 120
7
+ }
package/README.md CHANGED
@@ -1,106 +1,536 @@
1
- Server side component for monitoring WebRTC applications and services
1
+ # ObserverTC - Observer JS
2
+
3
+ [![NPM version](https://img.shields.io/npm/v/@observertc/observer-js.svg)](https://www.npmjs.com/package/@observertc/observer-js)
4
+ [![License](https://img.shields.io/npm/l/@observertc/observer-js.svg)](https://github.com/observertc/observer-js/blob/main/LICENSE)
5
+
6
+ `observer-js` is a Node.js library for monitoring WebRTC client data. It processes statistical samples from clients, organizes them into calls and participants, tracks a wide range of metrics, detects common issues, and calculates quality scores. This enables real-time insights into WebRTC session performance.
7
+
8
+ This library is a core component of the ObserverTC ecosystem, designed to provide robust server-side monitoring capabilities for WebRTC applications.
9
+
10
+ ## Features
11
+
12
+ - **Hierarchical Data Model**: Organizes data into `Observer` -> `ObservedCall` -> `ObservedClient` -> `ObservedPeerConnection` and further into streams and data channels.
13
+ - **Comprehensive Metrics**: Tracks a wide array of WebRTC statistics including RTT, jitter, packet loss, codecs, ICE states, TURN usage, bandwidth, and more.
14
+ - **Automatic Entity Management**: Can automatically create and manage call and client entities based on incoming data samples.
15
+ - **Issue Detection**: Built-in detectors for common WebRTC problems.
16
+ - **Quality Scoring**: Calculates quality scores for calls and clients.
17
+ - **Event-Driven**: Emits events for significant state changes, new entities, and detected issues.
18
+ - **Configurable Update Policies**: Flexible control over how and when metrics are processed and updated.
19
+ - **TypeScript Support**: Written in TypeScript, providing strong typing and intellisense.
20
+ - **Extensible**: Supports custom application data (`appData`) and integration with external schema definitions (e.g., `observertc/schemas`).
21
+
22
+ ## Installation
23
+
24
+ ```bash
25
+ npm install @observertc/observer-js
26
+ # or
27
+ yarn add @observertc/observer-js
28
+ ```
29
+
30
+ ## Quick Start
31
+
32
+ ```typescript
33
+ import { Observer, ObserverConfig } from '@observertc/observer-js';
34
+ import { ClientSample } from '@observertc/schemas'; // Assuming you use the official schemas
35
+
36
+ // 1. Configure the Observer
37
+ const observerConfig: ObserverConfig = {
38
+ updatePolicy: 'update-on-interval',
39
+ updateIntervalInMs: 5000, // Update observer every 5 seconds
40
+ defaultCallUpdatePolicy: 'update-on-any-client-updated', // Calls update when any client sends data
41
+ };
42
+ const observer = new Observer(observerConfig);
43
+
44
+ // 2. Listen to events
45
+ observer.on('newcall', (call) => {
46
+ console.log(`[Observer] New call detected: ${call.callId}`);
47
+
48
+ call.on('newclient', (client) => {
49
+ console.log(`[Call: ${call.callId}] New client joined: ${client.clientId}`);
50
+
51
+ client.on('issue', (issue) => {
52
+ console.warn(`[Client: ${client.clientId}] Issue: ${issue.type} - ${issue.severity} - ${issue.description}`);
53
+ });
54
+ });
55
+
56
+ call.on('update', () => {
57
+ console.log(
58
+ `[Call: ${call.callId}] Metrics updated. Score: ${call.score?.toFixed(1)}, Clients: ${call.numberOfClients}`
59
+ );
60
+ });
61
+ });
62
+
63
+ // 3. Process Client Samples
64
+ // (ClientSample typically comes from your application after processing getStats() output)
65
+ function processClientStats(rawStats: any, callId: string, clientId: string) {
66
+ // Transform rawStats into the ClientSample format
67
+ // This is a placeholder for your actual transformation logic
68
+ const sample: ClientSample = {
69
+ callId,
70
+ clientId,
71
+ timestamp: Date.now(),
72
+ // ...populate with transformed stats from rawStats, adhering to the ClientSample schema
73
+ // from github.com/observertc/schemas
74
+ };
75
+ observer.accept(sample);
76
+ }
77
+
78
+ // Example usage:
79
+ // const myRawClientStats = getStatsFromClient();
80
+ // processClientStats(myRawClientStats, 'myMeeting123', 'userABC');
81
+
82
+ // 4. Cleanup when done
83
+ // process.on('SIGINT', () => observer.close());
84
+ ```
85
+
2
86
  ---
3
87
 
4
- Table of Contents:
88
+ ## Detailed Documentation
89
+
90
+ The following sections provide a comprehensive guide to `observer-js`.
91
+
92
+ ### 1. General Description
93
+
94
+ (This section is identical to the introductory paragraph at the top of this README)
95
+
96
+ ### 2. Core Concepts
97
+
98
+ #### 2.1. Data Flow
99
+
100
+ 1. **Client-Side**: Your application collects WebRTC statistics (e.g., via `RTCPeerConnection.getStats()`).
101
+ 2. **Transformation**: These raw stats are transformed into the `ClientSample` schema (ideally from [observertc/schemas](https://github.com/observertc/schemas)).
102
+ 3. **Ingestion**: The `ClientSample` is passed to the `observer.accept()` method.
103
+ 4. **Processing**: `observer-js` processes the sample, updating or creating relevant entities (`ObservedCall`, `ObservedClient`, `ObservedPeerConnection`, etc.) and their metrics.
104
+ 5. **Analysis**: Metrics are analyzed for issue detection and quality scoring.
105
+ 6. **Events**: Events are emitted for significant state changes, new issues, or updates.
106
+
107
+ #### 2.2. Entity Hierarchy
5
108
 
6
- * [Quick Start](#quick-start)
7
- * [Configurations](#configurations)
8
- * [NPM package](#npm-package)
9
- * [Schemas](#schemas)
10
- * [License](#license)
109
+ - **`Observer`**: The root object, managing multiple calls and global settings.
110
+ - **`ObservedCall`**: Represents a distinct call session.
111
+ - **`ObservedClient`**: Represents an individual participant within a call.
112
+ - **`ObservedPeerConnection`**: Represents a WebRTC RTCPeerConnection of a client.
113
+ - **`ObservedInboundRtpStream` / `ObservedOutboundRtpStream`**: Tracks individual media streams.
114
+ - **`ObservedDataChannel`**: Tracks data channels.
115
+ - **`ObservedTURN`**: Tracks global TURN server usage metrics across the observer.
11
116
 
12
- ## Qucik Start
117
+ #### 2.3. Automatic Entity Creation
13
118
 
14
- Install it from [npm](https://www.npmjs.com/package/@observertc/observer-js) package repository.
119
+ When `observer.accept(sample)` is called:
15
120
 
121
+ - If an `ObservedCall` for `sample.callId` doesn't exist, it's typically created.
122
+ - If an `ObservedClient` for `sample.clientId` within that call doesn't exist, it's typically created.
123
+ - Peer connections, streams, and data channels are similarly managed based on IDs in the sample.
124
+
125
+ #### 2.4. Metrics Aggregation
126
+
127
+ The library aggregates a wide array of metrics at each level of the hierarchy, including (but not limited to):
128
+
129
+ - RTT, jitter, packet loss
130
+ - Bytes sent/received (audio, video, data)
131
+ - Codec information
132
+ - ICE connection details, TURN usage
133
+ - Stream/track states (muted, enabled)
134
+ - Frame rates, resolutions
135
+ - Bandwidth estimations
136
+
137
+ #### 2.5. Issue Detection
138
+
139
+ A `Detectors` system analyzes metrics to identify common WebRTC issues (e.g., high packet loss, low audio levels, frozen video, connection setup problems). Issues are reported via events.
140
+
141
+ #### 2.6. Quality Scoring
142
+
143
+ `ScoreCalculator` components assess the quality of calls and clients based on metrics and detected issues, typically resulting in a numerical score (e.g., 0.0 to 5.0).
144
+
145
+ #### 2.7. Event-Driven Architecture
146
+
147
+ The library uses Node.js `EventEmitter` to signal various occurrences, allowing applications to react to changes in real-time.
148
+
149
+ ### 3. API Reference
150
+
151
+ #### 3.1. `Observer`
152
+
153
+ Manages all monitored calls and global observer state.
154
+
155
+ **Configuration (`ObserverConfig`)**
156
+
157
+ ```typescript
158
+ export type ObserverConfig<AppData extends Record<string, unknown> = Record<string, unknown>> = {
159
+ updatePolicy?: 'update-on-any-call-updated' | 'update-when-all-call-updated' | 'update-on-interval';
160
+ updateIntervalInMs?: number; // Used if updatePolicy is 'update-on-interval'
161
+ defaultCallUpdatePolicy?: ObservedCallSettings['updatePolicy'];
162
+ defaultCallUpdateIntervalInMs?: number;
163
+ appData?: AppData; // Custom data for this observer instance
164
+ };
16
165
  ```
17
- npm i @observertc/observer-js
166
+
167
+ **Constructor**
168
+
169
+ ```typescript
170
+ new Observer<AppData>(config?: ObserverConfig<AppData>)
18
171
  ```
19
172
 
20
- Use it in your server side NodeJS app.
173
+ - `config`: Optional. Defaults: `updatePolicy: 'update-when-all-call-updated'`.
21
174
 
22
- ```javascript
23
- import { createObserver, ClientSample } from "@observertc/observer-js";
175
+ **Key Properties**
24
176
 
25
- const observer = createObserver({
26
- defaultServiceId: 'my-service-name',
27
- defaultMediaUnitId: 'my-reporting-component',
28
- });
177
+ - `observedCalls: Map<string, ObservedCall>`: Active calls.
178
+ - `observedTURN: ObservedTURN`: Aggregated TURN metrics.
179
+ - `appData: AppData | undefined`: Custom application data.
180
+ - `closed: boolean`: True if `close()` has been called.
181
+ - Counters: `totalAddedCall`, `totalRemovedCall`, RTT buckets, `totalClientIssues`, `numberOfClientsUsingTurn`, `numberOfClients`, `numberOfPeerConnections`, etc.
29
182
 
30
- const observedCall = observer.createObservedCall({
31
- roomId: 'roomId',
32
- callId: 'room-session-id',
33
- });
183
+ **Key Methods**
34
184
 
35
- const observedClient = observedCall.createObservedClient({
36
- clientId: 'client-id',
37
- mediaUnitId: 'media-unit-id',
38
- });
185
+ - `createObservedCall<T>(settings: ObservedCallSettings<T>): ObservedCall<T>`
186
+ - `getObservedCall<T>(callId: string): ObservedCall<T> | undefined`
187
+ - `accept(sample: ClientSample): void`: A convenience method to feed WebRTC stats. If `sample.callId` and `sample.clientId` are provided, it will route the sample to the appropriate `ObservedCall` and `ObservedClient`, creating them if they don't exist. The core sample processing for an existing client happens within the `ObservedClient`'s own `accept` or update mechanism.
188
+ - `update(): void`: Manually trigger an update cycle (behavior depends on `updatePolicy`).
189
+ - `close(): void`: Cleans up resources for the observer and all its calls.
190
+ - `createEventMonitor<CTX>(ctx?: CTX): ObserverEventMonitor<CTX>`: For contextual event listening.
191
+
192
+ **Events (`ObserverEvents`)**
193
+
194
+ - `'newcall' (call: ObservedCall)`
195
+ - `'call-updated' (call: ObservedCall)`
196
+ - `'client-event' (client: ObservedClient, event: ClientEvent)`
197
+ - `'client-issue' (client: ObservedClient, issue: ClientIssue)`
198
+ - `'client-metadata' (client: ObservedClient, metadata: ClientMetaData)`
199
+ - `'client-extension-stats' (client: ObservedClient, stats: ExtensionStat)`
200
+ - `'update' ()`
201
+ - `'close' ()`
39
202
 
40
- const clientSample: ClientSample; // Receive your samples, for example, from a WebSocket
203
+ #### 3.2. `ObservedCall`
41
204
 
42
- observedClient.accept(clientSample);
205
+ Represents a single call session.
206
+
207
+ **Configuration (`ObservedCallSettings`)**
208
+
209
+ ```typescript
210
+ export type ObservedCallSettings<AppData extends Record<string, unknown> = Record<string, unknown>> = {
211
+ callId: string;
212
+ appData?: AppData;
213
+ updatePolicy?: 'update-on-any-client-updated' | 'update-when-all-client-updated' | 'update-on-interval';
214
+ updateIntervalInMs?: number; // Used if updatePolicy is 'update-on-interval'
215
+ remoteTrackResolvePolicy?: 'mediasoup-sfu'; // For specific SFU integration
216
+ };
43
217
  ```
44
218
 
45
- The above example do as follows:
46
- 1. create an observer to evaluate samples from clients and sfus
47
- 2. create a client source object to accept client samples
48
- 3. add an evaluator process to evaluate ended calls
219
+ **Key Properties**
49
220
 
50
- ### Get a Summary of a call when it ends
221
+ - `callId: string`
222
+ - `appData: AppData | undefined`
223
+ - `numberOfClients: number`
224
+ - `score: number | undefined`: Overall call quality score.
225
+ - `observedClients: Map<string, ObservedClient>`
226
+ - Counters: `totalAddedClients`, `totalRemovedClients`, `numberOfIssues`, RTT buckets, total bytes sent/received (audio/video/data), etc.
51
227
 
52
- ```javascript
228
+ **Key Methods**
53
229
 
54
- const monitor = observer.createCallSummaryMonitor('summary', (summary) => {
55
- console.log('Call Summary', summary);
56
- });
57
- ```
230
+ - `createObservedClient<T>(settings: ObservedClientSettings<T>): ObservedClient<T>`
231
+ - `getObservedClient<T>(clientId: string): ObservedClient<T> | undefined`
232
+ - `update(): void`
233
+ - `close(): void`
234
+ - `createEventMonitor<CTX>(ctx?: CTX): ObservedCallEventMonitor<CTX>`
58
235
 
59
- ### How Many Clients are using TURN?
236
+ **Events (Emitted via `ObservedCall` instance)**
60
237
 
61
- ```javascript
62
- const monitor = observer.createTurnUsageMonitor('turn', (turn) => {
63
- console.log('TURN', turn);
64
- });
238
+ - `'newclient' (client: ObservedClient)`
239
+ - `'empty' ()`: When the last client leaves.
240
+ - `'not-empty' ()`: When the first client joins an empty call.
241
+ - `'update' ()`
242
+ - `'close' ()`
65
243
 
66
- // at any point of time you can get the current state of the turn usage
244
+ #### 3.3. `ObservedClient`
67
245
 
68
- console.log('Currently ', monitor.clients.size, 'clients are using TURN');
246
+ Represents a participant in a call.
69
247
 
70
- // you can get the incoming and outgoing bytes of the TURN server
71
- console.log(`${YOUR_TURN_SERVER_ADDRESS} usage:`, monitor.getUsage(YOUR_TURN_SERVER_ADDRESS));
248
+ **Configuration (`ObservedClientSettings`)**
72
249
 
250
+ ```typescript
251
+ export type ObservedClientSettings<AppData extends Record<string, unknown> = Record<string, unknown>> = {
252
+ clientId: string;
253
+ appData?: AppData;
254
+ // Potentially other client-specific settings
255
+ };
73
256
  ```
74
257
 
75
- ### Monitor Calls and Clients as they updated
258
+ **Key Properties**
259
+
260
+ - `clientId: string`
261
+ - `call: ObservedCall`: Reference to the parent call.
262
+ - `appData: AppData | undefined`
263
+ - `score: number | undefined`: Client quality score.
264
+ - `numberOfPeerConnections: number`
265
+ - `usingTURN: boolean`
266
+ - `observedPeerConnections: Map<string, ObservedPeerConnection>`
267
+ - Counters: `numberOfIssues`, RTT buckets, total bytes sent/received, `availableIncomingBitrate`, `availableOutgoingBitrate`, etc.
268
+
269
+ **Key Methods**
270
+
271
+ - `accept(sample: ClientSample): void`: (Or a similar internal update method called by `Observer.accept` or `ObservedCall`) Processes a `ClientSample` specific to this client, updating its metrics, peer connections, streams, etc. This is the primary point where a client's detailed WebRTC statistics are processed.
272
+ - `createObservedPeerConnection<T>(settings: ObservedPeerConnectionSettings<T>): ObservedPeerConnection<T>`
273
+ - `getObservedPeerConnection<T>(peerConnectionId: string): ObservedPeerConnection<T> | undefined`
274
+ - `update(): void`
275
+ - `close(): void`
276
+ - `createEventMonitor<CTX>(ctx?: CTX): ObservedClientEventMonitor<CTX>`
277
+
278
+ **Events (Emitted via `ObservedClient` instance)**
279
+
280
+ - `'joined' ()`
281
+ - `'left' ()`
282
+ - `'update' ()`
283
+ - `'close' ()`
284
+ - `'newpeerconnection' (pc: ObservedPeerConnection)`
285
+ - `'issue' (issue: ClientIssue)` (and other specific issue events)
286
+
287
+ #### 3.4. `ObservedPeerConnection`
288
+
289
+ Represents an `RTCPeerConnection`.
290
+
291
+ - Tracks ICE connection state, data channel stats, stream stats.
292
+ - Holds `ObservedInboundRtpStream`, `ObservedOutboundRtpStream`, and `ObservedDataChannel` instances.
293
+
294
+ #### 3.5. `ObservedInboundRtpStream` / `ObservedOutboundRtpStream`
295
+
296
+ - Track metrics for individual media streams (audio/video) like codec, packets lost/received, jitter, bytes, etc.
297
+
298
+ #### 3.6. `ObservedDataChannel`
299
+
300
+ - Tracks metrics for data channels like state, messages sent/received, bytes.
301
+
302
+ #### 3.7. `ClientSample` (Schema)
303
+
304
+ This is the primary input data structure passed to `observer.accept()`. It's a comprehensive object that should mirror the information obtainable from WebRTC `getStats()` and other client-side states. Key fields include:
305
+
306
+ - `callId`, `clientId`, `timestamp`
307
+ - `peerConnections: RTCPeerConnectionStats[]`
308
+ - `inboundRtpStreams: RTCInboundRtpStreamStats[]`
309
+ - `outboundRtpStreams: RTCOutboundRtpStreamStats[]`
310
+ - `remoteInboundRtpStreams: RTCRemoteInboundRtpStreamStats[]`
311
+ - `remoteOutboundRtpStreams: RTCRemoteOutboundRtpStreamStats[]`
312
+ - `dataChannels: RTCDataChannelStats[]`
313
+ - `iceLocalCandidates: RTCIceCandidateStats[]`, `iceRemoteCandidates: RTCIceCandidateStats[]`, `iceCandidatePairs: RTCIceCandidatePairStats[]`
314
+ - `mediaSources: RTCAudioSourceStats[] / RTCVideoSourceStats[]`
315
+ - `tracks: RTCMediaStreamTrackStats[]`
316
+ - `certificates: RTCCertificateStats[]`
317
+ - `codecs: RTCCodecStats[]`
318
+ - `transports: RTCIceTransportStats[]` (or similar depending on spec version)
319
+ - `browser`, `engine`, `platform`, `os` (client environment metadata)
320
+ - `userMediaErrors`, `iceConnectionStates`, `connectionStates` (client-reported events/states)
321
+ - `extensionStats` (for custom data)
322
+
323
+ _(Refer to the [observertc/schemas](https://github.com/observertc/schemas) repository, particularly the `ClientSample.ts` definition, for the exact and complete structure.)_
324
+
325
+ ### 4. Configuration Possibilities
326
+
327
+ #### 4.1. Update Policies
328
+
329
+ Control how frequently entities re-calculate metrics and emit `update` events.
330
+
331
+ **Observer Level (`ObserverConfig.updatePolicy`)**
332
+
333
+ - `'update-on-any-call-updated'`: Observer updates if any of its calls update.
334
+ - `'update-when-all-call-updated'`: Observer updates after all its calls update. (Default)
335
+ - `'update-on-interval'`: Observer updates at `ObserverConfig.updateIntervalInMs`.
336
+
337
+ **Call Level (`ObservedCallSettings.updatePolicy` or `ObserverConfig.defaultCallUpdatePolicy`)**
338
+
339
+ - `'update-on-any-client-updated'`: Call updates if any of its clients update.
340
+ - `'update-when-all-client-updated'`: Call updates after all its clients update.
341
+ - `'update-on-interval'`: Call updates at its `updateIntervalInMs`.
342
+
343
+ #### 4.2. Intervals
344
+
345
+ - `ObserverConfig.updateIntervalInMs`
346
+ - `ObserverConfig.defaultCallUpdateIntervalInMs`
347
+ - `ObservedCallSettings.updateIntervalInMs`
348
+
349
+ #### 4.3. Application Data (`appData`)
350
+
351
+ Associate custom context with `Observer`, `ObservedCall`, and `ObservedClient` instances using generics.
352
+
353
+ ```typescript
354
+ interface MyCallAppData {
355
+ meetingTitle: string;
356
+ scheduledAt: Date;
357
+ }
358
+ const call = observer.createObservedCall<MyCallAppData>({
359
+ callId: 'call1',
360
+ appData: { meetingTitle: 'Team Sync', scheduledAt: new Date() },
361
+ });
362
+ console.log(call.appData?.meetingTitle);
363
+ ```
364
+
365
+ #### 4.4. `appData` vs. Attachments
366
+
367
+ The `observer-js` library provides two primary ways to associate custom information with its entities: `appData` and `attachments`. Understanding their distinct purposes is key for effective use.
368
+
369
+ **`appData` (Application Data)**
370
+
371
+ - **Purpose**: `appData` is designed to hold structured, typed, and relatively static metadata about an entity (`Observer`, `ObservedCall`, `ObservedClient`). This data is typically set at the time of entity creation and is directly accessible as a property of the entity instance.
372
+ - **Typing**: It is strongly typed using generics (e.g., `Observer<MyObserverAppData>`). This provides type safety and autocompletion in TypeScript environments.
373
+ - **Mutability**: While technically mutable (if the object assigned is mutable), it's generally intended for information that defines or describes the entity and doesn't change frequently during its lifecycle.
374
+ - **Accessibility**: Directly accessible via `entity.appData`.
375
+ - **Use Cases**:
376
+ - Storing application-specific identifiers (e.g., `userId`, `roomId`, `meetingType`).
377
+ - Configuration flags relevant to how your application interprets this entity.
378
+ - Descriptive information (e.g., `clientDeviceType`, `callRegion`).
379
+
380
+ **`attachments` (Arbitrary Attachments)**
381
+
382
+ - **Purpose**: `attachments` (if implemented as a `Map<string, unknown>` or similar mechanism on entities) are meant for associating arbitrary, often dynamic, or less structured data with an entity. This can be useful for temporary state, inter-plugin communication, or data that doesn't fit neatly into a predefined `appData` schema.
383
+ - **Typing**: Typically less strictly typed (e.g., `unknown` or `any` values in a Map). Consumers of attachments need to perform their own type checks or assertions.
384
+ - **Mutability**: Designed to be more dynamic. Attachments can be added, updated, or removed throughout the entity's lifecycle.
385
+ - **Accessibility**: Accessed via methods like `entity.setAttachment(key, value)`, `entity.getAttachment(key)`, `entity.removeAttachment(key)`.
386
+ - **Use Cases**:
387
+ - Storing temporary state calculated by one part of your application to be read by another (e.g., a custom issue detector plugin might attach intermediate findings).
388
+ - Caching results of expensive computations related to the entity.
389
+ - Allowing different modules or plugins to associate their own private data with an observer entity without needing to modify its core `appData` type.
390
+ - Storing large binary data or complex objects that are not part of the core descriptive metadata.
391
+
392
+ **When to Use Which:**
393
+
394
+ - Use **`appData`** for:
395
+ - Core, descriptive metadata that is known at creation time or changes infrequently.
396
+ - Data that benefits from strong typing and is integral to your application's understanding of the entity.
397
+ - Use **`attachments`** for:
398
+ - Dynamic, temporary, or loosely structured data.
399
+ - Data added by different, potentially independent, parts of your system or plugins.
400
+ - Information that doesn't need to be part of the primary, typed `appData` schema.
401
+
402
+ If `attachments` are not yet a formal feature, this section can serve as a design consideration or be adapted if you introduce such a mechanism. If `attachments` are already present, ensure the description matches their actual implementation.
403
+
404
+ #### 4.5. Remote Track Resolution
405
+
406
+ For SFU scenarios, especially with MediaSoup:
407
+ `ObservedCallSettings.remoteTrackResolvePolicy: 'mediasoup-sfu'`
408
+
409
+ ### 5. Examples
410
+
411
+ #### 5.1. Basic Observer Setup & Sample Ingestion
412
+
413
+ ```typescript
414
+ // filepath: /path/to/your/app.ts
415
+ import { Observer, ObserverConfig } from '@observertc/observer-js'; // Adjust path
416
+ import { ClientSample } from '@observertc/schemas'; // Adjust path if using official schemas
417
+
418
+ const observerConfig: ObserverConfig = {
419
+ updatePolicy: 'update-on-interval',
420
+ updateIntervalInMs: 5000,
421
+ defaultCallUpdatePolicy: 'update-on-any-client-updated',
422
+ };
423
+ const observer = new Observer(observerConfig);
76
424
 
77
- ```javascript
78
425
  observer.on('newcall', (call) => {
79
- call.on('update', () => {
80
- console.log('Call Updated', call.callId);
81
- });
426
+ console.log(`[Observer] New call: ${call.callId}`);
427
+ call.on('update', () => {
428
+ console.log(`[Call: ${call.callId}] Updated. Clients: ${call.numberOfClients}, Score: ${call.score?.toFixed(1)}`);
429
+ });
430
+ call.on('newclient', (client) => {
431
+ console.log(`[Call: ${call.callId}] New client: ${client.clientId}`);
432
+ client.on('update', () => {
433
+ // console.log(`[Client: ${client.clientId}] Updated. Score: ${client.score?.toFixed(1)}`);
434
+ });
435
+ client.on('issue', (issue) => {
436
+ console.warn(`[Client: ${client.clientId}] Issue: ${issue.type} - ${issue.severity} - ${issue.description}`);
437
+ });
438
+ });
439
+ });
82
440
 
83
- call.on('newclient', (client) => {
441
+ // Function to transform your app's WebRTC stats to ClientSample
442
+ function mapStatsToClientSample(appStats: any, callId: string, clientId: string): ClientSample {
443
+ // Detailed mapping logic here based on ClientSample.ts schema
444
+ // from github.com/observertc/schemas
445
+ return {
446
+ callId,
447
+ clientId,
448
+ timestamp: Date.now(),
449
+ // ... map all relevant stats fields ...
450
+ } as ClientSample; // Ensure all required fields are present
451
+ }
452
+
453
+ // Example: Receiving stats and processing
454
+ const rawStatsFromClient = {
455
+ /* ... your client's getStats() output ... */
456
+ };
457
+ const callId = 'meeting-alpha-123';
458
+ const clientId = 'user-xyz-789';
459
+ const sample = mapStatsToClientSample(rawStatsFromClient, callId, clientId);
460
+ observer.accept(sample);
461
+
462
+ // Later, on application shutdown:
463
+ // observer.close();
464
+ ```
84
465
 
85
- client.on('update', () => {
86
- console.log('Client Updated', client.clientId);
466
+ #### 5.2. Manual Call and Client Creation
87
467
 
88
- console.log(`The avaialble incoming bitrate for the client ${client.clientId} is: ${client.availableIncomingBitrate}`)
89
- });
90
- })
468
+ ```typescript
469
+ // ... observer setup ...
470
+
471
+ const call = observer.createObservedCall({
472
+ callId: 'scheduled-webinar-456',
473
+ updatePolicy: 'update-on-interval',
474
+ updateIntervalInMs: 10000,
91
475
  });
476
+
477
+ const client1 = call.createObservedClient({ clientId: 'presenter-01' });
478
+ // Samples for 'presenter-01' in call 'scheduled-webinar-456' will update this client.
92
479
  ```
93
480
 
94
- ## NPM package
481
+ #### 5.3. Using Event Monitors for Contextual Logging
482
+
483
+ ```typescript
484
+ const call = observer.getObservedCall('meeting-alpha-123');
485
+ if (call) {
486
+ const callMonitor = call.createEventMonitor({ callId: call.callId, started: new Date() });
487
+ callMonitor.on('client-joined', (client, context) => {
488
+ console.log(`EVENT_MONITOR (${context.callId}): Client ${client.clientId} joined at ${new Date()}`);
489
+ });
490
+ callMonitor.on('issue-detected', (client, issue, context) => {
491
+ console.error(`EVENT_MONITOR (${context.callId}): Issue on ${client.clientId} - ${issue.description}`);
492
+ });
493
+ }
494
+ ```
95
495
 
96
- https://www.npmjs.com/package/@observertc/observer-js
496
+ ### 6. Best Practices
97
497
 
498
+ - **Resource Management**: Always call `observer.close()`, `call.close()`, and `client.close()` when entities are no longer needed to free resources and stop timers.
499
+ - **Error Handling**: Wrap calls to library methods in `try...catch` blocks where appropriate, especially for operations that might throw errors based on state (e.g., creating an entity that already exists if not using `getOrCreate` patterns).
500
+ - **Event Listener Cleanup**: If dynamically adding/removing listeners, ensure they are properly removed (e.g., using `emitter.off()` or `emitter.removeListener()`) to prevent memory leaks, especially for short-lived monitored entities.
501
+ - **`ClientSample` Accuracy**: The quality of monitoring heavily depends on the completeness and correctness of the `ClientSample` data provided. Ensure thorough mapping from `getStats()`.
502
+ - **Update Policies**: Choose update policies carefully based on the desired granularity of updates and performance considerations.
98
503
 
99
- ## Schemas
504
+ ### 7. Troubleshooting
505
+
506
+ - **Memory Leaks**: Ensure `close()` is called on all entities. Check for unremoved event listeners.
507
+ - **No Events / Missing Updates**:
508
+ - Verify `observer.accept()` is being called with correctly formatted `ClientSample` data.
509
+ - Ensure `callId` and `clientId` in samples match expectations.
510
+ - Check if `updatePolicy` and `updateIntervalInMs` are configured as intended.
511
+ - **Debugging**: Utilize `console.log` within event handlers at different levels (Observer, Call, Client) to trace data flow and state changes. Use `appData` to add correlation IDs for easier debugging.
512
+
513
+ ### 8. TypeScript Support
514
+
515
+ The library is written in TypeScript and provides type definitions.
516
+ Use generics with `Observer`, `ObservedCall`, and `ObservedClient` to type your custom `appData`.
517
+
518
+ ```typescript
519
+ interface MyClientAppData {
520
+ userId: string;
521
+ role: 'admin' | 'user';
522
+ }
523
+ const client = call.createObservedClient<MyClientAppData>({
524
+ clientId: 'user1',
525
+ appData: { userId: 'u-123', role: 'admin' },
526
+ });
527
+ // client.appData will be typed as MyClientAppData | undefined
528
+ ```
100
529
 
101
- https://github.com/observertc/schemas
530
+ ### 9. Contributing
102
531
 
532
+ (Placeholder for contribution guidelines - e.g., link to CONTRIBUTING.md, coding standards, pull request process)
103
533
 
104
- ## License
534
+ ### 10. License
105
535
 
106
- Apache-2.0
536
+ This project is licensed under the [MIT License](LICENSE).