@newgameplusinc/odyssey-audio-video-sdk-dev 1.0.257 → 1.0.258

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.
@@ -58,9 +58,8 @@ export declare class SpatialAudioManager extends EventManager {
58
58
  private panCenterDeadZone;
59
59
  private cachedSpeakerPositions;
60
60
  private cachedListenerPosition;
61
+ private listenerPositionInitialized;
61
62
  private positionSnapThreshold;
62
- private cachedGainValues;
63
- private gainChangeThreshold;
64
63
  private _listenerDebugLogTime?;
65
64
  private mlSuppressor;
66
65
  private mlModelReady;
@@ -42,16 +42,11 @@ class SpatialAudioManager extends EventManager_1.EventManager {
42
42
  this.cachedSpeakerPositions = new Map();
43
43
  // Cache for last snapped listener position
44
44
  this.cachedListenerPosition = { x: 0, y: 0, z: 0 };
45
+ // Track if listener position has been set at least once
46
+ this.listenerPositionInitialized = false;
45
47
  // Minimum position change (in meters) to trigger recalculation
46
48
  // 0.30m = 30cm - ignores pixel streaming jitter, physics wobble, breathing
47
- // ALIGNED with server-side 100cm filter - this catches smaller jitter
48
49
  this.positionSnapThreshold = 0.30;
49
- // GAIN STABILIZATION: Prevents gain fluctuations when distance is stable
50
- // Caches last calculated gain value for each participant
51
- this.cachedGainValues = new Map();
52
- // Minimum gain change (0-1 scale) to trigger update
53
- // 0.05 = 5% change required - filters out tiny distance jitter
54
- this.gainChangeThreshold = 0.05;
55
50
  // NOTE: Rate limiting variables removed - setTargetAtTime provides sufficient smoothing
56
51
  // The smoothPanValue() and position snapping handle jitter reduction
57
52
  // ML Noise Suppressor (TensorFlow.js-based)
@@ -387,25 +382,20 @@ class SpatialAudioManager extends EventManager_1.EventManager {
387
382
  // SNAP: Reduce jitter by ignoring micro-movements (<15cm)
388
383
  const snappedSpeakerPos = this.snapPosition(normalizedBodyPosition, participantId);
389
384
  const speakerHeadPosition = this.computeHeadPosition(snappedSpeakerPos);
390
- // SNAP: Use cached listener position to reduce jitter
391
- const listenerPos = this.cachedListenerPosition.x !== 0 || this.cachedListenerPosition.z !== 0
385
+ // Use cached listener position if initialized, otherwise use current position
386
+ const listenerPos = this.listenerPositionInitialized
392
387
  ? this.cachedListenerPosition
393
388
  : this.listenerPosition;
394
- // DEBUG: Log positions for troubleshooting distance issues
395
- const distX = speakerHeadPosition.x - listenerPos.x;
396
- const distY = speakerHeadPosition.y - listenerPos.y;
397
- const distZ = speakerHeadPosition.z - listenerPos.z;
398
389
  // Step 2: Calculate 3D distance (Euclidean distance from datum-based positions)
399
390
  // distance = √(Δx² + Δy² + Δz²)
400
391
  const distance = this.getDistanceBetween(listenerPos, speakerHeadPosition);
401
- // HARD CUTOFF: Fade out completely if beyond max distance (15m)
402
- // This prevents any audio processing for distant participants
403
- const maxDistance = 15.0;
404
- if (distance >= maxDistance) {
405
- // Smooth fade to zero - prevents click (100ms fade)
406
- nodes.gain.gain.setTargetAtTime(0, this.audioContext.currentTime, 0.033);
407
- this.cachedGainValues.set(participantId, 0);
408
- return; // Skip all other processing
392
+ // DEBUG: Log distance and gain every 2 seconds
393
+ const now = Date.now();
394
+ const lastLog = this._spatialDebugTimes.get(participantId) || 0;
395
+ if (now - lastLog > 2000) {
396
+ this._spatialDebugTimes.set(participantId, now);
397
+ const calculatedGainDebug = this.calculateLogarithmicGain(distance);
398
+ console.log(`🔊 SPATIAL DEBUG [${participantId.substring(0, 8)}]: dist=${distance.toFixed(2)}m, gain=${calculatedGainDebug}%, listenerInit=${this.listenerPositionInitialized}, listener=(${listenerPos.x.toFixed(1)},${listenerPos.y.toFixed(1)},${listenerPos.z.toFixed(1)}), speaker=(${speakerHeadPosition.x.toFixed(1)},${speakerHeadPosition.y.toFixed(1)},${speakerHeadPosition.z.toFixed(1)})`);
409
399
  }
410
400
  // Step 3: Calculate relative vector (speaker relative to listener)
411
401
  // vecToSource = speaker.pos - listener.pos
@@ -438,37 +428,22 @@ class SpatialAudioManager extends EventManager_1.EventManager {
438
428
  const panning = this.panningFromPanValue(smoothedPanValue, dxLocal);
439
429
  // Calculate gain based on distance
440
430
  const calculatedGain = this.calculateLogarithmicGain(distance);
441
- const newGainValue = calculatedGain / 100; // Convert to 0-1 range
442
- // SIMPLE GAIN STABILIZATION: Only update if change exceeds threshold
443
- const cachedGain = this.cachedGainValues.get(participantId);
444
- let finalGainValue = newGainValue;
445
- if (cachedGain !== undefined) {
446
- const gainChange = Math.abs(newGainValue - cachedGain);
447
- if (gainChange < this.gainChangeThreshold) {
448
- // Change too small - keep cached value for stability
449
- finalGainValue = cachedGain;
450
- }
451
- else {
452
- // Significant change - update cache
453
- this.cachedGainValues.set(participantId, newGainValue);
454
- }
455
- }
456
- else {
457
- // First time - cache the value
458
- this.cachedGainValues.set(participantId, newGainValue);
459
- }
431
+ const gainValue = calculatedGain / 100; // Convert to 0-1 range
432
+ // DEBUG: Log RSD processing in SDK with ALL data for matching with Vue
433
+ console.log(`[SDK-RSD] id=${participantId.substring(0, 8)} | speakerPos=(${speakerHeadPosition.x.toFixed(1)},${speakerHeadPosition.y.toFixed(1)},${speakerHeadPosition.z.toFixed(1)}) | listenerPos=(${listenerPos.x.toFixed(1)},${listenerPos.y.toFixed(1)},${listenerPos.z.toFixed(1)}) | dist=${distance.toFixed(2)}m | gain=${(gainValue * 100).toFixed(0)}% | pan=${smoothedPanValue.toFixed(2)} (L:${panning.left.toFixed(0)}% R:${panning.right.toFixed(0)}%)`);
460
434
  // Apply panning
461
435
  this.applyStereoPanning(participantId, panning);
462
436
  // Apply gain with Web Audio's built-in smoothing (setTargetAtTime)
437
+ // This provides all the smoothing needed - no additional caching required
463
438
  const currentTime = this.audioContext.currentTime;
464
439
  try {
465
440
  // setTargetAtTime provides smooth exponential interpolation
466
441
  // Time constant 0.1 = ~300ms to settle
467
- nodes.gain.gain.setTargetAtTime(finalGainValue, currentTime, 0.1);
442
+ nodes.gain.gain.setTargetAtTime(gainValue, currentTime, 0.1);
468
443
  }
469
444
  catch (err) {
470
445
  // Fallback: If scheduling fails, set value directly (rare edge case)
471
- nodes.gain.gain.value = finalGainValue;
446
+ nodes.gain.gain.value = gainValue;
472
447
  }
473
448
  }
474
449
  }
@@ -488,8 +463,6 @@ class SpatialAudioManager extends EventManager_1.EventManager {
488
463
  // Smooth ramp to 0 (muted) or 1 (unmuted) - prevents click
489
464
  // Time constant 0.05 = ~150ms to reach target (3 time constants)
490
465
  nodes.gain.gain.setTargetAtTime(muted ? 0 : 1, this.audioContext.currentTime, 0.05);
491
- // Update cached gain value when muting/unmuting
492
- this.cachedGainValues.set(participantId, muted ? 0 : 1);
493
466
  }
494
467
  }
495
468
  /**
@@ -532,6 +505,8 @@ class SpatialAudioManager extends EventManager_1.EventManager {
532
505
  * @param rot Rotation data (pitch, yaw, roll) - stored but not used for panning
533
506
  */
534
507
  setListenerFromLSD(listenerPos, cameraPos, lookAtPos, rot, localParticipantId) {
508
+ // DEBUG: Log LSD data received in SDK
509
+ console.log(`[SDK-LSD] cam=(${cameraPos.x.toFixed(1)},${cameraPos.y.toFixed(1)},${cameraPos.z.toFixed(1)}) rot=(${rot?.x?.toFixed(1)},${rot?.y?.toFixed(1)},${rot?.z?.toFixed(1)})`);
535
510
  // Store local participant ID for logging
536
511
  if (localParticipantId && !this.localParticipantId) {
537
512
  this.localParticipantId = localParticipantId;
@@ -685,8 +660,6 @@ class SpatialAudioManager extends EventManager_1.EventManager {
685
660
  this.participantNodes.delete(participantId);
686
661
  // Clean up smoothed pan value tracking
687
662
  this.smoothedPanValues.delete(participantId);
688
- // Clean up cached gain values
689
- this.cachedGainValues.delete(participantId);
690
663
  // Clean up cached speaker position
691
664
  this.cachedSpeakerPositions.delete(participantId);
692
665
  }
@@ -780,10 +753,12 @@ class SpatialAudioManager extends EventManager_1.EventManager {
780
753
  const cached = isListener
781
754
  ? this.cachedListenerPosition
782
755
  : this.cachedSpeakerPositions.get(participantId);
783
- // If no cached position, use this one as the baseline
784
- if (!cached || (cached.x === 0 && cached.y === 0 && cached.z === 0)) {
756
+ // If no cached position or first time, use this one as the baseline
757
+ const isFirstTime = !cached || (!this.listenerPositionInitialized && isListener);
758
+ if (isFirstTime) {
785
759
  if (isListener) {
786
760
  this.cachedListenerPosition = { ...position };
761
+ this.listenerPositionInitialized = true;
787
762
  }
788
763
  else {
789
764
  this.cachedSpeakerPositions.set(participantId, { ...position });
package/dist/index.js CHANGED
@@ -436,6 +436,8 @@ class OdysseySpatialComms extends EventManager_1.EventManager {
436
436
  }
437
437
  });
438
438
  this.socket.on("participant-position-updated", (data) => {
439
+ // DEBUG: Log position update received from socket
440
+ console.log(`[SDK-SOCKET] id=${data.participantId.substring(0, 8)} pos=(${data.position.x.toFixed(1)},${data.position.y.toFixed(1)},${data.position.z.toFixed(1)}) rot=(${data.rot?.x?.toFixed(1)},${data.rot?.y?.toFixed(1)},${data.rot?.z?.toFixed(1)})`);
439
441
  const participant = this.room?.participants.get(data.participantId);
440
442
  if (participant) {
441
443
  participant.position = data.position;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@newgameplusinc/odyssey-audio-video-sdk-dev",
3
- "version": "1.0.257",
3
+ "version": "1.0.258",
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",