TeaWeb/shared/js/ui/modal/echo-test/Controller.tsx
2021-01-12 04:38:21 +01:00

203 lines
No EOL
7.3 KiB
TypeScript

import {spawnReactModal} from "tc-shared/ui/react-elements/Modal";
import {InternalModal} from "tc-shared/ui/react-elements/internal-modal/Controller";
import * as React from "react";
import {Translatable} from "tc-shared/ui/react-elements/i18n";
import {EchoTestEventRegistry, EchoTestModal} from "tc-shared/ui/modal/echo-test/Renderer";
import {Registry} from "tc-shared/events";
import {EchoTestEvents, TestState} from "tc-shared/ui/modal/echo-test/Definitions";
import {ConnectionHandler} from "tc-shared/ConnectionHandler";
import {global_client_actions} from "tc-shared/events/GlobalEvents";
import {VoiceConnectionStatus} from "tc-shared/connection/VoiceConnection";
import {Settings, settings} from "tc-shared/settings";
import {CommandResult} from "tc-shared/connection/ServerConnectionDeclaration";
import {LogCategory, logError, logTrace, logWarn} from "tc-shared/log";
import {ServerFeature} from "tc-shared/connection/ServerFeatures";
export function spawnEchoTestModal(connection: ConnectionHandler) {
const events = new Registry<EchoTestEvents>();
initializeController(connection, events);
const modal = spawnReactModal(class extends InternalModal {
constructor() {
super();
}
renderBody(): React.ReactElement {
return (
<EchoTestEventRegistry.Provider value={events}>
<EchoTestModal/>
</EchoTestEventRegistry.Provider>
);
}
title(): string | React.ReactElement<Translatable> {
return <Translatable>Voice echo test</Translatable>;
}
});
events.on("action_close", () => {
modal.destroy();
});
modal.events.on("close", () => events.fire_react("notify_close"));
modal.events.on("destroy", () => {
events.fire("notify_destroy");
events.destroy();
});
modal.show();
}
function initializeController(connection: ConnectionHandler, events: Registry<EchoTestEvents>) {
let testState: TestState = {state: "stopped"};
events.on("action_open_microphone_settings", () => {
global_client_actions.fire("action_open_window_settings", {defaultCategory: "audio-microphone"});
});
events.on("action_toggle_tests", event => {
settings.setValue(Settings.KEY_VOICE_ECHO_TEST_ENABLED, event.enabled);
});
events.on("query_test_state", () => {
events.fire_react("notify_tests_toggle", {enabled: settings.getValue(Settings.KEY_VOICE_ECHO_TEST_ENABLED)});
});
events.on("notify_destroy", settings.globalChangeListener(Settings.KEY_VOICE_ECHO_TEST_ENABLED, value => {
events.fire_react("notify_tests_toggle", {enabled: value});
}));
events.on("action_test_result", event => {
if (event.status === "success") {
events.fire("action_close");
} else {
events.fire_react("action_stop_test");
events.fire_react("notify_test_phase", {phase: "troubleshooting"});
}
});
events.on("action_troubleshooting_finished", event => {
if (event.status === "aborted") {
events.fire("action_close");
} else {
events.fire_react("notify_test_phase", {phase: "testing"});
events.fire("action_start_test");
}
});
const reportVoiceConnectionState = (state: VoiceConnectionStatus) => {
if (state === VoiceConnectionStatus.Connected) {
beginTest();
} else {
endTest();
}
switch (state) {
case VoiceConnectionStatus.Connected:
events.fire_react("notify_voice_connection_state", {state: "connected"});
break;
case VoiceConnectionStatus.Disconnected:
case VoiceConnectionStatus.Disconnecting:
events.fire_react("notify_voice_connection_state", {state: "disconnected"});
break;
case VoiceConnectionStatus.Connecting:
events.fire_react("notify_voice_connection_state", {state: "connecting"});
break;
case VoiceConnectionStatus.ClientUnsupported:
events.fire_react("notify_voice_connection_state", {state: "unsupported-client"});
break;
case VoiceConnectionStatus.ServerUnsupported:
events.fire_react("notify_voice_connection_state", {state: "unsupported-server"});
break;
case VoiceConnectionStatus.Failed:
events.fire_react("notify_voice_connection_state", {state: "failed", message: connection.getServerConnection().getVoiceConnection().getFailedMessage() });
break;
}
};
events.on("notify_destroy", connection.getServerConnection().getVoiceConnection().events.on("notify_connection_status_changed", event => {
reportVoiceConnectionState(event.newStatus);
}));
events.on("query_voice_connection_state", () => reportVoiceConnectionState(connection.getServerConnection().getVoiceConnection().getConnectionState()));
events.on("query_test_state", () => {
events.fire_react("notify_test_state", {state: testState});
});
events.on("action_start_test", () => {
beginTest();
});
events.on("action_unmute", () => {
connection.setSpeakerMuted(false, true);
connection.setMicrophoneMuted(false, true);
beginTest();
});
const setTestState = (state: TestState) => {
testState = state;
events.fire_react("notify_test_state", {state: state});
}
let testId = 0;
const beginTest = () => {
if (testState.state === "initializing" || testState.state === "running") {
return;
} else if (!connection.serverFeatures.supportsFeature(ServerFeature.WHISPER_ECHO)) {
setTestState({state: "unsupported"});
return;
} else if (connection.isSpeakerMuted() || connection.isMicrophoneMuted()) {
setTestState({
state: "muted",
speaker: connection.isSpeakerMuted(),
microphone: connection.isMicrophoneMuted()
});
return;
}
setTestState({state: "initializing"});
const currentTestId = ++testId;
connection.startEchoTest().then(() => {
if (currentTestId !== testId) {
return;
}
logTrace(LogCategory.VOICE, tr("Echo test started."));
setTestState({state: "running"});
}).catch(error => {
logWarn(LogCategory.VOICE, tr("Failed to start echo test: %o"), error);
if (currentTestId !== testId) {
return;
}
let message;
if (error instanceof CommandResult) {
message = error.formattedMessage();
} else if (error instanceof Error) {
message = error.message;
} else if (typeof error === "string") {
message = error;
} else {
message = tr("lookup the console");
logError(LogCategory.AUDIO, tr("Failed to begin echo testing: %o"), error);
}
setTestState({state: "start-failed", error: message});
});
}
const endTest = () => {
setTestState({state: "stopped"});
connection.stopEchoTest();
}
events.on(["notify_destroy", "notify_close", "action_stop_test"], endTest);
}