182 lines
6.9 KiB
TypeScript
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);
|
|
}
|
|
}
|
|
}
|
|
} |