What is background playback with a MediaSessionService?

What is a MediaSessionService?

A MediaSessionService is part of the Android media APIs that allows apps to interact with media controllers and enables background audio playback (https://stackoverflow.com/questions/75322852/media-notification-not-showed). It is a service that creates a MediaSession and MediaController instance to handle transport controls, volume changes, media button events and notifications (https://github.com/mozilla-mobile/fenix/blob/main/app/src/main/AndroidManifest.xml).

With a MediaSessionService, an app can continue playing audio even when the app UI is no longer visible. The audio playback is moved to a background service so that users can listen while using other apps or when the device screen is off.

Enabling background playback

To enable background playback for media in your Android app, you need to set up a MediaSessionService. This service allows playback to continue when the app is in the background or the device screen is off.

First, you need to declare the MediaSessionService in your AndroidManifest.xml file with the android:exported attribute set to true. This allows the service to be accessed by MediaSession callbacks.

Next, create a class that extends MediaSessionService. This service class will create the MediaSession and Player instances that manage playback.

Within the service class, you need to override onGetRoot() and return a MediaSessionService.MediaSessionServiceImpl instance. This implementation handles all the session callbacks. Inside onGetRoot() is where you will construct and return the MediaSession and Player objects.

With the service declared and set up to extend MediaSessionService, your app will be able to continue audio playback when in the background. Just be sure to start the service when playback begins.

Handling playback controls

To handle playback controls like play, pause, skip, etc. you need to implement the MediaSession.Callback() interface and override methods for the playback actions you want to handle.

For example:


public class MusicService extends MediaBrowserServiceCompat {

  private MediaSessionCompat mediaSession;

  @Override
  public void onCreate() {
    super.onCreate();

    mediaSession = new MediaSessionCompat(this, "MusicService");
        
    mediaSession.setCallback(new MediaSessionCompat.Callback() {

      @Override
      public void onPlay() {
        // Handle play request
      }

      @Override 
      public void onPause() {
       // Handle pause request
      }

      @Override
      public void onSkipToNext() {
        // Handle skip to next request
      }

    });

  }

}

When these playback control actions are triggered, such as by pressing play/pause on headphone controls, the corresponding callback method will be invoked here to handle it.

You can override additional methods like onSkipToPrevious(), onFastForward(), etc. to handle all media playback controls.

The MediaSessionCompat handles communicating with the MediaSession system service to relay these playback actions. By implementing the callback interface, your app receives these playback events and can respond appropriately to control media playback.

Notifications

When using a MediaSessionService for background audio playback, it is important to create notifications to provide playback controls and track information to the user. This is done using the NotificationCompat.MediaStyle class.

To create a media playback notification:

  • Create a basic notification using NotificationCompat.Builder
  • Set the notification’s content intent to pending intent that will open your app’s UI when clicked
  • Create a MediaStyle notification object, passing the basic notification builder to its constructor
  • Call setMediaSession() on the MediaStyle notification, passing your app’s MediaSession.Session token
  • Set relevant metadata on the MediaStyle notification like the title, artist, album art etc.
  • Call setShowActionsInCompactView() to show playback buttons in the minimized notification view

This will create a notification with integrated playback controls using the MediaSession metadata and actions. The notification will also allow the media playback to continue when the user opens your app.

For more details, see the StackOverflow example.

Lock screen controls

MediaSessionService enables applications to show playback controls and metadata on the lock screen by default. This allows users to easily control playback without unlocking their device.

Developers can customize the appearance of lock screen controls by providing icons, album artwork, and metadata like track title and artist name. For example, the Spotify app displays album artwork and track info on lock screens as noted on the Reddit community.

With MediaSessionService, basic media playback controls are built-in. Developers can focus on customizing the look and feel of notifications and lock screen controls to match their app’s brand. This provides a more seamless user experience.

Audio Focus

Apps request audio focus using the AudioManager when they need exclusive access to the audio playback system. The system uses audio focus to coordinate multiple apps trying to play audio at the same time. Requesting audio focus during playback ensures your app properly handles interruptions and sharing of audio resources.

To request audio focus, call the AudioManager’s requestAudioFocus() method, passing in an AudioFocusRequest object defining the parameters like duration and behavior. To abandon audio focus, call abandonAudioFocus(). Be sure to request focus again later if needed.

When your app loses focus, it should pause playback. You can resume playback once focus returns by calling requestAudioFocus() again. For transient losses like notifications, you may want to just duck the audio instead of completely pausing.

Properly handling audio focus ensures a good user experience across multiple media apps. Your app should be a cooperative audio citizen and cede focus when appropriate.

Handling interruptions

Properly handling audio interruptions is an important part of implementing background audio playback. When certain events occur, such as the headphones being disconnected or an incoming phone call, the audio should be paused temporarily. As soon as the interruption ends, the audio playback should be resumed seamlessly.

The MediaSession API allows you to handle these interruptions appropriately. By setting the proper flags, playback will be paused automatically on disconnect and resumed when headphones are plugged back in. You can also declare a high priority audio focus to pause playback during calls and other disruptions.

As noted in the Android documentation, “Your app’s audio playback should duck (lower volume) during interruptions and resume at full volume once the interruption ends.” The system will handle the ducking volume, you just need to properly pause and resume based on session callbacks.

With careful handling of interruptions, your app can deliver seamless background audio playback no matter what disruptions occur on the device. Proper implementation results in a much better user experience.

Testing

Thoroughly testing background audio playback is crucial to providing a smooth user experience. Here are some key areas to test:

  • Verify that audio continues playing when switching to another app or minimizing the app.
  • Test on actual devices in addition to emulators. There can be differences in how background audio is handled.
  • Test with various audio formats – mp3, wav, m4a, etc. There may be inconsistencies.
  • Confirm the audio keeps playing after locking and unlocking the device.
  • Switch between wifi and cellular data to ensure playback persists.
  • Make sure playback resumes properly after a phone call or other interruption.
  • Test with do not disturb mode enabled and disabled.
  • Try toggling between speaker and wired/Bluetooth audio output.

Rigorously test background playback on a variety of devices and Android versions. Audio glitches or unexpected interruptions negatively impact the user experience.

Best Practices

When implementing background audio playback in Android, it’s important to follow best practices to provide a good user experience. According to the Android storage use cases and best practices guide, you should:

  • Follow Android audio guidelines – Use MediaPlayer or MediaSession based APIs for background audio, and comply with requirements like audio focus.
  • Optimize for battery/performance – Minimize CPU usage, network requests and other resource intensive operations. Only play audio at necessary quality levels for background playback.

These tips will help minimize negative impacts like battery drain while delivering responsive, quality background audio.

Use cases

The MediaSessionService is commonly used in the following types of apps that require background audio playback:

Music apps

Music apps like Spotify use the MediaSessionService to continue playing songs when the app is in the background. This allows users to minimize the app or lock their phone without the music stopping (1).

Podcast/audiobook apps

Podcast and audiobook apps such as Audible leverage the MediaSessionService to play long-form audio content even when the screen is off. This gives users a seamless listening experience (2).

Live streaming radio

Apps that stream live radio can use the MediaSessionService to continue playing the broadcast in the background. For example, users can start listening to a station on iHeartRadio and then lock their screen or switch to another app without missing any of the stream.

Leave a Reply

Your email address will not be published. Required fields are marked *