UNPKG

2.81 kBJavaScriptView Raw
1// @flow
2
3import { NativeModules, NativeEventEmitter, Platform } from 'react-native';
4
5const { ExponentSpeech } = NativeModules;
6const SpeechEventEmitter = new NativeEventEmitter(ExponentSpeech);
7
8type Options = {
9 language?: string,
10 pitch?: number,
11 rate?: number,
12 onStart?: () => void,
13 onStopped?: () => void,
14 onDone?: () => void,
15 onError?: string => void,
16};
17
18let _GLOBAL_ID = 1;
19
20const _CALLBACKS = {};
21let _LISTENERS_SET = false;
22
23function _unregisterListenersIfNeeded() {
24 if (Object.keys(_CALLBACKS).length === 0) {
25 removeSpeakingListener('Exponent.speakingStarted');
26 removeSpeakingListener('Exponent.speakingDone');
27 removeSpeakingListener('Exponent.speakingStopped');
28 removeSpeakingListener('Exponent.speakingError');
29 _LISTENERS_SET = false;
30 }
31}
32
33function _registerListenersIfNeeded() {
34 if (_LISTENERS_SET) return;
35 _LISTENERS_SET = true;
36 setSpeakingListener('Exponent.speakingStarted', ({ id }) => {
37 const options = _CALLBACKS[id];
38 if (options && options.onStart) {
39 options.onStart();
40 }
41 });
42 setSpeakingListener('Exponent.speakingDone', ({ id }) => {
43 const options = _CALLBACKS[id];
44 if (options && options.onDone) {
45 options.onDone();
46 }
47 delete _CALLBACKS[id];
48 _unregisterListenersIfNeeded();
49 });
50 setSpeakingListener('Exponent.speakingStopped', ({ id }) => {
51 const options = _CALLBACKS[id];
52 if (options && options.onStopped) {
53 options.onStopped();
54 }
55 delete _CALLBACKS[id];
56 _unregisterListenersIfNeeded();
57 });
58 setSpeakingListener('Exponent.speakingError', ({ id, error }) => {
59 const options = _CALLBACKS[id];
60 if (options && options.onError) {
61 options.onError(error);
62 }
63 delete _CALLBACKS[id];
64 _unregisterListenersIfNeeded();
65 });
66}
67
68export function speak(text: string, options: Options = {}) {
69 const id = _GLOBAL_ID++;
70 _CALLBACKS[id] = options;
71 _registerListenersIfNeeded();
72 ExponentSpeech.speak(String(id), text, options);
73}
74
75export async function isSpeakingAsync(): Promise<boolean> {
76 return await ExponentSpeech.isSpeaking();
77}
78
79export function stop() {
80 ExponentSpeech.stop();
81}
82
83export function pause() {
84 if (Platform.OS === 'ios') {
85 ExponentSpeech.pause();
86 } else {
87 throw new Error('Speech.pause is not available on Android');
88 }
89}
90
91export function resume() {
92 if (Platform.OS === 'ios') {
93 ExponentSpeech.resume();
94 } else {
95 throw new Error('Speech.resume is not available on Android');
96 }
97}
98
99function setSpeakingListener(eventName, callback) {
100 if (SpeechEventEmitter.listeners(eventName).length > 0) {
101 SpeechEventEmitter.removeAllListeners(eventName);
102 }
103 SpeechEventEmitter.addListener(eventName, callback);
104}
105
106function removeSpeakingListener(eventName) {
107 SpeechEventEmitter.removeAllListeners(eventName);
108}