From cb74c2ae316c0feaae6c7a0086a7238f6d6e2c01 Mon Sep 17 00:00:00 2001 From: Ralph Bergmann Date: Thu, 22 Feb 2018 14:17:02 +0100 Subject: [PATCH] refactor AudioplayerPlugin --- .../rxla/audioplayer/AudioplayerPlugin.java | 242 +++++++++++------- 1 file changed, 146 insertions(+), 96 deletions(-) diff --git a/android/src/main/java/bz/rxla/audioplayer/AudioplayerPlugin.java b/android/src/main/java/bz/rxla/audioplayer/AudioplayerPlugin.java index 04e10229f..8c3410d80 100644 --- a/android/src/main/java/bz/rxla/audioplayer/AudioplayerPlugin.java +++ b/android/src/main/java/bz/rxla/audioplayer/AudioplayerPlugin.java @@ -1,152 +1,202 @@ package bz.rxla.audioplayer; -import android.app.Activity; import android.media.AudioManager; import android.media.MediaPlayer; import android.os.Handler; -import android.util.Log; -import io.flutter.app.FlutterActivity; -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.MethodCall; -import io.flutter.plugin.common.PluginRegistry.Registrar; import java.io.IOException; +import java.lang.ref.WeakReference; import java.util.HashMap; +import java.util.Iterator; import java.util.Map; +import io.flutter.plugin.common.MethodCall; +import io.flutter.plugin.common.MethodChannel; +import io.flutter.plugin.common.MethodChannel.MethodCallHandler; +import io.flutter.plugin.common.PluginRegistry.Registrar; + /** * AudioplayerPlugin */ -public class AudioplayerPlugin implements MethodCallHandler { - private final MethodChannel channel; - private Activity activity; +public class AudioplayerPlugin implements MethodCallHandler, MediaPlayer.OnPreparedListener, MediaPlayer.OnCompletionListener { - final Handler handler = new Handler(); + private final MethodChannel channel; + private final Map mediaPlayers = new HashMap<>(); + private final Handler handler = new Handler(); + private Runnable positionUpdates; - Map mediaPlayers = new HashMap<>(); - public static void registerWith(Registrar registrar) { + public static void registerWith(final Registrar registrar) { final MethodChannel channel = new MethodChannel(registrar.messenger(), "bz.rxla.flutter/audio"); - channel.setMethodCallHandler(new AudioplayerPlugin(registrar.activity(), channel)); + channel.setMethodCallHandler(new AudioplayerPlugin(channel)); } - private AudioplayerPlugin(Activity activity, MethodChannel channel) { - this.activity = activity; + private AudioplayerPlugin(final MethodChannel channel) { this.channel = channel; this.channel.setMethodCallHandler(this); } @Override - public void onMethodCall(MethodCall call, MethodChannel.Result response) { - String playerId = ((HashMap) call.arguments()).get("playerId").toString(); - if (call.method.equals("play")) { - String url = ((HashMap) call.arguments()).get("url").toString(); - double volume = (double)((HashMap) call.arguments()).get("volume"); - Boolean resPlay = play(playerId, url, (float)volume); - response.success(1); - } else if (call.method.equals("pause")) { - pause(playerId); - response.success(1); - } else if (call.method.equals("stop")) { - stop(playerId); - response.success(1); - } else if (call.method.equals("seek")) { - double position = Double.parseDouble(((HashMap) call.arguments()).get("position").toString()); - seek(playerId, position); - response.success(1); - } else { - response.notImplemented(); + public void onMethodCall(final MethodCall call, final MethodChannel.Result response) { + final String playerId = call.argument("playerId"); + switch (call.method) { + case "play": + final String url = call.argument("url"); + final double volume = call.argument("volume"); + try { + play(playerId, url, (float) volume); + response.success(1); + } catch (IOException e) { + e.printStackTrace(); + response.error("IOException", e.getMessage(), e); + } + break; + case "pause": + pause(playerId); + response.success(1); + break; + case "stop": + stop(playerId); + response.success(1); + break; + case "seek": + double position = call.argument("position"); + seek(playerId, position); + response.success(1); + break; + default: + response.notImplemented(); + break; } } - private void seek(String playerId, double position) { + @Override + public void onPrepared(final MediaPlayer mediaPlayer) { + mediaPlayer.start(); + sendPositionUpdates(); + } + + @Override + public void onCompletion(final MediaPlayer mediaPlayer) { + mediaPlayer.stop(); + mediaPlayer.reset(); + mediaPlayer.release(); + removePlayer(mediaPlayer); + } + + private void play(final String playerId, final String url, final float volume) throws IOException { MediaPlayer mediaPlayer = mediaPlayers.get(playerId); - mediaPlayer.seekTo((int) (position * 1000)); + if (mediaPlayer == null) { + mediaPlayer = new MediaPlayer(); + mediaPlayer.setOnPreparedListener(this); + mediaPlayer.setOnCompletionListener(this); + mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); + mediaPlayers.put(playerId, mediaPlayer); + } + mediaPlayer.setDataSource(url); + mediaPlayer.setVolume(volume, volume); + mediaPlayer.prepareAsync(); } - private void stop(String playerId) { - handler.removeCallbacks(sendData); + private void pause(final String playerId) { MediaPlayer mediaPlayer = mediaPlayers.get(playerId); if (mediaPlayer != null) { - mediaPlayer.stop(); - mediaPlayer.release(); - mediaPlayers.remove(playerId); + mediaPlayer.pause(); } } - private void pause(String playerId) { + private void seek(final String playerId, final double position) { MediaPlayer mediaPlayer = mediaPlayers.get(playerId); if (mediaPlayer != null) { - mediaPlayer.pause(); + mediaPlayer.seekTo((int) (position * 1000)); } - handler.removeCallbacks(sendData); } - private Boolean play(final String playerId, String url, float volume) { + private void stop(final String playerId) { MediaPlayer mediaPlayer = mediaPlayers.get(playerId); - if (mediaPlayer == null) { - mediaPlayer = new MediaPlayer(); - mediaPlayers.put(playerId, mediaPlayer); - mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); + if (mediaPlayer != null) { + onCompletion(mediaPlayer); + } + } - try { - mediaPlayer.setDataSource(url); - } catch (IOException e) { - e.printStackTrace(); - Log.d("AUDIO", "invalid DataSource"); + private void removePlayer(final MediaPlayer mediaPlayer) { + final Iterator> iterator = mediaPlayers.entrySet().iterator(); + while (iterator.hasNext()) { + final Map.Entry next = iterator.next(); + if (next.getValue() == mediaPlayer) { + iterator.remove(); + channel.invokeMethod("audio.onComplete", buildArguments(next.getKey(), true)); + break; } + } + } - try { - mediaPlayer.prepare(); - } catch (IOException e) { - Log.d("AUDIO", "media prepare ERROR"); - e.printStackTrace(); - } + private void sendPositionUpdates() { + if (positionUpdates != null) { + return; } + positionUpdates = new UpdateCallback(mediaPlayers, channel, handler, this); + handler.post(positionUpdates); + } - channel.invokeMethod("audio.onDuration", buildArguments(playerId, mediaPlayer.getDuration())); + void stopPositionUpdates() { + positionUpdates = null; + handler.removeCallbacksAndMessages(null); + } - mediaPlayer.setVolume(volume, volume); - mediaPlayer.start(); + static Map buildArguments(String playerId, Object value) { + Map result = new HashMap<>(); + result.put("playerId", playerId); + result.put("value", value); + return result; + } - mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { - @Override - public void onCompletion(MediaPlayer mp) { - stop(playerId); - channel.invokeMethod("audio.onComplete", buildArguments(playerId, true)); - } - }); + private static final class UpdateCallback implements Runnable { + + private final WeakReference> _mediaPlayers; + private final WeakReference _channel; + private final WeakReference _handler; + private final WeakReference _audioplayerPlugin; + + UpdateCallback(final Map mediaPlayers, + final MethodChannel channel, + final Handler handler, + final AudioplayerPlugin audioplayerPlugin) { + _mediaPlayers = new WeakReference<>(mediaPlayers); + _channel = new WeakReference<>(channel); + _handler = new WeakReference<>(handler); + _audioplayerPlugin = new WeakReference<>(audioplayerPlugin); + } + + @Override + public void run() { - handler.post(sendData); + final Map mediaPlayers = _mediaPlayers.get(); + final MethodChannel channel = _channel.get(); + final Handler handler = _handler.get(); + final AudioplayerPlugin audioplayerPlugin = _audioplayerPlugin.get(); - return true; - } + if (mediaPlayers == null || channel == null || handler == null || audioplayerPlugin == null) { + return; + } - private final Runnable sendData = new Runnable() { - public void run() { - try { - for (String playerId : mediaPlayers.keySet()) { - MediaPlayer mediaPlayer = mediaPlayers.get(playerId); - if (!mediaPlayer.isPlaying()) { - handler.removeCallbacks(sendData); - } - int time = mediaPlayer.getCurrentPosition(); - channel.invokeMethod("audio.onCurrentPosition", buildArguments(playerId, time)); - - handler.postDelayed(this, 200); + if (mediaPlayers.isEmpty()) { + audioplayerPlugin.stopPositionUpdates(); + return; + } + + for (final Map.Entry next : mediaPlayers.entrySet()) { + final MediaPlayer mediaPlayer = next.getValue(); + if (!mediaPlayer.isPlaying()) { + continue; } - } catch (Exception e) { - e.printStackTrace(); + final String key = next.getKey(); + final int duration = mediaPlayer.getDuration(); + final int time = mediaPlayer.getCurrentPosition(); + channel.invokeMethod("audio.onDuration", buildArguments(key, duration)); + channel.invokeMethod("audio.onCurrentPosition", buildArguments(key, time)); } + handler.postDelayed(this, 200); } - }; - - private static Map buildArguments(String playerId, Object value) { - Map result = new HashMap<>(); - result.put("playerId", playerId); - result.put("value", value); - return result; } }