just_audio 0.2.2を使っていた時は、下記のコードで音声ファイルの連続再生を実装していました。
for (int i = 0; i < playableItems.length; i++) {
await audioPlayer.setAsset('assets/audio/${playableItems[i].audioFile}')
.catchError((error) {
print(error);
});
await audioPlayer.play();
}
just_audio 0.7.4+1にアップデートしたタイミングで、上記のコードままだと、i= 0
の最初のファイルが再生された後、続くファイルが再生されず、ループ進んでしまうという現象が発生しました。
まず、下記のようにprint関数を利用してawait audioPlayer.play()
前後のステート確認しました。
print("processingState (before) => ${audioPlayer.processingState.toString()}");
await audioPlayer.play();
print("processingState (after) => ${audioPlayer.processingState.toString()}");
すると、1つ目のファイルが再生される前のステータスはProcessingState.ready
というステートで、再生後にProcessingState.completed
になっていることがわかりました。しかし、2つ目のファイルを再生する前にステートはProcessingState.buffering
となり、その後ステートはbuffering
のままループが進んでしまっていることがわかりました。
これはステートモデルが大幅に変更されたことが原因だったのだろうなということは、薄々気付いていたので、下記のステートモデルの図を確認して、解決を試みました。
https://pub.dev/packages/just_audio#the-state-model
この図をみると、ready
→completed
→buffering
という流れでProcessingState
が変化したが、現状のコードではbuffering
からready
に切り替える処理が行われていないのだろうということが推測されます。おそらく、setAudioSource
を使って、音声ファイルを設定すれば、うまくいくのだろうと思いますが、ここではsetAsset
が使われています。
そこで強制的にProcessingState
をリセットするために、completed
になった時点で、音声ファイルを一度idle
ステートに戻すことで解決しました。つまり、await audioPlayer.stop()
を実行してProcessingState
がbuffering
になることを避け、次のループのsetAsset
がファイルを読み込んだ後、1回目と同様にready
ステートになるようにしたのです。コードは下記のようになります。
for (int i = 0; i < playableItems.length; i++) {
await audioPlayer.setAsset('assets/audio/${playableItems[i].audioFile}')
.catchError((error) {
print(error);
});
await audioPlayer.play();
await audioPlayer.stop();
}
無事、不具合は修正され、以前とほぼ同じように1つ目の音声ファイルの再生が完了した後に、次の音声が再生されるようになりました。
以下はStreamBuilderまでを含んだコードです。
StreamBuilder(
stream: audioPlayer.processingStateStream,
builder: (context, snapshot) {
if (gPlayingAll) {
return GestureDetector(
onTap: () {
audioPlayer.stop();
setState(() {
gPlayingAll = false;
});
},
child: Icon(Icons.stop),
);
} else {
return GestureDetector(
onTap: () async {
setState(() {
gPlayingAll = true;
});
for (int i = 0; i < playableItems.length; i++) {
if (gPlayingAll) {
await audioPlayer
.setAsset('assets/audio/${playableItems[i].audioFile}')
.catchError((error) {
print(error);
});
await audioPlayer.play();
await audioPlayer.stop();
} else {
break;
}
}
gPlayingAll = false;
},
child: Icon(Icons.play_circle_outline),
);
}
},
),