+
+
+
There are no setting entries for an always online voice detection.
+
+
+
Voice activity threshold (
20%)
+
diff --git a/js/main.js b/js/main.js
index 7009fee1..9522b5dd 100644
--- a/js/main.js
+++ b/js/main.js
@@ -6,22 +6,8 @@ let globalClient = new TSClient();
let chat = new ChatBox($("#chat"));
globalClient.setup();
//globalClient.startConnection("localhost:19974"); //TODO remove only for testing
-let modal = 0;
-$("#test").click(function () {
- console.log("Executing test function");
-});
//Modals.spawnConnectModal();
//Modals.spawnSettingsModal();
-/*
-createErrorModal("Could not connect to remote host",() => {
- let tag = $.spawn("div");
- tag.append("A fatal error occurred while connecting to host:port
");
- tag.append("Please reload the page and try again!
");
- return tag;
-}, {
- footer: ""
-}).open();
-*/
window.addEventListener("beforeunload", function (event) {
if (globalClient.serverConnection && globalClient.serverConnection.connected)
event.returnValue = "Are you really sure?
You're still connected!";
diff --git a/js/main.js.map b/js/main.js.map
index 3ddd4c57..2cc86e4e 100644
--- a/js/main.js.map
+++ b/js/main.js.map
@@ -1 +1 @@
-{"version":3,"file":"main.js","sourceRoot":"","sources":["main.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,kCAAkC;AAClC,uCAAuC;AACvC,iDAAiD;AAGjD,IAAI,YAAY,GAAG,IAAI,QAAQ,EAAE,CAAC;AAClC,IAAI,IAAI,GAAG,IAAI,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AACnC,YAAY,CAAC,KAAK,EAAE,CAAC;AACrB,iFAAiF;AAEjF,IAAI,KAAK,GAAG,CAAC,CAAC;AACd,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC;IACb,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;AAC3C,CAAC,CAAC,CAAC;AAEH,6BAA6B;AAC7B,8BAA8B;AAC9B;;;;;;;;;EASE;AAEF,MAAM,CAAC,gBAAgB,CAAC,cAAc,EAAE,UAAU,KAAK;IACnD,EAAE,CAAA,CAAC,YAAY,CAAC,gBAAgB,IAAI,YAAY,CAAC,gBAAgB,CAAC,SAAS,CAAC;QACxE,KAAK,CAAC,WAAW,GAAG,iDAAiD,CAAC;IAC1E,yBAAyB;AAC7B,CAAC,CAAC,CAAC"}
\ No newline at end of file
+{"version":3,"file":"main.js","sourceRoot":"","sources":["main.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,kCAAkC;AAClC,uCAAuC;AACvC,iDAAiD;AAEjD,IAAI,YAAY,GAAG,IAAI,QAAQ,EAAE,CAAC;AAClC,IAAI,IAAI,GAAG,IAAI,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AACnC,YAAY,CAAC,KAAK,EAAE,CAAC;AACrB,iFAAiF;AAEjF,6BAA6B;AAC7B,8BAA8B;AAE9B,MAAM,CAAC,gBAAgB,CAAC,cAAc,EAAE,UAAU,KAAK;IACnD,EAAE,CAAA,CAAC,YAAY,CAAC,gBAAgB,IAAI,YAAY,CAAC,gBAAgB,CAAC,SAAS,CAAC;QACxE,KAAK,CAAC,WAAW,GAAG,iDAAiD,CAAC;IAC1E,yBAAyB;AAC7B,CAAC,CAAC,CAAC"}
\ No newline at end of file
diff --git a/js/main.ts b/js/main.ts
index 33067435..8f77cfc1 100644
--- a/js/main.ts
+++ b/js/main.ts
@@ -3,29 +3,13 @@
///
///
-
let globalClient = new TSClient();
let chat = new ChatBox($("#chat"));
globalClient.setup();
//globalClient.startConnection("localhost:19974"); //TODO remove only for testing
-let modal = 0;
-$("#test").click(function () {
- console.log("Executing test function");
-});
-
//Modals.spawnConnectModal();
//Modals.spawnSettingsModal();
-/*
-createErrorModal("Could not connect to remote host",() => {
- let tag = $.spawn("div");
- tag.append("A fatal error occurred while connecting to host:port
");
- tag.append("Please reload the page and try again!
");
- return tag;
-}, {
- footer: ""
-}).open();
-*/
window.addEventListener("beforeunload", function (event) {
if(globalClient.serverConnection && globalClient.serverConnection.connected)
diff --git a/js/ui/modal/ModalConnect.js b/js/ui/modal/ModalConnect.js
new file mode 100644
index 00000000..c462d631
--- /dev/null
+++ b/js/ui/modal/ModalConnect.js
@@ -0,0 +1,82 @@
+///
+var Modals;
+(function (Modals) {
+ function spawnConnectModal(defaultHost = "ts.TeaSpeak.de") {
+ const connectModal = createModal({
+ header: function () {
+ let header = $.spawn("div");
+ header.text("Create a new connection");
+ return header;
+ },
+ body: function () {
+ let tag = $("#tmpl_connect").contents().clone();
+ let updateFields = function () {
+ let button = tag.parents(".modal-content").find(".connect_connect_button");
+ let field_address = tag.find(".connect_address");
+ let address = field_address.val().toString();
+ let flag_address = !!address.match(Regex.IP_V4) || !!address.match(Regex.DOMAIN);
+ let field_nickname = tag.find(".connect_nickname");
+ let nickname = field_nickname.val().toString();
+ let flag_nickname = nickname.length >= 3 && nickname.length <= 32;
+ if (flag_address) {
+ if (field_address.hasClass("invalid_input"))
+ field_address.removeClass("invalid_input");
+ }
+ else {
+ if (!field_address.hasClass("invalid_input"))
+ field_address.addClass("invalid_input");
+ }
+ if (flag_nickname) {
+ if (field_nickname.hasClass("invalid_input"))
+ field_nickname.removeClass("invalid_input");
+ }
+ else {
+ if (!field_nickname.hasClass("invalid_input"))
+ field_nickname.addClass("invalid_input");
+ }
+ if (!flag_nickname || !flag_address) {
+ button.attr("disabled", "true");
+ }
+ else {
+ button.removeAttr("disabled");
+ }
+ };
+ tag.find(".connect_address").val(defaultHost);
+ tag.find(".connect_address").on("keyup", () => updateFields());
+ tag.find(".connect_nickname").on("keyup", () => updateFields());
+ //connect_address
+ return tag;
+ },
+ footer: function () {
+ let tag = $.spawn("div");
+ tag.css("text-align", "right");
+ tag.css("margin-top", "3px");
+ tag.css("margin-bottom", "6px");
+ tag.addClass("modal-button-group");
+ let button = $.spawn("button");
+ button.addClass("connect_connect_button");
+ button.text("Connect");
+ button.on("click", function () {
+ connectModal.close();
+ let field_address = tag.parents(".modal-content").find(".connect_address");
+ let address = field_address.val().toString();
+ globalClient.startConnection(address);
+ });
+ tag.append(button);
+ return tag;
+ },
+ width: 600,
+ });
+ connectModal.open();
+ }
+ Modals.spawnConnectModal = spawnConnectModal;
+})(Modals || (Modals = {}));
+let Regex = {
+ //DOMAIN<:port>
+ DOMAIN: /^(localhost|((([a-zA-Z0-9_-]{0,63}\.){0,253})?[a-zA-Z0-9_-]{0,63}\.[a-zA-Z]{2,5}))(|:(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|6[0-4][0-9]{3}|[0-5]?[0-9]{1,4}))$/,
+ //IP<:port>
+ IP_V4: /(^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))(|:(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|6[0-4][0-9]{3}|[0-5]?[0-9]{1,4}))$/,
+ IP_V6: /(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))/,
+ IP: /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$|^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$|^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/,
+};
+//# sourceMappingURL=ModalConnect.js.map
\ No newline at end of file
diff --git a/js/ui/modal/ModalConnect.js.map b/js/ui/modal/ModalConnect.js.map
new file mode 100644
index 00000000..0f8c26a5
--- /dev/null
+++ b/js/ui/modal/ModalConnect.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"ModalConnect.js","sourceRoot":"","sources":["ModalConnect.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/js/ui/modal/ModalCreateChannel.js b/js/ui/modal/ModalCreateChannel.js
new file mode 100644
index 00000000..be4b92a2
--- /dev/null
+++ b/js/ui/modal/ModalCreateChannel.js
@@ -0,0 +1,37 @@
+///
+var Modals;
+(function (Modals) {
+ function createChannelModal(channel) {
+ const modal = createModal({
+ header: "Create channel",
+ body: () => {
+ let template = $("#tmpl_channel_edit").tmpl({
+ channel_name: "Hello World",
+ myArray: [
+ "A",
+ "B",
+ "C"
+ ]
+ });
+ template = $.spawn("div").append(template);
+ let tag = template.tabify();
+ return tag;
+ },
+ footer: () => {
+ let footer = $.spawn("div");
+ footer.addClass("modal-button-group");
+ footer.css("margin-top", "5px");
+ let buttonCancel = $.spawn("button");
+ buttonCancel.text("Cancel");
+ let buttonOk = $.spawn("button");
+ buttonOk.text("Ok");
+ footer.append(buttonCancel);
+ footer.append(buttonOk);
+ return footer;
+ },
+ width: 500
+ });
+ }
+ Modals.createChannelModal = createChannelModal;
+})(Modals || (Modals = {}));
+//# sourceMappingURL=ModalCreateChannel.js.map
\ No newline at end of file
diff --git a/js/ui/modal/ModalCreateChannel.js.map b/js/ui/modal/ModalCreateChannel.js.map
new file mode 100644
index 00000000..5afc575a
--- /dev/null
+++ b/js/ui/modal/ModalCreateChannel.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"ModalCreateChannel.js","sourceRoot":"","sources":["ModalCreateChannel.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAE7C,IAAU,MAAM,CAqCf;AArCD,WAAU,MAAM;IACZ,4BAAmC,OAAsB;QACrD,MAAM,KAAK,GAAG,WAAW,CAAC;YACtB,MAAM,EAAE,gBAAgB;YACxB,IAAI,EAAE,GAAG,EAAE;gBACP,IAAI,QAAQ,GAAG,CAAC,CAAC,oBAAoB,CAAC,CAAC,IAAI,CAAC;oBACxC,YAAY,EAAE,aAAa;oBAC3B,OAAO,EAAE;wBACL,GAAG;wBACH,GAAG;wBACH,GAAG;qBACN;iBACJ,CAAC,CAAC;gBACH,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;gBAC3C,IAAI,GAAG,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC;gBAE5B,MAAM,CAAC,GAAG,CAAC;YACf,CAAC;YACD,MAAM,EAAE,GAAG,EAAE;gBACT,IAAI,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;gBAC5B,MAAM,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC;gBACtC,MAAM,CAAC,GAAG,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;gBAEhC,IAAI,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;gBACrC,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBAE5B,IAAI,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;gBACjC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAEpB,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;gBAC5B,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;gBAExB,MAAM,CAAC,MAAM,CAAC;YAClB,CAAC;YACD,KAAK,EAAE,GAAG;SACb,CAAC,CAAC;IACP,CAAC;IAnCe,yBAAkB,qBAmCjC,CAAA;AACL,CAAC,EArCS,MAAM,KAAN,MAAM,QAqCf"}
\ No newline at end of file
diff --git a/js/ui/modal/ModalSettings.js b/js/ui/modal/ModalSettings.js
new file mode 100644
index 00000000..0facc387
--- /dev/null
+++ b/js/ui/modal/ModalSettings.js
@@ -0,0 +1,141 @@
+///
+///
+///
+var Modals;
+(function (Modals) {
+ function spawnSettingsModal() {
+ let modal;
+ modal = createModal({
+ header: "Settings",
+ body: () => {
+ let template = $("#tmpl_settings").tmpl();
+ template = $.spawn("div").append(template);
+ initialiseSettingListeners(modal, template = template.tabify());
+ return template;
+ },
+ footer: () => {
+ let footer = $.spawn("div");
+ footer.addClass("modal-button-group");
+ footer.css("margin-top", "5px");
+ footer.css("margin-bottom", "5px");
+ footer.css("text-align", "right");
+ let buttonOk = $.spawn("button");
+ buttonOk.text("Ok");
+ buttonOk.click(() => modal.close());
+ footer.append(buttonOk);
+ return footer;
+ },
+ width: 750
+ });
+ modal.open();
+ }
+ Modals.spawnSettingsModal = spawnSettingsModal;
+ function initialiseSettingListeners(modal, tag) {
+ //Voice
+ initialiseVoiceListeners(modal, tag.find(".settings_voice"));
+ }
+ function initialiseVoiceListeners(modal, tag) {
+ let currentVAD = globalClient.settings.global("vad_type");
+ tag.find("input[type=radio][name=\"vad_type\"]").change(function () {
+ tag.find(".vad_settings .vad_type").text($(this).attr("display"));
+ tag.find(".vad_settings .vad_type_settings").hide();
+ tag.find(".vad_settings .vad_type_" + this.value).show();
+ globalClient.settings.changeGlobal("vad_type", this.value);
+ globalClient.voiceConnection.voiceRecorder.reinizaliszeVAD();
+ switch (this.value) {
+ case "ppt":
+ let keyCode = Number.parseInt(globalClient.settings.global("vad_ppt_key", 84 /* T */.toString()));
+ tag.find(".vat_ppt_key").text(String.fromCharCode(keyCode));
+ break;
+ case "vad":
+ let slider = tag.find(".vad_vad_slider");
+ let vad = globalClient.voiceConnection.voiceRecorder.getVADHandler();
+ slider.val(vad.percentageThreshold);
+ slider.trigger("change");
+ globalClient.voiceConnection.voiceRecorder.update(true);
+ vad.percentage_listener = per => {
+ tag.find(".vad_vad_bar_filler")
+ .css("width", per + "%");
+ };
+ break;
+ }
+ });
+ if (!currentVAD)
+ currentVAD = "ppt";
+ let elm = tag.find("input[type=radio][name=\"vad_type\"][value=\"" + currentVAD + "\"]");
+ elm.attr("checked", "true");
+ tag.find(".vat_ppt_key").click(function () {
+ let modal = createModal({
+ body: "",
+ header: () => {
+ let head = $.spawn("div");
+ head.text("Type the key you wish");
+ head.css("background-color", "blue");
+ return head;
+ },
+ footer: ""
+ });
+ $(document).one("keypress", function (e) {
+ console.log("Got key " + e.keyCode);
+ modal.close();
+ globalClient.settings.changeGlobal("vad_ppt_key", e.keyCode.toString());
+ globalClient.voiceConnection.voiceRecorder.reinizaliszeVAD();
+ tag.find(".vat_ppt_key").text(String.fromCharCode(e.keyCode));
+ });
+ modal.open();
+ });
+ //VAD VAD
+ let slider = tag.find(".vad_vad_slider");
+ slider.on("input change", () => {
+ globalClient.settings.changeGlobal("vad_threshold", slider.val().toString());
+ let vad = globalClient.voiceConnection.voiceRecorder.getVADHandler();
+ if (vad instanceof VoiceActivityDetectorVAD)
+ vad.percentageThreshold = slider.val();
+ tag.find(".vad_vad_slider_value").text(slider.val().toString());
+ });
+ modal.properties.registerCloseListener(() => {
+ let vad = globalClient.voiceConnection.voiceRecorder.getVADHandler();
+ if (vad instanceof VoiceActivityDetectorVAD)
+ vad.percentage_listener = undefined;
+ });
+ //Trigger radio button select for VAD setting setup
+ elm.trigger("change");
+ //Initialise microphones
+ console.log(tag);
+ let mselect = tag.find(".voice_microphone_select");
+ console.log(mselect);
+ let mselectError = tag.find(".voice_microphone_select_error");
+ navigator.mediaDevices.enumerateDevices().then(devices => {
+ let currentStream = globalClient.voiceConnection.voiceRecorder.getMediaStream();
+ let currentDeviceId;
+ if (currentStream) {
+ let audio = currentStream.getAudioTracks()[0];
+ currentDeviceId = audio.getSettings().deviceId;
+ }
+ console.log("Got " + devices.length + " devices:");
+ for (let device of devices) {
+ console.log(device);
+ if (device.kind == "audioinput") {
+ let dtag = $.spawn("option");
+ dtag.attr("device-id", device.deviceId);
+ dtag.attr("device-group", device.groupId);
+ dtag.text(device.label);
+ mselect.append(dtag);
+ if (currentDeviceId && device.deviceId == currentDeviceId)
+ mselect.attr("selected", "");
+ }
+ }
+ }).catch(error => {
+ console.error("Could not enumerate over devices!");
+ console.error(error);
+ mselectError.text("Could not get device list!").show();
+ });
+ mselect.change(event => {
+ let deviceSelected = mselect.find("option:selected");
+ let deviceId = deviceSelected.attr("device-id");
+ console.log("Selected device: " + deviceId);
+ globalClient.voiceConnection.voiceRecorder.changeDevice(deviceId);
+ });
+ }
+})(Modals || (Modals = {}));
+//# sourceMappingURL=ModalSettings.js.map
\ No newline at end of file
diff --git a/js/ui/modal/ModalSettings.js.map b/js/ui/modal/ModalSettings.js.map
new file mode 100644
index 00000000..c4a9205c
--- /dev/null
+++ b/js/ui/modal/ModalSettings.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"ModalSettings.js","sourceRoot":"","sources":["ModalSettings.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/js/ui/modal/ModalSettings.ts b/js/ui/modal/ModalSettings.ts
index 11554256..1754bc8e 100644
--- a/js/ui/modal/ModalSettings.ts
+++ b/js/ui/modal/ModalSettings.ts
@@ -57,6 +57,7 @@ namespace Modals {
let vad: VoiceActivityDetectorVAD = globalClient.voiceConnection.voiceRecorder.getVADHandler() as VoiceActivityDetectorVAD;
slider.val(vad.percentageThreshold);
slider.trigger("change");
+ globalClient.voiceConnection.voiceRecorder.update(true);
vad.percentage_listener = per => {
tag.find(".vad_vad_bar_filler")
.css("width", per + "%");
@@ -112,5 +113,44 @@ namespace Modals {
//Trigger radio button select for VAD setting setup
elm.trigger("change");
+
+ //Initialise microphones
+ console.log(tag);
+ let mselect = tag.find(".voice_microphone_select");
+ console.log(mselect);
+ let mselectError = tag.find(".voice_microphone_select_error");
+ navigator.mediaDevices.enumerateDevices().then(devices => {
+ let currentStream = globalClient.voiceConnection.voiceRecorder.getMediaStream();
+ let currentDeviceId;
+ if(currentStream) {
+ let audio = currentStream.getAudioTracks()[0];
+ currentDeviceId = audio.getSettings().deviceId;
+ }
+ console.log("Got " + devices.length + " devices:");
+ for(let device of devices) {
+ console.log(device);
+ if(device.kind == "audioinput") {
+ let dtag = $.spawn("option");
+ dtag.attr("device-id", device.deviceId);
+ dtag.attr("device-group", device.groupId);
+ dtag.text(device.label);
+ mselect.append(dtag);
+
+ if(currentDeviceId && device.deviceId == currentDeviceId)
+ mselect.attr("selected", "");
+ }
+ }
+ }).catch(error => {
+ console.error("Could not enumerate over devices!");
+ console.error(error);
+ mselectError.text("Could not get device list!").show();
+ });
+
+ mselect.change(event => {
+ let deviceSelected = mselect.find("option:selected");
+ let deviceId = deviceSelected.attr("device-id");
+ console.log("Selected device: " + deviceId);
+ globalClient.voiceConnection.voiceRecorder.changeDevice(deviceId);
+ });
}
}
\ No newline at end of file
diff --git a/js/voice/AudioController.js b/js/voice/AudioController.js
new file mode 100644
index 00000000..114f2c76
--- /dev/null
+++ b/js/voice/AudioController.js
@@ -0,0 +1,103 @@
+var PlayerState;
+(function (PlayerState) {
+ PlayerState[PlayerState["PREBUFFERING"] = 0] = "PREBUFFERING";
+ PlayerState[PlayerState["PLAYING"] = 1] = "PLAYING";
+ PlayerState[PlayerState["BUFFERING"] = 2] = "BUFFERING";
+ PlayerState[PlayerState["STOPPED"] = 3] = "STOPPED";
+})(PlayerState || (PlayerState = {}));
+class AudioController {
+ constructor() {
+ this.timeIndex = 0;
+ this.playerState = PlayerState.STOPPED;
+ this._playingSources = [];
+ this.allowBuffering = false;
+ this.speakerContext = AudioController.globalContext;
+ this.audioCache = [];
+ this.onSpeaking = function () { };
+ this.onSilence = function () { };
+ }
+ static get globalContext() {
+ if (this._globalContext)
+ return this._globalContext;
+ this._globalContext = new AudioContext();
+ return this._globalContext;
+ }
+ playBuffer(buffer) {
+ if (buffer.sampleRate != this.speakerContext.sampleRate)
+ console.warn("[AudioController] Source sample rate isn't equal to playback sample rate!");
+ this.audioCache.push(buffer);
+ if (this.playerState == PlayerState.STOPPED) {
+ console.log("[Audio] Starting new playback");
+ this.playerState = PlayerState.PREBUFFERING;
+ //New audio
+ }
+ switch (this.playerState) {
+ case PlayerState.PREBUFFERING:
+ case PlayerState.BUFFERING:
+ if (this.audioCache.length < 5) {
+ if (this.playerState == PlayerState.BUFFERING) {
+ if (this.allowBuffering)
+ break;
+ }
+ else
+ break;
+ }
+ if (this.playerState == PlayerState.PREBUFFERING) {
+ console.log("[Audio] Prebuffering succeeded (Replaying now)");
+ this.onSpeaking();
+ }
+ else {
+ if (this.allowBuffering)
+ console.log("[Audio] Buffering succeeded (Replaying now)");
+ }
+ this.timeIndex = 0; //Instant replay
+ this.playerState = PlayerState.PLAYING;
+ case PlayerState.PLAYING:
+ this.playCache(this.audioCache);
+ break;
+ default:
+ break;
+ }
+ }
+ playCache(cache) {
+ while (cache.length) {
+ let buffer = cache.shift();
+ let source = this.speakerContext.createBufferSource();
+ source.buffer = buffer;
+ source.connect(this.speakerContext.destination);
+ source.onended = () => {
+ this._playingSources.remove(source);
+ this.testBufferQueue();
+ };
+ if (this.timeIndex == 0) {
+ this.timeIndex = this.speakerContext.currentTime;
+ console.log("New next time!");
+ }
+ source.start(this.timeIndex);
+ this.timeIndex += source.buffer.duration;
+ this._playingSources.push(source);
+ }
+ }
+ ;
+ stopAudio(now = false) {
+ this.playerState = PlayerState.STOPPED;
+ if (now) {
+ for (let e of this._playingSources)
+ e.stop();
+ this._playingSources = [];
+ }
+ }
+ testBufferQueue() {
+ if (this._playingSources.length == 0) {
+ this.onSilence();
+ if (this.playerState != PlayerState.STOPPED) {
+ this.playerState = PlayerState.BUFFERING;
+ if (!this.allowBuffering)
+ console.warn("[Audi] Detected a buffer underflow!");
+ }
+ }
+ }
+ close() {
+ }
+}
+//# sourceMappingURL=AudioController.js.map
\ No newline at end of file
diff --git a/js/voice/AudioController.js.map b/js/voice/AudioController.js.map
new file mode 100644
index 00000000..0da0ba83
--- /dev/null
+++ b/js/voice/AudioController.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"AudioController.js","sourceRoot":"","sources":["AudioController.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/js/voice/AudioResampler.js b/js/voice/AudioResampler.js
new file mode 100644
index 00000000..22ddf2fc
--- /dev/null
+++ b/js/voice/AudioResampler.js
@@ -0,0 +1,17 @@
+class AudioResampler {
+ constructor(targetSampleRate = 44100) {
+ this.targetSampleRate = targetSampleRate;
+ }
+ resample(buffer) {
+ if (buffer.sampleRate == this.targetSampleRate)
+ return new Promise(resolve => resolve(buffer));
+ let context;
+ context = new OfflineAudioContext(1, Math.ceil(buffer.length * this.targetSampleRate / buffer.sampleRate), this.targetSampleRate);
+ let source = context.createBufferSource();
+ source.buffer = buffer;
+ source.connect(context.destination);
+ source.start(0);
+ return context.startRendering();
+ }
+}
+//# sourceMappingURL=AudioResampler.js.map
\ No newline at end of file
diff --git a/js/voice/AudioResampler.js.map b/js/voice/AudioResampler.js.map
new file mode 100644
index 00000000..9b2111bf
--- /dev/null
+++ b/js/voice/AudioResampler.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"AudioResampler.js","sourceRoot":"","sources":["AudioResampler.ts"],"names":[],"mappings":"AAAA;IAGI,YAAY,mBAA2B,KAAK;QACxC,IAAI,CAAC,gBAAgB,GAAG,gBAAgB,CAAC;IAC7C,CAAC;IAED,QAAQ,CAAC,MAAmB;QACxB,EAAE,CAAA,CAAC,MAAM,CAAC,UAAU,IAAI,IAAI,CAAC,gBAAgB,CAAC;YAC1C,MAAM,CAAC,IAAI,OAAO,CAAc,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;QAEhE,IAAI,OAAO,CAAC;QACZ,OAAO,GAAG,IAAI,mBAAmB,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,gBAAgB,GAAG,MAAM,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC,gBAAgB,CAAC,CAAC;QAElI,IAAI,MAAM,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC;QAC1C,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;QACvB,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QACpC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAEhB,MAAM,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC;IACpC,CAAC;CACJ"}
\ No newline at end of file
diff --git a/js/voice/VoiceRecorder.js b/js/voice/VoiceRecorder.js
new file mode 100644
index 00000000..68027dec
--- /dev/null
+++ b/js/voice/VoiceRecorder.js
@@ -0,0 +1,249 @@
+///
+///
+class VoiceActivityDetector {
+ initialise() { }
+ finalize() { }
+ initialiseNewStream(old, _new) { }
+ changeHandle(handle, triggerNewStream) {
+ const oldStream = !this.handle ? undefined : this.handle.getMicrophoneStream();
+ this.handle = handle;
+ if (triggerNewStream)
+ this.initialiseNewStream(oldStream, !handle ? undefined : handle.getMicrophoneStream());
+ }
+}
+class VoiceRecorder {
+ constructor(handle) {
+ this.on_data = (data) => { };
+ this.on_end = () => { };
+ this._recording = false;
+ this.microphoneStream = undefined;
+ this.mediaStream = undefined;
+ this._chunkCount = 0;
+ this._deviceId = "default";
+ this.handle = handle;
+ this.userMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
+ this.audioContext = AudioController.globalContext;
+ this.processor = this.audioContext.createScriptProcessor(VoiceRecorder.BUFFER_SIZE, VoiceRecorder.CHANNELS, VoiceRecorder.CHANNELS);
+ const _this = this;
+ this.processor.addEventListener('audioprocess', ev => {
+ if (_this.microphoneStream && this.vadHandler.shouldRecord(ev.inputBuffer))
+ this.on_data(ev.inputBuffer, this._chunkCount++ == 0);
+ else {
+ if (this._chunkCount != 0)
+ this.on_end();
+ this._chunkCount = 0;
+ }
+ });
+ //Not needed but make sure we have data for the preprocessor
+ this.mute = this.audioContext.createGain();
+ this.mute.gain.setValueAtTime(0, 0);
+ this.processor.connect(this.mute);
+ this.mute.connect(this.audioContext.destination);
+ //this.setVADHander(new MuteVAD());
+ this.setVADHander(new PassThroughVAD());
+ }
+ avariable() {
+ return !!this.userMedia;
+ }
+ recording() {
+ return this._recording;
+ }
+ getMediaStream() {
+ return this.mediaStream;
+ }
+ getDestinationContext() {
+ return this.mute;
+ }
+ getMicrophoneStream() {
+ return this.microphoneStream;
+ }
+ reinizaliszeVAD() {
+ let type = this.handle.client.settings.global("vad_type", "ppt");
+ if (type == "ppt") {
+ let keyCode = Number.parseInt(globalClient.settings.global("vad_ppt_key", 84 /* T */.toString()));
+ if (!(this.getVADHandler() instanceof PushToTalkVAD))
+ this.setVADHander(new PushToTalkVAD(keyCode));
+ else
+ this.getVADHandler().key = keyCode;
+ }
+ else if (type == "pt") {
+ if (!(this.getVADHandler() instanceof PassThroughVAD))
+ this.setVADHander(new PassThroughVAD());
+ }
+ else if (type == "vad") {
+ if (!(this.getVADHandler() instanceof VoiceActivityDetectorVAD))
+ this.setVADHander(new VoiceActivityDetectorVAD());
+ let threshold = Number.parseInt(globalClient.settings.global("vad_threshold", "50"));
+ this.getVADHandler().percentageThreshold = threshold;
+ }
+ else {
+ console.warn("Invalid VAD handler! (" + type + ")");
+ }
+ }
+ setVADHander(handler) {
+ if (this.vadHandler) {
+ this.vadHandler.changeHandle(null, true);
+ this.vadHandler.finalize();
+ }
+ this.vadHandler = handler;
+ this.vadHandler.changeHandle(this, false);
+ this.vadHandler.initialise();
+ this.vadHandler.initialiseNewStream(undefined, this.microphoneStream);
+ }
+ getVADHandler() {
+ return this.vadHandler;
+ }
+ update(flag) {
+ if (this._recording == flag)
+ return;
+ if (flag)
+ this.start(this._deviceId);
+ else
+ this.stop();
+ }
+ changeDevice(device) {
+ if (this._deviceId == device)
+ return;
+ this._deviceId = device;
+ if (this._recording) {
+ this.stop();
+ this.start(device);
+ }
+ }
+ start(device) {
+ this._deviceId = device;
+ console.log("Attempt recording!");
+ this._recording = true;
+ this.userMedia({
+ audio: true,
+ deviceId: device
+ }, this.on_microphone.bind(this), error => {
+ createErrorModal("Could not resolve microphone!", "Could not resolve microphone!
Message: " + error).open();
+ console.error("Could not get microphone!");
+ console.error(error);
+ });
+ }
+ stop() {
+ console.log("Stop recording!");
+ this._recording = false;
+ if (this.microphoneStream)
+ this.microphoneStream.disconnect();
+ this.microphoneStream = undefined;
+ if (this.mediaStream) {
+ if (this.mediaStream.stop)
+ this.mediaStream.stop();
+ else
+ this.mediaStream.getTracks().forEach(value => {
+ value.stop();
+ });
+ }
+ this.mediaStream = undefined;
+ }
+ on_microphone(stream) {
+ if (this.microphoneStream) {
+ this.stop(); //Disconnect old stream
+ }
+ console.log("Start recording!");
+ this.mediaStream = stream;
+ const oldStream = this.microphoneStream;
+ this.microphoneStream = this.audioContext.createMediaStreamSource(stream);
+ this.microphoneStream.connect(this.processor);
+ this.vadHandler.initialiseNewStream(oldStream, this.microphoneStream);
+ }
+}
+VoiceRecorder.CHANNEL = 0;
+VoiceRecorder.CHANNELS = 1;
+VoiceRecorder.BUFFER_SIZE = 1024;
+class MuteVAD extends VoiceActivityDetector {
+ shouldRecord(buffer) {
+ return false;
+ }
+}
+class PassThroughVAD extends VoiceActivityDetector {
+ shouldRecord(buffer) {
+ return true;
+ }
+}
+class VoiceActivityDetectorVAD extends VoiceActivityDetector {
+ constructor() {
+ super(...arguments);
+ this.continuesCount = 0;
+ this.maxContinuesCount = 12;
+ this.percentageThreshold = 50;
+ this.percentage_listener = ($) => { };
+ }
+ initialise() {
+ this.analyzer = AudioController.globalContext.createAnalyser();
+ this.analyzer.smoothingTimeConstant = 1; //TODO test
+ this.buffer = new Uint8Array(this.analyzer.fftSize);
+ return super.initialise();
+ }
+ initialiseNewStream(old, _new) {
+ if (this.analyzer)
+ this.analyzer.disconnect();
+ if (_new)
+ _new.connect(this.analyzer);
+ }
+ shouldRecord(buffer) {
+ let usage = this.calculateUsage();
+ if ($.isFunction(this.percentage_listener))
+ this.percentage_listener(usage);
+ if (usage >= this.percentageThreshold) {
+ this.continuesCount = 0;
+ }
+ else
+ this.continuesCount++;
+ return this.continuesCount < this.maxContinuesCount;
+ }
+ calculateUsage() {
+ let total = 0, float, rms;
+ this.analyzer.getByteTimeDomainData(this.buffer);
+ for (let index = 0; index < this.analyzer.fftSize; index++) {
+ float = (this.buffer[index++] / 0x7f) - 1;
+ total += (float * float);
+ }
+ rms = Math.sqrt(total / this.analyzer.fftSize);
+ let db = 20 * (Math.log(rms) / Math.log(10));
+ // sanity check
+ db = Math.max(-192, Math.min(db, 0));
+ let percentage = 100 + (db * 1.92);
+ return percentage;
+ }
+}
+class PushToTalkVAD extends VoiceActivityDetector {
+ constructor(key) {
+ super();
+ this._pushed = false;
+ this._evListenerDown = (e) => {
+ //console.log("Down -> " + e.key + " -> " + e.keyCode);
+ if (e.key == String.fromCharCode(this._key))
+ this.pushed = true;
+ };
+ this._evListenerUp = e => {
+ if (e.key == String.fromCharCode(this._key))
+ this.pushed = false;
+ };
+ this._key = key;
+ }
+ initialise() {
+ document.addEventListener("keydown", this._evListenerDown);
+ document.addEventListener("keyup", this._evListenerUp);
+ return super.initialise();
+ }
+ finalize() {
+ document.removeEventListener("keydown", this._evListenerDown);
+ document.removeEventListener("keyup", this._evListenerUp);
+ return super.finalize();
+ }
+ set pushed(flag) {
+ this._pushed = flag;
+ }
+ set key(key) {
+ this._key = key;
+ this._pushed = false;
+ }
+ shouldRecord(buffer) {
+ return this._pushed;
+ }
+}
+//# sourceMappingURL=VoiceRecorder.js.map
\ No newline at end of file
diff --git a/js/voice/VoiceRecorder.js.map b/js/voice/VoiceRecorder.js.map
new file mode 100644
index 00000000..4bb50d66
--- /dev/null
+++ b/js/voice/VoiceRecorder.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"VoiceRecorder.js","sourceRoot":"","sources":["VoiceRecorder.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/js/voice/VoiceRecorder.ts b/js/voice/VoiceRecorder.ts
index 74312440..cd0ad216 100644
--- a/js/voice/VoiceRecorder.ts
+++ b/js/voice/VoiceRecorder.ts
@@ -39,6 +39,8 @@ class VoiceRecorder {
private vadHandler: VoiceActivityDetector;
private _chunkCount: number = 0;
+ private _deviceId: string = "default";
+
constructor(handle: VoiceConnection) {
this.handle = handle;
this.userMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
@@ -71,6 +73,10 @@ class VoiceRecorder {
return !!this.userMedia;
}
+ recording() : boolean {
+ return this._recording;
+ }
+
getMediaStream() : MediaStream {
return this.mediaStream;
}
@@ -120,14 +126,27 @@ class VoiceRecorder {
update(flag: boolean) {
if(this._recording == flag) return;
- if(flag) this.start();
+ if(flag) this.start(this._deviceId);
else this.stop();
}
- start(){
+ changeDevice(device: string) {
+ if(this._deviceId == device) return;
+ this._deviceId = device;
+ if(this._recording) {
+ this.stop();
+ this.start(device);
+ }
+ }
+
+ start(device: string){
+ this._deviceId = device;
console.log("Attempt recording!");
this._recording = true;
- this.userMedia({audio: true}, this.on_microphone.bind(this), error => {
+ this.userMedia({
+ audio: true,
+ deviceId: device
+ }, this.on_microphone.bind(this), error => {
createErrorModal("Could not resolve microphone!", "Could not resolve microphone!
Message: " + error).open();
console.error("Could not get microphone!");
console.error(error);