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

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.
@@ -15,7 +15,7 @@ export declare class MediasoupManager {
15
15
  createRecvTransport(participantId: string): Promise<void>;
16
16
  private connectSendTransport;
17
17
  private connectRecvTransport;
18
- produce(track: MediaStreamTrack): Promise<types.Producer>;
18
+ produce(track: MediaStreamTrack, appData?: any): Promise<types.Producer>;
19
19
  consume(data: {
20
20
  consumerId: string;
21
21
  producerId: string;
@@ -99,10 +99,10 @@ class MediasoupManager {
99
99
  });
100
100
  });
101
101
  }
102
- async produce(track) {
102
+ async produce(track, appData) {
103
103
  if (!this.sendTransport)
104
104
  throw new Error("Send transport not initialized");
105
- const producer = await this.sendTransport.produce({ track });
105
+ const producer = await this.sendTransport.produce({ track, appData });
106
106
  this.producers.set(producer.id, producer);
107
107
  return producer;
108
108
  }
@@ -243,7 +243,11 @@ class SpatialAudioManager extends EventManager_1.EventManager {
243
243
  */
244
244
  setParticipantMuted(participantId, muted) {
245
245
  const nodes = this.participantNodes.get(participantId);
246
- if (nodes?.gain) {
246
+ if (!nodes) {
247
+ // Audio nodes don't exist yet - this is normal if called before consumer is set up
248
+ return;
249
+ }
250
+ if (nodes.gain) {
247
251
  // Set gain to 0 (muted) or 1 (unmuted) immediately
248
252
  nodes.gain.gain.setValueAtTime(muted ? 0 : 1, this.audioContext.currentTime);
249
253
  }
package/dist/index.d.ts CHANGED
@@ -28,7 +28,9 @@ export declare class OdysseySpatialComms extends EventManager {
28
28
  leaveRoom(): void;
29
29
  resumeAudio(): Promise<void>;
30
30
  getAudioContextState(): AudioContextState;
31
- produceTrack(track: MediaStreamTrack): Promise<any>;
31
+ produceTrack(track: MediaStreamTrack, appData?: {
32
+ isScreenshare?: boolean;
33
+ }): Promise<any>;
32
34
  updatePosition(position: Position, direction: Direction, spatialData?: {
33
35
  cameraDistance?: number;
34
36
  screenPos?: {
@@ -95,11 +97,6 @@ export declare class OdysseySpatialComms extends EventManager {
95
97
  /**
96
98
  * Mute another participant (owner only)
97
99
  */
98
- /**
99
- * Update mute state for all participants based on channel matching
100
- * Called when local user switches channels
101
- */
102
- private updateAllParticipantsMuteState;
103
100
  muteParticipant(participantId: string): Promise<{
104
101
  success?: boolean;
105
102
  error?: string;
package/dist/index.js CHANGED
@@ -101,8 +101,8 @@ class OdysseySpatialComms extends EventManager_1.EventManager {
101
101
  getAudioContextState() {
102
102
  return this.spatialAudioManager.getAudioContextState();
103
103
  }
104
- async produceTrack(track) {
105
- const producer = await this.mediasoupManager.produce(track);
104
+ async produceTrack(track, appData) {
105
+ const producer = await this.mediasoupManager.produce(track, appData);
106
106
  if (this.localParticipant) {
107
107
  const isFirstProducer = this.localParticipant.producers.size === 0;
108
108
  this.localParticipant.producers.set(producer.id, producer);
@@ -111,8 +111,15 @@ class OdysseySpatialComms extends EventManager_1.EventManager {
111
111
  this.localParticipant.mediaState.audio = true;
112
112
  }
113
113
  else if (track.kind === "video") {
114
- this.localParticipant.videoTrack = track;
115
- this.localParticipant.mediaState.video = true;
114
+ // Store as videoTrack or screenshareTrack based on metadata
115
+ if (appData?.isScreenshare) {
116
+ this.localParticipant.screenshareTrack = track;
117
+ this.localParticipant.mediaState.sharescreen = true;
118
+ }
119
+ else {
120
+ this.localParticipant.videoTrack = track;
121
+ this.localParticipant.mediaState.video = true;
122
+ }
116
123
  }
117
124
  // Send device RTP capabilities after first track is produced
118
125
  // This ensures transports are fully connected via DTLS
@@ -233,13 +240,6 @@ class OdysseySpatialComms extends EventManager_1.EventManager {
233
240
  ? Array.from(this.room.participants.values())
234
241
  : [];
235
242
  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
243
  });
244
244
  this.socket.on("new-participant", (participantData) => {
245
245
  if (this.room) {
@@ -325,25 +325,11 @@ class OdysseySpatialComms extends EventManager_1.EventManager {
325
325
  return; // Exit early to prevent any audio processing
326
326
  }
327
327
  else {
328
- // Check if participant is in huddle - if so, skip spatial audio
329
- const participantChannel = participant.currentChannel || "spatial";
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}`);
336
- // Setup spatial audio with full 3D positioning (disabled for huddle users)
337
- await this.spatialAudioManager.setupSpatialAudioForParticipant(participant.participantId, track, isInHuddle // Disable spatial audio for huddle users
328
+ // Setup spatial audio with full 3D positioning
329
+ await this.spatialAudioManager.setupSpatialAudioForParticipant(participant.participantId, track, false // Always enable spatial audio
338
330
  );
339
- // CRITICAL: Mute if not in same channel
340
- const shouldMute = myChannel !== participantChannel;
341
- console.log(` - Should mute: ${shouldMute} (channels ${myChannel === participantChannel ? 'MATCH' : 'DIFFER'})`);
342
- this.spatialAudioManager.setParticipantMuted(participant.participantId, shouldMute);
343
- // Only update spatial audio position if NOT in huddle
344
- if (!isInHuddle) {
345
- this.spatialAudioManager.updateSpatialAudio(participant.participantId, data.position);
346
- }
331
+ // Update spatial audio position
332
+ this.spatialAudioManager.updateSpatialAudio(participant.participantId, data.position);
347
333
  }
348
334
  // NOW resume the consumer after audio pipeline is ready
349
335
  this.mediasoupManager
@@ -356,7 +342,16 @@ class OdysseySpatialComms extends EventManager_1.EventManager {
356
342
  });
357
343
  }
358
344
  else if (track.kind === "video") {
359
- participant.videoTrack = track;
345
+ // Check if this is a screenshare or camera video
346
+ const isScreenshare = data.appData?.isScreenshare;
347
+ if (isScreenshare) {
348
+ // Store as screenshareTrack
349
+ participant.screenshareTrack = track;
350
+ }
351
+ else {
352
+ // Store as regular videoTrack (camera)
353
+ participant.videoTrack = track;
354
+ }
360
355
  // Resume video consumer immediately (no audio pipeline needed)
361
356
  this.mediasoupManager
362
357
  .resumeConsumer(consumer.id)
@@ -367,6 +362,7 @@ class OdysseySpatialComms extends EventManager_1.EventManager {
367
362
  participant,
368
363
  track,
369
364
  consumer,
365
+ isScreenshare: data.appData?.isScreenshare,
370
366
  });
371
367
  }
372
368
  });
@@ -436,37 +432,13 @@ class OdysseySpatialComms extends EventManager_1.EventManager {
436
432
  this.emit("huddle-ended", data);
437
433
  });
438
434
  this.socket.on("participant-channel-changed", (data) => {
439
- console.log(`📡 participant-channel-changed: ${data.participantId?.substring(0, 8)} → ${data.channelId}`);
440
435
  const participant = this.room?.participants.get(data.participantId);
441
436
  if (participant) {
442
437
  participant.currentChannel = data.channelId;
443
- // Toggle spatial audio based on channel
444
- const isInHuddle = data.channelId !== "spatial";
445
- // Update spatial audio bypass state for this participant
446
- if (participant.audioTrack) {
447
- this.spatialAudioManager.setupSpatialAudioForParticipant(participant.participantId, participant.audioTrack, isInHuddle // Disable spatial for huddle, enable for spatial
448
- ).catch(err => {
449
- console.error(`Failed to update spatial audio for ${participant.participantId}:`, err);
450
- });
451
- }
452
- // CRITICAL: Mute/unmute based on channel matching
453
- const myChannel = this.localParticipant?.currentChannel || "spatial";
454
- const theirChannel = data.channelId || "spatial";
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}`);
461
- this.spatialAudioManager.setParticipantMuted(participant.participantId, shouldMute);
462
438
  }
463
439
  // Update local participant if it's them
464
440
  if (this.localParticipant?.participantId === data.participantId && this.localParticipant !== null) {
465
- console.log(`[CHANNEL-DEBUG] LOCAL USER changed channel to: ${data.channelId}`);
466
441
  this.localParticipant.currentChannel = data.channelId;
467
- // When LOCAL user changes channel, update ALL other participants' mute state
468
- console.log(`[CHANNEL-DEBUG] Updating ALL participants mute state...`);
469
- this.updateAllParticipantsMuteState();
470
442
  }
471
443
  this.emit("participant-channel-changed", data);
472
444
  });
@@ -529,7 +501,6 @@ class OdysseySpatialComms extends EventManager_1.EventManager {
529
501
  * Join huddle (anyone can join directly without invite)
530
502
  */
531
503
  async joinHuddle() {
532
- console.log(`🎧 [joinHuddle] Joining group huddle...`);
533
504
  if (!this.localParticipant || !this.room) {
534
505
  return { success: false, error: "Not in a room" };
535
506
  }
@@ -539,10 +510,7 @@ class OdysseySpatialComms extends EventManager_1.EventManager {
539
510
  roomId: this.room.id,
540
511
  }, (response) => {
541
512
  if (response.success && this.localParticipant) {
542
- console.log(`✅ [joinHuddle] Success! New channel: ${response.channelId}`);
543
513
  this.localParticipant.currentChannel = response.channelId;
544
- // CRITICAL: Update mute state for all participants when joining huddle
545
- this.updateAllParticipantsMuteState();
546
514
  }
547
515
  else {
548
516
  console.error(`❌ [joinHuddle] Failed:`, response.error);
@@ -555,7 +523,6 @@ class OdysseySpatialComms extends EventManager_1.EventManager {
555
523
  * Leave current huddle and return to spatial audio
556
524
  */
557
525
  async leaveHuddle() {
558
- console.log(`🚪 [leaveHuddle] Leaving huddle...`);
559
526
  if (!this.localParticipant || !this.room) {
560
527
  return { success: false, error: "Not in a room" };
561
528
  }
@@ -565,10 +532,7 @@ class OdysseySpatialComms extends EventManager_1.EventManager {
565
532
  roomId: this.room.id,
566
533
  }, (response) => {
567
534
  if (response.success && this.localParticipant) {
568
- console.log(`✅ [leaveHuddle] Success! New channel: ${response.channelId}`);
569
535
  this.localParticipant.currentChannel = response.channelId;
570
- // CRITICAL: Update mute state for all participants when leaving huddle
571
- this.updateAllParticipantsMuteState();
572
536
  }
573
537
  else {
574
538
  console.error(`❌ [leaveHuddle] Failed:`, response.error);
@@ -590,26 +554,6 @@ class OdysseySpatialComms extends EventManager_1.EventManager {
590
554
  /**
591
555
  * Mute another participant (owner only)
592
556
  */
593
- /**
594
- * Update mute state for all participants based on channel matching
595
- * Called when local user switches channels
596
- */
597
- updateAllParticipantsMuteState() {
598
- if (!this.localParticipant || !this.room)
599
- return;
600
- const myChannel = this.localParticipant.currentChannel || "spatial";
601
- console.log(`[CHANNEL-DEBUG] updateAllParticipantsMuteState - My channel: ${myChannel}`);
602
- this.room.participants.forEach((participant) => {
603
- // Skip local participant (never hear yourself)
604
- if (participant.participantId === this.localParticipant?.participantId) {
605
- return;
606
- }
607
- const theirChannel = participant.currentChannel || "spatial";
608
- const shouldMute = myChannel !== theirChannel;
609
- console.log(` - ${participant.participantId?.substring(0, 8)}: channel=${theirChannel}, shouldMute=${shouldMute}`);
610
- this.spatialAudioManager.setParticipantMuted(participant.participantId, shouldMute);
611
- });
612
- }
613
557
  async muteParticipant(participantId) {
614
558
  if (!this.localParticipant || !this.room) {
615
559
  return { success: false, error: "Not in a room" };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@newgameplusinc/odyssey-audio-video-sdk-dev",
3
- "version": "1.0.37",
3
+ "version": "1.0.39",
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",