Implemented speex for the native client
parent
5ac06d4819
commit
69537aee79
|
@ -4,7 +4,12 @@ interface CodecCostructor {
|
||||||
|
|
||||||
enum CodecType {
|
enum CodecType {
|
||||||
OPUS_VOICE,
|
OPUS_VOICE,
|
||||||
OPUS_MUSIC
|
OPUS_MUSIC,
|
||||||
|
|
||||||
|
SPEEX_NARROWBAND,
|
||||||
|
SPEEX_WIDEBAND,
|
||||||
|
SPEEX_ULTRA_WIDEBAND,
|
||||||
|
CELT_MONO
|
||||||
}
|
}
|
||||||
|
|
||||||
class BufferChunk {
|
class BufferChunk {
|
||||||
|
|
|
@ -121,6 +121,7 @@ function loadDebug() {
|
||||||
if(!window.require) {
|
if(!window.require) {
|
||||||
console.log("Adding browser audio player");
|
console.log("Adding browser audio player");
|
||||||
custom_scripts.push(["js/audio/AudioPlayer.js"]);
|
custom_scripts.push(["js/audio/AudioPlayer.js"]);
|
||||||
|
custom_scripts.push(["js/audio/WebCodec.js"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
load_wait_scripts([
|
load_wait_scripts([
|
||||||
|
|
|
@ -13,7 +13,7 @@ class CodecPool {
|
||||||
handle: VoiceConnection;
|
handle: VoiceConnection;
|
||||||
codecIndex: number;
|
codecIndex: number;
|
||||||
name: string;
|
name: string;
|
||||||
creator: () => BasicCodec;
|
type: CodecType;
|
||||||
|
|
||||||
entries: CodecPoolEntry[] = [];
|
entries: CodecPoolEntry[] = [];
|
||||||
maxInstances: number = 2;
|
maxInstances: number = 2;
|
||||||
|
@ -26,6 +26,7 @@ class CodecPool {
|
||||||
console.log("Release again! (%o)", codec);
|
console.log("Release again! (%o)", codec);
|
||||||
this.releaseCodec(i + 1);
|
this.releaseCodec(i + 1);
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
|
console.warn("Disabling codec support for " + this.name);
|
||||||
if(this._supported) {
|
if(this._supported) {
|
||||||
createErrorModal("Could not load codec driver", "Could not load or initialize codec " + this.name + "<br>" +
|
createErrorModal("Could not load codec driver", "Could not load or initialize codec " + this.name + "<br>" +
|
||||||
"Error: <code>" + JSON.stringify(error) + "</code>").open();
|
"Error: <code>" + JSON.stringify(error) + "</code>").open();
|
||||||
|
@ -35,11 +36,11 @@ class CodecPool {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
supported() { return this.creator != undefined && this._supported; }
|
supported() { return this._supported; }
|
||||||
|
|
||||||
ownCodec?(clientId: number, create: boolean = true) : Promise<BasicCodec | undefined> {
|
ownCodec?(clientId: number, create: boolean = true) : Promise<BasicCodec | undefined> {
|
||||||
return new Promise<BasicCodec>((resolve, reject) => {
|
return new Promise<BasicCodec>((resolve, reject) => {
|
||||||
if(!this.creator || !this._supported) {
|
if(!this._supported) {
|
||||||
reject("unsupported codec!");
|
reject("unsupported codec!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -72,7 +73,7 @@ class CodecPool {
|
||||||
if(freeSlot == 0){
|
if(freeSlot == 0){
|
||||||
freeSlot = this.entries.length;
|
freeSlot = this.entries.length;
|
||||||
let entry = new CodecPoolEntry();
|
let entry = new CodecPoolEntry();
|
||||||
entry.instance = this.creator();
|
entry.instance = audio.codec.new_instance(this.type);
|
||||||
entry.instance.on_encoded_data = buffer => this.handle.handleEncodedVoicePacket(buffer, this.codecIndex);
|
entry.instance.on_encoded_data = buffer => this.handle.handleEncodedVoicePacket(buffer, this.codecIndex);
|
||||||
this.entries.push(entry);
|
this.entries.push(entry);
|
||||||
}
|
}
|
||||||
|
@ -93,11 +94,13 @@ class CodecPool {
|
||||||
if(this.entries[index].owner == clientId) this.entries[index].owner = 0;
|
if(this.entries[index].owner == clientId) this.entries[index].owner = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(handle: VoiceConnection, index: number, name: string, creator: () => BasicCodec){
|
constructor(handle: VoiceConnection, index: number, name: string, type: CodecType){
|
||||||
this.creator = creator;
|
|
||||||
this.handle = handle;
|
this.handle = handle;
|
||||||
this.codecIndex = index;
|
this.codecIndex = index;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
this.type = type;
|
||||||
|
|
||||||
|
this._supported = this.type !== undefined && audio.codec.supported(this.type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,17 +124,17 @@ class VoiceConnection {
|
||||||
dataChannel: RTCDataChannel;
|
dataChannel: RTCDataChannel;
|
||||||
|
|
||||||
voiceRecorder: VoiceRecorder;
|
voiceRecorder: VoiceRecorder;
|
||||||
private _type: VoiceConnectionType = VoiceConnectionType.NATIVE_ENCODE;
|
private _type: VoiceConnectionType = VoiceConnectionType.JS_ENCODE;
|
||||||
|
|
||||||
local_audio_stream: any;
|
local_audio_stream: any;
|
||||||
|
|
||||||
private codec_pool: CodecPool[] = [
|
private codec_pool: CodecPool[] = [
|
||||||
new CodecPool(this,0,"Spex A", undefined), //Spex
|
new CodecPool(this,0,"Speex Narrowband", CodecType.SPEEX_NARROWBAND),
|
||||||
new CodecPool(this,1,"Spex B", undefined), //Spex
|
new CodecPool(this,1,"Speex Wideband", CodecType.SPEEX_WIDEBAND),
|
||||||
new CodecPool(this,2,"Spex C", undefined), //Spex
|
new CodecPool(this,2,"Speex Ultra Wideband", CodecType.SPEEX_ULTRA_WIDEBAND),
|
||||||
new CodecPool(this,3,"CELT Mono", undefined), //CELT Mono
|
new CodecPool(this,3,"CELT Mono", CodecType.CELT_MONO),
|
||||||
new CodecPool(this,4,"Opus Voice", () => { return audio.codec.new_instance(CodecType.OPUS_VOICE) }), //opus voice
|
new CodecPool(this,4,"Opus Voice", CodecType.OPUS_VOICE),
|
||||||
new CodecPool(this,5,"Opus Music", () => { return audio.codec.new_instance(CodecType.OPUS_MUSIC) }) //opus music
|
new CodecPool(this,5,"Opus Music", CodecType.OPUS_MUSIC)
|
||||||
];
|
];
|
||||||
|
|
||||||
private vpacketId: number = 0;
|
private vpacketId: number = 0;
|
||||||
|
@ -148,6 +151,12 @@ class VoiceConnection {
|
||||||
|
|
||||||
audio.player.on_ready(() => {
|
audio.player.on_ready(() => {
|
||||||
log.info(LogCategory.VOICE, "Initializing voice handler after AudioController has been initialized!");
|
log.info(LogCategory.VOICE, "Initializing voice handler after AudioController has been initialized!");
|
||||||
|
if(native_client) {
|
||||||
|
this.codec_pool[0].initialize(2);
|
||||||
|
this.codec_pool[1].initialize(2);
|
||||||
|
this.codec_pool[2].initialize(2);
|
||||||
|
this.codec_pool[3].initialize(2);
|
||||||
|
}
|
||||||
this.codec_pool[4].initialize(2);
|
this.codec_pool[4].initialize(2);
|
||||||
this.codec_pool[5].initialize(2);
|
this.codec_pool[5].initialize(2);
|
||||||
|
|
||||||
|
@ -415,6 +424,10 @@ class VoiceConnection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private current_channel_codec() : number {
|
||||||
|
return (this.client.getClient().currentChannel() || {properties: { channel_codec: 4}}).properties.channel_codec;
|
||||||
|
}
|
||||||
|
|
||||||
private handleVoiceData(data: AudioBuffer, head: boolean) {
|
private handleVoiceData(data: AudioBuffer, head: boolean) {
|
||||||
if(!this.voiceRecorder) return;
|
if(!this.voiceRecorder) return;
|
||||||
if(!this.client.connected) return false;
|
if(!this.client.connected) return false;
|
||||||
|
@ -426,8 +439,9 @@ class VoiceConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO Use channel codec!
|
//TODO Use channel codec!
|
||||||
this.codec_pool[4].ownCodec(this.client.getClientId())
|
const codec = this.current_channel_codec();
|
||||||
.then(encoder => encoder.encodeSamples(this.client.getClient().getAudioController().codecCache(4), data));
|
this.codec_pool[codec].ownCodec(this.client.getClientId())
|
||||||
|
.then(encoder => encoder.encodeSamples(this.client.getClient().getAudioController().codecCache(codec), data));
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleVoiceEnded() {
|
private handleVoiceEnded() {
|
||||||
|
@ -439,7 +453,7 @@ class VoiceConnection {
|
||||||
console.log("Local voice ended");
|
console.log("Local voice ended");
|
||||||
|
|
||||||
if(this.dataChannel)
|
if(this.dataChannel)
|
||||||
this.sendVoicePacket(new Uint8Array(0), 5); //TODO Use channel codec!
|
this.sendVoicePacket(new Uint8Array(0), this.current_channel_codec()); //TODO Use channel codec!
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleVoiceStarted() {
|
private handleVoiceStarted() {
|
||||||
|
|
|
@ -23,6 +23,7 @@ onmessage = function(e: MessageEvent) {
|
||||||
//console.log(prefix + " Got from main: %o", data);
|
//console.log(prefix + " Got from main: %o", data);
|
||||||
switch (data.command) {
|
switch (data.command) {
|
||||||
case "initialise":
|
case "initialise":
|
||||||
|
let error;
|
||||||
console.log(prefix + "Got initialize for type " + CodecType[data.type as CodecType]);
|
console.log(prefix + "Got initialize for type " + CodecType[data.type as CodecType]);
|
||||||
switch (data.type as CodecType) {
|
switch (data.type as CodecType) {
|
||||||
case CodecType.OPUS_MUSIC:
|
case CodecType.OPUS_MUSIC:
|
||||||
|
@ -32,12 +33,12 @@ onmessage = function(e: MessageEvent) {
|
||||||
codecInstance = new OpusWorker(1, OpusType.VOIP);
|
codecInstance = new OpusWorker(1, OpusType.VOIP);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
res.message = "Could not find worker type!";
|
error = "Could not find worker type!";
|
||||||
console.error("Could not resolve opus type!");
|
console.error("Could not resolve opus type!");
|
||||||
return;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
let error = codecInstance.initialise();
|
error = error || codecInstance.initialise();
|
||||||
if(error)
|
if(error)
|
||||||
res["message"] = error;
|
res["message"] = error;
|
||||||
else
|
else
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"codec/CodecWorker.ts",
|
"codec/CodecWorker.ts",
|
||||||
"codec/OpusCodec.ts"
|
"codec/OpusCodec.ts",
|
||||||
|
"../codec/Codec.ts"
|
||||||
]
|
]
|
||||||
}
|
}
|
|
@ -4,4 +4,8 @@ namespace audio.codec {
|
||||||
export function new_instance(type: CodecType) : BasicCodec {
|
export function new_instance(type: CodecType) : BasicCodec {
|
||||||
return new CodecWrapperWorker(type);
|
return new CodecWrapperWorker(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function supported(type: CodecType) : boolean {
|
||||||
|
return type == CodecType.OPUS_MUSIC || type == CodecType.OPUS_VOICE;
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue