Skip to content

Commit

Permalink
[AV][android] Fix progress update loop.
Browse files Browse the repository at this point in the history
  • Loading branch information
mczernek committed Feb 26, 2020
1 parent 99b3c6c commit 9a8ba04
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 31 deletions.
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ buildscript {
dbFlowVersion = '4.2.4'
buildToolsVersion = '28.0.0'
supportLibVersion = '28.0.0'
kotlinVersion = '1.3.50'
kotlinVersion = '1.3.61'
gradlePluginVersion = '3.5.3'
gradleDownloadTaskVersion = '3.4.3'
repositoryUrl = "file:${System.env.HOME}/.m2/repository/"
Expand Down
17 changes: 14 additions & 3 deletions packages/expo-av/android/build.gradle
Original file line number Diff line number Diff line change
@@ -1,12 +1,23 @@
apply plugin: 'com.android.library'
apply plugin: 'maven'
apply plugin: 'kotlin-android'

group = 'host.exp.exponent'
version = '8.0.0'

// Simple helper that allows the root project to override versions declared by this library.
def safeExtGet(prop, fallback) {
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
buildscript {
// Simple helper that allows the root project to override versions declared by this library.
ext.safeExtGet = { prop, fallback ->
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
}

repositories {
mavenCentral()
}

dependencies {
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${safeExtGet("kotlinVersion", "1.3.50")}")
}
}

// Upload android library to maven with javadoc and android sources
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,19 @@
import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.util.Pair;
import android.view.Surface;

import java.lang.ref.WeakReference;
import java.util.Map;

import org.unimodules.core.Promise;
import org.unimodules.core.arguments.ReadableArguments;

import java.util.Map;

import expo.modules.av.AVManagerInterface;
import expo.modules.av.AudioEventHandler;
import expo.modules.av.AudioFocusNotAcquiredException;
import expo.modules.av.progress.AndroidLooperTimeMachine;
import expo.modules.av.progress.ProgressLooper;

public abstract class PlayerData implements AudioEventHandler {
static final String STATUS_ANDROID_IMPLEMENTATION_KEY_PATH = "androidImplementation";
Expand Down Expand Up @@ -76,25 +77,8 @@ public interface FullscreenPresenter {
final Uri mUri;
final Map<String, Object> mRequestHeaders;

private Handler mHandler = new Handler();
private Runnable mProgressUpdater = new ProgressUpdater(this);

private class ProgressUpdater implements Runnable {
private WeakReference<PlayerData> mPlayerDataWeakReference;
private ProgressLooper mProgressUpdater = new ProgressLooper(new AndroidLooperTimeMachine());

private ProgressUpdater(PlayerData playerData) {
mPlayerDataWeakReference = new WeakReference<>(playerData);
}

@Override
public void run() {
final PlayerData playerData = mPlayerDataWeakReference.get();
if (playerData != null) {
playerData.callStatusUpdateListener();
playerData.progressUpdateLoop();
}
}
}

private FullscreenPresenter mFullscreenPresenter = null;
private StatusUpdateListener mStatusUpdateListener = null;
Expand Down Expand Up @@ -125,7 +109,7 @@ public static PlayerData createUnloadedPlayerData(final AVManagerInterface avMod
final Uri uri = Uri.parse(uriString);

if (status.containsKey(STATUS_ANDROID_IMPLEMENTATION_KEY_PATH)
&& status.getString(STATUS_ANDROID_IMPLEMENTATION_KEY_PATH).equals(MediaPlayerData.IMPLEMENTATION_NAME)) {
&& status.getString(STATUS_ANDROID_IMPLEMENTATION_KEY_PATH).equals(MediaPlayerData.IMPLEMENTATION_NAME)) {
return new MediaPlayerData(avModule, context, uri, requestHeaders);
} else {
return new SimpleExoPlayerData(avModule, context, uri, uriOverridingExtension, requestHeaders);
Expand Down Expand Up @@ -161,19 +145,25 @@ final void callStatusUpdateListener() {
abstract boolean shouldContinueUpdatingProgress();

final void stopUpdatingProgressIfNecessary() {
mHandler.removeCallbacks(mProgressUpdater);
mProgressUpdater.stopLooping();
}

private void progressUpdateLoop() {
if (!shouldContinueUpdatingProgress()) {
stopUpdatingProgressIfNecessary();
} else {
mHandler.postDelayed(mProgressUpdater, mProgressUpdateIntervalMillis);
mProgressUpdater.loop(mProgressUpdateIntervalMillis, () -> {
this.callStatusUpdateListener();
return null;
});
}
}

final void beginUpdatingProgressIfNecessary() {
mHandler.post(mProgressUpdater);
mProgressUpdater.loop(mProgressUpdateIntervalMillis, () -> {
this.callStatusUpdateListener();
return null;
});
}

public final void setStatusUpdateListener(final StatusUpdateListener listener) {
Expand All @@ -198,7 +188,7 @@ final boolean shouldPlayerPlay() {
abstract void playPlayerWithRateAndMuteIfNecessary() throws AudioFocusNotAcquiredException;

abstract void applyNewStatus(final Integer newPositionMillis, final Boolean newIsLooping)
throws AudioFocusNotAcquiredException, IllegalStateException;
throws AudioFocusNotAcquiredException, IllegalStateException;

final void setStatusWithListener(final Bundle status, final SetStatusCompletionListener setStatusCompletionListener) {
if (status.containsKey(STATUS_PROGRESS_UPDATE_INTERVAL_MILLIS_KEY_PATH)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package expo.modules.av.progress

import android.os.Handler

class AndroidLooperTimeMachine: TimeMachine {

override fun scheduleAt(intervalMillis: Long, callback: TimeMachineTick) {
Handler().postDelayed(callback, intervalMillis)
}

override val time: Long
get() = System.currentTimeMillis()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package expo.modules.av.progress

typealias TimeMachineTick = () -> Unit

interface TimeMachine {
fun scheduleAt(intervalMillis: Long, callback: TimeMachineTick)
val time: Long
}

typealias PlayerProgressListener = () -> Unit

class ProgressLooper(private val timeMachine: TimeMachine) {

private var interval = 0L
private var nextExpectedTick = -1L
private var waiting = false

private var shouldLoop: Boolean
get() = interval > 0 && nextExpectedTick >= 0 && !waiting
set(value) {
if (!value) {
interval = 0L
nextExpectedTick = -1L
waiting = false
}
}

private var listener: PlayerProgressListener? = null

fun changeListener(listener: PlayerProgressListener) {
this.listener = listener
}

fun loop(interval: Long, listener: PlayerProgressListener) {
this.listener = listener
this.interval = interval
scheduleNextTick()
}

fun stopLooping() {
this.shouldLoop = false
this.listener = null
}

private fun scheduleNextTick() {
if (nextExpectedTick == -1L) {
nextExpectedTick = timeMachine.time
}
if (shouldLoop) {
nextExpectedTick += calculateNextInterval()
waiting = true
timeMachine.scheduleAt(nextExpectedTick - timeMachine.time) {
waiting = false
listener?.invoke()
scheduleNextTick()
}
}
}

private fun calculateNextInterval() =
if (nextExpectedTick > timeMachine.time) {
interval
} else {
(((timeMachine.time - nextExpectedTick) / interval) + 1) * interval
}


}

0 comments on commit 9a8ba04

Please sign in to comment.