support dynamic duration (#104)
* add duration in PlaybackEvent * emit duration updates on dynamic length sources * Merge branch 'master' of https://github.com/ryanheise/just_audio into pr/android-duration # Conflicts: # lib/just_audio.dart * fix merge * update _durationFuture
This commit is contained in:
parent
bc766e834c
commit
ee0c4cd7cd
|
@ -1,11 +1,13 @@
|
|||
package com.ryanheise.just_audio;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||
import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.PlaybackParameters;
|
||||
import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||
import com.google.android.exoplayer2.metadata.Metadata;
|
||||
import com.google.android.exoplayer2.metadata.MetadataOutput;
|
||||
|
@ -21,10 +23,15 @@ import com.google.android.exoplayer2.source.hls.HlsMediaSource;
|
|||
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
||||
import com.google.android.exoplayer2.upstream.DataSource;
|
||||
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
|
||||
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory;
|
||||
import com.google.android.exoplayer2.upstream.DefaultHttpDataSource;
|
||||
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import io.flutter.Log;
|
||||
import io.flutter.plugin.common.EventChannel;
|
||||
import io.flutter.plugin.common.EventChannel.EventSink;
|
||||
|
@ -34,14 +41,6 @@ import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
|
|||
import io.flutter.plugin.common.MethodChannel.Result;
|
||||
import io.flutter.plugin.common.PluginRegistry.Registrar;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class AudioPlayer implements MethodCallHandler, Player.EventListener, MetadataOutput {
|
||||
static final String TAG = "AudioPlayer";
|
||||
|
||||
|
@ -76,12 +75,11 @@ public class AudioPlayer implements MethodCallHandler, Player.EventListener, Met
|
|||
private final Runnable bufferWatcher = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
long newBufferedPosition = Math.min(duration, player.getBufferedPosition());
|
||||
long newBufferedPosition = 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) {
|
||||
|
@ -161,7 +159,7 @@ public class AudioPlayer implements MethodCallHandler, Player.EventListener, Met
|
|||
switch (playbackState) {
|
||||
case Player.STATE_READY:
|
||||
if (prepareResult != null) {
|
||||
duration = player.getDuration();
|
||||
duration = getDuration();
|
||||
justConnected = true;
|
||||
transition(PlaybackState.stopped);
|
||||
prepareResult.success(duration);
|
||||
|
@ -301,6 +299,7 @@ public class AudioPlayer implements MethodCallHandler, Player.EventListener, Met
|
|||
event.add(updateTime = System.currentTimeMillis());
|
||||
event.add(Math.max(updatePosition, bufferedPosition));
|
||||
event.add(collectIcyMetadata());
|
||||
event.add(duration = getDuration());
|
||||
|
||||
if (eventSink != null) {
|
||||
eventSink.success(event);
|
||||
|
@ -344,6 +343,14 @@ public class AudioPlayer implements MethodCallHandler, Player.EventListener, Met
|
|||
}
|
||||
}
|
||||
|
||||
private long getDuration() {
|
||||
if (state == PlaybackState.none || state == PlaybackState.connecting) {
|
||||
return C.TIME_UNSET;
|
||||
} else {
|
||||
return player.getDuration();
|
||||
}
|
||||
}
|
||||
|
||||
private void setError(String errorCode, String errorMsg) {
|
||||
if (prepareResult != null) {
|
||||
prepareResult.error(errorCode, errorMsg, null);
|
||||
|
|
|
@ -1,41 +1,62 @@
|
|||
# Generated by pub
|
||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||
packages:
|
||||
archive:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: archive
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.11"
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: args
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.5.2"
|
||||
async:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: async
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
version: "2.4.0"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: boolean_selector
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
version: "1.0.5"
|
||||
charcode:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: charcode
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.3"
|
||||
clock:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: clock
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
version: "1.1.2"
|
||||
collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: collection
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.14.12"
|
||||
version: "1.14.11"
|
||||
convert:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: convert
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
crypto:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: crypto
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.3"
|
||||
cupertino_icons:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -43,13 +64,6 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.1.2"
|
||||
fake_async:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: fake_async
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
|
@ -65,13 +79,20 @@ packages:
|
|||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
image:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
just_audio:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
path: ".."
|
||||
relative: true
|
||||
source: path
|
||||
version: "0.1.6"
|
||||
version: "0.1.10"
|
||||
matcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -92,7 +113,7 @@ packages:
|
|||
name: path
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.7.0"
|
||||
version: "1.6.4"
|
||||
path_provider:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -100,6 +121,20 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.5.1"
|
||||
pedantic:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pedantic
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.8.0+1"
|
||||
petitparser:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: petitparser
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.4.0"
|
||||
platform:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -107,13 +142,20 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.2.1"
|
||||
quiver:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: quiver
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.5"
|
||||
rxdart:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: rxdart
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.24.0"
|
||||
version: "0.24.1"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
|
@ -125,7 +167,7 @@ packages:
|
|||
name: source_span
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.7.0"
|
||||
version: "1.5.5"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -160,7 +202,7 @@ packages:
|
|||
name: test_api
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.2.15"
|
||||
version: "0.2.11"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -175,6 +217,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.8"
|
||||
xml:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: xml
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.5.0"
|
||||
sdks:
|
||||
dart: ">=2.6.0 <3.0.0"
|
||||
flutter: ">=1.12.8 <2.0.0"
|
||||
|
|
|
@ -74,8 +74,6 @@ class AudioPlayer {
|
|||
|
||||
final int _id;
|
||||
|
||||
Duration _duration;
|
||||
|
||||
Future<Duration> _durationFuture;
|
||||
|
||||
final _durationSubject = BehaviorSubject<Duration>();
|
||||
|
@ -131,26 +129,32 @@ class AudioPlayer {
|
|||
AudioPlayer._internal(this._id) : _channel = _init(_id) {
|
||||
_eventChannelStream = EventChannel('com.ryanheise.just_audio.events.$_id')
|
||||
.receiveBroadcastStream()
|
||||
.map((data) => _audioPlaybackEvent = AudioPlaybackEvent(
|
||||
state: AudioPlaybackState.values[data[0]],
|
||||
buffering: data[1],
|
||||
updatePosition: Duration(milliseconds: data[2]),
|
||||
updateTime: Duration(milliseconds: data[3]),
|
||||
bufferedPosition: Duration(milliseconds: data[4]),
|
||||
speed: _speed,
|
||||
duration: _duration,
|
||||
icyMetadata: data.length < 6 || data[5] == null
|
||||
? null
|
||||
: IcyMetadata(
|
||||
info: IcyInfo(title: data[5][0][0], url: data[5][0][1]),
|
||||
headers: IcyHeaders(
|
||||
bitrate: data[5][1][0],
|
||||
genre: data[5][1][1],
|
||||
name: data[5][1][2],
|
||||
metadataInterval: data[5][1][3],
|
||||
url: data[5][1][4],
|
||||
isPublic: data[5][1][5])),
|
||||
));
|
||||
.map((data) {
|
||||
final duration =
|
||||
Duration(milliseconds: data.length < 7 || data[6] < 0 ? -1 : data[6]);
|
||||
_durationFuture = Future.value(duration);
|
||||
_durationSubject.add(duration);
|
||||
return _audioPlaybackEvent = AudioPlaybackEvent(
|
||||
state: AudioPlaybackState.values[data[0]],
|
||||
buffering: data[1],
|
||||
updatePosition: Duration(milliseconds: data[2]),
|
||||
updateTime: Duration(milliseconds: data[3]),
|
||||
bufferedPosition: Duration(milliseconds: data[4]),
|
||||
speed: _speed,
|
||||
duration: duration,
|
||||
icyMetadata: data.length < 6 || data[5] == null
|
||||
? null
|
||||
: IcyMetadata(
|
||||
info: IcyInfo(title: data[5][0][0], url: data[5][0][1]),
|
||||
headers: IcyHeaders(
|
||||
bitrate: data[5][1][0],
|
||||
genre: data[5][1][1],
|
||||
name: data[5][1][2],
|
||||
metadataInterval: data[5][1][3],
|
||||
url: data[5][1][4],
|
||||
isPublic: data[5][1][5])),
|
||||
);
|
||||
});
|
||||
_eventChannelStreamSubscription = _eventChannelStream.listen(
|
||||
_playbackEventSubject.add,
|
||||
onError: _playbackEventSubject.addError);
|
||||
|
@ -253,11 +257,13 @@ class AudioPlayer {
|
|||
/// https://somewhere.com/somestream?x=etc#.m3u8
|
||||
Future<Duration> setUrl(final String url) async {
|
||||
try {
|
||||
_durationFuture = _invokeMethod('setUrl', [url])
|
||||
.then((ms) => ms == null ? null : Duration(milliseconds: ms));
|
||||
_duration = await _durationFuture;
|
||||
_durationSubject.add(_duration);
|
||||
return _duration;
|
||||
_durationFuture = _invokeMethod('setUrl', [url]).then((ms) =>
|
||||
(ms == null || ms < 0)
|
||||
? const Duration(milliseconds: -1)
|
||||
: Duration(milliseconds: ms));
|
||||
final duration = await _durationFuture;
|
||||
_durationSubject.add(duration);
|
||||
return duration;
|
||||
} on PlatformException catch (e) {
|
||||
return Future.error(e.message);
|
||||
}
|
||||
|
@ -294,7 +300,9 @@ class AudioPlayer {
|
|||
Future<Duration> setClip({Duration start, Duration end}) async {
|
||||
_durationFuture =
|
||||
_invokeMethod('setClip', [start?.inMilliseconds, end?.inMilliseconds])
|
||||
.then((ms) => ms == null ? null : Duration(milliseconds: ms));
|
||||
.then((ms) => (ms == null || ms < 0)
|
||||
? const Duration(milliseconds: -1)
|
||||
: Duration(milliseconds: ms));
|
||||
final duration = await _durationFuture;
|
||||
_durationSubject.add(duration);
|
||||
return duration;
|
||||
|
|
11
pubspec.lock
11
pubspec.lock
|
@ -107,6 +107,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.5.1"
|
||||
pedantic:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pedantic
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.8.0+1"
|
||||
petitparser:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -134,7 +141,7 @@ packages:
|
|||
name: rxdart
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.24.0"
|
||||
version: "0.24.1"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
|
@ -181,7 +188,7 @@ packages:
|
|||
name: test_api
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.2.14"
|
||||
version: "0.2.11"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
Loading…
Reference in New Issue