mediasfu-shared 1.0.2 → 1.0.4
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/README.md +108 -103
- package/dist/index.cjs +163 -46
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +163 -46
- package/dist/index.js.map +1 -1
- package/package.json +99 -85
- package/src/consumers/connectIps.ts +3 -1
- package/src/consumers/connectLocalIps.ts +3 -1
- package/src/consumers/connectRecvTransport.ts +75 -21
- package/src/consumers/processConsumerTransportsAudio.ts +94 -2
- package/src/consumers/translationConsumerSwitch.ts +38 -16
- package/src/methods/requests/hostRequestResponse.ts +12 -7
- package/src/methods/socketReceive/translationReceiveMethods.ts +2 -2
- package/src/methods/stream/clickVideo.ts +6 -1
- package/src/methods/utils/resolveMediaSFURoomApi.ts +13 -1
package/README.md
CHANGED
|
@@ -1,103 +1,108 @@
|
|
|
1
|
-
# mediasfu-shared
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
-
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
- `mediasfu-shared
|
|
76
|
-
- `mediasfu-shared/
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
-
|
|
100
|
-
|
|
101
|
-
##
|
|
102
|
-
|
|
103
|
-
|
|
1
|
+
# mediasfu-shared · [mediasfu-shared on npm](https://www.npmjs.com/package/mediasfu-shared)
|
|
2
|
+
|
|
3
|
+
**mediasfu-shared** is the framework-agnostic WebRTC runtime at the core of the MediaSFU SDK family. It provides shared room helpers, mediasoup signaling, socket management, media state utilities, and TypeScript types for React, Vue, Angular, Svelte, and plain TypeScript. Install with `npm install mediasfu-shared`.
|
|
4
|
+
|
|
5
|
+
`mediasfu-shared` is the framework-agnostic MediaSFU runtime package. It exposes the shared room helpers, mediasoup/socket flows, state utilities, and TypeScript types used by the MediaSFU SDK family.
|
|
6
|
+
|
|
7
|
+
## When To Use This Package
|
|
8
|
+
|
|
9
|
+
Use `mediasfu-shared` when you want to:
|
|
10
|
+
|
|
11
|
+
- build your own browser client on top of MediaSFU primitives without adopting a framework-specific UI package
|
|
12
|
+
- share MediaSFU room, media, and participant logic across React, Vue, Angular, Svelte, or plain TypeScript codebases
|
|
13
|
+
- import low-level helpers such as `createRoomOnMediaSFU`, `joinRoomOnMediaSFU`, `connectSocket`, `SocketManager`, and the exported consumers, methods, and types entry points
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install mediasfu-shared mediasoup-client socket.io-client
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
`mediasoup-client` and `socket.io-client` are peer dependencies, so install them in the host app.
|
|
22
|
+
|
|
23
|
+
## Backend Requirement
|
|
24
|
+
|
|
25
|
+
The cloud room helpers in this package target `https://mediasfu.com/v1/rooms/` by default.
|
|
26
|
+
|
|
27
|
+
- Use MediaSFU Cloud when you want managed room creation, signaling, and media routing. Pass `apiUserName` and `apiKey`.
|
|
28
|
+
- Use MediaSFU Open / Community Edition when you self-host. Pass a non-MediaSFU `localLink` such as `http://localhost:3000`.
|
|
29
|
+
|
|
30
|
+
## Quick Example
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import {
|
|
34
|
+
SocketManager,
|
|
35
|
+
connectSocket,
|
|
36
|
+
createRoomOnMediaSFU,
|
|
37
|
+
joinRoomOnMediaSFU,
|
|
38
|
+
} from 'mediasfu-shared';
|
|
39
|
+
|
|
40
|
+
const createResult = await createRoomOnMediaSFU({
|
|
41
|
+
payload: {
|
|
42
|
+
action: 'create',
|
|
43
|
+
userName: 'Ada',
|
|
44
|
+
duration: 60,
|
|
45
|
+
capacity: 10,
|
|
46
|
+
},
|
|
47
|
+
apiUserName: 'your-api-username',
|
|
48
|
+
apiKey: 'your-64-character-api-key',
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const joinResult = await joinRoomOnMediaSFU({
|
|
52
|
+
payload: {
|
|
53
|
+
action: 'join',
|
|
54
|
+
meetingID: 'room123',
|
|
55
|
+
userName: 'Ben',
|
|
56
|
+
},
|
|
57
|
+
apiUserName: 'your-api-username',
|
|
58
|
+
apiKey: 'your-64-character-api-key',
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const socket = await connectSocket({
|
|
62
|
+
apiUserName: 'your-api-username',
|
|
63
|
+
apiKey: 'your-64-character-api-key',
|
|
64
|
+
apiToken: 'your-api-token',
|
|
65
|
+
link: 'https://mediasfu.com/socket',
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const socketManager = new SocketManager({ socket });
|
|
69
|
+
|
|
70
|
+
console.log(createResult.success, joinResult.success, socketManager.socket.connected);
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Import Paths
|
|
74
|
+
|
|
75
|
+
- `mediasfu-shared` exposes the full public runtime surface.
|
|
76
|
+
- `mediasfu-shared/consumers` is useful when you want consumer/grid helpers only.
|
|
77
|
+
- `mediasfu-shared/methods` is useful when you want action utilities and room helpers.
|
|
78
|
+
- `mediasfu-shared/types` is useful when you only need TypeScript contracts.
|
|
79
|
+
|
|
80
|
+
## Documentation
|
|
81
|
+
|
|
82
|
+
- Main docs: [https://mediasfu.com/documentation](https://mediasfu.com/documentation)
|
|
83
|
+
- User guide: [https://mediasfu.com/user-guide](https://mediasfu.com/user-guide)
|
|
84
|
+
- MediaSFU Open / CE: [https://github.com/MediaSFU/MediaSFUOpen](https://github.com/MediaSFU/MediaSFUOpen)
|
|
85
|
+
|
|
86
|
+
Generate package-local API docs with:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
npm run build-docs
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Related Packages
|
|
93
|
+
|
|
94
|
+
| Package | Framework | npm |
|
|
95
|
+
|---------|-----------|-----|
|
|
96
|
+
| [mediasfu-reactjs](https://github.com/MediaSFU/MediaSFU-ReactJS) | React 18/19 | [`npm install mediasfu-reactjs`](https://www.npmjs.com/package/mediasfu-reactjs) |
|
|
97
|
+
| [mediasfu-vue](https://github.com/MediaSFU/MediaSFU-Vue) | Vue 3 / Composition API | [`npm install mediasfu-vue`](https://www.npmjs.com/package/mediasfu-vue) |
|
|
98
|
+
| [mediasfu-angular](https://github.com/MediaSFU/MediaSFU-Angular) | Angular 17/18/19 | [`npm install mediasfu-angular`](https://www.npmjs.com/package/mediasfu-angular) |
|
|
99
|
+
| [mediasfu-reactnative](https://www.npmjs.com/package/mediasfu-reactnative) | React Native | [`npm install mediasfu-reactnative`](https://www.npmjs.com/package/mediasfu-reactnative) |
|
|
100
|
+
|
|
101
|
+
## Support
|
|
102
|
+
|
|
103
|
+
- GitHub issues: [https://github.com/MediaSFU/MediaSFU-Shared/issues](https://github.com/MediaSFU/MediaSFU-Shared/issues)
|
|
104
|
+
- Email: info@mediasfu.com
|
|
105
|
+
|
|
106
|
+
## License
|
|
107
|
+
|
|
108
|
+
MIT. See [LICENSE](LICENSE).
|
package/dist/index.cjs
CHANGED
|
@@ -1260,13 +1260,15 @@ const connectIps = async ({
|
|
|
1260
1260
|
roomRecvIPs.push(ip);
|
|
1261
1261
|
updateRoomRecvIPs(roomRecvIPs);
|
|
1262
1262
|
}
|
|
1263
|
-
remote_sock.on("new-pipe-producer", async ({ producerId, islevel }) => {
|
|
1263
|
+
remote_sock.on("new-pipe-producer", async ({ producerId, islevel, isTranslation, translationMeta }) => {
|
|
1264
1264
|
if (newProducerMethod) {
|
|
1265
1265
|
await newProducerMethod({
|
|
1266
1266
|
producerId,
|
|
1267
1267
|
islevel,
|
|
1268
1268
|
nsock: remote_sock,
|
|
1269
|
-
parameters
|
|
1269
|
+
parameters,
|
|
1270
|
+
isTranslation,
|
|
1271
|
+
translationMeta
|
|
1270
1272
|
});
|
|
1271
1273
|
}
|
|
1272
1274
|
});
|
|
@@ -1307,13 +1309,15 @@ const connectLocalIps = async ({
|
|
|
1307
1309
|
parameters
|
|
1308
1310
|
}) => {
|
|
1309
1311
|
try {
|
|
1310
|
-
socket.on("new-producer", async ({ producerId, islevel }) => {
|
|
1312
|
+
socket.on("new-producer", async ({ producerId, islevel, isTranslation, translationMeta }) => {
|
|
1311
1313
|
if (newProducerMethod) {
|
|
1312
1314
|
await newProducerMethod({
|
|
1313
1315
|
producerId,
|
|
1314
1316
|
islevel,
|
|
1315
1317
|
nsock: socket,
|
|
1316
|
-
parameters
|
|
1318
|
+
parameters,
|
|
1319
|
+
isTranslation,
|
|
1320
|
+
translationMeta
|
|
1317
1321
|
});
|
|
1318
1322
|
}
|
|
1319
1323
|
});
|
|
@@ -1327,6 +1331,47 @@ const connectLocalIps = async ({
|
|
|
1327
1331
|
console.log("ConnectLocalIps error", error);
|
|
1328
1332
|
}
|
|
1329
1333
|
};
|
|
1334
|
+
const getSpeakerNameForProducerId$1 = (producerId, parameters) => {
|
|
1335
|
+
const participants = parameters.participants;
|
|
1336
|
+
const participant = participants?.find((candidate) => candidate.audioID === producerId);
|
|
1337
|
+
if (participant?.name) {
|
|
1338
|
+
return participant.name;
|
|
1339
|
+
}
|
|
1340
|
+
const audStreamName = parameters.audStreamNames?.find((stream) => stream.producerId === producerId && typeof stream.name === "string");
|
|
1341
|
+
if (audStreamName?.name) {
|
|
1342
|
+
return audStreamName.name;
|
|
1343
|
+
}
|
|
1344
|
+
return parameters.allAudioStreams?.find((stream) => stream.producerId === producerId && typeof stream.name === "string")?.name;
|
|
1345
|
+
};
|
|
1346
|
+
const isOriginalAudioSuppressedByTranslation$1 = (producerId, parameters) => {
|
|
1347
|
+
const activeTranslationProducerIds = parameters.activeTranslationProducerIds;
|
|
1348
|
+
if (activeTranslationProducerIds?.has(producerId)) {
|
|
1349
|
+
return false;
|
|
1350
|
+
}
|
|
1351
|
+
const speakerTranslationStates = parameters.speakerTranslationStates;
|
|
1352
|
+
if (!speakerTranslationStates?.size) {
|
|
1353
|
+
return false;
|
|
1354
|
+
}
|
|
1355
|
+
const speakerName = getSpeakerNameForProducerId$1(producerId, parameters);
|
|
1356
|
+
if (speakerName) {
|
|
1357
|
+
const speakerState = speakerTranslationStates.get(speakerName);
|
|
1358
|
+
if (speakerState?.enabled) {
|
|
1359
|
+
return true;
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
return Array.from(speakerTranslationStates.values()).some((speakerState) => {
|
|
1363
|
+
if (!speakerState?.enabled) {
|
|
1364
|
+
return false;
|
|
1365
|
+
}
|
|
1366
|
+
if (speakerState.originalProducerId === producerId) {
|
|
1367
|
+
return true;
|
|
1368
|
+
}
|
|
1369
|
+
if (!speakerName) {
|
|
1370
|
+
return false;
|
|
1371
|
+
}
|
|
1372
|
+
return speakerState.speakerId === speakerName || speakerState.speakerName === speakerName;
|
|
1373
|
+
});
|
|
1374
|
+
};
|
|
1330
1375
|
const connectRecvTransport = async ({
|
|
1331
1376
|
consumerTransport,
|
|
1332
1377
|
remoteProducerId,
|
|
@@ -1388,24 +1433,15 @@ const connectRecvTransport = async ({
|
|
|
1388
1433
|
if (params.kind === "audio") {
|
|
1389
1434
|
try {
|
|
1390
1435
|
const updatedParams = parameters.getUpdatedAllParams();
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
if (participant?.name) {
|
|
1398
|
-
const speakerState = speakerTranslationStates.get(participant.name);
|
|
1399
|
-
if (speakerState?.enabled && speakerState.originalProducerId === remoteProducerId) {
|
|
1400
|
-
consumer.pause();
|
|
1401
|
-
nsock.emit(
|
|
1402
|
-
"consumer-pause",
|
|
1403
|
-
{ serverConsumerId: params.serverConsumerId },
|
|
1404
|
-
() => {
|
|
1405
|
-
}
|
|
1406
|
-
);
|
|
1436
|
+
if (isOriginalAudioSuppressedByTranslation$1(remoteProducerId, updatedParams)) {
|
|
1437
|
+
consumer.pause();
|
|
1438
|
+
nsock.emit(
|
|
1439
|
+
"consumer-pause",
|
|
1440
|
+
{ serverConsumerId: params.serverConsumerId },
|
|
1441
|
+
() => {
|
|
1407
1442
|
}
|
|
1408
|
-
|
|
1443
|
+
);
|
|
1444
|
+
return;
|
|
1409
1445
|
}
|
|
1410
1446
|
} catch {
|
|
1411
1447
|
}
|
|
@@ -2666,6 +2702,50 @@ async function processConsumerTransports({
|
|
|
2666
2702
|
const getProducerId$1 = (value) => {
|
|
2667
2703
|
return value?.producerId;
|
|
2668
2704
|
};
|
|
2705
|
+
const getSpeakerNameForProducerId = (producerId, parameters) => {
|
|
2706
|
+
const participants = parameters.participants;
|
|
2707
|
+
const participant = participants?.find((candidate) => candidate.audioID === producerId);
|
|
2708
|
+
if (participant?.name) {
|
|
2709
|
+
return participant.name;
|
|
2710
|
+
}
|
|
2711
|
+
const audStreamName = parameters.audStreamNames?.find((stream) => stream.producerId === producerId && typeof stream.name === "string");
|
|
2712
|
+
if (audStreamName?.name) {
|
|
2713
|
+
return audStreamName.name;
|
|
2714
|
+
}
|
|
2715
|
+
return parameters.allAudioStreams?.find((stream) => stream.producerId === producerId && typeof stream.name === "string")?.name;
|
|
2716
|
+
};
|
|
2717
|
+
const isOriginalAudioSuppressedByTranslation = (producerId, parameters) => {
|
|
2718
|
+
if (!producerId) {
|
|
2719
|
+
return false;
|
|
2720
|
+
}
|
|
2721
|
+
const activeTranslationProducerIds = parameters.activeTranslationProducerIds;
|
|
2722
|
+
if (activeTranslationProducerIds?.has(producerId)) {
|
|
2723
|
+
return false;
|
|
2724
|
+
}
|
|
2725
|
+
const speakerTranslationStates = parameters.speakerTranslationStates;
|
|
2726
|
+
if (!speakerTranslationStates?.size) {
|
|
2727
|
+
return false;
|
|
2728
|
+
}
|
|
2729
|
+
const speakerName = getSpeakerNameForProducerId(producerId, parameters);
|
|
2730
|
+
if (speakerName) {
|
|
2731
|
+
const speakerState = speakerTranslationStates.get(speakerName);
|
|
2732
|
+
if (speakerState?.enabled) {
|
|
2733
|
+
return true;
|
|
2734
|
+
}
|
|
2735
|
+
}
|
|
2736
|
+
return Array.from(speakerTranslationStates.values()).some((speakerState) => {
|
|
2737
|
+
if (!speakerState?.enabled) {
|
|
2738
|
+
return false;
|
|
2739
|
+
}
|
|
2740
|
+
if (speakerState.originalProducerId === producerId) {
|
|
2741
|
+
return true;
|
|
2742
|
+
}
|
|
2743
|
+
if (!speakerName) {
|
|
2744
|
+
return false;
|
|
2745
|
+
}
|
|
2746
|
+
return speakerState.speakerId === speakerName || speakerState.speakerName === speakerName;
|
|
2747
|
+
});
|
|
2748
|
+
};
|
|
2669
2749
|
const processConsumerTransportsAudio = async ({
|
|
2670
2750
|
consumerTransports,
|
|
2671
2751
|
lStreams,
|
|
@@ -2679,12 +2759,12 @@ const processConsumerTransportsAudio = async ({
|
|
|
2679
2759
|
});
|
|
2680
2760
|
};
|
|
2681
2761
|
const consumerTransportsToResume = consumerTransports.filter(
|
|
2682
|
-
(transport) => isValidProducerId(transport.producerId, lStreams) && transport.consumer?.paused === true && transport.consumer?.kind === "audio"
|
|
2762
|
+
(transport) => isValidProducerId(transport.producerId, lStreams) && !isOriginalAudioSuppressedByTranslation(transport.producerId, parameters) && transport.consumer?.paused === true && transport.consumer?.kind === "audio"
|
|
2683
2763
|
);
|
|
2684
2764
|
const consumerTransportsToPause = consumerTransports.filter(
|
|
2685
|
-
(transport) => transport.producerId && transport.producerId !== null && transport.producerId !== "" && !lStreams.some(
|
|
2765
|
+
(transport) => transport.producerId && transport.producerId !== null && transport.producerId !== "" && (isOriginalAudioSuppressedByTranslation(transport.producerId, parameters) || !lStreams.some(
|
|
2686
2766
|
(stream) => getProducerId$1(stream) === transport.producerId
|
|
2687
|
-
) && transport.consumer && transport.consumer?.kind && transport.consumer.paused !== true && transport.consumer.kind === "audio"
|
|
2767
|
+
)) && transport.consumer && transport.consumer?.kind && transport.consumer.paused !== true && transport.consumer.kind === "audio"
|
|
2688
2768
|
);
|
|
2689
2769
|
await sleep2({ ms: 100 });
|
|
2690
2770
|
for (const transport of consumerTransportsToPause) {
|
|
@@ -2697,6 +2777,9 @@ const processConsumerTransportsAudio = async ({
|
|
|
2697
2777
|
);
|
|
2698
2778
|
}
|
|
2699
2779
|
for (const transport of consumerTransportsToResume) {
|
|
2780
|
+
if (isOriginalAudioSuppressedByTranslation(transport.producerId, parameters)) {
|
|
2781
|
+
continue;
|
|
2782
|
+
}
|
|
2700
2783
|
transport.socket_.emit(
|
|
2701
2784
|
"consumer-resume",
|
|
2702
2785
|
{ serverConsumerId: transport.serverConsumerTransportId },
|
|
@@ -4152,7 +4235,9 @@ const clickVideo = async ({ parameters }) => {
|
|
|
4152
4235
|
audioSetting,
|
|
4153
4236
|
videoSetting,
|
|
4154
4237
|
screenshareSetting,
|
|
4155
|
-
chatSetting
|
|
4238
|
+
chatSetting,
|
|
4239
|
+
permissionConfig: parameters.permissionConfig,
|
|
4240
|
+
participantLevel: islevel
|
|
4156
4241
|
});
|
|
4157
4242
|
} else {
|
|
4158
4243
|
response = 0;
|
|
@@ -5307,11 +5392,17 @@ const hostRequestResponse = async ({
|
|
|
5307
5392
|
updateChatRequestTime,
|
|
5308
5393
|
updateRequestIntervalSeconds
|
|
5309
5394
|
}) => {
|
|
5395
|
+
const requestType = requestResponse.type ?? requestResponse.icon;
|
|
5310
5396
|
const filteredRequests = requestList.filter(
|
|
5311
|
-
(request) =>
|
|
5397
|
+
(request) => {
|
|
5398
|
+
const matchesId = request.id === requestResponse.id;
|
|
5399
|
+
const matchesType = requestType == null || request.icon === requestType;
|
|
5400
|
+
const matchesName = requestResponse.name == null || request.name === requestResponse.name;
|
|
5401
|
+
const matchesUsername = requestResponse.username == null || request.username === requestResponse.username;
|
|
5402
|
+
return !(matchesId && matchesType && matchesName && matchesUsername);
|
|
5403
|
+
}
|
|
5312
5404
|
);
|
|
5313
5405
|
updateRequestList(filteredRequests);
|
|
5314
|
-
const requestType = requestResponse.type;
|
|
5315
5406
|
if (requestResponse.action === "accepted") {
|
|
5316
5407
|
switch (requestType) {
|
|
5317
5408
|
case "fa-microphone":
|
|
@@ -6277,11 +6368,20 @@ const updateRoomParametersClient = ({ parameters }) => {
|
|
|
6277
6368
|
}
|
|
6278
6369
|
};
|
|
6279
6370
|
const DEFAULT_MEDIA_SFU_ROOM_API_URL = "https://mediasfu.com/v1/rooms/";
|
|
6371
|
+
const normalizeManagedRoomApi = (normalizedLink) => {
|
|
6372
|
+
if (normalizedLink.includes("/v1/rooms")) {
|
|
6373
|
+
return `${normalizedLink.replace(/\/$/, "")}/`;
|
|
6374
|
+
}
|
|
6375
|
+
return `${normalizedLink.replace(/\/$/, "")}/v1/rooms/`;
|
|
6376
|
+
};
|
|
6280
6377
|
const resolveMediaSFURoomApi = (localLink, action) => {
|
|
6281
6378
|
const normalizedLink = localLink?.trim();
|
|
6282
|
-
if (!normalizedLink
|
|
6379
|
+
if (!normalizedLink) {
|
|
6283
6380
|
return DEFAULT_MEDIA_SFU_ROOM_API_URL;
|
|
6284
6381
|
}
|
|
6382
|
+
if (normalizedLink.includes("mediasfu.com")) {
|
|
6383
|
+
return normalizeManagedRoomApi(normalizedLink);
|
|
6384
|
+
}
|
|
6285
6385
|
return `${normalizedLink.replace(/\/$/, "")}/${action}`;
|
|
6286
6386
|
};
|
|
6287
6387
|
const readResponseError$1 = async (response) => {
|
|
@@ -7355,15 +7455,22 @@ const pauseOriginalProducer = async ({
|
|
|
7355
7455
|
const transport = consumerTransports.find(
|
|
7356
7456
|
(t) => t.producerId === originalProducerId && t.consumer?.kind === "audio"
|
|
7357
7457
|
);
|
|
7358
|
-
if (
|
|
7359
|
-
|
|
7360
|
-
|
|
7361
|
-
|
|
7362
|
-
|
|
7363
|
-
|
|
7364
|
-
|
|
7365
|
-
|
|
7458
|
+
if (!transport?.consumer) {
|
|
7459
|
+
return;
|
|
7460
|
+
}
|
|
7461
|
+
if (transport.consumer.track) {
|
|
7462
|
+
transport.consumer.track.enabled = false;
|
|
7463
|
+
}
|
|
7464
|
+
if (transport.consumer.paused) {
|
|
7465
|
+
return;
|
|
7366
7466
|
}
|
|
7467
|
+
transport.consumer.pause();
|
|
7468
|
+
transport.socket_?.emit(
|
|
7469
|
+
"consumer-pause",
|
|
7470
|
+
{ serverConsumerId: transport.serverConsumerTransportId },
|
|
7471
|
+
async () => {
|
|
7472
|
+
}
|
|
7473
|
+
);
|
|
7367
7474
|
} catch (error) {
|
|
7368
7475
|
console.error("[TranslationSwitch] Error pausing original producer:", error);
|
|
7369
7476
|
}
|
|
@@ -7381,17 +7488,27 @@ const resumeOriginalProducer = async ({
|
|
|
7381
7488
|
const transport = consumerTransports.find(
|
|
7382
7489
|
(t) => t.producerId === originalProducerId && t.consumer?.kind === "audio"
|
|
7383
7490
|
);
|
|
7384
|
-
if (transport
|
|
7385
|
-
|
|
7386
|
-
|
|
7387
|
-
|
|
7388
|
-
|
|
7389
|
-
|
|
7390
|
-
|
|
7491
|
+
if (!transport?.consumer) {
|
|
7492
|
+
return;
|
|
7493
|
+
}
|
|
7494
|
+
if (!transport.consumer.paused) {
|
|
7495
|
+
if (transport.consumer.track) {
|
|
7496
|
+
transport.consumer.track.enabled = true;
|
|
7497
|
+
}
|
|
7498
|
+
return;
|
|
7499
|
+
}
|
|
7500
|
+
transport.socket_?.emit(
|
|
7501
|
+
"consumer-resume",
|
|
7502
|
+
{ serverConsumerId: transport.serverConsumerTransportId },
|
|
7503
|
+
async ({ resumed }) => {
|
|
7504
|
+
if (resumed) {
|
|
7505
|
+
if (transport.consumer.track) {
|
|
7506
|
+
transport.consumer.track.enabled = true;
|
|
7391
7507
|
}
|
|
7508
|
+
transport.consumer.resume();
|
|
7392
7509
|
}
|
|
7393
|
-
|
|
7394
|
-
|
|
7510
|
+
}
|
|
7511
|
+
);
|
|
7395
7512
|
} catch (error) {
|
|
7396
7513
|
console.error("[TranslationSwitch] Error resuming original producer:", error);
|
|
7397
7514
|
}
|
|
@@ -12238,7 +12355,7 @@ const translationSubscribed = async ({
|
|
|
12238
12355
|
}));
|
|
12239
12356
|
}
|
|
12240
12357
|
if (producerId && startConsumingTranslation) {
|
|
12241
|
-
await startConsumingTranslation(producerId, speakerId, language);
|
|
12358
|
+
await startConsumingTranslation(producerId, speakerId, language, originalProducerId);
|
|
12242
12359
|
}
|
|
12243
12360
|
if (showAlert && channelCreated) {
|
|
12244
12361
|
showAlert({
|