diff --git a/.babelrc b/.babelrc deleted file mode 100644 index 3c861b6..0000000 --- a/.babelrc +++ /dev/null @@ -1,4 +0,0 @@ -{ - "presets": ["@babel/preset-env"], - "plugins": ["transform-class-properties"] -} diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 0000000..4a54179 --- /dev/null +++ b/babel.config.js @@ -0,0 +1,16 @@ +module.exports = function(api) { + api.cache(true); + return { + presets: ['@babel/preset-env'], + plugins: [ + [ + '@babel/plugin-proposal-class-properties', + { + loose: true + } + ], + '@babel/plugin-external-helpers', + '@babel/plugin-transform-runtime' + ] + }; +}; diff --git a/dist/zeroth.amd.js b/dist/zeroth.amd.js deleted file mode 100644 index b7bfab0..0000000 --- a/dist/zeroth.amd.js +++ /dev/null @@ -1 +0,0 @@ -define("Zeroth",[],function(){return function(e){var n={};function t(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}return t.m=e,t.c=n,t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:r})},t.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.t=function(e,n){if(1&n&&(e=t(e)),8&n)return e;if(4&n&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(t.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var o in e)t.d(r,o,function(n){return e[n]}.bind(null,o));return r},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},t.p="",t(t.s=3)}([function(e,n,t){"use strict";n.a={wsServerAddr:"13.125.232.133",wsServerPort:3180,wssServerAddr:"zeroth-test.goodatlas.com",wssServerPort:2087,sampleRate:44100,defaultParams:{language:"eng",finalOnly:!1,ws:!1}}},function(e,n,t){function r(e){var n={};function t(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=e,t.c=n,t.i=function(e){return e},t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.r=function(e){Object.defineProperty(e,"__esModule",{value:!0})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},t.p="/",t.oe=function(e){throw console.error(e),e};var r=t(t.s=ENTRY_MODULE);return r.default||r}var o="[\\.|\\-|\\+|\\w|/|@]+",a="\\((/\\*.*?\\*/)?s?.*?("+o+").*?\\)";function i(e){return(e+"").replace(/[.?*+^$[\]\\(){}|-]/g,"\\$&")}function c(e){return!isNaN(1*e)}function s(e,n,r){var s={};s[r]=[];var u=n.toString(),f=u.match(/^function\s?\(\w+,\s*\w+,\s*(\w+)\)/);if(!f)return s;for(var l,d=f[1],p=new RegExp("(\\\\n|\\W)"+i(d)+a,"g");l=p.exec(u);)"dll-reference"!==l[3]&&s[r].push(l[3]);for(p=new RegExp("\\("+i(d)+'\\("(dll-reference\\s('+o+'))"\\)\\)'+a,"g");l=p.exec(u);)e[l[2]]||(s[r].push(l[1]),e[l[2]]=t(l[1]).m),s[l[2]]=s[l[2]]||[],s[l[2]].push(l[4]);for(var m=Object.keys(s),y=0;y0},!1)}e.exports=function(e,n){n=n||{};var o={main:t.m},a=n.all?{main:Object.keys(o.main)}:function(e,n){for(var t={main:[n]},r={main:[]},o={main:{}};u(t);)for(var a=Object.keys(t),i=0;i */ +var win = window, BlobBuilder = win.BlobBuilder || win.WebKitBlobBuilder || win.MozBlobBuilder || win.MSBlobBuilder, URL = win.URL || win.webkitURL || win.mozURL || win.msURL, SCRIPT_TYPE = "application/javascript", TARGET = "undefined" == typeof Symbol ? "__t" + +new Date() : Symbol(), Worker = win.Worker, nextTick = win.setImmediate || function(e) { + return setTimeout(e, 1); +}; + +function workerCtor(e, t) { + return function r(n) { + var o = this; + if (!(o instanceof r)) return new r(n); + if (!t) return new Worker(e); + if (Worker && !n) { + var i = createSourceObject(';(function(f){f&&new(f.default?f["default"]:f)(self)}((' + t.toString() + ")()))"), a = new Worker(i); + return URL.revokeObjectURL(i), o[TARGET] = a; + } + var c = new WorkerEmitter({ + close: function() { + this.destroy(); + } + }, o); + Object.assign(new WorkerEmitter(o, c), { + isThisThread: !0, + terminate: function() { + c.close(), this.destroy(); + } + }), t().call(c, c); + }; +} + +function WorkerEmitter(e, t) { + var r = Object.create(null); + return e.onmessage = null, e.addEventListener = function(e, t) { + var n = r[e] || (r[e] = []); + ~n.indexOf(t) || n.push(t); + }, e.removeEventListener = function(e, t) { + var n, o = r[e]; + o && -1 !== (n = o.indexOf(t)) && (o.splice(n, 1), o.length || delete r[e]); + }, e.postMessage = function(r) { + nextTick(function() { + var n = r; + if (t.onmessage) try { + t.onmessage({ + data: n, + target: e + }); + } catch (e) { + console.error(e); + } + t.emit("message", { + type: "message", + data: n, + target: e, + timeStamp: +new Date() + }); + }); + }, e.emit = function(t, n) { + var o = r[t]; + o && o.forEach(function(t, r) { + return t.call(e, n); + }); + }, e.destroy = function() { + Object.keys(r).forEach(function(e) { + var t = r[e]; + t && (t.length = 0, delete r[e]); + }), r = null; + }, e; +} + +if (Worker) { + var testWorker, objURL = createSourceObject("self.onmessage = function () {}"), testArray = new Uint8Array(1); + try { + if (/(?:Trident|Edge)\/(?:[567]|12)/i.test(navigator.userAgent)) throw new Error("Not available"); + (testWorker = new Worker(objURL)).postMessage(testArray, [ testArray.buffer ]); + } catch (e) { + Worker = null; + } finally { + URL.revokeObjectURL(objURL), testWorker && testWorker.terminate(); + } +} + +function createSourceObject(e) { + var t = SCRIPT_TYPE; + try { + return URL.createObjectURL(new Blob([ e ], { + type: t + })); + } catch (n) { + var r = new BlobBuilder(); + return r.append(e), URL.createObjectURL(r.getBlob(t)); + } +} + +var Worker$1 = workerCtor('worker#./base.worker.js', function () { + return function (e, r) { + return e(r = { + exports: {} + }, r.exports), r.exports; + }(function (module, exports) { + var sock = null; + var config = { + wsServerAddr: '13.125.232.133', + wsServerPort: 3180, + wssServerAddr: 'zeroth-test.goodatlas.com', + wssServerPort: 2087, + sampleRate: 44100, + defaultParams: { + language: 'eng', + finalOnly: false, + ws: false + } + }; + + module.exports = function (self) { + self.onmessage = function (e) { + switch (e.data.command) { + case 'init': + sock = new Socket(e.data.params); + break; + + case 'disconnect': + sock.disconnect(); + break; + + case 'send': + sock.send(e.data.data); + break; + } + }; + }; + + function _classCallCheck$$1(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError('Cannot call a class as a function'); + } + } + + var Socket = function Socket(params) { + _classCallCheck$$1(this, Socket); + + _initialiseProps.call(this); + + if (!params || !params.key) { + postMessage({ + command: 'onerror', + error: 'API key missing' + }); + return; + } + + if (params.debug) { + debug = function debug() { + var _console; + + for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + + return (_console = console).log.apply(_console, ['[zerothjs:debug]'].concat(args)); + }; + } + + var _config$defaultParams = config.defaultParams, + language = _config$defaultParams.language, + finalOnly = _config$defaultParams.finalOnly, + ws = _config$defaultParams.ws; + this.params = { + key: params.key, + language: params.language || language, + finalOnly: params.finalOnly || finalOnly, + ws: params.ws || ws + }; + this.ws = null; + this.connect(); + }; + + var _initialiseProps = function _initialiseProps() { + var _this = this; + + this.connect = function () { + var _config = config, + wsServerAddr = _config.wsServerAddr, + wsServerPort = _config.wsServerPort, + wssServerAddr = _config.wssServerAddr, + wssServerPort = _config.wssServerPort, + sampleRate = _config.sampleRate; + var _params = _this.params, + key = _params.key, + language = _params.language, + finalOnly = _params.finalOnly, + ws = _params.ws; + var contentType = 'audio/x-raw,+layout=(string)interleaved,+rate=(int)' + sampleRate + ',+format=(string)S16LE,+channels=(int)1'; + var query = 'content-type=' + contentType + '&key=' + key + '&language=' + language + '&final-only=' + finalOnly; + var uri = ws ? 'ws://' + wsServerAddr + ':' + wsServerPort + '/client/ws/speech?' + query : 'wss://' + wssServerAddr + ':' + wssServerPort + '/client/ws/speech?' + query; + debug('uri', uri); + _this.ws = new WebSocket(uri); + + _this.ws.onopen = function () { + postMessage({ + command: 'onconnect' + }); + }; + + _this.ws.onerror = function (e) { + // TODO handle error codes + debug('websocket error', e.code, e.reason, e.message); + postMessage({ + command: 'onerror', + error: e.message + }); + }; + + _this.ws.onclose = function (e) { + debug('websocket closed', e.code, e.reason, e.message); + _this.ws = null; + postMessage({ + command: 'ondisconnect' + }); + }; + + _this.ws.onmessage = function (e) { + // debug('received data', e.data); + postMessage({ + command: 'ondata', + data: JSON.parse(e.data) + }); + }; + }; + + this.send = function (data) { + if (!_this.ws) return; + + try { + _this.ws.send(data); + } catch (e) { + debug('websocket send data error', e.code, e.reason, e.message); + postMessage({ + command: 'onerror', + error: e.message + }); + + _this.ws.close(); + } + }; + + this.disconnect = function () { + _this.send('EOS'); + }; + }; + }); +}); + +var worker = null; + +var ZerothBase = function ZerothBase(params) { + var _this = this; + + _classCallCheck(this, ZerothBase); + + this.init = function () { + worker = new Worker$1(); + worker.postMessage({ + command: 'init', + params: _this.params + }); + + worker.onmessage = function (e) { + switch (e.data.command) { + case 'onerror': + _this.onerror(e.data.error); + + break; + + case 'onconnect': + _this.onconnect(); + + _this.onready(); + + break; + + case 'ondisconnect': + _this.ondisconnect(); + + worker.terminate(); + break; + + case 'ondata': + _this.ondata(e.data.data); + + break; + } + }; + }; + + this.send = function (data) { + worker.postMessage({ + command: 'send', + data: data + }); + }; + + this.disconnect = function () { + worker.postMessage({ + command: 'disconnect' + }); + }; + + var noop = function noop() {}; + + this.onconnect = this.onconnect || noop; + this.onready = this.onready || noop; + this.ondisconnect = this.ondisconnect || noop; + this.ondata = this.ondata || noop; + this.onerror = this.onerror || noop; + this.params = params; +}; + +var CrossAudioContext = window.AudioContext || window.webkitAudioContext; // export const resample = (audioBuffer, targetSampleRate, onComplete) => { +// const channels = audioBuffer.numberOfChannels; +// const samples = audioBuffer.length * targetSampleRate / audioBuffer.sampleRate; +// const offlineContext = new CrossOfflineAudioContext(channels, samples, targetSampleRate); +// const bufferSource = offlineContext.createBufferSource(); +// bufferSource.buffer = audioBuffer; +// bufferSource.connect(offlineContext.destination); +// bufferSource.start(0); +// offlineContext.oncomplete = e => onComplete(e.renderedBuffer); +// offlineContext.startRendering(); +// }; + +var convertFloat32ToInt16 = function convertFloat32ToInt16(buffer) { + var l = buffer.length; + var buf = new Int16Array(l); + + while (l--) { + buf[l] = Math.min(1, buffer[l]) * 0x7fff; + } + + return buf; +}; + +var config = { + wsServerAddr: '13.125.232.133', + wsServerPort: 3180, + wssServerAddr: 'zeroth-test.goodatlas.com', + wssServerPort: 2087, + sampleRate: 44100, + defaultParams: { + language: 'eng', + finalOnly: false, + ws: false + } +}; + +var debug$1 = function debug() {}; + +var ZerothMic = +/*#__PURE__*/ +function (_ZerothBase) { + _inherits(ZerothMic, _ZerothBase); + + function ZerothMic(params) { + var _this; + + _classCallCheck(this, ZerothMic); + + _this = _possibleConstructorReturn(this, _getPrototypeOf(ZerothMic).call(this, params)); + + _this.start = function () { + return new Promise(function (resolve, reject) { + var onSuccess = function onSuccess(stream) { + debug$1('Successfully got UserMedia'); + _this.stream = stream; + + _this.recording(); + + resolve(); + }; + + var onError = function onError(err) { + return reject(err); + }; + + var constraints = { + audio: true, + video: false + }; + + if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) { + var getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia; + + if (!getUserMedia) { + debug$1("Couldn't found getUserMedia on your browser."); + reject(new Error("Your browser dosen't support Media")); + return; + } + + getUserMedia(constraints).then(onSuccess, onError); + } else { + navigator.mediaDevices.getUserMedia(constraints).then(onSuccess, onError); + } + }); + }; + + _this.recording = function () { + _this.init(_this.params); + + _this.onready = function () { + var _assertThisInitialize = _assertThisInitialized(_assertThisInitialized(_this)), + bufferSize = _assertThisInitialize.bufferSize, + channels = _assertThisInitialize.channels, + stream = _assertThisInitialize.stream; + + _this.context = new CrossAudioContext(); + + var source = _this.context.createMediaStreamSource(stream); + + var processor = _this.context.createScriptProcessor(bufferSize, channels, channels); + + source.connect(processor); + processor.connect(_this.context.destination); + processor.onaudioprocess = _this.onAudioProcess; + }; + }; + + _this.onAudioProcess = function (e) { + var left = e.inputBuffer.getChannelData(0); + var buf = convertFloat32ToInt16(left); + + _this.send(buf); + }; + + _this.stop = function () { + if (_this.context && _this.context.state !== 'closed') _this.context.close(); + + var tracks = _this.stream.getTracks(); + + tracks.forEach(function (track) { + track.stop(); + }); + + _this.disconnect(); + }; + + _this.params = params; + _this.stream = null; + _this.bufferSize = 2048; + _this.channels = 1; + _this.sampleRate = config.sampleRate; + + if (params.debug) { + debug$1 = function debug() { + var _console; + + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + + return (_console = console).log.apply(_console, ['[zerothjs:debug]'].concat(args)); + }; + } + + _this.params = params; + return _this; + } // eslint-disable-next-line prettier/prettier + + + return ZerothMic; +}(ZerothBase); + +var ZerothFile = +/*#__PURE__*/ +function (_ZerothBase) { + _inherits(ZerothFile, _ZerothBase); + + function ZerothFile(params) { + var _this; + + _classCallCheck(this, ZerothFile); + + _this = _possibleConstructorReturn(this, _getPrototypeOf(ZerothFile).call(this, params)); + + _this.sendFile = function () { + var file = _this.file; + var reader = new FileReader(); + + reader.onload = function (e) { + var audioCtx = new CrossAudioContext(); + var buf = e.target.result; + audioCtx.decodeAudioData(buf, function (audioBuffer) { + var left = audioBuffer.getChannelData(0); + var buf = convertFloat32ToInt16(left); + zeroth.send(buf); + zeroth.disconnect(); + }); + }; + + reader.readAsArrayBuffer(file); + }; + + _this.onready = function () { + _this.sendFile(_this.file); + }; + + _this.init(params); + + _this.file = params.file; + + if (_this.file === undefined) { + throw Error('Parameter `file` is required.'); + } + + if (!/^audio/.test(_this.file.type)) { + throw Error("Expected Audio file but got ".concat(_this.file.type, " file.")); + } + + _this.sampleRate = config.sampleRate; + return _this; + } + + return ZerothFile; +}(ZerothBase); + +exports.ZerothBase = ZerothBase; +exports.ZerothMic = ZerothMic; +exports.ZerothFile = ZerothFile; diff --git a/dist/zeroth.commonjs2.js b/dist/zeroth.commonjs2.js deleted file mode 100644 index 90b907b..0000000 --- a/dist/zeroth.commonjs2.js +++ /dev/null @@ -1 +0,0 @@ -module.exports=function(e){var n={};function t(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}return t.m=e,t.c=n,t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:r})},t.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.t=function(e,n){if(1&n&&(e=t(e)),8&n)return e;if(4&n&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(t.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var o in e)t.d(r,o,function(n){return e[n]}.bind(null,o));return r},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},t.p="",t(t.s=3)}([function(e,n,t){"use strict";n.a={wsServerAddr:"13.125.232.133",wsServerPort:3180,wssServerAddr:"zeroth-test.goodatlas.com",wssServerPort:2087,sampleRate:44100,defaultParams:{language:"eng",finalOnly:!1,ws:!1}}},function(e,n,t){function r(e){var n={};function t(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=e,t.c=n,t.i=function(e){return e},t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.r=function(e){Object.defineProperty(e,"__esModule",{value:!0})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},t.p="/",t.oe=function(e){throw console.error(e),e};var r=t(t.s=ENTRY_MODULE);return r.default||r}var o="[\\.|\\-|\\+|\\w|/|@]+",a="\\((/\\*.*?\\*/)?s?.*?("+o+").*?\\)";function i(e){return(e+"").replace(/[.?*+^$[\]\\(){}|-]/g,"\\$&")}function c(e){return!isNaN(1*e)}function s(e,n,r){var s={};s[r]=[];var u=n.toString(),f=u.match(/^function\s?\(\w+,\s*\w+,\s*(\w+)\)/);if(!f)return s;for(var l,d=f[1],p=new RegExp("(\\\\n|\\W)"+i(d)+a,"g");l=p.exec(u);)"dll-reference"!==l[3]&&s[r].push(l[3]);for(p=new RegExp("\\("+i(d)+'\\("(dll-reference\\s('+o+'))"\\)\\)'+a,"g");l=p.exec(u);)e[l[2]]||(s[r].push(l[1]),e[l[2]]=t(l[1]).m),s[l[2]]=s[l[2]]||[],s[l[2]].push(l[4]);for(var m=Object.keys(s),y=0;y0},!1)}e.exports=function(e,n){n=n||{};var o={main:t.m},a=n.all?{main:Object.keys(o.main)}:function(e,n){for(var t={main:[n]},r={main:[]},o={main:{}};u(t);)for(var a=Object.keys(t),i=0;i */ +var win = window, BlobBuilder = win.BlobBuilder || win.WebKitBlobBuilder || win.MozBlobBuilder || win.MSBlobBuilder, URL = win.URL || win.webkitURL || win.mozURL || win.msURL, SCRIPT_TYPE = "application/javascript", TARGET = "undefined" == typeof Symbol ? "__t" + +new Date() : Symbol(), Worker = win.Worker, nextTick = win.setImmediate || function(e) { + return setTimeout(e, 1); +}; + +function workerCtor(e, t) { + return function r(n) { + var o = this; + if (!(o instanceof r)) return new r(n); + if (!t) return new Worker(e); + if (Worker && !n) { + var i = createSourceObject(';(function(f){f&&new(f.default?f["default"]:f)(self)}((' + t.toString() + ")()))"), a = new Worker(i); + return URL.revokeObjectURL(i), o[TARGET] = a; + } + var c = new WorkerEmitter({ + close: function() { + this.destroy(); + } + }, o); + Object.assign(new WorkerEmitter(o, c), { + isThisThread: !0, + terminate: function() { + c.close(), this.destroy(); + } + }), t().call(c, c); + }; +} + +function WorkerEmitter(e, t) { + var r = Object.create(null); + return e.onmessage = null, e.addEventListener = function(e, t) { + var n = r[e] || (r[e] = []); + ~n.indexOf(t) || n.push(t); + }, e.removeEventListener = function(e, t) { + var n, o = r[e]; + o && -1 !== (n = o.indexOf(t)) && (o.splice(n, 1), o.length || delete r[e]); + }, e.postMessage = function(r) { + nextTick(function() { + var n = r; + if (t.onmessage) try { + t.onmessage({ + data: n, + target: e + }); + } catch (e) { + console.error(e); + } + t.emit("message", { + type: "message", + data: n, + target: e, + timeStamp: +new Date() + }); + }); + }, e.emit = function(t, n) { + var o = r[t]; + o && o.forEach(function(t, r) { + return t.call(e, n); + }); + }, e.destroy = function() { + Object.keys(r).forEach(function(e) { + var t = r[e]; + t && (t.length = 0, delete r[e]); + }), r = null; + }, e; +} + +if (Worker) { + var testWorker, objURL = createSourceObject("self.onmessage = function () {}"), testArray = new Uint8Array(1); + try { + if (/(?:Trident|Edge)\/(?:[567]|12)/i.test(navigator.userAgent)) throw new Error("Not available"); + (testWorker = new Worker(objURL)).postMessage(testArray, [ testArray.buffer ]); + } catch (e) { + Worker = null; + } finally { + URL.revokeObjectURL(objURL), testWorker && testWorker.terminate(); + } +} + +function createSourceObject(e) { + var t = SCRIPT_TYPE; + try { + return URL.createObjectURL(new Blob([ e ], { + type: t + })); + } catch (n) { + var r = new BlobBuilder(); + return r.append(e), URL.createObjectURL(r.getBlob(t)); + } +} + +var Worker$1 = workerCtor('worker#./base.worker.js', function () { + return function (e, r) { + return e(r = { + exports: {} + }, r.exports), r.exports; + }(function (module, exports) { + var sock = null; + var config = { + wsServerAddr: '13.125.232.133', + wsServerPort: 3180, + wssServerAddr: 'zeroth-test.goodatlas.com', + wssServerPort: 2087, + sampleRate: 44100, + defaultParams: { + language: 'eng', + finalOnly: false, + ws: false + } + }; + + module.exports = function (self) { + self.onmessage = function (e) { + switch (e.data.command) { + case 'init': + sock = new Socket(e.data.params); + break; + + case 'disconnect': + sock.disconnect(); + break; + + case 'send': + sock.send(e.data.data); + break; + } + }; + }; + + function _classCallCheck$$1(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError('Cannot call a class as a function'); + } + } + + var Socket = function Socket(params) { + _classCallCheck$$1(this, Socket); + + _initialiseProps.call(this); + + if (!params || !params.key) { + postMessage({ + command: 'onerror', + error: 'API key missing' + }); + return; + } + + if (params.debug) { + debug = function debug() { + var _console; + + for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + + return (_console = console).log.apply(_console, ['[zerothjs:debug]'].concat(args)); + }; + } + + var _config$defaultParams = config.defaultParams, + language = _config$defaultParams.language, + finalOnly = _config$defaultParams.finalOnly, + ws = _config$defaultParams.ws; + this.params = { + key: params.key, + language: params.language || language, + finalOnly: params.finalOnly || finalOnly, + ws: params.ws || ws + }; + this.ws = null; + this.connect(); + }; + + var _initialiseProps = function _initialiseProps() { + var _this = this; + + this.connect = function () { + var _config = config, + wsServerAddr = _config.wsServerAddr, + wsServerPort = _config.wsServerPort, + wssServerAddr = _config.wssServerAddr, + wssServerPort = _config.wssServerPort, + sampleRate = _config.sampleRate; + var _params = _this.params, + key = _params.key, + language = _params.language, + finalOnly = _params.finalOnly, + ws = _params.ws; + var contentType = 'audio/x-raw,+layout=(string)interleaved,+rate=(int)' + sampleRate + ',+format=(string)S16LE,+channels=(int)1'; + var query = 'content-type=' + contentType + '&key=' + key + '&language=' + language + '&final-only=' + finalOnly; + var uri = ws ? 'ws://' + wsServerAddr + ':' + wsServerPort + '/client/ws/speech?' + query : 'wss://' + wssServerAddr + ':' + wssServerPort + '/client/ws/speech?' + query; + debug('uri', uri); + _this.ws = new WebSocket(uri); + + _this.ws.onopen = function () { + postMessage({ + command: 'onconnect' + }); + }; + + _this.ws.onerror = function (e) { + // TODO handle error codes + debug('websocket error', e.code, e.reason, e.message); + postMessage({ + command: 'onerror', + error: e.message + }); + }; + + _this.ws.onclose = function (e) { + debug('websocket closed', e.code, e.reason, e.message); + _this.ws = null; + postMessage({ + command: 'ondisconnect' + }); + }; + + _this.ws.onmessage = function (e) { + // debug('received data', e.data); + postMessage({ + command: 'ondata', + data: JSON.parse(e.data) + }); + }; + }; + + this.send = function (data) { + if (!_this.ws) return; + + try { + _this.ws.send(data); + } catch (e) { + debug('websocket send data error', e.code, e.reason, e.message); + postMessage({ + command: 'onerror', + error: e.message + }); + + _this.ws.close(); + } + }; + + this.disconnect = function () { + _this.send('EOS'); + }; + }; + }); +}); + +var worker = null; + +var ZerothBase = function ZerothBase(params) { + var _this = this; + + _classCallCheck(this, ZerothBase); + + this.init = function () { + worker = new Worker$1(); + worker.postMessage({ + command: 'init', + params: _this.params + }); + + worker.onmessage = function (e) { + switch (e.data.command) { + case 'onerror': + _this.onerror(e.data.error); + + break; + + case 'onconnect': + _this.onconnect(); + + _this.onready(); + + break; + + case 'ondisconnect': + _this.ondisconnect(); + + worker.terminate(); + break; + + case 'ondata': + _this.ondata(e.data.data); + + break; + } + }; + }; + + this.send = function (data) { + worker.postMessage({ + command: 'send', + data: data + }); + }; + + this.disconnect = function () { + worker.postMessage({ + command: 'disconnect' + }); + }; + + var noop = function noop() {}; + + this.onconnect = this.onconnect || noop; + this.onready = this.onready || noop; + this.ondisconnect = this.ondisconnect || noop; + this.ondata = this.ondata || noop; + this.onerror = this.onerror || noop; + this.params = params; +}; + +var CrossAudioContext = window.AudioContext || window.webkitAudioContext; // export const resample = (audioBuffer, targetSampleRate, onComplete) => { +// const channels = audioBuffer.numberOfChannels; +// const samples = audioBuffer.length * targetSampleRate / audioBuffer.sampleRate; +// const offlineContext = new CrossOfflineAudioContext(channels, samples, targetSampleRate); +// const bufferSource = offlineContext.createBufferSource(); +// bufferSource.buffer = audioBuffer; +// bufferSource.connect(offlineContext.destination); +// bufferSource.start(0); +// offlineContext.oncomplete = e => onComplete(e.renderedBuffer); +// offlineContext.startRendering(); +// }; + +var convertFloat32ToInt16 = function convertFloat32ToInt16(buffer) { + var l = buffer.length; + var buf = new Int16Array(l); + + while (l--) { + buf[l] = Math.min(1, buffer[l]) * 0x7fff; + } + + return buf; +}; + +var config = { + wsServerAddr: '13.125.232.133', + wsServerPort: 3180, + wssServerAddr: 'zeroth-test.goodatlas.com', + wssServerPort: 2087, + sampleRate: 44100, + defaultParams: { + language: 'eng', + finalOnly: false, + ws: false + } +}; + +var debug$1 = function debug() {}; + +var ZerothMic = +/*#__PURE__*/ +function (_ZerothBase) { + _inherits(ZerothMic, _ZerothBase); + + function ZerothMic(params) { + var _this; + + _classCallCheck(this, ZerothMic); + + _this = _possibleConstructorReturn(this, _getPrototypeOf(ZerothMic).call(this, params)); + + _this.start = function () { + return new Promise(function (resolve, reject) { + var onSuccess = function onSuccess(stream) { + debug$1('Successfully got UserMedia'); + _this.stream = stream; + + _this.recording(); + + resolve(); + }; + + var onError = function onError(err) { + return reject(err); + }; + + var constraints = { + audio: true, + video: false + }; + + if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) { + var getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia; + + if (!getUserMedia) { + debug$1("Couldn't found getUserMedia on your browser."); + reject(new Error("Your browser dosen't support Media")); + return; + } + + getUserMedia(constraints).then(onSuccess, onError); + } else { + navigator.mediaDevices.getUserMedia(constraints).then(onSuccess, onError); + } + }); + }; + + _this.recording = function () { + _this.init(_this.params); + + _this.onready = function () { + var _assertThisInitialize = _assertThisInitialized(_assertThisInitialized(_this)), + bufferSize = _assertThisInitialize.bufferSize, + channels = _assertThisInitialize.channels, + stream = _assertThisInitialize.stream; + + _this.context = new CrossAudioContext(); + + var source = _this.context.createMediaStreamSource(stream); + + var processor = _this.context.createScriptProcessor(bufferSize, channels, channels); + + source.connect(processor); + processor.connect(_this.context.destination); + processor.onaudioprocess = _this.onAudioProcess; + }; + }; + + _this.onAudioProcess = function (e) { + var left = e.inputBuffer.getChannelData(0); + var buf = convertFloat32ToInt16(left); + + _this.send(buf); + }; + + _this.stop = function () { + if (_this.context && _this.context.state !== 'closed') _this.context.close(); + + var tracks = _this.stream.getTracks(); + + tracks.forEach(function (track) { + track.stop(); + }); + + _this.disconnect(); + }; + + _this.params = params; + _this.stream = null; + _this.bufferSize = 2048; + _this.channels = 1; + _this.sampleRate = config.sampleRate; + + if (params.debug) { + debug$1 = function debug() { + var _console; + + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + + return (_console = console).log.apply(_console, ['[zerothjs:debug]'].concat(args)); + }; + } + + _this.params = params; + return _this; + } // eslint-disable-next-line prettier/prettier + + + return ZerothMic; +}(ZerothBase); + +var ZerothFile = +/*#__PURE__*/ +function (_ZerothBase) { + _inherits(ZerothFile, _ZerothBase); + + function ZerothFile(params) { + var _this; + + _classCallCheck(this, ZerothFile); + + _this = _possibleConstructorReturn(this, _getPrototypeOf(ZerothFile).call(this, params)); + + _this.sendFile = function () { + var file = _this.file; + var reader = new FileReader(); + + reader.onload = function (e) { + var audioCtx = new CrossAudioContext(); + var buf = e.target.result; + audioCtx.decodeAudioData(buf, function (audioBuffer) { + var left = audioBuffer.getChannelData(0); + var buf = convertFloat32ToInt16(left); + zeroth.send(buf); + zeroth.disconnect(); + }); + }; + + reader.readAsArrayBuffer(file); + }; + + _this.onready = function () { + _this.sendFile(_this.file); + }; + + _this.init(params); + + _this.file = params.file; + + if (_this.file === undefined) { + throw Error('Parameter `file` is required.'); + } + + if (!/^audio/.test(_this.file.type)) { + throw Error("Expected Audio file but got ".concat(_this.file.type, " file.")); + } + + _this.sampleRate = config.sampleRate; + return _this; + } + + return ZerothFile; +}(ZerothBase); + +export { ZerothBase, ZerothMic, ZerothFile }; diff --git a/dist/zeroth.min.js b/dist/zeroth.min.js index 22148b6..c850357 100644 --- a/dist/zeroth.min.js +++ b/dist/zeroth.min.js @@ -1 +1 @@ -!function(e,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define([],n):"object"==typeof exports?exports.Zeroth=n():e.Zeroth=n()}(window,function(){return function(e){var n={};function t(o){if(n[o])return n[o].exports;var r=n[o]={i:o,l:!1,exports:{}};return e[o].call(r.exports,r,r.exports,t),r.l=!0,r.exports}return t.m=e,t.c=n,t.d=function(e,n,o){t.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:o})},t.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.t=function(e,n){if(1&n&&(e=t(e)),8&n)return e;if(4&n&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(t.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var r in e)t.d(o,r,function(n){return e[n]}.bind(null,r));return o},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},t.p="",t(t.s=3)}([function(e,n,t){"use strict";n.a={wsServerAddr:"13.125.232.133",wsServerPort:3180,wssServerAddr:"zeroth-test.goodatlas.com",wssServerPort:2087,sampleRate:44100,defaultParams:{language:"eng",finalOnly:!1,ws:!1}}},function(e,n,t){function o(e){var n={};function t(o){if(n[o])return n[o].exports;var r=n[o]={i:o,l:!1,exports:{}};return e[o].call(r.exports,r,r.exports,t),r.l=!0,r.exports}t.m=e,t.c=n,t.i=function(e){return e},t.d=function(e,n,o){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:o})},t.r=function(e){Object.defineProperty(e,"__esModule",{value:!0})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},t.p="/",t.oe=function(e){throw console.error(e),e};var o=t(t.s=ENTRY_MODULE);return o.default||o}var r="[\\.|\\-|\\+|\\w|/|@]+",a="\\((/\\*.*?\\*/)?s?.*?("+r+").*?\\)";function i(e){return(e+"").replace(/[.?*+^$[\]\\(){}|-]/g,"\\$&")}function c(e){return!isNaN(1*e)}function s(e,n,o){var s={};s[o]=[];var u=n.toString(),f=u.match(/^function\s?\(\w+,\s*\w+,\s*(\w+)\)/);if(!f)return s;for(var l,d=f[1],p=new RegExp("(\\\\n|\\W)"+i(d)+a,"g");l=p.exec(u);)"dll-reference"!==l[3]&&s[o].push(l[3]);for(p=new RegExp("\\("+i(d)+'\\("(dll-reference\\s('+r+'))"\\)\\)'+a,"g");l=p.exec(u);)e[l[2]]||(s[o].push(l[1]),e[l[2]]=t(l[1]).m),s[l[2]]=s[l[2]]||[],s[l[2]].push(l[4]);for(var y=Object.keys(s),m=0;m0},!1)}e.exports=function(e,n){n=n||{};var r={main:t.m},a=n.all?{main:Object.keys(r.main)}:function(e,n){for(var t={main:[n]},o={main:[]},r={main:{}};u(t);)for(var a=Object.keys(t),i=0;i0},!1)}e.exports=function(e,n){n=n||{};var o={main:t.m},a=n.all?{main:Object.keys(o.main)}:function(e,n){for(var t={main:[n]},r={main:[]},o={main:{}};u(t);)for(var a=Object.keys(t),i=0;i { - worker = work(require.resolve('./worker.js')); + worker = new Worker(); worker.postMessage({ command: 'init', params: this.params diff --git a/src/base.worker.js b/src/base.worker.js new file mode 100644 index 0000000..97e284f --- /dev/null +++ b/src/base.worker.js @@ -0,0 +1,147 @@ +let sock = null; +const config = { + wsServerAddr: '13.125.232.133', + wsServerPort: 3180, + wssServerAddr: 'zeroth-test.goodatlas.com', + wssServerPort: 2087, + sampleRate: 44100, + defaultParams: { + language: 'eng', + finalOnly: false, + ws: false + } +}; +module.exports = function(self) { + self.onmessage = e => { + switch (e.data.command) { + case 'init': + sock = new Socket(e.data.params); + break; + case 'disconnect': + sock.disconnect(); + break; + case 'send': + sock.send(e.data.data); + break; + } + }; +}; + +function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError('Cannot call a class as a function'); + } +} + +var Socket = function Socket(params) { + _classCallCheck(this, Socket); + + _initialiseProps.call(this); + + if (!params || !params.key) { + postMessage({ command: 'onerror', error: 'API key missing' }); + return; + } + + if (params.debug) { + debug = function debug() { + var _console; + + for ( var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + + return (_console = console).log.apply(_console, ['[zerothjs:debug]'].concat(args)); + }; + } + + var _config$defaultParams = config.defaultParams, + language = _config$defaultParams.language, + finalOnly = _config$defaultParams.finalOnly, + ws = _config$defaultParams.ws; + + this.params = { + key: params.key, + language: params.language || language, + finalOnly: params.finalOnly || finalOnly, + ws: params.ws || ws + }; + this.ws = null; + this.connect(); +}; + +var _initialiseProps = function _initialiseProps() { + var _this = this; + + this.connect = function() { + var _config = config, + wsServerAddr = _config.wsServerAddr, + wsServerPort = _config.wsServerPort, + wssServerAddr = _config.wssServerAddr, + wssServerPort = _config.wssServerPort, + sampleRate = _config.sampleRate; + var _params = _this.params, + key = _params.key, + language = _params.language, + finalOnly = _params.finalOnly, + ws = _params.ws; + + var contentType = + 'audio/x-raw,+layout=(string)interleaved,+rate=(int)' + + sampleRate + + ',+format=(string)S16LE,+channels=(int)1'; + var query = + 'content-type=' + + contentType + + '&key=' + + key + + '&language=' + + language + + '&final-only=' + + finalOnly; + var uri = ws + ? 'ws://' + wsServerAddr + ':' + wsServerPort + '/client/ws/speech?' + query + : 'wss://' + wssServerAddr + ':' + wssServerPort + '/client/ws/speech?' + query; + + debug('uri', uri); + + _this.ws = new WebSocket(uri); + + _this.ws.onopen = function() { + postMessage({ command: 'onconnect' }); + }; + + _this.ws.onerror = function(e) { + // TODO handle error codes + debug('websocket error', e.code, e.reason, e.message); + postMessage({ command: 'onerror', error: e.message }); + }; + + _this.ws.onclose = function(e) { + debug('websocket closed', e.code, e.reason, e.message); + _this.ws = null; + postMessage({ command: 'ondisconnect' }); + }; + + _this.ws.onmessage = function(e) { + // debug('received data', e.data); + postMessage({ command: 'ondata', data: JSON.parse(e.data) }); + }; + }; + + this.send = function(data) { + if (!_this.ws) return; + + try { + _this.ws.send(data); + } catch (e) { + debug('websocket send data error', e.code, e.reason, e.message); + postMessage({ command: 'onerror', error: e.message }); + _this.ws.close(); + } + }; + + this.disconnect = function() { + _this.send('EOS'); + }; +}; diff --git a/src/worker.js b/src/socket.js similarity index 80% rename from src/worker.js rename to src/socket.js index 1b91c01..329c784 100644 --- a/src/worker.js +++ b/src/socket.js @@ -1,24 +1,3 @@ -import config from './config'; - -let debug = () => {}; -let sock = null; - -export default function worker(self) { - self.onmessage = e => { - switch (e.data.command) { - case 'init': - sock = new Socket(e.data.params); - break; - case 'disconnect': - sock.disconnect(); - break; - case 'send': - sock.send(e.data.data); - break; - } - }; -} - class Socket { constructor(params) { if (!params || !params.key) { @@ -42,7 +21,13 @@ class Socket { } connect = () => { - const { wsServerAddr, wsServerPort, wssServerAddr, wssServerPort, sampleRate } = config; + const { + wsServerAddr, + wsServerPort, + wssServerAddr, + wssServerPort, + sampleRate + } = config; const { key, language, finalOnly, ws } = this.params; const contentType = `audio/x-raw,+layout=(string)interleaved,+rate=(int)${sampleRate},+format=(string)S16LE,+channels=(int)1`; const query = `content-type=${contentType}&key=${key}&language=${language}&final-only=${finalOnly}`; diff --git a/webpack.config.js b/webpack.config.js index c99d0ee..d1beefc 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -13,6 +13,10 @@ function createConfig(target) { }, module: { rules: [ + { + test: /\.worker\.js$/, + use: { loader: 'worker-loader' } + }, { test: /\.js$/, exclude: /node_modules/,