/md_media_controls

Primary LanguageKotlinBSD 3-Clause "New" or "Revised" LicenseBSD-3-Clause

md_media_controls

A new flutter plugin project.

Getting Started

This project is a starting point for a Flutter plug-in package, a specialized package that includes platform-specific implementation code for Android and/or iOS.

For help getting started with Flutter, view our online documentation, which offers tutorials, samples, guidance on mobile development, and a full API reference.

MdMediaControls

A Flutter audio plugin (Swift/Kotlin) to play remote or local audio files and control it on LockScreen(iOS only, Android part will be ready soon)

Features

  • Android & iOS
    • play (remote file)
    • stop
    • pause
    • onEnd
    • position/duration
    • seek
    • mute
    • rate / onChangeRate
  • iOS
    • lockScreen controls
    • lockScreen events
  • Android
    • TBD

Usage

Example

To use this plugin :

  dependencies:
    flutter:
      sdk: flutter
    md_media_controls:
  • Instantiate an MdMediaControls instance
//...
MdMediaControls mdMediaControls = new MdMediaControls();
//...

Player Controls

const testUrl = "https://raw.githubusercontent.com/IgorBaranov/md_media_controls/master/example.mp3";

StreamBuilder<ControlsState>(
              initialData: ControlsState.STOPPED,
              stream: mdMediaControls.onPlayerStateChanged,
              builder: (BuildContext context, AsyncSnapshot<ControlsState> snapshot) {
                final ControlsState data = snapshot.data;

                return Row(mainAxisSize: MainAxisSize.min, children: [
                  IconButton(
                      onPressed: data == ControlsState.PLAYING ? null : () async {
                        await mdMediaControls.playNew(url: testUrl, rate: 2.0);
                        await mdMediaControls.setInfo(title: 'Some title', artist: 'some artist',
                            imageUrl: 'https://pngimage.net/wp-content/uploads/2018/05/example-icon-png-4.png'
                        );
                      },
                      iconSize: 64.0,
                      icon: Icon(Icons.play_arrow),
                      color: Colors.cyan),
                  IconButton(
                      onPressed: data == ControlsState.PLAYING ? () {
                        mdMediaControls.pause();
                      } : null,
                      iconSize: 64.0,
                      icon: Icon(Icons.pause),
                      color: Colors.cyan),
                  IconButton(
                      onPressed: data == ControlsState.PLAYING || data == ControlsState.PAUSED ? () {
                        mdMediaControls.stop();
                      } : null,
                      iconSize: 64.0,
                      icon: Icon(Icons.stop),
                      color: Colors.amberAccent),
                  IconButton(
                      onPressed: () async {
                        await mdMediaControls.setInfo(title: 'Some title 123', artist: 'some artist 123',
                            imageUrl: 'assets/test.png'
                        );
                      },
                      iconSize: 64.0,
                      icon: Icon(Icons.adb),
                      color: Colors.amberAccent),

                ]);
              },
            )

Status current position, seek and rate

The dart part of the plugin listen for platform calls :

StreamBuilder<ControlsState>(
                    initialData: ControlsState.STOPPED,
                    stream: mdMediaControls.onPlayerStateChanged,
                    builder: (BuildContext context, AsyncSnapshot<ControlsState> snapshot) {
                      final ControlsState data = snapshot.data;

                      return Row(mainAxisSize: MainAxisSize.min, children: [
                        IconButton(
                            onPressed: data == ControlsState.PLAYING ? null : () async {
                              await mdMediaControls.playNew(url: 'another url', rate: 1.0);
                              await mdMediaControls.setInfo(title: 'Some title', artist: 'some artist',
                                  imageUrl: 'https://pngimage.net/wp-content/uploads/2018/05/example-icon-png-4.png'
                              );
                            },
                            iconSize: 64.0,
                            icon: Icon(Icons.play_arrow),
                            color: Colors.cyan),
                        IconButton(
                            onPressed: data == ControlsState.PLAYING ? () {
                              mdMediaControls.pause();
                            } : null,
                            iconSize: 64.0,
                            icon: Icon(Icons.pause),
                            color: Colors.cyan),
                        IconButton(
                            onPressed: data == ControlsState.PLAYING || data == ControlsState.PAUSED ? () {
                              mdMediaControls.stop();
                            } : null,
                            iconSize: 64.0,
                            icon: Icon(Icons.stop),
                            color: Colors.amberAccent),

                      ]);
                    },
                  ),
                  StreamBuilder<Duration>(
                      initialData: Duration(),
                      stream: mdMediaControls.positionChanged,
                      builder: (BuildContext context, AsyncSnapshot<Duration> snapshot) {
                        final double max = sound.service.duration.inSeconds.toDouble();
                        final double value = snapshot.data.inSeconds.toDouble();

                        return Column(
                          children: <Widget>[
                            max > 0.0 ? Center(
                                child: Text('$value/$max')
                            ) : Container(),
                            value >= 0.0 && value <= max ? Slider(
                                onChanged: (double seconds) {
                                  mdMediaControls.seek(seconds);
                                },
                                min: 0.0,
                                value: value,
                                max: max
                            ) : Slider(
                                onChanged: null,
                                min: 0.0,
                                value: 0.0,
                                max: max
                            )
                          ],
                        );
                      }
                  ),
                  StreamBuilder<double>(
                    initialData: 1.0,
                    stream: mdMediaControls.onRateChanged,
                    builder: (BuildContext context, AsyncSnapshot<double> snapshot) {
                      return Column(
                        children: <Widget>[
                          Text('${snapshot.data}'),
                          Container(
                              child: Center(
                                child: Slider(
                                    onChanged: (double rate) => mdMediaControls.rate(rate: rate),
                                    value: snapshot.data,
                                    min: 0.0,
                                    max: 5.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>

Getting Started

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

For help on editing plugin code, view the documentation.