Audio in the background for Ionic / Capacitor app

Already looked at it, but I don’t understand how to implement it.

Read up on Creating and Building Capacitor plugins. The code I shared is considered a “local plugin”.

1 Like

I just used the @twestrick code as a local plugin myself! Works perfectly!

2 Likes

I’ll try and let you know later. Thanks a lot!! @twestrick

I’m getting this.

audioPlayerService is null

And then this

File: http://localhost/main.f7c9b52cd94d4b7aafea.js - Line 1 - Msg: ERROR Error: Uncaught (in promise): Error: There was an issue creating the audio player (1).
                                                                                                    Error: There was an issue creating the audio player (1).
                                                                                                        at cap.fromNative (http://localhost/:411:32)
                                                                                                        at <anonymous>:1:18

On my Android Studio logcat

Any Suggestions?

You’re gonna have to share more info than that. How did you set it up and what does your code look like?

Component

import { AudioPlayer} from 'src/app/MyPlugins/AudioPlayerPlugin';

ngOnInit() {
AudioPlayer.create({
      audioId:"centro-dig",
      audioSource:"http://streamingecuador.com:7046/stream",
      friendlyTitle:"Centro Digital",
      useForNotification:true,
      isBackgroundMusic:true,
      loop:false
    });
    AudioPlayer.initialize({audioId:"centro-dig"})
    AudioPlayer.play({
      audioId:"centro-dig"
    });
}

And then the same as you have on your repo

My bad, I had it wrong on my AndroidManifest.xml

Had this:

<service
                android:name="audio.AudioPlayerService"
                android:description="@string/audio_player_service_description"
            />

Instead of this and had no errors

<service
                android:name=".AudioPlayerService"
                android:description="@string/audio_player_service_description"
            />

But now I’m getting this

FATAL EXCEPTION: main
                                                                                                    Process: com.appsdabanda.wpblogapp, PID: 2085
                                                                                                    java.lang.IllegalArgumentException: Invalid notification (no valid small icon): Notification(channel=playback_channel pri=-1 contentView=null vibrate=null sound=null defaults=0x0 flags=0xa color=0x00000000 category=transport actions=1 vis=PUBLIC)
                                                                                                    	at android.app.NotificationManager.notifyAsUser(NotificationManager.java:312)
                                                                                                    	at android.app.NotificationManager.notify(NotificationManager.java:300)
                                                                                                    	at androidx.core.app.NotificationManagerCompat.notify(NotificationManagerCompat.java:223)
                                                                                                    	at androidx.core.app.NotificationManagerCompat.notify(NotificationManagerCompat.java:205)
                                                                                                    	at com.google.android.exoplayer2.ui.PlayerNotificationManager.startOrUpdateNotification(PlayerNotificationManager.java:1163)
                                                                                                    	at com.google.android.exoplayer2.ui.PlayerNotificationManager.handleMessage(PlayerNotificationManager.java:1415)
                                                                                                    	at com.google.android.exoplayer2.ui.PlayerNotificationManager.$r8$lambda$hDN6RMWHvTCSAt_reWH1_HHmp5E(Unknown Source:0)
                                                                                                    	at com.google.android.exoplayer2.ui.PlayerNotificationManager$$ExternalSyntheticLambda0.handleMessage(Unknown Source:2)
                                                                                                    	at android.os.Handler.dispatchMessage(Handler.java:104)
                                                                                                    	at android.os.Looper.loop(Looper.java:166)
                                                                                                    	at android.app.ActivityThread.main(ActivityThread.java:7428)
                                                                                                    	at java.lang.reflect.Method.invoke(Native Method)
                                                                                                    	at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:245)
                                                                                                    	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:921)

Either remove setting the small icon (reference) or create an Android resource called ic_stat_icon_default.

DUUUUUUUUUDE YOU ROCK!!! Works perfectly!!! Now I’m test it on iOS.

1 Like

It works on iOS too!! Thanks again @twestrick !!!

1 Like

Hi @twestrick !

I think that I found a small bug on AudioPlayerService.java.

setContentType(isBackgroundMusic ? C.AUDIO_CONTENT_TYPE_SPEECH : C.AUDIO_CONTENT_TYPE_SPEECH)

should be

.setContentType(isBackgroundMusic ? C.AUDIO_CONTENT_TYPE_MUSIC : C.AUDIO_CONTENT_TYPE_SPEECH)

This is actually in AudioSource.java :slight_smile: I found my commit in my repo where I changed it to both be AUDIO_CONTENT_TYPE_SPEECH from

.setContentType(isBackgroundMusic ? C.AUDIO_CONTENT_TYPE_MUSIC : C.AUDIO_CONTENT_TYPE_SPEECH)

I probably left the ternary in there so I could easily switch back if needed.

For my use case, I believe this was intended so both the speech and background music are paused when another app requests audio focus vs. the background music being ducked (reduced in volume).

I couldn’t find the ExoPlayer’s documentation but here is a link to Android’s general info about audio focus - Manage audio focus  |  Android media  |  Android Developers.

1 Like

Makes totally sense, thanks for explaining!

1 Like

@twestrick I have recently updated to Androidx media but I’m having this issue:

There was an issue stopping the audio (1).
                                                                                                    java.lang.NullPointerException: Attempt to invoke interface method 'void androidx.media3.exoplayer.ExoPlayer.pause()' on a null object reference
                                                                                                    	at com.vitiks.radiocentroapp.AudioSource.stop(AudioSource.java:119)
                                                                                                    	at com.vitiks.radiocentroapp.AudioPlayerService.stop(AudioPlayerService.java:109)
                                                                                                    	at com.vitiks.radiocentroapp.AudioPlayerPlugin.lambda$stop$8(AudioPlayerPlugin.java:260)
                                                                                                    	at com.vitiks.radiocentroapp.AudioPlayerPlugin.$r8$lambda$-xWP1Ai_D9dDcawrFVt4P0oCm7Q(Unknown Source:0)
                                                                                                    	at com.vitiks.radiocentroapp.AudioPlayerPlugin$$ExternalSyntheticLambda4.run(Unknown Source:4)
                                                                                                    	at android.os.Handler.handleCallback(Handler.java:808)
                                                                                                    	at android.os.Handler.dispatchMessage(Handler.java:101)
                                                                                                    	at android.os.Looper.loop(Looper.java:166)
                                                                                                    	at android.app.ActivityThread.main(ActivityThread.java:7428)
                                                                                                    	at java.lang.reflect.Method.invoke(Native Method)
                                                                                                    	at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:245)
                                                                                                    	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:921)

What can it be?

Thanks again for your help!!

Sorry for not getting back with you. I wasn’t familiar with Media3 so had no idea :slight_smile: Good news is that I have converted the code to a full Capacitor plugin!

Things to note:

  • Supports Capacitor 6
  • ExoPlayer is changed to Media3 (Android now has the standard audio notification). Much of the Android code had to be rewritten due to changes Media3 made
  • With the Media3 upgrade, controlling audio via bluetooth and other connected devices on Android now works out of the box
  • iOS interruptions fixed
  • Fix for background music not stopping is coming soon

It should get a 1.0.0 release in the next week or two.

1 Like

Nice. Do you think it might be ready for production right now?

I would say so :smile: I am currently testing it in my app and haven’t run into any issues.

Items to note when switching over:

  • Android service declaration and permissions were updated (see the README)
  • The notification icon ic_stat_icon_default is no longer being used, if you are using the same icon for local/push notifications, you’ll want to keep it around
  • A new artworkSource option was added in lieu of the notification icon

Hi, im getting this error

 java.lang.NullPointerException: Attempt to invoke interface method 'int androidx.media3.common.Player.getPlaybackState()' on a null object reference
                                                                                                    	at com.vitiks.radiocentroecapp.AudioSource.play(AudioSource.java:118)
public void play() {
        setIsPlaying();

        Player player = getPlayer();

        if (player.getPlaybackState() == Player.STATE_IDLE) {
            player.prepare();
        }

        player.play();
    }

Please help!

It doesn’t look like you are using the standalone plugin as the error is being thrown at com.vitiks.radiocentroecapp.AudioSource? Not really sure I can help if you aren’t using the plugin without seeing all your code. For example, getPlaybackState and prepare don’t exist in our plugin.

The basics of using the plugin can be seen in the example - capacitor-native-audio/example/src/js/example.ts at f93738a6afd525840e7cea31e7fcdd6b301950a1 · mediagrid/capacitor-native-audio · GitHub