UNPKG

react-native-wakeword

Version:

Voice/Wake-word detection library for React Native

316 lines (271 loc) 10.5 kB
// KeyWordRNBridge.js import { NativeModules, NativeEventEmitter, Platform } from 'react-native'; const { KeyWordRNBridge } = NativeModules; const keywordRNBridgeEmitter = new NativeEventEmitter(KeyWordRNBridge); if (KeyWordRNBridge) { console.log("KeyWordRNBridge is loaded:", KeyWordRNBridge); } else { console.error("KeyWordRNBridge is not linked correctly."); } export class KeyWordRNBridgeInstance { instanceId; listeners = []; isFirstInstance = false; constructor(instanceId, isSticky) { this.instanceId = instanceId; this.isSticky = isSticky; } async createInstanceMulti(modelNames, thresholds, bufferCnts, msBetweenCallbacks) { const instance = await KeyWordRNBridge.createInstanceMulti( this.instanceId, modelNames, thresholds, bufferCnts, msBetweenCallbacks ); if (instance && this.isFirstInstance) { this.isFirstInstance = false; await KeyWordRNBridge.startForegroundService(this.instanceId); } return instance; } async createInstance(modelName, threshold, bufferCnt) { const instance = await KeyWordRNBridge.createInstance( this.instanceId, modelName, threshold, bufferCnt); if (instance && this.isFirstInstance) { this.isFirstInstance = false; await KeyWordRNBridge.startForegroundService(this.instanceId); } return instance; } // 1) Voice props (parity with VAD) async getVoiceProps() { try { const voiceProps = await KeyWordRNBridge.getVoiceProps(this.instanceId); return { error: voiceProps.error, voiceProbability: voiceProps.voiceProbability, lastTimeHumanVoiceHeard: voiceProps.lastTimeHumanVoiceHeard, }; } catch (error) { console.error('Error getting voice properties:', error); throw error; } } // 2) Silent VAD control (iOS-only, optional but useful) async startSilentVADDetection() { if (Platform.OS === 'ios') { return await KeyWordRNBridge.startSilentVADDetection(this.instanceId); } } async stopSilentVADDetection() { if (Platform.OS === 'ios') { return await KeyWordRNBridge.stopSilentVADDetection(this.instanceId); } } // 3) Explicit VAD start/stop (if exposed by your native bridge) async startVADDetection() { return await KeyWordRNBridge.startVADDetection(this.instanceId); } async stopVADDetection() { return await KeyWordRNBridge.stopVADDetection(this.instanceId); } // 4) (Optional) VAD event listener if your native layer emits it onVADDetectionEvent(callback) { const listener = keywordRNBridgeEmitter.addListener('onVADDetectionEvent', (event) => { if (event.instanceId === this.instanceId) { callback(event.phrase); } }); this.listeners.push(listener); return listener; } // Configure VAD runtime parameters async setVADParams(threshold, msWindow) { return await KeyWordRNBridge.setVADParams(this.instanceId, threshold, msWindow); } async getVADParams() { // implement only if native exposes it return await KeyWordRNBridge.getVADParams(this.instanceId); } async setKeywordDetectionLicense(license) { return await KeyWordRNBridge.setKeywordDetectionLicense(this.instanceId, license); } async replaceKeywordDetectionModel(modelName, threshold, bufferCnt) { return KeyWordRNBridge.replaceKeywordDetectionModel(this.instanceId, modelName, threshold, bufferCnt); } /*startForegroundService() { return KeyWordRNBridge.startForegroundService(this.instanceId); } stopForegroundService() { return KeyWordRNBridge.stopForegroundService(this.instanceId); }*/ async setKeywordLicense(license) { return KeyWordRNBridge.setKeywordLicense(this.instanceId, license); } /** * @param {any} threshold * @param {string | boolean | undefined} [speakerVerificationEnrollmentJsonOrPathOrSetActive] * @param {boolean} [setActive] * @param {boolean} [duckOthers] * @param {boolean} [mixWithOthers] * @param {boolean} [defaultToSpeaker] */ async startKeywordDetection( threshold, speakerVerificationEnrollmentJsonOrPathOrSetActive = undefined, setActive = true, duckOthers = false, mixWithOthers = true, defaultToSpeaker = true ) { /** @type {string | undefined} */ let speakerVerificationEnrollmentJsonOrPath = undefined; let resolvedSetActive = setActive; let resolvedDuckOthers = duckOthers; let resolvedMixWithOthers = mixWithOthers; let resolvedDefaultToSpeaker = defaultToSpeaker; if ( typeof speakerVerificationEnrollmentJsonOrPathOrSetActive === 'string' || speakerVerificationEnrollmentJsonOrPathOrSetActive == null ) { speakerVerificationEnrollmentJsonOrPath = speakerVerificationEnrollmentJsonOrPathOrSetActive; } else { resolvedSetActive = speakerVerificationEnrollmentJsonOrPathOrSetActive; } if (Platform.OS === 'ios') { if (speakerVerificationEnrollmentJsonOrPath != null) { return KeyWordRNBridge.startKeywordDetectionWithSpeakerVerification( this.instanceId, threshold, speakerVerificationEnrollmentJsonOrPath, resolvedSetActive, resolvedDuckOthers, resolvedMixWithOthers, resolvedDefaultToSpeaker ); } return KeyWordRNBridge.startKeywordDetection( this.instanceId, threshold, resolvedSetActive, resolvedDuckOthers, resolvedMixWithOthers, resolvedDefaultToSpeaker ); } else { return KeyWordRNBridge.startKeywordDetection( this.instanceId, threshold, speakerVerificationEnrollmentJsonOrPath ); } } async getRecordingWavArray() { return await KeyWordRNBridge.getRecordingWavArray(this.instanceId); } async getRecordingWav() { return await KeyWordRNBridge.getRecordingWav(this.instanceId); } async stopKeywordDetection() { return KeyWordRNBridge.stopKeywordDetection(this.instanceId); } async pauseDetection(stopMic = false) { // XXX - check if needs await // return await KeyWordRNBridge.pauseDetection(this.instanceId, stopMic); return await KeyWordRNBridge.pauseDetection(this.instanceId, stopMic); } async unPauseDetection() { // XXX BUG - FIX pause with false not working on unpause on Android. if (Platform.OS === 'android') { await KeyWordRNBridge.unPauseDetection(this.instanceId); await KeyWordRNBridge.pauseDetection(this.instanceId, true); } // Check if needs await // return await KeyWordRNBridge.unPauseDetection(this.instanceId); return await KeyWordRNBridge.unPauseDetection(this.instanceId); } async destroyInstance() { return KeyWordRNBridge.destroyInstance(this.instanceId); } onKeywordDetectionEvent(callback) { const listener = keywordRNBridgeEmitter.addListener('onKeywordDetectionEvent', (event) => { if (event.instanceId === this.instanceId) { console.log("event == .", event); if (Platform.OS === 'ios') { console.log("event == .", event); callback(event.info); } else { callback(event.phrase); } } }); this.listeners.push(listener); return listener; } removeListeners() { this.listeners.forEach((listener) => listener.remove()); this.listeners = []; } } export const removeAllRNBridgeListeners = async () => { keywordRNBridgeEmitter.removeAllListeners('onKeywordDetectionEvent'); keywordRNBridgeEmitter.removeAllListeners('onVADDetectionEvent'); // NEW } export const pauseDetection = async (instanceId, stopMic = false) => { return KeyWordRNBridge.pauseDetection(instanceId, stopMic); }; export const unPauseDetection = async (instanceId) => { return KeyWordRNBridge.unPauseDetection(instanceId); }; export const createKeyWordRNBridgeInstance = async (instanceId, isSticky) => { return await new KeyWordRNBridgeInstance(instanceId, isSticky); }; export const enableDucking = async () => { if (Platform.OS === 'ios') { await KeyWordRNBridge.enableAggressiveDucking(); } } export const disableDucking = async () => { if (Platform.OS === 'ios') { await KeyWordRNBridge.disableDucking(); } } export const restartListeningAfterDucking = async () => { if (Platform.OS === 'ios') { await KeyWordRNBridge.restartListeningAfterDucking(); } } export const initAudioSessAndDuckManage = async () => { if (Platform.OS === 'ios') { await KeyWordRNBridge.initAudioSessAndDuckManage(); } } export const hasIOSMicPermissions = async () => { return await KeyWordRNBridge.hasMicPermissions(); } export const requestIOSMicPermissions = async (wait_timeout) => { return await KeyWordRNBridge.requestMicPermissions(wait_timeout); } export const hasIOSSpeechRecognitionPermissions = async () => { return await KeyWordRNBridge.hasSpeechRecognitionPermissions(); } export const requestIOSSpeechRecognitionPermissions = async (wait_timeout) => { return await KeyWordRNBridge.requestSpeechRecognitionPermissions(wait_timeout); } export const disableDuckingAndCleanup = async () => { if (Platform.OS === 'ios') { await KeyWordRNBridge.disableDuckingAndCleanup(); } } // NEW: global audio routing config setter (per package, not per instance) export const setWakewordAudioRoutingConfig = async (config) => { if (Platform.OS === 'ios') { // Native: implement KeyWordRNBridge.setAudioRoutingConfig(jsonString) return KeyWordRNBridge.setAudioRoutingConfig(JSON.stringify(config)); } };