flutter_exoplayer 0.3.1

Flutter_exoplayer #

A Flutter plugin that let's you play multiple audio files simultaneously with an option to choose if to play in background or as a forground service, for now works only for Android.

Why pick us #

Flutter_exoplayer uses the Java ExoPlayer library, which unlike Android's MediaPlayer offers fast audio buffering, especially when using playlists. All thanks to the ExoPlayersConcatenatingMediaSource` that let's you use an audio list that allways buffers the next audios. This feature of the ExoPlayer let's you play playlists very smoothly.

Moreover Flutter_exoplayer offers many features such as:

  • Providing realtime player states (PLAYING, PAUSED, STOPPED, RELEASED etc').
  • Run unlimited count of audios simultaneously.
  • Providing audio Session ID for visualizers.
  • It has 2 options for audio playing:
    • Foreground - plays the audio in foreground service so Android won't kill the service when app is in background.
    • Background - plays the audio in background (Android can easily kill the service when app is in background), the main use of this option is when app is in foreground.
  • Providing streams such as: current player position, player duration, current player index, player state etc`.

In addition this library is only in it's first steps, any new feature suggestions or bug reports are allways welcome (just submit an issue/PR in my repository), only in this way we can make this library better!

Install #

just add this dependency in your pubsec.yaml file:

  dependencies:
    flutter_exoplayer: ^0.3.1

Support us #

If you find a bug or a feature you want to be added to this library go to the github repository Github, there you can add a new issue and tell us about the bug/feature, and if you think you can fix/add by yourself I would love to get a PR from you.

Usage #

An AudioPlayer instance can play a single audio at a time. To create it, simply call the constructor:

  AudioPlayer audioPlayer = AudioPlayer();

You can create multiple instances to play audio simultaneously, but only if you choose playerMode: PlayerMode.BACKGROUND, because android can't run two similar services.

For all methods that return a Future<Result>: that's the status of the operation (Result is an enum which contains 3 options: SUCCESS, FAIL and ERROR). If SUCCESS, the operation was successful, If FAIL, you tried to call audio conrolling methods on released audio player (this status is never returned when calling play or playAll). Otherwise it's the platform native ERROR code.

Logs are disable by default! To debug, run:

  AudioPlayer.logEnabled = true;

Playing Audio #

To play audio you have two options:

  1. play single audio.
  2. play playlist.
  • play single audio.
  String url = "URL";
  audioPlayer.play(url);
  • play playlist.
  List<String> urls = ["URL1","URL2","URL3"];
  audioPlayer.playAll(urls);

The url you pass can be either local direction or network url.

By default the player is set to play in background (Android system can easily kill the Audio player when app is in background), if Player mode is set to FOREGROUND then you need to also pass audioObject instance for the foreground notification, respectAudioFocus is set to false (if your app is respectiong audio focus it will pause when other app get's audio focus and duck if other app getting temporary access of audio focus), repeatMode is also set by default to false (every audio source will play only once), by default the volume is set to max (1.0), the index of the audio that you you want to start with by default is set to 0. To change one or more of this parameters you need to just pass them to play method.

  final Result result = await audioPlayer.play(url,
      repeatMode: true,
      respectAudioFocus: true,
      playerMode: PlayerMode.FOREGROUND,
      audioObject: audioObject);
  if (result == Result.ERROR) {
    print("something went wrong in play method :(");
  }
  final Result result = await audioPlayer.playAll(urls,
      repeatMode: true,
      respectAudioFocus: true,
      playerMode: PlayerMode.FOREGROUND,
      audioObjects: audioObjects);
  if (result == Result.ERROR) {
    print("something went wrong in playAll method :(");
  }

Controlling #

After you call play you can control you audio with pause, resume, stop, release, next, previous and seek methods.

  • Pause: Will pause your audio and keep the position.
  final Result result = await audioPlayer.pause();
  if (result == Result.FAIL) {
    print(
        "you tried to call audio conrolling methods on released audio player :(");
  } else if (result == Result.ERROR) {
    print("something went wrong in pause :(");
  }
  • Resume: Will resume your audio from the exact position it was paused on.
  final Result result = await audioPlayer.resume();
  if (result == Result.FAIL) {
    print(
        "you tried to call audio conrolling methods on released audio player :(");
  } else if (result == Result.ERROR) {
    print("something went wrong in resume :(");
  }
  • Stop: Will stop your audio and restart it position.
  final Result result = await audioPlayer.stop();
  if (result == Result.FAIL) {
    print(
        "you tried to call audio conrolling methods on released audio player :(");
  } else if (result == Result.ERROR) {
    print("something went wrong in stop :(");
  } 
  • Release: Will release your audio source from the player (you need to call play again).
  final Result result = await audioPlayer.release();
  if (result == Result.FAIL) {
    print(
        "you tried to call audio conrolling methods on released audio player :(");
  } else if (result == Result.ERROR) {
    print("something went wrong in release :(");
  }
  • Next: Will play the next song in the playlist or if playing single audio it will restart the current.
  final Result result = await audioPlayer.next();
  if (result == Result.FAIL) {
    print(
        "you tried to call audio conrolling methods on released audio player :(");
  } else if (result == Result.ERROR) {
    print("something went wrong in next :(");
  }
  • Previous: Will play the previous song in the playlist or if playing single audio it will restart the current.
  final Result result = await audioPlayer.previous();
  if (result == Result.FAIL) {
    print(
        "you tried to call audio conrolling methods on released audio player :(");
  } else if (result == Result.ERROR) {
    print("something went wrong in previous :(");
  }
  • seekPosition: Will seek to the position you set.
  final Result result = await audioPlayer.seekPosition(_duration));
  if (result == Result.FAIL) {
    print(
        "you tried to call audio conrolling methods on released audio player :(");
  } else if (result == Result.ERROR) {
    print("something went wrong in seek :(");
  }
  • seekIndex: Will seek to the index in the playlist you set.
  final Result result = await audioPlayer.seekIndex(index));
  if (result == Result.FAIL) {
    print(
        "you tried to call audio conrolling methods on released audio player :(");
  } else if (result == Result.ERROR) {
    print("something went wrong in seekIndex :(");
  }

Notification Customization #

When playing in PlayerMode.FOREGROUND then the player will show foreground notification, You can customize it in the AudioObject thing like priority/ background color / what actions to show and etc'.

NotificationActionMode represents the actions you want to show with your notification (previous, play/pause, next), you have the option to choose between: NONE - only play/pause, PREVIOUS - previous and play/pause, NEXT - next and play/pause, and ALL - that include all actions.

NotificationActionCallbackMode is a mode that lets you choose between two options: DEFAULT or CUSTOM, this parameter decides if you will recieve action callback (CUSTOM) or not (DEFAULT) when user taps on the action via onNotificationActionCallback stream, and then you can make custom action for your taste. If set to DEFAULT then the action will do only as the action name says (PLAY -> play, PREVIOUS -> play previous etc`).

Attention! You need to place your app icon or the icon you want to show in the APP_NAME\android\app\src\main\res\drawable folder (you can drop multiple icons there), if you won`t do so your app will crash because android require a small icon for notification.

  AudioObject audioObject = AudioObject(
      smallIconFileName: "your icon file name",
      title: "title",
      subTitle: "artist",
      largeIconUrl: "local or network image url",
      isLocal: false,
      notificationActionMode: NotificationActionMode.ALL);

Streams #

The AudioPlayer supports subscribing to events like so:

Duration Event #

This event returns the duration of the file, when it's available (it might take a while because it's being downloaded or buffered).

  audioPlayer.onDurationChanged.listen((Duration d) {
    print('Max duration: $d');
    setState(() => duration = d);
  });

Position Event #

This Event updates the current position of the audio. You can use it to make a progress bar, for instance.

  audioPlayer.onAudioPositionChanged.listen((Duration  p) {
    print('Current position: $p');
    setState(() => position = p);
  });

State Event #

This Event returns the current player state. You can use it to show if player playing, or stopped, or paused.

  audioPlayer.onPlayerStateChanged.listen((PlayerState s) {
    print('Current player state: $s');
    setState(() => plaVyerState = s);
  });

Completion Event #

This Event is called when the audio finishes playing (in playAll mode it fires only when all playlist finishes playing). If repeatMode is set yo true then this event is never fired. It does not fire when you interrupt the audio with pause or stop. COMPLETED state acts just like PAUSED state with seek to the first audio and position 0, and can restart the audio player with resume/play/playAll.

  audioPlayer.onPlayerCompletion.listen((event) {
    print('Current player is completed');
  });

Audio Session ID Event #

This Event is called when audio session id is changed.

  audioPlayer.onAudioSessionIdChange.listen((audioSessionId) {
      print("audio Session Id: $audioSessionId");
  });

Notification Action Event #

This Event is called when the user taps on one of the notification actions, then the stream will return the action name of the action that the user has clicked on.

  audioPlayer.onNotificationActionCallback.listen((notificationActionName) {
    //do something
  });

Audio Index Event #

This Event is called when the current player audio index is changed (new audio is being played).

  audioPlayer.onCurrentAudioIndexChanged.listen((index) {
      setState(() {
        currentIndex = index;
      });
    });

Error Event #

This is called when an unexpected ERROR is thrown in the native code.

  audioPlayer.onPlayerError.listen((msg) {
    print('audioPlayer ERROR : $msg');
    setState(() {
      playerState = PlayerState.stopped;
      duration = Duration(seconds: 0);
      position = Duration(seconds: 0);
    });
  });

Supported Formats #

You can check a list of supported formats below:

IOS implementation #

If you have the time and want to implement this library on IOS, i would love to get PR, and hopefully add your PR to my library.

Credits #

This project was originally a fork of luanpotter's audioplayers that was also originally a fork of rxlabz's audioplayer, but since we have diverged and added more features.

Thanks for @rxlabz and @luanpotter for the amazing work!

Changelog #

0.3.1 #

  • Fixed seekPosition and seekIndex errors in foregroundPlayer.

0.3.0 #

  • Renamed seek to seekPosition.
  • Added seekIndex feature that lets you seek to a specific index in playlist (available only when playing playlist).
  • Added index parameter to playAll, that indicates from what index to start playing.

0.2.1 #

  • Updated code efficiency.
  • Fixed some minor bugs.

0.2.0 #

  • Fixed player state handling completly.
  • Changed the behavior of the COMPLETED state to act similarly as PAUSED state.

0.1.0 #

  • Fixed player state handling.
  • Added SetRepeatMode feature.

0.0.2 #

  • Changed the class name, Exoplayer => Audioplayer.
  • Added custom notification callback via stream (Dart side) in addition to the default (only Java side).

0.0.1 #

  • Initial Open Source release.

example/README.md

flutter_exoplayer example #

This is an example usage of flutter_exoplayer plugin.

It's a simple app with three tabs.

  • Remote Url: Plays audio from a remote url from the Internet.
  • Local File: Downloads a file to your device in order to play it from your device.
  • Remote Url and Local File: plays downloaded and not downloaded audio mix.

This example bundles a PlayerWidget that could be used as a very simple audio player interface.

Use this package as a library

1. Depend on it

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


dependencies:
  flutter_exoplayer: ^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:flutter_exoplayer/audioplayer.dart';
import 'package:flutter_exoplayer/audio_notification.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
37
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
100
Overall:
Weighted score of the above. [more]
68
Learn more about scoring.

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

  • Dart: 2.4.0
  • pana: 0.12.19
  • Flutter: 1.7.8+hotfix.4

Platforms

Detected platforms: Flutter

References Flutter, and has no conflicting libraries.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.1.0 <3.0.0
flutter 0.0.0
uuid ^2.0.0 2.0.2
Transitive dependencies
charcode 1.1.2
collection 1.14.11 1.14.12
convert 2.1.1
crypto 2.1.2
meta 1.1.6 1.1.7
sky_engine 0.0.99
typed_data 1.1.6
vector_math 2.0.8
Dev dependencies
flutter_test
test ^1.3.0