Using the audioplayers Package to Play Local and Remote Audio Files with Features Like Looping and Volume Control in Flutter

Flutter is a versatile framework for building cross-platform applications, and it excels in handling media content, including audio. The audioplayers package is a popular choice for Flutter developers to play both local and remote audio files seamlessly. In this comprehensive guide, we’ll explore how to use the audioplayers package effectively, focusing on playing audio from different sources, implementing looping, and controlling volume.

What is the audioplayers Package?

The audioplayers package is a Flutter library that allows you to play multiple audio files simultaneously, supporting both local and remote sources. It provides features such as:

  • Playing audio from a URL (remote files).
  • Playing audio from local files.
  • Looping audio.
  • Controlling volume.
  • Setting playback rate.
  • Monitoring playback state (playing, paused, stopped, completed).

Getting Started with audioplayers

Step 1: Add the Dependency

First, add the audioplayers package to your pubspec.yaml file:

dependencies:
  flutter:
    sdk: flutter
  audioplayers: ^5.2.0 # Use the latest version

Then, run flutter pub get in your terminal to install the package.

Step 2: Import the Package

Import the audioplayers package in your Dart file:

import 'package:audioplayers/audioplayers.dart';

Playing Audio Files

Playing Remote Audio Files

To play audio from a URL, use the setSourceUrl method followed by the play method:

import 'package:flutter/material.dart';
import 'package:audioplayers/audioplayers.dart';

class RemoteAudioPlayer extends StatefulWidget {
  @override
  _RemoteAudioPlayerState createState() => _RemoteAudioPlayerState();
}

class _RemoteAudioPlayerState extends State {
  final AudioPlayer audioPlayer = AudioPlayer();
  final String audioUrl = 'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3';

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

  Future _setupAudioPlayer() async {
    await audioPlayer.setSourceUrl(audioUrl);
  }

  Future _playAudio() async {
    await audioPlayer.play(UrlSource(audioUrl));
  }

  Future _pauseAudio() async {
    await audioPlayer.pause();
  }

  Future _stopAudio() async {
    await audioPlayer.stop();
  }

  @override
  void dispose() {
    audioPlayer.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Remote Audio Player'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: _playAudio,
              child: Text('Play'),
            ),
            ElevatedButton(
              onPressed: _pauseAudio,
              child: Text('Pause'),
            ),
            ElevatedButton(
              onPressed: _stopAudio,
              child: Text('Stop'),
            ),
          ],
        ),
      ),
    );
  }
}

Playing Local Audio Files

To play audio from a local file, you first need to add the file to your project. Create an assets folder in the root directory of your Flutter project, and add your audio file to it. Update your pubspec.yaml file to include the assets folder:

flutter:
  assets:
    - assets/

Then, use the setSourceAsset method followed by the play method:

import 'package:flutter/material.dart';
import 'package:audioplayers/audioplayers.dart';

class LocalAudioPlayer extends StatefulWidget {
  @override
  _LocalAudioPlayerState createState() => _LocalAudioPlayerState();
}

class _LocalAudioPlayerState extends State {
  final AudioPlayer audioPlayer = AudioPlayer();
  final String audioAsset = 'audio/sound.mp3'; // Replace with your asset path

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

  Future _setupAudioPlayer() async {
      await audioPlayer.setSourceAsset(audioAsset);
  }
  

  Future _playAudio() async {
     await audioPlayer.play(AssetSource(audioAsset));
  }

  Future _pauseAudio() async {
    await audioPlayer.pause();
  }

  Future _stopAudio() async {
    await audioPlayer.stop();
  }

  @override
  void dispose() {
    audioPlayer.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Local Audio Player'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: _playAudio,
              child: Text('Play'),
            ),
            ElevatedButton(
              onPressed: _pauseAudio,
              child: Text('Pause'),
            ),
            ElevatedButton(
              onPressed: _stopAudio,
              child: Text('Stop'),
            ),
          ],
        ),
      ),
    );
  }
}

Implementing Looping

To loop an audio file, set the loopMode property of the AudioPlayer to LoopMode.all:

import 'package:flutter/material.dart';
import 'package:audioplayers/audioplayers.dart';

class LoopingAudioPlayer extends StatefulWidget {
  @override
  _LoopingAudioPlayerState createState() => _LoopingAudioPlayerState();
}

class _LoopingAudioPlayerState extends State {
  final AudioPlayer audioPlayer = AudioPlayer();
  final String audioUrl = 'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3';

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

  Future _setupAudioPlayer() async {
    await audioPlayer.setSourceUrl(audioUrl);
    audioPlayer.setReleaseMode(ReleaseMode.loop); // Enable looping
  }

  Future _playAudio() async {
      await audioPlayer.play(UrlSource(audioUrl));
  }

  Future _pauseAudio() async {
    await audioPlayer.pause();
  }

  Future _stopAudio() async {
    await audioPlayer.stop();
  }

  @override
  void dispose() {
    audioPlayer.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Looping Audio Player'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: _playAudio,
              child: Text('Play'),
            ),
            ElevatedButton(
              onPressed: _pauseAudio,
              child: Text('Pause'),
            ),
            ElevatedButton(
              onPressed: _stopAudio,
              child: Text('Stop'),
            ),
          ],
        ),
      ),
    );
  }
}

Controlling Volume

To control the volume, use the setVolume method. The volume is a value between 0.0 (mute) and 1.0 (full volume):

import 'package:flutter/material.dart';
import 'package:audioplayers/audioplayers.dart';

class VolumeControlAudioPlayer extends StatefulWidget {
  @override
  _VolumeControlAudioPlayerState createState() => _VolumeControlAudioPlayerState();
}

class _VolumeControlAudioPlayerState extends State {
  final AudioPlayer audioPlayer = AudioPlayer();
  final String audioUrl = 'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3';
  double volume = 0.5; // Initial volume

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

  Future _setupAudioPlayer() async {
    await audioPlayer.setSourceUrl(audioUrl);
    await audioPlayer.setVolume(volume); // Set initial volume
  }

  Future _playAudio() async {
      await audioPlayer.play(UrlSource(audioUrl));
  }

  Future _pauseAudio() async {
    await audioPlayer.pause();
  }

  Future _stopAudio() async {
    await audioPlayer.stop();
  }

  Future _setVolume(double newVolume) async {
    setState(() {
      volume = newVolume;
    });
     await audioPlayer.setVolume(volume);
  }

  @override
  void dispose() {
    audioPlayer.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Volume Control Audio Player'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: _playAudio,
              child: Text('Play'),
            ),
            ElevatedButton(
              onPressed: _pauseAudio,
              child: Text('Pause'),
            ),
            ElevatedButton(
              onPressed: _stopAudio,
              child: Text('Stop'),
            ),
            Slider(
              value: volume,
              min: 0.0,
              max: 1.0,
              onChanged: (newValue) {
                _setVolume(newValue);
              },
            ),
            Text('Volume: ${volume.toStringAsFixed(2)}'),
          ],
        ),
      ),
    );
  }
}

Monitoring Playback State

You can listen to the audio player’s state changes by using the onPlayerStateChanged stream. This allows you to update the UI based on whether the audio is playing, paused, stopped, or completed:

import 'package:flutter/material.dart';
import 'package:audioplayers/audioplayers.dart';

class PlaybackStateAudioPlayer extends StatefulWidget {
  @override
  _PlaybackStateAudioPlayerState createState() => _PlaybackStateAudioPlayerState();
}

class _PlaybackStateAudioPlayerState extends State {
  final AudioPlayer audioPlayer = AudioPlayer();
  final String audioUrl = 'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3';
  PlayerState playerState = PlayerState.stopped;

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

  Future _setupAudioPlayer() async {
    await audioPlayer.setSourceUrl(audioUrl);
    audioPlayer.onPlayerStateChanged.listen((state) {
      setState(() {
        playerState = state;
      });
    });
  }

  Future _playAudio() async {
    await audioPlayer.play(UrlSource(audioUrl));
  }

  Future _pauseAudio() async {
    await audioPlayer.pause();
  }

  Future _stopAudio() async {
    await audioPlayer.stop();
  }

  @override
  void dispose() {
    audioPlayer.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Playback State Audio Player'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('Player State: $playerState'),
            ElevatedButton(
              onPressed: _playAudio,
              child: Text('Play'),
            ),
            ElevatedButton(
              onPressed: _pauseAudio,
              child: Text('Pause'),
            ),
            ElevatedButton(
              onPressed: _stopAudio,
              child: Text('Stop'),
            ),
          ],
        ),
      ),
    );
  }
}

Handling Audio Player Errors

It’s essential to handle potential errors when working with audio players. You can listen to the onPlayerError stream to catch any errors that occur during playback:

audioPlayer.onPlayerError.listen((msg) {
  print('Audio Player Error: $msg');
});

Complete Example

Here’s a complete example combining all the features discussed:

import 'package:flutter/material.dart';
import 'package:audioplayers/audioplayers.dart';

class CompleteAudioPlayer extends StatefulWidget {
  @override
  _CompleteAudioPlayerState createState() => _CompleteAudioPlayerState();
}

class _CompleteAudioPlayerState extends State {
  final AudioPlayer audioPlayer = AudioPlayer();
  final String audioUrl = 'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3';
  double volume = 0.5;
  bool isLooping = false;
  PlayerState playerState = PlayerState.stopped;

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

  Future _setupAudioPlayer() async {
    await audioPlayer.setSourceUrl(audioUrl);
    await audioPlayer.setVolume(volume);
    audioPlayer.setReleaseMode(isLooping ? ReleaseMode.loop : ReleaseMode.release);

    audioPlayer.onPlayerStateChanged.listen((state) {
      setState(() {
        playerState = state;
      });
    });

    audioPlayer.onPlayerError.listen((msg) {
      print('Audio Player Error: $msg');
    });
  }

  Future _playAudio() async {
     await audioPlayer.play(UrlSource(audioUrl));
  }

  Future _pauseAudio() async {
    await audioPlayer.pause();
  }

  Future _stopAudio() async {
    await audioPlayer.stop();
  }

  Future _setVolume(double newVolume) async {
    setState(() {
      volume = newVolume;
    });
    await audioPlayer.setVolume(volume);
  }

  Future _toggleLooping() async {
    setState(() {
      isLooping = !isLooping;
    });
    audioPlayer.setReleaseMode(isLooping ? ReleaseMode.loop : ReleaseMode.release);
  }

  @override
  void dispose() {
    audioPlayer.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Complete Audio Player'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('Player State: $playerState'),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                ElevatedButton(
                  onPressed: _playAudio,
                  child: Text('Play'),
                ),
                ElevatedButton(
                  onPressed: _pauseAudio,
                  child: Text('Pause'),
                ),
                ElevatedButton(
                  onPressed: _stopAudio,
                  child: Text('Stop'),
                ),
              ],
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Text('Volume: ${volume.toStringAsFixed(2)}'),
                Slider(
                  value: volume,
                  min: 0.0,
                  max: 1.0,
                  onChanged: (newValue) {
                    _setVolume(newValue);
                  },
                ),
              ],
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Text('Looping: ${isLooping ? 'On' : 'Off'}'),
                Switch(
                  value: isLooping,
                  onChanged: (value) {
                    _toggleLooping();
                  },
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

Conclusion

The audioplayers package in Flutter provides an efficient way to play audio from local and remote sources. By leveraging features like looping, volume control, and monitoring playback states, you can create a rich and interactive audio experience in your Flutter applications. This comprehensive guide has equipped you with the knowledge and code examples to implement these functionalities effectively. Happy coding!