watchOS 2 のオーディオ録音、再生機能を利用する

以前から音声からのテキスト入力機能（Dectation）として Apple Watch のマイクを利用することはできましたが、watchOS 2 より、WKInterfaceController に新たに **音声を録音してファイル出力する UI** を表示するメソッドが追加されました。

```swift:
func presentAudioRecordingControllerWithOutputURL(_ URL: NSURL,
                                           preset preset: WKAudioRecordingPreset,
                                  maximumDuration maximumDuration: NSTimeInterval,
                                      actionTitle actionTitle: String?,
                                       completion completion: (Bool,
                                                           NSError?) -> Void)
```

こんな感じの UI で録音することができます。

![recorder.jpg](https://qiita-image-store.s3.amazonaws.com/0/3180/e5cc1af4-e037-38b6-578c-71d979c60d32.jpeg)

（公開されているWWDCセッションの動画より）


##実装方法

###Swift

まず、オーディオファイルを出力する先の NSURL オブジェクトを生成しておきます。

```
let filePaths = NSSearchPathForDirectoriesInDomains(
    NSSearchPathDirectory.DocumentDirectory,
    NSSearchPathDomainMask.UserDomainMask,
    true)
let documentDir = filePaths.first!
let filePath = documentDir + "rec.m4a"
let fileUrl = NSURL.fileURLWithPath(filePath)
```

ファイルの拡張子は .wav, .mp4, .m4a が指定でき、これが録音するオーディオのタイプを決定します。


`presentAudioRecordingControllerWithOutputURL:preset:maximumDuration:actionTitle:completion:` メソッドを次のように呼びます。

```
self.presentAudioRecordingControllerWithOutputURL(
    fileUrl,
    preset: WKAudioRecordingPreset.WideBandSpeech,
    maximumDuration: 5.0,
    actionTitle: "SomeTitle") { (didSave, error) -> Void in
        
        print("didSave:\(didSave), error:\(error)")
}
```

第2引数の `preset` は録音品質を指定するもので、上記以外に `NarrowBandSpeech`, `HighQualityAudio` を渡せます。



###Objective-C

ちなみに ObjC で書くとこんな感じです。

```objc:
NSArray *filePaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
                                                         NSUserDomainMask,YES);
NSString *path = [[filePaths firstObject] stringByAppendingPathComponent:@"rec.m4a"];
NSURL *fileUrl = [NSURL fileURLWithPath:path];
```

```objc
[self presentAudioRecordingControllerWithOutputURL:fileUrl
                                            preset:WKAudioRecordingPresetWideBandSpeech
                                   maximumDuration:5.0
                                       actionTitle:@"Some Title"
                                        completion:^(BOOL didSave, NSError * __nullable error) {
                                            
                                            NSLog(@"didSave:%d, error:%@", didSave, error);
                                        }];
```


##再生

**オーディオやビデオファイルを再生する UI** を表示するメソッドも新たに追加されました。次のように、メディアファイルの NSURL オブジェクトを渡すだけ。

```swift:
self.presentMediaPlayerControllerWithURL(
    fileURL,
    options: nil) { (didPlayToEnd, endTime, error) -> Void in
        
        print("didPlayToEnd:\(didPlayToEnd), endTime:\(endTime), error:\(error)")
}
```

前述した `presentAudioRecording〜` で録音したファイルなら、そのとき渡した NSURL オブジェクトをそのままこっちのメソッドに渡すだけです。


こんな感じのUIが表示されます。

![player.jpg](https://qiita-image-store.s3.amazonaws.com/0/3180/1c03ac60-1393-27b1-17bb-5076f53fe149.jpeg)

（一般公開されているWWDCの動画より）


##WKAudioFilePlayer

WKAudioPlayer を利用すると、** Watch とペアリングされた Bluetooth オーディオヘッドセットでのオーディオファイル再生** が可能となります。

プロパティを定義しておいて、

```
var player: WKAudioFilePlayer!
```

こんな感じで、WKAudioFileAsset → WKAudioFilePlayerItem → WKAudioFilePlayer を作成します。

```
override func awakeWithContext(context: AnyObject?) {
    super.awakeWithContext(context)
    
    let filePath = NSBundle.mainBundle().pathForResource("se_tap", ofType: "m4a")!
    let fileUrl = NSURL.fileURLWithPath(filePath)
    let asset = WKAudioFileAsset(URL: fileUrl)
    let playerItem = WKAudioFilePlayerItem(asset: asset)
    player = WKAudioFilePlayer(playerItem: playerItem)
}
```

再生は `play` メソッドを呼ぶだけですが、`status` が `.ReadyToPlay` になってないといけないので、こんな感じにしてみました。

```
@IBAction func playBtnTapped() {
    
    switch player.status {
    case .ReadyToPlay:
        player.play()
    case .Failed:
        label.setText("failed")
    case .Unknown:
        label.setText("unknown")
    }
}
```

（実際には status が `.ReadyToPlay` になるまでタイマーでポーリングすべき？delegateみたいなのとか、再生準備完了の通知みたいなのは見当たらなかった。WKAudioFilePlayerItem にはいくつかの関連する通知があるみたいだけど。）

ちなみに WKAudioPlayer は、ひとつのオーディオファイル再生用です。**複数のオーディオファイルを再生したい場合は、WKAudioFileQueuePlayer を利用**します。


##参考資料（ログイン不要領域にて利用可能）

- [watchOS 2 Transition Guide: Incorporating New Features](https://developer.apple.com/library/prerelease/watchos/documentation/General/Conceptual/AppleWatch2TransitionGuide/ManagingYourData.html)
- [Presenting Video and Audio Interfaces - WKInterfaceController Class Reference](https://developer.apple.com/library/prerelease/watchos/documentation/WatchKit/Reference/WKInterfaceController_class/index.html#//apple_ref/doc/uid/TP40014957-CH1-SW93).
- [WKAudioFilePlayer Class Reference](https://developer.apple.com/library/prerelease/watchos/documentation/WatchKit/Reference/WKAudioFilePlayer_class/index.html)