iOS 4.0になってようやくiPodライブラリにある音楽を生のデータとして扱うことができるようになりましたので、その方法をまとめておきたいと思います。ムービーも同じような方法でできるようですが、とりあえずここではオーディオに限定して説明していきます。ちなみにシミュレータにはiPodライブラリがないので試せません。コードは実機で実行してください。
大まかな手順としては以下のような感じです。
① MPMediaItemを取得
② AVURLAssetを生成
③ AVAssetExportSessionを生成
④ Exportを実行
では、やっていきましょう。
① MPMediaItemを取得
MPMediaItemは、iOS3.xのときからありましたのでご存知の方も多いと思いますが、iPodライブラリに中にあるひとつひとつの曲(音楽の場合)の情報をもっているクラスです。これの取得の仕方は、いろいろiPhoneアプリ開発本にもくわしく載っていますので、細かいことはそれらを参考にしていただいた方が良いと思います。
取得の仕方としては、MPMediaPickerControllerを使う方法とMPMediaQueryを使う方法とありますが、今回は簡単に実装できるMPMediaPickerControllerを使ってみます。
では、実際にコードを書いていきたいと思います。Xcodeの新規プロジェクトでWindow Based Applicationを選択し、プロジェクトを作成します。MPMediaPickerControllerを使うのに必要なフレームワークはMediaPlayer.Frameworkですのでインポートします。またあとで必要になるので、AVFoundation.Frameworkもインポートしてください。AppDelegateの中に以下のコードを追加します。
#import <MediaPlayer/MediaPlayer.h> #import <AVFoundation/AVFoundation.h>
それから、起動するときにMPMediaPickerControllerを表示したいので、以下のコードをapplication:didFinishLaunchingWithOptions:メソッドに追加してください。MPMediaPickerControllerはどうやらUIViewControllerが表示されていないと出せないみたいなので、ダミーでUIViewControllerを作ってからMPMediaPickerControllerを出しています。このへんは適当ですので、あまり参考にしない方が良いかと思います。同期すると消えてしまいますし。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { UIViewController *viewController = [[UIViewController alloc] initWithNibName:nil bundle:nil]; [window addSubview:viewController.view]; MPMediaPickerController *pickerController = [[MPMediaPickerController alloc] initWithMediaTypes:MPMediaTypeMusic]; pickerController.delegate = self; [viewController presentModalViewController:pickerController animated:NO]; [pickerController release]; [window makeKeyAndVisible]; return YES; }
これでアプリを実行して起動するとMPMediaPickerControllerが表示される状態になっています。
② AVURLAssetを生成
ここからはMPMediaPickerControllerで曲が選択されたあとの処理です。MPMediaPickerControllerのデリゲートに処理を書き込んでいきましょう。
MPMediaItemを取得したら、valueForPropertyにMPMediaItemPropertyAssetURLを渡してNSURLを取得します。ちなみにこのURLはあくまでiPodライブラリの中の場所でしかないので、ここに直接アクセスしようとしても無駄です。AVPlayerなどを使えば再生できたりしますが、AudioFileService系では開くことはできません。まずは、取得したNSURLからAVURLAssetというメディアファイルを表すオブジェクトを生成します。
- (void)mediaPicker:(MPMediaPickerController *)mediaPicker didPickMediaItems:(MPMediaItemCollection *)mediaItemCollection { MPMediaItem *item = [mediaItemCollection.items lastObject]; NSURL *url = [item valueForProperty:MPMediaItemPropertyAssetURL]; AVURLAsset *urlAsset = [AVURLAsset URLAssetWithURL:url options:nil];
③ AVAssetExportSessionを生成
次に、AVURLAssetを渡してAVAssetExportSessionを生成します。これが、普通のオーディオファイルに書き出してくれるものです。生成するのはこんな感じです。
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:urlAsset presetName:AVAssetExportPresetAppleM4A];
この2つ目の引数のpresetNameというのは書き出すときのフォーマットで、オーディオで書き出すpresetNameはこのAVAssetExportPresetAppleM4Aしかないようです。AVAssetExportSessionのexportPresetsCompatibleWithAsset:で使えるものが取得できます。元のファイルのフォーマットをいろいろ変えて試しましたが、AVAssetExportPresetAppleM4Aにした状態では、常にAACの44.1kHz・Low Complexityで書き出されるようです。
AVAssetExportSessionが生成できたら、さらに情報を与えていきます。最低限必要なものは、outputFileTypeとoutputURLです。
exportSession.outputFileType = [[exportSession supportedFileTypes] objectAtIndex:0]; NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; NSString *filePath = [[docDir stringByAppendingPathComponent:[item valueForProperty:MPMediaItemPropertyTitle]] stringByAppendingPathExtension:@"m4a"]; exportSession.outputURL = [NSURL fileURLWithPath:filePath];
outputURLは書き出す先なので説明は省きます。お好きなところを指定してください。今回はDocumentディレクトリの中にTitleをファイルネームにして書き出しています。
exportSessionに設定できるFileTypeはsupportedFileTypesで取得できます。presetNameをAVAssetExportPresetAppleM4Aにしている場合、supportedFileTypesの中身は「@”com.apple.m4a-audio”」ひとつだけのようでしたので、そのままそれを設定しています。
④ Exportの実行
ここまで準備ができたらあとは書き出しを実行するだけです。書き出しはexportAsynchronouslyWithCompletionHandler:というメソッドで行います。とりあえずコードは以下のような感じ。メソッド名にAsynchronouslyとあるように非同期で実行されます。
[exportSession exportAsynchronouslyWithCompletionHandler:^{ if (exportSession.status == AVAssetExportSessionStatusCompleted) { NSLog(@"export session completed"); } else { NSLog(@"export session error"); } [exportSession release]; }]; }
書き出しが終了したら、このメソッドで渡したブロックが呼ばれます。exportSessionのstatusプロパティには書き出しが成功したか失敗したかキャンセルされたか等の状態が入ってますので、そのstatusに応じて処理を記述するという感じです。
ブロックの最後には、もうexportSessionが必要なくなったということでreleaseしています。キャンセル処理や進捗を実装する場合等はインスタンス変数とかにexportSessionを保持しておかないといけないと思いますので、releaseのタイミングはうまいことやってください。
以上のコードを実行して曲を選択すると、アプリ内のDocumentディレクトリにファイルがコピーされると思います。File SharingをONにしておけばiTunesからみたりしてコピーされたかどうかが確認できると思います。ただしコピーできないものがあって、DRM付きのファイルはもちろんなのですが、なぜかMP3もコピーしてくれませんでした。また、今回の方法だと自動的にAACに変換されてしまうので、WAVやAIFFなどの非圧縮ファイルをそのままコピーしたい場合などの対応についてはまた次回やります。