Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #8 from the4thfloor/#7_AudioPlayer_blocks_UI_on_An…
…dorid #7 audio player blocks ui on andorid
- Loading branch information
Showing
8 changed files
with
339 additions
and
232 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
242 changes: 146 additions & 96 deletions
242
android/src/main/java/bz/rxla/audioplayer/AudioplayerPlugin.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<String, MediaPlayer> mediaPlayers = new HashMap<>(); | ||
private final Handler handler = new Handler(); | ||
private Runnable positionUpdates; | ||
|
||
Map<String, MediaPlayer> 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<Map.Entry<String, MediaPlayer>> iterator = mediaPlayers.entrySet().iterator(); | ||
while (iterator.hasNext()) { | ||
final Map.Entry<String, MediaPlayer> 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<String, Object> buildArguments(String playerId, Object value) { | ||
Map<String, Object> 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<Map<String, MediaPlayer>> _mediaPlayers; | ||
private final WeakReference<MethodChannel> _channel; | ||
private final WeakReference<Handler> _handler; | ||
private final WeakReference<AudioplayerPlugin> _audioplayerPlugin; | ||
|
||
UpdateCallback(final Map<String, MediaPlayer> 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<String, MediaPlayer> 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<String, MediaPlayer> 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<String, Object> buildArguments(String playerId, Object value) { | ||
Map<String, Object> result = new HashMap<>(); | ||
result.put("playerId", playerId); | ||
result.put("value", value); | ||
return result; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.