mediasfu-shared 1.0.1 → 1.0.3
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/LICENSE +21 -21
- package/README.md +103 -222
- package/dist/index.cjs +7634 -2180
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +4203 -273
- package/dist/index.js +7663 -2209
- package/dist/index.js.map +1 -1
- package/package.json +96 -78
- package/src/ProducerClient/producerClientEmits/joinRoomClient.ts +57 -0
- package/src/ProducerClient/producerClientEmits/updateRoomParametersClient.ts +401 -0
- package/src/consumers/addVideosGrid.ts +3 -2
- package/src/consumers/changeVids.ts +111 -41
- package/src/consumers/checkPermission.ts +35 -1
- package/src/consumers/connectIps.ts +3 -1
- package/src/consumers/connectLocalIps.ts +3 -1
- package/src/consumers/connectRecvTransport.ts +96 -1
- package/src/consumers/consumerResume.ts +2 -2
- package/src/consumers/dispStreams.ts +83 -37
- package/src/consumers/frameworkConsumerContract.ts +6 -0
- package/src/consumers/generatePageContent.ts +24 -10
- package/src/consumers/getPipedProducersAlt.ts +112 -16
- package/src/consumers/gridLayout/addVideosGrid.engine.ts +42 -0
- package/src/consumers/gridLayout/prepopulateUserMedia.engine.ts +444 -0
- package/src/consumers/mixStreams.ts +45 -14
- package/src/consumers/onScreenChanges.ts +25 -10
- package/src/consumers/prepopulateUserMedia.ts +3 -2
- package/src/consumers/processConsumerTransports.ts +68 -23
- package/src/consumers/processConsumerTransportsAudio.ts +146 -17
- package/src/consumers/reUpdateInter.ts +61 -21
- package/src/consumers/readjust.ts +30 -14
- package/src/consumers/reorderStreams.ts +76 -42
- package/src/consumers/resumePauseAudioStreams.ts +66 -17
- package/src/consumers/resumePauseStreams.ts +53 -10
- package/src/consumers/socketReceiveMethods/joinConsumeRoom.ts +8 -0
- package/src/consumers/socketReceiveMethods/newPipeProducer.ts +114 -0
- package/src/consumers/socketReceiveMethods/producerClosed.ts +13 -0
- package/src/consumers/streamSuccessScreen.ts +2 -2
- package/src/consumers/streamSuccessVideo.ts +5 -0
- package/src/consumers/translationConsumerSwitch.ts +321 -0
- package/src/index.ts +85 -1
- package/src/methods/coHostMethods/modifyCoHostSettings.ts +9 -9
- package/src/methods/displaySettings/modifyDisplaySettings.ts +5 -0
- package/src/methods/index.ts +66 -0
- package/src/methods/message/sendMessage.ts +12 -29
- package/src/methods/panelists/focusPanelists.ts +83 -0
- package/src/methods/panelists/index.ts +3 -0
- package/src/methods/panelists/launchPanelists.ts +13 -0
- package/src/methods/panelists/updatePanelists.ts +135 -0
- package/src/methods/permissions/index.ts +3 -0
- package/src/methods/permissions/launchPermissions.ts +13 -0
- package/src/methods/permissions/updateParticipantPermission.ts +127 -0
- package/src/methods/permissions/updatePermissionConfig.ts +52 -0
- package/src/methods/polls/pollUpdated.ts +88 -0
- package/src/methods/recording/confirmRecording.ts +15 -12
- package/src/methods/recording/recordResumeTimer.ts +2 -2
- package/src/methods/recording/recordStartTimer.ts +2 -2
- package/src/methods/recording/timeLeftRecording.ts +25 -0
- package/src/methods/requests/hostRequestResponse.ts +158 -0
- package/src/methods/settings/modifySettings.ts +17 -17
- package/src/methods/socketReceive/allMembers.ts +450 -0
- package/src/methods/socketReceive/allMembersRest.ts +480 -0
- package/src/methods/socketReceive/allWaitingRoomMembers.ts +35 -0
- package/src/methods/socketReceive/banParticipant.ts +73 -0
- package/src/methods/socketReceive/controlMediaHost.ts +280 -0
- package/src/methods/socketReceive/disconnect.ts +40 -0
- package/src/methods/socketReceive/disconnectUserSelf.ts +56 -0
- package/src/methods/socketReceive/getDomains.ts +112 -0
- package/src/methods/socketReceive/meetingEnded.ts +49 -0
- package/src/methods/socketReceive/meetingStillThere.ts +26 -0
- package/src/methods/socketReceive/panelistReceiveMethods.ts +195 -0
- package/src/methods/socketReceive/participantRequested.ts +48 -0
- package/src/methods/socketReceive/permissionReceiveMethods.ts +59 -0
- package/src/methods/socketReceive/personJoined.ts +35 -0
- package/src/methods/socketReceive/producerMediaClosed.ts +223 -0
- package/src/methods/socketReceive/producerMediaPaused.ts +267 -0
- package/src/methods/socketReceive/producerMediaResumed.ts +157 -0
- package/src/methods/socketReceive/reInitiateRecording.ts +53 -0
- package/src/methods/socketReceive/receiveMessage.ts +117 -0
- package/src/methods/socketReceive/recordingNotice.ts +286 -0
- package/src/methods/socketReceive/roomRecordParams.ts +122 -0
- package/src/methods/socketReceive/screenProducerId.ts +61 -0
- package/src/methods/socketReceive/startRecords.ts +46 -0
- package/src/methods/socketReceive/stoppedRecording.ts +44 -0
- package/src/methods/socketReceive/translationReceiveMethods.ts +581 -0
- package/src/methods/socketReceive/updateConsumingDomains.ts +128 -0
- package/src/methods/socketReceive/updateMediaSettings.ts +45 -0
- package/src/methods/socketReceive/updatedCoHost.ts +75 -0
- package/src/methods/socketReceive/userWaiting.ts +45 -0
- package/src/methods/stream/clickAudio.ts +380 -0
- package/src/methods/stream/clickChat.ts +36 -0
- package/src/methods/stream/clickScreenShare.ts +173 -0
- package/src/methods/stream/clickVideo.ts +28 -6
- package/src/methods/stream/index.ts +1 -0
- package/src/methods/utils/SoundPlayer.ts +31 -0
- package/src/methods/utils/checkLimitsAndMakeRequest.ts +156 -2
- package/src/methods/utils/createResponseJoinRoom.ts +47 -0
- package/src/methods/utils/createRoomOnMediaSFU.ts +160 -0
- package/src/methods/utils/formatNumber.ts +42 -0
- package/src/methods/utils/generateRandomMessages.ts +70 -0
- package/src/methods/utils/generateRandomParticipants.ts +100 -0
- package/src/methods/utils/generateRandomPolls.ts +43 -0
- package/src/methods/utils/generateRandomRequestList.ts +51 -0
- package/src/methods/utils/generateRandomWaitingRoomList.ts +17 -0
- package/src/methods/utils/getModalPosition.ts +23 -0
- package/src/methods/utils/getOverlayPosition.ts +37 -0
- package/src/methods/utils/initialValuesState.ts +405 -0
- package/src/methods/utils/joinRoomOnMediaSFU.ts +124 -0
- package/src/methods/utils/liveSubtitle.ts +107 -0
- package/src/methods/utils/meetingTimeRemaining.ts +33 -0
- package/src/methods/utils/meetingTimer/startMeetingProgressTimer.ts +72 -0
- package/src/methods/utils/producer/aParams.ts +10 -0
- package/src/methods/utils/producer/hParams.ts +26 -0
- package/src/methods/utils/producer/screenParams.ts +13 -0
- package/src/methods/utils/producer/vParams.ts +26 -0
- package/src/methods/utils/producer/videoCaptureConstraints.ts +65 -0
- package/src/methods/utils/resolveMediaSFURoomApi.ts +28 -0
- package/src/methods/utils/sleep.ts +24 -0
- package/src/methods/utils/translationLanguages.ts +308 -0
- package/src/methods/utils/webrtc.ts +44 -0
- package/src/methods/welcome/handleWelcomeRequest.ts +11 -2
- package/src/methods/welcome/index.ts +5 -1
- package/src/methods/whiteboard/captureCanvasStream.ts +128 -0
- package/src/producers/producerEmits/joinConRoom.ts +2 -2
- package/src/producers/producerEmits/joinLocalRoom.ts +240 -0
- package/src/producers/producerEmits/joinRoom.ts +129 -0
- package/src/types/shared-base-types.ts +14 -3
- package/src/types/types.ts +255 -0
|
@@ -1,24 +1,62 @@
|
|
|
1
1
|
import { Participant, Transport, Stream } from "../types/types";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
interface ParticipantLike {
|
|
4
|
+
name: string;
|
|
5
|
+
islevel?: string | null;
|
|
6
|
+
videoID?: string | null;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
interface ConsumerLike {
|
|
10
|
+
kind?: string;
|
|
11
|
+
resume: () => unknown;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface SocketLike {
|
|
15
|
+
emit: (
|
|
16
|
+
event: string,
|
|
17
|
+
payload: { serverConsumerId: string },
|
|
18
|
+
callback?: ((payload: { resumed: boolean }) => void | Promise<unknown>)
|
|
19
|
+
) => void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface TransportLike {
|
|
23
|
+
producerId?: string | null;
|
|
24
|
+
consumer: ConsumerLike;
|
|
25
|
+
socket_: SocketLike;
|
|
26
|
+
serverConsumerTransportId: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface ResumePauseStreamsParameters<
|
|
30
|
+
TParticipant extends ParticipantLike = Participant,
|
|
31
|
+
TTransport extends TransportLike = Transport,
|
|
32
|
+
TStream = Stream,
|
|
33
|
+
> {
|
|
34
|
+
participants: TParticipant[];
|
|
5
35
|
dispActiveNames: string[];
|
|
6
|
-
remoteScreenStream:
|
|
7
|
-
consumerTransports:
|
|
36
|
+
remoteScreenStream: TStream[];
|
|
37
|
+
consumerTransports: TTransport[];
|
|
8
38
|
screenId?: string;
|
|
9
39
|
islevel: string;
|
|
10
40
|
|
|
11
41
|
// mediasfu functions
|
|
12
|
-
getUpdatedAllParams: () => ResumePauseStreamsParameters
|
|
42
|
+
getUpdatedAllParams: () => ResumePauseStreamsParameters<TParticipant, TTransport, TStream>;
|
|
13
43
|
[key: string]: any;
|
|
14
44
|
}
|
|
15
45
|
|
|
16
|
-
export interface ResumePauseStreamsOptions
|
|
17
|
-
|
|
46
|
+
export interface ResumePauseStreamsOptions<
|
|
47
|
+
TParticipant extends ParticipantLike = Participant,
|
|
48
|
+
TTransport extends TransportLike = Transport,
|
|
49
|
+
TStream = Stream,
|
|
50
|
+
> {
|
|
51
|
+
parameters: ResumePauseStreamsParameters<TParticipant, TTransport, TStream>;
|
|
18
52
|
}
|
|
19
53
|
|
|
20
54
|
// Export the type definition for the function
|
|
21
|
-
export type ResumePauseStreamsType =
|
|
55
|
+
export type ResumePauseStreamsType = <
|
|
56
|
+
TParticipant extends ParticipantLike = Participant,
|
|
57
|
+
TTransport extends TransportLike = Transport,
|
|
58
|
+
TStream = Stream,
|
|
59
|
+
>(options: ResumePauseStreamsOptions<TParticipant, TTransport, TStream>) => Promise<void>;
|
|
22
60
|
|
|
23
61
|
/**
|
|
24
62
|
* Resumes or pauses streams based on the provided parameters.
|
|
@@ -49,9 +87,13 @@ export type ResumePauseStreamsType = (options: ResumePauseStreamsOptions) => Pro
|
|
|
49
87
|
* ```
|
|
50
88
|
*/
|
|
51
89
|
|
|
52
|
-
export async function resumePauseStreams
|
|
90
|
+
export async function resumePauseStreams<
|
|
91
|
+
TParticipant extends ParticipantLike = Participant,
|
|
92
|
+
TTransport extends TransportLike = Transport,
|
|
93
|
+
TStream = Stream,
|
|
94
|
+
>({
|
|
53
95
|
parameters,
|
|
54
|
-
}: ResumePauseStreamsOptions): Promise<void> {
|
|
96
|
+
}: ResumePauseStreamsOptions<TParticipant, TTransport, TStream>): Promise<void> {
|
|
55
97
|
try {
|
|
56
98
|
// Destructure parameters
|
|
57
99
|
const { participants, dispActiveNames, consumerTransports, screenId, islevel } = parameters;
|
|
@@ -85,6 +127,7 @@ export async function resumePauseStreams({
|
|
|
85
127
|
// Get consumer transports with producerId in allVideoIDs
|
|
86
128
|
const consumerTransportsToResume = consumerTransports.filter(
|
|
87
129
|
(transport) =>
|
|
130
|
+
transport.producerId &&
|
|
88
131
|
allVideoIDs.includes(transport.producerId) &&
|
|
89
132
|
transport.consumer.kind !== "audio"
|
|
90
133
|
);
|
|
@@ -120,6 +120,14 @@ export const joinConsumeRoom = async ({
|
|
|
120
120
|
|
|
121
121
|
// Receive all piped transports
|
|
122
122
|
await receiveAllPipedTransports({ nsock: remote_sock, parameters });
|
|
123
|
+
|
|
124
|
+
setTimeout(async () => {
|
|
125
|
+
try {
|
|
126
|
+
await receiveAllPipedTransports({ nsock: remote_sock, parameters });
|
|
127
|
+
} catch (error) {
|
|
128
|
+
console.log('[joinConsumeRoom] Retry receiveAllPipedTransports failed:', error);
|
|
129
|
+
}
|
|
130
|
+
}, 30000);
|
|
123
131
|
}
|
|
124
132
|
|
|
125
133
|
return data;
|
|
@@ -2,6 +2,14 @@ import { Socket } from 'socket.io-client';
|
|
|
2
2
|
import { signalNewConsumerTransport } from '../signalNewConsumerTransport';
|
|
3
3
|
import { ReorderStreamsParameters, ReorderStreamsType, SignalNewConsumerTransportParameters, ConnectRecvTransportParameters, ConnectRecvTransportType, ShowAlert } from '../../types/types';
|
|
4
4
|
import type { Device } from 'mediasoup-client/lib/types';
|
|
5
|
+
|
|
6
|
+
export interface TranslationMeta {
|
|
7
|
+
speakerId: string;
|
|
8
|
+
speakerName: string;
|
|
9
|
+
language: string;
|
|
10
|
+
originalProducerId?: string;
|
|
11
|
+
isSpeakerControlled?: boolean;
|
|
12
|
+
}
|
|
5
13
|
export interface NewPipeProducerParameters extends ReorderStreamsParameters, SignalNewConsumerTransportParameters, ConnectRecvTransportParameters {
|
|
6
14
|
|
|
7
15
|
first_round: boolean;
|
|
@@ -21,6 +29,15 @@ export interface NewPipeProducerParameters extends ReorderStreamsParameters, Sig
|
|
|
21
29
|
connectRecvTransport: ConnectRecvTransportType;
|
|
22
30
|
reorderStreams: ReorderStreamsType;
|
|
23
31
|
getUpdatedAllParams: () => NewPipeProducerParameters;
|
|
32
|
+
|
|
33
|
+
startConsumingTranslation?: (producerId: string, speakerId: string, language: string, originalProducerId?: string, nsock?: Socket) => Promise<void>;
|
|
34
|
+
translationSubscriptions?: Map<string, { speakerId: string; language: string }>;
|
|
35
|
+
speakerTranslationStates?: Map<string, { speakerId: string; speakerName: string; inputLanguage: string; outputLanguage: string; originalProducerId: string; enabled: boolean }>;
|
|
36
|
+
listenerTranslationOverrides?: Map<string, { speakerId: string; wantOriginal: boolean; preferredLanguage?: string }>;
|
|
37
|
+
listenerTranslationPreferences?: {
|
|
38
|
+
perSpeaker: Map<string, { speakerId: string; language: string | null; wantOriginal: boolean }>;
|
|
39
|
+
globalLanguage: string | null;
|
|
40
|
+
};
|
|
24
41
|
[key: string]: any;
|
|
25
42
|
|
|
26
43
|
}
|
|
@@ -30,6 +47,8 @@ export interface NewPipeProducerOptions {
|
|
|
30
47
|
islevel: string;
|
|
31
48
|
nsock: Socket;
|
|
32
49
|
parameters: NewPipeProducerParameters;
|
|
50
|
+
isTranslation?: boolean;
|
|
51
|
+
translationMeta?: TranslationMeta;
|
|
33
52
|
}
|
|
34
53
|
|
|
35
54
|
// Export the type definition for the function
|
|
@@ -96,7 +115,102 @@ export const newPipeProducer = async ({
|
|
|
96
115
|
islevel,
|
|
97
116
|
nsock,
|
|
98
117
|
parameters,
|
|
118
|
+
isTranslation,
|
|
119
|
+
translationMeta,
|
|
99
120
|
}: NewPipeProducerOptions): Promise<void> => {
|
|
121
|
+
if (isTranslation && translationMeta) {
|
|
122
|
+
const freshParams = parameters.getUpdatedAllParams ? parameters.getUpdatedAllParams() : parameters;
|
|
123
|
+
|
|
124
|
+
const {
|
|
125
|
+
startConsumingTranslation,
|
|
126
|
+
translationSubscriptions,
|
|
127
|
+
speakerTranslationStates,
|
|
128
|
+
listenerTranslationOverrides,
|
|
129
|
+
listenerTranslationPreferences,
|
|
130
|
+
} = freshParams;
|
|
131
|
+
|
|
132
|
+
const normalizedLang = translationMeta.language?.toLowerCase();
|
|
133
|
+
const isSpeakerControlledFromMeta = translationMeta.isSpeakerControlled === true;
|
|
134
|
+
const speakerState = speakerTranslationStates?.get(translationMeta.speakerId);
|
|
135
|
+
const isSpeakerControlledFromState = speakerState?.enabled
|
|
136
|
+
&& speakerState?.outputLanguage?.toLowerCase() === normalizedLang;
|
|
137
|
+
const shouldSkipBecauseWrongLanguage = isSpeakerControlledFromMeta
|
|
138
|
+
&& speakerState?.enabled
|
|
139
|
+
&& speakerState?.outputLanguage?.toLowerCase() !== normalizedLang;
|
|
140
|
+
|
|
141
|
+
const subscriptionKey = `${translationMeta.speakerId}_${normalizedLang}`;
|
|
142
|
+
const isListenerSubscribed = translationSubscriptions?.has(subscriptionKey)
|
|
143
|
+
|| translationSubscriptions?.has(translationMeta.speakerId);
|
|
144
|
+
|
|
145
|
+
let overrideBlocksConsumption = false;
|
|
146
|
+
let shouldConsumeForOverride = false;
|
|
147
|
+
let shouldConsumeForGlobal = false;
|
|
148
|
+
|
|
149
|
+
const perSpeakerPref = listenerTranslationPreferences?.perSpeaker?.get(translationMeta.speakerId);
|
|
150
|
+
const globalPref = listenerTranslationPreferences?.globalLanguage;
|
|
151
|
+
const listenerOverride = listenerTranslationOverrides?.get(translationMeta.speakerId);
|
|
152
|
+
|
|
153
|
+
if (perSpeakerPref) {
|
|
154
|
+
if (perSpeakerPref.wantOriginal) {
|
|
155
|
+
overrideBlocksConsumption = true;
|
|
156
|
+
} else if (perSpeakerPref.language) {
|
|
157
|
+
if (perSpeakerPref.language === normalizedLang) {
|
|
158
|
+
shouldConsumeForOverride = true;
|
|
159
|
+
} else {
|
|
160
|
+
overrideBlocksConsumption = true;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
} else if (globalPref) {
|
|
164
|
+
if (globalPref === normalizedLang) {
|
|
165
|
+
shouldConsumeForGlobal = true;
|
|
166
|
+
} else {
|
|
167
|
+
overrideBlocksConsumption = true;
|
|
168
|
+
}
|
|
169
|
+
} else if (listenerOverride) {
|
|
170
|
+
if (listenerOverride.wantOriginal) {
|
|
171
|
+
overrideBlocksConsumption = true;
|
|
172
|
+
} else if (listenerOverride.preferredLanguage) {
|
|
173
|
+
if (listenerOverride.preferredLanguage.toLowerCase() === normalizedLang) {
|
|
174
|
+
shouldConsumeForOverride = true;
|
|
175
|
+
} else {
|
|
176
|
+
overrideBlocksConsumption = true;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const shouldConsumeForSpeakerControlled =
|
|
182
|
+
isSpeakerControlledFromMeta
|
|
183
|
+
&& (!speakerState?.enabled || speakerState?.outputLanguage?.toLowerCase() === normalizedLang);
|
|
184
|
+
const hasNoPreference = !perSpeakerPref && !globalPref && !listenerOverride;
|
|
185
|
+
const isListenerInitiated = !isSpeakerControlledFromMeta && !isSpeakerControlledFromState;
|
|
186
|
+
const blockBecauseNotRelevant = hasNoPreference && isListenerInitiated && !isListenerSubscribed;
|
|
187
|
+
|
|
188
|
+
const shouldConsume =
|
|
189
|
+
!overrideBlocksConsumption
|
|
190
|
+
&& !shouldSkipBecauseWrongLanguage
|
|
191
|
+
&& !blockBecauseNotRelevant
|
|
192
|
+
&& (shouldConsumeForOverride
|
|
193
|
+
|| shouldConsumeForGlobal
|
|
194
|
+
|| shouldConsumeForSpeakerControlled
|
|
195
|
+
|| isSpeakerControlledFromState
|
|
196
|
+
|| isListenerSubscribed);
|
|
197
|
+
|
|
198
|
+
if (shouldConsume && startConsumingTranslation) {
|
|
199
|
+
try {
|
|
200
|
+
await startConsumingTranslation(
|
|
201
|
+
producerId,
|
|
202
|
+
translationMeta.speakerId,
|
|
203
|
+
translationMeta.language,
|
|
204
|
+
translationMeta.originalProducerId,
|
|
205
|
+
nsock,
|
|
206
|
+
);
|
|
207
|
+
} catch {
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
|
|
100
214
|
const {
|
|
101
215
|
shareScreenStarted,
|
|
102
216
|
shared,
|
|
@@ -63,6 +63,19 @@ export const producerClosed = async ({
|
|
|
63
63
|
}: ProducerClosedOptions): Promise<void> => {
|
|
64
64
|
let { consumerTransports, closeAndResize, screenId, updateConsumerTransports } = parameters;
|
|
65
65
|
|
|
66
|
+
const activeTranslationProducerIds = parameters.activeTranslationProducerIds;
|
|
67
|
+
const isTranslationProducer = activeTranslationProducerIds?.has?.(remoteProducerId);
|
|
68
|
+
|
|
69
|
+
if (isTranslationProducer) {
|
|
70
|
+
activeTranslationProducerIds?.delete?.(remoteProducerId);
|
|
71
|
+
|
|
72
|
+
const removeTranslationStream = parameters.removeTranslationStream as ((producerId: string) => void) | undefined;
|
|
73
|
+
|
|
74
|
+
if (removeTranslationStream) {
|
|
75
|
+
removeTranslationStream(remoteProducerId);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
66
79
|
// Handle producer closed
|
|
67
80
|
const producerToClose = consumerTransports.find(
|
|
68
81
|
(transportData: any) => transportData.producerId === remoteProducerId
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
import { Socket } from "socket.io-client";
|
|
4
4
|
import {
|
|
5
5
|
SleepType, CreateSendTransportType, ConnectSendTransportScreenType, DisconnectSendTransportScreenType, StopShareScreenType, ReorderStreamsType, PrepopulateUserMediaType, RePortType,
|
|
6
|
-
ShowAlert, CreateSendTransportParameters, ConnectSendTransportScreenParameters, DisconnectSendTransportScreenParameters, StopShareScreenParameters, ReorderStreamsParameters, PrepopulateUserMediaParameters,
|
|
6
|
+
ShowAlert, CreateSendTransportParameters, ConnectSendTransportScreenParameters, DisconnectSendTransportScreenParameters, StopShareScreenParameters, ReorderStreamsParameters, PrepopulateUserMediaParameters, RePortParameters,
|
|
7
7
|
EventType
|
|
8
8
|
} from "../types/types";
|
|
9
9
|
|
|
10
|
-
export interface StreamSuccessScreenParameters extends CreateSendTransportParameters, ConnectSendTransportScreenParameters, DisconnectSendTransportScreenParameters, StopShareScreenParameters, ReorderStreamsParameters, PrepopulateUserMediaParameters {
|
|
10
|
+
export interface StreamSuccessScreenParameters extends CreateSendTransportParameters, ConnectSendTransportScreenParameters, DisconnectSendTransportScreenParameters, StopShareScreenParameters, ReorderStreamsParameters, PrepopulateUserMediaParameters, RePortParameters {
|
|
11
11
|
socket: Socket;
|
|
12
12
|
transportCreated: boolean;
|
|
13
13
|
localStreamScreen: MediaStream | null;
|
|
@@ -30,6 +30,7 @@ export interface StreamSuccessVideoParameters extends CreateSendTransportParamet
|
|
|
30
30
|
keepBackground: boolean;
|
|
31
31
|
appliedBackground: boolean;
|
|
32
32
|
videoProducer: Producer | null;
|
|
33
|
+
removeSingleVideoEncoding?: boolean;
|
|
33
34
|
|
|
34
35
|
// Update functions
|
|
35
36
|
updateTransportCreatedVideo: (created: boolean) => void;
|
|
@@ -275,6 +276,10 @@ export const streamSuccessVideo = async ({
|
|
|
275
276
|
(codec: RtpCodecCapability) => codec.mimeType.toLowerCase() !== "video/vp9" && codec.kind === "video"
|
|
276
277
|
) || [];
|
|
277
278
|
|
|
279
|
+
if (parameters.removeSingleVideoEncoding && videoParamse.encodings && videoParamse.encodings.length <= 1) {
|
|
280
|
+
delete videoParamse.encodings;
|
|
281
|
+
}
|
|
282
|
+
|
|
278
283
|
videoParams = {
|
|
279
284
|
track: localStream.getVideoTracks()[0],
|
|
280
285
|
...videoParamse,
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import { BreakoutParticipant, EventType, Participant, Transport } from '../types/types';
|
|
2
|
+
|
|
3
|
+
export interface TranslationConsumerSwitchParameters {
|
|
4
|
+
consumerTransports: Transport[];
|
|
5
|
+
roomName: string;
|
|
6
|
+
member: string;
|
|
7
|
+
updateConsumerTransports: (transports: Transport[]) => void;
|
|
8
|
+
breakOutRoomStarted?: boolean;
|
|
9
|
+
breakOutRoomEnded?: boolean;
|
|
10
|
+
breakoutRooms?: BreakoutParticipant[][];
|
|
11
|
+
limitedBreakRoom?: BreakoutParticipant[];
|
|
12
|
+
participants?: Participant[];
|
|
13
|
+
ref_participants?: Participant[];
|
|
14
|
+
islevel?: string;
|
|
15
|
+
eventType?: EventType;
|
|
16
|
+
hostNewRoom?: number;
|
|
17
|
+
[key: string]: any;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface PauseOriginalProducerOptions {
|
|
21
|
+
originalProducerId: string;
|
|
22
|
+
speakerId?: string;
|
|
23
|
+
parameters: TranslationConsumerSwitchParameters;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface ResumeOriginalProducerOptions {
|
|
27
|
+
originalProducerId: string;
|
|
28
|
+
speakerId?: string;
|
|
29
|
+
parameters: TranslationConsumerSwitchParameters;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export type PauseOriginalProducerType = (options: PauseOriginalProducerOptions) => Promise<void>;
|
|
33
|
+
export type ResumeOriginalProducerType = (options: ResumeOriginalProducerOptions) => Promise<void>;
|
|
34
|
+
|
|
35
|
+
export interface StopConsumingTranslationOptions {
|
|
36
|
+
speakerId?: string;
|
|
37
|
+
language: string;
|
|
38
|
+
translationProducerMap: Record<string, Record<string, string>>;
|
|
39
|
+
parameters: TranslationConsumerSwitchParameters;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export type StopConsumingTranslationType = (options: StopConsumingTranslationOptions) => Promise<string | null>;
|
|
43
|
+
|
|
44
|
+
export const isSpeakerInMyBreakoutRoom = (
|
|
45
|
+
speakerName: string,
|
|
46
|
+
parameters: TranslationConsumerSwitchParameters
|
|
47
|
+
): boolean => {
|
|
48
|
+
const {
|
|
49
|
+
breakOutRoomStarted = false,
|
|
50
|
+
breakOutRoomEnded = false,
|
|
51
|
+
limitedBreakRoom = [],
|
|
52
|
+
participants = [],
|
|
53
|
+
islevel = '1',
|
|
54
|
+
eventType = 'conference',
|
|
55
|
+
hostNewRoom = -1,
|
|
56
|
+
breakoutRooms = [],
|
|
57
|
+
member = '',
|
|
58
|
+
} = parameters;
|
|
59
|
+
|
|
60
|
+
if (!breakOutRoomStarted || breakOutRoomEnded) {
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const host = participants.find((p) => p.islevel === '2');
|
|
65
|
+
const speakerIsHost = host?.name === speakerName;
|
|
66
|
+
|
|
67
|
+
if (islevel !== '2') {
|
|
68
|
+
if (eventType === 'webinar' && speakerIsHost) {
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (eventType === 'conference' && speakerIsHost) {
|
|
73
|
+
const roomMember = breakoutRooms.find((r) =>
|
|
74
|
+
r.find((p) => p.name === member)
|
|
75
|
+
);
|
|
76
|
+
const memberBreakRoom = roomMember ? breakoutRooms.indexOf(roomMember) : -1;
|
|
77
|
+
const inBreakRoom = memberBreakRoom !== -1;
|
|
78
|
+
|
|
79
|
+
if (inBreakRoom) {
|
|
80
|
+
return memberBreakRoom === hostNewRoom;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (hostNewRoom === -1) {
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return hostNewRoom === memberBreakRoom && memberBreakRoom !== -1;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return limitedBreakRoom.some((p) => p.name === speakerName);
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
export const pauseOriginalProducer = async ({
|
|
95
|
+
originalProducerId,
|
|
96
|
+
speakerId,
|
|
97
|
+
parameters,
|
|
98
|
+
}: PauseOriginalProducerOptions): Promise<void> => {
|
|
99
|
+
try {
|
|
100
|
+
const { consumerTransports } = parameters;
|
|
101
|
+
|
|
102
|
+
if (speakerId && !isSpeakerInMyBreakoutRoom(speakerId, parameters)) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const transport = consumerTransports.find(
|
|
107
|
+
(t) => t.producerId === originalProducerId && t.consumer?.kind === 'audio'
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
if (!transport?.consumer) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (transport.consumer.track) {
|
|
115
|
+
transport.consumer.track.enabled = false;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (transport.consumer.paused) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
transport.consumer.pause();
|
|
123
|
+
|
|
124
|
+
transport.socket_?.emit(
|
|
125
|
+
'consumer-pause',
|
|
126
|
+
{ serverConsumerId: transport.serverConsumerTransportId },
|
|
127
|
+
async () => {}
|
|
128
|
+
);
|
|
129
|
+
} catch (error) {
|
|
130
|
+
console.error('[TranslationSwitch] Error pausing original producer:', error);
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
export const resumeOriginalProducer = async ({
|
|
135
|
+
originalProducerId,
|
|
136
|
+
speakerId,
|
|
137
|
+
parameters,
|
|
138
|
+
}: ResumeOriginalProducerOptions): Promise<void> => {
|
|
139
|
+
try {
|
|
140
|
+
const { consumerTransports } = parameters;
|
|
141
|
+
|
|
142
|
+
if (speakerId && !isSpeakerInMyBreakoutRoom(speakerId, parameters)) {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const transport = consumerTransports.find(
|
|
147
|
+
(t) => t.producerId === originalProducerId && t.consumer?.kind === 'audio'
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
if (!transport?.consumer) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (!transport.consumer.paused) {
|
|
155
|
+
if (transport.consumer.track) {
|
|
156
|
+
transport.consumer.track.enabled = true;
|
|
157
|
+
}
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
transport.socket_?.emit(
|
|
162
|
+
'consumer-resume',
|
|
163
|
+
{ serverConsumerId: transport.serverConsumerTransportId },
|
|
164
|
+
async ({ resumed }: { resumed: boolean }) => {
|
|
165
|
+
if (resumed) {
|
|
166
|
+
if (transport.consumer.track) {
|
|
167
|
+
transport.consumer.track.enabled = true;
|
|
168
|
+
}
|
|
169
|
+
transport.consumer.resume();
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
);
|
|
173
|
+
} catch (error) {
|
|
174
|
+
console.error('[TranslationSwitch] Error resuming original producer:', error);
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
export const isConsumingTranslationForSpeaker = (
|
|
179
|
+
speakerId: string,
|
|
180
|
+
consumerTransports: Transport[],
|
|
181
|
+
translationProducerMap: Map<string, { translationProducerId: string; originalProducerId: string; language: string }>
|
|
182
|
+
): { consuming: boolean; language?: string; translationProducerId?: string; originalProducerId?: string } => {
|
|
183
|
+
const translationInfo = translationProducerMap.get(speakerId);
|
|
184
|
+
|
|
185
|
+
if (translationInfo) {
|
|
186
|
+
const hasConsumer = consumerTransports.some(
|
|
187
|
+
(t) => t.producerId === translationInfo.translationProducerId
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
if (hasConsumer) {
|
|
191
|
+
return {
|
|
192
|
+
consuming: true,
|
|
193
|
+
language: translationInfo.language,
|
|
194
|
+
translationProducerId: translationInfo.translationProducerId,
|
|
195
|
+
originalProducerId: translationInfo.originalProducerId,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return { consuming: false };
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
export const getActiveTranslationConsumers = (
|
|
204
|
+
translationProducerMap: Map<string, { translationProducerId: string; originalProducerId: string; language: string }>,
|
|
205
|
+
consumerTransports: Transport[]
|
|
206
|
+
): Array<{ speakerId: string; translationProducerId: string; originalProducerId: string; language: string }> => {
|
|
207
|
+
const results: Array<{ speakerId: string; translationProducerId: string; originalProducerId: string; language: string }> = [];
|
|
208
|
+
|
|
209
|
+
translationProducerMap.forEach((info, speakerId) => {
|
|
210
|
+
const hasConsumer = consumerTransports.some(
|
|
211
|
+
(t) => t.producerId === info.translationProducerId
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
if (hasConsumer) {
|
|
215
|
+
results.push({
|
|
216
|
+
speakerId,
|
|
217
|
+
...info,
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
return results;
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
export const findOriginalProducerForSpeaker = (
|
|
226
|
+
speakerId: string,
|
|
227
|
+
allAudioStreams: Array<{ producerId: string; name?: string; [key: string]: any }>
|
|
228
|
+
): string | null => {
|
|
229
|
+
const stream = allAudioStreams.find(
|
|
230
|
+
(s) => s.name === speakerId || s.producerId?.includes(speakerId)
|
|
231
|
+
);
|
|
232
|
+
return stream?.producerId || null;
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
export const stopConsumingTranslation = async (options: StopConsumingTranslationOptions): Promise<string | null> => {
|
|
236
|
+
const { language, translationProducerMap, parameters } = options;
|
|
237
|
+
try {
|
|
238
|
+
const { consumerTransports, updateConsumerTransports } = parameters;
|
|
239
|
+
|
|
240
|
+
let originalProducerId: string | null = null;
|
|
241
|
+
let translationProducerId: string | null = null;
|
|
242
|
+
|
|
243
|
+
for (const [origId, langMap] of Object.entries(translationProducerMap)) {
|
|
244
|
+
if (langMap && langMap[language]) {
|
|
245
|
+
translationProducerId = langMap[language];
|
|
246
|
+
originalProducerId = origId;
|
|
247
|
+
break;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (!translationProducerId) {
|
|
252
|
+
return originalProducerId;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const transportIndex = consumerTransports.findIndex(
|
|
256
|
+
(t) => t.producerId === translationProducerId
|
|
257
|
+
);
|
|
258
|
+
|
|
259
|
+
if (transportIndex === -1) {
|
|
260
|
+
return originalProducerId;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const transport = consumerTransports[transportIndex];
|
|
264
|
+
|
|
265
|
+
if (transport.socket_ && transport.consumer) {
|
|
266
|
+
transport.socket_.emit(
|
|
267
|
+
'consumer-close',
|
|
268
|
+
{ serverConsumerId: transport.serverConsumerTransportId },
|
|
269
|
+
() => {}
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (transport.consumer) {
|
|
274
|
+
transport.consumer.close();
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const updatedTransports = consumerTransports.filter((_, i) => i !== transportIndex);
|
|
278
|
+
updateConsumerTransports(updatedTransports);
|
|
279
|
+
|
|
280
|
+
return originalProducerId;
|
|
281
|
+
} catch (error) {
|
|
282
|
+
console.error('[TranslationSwitch] Error stopping translation consumer:', error);
|
|
283
|
+
return null;
|
|
284
|
+
}
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
export const syncTranslationStateAfterBreakoutChange = async (
|
|
288
|
+
translationProducerMap: Record<string, Record<string, string>>,
|
|
289
|
+
speakerIdByProducerId: Record<string, string>,
|
|
290
|
+
parameters: TranslationConsumerSwitchParameters
|
|
291
|
+
): Promise<void> => {
|
|
292
|
+
try {
|
|
293
|
+
const { consumerTransports } = parameters;
|
|
294
|
+
|
|
295
|
+
for (const [originalProducerId, langMap] of Object.entries(translationProducerMap)) {
|
|
296
|
+
const speakerId = speakerIdByProducerId[originalProducerId];
|
|
297
|
+
if (!speakerId) continue;
|
|
298
|
+
|
|
299
|
+
const inMyRoom = isSpeakerInMyBreakoutRoom(speakerId, parameters);
|
|
300
|
+
const hasTranslation = Object.keys(langMap).length > 0;
|
|
301
|
+
|
|
302
|
+
const originalConsumer = consumerTransports.find(
|
|
303
|
+
(t) => t.producerId === originalProducerId && t.consumer?.kind === 'audio'
|
|
304
|
+
);
|
|
305
|
+
|
|
306
|
+
if (!originalConsumer) continue;
|
|
307
|
+
|
|
308
|
+
if (inMyRoom && hasTranslation) {
|
|
309
|
+
if (!originalConsumer.consumer.paused) {
|
|
310
|
+
await pauseOriginalProducer({
|
|
311
|
+
originalProducerId,
|
|
312
|
+
speakerId,
|
|
313
|
+
parameters,
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
} catch (error) {
|
|
319
|
+
console.error('[TranslationSwitch] Error syncing translation state:', error);
|
|
320
|
+
}
|
|
321
|
+
};
|