@newgameplusinc/odyssey-audio-video-sdk-dev 1.0.35 → 1.0.36

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 (2) hide show
  1. package/dist/index.js +106 -80
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -157,6 +157,86 @@ class OdysseySpatialComms extends EventManager_1.EventManager {
157
157
  this.spatialAudioManager.setListenerFromLSD(listenerPos, cameraPos, lookAtPos);
158
158
  }
159
159
  listenForEvents() {
160
+ // CRITICAL: Register all-participants-update listener at initialization
161
+ // This ensures channel data is available when consumers are created
162
+ this.socket.on("all-participants-update", (payload) => {
163
+ if (!this.room) {
164
+ this.room = {
165
+ id: payload.roomId,
166
+ participants: new Map(),
167
+ };
168
+ }
169
+ const activeParticipantIds = new Set();
170
+ for (const snapshot of payload.participants) {
171
+ activeParticipantIds.add(snapshot.participantId);
172
+ let participant = this.room?.participants.get(snapshot.participantId);
173
+ const normalizedPosition = {
174
+ x: snapshot.position?.x ?? 0,
175
+ y: snapshot.position?.y ?? 0,
176
+ z: snapshot.position?.z ?? 0,
177
+ };
178
+ const normalizedDirection = {
179
+ x: snapshot.direction?.x ?? 0,
180
+ y: snapshot.direction?.y ?? 0,
181
+ z: snapshot.direction?.z ?? 1,
182
+ };
183
+ const normalizedMediaState = {
184
+ audio: snapshot.mediaState?.audio ?? false,
185
+ video: snapshot.mediaState?.video ?? false,
186
+ sharescreen: snapshot.mediaState?.sharescreen ?? false,
187
+ };
188
+ if (!participant) {
189
+ participant = {
190
+ participantId: snapshot.participantId,
191
+ userId: snapshot.userId,
192
+ deviceId: snapshot.deviceId,
193
+ isLocal: this.localParticipant?.participantId ===
194
+ snapshot.participantId,
195
+ audioTrack: undefined,
196
+ videoTrack: undefined,
197
+ producers: new Map(),
198
+ consumers: new Map(),
199
+ position: normalizedPosition,
200
+ direction: normalizedDirection,
201
+ mediaState: normalizedMediaState,
202
+ };
203
+ }
204
+ else {
205
+ participant.userId = snapshot.userId;
206
+ participant.deviceId = snapshot.deviceId;
207
+ participant.position = normalizedPosition;
208
+ participant.direction = normalizedDirection;
209
+ participant.mediaState = normalizedMediaState;
210
+ }
211
+ participant.bodyHeight = snapshot.bodyHeight;
212
+ participant.bodyShape = snapshot.bodyShape;
213
+ participant.userName = snapshot.userName;
214
+ participant.userEmail = snapshot.userEmail;
215
+ participant.isLocal =
216
+ this.localParticipant?.participantId === snapshot.participantId;
217
+ // CRITICAL: Store channel data for huddle detection
218
+ participant.currentChannel = snapshot.currentChannel || "spatial";
219
+ this.room?.participants.set(snapshot.participantId, participant);
220
+ if (participant.isLocal) {
221
+ this.localParticipant = participant;
222
+ }
223
+ }
224
+ if (this.room) {
225
+ for (const existingId of Array.from(this.room.participants.keys())) {
226
+ if (!activeParticipantIds.has(existingId)) {
227
+ this.room.participants.delete(existingId);
228
+ }
229
+ }
230
+ }
231
+ const normalizedParticipants = this.room
232
+ ? Array.from(this.room.participants.values())
233
+ : [];
234
+ this.emit("all-participants-update", normalizedParticipants);
235
+ // CRITICAL: After receiving channel data, update ALL mute states
236
+ // This ensures existing audio consumers get the correct mute state
237
+ console.log(`📊 [all-participants-update] Received ${normalizedParticipants.length} participants, updating mute states...`);
238
+ this.updateAllParticipantsMuteState();
239
+ });
160
240
  this.socket.on("new-participant", (participantData) => {
161
241
  if (this.room) {
162
242
  const newParticipant = {
@@ -187,80 +267,6 @@ class OdysseySpatialComms extends EventManager_1.EventManager {
187
267
  });
188
268
  this.socket.on("consumer-created", async (data) => {
189
269
  const { consumer, track } = await this.mediasoupManager.consume(data);
190
- this.socket.on("all-participants-update", (payload) => {
191
- if (!this.room) {
192
- this.room = {
193
- id: payload.roomId,
194
- participants: new Map(),
195
- };
196
- }
197
- const activeParticipantIds = new Set();
198
- for (const snapshot of payload.participants) {
199
- activeParticipantIds.add(snapshot.participantId);
200
- let participant = this.room?.participants.get(snapshot.participantId);
201
- const normalizedPosition = {
202
- x: snapshot.position?.x ?? 0,
203
- y: snapshot.position?.y ?? 0,
204
- z: snapshot.position?.z ?? 0,
205
- };
206
- const normalizedDirection = {
207
- x: snapshot.direction?.x ?? 0,
208
- y: snapshot.direction?.y ?? 0,
209
- z: snapshot.direction?.z ?? 1,
210
- };
211
- const normalizedMediaState = {
212
- audio: snapshot.mediaState?.audio ?? false,
213
- video: snapshot.mediaState?.video ?? false,
214
- sharescreen: snapshot.mediaState?.sharescreen ?? false,
215
- };
216
- if (!participant) {
217
- participant = {
218
- participantId: snapshot.participantId,
219
- userId: snapshot.userId,
220
- deviceId: snapshot.deviceId,
221
- isLocal: this.localParticipant?.participantId ===
222
- snapshot.participantId,
223
- audioTrack: undefined,
224
- videoTrack: undefined,
225
- producers: new Map(),
226
- consumers: new Map(),
227
- position: normalizedPosition,
228
- direction: normalizedDirection,
229
- mediaState: normalizedMediaState,
230
- };
231
- }
232
- else {
233
- participant.userId = snapshot.userId;
234
- participant.deviceId = snapshot.deviceId;
235
- participant.position = normalizedPosition;
236
- participant.direction = normalizedDirection;
237
- participant.mediaState = normalizedMediaState;
238
- }
239
- participant.bodyHeight = snapshot.bodyHeight;
240
- participant.bodyShape = snapshot.bodyShape;
241
- participant.userName = snapshot.userName;
242
- participant.userEmail = snapshot.userEmail;
243
- participant.isLocal =
244
- this.localParticipant?.participantId === snapshot.participantId;
245
- // CRITICAL: Store channel data for huddle detection
246
- participant.currentChannel = snapshot.currentChannel || "spatial";
247
- this.room?.participants.set(snapshot.participantId, participant);
248
- if (participant.isLocal) {
249
- this.localParticipant = participant;
250
- }
251
- }
252
- if (this.room) {
253
- for (const existingId of Array.from(this.room.participants.keys())) {
254
- if (!activeParticipantIds.has(existingId)) {
255
- this.room.participants.delete(existingId);
256
- }
257
- }
258
- }
259
- const normalizedParticipants = this.room
260
- ? Array.from(this.room.participants.values())
261
- : [];
262
- this.emit("all-participants-update", normalizedParticipants);
263
- });
264
270
  // DON'T resume yet! Resume AFTER setting up the audio pipeline
265
271
  let participant = this.room?.participants.get(data.participantId);
266
272
  // If participant doesn't exist yet, create it with the data from the event
@@ -311,18 +317,23 @@ class OdysseySpatialComms extends EventManager_1.EventManager {
311
317
  const isLocalParticipant = participant.participantId === this.localParticipant?.participantId;
312
318
  if (isLocalParticipant) {
313
319
  // Do NOT connect this audio to Web Audio API
320
+ console.log(`🚫 Skipping local participant audio setup (prevent loopback)`);
314
321
  return; // Exit early to prevent any audio processing
315
322
  }
316
323
  else {
317
324
  // Check if participant is in huddle - if so, skip spatial audio
318
325
  const participantChannel = participant.currentChannel || "spatial";
319
- const isInHuddle = participantChannel === "odyssey-huddle";
326
+ const myChannel = this.localParticipant?.currentChannel || "spatial";
327
+ const isInHuddle = participantChannel !== "spatial";
328
+ console.log(`🎧 Setting up audio for ${participant.participantId?.substring(0, 8)}`);
329
+ console.log(` My channel: ${myChannel}`);
330
+ console.log(` Their channel: ${participantChannel}`);
320
331
  // Setup spatial audio with full 3D positioning (disabled for huddle users)
321
332
  await this.spatialAudioManager.setupSpatialAudioForParticipant(participant.participantId, track, isInHuddle // Disable spatial audio for huddle users
322
333
  );
323
334
  // CRITICAL: Mute if not in same channel
324
- const myChannel = this.localParticipant?.currentChannel || "spatial";
325
335
  const shouldMute = myChannel !== participantChannel;
336
+ console.log(` Should mute: ${shouldMute} (channels ${myChannel === participantChannel ? 'MATCH' : 'DIFFER'})`);
326
337
  this.spatialAudioManager.setParticipantMuted(participant.participantId, shouldMute);
327
338
  // Only update spatial audio position if NOT in huddle
328
339
  if (!isInHuddle) {
@@ -420,11 +431,12 @@ class OdysseySpatialComms extends EventManager_1.EventManager {
420
431
  this.emit("huddle-ended", data);
421
432
  });
422
433
  this.socket.on("participant-channel-changed", (data) => {
434
+ console.log(`📡 participant-channel-changed: ${data.participantId?.substring(0, 8)} → ${data.channelId}`);
423
435
  const participant = this.room?.participants.get(data.participantId);
424
436
  if (participant) {
425
437
  participant.currentChannel = data.channelId;
426
438
  // Toggle spatial audio based on channel
427
- const isInHuddle = data.channelId === "odyssey-huddle";
439
+ const isInHuddle = data.channelId !== "spatial";
428
440
  // Update spatial audio bypass state for this participant
429
441
  if (participant.audioTrack) {
430
442
  this.spatialAudioManager.setupSpatialAudioForParticipant(participant.participantId, participant.audioTrack, isInHuddle // Disable spatial for huddle, enable for spatial
@@ -433,18 +445,19 @@ class OdysseySpatialComms extends EventManager_1.EventManager {
433
445
  });
434
446
  }
435
447
  // CRITICAL: Mute/unmute based on channel matching
436
- // If I'm in huddle and they're in spatial -> MUTE them
437
- // If I'm in spatial and they're in huddle -> MUTE them
438
- // If we're in the same channel -> UNMUTE them
439
448
  const myChannel = this.localParticipant?.currentChannel || "spatial";
440
449
  const theirChannel = data.channelId || "spatial";
441
450
  const shouldMute = myChannel !== theirChannel;
451
+ console.log(` My channel: ${myChannel}, Their channel: ${theirChannel}`);
452
+ console.log(` ${shouldMute ? '🔇 MUTING' : '🔊 UNMUTING'} ${participant.participantId?.substring(0, 8)}`);
442
453
  this.spatialAudioManager.setParticipantMuted(participant.participantId, shouldMute);
443
454
  }
444
455
  // Update local participant if it's them
445
456
  if (this.localParticipant?.participantId === data.participantId && this.localParticipant !== null) {
457
+ console.log(` This is ME changing channel!`);
446
458
  this.localParticipant.currentChannel = data.channelId;
447
459
  // When LOCAL user changes channel, update ALL other participants' mute state
460
+ console.log(` 🔄 Updating ALL participants mute state`);
448
461
  this.updateAllParticipantsMuteState();
449
462
  }
450
463
  this.emit("participant-channel-changed", data);
@@ -508,6 +521,7 @@ class OdysseySpatialComms extends EventManager_1.EventManager {
508
521
  * Join huddle (anyone can join directly without invite)
509
522
  */
510
523
  async joinHuddle() {
524
+ console.log(`🎧 [joinHuddle] Joining group huddle...`);
511
525
  if (!this.localParticipant || !this.room) {
512
526
  return { success: false, error: "Not in a room" };
513
527
  }
@@ -517,10 +531,14 @@ class OdysseySpatialComms extends EventManager_1.EventManager {
517
531
  roomId: this.room.id,
518
532
  }, (response) => {
519
533
  if (response.success && this.localParticipant) {
534
+ console.log(`✅ [joinHuddle] Success! New channel: ${response.channelId}`);
520
535
  this.localParticipant.currentChannel = response.channelId;
521
536
  // CRITICAL: Update mute state for all participants when joining huddle
522
537
  this.updateAllParticipantsMuteState();
523
538
  }
539
+ else {
540
+ console.error(`❌ [joinHuddle] Failed:`, response.error);
541
+ }
524
542
  resolve(response);
525
543
  });
526
544
  });
@@ -529,6 +547,7 @@ class OdysseySpatialComms extends EventManager_1.EventManager {
529
547
  * Leave current huddle and return to spatial audio
530
548
  */
531
549
  async leaveHuddle() {
550
+ console.log(`🚪 [leaveHuddle] Leaving huddle...`);
532
551
  if (!this.localParticipant || !this.room) {
533
552
  return { success: false, error: "Not in a room" };
534
553
  }
@@ -538,10 +557,14 @@ class OdysseySpatialComms extends EventManager_1.EventManager {
538
557
  roomId: this.room.id,
539
558
  }, (response) => {
540
559
  if (response.success && this.localParticipant) {
560
+ console.log(`✅ [leaveHuddle] Success! New channel: ${response.channelId}`);
541
561
  this.localParticipant.currentChannel = response.channelId;
542
562
  // CRITICAL: Update mute state for all participants when leaving huddle
543
563
  this.updateAllParticipantsMuteState();
544
564
  }
565
+ else {
566
+ console.error(`❌ [leaveHuddle] Failed:`, response.error);
567
+ }
545
568
  resolve(response);
546
569
  });
547
570
  });
@@ -567,6 +590,7 @@ class OdysseySpatialComms extends EventManager_1.EventManager {
567
590
  if (!this.localParticipant || !this.room)
568
591
  return;
569
592
  const myChannel = this.localParticipant.currentChannel || "spatial";
593
+ console.log(`🔄 [updateAllParticipantsMuteState] My channel: ${myChannel}`);
570
594
  this.room.participants.forEach((participant) => {
571
595
  // Skip local participant (never hear yourself)
572
596
  if (participant.participantId === this.localParticipant?.participantId) {
@@ -574,8 +598,10 @@ class OdysseySpatialComms extends EventManager_1.EventManager {
574
598
  }
575
599
  const theirChannel = participant.currentChannel || "spatial";
576
600
  const shouldMute = myChannel !== theirChannel;
601
+ console.log(` ${participant.participantId?.substring(0, 8)}: channel=${theirChannel}, ${shouldMute ? '🔇 MUTE' : '🔊 UNMUTE'}`);
577
602
  this.spatialAudioManager.setParticipantMuted(participant.participantId, shouldMute);
578
603
  });
604
+ console.log(`✅ [updateAllParticipantsMuteState] Complete`);
579
605
  }
580
606
  async muteParticipant(participantId) {
581
607
  if (!this.localParticipant || !this.room) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@newgameplusinc/odyssey-audio-video-sdk-dev",
3
- "version": "1.0.35",
3
+ "version": "1.0.36",
4
4
  "description": "Odyssey Spatial Audio & Video SDK using MediaSoup for real-time communication",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",