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

iOS - Repeated AudioCache play() calls will delay playback until ultimately crashing the application #994

Open cqueen opened 3 years ago

cqueen commented 3 years ago

Overview On iOS, repeated calls to the audioCache.play method will eventually exhibit a delay between the method call and the playback of the sound. Continuing to call play() will slowly introduce a longer and longer delay until the application crashes.

Full Description I first noticed this issue when testing my application sounds on an iOS device. As I continued to play, the sound playback started playing the sound later and later after the time the play() was called. If I stopped pressing and activating sounds, the sounds would eventually come back in a flurry (stacked on top of one another). Note that 95% the sounds in my application are through user interaction (button presses), so it did happen in a standard use case.

In order to isolate the issue, I used the default Flutter app to continually play a mp3 asset over and over again, incrementing the counter as it goes. I noticed the delay creeps in after repeated use, and eventually leads to a crash in the application. In the default Flutter app on my setup, it can play the mp3 about 1000 times (or much sooner on physical device) before the crash happens. It does not appear that the delay between sounds that I introduce (line 40) has much effect on the issue. If I set the delay between play calls at 50ms, 500ms or even 2000ms, it will still crash around the 1000 mark on my iOS Simulator.

Code to Reproduce

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

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',      
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);
  final String title;
  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;
  AudioCache audioCache = AudioCache();
  List<AudioPlayer> audioPool = <AudioPlayer>[];
  bool started = false;

  void _incrementCounter() async {
    setState(() {      
      _counter++;
      print('Counter: $_counter');
    });

    audioCache.play('press.mp3');
    await Future.delayed(const Duration(milliseconds: 50), _incrementCounter);
  }

  @override
  Widget build(BuildContext context) {
    AudioPlayer.logEnabled = true;
    if (started == false) {
      Future.delayed(const Duration(milliseconds: 100), _incrementCounter);
      started = true;
    }

    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(        
        child: Column(          
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'Number of sounds played:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),      
    );
  }
}

Log Errors (Partial - from the last error before crash. Can include more if needed.)

flutter: _platformCallHandler call audio.onError {playerId: 0baab170-db40-4f75-933e-808099289133, value: AVPlayerItem.Status.failed}
flutter: _platformCallHandler call audio.onCurrentPosition {value: 528, playerId: 15edf56a-a2d0-4d1d-a917-e676c8cf3b6f}
flutter: _platformCallHandler call audio.onCurrentPosition {value: 528, playerId: 4968ccb5-d2a8-4e08-aea4-f8618a849de1}
flutter: _platformCallHandler call audio.onComplete {playerId: 15edf56a-a2d0-4d1d-a917-e676c8cf3b6f}
version=2.15.0-42.0.dev (dev) (Sun Aug 22 13:00:21 2021 -0700) on "ios_x64"
pid=65937, thread=42763, isolate_group=main(0x7f90c3832a00), isolate=main(0x7f90c383ac00)
isolate_instructions=10ecd9160, vm_instructions=10ecd9160
  pc 0x000000010ee067b4 fp 0x00007000008759b0 dart::Profiler::DumpStackTrace(void*)+0x64
  pc 0x000000010ecd9334 fp 0x0000700000875a90 dart::Assert::Fail(char const*, ...) const+0x84
  pc 0x000000010ee7e4c2 fp 0x0000700000875ad0 dart::ThreadPool::RunImpl(std::__1::unique_ptr<dart::ThreadPool::Task, std::__1::default_delete<dart::ThreadPool::Task> >)+0x182
  pc 0x000000010ee9fa9f fp 0x0000700000875b30 dart::GCMarker::StartConcurrentMark(dart::PageSpace*)+0x17f
  pc 0x000000010eea5cf0 fp 0x0000700000875c80 dart::PageSpace::CollectGarbageHelper(bool, bool, long long, long long)+0x340
  pc 0x000000010eea596c fp 0x0000700000875cf0 dart::PageSpace::CollectGarbage(bool, bool)+0x14c
  pc 0x000000010ee9cc39 fp 0x0000700000875dd0 dart::Heap::NotifyIdle(long long)+0x279
  pc 0x000000010ed3d4e0 fp 0x0000700000875df0 dart::IdleTimeHandler::NotifyIdle(long long)+0x30
  pc 0x000000010f0238f1 fp 0x0000700000875e70 Dart_NotifyIdle+0xd1
  pc 0x000000010eccead2 fp 0x0000700000875ee0 flutter::RuntimeController::NotifyIdle(long long)+0x9e
  pc 0x000000010eb16d10 fp 0x0000700000875f20 flutter::Engine::NotifyIdle(long long)+0x66
  pc 0x000000010eb24f14 fp 0x0000700000875f40 flutter::Shell::OnAnimatorNotifyIdle(long long)+0x1a
  pc 0x000000010eb14d73 fp 0x0000700000875f70 std::__1::__function::__func<flutter::Animator::BeginFrame(std::__1::unique_ptr<flutter::FrameTimingsRecorder, std::__1::default_delete<flutter::FrameTimingsRecorder> >)::$_1, std::__1::allocator<flutter::Animator::BeginFrame(std::__1::unique_ptr<flutter::FrameTimingsRecorder, std::__1::default_delete<flutter::FrameTimingsRecorder> >)::$_1>, void ()>::operator()()+0x8f
  pc 0x000000010eab86c6 fp 0x0000700000876020 fml::MessageLoopImpl::FlushTasks(fml::FlushType)+0xa4
  pc 0x000000010eabeb3c fp 0x0000700000876040 fml::MessageLoopDarwin::OnTimerFire(__CFRunLoopTimer*, fml::MessageLoopDarwin*)+0x1a
  pc 0x00007fff2039178a fp 0x0000700000876050 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__+0x14
  pc 0x00007fff2039127c fp 0x0000700000877100 __CFRunLoopDoTimer+0x39c
  pc 0x00007fff2039081a fp 0x0000700000877150 __CFRunLoopDoTimers+0x109
  pc 0x00007fff2038ae69 fp 0x0000700000877e80 __CFRunLoopRun+0x7dd
  pc 0x00007fff2038a1a7 fp 0x0000700000877f20 CFRunLoopRunSpecific+0x237
  pc 0x000000010eabec65 fp 0x0000700000877f50 fml::MessageLoopDarwin::Run()+0x41
  pc 0x000000010eab85d6 fp 0x0000700000877f70 fml::MessageLoopImpl::DoRun()+0x16
  pc 0x000000010eabd65e fp 0x0000700000877fb0 void* std::__1::__thread_proxy<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, fml::Thread::Thread(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)::$_0> >(void*)+0xaa
  pc 0x00007fff60342950 fp 0x0000700000877fd0 _pthread_start+0xe0
  pc 0x00007fff6033e47b fp 0x0000700000877ff0 thread_start+0xf

Files/URLs/Sources No special files needed - I used my own as well as two of the mp3s from the example project (https://github.com/luanpotter/audioplayers/tree/master/packages/audioplayers/example/assets/messenger.mp3). Note that a shorter file may take more plays to exhibit the issue.

Platforms

Issue Experienced on:

Platform 1 OS: iOS Version: 14.5 Device: Simulator - iPhone 12 Pro Max Flutter Version: Channel dev, 2.6.0-0.0.pre Audioplayers version: 0.19.1 Build: Debug

Platform 2 OS: iOS Version: 14.7.1 Device: Physical - iPhone 12 Pro Flutter Version: Channel dev, 2.6.0-0.0.pre Audioplayers version: 0.19.1 Build: Release Peculiarities: The physical device seems to hit the limit MUCH faster before the sounds stop playing and the app eventually crashes.

Issue NOT experienced on:

Platform 3 OS: Android Version: 11 Device: Simulator - Pixel 3 API R Flutter Version: Channel dev, 2.6.0-0.0.pre Audioplayers version: 0.19.1 Build: Debug

Platform 4 OS: Android Version: 10 Device: Physical - Pixel 3a Flutter Version: Channel dev, 2.6.0-0.0.pre Audioplayers version: 0.19.1 Build: Release

This is a great and super useful library, thank you for putting it together! Please let me know if there is anything else I can do to help solve this issue.

brannendl commented 3 years ago

I'm experiencing the same issue.

sircontreras commented 2 years ago

I having the same inconvenient right now.

EvGeniyLell commented 2 years ago

What about now? Doesn't fixed? I have the same issue. This topic is stated from 2 Sep 2021.

Gustl22 commented 2 years ago

Can you recheck with audioplayers: ^1.1.0? We do not have the time to fix all errors. Please contribute with a PR then!

Gustl22 commented 1 year ago

@cqueen @brannendl @sircontreras @EvGeniyLell I think this issue does not appear in the same form since AP 1.x.x as AudioCache doesn't have the play method anymore. If you have a similar issue with the current lib, feel free to reopen. I'll mark this as stale. We are happy for any contribution to fix this issue.