@cometchat/skills 4.1.0 → 4.2.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 (257) hide show
  1. package/bin/install.js +298 -41
  2. package/package.json +1 -1
  3. package/skills/cometchat/SKILL.md +146 -27
  4. package/skills/cometchat-a11y/SKILL.md +476 -0
  5. package/skills/cometchat-android-v5/SKILL.md +1 -1
  6. package/skills/cometchat-android-v5-calls/SKILL.md +413 -0
  7. package/skills/cometchat-android-v5-calls/references/README.md +53 -0
  8. package/skills/cometchat-android-v5-calls/references/add-calls-to-existing-chat.md +195 -0
  9. package/skills/cometchat-android-v5-calls/references/audio-controls.md +91 -0
  10. package/skills/cometchat-android-v5-calls/references/background-handling.md +168 -0
  11. package/skills/cometchat-android-v5-calls/references/call-layouts.md +123 -0
  12. package/skills/cometchat-android-v5-calls/references/call-logs.md +113 -0
  13. package/skills/cometchat-android-v5-calls/references/call-session.md +274 -0
  14. package/skills/cometchat-android-v5-calls/references/custom-ui.md +150 -0
  15. package/skills/cometchat-android-v5-calls/references/event-listeners.md +123 -0
  16. package/skills/cometchat-android-v5-calls/references/group-calls.md +205 -0
  17. package/skills/cometchat-android-v5-calls/references/idle-timeout.md +111 -0
  18. package/skills/cometchat-android-v5-calls/references/in-call-chat.md +134 -0
  19. package/skills/cometchat-android-v5-calls/references/join-session.md +120 -0
  20. package/skills/cometchat-android-v5-calls/references/migration-v4-to-v5.md +206 -0
  21. package/skills/cometchat-android-v5-calls/references/participant-management.md +110 -0
  22. package/skills/cometchat-android-v5-calls/references/picture-in-picture.md +106 -0
  23. package/skills/cometchat-android-v5-calls/references/raise-hand.md +242 -0
  24. package/skills/cometchat-android-v5-calls/references/recording.md +101 -0
  25. package/skills/cometchat-android-v5-calls/references/ringing-integration.md +152 -0
  26. package/skills/cometchat-android-v5-calls/references/screen-sharing.md +82 -0
  27. package/skills/cometchat-android-v5-calls/references/server-fcm-voip.md +215 -0
  28. package/skills/cometchat-android-v5-calls/references/session-settings.md +121 -0
  29. package/skills/cometchat-android-v5-calls/references/setup.md +137 -0
  30. package/skills/cometchat-android-v5-calls/references/share-invite.md +151 -0
  31. package/skills/cometchat-android-v5-calls/references/video-controls.md +87 -0
  32. package/skills/cometchat-android-v5-calls/references/voip-calling.md +526 -0
  33. package/skills/cometchat-android-v5-components/SKILL.md +1 -1
  34. package/skills/cometchat-android-v5-core/SKILL.md +1 -1
  35. package/skills/cometchat-android-v5-customization/SKILL.md +1 -1
  36. package/skills/cometchat-android-v5-extensions/SKILL.md +1 -1
  37. package/skills/cometchat-android-v5-features/SKILL.md +1 -1
  38. package/skills/cometchat-android-v5-placement/SKILL.md +1 -1
  39. package/skills/cometchat-android-v5-production/SKILL.md +1 -1
  40. package/skills/cometchat-android-v5-push/SKILL.md +1 -1
  41. package/skills/cometchat-android-v5-testing/SKILL.md +1 -1
  42. package/skills/cometchat-android-v5-theming/SKILL.md +1 -1
  43. package/skills/cometchat-android-v5-troubleshooting/SKILL.md +1 -1
  44. package/skills/cometchat-android-v6/SKILL.md +1 -1
  45. package/skills/cometchat-android-v6-builder-settings/SKILL.md +1 -1
  46. package/skills/cometchat-android-v6-calls/SKILL.md +375 -0
  47. package/skills/cometchat-android-v6-calls/references/add-calls-to-existing-chat.md +97 -0
  48. package/skills/cometchat-android-v6-calls/references/call-layouts.md +91 -0
  49. package/skills/cometchat-android-v6-calls/references/call-session.md +163 -0
  50. package/skills/cometchat-android-v6-calls/references/device-management.md +171 -0
  51. package/skills/cometchat-android-v6-calls/references/group-calls.md +191 -0
  52. package/skills/cometchat-android-v6-calls/references/idle-timeout.md +107 -0
  53. package/skills/cometchat-android-v6-calls/references/in-call-chat.md +136 -0
  54. package/skills/cometchat-android-v6-calls/references/raise-hand.md +186 -0
  55. package/skills/cometchat-android-v6-calls/references/ringing-integration.md +176 -0
  56. package/skills/cometchat-android-v6-calls/references/server-fcm-voip.md +127 -0
  57. package/skills/cometchat-android-v6-calls/references/share-invite.md +105 -0
  58. package/skills/cometchat-android-v6-compose-components/SKILL.md +2 -2
  59. package/skills/cometchat-android-v6-compose-customization/SKILL.md +1 -1
  60. package/skills/cometchat-android-v6-compose-placement/SKILL.md +1 -1
  61. package/skills/cometchat-android-v6-compose-theming/SKILL.md +1 -1
  62. package/skills/cometchat-android-v6-core/SKILL.md +1 -1
  63. package/skills/cometchat-android-v6-events/SKILL.md +1 -1
  64. package/skills/cometchat-android-v6-extensions/SKILL.md +1 -1
  65. package/skills/cometchat-android-v6-features/SKILL.md +1 -1
  66. package/skills/cometchat-android-v6-kotlin-components/SKILL.md +1 -1
  67. package/skills/cometchat-android-v6-kotlin-customization/SKILL.md +1 -1
  68. package/skills/cometchat-android-v6-kotlin-placement/SKILL.md +1 -1
  69. package/skills/cometchat-android-v6-kotlin-theming/SKILL.md +1 -1
  70. package/skills/cometchat-android-v6-migration/SKILL.md +398 -0
  71. package/skills/cometchat-android-v6-production/SKILL.md +1 -1
  72. package/skills/cometchat-android-v6-push/SKILL.md +1 -1
  73. package/skills/cometchat-android-v6-testing/SKILL.md +1 -1
  74. package/skills/cometchat-android-v6-troubleshooting/SKILL.md +1 -1
  75. package/skills/cometchat-angular-calls/SKILL.md +511 -0
  76. package/skills/cometchat-angular-calls/references/add-calls-to-existing-chat.md +95 -0
  77. package/skills/cometchat-angular-calls/references/call-layouts.md +106 -0
  78. package/skills/cometchat-angular-calls/references/call-session.md +167 -0
  79. package/skills/cometchat-angular-calls/references/custom-ui.md +231 -0
  80. package/skills/cometchat-angular-calls/references/device-management.md +135 -0
  81. package/skills/cometchat-angular-calls/references/group-calls.md +412 -0
  82. package/skills/cometchat-angular-calls/references/idle-timeout.md +145 -0
  83. package/skills/cometchat-angular-calls/references/in-call-chat.md +148 -0
  84. package/skills/cometchat-angular-calls/references/lazy-loading-pitfalls.md +205 -0
  85. package/skills/cometchat-angular-calls/references/migration-v4-to-v5.md +53 -0
  86. package/skills/cometchat-angular-calls/references/ngzone-and-async-callbacks.md +183 -0
  87. package/skills/cometchat-angular-calls/references/picture-in-picture.md +285 -0
  88. package/skills/cometchat-angular-calls/references/raise-hand.md +167 -0
  89. package/skills/cometchat-angular-calls/references/recording-screen-share.md +267 -0
  90. package/skills/cometchat-angular-calls/references/ringing-integration.md +131 -0
  91. package/skills/cometchat-angular-calls/references/server-web-push-vapid.md +100 -0
  92. package/skills/cometchat-angular-calls/references/share-invite.md +116 -0
  93. package/skills/cometchat-angular-components/SKILL.md +1 -1
  94. package/skills/cometchat-angular-core/SKILL.md +1 -1
  95. package/skills/cometchat-angular-customization/SKILL.md +1 -1
  96. package/skills/cometchat-angular-features/SKILL.md +1 -1
  97. package/skills/cometchat-angular-patterns/SKILL.md +1 -1
  98. package/skills/cometchat-angular-placement/SKILL.md +1 -1
  99. package/skills/cometchat-angular-production/SKILL.md +1 -1
  100. package/skills/cometchat-angular-push/SKILL.md +403 -0
  101. package/skills/cometchat-angular-testing/SKILL.md +333 -0
  102. package/skills/cometchat-angular-theming/SKILL.md +1 -1
  103. package/skills/cometchat-angular-troubleshooting/SKILL.md +1 -1
  104. package/skills/cometchat-astro-patterns/SKILL.md +1 -1
  105. package/skills/cometchat-calls/SKILL.md +358 -0
  106. package/skills/cometchat-calls/references/use-case-broadcast.md +194 -0
  107. package/skills/cometchat-calls/references/use-case-marketplace.md +158 -0
  108. package/skills/cometchat-calls/references/use-case-support.md +190 -0
  109. package/skills/cometchat-calls/references/use-case-team.md +169 -0
  110. package/skills/cometchat-calls/references/use-case-telehealth.md +154 -0
  111. package/skills/cometchat-components/SKILL.md +1 -1
  112. package/skills/cometchat-core/SKILL.md +1 -1
  113. package/skills/cometchat-customization/SKILL.md +2 -2
  114. package/skills/cometchat-features/SKILL.md +2 -2
  115. package/skills/cometchat-flutter-v5/SKILL.md +1 -1
  116. package/skills/cometchat-flutter-v5-calls/SKILL.md +325 -94
  117. package/skills/cometchat-flutter-v5-calls/references/add-calls-to-existing-chat.md +169 -0
  118. package/skills/cometchat-flutter-v5-calls/references/call-layouts.md +98 -0
  119. package/skills/cometchat-flutter-v5-calls/references/call-session.md +330 -0
  120. package/skills/cometchat-flutter-v5-calls/references/device-management.md +120 -0
  121. package/skills/cometchat-flutter-v5-calls/references/group-calls.md +187 -0
  122. package/skills/cometchat-flutter-v5-calls/references/idle-timeout.md +97 -0
  123. package/skills/cometchat-flutter-v5-calls/references/in-call-chat.md +132 -0
  124. package/skills/cometchat-flutter-v5-calls/references/migration-v4-to-v5.md +160 -0
  125. package/skills/cometchat-flutter-v5-calls/references/raise-hand.md +244 -0
  126. package/skills/cometchat-flutter-v5-calls/references/ringing-integration.md +193 -0
  127. package/skills/cometchat-flutter-v5-calls/references/server-push-bridge.md +101 -0
  128. package/skills/cometchat-flutter-v5-calls/references/share-invite.md +142 -0
  129. package/skills/cometchat-flutter-v5-conversations/SKILL.md +1 -1
  130. package/skills/cometchat-flutter-v5-core/SKILL.md +1 -1
  131. package/skills/cometchat-flutter-v5-customization/SKILL.md +1 -1
  132. package/skills/cometchat-flutter-v5-events/SKILL.md +1 -1
  133. package/skills/cometchat-flutter-v5-messages/SKILL.md +1 -1
  134. package/skills/cometchat-flutter-v5-production/SKILL.md +1 -1
  135. package/skills/cometchat-flutter-v5-push/SKILL.md +1 -1
  136. package/skills/cometchat-flutter-v5-testing/SKILL.md +390 -0
  137. package/skills/cometchat-flutter-v5-theming/SKILL.md +1 -1
  138. package/skills/cometchat-flutter-v5-troubleshooting/SKILL.md +1 -1
  139. package/skills/cometchat-flutter-v5-users-groups/SKILL.md +1 -1
  140. package/skills/cometchat-flutter-v6/SKILL.md +1 -1
  141. package/skills/cometchat-flutter-v6-calls/SKILL.md +308 -243
  142. package/skills/cometchat-flutter-v6-calls/references/add-calls-to-existing-chat.md +134 -0
  143. package/skills/cometchat-flutter-v6-calls/references/call-layouts.md +102 -0
  144. package/skills/cometchat-flutter-v6-calls/references/call-session.md +229 -0
  145. package/skills/cometchat-flutter-v6-calls/references/device-management.md +99 -0
  146. package/skills/cometchat-flutter-v6-calls/references/group-calls.md +190 -0
  147. package/skills/cometchat-flutter-v6-calls/references/idle-timeout.md +80 -0
  148. package/skills/cometchat-flutter-v6-calls/references/in-call-chat.md +122 -0
  149. package/skills/cometchat-flutter-v6-calls/references/raise-hand.md +268 -0
  150. package/skills/cometchat-flutter-v6-calls/references/ringing-integration.md +171 -0
  151. package/skills/cometchat-flutter-v6-calls/references/server-push-bridge.md +93 -0
  152. package/skills/cometchat-flutter-v6-calls/references/share-invite.md +102 -0
  153. package/skills/cometchat-flutter-v6-components/SKILL.md +1 -1
  154. package/skills/cometchat-flutter-v6-conversations/SKILL.md +1 -1
  155. package/skills/cometchat-flutter-v6-core/SKILL.md +1 -1
  156. package/skills/cometchat-flutter-v6-customization/SKILL.md +1 -1
  157. package/skills/cometchat-flutter-v6-events/SKILL.md +1 -1
  158. package/skills/cometchat-flutter-v6-features/SKILL.md +1 -1
  159. package/skills/cometchat-flutter-v6-messages/SKILL.md +1 -1
  160. package/skills/cometchat-flutter-v6-migration/SKILL.md +1 -1
  161. package/skills/cometchat-flutter-v6-placement/SKILL.md +1 -1
  162. package/skills/cometchat-flutter-v6-production/SKILL.md +1 -1
  163. package/skills/cometchat-flutter-v6-push/SKILL.md +452 -0
  164. package/skills/cometchat-flutter-v6-testing/SKILL.md +319 -0
  165. package/skills/cometchat-flutter-v6-theming/SKILL.md +1 -1
  166. package/skills/cometchat-flutter-v6-troubleshooting/SKILL.md +1 -1
  167. package/skills/cometchat-flutter-v6-users-groups/SKILL.md +1 -1
  168. package/skills/cometchat-i18n/SKILL.md +358 -0
  169. package/skills/cometchat-ios/SKILL.md +5 -5
  170. package/skills/cometchat-ios-calls/SKILL.md +409 -0
  171. package/skills/cometchat-ios-calls/references/add-calls-to-existing-chat.md +172 -0
  172. package/skills/cometchat-ios-calls/references/avaudiosession-routing.md +189 -0
  173. package/skills/cometchat-ios-calls/references/call-layouts.md +136 -0
  174. package/skills/cometchat-ios-calls/references/call-session.md +221 -0
  175. package/skills/cometchat-ios-calls/references/callkit-and-pushkit.md +353 -0
  176. package/skills/cometchat-ios-calls/references/custom-ui.md +322 -0
  177. package/skills/cometchat-ios-calls/references/device-management.md +171 -0
  178. package/skills/cometchat-ios-calls/references/group-calls.md +396 -0
  179. package/skills/cometchat-ios-calls/references/idle-timeout.md +185 -0
  180. package/skills/cometchat-ios-calls/references/in-call-chat.md +183 -0
  181. package/skills/cometchat-ios-calls/references/migration-v4-to-v5.md +138 -0
  182. package/skills/cometchat-ios-calls/references/picture-in-picture.md +246 -0
  183. package/skills/cometchat-ios-calls/references/raise-hand.md +239 -0
  184. package/skills/cometchat-ios-calls/references/recording-screen-share.md +339 -0
  185. package/skills/cometchat-ios-calls/references/ringing-integration.md +142 -0
  186. package/skills/cometchat-ios-calls/references/server-apns-pushkit.md +267 -0
  187. package/skills/cometchat-ios-calls/references/share-invite.md +152 -0
  188. package/skills/cometchat-ios-calls/references/swiftui-uikit-hosting.md +246 -0
  189. package/skills/cometchat-ios-calls/references/voip-cert-setup.md +166 -0
  190. package/skills/cometchat-ios-components/SKILL.md +1 -1
  191. package/skills/cometchat-ios-core/SKILL.md +1 -1
  192. package/skills/cometchat-ios-customization/SKILL.md +1 -1
  193. package/skills/cometchat-ios-features/SKILL.md +1 -1
  194. package/skills/cometchat-ios-placement/SKILL.md +1 -1
  195. package/skills/cometchat-ios-production/SKILL.md +1 -1
  196. package/skills/cometchat-ios-push/SKILL.md +1 -1
  197. package/skills/cometchat-ios-testing/SKILL.md +371 -0
  198. package/skills/cometchat-ios-theming/SKILL.md +1 -1
  199. package/skills/cometchat-ios-troubleshooting/SKILL.md +1 -1
  200. package/skills/cometchat-native-bare-patterns/SKILL.md +45 -3
  201. package/skills/cometchat-native-calls/SKILL.md +599 -0
  202. package/skills/cometchat-native-calls/references/add-calls-to-existing-chat.md +203 -0
  203. package/skills/cometchat-native-calls/references/call-layouts.md +124 -0
  204. package/skills/cometchat-native-calls/references/call-session.md +182 -0
  205. package/skills/cometchat-native-calls/references/custom-ui.md +250 -0
  206. package/skills/cometchat-native-calls/references/device-management.md +135 -0
  207. package/skills/cometchat-native-calls/references/expo-vs-bare.md +179 -0
  208. package/skills/cometchat-native-calls/references/group-calls.md +291 -0
  209. package/skills/cometchat-native-calls/references/idle-timeout.md +128 -0
  210. package/skills/cometchat-native-calls/references/in-call-chat.md +143 -0
  211. package/skills/cometchat-native-calls/references/migration-v4-to-v5.md +72 -0
  212. package/skills/cometchat-native-calls/references/picture-in-picture.md +276 -0
  213. package/skills/cometchat-native-calls/references/raise-hand.md +203 -0
  214. package/skills/cometchat-native-calls/references/recording-screen-share.md +290 -0
  215. package/skills/cometchat-native-calls/references/ringing-integration.md +118 -0
  216. package/skills/cometchat-native-calls/references/server-push-bridge.md +135 -0
  217. package/skills/cometchat-native-calls/references/server-push-payloads.md +193 -0
  218. package/skills/cometchat-native-calls/references/share-invite.md +144 -0
  219. package/skills/cometchat-native-calls/references/voip-push-end-to-end.md +317 -0
  220. package/skills/cometchat-native-components/SKILL.md +1 -1
  221. package/skills/cometchat-native-core/SKILL.md +1 -1
  222. package/skills/cometchat-native-customization/SKILL.md +1 -1
  223. package/skills/cometchat-native-expo-patterns/SKILL.md +18 -1
  224. package/skills/cometchat-native-features/SKILL.md +1 -1
  225. package/skills/cometchat-native-placement/SKILL.md +1 -1
  226. package/skills/cometchat-native-production/SKILL.md +1 -1
  227. package/skills/cometchat-native-push/SKILL.md +1 -1
  228. package/skills/cometchat-native-testing/SKILL.md +1 -1
  229. package/skills/cometchat-native-theming/SKILL.md +1 -1
  230. package/skills/cometchat-native-troubleshooting/SKILL.md +1 -1
  231. package/skills/cometchat-nextjs-patterns/SKILL.md +1 -1
  232. package/skills/cometchat-placement/SKILL.md +1 -1
  233. package/skills/cometchat-production/SKILL.md +1 -1
  234. package/skills/cometchat-react-calls/SKILL.md +539 -0
  235. package/skills/cometchat-react-calls/references/add-calls-to-existing-chat.md +145 -0
  236. package/skills/cometchat-react-calls/references/call-layouts.md +161 -0
  237. package/skills/cometchat-react-calls/references/call-session.md +235 -0
  238. package/skills/cometchat-react-calls/references/custom-ui.md +201 -0
  239. package/skills/cometchat-react-calls/references/device-management.md +206 -0
  240. package/skills/cometchat-react-calls/references/group-calls.md +262 -0
  241. package/skills/cometchat-react-calls/references/idle-timeout.md +175 -0
  242. package/skills/cometchat-react-calls/references/in-call-chat.md +212 -0
  243. package/skills/cometchat-react-calls/references/migration-v4-to-v5.md +172 -0
  244. package/skills/cometchat-react-calls/references/picture-in-picture.md +245 -0
  245. package/skills/cometchat-react-calls/references/raise-hand.md +238 -0
  246. package/skills/cometchat-react-calls/references/recording-screen-share.md +143 -0
  247. package/skills/cometchat-react-calls/references/ringing-integration.md +255 -0
  248. package/skills/cometchat-react-calls/references/server-web-push-vapid.md +241 -0
  249. package/skills/cometchat-react-calls/references/share-invite.md +176 -0
  250. package/skills/cometchat-react-calls/references/testing-calls-on-web.md +198 -0
  251. package/skills/cometchat-react-calls/references/voip-and-web-push.md +165 -0
  252. package/skills/cometchat-react-patterns/SKILL.md +1 -1
  253. package/skills/cometchat-react-push/SKILL.md +448 -0
  254. package/skills/cometchat-react-router-patterns/SKILL.md +1 -1
  255. package/skills/cometchat-react-testing/SKILL.md +404 -0
  256. package/skills/cometchat-theming/SKILL.md +3 -3
  257. package/skills/cometchat-troubleshooting/SKILL.md +2 -2
@@ -0,0 +1,201 @@
1
+ # Custom call UI on web
2
+
3
+ When the kit's default `<CometChatOngoingCall />` doesn't fit your app's design system, drop down to the Calls SDK directly. Two escalation paths:
4
+
5
+ 1. **Style the kit's component** — pass style props / CSS variable overrides. Cheapest. Covers most cases.
6
+ 2. **Build your own surface on the SDK** — use `CometChatCalls.joinSession(token, settings, container)` directly with your own DOM container. Maximum control. The kit doesn't render anything; you do. (`startSession` is a deprecated v4 shim — use `joinSession`.)
7
+
8
+ This reference covers path 2 — full custom UI on the SDK. Path 1 is in the kit's component documentation (see `cometchat-customization`).
9
+
10
+ ---
11
+
12
+ ## Architecture
13
+
14
+ ```
15
+ Your React component
16
+ ├── Local user video (mic + camera preview) ← <video> element + getUserMedia
17
+ ├── Remote participant video tile(s) ← <video> elements piped from Calls SDK
18
+ ├── Custom control panel (mute, end, switch cam) ← buttons calling SDK methods
19
+ └── Layout (full-screen / picture-in-picture / grid) ← your CSS
20
+ ```
21
+
22
+ The Calls SDK gives you:
23
+
24
+ - A `RTCMultiConnection`-like internal connection it manages
25
+ - Track-add events (when a participant's track arrives)
26
+ - Track-remove events
27
+ - Methods to mute/unmute, switch camera, end session
28
+ - A `htmlElement` you pass to `startSession` — **required** — where the SDK draws the call surface. With `enableDefaultLayout(false)`, the SDK still uses this container for internal video elements; your custom UI overlays on top via absolute positioning, OR you keep the container hidden and use the listener events to drive your own `<video>` elements (advanced; see "Advanced — bypassing the SDK's container" below).
29
+
30
+ ---
31
+
32
+ ## Hooking into track events
33
+
34
+ ```tsx
35
+ // CustomOngoingCallView.tsx
36
+ import { useEffect, useRef } from "react";
37
+ import { CometChatCalls } from "@cometchat/calls-sdk-javascript";
38
+
39
+ interface Props {
40
+ sessionId: string;
41
+ authToken: string;
42
+ onCallEnded: () => void;
43
+ }
44
+
45
+ export function CustomOngoingCallView({ sessionId, authToken, onCallEnded }: Props) {
46
+ const localVideoRef = useRef<HTMLVideoElement>(null);
47
+ const remoteVideoRef = useRef<HTMLVideoElement>(null);
48
+
49
+ useEffect(() => {
50
+ const callListener = new CometChatCalls.OngoingCallListener({
51
+ onUserListUpdated: (userList: unknown) => {
52
+ // userList = current participants — re-render your custom roster
53
+ },
54
+ onCallEnded: () => {
55
+ cleanup();
56
+ onCallEnded();
57
+ },
58
+ onCallEndButtonPressed: () => {
59
+ // User clicked YOUR end button — we still have to call endSession
60
+ CometChatCalls.leaveSession();
61
+ },
62
+ onError: (error: unknown) => {
63
+ console.error("Call error:", error);
64
+ },
65
+ onAudioModesUpdated: (audioModes: unknown[]) => {
66
+ // available mic / speaker devices
67
+ },
68
+ onCallSwitchedToVideo: (call: unknown) => {
69
+ // remote upgraded the call from voice to video
70
+ },
71
+ onMediaDeviceListUpdated: (devices: unknown) => {
72
+ // user plugged in headphones, etc.
73
+ },
74
+ });
75
+
76
+ const settings = new CometChatCalls.CallSettingsBuilder()
77
+ .setSessionID(sessionId)
78
+ .setIsAudioOnly(false)
79
+ .enableDefaultLayout(false) // ← key: we render the UI ourselves
80
+ .setCallEventListener(callListener)
81
+ .build();
82
+
83
+ // v5 generateToken takes ONLY sessionId — authToken is internal after CometChatCalls.login().
84
+ CometChatCalls.generateToken(sessionId).then((tokenRes) => {
85
+ // htmlElement is REQUIRED — pass a container the SDK can draw into.
86
+ // With custom UI you typically render your own <video> elements; the
87
+ // container can be hidden but must still be a real DOM node.
88
+ const container = document.getElementById("calls-container")!;
89
+ // joinSession is the v5 canonical — startSession is a deprecated shim.
90
+ CometChatCalls.joinSession(tokenRes.token, settings, container);
91
+ });
92
+
93
+ return () => cleanup();
94
+
95
+ function cleanup() {
96
+ // leaveSession is v5 canonical — endSession() is deprecated (still works as a shim).
97
+ CometChatCalls.leaveSession();
98
+ if (localVideoRef.current) localVideoRef.current.srcObject = null;
99
+ if (remoteVideoRef.current) remoteVideoRef.current.srcObject = null;
100
+ }
101
+ }, [sessionId, authToken, onCallEnded]);
102
+
103
+ return (
104
+ <div className="ongoing-call">
105
+ <video ref={remoteVideoRef} autoPlay playsInline className="remote-tile" />
106
+ <video ref={localVideoRef} autoPlay playsInline muted className="local-tile" />
107
+ <ControlPanel
108
+ onMute={() => CometChatCalls.muteAudio(true)}
109
+ onUnmute={() => CometChatCalls.muteAudio(false)}
110
+ onCameraOff={() => CometChatCalls.pauseVideo(true)}
111
+ onCameraOn={() => CometChatCalls.pauseVideo(false)}
112
+ onSwitchCamera={() => CometChatCalls.switchCamera()}
113
+ onEnd={() => {
114
+ CometChatCalls.leaveSession();
115
+ onCallEnded();
116
+ }}
117
+ />
118
+ </div>
119
+ );
120
+ }
121
+ ```
122
+
123
+ ---
124
+
125
+ ## Custom control panel — the canonical mute/end/camera buttons
126
+
127
+ ```tsx
128
+ function ControlPanel(props: {
129
+ onMute: () => void;
130
+ onUnmute: () => void;
131
+ onCameraOff: () => void;
132
+ onCameraOn: () => void;
133
+ onSwitchCamera: () => void;
134
+ onEnd: () => void;
135
+ }) {
136
+ const [muted, setMuted] = useState(false);
137
+ const [cameraOff, setCameraOff] = useState(false);
138
+
139
+ return (
140
+ <div className="control-panel">
141
+ <button onClick={() => { muted ? props.onUnmute() : props.onMute(); setMuted(!muted); }}>
142
+ {muted ? "Unmute" : "Mute"}
143
+ </button>
144
+ <button onClick={() => { cameraOff ? props.onCameraOn() : props.onCameraOff(); setCameraOff(!cameraOff); }}>
145
+ {cameraOff ? "Camera on" : "Camera off"}
146
+ </button>
147
+ <button onClick={props.onSwitchCamera}>Switch camera</button>
148
+ <button onClick={props.onEnd} className="end-call">End</button>
149
+ </div>
150
+ );
151
+ }
152
+ ```
153
+
154
+ The SDK methods (`muteAudio`, `pauseVideo`, `switchCamera`) propagate to all participants via the SDK's signaling — you don't manage track state yourself.
155
+
156
+ ---
157
+
158
+ ## Local preview (before the call connects)
159
+
160
+ For a "ringing" UI where the local user sees their own camera before the receiver picks up:
161
+
162
+ ```tsx
163
+ useEffect(() => {
164
+ let stream: MediaStream | null = null;
165
+ navigator.mediaDevices.getUserMedia({ video: true, audio: true }).then((s) => {
166
+ stream = s;
167
+ if (localVideoRef.current) localVideoRef.current.srcObject = s;
168
+ }).catch((err) => {
169
+ if (err.name === "NotAllowedError") setError("Camera/mic permission denied");
170
+ if (err.name === "NotFoundError") setError("No camera or mic on this device");
171
+ });
172
+
173
+ return () => {
174
+ stream?.getTracks().forEach((t) => t.stop()); // CRITICAL — release tracks (rule 1.3)
175
+ if (localVideoRef.current) localVideoRef.current.srcObject = null;
176
+ };
177
+ }, []);
178
+ ```
179
+
180
+ Once `startSession` runs, the SDK takes over the camera/mic — release your preview stream first or you'll have two consumers fighting over the device.
181
+
182
+ ---
183
+
184
+ ## Layout customization
185
+
186
+ The Calls SDK is layout-agnostic when `enableDefaultLayout(false)`. You compose remote tiles in any CSS layout:
187
+
188
+ - **Spotlight** — one large remote tile + small thumbnails for others. Track which user is speaking (`onActiveSpeakerUpdated` event in some SDK builds) and swap the spotlight.
189
+ - **Grid** — CSS grid with auto-fit columns, 1-N participant tiles equally sized.
190
+ - **Picture-in-picture** — small floating remote video that survives navigation. Mount it in a portal at the layout root (similar to `<CometChatIncomingCall />`).
191
+
192
+ ---
193
+
194
+ ## When to NOT go custom
195
+
196
+ - Default kit UI works for 80% of apps; custom is a real engineering investment.
197
+ - Recording / screen-share / participant-management features require deeper SDK plumbing — `references/recording-screen-share.md` covers them but custom-UI authors must wire all of them themselves.
198
+ - Kit components handle accessibility (keyboard nav, ARIA roles, focus traps) — custom must replicate.
199
+ - The kit is updated when CometChat ships breaking SDK changes; custom code is yours to migrate.
200
+
201
+ The dispatcher asks the user whether to go custom (defaults to "no — use kit") and only loads this reference when they say yes.
@@ -0,0 +1,206 @@
1
+ # Device management on web
2
+
3
+ Camera / mic / speaker enumeration + switching mid-call. SDK exposes `getAudioInputDevices()` / `getVideoInputDevices()` / `getAudioOutputDevices()` plus `setAudioInputDevice(deviceId)` etc. Browser handles the underlying `navigator.mediaDevices.enumerateDevices()` plumbing.
4
+
5
+ **Canonical docs:** https://www.cometchat.com/docs/calls/javascript/device-management
6
+ **Use it for:** "I'm on AirPods, switch from laptop mic"; "this monitor's webcam is bad, use the external one"; pre-call device picker; in-call settings menu.
7
+
8
+ ---
9
+
10
+ ## SDK API
11
+
12
+ ```ts
13
+ import { CometChatCalls } from "@cometchat/calls-sdk-javascript";
14
+
15
+ // Enumerate
16
+ const mics = await CometChatCalls.getAudioInputDevices();
17
+ const speakers = await CometChatCalls.getAudioOutputDevices();
18
+ const cameras = await CometChatCalls.getVideoInputDevices();
19
+
20
+ // Currently selected
21
+ const currentMic = CometChatCalls.getCurrentAudioInputDevice();
22
+
23
+ // Switch (mid-call OK)
24
+ await CometChatCalls.setAudioInputDevice(deviceId);
25
+ await CometChatCalls.setAudioOutputDevice(deviceId);
26
+ await CometChatCalls.setVideoInputDevice(deviceId);
27
+
28
+ // Listen for device changes (user plugs in headphones, etc.)
29
+ CometChatCalls.addEventListener("onAudioModesUpdated", (devices) => {
30
+ // re-enumerate; show toast "AirPods connected"
31
+ });
32
+ ```
33
+
34
+ Each device looks like:
35
+ ```ts
36
+ interface MediaDevice {
37
+ id: string; // browser-assigned ID
38
+ label: string; // "Built-in Microphone", "AirPods Pro"
39
+ // ... other fields per browser
40
+ }
41
+ ```
42
+
43
+ ---
44
+
45
+ ## Pre-call device picker
46
+
47
+ ```tsx
48
+ import { useEffect, useState } from "react";
49
+ import { CometChatCalls } from "@cometchat/calls-sdk-javascript";
50
+
51
+ interface MediaDevice { id: string; label: string; }
52
+
53
+ function DevicePicker({ onConfirm }: { onConfirm: () => void }) {
54
+ const [mics, setMics] = useState<MediaDevice[]>([]);
55
+ const [cameras, setCameras] = useState<MediaDevice[]>([]);
56
+ const [speakers, setSpeakers] = useState<MediaDevice[]>([]);
57
+ const [selectedMic, setSelectedMic] = useState<string>();
58
+ const [selectedCamera, setSelectedCamera] = useState<string>();
59
+ const [selectedSpeaker, setSelectedSpeaker] = useState<string>();
60
+
61
+ useEffect(() => {
62
+ async function load() {
63
+ // Devices have empty labels until permission is granted; trigger getUserMedia first
64
+ try {
65
+ await navigator.mediaDevices.getUserMedia({ audio: true, video: true });
66
+ } catch {
67
+ // permission denied — labels will be empty; offer settings link
68
+ }
69
+
70
+ const [m, c, s] = await Promise.all([
71
+ CometChatCalls.getAudioInputDevices(),
72
+ CometChatCalls.getVideoInputDevices(),
73
+ CometChatCalls.getAudioOutputDevices(),
74
+ ]);
75
+ setMics(m); setCameras(c); setSpeakers(s);
76
+
77
+ setSelectedMic(CometChatCalls.getCurrentAudioInputDevice()?.id ?? m[0]?.id);
78
+ setSelectedCamera(CometChatCalls.getCurrentVideoInputDevice()?.id ?? c[0]?.id);
79
+ setSelectedSpeaker(CometChatCalls.getCurrentAudioOutputDevice()?.id ?? s[0]?.id);
80
+ }
81
+ load();
82
+ }, []);
83
+
84
+ async function confirm() {
85
+ if (selectedMic) await CometChatCalls.setAudioInputDevice(selectedMic);
86
+ if (selectedCamera) await CometChatCalls.setVideoInputDevice(selectedCamera);
87
+ if (selectedSpeaker) await CometChatCalls.setAudioOutputDevice(selectedSpeaker);
88
+ onConfirm();
89
+ }
90
+
91
+ return (
92
+ <form>
93
+ <label>
94
+ Microphone
95
+ <select value={selectedMic} onChange={(e) => setSelectedMic(e.target.value)}>
96
+ {mics.map(d => <option key={d.id} value={d.id}>{d.label || `Mic ${d.id.slice(0, 6)}`}</option>)}
97
+ </select>
98
+ </label>
99
+ <label>
100
+ Camera
101
+ <select value={selectedCamera} onChange={(e) => setSelectedCamera(e.target.value)}>
102
+ {cameras.map(d => <option key={d.id} value={d.id}>{d.label || `Camera ${d.id.slice(0, 6)}`}</option>)}
103
+ </select>
104
+ </label>
105
+ <label>
106
+ Speaker
107
+ <select value={selectedSpeaker} onChange={(e) => setSelectedSpeaker(e.target.value)}>
108
+ {speakers.map(d => <option key={d.id} value={d.id}>{d.label || `Speaker ${d.id.slice(0, 6)}`}</option>)}
109
+ </select>
110
+ </label>
111
+ <button type="button" onClick={confirm}>Join call</button>
112
+ </form>
113
+ );
114
+ }
115
+ ```
116
+
117
+ **Empty labels gotcha:** browsers return empty `label` strings until permission is granted. Trigger `getUserMedia` once before enumerating to populate labels.
118
+
119
+ ---
120
+
121
+ ## Hot-swap during a call (settings menu)
122
+
123
+ ```tsx
124
+ function InCallDeviceSettings() {
125
+ const [showMenu, setShowMenu] = useState(false);
126
+ const [mics, setMics] = useState<MediaDevice[]>([]);
127
+
128
+ useEffect(() => {
129
+ if (!showMenu) return;
130
+ CometChatCalls.getAudioInputDevices().then(setMics);
131
+
132
+ const onModesUpdated = () => {
133
+ CometChatCalls.getAudioInputDevices().then(setMics);
134
+ };
135
+ CometChatCalls.addEventListener("onAudioModesUpdated", onModesUpdated);
136
+ return () => CometChatCalls.removeEventListener("onAudioModesUpdated", onModesUpdated);
137
+ }, [showMenu]);
138
+
139
+ async function selectMic(id: string) {
140
+ await CometChatCalls.setAudioInputDevice(id);
141
+ setShowMenu(false);
142
+ }
143
+
144
+ return (
145
+ <div>
146
+ <button onClick={() => setShowMenu(s => !s)}>Mic ▾</button>
147
+ {showMenu && (
148
+ <ul role="menu">
149
+ {mics.map(d => (
150
+ <li key={d.id}>
151
+ <button role="menuitem" onClick={() => selectMic(d.id)}>{d.label}</button>
152
+ </li>
153
+ ))}
154
+ </ul>
155
+ )}
156
+ </div>
157
+ );
158
+ }
159
+ ```
160
+
161
+ `onAudioModesUpdated` fires when the user plugs in headphones, AirPods connect, etc. Re-enumerate on the event.
162
+
163
+ ---
164
+
165
+ ## Bluetooth / AirPods routing
166
+
167
+ Browsers expose Bluetooth speakers in `getAudioOutputDevices()`. Selecting one calls `HTMLMediaElement.setSinkId()` under the hood — works in Chrome/Edge/Firefox, NOT in Safari (Safari uses system audio routing only).
168
+
169
+ ```ts
170
+ // Detect Safari (limited device-output support)
171
+ const safari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
172
+ if (safari) {
173
+ // Hide speaker selection; show "Use system audio" hint
174
+ }
175
+ ```
176
+
177
+ ---
178
+
179
+ ## Anti-patterns
180
+
181
+ 1. **Calling `getAudioInputDevices` before requesting permission.** Returns devices with empty `label` strings — UI shows "undefined" or empty entries.
182
+ 2. **Caching device list.** Devices change (plug/unplug). Re-enumerate on every menu open AND on `onAudioModesUpdated`.
183
+ 3. **Hardcoding the first device as default.** Browsers may sort differently (built-in vs USB). Read `getCurrent*Device` first; only fall back to first if no current selection.
184
+ 4. **Switching speakers in Safari.** `setAudioOutputDevice` silently fails. Detect Safari and hide the speaker picker (or show a "iOS uses system routing" tooltip).
185
+ 5. **No listener cleanup on unmount.** Event accumulates listeners on remount; spam every device change.
186
+
187
+ ---
188
+
189
+ ## Verification checklist
190
+
191
+ - [ ] Permission requested before enumeration (empty-label fix)
192
+ - [ ] `getCurrent*Device()` used as default in pickers
193
+ - [ ] `onAudioModesUpdated` listener for hot-swap detection
194
+ - [ ] Listener cleanup on unmount
195
+ - [ ] Safari speaker picker hidden / fallback message
196
+ - [ ] Browser smoke: plug/unplug headphones during call, picker updates
197
+ - [ ] AirPods smoke: connect AirPods → "AirPods" appears in mic + speaker lists
198
+ - [ ] Multi-camera smoke: USB webcam + built-in, switch between
199
+
200
+ ---
201
+
202
+ ## Pointers
203
+
204
+ - `cometchat-react-calls` SKILL.md — the seven hard rules
205
+ - `references/custom-ui.md` — full custom call UI integration
206
+ - Canonical docs: https://www.cometchat.com/docs/calls/javascript/device-management
@@ -0,0 +1,262 @@
1
+ # Group calls — broadcast meeting pattern (web)
2
+
3
+ Group calls in CometChat use a **different signaling channel than 1:1 user calls**. The Ringing flow (Chat SDK `initiateCall` → `onIncomingCallReceived` on peer) fires for **1:1 user calls only**. For groups, the kit broadcasts a **custom message** of type `meeting` to the group; receivers see a "Join meeting" card in their message list (kit-based) OR need an explicit message listener (custom UI).
4
+
5
+ This is by-design kit behavior — not a bug. Documented across all platform kits.
6
+
7
+ **Canonical docs:** https://www.cometchat.com/docs/calls/javascript/group-calls
8
+
9
+ ---
10
+
11
+ ## Architecture
12
+
13
+ ```
14
+ Caller (uid-A, member of group-X) CometChat Receivers (all other members of group-X)
15
+ │ │ │
16
+ │ <CometChatCallButtons group={x}> │ │
17
+ │ → CometChatUIKit.sendCustomMessage( │ │
18
+ │ CustomMessage(GUID, GROUP, │ │
19
+ │ "meeting", │ │
20
+ │ { callType, sessionId })) │ │
21
+ ├─────────────────────────────────────────>│ │
22
+ │ │ onCustomMessageReceived │
23
+ │ ├─────────────────────────────>│ (each member's
24
+ │ │ │ MessageListener
25
+ │ │ │ fires if they're
26
+ │ │ │ in the group)
27
+ │ │ │
28
+ │ caller jumps straight to OngoingCall │ │
29
+ │ (joins session GUID directly) │ receiver taps "Join" │
30
+ │ │ → joinSession(GUID) │
31
+ │ CometChatCalls.joinSession(token, GUID) │ <─────────────────────────── │
32
+ ├─────────────────────────────────────────>│ │
33
+ │ ───── WebRTC session active (sessionId = group GUID) ───── │
34
+ ```
35
+
36
+ Key contrast with 1:1 ringing:
37
+
38
+ | Channel | 1:1 user calls | Group calls |
39
+ |---|---|---|
40
+ | Signaling API | `CometChat.initiateCall(call)` | `CometChatUIKit.sendCustomMessage(meetingMessage)` |
41
+ | Receiver event | `CallListener.onIncomingCallReceived` | `MessageListener.onCustomMessageReceived` (category=CATEGORY_CUSTOM + type="meeting") |
42
+ | Session ID | server-generated unique per call | the group's GUID |
43
+ | Ring/decline semantics | yes — `acceptCall` / `rejectCall` | no — receivers just tap to join (or ignore) |
44
+ | Auto-cancel timeout | yes (45s default) | no — meeting card persists in chat history |
45
+
46
+ ---
47
+
48
+ ## Hard rules
49
+
50
+ 1. **Group calls broadcast a custom message; they do NOT use the call listener.** If your custom UI only registers `addCallListener`, group-call recipients will see NOTHING. Add a `MessageListener` that handles `category === CATEGORY_CUSTOM && type === 'meeting'`.
51
+ 2. **The session ID equals the group's GUID** — not a generated unique ID like 1:1 calls. Anyone with the GUID can join the session at any time (it's persistent, not auto-cancelled).
52
+ 3. **Anyone can join, including after the meeting started.** Late joiners are normal — the WebRTC session is open until all participants leave. UI must handle "joining an already-active meeting" as a valid state.
53
+ 4. **Joining = `CometChatCalls.joinSession(token, sessionSettings, container)` with sessionId set to the group GUID.** Same `generateToken(sessionId)` step as 1:1 ringing — auth is internal after `CometChatCalls.login()`.
54
+ 5. **No `CometChat.endCall(sessionId)` on the chat side for groups** — the meeting message is the persistent record, not a call entity. Each participant just calls `CometChatCalls.leaveSession()` when they hang up.
55
+ 6. **`onCallEndedMessageReceived` does NOT fire for group sessions.** The session persists as long as anyone's in it. Use `CometChatCalls.OngoingCallListener.onCallEnded` to detect when YOUR client's session ends.
56
+
57
+ ---
58
+
59
+ ## Caller side — kit-based
60
+
61
+ If you're using `<CometChatMessageHeader>` + `<CometChatCallButtons>`, the kit handles everything:
62
+
63
+ ```tsx
64
+ import { CometChatCallButtons } from "@cometchat/chat-uikit-react";
65
+
66
+ <CometChatCallButtons group={group} />
67
+ ```
68
+
69
+ Tapping voice/video automatically:
70
+ 1. Sends a `CustomMessage` of type `meeting` to the group
71
+ 2. Opens `<CometChatOutgoingCall>` UI (which transitions to `<CometChatOngoingCall>`)
72
+ 3. Joins the WebRTC session with `sessionId = group.getGuid()`
73
+
74
+ No additional code on the caller side.
75
+
76
+ ## Caller side — custom UI
77
+
78
+ If you don't use kit components and want full control:
79
+
80
+ ```ts
81
+ import { CometChat } from "@cometchat/chat-sdk-javascript";
82
+ import { CometChatCalls } from "@cometchat/calls-sdk-javascript";
83
+
84
+ async function startGroupCall(guid: string, callType: "audio" | "video") {
85
+ const loggedInUser = await CometChat.getLoggedInUser();
86
+ if (!loggedInUser) throw new Error("Not logged in");
87
+
88
+ // 1. Broadcast the meeting message to the group
89
+ const sessionId = guid; // group GUID becomes the session ID
90
+ const customData = { callType, sessionId };
91
+ const meetingMessage = new CometChat.CustomMessage(
92
+ guid,
93
+ CometChat.RECEIVER_TYPE.GROUP,
94
+ "meeting",
95
+ customData,
96
+ );
97
+ meetingMessage.setCategory(CometChat.CATEGORY_CUSTOM);
98
+ meetingMessage.setMetadata({
99
+ incrementUnreadCount: true,
100
+ pushNotification: "meeting",
101
+ ...customData,
102
+ });
103
+ await CometChat.sendCustomMessage(meetingMessage);
104
+
105
+ // 2. Generate a call token + join the session
106
+ const authToken = loggedInUser.getAuthToken();
107
+ const { token: callToken } = await CometChatCalls.generateToken(sessionId);
108
+
109
+ const callSettings = new CometChatCalls.CallSettingsBuilder()
110
+ .setIsAudioOnlyCall(callType === "audio")
111
+ .enableDefaultLayout(true)
112
+ .setCallListener(
113
+ new CometChatCalls.OngoingCallListener({
114
+ onCallEnded: () => { /* hangup UI */ },
115
+ onError: (err) => { /* show error */ },
116
+ }),
117
+ )
118
+ .build();
119
+
120
+ // 3. Mount the WebRTC view into your container element
121
+ await CometChatCalls.joinSession(callToken, callSettings, containerElement);
122
+ }
123
+ ```
124
+
125
+ The `meeting` message lands in the group's chat history immediately; other members get `onCustomMessageReceived` if they have a listener.
126
+
127
+ ---
128
+
129
+ ## Receiver side — kit-based (auto-renders meeting card)
130
+
131
+ If your app uses `<CometChatMessageList />` to render the group's messages, the kit auto-renders the meeting message as a **"Join meeting" card** with a tap target. No additional code needed:
132
+
133
+ ```tsx
134
+ <CometChatMessageList group={group} />
135
+ ```
136
+
137
+ When a user taps the meeting card, the kit:
138
+ 1. Calls `CometChatCalls.generateToken(sessionId, authToken)`
139
+ 2. Opens `<CometChatOngoingCall>` with `sessionID={group.getGuid()}`
140
+ 3. Joins the WebRTC session
141
+
142
+ The receiver is now in the same WebRTC session as the caller (and any other members who joined).
143
+
144
+ ## Receiver side — custom UI (needs a message listener)
145
+
146
+ If you DON'T use `<CometChatMessageList />` — e.g. you have a custom chat surface, OR you want incoming-meeting notifications globally — register a `MessageListener` and handle the meeting message yourself:
147
+
148
+ ```ts
149
+ import { CometChat } from "@cometchat/chat-sdk-javascript";
150
+
151
+ const GROUP_MEETING_LISTENER_ID = "APP_GROUP_MEETING_LISTENER";
152
+
153
+ CometChat.addMessageListener(
154
+ GROUP_MEETING_LISTENER_ID,
155
+ new CometChat.MessageListener({
156
+ onCustomMessageReceived: (msg: CometChat.CustomMessage) => {
157
+ if (msg.getCategory() !== CometChat.CATEGORY_CUSTOM) return;
158
+ if (msg.getType() !== "meeting") return;
159
+
160
+ const customData = msg.getCustomData() as { callType?: "audio" | "video"; sessionId?: string };
161
+ const sessionId = customData.sessionId ?? msg.getReceiverId();
162
+ const callType = customData.callType ?? "video";
163
+ const fromUid = msg.getSender().getUid();
164
+ const groupGuid = msg.getReceiverId();
165
+
166
+ // Show YOUR group-call incoming UI here
167
+ // (e.g. toast notification with "Join" button, badge on the group, etc.)
168
+ showIncomingGroupCallUI({ sessionId, callType, fromUid, groupGuid });
169
+ },
170
+ }),
171
+ );
172
+
173
+ // On hangup or logout:
174
+ CometChat.removeMessageListener(GROUP_MEETING_LISTENER_ID);
175
+ ```
176
+
177
+ Tap-to-join from your custom UI:
178
+
179
+ ```ts
180
+ async function joinGroupCall(sessionId: string, callType: "audio" | "video", container: HTMLElement) {
181
+ const loggedInUser = await CometChat.getLoggedInUser();
182
+ const authToken = loggedInUser!.getAuthToken();
183
+ const { token: callToken } = await CometChatCalls.generateToken(sessionId);
184
+
185
+ const callSettings = new CometChatCalls.CallSettingsBuilder()
186
+ .setIsAudioOnlyCall(callType === "audio")
187
+ .enableDefaultLayout(true)
188
+ .setCallListener(
189
+ new CometChatCalls.OngoingCallListener({
190
+ onCallEnded: () => { /* hangup UI */ },
191
+ }),
192
+ )
193
+ .build();
194
+
195
+ await CometChatCalls.joinSession(callToken, callSettings, container);
196
+ }
197
+ ```
198
+
199
+ No `acceptCall` step — receivers just join the session. The meeting message remains in the chat history regardless of who joins.
200
+
201
+ ---
202
+
203
+ ## Edge cases
204
+
205
+ ### Late joining
206
+
207
+ A meeting can be active for an hour before a member opens the app. The custom message persists in chat history; tapping the card joins the live session.
208
+
209
+ **UI implication:** the meeting card should reflect live state. Listen for `MessageListener.onCustomMessageReceived` to add new cards; poll or use presence to know if the session is currently active. There's no built-in "meeting is live" signal — apps typically render the card with a "Join meeting" CTA regardless and let the WebRTC layer fail gracefully if everyone has left.
210
+
211
+ ### Cancelling / leaving
212
+
213
+ There's no "cancel the meeting" — the meeting message is permanent in chat history. Each participant leaves independently:
214
+
215
+ ```ts
216
+ CometChatCalls.leaveSession(); // your local WebRTC session (v5 — endSession() is deprecated)
217
+ // No CometChat.endCall — meetings don't have a call entity.
218
+ ```
219
+
220
+ If you want to mark a meeting as "ended" UX-wise, send a follow-up message (e.g. another custom message of type `meeting_ended`) and have the receiver UI update its cards based on it. Not built into the SDK.
221
+
222
+ ### Push notifications
223
+
224
+ The meeting `CustomMessage` carries `metadata.pushNotification = "meeting"`. The CometChat push system can route this to a "meeting started in your group" push. Configure on the dashboard side under Notifications → Push Notification.
225
+
226
+ ### Missed meetings
227
+
228
+ Since meetings don't ring, there's no "missed call" entity. If you want missed-meeting UI, derive it from message history: list meeting messages where the current user has NOT joined the session.
229
+
230
+ ---
231
+
232
+ ## Anti-patterns
233
+
234
+ 1. **Registering only `addCallListener` and expecting group calls to ring.** They won't. Group calls fire `onCustomMessageReceived`, not `onIncomingCallReceived`. Always add both listeners if you support both 1:1 and group calling.
235
+ 2. **Treating `sessionId` as ephemeral for groups.** It's the group GUID — persistent. Don't generate a new sessionId per group call; the kit uses the GUID intentionally so all joiners hit the same WebRTC session.
236
+ 3. **Calling `CometChat.endCall(sessionId)` after a group hangup.** Meetings have no call entity to end; the API returns an error. Use `CometChatCalls.leaveSession()` (local) only.
237
+ 4. **Using `acceptCall` / `rejectCall` on the meeting message.** Those only work on 1:1 call entities. For meetings, you just join (no accept) or ignore (no reject).
238
+ 5. **Assuming all group members ring simultaneously.** Only members with an active `MessageListener` get `onCustomMessageReceived`. Offline members see the meeting card when they next open the group.
239
+ 6. **Sending the meeting message without `metadata.pushNotification`.** Offline members won't get a push. The kit handles this for you when you use `<CometChatCallButtons>`; if you're building custom, copy the metadata pattern in §"Caller side — custom UI".
240
+
241
+ ---
242
+
243
+ ## Verification checklist
244
+
245
+ - [ ] If using kit components: `<CometChatCallButtons group={g}>` renders + tap initiates a meeting message
246
+ - [ ] If using custom caller UI: `CometChat.sendCustomMessage` is called with `type: "meeting"`, `category: CATEGORY_CUSTOM`, `customData: { callType, sessionId: groupGuid }`
247
+ - [ ] If using kit receiver: `<CometChatMessageList group={g}>` renders the meeting card with a "Join" button
248
+ - [ ] If using custom receiver: `addMessageListener` registers `onCustomMessageReceived` and filters by category + type
249
+ - [ ] On hangup, `CometChatCalls.leaveSession()` is called (NOT `CometChat.endCall`)
250
+ - [ ] Late-joining works — open app while meeting is live; tap card; join session
251
+ - [ ] Push notifications fire for offline group members (server-side configured)
252
+ - [ ] Both listeners (`addCallListener` + `addMessageListener`) wired if app supports both 1:1 and group calls
253
+
254
+ ---
255
+
256
+ ## Pointers
257
+
258
+ - `ringing-integration.md` — the 1:1 user-call flow (different channel — call listener, not message listener)
259
+ - `call-session.md` — pure session-mode (URL-based, no chat-side signaling at all)
260
+ - `cometchat-react-calls/SKILL.md` rule 1.7 — IncomingCall mount (1:1 only; group calls don't use this)
261
+ - Canonical docs: https://www.cometchat.com/docs/calls/javascript/group-calls
262
+ - Kit source (verified 2026-05-15): `node_modules/@cometchat/chat-uikit-react-native/src/calls/CometChatCallButtons/CometChatCallButtons.tsx:138-201`