@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.
- package/dist/MediasoupManager.d.ts +1 -1
- package/dist/MediasoupManager.js +2 -2
- package/dist/SpatialAudioManager.js +5 -1
- package/dist/index.d.ts +3 -6
- package/dist/index.js +26 -82
- package/package.json +1 -1
|
@@ -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;
|
package/dist/MediasoupManager.js
CHANGED
|
@@ -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
|
|
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
|
|
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
|
-
|
|
115
|
-
|
|
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
|
-
//
|
|
329
|
-
|
|
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
|
-
//
|
|
340
|
-
|
|
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
|
-
|
|
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