diff --git a/SpeechSynthesizer.ios.js b/SpeechSynthesizer.ios.js index e148dda..c545d5d 100644 --- a/SpeechSynthesizer.ios.js +++ b/SpeechSynthesizer.ios.js @@ -62,6 +62,21 @@ var SpeechSynthesizer = { }); }); }, + + isStopped() { + return new Promise(function(resolve, reject) { + NativeSpeechSynthesizer.isStopped(function(error, finished) { + if (error) { + return reject(error); + } + if (finished === 1) { + resolve(true); + } else { + resolve(false); + } + }); + }); + }, supportedVoices() { return new Promise(function(resolve, reject) { diff --git a/SpeechSynthesizer.m b/SpeechSynthesizer.m index f7de53c..1453cc4 100644 --- a/SpeechSynthesizer.m +++ b/SpeechSynthesizer.m @@ -2,6 +2,10 @@ #import "RCTUtils.h" #import "RCTLog.h" +@interface SpeechSynthesizer() +@property (copy, nonatomic) RCTResponseSenderBlock stopCallback; +@end + @implementation SpeechSynthesizer RCT_EXPORT_MODULE() @@ -9,104 +13,110 @@ @implementation SpeechSynthesizer // Speak RCT_EXPORT_METHOD(speakUtterance:(NSDictionary *)args callback:(RCTResponseSenderBlock)callback) { - // Error if self.synthesizer was already initialized - if (self.synthesizer) { - return callback(@[RCTMakeError(@"There is a speech in progress. Use the `paused` method to know if it's paused.", nil, nil)]); - } + // Error if self.synthesizer was already initialized + if (self.synthesizer) { + return callback(@[RCTMakeError(@"There is a speech in progress. Use the `paused` method to know if it's paused.", nil, nil)]); + } - // Set args to variables - NSString *text = args[@"text"]; - NSString *voice = args[@"voice"]; - NSNumber *rate = args[@"rate"]; + // Set args to variables + NSString *text = args[@"text"]; + NSString *voice = args[@"voice"]; + NSNumber *rate = args[@"rate"]; - // Error if no text is passed - if (!text) { - RCTLogError(@"[Speech] You must specify a text to speak."); - return; - } + // Error if no text is passed + if (!text) { + RCTLogError(@"[Speech] You must specify a text to speak."); + return; + } - // Set default voice - NSString *voiceLanguage; + // Set default voice + NSString *voiceLanguage; - // Set voice if provided - if (voice) { - voiceLanguage = voice; + // Set voice if provided + if (voice) { + voiceLanguage = voice; - // Fallback to en-US - } else { - voiceLanguage = @"en-US"; - } + // Fallback to en-US + } else { + voiceLanguage = @"en-US"; + } - // Setup utterance and voice - AVSpeechUtterance *utterance = [[AVSpeechUtterance alloc] initWithString:text]; + // Setup utterance and voice + AVSpeechUtterance *utterance = [[AVSpeechUtterance alloc] initWithString:text]; - utterance.voice = [AVSpeechSynthesisVoice voiceWithLanguage:voiceLanguage]; + utterance.voice = [AVSpeechSynthesisVoice voiceWithLanguage:voiceLanguage]; - if (rate) { - utterance.rate = [rate doubleValue]; - } + if (rate) { + utterance.rate = [rate doubleValue]; + } - self.synthesizer = [[AVSpeechSynthesizer alloc] init]; - self.synthesizer.delegate = self; + self.synthesizer = [[AVSpeechSynthesizer alloc] init]; + self.synthesizer.delegate = self; - // Speak - [self.synthesizer speakUtterance:utterance]; + // Speak + [self.synthesizer speakUtterance:utterance]; - // Return that the speach has started - callback(@[[NSNull null], @true]); + // Return that the speach has started + callback(@[[NSNull null], @true]); } // Stops synthesizer RCT_EXPORT_METHOD(stopSpeakingAtBoundary) { - if (self.synthesizer) { - [self.synthesizer stopSpeakingAtBoundary:AVSpeechBoundaryImmediate]; - } + if (self.synthesizer) { + [self.synthesizer stopSpeakingAtBoundary:AVSpeechBoundaryImmediate]; + } } // Pauses synthesizer RCT_EXPORT_METHOD(pauseSpeakingAtBoundary) { - if (self.synthesizer) { - [self.synthesizer pauseSpeakingAtBoundary:AVSpeechBoundaryImmediate]; - } + if (self.synthesizer) { + [self.synthesizer pauseSpeakingAtBoundary:AVSpeechBoundaryImmediate]; + } } // Resumes synthesizer RCT_EXPORT_METHOD(continueSpeakingAtBoundary) { - if (self.synthesizer) { - [self.synthesizer continueSpeaking]; - } + if (self.synthesizer) { + [self.synthesizer continueSpeaking]; + } } // Returns false if synthesizer is paued RCT_EXPORT_METHOD(paused:(RCTResponseSenderBlock)callback) { - if (self.synthesizer.paused) { - callback(@[@true]); - } else { - callback(@[@false]); - } + if (self.synthesizer.paused) { + callback(@[@true]); + } else { + callback(@[@false]); + } } // Returns true if synthesizer is speaking RCT_EXPORT_METHOD(speaking:(RCTResponseSenderBlock)callback) { - if (self.synthesizer.speaking) { - callback(@[@true]); - } else { - callback(@[@false]); - } + if (self.synthesizer.speaking) { + callback(@[@true]); + } else { + callback(@[@false]); + } } // Returns available voices RCT_EXPORT_METHOD(speechVoices:(RCTResponseSenderBlock)callback) { - NSArray *speechVoices = [AVSpeechSynthesisVoice speechVoices]; - NSArray *locales = [speechVoices valueForKey:@"language"]; + NSArray *speechVoices = [AVSpeechSynthesisVoice speechVoices]; + NSArray *locales = [speechVoices valueForKey:@"language"]; + + callback(@[[NSNull null], locales]); +} - callback(@[[NSNull null], locales]); +// Returns true when sound is stopped +RCT_EXPORT_METHOD(isStopped:(RCTResponseSenderBlock)callback) +{ + self.stopCallback = callback; } // Delegate @@ -114,38 +124,48 @@ @implementation SpeechSynthesizer // Finished Handler -(void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer didFinishSpeechUtterance:(AVSpeechUtterance *)utterance { - NSLog(@"Speech finished"); - self.synthesizer = nil; + NSLog(@"Speech finished"); + self.synthesizer = nil; + if (self.stopCallback) { + self.stopCallback(@[@false]); + } + self.stopCallback = nil; } // Started Handler -(void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer didStartSpeechUtterance:(AVSpeechUtterance *)utterance { - NSLog(@"Speech started"); + NSLog(@"Speech started"); } // Paused Handler -(void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer didPauseSpeechUtterance:(AVSpeechUtterance *)utterance { - NSLog(@"Speech paused"); + NSLog(@"Speech paused"); } // Resumed Handler -(void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer didContinueSpeechUtterance:(AVSpeechUtterance *)utterance { - NSLog(@"Speech resumed"); + NSLog(@"Speech resumed"); } // Word Handler -(void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer willSpeakRangeOfSpeechString:(NSRange)characterRange utterance:(AVSpeechUtterance *)utterance { - NSLog(@"Started word"); + NSLog(@"Started word"); } // Cancelled Handler -(void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer didCancelSpeechUtterance:(AVSpeechUtterance *)utterance { - NSLog(@"Speech cancelled"); + NSLog(@"Speech cancelled"); + self.synthesizer = nil; + if (self.stopCallback) { + self.stopCallback(@[@false]); + } + self.stopCallback = nil; + } @end