[iOS][Swift]ミュージックライブラリの音楽の再生、情報の表示(MPMusicPlayerController使用)

MPMusicPlayerControllerを使ったミュージックライブラリアイテムの再生に関してこちらに記事を書きました。
[iOS][Swift]ミュージックライブラリにアクセスして音楽を再生する(MPMusicPlayerController使用) | nackpan Blog
この記事では、ミュージックライブラリから一つの曲を選んで再生・一時停止・停止を行いました。

今回のサンプルでは、MPMusicPlayerControllerを使用して複数のアイテムを順に再生します。
また、再生中の音楽アイテムの情報(アートワーク、アルバム名等)を表示します。
前回のサンプルでは、選曲するとすぐに再生を開始していましたが、今回は選曲するとアイテム情報を表示しますが再生は開始しないこととしました。PLAYボタンを押すと再生開始です。
再生されているアイテムが変更されると、それを検知して変更後のアイテム情報を表示します。
ファイル 2016-04-13 7 24 35
(今回のサンプルのスクリーンショット)

MusicPlayerControllerを使って、ミュージックライブラリのアイテムを再生し、情報を表示する

iPodライブラリアクセス プログラミングガイド(PDF)
iPod Library Access Programming Guide(英語版)
このappleのドキュメントにライブラリにアクセスして再生する方法、必要な曲を選択する方法、現在再生中の音楽の情報を知る方法等、まとめてあります。
(ちなみに、日本語ドキュメント – Apple DeveloperのページにappleのiOS用日本語ドキュメントがまとめてあります。英語版へのリンクもあります)

iOSシミュレータでは動作しないので、実機を用いてください。

Single View Applicationでプロジェクトを作成。
ss 2015-09-16 6.46.53

ViewController.SwiftにMediaPlayerフレームワークをimportします。

UI配置

ボタンとラベルとイメージビュー(Image View)を配置。
ss 2016-04-13 2.02.06

UIとViewControllerとの接続

ラベルおよびイメージビューとViewController.swiftをOutletを作成して接続。
ss 2016-04-12 21.53.43outletLabels
ss 2016-04-12 21.52.55

ボタンとViewController.swiftをactionを作成して接続。
ss 2016-04-13 2.35.53Action
ss 2015-09-13 9.09.50

プレイヤー準備

プレイヤーを表すpropertyをViewController.swiftに加えます。

プレイヤーのインスタンスを作成。

(ここで、applicationMusicPlayerではなく、systemMusicPlayerを用いると、「ミュージック」アプリでの再生状況(再生アイテムや、シャッフル、リピートなどのモード)を反映したものになる)

再生中アイテムの変更通知

今回は、複数の曲を選択して順に再生していきます。
アイテム情報を表示するには、現在再生中のアイテムがなにか分かっていなければなりません。
ミュージックプレーヤー通知という仕組みで、再生中アイテムに変更があった場合には通知を受け取ることができます。
この通知を受けて、プレイヤーが現在再生中のアイテムを取得し情報表示を更新します。

まず、再生中アイテム変更イベントを監視します。

再生中のアイテムが変更になったときに、ViewController.nowPlayingItemChanged(_:)を呼び出すように指定しています。

また、ViewControllerのdeinit内に、通知を受け取る必要がなくなった場合の後処理を書いておきます。

再生中のアイテムが変更になった際に呼び出されるViewController.nowPlayingItemChanged(_:)の内容を書きます。

MPMusicPlayerControllerのプロパティnowPlayingItemで再生中のアイテムを取得できます。
(今回は使いませんが、アイテムをsetすることもできます)
nowPlayingItemはMPMediaItem型のプロパティです。

MPMediaItem

ミュージックライブラリに対するアクセスでは、MPMediaItemというクラスでアイテム情報を扱います。
MPMediaItem Class Reference
MPMediaItemは、title, artist, artworkなどなど、さまざまな情報をもっています。
アイテム情報を表示する際には、現在再生中のアイテムから情報を取得してラベルやイメージビューに表示します。

メディアアイテムピッカー

曲を選択するために、メディアアイテムピッカーを用います。
(メディアアイテムピッカーというのは、iOSで用意されているあらかじめ設定済みのViewController。ミュージックライブラリの選択画面と同じようなことが出来る)
ss 2015-09-13 11 41 39

メディアアイテムピッカーでの「選択完了したとき」や「キャンセルされたとき」のイベントを、ViewControllerで受け取れるようにします。
そのために、ViewControllerをメディアアイテムピッカーのデリゲートとして設定します。
「選曲」ボタンを押すと、メディアアイテムピッカーを作成して、デリゲートの設定を行い、ライブラリの曲を選択できるようにします。
「選択完了したとき」「キャンセルされたとき」のメソッドを記述します。

選択完了した時に呼び出されるmediaPicker(mediaPicker: MPMediaPickerController, didPickMediaItems mediaItemCollection: MPMediaItemCollection)で、MPMediaItemCollection型の引数mediaItemCollectionがありますが、これにアイテム情報が入っています。
MPMediaItemCollection Class Reference
MPMediaItemCollectionクラスは、MPMediaItemを集めて管理しているクラスです。
そのプロパティitemsがMPMediaItemの配列になっていますので、今回はそこから先頭のMPMediaItemを取得してそれを元に情報を表示しています。

再生・一時停止・停止

各ボタンのアクションに、「再生」「一時停止」「停止」機能を加えます。

iOSシミュレータでは動作しません。実機を用いてください。 「選曲」ボタンを押すと、メディアアイテムピッカーが表示されるので、曲を選択してください。複数の曲を選択できます。「PLAY」ボタンで音楽の再生。「PAUSE」ボタンで一時停止。「STOP」ボタンで音楽を止めて、再生位置を一番始めに戻します。


ViewController.swift全文

関連

[iOS][Swift]ミュージックライブラリにアクセスして音楽を再生する(MPMusicPlayerController使用) | nackpan Blog
[iOS][Swift]MPMediaQueryを使って曲を絞り込む | nackpan Blog
[iOS][Swift]ミュージックライブラリにアクセスして音楽を再生する(AVAudioPlayer使用) | nackpan Blog

[Swift]iPhoneを振動させる

iPhoneのバイブレーション機能を用いるには?

システムサウンドにバイブレーションさせるものがあるのでそれを用います。

System Sound Services Reference

• AudioToolboxをimportしたうえで、バイブレーション用サウンドを指定して鳴らすことで、振動させることができます。

バイブレーションのサンプル

Startボタンを押すと3秒間隔で振動し続けるサンプルを作成しました。(Stopボタンを押すと止まります)

Single View Applicationで開発。

Main.storyboardにStartボタンを配置
ss 2015-11-13 17.09.33

StartボタンとViewController.swift間をActionで結びつける

Startボタンが押されると、Timerが起動します。
Timerは3秒間隔で、システムサウンドによるバイブレーションを実行しています。
また、ボタンは押されるごとに、”Start”と”Stop”の表記を切り替えています。
Stopボタンが押されると、Timerを無効にします。

ViewController.swift

[iOS]マイクへのアクセス許可を求めるダイアログを再度表示する

iOSアプリで、録音機能を使うときには最初にマイクへのアクセス許可を問うダイアログが表示されます。
ss2015-11-01

許可しない・OK どちらかを選ぶことになります。

選んだ後は、そのアプリで録音機能を使ってもダイアログは表示されません。

開発中に、はじめて実行した状態に戻して、「マイクへのアクセス許可ダイアログ」を表示する必要がありました。
アプリをiPhoneから削除して、再度ビルドし直して実行してみましたが、アクセス許可ダイアログは表示されません。
「許可しない・OK」の選んだ方の状態になっています。

困りました。調べてみるとStackOverFlowにそれに関する質問と回答がありました。
ios7 – Resetting iOS 7 microphone access permission – Stack Overflow
こちらの回答によると、
設定 > 一般 > リセット > 位置情報とプライバシーをリセット
で、「マイクへのアクセス許可」情報もリセットできます。

これで、録音をしようとした際に「マイクへのアクセス許可」ダイアログが表示されるようになりました。

ただ、すべてのアプリのプライバシー設定がリセットされるので、他のアプリも再度アクセス許可を出していく必要があります。

[iOS][Swift]録音する

iOSでAVAudioRecorderを使って、音声を録音する方法を紹介します。

AVAudioRecorder Class Reference

今回は
<図>
に示すサンプルを作成しました。
“Record”ボタンを押すと録音開始(それとともにボタンの表記が”Stop”に変わる)
“Stop”ボタンを押すと録音停止
“Play Recording”ボタンを押すと録音した音声の再生開始(それとともにボタンの表記が”Stop Playing”に変わる)
“Stop Playing”ボタンを押すと再生停止
となります。

録音機能の実装

必要なフレームワークをインポート

AVAudioRecorderとAVAudioPlayerを使用するのに必要なAVFoudationフレームワークをインポートします

レコーダーとプレイヤー

レコーダーとプレイヤーを保持するために、プロパティとして設定します
レコーダとしてAVAudioRecorder?型のプロパティを設定

オーディオセッションの設定

レコーダーの設定

• 録音したファイルの保存先URLを設定します
• 録音時の音質やチャンネル数を設定します
• 準備した保存先URLと録音設定を元にレコーダーを作成します

録音開始・停止

[iOS]電話がかかってきたとき、ヘッドホンジャックが抜かれたときの対応

オーディオ系アプリで、電話がかかってきたとき、ヘッドフォンジャックが抜かれたときの対応。

電話がかかってきたとき、ヘッドホンが抜かれたときには、音楽を再生していた場合自動的に停止します。
しかし、UIは更新されませんので、ボタン表示を停止した状況に合わせる必要があります。
また、再生中と停止中でプレイヤーがもつプロパティを変化させるようにしていた場合、更新する必要があります。

電話がかかってきたとき、ヘッドホンが抜かれたときを検知して対応するには、Notification Centerを使った通知の仕組みを使います。
(AVAudioPlayerDelegateにaudioPlayerBeginInterruption:メソッド、audioPlayerEndInterruption:メソッドがあり、割り込み開始と割り込み終了を検知していましたが、iOS 8でdeprecatedになっています)

Notification Centers
Notification centerにイベントを監視(Observe)するよう登録します。イベントからNotirication Centerに通知(Post Notification)があると、Notification Centerは、対応するメソッドを呼び出します。
今回は、割り込み(AVAudioSessionInterruptionNotification)とルートチェンジ(AVAudioSessionRouteChangeNotification)を監視するように記します。


(2016/11/12記。もともとこの記事は2015年9月に記したもので、サンプルコードはXcode 7, Swift 2で作成していました。そのコードをXcode 8のSwift 3への自動コンバート機能を使って変換したものを以下に記します。Swift 2でのコードは、しばらく記事の末尾に留めておきます)

監視する必要がなくなった段階で、Observerを取り外します


以下は、Swift 2 + Xcode 7でのソースコードです。

監視する必要がなくなった段階で、Observerを取り外します

[iOS][Swift]リモートコントロールイベントに対応する

たいていのオーディオ系アプリでは、イヤホンやロック画面、コントロールセンターからの再生や停止ができます。

iPhoneのイヤホンではセンターボタンの操作でオーディオの操作ができます。
ss2014-10-30-01
再生・一時停止:センターボタンを1回押す
次の区間へ:センターボタンをすばやく2回押す
前の区間へ:センターボタンをすばやく3回押す

といった操作ができます。

コントロールセンターでは、赤丸で囲った部分でオーディオアプリの再生制御ができます。
ss2015-09-25-01

iPhone用イヤホン操作などのイベントはリモートコントロールイベントとよばれています。
このリモートコントロールイベントを受け取るために、必要な実装を紹介します。

Appleのドキュメントを見てみます。
Remote Control Events
イベント処理ガイド(日本語・PDF)内の遠隔制御イベントの項目

以前の版(2013年)では、remoteControlReceivedWithEvent:を使った方法が紹介されていましたが、
2015年版では、MPRemoteCommandオブジェクトを使って、アクションハンドラを登録する方法が記されています。

MPRemoteCommandにアクションハンドラを登録してリモートコントロールイベントを制御

MPRemoteCommandCenter Class Reference
MPRemoteCommand Class Reference

MPRemoteCommandCenterがもつリモートコマンドにアクションハンドラを登録します。
リモートコマンドには、
・togglePlayPauseCommand(イヤホンのセンターボタンを押した)
・playCommand(コントロールセンターのプレイボタンを押した)
・pauseCommand(コントロールセンターのポーズボタンを押した)
などがありますので、それぞれのコマンドにたいしてどのようなアクションを起こすかを記述します。

[iOS][Swift]バックグラウンドに移行してもオーディオ再生を続ける

オーディオ再生中にバックグラウンドに移行しても再生を続けるには?

Targetsから
Capabilities > Background Modes をONにして、
Audio, AirPlay and Picture in Picture をチェックします
ss 2015-09-24 22.10.27
(この設定によって、Info.plistに”Required Background Modes”キーが書き加えられます)

この設定をした上で、ソースコード上でAVAudioSessionのカテゴリを設定します。
AVAudioSessionのカテゴリとは、消音スイッチが入っているときに音楽再生するか?や、録音可能か?などの設定を定めるものです。
AVAudioSessionプログラミングガイド(日本語・PDF)
バックグラウンド再生の場合には、 AVAudioSessionCategoryPlaybackにします。

これで、音楽再生中にバックグラウンドに移行しても再生は続きます。

ただ、これで音楽を流し続けることはできるのですが、イヤホンやコントロールセンターからの操作を受け付けません。
そういった操作(リモートコントロールイベント)を受け付ける手順はこちらの記事をごらんください。
[iOS][Swift]リモートコントロールイベントに対応する | nackpan Blog

参考

Technical Q&A QA1668: Playing media while in the background using AV Foundation on iOS

[iOS][Swift]AVAudioPlayerを使う(複数の曲をあつかう)

AVAudioPlayerを使う例として
[iOS][Swift]ミュージックライブラリにアクセスして音楽を再生する(AVAudioPlayer使用) | nackpan Blog
[iOS][Swift]AVAudioPlayerを使う(再生速度の変更、複数のプレイヤー) | nackpan Blog
という記事を書きました。

今回は、AVAudioPlayerで複数のアイテムを扱います。
複数のアイテムを選択したのち、順次再生されるようにしたいと思います。


サンプルプロジェクトを作りました
(プロジェクト一式はGitHubにあります nackpan/AVAudioPlayerDemo3
ss2015-09-23 16 18 32

「選曲」ボタンで、複数の曲を選択し再生を開始します。
「再生・一時停止」ボタンで、再生と一時停止を切り替えます。
「<<」ボタンで前の曲に移ります。
「>>」ボタンで次の曲に移ります。
Message Labelに現在の曲情報が表示されます。

iOSシミュレータでは動作しないので、実機を用いてください。

プレイヤークラスの作成

前回までのサンプルでは、ViewController.swiftに全部書いていました。
しかし、ViewController.swiftになにもかも書いていくと、どこが何の役割なのかがわかりづらくなってしまいます。
なので、プレイヤークラスを別に作成しました。
今回のサンプルでは、SimplePlayerクラスと名付けました。

複数のアイテムを扱う

プレイヤーが、MPMediaItemの配列をもち、currentIndexで現在のindexを示すこととします。
アイテム末尾到達、「>>」ボタンタップ、「<<」ボタンタップがおこなわれると、currentIndexを変更します。
別のアイテムになるたびにプレイヤーに新アイテムをセットします。

urlがnilのアイテムもアイテム配列に含めている

今回のサンプルでは、mediaItemsにurlがnilのMPMediaItemも含めています。
その場合のアイテム再生時には、「urlがnilなので再生できない」旨のメッセージを表示して、そこで再生を停止しています。
(実際のアプリでは、事前にチェックしてurlがnilのものを取り除いておく、あるいは再生中にnilのものがあれば飛ばすなどの処理のほうがよさそうですが…)

アイテム末尾到達を知る

AVAudioPlayerDelegateのaudioPlayerDidFinishPlaying(player: AVAudioPlayer, successfully flag: Bool) メソッドで知ることができます。

プレイヤーをAVAudioPlayerDelegateプロトコルに準拠させます

アイテム末尾に到達した際にaudioPlayerDidFinishPlaying(player: AVAudioPlayer, successfully flag: Bool)が呼ばれるので、そこで必要な処理を行います。
このサンプルでは、
・範囲内であればindexを進めて次の曲の再生に移る
・すべてのアイテムの再生が終わったならそこで再生を終えて、indexを0に戻して最初のアイテム情報を表示する
処理を行っています。


サンプルプロジェクトのGitHub
nackpan/AVAudioPlayerDemo3

関連

[iOS][Swift]ミュージックライブラリにアクセスして音楽を再生する(MPMusicPlayerController使用) | nackpan Blog
[iOS][Swift]MPMediaQueryを使って曲を絞り込む | nackpan Blog
[iOS][Swift]ミュージックライブラリにアクセスして音楽を再生する(AVAudioPlayer使用) | nackpan Blog
[iOS][Swift]AVAudioPlayerを使う(再生速度の変更、複数のプレイヤー) | nackpan Blog