mediasfu-shared 1.0.1 → 1.0.2
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 +7500 -2163
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +4203 -273
- package/dist/index.js +7521 -2184
- package/dist/index.js.map +1 -1
- package/package.json +85 -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/connectRecvTransport.ts +42 -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 +53 -16
- 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 +299 -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 +153 -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 +22 -5
- 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 +16 -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
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
export interface StartMeetingProgressTimerParameters {
|
|
2
|
+
updateMeetingProgressTime: (formattedTime: string) => void;
|
|
3
|
+
validated: boolean;
|
|
4
|
+
roomName: string;
|
|
5
|
+
getUpdatedAllParams: () => StartMeetingProgressTimerParameters;
|
|
6
|
+
[key: string]: any;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface StartMeetingProgressTimerOptions {
|
|
10
|
+
startTime: number;
|
|
11
|
+
parameters: StartMeetingProgressTimerParameters;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type StartMeetingProgressTimerType = (options: StartMeetingProgressTimerOptions) => void;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Starts a one-second meeting progress timer and updates a formatted elapsed-time string.
|
|
18
|
+
*
|
|
19
|
+
* The timer automatically stops when the current runtime parameters indicate the
|
|
20
|
+
* meeting is no longer validated or no room is active.
|
|
21
|
+
*
|
|
22
|
+
* @param options Timer start options.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* startMeetingProgressTimer({
|
|
27
|
+
* startTime: Math.floor(Date.now() / 1000),
|
|
28
|
+
* parameters: {
|
|
29
|
+
* validated: true,
|
|
30
|
+
* roomName: 'room123',
|
|
31
|
+
* updateMeetingProgressTime: setMeetingTime,
|
|
32
|
+
* getUpdatedAllParams: () => currentParams,
|
|
33
|
+
* },
|
|
34
|
+
* });
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export function startMeetingProgressTimer({
|
|
38
|
+
startTime,
|
|
39
|
+
parameters,
|
|
40
|
+
}: StartMeetingProgressTimerOptions): void {
|
|
41
|
+
let { updateMeetingProgressTime, getUpdatedAllParams } = parameters;
|
|
42
|
+
|
|
43
|
+
function calculateElapsedTime(currentStartTime: number): number {
|
|
44
|
+
const currentTime = Math.floor(new Date().getTime() / 1000);
|
|
45
|
+
return currentTime - currentStartTime;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function padNumber(value: number): string {
|
|
49
|
+
return value.toString().padStart(2, '0');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function formatTime(time: number): string {
|
|
53
|
+
const hours = Math.floor(time / 3600);
|
|
54
|
+
const minutes = Math.floor((time % 3600) / 60);
|
|
55
|
+
const seconds = Math.floor(time % 60);
|
|
56
|
+
return `${padNumber(hours)}:${padNumber(minutes)}:${padNumber(seconds)}`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
let elapsedTime = calculateElapsedTime(startTime);
|
|
60
|
+
|
|
61
|
+
let timeProgress: ReturnType<typeof setInterval> | null = setInterval(() => {
|
|
62
|
+
elapsedTime++;
|
|
63
|
+
updateMeetingProgressTime(formatTime(elapsedTime));
|
|
64
|
+
|
|
65
|
+
parameters = getUpdatedAllParams();
|
|
66
|
+
|
|
67
|
+
if (!parameters.validated || !parameters.roomName) {
|
|
68
|
+
clearInterval(timeProgress!);
|
|
69
|
+
timeProgress = null;
|
|
70
|
+
}
|
|
71
|
+
}, 1000);
|
|
72
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { HParamsType } from '../../../types/types';
|
|
2
|
+
|
|
3
|
+
export const hParams: HParamsType = {
|
|
4
|
+
encodings: [
|
|
5
|
+
{
|
|
6
|
+
rid: 'r8',
|
|
7
|
+
maxBitrate: 240000,
|
|
8
|
+
scalabilityMode: 'L1T3',
|
|
9
|
+
scaleResolutionDownBy: 4.0,
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
rid: 'r9',
|
|
13
|
+
maxBitrate: 480000,
|
|
14
|
+
scalabilityMode: 'L1T3',
|
|
15
|
+
scaleResolutionDownBy: 2.0,
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
rid: 'r10',
|
|
19
|
+
maxBitrate: 960000,
|
|
20
|
+
scalabilityMode: 'L1T3',
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
codecOptions: {
|
|
24
|
+
videoGoogleStartBitrate: 384,
|
|
25
|
+
},
|
|
26
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { VParamsType } from '../../../types/types';
|
|
2
|
+
|
|
3
|
+
export const vParams: VParamsType = {
|
|
4
|
+
encodings: [
|
|
5
|
+
{
|
|
6
|
+
rid: 'r3',
|
|
7
|
+
maxBitrate: 200000,
|
|
8
|
+
scalabilityMode: 'L1T3',
|
|
9
|
+
scaleResolutionDownBy: 4.0,
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
rid: 'r4',
|
|
13
|
+
maxBitrate: 400000,
|
|
14
|
+
scalabilityMode: 'L1T3',
|
|
15
|
+
scaleResolutionDownBy: 2.0,
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
rid: 'r5',
|
|
19
|
+
maxBitrate: 800000,
|
|
20
|
+
scalabilityMode: 'L1T3',
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
codecOptions: {
|
|
24
|
+
videoGoogleStartBitrate: 320,
|
|
25
|
+
},
|
|
26
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
const QnHDCons = { width: { ideal: 320 }, height: { ideal: 180 } };
|
|
2
|
+
const sdCons = { width: { ideal: 640 }, height: { ideal: 360 } };
|
|
3
|
+
const hdCons = { width: { ideal: 1280 }, height: { ideal: 720 } };
|
|
4
|
+
const fhdCons = { width: { ideal: 1920 }, height: { ideal: 1080 } };
|
|
5
|
+
const qhdCons = { width: { ideal: 2560 }, height: { ideal: 1440 } };
|
|
6
|
+
|
|
7
|
+
const QnHDConsPort = { width: { ideal: 180 }, height: { ideal: 320 } };
|
|
8
|
+
const sdConsPort = { width: { ideal: 360 }, height: { ideal: 640 } };
|
|
9
|
+
const hdConsPort = { width: { ideal: 720 }, height: { ideal: 1280 } };
|
|
10
|
+
const fhdConsPort = { width: { ideal: 1080 }, height: { ideal: 1920 } };
|
|
11
|
+
const qhdConsPort = { width: { ideal: 1440 }, height: { ideal: 2560 } };
|
|
12
|
+
|
|
13
|
+
const QnHDConsNeu = { width: { ideal: 240 }, height: { ideal: 240 } };
|
|
14
|
+
const sdConsNeu = { width: { ideal: 480 }, height: { ideal: 480 } };
|
|
15
|
+
const hdConsNeu = { width: { ideal: 960 }, height: { ideal: 960 } };
|
|
16
|
+
const fhdConsNeu = { width: { ideal: 1440 }, height: { ideal: 1440 } };
|
|
17
|
+
const qhdConsNeu = { width: { ideal: 1920 }, height: { ideal: 1920 } };
|
|
18
|
+
|
|
19
|
+
const QnHDFrameRate = 5;
|
|
20
|
+
const sdFrameRate = 10;
|
|
21
|
+
const hdFrameRate = 15;
|
|
22
|
+
const fhdFrameRate = 20;
|
|
23
|
+
const qhdFrameRate = 30;
|
|
24
|
+
const screenFrameRate = 30;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Preset video capture constraints and frame-rate defaults used by MediaSFU.
|
|
28
|
+
*
|
|
29
|
+
* These exports provide standard landscape, portrait, and neutral constraint
|
|
30
|
+
* presets along with recommended frame-rate values for each quality tier.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```typescript
|
|
34
|
+
* const constraints = {
|
|
35
|
+
* video: {
|
|
36
|
+
* ...hdCons,
|
|
37
|
+
* frameRate: { ideal: hdFrameRate },
|
|
38
|
+
* },
|
|
39
|
+
* audio: false,
|
|
40
|
+
* };
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export {
|
|
44
|
+
QnHDCons,
|
|
45
|
+
sdCons,
|
|
46
|
+
hdCons,
|
|
47
|
+
fhdCons,
|
|
48
|
+
qhdCons,
|
|
49
|
+
QnHDConsPort,
|
|
50
|
+
sdConsPort,
|
|
51
|
+
hdConsPort,
|
|
52
|
+
fhdConsPort,
|
|
53
|
+
qhdConsPort,
|
|
54
|
+
QnHDConsNeu,
|
|
55
|
+
sdConsNeu,
|
|
56
|
+
hdConsNeu,
|
|
57
|
+
fhdConsNeu,
|
|
58
|
+
qhdConsNeu,
|
|
59
|
+
QnHDFrameRate,
|
|
60
|
+
sdFrameRate,
|
|
61
|
+
hdFrameRate,
|
|
62
|
+
fhdFrameRate,
|
|
63
|
+
qhdFrameRate,
|
|
64
|
+
screenFrameRate,
|
|
65
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const DEFAULT_MEDIA_SFU_ROOM_API_URL = 'https://mediasfu.com/v1/rooms/';
|
|
2
|
+
|
|
3
|
+
type MediaSFURoomApiAction = 'createRoom' | 'joinRoom';
|
|
4
|
+
|
|
5
|
+
export const resolveMediaSFURoomApi = (
|
|
6
|
+
localLink: string | undefined,
|
|
7
|
+
action: MediaSFURoomApiAction,
|
|
8
|
+
): string => {
|
|
9
|
+
const normalizedLink = localLink?.trim();
|
|
10
|
+
|
|
11
|
+
if (!normalizedLink || normalizedLink.includes('mediasfu.com')) {
|
|
12
|
+
return DEFAULT_MEDIA_SFU_ROOM_API_URL;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return `${normalizedLink.replace(/\/$/, '')}/${action}`;
|
|
16
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface SleepOptions {
|
|
2
|
+
ms: number;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export type SleepType = (options: SleepOptions) => Promise<void>;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Delays execution for a specified number of milliseconds.
|
|
9
|
+
*
|
|
10
|
+
* This helper is used throughout MediaSFU to wait for short transport or media
|
|
11
|
+
* lifecycle transitions before continuing work.
|
|
12
|
+
*
|
|
13
|
+
* @param options Delay configuration.
|
|
14
|
+
* @returns A promise that resolves after the requested delay.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* await sleep({ ms: 500 });
|
|
19
|
+
* // Continue after a half-second pause.
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export function sleep({ ms }: SleepOptions): Promise<void> {
|
|
23
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
24
|
+
}
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
export type VoiceGender = 'male' | 'female' | 'neutral';
|
|
2
|
+
|
|
3
|
+
export type TTSSupport = 'excellent' | 'good' | 'moderate' | 'limited' | 'unknown' | 'n/a';
|
|
4
|
+
|
|
5
|
+
export type LanguageRegion =
|
|
6
|
+
| 'global'
|
|
7
|
+
| 'europe'
|
|
8
|
+
| 'asia'
|
|
9
|
+
| 'south-asia'
|
|
10
|
+
| 'mena'
|
|
11
|
+
| 'africa'
|
|
12
|
+
| 'caucasus'
|
|
13
|
+
| 'central-asia'
|
|
14
|
+
| 'constructed'
|
|
15
|
+
| 'special'
|
|
16
|
+
| 'other';
|
|
17
|
+
|
|
18
|
+
export interface LanguageMetadata {
|
|
19
|
+
name: string;
|
|
20
|
+
nativeName: string;
|
|
21
|
+
region: LanguageRegion;
|
|
22
|
+
ttsSupport: TTSSupport;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface LanguageOption {
|
|
26
|
+
code: string;
|
|
27
|
+
name: string;
|
|
28
|
+
nativeName: string;
|
|
29
|
+
region: LanguageRegion;
|
|
30
|
+
ttsSupport: TTSSupport;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface VoiceOption {
|
|
34
|
+
id: string;
|
|
35
|
+
name: string;
|
|
36
|
+
gender: VoiceGender;
|
|
37
|
+
provider: string;
|
|
38
|
+
language: string;
|
|
39
|
+
style?: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface VoiceSelectionPreference {
|
|
43
|
+
gender: VoiceGender;
|
|
44
|
+
voiceId?: string;
|
|
45
|
+
style?: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface TranslationVoiceConfig {
|
|
49
|
+
voiceGender?: VoiceGender;
|
|
50
|
+
voiceId?: string;
|
|
51
|
+
voiceClone?: {
|
|
52
|
+
provider: 'elevenlabs' | 'playht' | 'coqui' | 'cartesia';
|
|
53
|
+
voiceId: string;
|
|
54
|
+
stability?: number;
|
|
55
|
+
similarity?: number;
|
|
56
|
+
};
|
|
57
|
+
sttNickName?: string;
|
|
58
|
+
llmNickName?: string;
|
|
59
|
+
ttsNickName?: string;
|
|
60
|
+
ttsProvider?: string;
|
|
61
|
+
sttParams?: Record<string, string | number | boolean>;
|
|
62
|
+
llmParams?: Record<string, string | number | boolean>;
|
|
63
|
+
ttsParams?: Record<string, string | number | boolean>;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface TranslationLanguageEntry {
|
|
67
|
+
code: string;
|
|
68
|
+
nickname?: string;
|
|
69
|
+
voiceConfig?: TranslationVoiceConfig;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export const SUPPORTED_LANGUAGE_CODES: string[] = [
|
|
73
|
+
'en', 'es', 'fr', 'de', 'it', 'pt', 'ru', 'zh', 'ja', 'ko', 'ar',
|
|
74
|
+
'hi', 'bn', 'pa', 'te', 'mr', 'ta', 'ur', 'gu', 'kn', 'ml', 'ne', 'si',
|
|
75
|
+
'nl', 'pl', 'tr', 'cs', 'el', 'hu', 'ro', 'sv', 'da', 'fi', 'no', 'sk',
|
|
76
|
+
'uk', 'bg', 'hr', 'et', 'lt', 'lv', 'sl', 'sr', 'bs', 'mk', 'is',
|
|
77
|
+
'ga', 'cy', 'mt', 'lb', 'sq', 'be',
|
|
78
|
+
'he', 'fa', 'ps', 'ku',
|
|
79
|
+
'vi', 'th', 'id', 'ms', 'tl', 'km', 'lo', 'my',
|
|
80
|
+
'sw', 'yo', 'ig', 'ha', 'zu', 'xh', 'af', 'st', 'tn', 'sn', 'am', 'so', 'rw', 'mg', 'ny',
|
|
81
|
+
'ee', 'tw', 'gaa',
|
|
82
|
+
'ka', 'hy', 'az',
|
|
83
|
+
'eu', 'gl', 'ca', 'la', 'eo',
|
|
84
|
+
'kk', 'uz', 'tg', 'ky', 'tk', 'mn',
|
|
85
|
+
'auto',
|
|
86
|
+
];
|
|
87
|
+
|
|
88
|
+
const REGION_BY_LANGUAGE: Record<string, LanguageRegion> = {
|
|
89
|
+
en: 'global', es: 'global', fr: 'europe', de: 'europe', it: 'europe', pt: 'global', ru: 'europe', zh: 'asia', ja: 'asia', ko: 'asia', ar: 'mena',
|
|
90
|
+
hi: 'south-asia', bn: 'south-asia', pa: 'south-asia', te: 'south-asia', mr: 'south-asia', ta: 'south-asia', ur: 'south-asia', gu: 'south-asia', kn: 'south-asia', ml: 'south-asia', ne: 'south-asia', si: 'south-asia',
|
|
91
|
+
nl: 'europe', pl: 'europe', tr: 'europe', cs: 'europe', el: 'europe', hu: 'europe', ro: 'europe', sv: 'europe', da: 'europe', fi: 'europe', no: 'europe', sk: 'europe', uk: 'europe', bg: 'europe', hr: 'europe', et: 'europe', lt: 'europe', lv: 'europe', sl: 'europe', sr: 'europe', bs: 'europe', mk: 'europe', is: 'europe', ga: 'europe', cy: 'europe', mt: 'europe', lb: 'europe', sq: 'europe', be: 'europe',
|
|
92
|
+
he: 'mena', fa: 'mena', ps: 'mena', ku: 'mena',
|
|
93
|
+
vi: 'asia', th: 'asia', id: 'asia', ms: 'asia', tl: 'asia', km: 'asia', lo: 'asia', my: 'asia',
|
|
94
|
+
sw: 'africa', yo: 'africa', ig: 'africa', ha: 'africa', zu: 'africa', xh: 'africa', af: 'africa', st: 'africa', tn: 'africa', sn: 'africa', am: 'africa', so: 'africa', rw: 'africa', mg: 'africa', ny: 'africa', ee: 'africa', tw: 'africa', gaa: 'africa',
|
|
95
|
+
ka: 'caucasus', hy: 'caucasus', az: 'caucasus',
|
|
96
|
+
eu: 'europe', gl: 'europe', ca: 'europe', la: 'europe', eo: 'constructed',
|
|
97
|
+
kk: 'central-asia', uz: 'central-asia', tg: 'central-asia', ky: 'central-asia', tk: 'central-asia', mn: 'central-asia',
|
|
98
|
+
auto: 'special',
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
const TTS_SUPPORT_BY_LANGUAGE: Record<string, TTSSupport> = {
|
|
102
|
+
en: 'excellent', es: 'excellent', fr: 'excellent', de: 'excellent', it: 'excellent', pt: 'excellent', ru: 'excellent', zh: 'excellent', ja: 'excellent', ko: 'excellent', ar: 'excellent',
|
|
103
|
+
hi: 'good', bn: 'good', te: 'good', mr: 'good', ta: 'good', ur: 'good', nl: 'excellent', pl: 'excellent', tr: 'excellent', cs: 'good', el: 'good', hu: 'good', ro: 'good', sv: 'excellent',
|
|
104
|
+
da: 'good', fi: 'good', no: 'good', uk: 'good', he: 'good', vi: 'good', th: 'good', id: 'good', ms: 'good', af: 'good', ca: 'good',
|
|
105
|
+
auto: 'n/a',
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const getDisplayName = (code: string, locale: string, fallback: string) => {
|
|
109
|
+
try {
|
|
110
|
+
const displayNames = new Intl.DisplayNames([locale], { type: 'language' });
|
|
111
|
+
return displayNames.of(code) || fallback;
|
|
112
|
+
} catch {
|
|
113
|
+
return fallback;
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
export const normalizeLanguageCode = (code: string): string => {
|
|
118
|
+
if (!code || typeof code !== 'string') {
|
|
119
|
+
return 'en';
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return code.trim().toLowerCase().split('-')[0];
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
export const isLanguageSupported = (code: string): boolean => {
|
|
126
|
+
const normalized = normalizeLanguageCode(code);
|
|
127
|
+
return SUPPORTED_LANGUAGE_CODES.includes(normalized);
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
export const getLanguageName = (code: string, displayLocale = 'en'): string => {
|
|
131
|
+
const normalized = normalizeLanguageCode(code);
|
|
132
|
+
if (normalized === 'auto') {
|
|
133
|
+
return 'Auto-detect';
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return getDisplayName(normalized, displayLocale, normalized.toUpperCase());
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
export const getLanguageNativeName = (code: string): string => {
|
|
140
|
+
const normalized = normalizeLanguageCode(code);
|
|
141
|
+
if (normalized === 'auto') {
|
|
142
|
+
return 'Auto';
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return getDisplayName(normalized, normalized, getLanguageName(normalized));
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
export const getLanguageMetadata = (code: string): LanguageMetadata => {
|
|
149
|
+
const normalized = normalizeLanguageCode(code);
|
|
150
|
+
|
|
151
|
+
return {
|
|
152
|
+
name: getLanguageName(normalized),
|
|
153
|
+
nativeName: getLanguageNativeName(normalized),
|
|
154
|
+
region: REGION_BY_LANGUAGE[normalized] || 'other',
|
|
155
|
+
ttsSupport: TTS_SUPPORT_BY_LANGUAGE[normalized] || 'unknown',
|
|
156
|
+
};
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
export const getSupportedLanguages = (displayLocale = 'en'): LanguageOption[] => {
|
|
160
|
+
return SUPPORTED_LANGUAGE_CODES.map((code) => {
|
|
161
|
+
const metadata = getLanguageMetadata(code);
|
|
162
|
+
return {
|
|
163
|
+
code,
|
|
164
|
+
name: getLanguageName(code, displayLocale),
|
|
165
|
+
nativeName: metadata.nativeName,
|
|
166
|
+
region: metadata.region,
|
|
167
|
+
ttsSupport: metadata.ttsSupport,
|
|
168
|
+
};
|
|
169
|
+
}).sort((left, right) => left.name.localeCompare(right.name));
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
export type TTSProvider =
|
|
173
|
+
| 'deepgram'
|
|
174
|
+
| 'openai'
|
|
175
|
+
| 'azure'
|
|
176
|
+
| 'google'
|
|
177
|
+
| 'aws'
|
|
178
|
+
| 'elevenlabs'
|
|
179
|
+
| 'playht'
|
|
180
|
+
| 'cartesia'
|
|
181
|
+
| 'rime'
|
|
182
|
+
| 'kokoro'
|
|
183
|
+
| 'gemini'
|
|
184
|
+
| 'assemblyai';
|
|
185
|
+
|
|
186
|
+
export const TTS_PROVIDERS: Record<TTSProvider, { name: string; supportsSSML: boolean; multilingual?: boolean; isDefault?: boolean }> = {
|
|
187
|
+
deepgram: { name: 'Deepgram Aura', supportsSSML: false, isDefault: true },
|
|
188
|
+
openai: { name: 'OpenAI TTS', supportsSSML: false, multilingual: true },
|
|
189
|
+
azure: { name: 'Azure Neural TTS', supportsSSML: true },
|
|
190
|
+
google: { name: 'Google Cloud TTS', supportsSSML: true },
|
|
191
|
+
aws: { name: 'AWS Polly', supportsSSML: true },
|
|
192
|
+
elevenlabs: { name: 'ElevenLabs', supportsSSML: false, multilingual: true },
|
|
193
|
+
playht: { name: 'PlayHT', supportsSSML: false, multilingual: true },
|
|
194
|
+
cartesia: { name: 'Cartesia Sonic', supportsSSML: false, multilingual: true },
|
|
195
|
+
rime: { name: 'Rime AI', supportsSSML: false, multilingual: true },
|
|
196
|
+
kokoro: { name: 'Kokoro', supportsSSML: false, multilingual: true },
|
|
197
|
+
gemini: { name: 'Google Gemini TTS', supportsSSML: false, multilingual: true },
|
|
198
|
+
assemblyai: { name: 'AssemblyAI', supportsSSML: false },
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
export interface SocketVoiceResponse {
|
|
202
|
+
provider: string;
|
|
203
|
+
language: string;
|
|
204
|
+
voices: { male: VoiceOption[]; female: VoiceOption[] };
|
|
205
|
+
providers?: Record<string, unknown>;
|
|
206
|
+
error?: string;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const buildFallbackVoices = (langCode: string, provider: string): { male: VoiceOption[]; female: VoiceOption[] } => {
|
|
210
|
+
const normalizedLanguage = normalizeLanguageCode(langCode === 'auto' ? 'en' : langCode);
|
|
211
|
+
const providerKey = provider.toLowerCase();
|
|
212
|
+
const providerName = TTS_PROVIDERS[providerKey as TTSProvider]?.name || provider;
|
|
213
|
+
const languageName = getLanguageName(normalizedLanguage);
|
|
214
|
+
|
|
215
|
+
return {
|
|
216
|
+
female: [
|
|
217
|
+
{
|
|
218
|
+
id: `${providerKey}-${normalizedLanguage}-female-1`,
|
|
219
|
+
name: `${providerName} ${languageName} Female`,
|
|
220
|
+
gender: 'female',
|
|
221
|
+
provider: providerKey,
|
|
222
|
+
language: normalizedLanguage,
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
id: `${providerKey}-${normalizedLanguage}-female-2`,
|
|
226
|
+
name: `${providerName} ${languageName} Female 2`,
|
|
227
|
+
gender: 'female',
|
|
228
|
+
provider: providerKey,
|
|
229
|
+
language: normalizedLanguage,
|
|
230
|
+
},
|
|
231
|
+
],
|
|
232
|
+
male: [
|
|
233
|
+
{
|
|
234
|
+
id: `${providerKey}-${normalizedLanguage}-male-1`,
|
|
235
|
+
name: `${providerName} ${languageName} Male`,
|
|
236
|
+
gender: 'male',
|
|
237
|
+
provider: providerKey,
|
|
238
|
+
language: normalizedLanguage,
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
id: `${providerKey}-${normalizedLanguage}-male-2`,
|
|
242
|
+
name: `${providerName} ${languageName} Male 2`,
|
|
243
|
+
gender: 'male',
|
|
244
|
+
provider: providerKey,
|
|
245
|
+
language: normalizedLanguage,
|
|
246
|
+
},
|
|
247
|
+
],
|
|
248
|
+
};
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
export const getAvailableVoices = (
|
|
252
|
+
langCode: string,
|
|
253
|
+
provider: TTSProvider | string = 'deepgram'
|
|
254
|
+
): { male: VoiceOption[]; female: VoiceOption[] } => {
|
|
255
|
+
return buildFallbackVoices(langCode, provider.toString());
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
export const fetchVoicesViaSocket = (
|
|
259
|
+
socket: { emit: (event: string, data: unknown, callback?: (response: SocketVoiceResponse) => void) => void },
|
|
260
|
+
provider: TTSProvider | string = 'deepgram',
|
|
261
|
+
language: string = 'en'
|
|
262
|
+
): Promise<SocketVoiceResponse> => {
|
|
263
|
+
return new Promise((resolve) => {
|
|
264
|
+
const providerName = provider.toString();
|
|
265
|
+
const fallbackVoices = getAvailableVoices(language, providerName);
|
|
266
|
+
|
|
267
|
+
const timeout = setTimeout(() => {
|
|
268
|
+
resolve({
|
|
269
|
+
provider: providerName,
|
|
270
|
+
language,
|
|
271
|
+
voices: fallbackVoices,
|
|
272
|
+
error: 'Request timed out, using shared fallback voices',
|
|
273
|
+
});
|
|
274
|
+
}, 5000);
|
|
275
|
+
|
|
276
|
+
socket.emit('translation:getVoices', { provider, language }, (response: SocketVoiceResponse) => {
|
|
277
|
+
clearTimeout(timeout);
|
|
278
|
+
|
|
279
|
+
if (response?.voices) {
|
|
280
|
+
resolve(response);
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
resolve({
|
|
285
|
+
provider: response?.provider || providerName,
|
|
286
|
+
language: response?.language || language,
|
|
287
|
+
voices: fallbackVoices,
|
|
288
|
+
error: response?.error || 'No voices returned, using shared fallback voices',
|
|
289
|
+
});
|
|
290
|
+
});
|
|
291
|
+
});
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
export const fetchLanguagesViaSocket = (
|
|
295
|
+
socket: { emit: (event: string, data: unknown, callback?: (response: { languages?: LanguageOption[] }) => void) => void },
|
|
296
|
+
displayLocale: string = 'en'
|
|
297
|
+
): Promise<LanguageOption[]> => {
|
|
298
|
+
return new Promise((resolve) => {
|
|
299
|
+
const timeout = setTimeout(() => {
|
|
300
|
+
resolve(getSupportedLanguages(displayLocale));
|
|
301
|
+
}, 5000);
|
|
302
|
+
|
|
303
|
+
socket.emit('translation:getLanguages', { displayLocale }, (response: { languages?: LanguageOption[] }) => {
|
|
304
|
+
clearTimeout(timeout);
|
|
305
|
+
resolve(response?.languages?.length ? response.languages : getSupportedLanguages(displayLocale));
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// Default fallback
|
|
2
|
+
// Fallback for mediaDevices with support for getUserMedia
|
|
3
|
+
export const mediaDevices = {
|
|
4
|
+
getUserMedia: async (_constraints: MediaStreamConstraints): Promise<MediaStream> => {
|
|
5
|
+
// Fallback logic or mock implementation for getUserMedia
|
|
6
|
+
console.warn('getUserMedia is not implemented in this environment.');
|
|
7
|
+
return new MediaStream(); // Return an empty MediaStream as a fallback
|
|
8
|
+
},
|
|
9
|
+
|
|
10
|
+
getDisplayMedia: async (_constraints: MediaStreamConstraints): Promise<MediaStream> => {
|
|
11
|
+
// Fallback logic or mock implementation for getDisplayMedia
|
|
12
|
+
console.warn('getDisplayMedia is not implemented in this environment.');
|
|
13
|
+
return new MediaStream(); // Return an empty MediaStream as a fallback
|
|
14
|
+
},
|
|
15
|
+
|
|
16
|
+
enumerateDevices: async (): Promise<MediaDeviceInfo[]> => {
|
|
17
|
+
// Fallback logic or mock implementation for enumerateDevices
|
|
18
|
+
console.warn('enumerateDevices is not implemented in this environment.');
|
|
19
|
+
return []; // Return an empty array as a fallback
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export function registerGlobals() {}
|
|
24
|
+
|
|
25
|
+
export class MediaStream {
|
|
26
|
+
tracks: any[];
|
|
27
|
+
|
|
28
|
+
constructor(tracks: any[] = []) {
|
|
29
|
+
this.tracks = tracks; // Assign tracks to the MediaStream instance
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// You can add additional methods or properties if needed
|
|
33
|
+
[key: string]: any;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export class MediaStreamTrack {
|
|
37
|
+
[key: string]: any;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export class RTCView {
|
|
41
|
+
render(): null {
|
|
42
|
+
return null; // Empty RTCView implementation
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Socket } from 'socket.io-client';
|
|
1
|
+
import type { Socket } from 'socket.io-client';
|
|
2
2
|
import Cookies from 'universal-cookie';
|
|
3
3
|
import type { PreJoinPageParameters } from '../../types/types';
|
|
4
4
|
|
|
@@ -6,6 +6,15 @@ const cookies = new Cookies();
|
|
|
6
6
|
const MAX_ATTEMPTS = 10;
|
|
7
7
|
const RATE_LIMIT_DURATION = 3 * 60 * 60 * 1000; // 3 hours
|
|
8
8
|
|
|
9
|
+
const hasConnectedSocketId = (socket: unknown): socket is Socket & { id: string } => {
|
|
10
|
+
if (!socket || typeof socket !== 'object') {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const candidate = socket as { id?: unknown };
|
|
15
|
+
return typeof candidate.id === 'string' && candidate.id.length > 0;
|
|
16
|
+
};
|
|
17
|
+
|
|
9
18
|
/**
|
|
10
19
|
* Options for handleWelcomeRequest function
|
|
11
20
|
*/
|
|
@@ -143,7 +152,7 @@ export async function handleWelcomeRequest({
|
|
|
143
152
|
|
|
144
153
|
const socket = await Promise.race([socketPromise, timeoutPromise]);
|
|
145
154
|
|
|
146
|
-
if (socket
|
|
155
|
+
if (hasConnectedSocketId(socket)) {
|
|
147
156
|
unsuccessfulAttempts = 0;
|
|
148
157
|
cookies.set('unsuccessfulAttempts', unsuccessfulAttempts.toString());
|
|
149
158
|
cookies.set('lastRequestTimestamp', Date.now().toString());
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export {
|
|
2
|
+
handleWelcomeRequest,
|
|
3
|
+
validateAlphanumeric as validateWelcomeAlphanumeric,
|
|
4
|
+
validateWelcomeInputs,
|
|
5
|
+
} from './handleWelcomeRequest';
|
|
2
6
|
export type {
|
|
3
7
|
HandleWelcomeRequestOptions,
|
|
4
8
|
ValidateWelcomeInputsOptions,
|