Skip to content
This repository has been archived by the owner on May 23, 2023. It is now read-only.

Fix hasPermission() always returning success on iOS #90

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
176 changes: 100 additions & 76 deletions src/ios/SpeechRecognition.m
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#define MESSAGE_RESTRICTED @"Speech recognition restricted on this device"
#define MESSAGE_NOT_DETERMINED @"Speech recognition not determined on this device"
#define MESSAGE_ACCESS_DENIED_MICROPHONE @"User denied access to microphone"
#define MESSAGE_NOT_DETERMINED_MICROPHONE @"Microphone access not determined on this device"
#define MESSAGE_ONGOING @"Ongoing speech recognition"

@interface SpeechRecognition()
Expand All @@ -33,9 +34,9 @@ - (void)isRecognitionAvailable:(CDVInvokedUrlCommand*)command {
CDVPluginResult *pluginResult = nil;

if ([SFSpeechRecognizer class]) {
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsBool:YES];
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
} else {
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsBool:NO];
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR];
}

[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
Expand All @@ -58,100 +59,97 @@ - (void)startListening:(CDVInvokedUrlCommand*)command {
return;
}

[[AVAudioSession sharedInstance] requestRecordPermission:^(BOOL granted){
if (!granted) {
NSLog(@"startListening() microphone access not authorized");
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:MESSAGE_ACCESS_DENIED_MICROPHONE];
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
return;
}
AVAudioSessionRecordPermission micStatus = [[AVAudioSession sharedInstance] recordPermission];
if (micStatus != AVAudioSessionRecordPermissionGranted) {
NSLog(@"startListening() microphone access not authorized");
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:MESSAGE_MISSING_PERMISSION];
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
return;
}

NSString* language = [command argumentAtIndex:0 withDefault:DEFAULT_LANGUAGE];
int matches = [[command argumentAtIndex:1 withDefault:@(DEFAULT_MATCHES)] intValue];
BOOL showPartial = [[command argumentAtIndex:3 withDefault:@(NO)] boolValue];
NSString* language = [command argumentAtIndex:0 withDefault:DEFAULT_LANGUAGE];
int matches = [[command argumentAtIndex:1 withDefault:@(DEFAULT_MATCHES)] intValue];
BOOL showPartial = [[command argumentAtIndex:3 withDefault:@(NO)] boolValue];

NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:language];
self.speechRecognizer = [[SFSpeechRecognizer alloc] initWithLocale:locale];
self.audioEngine = [[AVAudioEngine alloc] init];
NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:language];
self.speechRecognizer = [[SFSpeechRecognizer alloc] initWithLocale:locale];
self.audioEngine = [[AVAudioEngine alloc] init];

// Cancel the previous task if it's running.
if ( self.recognitionTask ) {
[self.recognitionTask cancel];
self.recognitionTask = nil;
}
// Cancel the previous task if it's running.
if ( self.recognitionTask ) {
[self.recognitionTask cancel];
self.recognitionTask = nil;
}

AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker error:nil];
[audioSession setMode:AVAudioSessionModeDefault error:nil];
[audioSession setActive:YES withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker error:nil];
[audioSession setMode:AVAudioSessionModeDefault error:nil];
[audioSession setActive:YES withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];

self.recognitionRequest = [[SFSpeechAudioBufferRecognitionRequest alloc] init];
self.recognitionRequest.shouldReportPartialResults = showPartial;
self.recognitionRequest = [[SFSpeechAudioBufferRecognitionRequest alloc] init];
self.recognitionRequest.shouldReportPartialResults = showPartial;

AVAudioInputNode *inputNode = self.audioEngine.inputNode;
AVAudioFormat *format = [inputNode outputFormatForBus:0];
AVAudioInputNode *inputNode = self.audioEngine.inputNode;
AVAudioFormat *format = [inputNode outputFormatForBus:0];

self.recognitionTask = [self.speechRecognizer recognitionTaskWithRequest:self.recognitionRequest resultHandler:^(SFSpeechRecognitionResult *result, NSError *error) {
self.recognitionTask = [self.speechRecognizer recognitionTaskWithRequest:self.recognitionRequest resultHandler:^(SFSpeechRecognitionResult *result, NSError *error) {

if ( result ) {
if ( result ) {

NSMutableArray *resultArray = [[NSMutableArray alloc] init];
NSMutableArray *resultArray = [[NSMutableArray alloc] init];

int counter = 0;
for ( SFTranscription *transcription in result.transcriptions ) {
if (matches > 0 && counter < matches) {
[resultArray addObject:transcription.formattedString];
}
counter++;
int counter = 0;
for ( SFTranscription *transcription in result.transcriptions ) {
if (matches > 0 && counter < matches) {
[resultArray addObject:transcription.formattedString];
}
counter++;
}

NSArray *transcriptions = [NSArray arrayWithArray:resultArray];
NSArray *transcriptions = [NSArray arrayWithArray:resultArray];

NSLog(@"startListening() recognitionTask result array: %@", transcriptions.description);
NSLog(@"startListening() recognitionTask result array: %@", transcriptions.description);

CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:transcriptions];
if (showPartial){
[pluginResult setKeepCallbackAsBool:YES];
}
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:transcriptions];
if (showPartial){
[pluginResult setKeepCallbackAsBool:YES];
}
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}

if ( error ) {
NSLog(@"startListening() recognitionTask error: %@", error.description);
if ( error ) {
NSLog(@"startListening() recognitionTask error: %@", error.description);

[self.audioEngine stop];
[self.audioEngine.inputNode removeTapOnBus:0];
[self.audioEngine stop];
[self.audioEngine.inputNode removeTapOnBus:0];

self.recognitionRequest = nil;
self.recognitionTask = nil;
self.recognitionRequest = nil;
self.recognitionTask = nil;

CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:error.description];
if (showPartial){
[pluginResult setKeepCallbackAsBool:YES];
}
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:error.description];
if (showPartial){
[pluginResult setKeepCallbackAsBool:YES];
}
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}

if ( result.isFinal ) {
NSLog(@"startListening() recognitionTask isFinal");

[self.audioEngine stop];
[self.audioEngine.inputNode removeTapOnBus:0];
if ( result.isFinal ) {
NSLog(@"startListening() recognitionTask isFinal");

self.recognitionRequest = nil;
self.recognitionTask = nil;
}
}];

[inputNode installTapOnBus:0 bufferSize:1024 format:format block:^(AVAudioPCMBuffer *buffer, AVAudioTime *when) {
[self.recognitionRequest appendAudioPCMBuffer:buffer];
}];
[self.audioEngine stop];
[self.audioEngine.inputNode removeTapOnBus:0];

[self.audioEngine prepare];
[self.audioEngine startAndReturnError:nil];
self.recognitionRequest = nil;
self.recognitionTask = nil;
}
}];

[inputNode installTapOnBus:0 bufferSize:1024 format:format block:^(AVAudioPCMBuffer *buffer, AVAudioTime *when) {
[self.recognitionRequest appendAudioPCMBuffer:buffer];
}];

[self.audioEngine prepare];
[self.audioEngine startAndReturnError:nil];
}

- (void)stopListening:(CDVInvokedUrlCommand*)command {
Expand Down Expand Up @@ -183,18 +181,44 @@ - (void)getSupportedLanguages:(CDVInvokedUrlCommand*)command {

- (void)hasPermission:(CDVInvokedUrlCommand*)command {
SFSpeechRecognizerAuthorizationStatus status = [SFSpeechRecognizer authorizationStatus];
BOOL speechAuthGranted = (status == SFSpeechRecognizerAuthorizationStatusAuthorized);
CDVPluginResult *pluginResult = nil;
BOOL speechAuthGranted = NO;

switch (status) {
case SFSpeechRecognizerAuthorizationStatusAuthorized:
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
speechAuthGranted = YES;
break;
case SFSpeechRecognizerAuthorizationStatusDenied:
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:MESSAGE_ACCESS_DENIED];
break;
case SFSpeechRecognizerAuthorizationStatusRestricted:
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:MESSAGE_RESTRICTED];
break;
case SFSpeechRecognizerAuthorizationStatusNotDetermined:
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:MESSAGE_NOT_DETERMINED];
break;
}

if (!speechAuthGranted) {
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsBool:NO];
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
return;
}

[[AVAudioSession sharedInstance] requestRecordPermission:^(BOOL granted){
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsBool:granted];
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}];
AVAudioSessionRecordPermission micStatus = [[AVAudioSession sharedInstance] recordPermission];

switch (micStatus) {
case AVAudioSessionRecordPermissionGranted:
break;
case AVAudioSessionRecordPermissionDenied:
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:MESSAGE_ACCESS_DENIED_MICROPHONE];
break;
case AVAudioSessionRecordPermissionUndetermined:
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:MESSAGE_NOT_DETERMINED_MICROPHONE];
break;
}

[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}

- (void)requestPermission:(CDVInvokedUrlCommand*)command {
Expand Down