diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md
index e4d2e5c3..6e82d63d 100644
--- a/ISSUE_TEMPLATE.md
+++ b/ISSUE_TEMPLATE.md
@@ -14,4 +14,4 @@
-*Delete me: If you dont follow this issue template, you may not get a response or the issue get instandly closed.*
+*Delete me: If you dont follow this issue template, you may not get a response or the issue get instantly closed.*
diff --git a/asm/CMakeLists.txt b/asm/CMakeLists.txt
index a094529b..3b4154cf 100644
--- a/asm/CMakeLists.txt
+++ b/asm/CMakeLists.txt
@@ -9,7 +9,7 @@ set(CMAKE_C_LINK_EXECUTABLE "emcc")
set(CMAKE_CXX_FLAGS "-O2 --llvm-lto 1 --memory-init-file 0 -s WASM=1") #-s ASSERTIONS=2 -s ALLOW_MEMORY_GROWTH=1 -O3
set(CMAKE_VERBOSE_MAKEFILE ON)
set(CMAKE_EXE_LINKER_FLAGS "-s EXTRA_EXPORTED_RUNTIME_METHODS='[\"ccall\", \"cwrap\", \"Pointer_stringify\"]'") #
-add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0)
+#add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/generated/")
include_directories(libraries/tommath/)
@@ -17,6 +17,7 @@ include_directories(libraries/tomcrypt/src/headers)
include_directories(libraries/opus/include/)
add_definitions(-DLTM_DESC)
+#cmake .. -DCMAKE_CXX_COMPILER="emcc" -DCMAKE_C_COMPILER="emcc" -DCMAKE_C_LINK_EXECUTABLE="emcc"
add_executable(TeaWeb-Identity.js identity/Identity.cpp identity/TeamSpeakIdentity.cpp)
target_link_libraries(TeaWeb-Identity.js ${CMAKE_CURRENT_SOURCE_DIR}/libraries/tomcrypt/libtomcrypt.a ${CMAKE_CURRENT_SOURCE_DIR}/libraries/tommath/build/libtommathStatic.a)
diff --git a/asm/libraries/opus b/asm/libraries/opus
index 655cc54c..b97dd67f 160000
--- a/asm/libraries/opus
+++ b/asm/libraries/opus
@@ -1 +1 @@
-Subproject commit 655cc54c564b84ef2827f0b2152ce3811046201e
+Subproject commit b97dd67fdc75a39d0fc99ceee573921ba3e73b1f
diff --git a/asm/libraries/tomcrypt b/asm/libraries/tomcrypt
index 0f7fd3c6..5f0bdabf 160000
--- a/asm/libraries/tomcrypt
+++ b/asm/libraries/tomcrypt
@@ -1 +1 @@
-Subproject commit 0f7fd3c606c204cf13b39ca35722782d3d05e319
+Subproject commit 5f0bdabfc023376fed3640391f1a9228a4449fb0
diff --git a/index.php b/index.php
index 2b6d1717..14d9b749 100644
--- a/index.php
+++ b/index.php
@@ -69,6 +69,9 @@
gtag('js', new Date());
gtag('config', 'UA-113151733-4');
+
+
+
@@ -175,10 +178,6 @@
-
-
-
-
diff --git a/js/ui/frames/ControlBar.ts b/js/ui/frames/ControlBar.ts
index e9bc3ec7..0c724278 100644
--- a/js/ui/frames/ControlBar.ts
+++ b/js/ui/frames/ControlBar.ts
@@ -150,14 +150,14 @@ class ControlBar {
if(!targetChannel)
targetChannel = this.handle.getClient().currentChannel();
let voiceSupport = this.handle.voiceConnection.codecSupported(targetChannel.properties.channel_codec);
- if(voiceSupport == !this._codecNotSupported) return;
this._codecNotSupported = !voiceSupport;
- this.htmlTag.find(".btn_mute_input").prop("disabled", !this._codecNotSupported);
- this.htmlTag.find(".btn_mute_output").prop("disabled", !this._codecNotSupported);
+ let voice_support = this.handle.voiceConnection.voiceSupported();
+ this.htmlTag.find(".btn_mute_input").prop("disabled", !this._codecNotSupported && voice_support);
+ this.htmlTag.find(".btn_mute_output").prop("disabled", !this._codecNotSupported && voice_support);
this.handle.serverConnection.sendCommand("clientupdate", {
- client_input_hardware: this._codecNotSupported,
- client_output_hardware: this._codecNotSupported
+ client_input_hardware: this._codecNotSupported && voice_support,
+ client_output_hardware: this._codecNotSupported && voice_support
});
if(this._codecNotSupported)
diff --git a/js/voice/VoiceHandler.ts b/js/voice/VoiceHandler.ts
index 569f4a4b..2b79831e 100644
--- a/js/voice/VoiceHandler.ts
+++ b/js/voice/VoiceHandler.ts
@@ -108,7 +108,7 @@ class VoiceConnection {
voiceRecorder: VoiceRecorder;
- private codecPool: CodecPool[] = [
+ private codec_pool: CodecPool[] = [
new CodecPool(this,0,"Spex A", undefined), //Spex
new CodecPool(this,1,"Spex B", undefined), //Spex
new CodecPool(this,2,"Spex C", undefined), //Spex
@@ -129,15 +129,19 @@ class VoiceConnection {
this.voiceRecorder.reinitialiseVAD();
AudioController.on_initialized(() => {
- this.codecPool[4].initialize(2);
- this.codecPool[5].initialize(2);
+ this.codec_pool[4].initialize(2);
+ this.codec_pool[5].initialize(2);
});
this.send_task = setInterval(this.sendNextVoicePacket.bind(this), 20);
}
codecSupported(type: number) : boolean {
- return this.codecPool.length > type && this.codecPool[type].supported();
+ return this.codec_pool.length > type && this.codec_pool[type].supported();
+ }
+
+ voiceSupported() : boolean {
+ return this.dataChannel && this.dataChannel.readyState == "open";
}
private voice_send_queue: {data: Uint8Array, codec: number}[] = [];
@@ -174,14 +178,18 @@ class VoiceConnection {
createSession() {
- const config = { /*iceServers: [{ url: 'stun:stun.l.google.com:19302' }]*/ };
+ this._ice_use_cache = true;
+
+ let config: RTCConfiguration = {};
+ config.iceServers = [];
+ config.iceServers.push({ urls: 'stun:stun.l.google.com:19302' });
this.rtcPeerConnection = new RTCPeerConnection(config);
const dataChannelConfig = { ordered: false, maxRetransmits: 0 };
this.dataChannel = this.rtcPeerConnection.createDataChannel('main', dataChannelConfig);
this.dataChannel.onmessage = this.onDataChannelMessage.bind(this);
this.dataChannel.onopen = this.onDataChannelOpen.bind(this);
- //this.dataChannel.binaryType = "arraybuffer";
+ this.dataChannel.binaryType = "arraybuffer";
let sdpConstraints : RTCOfferOptions = {};
sdpConstraints.offerToReceiveAudio = 0;
@@ -199,13 +207,33 @@ class VoiceConnection {
//TODO here!
}
+ _ice_use_cache: boolean = true;
+ _ice_cache: any[] = [];
handleControlPacket(json) {
if(json["request"] === "answer") {
console.log("Set remote sdp! (%o)", json["msg"]);
this.rtcPeerConnection.setRemoteDescription(new RTCSessionDescription(json["msg"]));
+ this._ice_use_cache = false;
+ for(let msg of this._ice_cache) {
+ this.rtcPeerConnection.addIceCandidate(new RTCIceCandidate(msg));
+ }
} else if(json["request"] === "ice") {
- console.log("Add remote ice! (%s)", json["candidate"]);
- this.rtcPeerConnection.addIceCandidate(new RTCIceCandidate({candidate: json["candidate"],sdpMid: json["session"], sdpMLineIndex: json["line"]}));
+ if(!this._ice_use_cache) {
+ console.log("Add remote ice! (%s | %o)", json["msg"], json);
+ this.rtcPeerConnection.addIceCandidate(new RTCIceCandidate(json["msg"]));
+ } else {
+ console.log("Cache remote ice! (%s | %o)", json["msg"], json);
+ this._ice_cache.push(json["msg"]);
+ }
+ } else if(json["request"] == "status") {
+ if(json["state"] == "failed") {
+ chat.serverChat().appendError("Failed to setup voice bridge ({}). Allow reconnect: {}", json["reason"], json["allow_reconnect"]);
+ log.error(LogCategory.NETWORKING, "Failed to setup voice bridge (%s). Allow reconnect: %s", json["reason"], json["allow_reconnect"]);
+ if(json["allow_reconnect"] == true) {
+ this.createSession();
+ }
+ //TODO handle fail specially when its not allowed to reconnect
+ }
}
}
@@ -227,15 +255,15 @@ class VoiceConnection {
this.rtcPeerConnection.setLocalDescription(localSession);
console.log("Send offer: %o", localSession);
- this.client.serverConnection.sendData(JSON.stringify({type: 'WebRTC', request: "create", session: localSession}));
+ this.client.serverConnection.sendData(JSON.stringify({type: 'WebRTC', request: "create", msg: localSession}));
}
onDataChannelOpen(channel) {
- console.log("Got new data channel!");
+ console.log("Got new data channel! (%s)", this.dataChannel.readyState);
+ this.client.controlBar.updateVoice();
}
onDataChannelMessage(message) {
- console.log("Got message! %o", message);
if(this.client.controlBar.muteOutput) return;
let bin = new Uint8Array(message.data);
@@ -249,7 +277,7 @@ class VoiceConnection {
return;
}
- let codecPool = this.codecPool[codec];
+ let codecPool = this.codec_pool[codec];
if(!codecPool) {
console.error("Could not playback codec " + codec);
return;
@@ -267,8 +295,8 @@ class VoiceConnection {
codecPool.ownCodec(clientId)
.then(decoder => decoder.decodeSamples(client.getAudioController().codecCache(codec), encodedData))
.then(buffer => client.getAudioController().playBuffer(buffer)).catch(error => {
- console.error("Could not playback client's (" + clientId + ") audio (" + error + ")");
- });
+ console.error("Could not playback client's (" + clientId + ") audio (" + error + ")");
+ });
}
}
@@ -283,7 +311,7 @@ class VoiceConnection {
}
//TODO Use channel codec!
- this.codecPool[4].ownCodec(this.client.getClientId())
+ this.codec_pool[4].ownCodec(this.client.getClientId())
.then(encoder => encoder.encodeSamples(this.client.getClient().getAudioController().codecCache(4), data));
}
diff --git a/js/voice/VoiceRecorder.ts b/js/voice/VoiceRecorder.ts
index 41ffa8e7..2da7a2fc 100644
--- a/js/voice/VoiceRecorder.ts
+++ b/js/voice/VoiceRecorder.ts
@@ -1,8 +1,6 @@
///
///
-import group = log.group;
-
abstract class VoiceActivityDetector {
protected handle: VoiceRecorder;
@@ -167,13 +165,10 @@ class VoiceRecorder {
this._recording = true;
console.log("Function: %o", AudioController.userMedia);
let result = AudioController.userMedia({
- /*
audio: {
- deviceId: device
- //groupId: groupId
+ deviceId: device,
+ groupId: groupId
}
- */
- audio: true
}, this.on_microphone.bind(this), error => {
createErrorModal("Could not resolve microphone!", "Could not resolve microphone!
Message: " + error).open();
console.error("Could not get microphone!");
diff --git a/tsconfig/tsconfig_base.json b/tsconfig/tsconfig_base.json
index de7b9dfa..72e10888 100644
--- a/tsconfig/tsconfig_base.json
+++ b/tsconfig/tsconfig_base.json
@@ -1,7 +1,7 @@
{
"compilerOptions": {
"module": "none",
- "target": "es6",
+ "target": "es5",
"sourceMap": true
},
"exclude": [