@speechly/browser-client
Advanced tools
Comparing version 1.0.14 to 1.0.15
@@ -22,2 +22,13 @@ | ||
* | ||
* This method will be called by the Client as part of the initialisation process. | ||
* | ||
* @param apiUrl - url. | ||
* @param authToken - authentication token. | ||
* @param targetSampleRate - target sample rate of audio. | ||
* @param debug - debug flag. | ||
*/ | ||
initialize(apiUrl: string, authToken: string, targetSampleRate: number, debug: boolean): Promise<void>; | ||
/** | ||
* Initialises the client. | ||
* | ||
* This should prepare websocket to be used (set source sample rate). | ||
@@ -28,3 +39,3 @@ * This method will be called by the Client as part of the initialisation process. | ||
*/ | ||
initialize(sourceSampleRate: number): Promise<void>; | ||
setSourceSampleRate(sourceSampleRate: number): Promise<void>; | ||
/** | ||
@@ -97,2 +108,4 @@ * Closes the client. | ||
private initializeMicrophonePromise?; | ||
private readonly initializeApiClientPromise; | ||
private resolveInitialization?; | ||
private resolveStopContext?; | ||
@@ -99,0 +112,0 @@ private readonly deviceId; |
{ | ||
"name": "@speechly/browser-client", | ||
"version": "1.0.14", | ||
"version": "1.0.15", | ||
"description": "Browser client for Speechly API", | ||
@@ -5,0 +5,0 @@ "private": false, |
@@ -31,2 +31,4 @@ import { ClientOptions, StateChangeCallback, SegmentChangeCallback, TentativeTranscriptCallback, TranscriptCallback, TentativeEntitiesCallback, EntityCallback, IntentCallback } from './types'; | ||
private initializeMicrophonePromise?; | ||
private readonly initializeApiClientPromise; | ||
private resolveInitialization?; | ||
private resolveStopContext?; | ||
@@ -33,0 +35,0 @@ private readonly deviceId; |
@@ -162,2 +162,5 @@ "use strict"; | ||
// 2. Fetch auth token. It doesn't matter if it's not present. | ||
this.initializeApiClientPromise = new Promise(resolve => { | ||
this.resolveInitialization = resolve; | ||
}); | ||
if (storedToken == null || !token_1.validateToken(storedToken, this.projectId, this.appId, this.deviceId)) { | ||
@@ -197,9 +200,11 @@ token_1.fetchToken(this.loginUrl, this.projectId, this.appId, this.deviceId) | ||
connect(apiUrl) { | ||
this.apiClient.postMessage({ | ||
type: 'INIT', | ||
apiUrl: apiUrl, | ||
authToken: this.authToken, | ||
targetSampleRate: this.sampleRate, | ||
debug: this.debug, | ||
}); | ||
if (this.authToken != null) { | ||
this.apiClient.initialize(apiUrl, this.authToken, this.sampleRate, this.debug).then(() => { | ||
if (this.resolveInitialization != null) { | ||
this.resolveInitialization(); | ||
} | ||
}).catch(err => { | ||
throw err; | ||
}); | ||
} | ||
} | ||
@@ -217,2 +222,3 @@ /** | ||
return __awaiter(this, void 0, void 0, function* () { | ||
yield this.initializeApiClientPromise; | ||
if (this.state !== types_1.ClientState.Disconnected) { | ||
@@ -263,3 +269,3 @@ throw Error('Cannot initialize client - client is not in Disconnected state'); | ||
// 3. Initialise websocket. | ||
yield this.apiClient.initialize(this.audioContext.sampleRate); | ||
yield this.apiClient.setSourceSampleRate(this.audioContext.sampleRate); | ||
this.initializeMicrophonePromise = this.microphone.initialize(this.audioContext, opts); | ||
@@ -266,0 +272,0 @@ yield this.initializeMicrophonePromise; |
@@ -154,2 +154,13 @@ /** | ||
* | ||
* This method will be called by the Client as part of the initialisation process. | ||
* | ||
* @param apiUrl - url. | ||
* @param authToken - authentication token. | ||
* @param targetSampleRate - target sample rate of audio. | ||
* @param debug - debug flag. | ||
*/ | ||
initialize(apiUrl: string, authToken: string, targetSampleRate: number, debug: boolean): Promise<void>; | ||
/** | ||
* Initialises the client. | ||
* | ||
* This should prepare websocket to be used (set source sample rate). | ||
@@ -160,3 +171,3 @@ * This method will be called by the Client as part of the initialisation process. | ||
*/ | ||
initialize(sourceSampleRate: number): Promise<void>; | ||
setSourceSampleRate(sourceSampleRate: number): Promise<void>; | ||
/** | ||
@@ -163,0 +174,0 @@ * Closes the client. |
@@ -5,2 +5,3 @@ import { APIClient, ResponseCallback, CloseCallback } from './types'; | ||
private resolveInitialization?; | ||
private resolveSourceSampleRateSet?; | ||
private startCbs; | ||
@@ -13,3 +14,4 @@ private stopCbs; | ||
constructor(); | ||
initialize(sourceSampleRate: number): Promise<void>; | ||
initialize(apiUrl: string, authToken: string, targetSampleRate: number, debug: boolean): Promise<void>; | ||
setSourceSampleRate(sourceSampleRate: number): Promise<void>; | ||
close(): Promise<void>; | ||
@@ -16,0 +18,0 @@ startContext(appId?: string): Promise<string>; |
@@ -27,4 +27,2 @@ "use strict"; | ||
case types_1.WebsocketResponseType.Opened: | ||
break; | ||
case types_1.WebsocketResponseType.SourceSampleRateSetSuccess: | ||
if (this.resolveInitialization != null) { | ||
@@ -34,2 +32,7 @@ this.resolveInitialization(); | ||
break; | ||
case types_1.WebsocketResponseType.SourceSampleRateSetSuccess: | ||
if (this.resolveSourceSampleRateSet != null) { | ||
this.resolveSourceSampleRateSet(); | ||
} | ||
break; | ||
case types_1.WebsocketResponseType.Started: | ||
@@ -72,5 +75,19 @@ this.startCbs.forEach(cb => { | ||
} | ||
initialize(sourceSampleRate) { | ||
initialize(apiUrl, authToken, targetSampleRate, debug) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
this.worker.postMessage({ | ||
type: 'INIT', | ||
apiUrl, | ||
authToken, | ||
targetSampleRate, | ||
debug, | ||
}); | ||
return new Promise(resolve => { | ||
this.resolveInitialization = resolve; | ||
}); | ||
}); | ||
} | ||
setSourceSampleRate(sourceSampleRate) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
this.worker.postMessage({ | ||
type: 'SET_SOURSE_SAMPLE_RATE', | ||
@@ -80,3 +97,3 @@ sourceSampleRate, | ||
return new Promise(resolve => { | ||
this.resolveInitialization = resolve; | ||
this.resolveSourceSampleRateSet = resolve; | ||
}); | ||
@@ -83,0 +100,0 @@ }); |
@@ -1,2 +0,2 @@ | ||
declare const _default: "/**\n * Known WebSocket response types.\n * @public\n */\nvar WebsocketResponseType;\n(function (WebsocketResponseType) {\n WebsocketResponseType[\"Opened\"] = \"WEBSOCKET_OPEN\";\n WebsocketResponseType[\"SourceSampleRateSetSuccess\"] = \"SOURSE_SAMPLE_RATE_SET_SUCCESS\";\n WebsocketResponseType[\"Started\"] = \"started\";\n WebsocketResponseType[\"Stopped\"] = \"stopped\";\n})(WebsocketResponseType || (WebsocketResponseType = {}));\nvar CONTROL = {\n WRITE_INDEX: 0,\n FRAMES_AVAILABLE: 1,\n LOCK: 2\n};\nvar WebsocketClient = /** @class */ (function () {\n function WebsocketClient(ctx) {\n var _this = this;\n this.isContextStarted = false;\n this.isStartContextConfirmed = false;\n this.shouldResendLastFramesSent = false;\n this.buffer = new Float32Array(0);\n this.lastFramesSent = new Int16Array(0); // to re-send after switch context\n this.debug = false;\n this.initialized = false;\n this.onWebsocketClose = function (event) {\n _this.websocket = undefined;\n _this.connect(0);\n };\n this.onWebsocketOpen = function (_event) {\n if (_this.debug) {\n console.log('[SpeechlyClient]', 'websocket opened');\n }\n _this.workerCtx.postMessage({ type: 'WEBSOCKET_OPEN' });\n };\n this.onWebsocketError = function (_event) {\n if (_this.debug) {\n console.log('[SpeechlyClient]', 'websocket error');\n }\n _this.closeWebsocket();\n };\n this.onWebsocketMessage = function (event) {\n var response;\n try {\n response = JSON.parse(event.data);\n }\n catch (e) {\n console.error('[SpeechlyClient] Error parsing response from the server:', e);\n return;\n }\n if (response.type === WebsocketResponseType.Started) {\n _this.isStartContextConfirmed = true;\n if (_this.shouldResendLastFramesSent) {\n _this.resendLastFrames();\n _this.shouldResendLastFramesSent = false;\n }\n }\n _this.workerCtx.postMessage(response);\n };\n this.workerCtx = ctx;\n }\n WebsocketClient.prototype.init = function (apiUrl, authToken, targetSampleRate, debug) {\n if (this.initialized) {\n console.log('[SpeechlyClient]', 'already initialized');\n return;\n }\n this.debug = debug;\n if (this.debug) {\n console.log('[SpeechlyClient]', 'initialize worker');\n }\n this.apiUrl = apiUrl;\n this.authToken = authToken;\n this.targetSampleRate = targetSampleRate;\n this.initialized = true;\n this.connect(0);\n };\n WebsocketClient.prototype.setSourceSampleRate = function (sourceSampleRate) {\n this.sourceSampleRate = sourceSampleRate;\n this.resampleRatio = this.sourceSampleRate / this.targetSampleRate;\n if (this.debug) {\n console.log('[SpeechlyClient]', 'resampleRatio', this.resampleRatio);\n }\n if (this.resampleRatio > 1) {\n this.filter = generateFilter(this.sourceSampleRate, this.targetSampleRate, 127);\n }\n this.workerCtx.postMessage({ type: 'SOURSE_SAMPLE_RATE_SET_SUCCESS' });\n if (isNaN(this.resampleRatio)) {\n throw Error('resampleRatio is NaN');\n }\n };\n WebsocketClient.prototype.setSharedArrayBuffers = function (controlSAB, dataSAB) {\n this.controlSAB = new Int32Array(controlSAB);\n this.dataSAB = new Float32Array(dataSAB);\n var audioHandleInterval = this.dataSAB.length / 32; // ms\n if (this.debug) {\n console.log('[SpeechlyClient]', 'Audio handle interval', audioHandleInterval, 'ms');\n }\n setInterval(this.sendAudioFromSAB.bind(this), audioHandleInterval);\n };\n WebsocketClient.prototype.connect = function (timeout) {\n if (timeout === void 0) { timeout = 1000; }\n if (this.debug) {\n console.log('[SpeechlyClient]', 'connect in ', timeout / 1000, 'sec');\n }\n setTimeout(this.initializeWebsocket.bind(this), timeout);\n };\n WebsocketClient.prototype.initializeWebsocket = function () {\n if (this.debug) {\n console.log('[SpeechlyClient]', 'connecting to ', this.apiUrl);\n }\n this.websocket = new WebSocket(this.apiUrl, this.authToken);\n this.websocket.addEventListener('open', this.onWebsocketOpen);\n this.websocket.addEventListener('message', this.onWebsocketMessage);\n this.websocket.addEventListener('error', this.onWebsocketError);\n this.websocket.addEventListener('close', this.onWebsocketClose);\n };\n WebsocketClient.prototype.isOpen = function () {\n return this.websocket !== undefined && this.websocket.readyState === this.websocket.OPEN;\n };\n WebsocketClient.prototype.resendLastFrames = function () {\n if (!this.isOpen()) {\n return Error('Cannot resend data through inactive websocket');\n }\n if (this.lastFramesSent.length > 0) {\n this.websocket.send(this.lastFramesSent);\n this.lastFramesSent = new Int16Array(0);\n }\n };\n WebsocketClient.prototype.sendAudio = function (audioChunk) {\n if (!this.isContextStarted) {\n return;\n }\n if (!this.isOpen()) {\n return Error('Cannot send data through inactive websocket');\n }\n if (audioChunk.length > 0) {\n if (this.resampleRatio > 1) {\n // Downsampling\n this.websocket.send(this.downsample(audioChunk));\n }\n else {\n this.websocket.send(float32ToInt16(audioChunk));\n }\n }\n };\n WebsocketClient.prototype.sendAudioFromSAB = function () {\n if (!this.isContextStarted) {\n this.controlSAB[CONTROL.FRAMES_AVAILABLE] = 0;\n this.controlSAB[CONTROL.WRITE_INDEX] = 0;\n return;\n }\n if (this.controlSAB == undefined) {\n return;\n }\n var framesAvailable = this.controlSAB[CONTROL.FRAMES_AVAILABLE];\n var lock = this.controlSAB[CONTROL.LOCK];\n if (lock == 0 && framesAvailable > 0) {\n var data = this.dataSAB.subarray(0, framesAvailable);\n this.controlSAB[CONTROL.FRAMES_AVAILABLE] = 0;\n this.controlSAB[CONTROL.WRITE_INDEX] = 0;\n if (data.length > 0) {\n var frames_1;\n if (this.resampleRatio > 1) {\n frames_1 = this.downsample(data);\n }\n else {\n frames_1 = float32ToInt16(data);\n }\n this.websocket.send(frames_1);\n // 16000 per second, 1000 in 100 ms\n // save last 250 ms\n if (this.lastFramesSent.length > 1024 * 4) {\n this.lastFramesSent = frames_1;\n }\n else {\n var concat = new Int16Array(this.lastFramesSent.length + frames_1.length);\n concat.set(this.lastFramesSent);\n concat.set(frames_1, this.lastFramesSent.length);\n this.lastFramesSent = concat;\n }\n }\n }\n };\n WebsocketClient.prototype.startContext = function (appId) {\n if (!this.isOpen()) {\n throw Error('Cant start context: websocket is inactive');\n }\n if (this.isContextStarted) {\n console.log('Cant start context: it has been already started');\n return;\n }\n this.isContextStarted = true;\n this.isStartContextConfirmed = false;\n if (appId !== undefined) {\n this.websocket.send(JSON.stringify({ event: 'start', appId: appId }));\n }\n else {\n this.websocket.send(JSON.stringify({ event: 'start' }));\n }\n };\n WebsocketClient.prototype.stopContext = function () {\n if (this.websocket == undefined) {\n throw Error('Cant start context: websocket is undefined');\n }\n if (!this.isContextStarted) {\n console.log('Cant stop context: it is not started');\n return;\n }\n this.isContextStarted = false;\n this.isStartContextConfirmed = false;\n var StopEventJSON = JSON.stringify({ event: 'stop' });\n this.websocket.send(StopEventJSON);\n };\n WebsocketClient.prototype.switchContext = function (newAppId) {\n if (this.websocket == undefined) {\n throw Error('Cant switch context: websocket is undefined');\n }\n if (!this.isContextStarted) {\n console.log('Cant switch context: it is not started');\n return;\n }\n if (newAppId == undefined) {\n console.log('Cant switch context: new app id is undefined');\n return;\n }\n this.isStartContextConfirmed = false;\n var StopEventJSON = JSON.stringify({ event: 'stop' });\n this.websocket.send(StopEventJSON);\n this.shouldResendLastFramesSent = true;\n this.websocket.send(JSON.stringify({ event: 'start', appId: newAppId }));\n };\n WebsocketClient.prototype.closeWebsocket = function () {\n if (this.websocket == null) {\n throw Error('Websocket is not open');\n }\n this.websocket.removeEventListener('open', this.onWebsocketOpen);\n this.websocket.removeEventListener('message', this.onWebsocketMessage);\n this.websocket.removeEventListener('error', this.onWebsocketError);\n this.websocket.removeEventListener('close', this.onWebsocketClose);\n this.websocket.close();\n };\n WebsocketClient.prototype.downsample = function (input) {\n var inputBuffer = new Float32Array(this.buffer.length + input.length);\n inputBuffer.set(this.buffer, 0);\n inputBuffer.set(input, this.buffer.length);\n var outputLength = Math.ceil((inputBuffer.length - this.filter.length) / this.resampleRatio);\n var outputBuffer = new Int16Array(outputLength);\n for (var i = 0; i < outputLength; i++) {\n var offset = Math.round(this.resampleRatio * i);\n var val = 0.0;\n for (var j = 0; j < this.filter.length; j++) {\n val += inputBuffer[offset + j] * this.filter[j];\n }\n outputBuffer[i] = val * (val < 0 ? 0x8000 : 0x7fff);\n }\n var remainingOffset = Math.round(this.resampleRatio * outputLength);\n if (remainingOffset < inputBuffer.length) {\n this.buffer = inputBuffer.subarray(remainingOffset);\n }\n else {\n this.buffer = new Float32Array(0);\n }\n return outputBuffer;\n };\n return WebsocketClient;\n}());\nvar ctx = self;\nvar websocketClient = new WebsocketClient(ctx);\nctx.onmessage = function (e) {\n switch (e.data.type) {\n case 'INIT':\n websocketClient.init(e.data.apiUrl, e.data.authToken, e.data.targetSampleRate, e.data.debug);\n break;\n case 'SET_SOURSE_SAMPLE_RATE':\n websocketClient.setSourceSampleRate(e.data.sourceSampleRate);\n break;\n case 'SET_SHARED_ARRAY_BUFFERS':\n websocketClient.setSharedArrayBuffers(e.data.controlSAB, e.data.dataSAB);\n break;\n case 'CLOSE':\n websocketClient.closeWebsocket();\n break;\n case 'START_CONTEXT':\n websocketClient.startContext(e.data.appId);\n break;\n case 'SWITCH_CONTEXT':\n websocketClient.switchContext(e.data.appId);\n break;\n case 'STOP_CONTEXT':\n websocketClient.stopContext();\n break;\n case 'AUDIO':\n websocketClient.sendAudio(e.data.payload);\n break;\n default:\n console.log('WORKER', e);\n }\n};\nfunction float32ToInt16(buffer) {\n var buf = new Int16Array(buffer.length);\n for (var l = 0; l < buffer.length; l++) {\n buf[l] = buffer[l] * (buffer[l] < 0 ? 0x8000 : 0x7fff);\n }\n return buf;\n}\nfunction generateFilter(sourceSampleRate, targetSampleRate, length) {\n if (length % 2 === 0) {\n throw Error('Filter length must be odd');\n }\n var cutoff = targetSampleRate / 2;\n var filter = new Float32Array(length);\n var sum = 0;\n for (var i = 0; i < length; i++) {\n var x = sinc(((2 * cutoff) / sourceSampleRate) * (i - (length - 1) / 2));\n sum += x;\n filter[i] = x;\n }\n for (var i = 0; i < length; i++) {\n filter[i] = filter[i] / sum;\n }\n return filter;\n}\nfunction sinc(x) {\n if (x === 0.0) {\n return 1.0;\n }\n var piX = Math.PI * x;\n return Math.sin(piX) / piX;\n}\n"; | ||
declare const _default: "/**\n * Known WebSocket response types.\n * @public\n */\nvar WebsocketResponseType;\n(function (WebsocketResponseType) {\n WebsocketResponseType[\"Opened\"] = \"WEBSOCKET_OPEN\";\n WebsocketResponseType[\"SourceSampleRateSetSuccess\"] = \"SOURSE_SAMPLE_RATE_SET_SUCCESS\";\n WebsocketResponseType[\"Started\"] = \"started\";\n WebsocketResponseType[\"Stopped\"] = \"stopped\";\n})(WebsocketResponseType || (WebsocketResponseType = {}));\nvar CONTROL = {\n WRITE_INDEX: 0,\n FRAMES_AVAILABLE: 1,\n LOCK: 2\n};\nvar WebsocketClient = /** @class */ (function () {\n function WebsocketClient(ctx) {\n var _this = this;\n this.isContextStarted = false;\n this.isStartContextConfirmed = false;\n this.shouldResendLastFramesSent = false;\n this.buffer = new Float32Array(0);\n this.lastFramesSent = new Int16Array(0); // to re-send after switch context\n this.debug = false;\n this.initialized = false;\n this.onWebsocketClose = function (event) {\n _this.websocket = undefined;\n _this.connect(0);\n };\n this.onWebsocketOpen = function (_event) {\n if (_this.debug) {\n console.log('[SpeechlyClient]', 'websocket opened');\n }\n _this.workerCtx.postMessage({ type: 'WEBSOCKET_OPEN' });\n };\n this.onWebsocketError = function (_event) {\n if (_this.debug) {\n console.log('[SpeechlyClient]', 'websocket error');\n }\n _this.closeWebsocket();\n };\n this.onWebsocketMessage = function (event) {\n var response;\n try {\n response = JSON.parse(event.data);\n }\n catch (e) {\n console.error('[SpeechlyClient] Error parsing response from the server:', e);\n return;\n }\n if (response.type === WebsocketResponseType.Started) {\n _this.isStartContextConfirmed = true;\n if (_this.shouldResendLastFramesSent) {\n _this.resendLastFrames();\n _this.shouldResendLastFramesSent = false;\n }\n }\n _this.workerCtx.postMessage(response);\n };\n this.workerCtx = ctx;\n }\n WebsocketClient.prototype.init = function (apiUrl, authToken, targetSampleRate, debug) {\n if (this.initialized) {\n console.log('[SpeechlyClient]', 'already initialized');\n return;\n }\n this.debug = debug;\n if (this.debug) {\n console.log('[SpeechlyClient]', 'initialize worker');\n }\n this.apiUrl = apiUrl;\n this.authToken = authToken;\n this.targetSampleRate = targetSampleRate;\n this.initialized = true;\n this.connect(0);\n };\n WebsocketClient.prototype.setSourceSampleRate = function (sourceSampleRate) {\n this.sourceSampleRate = sourceSampleRate;\n this.resampleRatio = this.sourceSampleRate / this.targetSampleRate;\n if (this.debug) {\n console.log('[SpeechlyClient]', 'resampleRatio', this.resampleRatio);\n }\n if (this.resampleRatio > 1) {\n this.filter = generateFilter(this.sourceSampleRate, this.targetSampleRate, 127);\n }\n this.workerCtx.postMessage({ type: 'SOURSE_SAMPLE_RATE_SET_SUCCESS' });\n if (isNaN(this.resampleRatio)) {\n throw Error(\"resampleRatio is NaN source rate is \" + this.sourceSampleRate + \" and target rate is \" + this.targetSampleRate);\n }\n };\n WebsocketClient.prototype.setSharedArrayBuffers = function (controlSAB, dataSAB) {\n this.controlSAB = new Int32Array(controlSAB);\n this.dataSAB = new Float32Array(dataSAB);\n var audioHandleInterval = this.dataSAB.length / 32; // ms\n if (this.debug) {\n console.log('[SpeechlyClient]', 'Audio handle interval', audioHandleInterval, 'ms');\n }\n setInterval(this.sendAudioFromSAB.bind(this), audioHandleInterval);\n };\n WebsocketClient.prototype.connect = function (timeout) {\n if (timeout === void 0) { timeout = 1000; }\n if (this.debug) {\n console.log('[SpeechlyClient]', 'connect in ', timeout / 1000, 'sec');\n }\n setTimeout(this.initializeWebsocket.bind(this), timeout);\n };\n WebsocketClient.prototype.initializeWebsocket = function () {\n if (this.debug) {\n console.log('[SpeechlyClient]', 'connecting to ', this.apiUrl);\n }\n this.websocket = new WebSocket(this.apiUrl, this.authToken);\n this.websocket.addEventListener('open', this.onWebsocketOpen);\n this.websocket.addEventListener('message', this.onWebsocketMessage);\n this.websocket.addEventListener('error', this.onWebsocketError);\n this.websocket.addEventListener('close', this.onWebsocketClose);\n };\n WebsocketClient.prototype.isOpen = function () {\n return this.websocket !== undefined && this.websocket.readyState === this.websocket.OPEN;\n };\n WebsocketClient.prototype.resendLastFrames = function () {\n if (!this.isOpen()) {\n return Error('Cannot resend data through inactive websocket');\n }\n if (this.lastFramesSent.length > 0) {\n this.websocket.send(this.lastFramesSent);\n this.lastFramesSent = new Int16Array(0);\n }\n };\n WebsocketClient.prototype.sendAudio = function (audioChunk) {\n if (!this.isContextStarted) {\n return;\n }\n if (!this.isOpen()) {\n return Error('Cannot send data through inactive websocket');\n }\n if (audioChunk.length > 0) {\n if (this.resampleRatio > 1) {\n // Downsampling\n this.websocket.send(this.downsample(audioChunk));\n }\n else {\n this.websocket.send(float32ToInt16(audioChunk));\n }\n }\n };\n WebsocketClient.prototype.sendAudioFromSAB = function () {\n if (!this.isContextStarted) {\n this.controlSAB[CONTROL.FRAMES_AVAILABLE] = 0;\n this.controlSAB[CONTROL.WRITE_INDEX] = 0;\n return;\n }\n if (this.controlSAB == undefined) {\n return;\n }\n var framesAvailable = this.controlSAB[CONTROL.FRAMES_AVAILABLE];\n var lock = this.controlSAB[CONTROL.LOCK];\n if (lock == 0 && framesAvailable > 0) {\n var data = this.dataSAB.subarray(0, framesAvailable);\n this.controlSAB[CONTROL.FRAMES_AVAILABLE] = 0;\n this.controlSAB[CONTROL.WRITE_INDEX] = 0;\n if (data.length > 0) {\n var frames_1;\n if (this.resampleRatio > 1) {\n frames_1 = this.downsample(data);\n }\n else {\n frames_1 = float32ToInt16(data);\n }\n this.websocket.send(frames_1);\n // 16000 per second, 1000 in 100 ms\n // save last 250 ms\n if (this.lastFramesSent.length > 1024 * 4) {\n this.lastFramesSent = frames_1;\n }\n else {\n var concat = new Int16Array(this.lastFramesSent.length + frames_1.length);\n concat.set(this.lastFramesSent);\n concat.set(frames_1, this.lastFramesSent.length);\n this.lastFramesSent = concat;\n }\n }\n }\n };\n WebsocketClient.prototype.startContext = function (appId) {\n if (!this.isOpen()) {\n throw Error('Cant start context: websocket is inactive');\n }\n if (this.isContextStarted) {\n console.log('Cant start context: it has been already started');\n return;\n }\n this.isContextStarted = true;\n this.isStartContextConfirmed = false;\n if (appId !== undefined) {\n this.websocket.send(JSON.stringify({ event: 'start', appId: appId }));\n }\n else {\n this.websocket.send(JSON.stringify({ event: 'start' }));\n }\n };\n WebsocketClient.prototype.stopContext = function () {\n if (this.websocket == undefined) {\n throw Error('Cant start context: websocket is undefined');\n }\n if (!this.isContextStarted) {\n console.log('Cant stop context: it is not started');\n return;\n }\n this.isContextStarted = false;\n this.isStartContextConfirmed = false;\n var StopEventJSON = JSON.stringify({ event: 'stop' });\n this.websocket.send(StopEventJSON);\n };\n WebsocketClient.prototype.switchContext = function (newAppId) {\n if (this.websocket == undefined) {\n throw Error('Cant switch context: websocket is undefined');\n }\n if (!this.isContextStarted) {\n console.log('Cant switch context: it is not started');\n return;\n }\n if (newAppId == undefined) {\n console.log('Cant switch context: new app id is undefined');\n return;\n }\n this.isStartContextConfirmed = false;\n var StopEventJSON = JSON.stringify({ event: 'stop' });\n this.websocket.send(StopEventJSON);\n this.shouldResendLastFramesSent = true;\n this.websocket.send(JSON.stringify({ event: 'start', appId: newAppId }));\n };\n WebsocketClient.prototype.closeWebsocket = function () {\n if (this.websocket == null) {\n throw Error('Websocket is not open');\n }\n this.websocket.removeEventListener('open', this.onWebsocketOpen);\n this.websocket.removeEventListener('message', this.onWebsocketMessage);\n this.websocket.removeEventListener('error', this.onWebsocketError);\n this.websocket.removeEventListener('close', this.onWebsocketClose);\n this.websocket.close();\n };\n WebsocketClient.prototype.downsample = function (input) {\n var inputBuffer = new Float32Array(this.buffer.length + input.length);\n inputBuffer.set(this.buffer, 0);\n inputBuffer.set(input, this.buffer.length);\n var outputLength = Math.ceil((inputBuffer.length - this.filter.length) / this.resampleRatio);\n var outputBuffer = new Int16Array(outputLength);\n for (var i = 0; i < outputLength; i++) {\n var offset = Math.round(this.resampleRatio * i);\n var val = 0.0;\n for (var j = 0; j < this.filter.length; j++) {\n val += inputBuffer[offset + j] * this.filter[j];\n }\n outputBuffer[i] = val * (val < 0 ? 0x8000 : 0x7fff);\n }\n var remainingOffset = Math.round(this.resampleRatio * outputLength);\n if (remainingOffset < inputBuffer.length) {\n this.buffer = inputBuffer.subarray(remainingOffset);\n }\n else {\n this.buffer = new Float32Array(0);\n }\n return outputBuffer;\n };\n return WebsocketClient;\n}());\nvar ctx = self;\nvar websocketClient = new WebsocketClient(ctx);\nctx.onmessage = function (e) {\n switch (e.data.type) {\n case 'INIT':\n websocketClient.init(e.data.apiUrl, e.data.authToken, e.data.targetSampleRate, e.data.debug);\n break;\n case 'SET_SOURSE_SAMPLE_RATE':\n websocketClient.setSourceSampleRate(e.data.sourceSampleRate);\n break;\n case 'SET_SHARED_ARRAY_BUFFERS':\n websocketClient.setSharedArrayBuffers(e.data.controlSAB, e.data.dataSAB);\n break;\n case 'CLOSE':\n websocketClient.closeWebsocket();\n break;\n case 'START_CONTEXT':\n websocketClient.startContext(e.data.appId);\n break;\n case 'SWITCH_CONTEXT':\n websocketClient.switchContext(e.data.appId);\n break;\n case 'STOP_CONTEXT':\n websocketClient.stopContext();\n break;\n case 'AUDIO':\n websocketClient.sendAudio(e.data.payload);\n break;\n default:\n console.log('WORKER', e);\n }\n};\nfunction float32ToInt16(buffer) {\n var buf = new Int16Array(buffer.length);\n for (var l = 0; l < buffer.length; l++) {\n buf[l] = buffer[l] * (buffer[l] < 0 ? 0x8000 : 0x7fff);\n }\n return buf;\n}\nfunction generateFilter(sourceSampleRate, targetSampleRate, length) {\n if (length % 2 === 0) {\n throw Error('Filter length must be odd');\n }\n var cutoff = targetSampleRate / 2;\n var filter = new Float32Array(length);\n var sum = 0;\n for (var i = 0; i < length; i++) {\n var x = sinc(((2 * cutoff) / sourceSampleRate) * (i - (length - 1) / 2));\n sum += x;\n filter[i] = x;\n }\n for (var i = 0; i < length; i++) {\n filter[i] = filter[i] / sum;\n }\n return filter;\n}\nfunction sinc(x) {\n if (x === 0.0) {\n return 1.0;\n }\n var piX = Math.PI * x;\n return Math.sin(piX) / piX;\n}\n"; | ||
export default _default; |
@@ -91,3 +91,3 @@ "use strict"; | ||
if (isNaN(this.resampleRatio)) { | ||
throw Error('resampleRatio is NaN'); | ||
throw Error("resampleRatio is NaN source rate is " + this.sourceSampleRate + " and target rate is " + this.targetSampleRate); | ||
} | ||
@@ -94,0 +94,0 @@ }; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
186194
3284