Skip to content

Commit

Permalink
Merge pull request #8 from the4thfloor/#7_AudioPlayer_blocks_UI_on_An…
Browse files Browse the repository at this point in the history
…dorid

#7 audio player blocks ui on andorid
  • Loading branch information
luanpotter committed Feb 27, 2018
2 parents 971b78d + cb74c2a commit efcc029
Show file tree
Hide file tree
Showing 8 changed files with 339 additions and 232 deletions.
10 changes: 6 additions & 4 deletions android/build.gradle
Expand Up @@ -3,27 +3,29 @@ version '1.0-SNAPSHOT'

buildscript {
repositories {
google()
jcenter()
}

dependencies {
classpath 'com.android.tools.build:gradle:2.3.0'
classpath 'com.android.tools.build:gradle:3.0.1'
}
}

allprojects {
rootProject.allprojects {
repositories {
google()
jcenter()
}
}

apply plugin: 'com.android.library'

android {
compileSdkVersion 25
buildToolsVersion '25.0.3'
compileSdkVersion 27

defaultConfig {
minSdkVersion 16
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
lintOptions {
Expand Down
242 changes: 146 additions & 96 deletions 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<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;
}
}
14 changes: 8 additions & 6 deletions example/android/app/build.gradle
@@ -1,8 +1,8 @@
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withInputStream { stream ->
localProperties.load(stream)
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}

Expand All @@ -15,18 +15,20 @@ apply plugin: 'com.android.application'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"

android {
compileSdkVersion 25
buildToolsVersion '25.0.3'
compileSdkVersion 27

lintOptions {
disable 'InvalidPackage'
}

defaultConfig {
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "bz.rxla.audioplayer_example"
minSdkVersion 16
targetSdkVersion 27
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}

buildTypes {
Expand Down

0 comments on commit efcc029

Please sign in to comment.