Broadcast how much has been buffered

This commit is contained in:
Ryan Heise 2020-03-07 19:41:40 +11:00
parent 338401b23f
commit eebb343280
3 changed files with 53 additions and 6 deletions

View File

@ -40,7 +40,7 @@ public class AudioPlayer implements MethodCallHandler, Player.EventListener {
private volatile PlaybackState state; private volatile PlaybackState state;
private long updateTime; private long updateTime;
private long updatePosition; private long updatePosition;
private long bufferedPosition;
private long duration; private long duration;
private Long start; private Long start;
private Long end; private Long end;
@ -51,9 +51,31 @@ public class AudioPlayer implements MethodCallHandler, Player.EventListener {
private Result seekResult; private Result seekResult;
private boolean seekProcessed; private boolean seekProcessed;
private boolean buffering; private boolean buffering;
private boolean justConnected;
private MediaSource mediaSource; private MediaSource mediaSource;
private SimpleExoPlayer player; private final SimpleExoPlayer player;
private final Handler handler = new Handler();
private final Runnable bufferWatcher = new Runnable() {
@Override
public void run() {
long newBufferedPosition = Math.min(duration, player.getBufferedPosition());
if (newBufferedPosition != bufferedPosition) {
bufferedPosition = newBufferedPosition;
broadcastPlaybackEvent();
}
if (duration > 0 && newBufferedPosition >= duration) return;
if (buffering) {
handler.postDelayed(this, 200);
} else if (state == PlaybackState.playing) {
handler.postDelayed(this, 500);
} else if (state == PlaybackState.paused) {
handler.postDelayed(this, 1000);
} else if (justConnected) {
handler.postDelayed(this, 1000);
}
}
};
public AudioPlayer(final Registrar registrar, final String id) { public AudioPlayer(final Registrar registrar, final String id) {
this.registrar = registrar; this.registrar = registrar;
@ -79,12 +101,18 @@ public class AudioPlayer implements MethodCallHandler, Player.EventListener {
player.addListener(this); player.addListener(this);
} }
private void startWatchingBuffer() {
handler.removeCallbacks(bufferWatcher);
handler.post(bufferWatcher);
}
@Override @Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) { public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
switch (playbackState) { switch (playbackState) {
case Player.STATE_READY: case Player.STATE_READY:
if (prepareResult != null) { if (prepareResult != null) {
duration = player.getDuration(); duration = player.getDuration();
justConnected = true;
prepareResult.success(duration); prepareResult.success(duration);
prepareResult = null; prepareResult = null;
transition(PlaybackState.stopped); transition(PlaybackState.stopped);
@ -105,6 +133,9 @@ public class AudioPlayer implements MethodCallHandler, Player.EventListener {
if (notifyBuffering && (buffering != this.buffering)) { if (notifyBuffering && (buffering != this.buffering)) {
this.buffering = buffering; this.buffering = buffering;
broadcastPlaybackEvent(); broadcastPlaybackEvent();
if (buffering) {
startWatchingBuffer();
}
} }
} }
@ -194,6 +225,7 @@ public class AudioPlayer implements MethodCallHandler, Player.EventListener {
event.add(buffering); event.add(buffering);
event.add(updatePosition = getCurrentPosition()); event.add(updatePosition = getCurrentPosition());
event.add(updateTime = System.currentTimeMillis()); event.add(updateTime = System.currentTimeMillis());
event.add(Math.max(updatePosition, bufferedPosition));
eventSink.success(event); eventSink.success(event);
} }
@ -214,6 +246,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 {
justConnected = false;
abortExistingConnection(); abortExistingConnection();
prepareResult = result; prepareResult = result;
transition(PlaybackState.connecting); transition(PlaybackState.connecting);
@ -253,7 +286,9 @@ public class AudioPlayer implements MethodCallHandler, Player.EventListener {
case stopped: case stopped:
case completed: case completed:
case paused: case paused:
justConnected = false;
transition(PlaybackState.playing); transition(PlaybackState.playing);
startWatchingBuffer();
player.setPlayWhenReady(true); player.setPlayWhenReady(true);
break; break;
default: default:

View File

@ -124,14 +124,12 @@
_updatePosition = [self getCurrentPosition]; _updatePosition = [self getCurrentPosition];
_updateTime = now; _updateTime = now;
_eventSink(@[ _eventSink(@[
// state
@(_state), @(_state),
// buffering
@(_buffering), @(_buffering),
// updatePosition
@(_updatePosition), @(_updatePosition),
// updateTime
@(_updateTime), @(_updateTime),
// TODO: buffer position
@(_updatePosition),
]); ]);
} }

View File

@ -66,6 +66,7 @@ class AudioPlayer {
buffering: false, buffering: false,
updatePosition: Duration.zero, updatePosition: Duration.zero,
updateTime: Duration.zero, updateTime: Duration.zero,
bufferedPosition: Duration.zero,
speed: 1.0, speed: 1.0,
duration: Duration.zero, duration: Duration.zero,
); );
@ -80,6 +81,8 @@ class AudioPlayer {
final _bufferingSubject = BehaviorSubject<bool>(); final _bufferingSubject = BehaviorSubject<bool>();
final _bufferedPositionSubject = BehaviorSubject<Duration>();
final _fullPlaybackStateSubject = BehaviorSubject<FullAudioPlaybackState>(); final _fullPlaybackStateSubject = BehaviorSubject<FullAudioPlaybackState>();
double _volume = 1.0; double _volume = 1.0;
@ -102,6 +105,7 @@ class AudioPlayer {
buffering: data[1], buffering: data[1],
updatePosition: Duration(milliseconds: data[2]), updatePosition: Duration(milliseconds: data[2]),
updateTime: Duration(milliseconds: data[3]), updateTime: Duration(milliseconds: data[3]),
bufferedPosition: Duration(milliseconds: data[4]),
speed: _speed, speed: _speed,
duration: _duration, duration: _duration,
)); ));
@ -111,6 +115,8 @@ class AudioPlayer {
.addStream(playbackEventStream.map((state) => state.state).distinct()); .addStream(playbackEventStream.map((state) => state.state).distinct());
_bufferingSubject.addStream( _bufferingSubject.addStream(
playbackEventStream.map((state) => state.buffering).distinct()); playbackEventStream.map((state) => state.buffering).distinct());
_bufferedPositionSubject.addStream(
playbackEventStream.map((state) => state.bufferedPosition).distinct());
_fullPlaybackStateSubject.addStream( _fullPlaybackStateSubject.addStream(
Rx.combineLatest2<AudioPlaybackState, bool, FullAudioPlaybackState>( Rx.combineLatest2<AudioPlaybackState, bool, FullAudioPlaybackState>(
playbackStateStream, playbackStateStream,
@ -145,6 +151,10 @@ class AudioPlayer {
/// A stream of buffering state changes. /// A stream of buffering state changes.
Stream<bool> get bufferingStream => _bufferingSubject.stream; Stream<bool> get bufferingStream => _bufferingSubject.stream;
/// A stream of buffered positions.
Stream<Duration> get bufferedPositionStream =>
_bufferedPositionSubject.stream;
/// A stream of [FullAudioPlaybackState]s. /// A stream of [FullAudioPlaybackState]s.
Stream<FullAudioPlaybackState> get fullPlaybackStateStream => Stream<FullAudioPlaybackState> get fullPlaybackStateStream =>
_fullPlaybackStateSubject.stream; _fullPlaybackStateSubject.stream;
@ -325,6 +335,9 @@ class AudioPlaybackEvent {
/// The position at [updateTime]. /// The position at [updateTime].
final Duration updatePosition; final Duration updatePosition;
/// The buffer position.
final Duration bufferedPosition;
/// The playback speed. /// The playback speed.
final double speed; final double speed;
@ -336,6 +349,7 @@ class AudioPlaybackEvent {
@required this.buffering, @required this.buffering,
@required this.updateTime, @required this.updateTime,
@required this.updatePosition, @required this.updatePosition,
@required this.bufferedPosition,
@required this.speed, @required this.speed,
@required this.duration, @required this.duration,
}); });