Add debug log entry for video player pool usage.

fork-5.53.8
Alex Hart 2022-05-20 14:54:24 -03:00
rodzic 63f4f0bcec
commit eaa7262b2f
9 zmienionych plików z 90 dodań i 32 usunięć

Wyświetl plik

@ -54,7 +54,7 @@ public final class GiphyMp4ProjectionPlayerHolder implements Player.Listener, De
this.policyEnforcer = policyEnforcer;
if (player.getExoPlayer() == null) {
SimpleExoPlayer fromPool = ApplicationDependencies.getExoPlayerPool().get();
SimpleExoPlayer fromPool = ApplicationDependencies.getExoPlayerPool().get(TAG);
if (fromPool == null) {
Log.i(TAG, "Could not get exoplayer from pool.");
@ -142,7 +142,7 @@ public final class GiphyMp4ProjectionPlayerHolder implements Player.Listener, De
@Override
public void onResume(@NonNull LifecycleOwner owner) {
if (mediaItem != null) {
SimpleExoPlayer fromPool = ApplicationDependencies.getExoPlayerPool().get();
SimpleExoPlayer fromPool = ApplicationDependencies.getExoPlayerPool().get(TAG);
if (fromPool != null) {
ExoPlayerKt.configureForGifPlayback(fromPool);
fromPool.addListener(this);

Wyświetl plik

@ -0,0 +1,39 @@
package org.thoughtcrime.securesms.logsubmit
import android.content.Context
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
import org.thoughtcrime.securesms.video.exo.ExoPlayerPool
/**
* Prints off the current exoplayer pool stats, including ownership info.
*/
class LogSectionExoPlayerPool : LogSection {
override fun getTitle(): String = "EXOPLAYER POOL"
override fun getContent(context: Context): CharSequence {
val poolStats = ApplicationDependencies.getExoPlayerPool().getPoolStats()
val owners: Map<String, List<ExoPlayerPool.OwnershipInfo>> = poolStats.owners.groupBy { it.tag }
val output = StringBuilder()
output.append("Total players created: ${poolStats.created}\n")
output.append("Max allowed unreserved instances: ${poolStats.maxUnreserved}\n")
output.append("Max allowed reserved instances: ${poolStats.maxReserved}\n")
output.append("Available created unreserved instances: ${poolStats.unreservedAndAvailable}\n")
output.append("Available created reserved instances: ${poolStats.reservedAndAvailable}\n")
output.append("Total unreserved created: ${poolStats.unreserved}\n")
output.append("Total reserved created: ${poolStats.reserved}\n\n")
output.append("Ownership Info:\n")
if (owners.isEmpty()) {
output.append(" No ownership info to display.")
} else {
owners.forEach { (ownerTag, infoList) ->
output.append(" Owner $ownerTag\n")
output.append(" reserved: ${infoList.filter { it.isReserved }.size}\n")
output.append(" unreserved: ${infoList.filterNot { it.isReserved }.size}\n")
}
}
return output
}
}

Wyświetl plik

@ -78,6 +78,7 @@ public class SubmitDebugLogRepository {
}
add(new LogSectionNotifications());
add(new LogSectionNotificationProfiles());
add(new LogSectionExoPlayerPool());
add(new LogSectionKeyPreferences());
add(new LogSectionBadges());
add(new LogSectionPermissions());

Wyświetl plik

@ -49,7 +49,7 @@ public final class VideoMediaPreviewFragment extends MediaPreviewFragment {
videoView = itemView.findViewById(R.id.video_player);
videoView.setWindow(requireActivity().getWindow());
videoView.setVideoSource(new VideoSlide(getContext(), uri, size, false), autoPlay);
videoView.setVideoSource(new VideoSlide(getContext(), uri, size, false), autoPlay, TAG);
videoView.setPlayerPositionDiscontinuityCallback((v, r) -> {
if (events.getVideoControlsDelegate() != null) {
events.getVideoControlsDelegate().onPlayerPositionDiscontinuity(r);

Wyświetl plik

@ -98,7 +98,7 @@ public class VideoEditorFragment extends Fragment implements VideoEditorHud.Even
boolean autoplay = isVideoGif;
player.setWindow(requireActivity().getWindow());
player.setVideoSource(slide, autoplay);
player.setVideoSource(slide, autoplay, TAG);
if (slide.isVideoGif()) {
player.setPlayerCallback(new VideoPlayer.PlayerCallback() {

Wyświetl plik

@ -131,7 +131,7 @@ public class ViewOnceMessageActivity extends PassphraseRequiredActivity implemen
video.setWindow(getWindow());
video.setPlayerStateCallbacks(this);
video.setVideoSource(videoSlide, true);
video.setVideoSource(videoSlide, true, TAG);
video.hideControls();
video.loopForever();

Wyświetl plik

@ -121,9 +121,9 @@ public class VideoPlayer extends FrameLayout {
private MediaItem mediaItem;
public void setVideoSource(@NonNull VideoSlide videoSource, boolean autoplay) {
public void setVideoSource(@NonNull VideoSlide videoSource, boolean autoplay, String poolTag) {
if (exoPlayer == null) {
exoPlayer = ApplicationDependencies.getExoPlayerPool().require();
exoPlayer = ApplicationDependencies.getExoPlayerPool().require(poolTag);
exoPlayer.addListener(exoPlayerListener);
exoPlayer.addListener(playerListener);
exoView.setPlayer(exoPlayer);

Wyświetl plik

@ -10,6 +10,7 @@ import com.google.android.exoplayer2.source.MediaSourceFactory
import com.google.android.exoplayer2.source.ProgressiveMediaSource
import com.google.android.exoplayer2.upstream.DataSource
import com.google.android.exoplayer2.util.MimeTypes
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
import org.thoughtcrime.securesms.net.ContentProxySelector
import org.thoughtcrime.securesms.util.AppForegroundObserver
@ -81,6 +82,10 @@ abstract class ExoPlayerPool<T : ExoPlayer>(
private val maximumReservedPlayers: Int,
) : AppForegroundObserver.Listener {
companion object {
private val TAG = Log.tag(ExoPlayerPool::class.java)
}
private val pool: MutableMap<T, PoolState> = mutableMapOf()
/**
@ -89,8 +94,8 @@ abstract class ExoPlayerPool<T : ExoPlayer>(
* @return A player if one is available, otherwise null
*/
@MainThread
fun get(): T? {
return get(allowReserved = false)
fun get(tag: String): T? {
return get(allowReserved = false, tag = tag)
}
/**
@ -100,8 +105,8 @@ abstract class ExoPlayerPool<T : ExoPlayer>(
* @throws IllegalStateException if no player is available.
*/
@MainThread
fun require(): T {
return checkNotNull(get(allowReserved = true)) { "Required exoPlayer could not be acquired! :: ${poolStats()}" }
fun require(tag: String): T {
return checkNotNull(get(allowReserved = true, tag = tag)) { "Required exoPlayer could not be acquired for $tag! :: ${poolStats()}" }
}
/**
@ -113,25 +118,26 @@ abstract class ExoPlayerPool<T : ExoPlayer>(
fun pool(exoPlayer: T) {
val poolState = pool[exoPlayer]
if (poolState != null) {
pool[exoPlayer] = poolState.copy(available = true)
pool[exoPlayer] = poolState.copy(available = true, tag = null)
} else {
throw IllegalArgumentException("Tried to return unknown ExoPlayer to pool :: ${poolStats()}")
}
}
@MainThread
private fun get(allowReserved: Boolean): T? {
private fun get(allowReserved: Boolean, tag: String): T? {
val player = findAvailablePlayer(allowReserved)
return if (player == null && pool.size < getMaximumAllowed(allowReserved)) {
val newPlayer = createPlayer()
val poolState = createPoolStateForNewEntry(allowReserved)
val poolState = createPoolStateForNewEntry(allowReserved, tag)
pool[newPlayer] = poolState
newPlayer
} else if (player != null) {
val poolState = pool[player]!!.copy(available = false)
val poolState = pool[player]!!.copy(available = false, tag = tag)
pool[player] = poolState
player
} else {
Log.d(TAG, "Failed to get an ExoPlayer instance for tag: $tag")
null
}
}
@ -140,11 +146,11 @@ abstract class ExoPlayerPool<T : ExoPlayer>(
return if (allowReserved) getMaxSimultaneousPlayback() else getMaxSimultaneousPlayback() - maximumReservedPlayers
}
private fun createPoolStateForNewEntry(allowReserved: Boolean): PoolState {
private fun createPoolStateForNewEntry(allowReserved: Boolean, tag: String?): PoolState {
return if (allowReserved && pool.none { (_, v) -> v.reserved }) {
PoolState(available = false, reserved = true)
PoolState(available = false, reserved = true, tag = tag)
} else {
PoolState(available = false, reserved = false)
PoolState(available = false, reserved = false, tag = tag)
}
}
@ -175,39 +181,51 @@ abstract class ExoPlayerPool<T : ExoPlayer>(
}
private fun poolStats(): String {
return getPoolStats().toString()
}
fun getPoolStats(): PoolStats {
val poolStats = PoolStats(
created = pool.size,
maxUnreserved = getMaxSimultaneousPlayback() - maximumReservedPlayers,
maxReserved = maximumReservedPlayers
maxReserved = maximumReservedPlayers,
owners = emptyList()
)
pool.values.fold(poolStats) { acc, state ->
return pool.values.fold(poolStats) { acc, state ->
Log.d(TAG, "$state")
acc.copy(
unreservedAndAvailable = acc.unreservedAndAvailable + if (state.unreservedAndAvailable) 1 else 0,
reservedAndAvailable = acc.reservedAndAvailable + if (state.reservedAndAvailable) 1 else 0,
unreserved = acc.unreserved + if (!state.reserved) 1 else 0,
reserved = acc.reserved + if (state.reserved) 1 else 0
reserved = acc.reserved + if (state.reserved) 1 else 0,
owners = if (!state.available) acc.owners + OwnershipInfo(state.tag!!, state.reserved) else acc.owners
)
}
return poolStats.toString()
}
protected abstract fun getMaxSimultaneousPlayback(): Int
private data class PoolStats(
data class PoolStats(
val created: Int = 0,
val maxUnreserved: Int = 0,
val maxReserved: Int = 0,
val unreservedAndAvailable: Int = 0,
val reservedAndAvailable: Int = 0,
val unreserved: Int = 0,
val reserved: Int = 0
val reserved: Int = 0,
val owners: List<OwnershipInfo>
)
data class OwnershipInfo(
val tag: String,
val isReserved: Boolean
)
private data class PoolState(
val available: Boolean,
val reserved: Boolean
val reserved: Boolean,
val tag: String?
) {
val unreservedAndAvailable = available && !reserved
val reservedAndAvailable = available && reserved

Wyświetl plik

@ -18,7 +18,7 @@ class ExoPlayerPoolTest {
val testSubject = createTestSubject(1, 1)
// WHEN
val player = testSubject.require()
val player = testSubject.require("")
// THEN
assertNotNull(player)
@ -30,7 +30,7 @@ class ExoPlayerPoolTest {
val testSubject = createTestSubject(1, 0)
// WHEN
testSubject.require()
testSubject.require("")
// THEN
fail("Expected an IllegalStateException")
@ -42,8 +42,8 @@ class ExoPlayerPoolTest {
val testSubject = createTestSubject(0, 10)
// WHEN
val players = (1..10).map { testSubject.get() }
val nulls = (1..10).map { testSubject.get() }
val players = (1..10).map { testSubject.get("") }
val nulls = (1..10).map { testSubject.get("") }
// THEN
assertTrue(players.all { it != null })
@ -54,11 +54,11 @@ class ExoPlayerPoolTest {
fun `Given a pool that allows 10 items and has all items checked out, when I return then check them all out again, then I expect 10 non null players`() {
// GIVEN
val testSubject = createTestSubject(0, 10)
val players = (1..10).map { testSubject.get() }
val players = (1..10).map { testSubject.get("") }
// WHEN
players.filterNotNull().forEach { testSubject.pool(it) }
val morePlayers = (1..10).map { testSubject.get() }
val morePlayers = (1..10).map { testSubject.get("") }
assertTrue(morePlayers.all { it != null })
}