audioplayers icon indicating copy to clipboard operation
audioplayers copied to clipboard

Linux: Delay in playback unless file is played immediately after setting the source

Open japostoles opened this issue 1 year ago • 2 comments

Checklist

  • [X] I read the troubleshooting guide before raising this issue
  • [X] I made sure that the issue I am raising doesn't already exist

Current bug behaviour

There's a significant and somewhat random delay that occurs when playing local files if time passes between setSource() and resume().

During the delay the player state reports playing, and multiple position events are fired with position at 0:00:0000.

Eventually the file plays, and the position events continue with accurate time info.

If the file is played very quickly after setting the source the file the sound plays immediately (similar to using the play() shortcut).

Expected behaviour

The file should play immediately when calling resume().

Steps to reproduce

Run the code sample:

  1. Click PREPARE
  2. Wait a second or two
  3. Click PLAY

Compare with INSTA-PLAY button.

Code sample

Full Code Sample
import 'package:audioplayers/audioplayers.dart';
import 'package:flutter/material.dart';

class SampleApp extends StatelessWidget {
  AudioPlayer player = AudioPlayer();
  final SampleAudioFile = '/home/jonathan/Documents/music/6538.mp3';

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Container(
      color: Colors.black,
      child: Column(children: [
        DefaultTextStyle(
            style: TextStyle(fontSize: 12, color: Colors.white),
            child: Text(
              'Click prepare, wait, then click play\nCompare to hitting insta-play',
              textAlign: TextAlign.center,
            )),
        TextButton(onPressed: load, child: Text('PREPARE')),
        TextButton(onPressed: play, child: Text('PLAY')),
        TextButton(onPressed: insta, child: Text('INSTA-PLAY'))
      ]),
    ));
  }

  Future<void> load() async {
    player = AudioPlayer();
    await player.setSource(DeviceFileSource(SampleAudioFile));
  }

  Future<void> play() async {
    await player.resume();
  }

  Future<void> insta() async {
    player = AudioPlayer();
    await player.play(DeviceFileSource(SampleAudioFile));
  }
}

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(SampleApp());
}

Affected platforms

Linux

Platform details

Debian 12

AudioPlayers Version

5.2.1

Build mode

debug

Logs

    • Debian clang version 14.0.6
    • cmake version 3.25.1
    • ninja version 1.11.1
    • pkg-config version 1.8.1
Full Logs

Flutter doctor:

[✓] Flutter (Channel stable, 3.16.5, on Debian GNU/Linux 12 (bookworm) 6.6.6-surface-1, locale en_US.UTF-8)
  • Flutter version 3.16.5 on channel stable at /home/jonathan/src/flutter
  • Upstream repository https://github.com/flutter/flutter.git
  • Framework revision 78666c8dc5 (5 weeks ago), 2023-12-19 16:14:14 -0800
  • Engine revision 3f3e560236
  • Dart version 3.2.3
  • DevTools version 2.28.4

[✓] Linux toolchain - develop for Linux desktop
  • Debian clang version 14.0.6
  • cmake version 3.25.1
  • ninja version 1.11.1
  • pkg-config version 1.8.1

Related issues / more information

No response

Working on PR

no way

japostoles avatar Jan 25 '24 06:01 japostoles

Thank you for the detailed report! Currently we have a lot going on. I try to fix it eventually. Feel free to post a merge request, if you can provide a fix :D

Gustl22 avatar Mar 16 '24 08:03 Gustl22

I found a workaround for this! (I'm on Ubuntu 22.04. can provide more details if needed) This is the controller class I'm using for the audioplayer.


class Controller{
  AudioPlayer audioPlayer = AudioPlayer();
  ValueNotifier<int> sliderNotifier = ValueNotifier<int>(0); //ValueNotifier so no need for setState
  ValueNotifier<bool> playingNotifier = ValueNotifier<bool>(false); //ValueNotifier so no need for setState

  Controller() {
    audioPlayer.onPositionChanged.listen((Duration event){
      sliderNotifier.value = event.inMilliseconds; //can be set to seconds, I like it to be set to as small of a unit as possible
    });

    audioPlayer.onPlayerStateChanged.listen((PlayerState state) {
      playingNotifier.value = state == PlayerState.playing; 
    });

  }

  Future<void> playSong() async {
    if (playingNotifier.value){
      print("pause");
      await audioPlayer.pause();
      playingNotifier.value = false;
    }
    else{
      print("resume");
      //await audioPlayer.resume();
      // CHANGE TO:
      await audioPlayer.play(DeviceFileSource(...), position: Duration(milliseconds: sliderNotifier.value)); // this gives the same result as audioPlayer.resume()
      playingNotifier.value = true;
    }
  }
}

I can provide further snippets of my code if necessary. I tried looking into the issue, but really can't find the thing that's causing the delay. This can be used as a workaround in the meantime.

SDarius22 avatar Jul 28 '24 19:07 SDarius22