audioplayers icon indicating copy to clipboard operation
audioplayers copied to clipboard

[Android] TimeoutException for second `play` call when including AudioContext

Open komaxx opened this issue 1 year ago • 6 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

My app plays some alarm sounds from asset sound files every once in a while. The context may change so I call play with potentially different AudioContexts:

final audioPlayer = AudioPlayer()..setReleaseMode(ReleaseMode.loop);
final source = AssetSource('sounds/alarm.mp3');

await audioPlayer.play(
  source,
  volume: 1,
  mode: PlayerMode.lowLatency,
  ctx: createAudioContext(),
);

createAudioContext mostly delivers an AudioContext like this

AudioContext(
      iOS: AudioContextIOS(
        category: AVAudioSessionCategory.playAndRecord,
        options: [
          AVAudioSessionOptions.duckOthers,
          AVAudioSessionOptions.defaultToSpeaker,
        ],
      ),
      android: AudioContextAndroid(
        isSpeakerphoneOn: true,
        stayAwake: true,
        contentType: AndroidContentType.unknown,
        usageType: AndroidUsageType.notificationRingtone,
        audioFocus: AndroidAudioFocus.gainTransient,
      ),
    );

Then, sometimes later, the playback is stopped like this:

await audioPlayer.stop();
await audioPlayer.dispose();

While this works fine on iOS, on Android only the first play call will work. All subsequent calls of play will fail after thirty seconds with TimeoutException after 0:00:30.000000: Future not completed.

If I just call play without AudioContext:

await audioPlayer.play(source);

everything works as expected.

Expected behaviour

Subsequent play calls should work as the first one, not throw TimeoutExceptions.

Steps to reproduce

See bug description.

Code sample

Code sample
void main() {
}

Affected platforms

Android

Platform details

Seen on various Android devices with OS versions 11 to 13.

AudioPlayers Version

5.1.0

Build mode

release

Audio Files/URLs/Sources

No response

Screenshots

No response

Logs

No response

Related issues / more information

No response

Working on PR

no way

komaxx avatar Sep 01 '23 09:09 komaxx

same issue

kukufree avatar Sep 13 '23 07:09 kukufree

Can you confirm that the issue also occurs, when calling:

await audioPlayer.play(
  source,
  volume: 1,
  mode: PlayerMode.lowLatency,
  ctx: AudioContext(),
);

And if not can you work out the difference to the default (below) which parameter of these leads to the issue:

const AudioContextAndroid({
    this.isSpeakerphoneOn = false,
    this.audioMode = AndroidAudioMode.normal,
    this.stayAwake = false,
    this.contentType = AndroidContentType.music,
    this.usageType = AndroidUsageType.media,
    this.audioFocus = AndroidAudioFocus.gain,
  });

Gustl22 avatar Sep 26 '23 10:09 Gustl22

We have run into the same issue on a Linux platform. We believe this is caused by line 321 of audioplayer.dart:

await preparedCompleter.future.timeout(const Duration(seconds: 30));

Per the dart documentation:

If onTimeout is omitted, a timeout will cause the returned future to complete with a TimeoutException.

On line 321 shown above, onTimeout is omitted and the duration provided matches our experience as well as the operator's problem statement.

The AudioPlayers library could better handle this potential error by providing more details in the TimeoutException or throwing another exception from the library which better describes the error being generated by the library.

In our case, this issue occurred when we released the player while a sound was actively playing. We also saw the issue if we attempted to play a sound after the player was released (it's obvious why a sound wouldn't play here, but less obvious as to why the library would throw an exception).

Here is a minimal example to help the library maintainers reproduce the issue:

// Prerequisite: A sound file is stored in the assets folder named beep.wav and included via pubspec.yaml
import 'package:audioplayers/audioplayers.dart';
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

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

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;
  final beep = AssetSource('beep.wav');
  AudioPlayer player = AudioPlayer();

  void _incrementCounter() {
    player.play(beep);
    player.release();
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

mtkarp avatar Oct 06 '23 18:10 mtkarp

@mtkarp this is not related to Android and the AudioContext! Also you're using the library wrong by calling release directly after play which is not expected. Plz ask on Discord or open a separate issue for that. Thx ;D

Gustl22 avatar Nov 20 '23 14:11 Gustl22

same!

V/MediaPlayer( 8329): resetDrmState: mDrmInfo=null mDrmProvisioningThread=null mPrepareDrmInProgress=false mActiveDrmScheme=false V/MediaPlayer( 8329): cleanDrmObj: mDrmObj=null mDrmSessionId=null V/MediaHTTPService( 8329): MediaHTTPService(android.media.MediaHTTPService@e6c3b44): Cookies: null V/MediaHTTPService( 8329): makeHTTPConnection: CookieHandler (java.net.CookieManager@3614f03) exists. V/MediaHTTPService( 8329): makeHTTPConnection(android.media.MediaHTTPService@e6c3b44): cookieHandler: java.net.CookieManager@3614f03 Cookies: null E/flutter ( 8329): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: TimeoutException after 0:00:30.000000: Future not completed E/flutter ( 8329): W/FirebaseInstanceId( 8329): Token retrieval failed: SERVICE_NOT_AVAILABLE. Will retry token retrieval

alisinaee avatar Jan 04 '24 09:01 alisinaee

@alisinaee can you reevaluate these parameters? https://github.com/bluefireteam/audioplayers/issues/1628#issuecomment-1735271036

Gustl22 avatar Mar 15 '24 13:03 Gustl22