@webex/plugin-meetings 2.59.2 → 2.59.3-next.1
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.
- package/.eslintrc.js +6 -6
- package/LICENSE +1 -1
- package/README.md +1204 -1204
- package/UPGRADING.md +287 -287
- package/babel.config.js +3 -3
- package/browsers.js +108 -108
- package/dist/common/browser-detection.d.ts +9 -9
- package/dist/common/browser-detection.js.map +1 -1
- package/dist/common/collection.d.ts +48 -48
- package/dist/common/collection.js +43 -43
- package/dist/common/collection.js.map +1 -1
- package/dist/common/config.d.ts +2 -2
- package/dist/common/config.js.map +1 -1
- package/dist/common/errors/captcha-error.d.ts +15 -15
- package/dist/common/errors/captcha-error.js +7 -7
- package/dist/common/errors/captcha-error.js.map +1 -1
- package/dist/common/errors/intent-to-join.d.ts +16 -16
- package/dist/common/errors/intent-to-join.js +7 -7
- package/dist/common/errors/intent-to-join.js.map +1 -1
- package/dist/common/errors/join-meeting.d.ts +17 -17
- package/dist/common/errors/join-meeting.js +8 -8
- package/dist/common/errors/join-meeting.js.map +1 -1
- package/dist/common/errors/media.d.ts +15 -15
- package/dist/common/errors/media.js +7 -7
- package/dist/common/errors/media.js.map +1 -1
- package/dist/common/errors/parameter.d.ts +15 -15
- package/dist/common/errors/parameter.js +7 -7
- package/dist/common/errors/parameter.js.map +1 -1
- package/dist/common/errors/password-error.d.ts +15 -15
- package/dist/common/errors/password-error.js +7 -7
- package/dist/common/errors/password-error.js.map +1 -1
- package/dist/common/errors/permission.d.ts +14 -14
- package/dist/common/errors/permission.js +6 -6
- package/dist/common/errors/permission.js.map +1 -1
- package/dist/common/errors/reconnection-in-progress.d.ts +9 -9
- package/dist/common/errors/reconnection-in-progress.js +6 -6
- package/dist/common/errors/reconnection-in-progress.js.map +1 -1
- package/dist/common/errors/reconnection.d.ts +15 -15
- package/dist/common/errors/reconnection.js +7 -7
- package/dist/common/errors/reconnection.js.map +1 -1
- package/dist/common/errors/stats.d.ts +15 -15
- package/dist/common/errors/stats.js +7 -7
- package/dist/common/errors/stats.js.map +1 -1
- package/dist/common/errors/webex-errors.d.ts +81 -81
- package/dist/common/errors/webex-errors.js +42 -42
- package/dist/common/errors/webex-errors.js.map +1 -1
- package/dist/common/errors/webex-meetings-error.d.ts +20 -20
- package/dist/common/errors/webex-meetings-error.js +12 -12
- package/dist/common/errors/webex-meetings-error.js.map +1 -1
- package/dist/common/events/events-scope.d.ts +17 -17
- package/dist/common/events/events-scope.js +10 -10
- package/dist/common/events/events-scope.js.map +1 -1
- package/dist/common/events/events.d.ts +12 -12
- package/dist/common/events/events.js +4 -4
- package/dist/common/events/events.js.map +1 -1
- package/dist/common/events/trigger-proxy.d.ts +2 -2
- package/dist/common/events/trigger-proxy.js.map +1 -1
- package/dist/common/events/util.d.ts +2 -2
- package/dist/common/events/util.js.map +1 -1
- package/dist/common/logs/logger-config.d.ts +2 -2
- package/dist/common/logs/logger-config.js.map +1 -1
- package/dist/common/logs/logger-proxy.d.ts +2 -2
- package/dist/common/logs/logger-proxy.js.map +1 -1
- package/dist/common/logs/request.d.ts +34 -34
- package/dist/common/logs/request.js +18 -18
- package/dist/common/logs/request.js.map +1 -1
- package/dist/common/queue.d.ts +32 -32
- package/dist/common/queue.js +18 -18
- package/dist/common/queue.js.map +1 -1
- package/dist/config.d.ts +73 -73
- package/dist/config.js.map +1 -1
- package/dist/constants.d.ts +924 -924
- package/dist/constants.js +9 -9
- package/dist/constants.js.map +1 -1
- package/dist/controls-options-manager/constants.d.ts +4 -4
- package/dist/controls-options-manager/constants.js.map +1 -1
- package/dist/controls-options-manager/enums.d.ts +5 -5
- package/dist/controls-options-manager/enums.js.map +1 -1
- package/dist/controls-options-manager/index.d.ts +120 -120
- package/dist/controls-options-manager/index.js +81 -81
- package/dist/controls-options-manager/index.js.map +1 -1
- package/dist/controls-options-manager/util.d.ts +7 -7
- package/dist/controls-options-manager/util.js.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js.map +1 -1
- package/dist/locus-info/controlsUtils.d.ts +2 -2
- package/dist/locus-info/controlsUtils.js +21 -21
- package/dist/locus-info/controlsUtils.js.map +1 -1
- package/dist/locus-info/embeddedAppsUtils.d.ts +2 -2
- package/dist/locus-info/embeddedAppsUtils.js +14 -14
- package/dist/locus-info/embeddedAppsUtils.js.map +1 -1
- package/dist/locus-info/fullState.d.ts +2 -2
- package/dist/locus-info/fullState.js.map +1 -1
- package/dist/locus-info/hostUtils.d.ts +2 -2
- package/dist/locus-info/hostUtils.js +19 -19
- package/dist/locus-info/hostUtils.js.map +1 -1
- package/dist/locus-info/index.d.ts +269 -269
- package/dist/locus-info/index.js +180 -180
- package/dist/locus-info/index.js.map +1 -1
- package/dist/locus-info/infoUtils.d.ts +2 -2
- package/dist/locus-info/infoUtils.js.map +1 -1
- package/dist/locus-info/mediaSharesUtils.d.ts +2 -2
- package/dist/locus-info/mediaSharesUtils.js +50 -50
- package/dist/locus-info/mediaSharesUtils.js.map +1 -1
- package/dist/locus-info/parser.d.ts +212 -212
- package/dist/locus-info/parser.js +136 -136
- package/dist/locus-info/parser.js.map +1 -1
- package/dist/locus-info/selfUtils.d.ts +2 -2
- package/dist/locus-info/selfUtils.js +52 -52
- package/dist/locus-info/selfUtils.js.map +1 -1
- package/dist/media/index.d.ts +32 -32
- package/dist/media/index.js +145 -145
- package/dist/media/index.js.map +1 -1
- package/dist/media/properties.d.ts +108 -108
- package/dist/media/properties.js +49 -49
- package/dist/media/properties.js.map +1 -1
- package/dist/media/util.d.ts +2 -2
- package/dist/media/util.js.map +1 -1
- package/dist/mediaQualityMetrics/config.d.ts +233 -233
- package/dist/mediaQualityMetrics/config.js.map +1 -1
- package/dist/meeting/effectsState.d.ts +42 -42
- package/dist/meeting/effectsState.js +24 -24
- package/dist/meeting/effectsState.js.map +1 -1
- package/dist/meeting/in-meeting-actions.d.ts +79 -79
- package/dist/meeting/in-meeting-actions.js +11 -11
- package/dist/meeting/in-meeting-actions.js.map +1 -1
- package/dist/meeting/index.d.ts +1621 -1621
- package/dist/meeting/index.js +1502 -1505
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/muteState.d.ts +116 -116
- package/dist/meeting/muteState.js +85 -85
- package/dist/meeting/muteState.js.map +1 -1
- package/dist/meeting/request.d.ts +255 -255
- package/dist/meeting/request.js +141 -141
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/state.d.ts +9 -9
- package/dist/meeting/state.js +30 -30
- package/dist/meeting/state.js.map +1 -1
- package/dist/meeting/util.d.ts +2 -2
- package/dist/meeting/util.js.map +1 -1
- package/dist/meeting-info/collection.d.ts +20 -20
- package/dist/meeting-info/collection.js +11 -11
- package/dist/meeting-info/collection.js.map +1 -1
- package/dist/meeting-info/index.d.ts +57 -57
- package/dist/meeting-info/index.js +50 -50
- package/dist/meeting-info/index.js.map +1 -1
- package/dist/meeting-info/meeting-info-v2.d.ts +93 -93
- package/dist/meeting-info/meeting-info-v2.js +52 -52
- package/dist/meeting-info/meeting-info-v2.js.map +1 -1
- package/dist/meeting-info/request.d.ts +22 -22
- package/dist/meeting-info/request.js +14 -14
- package/dist/meeting-info/request.js.map +1 -1
- package/dist/meeting-info/util.d.ts +2 -2
- package/dist/meeting-info/util.js +9 -9
- package/dist/meeting-info/util.js.map +1 -1
- package/dist/meeting-info/utilv2.d.ts +2 -2
- package/dist/meeting-info/utilv2.js +20 -20
- package/dist/meeting-info/utilv2.js.map +1 -1
- package/dist/meetings/collection.d.ts +23 -23
- package/dist/meetings/collection.js +14 -14
- package/dist/meetings/collection.js.map +1 -1
- package/dist/meetings/index.d.ts +296 -296
- package/dist/meetings/index.js +259 -259
- package/dist/meetings/index.js.map +1 -1
- package/dist/meetings/request.d.ts +27 -27
- package/dist/meetings/request.js +15 -15
- package/dist/meetings/request.js.map +1 -1
- package/dist/meetings/util.d.ts +18 -18
- package/dist/meetings/util.js +29 -29
- package/dist/meetings/util.js.map +1 -1
- package/dist/member/index.d.ts +147 -147
- package/dist/member/index.js +214 -214
- package/dist/member/index.js.map +1 -1
- package/dist/member/member.types.d.ts +11 -11
- package/dist/member/member.types.js.map +1 -1
- package/dist/member/util.d.ts +2 -2
- package/dist/member/util.js +60 -60
- package/dist/member/util.js.map +1 -1
- package/dist/members/collection.d.ts +24 -24
- package/dist/members/collection.js +11 -11
- package/dist/members/collection.js.map +1 -1
- package/dist/members/index.d.ts +298 -298
- package/dist/members/index.js +275 -275
- package/dist/members/index.js.map +1 -1
- package/dist/members/request.d.ts +50 -50
- package/dist/members/request.js +27 -27
- package/dist/members/request.js.map +1 -1
- package/dist/members/util.d.ts +2 -2
- package/dist/members/util.js +21 -21
- package/dist/members/util.js.map +1 -1
- package/dist/metrics/config.d.ts +169 -169
- package/dist/metrics/config.js.map +1 -1
- package/dist/metrics/constants.d.ts +57 -57
- package/dist/metrics/constants.js.map +1 -1
- package/dist/metrics/index.d.ts +152 -152
- package/dist/metrics/index.js +90 -90
- package/dist/metrics/index.js.map +1 -1
- package/dist/networkQualityMonitor/index.d.ts +70 -70
- package/dist/networkQualityMonitor/index.js +65 -65
- package/dist/networkQualityMonitor/index.js.map +1 -1
- package/dist/peer-connection-manager/index.d.ts +6 -6
- package/dist/peer-connection-manager/index.js +87 -87
- package/dist/peer-connection-manager/index.js.map +1 -1
- package/dist/peer-connection-manager/util.d.ts +6 -6
- package/dist/peer-connection-manager/util.js +9 -9
- package/dist/peer-connection-manager/util.js.map +1 -1
- package/dist/personal-meeting-room/index.d.ts +47 -47
- package/dist/personal-meeting-room/index.js +67 -67
- package/dist/personal-meeting-room/index.js.map +1 -1
- package/dist/personal-meeting-room/request.d.ts +14 -14
- package/dist/personal-meeting-room/request.js +7 -7
- package/dist/personal-meeting-room/request.js.map +1 -1
- package/dist/personal-meeting-room/util.d.ts +2 -2
- package/dist/personal-meeting-room/util.js.map +1 -1
- package/dist/reachability/index.d.ts +139 -139
- package/dist/reachability/index.js +110 -110
- package/dist/reachability/index.js.map +1 -1
- package/dist/reachability/request.d.ts +35 -35
- package/dist/reachability/request.js +15 -15
- package/dist/reachability/request.js.map +1 -1
- package/dist/reactions/reactions.d.ts +4 -4
- package/dist/reactions/reactions.js.map +1 -1
- package/dist/reactions/reactions.type.d.ts +32 -32
- package/dist/reactions/reactions.type.js.map +1 -1
- package/dist/reconnection-manager/index.d.ts +112 -112
- package/dist/reconnection-manager/index.js +112 -112
- package/dist/reconnection-manager/index.js.map +1 -1
- package/dist/recording-controller/enums.d.ts +7 -7
- package/dist/recording-controller/enums.js.map +1 -1
- package/dist/recording-controller/index.d.ts +193 -193
- package/dist/recording-controller/index.js +127 -127
- package/dist/recording-controller/index.js.map +1 -1
- package/dist/recording-controller/util.d.ts +13 -13
- package/dist/recording-controller/util.js.map +1 -1
- package/dist/roap/collection.d.ts +10 -10
- package/dist/roap/collection.js.map +1 -1
- package/dist/roap/handler.d.ts +47 -47
- package/dist/roap/handler.js +27 -27
- package/dist/roap/handler.js.map +1 -1
- package/dist/roap/index.d.ts +116 -116
- package/dist/roap/index.js +111 -111
- package/dist/roap/index.js.map +1 -1
- package/dist/roap/request.d.ts +35 -35
- package/dist/roap/request.js +17 -17
- package/dist/roap/request.js.map +1 -1
- package/dist/roap/state.d.ts +9 -9
- package/dist/roap/state.js +14 -14
- package/dist/roap/state.js.map +1 -1
- package/dist/roap/turnDiscovery.d.ts +67 -67
- package/dist/roap/turnDiscovery.js +46 -46
- package/dist/roap/turnDiscovery.js.map +1 -1
- package/dist/roap/util.d.ts +2 -2
- package/dist/roap/util.js.map +1 -1
- package/dist/statsAnalyzer/global.d.ts +126 -116
- package/dist/statsAnalyzer/global.js +10 -0
- package/dist/statsAnalyzer/global.js.map +1 -1
- package/dist/statsAnalyzer/index.d.ts +190 -191
- package/dist/statsAnalyzer/index.js +137 -139
- package/dist/statsAnalyzer/index.js.map +1 -1
- package/dist/statsAnalyzer/mqaUtil.d.ts +22 -22
- package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
- package/dist/transcription/index.d.ts +64 -64
- package/dist/transcription/index.js +42 -42
- package/dist/transcription/index.js.map +1 -1
- package/internal-README.md +172 -172
- package/jest.config.js +3 -3
- package/package.json +22 -21
- package/process +1 -1
- package/src/common/browser-detection.ts +39 -39
- package/src/common/collection.ts +94 -94
- package/src/common/config.ts +9 -9
- package/src/common/errors/captcha-error.ts +25 -25
- package/src/common/errors/intent-to-join.ts +27 -27
- package/src/common/errors/join-meeting.ts +32 -32
- package/src/common/errors/media.ts +25 -25
- package/src/common/errors/parameter.ts +33 -33
- package/src/common/errors/password-error.ts +25 -25
- package/src/common/errors/permission.ts +24 -24
- package/src/common/errors/reconnection-in-progress.ts +8 -8
- package/src/common/errors/reconnection.ts +25 -25
- package/src/common/errors/stats.ts +25 -25
- package/src/common/errors/webex-errors.ts +140 -140
- package/src/common/errors/webex-meetings-error.ts +35 -35
- package/src/common/events/events-scope.ts +30 -30
- package/src/common/events/events.ts +25 -25
- package/src/common/events/trigger-proxy.ts +25 -25
- package/src/common/events/util.ts +39 -39
- package/src/common/logs/logger-config.ts +8 -8
- package/src/common/logs/logger-proxy.ts +44 -44
- package/src/common/logs/request.ts +65 -65
- package/src/common/queue.ts +50 -50
- package/src/config.ts +96 -96
- package/src/constants.ts +1121 -1121
- package/src/controls-options-manager/constants.ts +5 -5
- package/src/controls-options-manager/enums.ts +6 -6
- package/src/controls-options-manager/index.ts +183 -183
- package/src/controls-options-manager/util.ts +20 -20
- package/src/index.js +15 -15
- package/src/locus-info/controlsUtils.ts +112 -112
- package/src/locus-info/embeddedAppsUtils.ts +57 -57
- package/src/locus-info/fullState.ts +69 -69
- package/src/locus-info/hostUtils.ts +60 -60
- package/src/locus-info/index.ts +1303 -1303
- package/src/locus-info/infoUtils.ts +101 -101
- package/src/locus-info/mediaSharesUtils.ts +173 -173
- package/src/locus-info/parser.ts +680 -680
- package/src/locus-info/selfUtils.ts +428 -428
- package/src/media/index.ts +675 -675
- package/src/media/properties.ts +313 -313
- package/src/media/util.ts +37 -37
- package/src/mediaQualityMetrics/config.ts +382 -382
- package/src/meeting/effectsState.ts +209 -209
- package/src/meeting/in-meeting-actions.ts +153 -153
- package/src/meeting/index.ts +6537 -6543
- package/src/meeting/muteState.ts +365 -365
- package/src/meeting/request.ts +810 -810
- package/src/meeting/state.ts +194 -194
- package/src/meeting/util.ts +530 -530
- package/src/meeting-info/collection.ts +41 -41
- package/src/meeting-info/index.ts +137 -137
- package/src/meeting-info/meeting-info-v2.ts +273 -273
- package/src/meeting-info/request.ts +46 -46
- package/src/meeting-info/util.ts +314 -314
- package/src/meeting-info/utilv2.ts +324 -324
- package/src/meetings/collection.ts +43 -43
- package/src/meetings/index.ts +1128 -1128
- package/src/meetings/request.ts +81 -81
- package/src/meetings/util.ts +181 -181
- package/src/member/index.ts +446 -446
- package/src/member/member.types.ts +13 -13
- package/src/member/util.ts +286 -286
- package/src/members/collection.ts +40 -40
- package/src/members/index.ts +900 -900
- package/src/members/request.ts +175 -175
- package/src/members/util.ts +260 -260
- package/src/metrics/config.ts +485 -485
- package/src/metrics/constants.ts +61 -61
- package/src/metrics/index.ts +543 -543
- package/src/networkQualityMonitor/index.ts +211 -211
- package/src/peer-connection-manager/index.ts +847 -847
- package/src/peer-connection-manager/util.ts +119 -119
- package/src/personal-meeting-room/index.ts +157 -157
- package/src/personal-meeting-room/request.ts +48 -48
- package/src/personal-meeting-room/util.ts +49 -49
- package/src/reachability/index.ts +478 -478
- package/src/reachability/request.ts +81 -81
- package/src/reactions/reactions.ts +104 -104
- package/src/reactions/reactions.type.ts +36 -36
- package/src/reconnection-manager/index.ts +622 -622
- package/src/recording-controller/enums.ts +8 -8
- package/src/recording-controller/index.ts +315 -315
- package/src/recording-controller/util.ts +58 -58
- package/src/roap/collection.ts +62 -62
- package/src/roap/handler.ts +294 -294
- package/src/roap/index.ts +413 -413
- package/src/roap/request.ts +229 -229
- package/src/roap/state.ts +156 -156
- package/src/roap/turnDiscovery.ts +283 -283
- package/src/roap/util.ts +100 -100
- package/src/statsAnalyzer/global.ts +128 -118
- package/src/statsAnalyzer/index.ts +1266 -1265
- package/src/statsAnalyzer/mqaUtil.ts +290 -290
- package/src/transcription/index.ts +154 -154
- package/test/integration/spec/journey.js +941 -941
- package/test/integration/spec/space-meeting.js +457 -457
- package/test/integration/spec/transcription.js +55 -55
- package/test/unit/spec/common/browser-detection.js +119 -119
- package/test/unit/spec/common/queue.js +69 -69
- package/test/unit/spec/controls-options-manager/index.js +123 -123
- package/test/unit/spec/controls-options-manager/util.js +65 -65
- package/test/unit/spec/fixture/locus.js +406 -406
- package/test/unit/spec/locus-info/controlsUtils.js +82 -82
- package/test/unit/spec/locus-info/embeddedAppsUtils.js +104 -104
- package/test/unit/spec/locus-info/index.js +1272 -1272
- package/test/unit/spec/locus-info/infoUtils.js +138 -138
- package/test/unit/spec/locus-info/lib/BasicSeqCmp.json +975 -975
- package/test/unit/spec/locus-info/lib/SeqCmp.json +522 -522
- package/test/unit/spec/locus-info/lib/selfConstant.js +286 -286
- package/test/unit/spec/locus-info/parser.js +298 -298
- package/test/unit/spec/locus-info/selfUtils.js +185 -185
- package/test/unit/spec/media/properties.ts +305 -305
- package/test/unit/spec/meeting/effectsState.js +281 -281
- package/test/unit/spec/meeting/in-meeting-actions.ts +90 -90
- package/test/unit/spec/meeting/index.js +5227 -5227
- package/test/unit/spec/meeting/muteState.js +430 -430
- package/test/unit/spec/meeting/request.js +317 -317
- package/test/unit/spec/meeting/utils.js +319 -319
- package/test/unit/spec/meeting-info/meetinginfov2.js +376 -376
- package/test/unit/spec/meeting-info/request.js +64 -64
- package/test/unit/spec/meeting-info/util.js +37 -37
- package/test/unit/spec/meeting-info/utilv2.js +330 -330
- package/test/unit/spec/meetings/collection.js +52 -52
- package/test/unit/spec/meetings/index.js +1375 -1375
- package/test/unit/spec/meetings/utils.js +66 -66
- package/test/unit/spec/member/index.js +47 -47
- package/test/unit/spec/member/util.js +80 -80
- package/test/unit/spec/members/index.js +364 -364
- package/test/unit/spec/members/request.js +200 -200
- package/test/unit/spec/members/utils.js +42 -42
- package/test/unit/spec/metrics/index.js +111 -111
- package/test/unit/spec/networkQualityMonitor/index.js +99 -99
- package/test/unit/spec/peerconnection-manager/index.js +218 -218
- package/test/unit/spec/peerconnection-manager/utils.js +49 -49
- package/test/unit/spec/peerconnection-manager/utils.test-fixtures.ts +388 -388
- package/test/unit/spec/personal-meeting-room/personal-meeting-room.js +29 -29
- package/test/unit/spec/reachability/index.ts +50 -50
- package/test/unit/spec/reconnection-manager/index.js +206 -206
- package/test/unit/spec/recording-controller/index.js +230 -230
- package/test/unit/spec/recording-controller/util.js +101 -101
- package/test/unit/spec/roap/index.ts +128 -128
- package/test/unit/spec/roap/turnDiscovery.ts +372 -372
- package/test/unit/spec/roap/util.js +30 -30
- package/test/unit/spec/stats-analyzer/index.js +287 -355
- package/test/utils/cmr.js +104 -104
- package/test/utils/testUtils.js +287 -287
- package/test/utils/webex-config.js +77 -77
- package/test/utils/webex-test-users.js +82 -82
- package/tsconfig.json +5 -5
package/README.md
CHANGED
|
@@ -1,1204 +1,1204 @@
|
|
|
1
|
-
# @webex/plugin-meetings
|
|
2
|
-
|
|
3
|
-
[](https://github.com/RichardLitt/standard-readme)
|
|
4
|
-
|
|
5
|
-
> Meetings plugin for the Cisco Webex JS SDK.
|
|
6
|
-
|
|
7
|
-
- [Install](#install)
|
|
8
|
-
- [Usage](#usage)
|
|
9
|
-
- [Important Changes](#important-changes)
|
|
10
|
-
- [Development](#development)
|
|
11
|
-
- [Contribute](#contribute)
|
|
12
|
-
- [Maintainers](#maintainers)
|
|
13
|
-
- [License](#license)
|
|
14
|
-
|
|
15
|
-
# WARNING: This plugin is currently under active development
|
|
16
|
-
|
|
17
|
-
## Install
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
npm install --save @webex/plugin-meetings
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
## Usage
|
|
24
|
-
|
|
25
|
-
This is a plugin for the Cisco Webex JS SDK . Please see our [developer portal](https://developer.webex.com/) and the [API docs](https://webex.github.io/webex-js-sdk/api/) for full details.
|
|
26
|
-
|
|
27
|
-
## Important Changes
|
|
28
|
-
|
|
29
|
-
- Version `0.109.0` - Participant email has been removed to reduce PII. Please use participant identity (`members.membersCollection.members[id].participant.identity`) to lookup participant details via the [/people](https://developer.webex.com/docs/api/v1/people/get-person-details) endpoint.
|
|
30
|
-
|
|
31
|
-
## API Docs and Sample App
|
|
32
|
-
|
|
33
|
-
API Docs: https://webex.github.io/webex-js-sdk/api/
|
|
34
|
-
Hosted Sample App: https://webex.github.io/webex-js-sdk/samples/browser-plugin-meetings/
|
|
35
|
-
See https://github.com/webex/webex-js-sdk/tree/master/docs/samples/browser-plugin-meetings for the sample app code vs the readme
|
|
36
|
-
|
|
37
|
-
#### Device Registration
|
|
38
|
-
|
|
39
|
-
The meetings plugin relies on websocket data to function. The user's device needs to register and connect to the web socket server.
|
|
40
|
-
|
|
41
|
-
These setup actions are handled with the `register` function.
|
|
42
|
-
|
|
43
|
-
This function registers the device, connects web sockets, and listens for meeting events.
|
|
44
|
-
|
|
45
|
-
```js
|
|
46
|
-
webex.meetings.register();
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
#### Device Unregistration
|
|
50
|
-
|
|
51
|
-
The inverse of the `register()` function is available as well.
|
|
52
|
-
This function stops listening for meeting events, disconnects from web sockets and unregisters the device.
|
|
53
|
-
|
|
54
|
-
```js
|
|
55
|
-
webex.meetings.unregister();
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
#### Creating a basic meeting
|
|
59
|
-
|
|
60
|
-
##### Via [developer portal room id](https://developer.webex.com/docs/api/v1/rooms)
|
|
61
|
-
|
|
62
|
-
```javascript
|
|
63
|
-
let roomId = `Y2lzY29zcGFyazovL3VzL1JPT00vNWZhMWUzODAtZTkzZS0xMWU5LTgyZTEtOGRmYTg5ZTgzMjJm `;
|
|
64
|
-
return webex.meetings.create(roomId).then((meeting) ==> {...});
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
##### Via [developer portal people id](https://developer.webex.com/docs/api/v1/people)
|
|
68
|
-
|
|
69
|
-
```javascript
|
|
70
|
-
let peopleId = `Y2lzY29zcGFyazovL3VzL1BFT1BMRS8wMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDAw `;
|
|
71
|
-
return webex.meetings.create(peopleId).then((meeting) ==> {...});
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
##### Via conversation url
|
|
75
|
-
|
|
76
|
-
```javascript
|
|
77
|
-
let conversationUrl = `https://conv-a.wbx2.com/conversation/api/v1/ObiwanAnnouncementsConversationUUID`;
|
|
78
|
-
return webex.meetings.create(conversationUrl).then((meeting) ==> {...});
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
##### Via SIP URI
|
|
82
|
-
|
|
83
|
-
```javascript
|
|
84
|
-
let sipUri = `obiwan@example.com`;
|
|
85
|
-
return webex.meetings.create(sipUri).then((meeting) ==> {...});
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
##### Via Locus Object
|
|
89
|
-
|
|
90
|
-
```javascript
|
|
91
|
-
// unlikely to be used
|
|
92
|
-
return webex.meetings.create(locusObj, 'LOCUS_ID').then((meeting) ==> {...});
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
#### Meetings
|
|
96
|
-
|
|
97
|
-
##### List Active Meetings
|
|
98
|
-
|
|
99
|
-
We want to sync our meetings collection with the server.
|
|
100
|
-
|
|
101
|
-
```js
|
|
102
|
-
let existingMeetings;
|
|
103
|
-
// Sync Meetings From Server
|
|
104
|
-
webex.meetings.syncMeetings().then(() => {
|
|
105
|
-
// Existing meetings live in the meeting collection
|
|
106
|
-
existingMeetings = webex.meetings.getAllMeetings();
|
|
107
|
-
});
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
##### Get a Meeting
|
|
111
|
-
|
|
112
|
-
```js
|
|
113
|
-
webex.meetings.getMeetingByType('SIP_URI', sipUri);
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
##### Properties
|
|
117
|
-
|
|
118
|
-
```js
|
|
119
|
-
webex.meetings.personalMeetingRoom; // the personal meeting room instance
|
|
120
|
-
webex.meetings.reachability; // the reachability instance, not initialized until after setReachability is called
|
|
121
|
-
webex.meetings.meetingCollection; // the collection of meetings instance
|
|
122
|
-
webex.meetings.meetingInfo; // the meeting info instance
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
##### Media
|
|
126
|
-
|
|
127
|
-
After a meeting is created and joined, the media from the meeting needs to be connected.
|
|
128
|
-
|
|
129
|
-
###### Local Media
|
|
130
|
-
|
|
131
|
-
To get the local device media we use the function on the meeting object `getMediaStreams`. This takes an options object of which media streams to enable:
|
|
132
|
-
|
|
133
|
-
```js
|
|
134
|
-
const mediaSettings = {
|
|
135
|
-
receiveVideo: true,
|
|
136
|
-
receiveAudio: true,
|
|
137
|
-
receiveShare: true,
|
|
138
|
-
sendVideo: true,
|
|
139
|
-
sendAudio: true,
|
|
140
|
-
sendShare: false,
|
|
141
|
-
};
|
|
142
|
-
|
|
143
|
-
const myStreams = {};
|
|
144
|
-
meeting
|
|
145
|
-
.getMediaStreams(mediaSettings)
|
|
146
|
-
.then(([localStream, localShare]) => {
|
|
147
|
-
return {localStream, localShare};
|
|
148
|
-
})
|
|
149
|
-
.then((streams) => {
|
|
150
|
-
myStreams.localStream = streams.localStream;
|
|
151
|
-
myStreams.localShare = streams.localShare;
|
|
152
|
-
});
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
This local stream is now ready to be added to the DOM for a self preview via:
|
|
156
|
-
|
|
157
|
-
```html
|
|
158
|
-
<video id="localvideo" muted="true" autoplay playsinline></video>
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
```js
|
|
162
|
-
document.getElementById('localvideo').srcObject = myStreams.localStream;
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
##### Add Media
|
|
166
|
-
|
|
167
|
-
Once you have your local streams and shares, you need to add the media to the meeting with the `addMedia` function.
|
|
168
|
-
|
|
169
|
-
```js
|
|
170
|
-
meeting
|
|
171
|
-
.addMedia({
|
|
172
|
-
localShare,
|
|
173
|
-
localStream,
|
|
174
|
-
mediaSettings,
|
|
175
|
-
})
|
|
176
|
-
.then((mediaResponse) => {
|
|
177
|
-
// do something once you know media has been completed
|
|
178
|
-
});
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
#### Join a meeting
|
|
182
|
-
|
|
183
|
-
##### Basic Join
|
|
184
|
-
|
|
185
|
-
One can join a meeting without adding a media to just be present in the meeting without send/receive
|
|
186
|
-
Once a meeting object has been created, to start it, simply `join` it.
|
|
187
|
-
|
|
188
|
-
```javascript
|
|
189
|
-
let destination = `obiwan@example.com`; // email example
|
|
190
|
-
return webex.meetings.create(destination).then((meeting) => {
|
|
191
|
-
activeMeeting = meeting;
|
|
192
|
-
// attach listeners or other actions
|
|
193
|
-
activeMeeting.join().then(() => {
|
|
194
|
-
// now the meeting is joined!
|
|
195
|
-
// now you can addMedia
|
|
196
|
-
});
|
|
197
|
-
});
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
##### Full Example
|
|
201
|
-
|
|
202
|
-
```javascript
|
|
203
|
-
let activeMeeting;
|
|
204
|
-
|
|
205
|
-
const mediaSettings = {
|
|
206
|
-
receiveVideo: true,
|
|
207
|
-
receiveAudio: true,
|
|
208
|
-
receiveShare: true,
|
|
209
|
-
sendVideo: true,
|
|
210
|
-
sendAudio: true,
|
|
211
|
-
sendShare: false
|
|
212
|
-
};
|
|
213
|
-
|
|
214
|
-
const myStreams = {}
|
|
215
|
-
|
|
216
|
-
function setMedia(media){
|
|
217
|
-
if (media.type === 'local') {
|
|
218
|
-
document.getElementById('<videoId>').srcObject = media.stream;
|
|
219
|
-
} else if (media.type === 'remote') {
|
|
220
|
-
document.getElementById('<videoId>').srcObject = media.stream;
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
function handleAudioChange(audio){
|
|
225
|
-
// perform some actions after audio has been muted/unmuted
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
function handleVideoChange(video) {
|
|
229
|
-
// perform some action after video has been muted/unmuted
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
return webex.meetings
|
|
233
|
-
.create(destination)
|
|
234
|
-
.then((meeting) => {
|
|
235
|
-
activeMeeting = meeting;
|
|
236
|
-
activeMeeting.getMediaStreams(mediaSettings).then(([localStream, localShare]) => {
|
|
237
|
-
return {localStream, localShare};
|
|
238
|
-
}).then((streams) => {
|
|
239
|
-
myStreams.localStream = streams.localStream
|
|
240
|
-
myStreams.localShare = streams.localShare
|
|
241
|
-
});
|
|
242
|
-
activeMeeting.on('media:ready', () => setMedia));
|
|
243
|
-
activeMeeting.on('media:audioChanged', handleAudioChange);
|
|
244
|
-
activeMeeting.on('media:videoChanged', handleVideoChange);
|
|
245
|
-
// join a meeting using resourceId as the destination, i.e., paired to a device and using the device for the call
|
|
246
|
-
activeMeeting.join({resourceId: <DeviceId>}).then((joinResponse) => {
|
|
247
|
-
activeMeeting.addMedia({
|
|
248
|
-
localShare,
|
|
249
|
-
localStream,
|
|
250
|
-
mediaSettings
|
|
251
|
-
}).then((mediaResponse) => {
|
|
252
|
-
// do something once you know media has been completed
|
|
253
|
-
});
|
|
254
|
-
});
|
|
255
|
-
});
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
##### Join a PMR
|
|
259
|
-
|
|
260
|
-
From above, we build off of the join...
|
|
261
|
-
|
|
262
|
-
##### Join your own claimed PMR
|
|
263
|
-
|
|
264
|
-
```javascript
|
|
265
|
-
...
|
|
266
|
-
meeting.join().then((res) => {
|
|
267
|
-
// backend services determine you are the owner, so no pin, or moderator flag is required
|
|
268
|
-
// now you are in the meeting
|
|
269
|
-
});
|
|
270
|
-
...
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
##### Join someone elses claimed PMR
|
|
274
|
-
|
|
275
|
-
```javascript
|
|
276
|
-
...
|
|
277
|
-
// join as host (in place of them)
|
|
278
|
-
meeting.join({pin: <WebexHostPin>, moderator: true}).then((res) => {
|
|
279
|
-
// now you are in the meeting
|
|
280
|
-
});
|
|
281
|
-
```
|
|
282
|
-
|
|
283
|
-
```javascript
|
|
284
|
-
...
|
|
285
|
-
// join as attendee
|
|
286
|
-
meeting.join({pin: <WebexMeetingPin>}).then((res) => {
|
|
287
|
-
// if host hasn't started the meeting, now you are in the lobby, else if host has started the meeting, you are in the meeting
|
|
288
|
-
});
|
|
289
|
-
```
|
|
290
|
-
|
|
291
|
-
##### Join an unclaimed PMR
|
|
292
|
-
|
|
293
|
-
```javascript
|
|
294
|
-
// join as host automatically
|
|
295
|
-
meeting.join({pin: <WebexHostPin>, moderator: true}).then((res) => {
|
|
296
|
-
// now you are in the meeting
|
|
297
|
-
});
|
|
298
|
-
```
|
|
299
|
-
|
|
300
|
-
```javascript
|
|
301
|
-
// join as host with ask user option
|
|
302
|
-
// join as attendee
|
|
303
|
-
meeting.join().then((res) => {
|
|
304
|
-
}).catch((err) => {
|
|
305
|
-
if (err.joinIntentRequired) {
|
|
306
|
-
// at this point you can ask the user to join as host or join as guest
|
|
307
|
-
// if join as host, requires a pin
|
|
308
|
-
...
|
|
309
|
-
// join as host simply makes the join call again with the proper pin/moderator parameters
|
|
310
|
-
meeting.join({pin: <WebexHostPin>, moderator: true}).then(() => {
|
|
311
|
-
// you are now in the meeting
|
|
312
|
-
});
|
|
313
|
-
...
|
|
314
|
-
// join as guest simply makes the call again with moderator parameter
|
|
315
|
-
meeting.join(({moderator: false})).then(() => {
|
|
316
|
-
// if host hasn't started the meeting, now you are in the lobby, else if host has started the meeting, you are in the meeting
|
|
317
|
-
});
|
|
318
|
-
}
|
|
319
|
-
});
|
|
320
|
-
```
|
|
321
|
-
|
|
322
|
-
##### Join an incoming meeting
|
|
323
|
-
|
|
324
|
-
When listening to an added meeting, to determine if it is an "incoming" meeting, check the type property of the meeting:
|
|
325
|
-
|
|
326
|
-
```js
|
|
327
|
-
webex.meetings.on('meeting:added', (addedMeeting) => {
|
|
328
|
-
if (addedMeeting.type === 'INCOMING') {
|
|
329
|
-
// Handle incoming meeting
|
|
330
|
-
addedMeeting.acknowledge();
|
|
331
|
-
addedMeeting.join().then(() => {});
|
|
332
|
-
}
|
|
333
|
-
```
|
|
334
|
-
|
|
335
|
-
##### Reject an incoming meeting
|
|
336
|
-
|
|
337
|
-
When listening to an added meeting, to determine if it is an "incoming" meeting, check the type property of the meeting:
|
|
338
|
-
|
|
339
|
-
```js
|
|
340
|
-
webex.meetings.on('meeting:added', (addedMeeting) => {
|
|
341
|
-
if (addedMeeting.type === 'INCOMING') {
|
|
342
|
-
// Handle incoming meeting
|
|
343
|
-
addedMeeting.decline();
|
|
344
|
-
}
|
|
345
|
-
```
|
|
346
|
-
|
|
347
|
-
#### Enable receiving meeting real-time transcripts
|
|
348
|
-
|
|
349
|
-
In order to receive meeting transcripts, Webex assistant must be enabled for the meeting.
|
|
350
|
-
|
|
351
|
-
```javascript
|
|
352
|
-
...
|
|
353
|
-
// Subscribe to transcription events
|
|
354
|
-
meeting.on('meeting:receiveTranscription:started', (payload) => {
|
|
355
|
-
console.log(payload);
|
|
356
|
-
});
|
|
357
|
-
|
|
358
|
-
meeting.on('meeting:receiveTranscription:stopped', () => {});
|
|
359
|
-
|
|
360
|
-
await meeting.join({receiveTranscription: true});
|
|
361
|
-
```
|
|
362
|
-
|
|
363
|
-
##### Microphone, Speaker and Camera
|
|
364
|
-
|
|
365
|
-
Select a different device than the default:
|
|
366
|
-
|
|
367
|
-
```js
|
|
368
|
-
const audioInputSelect = document.querySelector('select#audioSource');
|
|
369
|
-
const audioOutputSelect = document.querySelector('select#audioOutput');
|
|
370
|
-
const videoSelect = document.querySelector('select#videoSource');
|
|
371
|
-
```
|
|
372
|
-
|
|
373
|
-
```js
|
|
374
|
-
const audio = {};
|
|
375
|
-
const video = {};
|
|
376
|
-
const media = {
|
|
377
|
-
receiveVideo: boolean,
|
|
378
|
-
receiveAudio: boolean,
|
|
379
|
-
receiveShare: boolean,
|
|
380
|
-
sendShare: boolean,
|
|
381
|
-
sendVideo: boolean,
|
|
382
|
-
sendAudio: boolean
|
|
383
|
-
};
|
|
384
|
-
|
|
385
|
-
// setting up the devices
|
|
386
|
-
const selectors = [audioInputSelect, audioOutputSelect, videoSelect];
|
|
387
|
-
|
|
388
|
-
meeting.getDevices().then((deviceInfos) => {
|
|
389
|
-
const values = selectors.map((select) => select.value);
|
|
390
|
-
|
|
391
|
-
selectors.forEach((select) => {
|
|
392
|
-
while (select.firstChild) {
|
|
393
|
-
select.removeChild(select.firstChild);
|
|
394
|
-
}
|
|
395
|
-
});
|
|
396
|
-
for (let i = 0; i !== deviceInfos.length; i += 1) {
|
|
397
|
-
const deviceInfo = deviceInfos[i];
|
|
398
|
-
const option = document.createElement('option');
|
|
399
|
-
|
|
400
|
-
option.value = deviceInfo.deviceId;
|
|
401
|
-
if (deviceInfo.kind === 'audioinput') {
|
|
402
|
-
option.text = deviceInfo.label || `microphone ${audioInputSelect.length + 1}`;
|
|
403
|
-
audioInputSelect.appendChild(option);
|
|
404
|
-
}
|
|
405
|
-
else if (deviceInfo.kind === 'audiooutput') {
|
|
406
|
-
option.text = deviceInfo.label || `speaker ${audioOutputSelect.length + 1}`;
|
|
407
|
-
audioOutputSelect.appendChild(option);
|
|
408
|
-
}
|
|
409
|
-
else if (deviceInfo.kind === 'videoinput') {
|
|
410
|
-
option.text = deviceInfo.label || `camera ${videoSelect.length + 1}`;
|
|
411
|
-
videoSelect.appendChild(option);
|
|
412
|
-
}
|
|
413
|
-
else {
|
|
414
|
-
console.log('Some other kind of source/device: ', deviceInfo);
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
selectors.forEach((select, selectorIndex) => {
|
|
418
|
-
if (Array.prototype.slice.call(select.childNodes).some((n) => n.value === values[selectorIndex])) {
|
|
419
|
-
select.value = values[selectorIndex];
|
|
420
|
-
}
|
|
421
|
-
});
|
|
422
|
-
|
|
423
|
-
// attaching before the request
|
|
424
|
-
|
|
425
|
-
audio.deviceId = {exact: audioInputSelect.value}
|
|
426
|
-
video.deviceId = {exact: videoSelect.value}
|
|
427
|
-
meeting.getMediaStreams(media, {audio, video}).then(...)
|
|
428
|
-
```
|
|
429
|
-
|
|
430
|
-
###### Changing remote audio output
|
|
431
|
-
|
|
432
|
-
```js
|
|
433
|
-
// Attach audio output device to video element using device/sink ID.
|
|
434
|
-
function attachSinkId(element, sinkId) {
|
|
435
|
-
if (typeof element.sinkId !== 'undefined') {
|
|
436
|
-
element
|
|
437
|
-
.setSinkId(sinkId)
|
|
438
|
-
.then(() => {
|
|
439
|
-
console.log(`Success, audio output device attached: ${sinkId}`);
|
|
440
|
-
})
|
|
441
|
-
.catch((error) => {
|
|
442
|
-
let errorMessage = error;
|
|
443
|
-
|
|
444
|
-
if (error.name === 'SecurityError') {
|
|
445
|
-
errorMessage = `You need to use HTTPS for selecting audio output device: ${error}`;
|
|
446
|
-
}
|
|
447
|
-
console.error(errorMessage);
|
|
448
|
-
// Jump back to first output device in the list as it's the default.
|
|
449
|
-
audioOutputSelect.selectedIndex = 0;
|
|
450
|
-
});
|
|
451
|
-
} else {
|
|
452
|
-
console.warn('Browser does not support output device selection.');
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
audioOutputSelect.onchange = function () {
|
|
457
|
-
attachSinkId(document.getElementById('remoteaudio'), audioOutputSelect.value);
|
|
458
|
-
};
|
|
459
|
-
```
|
|
460
|
-
|
|
461
|
-
##### Record
|
|
462
|
-
|
|
463
|
-
```js
|
|
464
|
-
// you can only pause if recording
|
|
465
|
-
// you can only start recording if not recording
|
|
466
|
-
// you can only resume recording if paused
|
|
467
|
-
// you can only pause recording if started
|
|
468
|
-
meeting.startRecording();
|
|
469
|
-
meeting.pauseRecording();
|
|
470
|
-
meeting.resumeRecording();
|
|
471
|
-
meeting.stopRecording();
|
|
472
|
-
// note, all recording is done in the cloud
|
|
473
|
-
// local recording is not yet available for this package
|
|
474
|
-
// but is technically possible
|
|
475
|
-
// please submit a feature request if desired :)
|
|
476
|
-
// https://github.com/webex/webex-js-sdk/blob/master/CONTRIBUTING.md
|
|
477
|
-
```
|
|
478
|
-
|
|
479
|
-
##### Mute Audio or Video
|
|
480
|
-
|
|
481
|
-
```js
|
|
482
|
-
meeting.muteAudio();
|
|
483
|
-
meeting.muteVideo();
|
|
484
|
-
```
|
|
485
|
-
|
|
486
|
-
##### Unmute Audio or Video
|
|
487
|
-
|
|
488
|
-
```js
|
|
489
|
-
meeting.unmuteAudio();
|
|
490
|
-
meeting.unmuteVideo();
|
|
491
|
-
```
|
|
492
|
-
|
|
493
|
-
##### Start Sending a Share
|
|
494
|
-
|
|
495
|
-
```js
|
|
496
|
-
meeting.shareScreen();
|
|
497
|
-
```
|
|
498
|
-
|
|
499
|
-
##### Stop Sending a Share
|
|
500
|
-
|
|
501
|
-
```js
|
|
502
|
-
meeting.stopShare();
|
|
503
|
-
```
|
|
504
|
-
|
|
505
|
-
##### Update Audio/Video Streams
|
|
506
|
-
|
|
507
|
-
Use this if you want to change the actual streams send and receive for audio or video component separately; `updateAudio` and `updateVideo` is for the developer to add and remove the streams completely.
|
|
508
|
-
|
|
509
|
-
```js
|
|
510
|
-
//video
|
|
511
|
-
if (media.sendVideo) {
|
|
512
|
-
meeting
|
|
513
|
-
.getMediaStreams(
|
|
514
|
-
{sendVideo: true},
|
|
515
|
-
{video: videoSelect.value ? {deviceId: {exact: videoSelect.value}} : media.sendVideo}
|
|
516
|
-
)
|
|
517
|
-
.then(([localStream]) =>
|
|
518
|
-
meeting.updateVideo({
|
|
519
|
-
stream: localStream,
|
|
520
|
-
sendVideo: media.sendVideo,
|
|
521
|
-
receiveVideo: media.receiveVideo,
|
|
522
|
-
})
|
|
523
|
-
);
|
|
524
|
-
} else {
|
|
525
|
-
meeting.updateVideo({
|
|
526
|
-
sendVideo: media.sendVideo,
|
|
527
|
-
receiveVideo: media.receiveVideo,
|
|
528
|
-
});
|
|
529
|
-
}
|
|
530
|
-
//audio
|
|
531
|
-
if (media.sendAudio) {
|
|
532
|
-
meeting
|
|
533
|
-
.getMediaStreams(media, {
|
|
534
|
-
audio: audioInputSelect.value ? {deviceId: {exact: audioInputSelect.value}} : media.sendAudio,
|
|
535
|
-
})
|
|
536
|
-
.then(([localStream]) =>
|
|
537
|
-
meeting.updateAudio({
|
|
538
|
-
stream: localStream,
|
|
539
|
-
sendAudio: media.sendAudio,
|
|
540
|
-
receiveAudio: media.receiveAudio,
|
|
541
|
-
})
|
|
542
|
-
);
|
|
543
|
-
} else {
|
|
544
|
-
meeting.updateAudio({
|
|
545
|
-
sendAudio: media.sendAudio,
|
|
546
|
-
receiveAudio: media.receiveAudio,
|
|
547
|
-
});
|
|
548
|
-
}
|
|
549
|
-
//all in one
|
|
550
|
-
meeting.getMediaStreams(media, {audio, video}).then(([localStream, localShare]) =>
|
|
551
|
-
meeting.updateMedia({
|
|
552
|
-
mediaSettings: media,
|
|
553
|
-
localStream,
|
|
554
|
-
localShare,
|
|
555
|
-
})
|
|
556
|
-
);
|
|
557
|
-
```
|
|
558
|
-
|
|
559
|
-
##### Accessing media directly (outside of a meeting)
|
|
560
|
-
|
|
561
|
-
You can also directly access the following media properties that are not on a meeting instance
|
|
562
|
-
|
|
563
|
-
```
|
|
564
|
-
this.media.getUserMedia(mediaSetting, audioVideo, sharePreferences, config)
|
|
565
|
-
```
|
|
566
|
-
|
|
567
|
-
See the [Media](https://github.com/webex/webex-js-sdk/blob/master/packages/node_modules/%40webex/plugin-meetings/src/media/index.js) util file for method signatures.
|
|
568
|
-
|
|
569
|
-
##### Leave a Meeting
|
|
570
|
-
|
|
571
|
-
To leave a meeting, simply call leave
|
|
572
|
-
|
|
573
|
-
```js
|
|
574
|
-
myMeeting.leave();
|
|
575
|
-
```
|
|
576
|
-
|
|
577
|
-
##### Lock/Unlock a Meeting
|
|
578
|
-
|
|
579
|
-
```js
|
|
580
|
-
meeting.lockMeeting();
|
|
581
|
-
meeting.unlockMeeting();
|
|
582
|
-
```
|
|
583
|
-
|
|
584
|
-
##### Transfer Host
|
|
585
|
-
|
|
586
|
-
```js
|
|
587
|
-
const hostMemberId = ...;
|
|
588
|
-
meeting.transfer(hostMemberId);
|
|
589
|
-
```
|
|
590
|
-
|
|
591
|
-
##### Check User Actions
|
|
592
|
-
|
|
593
|
-
```js
|
|
594
|
-
meeting.inMeetingActions.get();
|
|
595
|
-
{
|
|
596
|
-
canInviteNewParticipants: boolean,
|
|
597
|
-
canAdmitParticipant: boolean,
|
|
598
|
-
canLock: boolean,
|
|
599
|
-
canUnlock: boolean,
|
|
600
|
-
canAssignHost: boolean,
|
|
601
|
-
canStartRecording: boolean,
|
|
602
|
-
canPauseRecording: boolean,
|
|
603
|
-
canResumeRecording: boolean,
|
|
604
|
-
canStopRecording: boolean,
|
|
605
|
-
canRaiseHand: boolean,
|
|
606
|
-
canLowerAllHands: boolean,
|
|
607
|
-
canLowerSomeoneElsesHand: boolean,
|
|
608
|
-
bothLeaveAndEndMeetingAvailable: boolean,
|
|
609
|
-
}
|
|
610
|
-
```
|
|
611
|
-
|
|
612
|
-
#### Personal Meeting Room
|
|
613
|
-
|
|
614
|
-
##### Edit Personal Meeting Room
|
|
615
|
-
|
|
616
|
-
```javascript
|
|
617
|
-
const link = ...; // a valid pmr link
|
|
618
|
-
const pin = ...; // a valid host pin assoicated to the link
|
|
619
|
-
// claiming a pmr, and updating the cached values for the stored PMR
|
|
620
|
-
webex.meetings.personalMeetingRoom.claim(link, pin).then((pmr) => {
|
|
621
|
-
console.log(pmr); // do something else with the pmr
|
|
622
|
-
});
|
|
623
|
-
```
|
|
624
|
-
|
|
625
|
-
##### Get Personal Meeting Room
|
|
626
|
-
|
|
627
|
-
```javascript
|
|
628
|
-
webex.meetings.personalMeetingRoom.get().then((pmr) => {
|
|
629
|
-
// do some stuff with the pmr values
|
|
630
|
-
console.log(`PMR INFO:
|
|
631
|
-
link-${webex.meetings.personalMeetingRoom.meetingLink}-
|
|
632
|
-
uri-${webex.meetings.personalMeetingRoom.sipUri}-
|
|
633
|
-
tollFree-${webex.meetings.personalMeetingRoom.pmr.callInNumbersInfo.callInTollFreeNumber.number}-
|
|
634
|
-
toll-${webex.meetings.personalMeetingRoom.pmr.callInNumbersInfo.callInTollNumber.number}-
|
|
635
|
-
accessCode-${webex.meetings.personalMeetingRoom.pmr.meetingNumber}
|
|
636
|
-
`);
|
|
637
|
-
});
|
|
638
|
-
```
|
|
639
|
-
|
|
640
|
-
#### Usage of Webex Devices
|
|
641
|
-
|
|
642
|
-
For details on how to use the devices see https://github.com/webex/webex-js-sdk/tree/master/packages/node_modules/%40webex/plugin-device-manager
|
|
643
|
-
|
|
644
|
-
##### Leave a Meeting Using a Device
|
|
645
|
-
|
|
646
|
-
```js
|
|
647
|
-
const resourceId = ...;
|
|
648
|
-
|
|
649
|
-
meeting.leave({resourceId}).then((res) => {
|
|
650
|
-
console.log(`successful leave with device, ${res}`);
|
|
651
|
-
});
|
|
652
|
-
```
|
|
653
|
-
|
|
654
|
-
##### Leave a Meeting While Paired to the Device, Keep Device in Meeting
|
|
655
|
-
|
|
656
|
-
```js
|
|
657
|
-
meeting.leave().then((res) => {
|
|
658
|
-
console.log(`successful leave, ${res}`);
|
|
659
|
-
});
|
|
660
|
-
```
|
|
661
|
-
|
|
662
|
-
##### Move Meeting To Paired Device
|
|
663
|
-
|
|
664
|
-
```js
|
|
665
|
-
const resourceId = ...
|
|
666
|
-
|
|
667
|
-
meeting.moveTo(resourceId).then((res) => {
|
|
668
|
-
console.log(`successful move to ${res}`);
|
|
669
|
-
});
|
|
670
|
-
}
|
|
671
|
-
```
|
|
672
|
-
|
|
673
|
-
##### Move Meeting from Paired Device
|
|
674
|
-
|
|
675
|
-
```js
|
|
676
|
-
const resourceId = ...
|
|
677
|
-
|
|
678
|
-
meeting.moveFrom(resourceId).then((res) => {
|
|
679
|
-
console.log(`successful move from ${res}`);
|
|
680
|
-
});
|
|
681
|
-
```
|
|
682
|
-
|
|
683
|
-
##### Start Wireless Share
|
|
684
|
-
|
|
685
|
-
```js
|
|
686
|
-
const deviceId = ...
|
|
687
|
-
// create the meeting
|
|
688
|
-
webex.meetings.create(deviceId).then((m) => {
|
|
689
|
-
// attach listeners
|
|
690
|
-
// then join the meeting
|
|
691
|
-
meeting.getMediaStreams({
|
|
692
|
-
sendAudio: false,
|
|
693
|
-
sendVideo: false,
|
|
694
|
-
sendShare: true
|
|
695
|
-
}))
|
|
696
|
-
.then(([localStream, localShare]) =>
|
|
697
|
-
meeting.addMedia({
|
|
698
|
-
mediaSettings: {
|
|
699
|
-
sendAudio: false,
|
|
700
|
-
sendVideo: false,
|
|
701
|
-
sendShare: true,
|
|
702
|
-
receiveShare: false,
|
|
703
|
-
receiveAudio: false,
|
|
704
|
-
receiveVideo: false
|
|
705
|
-
},
|
|
706
|
-
localShare,
|
|
707
|
-
localStream
|
|
708
|
-
}))
|
|
709
|
-
.catch((e) => {
|
|
710
|
-
meeting.leave();
|
|
711
|
-
console.error('Error wireless screen sharing', e);
|
|
712
|
-
});
|
|
713
|
-
}
|
|
714
|
-
```
|
|
715
|
-
|
|
716
|
-
##### End Wireless Share
|
|
717
|
-
|
|
718
|
-
```js
|
|
719
|
-
meeting.leave();
|
|
720
|
-
```
|
|
721
|
-
|
|
722
|
-
##### Reconnect a Meeting Media
|
|
723
|
-
|
|
724
|
-
Warning: not necessary to use manually, internally the sdk listens to mercury reconnect events to determine for a reconnection
|
|
725
|
-
|
|
726
|
-
```js
|
|
727
|
-
meeting.reconnect();
|
|
728
|
-
```
|
|
729
|
-
|
|
730
|
-
#### Scheduled Meetings
|
|
731
|
-
|
|
732
|
-
For scheduled meetings see https://github.com/webex/webex-js-sdk/tree/master/packages/node_modules/%40webex/internal-plugin-calendar
|
|
733
|
-
|
|
734
|
-
#### Member
|
|
735
|
-
|
|
736
|
-
##### Properties
|
|
737
|
-
|
|
738
|
-
```javascript
|
|
739
|
-
member.participant ... // Object server participant object, advanced use only
|
|
740
|
-
member.id ... // String key for storing
|
|
741
|
-
member.name ... // String plain text name
|
|
742
|
-
member.isAudioMuted ... // Boolean
|
|
743
|
-
member.isVideoMuted ... // Boolean
|
|
744
|
-
member.isHandRaised ... //Boolean
|
|
745
|
-
member.isSelf ... // Boolean is this member YOUR user?
|
|
746
|
-
member.isHost ... // Boolean
|
|
747
|
-
member.isGuest ... // Boolean
|
|
748
|
-
member.isInLobby ... // Boolean
|
|
749
|
-
member.isInMeeting ... // Boolean
|
|
750
|
-
member.isNotAdmitted ... // Boolean -- waiting to be admitted to the meeting, will also have isInLobby true
|
|
751
|
-
member.isContentSharing ... // Boolean
|
|
752
|
-
member.status ... // String -- advanced use only
|
|
753
|
-
member.isDevice ... // Boolean
|
|
754
|
-
member.isUser ... // Boolean
|
|
755
|
-
member.associatedUser ... // String -- member.id if isDevice is true
|
|
756
|
-
member.isRecording ... // Boolean
|
|
757
|
-
member.isMutable ... // Boolean
|
|
758
|
-
member.isRemovable ... // Boolean
|
|
759
|
-
member.type ... // String
|
|
760
|
-
member.isModerator ... // Boolean
|
|
761
|
-
member.isModeratorAssignmentProhibited ... // Boolean
|
|
762
|
-
```
|
|
763
|
-
|
|
764
|
-
#### Members
|
|
765
|
-
|
|
766
|
-
You can access the members object on each individual meeting instance. It has some key events to listen to, and maintains what happens for members of a meeting with some key properties.
|
|
767
|
-
|
|
768
|
-
##### Properties
|
|
769
|
-
|
|
770
|
-
```javascript
|
|
771
|
-
meeting.members.membersCollection.members ... // the members collection, object {id0: member0, ... idN: memberN}
|
|
772
|
-
meeting.members.locusUrl ... // current locusUrl being used
|
|
773
|
-
meeting.members.hostId ... // active host id for the meeting
|
|
774
|
-
meeting.members.selfId ... // active self id for the meeting
|
|
775
|
-
meeting.members.mediaShareContentId ... // active content sharer id for the meeting
|
|
776
|
-
```
|
|
777
|
-
|
|
778
|
-
##### Functions
|
|
779
|
-
|
|
780
|
-
```javascript
|
|
781
|
-
// You can add a guest to the meeting by inviting them, this is proxied by meeting.invite
|
|
782
|
-
// use an emailAddress and a boolean value alertIfActive to notify server side (usually true)
|
|
783
|
-
meeting.members.addMember(emailAddress, alertIfActive);
|
|
784
|
-
|
|
785
|
-
// You can admit the guest to the meeting once they are waiting in the lobby, you can do this in bulk, proxied by meeting.admit
|
|
786
|
-
// use member ids, can be singular, but has to be put into an array
|
|
787
|
-
meeting.members.admitMembers([memberIds]);
|
|
788
|
-
|
|
789
|
-
// You can remove a member from the meeting by booting them, this is proxied by meeting.remove
|
|
790
|
-
// use a memberId string
|
|
791
|
-
meeting.members.removeMember(memberId);
|
|
792
|
-
|
|
793
|
-
// You can audio mute a member from the meeting by calling to mute them, this is proxied by meeting.mute
|
|
794
|
-
// use a memberId string and a boolean to mute or not, default to true
|
|
795
|
-
// mute them
|
|
796
|
-
meeting.members.muteMember(memberId);
|
|
797
|
-
|
|
798
|
-
// You can raise or lower the hand of a member from the meeting
|
|
799
|
-
// use a memberId string and a "raise" boolean to raise or lower, default to true ("raise the hand")
|
|
800
|
-
meeting.members.raiseOrLowerHand(memberId);
|
|
801
|
-
|
|
802
|
-
// You can lower all hands in a meeting
|
|
803
|
-
// use a memberId string to indicate who is requesting lowering all hands
|
|
804
|
-
meeting.members.lowerAllHands(requestingMemberId);
|
|
805
|
-
|
|
806
|
-
// You can transfer the host role to another member in the meeting, this is proxied by meeting.transfer
|
|
807
|
-
// use a memberId string and a moderator boolean to transfer or not, default to true
|
|
808
|
-
meeting.members.transferHostToMember(memberId);
|
|
809
|
-
```
|
|
810
|
-
|
|
811
|
-
##### Events
|
|
812
|
-
|
|
813
|
-
```javascript
|
|
814
|
-
// members collection updated
|
|
815
|
-
meeting.members.on('members:update', (payload) => {
|
|
816
|
-
const delta = payload.delta; // the changes to the members list
|
|
817
|
-
const full = payload.full; // the full members collection
|
|
818
|
-
const updated = delta.updated; // only the updates, includes removals, as they will have updated status and member properties
|
|
819
|
-
const added = delta.added; // added members to the meeting
|
|
820
|
-
Object.keys(full).forEach((key) => {
|
|
821
|
-
const member = full[key];
|
|
822
|
-
console.log(`Member: ... ${member.x}`);
|
|
823
|
-
});
|
|
824
|
-
Object.keys(updated).forEach((key) => {
|
|
825
|
-
const member = updated[key];
|
|
826
|
-
console.log(`Member Updated: ... ${member.x}`);
|
|
827
|
-
});
|
|
828
|
-
Object.keys(added).forEach((key) => {
|
|
829
|
-
const member = added[key];
|
|
830
|
-
console.log(`Member Added: ... ${member.x}`);
|
|
831
|
-
});
|
|
832
|
-
});
|
|
833
|
-
// content updates
|
|
834
|
-
meeting.members.on('members:content:update', (payload) => {
|
|
835
|
-
console.log(`who started sharing: ${payload.activeContentSharingId};`);
|
|
836
|
-
console.log(`who stopped sharing: ${payload.endedContentSharingId};`);
|
|
837
|
-
});
|
|
838
|
-
// host updates
|
|
839
|
-
meeting.members.on('members:host:update', (payload) => {
|
|
840
|
-
console.log(`who started hosting: ${payload.activeHostId};`);
|
|
841
|
-
console.log(`who stopped hosting: ${payload.endedHostId};`);
|
|
842
|
-
});
|
|
843
|
-
// self updates, not typically used
|
|
844
|
-
meeting.members.on('members:self:update', (payload) => {
|
|
845
|
-
console.log(`active self id: ${payload.activeSelfId};`);
|
|
846
|
-
console.log(`ended self Id: ${payload.endedSelfId};`);
|
|
847
|
-
});
|
|
848
|
-
```
|
|
849
|
-
|
|
850
|
-
## Events
|
|
851
|
-
|
|
852
|
-
### Meetings Events
|
|
853
|
-
|
|
854
|
-
```js
|
|
855
|
-
webex.meetings.on(...)
|
|
856
|
-
```
|
|
857
|
-
|
|
858
|
-
| Event Name | Description |
|
|
859
|
-
| --------------------- | -------------------------------------------------------------------------------------------------- |
|
|
860
|
-
| `meetings:ready` | Fired when the plugin has been instantiated and is ready for action! |
|
|
861
|
-
| `meeting:added` | Fired when a meeting has been added to the collection, either incoming, or outgoing, can be joined |
|
|
862
|
-
| `meeting:removed` | Fired when a meeting has been deleted from the collection, this meeting cannot be rejoined |
|
|
863
|
-
| `media:codec:loaded` | Fired when H.264 media codec has been loaded in the browser. Does not have a payload. |
|
|
864
|
-
| `media:codec:missing` | Fired when H.264 media codec appears to be missing from the browser. Does not have a payload. |
|
|
865
|
-
| --- | --- |
|
|
866
|
-
|
|
867
|
-
`meetings:ready` does not have a payload
|
|
868
|
-
|
|
869
|
-
`meeting:added` has the following payload
|
|
870
|
-
|
|
871
|
-
```js
|
|
872
|
-
{
|
|
873
|
-
meetingId; // the uuid of the meeting removed
|
|
874
|
-
type; // string type can be INCOMING, JOIN, or MEETING
|
|
875
|
-
}
|
|
876
|
-
```
|
|
877
|
-
|
|
878
|
-
`meeting:removed` has the following payload
|
|
879
|
-
|
|
880
|
-
```js
|
|
881
|
-
{
|
|
882
|
-
meetingId; // the uuid of the meeting removed
|
|
883
|
-
response; // a propagated server response
|
|
884
|
-
}
|
|
885
|
-
```
|
|
886
|
-
|
|
887
|
-
### Meeting Events
|
|
888
|
-
|
|
889
|
-
```js
|
|
890
|
-
meeting.on(...)
|
|
891
|
-
```
|
|
892
|
-
|
|
893
|
-
| Event Name | Description |
|
|
894
|
-
| -------------------------------------- | ------------------------------------------------------------------------------------------------- |
|
|
895
|
-
| `meetings:ready` | Fired when the meetings plugin has been successfully initialized |
|
|
896
|
-
| `meetings:registered` | Fired when the meetings plugin has registered the device and is listening to websocket events |
|
|
897
|
-
| `meetings:unregistered` | Fired when the meetings plugin has been disconnected from websockets and unregistered as a device |
|
|
898
|
-
| `media:ready` | Fired when remote or local media has been acquired |
|
|
899
|
-
| `media:stopped` | Fired when remote or local media has been torn down |
|
|
900
|
-
| `meeting:media:local:start` | Fired when local media has started sending bytes |
|
|
901
|
-
| `meeting:media:remote:start` | Fired when local media has started receiving bytes from the remote audio or video streams |
|
|
902
|
-
| `meeting:alerted` | Fired when locus was notified that user received meeting |
|
|
903
|
-
| `meeting:ringing` | Fired when meeting should have a ringing sound on repeat |
|
|
904
|
-
| `meeting:ringingStop` | Fired when meeting should stop a ringing sound |
|
|
905
|
-
| `meeting:startedSharingLocal` | Fired when local screen sharing was started |
|
|
906
|
-
| `meeting:stoppedSharingLocal` | Fired when local screen sharing ends |
|
|
907
|
-
| `meeting:startedSharingRemote` | Fired when remote screen sharing was started |
|
|
908
|
-
| `meeting:stoppedSharingRemote` | Fired when remote screen sharing ends |
|
|
909
|
-
| `meeting:self:lobbyWaiting` | Fired when user has entered the lobby for a PMR or the like |
|
|
910
|
-
| `meeting:self:guestAdmitted` | Fired when user has entered the meeting after waiting to be admitted from join |
|
|
911
|
-
| `meeting:self:mutedByOthers` | Fired when user has been audio muted by another in the muting |
|
|
912
|
-
| `meeting:reconnectionStarting` | Fired when a reconnect begins |
|
|
913
|
-
| `meeting:reconnectionSuccess` | Fired when the media was reconnected successfully |
|
|
914
|
-
| `meeting:reconnectionFailure` | Fired when the media failed to reconnect, user will have to rejoin and connect |
|
|
915
|
-
| `meeting:unlocked` | Fired when the meeting was unlocked by the host, for webex type meetings only |
|
|
916
|
-
| `meeting:locked` | Fired when the meeting was locked by the host, for webex type meetings only |
|
|
917
|
-
| `meeting:actionsUpdate` | Fired when the user has new actions they can take, such as lock, unlock, transferHost |
|
|
918
|
-
| `meeting:logUpload:success` | Fired when the meeting logs were successfully uploaded |
|
|
919
|
-
| `meeting:logUpload:failure` | Fired when the meeting logs failed to upload |
|
|
920
|
-
| `meeting:recording:started` | Fired when member starts recording |
|
|
921
|
-
| `meeting:recording:stopped` | Fired when member stops recording |
|
|
922
|
-
| `meeting:recording:paused` | Fired when member pauses recording |
|
|
923
|
-
| `meeting:recording:resumed` | Fired when member resumes recording |
|
|
924
|
-
| `meeting:receiveTranscription:started` | Fired when transcription is received |
|
|
925
|
-
| `meeting:receiveTranscription:stopped` | Fired when transcription has stopped from being received |
|
|
926
|
-
| `meeting:meetingContainer:update` | Fired when the meetingContainerUrl is updated |
|
|
927
|
-
| --- | --- |
|
|
928
|
-
|
|
929
|
-
`meetings:ready` does not have a payload
|
|
930
|
-
|
|
931
|
-
`meetings:registered` does not have a payload
|
|
932
|
-
|
|
933
|
-
`meetings:unregistered` does not have a payload
|
|
934
|
-
|
|
935
|
-
`media:ready` has the following payload
|
|
936
|
-
|
|
937
|
-
```javascript
|
|
938
|
-
{
|
|
939
|
-
type, // local or remote
|
|
940
|
-
stream; // the MediaStream
|
|
941
|
-
}
|
|
942
|
-
// usage
|
|
943
|
-
meeting.on('media:ready', (media) => {
|
|
944
|
-
if (!media) {
|
|
945
|
-
return;
|
|
946
|
-
}
|
|
947
|
-
if (media.type === 'local') {
|
|
948
|
-
document.getElementById('localvideo').srcObject = media.stream;
|
|
949
|
-
}
|
|
950
|
-
if (media.type === 'remoteVideo') {
|
|
951
|
-
document.getElementById('remotevideo').srcObject = media.stream;
|
|
952
|
-
}
|
|
953
|
-
if (media.type === 'remoteAudio') {
|
|
954
|
-
document.getElementById('remoteaudio').srcObject = media.stream;
|
|
955
|
-
}
|
|
956
|
-
if (media.type === 'remoteShare') {
|
|
957
|
-
document.getElementById('sharevideo').srcObject = media.stream;
|
|
958
|
-
}
|
|
959
|
-
if (media.type === 'localShare') {
|
|
960
|
-
document.getElementById('localshare').srcObject = media.stream;
|
|
961
|
-
}
|
|
962
|
-
});
|
|
963
|
-
```
|
|
964
|
-
|
|
965
|
-
`media:stopped` has the following payload
|
|
966
|
-
|
|
967
|
-
```javascript
|
|
968
|
-
{
|
|
969
|
-
type, // local or remote
|
|
970
|
-
}
|
|
971
|
-
// usage
|
|
972
|
-
meeting.on('media:stopped', (media) => {
|
|
973
|
-
if (media.type === 'local') {
|
|
974
|
-
document.getElementById('localvideo').srcObject = null;
|
|
975
|
-
}
|
|
976
|
-
if (media.type === 'remoteVideo') {
|
|
977
|
-
document.getElementById('remotevideo').srcObject = null;
|
|
978
|
-
}
|
|
979
|
-
if (media.type === 'remoteAudio') {
|
|
980
|
-
document.getElementById('remoteaudio').srcObject = null;
|
|
981
|
-
}
|
|
982
|
-
if (media.type === 'localShare') {
|
|
983
|
-
document.getElementById('localshare').srcObject = null;
|
|
984
|
-
}
|
|
985
|
-
if (media.type === 'remoteShare') {
|
|
986
|
-
document.getElementById('sharevideo').srcObject = null;
|
|
987
|
-
}
|
|
988
|
-
});
|
|
989
|
-
```
|
|
990
|
-
|
|
991
|
-
`meeting:alerted` does not have a payload
|
|
992
|
-
|
|
993
|
-
`meeting:ringing` has the following payload
|
|
994
|
-
|
|
995
|
-
```js
|
|
996
|
-
{
|
|
997
|
-
type // INCOMING or JOIN
|
|
998
|
-
id // the meeting id
|
|
999
|
-
}
|
|
1000
|
-
```
|
|
1001
|
-
|
|
1002
|
-
`meeting:ringingStop` has the following payload
|
|
1003
|
-
|
|
1004
|
-
```js
|
|
1005
|
-
{
|
|
1006
|
-
type // Object {remoteAnswered: boolean, remoteDeclined: boolean}
|
|
1007
|
-
id // the meeting id
|
|
1008
|
-
}
|
|
1009
|
-
```
|
|
1010
|
-
|
|
1011
|
-
`meeting:startedSharingLocal` does not have a payload
|
|
1012
|
-
|
|
1013
|
-
`meeting:stoppedSharingLocal` does not have a payload
|
|
1014
|
-
|
|
1015
|
-
`meeting:self:lobbyWaiting` has the following payload
|
|
1016
|
-
|
|
1017
|
-
```js
|
|
1018
|
-
{
|
|
1019
|
-
payload; // self object
|
|
1020
|
-
}
|
|
1021
|
-
```
|
|
1022
|
-
|
|
1023
|
-
`meeting:self:guestAdmitted` has the following payload
|
|
1024
|
-
|
|
1025
|
-
```js
|
|
1026
|
-
{
|
|
1027
|
-
payload; // self object
|
|
1028
|
-
}
|
|
1029
|
-
```
|
|
1030
|
-
|
|
1031
|
-
`meeting:self:mutedByOthers` has the following payload
|
|
1032
|
-
|
|
1033
|
-
```js
|
|
1034
|
-
{
|
|
1035
|
-
payload; // self object
|
|
1036
|
-
}
|
|
1037
|
-
```
|
|
1038
|
-
|
|
1039
|
-
`meeting:reconnectionStarting` does not have a payload
|
|
1040
|
-
|
|
1041
|
-
`meeting:reconnectionSuccess` has the following payload
|
|
1042
|
-
|
|
1043
|
-
```js
|
|
1044
|
-
{
|
|
1045
|
-
reconnect; // the media promise resolution
|
|
1046
|
-
}
|
|
1047
|
-
```
|
|
1048
|
-
|
|
1049
|
-
`meeting:reconnectionFailure` has the following payload
|
|
1050
|
-
|
|
1051
|
-
```js
|
|
1052
|
-
{
|
|
1053
|
-
error; // the forwarded error from media
|
|
1054
|
-
}
|
|
1055
|
-
```
|
|
1056
|
-
|
|
1057
|
-
`meeting:unlocked` has the following payload
|
|
1058
|
-
|
|
1059
|
-
```js
|
|
1060
|
-
{
|
|
1061
|
-
info; // info object
|
|
1062
|
-
}
|
|
1063
|
-
```
|
|
1064
|
-
|
|
1065
|
-
`meeting:locked` has the following payload
|
|
1066
|
-
|
|
1067
|
-
```js
|
|
1068
|
-
{
|
|
1069
|
-
info; // info object
|
|
1070
|
-
}
|
|
1071
|
-
```
|
|
1072
|
-
|
|
1073
|
-
`meeting:actionsUpdate` has the following payload
|
|
1074
|
-
|
|
1075
|
-
```js
|
|
1076
|
-
{
|
|
1077
|
-
canInviteNewParticipants, // boolean
|
|
1078
|
-
canAdmitParticipant, // boolean
|
|
1079
|
-
canLock, // boolean
|
|
1080
|
-
canUnlock, // boolean
|
|
1081
|
-
canAssignHost, // boolean
|
|
1082
|
-
canStartRecording, // boolean
|
|
1083
|
-
canPauseRecording, // boolean
|
|
1084
|
-
canResumeRecording, // boolean
|
|
1085
|
-
canStopRecording, // boolean
|
|
1086
|
-
canRaiseHand, //boolean
|
|
1087
|
-
canLowerAllHands, //boolean
|
|
1088
|
-
canLowerSomeoneElsesHand, //boolean
|
|
1089
|
-
bothLeaveAndEndMeetingAvailable, //boolean
|
|
1090
|
-
}
|
|
1091
|
-
```
|
|
1092
|
-
|
|
1093
|
-
`meeting:recording:started`
|
|
1094
|
-
`meeting:recording:stopped`
|
|
1095
|
-
`meeting:recording:paused`
|
|
1096
|
-
`meeting:recording:resumed` have the following payload
|
|
1097
|
-
|
|
1098
|
-
```js
|
|
1099
|
-
{
|
|
1100
|
-
state; // could be etiher `recording`, `idle` or `paused`
|
|
1101
|
-
modifiedBy; // user's decrypted ID who made an action
|
|
1102
|
-
lastModified; // when the action was made
|
|
1103
|
-
}
|
|
1104
|
-
```
|
|
1105
|
-
|
|
1106
|
-
### Event Caveats
|
|
1107
|
-
|
|
1108
|
-
##### Remote screen share is not displayed if started before participant joins
|
|
1109
|
-
|
|
1110
|
-
If you notice that the remote screen share is not being displayed to a participant when they join
|
|
1111
|
-
after a screen has already been shared, double-check that you are following the standard plugin-meeting workflow.
|
|
1112
|
-
|
|
1113
|
-
Standard plugin-meeting workflow is as follows:
|
|
1114
|
-
|
|
1115
|
-
1. Set event listener for `media:ready`
|
|
1116
|
-
2. Call `join()`
|
|
1117
|
-
3. Call `addMedia()` with `options.mediaSettings.receiveShare=true`
|
|
1118
|
-
4. Wait to receive an event from `media:ready` with payload `type=remoteShare` that contains the remote share media stream
|
|
1119
|
-
5. Set `srcObject` of a `video` element in the application to the previously obtained media stream
|
|
1120
|
-
(e.g. `document.getElementById('remote-screen').srcObject = media.stream`)
|
|
1121
|
-
|
|
1122
|
-
In most cases this will resolve the issue though an extra step could be to
|
|
1123
|
-
use `meeting.shareStatus` to control whether to show the video element or not.
|
|
1124
|
-
|
|
1125
|
-
This may be necessary as you can only register for events like `meeting:startedSharingRemote` on the
|
|
1126
|
-
meeting object, however, you can only do that after you've received the `meeting:added` event notification
|
|
1127
|
-
with the meeting payload. In the case when a host has already begun sharing before a participant joins,
|
|
1128
|
-
the registration for `meeting:startedSharingRemote` happens too late (after the SDK code that would send
|
|
1129
|
-
that event is already executed). Thus, you can check the value of `meeting.shareStatus` when you join the meeting
|
|
1130
|
-
to control whether to show that video element (the one that has srcObject set to the remote share stream) on the screen or not.
|
|
1131
|
-
|
|
1132
|
-
### Members Events
|
|
1133
|
-
|
|
1134
|
-
```js
|
|
1135
|
-
meeting.members.on(...)
|
|
1136
|
-
```
|
|
1137
|
-
|
|
1138
|
-
There are several events submitted by this package that you can subscribe to.
|
|
1139
|
-
| Event Name | Description |
|
|
1140
|
-
|---|---|
|
|
1141
|
-
| `members:update` | Fired when a member in the collection has been updated |
|
|
1142
|
-
| `members:content:update` | Fired when a member in the collection has a changed content stream (share screen) |
|
|
1143
|
-
| `members:host:update` | Fired when a member in the collection has a changed host value |
|
|
1144
|
-
| `members:self:update` | Fired when a member in the collection has a changed self value |
|
|
1145
|
-
|---|---|
|
|
1146
|
-
|
|
1147
|
-
`members:update` has the following payload
|
|
1148
|
-
|
|
1149
|
-
```js
|
|
1150
|
-
{
|
|
1151
|
-
delta: { // the changes to the members list
|
|
1152
|
-
updated // array only the updates, includes removals, as they will have updated status and member properties
|
|
1153
|
-
added // array added members to the meeting
|
|
1154
|
-
}
|
|
1155
|
-
full: // array the full members collection
|
|
1156
|
-
}
|
|
1157
|
-
```
|
|
1158
|
-
|
|
1159
|
-
`members:content:update` has the following payload
|
|
1160
|
-
|
|
1161
|
-
```js
|
|
1162
|
-
{
|
|
1163
|
-
activeContentSharingId; // the member id
|
|
1164
|
-
endedContentSharingId; // the member id
|
|
1165
|
-
}
|
|
1166
|
-
```
|
|
1167
|
-
|
|
1168
|
-
`members:host:update` has the following payload
|
|
1169
|
-
|
|
1170
|
-
```js
|
|
1171
|
-
{
|
|
1172
|
-
activeHostId; // the member id
|
|
1173
|
-
endedHostId; // the member id
|
|
1174
|
-
}
|
|
1175
|
-
```
|
|
1176
|
-
|
|
1177
|
-
`members:self:update` has the following payload
|
|
1178
|
-
|
|
1179
|
-
```js
|
|
1180
|
-
{
|
|
1181
|
-
activeSelfId; // the member id
|
|
1182
|
-
endedSelfId; // the member id
|
|
1183
|
-
}
|
|
1184
|
-
```
|
|
1185
|
-
|
|
1186
|
-
## Development
|
|
1187
|
-
|
|
1188
|
-
To use `webpack-dev-server` to load this package, run `yarn run samples:serve`.
|
|
1189
|
-
|
|
1190
|
-
Files placed in the `docs/samples/browser-plugin-meetings` folder will be served statically.
|
|
1191
|
-
|
|
1192
|
-
Files in the `src` folder will be compiled, bundled, and served as a static asset at `bundle.js` inside that directory.
|
|
1193
|
-
|
|
1194
|
-
## Maintainers
|
|
1195
|
-
|
|
1196
|
-
This package is maintained by [Cisco Webex for Developers](https://developer.webex.com/).
|
|
1197
|
-
|
|
1198
|
-
## Contribute
|
|
1199
|
-
|
|
1200
|
-
Pull requests welcome. Please see [CONTRIBUTING.md](https://github.com/webex/webex-js-sdk/blob/master/CONTRIBUTING.md) for more details.
|
|
1201
|
-
|
|
1202
|
-
## License
|
|
1203
|
-
|
|
1204
|
-
© 2016-2020 Cisco and/or its affiliates. All Rights Reserved.
|
|
1
|
+
# @webex/plugin-meetings
|
|
2
|
+
|
|
3
|
+
[](https://github.com/RichardLitt/standard-readme)
|
|
4
|
+
|
|
5
|
+
> Meetings plugin for the Cisco Webex JS SDK.
|
|
6
|
+
|
|
7
|
+
- [Install](#install)
|
|
8
|
+
- [Usage](#usage)
|
|
9
|
+
- [Important Changes](#important-changes)
|
|
10
|
+
- [Development](#development)
|
|
11
|
+
- [Contribute](#contribute)
|
|
12
|
+
- [Maintainers](#maintainers)
|
|
13
|
+
- [License](#license)
|
|
14
|
+
|
|
15
|
+
# WARNING: This plugin is currently under active development
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install --save @webex/plugin-meetings
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
This is a plugin for the Cisco Webex JS SDK . Please see our [developer portal](https://developer.webex.com/) and the [API docs](https://webex.github.io/webex-js-sdk/api/) for full details.
|
|
26
|
+
|
|
27
|
+
## Important Changes
|
|
28
|
+
|
|
29
|
+
- Version `0.109.0` - Participant email has been removed to reduce PII. Please use participant identity (`members.membersCollection.members[id].participant.identity`) to lookup participant details via the [/people](https://developer.webex.com/docs/api/v1/people/get-person-details) endpoint.
|
|
30
|
+
|
|
31
|
+
## API Docs and Sample App
|
|
32
|
+
|
|
33
|
+
API Docs: https://webex.github.io/webex-js-sdk/api/
|
|
34
|
+
Hosted Sample App: https://webex.github.io/webex-js-sdk/samples/browser-plugin-meetings/
|
|
35
|
+
See https://github.com/webex/webex-js-sdk/tree/master/docs/samples/browser-plugin-meetings for the sample app code vs the readme
|
|
36
|
+
|
|
37
|
+
#### Device Registration
|
|
38
|
+
|
|
39
|
+
The meetings plugin relies on websocket data to function. The user's device needs to register and connect to the web socket server.
|
|
40
|
+
|
|
41
|
+
These setup actions are handled with the `register` function.
|
|
42
|
+
|
|
43
|
+
This function registers the device, connects web sockets, and listens for meeting events.
|
|
44
|
+
|
|
45
|
+
```js
|
|
46
|
+
webex.meetings.register();
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
#### Device Unregistration
|
|
50
|
+
|
|
51
|
+
The inverse of the `register()` function is available as well.
|
|
52
|
+
This function stops listening for meeting events, disconnects from web sockets and unregisters the device.
|
|
53
|
+
|
|
54
|
+
```js
|
|
55
|
+
webex.meetings.unregister();
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
#### Creating a basic meeting
|
|
59
|
+
|
|
60
|
+
##### Via [developer portal room id](https://developer.webex.com/docs/api/v1/rooms)
|
|
61
|
+
|
|
62
|
+
```javascript
|
|
63
|
+
let roomId = `Y2lzY29zcGFyazovL3VzL1JPT00vNWZhMWUzODAtZTkzZS0xMWU5LTgyZTEtOGRmYTg5ZTgzMjJm `;
|
|
64
|
+
return webex.meetings.create(roomId).then((meeting) ==> {...});
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
##### Via [developer portal people id](https://developer.webex.com/docs/api/v1/people)
|
|
68
|
+
|
|
69
|
+
```javascript
|
|
70
|
+
let peopleId = `Y2lzY29zcGFyazovL3VzL1BFT1BMRS8wMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDAw `;
|
|
71
|
+
return webex.meetings.create(peopleId).then((meeting) ==> {...});
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
##### Via conversation url
|
|
75
|
+
|
|
76
|
+
```javascript
|
|
77
|
+
let conversationUrl = `https://conv-a.wbx2.com/conversation/api/v1/ObiwanAnnouncementsConversationUUID`;
|
|
78
|
+
return webex.meetings.create(conversationUrl).then((meeting) ==> {...});
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
##### Via SIP URI
|
|
82
|
+
|
|
83
|
+
```javascript
|
|
84
|
+
let sipUri = `obiwan@example.com`;
|
|
85
|
+
return webex.meetings.create(sipUri).then((meeting) ==> {...});
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
##### Via Locus Object
|
|
89
|
+
|
|
90
|
+
```javascript
|
|
91
|
+
// unlikely to be used
|
|
92
|
+
return webex.meetings.create(locusObj, 'LOCUS_ID').then((meeting) ==> {...});
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
#### Meetings
|
|
96
|
+
|
|
97
|
+
##### List Active Meetings
|
|
98
|
+
|
|
99
|
+
We want to sync our meetings collection with the server.
|
|
100
|
+
|
|
101
|
+
```js
|
|
102
|
+
let existingMeetings;
|
|
103
|
+
// Sync Meetings From Server
|
|
104
|
+
webex.meetings.syncMeetings().then(() => {
|
|
105
|
+
// Existing meetings live in the meeting collection
|
|
106
|
+
existingMeetings = webex.meetings.getAllMeetings();
|
|
107
|
+
});
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
##### Get a Meeting
|
|
111
|
+
|
|
112
|
+
```js
|
|
113
|
+
webex.meetings.getMeetingByType('SIP_URI', sipUri);
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
##### Properties
|
|
117
|
+
|
|
118
|
+
```js
|
|
119
|
+
webex.meetings.personalMeetingRoom; // the personal meeting room instance
|
|
120
|
+
webex.meetings.reachability; // the reachability instance, not initialized until after setReachability is called
|
|
121
|
+
webex.meetings.meetingCollection; // the collection of meetings instance
|
|
122
|
+
webex.meetings.meetingInfo; // the meeting info instance
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
##### Media
|
|
126
|
+
|
|
127
|
+
After a meeting is created and joined, the media from the meeting needs to be connected.
|
|
128
|
+
|
|
129
|
+
###### Local Media
|
|
130
|
+
|
|
131
|
+
To get the local device media we use the function on the meeting object `getMediaStreams`. This takes an options object of which media streams to enable:
|
|
132
|
+
|
|
133
|
+
```js
|
|
134
|
+
const mediaSettings = {
|
|
135
|
+
receiveVideo: true,
|
|
136
|
+
receiveAudio: true,
|
|
137
|
+
receiveShare: true,
|
|
138
|
+
sendVideo: true,
|
|
139
|
+
sendAudio: true,
|
|
140
|
+
sendShare: false,
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const myStreams = {};
|
|
144
|
+
meeting
|
|
145
|
+
.getMediaStreams(mediaSettings)
|
|
146
|
+
.then(([localStream, localShare]) => {
|
|
147
|
+
return {localStream, localShare};
|
|
148
|
+
})
|
|
149
|
+
.then((streams) => {
|
|
150
|
+
myStreams.localStream = streams.localStream;
|
|
151
|
+
myStreams.localShare = streams.localShare;
|
|
152
|
+
});
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
This local stream is now ready to be added to the DOM for a self preview via:
|
|
156
|
+
|
|
157
|
+
```html
|
|
158
|
+
<video id="localvideo" muted="true" autoplay playsinline></video>
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
```js
|
|
162
|
+
document.getElementById('localvideo').srcObject = myStreams.localStream;
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
##### Add Media
|
|
166
|
+
|
|
167
|
+
Once you have your local streams and shares, you need to add the media to the meeting with the `addMedia` function.
|
|
168
|
+
|
|
169
|
+
```js
|
|
170
|
+
meeting
|
|
171
|
+
.addMedia({
|
|
172
|
+
localShare,
|
|
173
|
+
localStream,
|
|
174
|
+
mediaSettings,
|
|
175
|
+
})
|
|
176
|
+
.then((mediaResponse) => {
|
|
177
|
+
// do something once you know media has been completed
|
|
178
|
+
});
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
#### Join a meeting
|
|
182
|
+
|
|
183
|
+
##### Basic Join
|
|
184
|
+
|
|
185
|
+
One can join a meeting without adding a media to just be present in the meeting without send/receive
|
|
186
|
+
Once a meeting object has been created, to start it, simply `join` it.
|
|
187
|
+
|
|
188
|
+
```javascript
|
|
189
|
+
let destination = `obiwan@example.com`; // email example
|
|
190
|
+
return webex.meetings.create(destination).then((meeting) => {
|
|
191
|
+
activeMeeting = meeting;
|
|
192
|
+
// attach listeners or other actions
|
|
193
|
+
activeMeeting.join().then(() => {
|
|
194
|
+
// now the meeting is joined!
|
|
195
|
+
// now you can addMedia
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
##### Full Example
|
|
201
|
+
|
|
202
|
+
```javascript
|
|
203
|
+
let activeMeeting;
|
|
204
|
+
|
|
205
|
+
const mediaSettings = {
|
|
206
|
+
receiveVideo: true,
|
|
207
|
+
receiveAudio: true,
|
|
208
|
+
receiveShare: true,
|
|
209
|
+
sendVideo: true,
|
|
210
|
+
sendAudio: true,
|
|
211
|
+
sendShare: false
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
const myStreams = {}
|
|
215
|
+
|
|
216
|
+
function setMedia(media){
|
|
217
|
+
if (media.type === 'local') {
|
|
218
|
+
document.getElementById('<videoId>').srcObject = media.stream;
|
|
219
|
+
} else if (media.type === 'remote') {
|
|
220
|
+
document.getElementById('<videoId>').srcObject = media.stream;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function handleAudioChange(audio){
|
|
225
|
+
// perform some actions after audio has been muted/unmuted
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function handleVideoChange(video) {
|
|
229
|
+
// perform some action after video has been muted/unmuted
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return webex.meetings
|
|
233
|
+
.create(destination)
|
|
234
|
+
.then((meeting) => {
|
|
235
|
+
activeMeeting = meeting;
|
|
236
|
+
activeMeeting.getMediaStreams(mediaSettings).then(([localStream, localShare]) => {
|
|
237
|
+
return {localStream, localShare};
|
|
238
|
+
}).then((streams) => {
|
|
239
|
+
myStreams.localStream = streams.localStream
|
|
240
|
+
myStreams.localShare = streams.localShare
|
|
241
|
+
});
|
|
242
|
+
activeMeeting.on('media:ready', () => setMedia));
|
|
243
|
+
activeMeeting.on('media:audioChanged', handleAudioChange);
|
|
244
|
+
activeMeeting.on('media:videoChanged', handleVideoChange);
|
|
245
|
+
// join a meeting using resourceId as the destination, i.e., paired to a device and using the device for the call
|
|
246
|
+
activeMeeting.join({resourceId: <DeviceId>}).then((joinResponse) => {
|
|
247
|
+
activeMeeting.addMedia({
|
|
248
|
+
localShare,
|
|
249
|
+
localStream,
|
|
250
|
+
mediaSettings
|
|
251
|
+
}).then((mediaResponse) => {
|
|
252
|
+
// do something once you know media has been completed
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
##### Join a PMR
|
|
259
|
+
|
|
260
|
+
From above, we build off of the join...
|
|
261
|
+
|
|
262
|
+
##### Join your own claimed PMR
|
|
263
|
+
|
|
264
|
+
```javascript
|
|
265
|
+
...
|
|
266
|
+
meeting.join().then((res) => {
|
|
267
|
+
// backend services determine you are the owner, so no pin, or moderator flag is required
|
|
268
|
+
// now you are in the meeting
|
|
269
|
+
});
|
|
270
|
+
...
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
##### Join someone elses claimed PMR
|
|
274
|
+
|
|
275
|
+
```javascript
|
|
276
|
+
...
|
|
277
|
+
// join as host (in place of them)
|
|
278
|
+
meeting.join({pin: <WebexHostPin>, moderator: true}).then((res) => {
|
|
279
|
+
// now you are in the meeting
|
|
280
|
+
});
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
```javascript
|
|
284
|
+
...
|
|
285
|
+
// join as attendee
|
|
286
|
+
meeting.join({pin: <WebexMeetingPin>}).then((res) => {
|
|
287
|
+
// if host hasn't started the meeting, now you are in the lobby, else if host has started the meeting, you are in the meeting
|
|
288
|
+
});
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
##### Join an unclaimed PMR
|
|
292
|
+
|
|
293
|
+
```javascript
|
|
294
|
+
// join as host automatically
|
|
295
|
+
meeting.join({pin: <WebexHostPin>, moderator: true}).then((res) => {
|
|
296
|
+
// now you are in the meeting
|
|
297
|
+
});
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
```javascript
|
|
301
|
+
// join as host with ask user option
|
|
302
|
+
// join as attendee
|
|
303
|
+
meeting.join().then((res) => {
|
|
304
|
+
}).catch((err) => {
|
|
305
|
+
if (err.joinIntentRequired) {
|
|
306
|
+
// at this point you can ask the user to join as host or join as guest
|
|
307
|
+
// if join as host, requires a pin
|
|
308
|
+
...
|
|
309
|
+
// join as host simply makes the join call again with the proper pin/moderator parameters
|
|
310
|
+
meeting.join({pin: <WebexHostPin>, moderator: true}).then(() => {
|
|
311
|
+
// you are now in the meeting
|
|
312
|
+
});
|
|
313
|
+
...
|
|
314
|
+
// join as guest simply makes the call again with moderator parameter
|
|
315
|
+
meeting.join(({moderator: false})).then(() => {
|
|
316
|
+
// if host hasn't started the meeting, now you are in the lobby, else if host has started the meeting, you are in the meeting
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
});
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
##### Join an incoming meeting
|
|
323
|
+
|
|
324
|
+
When listening to an added meeting, to determine if it is an "incoming" meeting, check the type property of the meeting:
|
|
325
|
+
|
|
326
|
+
```js
|
|
327
|
+
webex.meetings.on('meeting:added', (addedMeeting) => {
|
|
328
|
+
if (addedMeeting.type === 'INCOMING') {
|
|
329
|
+
// Handle incoming meeting
|
|
330
|
+
addedMeeting.acknowledge();
|
|
331
|
+
addedMeeting.join().then(() => {});
|
|
332
|
+
}
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
##### Reject an incoming meeting
|
|
336
|
+
|
|
337
|
+
When listening to an added meeting, to determine if it is an "incoming" meeting, check the type property of the meeting:
|
|
338
|
+
|
|
339
|
+
```js
|
|
340
|
+
webex.meetings.on('meeting:added', (addedMeeting) => {
|
|
341
|
+
if (addedMeeting.type === 'INCOMING') {
|
|
342
|
+
// Handle incoming meeting
|
|
343
|
+
addedMeeting.decline();
|
|
344
|
+
}
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
#### Enable receiving meeting real-time transcripts
|
|
348
|
+
|
|
349
|
+
In order to receive meeting transcripts, Webex assistant must be enabled for the meeting.
|
|
350
|
+
|
|
351
|
+
```javascript
|
|
352
|
+
...
|
|
353
|
+
// Subscribe to transcription events
|
|
354
|
+
meeting.on('meeting:receiveTranscription:started', (payload) => {
|
|
355
|
+
console.log(payload);
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
meeting.on('meeting:receiveTranscription:stopped', () => {});
|
|
359
|
+
|
|
360
|
+
await meeting.join({receiveTranscription: true});
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
##### Microphone, Speaker and Camera
|
|
364
|
+
|
|
365
|
+
Select a different device than the default:
|
|
366
|
+
|
|
367
|
+
```js
|
|
368
|
+
const audioInputSelect = document.querySelector('select#audioSource');
|
|
369
|
+
const audioOutputSelect = document.querySelector('select#audioOutput');
|
|
370
|
+
const videoSelect = document.querySelector('select#videoSource');
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
```js
|
|
374
|
+
const audio = {};
|
|
375
|
+
const video = {};
|
|
376
|
+
const media = {
|
|
377
|
+
receiveVideo: boolean,
|
|
378
|
+
receiveAudio: boolean,
|
|
379
|
+
receiveShare: boolean,
|
|
380
|
+
sendShare: boolean,
|
|
381
|
+
sendVideo: boolean,
|
|
382
|
+
sendAudio: boolean
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
// setting up the devices
|
|
386
|
+
const selectors = [audioInputSelect, audioOutputSelect, videoSelect];
|
|
387
|
+
|
|
388
|
+
meeting.getDevices().then((deviceInfos) => {
|
|
389
|
+
const values = selectors.map((select) => select.value);
|
|
390
|
+
|
|
391
|
+
selectors.forEach((select) => {
|
|
392
|
+
while (select.firstChild) {
|
|
393
|
+
select.removeChild(select.firstChild);
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
for (let i = 0; i !== deviceInfos.length; i += 1) {
|
|
397
|
+
const deviceInfo = deviceInfos[i];
|
|
398
|
+
const option = document.createElement('option');
|
|
399
|
+
|
|
400
|
+
option.value = deviceInfo.deviceId;
|
|
401
|
+
if (deviceInfo.kind === 'audioinput') {
|
|
402
|
+
option.text = deviceInfo.label || `microphone ${audioInputSelect.length + 1}`;
|
|
403
|
+
audioInputSelect.appendChild(option);
|
|
404
|
+
}
|
|
405
|
+
else if (deviceInfo.kind === 'audiooutput') {
|
|
406
|
+
option.text = deviceInfo.label || `speaker ${audioOutputSelect.length + 1}`;
|
|
407
|
+
audioOutputSelect.appendChild(option);
|
|
408
|
+
}
|
|
409
|
+
else if (deviceInfo.kind === 'videoinput') {
|
|
410
|
+
option.text = deviceInfo.label || `camera ${videoSelect.length + 1}`;
|
|
411
|
+
videoSelect.appendChild(option);
|
|
412
|
+
}
|
|
413
|
+
else {
|
|
414
|
+
console.log('Some other kind of source/device: ', deviceInfo);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
selectors.forEach((select, selectorIndex) => {
|
|
418
|
+
if (Array.prototype.slice.call(select.childNodes).some((n) => n.value === values[selectorIndex])) {
|
|
419
|
+
select.value = values[selectorIndex];
|
|
420
|
+
}
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
// attaching before the request
|
|
424
|
+
|
|
425
|
+
audio.deviceId = {exact: audioInputSelect.value}
|
|
426
|
+
video.deviceId = {exact: videoSelect.value}
|
|
427
|
+
meeting.getMediaStreams(media, {audio, video}).then(...)
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
###### Changing remote audio output
|
|
431
|
+
|
|
432
|
+
```js
|
|
433
|
+
// Attach audio output device to video element using device/sink ID.
|
|
434
|
+
function attachSinkId(element, sinkId) {
|
|
435
|
+
if (typeof element.sinkId !== 'undefined') {
|
|
436
|
+
element
|
|
437
|
+
.setSinkId(sinkId)
|
|
438
|
+
.then(() => {
|
|
439
|
+
console.log(`Success, audio output device attached: ${sinkId}`);
|
|
440
|
+
})
|
|
441
|
+
.catch((error) => {
|
|
442
|
+
let errorMessage = error;
|
|
443
|
+
|
|
444
|
+
if (error.name === 'SecurityError') {
|
|
445
|
+
errorMessage = `You need to use HTTPS for selecting audio output device: ${error}`;
|
|
446
|
+
}
|
|
447
|
+
console.error(errorMessage);
|
|
448
|
+
// Jump back to first output device in the list as it's the default.
|
|
449
|
+
audioOutputSelect.selectedIndex = 0;
|
|
450
|
+
});
|
|
451
|
+
} else {
|
|
452
|
+
console.warn('Browser does not support output device selection.');
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
audioOutputSelect.onchange = function () {
|
|
457
|
+
attachSinkId(document.getElementById('remoteaudio'), audioOutputSelect.value);
|
|
458
|
+
};
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
##### Record
|
|
462
|
+
|
|
463
|
+
```js
|
|
464
|
+
// you can only pause if recording
|
|
465
|
+
// you can only start recording if not recording
|
|
466
|
+
// you can only resume recording if paused
|
|
467
|
+
// you can only pause recording if started
|
|
468
|
+
meeting.startRecording();
|
|
469
|
+
meeting.pauseRecording();
|
|
470
|
+
meeting.resumeRecording();
|
|
471
|
+
meeting.stopRecording();
|
|
472
|
+
// note, all recording is done in the cloud
|
|
473
|
+
// local recording is not yet available for this package
|
|
474
|
+
// but is technically possible
|
|
475
|
+
// please submit a feature request if desired :)
|
|
476
|
+
// https://github.com/webex/webex-js-sdk/blob/master/CONTRIBUTING.md
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
##### Mute Audio or Video
|
|
480
|
+
|
|
481
|
+
```js
|
|
482
|
+
meeting.muteAudio();
|
|
483
|
+
meeting.muteVideo();
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
##### Unmute Audio or Video
|
|
487
|
+
|
|
488
|
+
```js
|
|
489
|
+
meeting.unmuteAudio();
|
|
490
|
+
meeting.unmuteVideo();
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
##### Start Sending a Share
|
|
494
|
+
|
|
495
|
+
```js
|
|
496
|
+
meeting.shareScreen();
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
##### Stop Sending a Share
|
|
500
|
+
|
|
501
|
+
```js
|
|
502
|
+
meeting.stopShare();
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
##### Update Audio/Video Streams
|
|
506
|
+
|
|
507
|
+
Use this if you want to change the actual streams send and receive for audio or video component separately; `updateAudio` and `updateVideo` is for the developer to add and remove the streams completely.
|
|
508
|
+
|
|
509
|
+
```js
|
|
510
|
+
//video
|
|
511
|
+
if (media.sendVideo) {
|
|
512
|
+
meeting
|
|
513
|
+
.getMediaStreams(
|
|
514
|
+
{sendVideo: true},
|
|
515
|
+
{video: videoSelect.value ? {deviceId: {exact: videoSelect.value}} : media.sendVideo}
|
|
516
|
+
)
|
|
517
|
+
.then(([localStream]) =>
|
|
518
|
+
meeting.updateVideo({
|
|
519
|
+
stream: localStream,
|
|
520
|
+
sendVideo: media.sendVideo,
|
|
521
|
+
receiveVideo: media.receiveVideo,
|
|
522
|
+
})
|
|
523
|
+
);
|
|
524
|
+
} else {
|
|
525
|
+
meeting.updateVideo({
|
|
526
|
+
sendVideo: media.sendVideo,
|
|
527
|
+
receiveVideo: media.receiveVideo,
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
//audio
|
|
531
|
+
if (media.sendAudio) {
|
|
532
|
+
meeting
|
|
533
|
+
.getMediaStreams(media, {
|
|
534
|
+
audio: audioInputSelect.value ? {deviceId: {exact: audioInputSelect.value}} : media.sendAudio,
|
|
535
|
+
})
|
|
536
|
+
.then(([localStream]) =>
|
|
537
|
+
meeting.updateAudio({
|
|
538
|
+
stream: localStream,
|
|
539
|
+
sendAudio: media.sendAudio,
|
|
540
|
+
receiveAudio: media.receiveAudio,
|
|
541
|
+
})
|
|
542
|
+
);
|
|
543
|
+
} else {
|
|
544
|
+
meeting.updateAudio({
|
|
545
|
+
sendAudio: media.sendAudio,
|
|
546
|
+
receiveAudio: media.receiveAudio,
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
//all in one
|
|
550
|
+
meeting.getMediaStreams(media, {audio, video}).then(([localStream, localShare]) =>
|
|
551
|
+
meeting.updateMedia({
|
|
552
|
+
mediaSettings: media,
|
|
553
|
+
localStream,
|
|
554
|
+
localShare,
|
|
555
|
+
})
|
|
556
|
+
);
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
##### Accessing media directly (outside of a meeting)
|
|
560
|
+
|
|
561
|
+
You can also directly access the following media properties that are not on a meeting instance
|
|
562
|
+
|
|
563
|
+
```
|
|
564
|
+
this.media.getUserMedia(mediaSetting, audioVideo, sharePreferences, config)
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
See the [Media](https://github.com/webex/webex-js-sdk/blob/master/packages/node_modules/%40webex/plugin-meetings/src/media/index.js) util file for method signatures.
|
|
568
|
+
|
|
569
|
+
##### Leave a Meeting
|
|
570
|
+
|
|
571
|
+
To leave a meeting, simply call leave
|
|
572
|
+
|
|
573
|
+
```js
|
|
574
|
+
myMeeting.leave();
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
##### Lock/Unlock a Meeting
|
|
578
|
+
|
|
579
|
+
```js
|
|
580
|
+
meeting.lockMeeting();
|
|
581
|
+
meeting.unlockMeeting();
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
##### Transfer Host
|
|
585
|
+
|
|
586
|
+
```js
|
|
587
|
+
const hostMemberId = ...;
|
|
588
|
+
meeting.transfer(hostMemberId);
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
##### Check User Actions
|
|
592
|
+
|
|
593
|
+
```js
|
|
594
|
+
meeting.inMeetingActions.get();
|
|
595
|
+
{
|
|
596
|
+
canInviteNewParticipants: boolean,
|
|
597
|
+
canAdmitParticipant: boolean,
|
|
598
|
+
canLock: boolean,
|
|
599
|
+
canUnlock: boolean,
|
|
600
|
+
canAssignHost: boolean,
|
|
601
|
+
canStartRecording: boolean,
|
|
602
|
+
canPauseRecording: boolean,
|
|
603
|
+
canResumeRecording: boolean,
|
|
604
|
+
canStopRecording: boolean,
|
|
605
|
+
canRaiseHand: boolean,
|
|
606
|
+
canLowerAllHands: boolean,
|
|
607
|
+
canLowerSomeoneElsesHand: boolean,
|
|
608
|
+
bothLeaveAndEndMeetingAvailable: boolean,
|
|
609
|
+
}
|
|
610
|
+
```
|
|
611
|
+
|
|
612
|
+
#### Personal Meeting Room
|
|
613
|
+
|
|
614
|
+
##### Edit Personal Meeting Room
|
|
615
|
+
|
|
616
|
+
```javascript
|
|
617
|
+
const link = ...; // a valid pmr link
|
|
618
|
+
const pin = ...; // a valid host pin assoicated to the link
|
|
619
|
+
// claiming a pmr, and updating the cached values for the stored PMR
|
|
620
|
+
webex.meetings.personalMeetingRoom.claim(link, pin).then((pmr) => {
|
|
621
|
+
console.log(pmr); // do something else with the pmr
|
|
622
|
+
});
|
|
623
|
+
```
|
|
624
|
+
|
|
625
|
+
##### Get Personal Meeting Room
|
|
626
|
+
|
|
627
|
+
```javascript
|
|
628
|
+
webex.meetings.personalMeetingRoom.get().then((pmr) => {
|
|
629
|
+
// do some stuff with the pmr values
|
|
630
|
+
console.log(`PMR INFO:
|
|
631
|
+
link-${webex.meetings.personalMeetingRoom.meetingLink}-
|
|
632
|
+
uri-${webex.meetings.personalMeetingRoom.sipUri}-
|
|
633
|
+
tollFree-${webex.meetings.personalMeetingRoom.pmr.callInNumbersInfo.callInTollFreeNumber.number}-
|
|
634
|
+
toll-${webex.meetings.personalMeetingRoom.pmr.callInNumbersInfo.callInTollNumber.number}-
|
|
635
|
+
accessCode-${webex.meetings.personalMeetingRoom.pmr.meetingNumber}
|
|
636
|
+
`);
|
|
637
|
+
});
|
|
638
|
+
```
|
|
639
|
+
|
|
640
|
+
#### Usage of Webex Devices
|
|
641
|
+
|
|
642
|
+
For details on how to use the devices see https://github.com/webex/webex-js-sdk/tree/master/packages/node_modules/%40webex/plugin-device-manager
|
|
643
|
+
|
|
644
|
+
##### Leave a Meeting Using a Device
|
|
645
|
+
|
|
646
|
+
```js
|
|
647
|
+
const resourceId = ...;
|
|
648
|
+
|
|
649
|
+
meeting.leave({resourceId}).then((res) => {
|
|
650
|
+
console.log(`successful leave with device, ${res}`);
|
|
651
|
+
});
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
##### Leave a Meeting While Paired to the Device, Keep Device in Meeting
|
|
655
|
+
|
|
656
|
+
```js
|
|
657
|
+
meeting.leave().then((res) => {
|
|
658
|
+
console.log(`successful leave, ${res}`);
|
|
659
|
+
});
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
##### Move Meeting To Paired Device
|
|
663
|
+
|
|
664
|
+
```js
|
|
665
|
+
const resourceId = ...
|
|
666
|
+
|
|
667
|
+
meeting.moveTo(resourceId).then((res) => {
|
|
668
|
+
console.log(`successful move to ${res}`);
|
|
669
|
+
});
|
|
670
|
+
}
|
|
671
|
+
```
|
|
672
|
+
|
|
673
|
+
##### Move Meeting from Paired Device
|
|
674
|
+
|
|
675
|
+
```js
|
|
676
|
+
const resourceId = ...
|
|
677
|
+
|
|
678
|
+
meeting.moveFrom(resourceId).then((res) => {
|
|
679
|
+
console.log(`successful move from ${res}`);
|
|
680
|
+
});
|
|
681
|
+
```
|
|
682
|
+
|
|
683
|
+
##### Start Wireless Share
|
|
684
|
+
|
|
685
|
+
```js
|
|
686
|
+
const deviceId = ...
|
|
687
|
+
// create the meeting
|
|
688
|
+
webex.meetings.create(deviceId).then((m) => {
|
|
689
|
+
// attach listeners
|
|
690
|
+
// then join the meeting
|
|
691
|
+
meeting.getMediaStreams({
|
|
692
|
+
sendAudio: false,
|
|
693
|
+
sendVideo: false,
|
|
694
|
+
sendShare: true
|
|
695
|
+
}))
|
|
696
|
+
.then(([localStream, localShare]) =>
|
|
697
|
+
meeting.addMedia({
|
|
698
|
+
mediaSettings: {
|
|
699
|
+
sendAudio: false,
|
|
700
|
+
sendVideo: false,
|
|
701
|
+
sendShare: true,
|
|
702
|
+
receiveShare: false,
|
|
703
|
+
receiveAudio: false,
|
|
704
|
+
receiveVideo: false
|
|
705
|
+
},
|
|
706
|
+
localShare,
|
|
707
|
+
localStream
|
|
708
|
+
}))
|
|
709
|
+
.catch((e) => {
|
|
710
|
+
meeting.leave();
|
|
711
|
+
console.error('Error wireless screen sharing', e);
|
|
712
|
+
});
|
|
713
|
+
}
|
|
714
|
+
```
|
|
715
|
+
|
|
716
|
+
##### End Wireless Share
|
|
717
|
+
|
|
718
|
+
```js
|
|
719
|
+
meeting.leave();
|
|
720
|
+
```
|
|
721
|
+
|
|
722
|
+
##### Reconnect a Meeting Media
|
|
723
|
+
|
|
724
|
+
Warning: not necessary to use manually, internally the sdk listens to mercury reconnect events to determine for a reconnection
|
|
725
|
+
|
|
726
|
+
```js
|
|
727
|
+
meeting.reconnect();
|
|
728
|
+
```
|
|
729
|
+
|
|
730
|
+
#### Scheduled Meetings
|
|
731
|
+
|
|
732
|
+
For scheduled meetings see https://github.com/webex/webex-js-sdk/tree/master/packages/node_modules/%40webex/internal-plugin-calendar
|
|
733
|
+
|
|
734
|
+
#### Member
|
|
735
|
+
|
|
736
|
+
##### Properties
|
|
737
|
+
|
|
738
|
+
```javascript
|
|
739
|
+
member.participant ... // Object server participant object, advanced use only
|
|
740
|
+
member.id ... // String key for storing
|
|
741
|
+
member.name ... // String plain text name
|
|
742
|
+
member.isAudioMuted ... // Boolean
|
|
743
|
+
member.isVideoMuted ... // Boolean
|
|
744
|
+
member.isHandRaised ... //Boolean
|
|
745
|
+
member.isSelf ... // Boolean is this member YOUR user?
|
|
746
|
+
member.isHost ... // Boolean
|
|
747
|
+
member.isGuest ... // Boolean
|
|
748
|
+
member.isInLobby ... // Boolean
|
|
749
|
+
member.isInMeeting ... // Boolean
|
|
750
|
+
member.isNotAdmitted ... // Boolean -- waiting to be admitted to the meeting, will also have isInLobby true
|
|
751
|
+
member.isContentSharing ... // Boolean
|
|
752
|
+
member.status ... // String -- advanced use only
|
|
753
|
+
member.isDevice ... // Boolean
|
|
754
|
+
member.isUser ... // Boolean
|
|
755
|
+
member.associatedUser ... // String -- member.id if isDevice is true
|
|
756
|
+
member.isRecording ... // Boolean
|
|
757
|
+
member.isMutable ... // Boolean
|
|
758
|
+
member.isRemovable ... // Boolean
|
|
759
|
+
member.type ... // String
|
|
760
|
+
member.isModerator ... // Boolean
|
|
761
|
+
member.isModeratorAssignmentProhibited ... // Boolean
|
|
762
|
+
```
|
|
763
|
+
|
|
764
|
+
#### Members
|
|
765
|
+
|
|
766
|
+
You can access the members object on each individual meeting instance. It has some key events to listen to, and maintains what happens for members of a meeting with some key properties.
|
|
767
|
+
|
|
768
|
+
##### Properties
|
|
769
|
+
|
|
770
|
+
```javascript
|
|
771
|
+
meeting.members.membersCollection.members ... // the members collection, object {id0: member0, ... idN: memberN}
|
|
772
|
+
meeting.members.locusUrl ... // current locusUrl being used
|
|
773
|
+
meeting.members.hostId ... // active host id for the meeting
|
|
774
|
+
meeting.members.selfId ... // active self id for the meeting
|
|
775
|
+
meeting.members.mediaShareContentId ... // active content sharer id for the meeting
|
|
776
|
+
```
|
|
777
|
+
|
|
778
|
+
##### Functions
|
|
779
|
+
|
|
780
|
+
```javascript
|
|
781
|
+
// You can add a guest to the meeting by inviting them, this is proxied by meeting.invite
|
|
782
|
+
// use an emailAddress and a boolean value alertIfActive to notify server side (usually true)
|
|
783
|
+
meeting.members.addMember(emailAddress, alertIfActive);
|
|
784
|
+
|
|
785
|
+
// You can admit the guest to the meeting once they are waiting in the lobby, you can do this in bulk, proxied by meeting.admit
|
|
786
|
+
// use member ids, can be singular, but has to be put into an array
|
|
787
|
+
meeting.members.admitMembers([memberIds]);
|
|
788
|
+
|
|
789
|
+
// You can remove a member from the meeting by booting them, this is proxied by meeting.remove
|
|
790
|
+
// use a memberId string
|
|
791
|
+
meeting.members.removeMember(memberId);
|
|
792
|
+
|
|
793
|
+
// You can audio mute a member from the meeting by calling to mute them, this is proxied by meeting.mute
|
|
794
|
+
// use a memberId string and a boolean to mute or not, default to true
|
|
795
|
+
// mute them
|
|
796
|
+
meeting.members.muteMember(memberId);
|
|
797
|
+
|
|
798
|
+
// You can raise or lower the hand of a member from the meeting
|
|
799
|
+
// use a memberId string and a "raise" boolean to raise or lower, default to true ("raise the hand")
|
|
800
|
+
meeting.members.raiseOrLowerHand(memberId);
|
|
801
|
+
|
|
802
|
+
// You can lower all hands in a meeting
|
|
803
|
+
// use a memberId string to indicate who is requesting lowering all hands
|
|
804
|
+
meeting.members.lowerAllHands(requestingMemberId);
|
|
805
|
+
|
|
806
|
+
// You can transfer the host role to another member in the meeting, this is proxied by meeting.transfer
|
|
807
|
+
// use a memberId string and a moderator boolean to transfer or not, default to true
|
|
808
|
+
meeting.members.transferHostToMember(memberId);
|
|
809
|
+
```
|
|
810
|
+
|
|
811
|
+
##### Events
|
|
812
|
+
|
|
813
|
+
```javascript
|
|
814
|
+
// members collection updated
|
|
815
|
+
meeting.members.on('members:update', (payload) => {
|
|
816
|
+
const delta = payload.delta; // the changes to the members list
|
|
817
|
+
const full = payload.full; // the full members collection
|
|
818
|
+
const updated = delta.updated; // only the updates, includes removals, as they will have updated status and member properties
|
|
819
|
+
const added = delta.added; // added members to the meeting
|
|
820
|
+
Object.keys(full).forEach((key) => {
|
|
821
|
+
const member = full[key];
|
|
822
|
+
console.log(`Member: ... ${member.x}`);
|
|
823
|
+
});
|
|
824
|
+
Object.keys(updated).forEach((key) => {
|
|
825
|
+
const member = updated[key];
|
|
826
|
+
console.log(`Member Updated: ... ${member.x}`);
|
|
827
|
+
});
|
|
828
|
+
Object.keys(added).forEach((key) => {
|
|
829
|
+
const member = added[key];
|
|
830
|
+
console.log(`Member Added: ... ${member.x}`);
|
|
831
|
+
});
|
|
832
|
+
});
|
|
833
|
+
// content updates
|
|
834
|
+
meeting.members.on('members:content:update', (payload) => {
|
|
835
|
+
console.log(`who started sharing: ${payload.activeContentSharingId};`);
|
|
836
|
+
console.log(`who stopped sharing: ${payload.endedContentSharingId};`);
|
|
837
|
+
});
|
|
838
|
+
// host updates
|
|
839
|
+
meeting.members.on('members:host:update', (payload) => {
|
|
840
|
+
console.log(`who started hosting: ${payload.activeHostId};`);
|
|
841
|
+
console.log(`who stopped hosting: ${payload.endedHostId};`);
|
|
842
|
+
});
|
|
843
|
+
// self updates, not typically used
|
|
844
|
+
meeting.members.on('members:self:update', (payload) => {
|
|
845
|
+
console.log(`active self id: ${payload.activeSelfId};`);
|
|
846
|
+
console.log(`ended self Id: ${payload.endedSelfId};`);
|
|
847
|
+
});
|
|
848
|
+
```
|
|
849
|
+
|
|
850
|
+
## Events
|
|
851
|
+
|
|
852
|
+
### Meetings Events
|
|
853
|
+
|
|
854
|
+
```js
|
|
855
|
+
webex.meetings.on(...)
|
|
856
|
+
```
|
|
857
|
+
|
|
858
|
+
| Event Name | Description |
|
|
859
|
+
| --------------------- | -------------------------------------------------------------------------------------------------- |
|
|
860
|
+
| `meetings:ready` | Fired when the plugin has been instantiated and is ready for action! |
|
|
861
|
+
| `meeting:added` | Fired when a meeting has been added to the collection, either incoming, or outgoing, can be joined |
|
|
862
|
+
| `meeting:removed` | Fired when a meeting has been deleted from the collection, this meeting cannot be rejoined |
|
|
863
|
+
| `media:codec:loaded` | Fired when H.264 media codec has been loaded in the browser. Does not have a payload. |
|
|
864
|
+
| `media:codec:missing` | Fired when H.264 media codec appears to be missing from the browser. Does not have a payload. |
|
|
865
|
+
| --- | --- |
|
|
866
|
+
|
|
867
|
+
`meetings:ready` does not have a payload
|
|
868
|
+
|
|
869
|
+
`meeting:added` has the following payload
|
|
870
|
+
|
|
871
|
+
```js
|
|
872
|
+
{
|
|
873
|
+
meetingId; // the uuid of the meeting removed
|
|
874
|
+
type; // string type can be INCOMING, JOIN, or MEETING
|
|
875
|
+
}
|
|
876
|
+
```
|
|
877
|
+
|
|
878
|
+
`meeting:removed` has the following payload
|
|
879
|
+
|
|
880
|
+
```js
|
|
881
|
+
{
|
|
882
|
+
meetingId; // the uuid of the meeting removed
|
|
883
|
+
response; // a propagated server response
|
|
884
|
+
}
|
|
885
|
+
```
|
|
886
|
+
|
|
887
|
+
### Meeting Events
|
|
888
|
+
|
|
889
|
+
```js
|
|
890
|
+
meeting.on(...)
|
|
891
|
+
```
|
|
892
|
+
|
|
893
|
+
| Event Name | Description |
|
|
894
|
+
| -------------------------------------- | ------------------------------------------------------------------------------------------------- |
|
|
895
|
+
| `meetings:ready` | Fired when the meetings plugin has been successfully initialized |
|
|
896
|
+
| `meetings:registered` | Fired when the meetings plugin has registered the device and is listening to websocket events |
|
|
897
|
+
| `meetings:unregistered` | Fired when the meetings plugin has been disconnected from websockets and unregistered as a device |
|
|
898
|
+
| `media:ready` | Fired when remote or local media has been acquired |
|
|
899
|
+
| `media:stopped` | Fired when remote or local media has been torn down |
|
|
900
|
+
| `meeting:media:local:start` | Fired when local media has started sending bytes |
|
|
901
|
+
| `meeting:media:remote:start` | Fired when local media has started receiving bytes from the remote audio or video streams |
|
|
902
|
+
| `meeting:alerted` | Fired when locus was notified that user received meeting |
|
|
903
|
+
| `meeting:ringing` | Fired when meeting should have a ringing sound on repeat |
|
|
904
|
+
| `meeting:ringingStop` | Fired when meeting should stop a ringing sound |
|
|
905
|
+
| `meeting:startedSharingLocal` | Fired when local screen sharing was started |
|
|
906
|
+
| `meeting:stoppedSharingLocal` | Fired when local screen sharing ends |
|
|
907
|
+
| `meeting:startedSharingRemote` | Fired when remote screen sharing was started |
|
|
908
|
+
| `meeting:stoppedSharingRemote` | Fired when remote screen sharing ends |
|
|
909
|
+
| `meeting:self:lobbyWaiting` | Fired when user has entered the lobby for a PMR or the like |
|
|
910
|
+
| `meeting:self:guestAdmitted` | Fired when user has entered the meeting after waiting to be admitted from join |
|
|
911
|
+
| `meeting:self:mutedByOthers` | Fired when user has been audio muted by another in the muting |
|
|
912
|
+
| `meeting:reconnectionStarting` | Fired when a reconnect begins |
|
|
913
|
+
| `meeting:reconnectionSuccess` | Fired when the media was reconnected successfully |
|
|
914
|
+
| `meeting:reconnectionFailure` | Fired when the media failed to reconnect, user will have to rejoin and connect |
|
|
915
|
+
| `meeting:unlocked` | Fired when the meeting was unlocked by the host, for webex type meetings only |
|
|
916
|
+
| `meeting:locked` | Fired when the meeting was locked by the host, for webex type meetings only |
|
|
917
|
+
| `meeting:actionsUpdate` | Fired when the user has new actions they can take, such as lock, unlock, transferHost |
|
|
918
|
+
| `meeting:logUpload:success` | Fired when the meeting logs were successfully uploaded |
|
|
919
|
+
| `meeting:logUpload:failure` | Fired when the meeting logs failed to upload |
|
|
920
|
+
| `meeting:recording:started` | Fired when member starts recording |
|
|
921
|
+
| `meeting:recording:stopped` | Fired when member stops recording |
|
|
922
|
+
| `meeting:recording:paused` | Fired when member pauses recording |
|
|
923
|
+
| `meeting:recording:resumed` | Fired when member resumes recording |
|
|
924
|
+
| `meeting:receiveTranscription:started` | Fired when transcription is received |
|
|
925
|
+
| `meeting:receiveTranscription:stopped` | Fired when transcription has stopped from being received |
|
|
926
|
+
| `meeting:meetingContainer:update` | Fired when the meetingContainerUrl is updated |
|
|
927
|
+
| --- | --- |
|
|
928
|
+
|
|
929
|
+
`meetings:ready` does not have a payload
|
|
930
|
+
|
|
931
|
+
`meetings:registered` does not have a payload
|
|
932
|
+
|
|
933
|
+
`meetings:unregistered` does not have a payload
|
|
934
|
+
|
|
935
|
+
`media:ready` has the following payload
|
|
936
|
+
|
|
937
|
+
```javascript
|
|
938
|
+
{
|
|
939
|
+
type, // local or remote
|
|
940
|
+
stream; // the MediaStream
|
|
941
|
+
}
|
|
942
|
+
// usage
|
|
943
|
+
meeting.on('media:ready', (media) => {
|
|
944
|
+
if (!media) {
|
|
945
|
+
return;
|
|
946
|
+
}
|
|
947
|
+
if (media.type === 'local') {
|
|
948
|
+
document.getElementById('localvideo').srcObject = media.stream;
|
|
949
|
+
}
|
|
950
|
+
if (media.type === 'remoteVideo') {
|
|
951
|
+
document.getElementById('remotevideo').srcObject = media.stream;
|
|
952
|
+
}
|
|
953
|
+
if (media.type === 'remoteAudio') {
|
|
954
|
+
document.getElementById('remoteaudio').srcObject = media.stream;
|
|
955
|
+
}
|
|
956
|
+
if (media.type === 'remoteShare') {
|
|
957
|
+
document.getElementById('sharevideo').srcObject = media.stream;
|
|
958
|
+
}
|
|
959
|
+
if (media.type === 'localShare') {
|
|
960
|
+
document.getElementById('localshare').srcObject = media.stream;
|
|
961
|
+
}
|
|
962
|
+
});
|
|
963
|
+
```
|
|
964
|
+
|
|
965
|
+
`media:stopped` has the following payload
|
|
966
|
+
|
|
967
|
+
```javascript
|
|
968
|
+
{
|
|
969
|
+
type, // local or remote
|
|
970
|
+
}
|
|
971
|
+
// usage
|
|
972
|
+
meeting.on('media:stopped', (media) => {
|
|
973
|
+
if (media.type === 'local') {
|
|
974
|
+
document.getElementById('localvideo').srcObject = null;
|
|
975
|
+
}
|
|
976
|
+
if (media.type === 'remoteVideo') {
|
|
977
|
+
document.getElementById('remotevideo').srcObject = null;
|
|
978
|
+
}
|
|
979
|
+
if (media.type === 'remoteAudio') {
|
|
980
|
+
document.getElementById('remoteaudio').srcObject = null;
|
|
981
|
+
}
|
|
982
|
+
if (media.type === 'localShare') {
|
|
983
|
+
document.getElementById('localshare').srcObject = null;
|
|
984
|
+
}
|
|
985
|
+
if (media.type === 'remoteShare') {
|
|
986
|
+
document.getElementById('sharevideo').srcObject = null;
|
|
987
|
+
}
|
|
988
|
+
});
|
|
989
|
+
```
|
|
990
|
+
|
|
991
|
+
`meeting:alerted` does not have a payload
|
|
992
|
+
|
|
993
|
+
`meeting:ringing` has the following payload
|
|
994
|
+
|
|
995
|
+
```js
|
|
996
|
+
{
|
|
997
|
+
type // INCOMING or JOIN
|
|
998
|
+
id // the meeting id
|
|
999
|
+
}
|
|
1000
|
+
```
|
|
1001
|
+
|
|
1002
|
+
`meeting:ringingStop` has the following payload
|
|
1003
|
+
|
|
1004
|
+
```js
|
|
1005
|
+
{
|
|
1006
|
+
type // Object {remoteAnswered: boolean, remoteDeclined: boolean}
|
|
1007
|
+
id // the meeting id
|
|
1008
|
+
}
|
|
1009
|
+
```
|
|
1010
|
+
|
|
1011
|
+
`meeting:startedSharingLocal` does not have a payload
|
|
1012
|
+
|
|
1013
|
+
`meeting:stoppedSharingLocal` does not have a payload
|
|
1014
|
+
|
|
1015
|
+
`meeting:self:lobbyWaiting` has the following payload
|
|
1016
|
+
|
|
1017
|
+
```js
|
|
1018
|
+
{
|
|
1019
|
+
payload; // self object
|
|
1020
|
+
}
|
|
1021
|
+
```
|
|
1022
|
+
|
|
1023
|
+
`meeting:self:guestAdmitted` has the following payload
|
|
1024
|
+
|
|
1025
|
+
```js
|
|
1026
|
+
{
|
|
1027
|
+
payload; // self object
|
|
1028
|
+
}
|
|
1029
|
+
```
|
|
1030
|
+
|
|
1031
|
+
`meeting:self:mutedByOthers` has the following payload
|
|
1032
|
+
|
|
1033
|
+
```js
|
|
1034
|
+
{
|
|
1035
|
+
payload; // self object
|
|
1036
|
+
}
|
|
1037
|
+
```
|
|
1038
|
+
|
|
1039
|
+
`meeting:reconnectionStarting` does not have a payload
|
|
1040
|
+
|
|
1041
|
+
`meeting:reconnectionSuccess` has the following payload
|
|
1042
|
+
|
|
1043
|
+
```js
|
|
1044
|
+
{
|
|
1045
|
+
reconnect; // the media promise resolution
|
|
1046
|
+
}
|
|
1047
|
+
```
|
|
1048
|
+
|
|
1049
|
+
`meeting:reconnectionFailure` has the following payload
|
|
1050
|
+
|
|
1051
|
+
```js
|
|
1052
|
+
{
|
|
1053
|
+
error; // the forwarded error from media
|
|
1054
|
+
}
|
|
1055
|
+
```
|
|
1056
|
+
|
|
1057
|
+
`meeting:unlocked` has the following payload
|
|
1058
|
+
|
|
1059
|
+
```js
|
|
1060
|
+
{
|
|
1061
|
+
info; // info object
|
|
1062
|
+
}
|
|
1063
|
+
```
|
|
1064
|
+
|
|
1065
|
+
`meeting:locked` has the following payload
|
|
1066
|
+
|
|
1067
|
+
```js
|
|
1068
|
+
{
|
|
1069
|
+
info; // info object
|
|
1070
|
+
}
|
|
1071
|
+
```
|
|
1072
|
+
|
|
1073
|
+
`meeting:actionsUpdate` has the following payload
|
|
1074
|
+
|
|
1075
|
+
```js
|
|
1076
|
+
{
|
|
1077
|
+
canInviteNewParticipants, // boolean
|
|
1078
|
+
canAdmitParticipant, // boolean
|
|
1079
|
+
canLock, // boolean
|
|
1080
|
+
canUnlock, // boolean
|
|
1081
|
+
canAssignHost, // boolean
|
|
1082
|
+
canStartRecording, // boolean
|
|
1083
|
+
canPauseRecording, // boolean
|
|
1084
|
+
canResumeRecording, // boolean
|
|
1085
|
+
canStopRecording, // boolean
|
|
1086
|
+
canRaiseHand, //boolean
|
|
1087
|
+
canLowerAllHands, //boolean
|
|
1088
|
+
canLowerSomeoneElsesHand, //boolean
|
|
1089
|
+
bothLeaveAndEndMeetingAvailable, //boolean
|
|
1090
|
+
}
|
|
1091
|
+
```
|
|
1092
|
+
|
|
1093
|
+
`meeting:recording:started`
|
|
1094
|
+
`meeting:recording:stopped`
|
|
1095
|
+
`meeting:recording:paused`
|
|
1096
|
+
`meeting:recording:resumed` have the following payload
|
|
1097
|
+
|
|
1098
|
+
```js
|
|
1099
|
+
{
|
|
1100
|
+
state; // could be etiher `recording`, `idle` or `paused`
|
|
1101
|
+
modifiedBy; // user's decrypted ID who made an action
|
|
1102
|
+
lastModified; // when the action was made
|
|
1103
|
+
}
|
|
1104
|
+
```
|
|
1105
|
+
|
|
1106
|
+
### Event Caveats
|
|
1107
|
+
|
|
1108
|
+
##### Remote screen share is not displayed if started before participant joins
|
|
1109
|
+
|
|
1110
|
+
If you notice that the remote screen share is not being displayed to a participant when they join
|
|
1111
|
+
after a screen has already been shared, double-check that you are following the standard plugin-meeting workflow.
|
|
1112
|
+
|
|
1113
|
+
Standard plugin-meeting workflow is as follows:
|
|
1114
|
+
|
|
1115
|
+
1. Set event listener for `media:ready`
|
|
1116
|
+
2. Call `join()`
|
|
1117
|
+
3. Call `addMedia()` with `options.mediaSettings.receiveShare=true`
|
|
1118
|
+
4. Wait to receive an event from `media:ready` with payload `type=remoteShare` that contains the remote share media stream
|
|
1119
|
+
5. Set `srcObject` of a `video` element in the application to the previously obtained media stream
|
|
1120
|
+
(e.g. `document.getElementById('remote-screen').srcObject = media.stream`)
|
|
1121
|
+
|
|
1122
|
+
In most cases this will resolve the issue though an extra step could be to
|
|
1123
|
+
use `meeting.shareStatus` to control whether to show the video element or not.
|
|
1124
|
+
|
|
1125
|
+
This may be necessary as you can only register for events like `meeting:startedSharingRemote` on the
|
|
1126
|
+
meeting object, however, you can only do that after you've received the `meeting:added` event notification
|
|
1127
|
+
with the meeting payload. In the case when a host has already begun sharing before a participant joins,
|
|
1128
|
+
the registration for `meeting:startedSharingRemote` happens too late (after the SDK code that would send
|
|
1129
|
+
that event is already executed). Thus, you can check the value of `meeting.shareStatus` when you join the meeting
|
|
1130
|
+
to control whether to show that video element (the one that has srcObject set to the remote share stream) on the screen or not.
|
|
1131
|
+
|
|
1132
|
+
### Members Events
|
|
1133
|
+
|
|
1134
|
+
```js
|
|
1135
|
+
meeting.members.on(...)
|
|
1136
|
+
```
|
|
1137
|
+
|
|
1138
|
+
There are several events submitted by this package that you can subscribe to.
|
|
1139
|
+
| Event Name | Description |
|
|
1140
|
+
|---|---|
|
|
1141
|
+
| `members:update` | Fired when a member in the collection has been updated |
|
|
1142
|
+
| `members:content:update` | Fired when a member in the collection has a changed content stream (share screen) |
|
|
1143
|
+
| `members:host:update` | Fired when a member in the collection has a changed host value |
|
|
1144
|
+
| `members:self:update` | Fired when a member in the collection has a changed self value |
|
|
1145
|
+
|---|---|
|
|
1146
|
+
|
|
1147
|
+
`members:update` has the following payload
|
|
1148
|
+
|
|
1149
|
+
```js
|
|
1150
|
+
{
|
|
1151
|
+
delta: { // the changes to the members list
|
|
1152
|
+
updated // array only the updates, includes removals, as they will have updated status and member properties
|
|
1153
|
+
added // array added members to the meeting
|
|
1154
|
+
}
|
|
1155
|
+
full: // array the full members collection
|
|
1156
|
+
}
|
|
1157
|
+
```
|
|
1158
|
+
|
|
1159
|
+
`members:content:update` has the following payload
|
|
1160
|
+
|
|
1161
|
+
```js
|
|
1162
|
+
{
|
|
1163
|
+
activeContentSharingId; // the member id
|
|
1164
|
+
endedContentSharingId; // the member id
|
|
1165
|
+
}
|
|
1166
|
+
```
|
|
1167
|
+
|
|
1168
|
+
`members:host:update` has the following payload
|
|
1169
|
+
|
|
1170
|
+
```js
|
|
1171
|
+
{
|
|
1172
|
+
activeHostId; // the member id
|
|
1173
|
+
endedHostId; // the member id
|
|
1174
|
+
}
|
|
1175
|
+
```
|
|
1176
|
+
|
|
1177
|
+
`members:self:update` has the following payload
|
|
1178
|
+
|
|
1179
|
+
```js
|
|
1180
|
+
{
|
|
1181
|
+
activeSelfId; // the member id
|
|
1182
|
+
endedSelfId; // the member id
|
|
1183
|
+
}
|
|
1184
|
+
```
|
|
1185
|
+
|
|
1186
|
+
## Development
|
|
1187
|
+
|
|
1188
|
+
To use `webpack-dev-server` to load this package, run `yarn run samples:serve`.
|
|
1189
|
+
|
|
1190
|
+
Files placed in the `docs/samples/browser-plugin-meetings` folder will be served statically.
|
|
1191
|
+
|
|
1192
|
+
Files in the `src` folder will be compiled, bundled, and served as a static asset at `bundle.js` inside that directory.
|
|
1193
|
+
|
|
1194
|
+
## Maintainers
|
|
1195
|
+
|
|
1196
|
+
This package is maintained by [Cisco Webex for Developers](https://developer.webex.com/).
|
|
1197
|
+
|
|
1198
|
+
## Contribute
|
|
1199
|
+
|
|
1200
|
+
Pull requests welcome. Please see [CONTRIBUTING.md](https://github.com/webex/webex-js-sdk/blob/master/CONTRIBUTING.md) for more details.
|
|
1201
|
+
|
|
1202
|
+
## License
|
|
1203
|
+
|
|
1204
|
+
© 2016-2020 Cisco and/or its affiliates. All Rights Reserved.
|