Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions SpeechSynthesizer.ios.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
146 changes: 83 additions & 63 deletions SpeechSynthesizer.m
Original file line number Diff line number Diff line change
Expand Up @@ -2,150 +2,170 @@
#import "RCTUtils.h"
#import "RCTLog.h"

@interface SpeechSynthesizer()
@property (copy, nonatomic) RCTResponseSenderBlock stopCallback;
@end

@implementation SpeechSynthesizer

RCT_EXPORT_MODULE()

// 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

// 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