音楽プレイヤーを作成する
続いては、音楽を再生する時の利用シーンを想定し、再生、一時停止、停止、スキップ、ボリュームの変更やオーディオファイルの長さ、再生中の時間を表示する機能など一連の再生にかかわる機能を利用する図2のようなサンプルを作成します。
このサンプルで利用するAPIを表3に示します。
メソッド | 説明 |
---|---|
play() | オーディオファイルを再生する |
stop() | 再生、もしくは録画を停止する |
pause() | 再生を一時中断する |
release() | メディアインスタンスを解放する |
seekTo(millseconds) | 再生する位置を指定した時間(ミリ秒)に移動する |
setVolume(val) | 指定(0.0から1.0まで)した値でボリュームを設定する |
getDuration() | オーディオファイルの長さ(時間)を取得する |
getCurrentPosition(callback) | 再生中の現在の再生時間を取得する。Callbackには秒で値が取得できる |
また、今回作成するサンプルでは、前回省略していたコンストラクタでの各コールバック関数をリスト5のように利用します。
function PlayerController($scope) { // : (省略) // (1) 再生が終了したとき this.mediaSuccess = function () { console.log("media success"); }; // (2) エラーが発生したとき this.mediaError = function (e) { window.alert("Error :" + e.code); }; // (3) ステータスが変わったとき this.mediaStatus = function (status) { if(status != Media.MEDIA_NONE){ // (メディアの状態が初期状態でなくなったとき) } if(status == Media.MEDIA_RUNNING){ // 再生が開始されたタイミング // (省略) } else if(status == Media.MEDIA_STOPPED){ // 停止された時の処理 } }; // : (省略) var media = new Media(src, this.mediaSuccess, this.mediaError, this.mediaStatus); // : (省略) };
(1)は再生が終了したときのコールバック関数です。つまり、指定したオーディオファイルが最後まで再生された時、もしくは停止処理がされた場合に実行されるコールバック関数です。筆者は当初メディアオブジェクトの初期化が完了したときと勘違いしてしまいました。初期化が完了した、もしくは、再生可能な状態になったなどのようなタイミングを取得ことはできません。
続いて、(2)はエラーが発生したときのコールバック関数です。エラー原因はコールバック関数(ここではmediaError関数)の引数(e)のプロパティから表4で示すエラー情報を取得可能です。
変数名 | 説明 |
---|---|
code | 数値 エラーコードを示す。 |
message | エラー理由の説明メッセージ。ただし、必ずこのプロパティがあるわけではないので注意。 |
また、エラーコードは表5で示す理由を示します。
変数名 | 値 | 説明 |
---|---|---|
MediaError.MEDIA_ERR_ABORTED | 1 | 何らかのエラーにより処理が停止した |
MediaError.MEDIA_ERR_NETWORK | 2 | ネットワークエラーにより処理が停止した |
MediaError.MEDIA_ERR_DECODE | 3 | デコード処理に関するよるエラー |
MediaError.MEDIA_ERR_NONE_SUPPORTED | 4 | サポートされていない処理に関するエラー |
ただし、筆者が確認した限りでは、ほとんどのケースでMediaError.MEDIA_ERR_ABORTEDのエラーになり、messageにも何もメッセージがありませんでした。
再生前にエラーになる場合には、オーディオファイル名の間違い、もしくは、プラットフォーム毎のパスの指定方法が主な原因と思われます。
また、再生していないにもかかわらず、一時停止(pause())などをした場合にもエラーになります。エラーコードのみからエラー原因を把握することは難しいため、続いて紹介するステータスなども踏まえて判断する必要があるでしょう。
(3)はステータスが変わったときのコールバック関数です。ステータスは表6のステータスがあります。
変数名 | 値 | 説明 |
---|---|---|
Media.MEDIA_NONE | 0 | 初期状態 |
Media.MEDIA_STARTING | 1 | 初期処理が開始された時 |
Media.MEDIA_RUNNING | 2 | 再生が開始、もしくは録画が開始した時 |
Media.MEDIA_PAUSED | 3 | 再生が一時停止された時 |
Media.MEDIA_STOPPED | 4 | 再生、録画が終了した時 |
ステータスの変更をトリガーにして処理するケースは多々あることと思います。後述する再生時間などを取得する場合には、MEDIA_RUNNINGステータスになったタイミングで処理を行っていますし、操作ボタンの表示・非表示をコンロールするなどの時にもこれらのステータス変更のタイミングを利用できます。
続いて、先ほどのコードにオーディオファイルの操作と再生時間やトータル時間などの実装したものが、リスト6のようになります。
function PlayerController($scope) { // : (省略) this.mediaStatus = function(status) { // : (省略) if(status == Media.MEDIA_RUNNING) { // AngularJSの場合には$intervalの利用を推奨。下記では説明上 setIntervalを利用 timer = setInterval(function() { if($scope.duration <= 0) { // (1) トータル時間の取得 var duration = media.getDuration(); if(duration > 0) { $scope.$apply(function() { $scope.duration = duration; }) } } // (2) 現在の再生時間を取得 media.getCurrentPosition(function(sec) { if(sec > 0) { $scope.$apply(function() { $scope.current = sec; }); } }); }, 200); } else if(status == Media.MEDIA_STOPPED){ if(timer){ clearInterval(timer); // : (省略) } } // : (省略) }; // : (省略) var media = new Media(src, this.mediaSuccess, this.mediaError, this.mediaStatus); $scope.current = 0; media.setVolume(vol); // (3) ボリュームの設定 $scope.play = function() { media.play(); // (4) 再生 }; $scope.pause = function() { media.pause(); // (5) 一時停止 }; $scope.stop = function() { media.stop(); // (6) 再生停止 }; // : 省略 $scope.skip = function() { // (7) 10秒ほど現在位置より、先にスキップする var millsec = ($scope.current * 1000) + (10 * 1000); media.seekTo(millsec); }; // : 省略 }
(1)では再生するオーディオファイルの長さを取得するためにgetDuration()メソッドを実行しています。この再生時間は取得できない状態の時には-1を返し、インスタンスを作成した直後では-1になります。
そして、実際に再生などの処理をしてからしか値が取得できず、AndroidとiOSで取得できるタイミングが異なるようです。筆者が確認した限りでは、Androidでは再生して多少の時間がたったとき、iOSではMEDIA_RUNNINGのステータスに変わったときに取得可能でした。そのためステータスがMEDIA_RUNNINGになったタイミングの中でタイマー処理で取得しています。Android側のプラグイン内部のコードを見る限りプラグイン側のJSコード内ではトータル時間が取得できるステータスを管理していますが、プラグインの利用者側にはその状態の取得まではサポートしていないようでした。
(2)では、現在再生している時間を取得します。この処理も再生が始まった時のタイマー処理内で処理をしています。そして、再生が止まったときにはそのタイマー処理を停止しています。
続いてボリュームの設定ではgetVolume()のようなメソッドで現在のボリューム値を取得するAPIはなく、また、初期値に既定がないため(3)のように設定をしています。また、変更する際にも0.0から1.0までの値で必ず指定する必要がありますので注意してください。
(4)、(5)、(6)は再生する処理、一時停止する処理、停止する処理になります。
また、時間を指定して特定の時間まで移動するには、(7)のようにseekToにミリ秒単位で値を取得します。getCurrentPositionメソッドで取得する時間は秒単位での取得ですので注意が必要です。
最後に
今回は、オーディオファイルの再生を紹介しました。ドキュメントを参照しても各環境の制限を含めたところにまで記載が至っていないため、実装依存の部分が多々あります。そして、その実装は各OSで提供しているSDKにも依存しているのだと思います。しかし、実際にそれらについてわかってしまえば、単純に再生するというのであればそれほど面倒ではなく利用できます。
ただし、今回説明した制限も今後は同じであるかはわからない部分がありますので、実際に開発するに際しては注意が必要です。
次回はこのプラグインの録音機能の紹介と別のプラグインで音声、画像、映像をキャプチャーができるプラグインがあります。次回はそのプラグインについても紹介しますので、録音が必要な場合には、どちらのプラグインが合っているのかを比べるとよいかと思います。