Audio in the background for Ionic / Capacitor app

Hi,
Still the same.

There was an issue posting to the looper for method play
                                                                                                    java.lang.NullPointerException: Attempt to invoke interface method 'int androidx.media3.common.Player.getPlaybackState()' on a null object reference
                                                                                                    	at us.mediagrid.capacitorjs.plugins.nativeaudio.AudioSource.play(AudioSource.java:118)
                                                                                                    	at us.mediagrid.capacitorjs.plugins.nativeaudio.AudioPlayerPlugin.lambda$play$7(AudioPlayerPlugin.java:234)
                                                                                                    	at us.mediagrid.capacitorjs.plugins.nativeaudio.AudioPlayerPlugin.$r8$lambda$Iy2Q_1eSWn3Vg4YUGZnkaltI1K4(Unknown Source:0)
                                                                                                    	at us.mediagrid.capacitorjs.plugins.nativeaudio.AudioPlayerPlugin$$ExternalSyntheticLambda8.run(Unknown Source:4)
                                                                                                    	at us.mediagrid.capacitorjs.plugins.nativeaudio.AudioPlayerPlugin.lambda$postToLooper$17(AudioPlayerPlugin.java:566)
                                                                                                    	at us.mediagrid.capacitorjs.plugins.nativeaudio.AudioPlayerPlugin$$ExternalSyntheticLambda16.run(Unknown Source:6)
                                                                                                    	at android.os.Handler.handleCallback(Handler.java:942)
                                                                                                    	at android.os.Handler.dispatchMessage(Handler.java:99)
                                                                                                    	at android.os.Looper.loopOnce(Looper.java:211)
                                                                                                    	at android.os.Looper.loop(Looper.java:300)
                                                                                                    	at android.app.ActivityThread.main(ActivityThread.java:8232)
                                                                                                    	at java.lang.reflect.Method.invoke(Native Method)
                                                                                                    	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:580)
                                                                                                    	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1028)

Are you calling await AudioPlayer.create and once that resolves AudioPlayer.initialize? It would be helpful if you shared the JS you have implementing the AudioPlayer.

Yes!

prepare(){
    AudioPlayer.create({
      audioId:"centro-dig",
      audioSource:"http://streamingecuador.com:7046/stream",
      friendlyTitle:"Centro Digital",
      useForNotification:true,
      isBackgroundMusic:true,
      loop:false
    }).catch(ex => this.setError(ex));
    AudioPlayer.initialize({audioId:"centro-dig"}).catch(ex => this.setError(ex));
    
  }
start() {
    AudioPlayer.play({
      audioId:"centro-dig"
    });
}
ngOnInit() {
    this.platform.ready().then(async()=>{
      this.prepare();
      this.start();
    });
}

AudioPlayer.initialize needs to be within the .then of AudioPlayer.create as create needs to resolve before calling initialize.

useForNotification and isBackgroundMusic should also not both be set to true for the same audio source.

Can you write an example please?

Got it working with something like this:

 await AudioPlayer.create({
      audioId:"centro-dig",
      audioSource:"http://streamingecuador.com:7046/stream",
      friendlyTitle:"Centro Digital",
      useForNotification:true,
      isBackgroundMusic:false,
      loop:false
    }).then(async ()=>{
      await AudioPlayer.initialize({audioId:"centro-dig"}).catch(ex => this.setError(ex));

    }).catch(ex => this.setError(ex));
this.platform.ready().then(async()=>{
      this.prepare().then(()=>{
        this.start();
      });
      
    });

On the other hand, the icon is not showing on iOS.
Thanks!

You don’t need to do await and .then(). You use one or the other. When using await, you wrap the code in a try / catch. When using .then(), you use a .catch(). Reading up on Promises might be helpful - How to use promises - Learn web development | MDN

In regards to the iOS icon, did you create a NowPlayingIcon asset? See the README.

Hello @twestrick,

Are you planning to support remote audio stream in the future?
Also, when you have phone call incoming, does the audio plays back when the call is over?

I am looking for a capacitor alternative to cordova-media. The HTML5 audio is good but have the phone call problem.

Can you elaborate on this? It currently supports playing an mp3 from a web/internet/remote source.

Yes, it supports this (it should at least :smile:). I didn’t actually test this on Android after changing to Media3. I only tested ducking, i.e. when GPS directions are spoken. That is an oversight on my part.

For the remote audio streaming, I meant to play an audio stream, generally used for web radio.

For example : http://newiberia.onlineradiostation.co:8036/stream?type=http&nocache=106921

I have tried to use your plugin with it but with no success.

Hi @twestrick. If I display the song title in friendlyTitle, can the data be updated when the song title changes?

At the moment friendlyTitle can only be set when create is called. What is your use case?

I’m using the plugin to play streaming audio.
The song title changes while the stream is playing, and I need to display the updated information in the notification or media controls.
Since the songs are dynamically changing during playback, it’s important to be able to update the title without having to create a new audio player each time.

Just to clarify, you aren’t changing the audio source (by calling changeAudioSource), but using an actual stream that just keeps playing? Curious what format for the stream you are using as @soravengeur said they couldn’t get it to work.

As a solution, you are looking for a method to just be able to change the friendlyTitle? Does your stream have the song title embedded in it?

Yes, that’s correct. I’m not changing the audio source using changeAudioSource. It’s a continuous streaming audio feed, so the stream keeps playing without switching to a different source.
The stream is an Icecast audio stream in MP3 format.
As a solution, I’m looking for a way to dynamically update the friendlyTitle during playback when the song or content title changes.
The stream itself doesn’t have the song title embedded. I’m fetching the current song information from an external API, so I need to update the title manually in the media controls and notification when a new song starts.

I will take a look and see if it’s possible (meaning if it will cause any weird issues). I am thinking a method called changeMetadata that will allow changing the friendlyTitle and artworkSource.

I’ve opened up Discussions on the repo so future conversations can happen over there.

I created a PR over here - feat: Add method to change metadata by wsamoht · Pull Request #6 · mediagrid/capacitor-native-audio · GitHub

Can you try it out before I release it? Please comment over on the PR with any issues or if it’s good.

You should be able to install the branch with the following:

npm install https://github.com/mediagrid/capacitor-native-audio#add-method-to-change-metadata

It’s working perfectly! Thank you.

1 Like

Hello @alexdemon123 ,

You have mentioned that you are playing the a audio stream from Icecast. Can you confirm than it is working fine by just provided the URL of the stream on your side? Is this stream remote, accessible via a HTTP url?