matrix-js-sdk 41.8.0 → 41.9.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 (458) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/README.md +1 -1
  3. package/lib/@types/AESEncryptedSecretStoragePayload.js +3 -1
  4. package/lib/@types/IIdentityServerProvider.js +3 -1
  5. package/lib/@types/PushRules.js +7 -7
  6. package/lib/@types/PushRules.js.map +1 -1
  7. package/lib/@types/auth.js +4 -4
  8. package/lib/@types/auth.js.map +1 -1
  9. package/lib/@types/beacon.js +2 -2
  10. package/lib/@types/beacon.js.map +1 -1
  11. package/lib/@types/common.js +3 -1
  12. package/lib/@types/crypto.js +3 -1
  13. package/lib/@types/event.js +20 -20
  14. package/lib/@types/event.js.map +1 -1
  15. package/lib/@types/events.js +3 -1
  16. package/lib/@types/extensible_events.js +6 -6
  17. package/lib/@types/extensible_events.js.map +1 -1
  18. package/lib/@types/global.d.js.map +1 -1
  19. package/lib/@types/json.js +3 -1
  20. package/lib/@types/local_notifications.js +3 -1
  21. package/lib/@types/location.js +4 -4
  22. package/lib/@types/location.js.map +1 -1
  23. package/lib/@types/matrix-sdk-crypto-wasm.d.js +3 -1
  24. package/lib/@types/media.js +3 -1
  25. package/lib/@types/membership.js +1 -1
  26. package/lib/@types/membership.js.map +1 -1
  27. package/lib/@types/partials.js +6 -6
  28. package/lib/@types/partials.js.map +1 -1
  29. package/lib/@types/polls.js +5 -5
  30. package/lib/@types/polls.js.map +1 -1
  31. package/lib/@types/read_receipts.js +2 -2
  32. package/lib/@types/read_receipts.js.map +1 -1
  33. package/lib/@types/registration.js +3 -1
  34. package/lib/@types/requests.js +1 -1
  35. package/lib/@types/requests.js.map +1 -1
  36. package/lib/@types/retention.js +1 -1
  37. package/lib/@types/retention.js.map +1 -1
  38. package/lib/@types/search.js +1 -1
  39. package/lib/@types/search.js.map +1 -1
  40. package/lib/@types/signed.js +3 -1
  41. package/lib/@types/spaces.js +3 -1
  42. package/lib/@types/state_events.js +3 -1
  43. package/lib/@types/synapse.js +3 -1
  44. package/lib/@types/sync.js +1 -1
  45. package/lib/@types/sync.js.map +1 -1
  46. package/lib/@types/threepids.js +1 -1
  47. package/lib/@types/threepids.js.map +1 -1
  48. package/lib/@types/topic.js +1 -1
  49. package/lib/@types/topic.js.map +1 -1
  50. package/lib/@types/uia.js +3 -1
  51. package/lib/NamespacedValue.js +8 -8
  52. package/lib/NamespacedValue.js.map +1 -1
  53. package/lib/ReEmitter.js +9 -16
  54. package/lib/ReEmitter.js.map +1 -1
  55. package/lib/ToDeviceMessageQueue.js +49 -57
  56. package/lib/ToDeviceMessageQueue.js.map +1 -1
  57. package/lib/autodiscovery.js +232 -247
  58. package/lib/autodiscovery.js.map +1 -1
  59. package/lib/base64.js +1 -1
  60. package/lib/base64.js.map +1 -1
  61. package/lib/browser-index.d.ts +2 -2
  62. package/lib/browser-index.d.ts.map +1 -1
  63. package/lib/browser-index.js +5 -5
  64. package/lib/browser-index.js.map +1 -1
  65. package/lib/capabilityPoller.js +19 -22
  66. package/lib/capabilityPoller.js.map +1 -1
  67. package/lib/client.d.ts +2 -8
  68. package/lib/client.d.ts.map +1 -1
  69. package/lib/client.js +2043 -2487
  70. package/lib/client.js.map +1 -1
  71. package/lib/common-crypto/CryptoBackend.js +2 -2
  72. package/lib/common-crypto/CryptoBackend.js.map +1 -1
  73. package/lib/common-crypto/key-passphrase.js.map +1 -1
  74. package/lib/content-helpers.js +43 -48
  75. package/lib/content-helpers.js.map +1 -1
  76. package/lib/content-repo.js +14 -24
  77. package/lib/content-repo.js.map +1 -1
  78. package/lib/crypto/store/base.js +6 -6
  79. package/lib/crypto/store/base.js.map +1 -1
  80. package/lib/crypto/store/indexeddb-crypto-store-backend.js +190 -238
  81. package/lib/crypto/store/indexeddb-crypto-store-backend.js.map +1 -1
  82. package/lib/crypto/store/indexeddb-crypto-store.js +25 -30
  83. package/lib/crypto/store/indexeddb-crypto-store.js.map +1 -1
  84. package/lib/crypto/store/localStorage-crypto-store.js +113 -145
  85. package/lib/crypto/store/localStorage-crypto-store.js.map +1 -1
  86. package/lib/crypto/store/memory-crypto-store.js +74 -105
  87. package/lib/crypto/store/memory-crypto-store.js.map +1 -1
  88. package/lib/crypto-api/CryptoEvent.js +1 -1
  89. package/lib/crypto-api/CryptoEvent.js.map +1 -1
  90. package/lib/crypto-api/CryptoEventHandlerMap.js +3 -1
  91. package/lib/crypto-api/index.d.ts +15 -6
  92. package/lib/crypto-api/index.d.ts.map +1 -1
  93. package/lib/crypto-api/index.js +22 -22
  94. package/lib/crypto-api/index.js.map +1 -1
  95. package/lib/crypto-api/key-passphrase.js +15 -23
  96. package/lib/crypto-api/key-passphrase.js.map +1 -1
  97. package/lib/crypto-api/keybackup.js +3 -1
  98. package/lib/crypto-api/recovery-key.js +11 -12
  99. package/lib/crypto-api/recovery-key.js.map +1 -1
  100. package/lib/crypto-api/verification.js +3 -3
  101. package/lib/crypto-api/verification.js.map +1 -1
  102. package/lib/digest.js +7 -14
  103. package/lib/digest.js.map +1 -1
  104. package/lib/embedded.d.ts.map +1 -1
  105. package/lib/embedded.js +380 -505
  106. package/lib/embedded.js.map +1 -1
  107. package/lib/errors.js +2 -2
  108. package/lib/errors.js.map +1 -1
  109. package/lib/event-mapper.js +10 -12
  110. package/lib/event-mapper.js.map +1 -1
  111. package/lib/extensible_events_v1/ExtensibleEvent.js.map +1 -1
  112. package/lib/extensible_events_v1/InvalidEventError.js.map +1 -1
  113. package/lib/extensible_events_v1/MessageEvent.js +11 -13
  114. package/lib/extensible_events_v1/MessageEvent.js.map +1 -1
  115. package/lib/extensible_events_v1/PollEndEvent.js +3 -4
  116. package/lib/extensible_events_v1/PollEndEvent.js.map +1 -1
  117. package/lib/extensible_events_v1/PollResponseEvent.js +5 -6
  118. package/lib/extensible_events_v1/PollResponseEvent.js.map +1 -1
  119. package/lib/extensible_events_v1/PollStartEvent.js +8 -10
  120. package/lib/extensible_events_v1/PollStartEvent.js.map +1 -1
  121. package/lib/extensible_events_v1/utilities.js.map +1 -1
  122. package/lib/feature.js +18 -31
  123. package/lib/feature.js.map +1 -1
  124. package/lib/filter-component.d.ts.map +1 -1
  125. package/lib/filter-component.js +20 -26
  126. package/lib/filter-component.js.map +1 -1
  127. package/lib/filter.js +14 -17
  128. package/lib/filter.js.map +1 -1
  129. package/lib/http-api/errors.js +28 -43
  130. package/lib/http-api/errors.js.map +1 -1
  131. package/lib/http-api/fetch.js +141 -159
  132. package/lib/http-api/fetch.js.map +1 -1
  133. package/lib/http-api/index.js +17 -20
  134. package/lib/http-api/index.js.map +1 -1
  135. package/lib/http-api/interface.js +1 -1
  136. package/lib/http-api/interface.js.map +1 -1
  137. package/lib/http-api/method.js +1 -1
  138. package/lib/http-api/method.js.map +1 -1
  139. package/lib/http-api/prefix.js +3 -3
  140. package/lib/http-api/prefix.js.map +1 -1
  141. package/lib/http-api/refresh.js +74 -94
  142. package/lib/http-api/refresh.js.map +1 -1
  143. package/lib/http-api/utils.d.ts +1 -1
  144. package/lib/http-api/utils.d.ts.map +1 -1
  145. package/lib/http-api/utils.js +34 -42
  146. package/lib/http-api/utils.js.map +1 -1
  147. package/lib/index.js.map +1 -1
  148. package/lib/indexeddb-helpers.js +3 -3
  149. package/lib/indexeddb-helpers.js.map +1 -1
  150. package/lib/indexeddb-worker.js.map +1 -1
  151. package/lib/interactive-auth.d.ts +5 -5
  152. package/lib/interactive-auth.d.ts.map +1 -1
  153. package/lib/interactive-auth.js +172 -204
  154. package/lib/interactive-auth.js.map +1 -1
  155. package/lib/logger.js +21 -57
  156. package/lib/logger.js.map +1 -1
  157. package/lib/matrix.js +7 -11
  158. package/lib/matrix.js.map +1 -1
  159. package/lib/matrixrtc/CallMembership.js +80 -74
  160. package/lib/matrixrtc/CallMembership.js.map +1 -1
  161. package/lib/matrixrtc/EncryptionManager.js +1 -1
  162. package/lib/matrixrtc/EncryptionManager.js.map +1 -1
  163. package/lib/matrixrtc/IKeyTransport.js +1 -1
  164. package/lib/matrixrtc/IKeyTransport.js.map +1 -1
  165. package/lib/matrixrtc/IMembershipManager.js +1 -1
  166. package/lib/matrixrtc/IMembershipManager.js.map +1 -1
  167. package/lib/matrixrtc/LivekitTransport.d.ts +1 -1
  168. package/lib/matrixrtc/LivekitTransport.js +4 -4
  169. package/lib/matrixrtc/LivekitTransport.js.map +1 -1
  170. package/lib/matrixrtc/MatrixRTCSession.js +137 -187
  171. package/lib/matrixrtc/MatrixRTCSession.js.map +1 -1
  172. package/lib/matrixrtc/MatrixRTCSessionManager.js +36 -41
  173. package/lib/matrixrtc/MatrixRTCSessionManager.js.map +1 -1
  174. package/lib/matrixrtc/MembershipManager.js +332 -378
  175. package/lib/matrixrtc/MembershipManager.js.map +1 -1
  176. package/lib/matrixrtc/MembershipManagerActionScheduler.js +54 -63
  177. package/lib/matrixrtc/MembershipManagerActionScheduler.js.map +1 -1
  178. package/lib/matrixrtc/RTCEncryptionManager.js +119 -143
  179. package/lib/matrixrtc/RTCEncryptionManager.js.map +1 -1
  180. package/lib/matrixrtc/ToDeviceKeyTransport.js +53 -58
  181. package/lib/matrixrtc/ToDeviceKeyTransport.js.map +1 -1
  182. package/lib/matrixrtc/index.js.map +1 -1
  183. package/lib/matrixrtc/membershipData/common.js +1 -1
  184. package/lib/matrixrtc/membershipData/common.js.map +1 -1
  185. package/lib/matrixrtc/membershipData/index.js.map +1 -1
  186. package/lib/matrixrtc/membershipData/rtc.js +15 -23
  187. package/lib/matrixrtc/membershipData/rtc.js.map +1 -1
  188. package/lib/matrixrtc/membershipData/session.js +4 -5
  189. package/lib/matrixrtc/membershipData/session.js.map +1 -1
  190. package/lib/matrixrtc/types.js +4 -6
  191. package/lib/matrixrtc/types.js.map +1 -1
  192. package/lib/matrixrtc/utils.js +4 -11
  193. package/lib/matrixrtc/utils.js.map +1 -1
  194. package/lib/models/MSC3089Branch.js +91 -116
  195. package/lib/models/MSC3089Branch.js.map +1 -1
  196. package/lib/models/MSC3089TreeSpace.js +209 -245
  197. package/lib/models/MSC3089TreeSpace.js.map +1 -1
  198. package/lib/models/ToDeviceMessage.js +3 -1
  199. package/lib/models/beacon.js +14 -13
  200. package/lib/models/beacon.js.map +1 -1
  201. package/lib/models/compare-event-ordering.js +13 -13
  202. package/lib/models/compare-event-ordering.js.map +1 -1
  203. package/lib/models/device.js +3 -3
  204. package/lib/models/device.js.map +1 -1
  205. package/lib/models/event-context.js +5 -8
  206. package/lib/models/event-context.js.map +1 -1
  207. package/lib/models/event-status.js +1 -1
  208. package/lib/models/event-status.js.map +1 -1
  209. package/lib/models/event-timeline-set.js +88 -94
  210. package/lib/models/event-timeline-set.js.map +1 -1
  211. package/lib/models/event-timeline.js +28 -30
  212. package/lib/models/event-timeline.js.map +1 -1
  213. package/lib/models/event.js +182 -226
  214. package/lib/models/event.js.map +1 -1
  215. package/lib/models/invites-ignorer-types.js +4 -4
  216. package/lib/models/invites-ignorer-types.js.map +1 -1
  217. package/lib/models/invites-ignorer.js +159 -179
  218. package/lib/models/invites-ignorer.js.map +1 -1
  219. package/lib/models/poll.js +71 -81
  220. package/lib/models/poll.js.map +1 -1
  221. package/lib/models/profile-keys.js +2 -2
  222. package/lib/models/profile-keys.js.map +1 -1
  223. package/lib/models/read-receipt.js +40 -56
  224. package/lib/models/read-receipt.js.map +1 -1
  225. package/lib/models/related-relations.js.map +1 -1
  226. package/lib/models/relations-container.js +22 -23
  227. package/lib/models/relations-container.js.map +1 -1
  228. package/lib/models/relations.js +133 -159
  229. package/lib/models/relations.js.map +1 -1
  230. package/lib/models/room-member.js +24 -29
  231. package/lib/models/room-member.js.map +1 -1
  232. package/lib/models/room-receipts.js +29 -43
  233. package/lib/models/room-receipts.js.map +1 -1
  234. package/lib/models/room-retention.js +74 -83
  235. package/lib/models/room-retention.js.map +1 -1
  236. package/lib/models/room-state.js +143 -172
  237. package/lib/models/room-state.js.map +1 -1
  238. package/lib/models/room-sticky-events.d.ts +1 -0
  239. package/lib/models/room-sticky-events.d.ts.map +1 -1
  240. package/lib/models/room-sticky-events.js +45 -65
  241. package/lib/models/room-sticky-events.js.map +1 -1
  242. package/lib/models/room-summary.js.map +1 -1
  243. package/lib/models/room.d.ts.map +1 -1
  244. package/lib/models/room.js +765 -909
  245. package/lib/models/room.js.map +1 -1
  246. package/lib/models/search-result.js +5 -5
  247. package/lib/models/search-result.js.map +1 -1
  248. package/lib/models/thread.js +225 -285
  249. package/lib/models/thread.js.map +1 -1
  250. package/lib/models/typed-event-emitter.js +7 -18
  251. package/lib/models/typed-event-emitter.js.map +1 -1
  252. package/lib/models/user.js +8 -8
  253. package/lib/models/user.js.map +1 -1
  254. package/lib/oidc/authorize.js +208 -241
  255. package/lib/oidc/authorize.js.map +1 -1
  256. package/lib/oidc/discovery.js +23 -36
  257. package/lib/oidc/discovery.js.map +1 -1
  258. package/lib/oidc/error.js +1 -1
  259. package/lib/oidc/error.js.map +1 -1
  260. package/lib/oidc/index.js +1 -0
  261. package/lib/oidc/index.js.map +1 -1
  262. package/lib/oidc/register.js +60 -66
  263. package/lib/oidc/register.js.map +1 -1
  264. package/lib/oidc/tokenRefresher.js +77 -91
  265. package/lib/oidc/tokenRefresher.js.map +1 -1
  266. package/lib/oidc/validate.js +18 -18
  267. package/lib/oidc/validate.js.map +1 -1
  268. package/lib/pushprocessor.js +71 -82
  269. package/lib/pushprocessor.js.map +1 -1
  270. package/lib/randomstring.js +9 -9
  271. package/lib/randomstring.js.map +1 -1
  272. package/lib/realtime-callbacks.js +25 -28
  273. package/lib/realtime-callbacks.js.map +1 -1
  274. package/lib/receipt-accumulator.d.ts +2 -0
  275. package/lib/receipt-accumulator.d.ts.map +1 -1
  276. package/lib/receipt-accumulator.js +14 -22
  277. package/lib/receipt-accumulator.js.map +1 -1
  278. package/lib/rendezvous/MSC4108SignInWithQR.js +271 -302
  279. package/lib/rendezvous/MSC4108SignInWithQR.js.map +1 -1
  280. package/lib/rendezvous/RendezvousChannel.js +3 -1
  281. package/lib/rendezvous/RendezvousCode.js +3 -1
  282. package/lib/rendezvous/RendezvousError.js.map +1 -1
  283. package/lib/rendezvous/RendezvousFailureReason.js +2 -2
  284. package/lib/rendezvous/RendezvousFailureReason.js.map +1 -1
  285. package/lib/rendezvous/RendezvousIntent.js +1 -1
  286. package/lib/rendezvous/RendezvousIntent.js.map +1 -1
  287. package/lib/rendezvous/RendezvousTransport.js +3 -1
  288. package/lib/rendezvous/channels/MSC4108SecureChannel.js +123 -147
  289. package/lib/rendezvous/channels/MSC4108SecureChannel.js.map +1 -1
  290. package/lib/rendezvous/index.js +44 -69
  291. package/lib/rendezvous/index.js.map +1 -1
  292. package/lib/rendezvous/transports/MSC4108RendezvousSession.d.ts +1 -1
  293. package/lib/rendezvous/transports/MSC4108RendezvousSession.js +134 -152
  294. package/lib/rendezvous/transports/MSC4108RendezvousSession.js.map +1 -1
  295. package/lib/retentionPolicy.js +6 -9
  296. package/lib/retentionPolicy.js.map +1 -1
  297. package/lib/room-hierarchy.js +52 -60
  298. package/lib/room-hierarchy.js.map +1 -1
  299. package/lib/rust-crypto/CrossSigningIdentity.js +94 -104
  300. package/lib/rust-crypto/CrossSigningIdentity.js.map +1 -1
  301. package/lib/rust-crypto/DehydratedDeviceManager.js +157 -190
  302. package/lib/rust-crypto/DehydratedDeviceManager.js.map +1 -1
  303. package/lib/rust-crypto/KeyClaimManager.js +18 -22
  304. package/lib/rust-crypto/KeyClaimManager.js.map +1 -1
  305. package/lib/rust-crypto/OutgoingRequestProcessor.js +109 -139
  306. package/lib/rust-crypto/OutgoingRequestProcessor.js.map +1 -1
  307. package/lib/rust-crypto/OutgoingRequestsManager.js +66 -80
  308. package/lib/rust-crypto/OutgoingRequestsManager.js.map +1 -1
  309. package/lib/rust-crypto/PerSessionKeyBackupDownloader.d.ts +1 -1
  310. package/lib/rust-crypto/PerSessionKeyBackupDownloader.js +196 -224
  311. package/lib/rust-crypto/PerSessionKeyBackupDownloader.js.map +1 -1
  312. package/lib/rust-crypto/RoomEncryptor.js +127 -143
  313. package/lib/rust-crypto/RoomEncryptor.js.map +1 -1
  314. package/lib/rust-crypto/backup.js +453 -549
  315. package/lib/rust-crypto/backup.js.map +1 -1
  316. package/lib/rust-crypto/constants.js +1 -1
  317. package/lib/rust-crypto/constants.js.map +1 -1
  318. package/lib/rust-crypto/device-converter.js +15 -28
  319. package/lib/rust-crypto/device-converter.js.map +1 -1
  320. package/lib/rust-crypto/index.js +103 -116
  321. package/lib/rust-crypto/index.js.map +1 -1
  322. package/lib/rust-crypto/libolm_migration.js +303 -365
  323. package/lib/rust-crypto/libolm_migration.js.map +1 -1
  324. package/lib/rust-crypto/rust-crypto.d.ts +5 -1
  325. package/lib/rust-crypto/rust-crypto.d.ts.map +1 -1
  326. package/lib/rust-crypto/rust-crypto.js +1067 -1332
  327. package/lib/rust-crypto/rust-crypto.js.map +1 -1
  328. package/lib/rust-crypto/secret-storage.js +12 -25
  329. package/lib/rust-crypto/secret-storage.js.map +1 -1
  330. package/lib/rust-crypto/verification.js +137 -189
  331. package/lib/rust-crypto/verification.js.map +1 -1
  332. package/lib/scheduler.js +44 -19
  333. package/lib/scheduler.js.map +1 -1
  334. package/lib/secret-storage.js +179 -213
  335. package/lib/secret-storage.js.map +1 -1
  336. package/lib/serverCapabilities.js +6 -9
  337. package/lib/serverCapabilities.js.map +1 -1
  338. package/lib/service-types.js +1 -1
  339. package/lib/service-types.js.map +1 -1
  340. package/lib/sliding-sync-sdk.d.ts.map +1 -1
  341. package/lib/sliding-sync-sdk.js +368 -424
  342. package/lib/sliding-sync-sdk.js.map +1 -1
  343. package/lib/sliding-sync.js +135 -171
  344. package/lib/sliding-sync.js.map +1 -1
  345. package/lib/store/index.js +3 -1
  346. package/lib/store/indexeddb-backend.js +3 -1
  347. package/lib/store/indexeddb-local-backend.js +194 -253
  348. package/lib/store/indexeddb-local-backend.js.map +1 -1
  349. package/lib/store/indexeddb-remote-backend.js +33 -63
  350. package/lib/store/indexeddb-remote-backend.js.map +1 -1
  351. package/lib/store/indexeddb-store-worker.js +22 -23
  352. package/lib/store/indexeddb-store-worker.js.map +1 -1
  353. package/lib/store/indexeddb.js +44 -71
  354. package/lib/store/indexeddb.js.map +1 -1
  355. package/lib/store/local-storage-events-emitter.js +2 -2
  356. package/lib/store/local-storage-events-emitter.js.map +1 -1
  357. package/lib/store/memory.js +34 -57
  358. package/lib/store/memory.js.map +1 -1
  359. package/lib/store/stub.js +22 -35
  360. package/lib/store/stub.js.map +1 -1
  361. package/lib/sync-accumulator.js +54 -66
  362. package/lib/sync-accumulator.js.map +1 -1
  363. package/lib/sync.d.ts.map +1 -1
  364. package/lib/sync.js +905 -998
  365. package/lib/sync.js.map +1 -1
  366. package/lib/testing.js +63 -105
  367. package/lib/testing.js.map +1 -1
  368. package/lib/thread-utils.js +1 -4
  369. package/lib/thread-utils.js.map +1 -1
  370. package/lib/timeline-window.js +89 -102
  371. package/lib/timeline-window.js.map +1 -1
  372. package/lib/types.js +1 -1
  373. package/lib/types.js.map +1 -1
  374. package/lib/utils/decryptAESSecretStorageItem.js +14 -25
  375. package/lib/utils/decryptAESSecretStorageItem.js.map +1 -1
  376. package/lib/utils/encryptAESSecretStorageItem.js +27 -38
  377. package/lib/utils/encryptAESSecretStorageItem.js.map +1 -1
  378. package/lib/utils/internal/deriveKeys.js +25 -32
  379. package/lib/utils/internal/deriveKeys.js.map +1 -1
  380. package/lib/utils/roomVersion.js +1 -1
  381. package/lib/utils/roomVersion.js.map +1 -1
  382. package/lib/utils.js +83 -135
  383. package/lib/utils.js.map +1 -1
  384. package/lib/version-support.js +3 -3
  385. package/lib/version-support.js.map +1 -1
  386. package/lib/webrtc/audioContext.js +5 -6
  387. package/lib/webrtc/audioContext.js.map +1 -1
  388. package/lib/webrtc/call.js +1081 -1250
  389. package/lib/webrtc/call.js.map +1 -1
  390. package/lib/webrtc/callEventHandler.js +202 -214
  391. package/lib/webrtc/callEventHandler.js.map +1 -1
  392. package/lib/webrtc/callEventTypes.js +2 -2
  393. package/lib/webrtc/callEventTypes.js.map +1 -1
  394. package/lib/webrtc/callFeed.js +18 -20
  395. package/lib/webrtc/callFeed.js.map +1 -1
  396. package/lib/webrtc/groupCall.js +513 -602
  397. package/lib/webrtc/groupCall.js.map +1 -1
  398. package/lib/webrtc/groupCallEventHandler.js +59 -62
  399. package/lib/webrtc/groupCallEventHandler.js.map +1 -1
  400. package/lib/webrtc/mediaHandler.js +198 -232
  401. package/lib/webrtc/mediaHandler.js.map +1 -1
  402. package/lib/webrtc/stats/callFeedStatsReporter.js +16 -20
  403. package/lib/webrtc/stats/callFeedStatsReporter.js.map +1 -1
  404. package/lib/webrtc/stats/callStatsReportGatherer.js +67 -75
  405. package/lib/webrtc/stats/callStatsReportGatherer.js.map +1 -1
  406. package/lib/webrtc/stats/callStatsReportSummary.js +3 -1
  407. package/lib/webrtc/stats/connectionStats.js.map +1 -1
  408. package/lib/webrtc/stats/connectionStatsBuilder.js +2 -2
  409. package/lib/webrtc/stats/connectionStatsBuilder.js.map +1 -1
  410. package/lib/webrtc/stats/connectionStatsReportBuilder.js +20 -24
  411. package/lib/webrtc/stats/connectionStatsReportBuilder.js.map +1 -1
  412. package/lib/webrtc/stats/groupCallStats.js +6 -8
  413. package/lib/webrtc/stats/groupCallStats.js.map +1 -1
  414. package/lib/webrtc/stats/media/mediaSsrcHandler.js +7 -8
  415. package/lib/webrtc/stats/media/mediaSsrcHandler.js.map +1 -1
  416. package/lib/webrtc/stats/media/mediaTrackHandler.js +7 -9
  417. package/lib/webrtc/stats/media/mediaTrackHandler.js.map +1 -1
  418. package/lib/webrtc/stats/media/mediaTrackStats.js +3 -3
  419. package/lib/webrtc/stats/media/mediaTrackStats.js.map +1 -1
  420. package/lib/webrtc/stats/media/mediaTrackStatsHandler.js +7 -7
  421. package/lib/webrtc/stats/media/mediaTrackStatsHandler.js.map +1 -1
  422. package/lib/webrtc/stats/statsReport.js +1 -1
  423. package/lib/webrtc/stats/statsReport.js.map +1 -1
  424. package/lib/webrtc/stats/statsReportEmitter.js.map +1 -1
  425. package/lib/webrtc/stats/summaryStatsReportGatherer.js +14 -14
  426. package/lib/webrtc/stats/summaryStatsReportGatherer.js.map +1 -1
  427. package/lib/webrtc/stats/trackStatsBuilder.js +32 -34
  428. package/lib/webrtc/stats/trackStatsBuilder.js.map +1 -1
  429. package/lib/webrtc/stats/transportStats.js +3 -1
  430. package/lib/webrtc/stats/transportStatsBuilder.js +9 -9
  431. package/lib/webrtc/stats/transportStatsBuilder.js.map +1 -1
  432. package/lib/webrtc/stats/valueFormatter.js +1 -1
  433. package/lib/webrtc/stats/valueFormatter.js.map +1 -1
  434. package/package.json +18 -33
  435. package/src/@types/global.d.ts +2 -2
  436. package/src/ToDeviceMessageQueue.ts +2 -2
  437. package/src/browser-index.ts +4 -4
  438. package/src/client.ts +15 -20
  439. package/src/crypto-api/index.ts +17 -6
  440. package/src/embedded.ts +4 -6
  441. package/src/filter-component.ts +1 -0
  442. package/src/http-api/utils.ts +1 -1
  443. package/src/interactive-auth.ts +11 -5
  444. package/src/matrixrtc/LivekitTransport.ts +1 -1
  445. package/src/matrixrtc/MatrixRTCSession.ts +1 -1
  446. package/src/models/MSC3089Branch.ts +1 -1
  447. package/src/models/room-sticky-events.ts +1 -0
  448. package/src/models/room.ts +9 -11
  449. package/src/receipt-accumulator.ts +2 -0
  450. package/src/rendezvous/index.ts +1 -1
  451. package/src/rendezvous/transports/MSC4108RendezvousSession.ts +2 -2
  452. package/src/rust-crypto/PerSessionKeyBackupDownloader.ts +1 -1
  453. package/src/rust-crypto/index.ts +6 -6
  454. package/src/rust-crypto/rust-crypto.ts +31 -7
  455. package/src/rust-crypto/verification.ts +1 -1
  456. package/src/sliding-sync-sdk.ts +5 -7
  457. package/src/store/indexeddb-local-backend.ts +3 -3
  458. package/src/sync.ts +6 -8
@@ -1,8 +1,5 @@
1
- import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
2
- import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
1
+ import _objectSpread from "@babel/runtime/helpers/objectSpread2";
3
2
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
4
- function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
5
- function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
6
3
  /*
7
4
  Copyright 2015, 2016 OpenMarket Ltd
8
5
  Copyright 2017 New Vector Ltd
@@ -45,7 +42,7 @@ var CodecName = /*#__PURE__*/function (CodecName) {
45
42
  CodecName["OPUS"] = "opus"; // add more as needed
46
43
  return CodecName;
47
44
  }(CodecName || {}); // Used internally to specify modifications to codec parameters in SDP
48
- export var CallState = /*#__PURE__*/function (CallState) {
45
+ export let CallState = /*#__PURE__*/function (CallState) {
49
46
  CallState["Fledgling"] = "fledgling";
50
47
  CallState["InviteSent"] = "invite_sent";
51
48
  CallState["WaitLocalMedia"] = "wait_local_media";
@@ -57,22 +54,22 @@ export var CallState = /*#__PURE__*/function (CallState) {
57
54
  CallState["Ended"] = "ended";
58
55
  return CallState;
59
56
  }({});
60
- export var CallType = /*#__PURE__*/function (CallType) {
57
+ export let CallType = /*#__PURE__*/function (CallType) {
61
58
  CallType["Voice"] = "voice";
62
59
  CallType["Video"] = "video";
63
60
  return CallType;
64
61
  }({});
65
- export var CallDirection = /*#__PURE__*/function (CallDirection) {
62
+ export let CallDirection = /*#__PURE__*/function (CallDirection) {
66
63
  CallDirection["Inbound"] = "inbound";
67
64
  CallDirection["Outbound"] = "outbound";
68
65
  return CallDirection;
69
66
  }({});
70
- export var CallParty = /*#__PURE__*/function (CallParty) {
67
+ export let CallParty = /*#__PURE__*/function (CallParty) {
71
68
  CallParty["Local"] = "local";
72
69
  CallParty["Remote"] = "remote";
73
70
  return CallParty;
74
71
  }({});
75
- export var CallEvent = /*#__PURE__*/function (CallEvent) {
72
+ export let CallEvent = /*#__PURE__*/function (CallEvent) {
76
73
  CallEvent["Hangup"] = "hangup";
77
74
  CallEvent["State"] = "state";
78
75
  CallEvent["Error"] = "error";
@@ -94,7 +91,7 @@ export var CallEvent = /*#__PURE__*/function (CallEvent) {
94
91
  CallEvent["PeerConnectionCreated"] = "peer_connection_created";
95
92
  return CallEvent;
96
93
  }({});
97
- export var CallErrorCode = /*#__PURE__*/function (CallErrorCode) {
94
+ export let CallErrorCode = /*#__PURE__*/function (CallErrorCode) {
98
95
  /** The user chose to end the call */
99
96
  CallErrorCode["UserHangup"] = "user_hangup";
100
97
  /** An error code when the local client failed to create an offer. */
@@ -173,19 +170,19 @@ export var CallErrorCode = /*#__PURE__*/function (CallErrorCode) {
173
170
  /**
174
171
  * The version field that we set in m.call.* events
175
172
  */
176
- var VOIP_PROTO_VERSION = "1";
173
+ const VOIP_PROTO_VERSION = "1";
177
174
 
178
175
  /** The fallback ICE server to use for STUN or TURN protocols. */
179
- export var FALLBACK_ICE_SERVER = "stun:turn.matrix.org";
176
+ export const FALLBACK_ICE_SERVER = "stun:turn.matrix.org";
180
177
 
181
178
  /** The length of time a call can be ringing for. */
182
- var CALL_TIMEOUT_MS = 60 * 1000; // ms
179
+ const CALL_TIMEOUT_MS = 60 * 1000; // ms
183
180
  /** The time after which we increment callLength */
184
- var CALL_LENGTH_INTERVAL = 1000; // ms
181
+ const CALL_LENGTH_INTERVAL = 1000; // ms
185
182
  /** The time after which we end the call, if ICE got disconnected */
186
- var ICE_DISCONNECTED_TIMEOUT = 30 * 1000; // ms
183
+ const ICE_DISCONNECTED_TIMEOUT = 30 * 1000; // ms
187
184
  /** The time after which we try a ICE restart, if ICE got disconnected */
188
- var ICE_RECONNECTING_TIMEOUT = 2 * 1000; // ms
185
+ const ICE_RECONNECTING_TIMEOUT = 2 * 1000; // ms
189
186
  export class CallError extends Error {
190
187
  constructor(code, msg, err) {
191
188
  // Still don't think there's any way to have proper nested errors
@@ -198,7 +195,7 @@ export function genCallID() {
198
195
  return Date.now().toString() + secureRandomString(16);
199
196
  }
200
197
  function getCodecParamMods(isPtt) {
201
- var mods = [{
198
+ const mods = [{
202
199
  mediaType: "audio",
203
200
  codec: "opus",
204
201
  enableDtx: true,
@@ -236,9 +233,7 @@ export class MatrixCall extends TypedEventEmitter {
236
233
  * @param opts - Config options.
237
234
  */
238
235
  constructor(opts) {
239
- var _this, _opts$forceTURN;
240
236
  super();
241
- _this = this;
242
237
  _defineProperty(this, "roomId", void 0);
243
238
  _defineProperty(this, "callId", void 0);
244
239
  _defineProperty(this, "invitee", void 0);
@@ -314,9 +309,9 @@ export class MatrixCall extends TypedEventEmitter {
314
309
  _defineProperty(this, "gotLocalIceCandidate", event => {
315
310
  if (event.candidate) {
316
311
  if (this.candidatesEnded) {
317
- logger.warn("Call ".concat(this.callId, " gotLocalIceCandidate() got candidate after candidates have ended!"));
312
+ logger.warn(`Call ${this.callId} gotLocalIceCandidate() got candidate after candidates have ended!`);
318
313
  }
319
- logger.debug("Call ".concat(this.callId, " got local ICE ").concat(event.candidate.sdpMid, " ").concat(event.candidate.candidate));
314
+ logger.debug(`Call ${this.callId} got local ICE ${event.candidate.sdpMid} ${event.candidate.candidate}`);
320
315
  if (this.callHasEnded()) return;
321
316
 
322
317
  // As with the offer, note we need to make a copy of this object, not
@@ -329,15 +324,14 @@ export class MatrixCall extends TypedEventEmitter {
329
324
  }
330
325
  });
331
326
  _defineProperty(this, "onIceGatheringStateChange", event => {
332
- var _this$peerConn;
333
- logger.debug("Call ".concat(this.callId, " onIceGatheringStateChange() ice gathering state changed to ").concat(this.peerConn.iceGatheringState));
334
- if (((_this$peerConn = this.peerConn) === null || _this$peerConn === void 0 ? void 0 : _this$peerConn.iceGatheringState) === "complete") {
327
+ logger.debug(`Call ${this.callId} onIceGatheringStateChange() ice gathering state changed to ${this.peerConn.iceGatheringState}`);
328
+ if (this.peerConn?.iceGatheringState === "complete") {
335
329
  this.queueCandidate(null); // We should leave it to WebRTC to announce the end
336
- logger.debug("Call ".concat(this.callId, " onIceGatheringStateChange() ice gathering state complete, set candidates have ended"));
330
+ logger.debug(`Call ${this.callId} onIceGatheringStateChange() ice gathering state complete, set candidates have ended`);
337
331
  }
338
332
  });
339
333
  _defineProperty(this, "getLocalOfferFailed", err => {
340
- logger.error("Call ".concat(this.callId, " getLocalOfferFailed() running"), err);
334
+ logger.error(`Call ${this.callId} getLocalOfferFailed() running`, err);
341
335
  this.emit(CallEvent.Error, new CallError(CallErrorCode.LocalOfferFailed, "Failed to get local offer!", err), this);
342
336
  this.terminate(CallParty.Local, CallErrorCode.LocalOfferFailed, false);
343
337
  });
@@ -346,7 +340,7 @@ export class MatrixCall extends TypedEventEmitter {
346
340
  this.successor.getUserMediaFailed(err);
347
341
  return;
348
342
  }
349
- logger.warn("Call ".concat(this.callId, " getUserMediaFailed() failed to get user media - ending call"), err);
343
+ logger.warn(`Call ${this.callId} getUserMediaFailed() failed to get user media - ending call`, err);
350
344
  this.emit(CallEvent.Error, new CallError(CallErrorCode.NoUserMedia, "Couldn't start capturing media! Is your microphone set up and does this app have permission?", err), this);
351
345
  this.terminate(CallParty.Local, CallErrorCode.NoUserMedia, false);
352
346
  });
@@ -355,20 +349,19 @@ export class MatrixCall extends TypedEventEmitter {
355
349
  this.successor.placeCallFailed(err);
356
350
  return;
357
351
  }
358
- logger.warn("Call ".concat(this.callId, " placeCallWithCallFeeds() failed - ending call"), err);
352
+ logger.warn(`Call ${this.callId} placeCallWithCallFeeds() failed - ending call`, err);
359
353
  this.emit(CallEvent.Error, new CallError(CallErrorCode.IceFailed, "Couldn't start call! Invalid ICE server configuration.", err), this);
360
354
  this.terminate(CallParty.Local, CallErrorCode.IceFailed, false);
361
355
  });
362
356
  _defineProperty(this, "onIceConnectionStateChanged", () => {
363
- var _this$peerConn2, _this$peerConn3, _this$peerConn$iceCon, _this$peerConn4, _this$peerConn5, _this$peerConn8;
364
357
  if (this.callHasEnded()) {
365
358
  return; // because ICE can still complete as we're ending the call
366
359
  }
367
- logger.debug("Call ".concat(this.callId, " onIceConnectionStateChanged() running (state=").concat((_this$peerConn2 = this.peerConn) === null || _this$peerConn2 === void 0 ? void 0 : _this$peerConn2.iceConnectionState, ", conn=").concat((_this$peerConn3 = this.peerConn) === null || _this$peerConn3 === void 0 ? void 0 : _this$peerConn3.connectionState, ")"));
360
+ logger.debug(`Call ${this.callId} onIceConnectionStateChanged() running (state=${this.peerConn?.iceConnectionState}, conn=${this.peerConn?.connectionState})`);
368
361
 
369
362
  // ideally we'd consider the call to be connected when we get media but
370
363
  // chrome doesn't implement any of the 'onstarted' events yet
371
- if (["connected", "completed"].includes((_this$peerConn$iceCon = (_this$peerConn4 = this.peerConn) === null || _this$peerConn4 === void 0 ? void 0 : _this$peerConn4.iceConnectionState) !== null && _this$peerConn$iceCon !== void 0 ? _this$peerConn$iceCon : "")) {
364
+ if (["connected", "completed"].includes(this.peerConn?.iceConnectionState ?? "")) {
372
365
  clearTimeout(this.iceDisconnectedTimeout);
373
366
  this.iceDisconnectedTimeout = undefined;
374
367
  if (this.iceReconnectionTimeOut) {
@@ -381,34 +374,31 @@ export class MatrixCall extends TypedEventEmitter {
381
374
  this.emit(CallEvent.LengthChanged, Math.round((Date.now() - this.callStartTime) / 1000), this);
382
375
  }, CALL_LENGTH_INTERVAL);
383
376
  }
384
- } else if (((_this$peerConn5 = this.peerConn) === null || _this$peerConn5 === void 0 ? void 0 : _this$peerConn5.iceConnectionState) == "failed") {
385
- var _this$peerConn6;
377
+ } else if (this.peerConn?.iceConnectionState == "failed") {
386
378
  this.candidatesEnded = false;
387
379
  // Firefox for Android does not yet have support for restartIce()
388
380
  // (the types say it's always defined though, so we have to cast
389
381
  // to prevent typescript from warning).
390
- if ((_this$peerConn6 = this.peerConn) !== null && _this$peerConn6 !== void 0 && _this$peerConn6.restartIce) {
391
- var _this$peerConn7;
382
+ if (this.peerConn?.restartIce) {
392
383
  this.candidatesEnded = false;
393
- logger.debug("Call ".concat(this.callId, " onIceConnectionStateChanged() ice restart (state=").concat((_this$peerConn7 = this.peerConn) === null || _this$peerConn7 === void 0 ? void 0 : _this$peerConn7.iceConnectionState, ")"));
384
+ logger.debug(`Call ${this.callId} onIceConnectionStateChanged() ice restart (state=${this.peerConn?.iceConnectionState})`);
394
385
  this.peerConn.restartIce();
395
386
  } else {
396
- logger.info("Call ".concat(this.callId, " onIceConnectionStateChanged() hanging up call (ICE failed and no ICE restart method)"));
387
+ logger.info(`Call ${this.callId} onIceConnectionStateChanged() hanging up call (ICE failed and no ICE restart method)`);
397
388
  this.hangup(CallErrorCode.IceFailed, false);
398
389
  }
399
- } else if (((_this$peerConn8 = this.peerConn) === null || _this$peerConn8 === void 0 ? void 0 : _this$peerConn8.iceConnectionState) == "disconnected") {
390
+ } else if (this.peerConn?.iceConnectionState == "disconnected") {
400
391
  this.candidatesEnded = false;
401
392
  this.iceReconnectionTimeOut = setTimeout(() => {
402
- var _this$peerConn9, _this$peerConn0, _this$peerConn1;
403
- logger.info("Call ".concat(this.callId, " onIceConnectionStateChanged() ICE restarting because of ICE disconnected, (state=").concat((_this$peerConn9 = this.peerConn) === null || _this$peerConn9 === void 0 ? void 0 : _this$peerConn9.iceConnectionState, ", conn=").concat((_this$peerConn0 = this.peerConn) === null || _this$peerConn0 === void 0 ? void 0 : _this$peerConn0.connectionState, ")"));
404
- if ((_this$peerConn1 = this.peerConn) !== null && _this$peerConn1 !== void 0 && _this$peerConn1.restartIce) {
393
+ logger.info(`Call ${this.callId} onIceConnectionStateChanged() ICE restarting because of ICE disconnected, (state=${this.peerConn?.iceConnectionState}, conn=${this.peerConn?.connectionState})`);
394
+ if (this.peerConn?.restartIce) {
405
395
  this.candidatesEnded = false;
406
396
  this.peerConn.restartIce();
407
397
  }
408
398
  this.iceReconnectionTimeOut = undefined;
409
399
  }, ICE_RECONNECTING_TIMEOUT);
410
400
  this.iceDisconnectedTimeout = setTimeout(() => {
411
- logger.info("Call ".concat(this.callId, " onIceConnectionStateChanged() hanging up call (ICE disconnected for too long)"));
401
+ logger.info(`Call ${this.callId} onIceConnectionStateChanged() hanging up call (ICE disconnected for too long)`);
412
402
  this.hangup(CallErrorCode.IceFailed, false);
413
403
  }, ICE_DISCONNECTED_TIMEOUT);
414
404
  this.state = CallState.Connecting;
@@ -419,26 +409,25 @@ export class MatrixCall extends TypedEventEmitter {
419
409
  // Experimenting in Chrome, this happens after 5 or 6 seconds, which is probably
420
410
  // fast enough.
421
411
  if (this.isPtt && ["failed", "disconnected"].includes(this.peerConn.iceConnectionState)) {
422
- for (var feed of this.getRemoteFeeds()) {
412
+ for (const feed of this.getRemoteFeeds()) {
423
413
  feed.setAudioVideoMuted(true, true);
424
414
  }
425
415
  }
426
416
  });
427
417
  _defineProperty(this, "onSignallingStateChanged", () => {
428
- var _this$peerConn10;
429
- logger.debug("Call ".concat(this.callId, " onSignallingStateChanged() running (state=").concat((_this$peerConn10 = this.peerConn) === null || _this$peerConn10 === void 0 ? void 0 : _this$peerConn10.signalingState, ")"));
418
+ logger.debug(`Call ${this.callId} onSignallingStateChanged() running (state=${this.peerConn?.signalingState})`);
430
419
  });
431
420
  _defineProperty(this, "onTrack", ev => {
432
421
  if (ev.streams.length === 0) {
433
- logger.warn("Call ".concat(this.callId, " onTrack() called with streamless track streamless (kind=").concat(ev.track.kind, ")"));
422
+ logger.warn(`Call ${this.callId} onTrack() called with streamless track streamless (kind=${ev.track.kind})`);
434
423
  return;
435
424
  }
436
- var stream = ev.streams[0];
425
+ const stream = ev.streams[0];
437
426
  this.pushRemoteFeed(stream);
438
427
  if (!this.removeTrackListeners.has(stream)) {
439
- var onRemoveTrack = () => {
428
+ const onRemoveTrack = () => {
440
429
  if (stream.getTracks().length === 0) {
441
- logger.info("Call ".concat(this.callId, " onTrack() removing track (streamId=").concat(stream.id, ")"));
430
+ logger.info(`Call ${this.callId} onTrack() removing track (streamId=${stream.id})`);
442
431
  this.deleteFeedByStream(stream);
443
432
  stream.removeEventListener("removetrack", onRemoveTrack);
444
433
  this.removeTrackListeners.delete(stream);
@@ -451,16 +440,16 @@ export class MatrixCall extends TypedEventEmitter {
451
440
  _defineProperty(this, "onDataChannel", ev => {
452
441
  this.emit(CallEvent.DataChannel, ev.channel, this);
453
442
  });
454
- _defineProperty(this, "onNegotiationNeeded", /*#__PURE__*/_asyncToGenerator(function* () {
455
- logger.info("Call ".concat(_this.callId, " onNegotiationNeeded() negotiation is needed!"));
456
- if (_this.state !== CallState.CreateOffer && _this.opponentVersion === 0) {
457
- logger.info("Call ".concat(_this.callId, " onNegotiationNeeded() opponent does not support renegotiation: ignoring negotiationneeded event"));
443
+ _defineProperty(this, "onNegotiationNeeded", async () => {
444
+ logger.info(`Call ${this.callId} onNegotiationNeeded() negotiation is needed!`);
445
+ if (this.state !== CallState.CreateOffer && this.opponentVersion === 0) {
446
+ logger.info(`Call ${this.callId} onNegotiationNeeded() opponent does not support renegotiation: ignoring negotiationneeded event`);
458
447
  return;
459
448
  }
460
- _this.queueGotLocalOffer();
461
- }));
449
+ this.queueGotLocalOffer();
450
+ });
462
451
  _defineProperty(this, "onHangupReceived", msg => {
463
- logger.debug("Call ".concat(this.callId, " onHangupReceived() running"));
452
+ logger.debug(`Call ${this.callId} onHangupReceived() running`);
464
453
 
465
454
  // party ID must match (our chosen partner hanging up the call) or be undefined (we haven't chosen
466
455
  // a partner yet but we're treating the hangup as a reject as per VoIP v0)
@@ -468,16 +457,16 @@ export class MatrixCall extends TypedEventEmitter {
468
457
  // default reason is user_hangup
469
458
  this.terminate(CallParty.Remote, msg.reason || CallErrorCode.UserHangup, true);
470
459
  } else {
471
- logger.info("Call ".concat(this.callId, " onHangupReceived() ignoring message from party ID ").concat(msg.party_id, ": our partner is ").concat(this.opponentPartyId));
460
+ logger.info(`Call ${this.callId} onHangupReceived() ignoring message from party ID ${msg.party_id}: our partner is ${this.opponentPartyId}`);
472
461
  }
473
462
  });
474
463
  _defineProperty(this, "onRejectReceived", msg => {
475
- logger.debug("Call ".concat(this.callId, " onRejectReceived() running"));
464
+ logger.debug(`Call ${this.callId} onRejectReceived() running`);
476
465
 
477
466
  // No need to check party_id for reject because if we'd received either
478
467
  // an answer or reject, we wouldn't be in state InviteSent
479
468
 
480
- var shouldTerminate =
469
+ const shouldTerminate =
481
470
  // reject events also end the call if it's ringing: it's another of
482
471
  // our devices rejecting the call.
483
472
  [CallState.InviteSent, CallState.Ringing].includes(this.state) ||
@@ -487,18 +476,18 @@ export class MatrixCall extends TypedEventEmitter {
487
476
  if (shouldTerminate) {
488
477
  this.terminate(CallParty.Remote, msg.reason || CallErrorCode.UserHangup, true);
489
478
  } else {
490
- logger.debug("Call ".concat(this.callId, " onRejectReceived() called in wrong state (state=").concat(this.state, ")"));
479
+ logger.debug(`Call ${this.callId} onRejectReceived() called in wrong state (state=${this.state})`);
491
480
  }
492
481
  });
493
482
  _defineProperty(this, "onAnsweredElsewhere", msg => {
494
- logger.debug("Call ".concat(this.callId, " onAnsweredElsewhere() running"));
483
+ logger.debug(`Call ${this.callId} onAnsweredElsewhere() running`);
495
484
  this.terminate(CallParty.Remote, CallErrorCode.AnsweredElsewhere, true);
496
485
  });
497
486
  this.roomId = opts.roomId;
498
487
  this.invitee = opts.invitee;
499
488
  this.client = opts.client;
500
489
  if (!this.client.deviceId) throw new Error("Client must have a device ID to start calls");
501
- this.forceTURN = (_opts$forceTURN = opts.forceTURN) !== null && _opts$forceTURN !== void 0 ? _opts$forceTURN : false;
490
+ this.forceTURN = opts.forceTURN ?? false;
502
491
  this.ourPartyId = this.client.deviceId;
503
492
  this.opponentDeviceId = opts.opponentDeviceId;
504
493
  this.opponentSessionId = opts.opponentSessionId;
@@ -510,7 +499,7 @@ export class MatrixCall extends TypedEventEmitter {
510
499
  urls: [FALLBACK_ICE_SERVER]
511
500
  });
512
501
  }
513
- for (var server of this.turnServers) {
502
+ for (const server of this.turnServers) {
514
503
  checkObjectHasKeys(server, ["urls"]);
515
504
  }
516
505
  this.callId = genCallID();
@@ -522,22 +511,16 @@ export class MatrixCall extends TypedEventEmitter {
522
511
  * Place a voice call to this room.
523
512
  * @throws If you have not specified a listener for 'error' events.
524
513
  */
525
- placeVoiceCall() {
526
- var _this2 = this;
527
- return _asyncToGenerator(function* () {
528
- yield _this2.placeCall(true, false);
529
- })();
514
+ async placeVoiceCall() {
515
+ await this.placeCall(true, false);
530
516
  }
531
517
 
532
518
  /**
533
519
  * Place a video call to this room.
534
520
  * @throws If you have not specified a listener for 'error' events.
535
521
  */
536
- placeVideoCall() {
537
- var _this3 = this;
538
- return _asyncToGenerator(function* () {
539
- yield _this3.placeCall(true, true);
540
- })();
522
+ async placeVideoCall() {
523
+ await this.placeCall(true, true);
541
524
  }
542
525
 
543
526
  /**
@@ -546,7 +529,7 @@ export class MatrixCall extends TypedEventEmitter {
546
529
  * @param options - An object providing configuration options for the data channel.
547
530
  */
548
531
  createDataChannel(label, options) {
549
- var dataChannel = this.peerConn.createDataChannel(label, options);
532
+ const dataChannel = this.peerConn.createDataChannel(label, options);
550
533
  this.emit(CallEvent.DataChannel, dataChannel, this);
551
534
  return dataChannel;
552
535
  }
@@ -572,7 +555,7 @@ export class MatrixCall extends TypedEventEmitter {
572
555
  return this._state;
573
556
  }
574
557
  set state(state) {
575
- var oldState = this._state;
558
+ const oldState = this._state;
576
559
  this._state = state;
577
560
  this.emit(CallEvent.State, state, oldState, this);
578
561
  }
@@ -582,32 +565,26 @@ export class MatrixCall extends TypedEventEmitter {
582
565
  return this.hasUserMediaVideoSender || this.hasRemoteUserMediaVideoTrack ? CallType.Video : CallType.Voice;
583
566
  }
584
567
  get hasLocalUserMediaVideoTrack() {
585
- var _this$localUsermediaS;
586
- return !!((_this$localUsermediaS = this.localUsermediaStream) !== null && _this$localUsermediaS !== void 0 && _this$localUsermediaS.getVideoTracks().length);
568
+ return !!this.localUsermediaStream?.getVideoTracks().length;
587
569
  }
588
570
  get hasRemoteUserMediaVideoTrack() {
589
571
  return this.getRemoteFeeds().some(feed => {
590
- var _feed$stream;
591
- return feed.purpose === SDPStreamMetadataPurpose.Usermedia && ((_feed$stream = feed.stream) === null || _feed$stream === void 0 ? void 0 : _feed$stream.getVideoTracks().length);
572
+ return feed.purpose === SDPStreamMetadataPurpose.Usermedia && feed.stream?.getVideoTracks().length;
592
573
  });
593
574
  }
594
575
  get hasLocalUserMediaAudioTrack() {
595
- var _this$localUsermediaS2;
596
- return !!((_this$localUsermediaS2 = this.localUsermediaStream) !== null && _this$localUsermediaS2 !== void 0 && _this$localUsermediaS2.getAudioTracks().length);
576
+ return !!this.localUsermediaStream?.getAudioTracks().length;
597
577
  }
598
578
  get hasRemoteUserMediaAudioTrack() {
599
579
  return this.getRemoteFeeds().some(feed => {
600
- var _feed$stream2;
601
- return feed.purpose === SDPStreamMetadataPurpose.Usermedia && !!((_feed$stream2 = feed.stream) !== null && _feed$stream2 !== void 0 && _feed$stream2.getAudioTracks().length);
580
+ return feed.purpose === SDPStreamMetadataPurpose.Usermedia && !!feed.stream?.getAudioTracks().length;
602
581
  });
603
582
  }
604
583
  get hasUserMediaAudioSender() {
605
- var _this$transceivers$ge;
606
- return Boolean((_this$transceivers$ge = this.transceivers.get(getTransceiverKey(SDPStreamMetadataPurpose.Usermedia, "audio"))) === null || _this$transceivers$ge === void 0 ? void 0 : _this$transceivers$ge.sender);
584
+ return Boolean(this.transceivers.get(getTransceiverKey(SDPStreamMetadataPurpose.Usermedia, "audio"))?.sender);
607
585
  }
608
586
  get hasUserMediaVideoSender() {
609
- var _this$transceivers$ge2;
610
- return Boolean((_this$transceivers$ge2 = this.transceivers.get(getTransceiverKey(SDPStreamMetadataPurpose.Usermedia, "video"))) === null || _this$transceivers$ge2 === void 0 ? void 0 : _this$transceivers$ge2.sender);
587
+ return Boolean(this.transceivers.get(getTransceiverKey(SDPStreamMetadataPurpose.Usermedia, "video"))?.sender);
611
588
  }
612
589
  get localUsermediaFeed() {
613
590
  return this.getLocalFeeds().find(feed => feed.purpose === SDPStreamMetadataPurpose.Usermedia);
@@ -616,12 +593,10 @@ export class MatrixCall extends TypedEventEmitter {
616
593
  return this.getLocalFeeds().find(feed => feed.purpose === SDPStreamMetadataPurpose.Screenshare);
617
594
  }
618
595
  get localUsermediaStream() {
619
- var _this$localUsermediaF;
620
- return (_this$localUsermediaF = this.localUsermediaFeed) === null || _this$localUsermediaF === void 0 ? void 0 : _this$localUsermediaF.stream;
596
+ return this.localUsermediaFeed?.stream;
621
597
  }
622
598
  get localScreensharingStream() {
623
- var _this$localScreenshar;
624
- return (_this$localScreenshar = this.localScreensharingFeed) === null || _this$localScreenshar === void 0 ? void 0 : _this$localScreenshar.stream;
599
+ return this.localScreensharingFeed?.stream;
625
600
  }
626
601
  get remoteUsermediaFeed() {
627
602
  return this.getRemoteFeeds().find(feed => feed.purpose === SDPStreamMetadataPurpose.Usermedia);
@@ -630,12 +605,10 @@ export class MatrixCall extends TypedEventEmitter {
630
605
  return this.getRemoteFeeds().find(feed => feed.purpose === SDPStreamMetadataPurpose.Screenshare);
631
606
  }
632
607
  get remoteUsermediaStream() {
633
- var _this$remoteUsermedia;
634
- return (_this$remoteUsermedia = this.remoteUsermediaFeed) === null || _this$remoteUsermedia === void 0 ? void 0 : _this$remoteUsermedia.stream;
608
+ return this.remoteUsermediaFeed?.stream;
635
609
  }
636
610
  get remoteScreensharingStream() {
637
- var _this$remoteScreensha;
638
- return (_this$remoteScreensha = this.remoteScreensharingFeed) === null || _this$remoteScreensha === void 0 ? void 0 : _this$remoteScreensha.stream;
611
+ return this.remoteScreensharingFeed?.stream;
639
612
  }
640
613
  getFeedByStreamId(streamId) {
641
614
  return this.getFeeds().find(feed => feed.stream.id === streamId);
@@ -664,36 +637,31 @@ export class MatrixCall extends TypedEventEmitter {
664
637
  getRemoteFeeds() {
665
638
  return this.feeds.filter(feed => !feed.isLocal());
666
639
  }
667
- initOpponentCrypto() {
668
- var _this4 = this;
669
- return _asyncToGenerator(function* () {
670
- var _this4$getOpponentMem;
671
- if (!_this4.opponentDeviceId) return;
672
- if (!_this4.client.getUseE2eForGroupCall()) return;
673
- // It's possible to want E2EE and yet not have the means to manage E2EE
674
- // ourselves (for example if the client is a RoomWidgetClient)
675
- if (!_this4.client.getCrypto()) {
676
- // All we know is the device ID
677
- _this4.hasOpponentDeviceInfo = true;
678
- return;
679
- }
680
- var userId = _this4.invitee || ((_this4$getOpponentMem = _this4.getOpponentMember()) === null || _this4$getOpponentMem === void 0 ? void 0 : _this4$getOpponentMem.userId);
681
- if (!userId) throw new Error("Couldn't find opponent user ID to init crypto");
640
+ async initOpponentCrypto() {
641
+ if (!this.opponentDeviceId) return;
642
+ if (!this.client.getUseE2eForGroupCall()) return;
643
+ // It's possible to want E2EE and yet not have the means to manage E2EE
644
+ // ourselves (for example if the client is a RoomWidgetClient)
645
+ if (!this.client.getCrypto()) {
646
+ // All we know is the device ID
647
+ this.hasOpponentDeviceInfo = true;
648
+ return;
649
+ }
650
+ const userId = this.invitee || this.getOpponentMember()?.userId;
651
+ if (!userId) throw new Error("Couldn't find opponent user ID to init crypto");
682
652
 
683
- // Here we were calling `MatrixClient.crypto.deviceList.downloadKeys` which is not supported by the rust cryptography.
684
- _this4.hasOpponentDeviceInfo = false;
685
- throw new GroupCallUnknownDeviceError(userId);
686
- })();
653
+ // Here we were calling `MatrixClient.crypto.deviceList.downloadKeys` which is not supported by the rust cryptography.
654
+ this.hasOpponentDeviceInfo = false;
655
+ throw new GroupCallUnknownDeviceError(userId);
687
656
  }
688
657
 
689
658
  /**
690
659
  * Generates and returns localSDPStreamMetadata
691
660
  * @returns localSDPStreamMetadata
692
661
  */
693
- getLocalSDPStreamMetadata() {
694
- var updateStreamIds = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
695
- var metadata = {};
696
- for (var localFeed of this.getLocalFeeds()) {
662
+ getLocalSDPStreamMetadata(updateStreamIds = false) {
663
+ const metadata = {};
664
+ for (const localFeed of this.getLocalFeeds()) {
697
665
  if (updateStreamIds) {
698
666
  localFeed.sdpMetadataStreamId = localFeed.stream.id;
699
667
  }
@@ -720,16 +688,16 @@ export class MatrixCall extends TypedEventEmitter {
720
688
  this.pushRemoteFeedWithoutMetadata(stream);
721
689
  return;
722
690
  }
723
- var userId = this.getOpponentMember().userId;
724
- var purpose = this.remoteSDPStreamMetadata[stream.id].purpose;
725
- var audioMuted = this.remoteSDPStreamMetadata[stream.id].audio_muted;
726
- var videoMuted = this.remoteSDPStreamMetadata[stream.id].video_muted;
691
+ const userId = this.getOpponentMember().userId;
692
+ const purpose = this.remoteSDPStreamMetadata[stream.id].purpose;
693
+ const audioMuted = this.remoteSDPStreamMetadata[stream.id].audio_muted;
694
+ const videoMuted = this.remoteSDPStreamMetadata[stream.id].video_muted;
727
695
  if (!purpose) {
728
- logger.warn("Call ".concat(this.callId, " pushRemoteFeed() ignoring stream because we didn't get any metadata about it (streamId=").concat(stream.id, ")"));
696
+ logger.warn(`Call ${this.callId} pushRemoteFeed() ignoring stream because we didn't get any metadata about it (streamId=${stream.id})`);
729
697
  return;
730
698
  }
731
699
  if (this.getFeedByStreamId(stream.id)) {
732
- logger.warn("Call ".concat(this.callId, " pushRemoteFeed() ignoring stream because we already have a feed for it (streamId=").concat(stream.id, ")"));
700
+ logger.warn(`Call ${this.callId} pushRemoteFeed() ignoring stream because we already have a feed for it (streamId=${stream.id})`);
733
701
  return;
734
702
  }
735
703
  this.feeds.push(new CallFeed({
@@ -744,29 +712,28 @@ export class MatrixCall extends TypedEventEmitter {
744
712
  videoMuted
745
713
  }));
746
714
  this.emit(CallEvent.FeedsChanged, this.feeds, this);
747
- logger.info("Call ".concat(this.callId, " pushRemoteFeed() pushed stream (streamId=").concat(stream.id, ", active=").concat(stream.active, ", purpose=").concat(purpose, ")"));
715
+ logger.info(`Call ${this.callId} pushRemoteFeed() pushed stream (streamId=${stream.id}, active=${stream.active}, purpose=${purpose})`);
748
716
  }
749
717
 
750
718
  /**
751
719
  * This method is used ONLY if the other client doesn't support sending SDPStreamMetadata
752
720
  */
753
721
  pushRemoteFeedWithoutMetadata(stream) {
754
- var _this$feeds$find;
755
- var userId = this.getOpponentMember().userId;
722
+ const userId = this.getOpponentMember().userId;
756
723
  // We can guess the purpose here since the other client can only send one stream
757
- var purpose = SDPStreamMetadataPurpose.Usermedia;
758
- var oldRemoteStream = (_this$feeds$find = this.feeds.find(feed => !feed.isLocal())) === null || _this$feeds$find === void 0 ? void 0 : _this$feeds$find.stream;
724
+ const purpose = SDPStreamMetadataPurpose.Usermedia;
725
+ const oldRemoteStream = this.feeds.find(feed => !feed.isLocal())?.stream;
759
726
 
760
727
  // Note that we check by ID and always set the remote stream: Chrome appears
761
728
  // to make new stream objects when transceiver directionality is changed and the 'active'
762
729
  // status of streams change - Dave
763
730
  // If we already have a stream, check this stream has the same id
764
731
  if (oldRemoteStream && stream.id !== oldRemoteStream.id) {
765
- logger.warn("Call ".concat(this.callId, " pushRemoteFeedWithoutMetadata() ignoring new stream because we already have stream (streamId=").concat(stream.id, ")"));
732
+ logger.warn(`Call ${this.callId} pushRemoteFeedWithoutMetadata() ignoring new stream because we already have stream (streamId=${stream.id})`);
766
733
  return;
767
734
  }
768
735
  if (this.getFeedByStreamId(stream.id)) {
769
- logger.warn("Call ".concat(this.callId, " pushRemoteFeedWithoutMetadata() ignoring stream because we already have a feed for it (streamId=").concat(stream.id, ")"));
736
+ logger.warn(`Call ${this.callId} pushRemoteFeedWithoutMetadata() ignoring stream because we already have a feed for it (streamId=${stream.id})`);
770
737
  return;
771
738
  }
772
739
  this.feeds.push(new CallFeed({
@@ -781,11 +748,10 @@ export class MatrixCall extends TypedEventEmitter {
781
748
  purpose
782
749
  }));
783
750
  this.emit(CallEvent.FeedsChanged, this.feeds, this);
784
- logger.info("Call ".concat(this.callId, " pushRemoteFeedWithoutMetadata() pushed stream (streamId=").concat(stream.id, ", active=").concat(stream.active, ")"));
751
+ logger.info(`Call ${this.callId} pushRemoteFeedWithoutMetadata() pushed stream (streamId=${stream.id}, active=${stream.active})`);
785
752
  }
786
- pushNewLocalFeed(stream, purpose) {
787
- var addToPeerConnection = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
788
- var userId = this.client.getUserId();
753
+ pushNewLocalFeed(stream, purpose, addToPeerConnection = true) {
754
+ const userId = this.client.getUserId();
789
755
 
790
756
  // Tracks don't always start off enabled, eg. chrome will give a disabled
791
757
  // audio track if you ask for user media audio and already had one that
@@ -793,7 +759,7 @@ export class MatrixCall extends TypedEventEmitter {
793
759
  setTracksEnabled(stream.getAudioTracks(), true);
794
760
  setTracksEnabled(stream.getVideoTracks(), true);
795
761
  if (this.getFeedByStreamId(stream.id)) {
796
- logger.warn("Call ".concat(this.callId, " pushNewLocalFeed() ignoring stream because we already have a feed for it (streamId=").concat(stream.id, ")"));
762
+ logger.warn(`Call ${this.callId} pushNewLocalFeed() ignoring stream because we already have a feed for it (streamId=${stream.id})`);
797
763
  return;
798
764
  }
799
765
  this.pushLocalFeed(new CallFeed({
@@ -813,25 +779,23 @@ export class MatrixCall extends TypedEventEmitter {
813
779
  * @param callFeed - to push
814
780
  * @param addToPeerConnection - whether to add the tracks to the peer connection
815
781
  */
816
- pushLocalFeed(callFeed) {
817
- var _this5 = this;
818
- var addToPeerConnection = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
782
+ pushLocalFeed(callFeed, addToPeerConnection = true) {
819
783
  if (this.feeds.some(feed => callFeed.stream.id === feed.stream.id)) {
820
- logger.info("Call ".concat(this.callId, " pushLocalFeed() ignoring duplicate local stream (streamId=").concat(callFeed.stream.id, ")"));
784
+ logger.info(`Call ${this.callId} pushLocalFeed() ignoring duplicate local stream (streamId=${callFeed.stream.id})`);
821
785
  return;
822
786
  }
823
787
  this.feeds.push(callFeed);
824
788
  if (addToPeerConnection) {
825
- var _loop = function _loop() {
826
- logger.info("Call ".concat(_this5.callId, " pushLocalFeed() adding track to peer connection (id=").concat(track.id, ", kind=").concat(track.kind, ", streamId=").concat(callFeed.stream.id, ", streamPurpose=").concat(callFeed.purpose, ", enabled=").concat(track.enabled, ")"));
827
- var tKey = getTransceiverKey(callFeed.purpose, track.kind);
828
- if (_this5.transceivers.has(tKey)) {
789
+ for (const track of callFeed.stream.getTracks()) {
790
+ logger.info(`Call ${this.callId} pushLocalFeed() adding track to peer connection (id=${track.id}, kind=${track.kind}, streamId=${callFeed.stream.id}, streamPurpose=${callFeed.purpose}, enabled=${track.enabled})`);
791
+ const tKey = getTransceiverKey(callFeed.purpose, track.kind);
792
+ if (this.transceivers.has(tKey)) {
829
793
  // we already have a sender, so we re-use it. We try to re-use transceivers as much
830
794
  // as possible because they can't be removed once added, so otherwise they just
831
795
  // accumulate which makes the SDP very large very quickly: in fact it only takes
832
796
  // about 6 video tracks to exceed the maximum size of an Olm-encrypted
833
797
  // Matrix event.
834
- var transceiver = _this5.transceivers.get(tKey);
798
+ const transceiver = this.transceivers.get(tKey);
835
799
  transceiver.sender.replaceTrack(track);
836
800
  // set the direction to indicate we're going to start sending again
837
801
  // (this will trigger the re-negotiation)
@@ -841,22 +805,19 @@ export class MatrixCall extends TypedEventEmitter {
841
805
  // doesn't yet implement RTCRTPSender.setStreams()
842
806
  // (https://bugzilla.mozilla.org/show_bug.cgi?id=1510802) so we'd have no way to group the
843
807
  // two tracks together into a stream.
844
- var newSender = _this5.peerConn.addTrack(track, callFeed.stream);
808
+ const newSender = this.peerConn.addTrack(track, callFeed.stream);
845
809
 
846
810
  // now go & fish for the new transceiver
847
- var newTransceiver = _this5.peerConn.getTransceivers().find(t => t.sender === newSender);
811
+ const newTransceiver = this.peerConn.getTransceivers().find(t => t.sender === newSender);
848
812
  if (newTransceiver) {
849
- _this5.transceivers.set(tKey, newTransceiver);
813
+ this.transceivers.set(tKey, newTransceiver);
850
814
  } else {
851
- logger.warn("Call ".concat(_this5.callId, " pushLocalFeed() didn't find a matching transceiver after adding track!"));
815
+ logger.warn(`Call ${this.callId} pushLocalFeed() didn't find a matching transceiver after adding track!`);
852
816
  }
853
817
  }
854
- };
855
- for (var track of callFeed.stream.getTracks()) {
856
- _loop();
857
818
  }
858
819
  }
859
- logger.info("Call ".concat(this.callId, " pushLocalFeed() pushed stream (id=").concat(callFeed.stream.id, ", active=").concat(callFeed.stream.active, ", purpose=").concat(callFeed.purpose, ")"));
820
+ logger.info(`Call ${this.callId} pushLocalFeed() pushed stream (id=${callFeed.stream.id}, active=${callFeed.stream.active}, purpose=${callFeed.purpose})`);
860
821
  this.emit(CallEvent.FeedsChanged, this.feeds, this);
861
822
  }
862
823
 
@@ -866,14 +827,14 @@ export class MatrixCall extends TypedEventEmitter {
866
827
  * @param callFeed - to remove
867
828
  */
868
829
  removeLocalFeed(callFeed) {
869
- var audioTransceiverKey = getTransceiverKey(callFeed.purpose, "audio");
870
- var videoTransceiverKey = getTransceiverKey(callFeed.purpose, "video");
871
- for (var transceiverKey of [audioTransceiverKey, videoTransceiverKey]) {
830
+ const audioTransceiverKey = getTransceiverKey(callFeed.purpose, "audio");
831
+ const videoTransceiverKey = getTransceiverKey(callFeed.purpose, "video");
832
+ for (const transceiverKey of [audioTransceiverKey, videoTransceiverKey]) {
872
833
  // this is slightly mixing the track and transceiver API but is basically just shorthand.
873
834
  // There is no way to actually remove a transceiver, so this just sets it to inactive
874
835
  // (or recvonly) and replaces the source with nothing.
875
836
  if (this.transceivers.has(transceiverKey)) {
876
- var transceiver = this.transceivers.get(transceiverKey);
837
+ const transceiver = this.transceivers.get(transceiverKey);
877
838
  if (transceiver.sender) this.peerConn.removeTrack(transceiver.sender);
878
839
  }
879
840
  }
@@ -883,7 +844,7 @@ export class MatrixCall extends TypedEventEmitter {
883
844
  this.deleteFeed(callFeed);
884
845
  }
885
846
  deleteAllFeeds() {
886
- for (var feed of this.feeds) {
847
+ for (const feed of this.feeds) {
887
848
  if (!feed.isLocal() || !this.groupCallId) {
888
849
  feed.dispose();
889
850
  }
@@ -892,9 +853,9 @@ export class MatrixCall extends TypedEventEmitter {
892
853
  this.emit(CallEvent.FeedsChanged, this.feeds, this);
893
854
  }
894
855
  deleteFeedByStream(stream) {
895
- var feed = this.getFeedByStreamId(stream.id);
856
+ const feed = this.getFeedByStreamId(stream.id);
896
857
  if (!feed) {
897
- logger.warn("Call ".concat(this.callId, " deleteFeedByStream() didn't find the feed to delete (streamId=").concat(stream.id, ")"));
858
+ logger.warn(`Call ${this.callId} deleteFeedByStream() didn't find the feed to delete (streamId=${stream.id})`);
898
859
  return;
899
860
  }
900
861
  this.deleteFeed(feed);
@@ -906,109 +867,98 @@ export class MatrixCall extends TypedEventEmitter {
906
867
  }
907
868
 
908
869
  // The typescript definitions have this type as 'any' :(
909
- getCurrentCallStats() {
910
- var _this6 = this;
911
- return _asyncToGenerator(function* () {
912
- if (_this6.callHasEnded()) {
913
- return _this6.callStatsAtEnd;
914
- }
915
- return _this6.collectCallStats();
916
- })();
917
- }
918
- collectCallStats() {
919
- var _this7 = this;
920
- return _asyncToGenerator(function* () {
921
- // This happens when the call fails before it starts.
922
- // For example when we fail to get capture sources
923
- if (!_this7.peerConn) return;
924
- var statsReport = yield _this7.peerConn.getStats();
925
- var stats = [];
926
- statsReport.forEach(item => {
927
- stats.push(item);
928
- });
929
- return stats;
930
- })();
870
+ async getCurrentCallStats() {
871
+ if (this.callHasEnded()) {
872
+ return this.callStatsAtEnd;
873
+ }
874
+ return this.collectCallStats();
875
+ }
876
+ async collectCallStats() {
877
+ // This happens when the call fails before it starts.
878
+ // For example when we fail to get capture sources
879
+ if (!this.peerConn) return;
880
+ const statsReport = await this.peerConn.getStats();
881
+ const stats = [];
882
+ statsReport.forEach(item => {
883
+ stats.push(item);
884
+ });
885
+ return stats;
931
886
  }
932
887
 
933
888
  /**
934
889
  * Configure this call from an invite event. Used by MatrixClient.
935
890
  * @param event - The m.call.invite event
936
891
  */
937
- initWithInvite(event) {
938
- var _this8 = this;
939
- return _asyncToGenerator(function* () {
940
- var _this8$feeds$find;
941
- var invite = event.getContent();
942
- _this8.direction = CallDirection.Inbound;
943
-
944
- // make sure we have valid turn creds. Unless something's gone wrong, it should
945
- // poll and keep the credentials valid so this should be instant.
946
- var haveTurnCreds = yield _this8.client.checkTurnServers();
947
- if (!haveTurnCreds) {
948
- logger.warn("Call ".concat(_this8.callId, " initWithInvite() failed to get TURN credentials! Proceeding with call anyway..."));
949
- }
950
- var sdpStreamMetadata = SDPStreamMetadataKey.findIn(invite);
951
- if (sdpStreamMetadata) {
952
- _this8.updateRemoteSDPStreamMetadata(sdpStreamMetadata);
953
- } else {
954
- logger.debug("Call ".concat(_this8.callId, " initWithInvite() did not get any SDPStreamMetadata! Can not send/receive multiple streams"));
955
- }
956
- _this8.peerConn = _this8.createPeerConnection();
957
- _this8.emit(CallEvent.PeerConnectionCreated, _this8.peerConn, _this8);
958
- // we must set the party ID before await-ing on anything: the call event
959
- // handler will start giving us more call events (eg. candidates) so if
960
- // we haven't set the party ID, we'll ignore them.
961
- _this8.chooseOpponent(event);
962
- yield _this8.initOpponentCrypto();
963
- try {
964
- yield _this8.peerConn.setRemoteDescription(invite.offer);
965
- logger.debug("Call ".concat(_this8.callId, " initWithInvite() set remote description: ").concat(invite.offer.type));
966
- yield _this8.addBufferedIceCandidates();
967
- } catch (e) {
968
- logger.debug("Call ".concat(_this8.callId, " initWithInvite() failed to set remote description"), e);
969
- _this8.terminate(CallParty.Local, CallErrorCode.SetRemoteDescription, false);
970
- return;
971
- }
972
- var remoteStream = (_this8$feeds$find = _this8.feeds.find(feed => !feed.isLocal())) === null || _this8$feeds$find === void 0 ? void 0 : _this8$feeds$find.stream;
973
-
974
- // According to previous comments in this file, firefox at some point did not
975
- // add streams until media started arriving on them. Testing latest firefox
976
- // (81 at time of writing), this is no longer a problem, so let's do it the correct way.
977
- //
978
- // For example in case of no media webrtc connections like screen share only call we have to allow webrtc
979
- // connections without remote media. In this case we always use a data channel. At the moment we allow as well
980
- // only data channel as media in the WebRTC connection with this setup here.
981
- if (!_this8.isOnlyDataChannelAllowed && (!remoteStream || remoteStream.getTracks().length === 0)) {
982
- logger.error("Call ".concat(_this8.callId, " initWithInvite() no remote stream or no tracks after setting remote description!"));
983
- _this8.terminate(CallParty.Local, CallErrorCode.SetRemoteDescription, false);
984
- return;
985
- }
986
- _this8.state = CallState.Ringing;
987
- if (event.getLocalAge()) {
988
- // Time out the call if it's ringing for too long
989
- var ringingTimer = setTimeout(() => {
990
- if (_this8.state == CallState.Ringing) {
991
- var _this8$stats;
992
- logger.debug("Call ".concat(_this8.callId, " initWithInvite() invite has expired. Hanging up."));
993
- _this8.hangupParty = CallParty.Remote; // effectively
994
- _this8.state = CallState.Ended;
995
- _this8.stopAllMedia();
996
- if (_this8.peerConn.signalingState != "closed") {
997
- _this8.peerConn.close();
998
- }
999
- (_this8$stats = _this8.stats) === null || _this8$stats === void 0 || _this8$stats.removeStatsReportGatherer(_this8.callId);
1000
- _this8.emit(CallEvent.Hangup, _this8);
1001
- }
1002
- }, invite.lifetime - event.getLocalAge());
1003
- var onState = state => {
1004
- if (state !== CallState.Ringing) {
1005
- clearTimeout(ringingTimer);
1006
- _this8.off(CallEvent.State, onState);
892
+ async initWithInvite(event) {
893
+ const invite = event.getContent();
894
+ this.direction = CallDirection.Inbound;
895
+
896
+ // make sure we have valid turn creds. Unless something's gone wrong, it should
897
+ // poll and keep the credentials valid so this should be instant.
898
+ const haveTurnCreds = await this.client.checkTurnServers();
899
+ if (!haveTurnCreds) {
900
+ logger.warn(`Call ${this.callId} initWithInvite() failed to get TURN credentials! Proceeding with call anyway...`);
901
+ }
902
+ const sdpStreamMetadata = SDPStreamMetadataKey.findIn(invite);
903
+ if (sdpStreamMetadata) {
904
+ this.updateRemoteSDPStreamMetadata(sdpStreamMetadata);
905
+ } else {
906
+ logger.debug(`Call ${this.callId} initWithInvite() did not get any SDPStreamMetadata! Can not send/receive multiple streams`);
907
+ }
908
+ this.peerConn = this.createPeerConnection();
909
+ this.emit(CallEvent.PeerConnectionCreated, this.peerConn, this);
910
+ // we must set the party ID before await-ing on anything: the call event
911
+ // handler will start giving us more call events (eg. candidates) so if
912
+ // we haven't set the party ID, we'll ignore them.
913
+ this.chooseOpponent(event);
914
+ await this.initOpponentCrypto();
915
+ try {
916
+ await this.peerConn.setRemoteDescription(invite.offer);
917
+ logger.debug(`Call ${this.callId} initWithInvite() set remote description: ${invite.offer.type}`);
918
+ await this.addBufferedIceCandidates();
919
+ } catch (e) {
920
+ logger.debug(`Call ${this.callId} initWithInvite() failed to set remote description`, e);
921
+ this.terminate(CallParty.Local, CallErrorCode.SetRemoteDescription, false);
922
+ return;
923
+ }
924
+ const remoteStream = this.feeds.find(feed => !feed.isLocal())?.stream;
925
+
926
+ // According to previous comments in this file, firefox at some point did not
927
+ // add streams until media started arriving on them. Testing latest firefox
928
+ // (81 at time of writing), this is no longer a problem, so let's do it the correct way.
929
+ //
930
+ // For example in case of no media webrtc connections like screen share only call we have to allow webrtc
931
+ // connections without remote media. In this case we always use a data channel. At the moment we allow as well
932
+ // only data channel as media in the WebRTC connection with this setup here.
933
+ if (!this.isOnlyDataChannelAllowed && (!remoteStream || remoteStream.getTracks().length === 0)) {
934
+ logger.error(`Call ${this.callId} initWithInvite() no remote stream or no tracks after setting remote description!`);
935
+ this.terminate(CallParty.Local, CallErrorCode.SetRemoteDescription, false);
936
+ return;
937
+ }
938
+ this.state = CallState.Ringing;
939
+ if (event.getLocalAge()) {
940
+ // Time out the call if it's ringing for too long
941
+ const ringingTimer = setTimeout(() => {
942
+ if (this.state == CallState.Ringing) {
943
+ logger.debug(`Call ${this.callId} initWithInvite() invite has expired. Hanging up.`);
944
+ this.hangupParty = CallParty.Remote; // effectively
945
+ this.state = CallState.Ended;
946
+ this.stopAllMedia();
947
+ if (this.peerConn.signalingState != "closed") {
948
+ this.peerConn.close();
1007
949
  }
1008
- };
1009
- _this8.on(CallEvent.State, onState);
1010
- }
1011
- })();
950
+ this.stats?.removeStatsReportGatherer(this.callId);
951
+ this.emit(CallEvent.Hangup, this);
952
+ }
953
+ }, invite.lifetime - event.getLocalAge());
954
+ const onState = state => {
955
+ if (state !== CallState.Ringing) {
956
+ clearTimeout(ringingTimer);
957
+ this.off(CallEvent.State, onState);
958
+ }
959
+ };
960
+ this.on(CallEvent.State, onState);
961
+ }
1012
962
  }
1013
963
 
1014
964
  /**
@@ -1024,65 +974,61 @@ export class MatrixCall extends TypedEventEmitter {
1024
974
  shouldAnswerWithMediaType(wantedValue, valueOfTheOtherSide, type) {
1025
975
  if (wantedValue && !valueOfTheOtherSide) {
1026
976
  // TODO: Figure out how to do this
1027
- logger.warn("Call ".concat(this.callId, " shouldAnswerWithMediaType() unable to answer with ").concat(type, " because the other side isn't sending it either."));
977
+ logger.warn(`Call ${this.callId} shouldAnswerWithMediaType() unable to answer with ${type} because the other side isn't sending it either.`);
1028
978
  return false;
1029
979
  } else if (!isNullOrUndefined(wantedValue) && wantedValue !== valueOfTheOtherSide && !this.opponentSupportsSDPStreamMetadata()) {
1030
- logger.warn("Call ".concat(this.callId, " shouldAnswerWithMediaType() unable to answer with ").concat(type, "=").concat(wantedValue, " because the other side doesn't support it. Answering with ").concat(type, "=").concat(valueOfTheOtherSide, "."));
980
+ logger.warn(`Call ${this.callId} shouldAnswerWithMediaType() unable to answer with ${type}=${wantedValue} because the other side doesn't support it. Answering with ${type}=${valueOfTheOtherSide}.`);
1031
981
  return valueOfTheOtherSide;
1032
982
  }
1033
- return wantedValue !== null && wantedValue !== void 0 ? wantedValue : valueOfTheOtherSide;
983
+ return wantedValue ?? valueOfTheOtherSide;
1034
984
  }
1035
985
 
1036
986
  /**
1037
987
  * Answer a call.
1038
988
  */
1039
- answer(audio, video) {
1040
- var _this9 = this;
1041
- return _asyncToGenerator(function* () {
1042
- if (_this9.inviteOrAnswerSent) return;
1043
- // TODO: Figure out how to do this
1044
- if (audio === false && video === false) throw new Error("You CANNOT answer a call without media");
1045
- if (!_this9.localUsermediaStream && !_this9.waitForLocalAVStream) {
1046
- var prevState = _this9.state;
1047
- var answerWithAudio = _this9.shouldAnswerWithMediaType(audio, _this9.hasRemoteUserMediaAudioTrack, "audio");
1048
- var answerWithVideo = _this9.shouldAnswerWithMediaType(video, _this9.hasRemoteUserMediaVideoTrack, "video");
1049
- _this9.state = CallState.WaitLocalMedia;
1050
- _this9.waitForLocalAVStream = true;
1051
- try {
1052
- var _this9$client$getDevi;
1053
- var stream = yield _this9.client.getMediaHandler().getUserMediaStream(answerWithAudio, answerWithVideo);
1054
- _this9.waitForLocalAVStream = false;
1055
- var usermediaFeed = new CallFeed({
1056
- client: _this9.client,
1057
- roomId: _this9.roomId,
1058
- userId: _this9.client.getUserId(),
1059
- deviceId: (_this9$client$getDevi = _this9.client.getDeviceId()) !== null && _this9$client$getDevi !== void 0 ? _this9$client$getDevi : undefined,
1060
- stream,
1061
- purpose: SDPStreamMetadataPurpose.Usermedia,
1062
- audioMuted: false,
1063
- videoMuted: false
1064
- });
1065
- var feeds = [usermediaFeed];
1066
- if (_this9.localScreensharingFeed) {
1067
- feeds.push(_this9.localScreensharingFeed);
1068
- }
1069
- _this9.answerWithCallFeeds(feeds);
1070
- } catch (e) {
1071
- if (answerWithVideo) {
1072
- // Try to answer without video
1073
- logger.warn("Call ".concat(_this9.callId, " answer() failed to getUserMedia(), trying to getUserMedia() without video"));
1074
- _this9.state = prevState;
1075
- _this9.waitForLocalAVStream = false;
1076
- yield _this9.answer(answerWithAudio, false);
1077
- } else {
1078
- _this9.getUserMediaFailed(e);
1079
- return;
1080
- }
989
+ async answer(audio, video) {
990
+ if (this.inviteOrAnswerSent) return;
991
+ // TODO: Figure out how to do this
992
+ if (audio === false && video === false) throw new Error("You CANNOT answer a call without media");
993
+ if (!this.localUsermediaStream && !this.waitForLocalAVStream) {
994
+ const prevState = this.state;
995
+ const answerWithAudio = this.shouldAnswerWithMediaType(audio, this.hasRemoteUserMediaAudioTrack, "audio");
996
+ const answerWithVideo = this.shouldAnswerWithMediaType(video, this.hasRemoteUserMediaVideoTrack, "video");
997
+ this.state = CallState.WaitLocalMedia;
998
+ this.waitForLocalAVStream = true;
999
+ try {
1000
+ const stream = await this.client.getMediaHandler().getUserMediaStream(answerWithAudio, answerWithVideo);
1001
+ this.waitForLocalAVStream = false;
1002
+ const usermediaFeed = new CallFeed({
1003
+ client: this.client,
1004
+ roomId: this.roomId,
1005
+ userId: this.client.getUserId(),
1006
+ deviceId: this.client.getDeviceId() ?? undefined,
1007
+ stream,
1008
+ purpose: SDPStreamMetadataPurpose.Usermedia,
1009
+ audioMuted: false,
1010
+ videoMuted: false
1011
+ });
1012
+ const feeds = [usermediaFeed];
1013
+ if (this.localScreensharingFeed) {
1014
+ feeds.push(this.localScreensharingFeed);
1015
+ }
1016
+ this.answerWithCallFeeds(feeds);
1017
+ } catch (e) {
1018
+ if (answerWithVideo) {
1019
+ // Try to answer without video
1020
+ logger.warn(`Call ${this.callId} answer() failed to getUserMedia(), trying to getUserMedia() without video`);
1021
+ this.state = prevState;
1022
+ this.waitForLocalAVStream = false;
1023
+ await this.answer(answerWithAudio, false);
1024
+ } else {
1025
+ this.getUserMediaFailed(e);
1026
+ return;
1081
1027
  }
1082
- } else if (_this9.waitForLocalAVStream) {
1083
- _this9.state = CallState.WaitLocalMedia;
1084
1028
  }
1085
- })();
1029
+ } else if (this.waitForLocalAVStream) {
1030
+ this.state = CallState.WaitLocalMedia;
1031
+ }
1086
1032
  }
1087
1033
  answerWithCallFeeds(callFeeds) {
1088
1034
  if (this.inviteOrAnswerSent) return;
@@ -1095,15 +1041,15 @@ export class MatrixCall extends TypedEventEmitter {
1095
1041
  * @param newCall - The new call.
1096
1042
  */
1097
1043
  replacedBy(newCall) {
1098
- logger.debug("Call ".concat(this.callId, " replacedBy() running (newCallId=").concat(newCall.callId, ")"));
1044
+ logger.debug(`Call ${this.callId} replacedBy() running (newCallId=${newCall.callId})`);
1099
1045
  if (this.state === CallState.WaitLocalMedia) {
1100
- logger.debug("Call ".concat(this.callId, " replacedBy() telling new call to wait for local media (newCallId=").concat(newCall.callId, ")"));
1046
+ logger.debug(`Call ${this.callId} replacedBy() telling new call to wait for local media (newCallId=${newCall.callId})`);
1101
1047
  newCall.waitForLocalAVStream = true;
1102
1048
  } else if ([CallState.CreateOffer, CallState.InviteSent].includes(this.state)) {
1103
1049
  if (newCall.direction === CallDirection.Outbound) {
1104
1050
  newCall.queueGotCallFeedsForAnswer([]);
1105
1051
  } else {
1106
- logger.debug("Call ".concat(this.callId, " replacedBy() handing local stream to new call(newCallId=").concat(newCall.callId, ")"));
1052
+ logger.debug(`Call ${this.callId} replacedBy() handing local stream to new call(newCallId=${newCall.callId})`);
1107
1053
  newCall.queueGotCallFeedsForAnswer(this.getLocalFeeds().map(feed => feed.clone()));
1108
1054
  }
1109
1055
  }
@@ -1119,11 +1065,11 @@ export class MatrixCall extends TypedEventEmitter {
1119
1065
  */
1120
1066
  hangup(reason, suppressEvent) {
1121
1067
  if (this.callHasEnded()) return;
1122
- logger.debug("Call ".concat(this.callId, " hangup() ending call (reason=").concat(reason, ")"));
1068
+ logger.debug(`Call ${this.callId} hangup() ending call (reason=${reason})`);
1123
1069
  this.terminate(CallParty.Local, reason, !suppressEvent);
1124
1070
  // We don't want to send hangup here if we didn't even get to sending an invite
1125
1071
  if ([CallState.Fledgling, CallState.WaitLocalMedia].includes(this.state)) return;
1126
- var content = {};
1072
+ const content = {};
1127
1073
  // Don't send UserHangup reason to older clients
1128
1074
  if (this.opponentVersion && this.opponentVersion !== 0 || reason !== CallErrorCode.UserHangup) {
1129
1075
  content["reason"] = reason;
@@ -1141,7 +1087,7 @@ export class MatrixCall extends TypedEventEmitter {
1141
1087
  throw Error("Call must be in 'ringing' state to reject!");
1142
1088
  }
1143
1089
  if (this.opponentVersion === 0) {
1144
- logger.info("Call ".concat(this.callId, " reject() opponent version is less than 1: sending hangup instead of reject (opponentVersion=").concat(this.opponentVersion, ")"));
1090
+ logger.info(`Call ${this.callId} reject() opponent version is less than 1: sending hangup instead of reject (opponentVersion=${this.opponentVersion})`);
1145
1091
  this.hangup(CallErrorCode.UserHangup, true);
1146
1092
  return;
1147
1093
  }
@@ -1155,26 +1101,23 @@ export class MatrixCall extends TypedEventEmitter {
1155
1101
  * @param audio - should add an audio track
1156
1102
  * @param video - should add an video track
1157
1103
  */
1158
- upgradeCall(audio, video) {
1159
- var _this0 = this;
1160
- return _asyncToGenerator(function* () {
1161
- // We don't do call downgrades
1162
- if (!audio && !video) return;
1163
- if (!_this0.opponentSupportsSDPStreamMetadata()) return;
1164
- try {
1165
- logger.debug("Call ".concat(_this0.callId, " upgradeCall() upgrading call (audio=").concat(audio, ", video=").concat(video, ")"));
1166
- var getAudio = audio || _this0.hasLocalUserMediaAudioTrack;
1167
- var getVideo = video || _this0.hasLocalUserMediaVideoTrack;
1168
-
1169
- // updateLocalUsermediaStream() will take the tracks, use them as
1170
- // replacement and throw the stream away, so it isn't reusable
1171
- var stream = yield _this0.client.getMediaHandler().getUserMediaStream(getAudio, getVideo, false);
1172
- yield _this0.updateLocalUsermediaStream(stream, audio, video);
1173
- } catch (error) {
1174
- logger.error("Call ".concat(_this0.callId, " upgradeCall() failed to upgrade the call"), error);
1175
- _this0.emit(CallEvent.Error, new CallError(CallErrorCode.NoUserMedia, "Failed to get camera access: ", error), _this0);
1176
- }
1177
- })();
1104
+ async upgradeCall(audio, video) {
1105
+ // We don't do call downgrades
1106
+ if (!audio && !video) return;
1107
+ if (!this.opponentSupportsSDPStreamMetadata()) return;
1108
+ try {
1109
+ logger.debug(`Call ${this.callId} upgradeCall() upgrading call (audio=${audio}, video=${video})`);
1110
+ const getAudio = audio || this.hasLocalUserMediaAudioTrack;
1111
+ const getVideo = video || this.hasLocalUserMediaVideoTrack;
1112
+
1113
+ // updateLocalUsermediaStream() will take the tracks, use them as
1114
+ // replacement and throw the stream away, so it isn't reusable
1115
+ const stream = await this.client.getMediaHandler().getUserMediaStream(getAudio, getVideo, false);
1116
+ await this.updateLocalUsermediaStream(stream, audio, video);
1117
+ } catch (error) {
1118
+ logger.error(`Call ${this.callId} upgradeCall() failed to upgrade the call`, error);
1119
+ this.emit(CallEvent.Error, new CallError(CallErrorCode.NoUserMedia, "Failed to get camera access: ", error), this);
1120
+ }
1178
1121
  }
1179
1122
 
1180
1123
  /**
@@ -1199,46 +1142,43 @@ export class MatrixCall extends TypedEventEmitter {
1199
1142
  * @param opts - screen sharing options
1200
1143
  * @returns new screensharing state
1201
1144
  */
1202
- setScreensharingEnabled(enabled, opts) {
1203
- var _this1 = this;
1204
- return _asyncToGenerator(function* () {
1205
- // Skip if there is nothing to do
1206
- if (enabled && _this1.isScreensharing()) {
1207
- logger.warn("Call ".concat(_this1.callId, " setScreensharingEnabled() there is already a screensharing stream - there is nothing to do!"));
1208
- return true;
1209
- } else if (!enabled && !_this1.isScreensharing()) {
1210
- logger.warn("Call ".concat(_this1.callId, " setScreensharingEnabled() there already isn't a screensharing stream - there is nothing to do!"));
1211
- return false;
1212
- }
1145
+ async setScreensharingEnabled(enabled, opts) {
1146
+ // Skip if there is nothing to do
1147
+ if (enabled && this.isScreensharing()) {
1148
+ logger.warn(`Call ${this.callId} setScreensharingEnabled() there is already a screensharing stream - there is nothing to do!`);
1149
+ return true;
1150
+ } else if (!enabled && !this.isScreensharing()) {
1151
+ logger.warn(`Call ${this.callId} setScreensharingEnabled() there already isn't a screensharing stream - there is nothing to do!`);
1152
+ return false;
1153
+ }
1213
1154
 
1214
- // Fallback to replaceTrack()
1215
- if (!_this1.opponentSupportsSDPStreamMetadata()) {
1216
- return _this1.setScreensharingEnabledWithoutMetadataSupport(enabled, opts);
1217
- }
1218
- logger.debug("Call ".concat(_this1.callId, " setScreensharingEnabled() running (enabled=").concat(enabled, ")"));
1219
- if (enabled) {
1220
- try {
1221
- var stream = yield _this1.client.getMediaHandler().getScreensharingStream(opts);
1222
- if (!stream) return false;
1223
- _this1.pushNewLocalFeed(stream, SDPStreamMetadataPurpose.Screenshare);
1224
- return true;
1225
- } catch (err) {
1226
- logger.error("Call ".concat(_this1.callId, " setScreensharingEnabled() failed to get screen-sharing stream:"), err);
1227
- return false;
1228
- }
1229
- } else {
1230
- var audioTransceiver = _this1.transceivers.get(getTransceiverKey(SDPStreamMetadataPurpose.Screenshare, "audio"));
1231
- var videoTransceiver = _this1.transceivers.get(getTransceiverKey(SDPStreamMetadataPurpose.Screenshare, "video"));
1232
- for (var transceiver of [audioTransceiver, videoTransceiver]) {
1233
- // this is slightly mixing the track and transceiver API but is basically just shorthand
1234
- // for removing the sender.
1235
- if (transceiver && transceiver.sender) _this1.peerConn.removeTrack(transceiver.sender);
1236
- }
1237
- _this1.client.getMediaHandler().stopScreensharingStream(_this1.localScreensharingStream);
1238
- _this1.deleteFeedByStream(_this1.localScreensharingStream);
1155
+ // Fallback to replaceTrack()
1156
+ if (!this.opponentSupportsSDPStreamMetadata()) {
1157
+ return this.setScreensharingEnabledWithoutMetadataSupport(enabled, opts);
1158
+ }
1159
+ logger.debug(`Call ${this.callId} setScreensharingEnabled() running (enabled=${enabled})`);
1160
+ if (enabled) {
1161
+ try {
1162
+ const stream = await this.client.getMediaHandler().getScreensharingStream(opts);
1163
+ if (!stream) return false;
1164
+ this.pushNewLocalFeed(stream, SDPStreamMetadataPurpose.Screenshare);
1165
+ return true;
1166
+ } catch (err) {
1167
+ logger.error(`Call ${this.callId} setScreensharingEnabled() failed to get screen-sharing stream:`, err);
1239
1168
  return false;
1240
1169
  }
1241
- })();
1170
+ } else {
1171
+ const audioTransceiver = this.transceivers.get(getTransceiverKey(SDPStreamMetadataPurpose.Screenshare, "audio"));
1172
+ const videoTransceiver = this.transceivers.get(getTransceiverKey(SDPStreamMetadataPurpose.Screenshare, "video"));
1173
+ for (const transceiver of [audioTransceiver, videoTransceiver]) {
1174
+ // this is slightly mixing the track and transceiver API but is basically just shorthand
1175
+ // for removing the sender.
1176
+ if (transceiver && transceiver.sender) this.peerConn.removeTrack(transceiver.sender);
1177
+ }
1178
+ this.client.getMediaHandler().stopScreensharingStream(this.localScreensharingStream);
1179
+ this.deleteFeedByStream(this.localScreensharingStream);
1180
+ return false;
1181
+ }
1242
1182
  }
1243
1183
 
1244
1184
  /**
@@ -1248,99 +1188,85 @@ export class MatrixCall extends TypedEventEmitter {
1248
1188
  * @param opts - screen sharing options
1249
1189
  * @returns new screensharing state
1250
1190
  */
1251
- setScreensharingEnabledWithoutMetadataSupport(enabled, opts) {
1252
- var _this10 = this;
1253
- return _asyncToGenerator(function* () {
1254
- logger.debug("Call ".concat(_this10.callId, " setScreensharingEnabledWithoutMetadataSupport() running (enabled=").concat(enabled, ")"));
1255
- if (enabled) {
1256
- try {
1257
- var _this10$transceivers$;
1258
- var stream = yield _this10.client.getMediaHandler().getScreensharingStream(opts);
1259
- if (!stream) return false;
1260
- var track = stream.getTracks().find(track => track.kind === "video");
1261
- var sender = (_this10$transceivers$ = _this10.transceivers.get(getTransceiverKey(SDPStreamMetadataPurpose.Usermedia, "video"))) === null || _this10$transceivers$ === void 0 ? void 0 : _this10$transceivers$.sender;
1262
- sender === null || sender === void 0 || sender.replaceTrack(track !== null && track !== void 0 ? track : null);
1263
- _this10.pushNewLocalFeed(stream, SDPStreamMetadataPurpose.Screenshare, false);
1264
- return true;
1265
- } catch (err) {
1266
- logger.error("Call ".concat(_this10.callId, " setScreensharingEnabledWithoutMetadataSupport() failed to get screen-sharing stream:"), err);
1267
- return false;
1268
- }
1269
- } else {
1270
- var _this10$localUsermedi, _this10$transceivers$2;
1271
- var _track = (_this10$localUsermedi = _this10.localUsermediaStream) === null || _this10$localUsermedi === void 0 ? void 0 : _this10$localUsermedi.getTracks().find(track => track.kind === "video");
1272
- var _sender = (_this10$transceivers$2 = _this10.transceivers.get(getTransceiverKey(SDPStreamMetadataPurpose.Usermedia, "video"))) === null || _this10$transceivers$2 === void 0 ? void 0 : _this10$transceivers$2.sender;
1273
- _sender === null || _sender === void 0 || _sender.replaceTrack(_track !== null && _track !== void 0 ? _track : null);
1274
- _this10.client.getMediaHandler().stopScreensharingStream(_this10.localScreensharingStream);
1275
- _this10.deleteFeedByStream(_this10.localScreensharingStream);
1191
+ async setScreensharingEnabledWithoutMetadataSupport(enabled, opts) {
1192
+ logger.debug(`Call ${this.callId} setScreensharingEnabledWithoutMetadataSupport() running (enabled=${enabled})`);
1193
+ if (enabled) {
1194
+ try {
1195
+ const stream = await this.client.getMediaHandler().getScreensharingStream(opts);
1196
+ if (!stream) return false;
1197
+ const track = stream.getTracks().find(track => track.kind === "video");
1198
+ const sender = this.transceivers.get(getTransceiverKey(SDPStreamMetadataPurpose.Usermedia, "video"))?.sender;
1199
+ sender?.replaceTrack(track ?? null);
1200
+ this.pushNewLocalFeed(stream, SDPStreamMetadataPurpose.Screenshare, false);
1201
+ return true;
1202
+ } catch (err) {
1203
+ logger.error(`Call ${this.callId} setScreensharingEnabledWithoutMetadataSupport() failed to get screen-sharing stream:`, err);
1276
1204
  return false;
1277
1205
  }
1278
- })();
1206
+ } else {
1207
+ const track = this.localUsermediaStream?.getTracks().find(track => track.kind === "video");
1208
+ const sender = this.transceivers.get(getTransceiverKey(SDPStreamMetadataPurpose.Usermedia, "video"))?.sender;
1209
+ sender?.replaceTrack(track ?? null);
1210
+ this.client.getMediaHandler().stopScreensharingStream(this.localScreensharingStream);
1211
+ this.deleteFeedByStream(this.localScreensharingStream);
1212
+ return false;
1213
+ }
1279
1214
  }
1280
1215
 
1281
1216
  /**
1282
1217
  * Replaces/adds the tracks from the passed stream to the localUsermediaStream
1283
1218
  * @param stream - to use a replacement for the local usermedia stream
1284
1219
  */
1285
- updateLocalUsermediaStream(stream) {
1286
- var _arguments = arguments,
1287
- _this11 = this;
1288
- return _asyncToGenerator(function* () {
1289
- var forceAudio = _arguments.length > 1 && _arguments[1] !== undefined ? _arguments[1] : false;
1290
- var forceVideo = _arguments.length > 2 && _arguments[2] !== undefined ? _arguments[2] : false;
1291
- var callFeed = _this11.localUsermediaFeed;
1292
- var audioEnabled = forceAudio || !callFeed.isAudioMuted() && !_this11.remoteOnHold;
1293
- var videoEnabled = forceVideo || !callFeed.isVideoMuted() && !_this11.remoteOnHold;
1294
- logger.log("Call ".concat(_this11.callId, " updateLocalUsermediaStream() running (streamId=").concat(stream.id, ", audio=").concat(audioEnabled, ", video=").concat(videoEnabled, ")"));
1295
- setTracksEnabled(stream.getAudioTracks(), audioEnabled);
1296
- setTracksEnabled(stream.getVideoTracks(), videoEnabled);
1297
-
1298
- // We want to keep the same stream id, so we replace the tracks rather
1299
- // than the whole stream.
1300
-
1301
- // Firstly, we replace the tracks in our localUsermediaStream.
1302
- for (var track of _this11.localUsermediaStream.getTracks()) {
1303
- _this11.localUsermediaStream.removeTrack(track);
1304
- track.stop();
1305
- }
1306
- for (var _track2 of stream.getTracks()) {
1307
- _this11.localUsermediaStream.addTrack(_track2);
1308
- }
1220
+ async updateLocalUsermediaStream(stream, forceAudio = false, forceVideo = false) {
1221
+ const callFeed = this.localUsermediaFeed;
1222
+ const audioEnabled = forceAudio || !callFeed.isAudioMuted() && !this.remoteOnHold;
1223
+ const videoEnabled = forceVideo || !callFeed.isVideoMuted() && !this.remoteOnHold;
1224
+ logger.log(`Call ${this.callId} updateLocalUsermediaStream() running (streamId=${stream.id}, audio=${audioEnabled}, video=${videoEnabled})`);
1225
+ setTracksEnabled(stream.getAudioTracks(), audioEnabled);
1226
+ setTracksEnabled(stream.getVideoTracks(), videoEnabled);
1227
+
1228
+ // We want to keep the same stream id, so we replace the tracks rather
1229
+ // than the whole stream.
1230
+
1231
+ // Firstly, we replace the tracks in our localUsermediaStream.
1232
+ for (const track of this.localUsermediaStream.getTracks()) {
1233
+ this.localUsermediaStream.removeTrack(track);
1234
+ track.stop();
1235
+ }
1236
+ for (const track of stream.getTracks()) {
1237
+ this.localUsermediaStream.addTrack(track);
1238
+ }
1309
1239
 
1310
- // Then replace the old tracks, if possible.
1311
- var _loop2 = function* _loop2() {
1312
- var tKey = getTransceiverKey(SDPStreamMetadataPurpose.Usermedia, _track3.kind);
1313
- var transceiver = _this11.transceivers.get(tKey);
1314
- var oldSender = transceiver === null || transceiver === void 0 ? void 0 : transceiver.sender;
1315
- var added = false;
1316
- if (oldSender) {
1317
- try {
1318
- logger.info("Call ".concat(_this11.callId, " updateLocalUsermediaStream() replacing track (id=").concat(_track3.id, ", kind=").concat(_track3.kind, ", streamId=").concat(stream.id, ", streamPurpose=").concat(callFeed.purpose, ")"));
1319
- yield oldSender.replaceTrack(_track3);
1320
- // Set the direction to indicate we're going to be sending.
1321
- // This is only necessary in the cases where we're upgrading
1322
- // the call to video after downgrading it.
1323
- transceiver.direction = transceiver.direction === "inactive" ? "sendonly" : "sendrecv";
1324
- added = true;
1325
- } catch (error) {
1326
- logger.warn("Call ".concat(_this11.callId, " updateLocalUsermediaStream() replaceTrack failed: adding new transceiver instead"), error);
1327
- }
1240
+ // Then replace the old tracks, if possible.
1241
+ for (const track of stream.getTracks()) {
1242
+ const tKey = getTransceiverKey(SDPStreamMetadataPurpose.Usermedia, track.kind);
1243
+ const transceiver = this.transceivers.get(tKey);
1244
+ const oldSender = transceiver?.sender;
1245
+ let added = false;
1246
+ if (oldSender) {
1247
+ try {
1248
+ logger.info(`Call ${this.callId} updateLocalUsermediaStream() replacing track (id=${track.id}, kind=${track.kind}, streamId=${stream.id}, streamPurpose=${callFeed.purpose})`);
1249
+ await oldSender.replaceTrack(track);
1250
+ // Set the direction to indicate we're going to be sending.
1251
+ // This is only necessary in the cases where we're upgrading
1252
+ // the call to video after downgrading it.
1253
+ transceiver.direction = transceiver.direction === "inactive" ? "sendonly" : "sendrecv";
1254
+ added = true;
1255
+ } catch (error) {
1256
+ logger.warn(`Call ${this.callId} updateLocalUsermediaStream() replaceTrack failed: adding new transceiver instead`, error);
1328
1257
  }
1329
- if (!added) {
1330
- logger.info("Call ".concat(_this11.callId, " updateLocalUsermediaStream() adding track to peer connection (id=").concat(_track3.id, ", kind=").concat(_track3.kind, ", streamId=").concat(stream.id, ", streamPurpose=").concat(callFeed.purpose, ")"));
1331
- var newSender = _this11.peerConn.addTrack(_track3, _this11.localUsermediaStream);
1332
- var newTransceiver = _this11.peerConn.getTransceivers().find(t => t.sender === newSender);
1333
- if (newTransceiver) {
1334
- _this11.transceivers.set(tKey, newTransceiver);
1335
- } else {
1336
- logger.warn("Call ".concat(_this11.callId, " updateLocalUsermediaStream() couldn't find matching transceiver for newly added track!"));
1337
- }
1258
+ }
1259
+ if (!added) {
1260
+ logger.info(`Call ${this.callId} updateLocalUsermediaStream() adding track to peer connection (id=${track.id}, kind=${track.kind}, streamId=${stream.id}, streamPurpose=${callFeed.purpose})`);
1261
+ const newSender = this.peerConn.addTrack(track, this.localUsermediaStream);
1262
+ const newTransceiver = this.peerConn.getTransceivers().find(t => t.sender === newSender);
1263
+ if (newTransceiver) {
1264
+ this.transceivers.set(tKey, newTransceiver);
1265
+ } else {
1266
+ logger.warn(`Call ${this.callId} updateLocalUsermediaStream() couldn't find matching transceiver for newly added track!`);
1338
1267
  }
1339
- };
1340
- for (var _track3 of stream.getTracks()) {
1341
- yield* _loop2();
1342
1268
  }
1343
- })();
1269
+ }
1344
1270
  }
1345
1271
 
1346
1272
  /**
@@ -1348,55 +1274,50 @@ export class MatrixCall extends TypedEventEmitter {
1348
1274
  * @param muted - True to mute the outbound video.
1349
1275
  * @returns the new mute state
1350
1276
  */
1351
- setLocalVideoMuted(muted) {
1352
- var _this12 = this;
1353
- return _asyncToGenerator(function* () {
1354
- var _this12$localUsermedi2;
1355
- logger.log("Call ".concat(_this12.callId, " setLocalVideoMuted() running ").concat(muted));
1356
-
1357
- // if we were still thinking about stopping and removing the video
1358
- // track: don't, because we want it back.
1359
- if (!muted && _this12.stopVideoTrackTimer !== undefined) {
1360
- clearTimeout(_this12.stopVideoTrackTimer);
1361
- _this12.stopVideoTrackTimer = undefined;
1362
- }
1363
- if (!(yield _this12.client.getMediaHandler().hasVideoDevice())) {
1364
- return _this12.isLocalVideoMuted();
1365
- }
1366
- if (!_this12.hasUserMediaVideoSender && !muted) {
1367
- var _this12$localUsermedi;
1368
- (_this12$localUsermedi = _this12.localUsermediaFeed) === null || _this12$localUsermedi === void 0 || _this12$localUsermedi.setAudioVideoMuted(null, muted);
1369
- yield _this12.upgradeCall(false, true);
1370
- return _this12.isLocalVideoMuted();
1371
- }
1277
+ async setLocalVideoMuted(muted) {
1278
+ logger.log(`Call ${this.callId} setLocalVideoMuted() running ${muted}`);
1279
+
1280
+ // if we were still thinking about stopping and removing the video
1281
+ // track: don't, because we want it back.
1282
+ if (!muted && this.stopVideoTrackTimer !== undefined) {
1283
+ clearTimeout(this.stopVideoTrackTimer);
1284
+ this.stopVideoTrackTimer = undefined;
1285
+ }
1286
+ if (!(await this.client.getMediaHandler().hasVideoDevice())) {
1287
+ return this.isLocalVideoMuted();
1288
+ }
1289
+ if (!this.hasUserMediaVideoSender && !muted) {
1290
+ this.localUsermediaFeed?.setAudioVideoMuted(null, muted);
1291
+ await this.upgradeCall(false, true);
1292
+ return this.isLocalVideoMuted();
1293
+ }
1372
1294
 
1373
- // we may not have a video track - if not, re-request usermedia
1374
- if (!muted && _this12.localUsermediaStream.getVideoTracks().length === 0) {
1375
- var stream = yield _this12.client.getMediaHandler().getUserMediaStream(true, true);
1376
- yield _this12.updateLocalUsermediaStream(stream);
1377
- }
1378
- (_this12$localUsermedi2 = _this12.localUsermediaFeed) === null || _this12$localUsermedi2 === void 0 || _this12$localUsermedi2.setAudioVideoMuted(null, muted);
1379
- _this12.updateMuteStatus();
1380
- yield _this12.sendMetadataUpdate();
1381
-
1382
- // if we're muting video, set a timeout to stop & remove the video track so we release
1383
- // the camera. We wait a short time to do this because when we disable a track, WebRTC
1384
- // will send black video for it. If we just stop and remove it straight away, the video
1385
- // will just freeze which means that when we unmute video, the other side will briefly
1386
- // get a static frame of us from before we muted. This way, the still frame is just black.
1387
- // A very small delay is not always enough so the theory here is that it needs to be long
1388
- // enough for WebRTC to encode a frame: 120ms should be long enough even if we're only
1389
- // doing 10fps.
1390
- if (muted) {
1391
- _this12.stopVideoTrackTimer = setTimeout(() => {
1392
- for (var t of _this12.localUsermediaStream.getVideoTracks()) {
1393
- t.stop();
1394
- _this12.localUsermediaStream.removeTrack(t);
1395
- }
1396
- }, 120);
1397
- }
1398
- return _this12.isLocalVideoMuted();
1399
- })();
1295
+ // we may not have a video track - if not, re-request usermedia
1296
+ if (!muted && this.localUsermediaStream.getVideoTracks().length === 0) {
1297
+ const stream = await this.client.getMediaHandler().getUserMediaStream(true, true);
1298
+ await this.updateLocalUsermediaStream(stream);
1299
+ }
1300
+ this.localUsermediaFeed?.setAudioVideoMuted(null, muted);
1301
+ this.updateMuteStatus();
1302
+ await this.sendMetadataUpdate();
1303
+
1304
+ // if we're muting video, set a timeout to stop & remove the video track so we release
1305
+ // the camera. We wait a short time to do this because when we disable a track, WebRTC
1306
+ // will send black video for it. If we just stop and remove it straight away, the video
1307
+ // will just freeze which means that when we unmute video, the other side will briefly
1308
+ // get a static frame of us from before we muted. This way, the still frame is just black.
1309
+ // A very small delay is not always enough so the theory here is that it needs to be long
1310
+ // enough for WebRTC to encode a frame: 120ms should be long enough even if we're only
1311
+ // doing 10fps.
1312
+ if (muted) {
1313
+ this.stopVideoTrackTimer = setTimeout(() => {
1314
+ for (const t of this.localUsermediaStream.getVideoTracks()) {
1315
+ t.stop();
1316
+ this.localUsermediaStream.removeTrack(t);
1317
+ }
1318
+ }, 120);
1319
+ }
1320
+ return this.isLocalVideoMuted();
1400
1321
  }
1401
1322
 
1402
1323
  /**
@@ -1409,8 +1330,7 @@ export class MatrixCall extends TypedEventEmitter {
1409
1330
  * (including if the call is not set up yet).
1410
1331
  */
1411
1332
  isLocalVideoMuted() {
1412
- var _this$localUsermediaF2, _this$localUsermediaF3;
1413
- return (_this$localUsermediaF2 = (_this$localUsermediaF3 = this.localUsermediaFeed) === null || _this$localUsermediaF3 === void 0 ? void 0 : _this$localUsermediaF3.isVideoMuted()) !== null && _this$localUsermediaF2 !== void 0 ? _this$localUsermediaF2 : false;
1333
+ return this.localUsermediaFeed?.isVideoMuted() ?? false;
1414
1334
  }
1415
1335
 
1416
1336
  /**
@@ -1418,23 +1338,19 @@ export class MatrixCall extends TypedEventEmitter {
1418
1338
  * @param muted - True to mute the mic.
1419
1339
  * @returns the new mute state
1420
1340
  */
1421
- setMicrophoneMuted(muted) {
1422
- var _this13 = this;
1423
- return _asyncToGenerator(function* () {
1424
- var _this13$localUsermedi;
1425
- logger.log("Call ".concat(_this13.callId, " setMicrophoneMuted() running ").concat(muted));
1426
- if (!(yield _this13.client.getMediaHandler().hasAudioDevice())) {
1427
- return _this13.isMicrophoneMuted();
1428
- }
1429
- if (!muted && (!_this13.hasUserMediaAudioSender || !_this13.hasLocalUserMediaAudioTrack)) {
1430
- yield _this13.upgradeCall(true, false);
1431
- return _this13.isMicrophoneMuted();
1432
- }
1433
- (_this13$localUsermedi = _this13.localUsermediaFeed) === null || _this13$localUsermedi === void 0 || _this13$localUsermedi.setAudioVideoMuted(muted, null);
1434
- _this13.updateMuteStatus();
1435
- yield _this13.sendMetadataUpdate();
1436
- return _this13.isMicrophoneMuted();
1437
- })();
1341
+ async setMicrophoneMuted(muted) {
1342
+ logger.log(`Call ${this.callId} setMicrophoneMuted() running ${muted}`);
1343
+ if (!(await this.client.getMediaHandler().hasAudioDevice())) {
1344
+ return this.isMicrophoneMuted();
1345
+ }
1346
+ if (!muted && (!this.hasUserMediaAudioSender || !this.hasLocalUserMediaAudioTrack)) {
1347
+ await this.upgradeCall(true, false);
1348
+ return this.isMicrophoneMuted();
1349
+ }
1350
+ this.localUsermediaFeed?.setAudioVideoMuted(muted, null);
1351
+ this.updateMuteStatus();
1352
+ await this.sendMetadataUpdate();
1353
+ return this.isMicrophoneMuted();
1438
1354
  }
1439
1355
 
1440
1356
  /**
@@ -1447,8 +1363,7 @@ export class MatrixCall extends TypedEventEmitter {
1447
1363
  * is not set up yet).
1448
1364
  */
1449
1365
  isMicrophoneMuted() {
1450
- var _this$localUsermediaF4, _this$localUsermediaF5;
1451
- return (_this$localUsermediaF4 = (_this$localUsermediaF5 = this.localUsermediaFeed) === null || _this$localUsermediaF5 === void 0 ? void 0 : _this$localUsermediaF5.isAudioMuted()) !== null && _this$localUsermediaF4 !== void 0 ? _this$localUsermediaF4 : false;
1366
+ return this.localUsermediaFeed?.isAudioMuted() ?? false;
1452
1367
  }
1453
1368
 
1454
1369
  /**
@@ -1461,7 +1376,7 @@ export class MatrixCall extends TypedEventEmitter {
1461
1376
  setRemoteOnHold(onHold) {
1462
1377
  if (this.isRemoteOnHold() === onHold) return;
1463
1378
  this.remoteOnHold = onHold;
1464
- for (var transceiver of this.peerConn.getTransceivers()) {
1379
+ for (const transceiver of this.peerConn.getTransceivers()) {
1465
1380
  // We don't send hold music or anything so we're not actually
1466
1381
  // sending anything, but sendrecv is fairly standard for hold and
1467
1382
  // it makes it a lot easier to figure out who's put who on hold.
@@ -1479,12 +1394,12 @@ export class MatrixCall extends TypedEventEmitter {
1479
1394
  */
1480
1395
  isLocalOnHold() {
1481
1396
  if (this.state !== CallState.Connected) return false;
1482
- var callOnHold = true;
1397
+ let callOnHold = true;
1483
1398
 
1484
1399
  // We consider a call to be on hold only if *all* the tracks are on hold
1485
1400
  // (is this the right thing to do?)
1486
- for (var transceiver of this.peerConn.getTransceivers()) {
1487
- var trackOnHold = ["inactive", "recvonly"].includes(transceiver.currentDirection);
1401
+ for (const transceiver of this.peerConn.getTransceivers()) {
1402
+ const trackOnHold = ["inactive", "recvonly"].includes(transceiver.currentDirection);
1488
1403
  if (!trackOnHold) callOnHold = false;
1489
1404
  }
1490
1405
  return callOnHold;
@@ -1495,9 +1410,8 @@ export class MatrixCall extends TypedEventEmitter {
1495
1410
  * @param digit - The digit (nb. string - '#' and '*' are dtmf too)
1496
1411
  */
1497
1412
  sendDtmfDigit(digit) {
1498
- for (var sender of this.peerConn.getSenders()) {
1499
- var _sender$track;
1500
- if (((_sender$track = sender.track) === null || _sender$track === void 0 ? void 0 : _sender$track.kind) === "audio" && sender.dtmf) {
1413
+ for (const sender of this.peerConn.getSenders()) {
1414
+ if (sender.track?.kind === "audio" && sender.dtmf) {
1501
1415
  sender.dtmf.insertDTMF(digit);
1502
1416
  return;
1503
1417
  }
@@ -1505,22 +1419,18 @@ export class MatrixCall extends TypedEventEmitter {
1505
1419
  throw new Error("Unable to find a track to send DTMF on");
1506
1420
  }
1507
1421
  updateMuteStatus() {
1508
- var micShouldBeMuted = this.isMicrophoneMuted() || this.remoteOnHold;
1509
- var vidShouldBeMuted = this.isLocalVideoMuted() || this.remoteOnHold;
1510
- logger.log("Call ".concat(this.callId, " updateMuteStatus stream ").concat(this.localUsermediaStream.id, " micShouldBeMuted ").concat(micShouldBeMuted, " vidShouldBeMuted ").concat(vidShouldBeMuted));
1422
+ const micShouldBeMuted = this.isMicrophoneMuted() || this.remoteOnHold;
1423
+ const vidShouldBeMuted = this.isLocalVideoMuted() || this.remoteOnHold;
1424
+ logger.log(`Call ${this.callId} updateMuteStatus stream ${this.localUsermediaStream.id} micShouldBeMuted ${micShouldBeMuted} vidShouldBeMuted ${vidShouldBeMuted}`);
1511
1425
  setTracksEnabled(this.localUsermediaStream.getAudioTracks(), !micShouldBeMuted);
1512
1426
  setTracksEnabled(this.localUsermediaStream.getVideoTracks(), !vidShouldBeMuted);
1513
1427
  }
1514
- sendMetadataUpdate() {
1515
- var _this14 = this;
1516
- return _asyncToGenerator(function* () {
1517
- yield _this14.sendVoipEvent(EventType.CallSDPStreamMetadataChanged, {
1518
- [SDPStreamMetadataKey.name]: _this14.getLocalSDPStreamMetadata()
1519
- });
1520
- })();
1428
+ async sendMetadataUpdate() {
1429
+ await this.sendVoipEvent(EventType.CallSDPStreamMetadataChanged, {
1430
+ [SDPStreamMetadataKey.name]: this.getLocalSDPStreamMetadata()
1431
+ });
1521
1432
  }
1522
- gotCallFeedsForInvite(callFeeds) {
1523
- var requestScreenshareFeed = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
1433
+ gotCallFeedsForInvite(callFeeds, requestScreenshareFeed = false) {
1524
1434
  if (this.successor) {
1525
1435
  this.successor.queueGotCallFeedsForAnswer(callFeeds);
1526
1436
  return;
@@ -1529,7 +1439,7 @@ export class MatrixCall extends TypedEventEmitter {
1529
1439
  this.stopAllMedia();
1530
1440
  return;
1531
1441
  }
1532
- for (var feed of callFeeds) {
1442
+ for (const feed of callFeeds) {
1533
1443
  this.pushLocalFeed(feed);
1534
1444
  }
1535
1445
  if (requestScreenshareFeed) {
@@ -1538,54 +1448,51 @@ export class MatrixCall extends TypedEventEmitter {
1538
1448
  });
1539
1449
  }
1540
1450
  this.state = CallState.CreateOffer;
1541
- logger.debug("Call ".concat(this.callId, " gotUserMediaForInvite() run"));
1451
+ logger.debug(`Call ${this.callId} gotUserMediaForInvite() run`);
1542
1452
  // Now we wait for the negotiationneeded event
1543
1453
  }
1544
- sendAnswer() {
1545
- var _this15 = this;
1546
- return _asyncToGenerator(function* () {
1547
- var answerContent = {
1548
- answer: {
1549
- sdp: _this15.peerConn.localDescription.sdp,
1550
- // type is now deprecated as of Matrix VoIP v1, but
1551
- // required to still be sent for backwards compat
1552
- type: _this15.peerConn.localDescription.type
1553
- },
1554
- [SDPStreamMetadataKey.name]: _this15.getLocalSDPStreamMetadata(true)
1555
- };
1556
- answerContent.capabilities = {
1557
- "m.call.transferee": _this15.client.supportsCallTransfer,
1558
- "m.call.dtmf": false
1559
- };
1560
-
1561
- // We have just taken the local description from the peerConn which will
1562
- // contain all the local candidates added so far, so we can discard any candidates
1563
- // we had queued up because they'll be in the answer.
1564
- var discardCount = _this15.discardDuplicateCandidates();
1565
- logger.info("Call ".concat(_this15.callId, " sendAnswer() discarding ").concat(discardCount, " candidates that will be sent in answer"));
1566
- try {
1567
- yield _this15.sendVoipEvent(EventType.CallAnswer, answerContent);
1568
- // If this isn't the first time we've tried to send the answer,
1569
- // we may have candidates queued up, so send them now.
1570
- _this15.inviteOrAnswerSent = true;
1571
- } catch (error) {
1572
- // We've failed to answer: back to the ringing state
1573
- _this15.state = CallState.Ringing;
1574
- if (error instanceof MatrixError && error.event) _this15.client.cancelPendingEvent(error.event);
1575
- var code = CallErrorCode.SendAnswer;
1576
- var message = "Failed to send answer";
1577
- if (error.name == "UnknownDeviceError") {
1578
- code = CallErrorCode.UnknownDevices;
1579
- message = "Unknown devices present in the room";
1580
- }
1581
- _this15.emit(CallEvent.Error, new CallError(code, message, error), _this15);
1582
- throw error;
1583
- }
1454
+ async sendAnswer() {
1455
+ const answerContent = {
1456
+ answer: {
1457
+ sdp: this.peerConn.localDescription.sdp,
1458
+ // type is now deprecated as of Matrix VoIP v1, but
1459
+ // required to still be sent for backwards compat
1460
+ type: this.peerConn.localDescription.type
1461
+ },
1462
+ [SDPStreamMetadataKey.name]: this.getLocalSDPStreamMetadata(true)
1463
+ };
1464
+ answerContent.capabilities = {
1465
+ "m.call.transferee": this.client.supportsCallTransfer,
1466
+ "m.call.dtmf": false
1467
+ };
1468
+
1469
+ // We have just taken the local description from the peerConn which will
1470
+ // contain all the local candidates added so far, so we can discard any candidates
1471
+ // we had queued up because they'll be in the answer.
1472
+ const discardCount = this.discardDuplicateCandidates();
1473
+ logger.info(`Call ${this.callId} sendAnswer() discarding ${discardCount} candidates that will be sent in answer`);
1474
+ try {
1475
+ await this.sendVoipEvent(EventType.CallAnswer, answerContent);
1476
+ // If this isn't the first time we've tried to send the answer,
1477
+ // we may have candidates queued up, so send them now.
1478
+ this.inviteOrAnswerSent = true;
1479
+ } catch (error) {
1480
+ // We've failed to answer: back to the ringing state
1481
+ this.state = CallState.Ringing;
1482
+ if (error instanceof MatrixError && error.event) this.client.cancelPendingEvent(error.event);
1483
+ let code = CallErrorCode.SendAnswer;
1484
+ let message = "Failed to send answer";
1485
+ if (error.name == "UnknownDeviceError") {
1486
+ code = CallErrorCode.UnknownDevices;
1487
+ message = "Unknown devices present in the room";
1488
+ }
1489
+ this.emit(CallEvent.Error, new CallError(code, message, error), this);
1490
+ throw error;
1491
+ }
1584
1492
 
1585
- // error handler re-throws so this won't happen on error, but
1586
- // we don't want the same error handling on the candidate queue
1587
- _this15.sendCandidateQueue();
1588
- })();
1493
+ // error handler re-throws so this won't happen on error, but
1494
+ // we don't want the same error handling on the candidate queue
1495
+ this.sendCandidateQueue();
1589
1496
  }
1590
1497
  queueGotCallFeedsForAnswer(callFeeds) {
1591
1498
  // Ensure only one negotiate/answer event is being processed at a time.
@@ -1600,29 +1507,29 @@ export class MatrixCall extends TypedEventEmitter {
1600
1507
  // bandwidth when transmitting silence
1601
1508
  mungeSdp(description, mods) {
1602
1509
  // The only way to enable DTX at this time is through SDP munging
1603
- var sdp = parseSdp(description.sdp);
1510
+ const sdp = parseSdp(description.sdp);
1604
1511
  sdp.media.forEach(media => {
1605
- var payloadTypeToCodecMap = new Map();
1606
- var codecToPayloadTypeMap = new Map();
1607
- for (var rtp of media.rtp) {
1512
+ const payloadTypeToCodecMap = new Map();
1513
+ const codecToPayloadTypeMap = new Map();
1514
+ for (const rtp of media.rtp) {
1608
1515
  payloadTypeToCodecMap.set(rtp.payload, rtp.codec);
1609
1516
  codecToPayloadTypeMap.set(rtp.codec, rtp.payload);
1610
1517
  }
1611
- for (var mod of mods) {
1518
+ for (const mod of mods) {
1612
1519
  if (mod.mediaType !== media.type) continue;
1613
1520
  if (!codecToPayloadTypeMap.has(mod.codec)) {
1614
- logger.info("Call ".concat(this.callId, " mungeSdp() ignoring SDP modifications for ").concat(mod.codec, " as it's not present."));
1521
+ logger.info(`Call ${this.callId} mungeSdp() ignoring SDP modifications for ${mod.codec} as it's not present.`);
1615
1522
  continue;
1616
1523
  }
1617
- var extraConfig = [];
1524
+ const extraConfig = [];
1618
1525
  if (mod.enableDtx !== undefined) {
1619
- extraConfig.push("usedtx=".concat(mod.enableDtx ? "1" : "0"));
1526
+ extraConfig.push(`usedtx=${mod.enableDtx ? "1" : "0"}`);
1620
1527
  }
1621
1528
  if (mod.maxAverageBitrate !== undefined) {
1622
- extraConfig.push("maxaveragebitrate=".concat(mod.maxAverageBitrate));
1529
+ extraConfig.push(`maxaveragebitrate=${mod.maxAverageBitrate}`);
1623
1530
  }
1624
- var found = false;
1625
- for (var fmtp of media.fmtp) {
1531
+ let found = false;
1532
+ for (const fmtp of media.fmtp) {
1626
1533
  if (payloadTypeToCodecMap.get(fmtp.payload) === mod.codec) {
1627
1534
  found = true;
1628
1535
  fmtp.config += ";" + extraConfig.join(";");
@@ -1638,260 +1545,234 @@ export class MatrixCall extends TypedEventEmitter {
1638
1545
  });
1639
1546
  description.sdp = writeSdp(sdp);
1640
1547
  }
1641
- createOffer() {
1642
- var _this16 = this;
1643
- return _asyncToGenerator(function* () {
1644
- var offer = yield _this16.peerConn.createOffer();
1645
- _this16.mungeSdp(offer, getCodecParamMods(_this16.isPtt));
1646
- return offer;
1647
- })();
1648
- }
1649
- createAnswer() {
1650
- var _this17 = this;
1651
- return _asyncToGenerator(function* () {
1652
- var answer = yield _this17.peerConn.createAnswer();
1653
- _this17.mungeSdp(answer, getCodecParamMods(_this17.isPtt));
1654
- return answer;
1655
- })();
1656
- }
1657
- gotCallFeedsForAnswer(callFeeds) {
1658
- var _this18 = this;
1659
- return _asyncToGenerator(function* () {
1660
- if (_this18.callHasEnded()) return;
1661
- _this18.waitForLocalAVStream = false;
1662
- for (var feed of callFeeds) {
1663
- _this18.pushLocalFeed(feed);
1664
- }
1665
- _this18.state = CallState.CreateAnswer;
1666
- var answer;
1667
- try {
1668
- _this18.getRidOfRTXCodecs();
1669
- answer = yield _this18.createAnswer();
1670
- } catch (err) {
1671
- logger.debug("Call ".concat(_this18.callId, " gotCallFeedsForAnswer() failed to create answer: "), err);
1672
- _this18.terminate(CallParty.Local, CallErrorCode.CreateAnswer, true);
1673
- return;
1674
- }
1675
- try {
1676
- yield _this18.peerConn.setLocalDescription(answer);
1548
+ async createOffer() {
1549
+ const offer = await this.peerConn.createOffer();
1550
+ this.mungeSdp(offer, getCodecParamMods(this.isPtt));
1551
+ return offer;
1552
+ }
1553
+ async createAnswer() {
1554
+ const answer = await this.peerConn.createAnswer();
1555
+ this.mungeSdp(answer, getCodecParamMods(this.isPtt));
1556
+ return answer;
1557
+ }
1558
+ async gotCallFeedsForAnswer(callFeeds) {
1559
+ if (this.callHasEnded()) return;
1560
+ this.waitForLocalAVStream = false;
1561
+ for (const feed of callFeeds) {
1562
+ this.pushLocalFeed(feed);
1563
+ }
1564
+ this.state = CallState.CreateAnswer;
1565
+ let answer;
1566
+ try {
1567
+ this.getRidOfRTXCodecs();
1568
+ answer = await this.createAnswer();
1569
+ } catch (err) {
1570
+ logger.debug(`Call ${this.callId} gotCallFeedsForAnswer() failed to create answer: `, err);
1571
+ this.terminate(CallParty.Local, CallErrorCode.CreateAnswer, true);
1572
+ return;
1573
+ }
1574
+ try {
1575
+ await this.peerConn.setLocalDescription(answer);
1677
1576
 
1678
- // make sure we're still going
1679
- if (_this18.callHasEnded()) return;
1680
- _this18.state = CallState.Connecting;
1577
+ // make sure we're still going
1578
+ if (this.callHasEnded()) return;
1579
+ this.state = CallState.Connecting;
1681
1580
 
1682
- // Allow a short time for initial candidates to be gathered
1683
- yield new Promise(resolve => {
1684
- setTimeout(resolve, 200);
1685
- });
1581
+ // Allow a short time for initial candidates to be gathered
1582
+ await new Promise(resolve => {
1583
+ setTimeout(resolve, 200);
1584
+ });
1686
1585
 
1687
- // make sure the call hasn't ended before we continue
1688
- if (_this18.callHasEnded()) return;
1689
- _this18.sendAnswer();
1690
- } catch (err) {
1691
- logger.debug("Call ".concat(_this18.callId, " gotCallFeedsForAnswer() error setting local description!"), err);
1692
- _this18.terminate(CallParty.Local, CallErrorCode.SetLocalDescription, true);
1693
- return;
1694
- }
1695
- })();
1586
+ // make sure the call hasn't ended before we continue
1587
+ if (this.callHasEnded()) return;
1588
+ this.sendAnswer();
1589
+ } catch (err) {
1590
+ logger.debug(`Call ${this.callId} gotCallFeedsForAnswer() error setting local description!`, err);
1591
+ this.terminate(CallParty.Local, CallErrorCode.SetLocalDescription, true);
1592
+ return;
1593
+ }
1696
1594
  }
1697
- onRemoteIceCandidatesReceived(ev) {
1698
- var _this19 = this;
1699
- return _asyncToGenerator(function* () {
1700
- if (_this19.callHasEnded()) {
1701
- //debuglog("Ignoring remote ICE candidate because call has ended");
1702
- return;
1703
- }
1704
- var content = ev.getContent();
1705
- var candidates = content.candidates;
1706
- if (!candidates) {
1707
- logger.info("Call ".concat(_this19.callId, " onRemoteIceCandidatesReceived() ignoring candidates event with no candidates!"));
1708
- return;
1709
- }
1710
- var fromPartyId = content.version === 0 ? null : content.party_id || null;
1711
- if (_this19.opponentPartyId === undefined) {
1712
- // we haven't picked an opponent yet so save the candidates
1713
- if (fromPartyId) {
1714
- logger.info("Call ".concat(_this19.callId, " onRemoteIceCandidatesReceived() buffering ").concat(candidates.length, " candidates until we pick an opponent"));
1715
- var bufferedCandidates = _this19.remoteCandidateBuffer.get(fromPartyId) || [];
1716
- bufferedCandidates.push(...candidates);
1717
- _this19.remoteCandidateBuffer.set(fromPartyId, bufferedCandidates);
1718
- }
1719
- return;
1720
- }
1721
- if (!_this19.partyIdMatches(content)) {
1722
- logger.info("Call ".concat(_this19.callId, " onRemoteIceCandidatesReceived() ignoring candidates from party ID ").concat(content.party_id, ": we have chosen party ID ").concat(_this19.opponentPartyId));
1723
- return;
1595
+ async onRemoteIceCandidatesReceived(ev) {
1596
+ if (this.callHasEnded()) {
1597
+ //debuglog("Ignoring remote ICE candidate because call has ended");
1598
+ return;
1599
+ }
1600
+ const content = ev.getContent();
1601
+ const candidates = content.candidates;
1602
+ if (!candidates) {
1603
+ logger.info(`Call ${this.callId} onRemoteIceCandidatesReceived() ignoring candidates event with no candidates!`);
1604
+ return;
1605
+ }
1606
+ const fromPartyId = content.version === 0 ? null : content.party_id || null;
1607
+ if (this.opponentPartyId === undefined) {
1608
+ // we haven't picked an opponent yet so save the candidates
1609
+ if (fromPartyId) {
1610
+ logger.info(`Call ${this.callId} onRemoteIceCandidatesReceived() buffering ${candidates.length} candidates until we pick an opponent`);
1611
+ const bufferedCandidates = this.remoteCandidateBuffer.get(fromPartyId) || [];
1612
+ bufferedCandidates.push(...candidates);
1613
+ this.remoteCandidateBuffer.set(fromPartyId, bufferedCandidates);
1724
1614
  }
1725
- yield _this19.addIceCandidates(candidates);
1726
- })();
1615
+ return;
1616
+ }
1617
+ if (!this.partyIdMatches(content)) {
1618
+ logger.info(`Call ${this.callId} onRemoteIceCandidatesReceived() ignoring candidates from party ID ${content.party_id}: we have chosen party ID ${this.opponentPartyId}`);
1619
+ return;
1620
+ }
1621
+ await this.addIceCandidates(candidates);
1727
1622
  }
1728
1623
 
1729
1624
  /**
1730
1625
  * Used by MatrixClient.
1731
1626
  */
1732
- onAnswerReceived(event) {
1733
- var _this20 = this;
1734
- return _asyncToGenerator(function* () {
1735
- var content = event.getContent();
1736
- logger.debug("Call ".concat(_this20.callId, " onAnswerReceived() running (hangupParty=").concat(content.party_id, ")"));
1737
- if (_this20.callHasEnded()) {
1738
- logger.debug("Call ".concat(_this20.callId, " onAnswerReceived() ignoring answer because call has ended"));
1739
- return;
1740
- }
1741
- if (_this20.opponentPartyId !== undefined) {
1742
- logger.info("Call ".concat(_this20.callId, " onAnswerReceived() ignoring answer from party ID ").concat(content.party_id, ": we already have an answer/reject from ").concat(_this20.opponentPartyId));
1743
- return;
1744
- }
1745
- _this20.chooseOpponent(event);
1746
- yield _this20.addBufferedIceCandidates();
1747
- _this20.state = CallState.Connecting;
1748
- var sdpStreamMetadata = SDPStreamMetadataKey.findIn(content);
1749
- if (sdpStreamMetadata) {
1750
- _this20.updateRemoteSDPStreamMetadata(sdpStreamMetadata);
1751
- } else {
1752
- logger.warn("Call ".concat(_this20.callId, " onAnswerReceived() did not get any SDPStreamMetadata! Can not send/receive multiple streams"));
1753
- }
1627
+ async onAnswerReceived(event) {
1628
+ const content = event.getContent();
1629
+ logger.debug(`Call ${this.callId} onAnswerReceived() running (hangupParty=${content.party_id})`);
1630
+ if (this.callHasEnded()) {
1631
+ logger.debug(`Call ${this.callId} onAnswerReceived() ignoring answer because call has ended`);
1632
+ return;
1633
+ }
1634
+ if (this.opponentPartyId !== undefined) {
1635
+ logger.info(`Call ${this.callId} onAnswerReceived() ignoring answer from party ID ${content.party_id}: we already have an answer/reject from ${this.opponentPartyId}`);
1636
+ return;
1637
+ }
1638
+ this.chooseOpponent(event);
1639
+ await this.addBufferedIceCandidates();
1640
+ this.state = CallState.Connecting;
1641
+ const sdpStreamMetadata = SDPStreamMetadataKey.findIn(content);
1642
+ if (sdpStreamMetadata) {
1643
+ this.updateRemoteSDPStreamMetadata(sdpStreamMetadata);
1644
+ } else {
1645
+ logger.warn(`Call ${this.callId} onAnswerReceived() did not get any SDPStreamMetadata! Can not send/receive multiple streams`);
1646
+ }
1647
+ try {
1648
+ this.isSettingRemoteAnswerPending = true;
1649
+ await this.peerConn.setRemoteDescription(content.answer);
1650
+ this.isSettingRemoteAnswerPending = false;
1651
+ logger.debug(`Call ${this.callId} onAnswerReceived() set remote description: ${content.answer.type}`);
1652
+ } catch (e) {
1653
+ this.isSettingRemoteAnswerPending = false;
1654
+ logger.debug(`Call ${this.callId} onAnswerReceived() failed to set remote description`, e);
1655
+ this.terminate(CallParty.Local, CallErrorCode.SetRemoteDescription, false);
1656
+ return;
1657
+ }
1658
+
1659
+ // If the answer we selected has a party_id, send a select_answer event
1660
+ // We do this after setting the remote description since otherwise we'd block
1661
+ // call setup on it
1662
+ if (this.opponentPartyId !== null) {
1754
1663
  try {
1755
- _this20.isSettingRemoteAnswerPending = true;
1756
- yield _this20.peerConn.setRemoteDescription(content.answer);
1757
- _this20.isSettingRemoteAnswerPending = false;
1758
- logger.debug("Call ".concat(_this20.callId, " onAnswerReceived() set remote description: ").concat(content.answer.type));
1759
- } catch (e) {
1760
- _this20.isSettingRemoteAnswerPending = false;
1761
- logger.debug("Call ".concat(_this20.callId, " onAnswerReceived() failed to set remote description"), e);
1762
- _this20.terminate(CallParty.Local, CallErrorCode.SetRemoteDescription, false);
1763
- return;
1664
+ await this.sendVoipEvent(EventType.CallSelectAnswer, {
1665
+ selected_party_id: this.opponentPartyId
1666
+ });
1667
+ } catch (err) {
1668
+ // This isn't fatal, and will just mean that if another party has raced to answer
1669
+ // the call, they won't know they got rejected, so we carry on & don't retry.
1670
+ logger.warn(`Call ${this.callId} onAnswerReceived() failed to send select_answer event`, err);
1764
1671
  }
1765
-
1766
- // If the answer we selected has a party_id, send a select_answer event
1767
- // We do this after setting the remote description since otherwise we'd block
1768
- // call setup on it
1769
- if (_this20.opponentPartyId !== null) {
1672
+ }
1673
+ }
1674
+ async onSelectAnswerReceived(event) {
1675
+ if (this.direction !== CallDirection.Inbound) {
1676
+ logger.warn(`Call ${this.callId} onSelectAnswerReceived() got select_answer for an outbound call: ignoring`);
1677
+ return;
1678
+ }
1679
+ const selectedPartyId = event.getContent().selected_party_id;
1680
+ if (selectedPartyId === undefined || selectedPartyId === null) {
1681
+ logger.warn(`Call ${this.callId} onSelectAnswerReceived() got nonsensical select_answer with null/undefined selected_party_id: ignoring`);
1682
+ return;
1683
+ }
1684
+ if (selectedPartyId !== this.ourPartyId) {
1685
+ logger.info(`Call ${this.callId} onSelectAnswerReceived() got select_answer for party ID ${selectedPartyId}: we are party ID ${this.ourPartyId}.`);
1686
+ // The other party has picked somebody else's answer
1687
+ await this.terminate(CallParty.Remote, CallErrorCode.AnsweredElsewhere, true);
1688
+ }
1689
+ }
1690
+ async onNegotiateReceived(event) {
1691
+ const content = event.getContent();
1692
+ const description = content.description;
1693
+ if (!description || !description.sdp || !description.type) {
1694
+ logger.info(`Call ${this.callId} onNegotiateReceived() ignoring invalid m.call.negotiate event`);
1695
+ return;
1696
+ }
1697
+ // Politeness always follows the direction of the call: in a glare situation,
1698
+ // we pick either the inbound or outbound call, so one side will always be
1699
+ // inbound and one outbound
1700
+ const polite = this.direction === CallDirection.Inbound;
1701
+
1702
+ // Here we follow the perfect negotiation logic from
1703
+ // https://w3c.github.io/webrtc-pc/#perfect-negotiation-example
1704
+ const readyForOffer = !this.makingOffer && (this.peerConn.signalingState === "stable" || this.isSettingRemoteAnswerPending);
1705
+ const offerCollision = description.type === "offer" && !readyForOffer;
1706
+ this.ignoreOffer = !polite && offerCollision;
1707
+ if (this.ignoreOffer) {
1708
+ logger.info(`Call ${this.callId} onNegotiateReceived() ignoring colliding negotiate event because we're impolite`);
1709
+ return;
1710
+ }
1711
+ const prevLocalOnHold = this.isLocalOnHold();
1712
+ const sdpStreamMetadata = SDPStreamMetadataKey.findIn(content);
1713
+ if (sdpStreamMetadata) {
1714
+ this.updateRemoteSDPStreamMetadata(sdpStreamMetadata);
1715
+ } else {
1716
+ logger.warn(`Call ${this.callId} onNegotiateReceived() received negotiation event without SDPStreamMetadata!`);
1717
+ }
1718
+ try {
1719
+ this.isSettingRemoteAnswerPending = description.type == "answer";
1720
+ await this.peerConn.setRemoteDescription(description); // SRD rolls back as needed
1721
+ this.isSettingRemoteAnswerPending = false;
1722
+ logger.debug(`Call ${this.callId} onNegotiateReceived() set remote description: ${description.type}`);
1723
+ if (description.type === "offer") {
1724
+ let answer;
1770
1725
  try {
1771
- yield _this20.sendVoipEvent(EventType.CallSelectAnswer, {
1772
- selected_party_id: _this20.opponentPartyId
1773
- });
1726
+ this.getRidOfRTXCodecs();
1727
+ answer = await this.createAnswer();
1774
1728
  } catch (err) {
1775
- // This isn't fatal, and will just mean that if another party has raced to answer
1776
- // the call, they won't know they got rejected, so we carry on & don't retry.
1777
- logger.warn("Call ".concat(_this20.callId, " onAnswerReceived() failed to send select_answer event"), err);
1778
- }
1779
- }
1780
- })();
1781
- }
1782
- onSelectAnswerReceived(event) {
1783
- var _this21 = this;
1784
- return _asyncToGenerator(function* () {
1785
- if (_this21.direction !== CallDirection.Inbound) {
1786
- logger.warn("Call ".concat(_this21.callId, " onSelectAnswerReceived() got select_answer for an outbound call: ignoring"));
1787
- return;
1788
- }
1789
- var selectedPartyId = event.getContent().selected_party_id;
1790
- if (selectedPartyId === undefined || selectedPartyId === null) {
1791
- logger.warn("Call ".concat(_this21.callId, " onSelectAnswerReceived() got nonsensical select_answer with null/undefined selected_party_id: ignoring"));
1792
- return;
1793
- }
1794
- if (selectedPartyId !== _this21.ourPartyId) {
1795
- logger.info("Call ".concat(_this21.callId, " onSelectAnswerReceived() got select_answer for party ID ").concat(selectedPartyId, ": we are party ID ").concat(_this21.ourPartyId, "."));
1796
- // The other party has picked somebody else's answer
1797
- yield _this21.terminate(CallParty.Remote, CallErrorCode.AnsweredElsewhere, true);
1798
- }
1799
- })();
1800
- }
1801
- onNegotiateReceived(event) {
1802
- var _this22 = this;
1803
- return _asyncToGenerator(function* () {
1804
- var content = event.getContent();
1805
- var description = content.description;
1806
- if (!description || !description.sdp || !description.type) {
1807
- logger.info("Call ".concat(_this22.callId, " onNegotiateReceived() ignoring invalid m.call.negotiate event"));
1808
- return;
1809
- }
1810
- // Politeness always follows the direction of the call: in a glare situation,
1811
- // we pick either the inbound or outbound call, so one side will always be
1812
- // inbound and one outbound
1813
- var polite = _this22.direction === CallDirection.Inbound;
1814
-
1815
- // Here we follow the perfect negotiation logic from
1816
- // https://w3c.github.io/webrtc-pc/#perfect-negotiation-example
1817
- var readyForOffer = !_this22.makingOffer && (_this22.peerConn.signalingState === "stable" || _this22.isSettingRemoteAnswerPending);
1818
- var offerCollision = description.type === "offer" && !readyForOffer;
1819
- _this22.ignoreOffer = !polite && offerCollision;
1820
- if (_this22.ignoreOffer) {
1821
- logger.info("Call ".concat(_this22.callId, " onNegotiateReceived() ignoring colliding negotiate event because we're impolite"));
1822
- return;
1823
- }
1824
- var prevLocalOnHold = _this22.isLocalOnHold();
1825
- var sdpStreamMetadata = SDPStreamMetadataKey.findIn(content);
1826
- if (sdpStreamMetadata) {
1827
- _this22.updateRemoteSDPStreamMetadata(sdpStreamMetadata);
1828
- } else {
1829
- logger.warn("Call ".concat(_this22.callId, " onNegotiateReceived() received negotiation event without SDPStreamMetadata!"));
1830
- }
1831
- try {
1832
- _this22.isSettingRemoteAnswerPending = description.type == "answer";
1833
- yield _this22.peerConn.setRemoteDescription(description); // SRD rolls back as needed
1834
- _this22.isSettingRemoteAnswerPending = false;
1835
- logger.debug("Call ".concat(_this22.callId, " onNegotiateReceived() set remote description: ").concat(description.type));
1836
- if (description.type === "offer") {
1837
- var _localDescription;
1838
- var answer;
1839
- try {
1840
- _this22.getRidOfRTXCodecs();
1841
- answer = yield _this22.createAnswer();
1842
- } catch (err) {
1843
- logger.debug("Call ".concat(_this22.callId, " onNegotiateReceived() failed to create answer: "), err);
1844
- _this22.terminate(CallParty.Local, CallErrorCode.CreateAnswer, true);
1845
- return;
1846
- }
1847
- yield _this22.peerConn.setLocalDescription(answer);
1848
- logger.debug("Call ".concat(_this22.callId, " onNegotiateReceived() create an answer"));
1849
- _this22.sendVoipEvent(EventType.CallNegotiate, {
1850
- lifetime: CALL_TIMEOUT_MS,
1851
- description: (_localDescription = _this22.peerConn.localDescription) === null || _localDescription === void 0 ? void 0 : _localDescription.toJSON(),
1852
- [SDPStreamMetadataKey.name]: _this22.getLocalSDPStreamMetadata(true)
1853
- });
1729
+ logger.debug(`Call ${this.callId} onNegotiateReceived() failed to create answer: `, err);
1730
+ this.terminate(CallParty.Local, CallErrorCode.CreateAnswer, true);
1731
+ return;
1854
1732
  }
1855
- } catch (err) {
1856
- _this22.isSettingRemoteAnswerPending = false;
1857
- logger.warn("Call ".concat(_this22.callId, " onNegotiateReceived() failed to complete negotiation"), err);
1858
- }
1859
- var newLocalOnHold = _this22.isLocalOnHold();
1860
- if (prevLocalOnHold !== newLocalOnHold) {
1861
- _this22.emit(CallEvent.LocalHoldUnhold, newLocalOnHold, _this22);
1862
- // also this one for backwards compat
1863
- _this22.emit(CallEvent.HoldUnhold, newLocalOnHold);
1733
+ await this.peerConn.setLocalDescription(answer);
1734
+ logger.debug(`Call ${this.callId} onNegotiateReceived() create an answer`);
1735
+ this.sendVoipEvent(EventType.CallNegotiate, {
1736
+ lifetime: CALL_TIMEOUT_MS,
1737
+ description: this.peerConn.localDescription?.toJSON(),
1738
+ [SDPStreamMetadataKey.name]: this.getLocalSDPStreamMetadata(true)
1739
+ });
1864
1740
  }
1865
- })();
1741
+ } catch (err) {
1742
+ this.isSettingRemoteAnswerPending = false;
1743
+ logger.warn(`Call ${this.callId} onNegotiateReceived() failed to complete negotiation`, err);
1744
+ }
1745
+ const newLocalOnHold = this.isLocalOnHold();
1746
+ if (prevLocalOnHold !== newLocalOnHold) {
1747
+ this.emit(CallEvent.LocalHoldUnhold, newLocalOnHold, this);
1748
+ // also this one for backwards compat
1749
+ this.emit(CallEvent.HoldUnhold, newLocalOnHold);
1750
+ }
1866
1751
  }
1867
1752
  updateRemoteSDPStreamMetadata(metadata) {
1868
1753
  this.remoteSDPStreamMetadata = recursivelyAssign(this.remoteSDPStreamMetadata || {}, metadata, true);
1869
- for (var feed of this.getRemoteFeeds()) {
1870
- var _streamId;
1871
- var streamId = feed.stream.id;
1872
- var _metadata = this.remoteSDPStreamMetadata[streamId];
1873
- feed.setAudioVideoMuted(_metadata === null || _metadata === void 0 ? void 0 : _metadata.audio_muted, _metadata === null || _metadata === void 0 ? void 0 : _metadata.video_muted);
1874
- feed.purpose = (_streamId = this.remoteSDPStreamMetadata[streamId]) === null || _streamId === void 0 ? void 0 : _streamId.purpose;
1754
+ for (const feed of this.getRemoteFeeds()) {
1755
+ const streamId = feed.stream.id;
1756
+ const metadata = this.remoteSDPStreamMetadata[streamId];
1757
+ feed.setAudioVideoMuted(metadata?.audio_muted, metadata?.video_muted);
1758
+ feed.purpose = this.remoteSDPStreamMetadata[streamId]?.purpose;
1875
1759
  }
1876
1760
  }
1877
1761
  onSDPStreamMetadataChangedReceived(event) {
1878
- var content = event.getContent();
1879
- var metadata = SDPStreamMetadataKey.findIn(content);
1762
+ const content = event.getContent();
1763
+ const metadata = SDPStreamMetadataKey.findIn(content);
1880
1764
  if (metadata) {
1881
1765
  this.updateRemoteSDPStreamMetadata(metadata);
1882
1766
  }
1883
1767
  }
1884
- onAssertedIdentityReceived(event) {
1885
- var _this23 = this;
1886
- return _asyncToGenerator(function* () {
1887
- var content = event.getContent();
1888
- if (!content.asserted_identity) return;
1889
- _this23.remoteAssertedIdentity = {
1890
- id: content.asserted_identity.id,
1891
- displayName: content.asserted_identity.display_name
1892
- };
1893
- _this23.emit(CallEvent.AssertedIdentityChanged, _this23);
1894
- })();
1768
+ async onAssertedIdentityReceived(event) {
1769
+ const content = event.getContent();
1770
+ if (!content.asserted_identity) return;
1771
+ this.remoteAssertedIdentity = {
1772
+ id: content.asserted_identity.id,
1773
+ displayName: content.asserted_identity.display_name
1774
+ };
1775
+ this.emit(CallEvent.AssertedIdentityChanged, this);
1895
1776
  }
1896
1777
  callHasEnded() {
1897
1778
  // This exists as workaround to typescript trying to be clever and erroring
@@ -1907,117 +1788,109 @@ export class MatrixCall extends TypedEventEmitter {
1907
1788
  this.responsePromiseChain = this.wrappedGotLocalOffer();
1908
1789
  }
1909
1790
  }
1910
- wrappedGotLocalOffer() {
1911
- var _this24 = this;
1912
- return _asyncToGenerator(function* () {
1913
- _this24.makingOffer = true;
1914
- try {
1915
- // XXX: in what situations do we believe gotLocalOffer actually throws? It appears
1916
- // to handle most of its exceptions itself and terminate the call. I'm not entirely
1917
- // sure it would ever throw, so I can't add a test for these lines.
1918
- // Also the tense is different between "gotLocalOffer" and "getLocalOfferFailed" so
1919
- // it's not entirely clear whether getLocalOfferFailed is just misnamed or whether
1920
- // they've been cross-polinated somehow at some point.
1921
- yield _this24.gotLocalOffer();
1922
- } catch (e) {
1923
- _this24.getLocalOfferFailed(e);
1924
- return;
1925
- } finally {
1926
- _this24.makingOffer = false;
1927
- }
1928
- })();
1929
- }
1930
- gotLocalOffer() {
1931
- var _this25 = this;
1932
- return _asyncToGenerator(function* () {
1933
- logger.debug("Call ".concat(_this25.callId, " gotLocalOffer() running"));
1934
- if (_this25.callHasEnded()) {
1935
- logger.debug("Call ".concat(_this25.callId, " gotLocalOffer() ignoring newly created offer because the call has ended\""));
1936
- return;
1937
- }
1938
- var offer;
1939
- try {
1940
- _this25.getRidOfRTXCodecs();
1941
- offer = yield _this25.createOffer();
1942
- } catch (err) {
1943
- logger.debug("Call ".concat(_this25.callId, " gotLocalOffer() failed to create offer: "), err);
1944
- _this25.terminate(CallParty.Local, CallErrorCode.CreateOffer, true);
1945
- return;
1946
- }
1947
- try {
1948
- yield _this25.peerConn.setLocalDescription(offer);
1949
- } catch (err) {
1950
- logger.debug("Call ".concat(_this25.callId, " gotLocalOffer() error setting local description!"), err);
1951
- _this25.terminate(CallParty.Local, CallErrorCode.SetLocalDescription, true);
1952
- return;
1953
- }
1954
- if (_this25.peerConn.iceGatheringState === "gathering") {
1955
- // Allow a short time for initial candidates to be gathered
1956
- yield new Promise(resolve => {
1957
- setTimeout(resolve, 200);
1958
- });
1959
- }
1960
- if (_this25.callHasEnded()) return;
1961
- var eventType = _this25.state === CallState.CreateOffer ? EventType.CallInvite : EventType.CallNegotiate;
1962
- var content = {
1963
- lifetime: CALL_TIMEOUT_MS
1964
- };
1965
- if (eventType === EventType.CallInvite && _this25.invitee) {
1966
- content.invitee = _this25.invitee;
1967
- }
1968
-
1969
- // clunky because TypeScript can't follow the types through if we use an expression as the key
1970
- if (_this25.state === CallState.CreateOffer) {
1971
- var _localDescription2;
1972
- content.offer = (_localDescription2 = _this25.peerConn.localDescription) === null || _localDescription2 === void 0 ? void 0 : _localDescription2.toJSON();
1973
- } else {
1974
- var _localDescription3;
1975
- content.description = (_localDescription3 = _this25.peerConn.localDescription) === null || _localDescription3 === void 0 ? void 0 : _localDescription3.toJSON();
1976
- }
1977
- content.capabilities = {
1978
- "m.call.transferee": _this25.client.supportsCallTransfer,
1979
- "m.call.dtmf": false
1980
- };
1981
- content[SDPStreamMetadataKey.name] = _this25.getLocalSDPStreamMetadata(true);
1791
+ async wrappedGotLocalOffer() {
1792
+ this.makingOffer = true;
1793
+ try {
1794
+ // XXX: in what situations do we believe gotLocalOffer actually throws? It appears
1795
+ // to handle most of its exceptions itself and terminate the call. I'm not entirely
1796
+ // sure it would ever throw, so I can't add a test for these lines.
1797
+ // Also the tense is different between "gotLocalOffer" and "getLocalOfferFailed" so
1798
+ // it's not entirely clear whether getLocalOfferFailed is just misnamed or whether
1799
+ // they've been cross-polinated somehow at some point.
1800
+ await this.gotLocalOffer();
1801
+ } catch (e) {
1802
+ this.getLocalOfferFailed(e);
1803
+ return;
1804
+ } finally {
1805
+ this.makingOffer = false;
1806
+ }
1807
+ }
1808
+ async gotLocalOffer() {
1809
+ logger.debug(`Call ${this.callId} gotLocalOffer() running`);
1810
+ if (this.callHasEnded()) {
1811
+ logger.debug(`Call ${this.callId} gotLocalOffer() ignoring newly created offer because the call has ended"`);
1812
+ return;
1813
+ }
1814
+ let offer;
1815
+ try {
1816
+ this.getRidOfRTXCodecs();
1817
+ offer = await this.createOffer();
1818
+ } catch (err) {
1819
+ logger.debug(`Call ${this.callId} gotLocalOffer() failed to create offer: `, err);
1820
+ this.terminate(CallParty.Local, CallErrorCode.CreateOffer, true);
1821
+ return;
1822
+ }
1823
+ try {
1824
+ await this.peerConn.setLocalDescription(offer);
1825
+ } catch (err) {
1826
+ logger.debug(`Call ${this.callId} gotLocalOffer() error setting local description!`, err);
1827
+ this.terminate(CallParty.Local, CallErrorCode.SetLocalDescription, true);
1828
+ return;
1829
+ }
1830
+ if (this.peerConn.iceGatheringState === "gathering") {
1831
+ // Allow a short time for initial candidates to be gathered
1832
+ await new Promise(resolve => {
1833
+ setTimeout(resolve, 200);
1834
+ });
1835
+ }
1836
+ if (this.callHasEnded()) return;
1837
+ const eventType = this.state === CallState.CreateOffer ? EventType.CallInvite : EventType.CallNegotiate;
1838
+ const content = {
1839
+ lifetime: CALL_TIMEOUT_MS
1840
+ };
1841
+ if (eventType === EventType.CallInvite && this.invitee) {
1842
+ content.invitee = this.invitee;
1843
+ }
1982
1844
 
1983
- // Get rid of any candidates waiting to be sent: they'll be included in the local
1984
- // description we just got and will send in the offer.
1985
- var discardCount = _this25.discardDuplicateCandidates();
1986
- logger.info("Call ".concat(_this25.callId, " gotLocalOffer() discarding ").concat(discardCount, " candidates that will be sent in offer"));
1987
- try {
1988
- yield _this25.sendVoipEvent(eventType, content);
1989
- } catch (error) {
1990
- logger.error("Call ".concat(_this25.callId, " gotLocalOffer() failed to send invite"), error);
1991
- if (error instanceof MatrixError && error.event) _this25.client.cancelPendingEvent(error.event);
1992
- var code = CallErrorCode.SignallingFailed;
1993
- var message = "Signalling failed";
1994
- if (_this25.state === CallState.CreateOffer) {
1995
- code = CallErrorCode.SendInvite;
1996
- message = "Failed to send invite";
1997
- }
1998
- if (error.name == "UnknownDeviceError") {
1999
- code = CallErrorCode.UnknownDevices;
2000
- message = "Unknown devices present in the room";
1845
+ // clunky because TypeScript can't follow the types through if we use an expression as the key
1846
+ if (this.state === CallState.CreateOffer) {
1847
+ content.offer = this.peerConn.localDescription?.toJSON();
1848
+ } else {
1849
+ content.description = this.peerConn.localDescription?.toJSON();
1850
+ }
1851
+ content.capabilities = {
1852
+ "m.call.transferee": this.client.supportsCallTransfer,
1853
+ "m.call.dtmf": false
1854
+ };
1855
+ content[SDPStreamMetadataKey.name] = this.getLocalSDPStreamMetadata(true);
1856
+
1857
+ // Get rid of any candidates waiting to be sent: they'll be included in the local
1858
+ // description we just got and will send in the offer.
1859
+ const discardCount = this.discardDuplicateCandidates();
1860
+ logger.info(`Call ${this.callId} gotLocalOffer() discarding ${discardCount} candidates that will be sent in offer`);
1861
+ try {
1862
+ await this.sendVoipEvent(eventType, content);
1863
+ } catch (error) {
1864
+ logger.error(`Call ${this.callId} gotLocalOffer() failed to send invite`, error);
1865
+ if (error instanceof MatrixError && error.event) this.client.cancelPendingEvent(error.event);
1866
+ let code = CallErrorCode.SignallingFailed;
1867
+ let message = "Signalling failed";
1868
+ if (this.state === CallState.CreateOffer) {
1869
+ code = CallErrorCode.SendInvite;
1870
+ message = "Failed to send invite";
1871
+ }
1872
+ if (error.name == "UnknownDeviceError") {
1873
+ code = CallErrorCode.UnknownDevices;
1874
+ message = "Unknown devices present in the room";
1875
+ }
1876
+ this.emit(CallEvent.Error, new CallError(code, message, error), this);
1877
+ this.terminate(CallParty.Local, code, false);
1878
+
1879
+ // no need to carry on & send the candidate queue, but we also
1880
+ // don't want to rethrow the error
1881
+ return;
1882
+ }
1883
+ this.sendCandidateQueue();
1884
+ if (this.state === CallState.CreateOffer) {
1885
+ this.inviteOrAnswerSent = true;
1886
+ this.state = CallState.InviteSent;
1887
+ this.inviteTimeout = setTimeout(() => {
1888
+ this.inviteTimeout = undefined;
1889
+ if (this.state === CallState.InviteSent) {
1890
+ this.hangup(CallErrorCode.InviteTimeout, false);
2001
1891
  }
2002
- _this25.emit(CallEvent.Error, new CallError(code, message, error), _this25);
2003
- _this25.terminate(CallParty.Local, code, false);
2004
-
2005
- // no need to carry on & send the candidate queue, but we also
2006
- // don't want to rethrow the error
2007
- return;
2008
- }
2009
- _this25.sendCandidateQueue();
2010
- if (_this25.state === CallState.CreateOffer) {
2011
- _this25.inviteOrAnswerSent = true;
2012
- _this25.state = CallState.InviteSent;
2013
- _this25.inviteTimeout = setTimeout(() => {
2014
- _this25.inviteTimeout = undefined;
2015
- if (_this25.state === CallState.InviteSent) {
2016
- _this25.hangup(CallErrorCode.InviteTimeout, false);
2017
- }
2018
- }, CALL_TIMEOUT_MS);
2019
- }
2020
- })();
1892
+ }, CALL_TIMEOUT_MS);
1893
+ }
2021
1894
  }
2022
1895
  /**
2023
1896
  * This method removes all video/rtx codecs from screensharing video
@@ -2035,14 +1908,14 @@ export class MatrixCall extends TypedEventEmitter {
2035
1908
  getRidOfRTXCodecs() {
2036
1909
  // RTCRtpReceiver.getCapabilities and RTCRtpSender.getCapabilities don't seem to be supported on FF before v113
2037
1910
  if (!RTCRtpReceiver.getCapabilities || !RTCRtpSender.getCapabilities) return;
2038
- var screenshareVideoTransceiver = this.transceivers.get(getTransceiverKey(SDPStreamMetadataPurpose.Screenshare, "video"));
1911
+ const screenshareVideoTransceiver = this.transceivers.get(getTransceiverKey(SDPStreamMetadataPurpose.Screenshare, "video"));
2039
1912
 
2040
1913
  // setCodecPreferences isn't supported on FF (as of v113)
2041
1914
  if (!screenshareVideoTransceiver || !screenshareVideoTransceiver.setCodecPreferences) return;
2042
- var recvCodecs = RTCRtpReceiver.getCapabilities("video").codecs;
2043
- var sendCodecs = RTCRtpSender.getCapabilities("video").codecs;
2044
- var codecs = [];
2045
- for (var codec of [...recvCodecs, ...sendCodecs]) {
1915
+ const recvCodecs = RTCRtpReceiver.getCapabilities("video").codecs;
1916
+ const sendCodecs = RTCRtpSender.getCapabilities("video").codecs;
1917
+ const codecs = [];
1918
+ for (const codec of [...recvCodecs, ...sendCodecs]) {
2046
1919
  if (codec.mimeType !== "video/rtx") {
2047
1920
  codecs.push(codec);
2048
1921
  try {
@@ -2065,57 +1938,52 @@ export class MatrixCall extends TypedEventEmitter {
2065
1938
  /**
2066
1939
  * @internal
2067
1940
  */
2068
- sendVoipEvent(eventType, content) {
2069
- var _this26 = this;
2070
- return _asyncToGenerator(function* () {
2071
- var realContent = _objectSpread(_objectSpread({}, content), {}, {
2072
- version: VOIP_PROTO_VERSION,
2073
- call_id: _this26.callId,
2074
- party_id: _this26.ourPartyId,
2075
- conf_id: _this26.groupCallId
1941
+ async sendVoipEvent(eventType, content) {
1942
+ const realContent = _objectSpread(_objectSpread({}, content), {}, {
1943
+ version: VOIP_PROTO_VERSION,
1944
+ call_id: this.callId,
1945
+ party_id: this.ourPartyId,
1946
+ conf_id: this.groupCallId
1947
+ });
1948
+ if (this.opponentDeviceId) {
1949
+ const toDeviceSeq = this.toDeviceSeq++;
1950
+ const content = _objectSpread(_objectSpread({}, realContent), {}, {
1951
+ device_id: this.client.deviceId,
1952
+ sender_session_id: this.client.getSessionId(),
1953
+ dest_session_id: this.opponentSessionId,
1954
+ seq: toDeviceSeq,
1955
+ [ToDeviceMessageId]: globalThis.crypto.randomUUID()
2076
1956
  });
2077
- if (_this26.opponentDeviceId) {
2078
- var _this26$getOpponentMe;
2079
- var toDeviceSeq = _this26.toDeviceSeq++;
2080
- var _content = _objectSpread(_objectSpread({}, realContent), {}, {
2081
- device_id: _this26.client.deviceId,
2082
- sender_session_id: _this26.client.getSessionId(),
2083
- dest_session_id: _this26.opponentSessionId,
2084
- seq: toDeviceSeq,
2085
- [ToDeviceMessageId]: globalThis.crypto.randomUUID()
2086
- });
2087
- _this26.emit(CallEvent.SendVoipEvent, {
2088
- type: "toDevice",
2089
- eventType,
2090
- userId: _this26.invitee || ((_this26$getOpponentMe = _this26.getOpponentMember()) === null || _this26$getOpponentMe === void 0 ? void 0 : _this26$getOpponentMe.userId),
2091
- opponentDeviceId: _this26.opponentDeviceId,
2092
- content: _content
2093
- }, _this26);
2094
- var userId = _this26.invitee || _this26.getOpponentMember().userId;
2095
- if (_this26.client.getUseE2eForGroupCall()) {
2096
- if (!_this26.hasOpponentDeviceInfo) {
2097
- logger.warn("Call ".concat(_this26.callId, " sendVoipEvent() failed: we do not have opponentDeviceInfo"));
2098
- return;
2099
- }
2100
-
2101
- // TODO: Here we were sending the event to the opponent's device as a to-device message with MatrixClient.encryptAndSendToDevice.
2102
- // However due to the switch to Rust cryptography we need to migrate to the new encryptToDeviceMessages API.
2103
- throw new Error("Unimplemented");
2104
- } else {
2105
- yield _this26.client.sendToDevice(eventType, new Map([[userId, new Map([[_this26.opponentDeviceId, _content]])]]));
1957
+ this.emit(CallEvent.SendVoipEvent, {
1958
+ type: "toDevice",
1959
+ eventType,
1960
+ userId: this.invitee || this.getOpponentMember()?.userId,
1961
+ opponentDeviceId: this.opponentDeviceId,
1962
+ content
1963
+ }, this);
1964
+ const userId = this.invitee || this.getOpponentMember().userId;
1965
+ if (this.client.getUseE2eForGroupCall()) {
1966
+ if (!this.hasOpponentDeviceInfo) {
1967
+ logger.warn(`Call ${this.callId} sendVoipEvent() failed: we do not have opponentDeviceInfo`);
1968
+ return;
2106
1969
  }
1970
+
1971
+ // TODO: Here we were sending the event to the opponent's device as a to-device message with MatrixClient.encryptAndSendToDevice.
1972
+ // However due to the switch to Rust cryptography we need to migrate to the new encryptToDeviceMessages API.
1973
+ throw new Error("Unimplemented");
2107
1974
  } else {
2108
- var _this26$getOpponentMe2;
2109
- _this26.emit(CallEvent.SendVoipEvent, {
2110
- type: "sendEvent",
2111
- eventType,
2112
- roomId: _this26.roomId,
2113
- content: realContent,
2114
- userId: _this26.invitee || ((_this26$getOpponentMe2 = _this26.getOpponentMember()) === null || _this26$getOpponentMe2 === void 0 ? void 0 : _this26$getOpponentMe2.userId)
2115
- }, _this26);
2116
- yield _this26.client.sendEvent(_this26.roomId, eventType, realContent);
1975
+ await this.client.sendToDevice(eventType, new Map([[userId, new Map([[this.opponentDeviceId, content]])]]));
2117
1976
  }
2118
- })();
1977
+ } else {
1978
+ this.emit(CallEvent.SendVoipEvent, {
1979
+ type: "sendEvent",
1980
+ eventType,
1981
+ roomId: this.roomId,
1982
+ content: realContent,
1983
+ userId: this.invitee || this.getOpponentMember()?.userId
1984
+ }, this);
1985
+ await this.client.sendEvent(this.roomId, eventType, realContent);
1986
+ }
2119
1987
  }
2120
1988
 
2121
1989
  /**
@@ -2149,7 +2017,7 @@ export class MatrixCall extends TypedEventEmitter {
2149
2017
 
2150
2018
  // MSC2746 recommends these values (can be quite long when calling because the
2151
2019
  // callee will need a while to answer the call)
2152
- var delay = this.direction === CallDirection.Inbound ? 500 : 2000;
2020
+ const delay = this.direction === CallDirection.Inbound ? 500 : 2000;
2153
2021
  if (this.candidateSendTries === 0) {
2154
2022
  setTimeout(() => {
2155
2023
  this.sendCandidateQueue();
@@ -2161,10 +2029,10 @@ export class MatrixCall extends TypedEventEmitter {
2161
2029
  // Return the number of candidate messages that were discarded.
2162
2030
  // Call this method before sending an invite or answer message
2163
2031
  discardDuplicateCandidates() {
2164
- var discardCount = 0;
2165
- var newQueue = [];
2166
- for (var i = 0; i < this.candidateSendQueue.length; i++) {
2167
- var candidate = this.candidateSendQueue[i];
2032
+ let discardCount = 0;
2033
+ const newQueue = [];
2034
+ for (let i = 0; i < this.candidateSendQueue.length; i++) {
2035
+ const candidate = this.candidateSendQueue[i];
2168
2036
  if (candidate.candidate === "") {
2169
2037
  newQueue.push(candidate);
2170
2038
  } else {
@@ -2178,115 +2046,101 @@ export class MatrixCall extends TypedEventEmitter {
2178
2046
  /*
2179
2047
  * Transfers this call to another user
2180
2048
  */
2181
- transfer(targetUserId) {
2182
- var _this27 = this;
2183
- return _asyncToGenerator(function* () {
2184
- // Fetch the target user's global profile info: their room avatar / displayname
2185
- // could be different in whatever room we share with them.
2186
- var profileInfo = yield _this27.client.getProfileInfo(targetUserId);
2187
- var replacementId = genCallID();
2188
- var body = {
2189
- replacement_id: genCallID(),
2190
- target_user: {
2191
- id: targetUserId,
2192
- display_name: profileInfo.displayname,
2193
- avatar_url: profileInfo.avatar_url
2194
- },
2195
- create_call: replacementId
2196
- };
2197
- yield _this27.sendVoipEvent(EventType.CallReplaces, body);
2198
- yield _this27.terminate(CallParty.Local, CallErrorCode.Transferred, true);
2199
- })();
2049
+ async transfer(targetUserId) {
2050
+ // Fetch the target user's global profile info: their room avatar / displayname
2051
+ // could be different in whatever room we share with them.
2052
+ const profileInfo = await this.client.getProfileInfo(targetUserId);
2053
+ const replacementId = genCallID();
2054
+ const body = {
2055
+ replacement_id: genCallID(),
2056
+ target_user: {
2057
+ id: targetUserId,
2058
+ display_name: profileInfo.displayname,
2059
+ avatar_url: profileInfo.avatar_url
2060
+ },
2061
+ create_call: replacementId
2062
+ };
2063
+ await this.sendVoipEvent(EventType.CallReplaces, body);
2064
+ await this.terminate(CallParty.Local, CallErrorCode.Transferred, true);
2200
2065
  }
2201
2066
 
2202
2067
  /*
2203
2068
  * Transfers this call to the target call, effectively 'joining' the
2204
2069
  * two calls (so the remote parties on each call are connected together).
2205
2070
  */
2206
- transferToCall(transferTargetCall) {
2207
- var _this28 = this;
2208
- return _asyncToGenerator(function* () {
2209
- var _transferTargetCall$g, _this28$getOpponentMe;
2210
- var targetUserId = (_transferTargetCall$g = transferTargetCall.getOpponentMember()) === null || _transferTargetCall$g === void 0 ? void 0 : _transferTargetCall$g.userId;
2211
- var targetProfileInfo = targetUserId ? yield _this28.client.getProfileInfo(targetUserId) : undefined;
2212
- var opponentUserId = (_this28$getOpponentMe = _this28.getOpponentMember()) === null || _this28$getOpponentMe === void 0 ? void 0 : _this28$getOpponentMe.userId;
2213
- var transfereeProfileInfo = opponentUserId ? yield _this28.client.getProfileInfo(opponentUserId) : undefined;
2214
- var newCallId = genCallID();
2215
- var bodyToTransferTarget = {
2216
- // the replacements on each side have their own ID, and it's distinct from the
2217
- // ID of the new call (but we can use the same function to generate it)
2218
- replacement_id: genCallID(),
2219
- target_user: {
2220
- id: opponentUserId,
2221
- display_name: transfereeProfileInfo === null || transfereeProfileInfo === void 0 ? void 0 : transfereeProfileInfo.displayname,
2222
- avatar_url: transfereeProfileInfo === null || transfereeProfileInfo === void 0 ? void 0 : transfereeProfileInfo.avatar_url
2223
- },
2224
- await_call: newCallId
2225
- };
2226
- yield transferTargetCall.sendVoipEvent(EventType.CallReplaces, bodyToTransferTarget);
2227
- var bodyToTransferee = {
2228
- replacement_id: genCallID(),
2229
- target_user: {
2230
- id: targetUserId,
2231
- display_name: targetProfileInfo === null || targetProfileInfo === void 0 ? void 0 : targetProfileInfo.displayname,
2232
- avatar_url: targetProfileInfo === null || targetProfileInfo === void 0 ? void 0 : targetProfileInfo.avatar_url
2233
- },
2234
- create_call: newCallId
2235
- };
2236
- yield _this28.sendVoipEvent(EventType.CallReplaces, bodyToTransferee);
2237
- yield _this28.terminate(CallParty.Local, CallErrorCode.Transferred, true);
2238
- yield transferTargetCall.terminate(CallParty.Local, CallErrorCode.Transferred, true);
2239
- })();
2240
- }
2241
- terminate(hangupParty, hangupReason, shouldEmit) {
2242
- var _this29 = this;
2243
- return _asyncToGenerator(function* () {
2244
- var _this29$stats;
2245
- if (_this29.callHasEnded()) return;
2246
- _this29.hangupParty = hangupParty;
2247
- _this29.hangupReason = hangupReason;
2248
- _this29.state = CallState.Ended;
2249
- if (_this29.inviteTimeout) {
2250
- clearTimeout(_this29.inviteTimeout);
2251
- _this29.inviteTimeout = undefined;
2252
- }
2253
- if (_this29.iceDisconnectedTimeout !== undefined) {
2254
- clearTimeout(_this29.iceDisconnectedTimeout);
2255
- _this29.iceDisconnectedTimeout = undefined;
2256
- }
2257
- if (_this29.callLengthInterval) {
2258
- clearInterval(_this29.callLengthInterval);
2259
- _this29.callLengthInterval = undefined;
2260
- }
2261
- if (_this29.stopVideoTrackTimer !== undefined) {
2262
- clearTimeout(_this29.stopVideoTrackTimer);
2263
- _this29.stopVideoTrackTimer = undefined;
2264
- }
2265
- for (var _ref4 of _this29.removeTrackListeners) {
2266
- var _ref3 = _slicedToArray(_ref4, 2);
2267
- var stream = _ref3[0];
2268
- var listener = _ref3[1];
2269
- stream.removeEventListener("removetrack", listener);
2270
- }
2271
- _this29.removeTrackListeners.clear();
2272
- _this29.callStatsAtEnd = yield _this29.collectCallStats();
2273
-
2274
- // Order is important here: first we stopAllMedia() and only then we can deleteAllFeeds()
2275
- _this29.stopAllMedia();
2276
- _this29.deleteAllFeeds();
2277
- if (_this29.peerConn && _this29.peerConn.signalingState !== "closed") {
2278
- _this29.peerConn.close();
2279
- }
2280
- (_this29$stats = _this29.stats) === null || _this29$stats === void 0 || _this29$stats.removeStatsReportGatherer(_this29.callId);
2281
- if (shouldEmit) {
2282
- _this29.emit(CallEvent.Hangup, _this29);
2283
- }
2284
- _this29.client.callEventHandler.calls.delete(_this29.callId);
2285
- })();
2071
+ async transferToCall(transferTargetCall) {
2072
+ const targetUserId = transferTargetCall.getOpponentMember()?.userId;
2073
+ const targetProfileInfo = targetUserId ? await this.client.getProfileInfo(targetUserId) : undefined;
2074
+ const opponentUserId = this.getOpponentMember()?.userId;
2075
+ const transfereeProfileInfo = opponentUserId ? await this.client.getProfileInfo(opponentUserId) : undefined;
2076
+ const newCallId = genCallID();
2077
+ const bodyToTransferTarget = {
2078
+ // the replacements on each side have their own ID, and it's distinct from the
2079
+ // ID of the new call (but we can use the same function to generate it)
2080
+ replacement_id: genCallID(),
2081
+ target_user: {
2082
+ id: opponentUserId,
2083
+ display_name: transfereeProfileInfo?.displayname,
2084
+ avatar_url: transfereeProfileInfo?.avatar_url
2085
+ },
2086
+ await_call: newCallId
2087
+ };
2088
+ await transferTargetCall.sendVoipEvent(EventType.CallReplaces, bodyToTransferTarget);
2089
+ const bodyToTransferee = {
2090
+ replacement_id: genCallID(),
2091
+ target_user: {
2092
+ id: targetUserId,
2093
+ display_name: targetProfileInfo?.displayname,
2094
+ avatar_url: targetProfileInfo?.avatar_url
2095
+ },
2096
+ create_call: newCallId
2097
+ };
2098
+ await this.sendVoipEvent(EventType.CallReplaces, bodyToTransferee);
2099
+ await this.terminate(CallParty.Local, CallErrorCode.Transferred, true);
2100
+ await transferTargetCall.terminate(CallParty.Local, CallErrorCode.Transferred, true);
2101
+ }
2102
+ async terminate(hangupParty, hangupReason, shouldEmit) {
2103
+ if (this.callHasEnded()) return;
2104
+ this.hangupParty = hangupParty;
2105
+ this.hangupReason = hangupReason;
2106
+ this.state = CallState.Ended;
2107
+ if (this.inviteTimeout) {
2108
+ clearTimeout(this.inviteTimeout);
2109
+ this.inviteTimeout = undefined;
2110
+ }
2111
+ if (this.iceDisconnectedTimeout !== undefined) {
2112
+ clearTimeout(this.iceDisconnectedTimeout);
2113
+ this.iceDisconnectedTimeout = undefined;
2114
+ }
2115
+ if (this.callLengthInterval) {
2116
+ clearInterval(this.callLengthInterval);
2117
+ this.callLengthInterval = undefined;
2118
+ }
2119
+ if (this.stopVideoTrackTimer !== undefined) {
2120
+ clearTimeout(this.stopVideoTrackTimer);
2121
+ this.stopVideoTrackTimer = undefined;
2122
+ }
2123
+ for (const [stream, listener] of this.removeTrackListeners) {
2124
+ stream.removeEventListener("removetrack", listener);
2125
+ }
2126
+ this.removeTrackListeners.clear();
2127
+ this.callStatsAtEnd = await this.collectCallStats();
2128
+
2129
+ // Order is important here: first we stopAllMedia() and only then we can deleteAllFeeds()
2130
+ this.stopAllMedia();
2131
+ this.deleteAllFeeds();
2132
+ if (this.peerConn && this.peerConn.signalingState !== "closed") {
2133
+ this.peerConn.close();
2134
+ }
2135
+ this.stats?.removeStatsReportGatherer(this.callId);
2136
+ if (shouldEmit) {
2137
+ this.emit(CallEvent.Hangup, this);
2138
+ }
2139
+ this.client.callEventHandler.calls.delete(this.callId);
2286
2140
  }
2287
2141
  stopAllMedia() {
2288
- logger.debug("Call ".concat(this.callId, " stopAllMedia() running"));
2289
- for (var feed of this.feeds) {
2142
+ logger.debug(`Call ${this.callId} stopAllMedia() running`);
2143
+ for (const feed of this.feeds) {
2290
2144
  // Slightly awkward as local feed need to go via the correct method on
2291
2145
  // the MediaHandler so they get removed from MediaHandler (remote tracks
2292
2146
  // don't)
@@ -2298,8 +2152,8 @@ export class MatrixCall extends TypedEventEmitter {
2298
2152
  } else if (feed.isLocal() && feed.purpose === SDPStreamMetadataPurpose.Screenshare) {
2299
2153
  this.client.getMediaHandler().stopScreensharingStream(feed.stream);
2300
2154
  } else if (!feed.isLocal()) {
2301
- logger.debug("Call ".concat(this.callId, " stopAllMedia() stopping stream (streamId=").concat(feed.stream.id, ")"));
2302
- for (var track of feed.stream.getTracks()) {
2155
+ logger.debug(`Call ${this.callId} stopAllMedia() stopping stream (streamId=${feed.stream.id})`);
2156
+ for (const track of feed.stream.getTracks()) {
2303
2157
  track.stop();
2304
2158
  }
2305
2159
  }
@@ -2310,56 +2164,53 @@ export class MatrixCall extends TypedEventEmitter {
2310
2164
  throw new Error("You MUST attach an error listener using call.on('error', function() {})");
2311
2165
  }
2312
2166
  }
2313
- sendCandidateQueue() {
2314
- var _this30 = this;
2315
- return _asyncToGenerator(function* () {
2316
- if (_this30.candidateSendQueue.length === 0 || _this30.callHasEnded()) {
2167
+ async sendCandidateQueue() {
2168
+ if (this.candidateSendQueue.length === 0 || this.callHasEnded()) {
2169
+ return;
2170
+ }
2171
+ const candidates = this.candidateSendQueue;
2172
+ this.candidateSendQueue = [];
2173
+ ++this.candidateSendTries;
2174
+ const content = {
2175
+ candidates: candidates.map(candidate => candidate.toJSON())
2176
+ };
2177
+ if (this.candidatesEnded) {
2178
+ // If there are no more candidates, signal this by adding an empty string candidate
2179
+ content.candidates.push({
2180
+ candidate: ""
2181
+ });
2182
+ }
2183
+ logger.debug(`Call ${this.callId} sendCandidateQueue() attempting to send ${candidates.length} candidates`);
2184
+ try {
2185
+ await this.sendVoipEvent(EventType.CallCandidates, content);
2186
+ // reset our retry count if we have successfully sent our candidates
2187
+ // otherwise queueCandidate() will refuse to try to flush the queue
2188
+ this.candidateSendTries = 0;
2189
+
2190
+ // Try to send candidates again just in case we received more candidates while sending.
2191
+ this.sendCandidateQueue();
2192
+ } catch (error) {
2193
+ // don't retry this event: we'll send another one later as we might
2194
+ // have more candidates by then.
2195
+ if (error instanceof MatrixError && error.event) this.client.cancelPendingEvent(error.event);
2196
+
2197
+ // put all the candidates we failed to send back in the queue
2198
+ this.candidateSendQueue.push(...candidates);
2199
+ if (this.candidateSendTries > 5) {
2200
+ logger.debug(`Call ${this.callId} sendCandidateQueue() failed to send candidates on attempt ${this.candidateSendTries}. Giving up on this call.`, error);
2201
+ const code = CallErrorCode.SignallingFailed;
2202
+ const message = "Signalling failed";
2203
+ this.emit(CallEvent.Error, new CallError(code, message, error), this);
2204
+ this.hangup(code, false);
2317
2205
  return;
2318
2206
  }
2319
- var candidates = _this30.candidateSendQueue;
2320
- _this30.candidateSendQueue = [];
2321
- ++_this30.candidateSendTries;
2322
- var content = {
2323
- candidates: candidates.map(candidate => candidate.toJSON())
2324
- };
2325
- if (_this30.candidatesEnded) {
2326
- // If there are no more candidates, signal this by adding an empty string candidate
2327
- content.candidates.push({
2328
- candidate: ""
2329
- });
2330
- }
2331
- logger.debug("Call ".concat(_this30.callId, " sendCandidateQueue() attempting to send ").concat(candidates.length, " candidates"));
2332
- try {
2333
- yield _this30.sendVoipEvent(EventType.CallCandidates, content);
2334
- // reset our retry count if we have successfully sent our candidates
2335
- // otherwise queueCandidate() will refuse to try to flush the queue
2336
- _this30.candidateSendTries = 0;
2337
-
2338
- // Try to send candidates again just in case we received more candidates while sending.
2339
- _this30.sendCandidateQueue();
2340
- } catch (error) {
2341
- // don't retry this event: we'll send another one later as we might
2342
- // have more candidates by then.
2343
- if (error instanceof MatrixError && error.event) _this30.client.cancelPendingEvent(error.event);
2344
-
2345
- // put all the candidates we failed to send back in the queue
2346
- _this30.candidateSendQueue.push(...candidates);
2347
- if (_this30.candidateSendTries > 5) {
2348
- logger.debug("Call ".concat(_this30.callId, " sendCandidateQueue() failed to send candidates on attempt ").concat(_this30.candidateSendTries, ". Giving up on this call."), error);
2349
- var code = CallErrorCode.SignallingFailed;
2350
- var message = "Signalling failed";
2351
- _this30.emit(CallEvent.Error, new CallError(code, message, error), _this30);
2352
- _this30.hangup(code, false);
2353
- return;
2354
- }
2355
- var delayMs = 500 * Math.pow(2, _this30.candidateSendTries);
2356
- ++_this30.candidateSendTries;
2357
- logger.debug("Call ".concat(_this30.callId, " sendCandidateQueue() failed to send candidates. Retrying in ").concat(delayMs, "ms"), error);
2358
- setTimeout(() => {
2359
- _this30.sendCandidateQueue();
2360
- }, delayMs);
2361
- }
2362
- })();
2207
+ const delayMs = 500 * Math.pow(2, this.candidateSendTries);
2208
+ ++this.candidateSendTries;
2209
+ logger.debug(`Call ${this.callId} sendCandidateQueue() failed to send candidates. Retrying in ${delayMs}ms`, error);
2210
+ setTimeout(() => {
2211
+ this.sendCandidateQueue();
2212
+ }, delayMs);
2213
+ }
2363
2214
  }
2364
2215
 
2365
2216
  /**
@@ -2367,43 +2218,39 @@ export class MatrixCall extends TypedEventEmitter {
2367
2218
  * @throws if you have not specified a listener for 'error' events.
2368
2219
  * @throws if have passed audio=false.
2369
2220
  */
2370
- placeCall(audio, video) {
2371
- var _this31 = this;
2372
- return _asyncToGenerator(function* () {
2373
- if (!audio) {
2374
- throw new Error("You CANNOT start a call without audio");
2375
- }
2376
- _this31.state = CallState.WaitLocalMedia;
2377
- var callFeed;
2378
- try {
2379
- var _this31$client$getDev;
2380
- var stream = yield _this31.client.getMediaHandler().getUserMediaStream(audio, video);
2381
-
2382
- // make sure all the tracks are enabled (same as pushNewLocalFeed -
2383
- // we probably ought to just have one code path for adding streams)
2384
- setTracksEnabled(stream.getAudioTracks(), true);
2385
- setTracksEnabled(stream.getVideoTracks(), true);
2386
- callFeed = new CallFeed({
2387
- client: _this31.client,
2388
- roomId: _this31.roomId,
2389
- userId: _this31.client.getUserId(),
2390
- deviceId: (_this31$client$getDev = _this31.client.getDeviceId()) !== null && _this31$client$getDev !== void 0 ? _this31$client$getDev : undefined,
2391
- stream,
2392
- purpose: SDPStreamMetadataPurpose.Usermedia,
2393
- audioMuted: false,
2394
- videoMuted: false
2395
- });
2396
- } catch (e) {
2397
- _this31.getUserMediaFailed(e);
2398
- return;
2399
- }
2400
- try {
2401
- yield _this31.placeCallWithCallFeeds([callFeed]);
2402
- } catch (e) {
2403
- _this31.placeCallFailed(e);
2404
- return;
2405
- }
2406
- })();
2221
+ async placeCall(audio, video) {
2222
+ if (!audio) {
2223
+ throw new Error("You CANNOT start a call without audio");
2224
+ }
2225
+ this.state = CallState.WaitLocalMedia;
2226
+ let callFeed;
2227
+ try {
2228
+ const stream = await this.client.getMediaHandler().getUserMediaStream(audio, video);
2229
+
2230
+ // make sure all the tracks are enabled (same as pushNewLocalFeed -
2231
+ // we probably ought to just have one code path for adding streams)
2232
+ setTracksEnabled(stream.getAudioTracks(), true);
2233
+ setTracksEnabled(stream.getVideoTracks(), true);
2234
+ callFeed = new CallFeed({
2235
+ client: this.client,
2236
+ roomId: this.roomId,
2237
+ userId: this.client.getUserId(),
2238
+ deviceId: this.client.getDeviceId() ?? undefined,
2239
+ stream,
2240
+ purpose: SDPStreamMetadataPurpose.Usermedia,
2241
+ audioMuted: false,
2242
+ videoMuted: false
2243
+ });
2244
+ } catch (e) {
2245
+ this.getUserMediaFailed(e);
2246
+ return;
2247
+ }
2248
+ try {
2249
+ await this.placeCallWithCallFeeds([callFeed]);
2250
+ } catch (e) {
2251
+ this.placeCallFailed(e);
2252
+ return;
2253
+ }
2407
2254
  }
2408
2255
 
2409
2256
  /**
@@ -2412,35 +2259,29 @@ export class MatrixCall extends TypedEventEmitter {
2412
2259
  * @throws if you have not specified a listener for 'error' events.
2413
2260
  * @throws if have passed audio=false.
2414
2261
  */
2415
- placeCallWithCallFeeds(callFeeds) {
2416
- var _arguments2 = arguments,
2417
- _this32 = this;
2418
- return _asyncToGenerator(function* () {
2419
- var requestScreenshareFeed = _arguments2.length > 1 && _arguments2[1] !== undefined ? _arguments2[1] : false;
2420
- _this32.checkForErrorListener();
2421
- _this32.direction = CallDirection.Outbound;
2422
- yield _this32.initOpponentCrypto();
2423
-
2424
- // XXX Find a better way to do this
2425
- _this32.client.callEventHandler.calls.set(_this32.callId, _this32);
2426
-
2427
- // make sure we have valid turn creds. Unless something's gone wrong, it should
2428
- // poll and keep the credentials valid so this should be instant.
2429
- var haveTurnCreds = yield _this32.client.checkTurnServers();
2430
- if (!haveTurnCreds) {
2431
- logger.warn("Call ".concat(_this32.callId, " placeCallWithCallFeeds() failed to get TURN credentials! Proceeding with call anyway..."));
2432
- }
2262
+ async placeCallWithCallFeeds(callFeeds, requestScreenshareFeed = false) {
2263
+ this.checkForErrorListener();
2264
+ this.direction = CallDirection.Outbound;
2265
+ await this.initOpponentCrypto();
2266
+
2267
+ // XXX Find a better way to do this
2268
+ this.client.callEventHandler.calls.set(this.callId, this);
2269
+
2270
+ // make sure we have valid turn creds. Unless something's gone wrong, it should
2271
+ // poll and keep the credentials valid so this should be instant.
2272
+ const haveTurnCreds = await this.client.checkTurnServers();
2273
+ if (!haveTurnCreds) {
2274
+ logger.warn(`Call ${this.callId} placeCallWithCallFeeds() failed to get TURN credentials! Proceeding with call anyway...`);
2275
+ }
2433
2276
 
2434
- // create the peer connection now so it can be gathering candidates while we get user
2435
- // media (assuming a candidate pool size is configured)
2436
- _this32.peerConn = _this32.createPeerConnection();
2437
- _this32.emit(CallEvent.PeerConnectionCreated, _this32.peerConn, _this32);
2438
- _this32.gotCallFeedsForInvite(callFeeds, requestScreenshareFeed);
2439
- })();
2277
+ // create the peer connection now so it can be gathering candidates while we get user
2278
+ // media (assuming a candidate pool size is configured)
2279
+ this.peerConn = this.createPeerConnection();
2280
+ this.emit(CallEvent.PeerConnectionCreated, this.peerConn, this);
2281
+ this.gotCallFeedsForInvite(callFeeds, requestScreenshareFeed);
2440
2282
  }
2441
2283
  createPeerConnection() {
2442
- var _this$stats;
2443
- var pc = new window.RTCPeerConnection({
2284
+ const pc = new window.RTCPeerConnection({
2444
2285
  iceTransportPolicy: this.forceTURN ? "relay" : undefined,
2445
2286
  iceServers: this.turnServers.length ? this.turnServers : undefined,
2446
2287
  iceCandidatePoolSize: this.client.iceCandidatePoolSize,
@@ -2455,9 +2296,9 @@ export class MatrixCall extends TypedEventEmitter {
2455
2296
  pc.addEventListener("track", this.onTrack);
2456
2297
  pc.addEventListener("negotiationneeded", this.onNegotiationNeeded);
2457
2298
  pc.addEventListener("datachannel", this.onDataChannel);
2458
- var opponentMember = this.getOpponentMember();
2459
- var opponentMemberId = opponentMember ? opponentMember.userId : "unknown";
2460
- (_this$stats = this.stats) === null || _this$stats === void 0 || _this$stats.addStatsReportGatherer(this.callId, opponentMemberId, pc);
2299
+ const opponentMember = this.getOpponentMember();
2300
+ const opponentMemberId = opponentMember ? opponentMember.userId : "unknown";
2301
+ this.stats?.addStatsReportGatherer(this.callId, opponentMemberId, pc);
2461
2302
  return pc;
2462
2303
  }
2463
2304
  partyIdMatches(msg) {
@@ -2465,17 +2306,16 @@ export class MatrixCall extends TypedEventEmitter {
2465
2306
  // Also we ignore party IDs on the invite/offer if the version is 0, so we must do the same
2466
2307
  // here and use null if the version is 0 (woe betide any opponent sending messages in the
2467
2308
  // same call with different versions)
2468
- var msgPartyId = msg.version === 0 ? null : msg.party_id || null;
2309
+ const msgPartyId = msg.version === 0 ? null : msg.party_id || null;
2469
2310
  return msgPartyId === this.opponentPartyId;
2470
2311
  }
2471
2312
 
2472
2313
  // Commits to an opponent for the call
2473
2314
  // ev: An invite or answer event
2474
2315
  chooseOpponent(ev) {
2475
- var _getMember;
2476
2316
  // I choo-choo-choose you
2477
- var msg = ev.getContent();
2478
- logger.debug("Call ".concat(this.callId, " chooseOpponent() running (partyId=").concat(msg.party_id, ")"));
2317
+ const msg = ev.getContent();
2318
+ logger.debug(`Call ${this.callId} chooseOpponent() running (partyId=${msg.party_id})`);
2479
2319
  this.opponentVersion = msg.version;
2480
2320
  if (this.opponentVersion === 0) {
2481
2321
  // set to null to indicate that we've chosen an opponent, but because
@@ -2488,55 +2328,47 @@ export class MatrixCall extends TypedEventEmitter {
2488
2328
  this.opponentPartyId = msg.party_id || null;
2489
2329
  }
2490
2330
  this.opponentCaps = msg.capabilities || {};
2491
- this.opponentMember = (_getMember = this.client.getRoom(this.roomId).getMember(ev.getSender())) !== null && _getMember !== void 0 ? _getMember : undefined;
2331
+ this.opponentMember = this.client.getRoom(this.roomId).getMember(ev.getSender()) ?? undefined;
2492
2332
  if (this.opponentMember) {
2493
- var _this$stats2;
2494
- (_this$stats2 = this.stats) === null || _this$stats2 === void 0 || _this$stats2.updateOpponentMember(this.callId, this.opponentMember.userId);
2333
+ this.stats?.updateOpponentMember(this.callId, this.opponentMember.userId);
2495
2334
  }
2496
2335
  }
2497
- addBufferedIceCandidates() {
2498
- var _this33 = this;
2499
- return _asyncToGenerator(function* () {
2500
- var bufferedCandidates = _this33.remoteCandidateBuffer.get(_this33.opponentPartyId);
2501
- if (bufferedCandidates) {
2502
- logger.info("Call ".concat(_this33.callId, " addBufferedIceCandidates() adding ").concat(bufferedCandidates.length, " buffered candidates for opponent ").concat(_this33.opponentPartyId));
2503
- yield _this33.addIceCandidates(bufferedCandidates);
2336
+ async addBufferedIceCandidates() {
2337
+ const bufferedCandidates = this.remoteCandidateBuffer.get(this.opponentPartyId);
2338
+ if (bufferedCandidates) {
2339
+ logger.info(`Call ${this.callId} addBufferedIceCandidates() adding ${bufferedCandidates.length} buffered candidates for opponent ${this.opponentPartyId}`);
2340
+ await this.addIceCandidates(bufferedCandidates);
2341
+ }
2342
+ this.remoteCandidateBuffer.clear();
2343
+ }
2344
+ async addIceCandidates(candidates) {
2345
+ for (const candidate of candidates) {
2346
+ if ((candidate.sdpMid === null || candidate.sdpMid === undefined) && (candidate.sdpMLineIndex === null || candidate.sdpMLineIndex === undefined)) {
2347
+ logger.debug(`Call ${this.callId} addIceCandidates() got remote ICE end-of-candidates`);
2348
+ } else {
2349
+ logger.debug(`Call ${this.callId} addIceCandidates() got remote ICE candidate (sdpMid=${candidate.sdpMid}, candidate=${candidate.candidate})`);
2504
2350
  }
2505
- _this33.remoteCandidateBuffer.clear();
2506
- })();
2507
- }
2508
- addIceCandidates(candidates) {
2509
- var _this34 = this;
2510
- return _asyncToGenerator(function* () {
2511
- for (var candidate of candidates) {
2512
- if ((candidate.sdpMid === null || candidate.sdpMid === undefined) && (candidate.sdpMLineIndex === null || candidate.sdpMLineIndex === undefined)) {
2513
- logger.debug("Call ".concat(_this34.callId, " addIceCandidates() got remote ICE end-of-candidates"));
2351
+ try {
2352
+ await this.peerConn.addIceCandidate(candidate);
2353
+ } catch (err) {
2354
+ if (!this.ignoreOffer) {
2355
+ logger.info(`Call ${this.callId} addIceCandidates() failed to add remote ICE candidate`, err);
2514
2356
  } else {
2515
- logger.debug("Call ".concat(_this34.callId, " addIceCandidates() got remote ICE candidate (sdpMid=").concat(candidate.sdpMid, ", candidate=").concat(candidate.candidate, ")"));
2516
- }
2517
- try {
2518
- yield _this34.peerConn.addIceCandidate(candidate);
2519
- } catch (err) {
2520
- if (!_this34.ignoreOffer) {
2521
- logger.info("Call ".concat(_this34.callId, " addIceCandidates() failed to add remote ICE candidate"), err);
2522
- } else {
2523
- logger.debug("Call ".concat(_this34.callId, " addIceCandidates() failed to add remote ICE candidate because ignoring offer"), err);
2524
- }
2357
+ logger.debug(`Call ${this.callId} addIceCandidates() failed to add remote ICE candidate because ignoring offer`, err);
2525
2358
  }
2526
2359
  }
2527
- })();
2360
+ }
2528
2361
  }
2529
2362
  get hasPeerConnection() {
2530
2363
  return Boolean(this.peerConn);
2531
2364
  }
2532
- initStats(stats) {
2533
- var peerId = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "unknown";
2365
+ initStats(stats, peerId = "unknown") {
2534
2366
  this.stats = stats;
2535
2367
  this.stats.start();
2536
2368
  }
2537
2369
  }
2538
2370
  export function setTracksEnabled(tracks, enabled) {
2539
- for (var track of tracks) {
2371
+ for (const track of tracks) {
2540
2372
  track.enabled = enabled;
2541
2373
  }
2542
2374
  }
@@ -2552,8 +2384,7 @@ export function supportsMatrixCall() {
2552
2384
  // There's some information at https://bugzilla.mozilla.org/show_bug.cgi?id=1542616 though the concern
2553
2385
  // is that the browser throwing a SecurityError will brick the client creation process.
2554
2386
  try {
2555
- var _ref5, _ref6, _window$RTCPeerConnec;
2556
- var supported = Boolean((_ref5 = (_ref6 = (_window$RTCPeerConnec = window.RTCPeerConnection) !== null && _window$RTCPeerConnec !== void 0 ? _window$RTCPeerConnec : window.RTCSessionDescription) !== null && _ref6 !== void 0 ? _ref6 : window.RTCIceCandidate) !== null && _ref5 !== void 0 ? _ref5 : navigator.mediaDevices);
2387
+ const supported = Boolean(window.RTCPeerConnection ?? window.RTCSessionDescription ?? window.RTCIceCandidate ?? navigator.mediaDevices);
2557
2388
  if (!supported) {
2558
2389
  /* istanbul ignore if */ // Adds a lot of noise to test runs, so disable logging there.
2559
2390
  if (process.env.NODE_ENV !== "test") {
@@ -2580,19 +2411,19 @@ export function supportsMatrixCall() {
2580
2411
  */
2581
2412
  export function createNewMatrixCall(client, roomId, options) {
2582
2413
  if (!supportsMatrixCall()) return null;
2583
- var optionsForceTURN = options ? options.forceTURN : false;
2584
- var opts = {
2414
+ const optionsForceTURN = options ? options.forceTURN : false;
2415
+ const opts = {
2585
2416
  client: client,
2586
2417
  roomId: roomId,
2587
- invitee: options === null || options === void 0 ? void 0 : options.invitee,
2418
+ invitee: options?.invitee,
2588
2419
  turnServers: client.getTurnServers(),
2589
2420
  // call level options
2590
2421
  forceTURN: client.forceTURN || optionsForceTURN,
2591
- opponentDeviceId: options === null || options === void 0 ? void 0 : options.opponentDeviceId,
2592
- opponentSessionId: options === null || options === void 0 ? void 0 : options.opponentSessionId,
2593
- groupCallId: options === null || options === void 0 ? void 0 : options.groupCallId
2422
+ opponentDeviceId: options?.opponentDeviceId,
2423
+ opponentSessionId: options?.opponentSessionId,
2424
+ groupCallId: options?.groupCallId
2594
2425
  };
2595
- var call = new MatrixCall(opts);
2426
+ const call = new MatrixCall(opts);
2596
2427
  client.reEmitter.reEmit(call, Object.values(CallEvent));
2597
2428
  return call;
2598
2429
  }