iOS開発の小技集其の一:音楽のバックグラウンド再生

皆さんおはこんにちばんは!星野Dです〜プロデューサーから承認を得て、今後はたま〜に技術的なことも掲載していきたいと思います!もし御覧の皆さんの中にiOS開発者の方もいらっしゃればすこしでもご参考になれたら嬉しいです(≧∇≦)

それでは今回はまずiOS版フェノグラムの目玉機能となり、多くの方々からご公表を頂きましたSOUND LIBRARYのバックグラウンド再生機能について少し語りたいと思います〜この機能はiOSは標準APIとして提供されていますので、実現に関してはさほど難しくありまえん。AVPlayerかAVAudioPlayerを利用すればほぼすぐにでも実現できます。(今回は時間の都合上、本当に「バックグラウンドで音を流す」だけを語ります。SOUND LIBRARYに対応している他の部分、例えばiOSのコントロールセンターから曲の再生制御とかの機能については今回は語りません。というか時間がなくて語れません^^;どうかご理解お願いします^^;)

まず一番最初にやっておくことは、Xcodeの設定で「Capabilities」→「Background Modes」をオンにして、Modesのところ「Audio and AirPlay」にチェックを入れます。これで「このアプリはバックグラウンドでも動作するよ」とOSに伝えます。
スクリーンショット 2014-10-14 20.12.05

次にコーディング作業に入りますが、必要な場所に(例えばSOUND LIBRARY画面に入った時に)オーディオをバックグラウンドでも再生できるよう、AVAudioPlayerのオブジェクトをつくって、オーディオセッションを作ります。まずはヘッダーファイルで

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

を入れれば、バックグラウンド再生に使う一連のものが使えるようになります。次にプレイヤーオブジェクトとオーディオセッションをヘッダーファイルで定義されているクラス内に作ります。例えばフェノグラムではこのように作られています:

@interface MusicView : UIView {
@public
	………
	AVAudioPlayer	*musicPlayer;
	AVAudioSession	*audioSession;
}
…………
@property (nonatomic, retain) AVAudioPlayer *musicPlayer;

………
@end


このように、まずはパブリックオブジェクトにAVAudioPlayerオブジェクトとAVAudioSessionオブジェクトを作り、次にAVAudioPlayerが勝手にリリースされないよう、プロパティで保持しておきます。(最近なら一応ARCによるメモリ管理のほうが推奨されているため、本当はcopy/retainなどではなくweak/strongによるオブジェクト管理のほうが主流?かと思いますが、フェノグラムの場合はベースとなるSTEINS;GATEはプロジェクト自体が割と古いため、MRCのretainを利用しています。皆さんがコーディングしているときは自分の状況を確認してコーディングしましょう。)

次に実際音楽を再生できますよう、AVAudioPlayerオブジェクトを初期化します。例えば音楽のファイル名が「musicName.m4a」、この画面に入った瞬間にこの音楽を再生するようコーディングするなら、initメソッドでこんな風に書けばOKです:

-(id) init {
	………
	NSURL *musicURL = [[NSBundle mainBundle] URLForResource:@"musicName" withExtension:@"m4a"];
	if (!musicPlayer) {
		[musicPlayer stop];
		[musicPlayer release];
		musicPlayer = nil;
	}
	musicPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:musicURL error:nil];
	[musicPlayer play];
}

(一応説明しますが、ここではなるべく簡潔にソースコードをまとめるために、エラーをすべてnilに設定していますので、きちんとエラーメッセージを受け取りたい方は先にNSErrorオブジェクトをつくって、error:のところに書き込む必要があります。また[musicPlayer play]などの一部戻り値がメソッド実行成功したかどうかを判定したBOOL値のメソッドに関してもここではすべて戻り値に準じた処理を省いています。以降のコードも同様です。)
これでアプリ内の「musicName.m4a」という音楽がこの画面に入った瞬間再生が始まります。ちなみにAVAudioPlayerオブジェクトが対応している形式はMP3、MPEG4-AACなどのロス圧縮形式からAppleLosslessやwavなどのロスレス形式など様々な形式に対応しています。詳しくはググれば出てくると思います。多分。そしてわかっていると思いますが、musicPlayerオブジェクトはretainされているので、手動でリリースしないといけません。deallocメソッドにリリースされるよう書きましょう:

-(void) dealloc {
	………
	if (musicPlayer != nil) {
		[musicPlayer stop];
		[musicPlayer release];
		musicPlayer = nil;
	}
	[super dealloc];
}

こんな風にリリースします。

ただ、このままでは音楽を再生するだけで、バックグラウンドでの再生はまだできません。なので、バックグラウンドでも再生できるよう、次はこんなふうに修正します:まずはバックグラウンドの動作があるよということを伝えるよう、クラスにこのメソッドの戻り値を追加します(もしこのメソッドが書かれていなければ入れればOKです):

-(BOOL) canBecomeFirstResponder {
	return YES;
}

audioPlayerオブジェクトが初期化される前に、audioSessionオブジェクトをきちんと動作させます:

-(id) init {	
	………
	[self becomeFirstResponder];
	audioSession = [AVAudioSession sharedInstance];
	[audioSession setCategory:AVAudioSessionCategoryPlayback error:nil];
	[audioSession setActive:YES error:nil];
	

	NSURL *musicURL = [[NSBundle mainBundle] URLForResource:@"musicName" withExtension:@"m4a"];
	musicPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:musicURL error:nil];
	[musicPlayer play];
}

そして最後はこの画面から離れたらFirstResponderを戻すよう、deallocでこんな風に追加します:

-(void) dealloc {
	………
	if (musicPlayer != nil) {
		[musicPlayer stop];
		[musicPlayer release];
		musicPlayer = nil;
	}
	[self resignFirstResponder];
	[super dealloc];
}

これで一応この画面で音楽が流れている時、HOMEボタンを押してもSLEEPボタンを押しても、音楽がバックグラウンドでそのまま流れ続けると思います!フェノグラムは更にバックグラウンドで曲の再生コントロールとかもできますが、それらについての実装はまた今度お話します^^;ではではノシ

カテゴリー: 技術 パーマリンク

コメントは停止中です。