audio_service 0.3.1

audio_service #

Play audio in the background.

  • Continues playing while the screen is off or the app is in the background
  • Control playback from your Flutter UI, headset, Wear OS or Android Auto
  • Drive audio playback from Dart code

This plugin provides a complete framework for playing any audio in the background. You implement callbacks in Dart to play/pause/seek/etc audio in the background giving you the flexibility to use any Dart plugin and any custom Dart logic to output the audio. For example, if you wish to play music in the background, you may use the audioplayer plugin in conjunction with audio_service. If you would rather play text-to-speech in the background, you may use the flutter_tts plugin in conjunction with audio_service.

audio_service itself manages all of the platform-specific code for setting up the environment for background audio, and interfacing with various peripherals used to control audio playback. For Android, this means acquiring a wake lock so that audio will play with the screen turned off, acquiring audio focus so that your app can gracefully handle phone call interruptions, creating a media session and media browser service so that your app can be controlled by wearable devices and Android Auto. The iOS side is currently not implemented and contributors are welcome (please see the Help section at the bottom of this page).

Since background execution of Dart code is a relatively new feature of Flutter, not all plugins are yet compatible with audio_service (I am contacting some of these authors to make their packages compatible.)

Example #

Client-side code #

This code runs in the main UI isolate.

AudioService.connect();    // When UI becomes visible
AudioService.start(        // When user clicks button to start playback
  backgroundTask: myBackgroundTask,
  androidNotificationChannelName: 'Music Player',
  androidNotificationIcon: "mipmap/ic_launcher",
);
AudioService.pause();      // When user clicks button to pause playback
AudioService.play();       // When user clicks button to resume playback
AudioService.disconnect(); // When UI is gone

Background code #

This code runs in a background isolate.

void myBackgroundTask() {
  AudioServiceBackground.run(
    onStart: () async {
      // Your custom dart code to start audio playback.
      // NOTE: The background audio task will shut down
      // as soon as this async function completes.
    },
    onPlay: () {
      // Your custom dart code to resume audio playback.
    },
    onPause: () {
      // Your custom dart code to pause audio playback.
    },
    onStop: () {
      // Your custom dart code to stop audio playback.
    },
    onClick: (MediaButton button) {
      // Your custom dart code to handle a media button click.
    },
  );
}

Android setup #

You will need to create a custom MainApplication class as follows:

public class MainApplication extends FlutterApplication implements PluginRegistry.PluginRegistrantCallback {
  @Override
  public void onCreate() {
    super.onCreate();
    AudioServicePlugin.setPluginRegistrantCallback(this);
  }

  @Override
  public void registerWith(PluginRegistry registry) {
    GeneratedPluginRegistrant.registerWith(registry);
  }
}

Edit your project's AndroidManifest.xml file to reference your MainApplication class, declare the permission to create a wake lock, and add component entries for the <service> and <receiver>:

<manifest ...>
  <uses-permission android:name="android.permission.WAKE_LOCK"/>
  <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
  
  <application
    android:name=".MainApplication"
    ...>
    
    ...
    
    <service android:name="com.ryanheise.audioservice.AudioService">
      <intent-filter>
        <action android:name="android.media.browse.MediaBrowserService" />
      </intent-filter>
    </service>

    <receiver android:name="androidx.media.session.MediaButtonReceiver" >
      <intent-filter>
        <action android:name="android.intent.action.MEDIA_BUTTON" />
      </intent-filter>
    </receiver> 
  </application>
</manifest>

Any icons that you want to appear in the notification (see the MediaControl class) should be defined as Android resources in android/app/src/main/res. Here you will find a subdirectory for each different resolution:

drawable-hdpi
drawable-mdpi
drawable-xhdpi
drawable-xxhdpi
drawable-xxxhdpi

You can use Android Asset Studio to generate these different subdirectories for any standard material design icon.

Help/Contribute #

  • If you would like to contribute to the iOS side, please see https://github.com/ryanheise/audio_service/issues/10 for a description of the work to be done, and read or contribute to the ongoing discussion on how we could make this work.

  • If you find another Flutter plugin (audio or otherwise) that crashes when running in the background environment, another way you can help is to file a bug report with that project, letting them know of the simple fix to make it work (see below).

Sample bug report #

Here is a sample bug report.

Flutter's new background execution feature (described here: https://medium.com/flutter-io/executing-dart-in-the-background-with-flutter-plugins-and-geofencing-2b3e40a1a124) allows plugins to be registered in a background context (e.g. a Service). The problem is that the wifi plugin assumes that the context for plugin registration is an activity with this line of code:

WifiManager wifiManager = (WifiManager) registrar.activity().getApplicationContext().getSystemService(Context.WIFI_SERVICE);

registrar.activity() may now return null, and this leads to a NullPointerException:

E/AndroidRuntime( 2453):   at com.ly.wifi.WifiPlugin.registerWith(WifiPlugin.java:23)
E/AndroidRuntime( 2453):   at io.flutter.plugins.GeneratedPluginRegistrant.registerWith(GeneratedPluginRegistrant.java:30)

The solution is to change the above line of code to this:

WifiManager wifiManager = (WifiManager) registrar.activeContext().getApplicationContext().getSystemService(Context.WIFI_SERVICE);

0.3.1 #

  • Update example to disconnect when pressing back button.

0.3.0 #

  • Breaking change: updateTime now measured since epoch instead of boot time.

0.2.1 #

  • Streams use RxDart BehaviorSubject.

0.2.0 #

  • Migrate to AndroidX.

0.1.1 #

  • Bump targetSdkVersion to 28
  • Clear client-side metadata and state on stop.

0.1.0 #

  • onClick is now always called for media button clicks.
  • Option to set notifications as ongoing.

0.0.15 #

  • Option to set subText in notification.
  • Support media item ratings

0.0.14 #

  • Can update existing media items.
  • Can specify order of Android notification compact actions.
  • Bug fix with connect.

0.0.13 #

  • Option to preload artwork.
  • Allow client to browse media items.

0.0.12 #

  • More options to customise the notification content.

0.0.11 #

  • Breaking API changes.
  • Connection callbacks replaced by a streams API.
  • AudioService properties for playbackState, currentMediaItem, queue.
  • Option to set Android notification channel description.
  • AudioService.customAction awaits completion of the action.

0.0.10 #

  • Bug fixes with queue management.
  • AudioService.start completes when the background task is ready.

0.0.9 #

  • Support queue management.

0.0.8 #

  • Bug fix.

0.0.7 #

  • onMediaChanged takes MediaItem parameter.
  • Support playFromMediaId, fastForward, rewind.

0.0.6 #

  • All APIs address media items by String mediaId.

0.0.5 #

  • Show media art in notification and lock screen.

0.0.4 #

  • Support and example for playing TextToSpeech.
  • Click notification to launch UI.
  • More properties added to MediaItem.
  • Minor API changes.

0.0.3 #

  • Pause now keeps background isolate running
  • Notification channel id is generated from package name
  • Updated example to use audioplayer plugin
  • Fixed media button handling

0.0.2 #

  • Better connection handling.

0.0.1 #

  • Initial release.

example/README.md

audio_service_example #

This example demonstrates how to play an audio file or text-to-speech in the background.

Getting Started #

For help getting started with Flutter, view our online documentation.

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  audio_service: ^0.3.1

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:audio_service/audio_service.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
84
Health:
Code health derived from static analysis. [more]
99
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
100
Overall:
Weighted score of the above. [more]
92
Learn more about scoring.

We analyzed this package on Sep 13, 2019, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.5.0
  • pana: 0.12.21
  • Flutter: 1.9.1+hotfix.2

Platforms

Detected platforms: Flutter

References Flutter, and has no conflicting libraries.

Health suggestions

Fix lib/audio_service.dart. (-1 points)

Analysis of lib/audio_service.dart reported 2 hints:

line 380 col 35: This function has a return type of 'Future', but doesn't end with a return statement.

line 679 col 45: This function has a return type of 'Future

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.1.0 <3.0.0
flutter 0.0.0
rxdart ^0.22.0 0.22.2
Transitive dependencies
collection 1.14.11 1.14.12
meta 1.1.7
sky_engine 0.0.99
typed_data 1.1.6
vector_math 2.0.8