Make states more permissive
This commit is contained in:
parent
8100b80d8d
commit
af679100ea
|
@ -223,10 +223,7 @@ public class AudioPlayer implements MethodCallHandler, Player.EventListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void transition(final PlaybackState newState) {
|
private void transition(final PlaybackState newState) {
|
||||||
transition(state, newState);
|
final PlaybackState oldState = state;
|
||||||
}
|
|
||||||
|
|
||||||
private void transition(final PlaybackState oldState, final PlaybackState newState) {
|
|
||||||
state = newState;
|
state = newState;
|
||||||
if (oldState != PlaybackState.playing && newState == PlaybackState.playing) {
|
if (oldState != PlaybackState.playing && newState == PlaybackState.playing) {
|
||||||
startObservingPosition();
|
startObservingPosition();
|
||||||
|
@ -235,6 +232,7 @@ public class AudioPlayer implements MethodCallHandler, Player.EventListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUrl(final String url, final Result result) throws IOException {
|
public void setUrl(final String url, final Result result) throws IOException {
|
||||||
|
abortExistingConnection();
|
||||||
prepareResult = result;
|
prepareResult = result;
|
||||||
transition(PlaybackState.connecting);
|
transition(PlaybackState.connecting);
|
||||||
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(context, Util.getUserAgent(context, "just_audio"));
|
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(context, Util.getUserAgent(context, "just_audio"));
|
||||||
|
@ -250,6 +248,10 @@ public class AudioPlayer implements MethodCallHandler, Player.EventListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setClip(final Long start, final Long end, final Result result) {
|
public void setClip(final Long start, final Long end, final Result result) {
|
||||||
|
if (state == PlaybackState.none) {
|
||||||
|
throw new IllegalStateException("Cannot call setClip from none state");
|
||||||
|
}
|
||||||
|
abortExistingConnection();
|
||||||
this.start = start;
|
this.start = start;
|
||||||
this.end = end;
|
this.end = end;
|
||||||
prepareResult = result;
|
prepareResult = result;
|
||||||
|
@ -264,6 +266,8 @@ public class AudioPlayer implements MethodCallHandler, Player.EventListener {
|
||||||
|
|
||||||
public void play() {
|
public void play() {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
|
case playing:
|
||||||
|
break;
|
||||||
case stopped:
|
case stopped:
|
||||||
case completed:
|
case completed:
|
||||||
case buffering:
|
case buffering:
|
||||||
|
@ -272,12 +276,14 @@ public class AudioPlayer implements MethodCallHandler, Player.EventListener {
|
||||||
transition(PlaybackState.playing);
|
transition(PlaybackState.playing);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalStateException("Can call play only from stopped, completed and paused states (" + state + ")");
|
throw new IllegalStateException("Cannot call play from connecting or none states (" + state + ")");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void pause() {
|
public void pause() {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
|
case paused:
|
||||||
|
break;
|
||||||
case playing:
|
case playing:
|
||||||
case buffering:
|
case buffering:
|
||||||
player.setPlayWhenReady(false);
|
player.setPlayWhenReady(false);
|
||||||
|
@ -293,7 +299,10 @@ public class AudioPlayer implements MethodCallHandler, Player.EventListener {
|
||||||
case stopped:
|
case stopped:
|
||||||
result.success(null);
|
result.success(null);
|
||||||
break;
|
break;
|
||||||
// TODO: Allow stopping from connecting states.
|
case connecting:
|
||||||
|
transition(PlaybackState.stopped);
|
||||||
|
result.success(null);
|
||||||
|
break;
|
||||||
case completed:
|
case completed:
|
||||||
case playing:
|
case playing:
|
||||||
case buffering:
|
case buffering:
|
||||||
|
@ -304,7 +313,7 @@ public class AudioPlayer implements MethodCallHandler, Player.EventListener {
|
||||||
result.success(null);
|
result.success(null);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalStateException("Can call stop only from playing/paused/stopped/completed states (" + state + ")");
|
throw new IllegalStateException("Can call stop only from playing/paused/completed states (" + state + ")");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -320,6 +329,9 @@ public class AudioPlayer implements MethodCallHandler, Player.EventListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void seek(final long position, final Result result) {
|
public void seek(final long position, final Result result) {
|
||||||
|
if (state == PlaybackState.none || state == PlaybackState.connecting) {
|
||||||
|
throw new IllegalStateException("Cannot call seek from none none/connecting states");
|
||||||
|
}
|
||||||
seekPos = position;
|
seekPos = position;
|
||||||
seekResult = result;
|
seekResult = result;
|
||||||
if (stateBeforeSeek == null) {
|
if (stateBeforeSeek == null) {
|
||||||
|
@ -331,13 +343,17 @@ public class AudioPlayer implements MethodCallHandler, Player.EventListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
if (state != PlaybackState.stopped && state != PlaybackState.completed && state != PlaybackState.none) {
|
|
||||||
throw new IllegalStateException("Can call dispose only from stopped/completed/none states (" + state + ")");
|
|
||||||
}
|
|
||||||
player.release();
|
player.release();
|
||||||
transition(PlaybackState.none);
|
transition(PlaybackState.none);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void abortExistingConnection() {
|
||||||
|
if (prepareResult != null) {
|
||||||
|
prepareResult.error("setUrl aborted", null, null);
|
||||||
|
prepareResult = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void startObservingPosition() {
|
private void startObservingPosition() {
|
||||||
handler.removeCallbacks(positionObserver);
|
handler.removeCallbacks(positionObserver);
|
||||||
handler.post(positionObserver);
|
handler.post(positionObserver);
|
||||||
|
|
|
@ -30,11 +30,10 @@ import 'package:rxdart/rxdart.dart';
|
||||||
///
|
///
|
||||||
/// The [AudioPlayer] instance transitions through different states as follows:
|
/// The [AudioPlayer] instance transitions through different states as follows:
|
||||||
///
|
///
|
||||||
/// * [AudioPlaybackState.none]: immediately after instantiation.
|
/// * [AudioPlaybackState.none]: immediately after instantiation and [dispose].
|
||||||
/// * [AudioPlaybackState.stopped]: eventually after [setUrl], [setFilePath] or
|
/// * [AudioPlaybackState.stopped]: eventually after [setUrl], [setFilePath],
|
||||||
/// [setAsset] completes, and immediately after [stop].
|
/// [setAsset] or [setClip] completes, and immediately after [stop].
|
||||||
/// * [AudioPlaybackState.paused]: after [pause] and after reaching the end of
|
/// * [AudioPlaybackState.paused]: after [pause].
|
||||||
/// the requested [play] segment.
|
|
||||||
/// * [AudioPlaybackState.playing]: after [play] and after sufficiently
|
/// * [AudioPlaybackState.playing]: after [play] and after sufficiently
|
||||||
/// buffering during normal playback.
|
/// buffering during normal playback.
|
||||||
/// * [AudioPlaybackState.buffering]: immediately after a seek request and
|
/// * [AudioPlaybackState.buffering]: immediately after a seek request and
|
||||||
|
@ -42,7 +41,7 @@ import 'package:rxdart/rxdart.dart';
|
||||||
/// * [AudioPlaybackState.connecting]: immediately after [setUrl],
|
/// * [AudioPlaybackState.connecting]: immediately after [setUrl],
|
||||||
/// [setFilePath] and [setAsset] while waiting for the media to load.
|
/// [setFilePath] and [setAsset] while waiting for the media to load.
|
||||||
/// * [AudioPlaybackState.completed]: immediately after playback reaches the
|
/// * [AudioPlaybackState.completed]: immediately after playback reaches the
|
||||||
/// end of the media.
|
/// end of the media or the end of the clip.
|
||||||
///
|
///
|
||||||
/// Additionally, after a [seek] request completes, the state will return to
|
/// Additionally, after a [seek] request completes, the state will return to
|
||||||
/// whatever state the player was in prior to the seek request.
|
/// whatever state the player was in prior to the seek request.
|
||||||
|
@ -131,12 +130,7 @@ class AudioPlayer {
|
||||||
/// The current speed of the player.
|
/// The current speed of the player.
|
||||||
double get speed => _speed;
|
double get speed => _speed;
|
||||||
|
|
||||||
/// Loads audio media from a URL and returns the duration of that audio. It
|
/// Loads audio media from a URL and returns the duration of that audio.
|
||||||
/// is legal to invoke this method only from one of the following states:
|
|
||||||
///
|
|
||||||
/// * [AudioPlaybackState.none]
|
|
||||||
/// * [AudioPlaybackState.stopped]
|
|
||||||
/// * [AudioPlaybackState.completed]
|
|
||||||
Future<Duration> setUrl(final String url) async {
|
Future<Duration> setUrl(final String url) async {
|
||||||
_durationFuture =
|
_durationFuture =
|
||||||
_invokeMethod('setUrl', [url]).then((ms) => Duration(milliseconds: ms));
|
_invokeMethod('setUrl', [url]).then((ms) => Duration(milliseconds: ms));
|
||||||
|
@ -145,21 +139,11 @@ class AudioPlayer {
|
||||||
return duration;
|
return duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loads audio media from a file and returns the duration of that audio. It
|
/// Loads audio media from a file and returns the duration of that audio.
|
||||||
/// is legal to invoke this method only from one of the following states:
|
|
||||||
///
|
|
||||||
/// * [AudioPlaybackState.none]
|
|
||||||
/// * [AudioPlaybackState.stopped]
|
|
||||||
/// * [AudioPlaybackState.completed]
|
|
||||||
Future<Duration> setFilePath(final String filePath) =>
|
Future<Duration> setFilePath(final String filePath) =>
|
||||||
setUrl('file://$filePath');
|
setUrl('file://$filePath');
|
||||||
|
|
||||||
/// Loads audio media from an asset and returns the duration of that audio.
|
/// Loads audio media from an asset and returns the duration of that audio.
|
||||||
/// It is legal to invoke this method only from one of the following states:
|
|
||||||
///
|
|
||||||
/// * [AudioPlaybackState.none]
|
|
||||||
/// * [AudioPlaybackState.stopped]
|
|
||||||
/// * [AudioPlaybackState.completed]
|
|
||||||
Future<Duration> setAsset(final String assetPath) async {
|
Future<Duration> setAsset(final String assetPath) async {
|
||||||
final file = await _cacheFile;
|
final file = await _cacheFile;
|
||||||
if (!file.existsSync()) {
|
if (!file.existsSync()) {
|
||||||
|
@ -173,7 +157,8 @@ class AudioPlayer {
|
||||||
Future<File> get _cacheFile async => File(p.join(
|
Future<File> get _cacheFile async => File(p.join(
|
||||||
(await getTemporaryDirectory()).path, 'just_audio_asset_cache', '$_id'));
|
(await getTemporaryDirectory()).path, 'just_audio_asset_cache', '$_id'));
|
||||||
|
|
||||||
/// Clip the audio to the given [start] and [end] timestamps.
|
/// Clip the audio to the given [start] and [end] timestamps. This method
|
||||||
|
/// cannot be called from the [AudioPlaybackState.none] state.
|
||||||
Future<Duration> setClip({Duration start, Duration end}) async {
|
Future<Duration> setClip({Duration start, Duration end}) async {
|
||||||
_durationFuture =
|
_durationFuture =
|
||||||
_invokeMethod('setClip', [start?.inMilliseconds, end?.inMilliseconds])
|
_invokeMethod('setClip', [start?.inMilliseconds, end?.inMilliseconds])
|
||||||
|
@ -185,12 +170,10 @@ class AudioPlayer {
|
||||||
|
|
||||||
/// Plays the currently loaded media from the current position. The [Future]
|
/// Plays the currently loaded media from the current position. The [Future]
|
||||||
/// returned by this method completes when playback completes or is paused or
|
/// returned by this method completes when playback completes or is paused or
|
||||||
/// stopped. It is legal to invoke this method only from one of the following
|
/// stopped. This method can be called from any state except for:
|
||||||
/// states:
|
|
||||||
///
|
///
|
||||||
/// * [AudioPlaybackState.stopped]
|
/// * [AudioPlaybackState.connecting]
|
||||||
/// * [AudioPlaybackState.completed]
|
/// * [AudioPlaybackState.none]
|
||||||
/// * [AudioPlaybackState.paused]
|
|
||||||
Future<void> play() async {
|
Future<void> play() async {
|
||||||
StreamSubscription subscription;
|
StreamSubscription subscription;
|
||||||
Completer completer = Completer();
|
Completer completer = Completer();
|
||||||
|
@ -228,7 +211,6 @@ class AudioPlayer {
|
||||||
///
|
///
|
||||||
/// * [AudioPlaybackState.playing]
|
/// * [AudioPlaybackState.playing]
|
||||||
/// * [AudioPlaybackState.paused]
|
/// * [AudioPlaybackState.paused]
|
||||||
/// * [AudioPlaybackState.stopped]
|
|
||||||
/// * [AudioPlaybackState.completed]
|
/// * [AudioPlaybackState.completed]
|
||||||
Future<void> stop() async {
|
Future<void> stop() async {
|
||||||
await _invokeMethod('stop');
|
await _invokeMethod('stop');
|
||||||
|
@ -254,12 +236,11 @@ class AudioPlayer {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Release all resources associated with this player. You must invoke this
|
/// Release all resources associated with this player. You must invoke this
|
||||||
/// after you are done with the player. It is legal to invoke this method
|
/// after you are done with the player. This method can be invoked from any
|
||||||
/// only from the following states:
|
/// state except for:
|
||||||
///
|
///
|
||||||
/// * [AudioPlaybackState.stopped]
|
|
||||||
/// * [AudioPlaybackState.completed]
|
|
||||||
/// * [AudioPlaybackState.none]
|
/// * [AudioPlaybackState.none]
|
||||||
|
/// * [AudioPlaybackState.connecting]
|
||||||
Future<void> dispose() async {
|
Future<void> dispose() async {
|
||||||
if ((await _cacheFile).existsSync()) {
|
if ((await _cacheFile).existsSync()) {
|
||||||
(await _cacheFile).deleteSync();
|
(await _cacheFile).deleteSync();
|
||||||
|
|
Loading…
Reference in New Issue