easy_audio_player 1.0.1 copy "easy_audio_player: ^1.0.1" to clipboard
easy_audio_player: ^1.0.1 copied to clipboard

A drop-in Flutter audio player with background playback, notification controls, and Material 3 adaptive theming.

easy_audio_player #

A Flutter audio player package that combines polished Material 3 UI, background playback with lock-screen notifications, and a simple one-line setup.

pub.dev coverage platforms


Screenshots #


MiniPlayer

ExpandedPlayer

PlayerControls

Features

Features #

  • Three ready-made widgetsMiniPlayer, ExpandedPlayer, PlayerControls
  • Background playback — lock-screen controls and notification via just_audio_background
  • Playlist management — load, add, remove, reorder, shuffle, loop
  • Material 3 adaptive theming — reads your app's ColorScheme by default
  • Waveform visualization — Android, iOS, macOS (opt-in via showWaveform)
  • Headless mode — drive the service directly via EasyAudioPlayer.service for custom UIs

Installation #

dependencies:
  easy_audio_player: ^1.0.0

Platform setup #

Android #

In android/app/src/main/AndroidManifest.xml:

<!-- Permissions (inside <manifest>) -->
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK"/>

<!-- Replace MainActivity with AudioServiceActivity (inside <application>) -->
<activity android:name="com.ryanheise.audioservice.AudioServiceActivity" ...>

<!-- Background service + media button receiver (inside <application>) -->
<service
  android:name="com.ryanheise.audioservice.AudioService"
  android:foregroundServiceType="mediaPlayback"
  android:exported="true">
  <intent-filter>
    <action android:name="android.media.browse.MediaBrowserService"/>
  </intent-filter>
</service>

<receiver
  android:name="com.ryanheise.audioservice.MediaButtonReceiver"
  android:exported="true">
  <intent-filter>
    <action android:name="android.intent.action.MEDIA_BUTTON"/>
  </intent-filter>
</receiver>

In android/app/build.gradle, set minSdkVersion 21.

iOS #

In ios/Runner/Info.plist:

<key>UIBackgroundModes</key>
<array>
  <string>audio</string>
</array>

Quick start #

1. Initialize in main() #

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await EasyAudioPlayer.init(
    config: const AudioPlayerConfig(
      androidNotificationChannelId: 'com.myapp.audio',
      androidNotificationChannelName: 'My App Audio',
    ),
  );

  runApp(const MyApp());
}

2. Load tracks and drop in a widget #

// Load a playlist
await EasyAudioPlayer.service.load([
  AudioTrack.network(
    id: 'track_1',
    url: 'https://example.com/song.mp3',
    title: 'My Song',
    artist: 'Artist',
    artworkUrl: 'https://example.com/art.jpg',
  ),
]);
await EasyAudioPlayer.service.play();

// Pin a mini player at the bottom
Scaffold(
  body: Column(
    children: [
      Expanded(child: MyContent()),
      const MiniPlayer(),
    ],
  ),
)

Widgets #

MiniPlayer #

A compact 72 px player — artwork, title/artist, play/pause, and skip next.

MiniPlayer(
  onTap: () => navigateToFullPlayer(),
)

ExpandedPlayer #

Full-screen player with artwork, metadata, seek bar, controls, optional waveform, and optional playlist.

ExpandedPlayer(
  showWaveform: true,   // Android, iOS, macOS only — silently ignored elsewhere
  showPlaylist: true,
)

Note: When showPlaylist: true, ExpandedPlayer uses an Expanded widget internally and must be placed inside a parent with bounded height (e.g., a Scaffold body). Set showPlaylist: false for unbounded contexts.

PlayerControls #

Headless controls widget — no artwork, no layout opinions. Use this to build your own player UI.

PlayerControls(
  showSeekBar: true,
  showShuffle: true,
  showLoop: true,
  showVolume: true,
  showSpeed: true,
)

AudioTrack #

// Network stream
AudioTrack.network(
  id: 'unique_id',
  url: 'https://example.com/track.mp3',
  title: 'Track Title',
  artist: 'Artist',         // optional
  album: 'Album',           // optional
  artworkUrl: 'https://…',  // optional, shown in notification
  duration: Duration(minutes: 3, seconds: 30), // optional
  extras: {'genre': 'Pop'}, // optional, passed to MediaItem
)

// Local file
AudioTrack.file(
  id: 'local_1',
  file: File('/path/to/track.mp3'),
  title: 'Local Track',
)

Service API #

All streams are BehaviorSubject-backed — they replay the latest value immediately on subscription.

final service = EasyAudioPlayer.service;

// Playback controls
await service.load(tracks, initialIndex: 0);
await service.play();
await service.pause();
await service.seek(Duration(seconds: 30));
await service.skipToNext();
await service.skipToPrevious();

// Queue management
await service.add(track);
await service.insert(0, track);
await service.remove(index);
await service.move(from, to);
await service.clear();

// Settings
await service.setVolume(0.8);      // 0.0–1.0
await service.setSpeed(1.5);       // 0.5–2.0
await service.setLoopMode(EasyLoopMode.all); // off | one | all
await service.setShuffle(true);

// Streams
service.playerStateStream   // Stream<EasyPlayerState>
service.currentTrackStream  // Stream<AudioTrack?>
service.positionStream      // Stream<Duration>
service.durationStream      // Stream<Duration?>
service.queueStream         // Stream<List<AudioTrack>>
service.errorStream         // Stream<AudioPlayerError>

// Sync getters (latest value, no await needed)
service.playerState
service.currentTrack
service.position
service.queue

Player states #

switch (service.playerState) {
  PlayerIdle()       => // nothing loaded
  PlayerBuffering()  => // loading
  PlayerPlaying(pos) => // playing at pos
  PlayerPaused(pos)  => // paused at pos
  PlayerCompleted()  => // reached end
  PlayerError(err)   => // failed — auto-skips to next track
}

Error handling #

On track failure the player auto-skips to the next track and emits on errorStream:

EasyAudioPlayer.service.errorStream.listen((error) {
  print('${error.trackId} failed: ${error.message} (${error.category})');
});

Theming #

Widgets inherit your app's Material 3 ColorScheme and TextTheme by default. Pass an AudioPlayerTheme to override:

MiniPlayer(
  theme: AudioPlayerTheme(
    primaryColor: Colors.deepPurple,
    backgroundColor: Colors.black,
  ),
)

Teardown #

await EasyAudioPlayer.dispose();
11
likes
150
points
29
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A drop-in Flutter audio player with background playback, notification controls, and Material 3 adaptive theming.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

audio_session, audio_video_progress_bar, flutter, just_audio, just_audio_background, just_waveform, rxdart

More

Packages that depend on easy_audio_player