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

182 lines
6.9 KiB
TypeScript

import {_connection} from "./ServerConnection";
import {_audio as _recorder} from "../audio/AudioRecorder";
import {
NativeVoiceConnection,
NativeVoiceClient
} from "teaclient_connection";
export namespace _audio {
export namespace native {
import ServerConnection = _connection.native.ServerConnection;
export class VoiceConnection extends connection.voice.AbstractVoiceConnection {
readonly connection: ServerConnection;
readonly handle: NativeVoiceConnection;
private _audio_source: RecorderProfile;
constructor(connection: ServerConnection, voice: NativeVoiceConnection) {
super(connection);
this.connection = connection;
this.handle = voice;
}
setup() { }
async acquire_voice_recorder(recorder: RecorderProfile | undefined, enforce?: boolean) {
if(this._audio_source === recorder && !enforce)
return;
if(this._audio_source)
await this._audio_source.unmount();
if(recorder) {
if(!(recorder.input instanceof _recorder.recorder.NativeInput))
throw "Recorder input must be an instance of NativeInput!";
await recorder.unmount();
}
this.handleVoiceEnded();
this._audio_source = recorder;
if(recorder) {
recorder.current_handler = this.connection.client;
recorder.callback_unmount = () => {
this._audio_source = undefined;
this.handle.set_audio_source(undefined);
this.connection.client.update_voice_status(undefined);
};
recorder.callback_start = this.on_voice_started.bind(this);
recorder.callback_stop = this.handleVoiceEnded.bind(this);
recorder.callback_support_change = () => {
this.connection.client.update_voice_status(undefined);
};
this.handle.set_audio_source((recorder.input as _recorder.recorder.NativeInput).consumer);
}
this.connection.client.update_voice_status(undefined);
}
voice_playback_support() : boolean {
return this.connection.connected();
}
voice_send_support() : boolean {
return this.connection.connected();
}
private current_channel_codec() : number {
const chandler = this.connection.client;
return (chandler.getClient().currentChannel() || {properties: { channel_codec: 4}}).properties.channel_codec;
}
private handleVoiceEnded() {
const chandler = this.connection.client;
chandler.getClient().speaking = false;
if(!chandler.connected)
return false;
if(chandler.client_status.input_muted)
return false;
console.log(tr("Local voice ended"));
//TODO
}
private on_voice_started() {
const chandler = this.connection.client;
if(chandler.client_status.input_muted) {
/* 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);
}
return;
}
log.info(LogCategory.VOICE, tr("Local voice started"));
this.handle.enable_voice_send(true);
const ch = chandler.getClient();
if(ch) ch.speaking = true;
}
connected(): boolean {
return true; /* we cant be disconnected at any time! */
}
voice_recorder(): RecorderProfile {
return this._audio_source;
}
available_clients(): connection.voice.VoiceClient[] {
return this.handle.available_clients().map(e => Object.assign(e, {
support_latency_settings() { return true; },
reset_latency_settings: function() {
const stream = this.get_stream();
stream.set_buffer_latency(0.02);
stream.set_buffer_max_latency(0.2);
return this.latency_settings();
},
latency_settings: function (settings?: connection.voice.LatencySettings) : connection.voice.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);
}
return {
max_buffer: Math.floor(stream.get_buffer_max_latency() * 1000),
min_buffer: Math.floor(stream.get_buffer_latency() * 1000)
};
},
support_flush() { return true; },
flush: function () {
const stream = this.get_stream();
stream.flush_buffer();
}
}));
}
find_client(client_id: number) : connection.voice.VoiceClient | undefined {
for(const client of this.available_clients())
if(client.client_id === client_id)
return client;
return undefined;
}
unregister_client(client: connection.voice.VoiceClient): Promise<void> {
this.handle.unregister_client(client.client_id);
return Promise.resolve();
}
register_client(client_id: number): connection.voice.VoiceClient {
const client = this.handle.register_client(client_id);
const c = this.find_client(client_id);
c.reset_latency_settings();
return c;
}
decoding_supported(codec: number): boolean {
return this.handle.decoding_supported(codec);
}
encoding_supported(codec: number): boolean {
return this.handle.encoding_supported(codec);
}
get_encoder_codec(): number {
return this.handle.get_encoder_codec();
}
set_encoder_codec(codec: number) {
return this.handle.set_encoder_codec(codec);
}
}
}
}