Skip to content

Commit

Permalink
fix(android): reset prepared state on player error (fixes #1260)
Browse files Browse the repository at this point in the history
  • Loading branch information
Gustl22 committed Feb 13, 2023
1 parent 8a0a4f8 commit 34d734a
Show file tree
Hide file tree
Showing 4 changed files with 23 additions and 65 deletions.
Binary file removed packages/audioplayers/example/assets/two_beeps.mp2
Binary file not shown.
28 changes: 0 additions & 28 deletions packages/audioplayers/example/integration_test/lib_test.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import 'dart:async';
import 'dart:io';

import 'package:audioplayers/audioplayers.dart';
Expand Down Expand Up @@ -201,31 +200,4 @@ void main() {
skip: !features.hasForceSpeaker || !features.hasLowLatency,
);
});

group('Platform testing', () {
/// This section is to test issues for specific platforms.
/// This can be used to set up scenarios which are hard to implement or
/// reproduce on the native side.
/// Nether the less: common native unit tests are preferred.
testWidgets(
'test #1260 - setting .mp2 on Android should not crash',
(WidgetTester tester) async {
final completer = Completer<void>();
final player = AudioPlayer();

player.onPlayerComplete.listen(
(_) => completer.complete(),
onError: completer.completeError,
);
// The play event is handled asynchronously and therefore the error is
// not thrown while preparing the source, but returned via error stream.
await player.play(AssetSource(mp2Asset));
await completer.future;
// TODO(gustl22): check error with stream, if supported via #1352
// Unexpected platform error: MediaPlayer error with
// what:MEDIA_ERROR_UNKNOWN {what:1} extra:MEDIA_ERROR_SYSTEM
},
skip: kIsWeb || !Platform.isAndroid,
);
});
}
1 change: 0 additions & 1 deletion packages/audioplayers/example/lib/tabs/sources.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ const mpgaStreamUrl = 'https://timesradio.wireless.radio/stream';

const asset1 = 'laser.wav';
const asset2 = 'nasa_on_a_mission.mp3';
const mp2Asset = 'two_beeps.mp2';

class SourcesTab extends StatefulWidget {
final AudioPlayer player;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -247,50 +247,28 @@ class WrappedPlayer internal constructor(
* Player callbacks
*/
fun onPrepared() {
try {
prepared = true
ref.handleDuration(this)
if (playing) {
player?.start()
ref.handleIsPlaying()
}
if (shouldSeekTo >= 0 && player?.isLiveStream() != true) {
player?.seekTo(shouldSeekTo)
}
} catch (e: Exception) {
handleError(e)
prepared = true
ref.handleDuration(this)
if (playing) {
player?.start()
ref.handleIsPlaying()
}
}

fun onCompletion() {
try {
if (releaseMode != ReleaseMode.LOOP) {
stop()
}
ref.handleComplete(this)
} catch (e: Exception) {
handleError(e)
if (shouldSeekTo >= 0 && player?.isLiveStream() != true) {
player?.seekTo(shouldSeekTo)
}
}

@Suppress("UNUSED_PARAMETER")
fun onBuffering(percent: Int) {
// TODO(luan): expose this as a stream
}

fun onSeekComplete() {
try {
ref.handleSeekComplete(this)
} catch (e: Exception) {
handleError(e)
fun onCompletion() {
if (releaseMode != ReleaseMode.LOOP) {
stop()
}
}

private fun handleError(error: Throwable) {
ref.handleError(this, error.stackTraceToString())
ref.handleComplete(this)
}

fun onError(what: Int, extra: Int): Boolean {
// When an error occurs, reset player to not [prepared].
// Then no functions will be called, which end up in an illegal player state.
prepared = false
val whatMsg = if (what == MediaPlayer.MEDIA_ERROR_SERVER_DIED) {
"MEDIA_ERROR_SERVER_DIED"
} else {
Expand All @@ -308,6 +286,15 @@ class WrappedPlayer internal constructor(
return false
}

@Suppress("UNUSED_PARAMETER")
fun onBuffering(percent: Int) {
// TODO(luan): expose this as a stream
}

fun onSeekComplete() {
ref.handleSeekComplete(this)
}

/**
* Internal logic. Private methods
*/
Expand Down

0 comments on commit 34d734a

Please sign in to comment.