サウンド処理は非同期で その1 ― 2013/11/28
例えばサウンドの再生、OGGファイルを読み込んで再生するような場合、
・ファイルの読み込み
・オブジェクトの初期化などOpenSLで必要な各種設定
・出だしのデータのデコード
・再生
と、結構多くの処理が必要です。
その処理の間メインを止めてしまっているのは何とも忍びないので、サウンドは別のスレッドで非同期に処理するようにしてみます。
具体的には、
・再生などの命令が来たら、その命令とパラメータをキューに貯める
・別のスレッドで非同期にキューを監視して、命令を処理する
という流れになります。
キューを管理するスレッドの処理は javaで行います。
SoundManager.java
重要なのは2つ、
・AsyncTaskで非同期処理
・ArrayBlockingQueueでキューの管理
ということくらいです。
サウンド管理と名前はついていますが、サウンドの処理自体は native側で行っていますので、ここでは"サウンド用のデータ"を管理しているだけです。
native側からは set_commandコマンドが呼ばれます。
ここでキューに貯められた命令を doInBackgroundの中で取り出して、nativeの関数 sendSoundCommandを呼び出して実際のサウンド処理を行うようになっています。
native側の処理は、また次回以降に。
・ファイルの読み込み
・オブジェクトの初期化などOpenSLで必要な各種設定
・出だしのデータのデコード
・再生
と、結構多くの処理が必要です。
その処理の間メインを止めてしまっているのは何とも忍びないので、サウンドは別のスレッドで非同期に処理するようにしてみます。
具体的には、
・再生などの命令が来たら、その命令とパラメータをキューに貯める
・別のスレッドで非同期にキューを監視して、命令を処理する
という流れになります。
キューを管理するスレッドの処理は javaで行います。
SoundManager.java
package sys; import java.util.concurrent.ArrayBlockingQueue; import android.os.AsyncTask; import android.util.Log; /****************** サウンド管理 ******************/ public class SoundManager extends AsyncTask<Void, Void, Void> { static private SoundManager manager; // サウンド管理タスク static private ArrayBlockingQueue<SoundCommand> queue; // コマンドキュー /************ 初期化 ************/ static public void init() { queue = new ArrayBlockingQueue<SoundCommand>(32, true); // キュー作成 manager = new SoundManager(); manager.execute(); } /********** 終了 **********/ static public void quit() { queue = null; manager = null; } /****************** コマンド予約 ******************/ static public void set_command(short _channel, short _command, int _data, int _size, short _loop, float _volume) { try { queue.put(new SoundCommand(_channel, _command, _data, _size, _loop, _volume)); } catch (InterruptedException e) {} } /****************** コマンド停止 ******************/ static public void stop_command() { manager.cancel(true); while ( queue != null ) { try { Thread.sleep(1); } catch (Exception ex) { ex.printStackTrace(); } } } @Override protected void onPreExecute() {} public native void sendSoundCommand(short _channel, short _command, int _data, int _size, short _loop, float _volume); /********** 稼働 **********/ @Override protected Void doInBackground(Void... params) { SoundCommand _command; while ( !isCancelled() ) { try { _command = queue.take(); // コマンド取得 if ( _command != null ) { // コマンド実行 sendSoundCommand(_command.channel, _command.command, _command.data, _command.size, _command.loop, _command.volume); _command = null; } } catch (InterruptedException e) { queue.clear(); } } queue.clear(); queue = null; return null; } protected void onPostExecute(Void result) {} } /********** 命令 **********/ class SoundCommand { public short channel; // チャンネル public short command; // コマンド public int data; // データ public int size; // サイズ public short loop; // ループ回数 public float volume; // 音量 /******************** コンストラクタ ********************/ public SoundCommand(short _channel, short _command, int _data, int _size, short _loop, float _volume) { channel = _channel; command = _command; data = _data; size = _size; loop = _loop; volume = _volume; } } /******************** End of File *******************************************************/
重要なのは2つ、
・AsyncTaskで非同期処理
・ArrayBlockingQueueでキューの管理
ということくらいです。
サウンド管理と名前はついていますが、サウンドの処理自体は native側で行っていますので、ここでは"サウンド用のデータ"を管理しているだけです。
native側からは set_commandコマンドが呼ばれます。
ここでキューに貯められた命令を doInBackgroundの中で取り出して、nativeの関数 sendSoundCommandを呼び出して実際のサウンド処理を行うようになっています。
native側の処理は、また次回以降に。
最近のコメント