bluefireteam / audioplayers

A Flutter package to play multiple audio files simultaneously (Android/iOS/web/Linux/Windows/macOS)
https://pub.dartlang.org/packages/audioplayers
MIT License
2.01k stars 845 forks source link

Steam Deck compatibility #1839

Open fabianhemmert opened 2 months ago

fabianhemmert commented 2 months ago

Checklist

Current bug behaviour

Trying to run the minimal example (https://pub.dev/packages/audioplayers/example) on Steam deck yields the following error:


flutter: AudioPlayers Exception: AudioPlayerException(
    AssetSource(path: ambient_c_motion.mp3, mimeType: null),
    PlatformException(LinuxAudioError, Failed to set source. For troubleshooting, see: https://github.com/bluefireteam/audioplayers/blob/main/troubleshooting.md, Internal data stream error. (Domain: gst-stream-error-quark, Code: 1), null)
[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(LinuxAudioError, Failed to set source. For troubleshooting, see: https://github.com/bluefireteam/audioplayers/blob/main/troubleshooting.md, Internal data stream error. (Domain: gst-stream-error-quark, Code: 1), null)

[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(LinuxAudioError, Failed to set source. For troubleshooting, see: https://github.com/bluefireteam/audioplayers/blob/main/troubleshooting.md, Internal data stream error. (Domain: gst-stream-error-quark, Code: 1), null)

Expected behaviour

I was expecting the audio to play, but it didn`t.

Steps to reproduce

  1. Run the minimal example on Steam Deck

Code sample

Code sample ```dart 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(); @override void initState() { super.initState(); // Create the audio player. player = AudioPlayer(); // Set the release mode to keep the source after playback has completed. player.setReleaseMode(ReleaseMode.stop); // Start the player as soon as the app is displayed. WidgetsBinding.instance.addPostFrameCallback((_) async { await player.setSource(AssetSource('ambient_c_motion.mp3')); await player.resume(); }); } @override void dispose() { // Release all sources and dispose the player. player.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Simple Player'), ), body: PlayerWidget(player: player), ); } } // 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 createState() { return _PlayerWidgetState(); } } class _PlayerWidgetState extends State { 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: [ 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 _play() async { await player.resume(); setState(() => _playerState = PlayerState.playing); } Future _pause() async { await player.pause(); setState(() => _playerState = PlayerState.paused); } Future _stop() async { await player.stop(); setState(() { _playerState = PlayerState.stopped; _position = Duration.zero; }); } } ```

Affected platforms

Linux

Platform details

Steam Deck (Steam OS 3.4.11)

AudioPlayers Version

6.1.0

Build mode

release

Audio Files/URLs/Sources

No response

Screenshots

No response

Logs


[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(LinuxAudioError, Unknown GstGError. See details., Your GStreamer installation is missing a plug-in. (Domain: gst-core-error-quark, Code: 12), null)

flutter: AudioPlayers Exception: AudioPlayerException(
    AssetSource(path: ambient_c_motion.mp3, mimeType: null),
    PlatformException(LinuxAudioError, Failed to set source. For troubleshooting, see: https://github.com/bluefireteam/audioplayers/blob/main/troubleshooting.md, Internal data stream error. (Domain: gst-stream-error-quark, Code: 1), null)
[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(LinuxAudioError, Failed to set source. For troubleshooting, see: https://github.com/bluefireteam/audioplayers/blob/main/troubleshooting.md, Internal data stream error. (Domain: gst-stream-error-quark, Code: 1), null)

[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(LinuxAudioError, Failed to set source. For troubleshooting, see: https://github.com/bluefireteam/audioplayers/blob/main/troubleshooting.md, Internal data stream error. (Domain: gst-stream-error-quark, Code: 1), null)

Related issues / more information

No response

Working on PR

no way