Merge branch 'master' of github.com:ryanheise/just_audio
This commit is contained in:
commit
8680cac01a
|
@ -8,7 +8,7 @@ buildscript {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.5.0'
|
classpath 'com.android.tools.build:gradle:3.6.3'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ package com.ryanheise.just_audio;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||||
import com.google.android.exoplayer2.PlaybackParameters;
|
import com.google.android.exoplayer2.PlaybackParameters;
|
||||||
|
@ -26,31 +25,28 @@ import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
|
||||||
import com.google.android.exoplayer2.upstream.DefaultHttpDataSource;
|
import com.google.android.exoplayer2.upstream.DefaultHttpDataSource;
|
||||||
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory;
|
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
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.Log;
|
||||||
|
import io.flutter.plugin.common.BinaryMessenger;
|
||||||
import io.flutter.plugin.common.EventChannel;
|
import io.flutter.plugin.common.EventChannel;
|
||||||
import io.flutter.plugin.common.EventChannel.EventSink;
|
import io.flutter.plugin.common.EventChannel.EventSink;
|
||||||
import io.flutter.plugin.common.MethodCall;
|
import io.flutter.plugin.common.MethodCall;
|
||||||
import io.flutter.plugin.common.MethodChannel;
|
import io.flutter.plugin.common.MethodChannel;
|
||||||
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
|
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
|
||||||
import io.flutter.plugin.common.MethodChannel.Result;
|
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 java.util.List;
|
||||||
|
|
||||||
public class AudioPlayer implements MethodCallHandler, Player.EventListener, MetadataOutput {
|
public class AudioPlayer implements MethodCallHandler, Player.EventListener, MetadataOutput {
|
||||||
|
|
||||||
static final String TAG = "AudioPlayer";
|
static final String TAG = "AudioPlayer";
|
||||||
|
|
||||||
private final Registrar registrar;
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final MethodChannel methodChannel;
|
private final MethodChannel methodChannel;
|
||||||
private final EventChannel eventChannel;
|
private final EventChannel eventChannel;
|
||||||
private EventSink eventSink;
|
private EventSink eventSink;
|
||||||
|
|
||||||
private final String id;
|
|
||||||
private volatile PlaybackState state;
|
private volatile PlaybackState state;
|
||||||
private long updateTime;
|
private long updateTime;
|
||||||
private long updatePosition;
|
private long updatePosition;
|
||||||
|
@ -70,11 +66,15 @@ public class AudioPlayer implements MethodCallHandler, Player.EventListener, Met
|
||||||
private IcyInfo icyInfo;
|
private IcyInfo icyInfo;
|
||||||
private IcyHeaders icyHeaders;
|
private IcyHeaders icyHeaders;
|
||||||
|
|
||||||
private final SimpleExoPlayer player;
|
private SimpleExoPlayer player;
|
||||||
private final Handler handler = new Handler();
|
private final Handler handler = new Handler();
|
||||||
private final Runnable bufferWatcher = new Runnable() {
|
private final Runnable bufferWatcher = new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
if (player == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
long newBufferedPosition = player.getBufferedPosition();
|
long newBufferedPosition = player.getBufferedPosition();
|
||||||
if (newBufferedPosition != bufferedPosition) {
|
if (newBufferedPosition != bufferedPosition) {
|
||||||
bufferedPosition = newBufferedPosition;
|
bufferedPosition = newBufferedPosition;
|
||||||
|
@ -92,13 +92,15 @@ public class AudioPlayer implements MethodCallHandler, Player.EventListener, Met
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public AudioPlayer(final Registrar registrar, final String id) {
|
private final Runnable onDispose;
|
||||||
this.registrar = registrar;
|
|
||||||
this.context = registrar.activeContext();
|
public AudioPlayer(final Context applicationContext, final BinaryMessenger messenger,
|
||||||
this.id = id;
|
final String id, final Runnable onDispose) {
|
||||||
methodChannel = new MethodChannel(registrar.messenger(), "com.ryanheise.just_audio.methods." + id);
|
this.context = applicationContext;
|
||||||
|
this.onDispose = onDispose;
|
||||||
|
methodChannel = new MethodChannel(messenger, "com.ryanheise.just_audio.methods." + id);
|
||||||
methodChannel.setMethodCallHandler(this);
|
methodChannel.setMethodCallHandler(this);
|
||||||
eventChannel = new EventChannel(registrar.messenger(), "com.ryanheise.just_audio.events." + id);
|
eventChannel = new EventChannel(messenger, "com.ryanheise.just_audio.events." + id);
|
||||||
eventChannel.setStreamHandler(new EventChannel.StreamHandler() {
|
eventChannel.setStreamHandler(new EventChannel.StreamHandler() {
|
||||||
@Override
|
@Override
|
||||||
public void onListen(final Object arguments, final EventSink eventSink) {
|
public void onListen(final Object arguments, final EventSink eventSink) {
|
||||||
|
@ -111,10 +113,6 @@ public class AudioPlayer implements MethodCallHandler, Player.EventListener, Met
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
state = PlaybackState.none;
|
state = PlaybackState.none;
|
||||||
|
|
||||||
player = new SimpleExoPlayer.Builder(context).build();
|
|
||||||
player.addMetadataOutput(this);
|
|
||||||
player.addListener(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startWatchingBuffer() {
|
private void startWatchingBuffer() {
|
||||||
|
@ -227,22 +225,24 @@ public class AudioPlayer implements MethodCallHandler, Player.EventListener, Met
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMethodCall(final MethodCall call, final Result result) {
|
public void onMethodCall(final MethodCall call, final Result result) {
|
||||||
final List<?> args = (List<?>)call.arguments;
|
ensurePlayerInitialized();
|
||||||
|
|
||||||
|
final List<?> args = (List<?>) call.arguments;
|
||||||
try {
|
try {
|
||||||
switch (call.method) {
|
switch (call.method) {
|
||||||
case "setUrl":
|
case "setUrl":
|
||||||
setUrl((String)args.get(0), result);
|
setUrl((String) args.get(0), result);
|
||||||
break;
|
break;
|
||||||
case "setClip":
|
case "setClip":
|
||||||
Object start = args.get(0);
|
Object start = args.get(0);
|
||||||
if (start != null && start instanceof Integer) {
|
if (start != null && start instanceof Integer) {
|
||||||
start = new Long((Integer)start);
|
start = new Long((Integer) start);
|
||||||
}
|
}
|
||||||
Object end = args.get(1);
|
Object end = args.get(1);
|
||||||
if (end != null && end instanceof Integer) {
|
if (end != null && end instanceof Integer) {
|
||||||
end = new Long((Integer)end);
|
end = new Long((Integer) end);
|
||||||
}
|
}
|
||||||
setClip((Long)start, (Long)end, result);
|
setClip((Long) start, (Long) end, result);
|
||||||
break;
|
break;
|
||||||
case "play":
|
case "play":
|
||||||
play();
|
play();
|
||||||
|
@ -256,11 +256,11 @@ public class AudioPlayer implements MethodCallHandler, Player.EventListener, Met
|
||||||
stop(result);
|
stop(result);
|
||||||
break;
|
break;
|
||||||
case "setVolume":
|
case "setVolume":
|
||||||
setVolume((float)((double)((Double)args.get(0))));
|
setVolume((float) ((double) ((Double) args.get(0))));
|
||||||
result.success(null);
|
result.success(null);
|
||||||
break;
|
break;
|
||||||
case "setSpeed":
|
case "setSpeed":
|
||||||
setSpeed((float)((double)((Double)args.get(0))));
|
setSpeed((float) ((double) ((Double) args.get(0))));
|
||||||
result.success(null);
|
result.success(null);
|
||||||
break;
|
break;
|
||||||
case "setAutomaticallyWaitsToMinimizeStalling":
|
case "setAutomaticallyWaitsToMinimizeStalling":
|
||||||
|
@ -270,14 +270,15 @@ public class AudioPlayer implements MethodCallHandler, Player.EventListener, Met
|
||||||
Object position = args.get(0);
|
Object position = args.get(0);
|
||||||
long position2;
|
long position2;
|
||||||
if (position instanceof Integer) {
|
if (position instanceof Integer) {
|
||||||
position2 = (Integer)position;
|
position2 = (Integer) position;
|
||||||
} else {
|
} else {
|
||||||
position2 = (Long)position;
|
position2 = (Long) position;
|
||||||
}
|
}
|
||||||
seek(position2 == -2 ? C.TIME_UNSET : position2, result);
|
seek(position2 == -2 ? C.TIME_UNSET : position2, result);
|
||||||
break;
|
break;
|
||||||
case "dispose":
|
case "dispose":
|
||||||
dispose();
|
dispose();
|
||||||
|
onDispose.run();
|
||||||
result.success(null);
|
result.success(null);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -293,6 +294,14 @@ public class AudioPlayer implements MethodCallHandler, Player.EventListener, Met
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ensurePlayerInitialized() {
|
||||||
|
if (player == null) {
|
||||||
|
player = new SimpleExoPlayer.Builder(context).build();
|
||||||
|
player.addMetadataOutput(this);
|
||||||
|
player.addListener(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void broadcastPlaybackEvent() {
|
private void broadcastPlaybackEvent() {
|
||||||
final ArrayList<Object> event = new ArrayList<Object>();
|
final ArrayList<Object> event = new ArrayList<Object>();
|
||||||
event.add(state.ordinal());
|
event.add(state.ordinal());
|
||||||
|
@ -382,7 +391,8 @@ public class AudioPlayer implements MethodCallHandler, Player.EventListener, Met
|
||||||
DefaultHttpDataSource.DEFAULT_READ_TIMEOUT_MILLIS,
|
DefaultHttpDataSource.DEFAULT_READ_TIMEOUT_MILLIS,
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(context, httpDataSourceFactory);
|
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(context,
|
||||||
|
httpDataSourceFactory);
|
||||||
Uri uri = Uri.parse(url);
|
Uri uri = Uri.parse(url);
|
||||||
String extension = getLowerCaseExtension(uri);
|
String extension = getLowerCaseExtension(uri);
|
||||||
if (extension.equals("mpd")) {
|
if (extension.equals("mpd")) {
|
||||||
|
@ -435,7 +445,8 @@ public class AudioPlayer implements MethodCallHandler, Player.EventListener, Met
|
||||||
player.setPlayWhenReady(true);
|
player.setPlayWhenReady(true);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalStateException("Cannot call play from connecting/none states (" + state + ")");
|
throw new IllegalStateException(
|
||||||
|
"Cannot call play from connecting/none states (" + state + ")");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -448,7 +459,8 @@ public class AudioPlayer implements MethodCallHandler, Player.EventListener, Met
|
||||||
transition(PlaybackState.paused);
|
transition(PlaybackState.paused);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalStateException("Can call pause only from playing and buffering states (" + state + ")");
|
throw new IllegalStateException(
|
||||||
|
"Can call pause only from playing and buffering states (" + state + ")");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -500,10 +512,13 @@ public class AudioPlayer implements MethodCallHandler, Player.EventListener, Met
|
||||||
}
|
}
|
||||||
|
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
|
if (player != null) {
|
||||||
player.release();
|
player.release();
|
||||||
|
player = null;
|
||||||
buffering = false;
|
buffering = false;
|
||||||
transition(PlaybackState.none);
|
transition(PlaybackState.none);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void abortSeek() {
|
private void abortSeek() {
|
||||||
if (seekResult != null) {
|
if (seekResult != null) {
|
||||||
|
|
|
@ -1,41 +1,57 @@
|
||||||
package com.ryanheise.just_audio;
|
package com.ryanheise.just_audio;
|
||||||
|
|
||||||
import io.flutter.plugin.common.MethodCall;
|
import android.content.Context;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import io.flutter.embedding.engine.plugins.FlutterPlugin;
|
||||||
|
import io.flutter.plugin.common.BinaryMessenger;
|
||||||
import io.flutter.plugin.common.MethodChannel;
|
import io.flutter.plugin.common.MethodChannel;
|
||||||
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
|
|
||||||
import io.flutter.plugin.common.MethodChannel.Result;
|
|
||||||
import io.flutter.plugin.common.PluginRegistry.Registrar;
|
import io.flutter.plugin.common.PluginRegistry.Registrar;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/** JustAudioPlugin */
|
/**
|
||||||
public class JustAudioPlugin implements MethodCallHandler {
|
* JustAudioPlugin
|
||||||
/** Plugin registration. */
|
*/
|
||||||
public static void registerWith(Registrar registrar) {
|
public class JustAudioPlugin implements FlutterPlugin {
|
||||||
final MethodChannel channel = new MethodChannel(registrar.messenger(), "com.ryanheise.just_audio.methods");
|
|
||||||
channel.setMethodCallHandler(new JustAudioPlugin(registrar));
|
private MethodChannel channel;
|
||||||
|
private MethodCallHandlerImpl methodCallHandler;
|
||||||
|
|
||||||
|
public JustAudioPlugin() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Registrar registrar;
|
/**
|
||||||
|
* Plugin registration.
|
||||||
public JustAudioPlugin(Registrar registrar) {
|
*/
|
||||||
this.registrar = registrar;
|
public static void registerWith(Registrar registrar) {
|
||||||
|
final JustAudioPlugin plugin = new JustAudioPlugin();
|
||||||
|
plugin.startListening(registrar.context(), registrar.messenger());
|
||||||
|
registrar.addViewDestroyListener(
|
||||||
|
view -> {
|
||||||
|
plugin.stopListening();
|
||||||
|
return false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMethodCall(MethodCall call, Result result) {
|
public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {
|
||||||
switch (call.method) {
|
startListening(binding.getApplicationContext(), binding.getBinaryMessenger());
|
||||||
case "init":
|
|
||||||
final List<?> args = (List<?>)call.arguments;
|
|
||||||
String id = (String)args.get(0);
|
|
||||||
new AudioPlayer(registrar, id);
|
|
||||||
result.success(null);
|
|
||||||
break;
|
|
||||||
case "setIosCategory":
|
|
||||||
result.success(null);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
result.notImplemented();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
|
||||||
|
stopListening();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startListening(Context applicationContext, BinaryMessenger messenger) {
|
||||||
|
methodCallHandler = new MethodCallHandlerImpl(applicationContext, messenger);
|
||||||
|
|
||||||
|
channel = new MethodChannel(messenger, "com.ryanheise.just_audio.methods");
|
||||||
|
channel.setMethodCallHandler(methodCallHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stopListening() {
|
||||||
|
methodCallHandler.dispose();
|
||||||
|
methodCallHandler = null;
|
||||||
|
|
||||||
|
channel.setMethodCallHandler(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
package com.ryanheise.just_audio;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import io.flutter.plugin.common.BinaryMessenger;
|
||||||
|
import io.flutter.plugin.common.MethodCall;
|
||||||
|
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
|
||||||
|
import io.flutter.plugin.common.MethodChannel.Result;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class MethodCallHandlerImpl implements MethodCallHandler {
|
||||||
|
|
||||||
|
private final Context applicationContext;
|
||||||
|
private final BinaryMessenger messenger;
|
||||||
|
|
||||||
|
private final Map<String, AudioPlayer> players = new HashMap<>();
|
||||||
|
|
||||||
|
public MethodCallHandlerImpl(Context applicationContext,
|
||||||
|
BinaryMessenger messenger) {
|
||||||
|
this.applicationContext = applicationContext;
|
||||||
|
this.messenger = messenger;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMethodCall(MethodCall call, @NonNull Result result) {
|
||||||
|
switch (call.method) {
|
||||||
|
case "init":
|
||||||
|
final List<String> ids = call.arguments();
|
||||||
|
String id = ids.get(0);
|
||||||
|
players.put(id, new AudioPlayer(applicationContext, messenger, id,
|
||||||
|
() -> players.remove(id)
|
||||||
|
));
|
||||||
|
result.success(null);
|
||||||
|
break;
|
||||||
|
case "setIosCategory":
|
||||||
|
result.success(null);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
result.notImplemented();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dispose() {
|
||||||
|
for (AudioPlayer player : players.values()) {
|
||||||
|
player.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
players.clear();
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,7 +5,7 @@ buildscript {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.5.0'
|
classpath 'com.android.tools.build:gradle:3.6.3'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#Fri Jun 23 08:50:38 CEST 2017
|
#Sun Jun 07 15:20:36 BST 2020
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
|
||||||
|
|
|
@ -451,7 +451,7 @@ class AudioPlayer {
|
||||||
/// * [AudioPlaybackState.none]
|
/// * [AudioPlaybackState.none]
|
||||||
/// * [AudioPlaybackState.connecting]
|
/// * [AudioPlaybackState.connecting]
|
||||||
Future<void> dispose() async {
|
Future<void> dispose() async {
|
||||||
await _invokeMethod('dispose');
|
await _invokeMethod('dispose', [_id]);
|
||||||
if (_cacheFile?.existsSync() == true) {
|
if (_cacheFile?.existsSync() == true) {
|
||||||
_cacheFile?.deleteSync();
|
_cacheFile?.deleteSync();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue