audioplayer 0.5.0

  • README.md
  • CHANGELOG.md
  • Example
  • Installing
  • Versions
  • 46

AudioPlayer

A Flutter audio plugin (ObjC/Java) to play remote or local audio files

Features

  • [x] Android & iOS
    • [x] play (remote file)
    • [x] stop
    • [x] pause
    • [x] onComplete
    • [x] onDuration / onCurrentPosition
    • [x] seek
    • [x] mute

screenshot

Usage

Example

To use this plugin :

  dependencies:
    flutter:
      sdk: flutter
    audioplayer:
  • Instantiate an AudioPlayer instance
//...
AudioPlayer audioPlugin = new AudioPlayer();
//...

Player Controls

Future<void> play() async {
  await audioPlayer.play(kUrl);
  setState(() => playerState = PlayerState.playing);
}

Future<void> pause() async {
  await audioPlayer.pause();
  setState(() => playerState = PlayerState.paused);
}

Future<void> stop() async {
  await audioPlayer.stop();
  setState(() {
    playerState = PlayerState.stopped;
    position = new Duration();
  });
}

Status and current position

The dart part of the plugin listen for platform calls :

//...
_positionSubscription = audioPlayer.onAudioPositionChanged.listen(
  (p) => setState(() => position = p)
);

_audioPlayerStateSubscription = audioPlayer.onPlayerStateChanged.listen((s) {
  if (s == AudioPlayerState.PLAYING) {
    setState(() => duration = audioPlayer.duration);
  } else if (s == AudioPlayerState.STOPPED) {
    onComplete();
    setState(() {
      position = duration;
    });
  }
}, onError: (msg) {
  setState(() {
    playerState = PlayerState.stopped;
    duration = new Duration(seconds: 0);
    position = new Duration(seconds: 0);
  });
});

Do not forget to cancel all the subscriptions when the widget is disposed.

iOS

⚠️ iOS App Transport Security

By default iOS forbids loading from non-https url. To cancel this restriction edit your .plist and add :

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>

Troubleshooting

  • If you get a MissingPluginException, try to flutter build apk on Android, or flutter build ios
  • to use the plugin in a ObjC iOS project, add 'use_frameworks!' to your podfile cf. example

Getting Started

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

For help on editing plugin code, view the documentation.

Changelog

0.5.0

  • BREAKING Change: No more separate handlers for communicating the state of the player. Instead we rely on streams to publish state changes and position updates.
  • Code formatting and flow improvements. Preparation for testing.

0.4.0

  • Feat : merge PR from mindon with mute methods and various improvements
  • fixes Future<int> errors with --preview-dart2
  • Example : add a slider to demonstrate the seek feature

0.3.0

  • merge PR from johanhenselmans to switch iOS to ObjectiveC
  • merge PR from oaks to add the seek feature

0.2.0

  • support for local files

0.1.0

0.0.2

Separated handlers for position, duration, completion and errors

  • setDurationHandler(TimeChangeHandler handler)

  • setPositionHandler(TimeChangeHandler handler)

  • setCompletionHandler(VoidCallback callback)

  • setErrorHandler(ErrorHandler handler)

  • new typedef

typedef void TimeChangeHandler(Duration duration);
typedef void ErrorHandler(String message);

0.0.1

  • first POC :
    • methods : play, pause, stop
    • a globalHandler for position, duration, completion and errors

example/lib/main.dart

import 'dart:async';
import 'dart:io';
import 'dart:typed_data';

import 'package:audioplayer/audioplayer.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart';
import 'package:path_provider/path_provider.dart';

typedef void OnError(Exception exception);

const kUrl = "http://www.rxlabz.com/labz/audio2.mp3";
const kUrl2 = "http://www.rxlabz.com/labz/audio.mp3";

void main() {
  runApp(new MaterialApp(home: new Scaffold(body: new AudioApp())));
}

enum PlayerState { stopped, playing, paused }

class AudioApp extends StatefulWidget {
  @override
  _AudioAppState createState() => new _AudioAppState();
}

class _AudioAppState extends State<AudioApp> {
  Duration duration;
  Duration position;

  AudioPlayer audioPlayer;

  String localFilePath;

  PlayerState playerState = PlayerState.stopped;

  get isPlaying => playerState == PlayerState.playing;
  get isPaused => playerState == PlayerState.paused;

  get durationText =>
      duration != null ? duration.toString().split('.').first : '';
  get positionText =>
      position != null ? position.toString().split('.').first : '';

  bool isMuted = false;

  StreamSubscription _positionSubscription;
  StreamSubscription _audioPlayerStateSubscription;

  @override
  void initState() {
    super.initState();
    initAudioPlayer();
  }

  @override
  void dispose() {
    _positionSubscription.cancel();
    _audioPlayerStateSubscription.cancel();
    audioPlayer.stop();
    super.dispose();
  }

  void initAudioPlayer() {
    audioPlayer = new AudioPlayer();
    _positionSubscription = audioPlayer.onAudioPositionChanged.listen(
      (p) => setState(() => position = p)
    );
    _audioPlayerStateSubscription = audioPlayer.onPlayerStateChanged.listen((s) {
      if (s == AudioPlayerState.PLAYING) {
        setState(() => duration = audioPlayer.duration);
      } else if (s == AudioPlayerState.STOPPED) {
        onComplete();
        setState(() {
          position = duration;
        });
      }
    }, onError: (msg) {
      setState(() {
        playerState = PlayerState.stopped;
        duration = new Duration(seconds: 0);
        position = new Duration(seconds: 0);
      });
    });
  }

  Future play() async {
    await audioPlayer.play(kUrl);
    setState(() {
      playerState = PlayerState.playing;
    });
  }

  Future _playLocal() async {
    await audioPlayer.play(localFilePath, isLocal: true);
    setState(() => playerState = PlayerState.playing);
  }

  Future pause() async {
    await audioPlayer.pause();
    setState(() => playerState = PlayerState.paused);
  }

  Future stop() async {
    await audioPlayer.stop();
    setState(() {
      playerState = PlayerState.stopped;
      position = new Duration();
    });
  }

  Future mute(bool muted) async {
    await audioPlayer.mute(muted);
    setState(() {
      isMuted = muted;
    });
  }

  void onComplete() {
    setState(() => playerState = PlayerState.stopped);
  }

  Future<Uint8List> _loadFileBytes(String url, {OnError onError}) async {
    Uint8List bytes;
    try {
      bytes = await readBytes(url);
    } on ClientException {
      rethrow;
    }
    return bytes;
  }

  Future _loadFile() async {
    final bytes = await _loadFileBytes(kUrl,
        onError: (Exception exception) =>
            print('_loadFile => exception $exception'));

    final dir = await getApplicationDocumentsDirectory();
    final file = new File('${dir.path}/audio.mp3');

    await file.writeAsBytes(bytes);
    if (await file.exists())
      setState(() {
        localFilePath = file.path;
      });
  }

  @override
  Widget build(BuildContext context) {
    return new Center(
        child: new Material(
            elevation: 2.0,
            color: Colors.grey[200],
            child: new Center(
              child: new Column(
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    new Material(child: _buildPlayer()),
                    localFilePath != null
                        ? new Text(localFilePath)
                        : new Container(),
                    new Padding(
                      padding: const EdgeInsets.all(8.0),
                      child: new Row(
                          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                          children: [
                            new RaisedButton(
                              onPressed: () => _loadFile(),
                              child: new Text('Download'),
                            ),
                            new RaisedButton(
                              onPressed: () => _playLocal(),
                              child: new Text('play local'),
                            ),
                          ]),
                    )
                  ]),
            )));
  }

  Widget _buildPlayer() => new Container(
      padding: new EdgeInsets.all(16.0),
      child: new Column(mainAxisSize: MainAxisSize.min, children: [
        new Row(mainAxisSize: MainAxisSize.min, children: [
          new IconButton(
              onPressed: isPlaying ? null : () => play(),
              iconSize: 64.0,
              icon: new Icon(Icons.play_arrow),
              color: Colors.cyan),
          new IconButton(
              onPressed: isPlaying ? () => pause() : null,
              iconSize: 64.0,
              icon: new Icon(Icons.pause),
              color: Colors.cyan),
          new IconButton(
              onPressed: isPlaying || isPaused ? () => stop() : null,
              iconSize: 64.0,
              icon: new Icon(Icons.stop),
              color: Colors.cyan),
        ]),
        duration == null
            ? new Container()
            : new Slider(
                value: position?.inMilliseconds?.toDouble() ?? 0.0,
                onChanged: (double value) =>
                    audioPlayer.seek((value / 1000).roundToDouble()),
                min: 0.0,
                max: duration.inMilliseconds.toDouble()),
        new Row(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: <Widget>[
            new IconButton(
                onPressed: () => mute(true),
                icon: new Icon(Icons.headset_off),
                color: Colors.cyan),
            new IconButton(
                onPressed: () => mute(false),
                icon: new Icon(Icons.headset),
                color: Colors.cyan),
          ],
        ),
        new Row(mainAxisSize: MainAxisSize.min, children: [
          new Padding(
              padding: new EdgeInsets.all(12.0),
              child: new Stack(children: [
                new CircularProgressIndicator(
                    value: 1.0,
                    valueColor: new AlwaysStoppedAnimation(Colors.grey[300])),
                new CircularProgressIndicator(
                  value: position != null && position.inMilliseconds > 0
                      ? (position?.inMilliseconds?.toDouble() ?? 0.0) /
                          (duration?.inMilliseconds?.toDouble() ?? 0.0)
                      : 0.0,
                  valueColor: new AlwaysStoppedAnimation(Colors.cyan),
                  backgroundColor: Colors.yellow,
                ),
              ])),
          new Text(
              position != null
                  ? "${positionText ?? ''} / ${durationText ?? ''}"
                  : duration != null ? durationText : '',
              style: new TextStyle(fontSize: 24.0))
        ])
      ]));
}

Use this package as a library

1. Depend on it

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


dependencies:
  audioplayer: ^0.5.0

2. Install it

You can install packages from the command line:

with pub:


$ pub get

with Flutter:


$ flutter packages get

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

3. Import it

Now in your Dart code, you can use:


import 'package:audioplayer/audioplayer.dart';
  
Version Uploaded Documentation Archive
0.5.0 Jun 12, 2018 Go to the documentation of audioplayer 0.5.0 Download audioplayer 0.5.0 archive
0.4.0 Mar 22, 2018 Go to the documentation of audioplayer 0.4.0 Download audioplayer 0.4.0 archive
0.3.0 Oct 23, 2017 Go to the documentation of audioplayer 0.3.0 Download audioplayer 0.3.0 archive
0.2.0 May 26, 2017 Go to the documentation of audioplayer 0.2.0 Download audioplayer 0.2.0 archive
0.1.0+2 May 25, 2017 Go to the documentation of audioplayer 0.1.0+2 Download audioplayer 0.1.0+2 archive
0.1.0+1 May 25, 2017 Go to the documentation of audioplayer 0.1.0+1 Download audioplayer 0.1.0+1 archive
0.1.0 May 25, 2017 Go to the documentation of audioplayer 0.1.0 Download audioplayer 0.1.0 archive
Popularity:
Describes how popular the package is relative to other packages. [more]
93
Health:
Code health derived from static analysis. [more]
0
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
0
Overall:
Weighted score of the above. [more]
46
Learn more about scoring.

The package version is not analyzed, because it does not support Dart 2. Until this is resolved, the package will receive a health and maintenance score of 0.

Analysis issues and suggestions

Support Dart 2 in pubspec.yaml.

The SDK constraint in pubspec.yaml doesn't allow the Dart 2.0.0 release. For information about upgrading it to be Dart 2 compatible, please see https://www.dartlang.org/dart-2#migration.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=1.19.0 <2.0.0