/* Copyright 2018-2022 Picovoice Inc. You may not use this file except in compliance with the license. A copy of the license is located in the "LICENSE" file accompanying this source. Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ import PorcupineWorker from 'web-worker:./porcupine_worker.ts'; import { PorcupineKeyword, PorcupineWorkerRequestInit, PorcupineWorkerResponse, } from '@picovoice/porcupine-web-core'; export default class PorcupineWorkerFactory { private constructor() { } /** * Create Porcupine web worker instances. The promise resolves when the worker is ready to process * voice data (perhaps from WebVoiceProcessor). * * @param accessKey - AccessKey generated by Picovoice Console * @param keywords - Builtin or Base64 representations of keywords and their sensitivities. * @param keywordDetectionCallback - User-defined callback invoked upon detection of the wake phrase. * The only input argument is the keyword label defined at initialization. * @param processErrorCallback - User-defined callback invoked if any error happens * while processing the audio stream. Its only input argument is the error message. */ public static async create( accessKey: string, keywords: Array | PorcupineKeyword | string, keywordDetectionCallback?: (label: string) => void, processErrorCallback?: (error: string) => void, start?: boolean ): Promise { // n.b. The *worker* creation is itself synchronous. But, inside the worker is an async // method of PorcupineFactory which is initializing. This means the worker is not actually ready // for voice processing immediately after instantiation. When its initialization completes, // we receive a special PorcupineWorkerMessageOut message and resolve the worker promise. const porcupineWorker = new PorcupineWorker(); const keywordArray = Array.isArray(keywords) ? keywords : [keywords]; const ppnInitCmd: PorcupineWorkerRequestInit = { command: 'init', accessKey: accessKey, keywords: keywordArray, start, }; porcupineWorker.postMessage(ppnInitCmd); const workerPromise = new Promise((resolve, reject) => { porcupineWorker.onmessage = function ( event: MessageEvent ): void { switch (event.data.command) { case 'ppn-ready': resolve(porcupineWorker); break; case 'ppn-failed': reject(event.data.message); break; case 'ppn-keyword': if (keywordDetectionCallback !== undefined) { keywordDetectionCallback(event.data.keywordLabel); } else { console.log(`Porcupine detected ${event.data.keywordLabel}`); } break; case 'ppn-error': if (processErrorCallback !== undefined) { processErrorCallback(event.data.message); } break; default: // eslint-disable-next-line no-console console.warn(`Unhandled message in main.js: ${event.data}`); break; } }; }); return workerPromise; } }