-
Notifications
You must be signed in to change notification settings - Fork 868
Open
Labels
Description
Checklist
- I read the troubleshooting guide before raising this issue
- I made sure that the issue I am raising doesn't already exist
Current bug behaviour
Playing audio from one instance, stops audio from the second instance. This issue is observed and reproduced on a slightly modified official example app.
Expected behaviour
It is expected that playing sounds from two different AudioPlayer instances should work.
Steps to reproduce
Simple press the play button for the first widget, and then for the second. Only one audio file will play at a time. The buttons for the players do not update, and even if the audio is silent and "stops", the player will say it is still playing.
Code sample
import 'dart:async';
import 'package:audioplayers/audioplayers.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MaterialApp(home: _SimpleExampleApp()));
}
class _SimpleExampleApp extends StatefulWidget {
const _SimpleExampleApp();
@override
_SimpleExampleAppState createState() => _SimpleExampleAppState();
}
class _SimpleExampleAppState extends State<_SimpleExampleApp> {
late AudioPlayer player = AudioPlayer();
late AudioPlayer player2 = AudioPlayer();
@override
void initState() {
super.initState();
// Create the audio player.
player = AudioPlayer();
player2 = AudioPlayer();
// Set the release mode to keep the source after playback has completed.
player.setReleaseMode(ReleaseMode.stop);
player2.setReleaseMode(ReleaseMode.stop);
// Start the player as soon as the app is displayed.
WidgetsBinding.instance.addPostFrameCallback((_) async {
await player.setSource(AssetSource('audio/piano.mp3'));
await player2.setSource(AssetSource('audio/chords.mp3'));
});
}
@override
void dispose() {
// Release all sources and dispose the player.
player.dispose();
player2.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Simple Player'),
),
body: Column(
children: [
PlayerWidget(player: player),
PlayerWidget(player: player2),
],
)
);
}
}
// The PlayerWidget is a copy of "/lib/components/player_widget.dart".
//#region PlayerWidget
class PlayerWidget extends StatefulWidget {
final AudioPlayer player;
const PlayerWidget({
required this.player,
super.key,
});
@override
State<StatefulWidget> createState() {
return _PlayerWidgetState();
}
}
class _PlayerWidgetState extends State<PlayerWidget> {
PlayerState? _playerState;
Duration? _duration;
Duration? _position;
StreamSubscription? _durationSubscription;
StreamSubscription? _positionSubscription;
StreamSubscription? _playerCompleteSubscription;
StreamSubscription? _playerStateChangeSubscription;
bool get _isPlaying => _playerState == PlayerState.playing;
bool get _isPaused => _playerState == PlayerState.paused;
String get _durationText => _duration?.toString().split('.').first ?? '';
String get _positionText => _position?.toString().split('.').first ?? '';
AudioPlayer get player => widget.player;
@override
void initState() {
super.initState();
// Use initial values from player
_playerState = player.state;
player.getDuration().then(
(value) => setState(() {
_duration = value;
}),
);
player.getCurrentPosition().then(
(value) => setState(() {
_position = value;
}),
);
_initStreams();
}
@override
void setState(VoidCallback fn) {
// Subscriptions only can be closed asynchronously,
// therefore events can occur after widget has been disposed.
if (mounted) {
super.setState(fn);
}
}
@override
void dispose() {
_durationSubscription?.cancel();
_positionSubscription?.cancel();
_playerCompleteSubscription?.cancel();
_playerStateChangeSubscription?.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
final color = Theme.of(context).primaryColor;
return Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
key: const Key('play_button'),
onPressed: _isPlaying ? null : _play,
iconSize: 48.0,
icon: const Icon(Icons.play_arrow),
color: color,
),
IconButton(
key: const Key('pause_button'),
onPressed: _isPlaying ? _pause : null,
iconSize: 48.0,
icon: const Icon(Icons.pause),
color: color,
),
IconButton(
key: const Key('stop_button'),
onPressed: _isPlaying || _isPaused ? _stop : null,
iconSize: 48.0,
icon: const Icon(Icons.stop),
color: color,
),
],
),
Slider(
onChanged: (value) {
final duration = _duration;
if (duration == null) {
return;
}
final position = value * duration.inMilliseconds;
player.seek(Duration(milliseconds: position.round()));
},
value: (_position != null &&
_duration != null &&
_position!.inMilliseconds > 0 &&
_position!.inMilliseconds < _duration!.inMilliseconds)
? _position!.inMilliseconds / _duration!.inMilliseconds
: 0.0,
),
Text(
_position != null
? '$_positionText / $_durationText'
: _duration != null
? _durationText
: '',
style: const TextStyle(fontSize: 16.0),
),
],
);
}
void _initStreams() {
_durationSubscription = player.onDurationChanged.listen((duration) {
setState(() => _duration = duration);
});
_positionSubscription = player.onPositionChanged.listen(
(p) => setState(() => _position = p),
);
_playerCompleteSubscription = player.onPlayerComplete.listen((event) {
setState(() {
_playerState = PlayerState.stopped;
_position = Duration.zero;
});
});
_playerStateChangeSubscription =
player.onPlayerStateChanged.listen((state) {
setState(() {
_playerState = state;
});
});
}
Future<void> _play() async {
await player.resume();
setState(() => _playerState = PlayerState.playing);
}
Future<void> _pause() async {
await player.pause();
setState(() => _playerState = PlayerState.paused);
}
Future<void> _stop() async {
await player.stop();
setState(() {
_playerState = PlayerState.stopped;
_position = Duration.zero;
});
}
}
//#endregion
Affected platforms
Android
Platform details
Platform 1: Android Pixel 8 API 35 (Emulator)
Platform 2: Android Pixel 5 Hardware
AudioPlayers Version
6.4.0
Build mode
debug
Audio Files/URLs/Sources
No response
Screenshots
Logs
No response
Related issues / more information
No response
Working on PR
no way
gepbird