Skip to content

Android loop() does not start playback and play() resets looping flag #171

@KenichiroMatsubara

Description

@KenichiroMatsubara

Bug Report: Android loop() doesn't start playback and play() resets looping flag

Describe the bug
On Android, the NativeAudio.loop() method sets the internal looping flag but does not actually initiate audio playback. Conversely, the NativeAudio.play() method initiates playback but explicitly resets the looping flag to false. This design makes it impossible to start a looping audio track (like BGM) with a single method call when using the Android platform.

To Reproduce
Steps to reproduce the behavior:

  1. Preload an audio asset using NativeAudio.preload().
  2. Call NativeAudio.loop({ assetId: 'my-bgm' }).
  3. Observed result: Silence. The audio never starts playing.
  4. Alternatively, call NativeAudio.play({ assetId: 'my-bgm' }).
  5. Observed result: The audio plays once and stops, even if it was intended to loop.

Expected behavior

  • NativeAudio.loop() should initiate playback if the asset is not already playing.
  • Alternatively, NativeAudio.play() should accept a loop: boolean option, or there should be a way to ensure the looping flag persists during playback initialization.

Screenshots
N/A (Audio behavior issue)

Desktop (please complete the following information):
N/A (Plugin specific behavior on Native Android)

Smartphone (please complete the following information):

  • Device: Android Device/Emulator
  • OS: Android (Tested on various versions)
  • Plugin Version: @capacitor-community/native-audio ^8.0.0

Additional context

Technical Analysis (Android implementation)

Analysis of the AudioDispatcher.java and AudioAsset.java source code reveals the root cause:

  1. loop() lack of start():
    In AudioDispatcher.java, loop() only calls mediaPlayer.setLooping(true) without calling mediaPlayer.start().
public void loop() throws Exception {
    mediaPlayer.setLooping(true);
}
  1. play() forces loop = false:
    The play() method hardcodes the loop parameter to false when calling invokePlay.
// AudioDispatcher.java
public void play(Double time, Callable<Void> callable) throws Exception {
    invokePlay(time, false); // 'false' is hardcoded here
    callable.call();
}

private void invokePlay(Double time, Boolean loop) {
    ...
    mediaPlayer.setLooping(loop); // Forces looping to false
    ...
}

Known Workaround

Users currently have to chain calls, which might lead to inconsistent timing:

await NativeAudio.play({ assetId: 'bgm' });
await NativeAudio.loop({ assetId: 'bgm' }); // Force looping flag while playing

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions