@webex/plugin-meetings 3.12.0-next.7 → 3.12.0-next.70

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 (178) hide show
  1. package/AGENTS.md +9 -0
  2. package/dist/aiEnableRequest/index.js +15 -2
  3. package/dist/aiEnableRequest/index.js.map +1 -1
  4. package/dist/breakouts/breakout.js +8 -3
  5. package/dist/breakouts/breakout.js.map +1 -1
  6. package/dist/breakouts/index.js +26 -2
  7. package/dist/breakouts/index.js.map +1 -1
  8. package/dist/config.js +2 -0
  9. package/dist/config.js.map +1 -1
  10. package/dist/constants.js +30 -7
  11. package/dist/constants.js.map +1 -1
  12. package/dist/controls-options-manager/constants.js +11 -1
  13. package/dist/controls-options-manager/constants.js.map +1 -1
  14. package/dist/controls-options-manager/index.js +38 -24
  15. package/dist/controls-options-manager/index.js.map +1 -1
  16. package/dist/controls-options-manager/util.js +91 -0
  17. package/dist/controls-options-manager/util.js.map +1 -1
  18. package/dist/hashTree/constants.js +13 -1
  19. package/dist/hashTree/constants.js.map +1 -1
  20. package/dist/hashTree/hashTreeParser.js +880 -382
  21. package/dist/hashTree/hashTreeParser.js.map +1 -1
  22. package/dist/hashTree/utils.js +42 -0
  23. package/dist/hashTree/utils.js.map +1 -1
  24. package/dist/index.js +7 -0
  25. package/dist/index.js.map +1 -1
  26. package/dist/interceptors/dataChannelAuthToken.js +75 -15
  27. package/dist/interceptors/dataChannelAuthToken.js.map +1 -1
  28. package/dist/interceptors/locusRetry.js +23 -8
  29. package/dist/interceptors/locusRetry.js.map +1 -1
  30. package/dist/interpretation/index.js +10 -1
  31. package/dist/interpretation/index.js.map +1 -1
  32. package/dist/interpretation/interpretation.types.js +7 -0
  33. package/dist/interpretation/interpretation.types.js.map +1 -0
  34. package/dist/interpretation/siLanguage.js +1 -1
  35. package/dist/locus-info/controlsUtils.js +4 -1
  36. package/dist/locus-info/controlsUtils.js.map +1 -1
  37. package/dist/locus-info/index.js +298 -87
  38. package/dist/locus-info/index.js.map +1 -1
  39. package/dist/locus-info/types.js +19 -0
  40. package/dist/locus-info/types.js.map +1 -1
  41. package/dist/media/index.js +3 -1
  42. package/dist/media/index.js.map +1 -1
  43. package/dist/media/properties.js +1 -0
  44. package/dist/media/properties.js.map +1 -1
  45. package/dist/meeting/in-meeting-actions.js +3 -1
  46. package/dist/meeting/in-meeting-actions.js.map +1 -1
  47. package/dist/meeting/index.js +1046 -689
  48. package/dist/meeting/index.js.map +1 -1
  49. package/dist/meeting/muteState.js +10 -1
  50. package/dist/meeting/muteState.js.map +1 -1
  51. package/dist/meeting/request.js +5 -2
  52. package/dist/meeting/request.js.map +1 -1
  53. package/dist/meeting/util.js +20 -2
  54. package/dist/meeting/util.js.map +1 -1
  55. package/dist/meeting-info/meeting-info-v2.js +2 -2
  56. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  57. package/dist/meetings/index.js +231 -78
  58. package/dist/meetings/index.js.map +1 -1
  59. package/dist/meetings/meetings.types.js +6 -1
  60. package/dist/meetings/meetings.types.js.map +1 -1
  61. package/dist/meetings/request.js +39 -0
  62. package/dist/meetings/request.js.map +1 -1
  63. package/dist/meetings/util.js +79 -5
  64. package/dist/meetings/util.js.map +1 -1
  65. package/dist/member/index.js +10 -0
  66. package/dist/member/index.js.map +1 -1
  67. package/dist/member/types.js.map +1 -1
  68. package/dist/member/util.js +3 -0
  69. package/dist/member/util.js.map +1 -1
  70. package/dist/metrics/constants.js +4 -1
  71. package/dist/metrics/constants.js.map +1 -1
  72. package/dist/multistream/codec/constants.js +63 -0
  73. package/dist/multistream/codec/constants.js.map +1 -0
  74. package/dist/multistream/mediaRequestManager.js +62 -15
  75. package/dist/multistream/mediaRequestManager.js.map +1 -1
  76. package/dist/multistream/receiveSlot.js +9 -0
  77. package/dist/multistream/receiveSlot.js.map +1 -1
  78. package/dist/reactions/reactions.type.js.map +1 -1
  79. package/dist/recording-controller/index.js +1 -3
  80. package/dist/recording-controller/index.js.map +1 -1
  81. package/dist/types/config.d.ts +2 -0
  82. package/dist/types/constants.d.ts +9 -1
  83. package/dist/types/controls-options-manager/constants.d.ts +6 -1
  84. package/dist/types/controls-options-manager/index.d.ts +10 -0
  85. package/dist/types/hashTree/constants.d.ts +2 -0
  86. package/dist/types/hashTree/hashTreeParser.d.ts +146 -17
  87. package/dist/types/hashTree/utils.d.ts +18 -0
  88. package/dist/types/index.d.ts +3 -0
  89. package/dist/types/interceptors/locusRetry.d.ts +4 -4
  90. package/dist/types/interpretation/interpretation.types.d.ts +10 -0
  91. package/dist/types/locus-info/index.d.ts +50 -6
  92. package/dist/types/locus-info/types.d.ts +21 -1
  93. package/dist/types/media/properties.d.ts +1 -0
  94. package/dist/types/meeting/in-meeting-actions.d.ts +2 -0
  95. package/dist/types/meeting/index.d.ts +78 -5
  96. package/dist/types/meeting/request.d.ts +1 -0
  97. package/dist/types/meeting/util.d.ts +8 -0
  98. package/dist/types/meetings/index.d.ts +30 -2
  99. package/dist/types/meetings/meetings.types.d.ts +15 -0
  100. package/dist/types/meetings/request.d.ts +14 -0
  101. package/dist/types/member/index.d.ts +1 -0
  102. package/dist/types/member/types.d.ts +1 -0
  103. package/dist/types/member/util.d.ts +1 -0
  104. package/dist/types/metrics/constants.d.ts +3 -0
  105. package/dist/types/multistream/codec/constants.d.ts +7 -0
  106. package/dist/types/multistream/mediaRequestManager.d.ts +22 -5
  107. package/dist/types/reactions/reactions.type.d.ts +3 -0
  108. package/dist/webinar/index.js +305 -159
  109. package/dist/webinar/index.js.map +1 -1
  110. package/package.json +22 -22
  111. package/src/aiEnableRequest/index.ts +16 -0
  112. package/src/breakouts/breakout.ts +3 -1
  113. package/src/breakouts/index.ts +31 -0
  114. package/src/config.ts +2 -0
  115. package/src/constants.ts +13 -2
  116. package/src/controls-options-manager/constants.ts +14 -1
  117. package/src/controls-options-manager/index.ts +47 -24
  118. package/src/controls-options-manager/util.ts +81 -1
  119. package/src/hashTree/constants.ts +16 -0
  120. package/src/hashTree/hashTreeParser.ts +580 -196
  121. package/src/hashTree/utils.ts +36 -0
  122. package/src/index.ts +6 -0
  123. package/src/interceptors/dataChannelAuthToken.ts +88 -12
  124. package/src/interceptors/locusRetry.ts +25 -4
  125. package/src/interpretation/index.ts +27 -9
  126. package/src/interpretation/interpretation.types.ts +11 -0
  127. package/src/locus-info/controlsUtils.ts +3 -1
  128. package/src/locus-info/index.ts +293 -97
  129. package/src/locus-info/types.ts +25 -1
  130. package/src/media/index.ts +3 -0
  131. package/src/media/properties.ts +1 -0
  132. package/src/meeting/in-meeting-actions.ts +4 -0
  133. package/src/meeting/index.ts +386 -48
  134. package/src/meeting/muteState.ts +10 -1
  135. package/src/meeting/request.ts +11 -0
  136. package/src/meeting/util.ts +21 -2
  137. package/src/meeting-info/meeting-info-v2.ts +4 -2
  138. package/src/meetings/index.ts +134 -44
  139. package/src/meetings/meetings.types.ts +19 -0
  140. package/src/meetings/request.ts +43 -0
  141. package/src/meetings/util.ts +97 -1
  142. package/src/member/index.ts +10 -0
  143. package/src/member/types.ts +1 -0
  144. package/src/member/util.ts +3 -0
  145. package/src/metrics/constants.ts +3 -0
  146. package/src/multistream/codec/constants.ts +58 -0
  147. package/src/multistream/mediaRequestManager.ts +119 -28
  148. package/src/multistream/receiveSlot.ts +18 -0
  149. package/src/reactions/reactions.type.ts +3 -0
  150. package/src/recording-controller/index.ts +1 -2
  151. package/src/webinar/index.ts +214 -36
  152. package/test/unit/spec/aiEnableRequest/index.ts +86 -0
  153. package/test/unit/spec/breakouts/breakout.ts +9 -3
  154. package/test/unit/spec/breakouts/index.ts +49 -0
  155. package/test/unit/spec/controls-options-manager/index.js +140 -29
  156. package/test/unit/spec/controls-options-manager/util.js +165 -0
  157. package/test/unit/spec/hashTree/hashTreeParser.ts +1838 -180
  158. package/test/unit/spec/hashTree/utils.ts +125 -1
  159. package/test/unit/spec/interceptors/dataChannelAuthToken.ts +196 -0
  160. package/test/unit/spec/interceptors/locusRetry.ts +205 -4
  161. package/test/unit/spec/interpretation/index.ts +26 -4
  162. package/test/unit/spec/locus-info/controlsUtils.js +172 -57
  163. package/test/unit/spec/locus-info/index.js +487 -81
  164. package/test/unit/spec/media/index.ts +31 -0
  165. package/test/unit/spec/meeting/in-meeting-actions.ts +2 -0
  166. package/test/unit/spec/meeting/index.js +1240 -37
  167. package/test/unit/spec/meeting/muteState.js +81 -0
  168. package/test/unit/spec/meeting/request.js +12 -0
  169. package/test/unit/spec/meeting/utils.js +33 -0
  170. package/test/unit/spec/meeting-info/meetinginfov2.js +19 -10
  171. package/test/unit/spec/meetings/index.js +360 -10
  172. package/test/unit/spec/meetings/request.js +141 -0
  173. package/test/unit/spec/meetings/utils.js +189 -0
  174. package/test/unit/spec/member/index.js +7 -0
  175. package/test/unit/spec/member/util.js +24 -0
  176. package/test/unit/spec/multistream/mediaRequestManager.ts +501 -37
  177. package/test/unit/spec/recording-controller/index.js +9 -8
  178. package/test/unit/spec/webinar/index.ts +329 -28
@@ -27,6 +27,7 @@ export default class Member {
27
27
  isModerator: any;
28
28
  isModeratorAssignmentProhibited: any;
29
29
  isPresenterAssignmentProhibited: any;
30
+ isAttendeeAssignmentProhibited: any;
30
31
  isMutable: any;
31
32
  isNotAdmitted: any;
32
33
  isRecording: any;
@@ -292,6 +293,14 @@ export default class Member {
292
293
  */
293
294
  this.isPresenterAssignmentProhibited = null;
294
295
 
296
+ /**
297
+ * @instance
298
+ * @type {Boolean}
299
+ * @public
300
+ * @memberof Member
301
+ */
302
+ this.isAttendeeAssignmentProhibited = null;
303
+
295
304
  /**
296
305
  * @instance
297
306
  * @type {Boolean}
@@ -369,6 +378,7 @@ export default class Member {
369
378
  MemberUtil.isModeratorAssignmentProhibited(participant);
370
379
  this.isPresenterAssignmentProhibited =
371
380
  MemberUtil.isPresenterAssignmentProhibited(participant);
381
+ this.isAttendeeAssignmentProhibited = MemberUtil.isAttendeeAssignmentProhibited(participant);
372
382
  this.canApproveAIEnablement = MemberUtil.canApproveAIEnablement(participant);
373
383
  this.processStatus(participant);
374
384
  this.processRoles(participant);
@@ -103,6 +103,7 @@ export interface Participant {
103
103
  moderator: boolean; // Locus docs say this is deprecated and role control should be used instead
104
104
  moderatorAssignmentNotAllowed: boolean;
105
105
  presenterAssignmentNotAllowed: boolean;
106
+ attendeeAssignmentNotAllowed?: boolean;
106
107
  person: ParticipantPerson;
107
108
  resourceGuest: boolean;
108
109
  state: string; // probably one of MEETING_STATE.STATES
@@ -140,6 +140,9 @@ const MemberUtil = {
140
140
  isPresenterAssignmentProhibited: (participant: Participant) =>
141
141
  participant && participant.presenterAssignmentNotAllowed,
142
142
 
143
+ isAttendeeAssignmentProhibited: (participant: Participant) =>
144
+ !!(participant && participant.attendeeAssignmentNotAllowed),
145
+
143
146
  /**
144
147
  * checks to see if the participant id is the same as the passed id
145
148
  * there are multiple ids that can be used
@@ -96,6 +96,9 @@ const BEHAVIORAL_METRICS = {
96
96
  SET_CUSTOM_CODEC_PARAMETERS_USED: 'js_sdk_set_custom_codec_parameters_used',
97
97
  MARK_CUSTOM_CODEC_PARAMETERS_FOR_DELETION_USED:
98
98
  'js_sdk_mark_custom_codec_parameters_for_deletion_used',
99
+ HASH_TREE_SYNC_FAILURE: 'js_sdk_hash_tree_sync_failure',
100
+ HASH_TREE_HEARTBEAT_WATCHDOG_EXPIRED: 'js_sdk_hash_tree_heartbeat_watchdog_expired',
101
+ HASH_TREE_EMPTY_LOCUS_STATE_ELEMENTS: 'js_sdk_hash_tree_empty_locus_state_elements',
99
102
  };
100
103
 
101
104
  export {BEHAVIORAL_METRICS as default};
@@ -0,0 +1,58 @@
1
+ import {AV1EncodingParams, SupportedResolution} from '@webex/internal-media-core';
2
+
3
+ export const AV1_CODEC_PARAMETERS: Record<SupportedResolution, AV1EncodingParams> = {
4
+ '90p': {
5
+ levelIdx: 0,
6
+ tier: 0,
7
+ maxWidth: 160,
8
+ maxHeight: 90,
9
+ maxPicSize: 160 * 90,
10
+ maxDecodeRate: 5_529_600,
11
+ },
12
+ '180p': {
13
+ levelIdx: 0,
14
+ tier: 0,
15
+ maxWidth: 320,
16
+ maxHeight: 180,
17
+ maxPicSize: 320 * 180,
18
+ maxDecodeRate: 5_529_600,
19
+ },
20
+ '360p': {
21
+ levelIdx: 1,
22
+ tier: 0,
23
+ maxWidth: 640,
24
+ maxHeight: 360,
25
+ maxPicSize: 640 * 360,
26
+ maxDecodeRate: 10_454_400,
27
+ },
28
+ '540p': {
29
+ levelIdx: 4,
30
+ tier: 0,
31
+ maxWidth: 960,
32
+ maxHeight: 540,
33
+ maxPicSize: 960 * 540,
34
+ maxDecodeRate: 24_969_600,
35
+ },
36
+ '720p': {
37
+ levelIdx: 5,
38
+ tier: 0,
39
+ maxWidth: 1280,
40
+ maxHeight: 720,
41
+ maxPicSize: 1280 * 720,
42
+ maxDecodeRate: 39_938_400,
43
+ },
44
+ '1080p': {
45
+ levelIdx: 8,
46
+ tier: 0,
47
+ maxWidth: 1920,
48
+ maxHeight: 1080,
49
+ maxPicSize: 1920 * 1080,
50
+ maxDecodeRate: 77_856_768,
51
+ },
52
+ };
53
+
54
+ export const H264_CODEC_PARAMETERS = {
55
+ maxFs: 8192,
56
+ maxFps: 3000,
57
+ maxMbps: 245760,
58
+ };
@@ -9,6 +9,11 @@ import {
9
9
  getRecommendedMaxBitrateForFrameSize,
10
10
  RecommendedOpusBitrates,
11
11
  NamedMediaGroup,
12
+ AV1Codec,
13
+ SupportedResolution,
14
+ AV1EncodingParams,
15
+ MediaType,
16
+ MediaCodecMimeType,
12
17
  } from '@webex/internal-media-core';
13
18
  import {cloneDeepWith, debounce} from 'lodash';
14
19
 
@@ -16,6 +21,7 @@ import LoggerProxy from '../common/logs/logger-proxy';
16
21
 
17
22
  import {ReceiveSlot, ReceiveSlotEvents} from './receiveSlot';
18
23
  import {MAX_FS_VALUES} from './remoteMedia';
24
+ import {AV1_CODEC_PARAMETERS, H264_CODEC_PARAMETERS} from './codec/constants';
19
25
 
20
26
  export interface ActiveSpeakerPolicyInfo {
21
27
  policy: 'active-speaker';
@@ -54,34 +60,49 @@ export interface MediaRequest {
54
60
 
55
61
  export type MediaRequestId = string;
56
62
 
57
- const CODEC_DEFAULTS = {
58
- h264: {
59
- maxFs: 8192,
60
- maxFps: 3000,
61
- maxMbps: 245760,
62
- },
63
- };
64
-
65
63
  const DEBOUNCED_SOURCE_UPDATE_TIME = 1000;
66
64
 
65
+ const RESOLUTION_BUCKETS: Array<[SupportedResolution, number]> = [
66
+ ['90p', MAX_FS_VALUES['90p']],
67
+ ['180p', MAX_FS_VALUES['180p']],
68
+ ['360p', MAX_FS_VALUES['360p']],
69
+ ['540p', MAX_FS_VALUES['540p']],
70
+ ['720p', MAX_FS_VALUES['720p']],
71
+ ];
72
+
67
73
  type DegradationPreferences = {
68
74
  maxMacroblocksLimit: number;
69
75
  };
70
76
 
71
77
  type SendMediaRequestsCallback = (streamRequests: StreamRequest[]) => void;
78
+ type GetIngressPayloadTypeCallback = (
79
+ mediaType: MediaType,
80
+ codecMimeType: MediaCodecMimeType
81
+ ) => number | undefined;
72
82
  type Kind = 'audio' | 'video';
73
83
 
74
- type Options = {
84
+ type AudioMediaRequestManagerOptions = {
75
85
  degradationPreferences: DegradationPreferences;
76
- kind: Kind;
86
+ kind: 'audio';
77
87
  trimRequestsToNumOfSources: boolean; // if enabled, AS speaker requests will be trimmed based on the calls to setNumCurrentSources()
78
88
  };
79
89
 
90
+ type VideoMediaRequestManagerOptions = {
91
+ degradationPreferences: DegradationPreferences;
92
+ kind: 'video';
93
+ trimRequestsToNumOfSources: boolean;
94
+ enableAv1?: boolean;
95
+ };
96
+
97
+ type Options = AudioMediaRequestManagerOptions | VideoMediaRequestManagerOptions;
98
+
80
99
  type ClientRequestsMap = {[key: MediaRequestId]: MediaRequest};
81
100
 
82
101
  export class MediaRequestManager {
83
102
  private sendMediaRequestsCallback: SendMediaRequestsCallback;
84
103
 
104
+ private getIngressPayloadTypeCallback: GetIngressPayloadTypeCallback;
105
+
85
106
  private kind: Kind;
86
107
 
87
108
  private counter: number;
@@ -95,11 +116,17 @@ export class MediaRequestManager {
95
116
  private debouncedSourceUpdateListener: () => void;
96
117
 
97
118
  private trimRequestsToNumOfSources: boolean;
119
+ private enableAv1: boolean;
98
120
  private numTotalSources: number;
99
121
  private numLiveSources: number;
100
122
 
101
- constructor(sendMediaRequestsCallback: SendMediaRequestsCallback, options: Options) {
123
+ constructor(
124
+ sendMediaRequestsCallback: SendMediaRequestsCallback,
125
+ getIngressPayloadTypeCallback: GetIngressPayloadTypeCallback,
126
+ options: Options
127
+ ) {
102
128
  this.sendMediaRequestsCallback = sendMediaRequestsCallback;
129
+ this.getIngressPayloadTypeCallback = getIngressPayloadTypeCallback;
103
130
  this.counter = 0;
104
131
  this.numLiveSources = 0;
105
132
  this.numTotalSources = 0;
@@ -107,6 +134,7 @@ export class MediaRequestManager {
107
134
  this.degradationPreferences = options.degradationPreferences;
108
135
  this.kind = options.kind;
109
136
  this.trimRequestsToNumOfSources = options.trimRequestsToNumOfSources;
137
+ this.enableAv1 = options.kind === 'video' && !!options.enableAv1;
110
138
  this.sourceUpdateListener = this.commit.bind(this);
111
139
  this.debouncedSourceUpdateListener = debounce(
112
140
  this.sourceUpdateListener,
@@ -135,8 +163,8 @@ export class MediaRequestManager {
135
163
  Object.values(clientRequests).forEach((mr) => {
136
164
  if (mr.codecInfo) {
137
165
  mr.codecInfo.maxFs = Math.min(
138
- mr.preferredMaxFs || CODEC_DEFAULTS.h264.maxFs,
139
- mr.codecInfo.maxFs || CODEC_DEFAULTS.h264.maxFs,
166
+ mr.preferredMaxFs || H264_CODEC_PARAMETERS.maxFs,
167
+ mr.codecInfo.maxFs || H264_CODEC_PARAMETERS.maxFs,
140
168
  maxFsLimits[i]
141
169
  );
142
170
  // we only consider sources with "live" state
@@ -176,7 +204,7 @@ export class MediaRequestManager {
176
204
  }
177
205
 
178
206
  return getRecommendedMaxBitrateForFrameSize(
179
- mediaRequest.codecInfo.maxFs || CODEC_DEFAULTS.h264.maxFs
207
+ mediaRequest.codecInfo.maxFs || H264_CODEC_PARAMETERS.maxFs
180
208
  );
181
209
  }
182
210
 
@@ -192,12 +220,80 @@ export class MediaRequestManager {
192
220
  // eslint-disable-next-line class-methods-use-this
193
221
  private getH264MaxMbps(mediaRequest: MediaRequest): number {
194
222
  // fallback for maxFps (not needed for maxFs, since there is a fallback already in getDegradedClientRequests)
195
- const maxFps = mediaRequest.codecInfo.maxFps || CODEC_DEFAULTS.h264.maxFps;
223
+ const maxFps = mediaRequest.codecInfo.maxFps || H264_CODEC_PARAMETERS.maxFps;
196
224
 
197
225
  // divided by 100 since maxFps is 3000 (for 30 frames per seconds)
198
226
  return (mediaRequest.codecInfo.maxFs * maxFps) / 100;
199
227
  }
200
228
 
229
+ /**
230
+ * Returns the AV1 encoding parameters for a media request
231
+ * @param mediaRequest - The media request to get the AV1 encoding parameters for
232
+ * @returns {AV1EncodingParams} The AV1 encoding parameters
233
+ */
234
+ // eslint-disable-next-line class-methods-use-this
235
+ private getAv1EncodingParams(mediaRequest: MediaRequest): AV1EncodingParams {
236
+ const frameSize = mediaRequest.codecInfo.maxFs || H264_CODEC_PARAMETERS.maxFs;
237
+ const resolution = RESOLUTION_BUCKETS.find(([, maxFs]) => frameSize <= maxFs)?.[0] ?? '1080p';
238
+
239
+ return AV1_CODEC_PARAMETERS[resolution];
240
+ }
241
+
242
+ private buildH264CodecInfo(mr: MediaRequest): WcmeCodecInfo | undefined {
243
+ if (!mr.codecInfo) {
244
+ return undefined;
245
+ }
246
+
247
+ const h264PayloadType = this.getIngressPayloadTypeCallback(
248
+ mr.receiveSlots[0].mediaType,
249
+ MediaCodecMimeType.H264
250
+ );
251
+
252
+ if (h264PayloadType === undefined) {
253
+ return undefined;
254
+ }
255
+
256
+ return WcmeCodecInfo.fromH264(
257
+ h264PayloadType,
258
+ new H264Codec(
259
+ mr.codecInfo.maxFs,
260
+ mr.codecInfo.maxFps || H264_CODEC_PARAMETERS.maxFps,
261
+ this.getH264MaxMbps(mr),
262
+ mr.codecInfo.maxWidth,
263
+ mr.codecInfo.maxHeight
264
+ )
265
+ );
266
+ }
267
+
268
+ private buildAv1CodecInfo(mr: MediaRequest): WcmeCodecInfo | undefined {
269
+ if (!this.enableAv1 || !mr.codecInfo) {
270
+ return undefined;
271
+ }
272
+
273
+ const av1PayloadType = this.getIngressPayloadTypeCallback(
274
+ mr.receiveSlots[0].mediaType,
275
+ MediaCodecMimeType.AV1
276
+ );
277
+
278
+ if (av1PayloadType === undefined) {
279
+ return undefined;
280
+ }
281
+
282
+ const av1EncodingParams = this.getAv1EncodingParams(mr);
283
+
284
+ return WcmeCodecInfo.fromAv1(
285
+ av1PayloadType,
286
+ new AV1Codec(
287
+ av1EncodingParams.levelIdx,
288
+ av1EncodingParams.tier,
289
+ mr.codecInfo.maxWidth || av1EncodingParams.maxWidth,
290
+ mr.codecInfo.maxHeight || av1EncodingParams.maxHeight,
291
+ av1EncodingParams.maxPicSize,
292
+ av1EncodingParams.maxDecodeRate
293
+ )
294
+ );
295
+ }
296
+
201
297
  /** Modifies the passed in clientRequests and makes sure that in total they don't ask
202
298
  * for more streams than there are available.
203
299
  *
@@ -298,6 +394,12 @@ export class MediaRequestManager {
298
394
  // map all the client media requests to wcme stream requests
299
395
  Object.values(clientRequests).forEach((mr) => {
300
396
  if (mr.receiveSlots.length > 0) {
397
+ const codecInfos: WcmeCodecInfo[] = mr.codecInfo
398
+ ? [this.buildH264CodecInfo(mr), this.buildAv1CodecInfo(mr)].filter(
399
+ (info): info is WcmeCodecInfo => info !== undefined
400
+ )
401
+ : [];
402
+
301
403
  streamRequests.push(
302
404
  new StreamRequest(
303
405
  mr.policyInfo.policy === 'active-speaker'
@@ -314,25 +416,14 @@ export class MediaRequestManager {
314
416
  : new ReceiverSelectedInfo(mr.policyInfo.csi),
315
417
  mr.receiveSlots.map((receiveSlot) => receiveSlot.wcmeReceiveSlot),
316
418
  this.getMaxPayloadBitsPerSecond(mr),
317
- mr.codecInfo && [
318
- WcmeCodecInfo.fromH264(
319
- 0x80,
320
- new H264Codec(
321
- mr.codecInfo.maxFs,
322
- mr.codecInfo.maxFps || CODEC_DEFAULTS.h264.maxFps,
323
- this.getH264MaxMbps(mr),
324
- mr.codecInfo.maxWidth,
325
- mr.codecInfo.maxHeight
326
- )
327
- ),
328
- ]
419
+ codecInfos
329
420
  )
330
421
  );
331
422
  }
332
423
  });
333
424
 
334
425
  this.sendMediaRequestsCallback(streamRequests);
335
- LoggerProxy.logger.info(`multistream:sendRequests --> media requests sent. `);
426
+ LoggerProxy.logger.info(`multistream:sendRequests --> media requests sent.`);
336
427
  }
337
428
 
338
429
  public addRequest(mediaRequest: MediaRequest, commit = true): MediaRequestId {
@@ -134,6 +134,24 @@ export class ReceiveSlot extends EventsScope {
134
134
  });
135
135
  }
136
136
  );
137
+
138
+ this.mcReceiveSlot.on(WcmeReceiveSlotEvents.MediaStarted, () => {
139
+ LoggerProxy.logger.log(
140
+ `ReceiveSlot#setupEventListeners --> media started on receive slot ${this.id}, mediaType=${this.mediaType}`
141
+ );
142
+ });
143
+
144
+ this.mcReceiveSlot.on(WcmeReceiveSlotEvents.MediaStopped, () => {
145
+ LoggerProxy.logger.log(
146
+ `ReceiveSlot#setupEventListeners --> media stopped on receive slot ${this.id}, mediaType=${this.mediaType}`
147
+ );
148
+ });
149
+
150
+ this.mcReceiveSlot.on(WcmeReceiveSlotEvents.MediaEnded, () => {
151
+ LoggerProxy.logger.log(
152
+ `ReceiveSlot#setupEventListeners --> media ended on receive slot ${this.id}, mediaType=${this.mediaType}`
153
+ );
154
+ });
137
155
  }
138
156
 
139
157
  /** Tries to find the member id for this receive slot if it hasn't got one */
@@ -60,4 +60,7 @@ type RelayEventData = {
60
60
 
61
61
  export type RelayEvent = {
62
62
  data: RelayEventData;
63
+ headers?: {
64
+ route?: string;
65
+ };
63
66
  };
@@ -261,8 +261,7 @@ export default class RecordingController {
261
261
 
262
262
  LoggerProxy.logger.log(`RecordingController:index#recordingControls --> ${record}`);
263
263
 
264
- // @ts-ignore
265
- return this.request.request({
264
+ return this.request.locusDeltaRequest({
266
265
  uri: `${this.locusUrl}/${CONTROLS}`,
267
266
  body: {
268
267
  record,