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

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 +113 -80
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -52,6 +52,7 @@ class OdysseySpatialComms extends EventManager_1.EventManager {
52
52
  isLocal: true,
53
53
  producers: new Map(),
54
54
  consumers: new Map(),
55
+ currentChannel: "spatial",
55
56
  };
56
57
  // 4. Initialize room state
57
58
  this.room = {
@@ -157,6 +158,89 @@ class OdysseySpatialComms extends EventManager_1.EventManager {
157
158
  this.spatialAudioManager.setListenerFromLSD(listenerPos, cameraPos, lookAtPos);
158
159
  }
159
160
  listenForEvents() {
161
+ // CRITICAL: Register all-participants-update listener at initialization
162
+ // This ensures channel data is available when consumers are created
163
+ this.socket.on("all-participants-update", (payload) => {
164
+ if (!this.room) {
165
+ this.room = {
166
+ id: payload.roomId,
167
+ participants: new Map(),
168
+ };
169
+ }
170
+ const activeParticipantIds = new Set();
171
+ for (const snapshot of payload.participants) {
172
+ activeParticipantIds.add(snapshot.participantId);
173
+ let participant = this.room?.participants.get(snapshot.participantId);
174
+ const normalizedPosition = {
175
+ x: snapshot.position?.x ?? 0,
176
+ y: snapshot.position?.y ?? 0,
177
+ z: snapshot.position?.z ?? 0,
178
+ };
179
+ const normalizedDirection = {
180
+ x: snapshot.direction?.x ?? 0,
181
+ y: snapshot.direction?.y ?? 0,
182
+ z: snapshot.direction?.z ?? 1,
183
+ };
184
+ const normalizedMediaState = {
185
+ audio: snapshot.mediaState?.audio ?? false,
186
+ video: snapshot.mediaState?.video ?? false,
187
+ sharescreen: snapshot.mediaState?.sharescreen ?? false,
188
+ };
189
+ if (!participant) {
190
+ participant = {
191
+ participantId: snapshot.participantId,
192
+ userId: snapshot.userId,
193
+ deviceId: snapshot.deviceId,
194
+ isLocal: this.localParticipant?.participantId ===
195
+ snapshot.participantId,
196
+ audioTrack: undefined,
197
+ videoTrack: undefined,
198
+ producers: new Map(),
199
+ consumers: new Map(),
200
+ position: normalizedPosition,
201
+ direction: normalizedDirection,
202
+ mediaState: normalizedMediaState,
203
+ };
204
+ }
205
+ else {
206
+ participant.userId = snapshot.userId;
207
+ participant.deviceId = snapshot.deviceId;
208
+ participant.position = normalizedPosition;
209
+ participant.direction = normalizedDirection;
210
+ participant.mediaState = normalizedMediaState;
211
+ }
212
+ participant.bodyHeight = snapshot.bodyHeight;
213
+ participant.bodyShape = snapshot.bodyShape;
214
+ participant.userName = snapshot.userName;
215
+ participant.userEmail = snapshot.userEmail;
216
+ participant.isLocal =
217
+ this.localParticipant?.participantId === snapshot.participantId;
218
+ // CRITICAL: Store channel data for huddle detection
219
+ participant.currentChannel = snapshot.currentChannel || "spatial";
220
+ this.room?.participants.set(snapshot.participantId, participant);
221
+ if (participant.isLocal) {
222
+ this.localParticipant = participant;
223
+ }
224
+ }
225
+ if (this.room) {
226
+ for (const existingId of Array.from(this.room.participants.keys())) {
227
+ if (!activeParticipantIds.has(existingId)) {
228
+ this.room.participants.delete(existingId);
229
+ }
230
+ }
231
+ }
232
+ const normalizedParticipants = this.room
233
+ ? Array.from(this.room.participants.values())
234
+ : [];
235
+ this.emit("all-participants-update", normalizedParticipants);
236
+ // CRITICAL: After receiving channel data, update ALL mute states
237
+ // This ensures existing audio consumers get the correct mute state
238
+ console.log(`[CHANNEL-DEBUG] all-participants-update: Received ${normalizedParticipants.length} participants`);
239
+ normalizedParticipants.forEach(p => {
240
+ console.log(` - ${p.participantId?.substring(0, 8)}: channel=${p.currentChannel || 'spatial'}`);
241
+ });
242
+ this.updateAllParticipantsMuteState();
243
+ });
160
244
  this.socket.on("new-participant", (participantData) => {
161
245
  if (this.room) {
162
246
  const newParticipant = {
@@ -187,80 +271,6 @@ class OdysseySpatialComms extends EventManager_1.EventManager {
187
271
  });
188
272
  this.socket.on("consumer-created", async (data) => {
189
273
  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
274
  // DON'T resume yet! Resume AFTER setting up the audio pipeline
265
275
  let participant = this.room?.participants.get(data.participantId);
266
276
  // If participant doesn't exist yet, create it with the data from the event
@@ -311,18 +321,24 @@ class OdysseySpatialComms extends EventManager_1.EventManager {
311
321
  const isLocalParticipant = participant.participantId === this.localParticipant?.participantId;
312
322
  if (isLocalParticipant) {
313
323
  // Do NOT connect this audio to Web Audio API
324
+ console.log(`🚫 Skipping local participant audio setup (prevent loopback)`);
314
325
  return; // Exit early to prevent any audio processing
315
326
  }
316
327
  else {
317
328
  // Check if participant is in huddle - if so, skip spatial audio
318
329
  const participantChannel = participant.currentChannel || "spatial";
319
- const isInHuddle = participantChannel === "odyssey-huddle";
330
+ const myChannel = this.localParticipant?.currentChannel || "spatial";
331
+ const isInHuddle = participantChannel !== "spatial";
332
+ console.log(`[CHANNEL-DEBUG] Setting up audio consumer:`);
333
+ console.log(` - Participant: ${participant.participantId?.substring(0, 8)}`);
334
+ console.log(` - My channel: ${myChannel}`);
335
+ console.log(` - Their channel: ${participantChannel}`);
320
336
  // Setup spatial audio with full 3D positioning (disabled for huddle users)
321
337
  await this.spatialAudioManager.setupSpatialAudioForParticipant(participant.participantId, track, isInHuddle // Disable spatial audio for huddle users
322
338
  );
323
339
  // CRITICAL: Mute if not in same channel
324
- const myChannel = this.localParticipant?.currentChannel || "spatial";
325
340
  const shouldMute = myChannel !== participantChannel;
341
+ console.log(` - Should mute: ${shouldMute} (channels ${myChannel === participantChannel ? 'MATCH' : 'DIFFER'})`);
326
342
  this.spatialAudioManager.setParticipantMuted(participant.participantId, shouldMute);
327
343
  // Only update spatial audio position if NOT in huddle
328
344
  if (!isInHuddle) {
@@ -420,11 +436,12 @@ class OdysseySpatialComms extends EventManager_1.EventManager {
420
436
  this.emit("huddle-ended", data);
421
437
  });
422
438
  this.socket.on("participant-channel-changed", (data) => {
439
+ console.log(`📡 participant-channel-changed: ${data.participantId?.substring(0, 8)} → ${data.channelId}`);
423
440
  const participant = this.room?.participants.get(data.participantId);
424
441
  if (participant) {
425
442
  participant.currentChannel = data.channelId;
426
443
  // Toggle spatial audio based on channel
427
- const isInHuddle = data.channelId === "odyssey-huddle";
444
+ const isInHuddle = data.channelId !== "spatial";
428
445
  // Update spatial audio bypass state for this participant
429
446
  if (participant.audioTrack) {
430
447
  this.spatialAudioManager.setupSpatialAudioForParticipant(participant.participantId, participant.audioTrack, isInHuddle // Disable spatial for huddle, enable for spatial
@@ -433,18 +450,22 @@ class OdysseySpatialComms extends EventManager_1.EventManager {
433
450
  });
434
451
  }
435
452
  // 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
453
  const myChannel = this.localParticipant?.currentChannel || "spatial";
440
454
  const theirChannel = data.channelId || "spatial";
441
455
  const shouldMute = myChannel !== theirChannel;
456
+ console.log(`[CHANNEL-DEBUG] participant-channel-changed:`);
457
+ console.log(` - Participant: ${participant.participantId?.substring(0, 8)}`);
458
+ console.log(` - My channel: ${myChannel}`);
459
+ console.log(` - Their new channel: ${theirChannel}`);
460
+ console.log(` - Should mute: ${shouldMute}`);
442
461
  this.spatialAudioManager.setParticipantMuted(participant.participantId, shouldMute);
443
462
  }
444
463
  // Update local participant if it's them
445
464
  if (this.localParticipant?.participantId === data.participantId && this.localParticipant !== null) {
465
+ console.log(`[CHANNEL-DEBUG] LOCAL USER changed channel to: ${data.channelId}`);
446
466
  this.localParticipant.currentChannel = data.channelId;
447
467
  // When LOCAL user changes channel, update ALL other participants' mute state
468
+ console.log(`[CHANNEL-DEBUG] Updating ALL participants mute state...`);
448
469
  this.updateAllParticipantsMuteState();
449
470
  }
450
471
  this.emit("participant-channel-changed", data);
@@ -508,6 +529,7 @@ class OdysseySpatialComms extends EventManager_1.EventManager {
508
529
  * Join huddle (anyone can join directly without invite)
509
530
  */
510
531
  async joinHuddle() {
532
+ console.log(`🎧 [joinHuddle] Joining group huddle...`);
511
533
  if (!this.localParticipant || !this.room) {
512
534
  return { success: false, error: "Not in a room" };
513
535
  }
@@ -517,10 +539,14 @@ class OdysseySpatialComms extends EventManager_1.EventManager {
517
539
  roomId: this.room.id,
518
540
  }, (response) => {
519
541
  if (response.success && this.localParticipant) {
542
+ console.log(`✅ [joinHuddle] Success! New channel: ${response.channelId}`);
520
543
  this.localParticipant.currentChannel = response.channelId;
521
544
  // CRITICAL: Update mute state for all participants when joining huddle
522
545
  this.updateAllParticipantsMuteState();
523
546
  }
547
+ else {
548
+ console.error(`❌ [joinHuddle] Failed:`, response.error);
549
+ }
524
550
  resolve(response);
525
551
  });
526
552
  });
@@ -529,6 +555,7 @@ class OdysseySpatialComms extends EventManager_1.EventManager {
529
555
  * Leave current huddle and return to spatial audio
530
556
  */
531
557
  async leaveHuddle() {
558
+ console.log(`🚪 [leaveHuddle] Leaving huddle...`);
532
559
  if (!this.localParticipant || !this.room) {
533
560
  return { success: false, error: "Not in a room" };
534
561
  }
@@ -538,10 +565,14 @@ class OdysseySpatialComms extends EventManager_1.EventManager {
538
565
  roomId: this.room.id,
539
566
  }, (response) => {
540
567
  if (response.success && this.localParticipant) {
568
+ console.log(`✅ [leaveHuddle] Success! New channel: ${response.channelId}`);
541
569
  this.localParticipant.currentChannel = response.channelId;
542
570
  // CRITICAL: Update mute state for all participants when leaving huddle
543
571
  this.updateAllParticipantsMuteState();
544
572
  }
573
+ else {
574
+ console.error(`❌ [leaveHuddle] Failed:`, response.error);
575
+ }
545
576
  resolve(response);
546
577
  });
547
578
  });
@@ -567,6 +598,7 @@ class OdysseySpatialComms extends EventManager_1.EventManager {
567
598
  if (!this.localParticipant || !this.room)
568
599
  return;
569
600
  const myChannel = this.localParticipant.currentChannel || "spatial";
601
+ console.log(`[CHANNEL-DEBUG] updateAllParticipantsMuteState - My channel: ${myChannel}`);
570
602
  this.room.participants.forEach((participant) => {
571
603
  // Skip local participant (never hear yourself)
572
604
  if (participant.participantId === this.localParticipant?.participantId) {
@@ -574,6 +606,7 @@ class OdysseySpatialComms extends EventManager_1.EventManager {
574
606
  }
575
607
  const theirChannel = participant.currentChannel || "spatial";
576
608
  const shouldMute = myChannel !== theirChannel;
609
+ console.log(` - ${participant.participantId?.substring(0, 8)}: channel=${theirChannel}, shouldMute=${shouldMute}`);
577
610
  this.spatialAudioManager.setParticipantMuted(participant.participantId, shouldMute);
578
611
  });
579
612
  }
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.37",
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",