【Objective-C】AWSのAmazonPollyでText to Speachを実装する方法【iOS11】

2020年8月27日

AWSにあるAmazoPollyを使い文字を読み上げる機能を作成する方法をご紹介します。

1. PoolIDの作成

AWSの管理画面からAmazonPollyのPoolIDを作成します

ap-sortheast-1:xxxxxxxxx-xxxxxxxx-xxxxxxxx

このような値がPoolIDになります。

2. ロールの設定

次にAWSの管理画面より、作成したPoolIDにロールを設定してください。
ロールの設定をしないと、音声ファイル取得ようのurlを叩いても

CognitoIdentityCredentials is not authorized to perform: polly:SynthesizeSpeech

というエラーになり音声ファイルをダウンロードすることができません。

3. CocoapodによるAWSPollyのインストール

pod 'AWSPolly'

Podfileに追記してください。

pod install

ターミナルでpodを更新します。

4. プログラムの実装

#import <AWSPolly/AWSPolly.h>
#import <AVFoundation/AVFoundation.h>

AWSPollyと再生用PlayerのためのAVFoundationをimportします。

@interface ViewController () {
   // 音声再生用のプレイヤーを用意
    AVAudioPlayer *audioPlayer;
}

音声再生用のプレイヤーを用意します。

- (void)textToSpeach:(NSString *)text {
    AWSCognitoCredentialsProvider *credentialsProvider = [[AWSCognitoCredentialsProvider alloc] initWithRegionType:AWSRegionAPSoutheast1
                                                                                                    identityPoolId:@"ap-sortheast-1:xxxxxxxxx-xxxxxxxx-xxxxxxxx"];
    AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc] initWithRegion:AWSRegionAPSoutheast1
                                                                         credentialsProvider:credentialsProvider];
    [AWSServiceManager defaultServiceManager].defaultServiceConfiguration = configuration;
    
    AWSPollySynthesizeSpeechURLBuilderRequest *input = [[AWSPollySynthesizeSpeechURLBuilderRequest alloc] init];
    input.text = text;
    input.outputFormat = AWSPollyOutputFormatMp3;
    input.voiceId = AWSPollyVoiceIdMizuki;
    AWSTask *builder = [[AWSPollySynthesizeSpeechURLBuilder defaultPollySynthesizeSpeechURLBuilder] getPreSignedURL:input];
    
    [builder continueWithBlock:^id(AWSTask *awsTask){
        // 非同期処理にしないと音声ファイルのダウンロードにより画面が止まる
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            
            // 音声ファイル取得用urlの取得
            NSURL *url = awsTask.result;
            // 音声ファイルの取得
            NSData *data = [NSData dataWithContentsOfURL:url];
            
            NSError *error = nil;
            audioPlayer = [[AVAudioPlayer alloc] initWithData:data error:&error];
            
            if (error) {
                NSLog(@"error:%@",error);
            }
            else {
                NSLog(@"play")
                [audioPlayer play];
            }
        });
        
        return nil;
    }];
}

PoolIDとRegionを設定して任意の文字を送るだけです。
注意点として、AWSより取得したURLからさらに音声ファイルを取得しているのですが、音声ファイルを取得するタイミングでサブスレッドにしています。

この処理を入れておかないと、音声ファイルのダウンロードが完了するまでアプリが固まります。
必ずサブスレッド化しておきましょう。

4. まとめ

全ての実装コードは以下になります。

#import "ViewController.h"

#import <AWSPolly/AWSPolly.h>
#import <AVFoundation/AVFoundation.h>

@interface ViewController () {
    AVAudioPlayer *audioPlayer;
}

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self textToSpeach:@"こんにちわ"];
}

- (void)textToSpeach:(NSString *)text {
    AWSCognitoCredentialsProvider *credentialsProvider = [[AWSCognitoCredentialsProvider alloc] initWithRegionType:AWSRegionAPSoutheast1
                                                                                                    identityPoolId:@"ap-sortheast-1:xxxxxxxxx-xxxxxxxx-xxxxxxxx"];
    AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc] initWithRegion:AWSRegionAPSoutheast1
                                                                         credentialsProvider:credentialsProvider];
    [AWSServiceManager defaultServiceManager].defaultServiceConfiguration = configuration;
    
    AWSPollySynthesizeSpeechURLBuilderRequest *input = [[AWSPollySynthesizeSpeechURLBuilderRequest alloc] init];
    input.text = text;
    input.outputFormat = AWSPollyOutputFormatMp3;
    input.voiceId = AWSPollyVoiceIdMizuki;
    AWSTask *builder = [[AWSPollySynthesizeSpeechURLBuilder defaultPollySynthesizeSpeechURLBuilder] getPreSignedURL:input];
    
    [builder continueWithBlock:^id(AWSTask *awsTask){
        // 非同期処理にしないと音声ファイルのダウンロードにより画面が止まる
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            
            // 音声ファイル取得用urlの取得
            NSURL *url = awsTask.result;
            // 音声ファイルの取得
            NSData *data = [NSData dataWithContentsOfURL:url];
            
            NSError *error = nil;
            audioPlayer = [[AVAudioPlayer alloc] initWithData:data error:&error];
            
            if (error) {
                NSLog(@"error:%@",error);
            }
            else {
                NSLog(@"play")
                [audioPlayer play];
            }
        });
        
        return nil;
    }];
}

@end