Getting to know Flutter: Simple audioplayer
Tags: flutter, dart, beginners, tutorial
Published: 2021-06-09 15:20:40

Nowadays many apps have audio files inside to listen to, whether they are fitness, music or mental health apps. Let's see a basic approach to build an app with an audio player.

In this article we will focus on the *audioplayers* plugin but there are many other plugins to handle audios like *audio_service.* 

So without further ado let's dive into coding! The first thing to do is to add the following packages to your `pubspec.yaml `and then run` flutter pub get.`

```dart
dependencies:
  audioplayers: ^0.19.0
  http: ^0.13.3
  path_provider: ^2.0.2
```

Notice that **http** and **path_provider** are required only if you need to download your audio files.

## 

## Platform Specific Setup

To allow HTTP connections to any site you will need few lines of code:



### iOS

Edit the *Info.plist* file with:

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


### Android

Edit *AndroidManifest.xml* file located in `android/app/src/main/AndroidManifest.xml`

```java
<manifest ...>
    <uses-permission android:name="android.permission.INTERNET" />
    <application
        ...
        android:usesCleartextTraffic="true"
        ...>
        ...
    </application>
</manifest>
```

 

## Creating the widget

Now, let's start to create our Widget that will handle the audio; First of all, let's import the package in our widget:

```
import 'package:audioplayers/audioplayers.dart';
```

then create a Stateful Widget that will accept a url as parameter and an `isAsset` that will be true only if the audio to be played will be inside assets:

```dart
class AudioPlayerWidget extends StatefulWidget {
  final String url;
  final bool isAsset;

  const AudioPlayerWidget({
    Key? key,
    required this.url,
    this.isAsset = false,
  }) : super(key: key);

  @override
  _AudioPlayerWidgetState createState() => _AudioPlayerWidgetState();
}
```

In our `_AudioPlayerWidgetState` let's setup some properties:

- the AudioPlayer itself
- the AudioCache**, mandatory** if you need to reproduce an asset audio
- our PlayerState that will store the current state of the AudioPlayer
- a commodity computed variable` isPlaying` that we'll use to see wether the player is playing or not
- another computed variable` _isLocal` that we'll use to see whether the url to play is local or not

```dart
late AudioPlayer _audioPlayer;
late AudioCache _audioCache;

PlayerState _playerState = PlayerState.STOPPED;

bool get _isPlaying => _playerState == PlayerState.PLAYING;
bool get _isLocal => !widget.url.contains('https');
```

Since we've declared the `_audioPlayer` and `_audioCache` as **late** variables we are going to init them inside the `initState` method:

```dart
@override
  void initState() {
    _audioPlayer = AudioPlayer(mode: PlayerMode.MEDIA_PLAYER);
    _audioCache = AudioCache(fixedPlayer: _audioPlayer);
    AudioPlayer.logEnabled = true;

    _audioPlayer.onPlayerError.listen((msg) {
      print('audioPlayer error : $msg');
      setState(() {
        _playerState = PlayerState.STOPPED;
      });
    });
    super.initState();
  }

  @override
  void dispose() {
    _audioPlayer.dispose();
    super.dispose();
  }
```

Again, this is a starter guide so I won't handle here duration, seek or background; just remember that if you are going to choose the `PlayerMode.LOW_LATENCY`you won't be able to handle seek or duration updates since this mode is crafted for very short audio files.

The only stream that we're going to listen to will be `onPlayerError`, so, if an error is thrown for any reason, we will stop immediately the audio. 

**Please note:** always remember to invoke the `dispose()` method to close all the streams!!

### Play / Pause / Stop

Play/pause actions are managed by the `_playPause()` method which checks the player's status and invokes an action accordingly. We won't show the **Stop** method for the sake of brevity but the logic is exactly the same as for the method below.

```dart
_playPause() async {
    if (_playerState == PlayerState.PLAYING) {
      final playerResult = await _audioPlayer.pause();
      if (playerResult == 1) {
        setState(() {
          _playerState = PlayerState.PAUSED;
        });
      }
    } else if (_playerState == PlayerState.PAUSED) {
      final playerResult = await _audioPlayer.resume();
      if (playerResult == 1) {
        setState(() {
          _playerState = PlayerState.PLAYING;
        });
      }
    } else {
      if (widget.isAsset) {
        _audioPlayer = await _audioCache.play(widget.url);
        setState(() {
          _playerState = PlayerState.PLAYING;
        });
      } else {
        final playerResult = await _audioPlayer.play(widget.url, isLocal: _isLocal);
        if (playerResult == 1) {
          setState(() {
            _playerState = PlayerState.PLAYING;
          });
        }
      }
    }
  }
```

#### 

## Usage

The usage is pretty straightforward, just implement the` AudioPlayerWidget` inside you widget specifying for: 


### Assets

- specify the *filename* + *extension* (e.g. my_audio.mp3) of the asset to reproduce
- set `isAsset` variable to *true*



### Remote

Set the audio widget's url property with the url of the audio.



### Local

Download the audio from the url, save it and set the file path as the audio widget's url property.



####Bonus :partying_face:

You don't how how to fetch and save an audio from a provided url? don't worry we are here for this  Just set `_loadFilePath()` as the future of a `FutureBuilder.`

```dart
Future<String> _loadFilePath() async {
    final dir = await getApplicationDocumentsDirectory();
    final file = File('${dir.path}/the_name.mp3');

    if (await _assetAlreadyPresent(file.path)) {
      return file.path;
    }

    final bytes = await readBytes(Uri.parse(_remoteUrl));

    await file.writeAsBytes(bytes);

    return file.path;
  }

  Future<bool> _assetAlreadyPresent(String filePath) async {
    final File file = File(filePath);
    return file.exists();
  }
```



## Conclusions

As you may have noticed a simple implementation of an Audio Player is pretty straightforward and you won't have any problem to implement it in you app.

You can find the whole code inside this [GitHub](https://github.com/Alessandro-v/audioplayer_tutorial) repo! 


## Where to go now?

You can dig deeper inside *audioplayers* plugin and do some experiments with seek and background handling or... just wait my next chapter of this Audio Player series  see you soon!

*Article written by the majestic [Alessandro Viviani](https://www.linkedin.com/in/alessandro-viviani-404b8a115/).*