@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.
- package/dist/index.js +113 -80
- 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
|
|
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
|
|
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