@webex/plugin-meetings 3.4.0 → 3.5.0-next.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/dist/breakouts/breakout.js +1 -1
  2. package/dist/breakouts/index.js +1 -1
  3. package/dist/interpretation/index.js +1 -1
  4. package/dist/interpretation/siLanguage.js +1 -1
  5. package/dist/media/index.js +6 -9
  6. package/dist/media/index.js.map +1 -1
  7. package/dist/meeting/index.js +151 -50
  8. package/dist/meeting/index.js.map +1 -1
  9. package/dist/meeting/util.js +1 -0
  10. package/dist/meeting/util.js.map +1 -1
  11. package/dist/meetings/index.js +11 -2
  12. package/dist/meetings/index.js.map +1 -1
  13. package/dist/reachability/index.js +175 -103
  14. package/dist/reachability/index.js.map +1 -1
  15. package/dist/reconnection-manager/index.js +1 -1
  16. package/dist/reconnection-manager/index.js.map +1 -1
  17. package/dist/rtcMetrics/index.js +26 -6
  18. package/dist/rtcMetrics/index.js.map +1 -1
  19. package/dist/types/meeting/index.d.ts +22 -2
  20. package/dist/types/meetings/index.d.ts +4 -2
  21. package/dist/types/reachability/index.d.ts +14 -2
  22. package/dist/types/rtcMetrics/index.d.ts +11 -1
  23. package/dist/webinar/index.js +1 -1
  24. package/package.json +22 -22
  25. package/src/media/index.ts +5 -9
  26. package/src/meeting/index.ts +88 -10
  27. package/src/meeting/util.ts +2 -0
  28. package/src/meetings/index.ts +11 -4
  29. package/src/reachability/index.ts +49 -4
  30. package/src/reconnection-manager/index.ts +1 -1
  31. package/src/rtcMetrics/index.ts +25 -5
  32. package/test/integration/spec/converged-space-meetings.js +1 -1
  33. package/test/unit/spec/breakouts/index.ts +1 -0
  34. package/test/unit/spec/interceptors/locusRetry.ts +11 -10
  35. package/test/unit/spec/media/MediaConnectionAwaiter.ts +1 -0
  36. package/test/unit/spec/media/index.ts +34 -7
  37. package/test/unit/spec/media/properties.ts +1 -1
  38. package/test/unit/spec/meeting/connectionStateHandler.ts +1 -0
  39. package/test/unit/spec/meeting/index.js +116 -12
  40. package/test/unit/spec/meeting/locusMediaRequest.ts +3 -2
  41. package/test/unit/spec/meeting/request.js +1 -0
  42. package/test/unit/spec/meeting/utils.js +4 -0
  43. package/test/unit/spec/meeting-info/meetinginfov2.js +10 -11
  44. package/test/unit/spec/meeting-info/request.js +1 -1
  45. package/test/unit/spec/meetings/index.js +40 -5
  46. package/test/unit/spec/members/request.js +2 -1
  47. package/test/unit/spec/multistream/mediaRequestManager.ts +1 -0
  48. package/test/unit/spec/multistream/receiveSlot.ts +1 -0
  49. package/test/unit/spec/multistream/receiveSlotManager.ts +1 -0
  50. package/test/unit/spec/multistream/remoteMedia.ts +1 -0
  51. package/test/unit/spec/multistream/remoteMediaGroup.ts +1 -0
  52. package/test/unit/spec/multistream/remoteMediaManager.ts +1 -0
  53. package/test/unit/spec/multistream/sendSlotManager.ts +1 -0
  54. package/test/unit/spec/personal-meeting-room/personal-meeting-room.js +0 -1
  55. package/test/unit/spec/reachability/index.ts +211 -13
  56. package/test/unit/spec/reachability/request.js +1 -0
  57. package/test/unit/spec/roap/request.ts +1 -0
  58. package/test/unit/spec/rtcMetrics/index.ts +31 -0
  59. package/dist/networkQualityMonitor/index.js +0 -227
  60. package/dist/networkQualityMonitor/index.js.map +0 -1
  61. package/dist/types/networkQualityMonitor/index.d.ts +0 -70
  62. package/src/networkQualityMonitor/index.ts +0 -211
  63. package/test/unit/spec/networkQualityMonitor/index.js +0 -99
@@ -1 +1 @@
1
- {"version":3,"names":["_internalPluginMetrics","require","_uuid","_interopRequireDefault","_constants","parseJsonPayload","payload","JSON","parse","_","RtcMetrics","exports","default","webex","meetingId","correlationId","_classCallCheck2","_defineProperty2","intervalId","window","setInterval","sendMetricsInQueue","bind","setNewConnectionId","setTimeout","_createClass2","key","value","metricsQueue","length","sendMetrics","addMetrics","data","name","map","anonymizeIp","push","parsedPayload","e","console","error","closeMetrics","clearInterval","stats","type","ip","CallDiagnosticUtils","anonymizeIPAddress","undefined","address","relatedAddress","_stringify","connectionId","uuid","v4","request","method","service","resource","headers","appId","RTC_METRICS","APP_ID","body","metrics","version","userId","internal","device"],"sources":["index.ts"],"sourcesContent":["/* eslint-disable class-methods-use-this */\nimport {CallDiagnosticUtils} from '@webex/internal-plugin-metrics';\nimport uuid from 'uuid';\nimport RTC_METRICS from './constants';\n\nconst parseJsonPayload = (payload: any[]): any | null => {\n try {\n if (payload && payload[0]) {\n return JSON.parse(payload[0]);\n }\n\n return null;\n } catch (_) {\n return null;\n }\n};\n\n/**\n * Rtc Metrics\n */\nexport default class RtcMetrics {\n /**\n * Array of MetricData items to be sent to the metrics service.\n */\n metricsQueue = [];\n\n intervalId: number;\n\n webex: any;\n\n meetingId: string;\n\n correlationId: string;\n\n connectionId: string;\n\n /**\n * Initialize the interval.\n *\n * @param {object} webex - The main `webex` object.\n * @param {string} meetingId - The meeting id.\n * @param {string} correlationId - The correlation id.\n */\n constructor(webex, meetingId, correlationId) {\n // `window` is used to prevent typescript from returning a NodeJS.Timer.\n this.intervalId = window.setInterval(this.sendMetricsInQueue.bind(this), 30 * 1000);\n this.meetingId = meetingId;\n this.webex = webex;\n this.correlationId = correlationId;\n this.setNewConnectionId();\n // Send the first set of metrics at 5 seconds in the case of a user leaving the call shortly after joining.\n setTimeout(this.sendMetricsInQueue.bind(this), 5 * 1000);\n }\n\n /**\n * Check to see if the metrics queue has any items.\n *\n * @returns {void}\n */\n public sendMetricsInQueue() {\n if (this.metricsQueue.length) {\n this.sendMetrics();\n this.metricsQueue = [];\n }\n }\n\n /**\n * Add metrics items to the metrics queue.\n *\n * @param {object} data - An object with a payload array of metrics items.\n *\n * @returns {void}\n */\n addMetrics(data) {\n if (data.payload.length) {\n if (data.name === 'stats-report') {\n data.payload = data.payload.map(this.anonymizeIp);\n }\n\n this.metricsQueue.push(data);\n\n try {\n // If a connection fails, send the rest of the metrics in queue and get a new connection id.\n const parsedPayload = parseJsonPayload(data.payload);\n if (\n data.name === 'onconnectionstatechange' &&\n parsedPayload &&\n parsedPayload.value === 'failed'\n ) {\n this.sendMetricsInQueue();\n this.setNewConnectionId();\n }\n } catch (e) {\n console.error(e);\n }\n }\n }\n\n /**\n * Clear the metrics interval.\n *\n * @returns {void}\n */\n closeMetrics() {\n this.sendMetricsInQueue();\n clearInterval(this.intervalId);\n }\n\n /**\n * Anonymize IP addresses.\n *\n * @param {array} stats - An RTCStatsReport organized into an array of strings.\n * @returns {string}\n */\n anonymizeIp(stats: string): string {\n const data = JSON.parse(stats);\n // on local and remote candidates, anonymize the last 4 bits.\n if (data.type === 'local-candidate' || data.type === 'remote-candidate') {\n data.ip = CallDiagnosticUtils.anonymizeIPAddress(data.ip) || undefined;\n data.address = CallDiagnosticUtils.anonymizeIPAddress(data.address) || undefined;\n data.relatedAddress =\n CallDiagnosticUtils.anonymizeIPAddress(data.relatedAddress) || undefined;\n }\n\n return JSON.stringify(data);\n }\n\n /**\n * Set a new connection id.\n *\n * @returns {void}\n */\n private setNewConnectionId() {\n this.connectionId = uuid.v4();\n }\n\n /**\n * Send metrics to the metrics service.\n *\n * @returns {void}\n */\n private sendMetrics() {\n this.webex.request({\n method: 'POST',\n service: 'unifiedTelemetry',\n resource: 'metric/v2',\n headers: {\n type: 'webrtcMedia',\n appId: RTC_METRICS.APP_ID,\n },\n body: {\n metrics: [\n {\n type: 'webrtc',\n version: '1.1.0',\n userId: this.webex.internal.device.userId,\n meetingId: this.meetingId,\n correlationId: this.correlationId,\n connectionId: this.connectionId,\n data: this.metricsQueue,\n },\n ],\n },\n });\n }\n}\n"],"mappings":";;;;;;;;;;;;AACA,IAAAA,sBAAA,GAAAC,OAAA;AACA,IAAAC,KAAA,GAAAC,sBAAA,CAAAF,OAAA;AACA,IAAAG,UAAA,GAAAD,sBAAA,CAAAF,OAAA;AAHA;;AAKA,IAAMI,gBAAgB,GAAG,SAAnBA,gBAAgBA,CAAIC,OAAc,EAAiB;EACvD,IAAI;IACF,IAAIA,OAAO,IAAIA,OAAO,CAAC,CAAC,CAAC,EAAE;MACzB,OAAOC,IAAI,CAACC,KAAK,CAACF,OAAO,CAAC,CAAC,CAAC,CAAC;IAC/B;IAEA,OAAO,IAAI;EACb,CAAC,CAAC,OAAOG,CAAC,EAAE;IACV,OAAO,IAAI;EACb;AACF,CAAC;;AAED;AACA;AACA;AAFA,IAGqBC,UAAU,GAAAC,OAAA,CAAAC,OAAA;EAgB7B;AACF;AACA;AACA;AACA;AACA;AACA;EACE,SAAAF,WAAYG,KAAK,EAAEC,SAAS,EAAEC,aAAa,EAAE;IAAA,IAAAC,gBAAA,CAAAJ,OAAA,QAAAF,UAAA;IAtB7C;AACF;AACA;IAFE,IAAAO,gBAAA,CAAAL,OAAA,wBAGe,EAAE;IAAA,IAAAK,gBAAA,CAAAL,OAAA;IAAA,IAAAK,gBAAA,CAAAL,OAAA;IAAA,IAAAK,gBAAA,CAAAL,OAAA;IAAA,IAAAK,gBAAA,CAAAL,OAAA;IAAA,IAAAK,gBAAA,CAAAL,OAAA;IAoBf;IACA,IAAI,CAACM,UAAU,GAAGC,MAAM,CAACC,WAAW,CAAC,IAAI,CAACC,kBAAkB,CAACC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,GAAG,IAAI,CAAC;IACnF,IAAI,CAACR,SAAS,GAAGA,SAAS;IAC1B,IAAI,CAACD,KAAK,GAAGA,KAAK;IAClB,IAAI,CAACE,aAAa,GAAGA,aAAa;IAClC,IAAI,CAACQ,kBAAkB,CAAC,CAAC;IACzB;IACAC,UAAU,CAAC,IAAI,CAACH,kBAAkB,CAACC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC;EAC1D;;EAEA;AACF;AACA;AACA;AACA;EAJE,IAAAG,aAAA,CAAAb,OAAA,EAAAF,UAAA;IAAAgB,GAAA;IAAAC,KAAA,EAKA,SAAAN,mBAAA,EAA4B;MAC1B,IAAI,IAAI,CAACO,YAAY,CAACC,MAAM,EAAE;QAC5B,IAAI,CAACC,WAAW,CAAC,CAAC;QAClB,IAAI,CAACF,YAAY,GAAG,EAAE;MACxB;IACF;;IAEA;AACF;AACA;AACA;AACA;AACA;AACA;EANE;IAAAF,GAAA;IAAAC,KAAA,EAOA,SAAAI,WAAWC,IAAI,EAAE;MACf,IAAIA,IAAI,CAAC1B,OAAO,CAACuB,MAAM,EAAE;QACvB,IAAIG,IAAI,CAACC,IAAI,KAAK,cAAc,EAAE;UAChCD,IAAI,CAAC1B,OAAO,GAAG0B,IAAI,CAAC1B,OAAO,CAAC4B,GAAG,CAAC,IAAI,CAACC,WAAW,CAAC;QACnD;QAEA,IAAI,CAACP,YAAY,CAACQ,IAAI,CAACJ,IAAI,CAAC;QAE5B,IAAI;UACF;UACA,IAAMK,aAAa,GAAGhC,gBAAgB,CAAC2B,IAAI,CAAC1B,OAAO,CAAC;UACpD,IACE0B,IAAI,CAACC,IAAI,KAAK,yBAAyB,IACvCI,aAAa,IACbA,aAAa,CAACV,KAAK,KAAK,QAAQ,EAChC;YACA,IAAI,CAACN,kBAAkB,CAAC,CAAC;YACzB,IAAI,CAACE,kBAAkB,CAAC,CAAC;UAC3B;QACF,CAAC,CAAC,OAAOe,CAAC,EAAE;UACVC,OAAO,CAACC,KAAK,CAACF,CAAC,CAAC;QAClB;MACF;IACF;;IAEA;AACF;AACA;AACA;AACA;EAJE;IAAAZ,GAAA;IAAAC,KAAA,EAKA,SAAAc,aAAA,EAAe;MACb,IAAI,CAACpB,kBAAkB,CAAC,CAAC;MACzBqB,aAAa,CAAC,IAAI,CAACxB,UAAU,CAAC;IAChC;;IAEA;AACF;AACA;AACA;AACA;AACA;EALE;IAAAQ,GAAA;IAAAC,KAAA,EAMA,SAAAQ,YAAYQ,KAAa,EAAU;MACjC,IAAMX,IAAI,GAAGzB,IAAI,CAACC,KAAK,CAACmC,KAAK,CAAC;MAC9B;MACA,IAAIX,IAAI,CAACY,IAAI,KAAK,iBAAiB,IAAIZ,IAAI,CAACY,IAAI,KAAK,kBAAkB,EAAE;QACvEZ,IAAI,CAACa,EAAE,GAAGC,0CAAmB,CAACC,kBAAkB,CAACf,IAAI,CAACa,EAAE,CAAC,IAAIG,SAAS;QACtEhB,IAAI,CAACiB,OAAO,GAAGH,0CAAmB,CAACC,kBAAkB,CAACf,IAAI,CAACiB,OAAO,CAAC,IAAID,SAAS;QAChFhB,IAAI,CAACkB,cAAc,GACjBJ,0CAAmB,CAACC,kBAAkB,CAACf,IAAI,CAACkB,cAAc,CAAC,IAAIF,SAAS;MAC5E;MAEA,OAAO,IAAAG,UAAA,CAAAvC,OAAA,EAAeoB,IAAI,CAAC;IAC7B;;IAEA;AACF;AACA;AACA;AACA;EAJE;IAAAN,GAAA;IAAAC,KAAA,EAKA,SAAAJ,mBAAA,EAA6B;MAC3B,IAAI,CAAC6B,YAAY,GAAGC,aAAI,CAACC,EAAE,CAAC,CAAC;IAC/B;;IAEA;AACF;AACA;AACA;AACA;EAJE;IAAA5B,GAAA;IAAAC,KAAA,EAKA,SAAAG,YAAA,EAAsB;MACpB,IAAI,CAACjB,KAAK,CAAC0C,OAAO,CAAC;QACjBC,MAAM,EAAE,MAAM;QACdC,OAAO,EAAE,kBAAkB;QAC3BC,QAAQ,EAAE,WAAW;QACrBC,OAAO,EAAE;UACPf,IAAI,EAAE,aAAa;UACnBgB,KAAK,EAAEC,kBAAW,CAACC;QACrB,CAAC;QACDC,IAAI,EAAE;UACJC,OAAO,EAAE,CACP;YACEpB,IAAI,EAAE,QAAQ;YACdqB,OAAO,EAAE,OAAO;YAChBC,MAAM,EAAE,IAAI,CAACrD,KAAK,CAACsD,QAAQ,CAACC,MAAM,CAACF,MAAM;YACzCpD,SAAS,EAAE,IAAI,CAACA,SAAS;YACzBC,aAAa,EAAE,IAAI,CAACA,aAAa;YACjCqC,YAAY,EAAE,IAAI,CAACA,YAAY;YAC/BpB,IAAI,EAAE,IAAI,CAACJ;UACb,CAAC;QAEL;MACF,CAAC,CAAC;IACJ;EAAC;EAAA,OAAAlB,UAAA;AAAA"}
1
+ {"version":3,"names":["_internalPluginMetrics","require","_uuid","_interopRequireDefault","_constants","parseJsonPayload","payload","JSON","parse","_","RtcMetrics","exports","default","webex","meetingId","correlationId","_classCallCheck2","_defineProperty2","intervalId","window","setInterval","sendMetricsInQueue","bind","resetConnection","_createClass2","key","value","metricsQueue","length","sendMetrics","sendNextMetrics","shouldSendMetricsOnNextStatsReport","addMetrics","data","name","map","anonymizeIp","push","parsedPayload","e","console","error","closeMetrics","clearInterval","stats","type","ip","CallDiagnosticUtils","anonymizeIPAddress","undefined","address","relatedAddress","_stringify","connectionId","uuid","v4","request","method","service","resource","headers","appId","RTC_METRICS","APP_ID","body","metrics","version","userId","internal","device"],"sources":["index.ts"],"sourcesContent":["/* eslint-disable class-methods-use-this */\nimport {CallDiagnosticUtils} from '@webex/internal-plugin-metrics';\nimport uuid from 'uuid';\nimport RTC_METRICS from './constants';\n\nconst parseJsonPayload = (payload: any[]): any | null => {\n try {\n if (payload && payload[0]) {\n return JSON.parse(payload[0]);\n }\n\n return null;\n } catch (_) {\n return null;\n }\n};\n\n/**\n * Rtc Metrics\n */\nexport default class RtcMetrics {\n /**\n * Array of MetricData items to be sent to the metrics service.\n */\n metricsQueue = [];\n\n intervalId: number;\n\n webex: any;\n\n meetingId: string;\n\n correlationId: string;\n\n connectionId: string;\n\n shouldSendMetricsOnNextStatsReport: boolean;\n\n /**\n * Initialize the interval.\n *\n * @param {object} webex - The main `webex` object.\n * @param {string} meetingId - The meeting id.\n * @param {string} correlationId - The correlation id.\n */\n constructor(webex, meetingId, correlationId) {\n // `window` is used to prevent typescript from returning a NodeJS.Timer.\n this.intervalId = window.setInterval(this.sendMetricsInQueue.bind(this), 30 * 1000);\n this.meetingId = meetingId;\n this.webex = webex;\n this.correlationId = correlationId;\n this.resetConnection();\n }\n\n /**\n * Check to see if the metrics queue has any items.\n *\n * @returns {void}\n */\n public sendMetricsInQueue() {\n if (this.metricsQueue.length) {\n this.sendMetrics();\n this.metricsQueue = [];\n }\n }\n\n /**\n * Forces sending metrics when we get the next stats-report\n *\n * This is useful for cases when something important happens that affects the media connection,\n * for example when we move from lobby into the meeting.\n *\n * @returns {void}\n */\n public sendNextMetrics() {\n this.shouldSendMetricsOnNextStatsReport = true;\n }\n\n /**\n * Add metrics items to the metrics queue.\n *\n * @param {object} data - An object with a payload array of metrics items.\n *\n * @returns {void}\n */\n addMetrics(data) {\n if (data.payload.length) {\n if (data.name === 'stats-report') {\n data.payload = data.payload.map(this.anonymizeIp);\n }\n\n this.metricsQueue.push(data);\n\n if (this.shouldSendMetricsOnNextStatsReport && data.name === 'stats-report') {\n // this is the first useful set of data (WCME gives it to us after 5s), send it out immediately\n // in case the user is unhappy and closes the browser early\n this.sendMetricsInQueue();\n this.shouldSendMetricsOnNextStatsReport = false;\n }\n\n try {\n // If a connection fails, send the rest of the metrics in queue and get a new connection id.\n const parsedPayload = parseJsonPayload(data.payload);\n if (\n data.name === 'onconnectionstatechange' &&\n parsedPayload &&\n parsedPayload.value === 'failed'\n ) {\n this.sendMetricsInQueue();\n this.resetConnection();\n }\n } catch (e) {\n console.error(e);\n }\n }\n }\n\n /**\n * Clear the metrics interval.\n *\n * @returns {void}\n */\n closeMetrics() {\n this.sendMetricsInQueue();\n clearInterval(this.intervalId);\n }\n\n /**\n * Anonymize IP addresses.\n *\n * @param {array} stats - An RTCStatsReport organized into an array of strings.\n * @returns {string}\n */\n anonymizeIp(stats: string): string {\n const data = JSON.parse(stats);\n // on local and remote candidates, anonymize the last 4 bits.\n if (data.type === 'local-candidate' || data.type === 'remote-candidate') {\n data.ip = CallDiagnosticUtils.anonymizeIPAddress(data.ip) || undefined;\n data.address = CallDiagnosticUtils.anonymizeIPAddress(data.address) || undefined;\n data.relatedAddress =\n CallDiagnosticUtils.anonymizeIPAddress(data.relatedAddress) || undefined;\n }\n\n return JSON.stringify(data);\n }\n\n /**\n * Set a new connection id.\n *\n * @returns {void}\n */\n private resetConnection() {\n this.connectionId = uuid.v4();\n this.shouldSendMetricsOnNextStatsReport = true;\n }\n\n /**\n * Send metrics to the metrics service.\n *\n * @returns {void}\n */\n private sendMetrics() {\n this.webex.request({\n method: 'POST',\n service: 'unifiedTelemetry',\n resource: 'metric/v2',\n headers: {\n type: 'webrtcMedia',\n appId: RTC_METRICS.APP_ID,\n },\n body: {\n metrics: [\n {\n type: 'webrtc',\n version: '1.1.0',\n userId: this.webex.internal.device.userId,\n meetingId: this.meetingId,\n correlationId: this.correlationId,\n connectionId: this.connectionId,\n data: this.metricsQueue,\n },\n ],\n },\n });\n }\n}\n"],"mappings":"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"}
@@ -2,9 +2,8 @@
2
2
  import { StatelessWebexPlugin } from '@webex/webex-core';
3
3
  import { ClientEvent, ClientEventLeaveReason } from '@webex/internal-plugin-metrics';
4
4
  import { ClientEvent as RawClientEvent } from '@webex/event-dictionary-ts';
5
- import { MediaType, StatsAnalyzer } from '@webex/internal-media-core';
5
+ import { MediaType, StatsAnalyzer, NetworkQualityMonitor } from '@webex/internal-media-core';
6
6
  import { LocalStream, LocalCameraStream, LocalDisplayStream, LocalSystemAudioStream, LocalMicrophoneStream } from '@webex/media-helpers';
7
- import NetworkQualityMonitor from '../networkQualityMonitor';
8
7
  import Roap, { type TurnServerInfo, type TurnDiscoverySkipReason } from '../roap/index';
9
8
  import { type BundlePolicy } from '../media';
10
9
  import MediaProperties from '../media/properties';
@@ -68,6 +67,7 @@ export type AddMediaOptions = {
68
67
  };
69
68
  export type CallStateForMetrics = {
70
69
  correlationId?: string;
70
+ sessionCorrelationId?: string;
71
71
  joinTrigger?: string;
72
72
  loginType?: string;
73
73
  };
@@ -334,6 +334,7 @@ type FetchMeetingInfoParams = {
334
334
  * @class Meeting
335
335
  */
336
336
  export default class Meeting extends StatelessWebexPlugin {
337
+ #private;
337
338
  attrs: any;
338
339
  audio: any;
339
340
  breakouts: any;
@@ -458,6 +459,7 @@ export default class Meeting extends StatelessWebexPlugin {
458
459
  private connectionStateHandler?;
459
460
  private iceCandidateErrors;
460
461
  private iceCandidatesCount;
462
+ private rtcMetrics?;
461
463
  /**
462
464
  * @param {Object} attrs
463
465
  * @param {Object} options
@@ -487,6 +489,22 @@ export default class Meeting extends StatelessWebexPlugin {
487
489
  * @param {string} correlationId
488
490
  */
489
491
  set correlationId(correlationId: string);
492
+ /**
493
+ * Getter - Returns callStateForMetrics.sessionCorrelationId
494
+ * @returns {string}
495
+ */
496
+ get sessionCorrelationId(): string;
497
+ /**
498
+ * Setter - sets callStateForMetrics.sessionCorrelationId
499
+ * @param {string} sessionCorrelationId
500
+ */
501
+ set sessionCorrelationId(sessionCorrelationId: string);
502
+ /**
503
+ * Getter - Returns isoLocalClientMeetingJoinTime
504
+ * This will be set once on meeting join, and not updated again
505
+ * @returns {string | undefined}
506
+ */
507
+ get isoLocalClientMeetingJoinTime(): string | undefined;
490
508
  /**
491
509
  * Set meeting info and trigger `MEETING_INFO_AVAILABLE` event
492
510
  * @param {any} info
@@ -1295,6 +1313,8 @@ export default class Meeting extends StatelessWebexPlugin {
1295
1313
  *
1296
1314
  * @private
1297
1315
  * @static
1316
+ * @param {boolean} isAudioEnabled
1317
+ * @param {boolean} isVideoEnabled
1298
1318
  * @returns {Promise<void>}
1299
1319
  */
1300
1320
  private static handleDeviceLogging;
@@ -253,11 +253,12 @@ export default class Meetings extends WebexPlugin {
253
253
  getReachability(): Reachability;
254
254
  /**
255
255
  * initializes and starts gathering reachability for Meetings
256
+ * @param {string} trigger - explains the reason for starting reachability
256
257
  * @returns {Promise}
257
258
  * @public
258
259
  * @memberof Meetings
259
260
  */
260
- startReachability(): Promise<import("../reachability").ReachabilityResults>;
261
+ startReachability(trigger?: string): Promise<import("../reachability").ReachabilityResults>;
261
262
  /**
262
263
  * Get geoHint for info for meetings
263
264
  * @returns {Promise}
@@ -303,11 +304,12 @@ export default class Meetings extends WebexPlugin {
303
304
  * @param {CallStateForMetrics} callStateForMetrics - information about call state for metrics
304
305
  * @param {Object} [meetingInfo] - Pre-fetched complete meeting info
305
306
  * @param {String} [meetingLookupUrl] - meeting info prefetch url
307
+ * @param {string} sessionCorrelationId - the optional specified sessionCorrelationId (callStateForMetrics.sessionCorrelationId) can be provided instead
306
308
  * @returns {Promise<Meeting>} A new Meeting.
307
309
  * @public
308
310
  * @memberof Meetings
309
311
  */
310
- create(destination: string, type?: DESTINATION_TYPE, useRandomDelayForInfo?: boolean, infoExtraParams?: {}, correlationId?: string, failOnMissingMeetingInfo?: boolean, callStateForMetrics?: CallStateForMetrics, meetingInfo?: any, meetingLookupUrl?: any): any;
312
+ create(destination: string, type?: DESTINATION_TYPE, useRandomDelayForInfo?: boolean, infoExtraParams?: {}, correlationId?: string, failOnMissingMeetingInfo?: boolean, callStateForMetrics?: CallStateForMetrics, meetingInfo?: any, meetingLookupUrl?: any, sessionCorrelationId?: string): any;
311
313
  /**
312
314
  * Create meeting
313
315
  *
@@ -2,7 +2,7 @@
2
2
  * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
3
  */
4
4
  import { Defer } from '@webex/common';
5
- import ReachabilityRequest from './request';
5
+ import ReachabilityRequest, { ClusterList } from './request';
6
6
  import { ClusterReachability, ClusterReachabilityResult } from './clusterReachability';
7
7
  import EventsScope from '../common/events/events-scope';
8
8
  export type ReachabilityMetrics = {
@@ -73,19 +73,31 @@ export default class Reachability extends EventsScope {
73
73
  xtls: number;
74
74
  };
75
75
  };
76
+ protected lastTrigger?: string;
76
77
  /**
77
78
  * Creates an instance of Reachability.
78
79
  * @param {object} webex
79
80
  * @memberof Reachability
80
81
  */
81
82
  constructor(webex: object);
83
+ /**
84
+ * Fetches the list of media clusters from the backend
85
+ * @param {boolean} isRetry
86
+ * @private
87
+ * @returns {Promise<{clusters: ClusterList, joinCookie: any}>}
88
+ */
89
+ getClusters(isRetry?: boolean): Promise<{
90
+ clusters: ClusterList;
91
+ joinCookie: any;
92
+ }>;
82
93
  /**
83
94
  * Gets a list of media clusters from the backend and performs reachability checks on all the clusters
95
+ * @param {string} trigger - explains the reason for starting reachability
84
96
  * @returns {Promise<ReachabilityResults>} reachability results
85
97
  * @public
86
98
  * @memberof Reachability
87
99
  */
88
- gatherReachability(): Promise<ReachabilityResults>;
100
+ gatherReachability(trigger: string): Promise<ReachabilityResults>;
89
101
  /**
90
102
  * Returns statistics about last reachability results. The returned value is an object
91
103
  * with a flat list of properties so that it can be easily sent with metrics
@@ -11,6 +11,7 @@ export default class RtcMetrics {
11
11
  meetingId: string;
12
12
  correlationId: string;
13
13
  connectionId: string;
14
+ shouldSendMetricsOnNextStatsReport: boolean;
14
15
  /**
15
16
  * Initialize the interval.
16
17
  *
@@ -25,6 +26,15 @@ export default class RtcMetrics {
25
26
  * @returns {void}
26
27
  */
27
28
  sendMetricsInQueue(): void;
29
+ /**
30
+ * Forces sending metrics when we get the next stats-report
31
+ *
32
+ * This is useful for cases when something important happens that affects the media connection,
33
+ * for example when we move from lobby into the meeting.
34
+ *
35
+ * @returns {void}
36
+ */
37
+ sendNextMetrics(): void;
28
38
  /**
29
39
  * Add metrics items to the metrics queue.
30
40
  *
@@ -51,7 +61,7 @@ export default class RtcMetrics {
51
61
  *
52
62
  * @returns {void}
53
63
  */
54
- private setNewConnectionId;
64
+ private resetConnection;
55
65
  /**
56
66
  * Send metrics to the metrics service.
57
67
  *
@@ -62,7 +62,7 @@ var Webinar = _webexCore.WebexPlugin.extend({
62
62
  updateCanManageWebcast: function updateCanManageWebcast(canManageWebcast) {
63
63
  this.set('canManageWebcast', canManageWebcast);
64
64
  },
65
- version: "3.4.0"
65
+ version: "3.5.0-next.2"
66
66
  });
67
67
  var _default = exports.default = Webinar;
68
68
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -43,13 +43,13 @@
43
43
  "@webex/eslint-config-legacy": "0.0.0",
44
44
  "@webex/jest-config-legacy": "0.0.0",
45
45
  "@webex/legacy-tools": "0.0.0",
46
- "@webex/plugin-meetings": "3.4.0",
47
- "@webex/plugin-rooms": "3.4.0",
48
- "@webex/test-helper-chai": "3.4.0",
49
- "@webex/test-helper-mocha": "3.4.0",
50
- "@webex/test-helper-mock-webex": "3.4.0",
51
- "@webex/test-helper-retry": "3.4.0",
52
- "@webex/test-helper-test-users": "3.4.0",
46
+ "@webex/plugin-meetings": "3.5.0-next.2",
47
+ "@webex/plugin-rooms": "3.5.0-next.2",
48
+ "@webex/test-helper-chai": "3.5.0-next.2",
49
+ "@webex/test-helper-mocha": "3.5.0-next.2",
50
+ "@webex/test-helper-mock-webex": "3.5.0-next.2",
51
+ "@webex/test-helper-retry": "3.5.0-next.2",
52
+ "@webex/test-helper-test-users": "3.5.0-next.2",
53
53
  "chai": "^4.3.4",
54
54
  "chai-as-promised": "^7.1.1",
55
55
  "eslint": "^8.24.0",
@@ -61,21 +61,21 @@
61
61
  "typescript": "^4.7.4"
62
62
  },
63
63
  "dependencies": {
64
- "@webex/common": "3.4.0",
65
- "@webex/internal-media-core": "2.10.0",
66
- "@webex/internal-plugin-conversation": "3.4.0",
67
- "@webex/internal-plugin-device": "3.4.0",
68
- "@webex/internal-plugin-llm": "3.4.0",
69
- "@webex/internal-plugin-mercury": "3.4.0",
70
- "@webex/internal-plugin-metrics": "3.4.0",
71
- "@webex/internal-plugin-support": "3.4.0",
72
- "@webex/internal-plugin-user": "3.4.0",
73
- "@webex/internal-plugin-voicea": "3.4.0",
74
- "@webex/media-helpers": "3.4.0",
75
- "@webex/plugin-people": "3.4.0",
76
- "@webex/plugin-rooms": "3.4.0",
64
+ "@webex/common": "3.5.0-next.2",
65
+ "@webex/internal-media-core": "2.11.1",
66
+ "@webex/internal-plugin-conversation": "3.5.0-next.2",
67
+ "@webex/internal-plugin-device": "3.5.0-next.2",
68
+ "@webex/internal-plugin-llm": "3.5.0-next.2",
69
+ "@webex/internal-plugin-mercury": "3.5.0-next.2",
70
+ "@webex/internal-plugin-metrics": "3.5.0-next.2",
71
+ "@webex/internal-plugin-support": "3.5.0-next.2",
72
+ "@webex/internal-plugin-user": "3.5.0-next.2",
73
+ "@webex/internal-plugin-voicea": "3.5.0-next.2",
74
+ "@webex/media-helpers": "3.5.0-next.2",
75
+ "@webex/plugin-people": "3.5.0-next.2",
76
+ "@webex/plugin-rooms": "3.5.0-next.2",
77
77
  "@webex/web-capabilities": "^1.4.0",
78
- "@webex/webex-core": "3.4.0",
78
+ "@webex/webex-core": "3.5.0-next.2",
79
79
  "ampersand-collection": "^2.0.2",
80
80
  "bowser": "^2.11.0",
81
81
  "btoa": "^1.2.1",
@@ -91,5 +91,5 @@
91
91
  "//": [
92
92
  "TODO: upgrade jwt-decode when moving to node 18"
93
93
  ],
94
- "version": "3.4.0"
94
+ "version": "3.5.0-next.2"
95
95
  }
@@ -104,9 +104,7 @@ Media.getDirection = (forceSendRecv: boolean, receive: boolean, send: boolean) =
104
104
  *
105
105
  * @param {boolean} isMultistream
106
106
  * @param {string} debugId string useful for debugging (will appear in media connection logs)
107
- * @param {object} webex main `webex` object.
108
107
  * @param {string} meetingId id for the meeting using this connection
109
- * @param {string} correlationId id used in requests to correlate to this session
110
108
  * @param {Object} options
111
109
  * @param {Object} [options.mediaProperties] contains mediaDirection and local tracks:
112
110
  * audioTrack, videoTrack, shareVideoTrack, and shareAudioTrack
@@ -120,10 +118,9 @@ Media.getDirection = (forceSendRecv: boolean, receive: boolean, send: boolean) =
120
118
  Media.createMediaConnection = (
121
119
  isMultistream: boolean,
122
120
  debugId: string,
123
- webex: object,
124
121
  meetingId: string,
125
- correlationId: string,
126
122
  options: {
123
+ rtcMetrics?: RtcMetrics;
127
124
  mediaProperties: {
128
125
  mediaDirection?: {
129
126
  receiveAudio: boolean;
@@ -150,6 +147,7 @@ Media.createMediaConnection = (
150
147
  }
151
148
  ) => {
152
149
  const {
150
+ rtcMetrics,
153
151
  mediaProperties,
154
152
  remoteQualityLevel,
155
153
  enableRtx,
@@ -192,15 +190,13 @@ Media.createMediaConnection = (
192
190
  config.bundlePolicy = bundlePolicy;
193
191
  }
194
192
 
195
- const rtcMetrics = new RtcMetrics(webex, meetingId, correlationId);
196
-
197
193
  return new MultistreamRoapMediaConnection(
198
194
  config,
199
195
  meetingId,
200
196
  /* the rtc metrics objects callbacks */
201
- (data) => rtcMetrics.addMetrics(data),
202
- () => rtcMetrics.closeMetrics(),
203
- () => rtcMetrics.sendMetricsInQueue()
197
+ (data) => rtcMetrics?.addMetrics(data),
198
+ () => rtcMetrics?.closeMetrics(),
199
+ () => rtcMetrics?.sendMetricsInQueue()
204
200
  );
205
201
  }
206
202
 
@@ -24,6 +24,8 @@ import {
24
24
  RoapMessage,
25
25
  StatsAnalyzer,
26
26
  StatsAnalyzerEventNames,
27
+ NetworkQualityEventNames,
28
+ NetworkQualityMonitor,
27
29
  } from '@webex/internal-media-core';
28
30
 
29
31
  import {
@@ -54,7 +56,6 @@ import {
54
56
  AddMediaFailed,
55
57
  } from '../common/errors/webex-errors';
56
58
 
57
- import NetworkQualityMonitor from '../networkQualityMonitor';
58
59
  import LoggerProxy from '../common/logs/logger-proxy';
59
60
  import EventsUtil from '../common/events/util';
60
61
  import Trigger from '../common/events/trigger-proxy';
@@ -154,6 +155,7 @@ import ControlsOptionsManager from '../controls-options-manager';
154
155
  import PermissionError from '../common/errors/permission';
155
156
  import {LocusMediaRequest} from './locusMediaRequest';
156
157
  import {ConnectionStateHandler, ConnectionStateEvent} from './connectionStateHandler';
158
+ import RtcMetrics from '../rtcMetrics';
157
159
 
158
160
  // default callback so we don't call an undefined function, but in practice it should never be used
159
161
  const DEFAULT_ICE_PHASE_CALLBACK = () => 'JOIN_MEETING_FINAL';
@@ -225,6 +227,7 @@ export type AddMediaOptions = {
225
227
 
226
228
  export type CallStateForMetrics = {
227
229
  correlationId?: string;
230
+ sessionCorrelationId?: string;
228
231
  joinTrigger?: string;
229
232
  loginType?: string;
230
233
  };
@@ -536,6 +539,7 @@ export default class Meeting extends StatelessWebexPlugin {
536
539
  id: string;
537
540
  isMultistream: boolean;
538
541
  locusUrl: string;
542
+ #isoLocalClientMeetingJoinTime?: string;
539
543
  mediaConnections: any[];
540
544
  mediaId?: string;
541
545
  meetingFiniteStateMachine: any;
@@ -695,6 +699,7 @@ export default class Meeting extends StatelessWebexPlugin {
695
699
  private connectionStateHandler?: ConnectionStateHandler;
696
700
  private iceCandidateErrors: Map<string, number>;
697
701
  private iceCandidatesCount: number;
702
+ private rtcMetrics?: RtcMetrics;
698
703
 
699
704
  /**
700
705
  * @param {Object} attrs
@@ -738,12 +743,29 @@ export default class Meeting extends StatelessWebexPlugin {
738
743
  */
739
744
  this.callStateForMetrics = attrs.callStateForMetrics || {};
740
745
  const correlationId = attrs.correlationId || attrs.callStateForMetrics?.correlationId;
746
+ const sessionCorrelationId =
747
+ attrs.sessionCorrelationId || attrs.callStateForMetrics?.sessionCorrelationId;
748
+ if (sessionCorrelationId) {
749
+ LoggerProxy.logger.log(
750
+ `Meetings:index#constructor --> Initializing the meeting object with session correlation id from app ${correlationId}`
751
+ );
752
+ this.callStateForMetrics.sessionCorrelationId = sessionCorrelationId;
753
+ } else {
754
+ LoggerProxy.logger.log(
755
+ `Meetings:index#constructor --> No session correlation id supplied. None will be generated and this field will remain blank`
756
+ );
757
+ // TODO: supply a session from the meetings instance
758
+ this.callStateForMetrics.sessionCorrelationId = '';
759
+ }
741
760
  if (correlationId) {
742
761
  LoggerProxy.logger.log(
743
762
  `Meetings:index#constructor --> Initializing the meeting object with correlation id from app ${correlationId}`
744
763
  );
745
764
  this.callStateForMetrics.correlationId = correlationId;
746
765
  } else {
766
+ LoggerProxy.logger.log(
767
+ `Meetings:index#constructor --> Initializing the meeting object with generated correlation id from sdk ${this.id}`
768
+ );
747
769
  this.callStateForMetrics.correlationId = this.id;
748
770
  }
749
771
  /**
@@ -1518,6 +1540,17 @@ export default class Meeting extends StatelessWebexPlugin {
1518
1540
  * @memberof Meeting
1519
1541
  */
1520
1542
  this.iceCandidatesCount = 0;
1543
+
1544
+ /**
1545
+ * Start time of meeting as an ISO string
1546
+ * based on browser time, so can only be used to compute durations client side
1547
+ * undefined if meeting has not been joined, set once on meeting join, and not updated again
1548
+ * @instance
1549
+ * @type {string}
1550
+ * @private
1551
+ * @memberof Meeting
1552
+ */
1553
+ this.#isoLocalClientMeetingJoinTime = undefined;
1521
1554
  }
1522
1555
 
1523
1556
  /**
@@ -1566,6 +1599,31 @@ export default class Meeting extends StatelessWebexPlugin {
1566
1599
  this.callStateForMetrics.correlationId = correlationId;
1567
1600
  }
1568
1601
 
1602
+ /**
1603
+ * Getter - Returns callStateForMetrics.sessionCorrelationId
1604
+ * @returns {string}
1605
+ */
1606
+ get sessionCorrelationId() {
1607
+ return this.callStateForMetrics.correlationId;
1608
+ }
1609
+
1610
+ /**
1611
+ * Setter - sets callStateForMetrics.sessionCorrelationId
1612
+ * @param {string} sessionCorrelationId
1613
+ */
1614
+ set sessionCorrelationId(sessionCorrelationId: string) {
1615
+ this.callStateForMetrics.sessionCorrelationId = sessionCorrelationId;
1616
+ }
1617
+
1618
+ /**
1619
+ * Getter - Returns isoLocalClientMeetingJoinTime
1620
+ * This will be set once on meeting join, and not updated again
1621
+ * @returns {string | undefined}
1622
+ */
1623
+ get isoLocalClientMeetingJoinTime(): string | undefined {
1624
+ return this.#isoLocalClientMeetingJoinTime;
1625
+ }
1626
+
1569
1627
  /**
1570
1628
  * Set meeting info and trigger `MEETING_INFO_AVAILABLE` event
1571
1629
  * @param {any} info
@@ -3155,6 +3213,7 @@ export default class Meeting extends StatelessWebexPlugin {
3155
3213
  options: {meetingId: this.id},
3156
3214
  });
3157
3215
  }
3216
+ this.rtcMetrics?.sendNextMetrics();
3158
3217
  this.updateLLMConnection();
3159
3218
  });
3160
3219
 
@@ -5228,6 +5287,11 @@ export default class Meeting extends StatelessWebexPlugin {
5228
5287
  this.meetingFiniteStateMachine.join();
5229
5288
  this.setupLocusMediaRequest();
5230
5289
 
5290
+ // @ts-ignore
5291
+ this.webex.internal.device.meetingStarted();
5292
+
5293
+ this.#isoLocalClientMeetingJoinTime = new Date().toISOString();
5294
+
5231
5295
  LoggerProxy.logger.log('Meeting:index#join --> Success');
5232
5296
 
5233
5297
  Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.JOIN_SUCCESS, {
@@ -6306,14 +6370,17 @@ export default class Meeting extends StatelessWebexPlugin {
6306
6370
  * @returns {RoapMediaConnection | MultistreamRoapMediaConnection}
6307
6371
  */
6308
6372
  private async createMediaConnection(turnServerInfo, bundlePolicy?: BundlePolicy) {
6373
+ this.rtcMetrics = this.isMultistream
6374
+ ? // @ts-ignore
6375
+ new RtcMetrics(this.webex, this.id, this.correlationId)
6376
+ : undefined;
6377
+
6309
6378
  const mc = Media.createMediaConnection(
6310
6379
  this.isMultistream,
6311
6380
  this.getMediaConnectionDebugId(),
6312
- // @ts-ignore
6313
- this.webex,
6314
6381
  this.id,
6315
- this.correlationId,
6316
6382
  {
6383
+ rtcMetrics: this.rtcMetrics,
6317
6384
  mediaProperties: this.mediaProperties,
6318
6385
  remoteQualityLevel: this.mediaProperties.remoteQualityLevel,
6319
6386
  // @ts-ignore - config coming from registerPlugin
@@ -6500,7 +6567,7 @@ export default class Meeting extends StatelessWebexPlugin {
6500
6567
  });
6501
6568
  this.setupStatsAnalyzerEventHandlers();
6502
6569
  this.networkQualityMonitor.on(
6503
- EVENT_TRIGGERS.NETWORK_QUALITY,
6570
+ NetworkQualityEventNames.NETWORK_QUALITY,
6504
6571
  this.sendNetworkQualityEvent.bind(this)
6505
6572
  );
6506
6573
  }
@@ -6511,12 +6578,21 @@ export default class Meeting extends StatelessWebexPlugin {
6511
6578
  *
6512
6579
  * @private
6513
6580
  * @static
6581
+ * @param {boolean} isAudioEnabled
6582
+ * @param {boolean} isVideoEnabled
6514
6583
  * @returns {Promise<void>}
6515
6584
  */
6516
- private static async handleDeviceLogging(): Promise<void> {
6517
- try {
6518
- const devices = await getDevices();
6519
6585
 
6586
+ private static async handleDeviceLogging(isAudioEnabled, isVideoEnabled): Promise<void> {
6587
+ try {
6588
+ let devices = [];
6589
+ if (isVideoEnabled && isAudioEnabled) {
6590
+ devices = await getDevices();
6591
+ } else if (isVideoEnabled) {
6592
+ devices = await getDevices(Media.DeviceKind.VIDEO_INPUT);
6593
+ } else if (isAudioEnabled) {
6594
+ devices = await getDevices(Media.DeviceKind.AUDIO_INPUT);
6595
+ }
6520
6596
  MeetingUtil.handleDeviceLogging(devices);
6521
6597
  } catch {
6522
6598
  // getDevices may fail if we don't have browser permissions, that's ok, we still can have a media connection
@@ -7009,7 +7085,7 @@ export default class Meeting extends StatelessWebexPlugin {
7009
7085
  );
7010
7086
 
7011
7087
  if (audioEnabled || videoEnabled) {
7012
- await Meeting.handleDeviceLogging();
7088
+ await Meeting.handleDeviceLogging(audioEnabled, videoEnabled);
7013
7089
  } else {
7014
7090
  LoggerProxy.logger.info(`${LOG_HEADER} device logging not required`);
7015
7091
  }
@@ -7022,6 +7098,7 @@ export default class Meeting extends StatelessWebexPlugin {
7022
7098
  await this.mediaProperties.getCurrentConnectionInfo();
7023
7099
  // @ts-ignore
7024
7100
  const reachabilityStats = await this.webex.meetings.reachability.getReachabilityMetrics();
7101
+ const iceCandidateErrors = Object.fromEntries(this.iceCandidateErrors);
7025
7102
 
7026
7103
  Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ADD_MEDIA_SUCCESS, {
7027
7104
  correlation_id: this.correlationId,
@@ -7033,6 +7110,7 @@ export default class Meeting extends StatelessWebexPlugin {
7033
7110
  retriedWithTurnServer: this.addMediaData.retriedWithTurnServer,
7034
7111
  isJoinWithMediaRetry: this.joinWithMediaRetryInfo.isRetry,
7035
7112
  ...reachabilityStats,
7113
+ ...iceCandidateErrors,
7036
7114
  iceCandidatesCount: this.iceCandidatesCount,
7037
7115
  });
7038
7116
  // @ts-ignore
@@ -8191,7 +8269,7 @@ export default class Meeting extends StatelessWebexPlugin {
8191
8269
  * @private
8192
8270
  * @memberof Meeting
8193
8271
  */
8194
- private sendNetworkQualityEvent(res: any) {
8272
+ private sendNetworkQualityEvent(res: {networkQualityScore: number; mediaType: string}) {
8195
8273
  Trigger.trigger(
8196
8274
  this,
8197
8275
  {
@@ -170,6 +170,8 @@ const MeetingUtil = {
170
170
  },
171
171
 
172
172
  cleanUp: (meeting) => {
173
+ meeting.getWebexObject().internal.device.meetingEnded();
174
+
173
175
  meeting.breakouts.cleanUp();
174
176
  meeting.simultaneousInterpretation.cleanUp();
175
177
  meeting.locusMediaRequest = undefined;
@@ -765,7 +765,7 @@ export default class Meetings extends WebexPlugin {
765
765
  return Promise.all([
766
766
  this.fetchUserPreferredWebexSite(),
767
767
  this.getGeoHint(),
768
- this.startReachability().catch((error) => {
768
+ this.startReachability('registration').catch((error) => {
769
769
  LoggerProxy.logger.error(`Meetings:index#register --> GDM error, ${error.message}`);
770
770
  }),
771
771
  // @ts-ignore
@@ -967,12 +967,13 @@ export default class Meetings extends WebexPlugin {
967
967
 
968
968
  /**
969
969
  * initializes and starts gathering reachability for Meetings
970
+ * @param {string} trigger - explains the reason for starting reachability
970
971
  * @returns {Promise}
971
972
  * @public
972
973
  * @memberof Meetings
973
974
  */
974
- startReachability() {
975
- return this.getReachability().gatherReachability();
975
+ startReachability(trigger = 'client') {
976
+ return this.getReachability().gatherReachability(trigger);
976
977
  }
977
978
 
978
979
  /**
@@ -1080,6 +1081,7 @@ export default class Meetings extends WebexPlugin {
1080
1081
  * @param {CallStateForMetrics} callStateForMetrics - information about call state for metrics
1081
1082
  * @param {Object} [meetingInfo] - Pre-fetched complete meeting info
1082
1083
  * @param {String} [meetingLookupUrl] - meeting info prefetch url
1084
+ * @param {string} sessionCorrelationId - the optional specified sessionCorrelationId (callStateForMetrics.sessionCorrelationId) can be provided instead
1083
1085
  * @returns {Promise<Meeting>} A new Meeting.
1084
1086
  * @public
1085
1087
  * @memberof Meetings
@@ -1093,7 +1095,8 @@ export default class Meetings extends WebexPlugin {
1093
1095
  failOnMissingMeetingInfo = false,
1094
1096
  callStateForMetrics: CallStateForMetrics = undefined,
1095
1097
  meetingInfo = undefined,
1096
- meetingLookupUrl = undefined
1098
+ meetingLookupUrl = undefined,
1099
+ sessionCorrelationId: string = undefined
1097
1100
  ) {
1098
1101
  // Validate meeting information based on the provided destination and
1099
1102
  // type. This must be performed prior to determining if the meeting is
@@ -1104,6 +1107,10 @@ export default class Meetings extends WebexPlugin {
1104
1107
  callStateForMetrics = {...(callStateForMetrics || {}), correlationId};
1105
1108
  }
1106
1109
 
1110
+ if (sessionCorrelationId) {
1111
+ callStateForMetrics = {...(callStateForMetrics || {}), sessionCorrelationId};
1112
+ }
1113
+
1107
1114
  return (
1108
1115
  this.meetingInfo
1109
1116
  .fetchInfoOptions(destination, type)