person t-kobayashi

just audio 0.2.2から0.7.4+1に更新後の挙動の変化

calendar_today 2021年08月16日 update 2021年08月16日
Facebook Twitter LINE はてなブックマーク Pocket

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

この図をみると、readycompletedbufferingという流れでProcessingStateが変化したが、現状のコードではbufferingからreadyに切り替える処理が行われていないのだろうということが推測されます。おそらく、setAudioSourceを使って、音声ファイルを設定すれば、うまくいくのだろうと思いますが、ここではsetAssetが使われています。

そこで強制的にProcessingStateをリセットするために、completedになった時点で、音声ファイルを一度idleステートに戻すことで解決しました。つまり、await audioPlayer.stop()を実行してProcessingStatebufferingになることを避け、次のループの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),
            );
        }
    },
),

関連記事

Flutterの記事一覧を見る

Flutterの質問

soichiro1210 が1年前に投稿

質問日時 2023年07月31日

a-sato が3年前に投稿

質問日時 2021年07月01日

a-sato が3年前に投稿

質問日時 2021年06月30日

takumi が3年前に投稿

質問日時 2021年05月20日

a-sato が3年前に投稿

質問日時 2021年05月14日

Flutterの質問一覧を見る
search