TeaSpeak-Client/modules/renderer/connection/VoiceConnection.ts

182 lines
6.1 KiB
TypeScript
Raw Normal View History

import {ServerConnection} from "./ServerConnection";
import {NativeVoiceConnection} from "tc-native/connection";
import {RecorderProfile} from "tc-shared/voice/RecorderProfile";
import {tr} from "tc-shared/i18n/localize";
import {LogCategory} from "tc-shared/log";
import * as log from "tc-shared/log";
2020-08-21 07:37:10 -04:00
import {
AbstractVoiceConnection,
LatencySettings,
VoiceClient,
VoiceConnectionStatus
} from "tc-shared/connection/VoiceConnection";
import {NativeInput} from "../audio/AudioRecorder";
export class VoiceConnection extends AbstractVoiceConnection {
readonly connection: ServerConnection;
readonly handle: NativeVoiceConnection;
private _audio_source: RecorderProfile;
constructor(connection: ServerConnection, voice: NativeVoiceConnection) {
super(connection);
this.connection = connection;
this.handle = voice;
}
2019-10-25 19:51:40 -04:00
setup() { }
2019-10-25 19:51:40 -04:00
async acquire_voice_recorder(recorder: RecorderProfile | undefined, enforce?: boolean) {
if(this._audio_source === recorder && !enforce)
return;
2019-10-25 19:51:40 -04:00
if(this._audio_source)
await this._audio_source.unmount();
2019-10-25 19:51:40 -04:00
if(recorder) {
if(!(recorder.input instanceof NativeInput))
throw "Recorder input must be an instance of NativeInput!";
await recorder.unmount();
}
2019-10-25 19:51:40 -04:00
this.handleVoiceEnded();
this._audio_source = recorder;
2019-10-25 19:51:40 -04:00
if(recorder) {
recorder.current_handler = this.connection.client;
2019-10-25 19:51:40 -04:00
recorder.callback_unmount = () => {
this._audio_source = undefined;
this.handle.set_audio_source(undefined);
this.connection.client.update_voice_status(undefined);
};
2019-10-25 19:51:40 -04:00
recorder.callback_start = this.on_voice_started.bind(this);
recorder.callback_stop = this.handleVoiceEnded.bind(this);
2019-10-25 19:51:40 -04:00
2020-06-13 09:05:49 -04:00
(recorder as any).callback_support_change = () => {
this.connection.client.update_voice_status(undefined);
};
2020-06-13 09:05:49 -04:00
2020-08-21 07:37:10 -04:00
this.handle.set_audio_source((recorder.input as NativeInput).getNativeConsumer());
}
this.connection.client.update_voice_status(undefined);
}
2019-10-25 19:51:40 -04:00
voice_playback_support() : boolean {
return this.connection.connected();
}
2019-10-25 19:51:40 -04:00
voice_send_support() : boolean {
return this.connection.connected();
}
2019-10-25 19:51:40 -04:00
private current_channel_codec() : number {
const chandler = this.connection.client;
return (chandler.getClient().currentChannel() || {properties: { channel_codec: 4}}).properties.channel_codec;
}
2019-10-25 19:51:40 -04:00
private handleVoiceEnded() {
const chandler = this.connection.client;
chandler.getClient().speaking = false;
2019-10-25 19:51:40 -04:00
if(!chandler.connected)
return false;
2019-10-25 19:51:40 -04:00
2020-06-13 09:05:49 -04:00
if(chandler.isMicrophoneMuted())
return false;
2019-10-25 19:51:40 -04:00
console.log(tr("Local voice ended"));
2020-04-25 06:48:44 -04:00
//TODO Send end? (Or is this already an automated thing?)
}
2019-10-25 19:51:40 -04:00
private on_voice_started() {
const chandler = this.connection.client;
2020-06-13 09:05:49 -04:00
if(chandler.isMicrophoneMuted()) {
/* evil hack due to the settings :D */
log.warn(LogCategory.VOICE, tr("Received local voice started event, even thou we're muted! Do not send any voice."));
if(this.handle) {
this.handle.enable_voice_send(false);
2019-10-25 19:51:40 -04:00
}
return;
}
2019-10-25 19:51:40 -04:00
2020-08-21 07:37:10 -04:00
log.info(LogCategory.VOICE, tr("Local voice started (Native)"));
this.handle.enable_voice_send(true);
2019-10-25 19:51:40 -04:00
const ch = chandler.getClient();
if(ch) ch.speaking = true;
}
2019-10-25 19:51:40 -04:00
2020-08-21 07:37:10 -04:00
getConnectionState(): VoiceConnectionStatus {
return VoiceConnectionStatus.Connected;
}
2019-10-25 19:51:40 -04:00
voice_recorder(): RecorderProfile {
return this._audio_source;
}
2019-10-25 19:51:40 -04:00
available_clients(): VoiceClient[] {
return this.handle.available_clients().map(e => Object.assign(e, {
support_latency_settings() { return true; },
2020-06-13 09:05:49 -04:00
reset_latency_settings() {
const stream = this.get_stream();
stream.set_buffer_latency(0.080);
stream.set_buffer_max_latency(0.5);
return this.latency_settings();
},
2020-06-13 09:05:49 -04:00
latency_settings(settings?: LatencySettings) : LatencySettings {
const stream = this.get_stream();
if(typeof settings !== "undefined") {
stream.set_buffer_latency(settings.min_buffer / 1000);
stream.set_buffer_max_latency(settings.max_buffer / 100);
2019-10-25 19:51:40 -04:00
}
return {
max_buffer: Math.floor(stream.get_buffer_max_latency() * 1000),
min_buffer: Math.floor(stream.get_buffer_latency() * 1000)
};
},
support_flush() { return true; },
2020-06-13 09:05:49 -04:00
flush() {
const stream = this.get_stream();
stream.flush_buffer();
}
2020-06-13 09:05:49 -04:00
}) as any); /* cast to any because of: Type 'import("/mnt/d/TeaSpeak/client_linux/client/imports/shared-app/connection/ConnectionBase").voice.PlayerState' is not assignable to type 'import("tc-native/connection").PlayerState' */
}
2019-10-25 19:51:40 -04:00
find_client(client_id: number) : VoiceClient | undefined {
for(const client of this.available_clients())
if(client.client_id === client_id)
return client;
return undefined;
}
2019-10-25 19:51:40 -04:00
unregister_client(client: VoiceClient): Promise<void> {
this.handle.unregister_client(client.client_id);
return Promise.resolve();
}
2019-10-25 19:51:40 -04:00
register_client(client_id: number): VoiceClient {
const client = this.handle.register_client(client_id);
const c = this.find_client(client_id);
c.reset_latency_settings();
return c;
}
2019-10-25 19:51:40 -04:00
decoding_supported(codec: number): boolean {
return this.handle.decoding_supported(codec);
}
2019-10-25 19:51:40 -04:00
encoding_supported(codec: number): boolean {
return this.handle.encoding_supported(codec);
}
2019-10-25 19:51:40 -04:00
get_encoder_codec(): number {
return this.handle.get_encoder_codec();
}
2019-10-25 19:51:40 -04:00
set_encoder_codec(codec: number) {
return this.handle.set_encoder_codec(codec);
2019-10-25 19:51:40 -04:00
}
}