package com.suno.android.media.player.pool import androidx.media3.common.Player import com.suno.android.common_core_utils.Id import com.suno.android.common_core_utils.SunoLogger import com.suno.android.media.player.PlayerFactory import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject /** * Represents a slot in the player pool that can hold a Player instance. * Tracks assignment state, access time for LRU eviction, and manages player lifecycle. * * @param poolIndex The slot's position in the pool array */ class PlayerSlot @AssistedInject constructor( loggerFactory: SunoLogger.Factory, @Assisted private val poolIndex: Int, ) { private val logger = loggerFactory.create(this@PlayerSlot) /** * The player instance held by this slot, null if no player is created yet */ var player: Player? = null private set /** * The media ID currently assigned to this slot */ var mediaId: Id? = null private set /** * Position of the media item for position-aware eviction policy */ var mediaIndex: Int? = null private set /** * Assigns this slot to a media ID, creating or reusing a player instance. * Resets existing player state if reusing. */ fun assignSlot( mediaId: Id, mediaIndex: Int, playerFactory: PlayerFactory, ): Result { this.mediaId = mediaId this.mediaIndex = mediaIndex return runCatching { val assignedPlayer = player?.apply { reset() } ?: playerFactory.create().also { logger.d { "Player slot $poolIndex - created new player" } player = it } assignedPlayer.also { logger.d { "Player slot $poolIndex - assigned to mediaId: ${mediaId.value}" } } }.onFailure { e -> this.mediaId = null this.mediaIndex = null logger.e(e) { "Player slot $poolIndex - error assigning to mediaId: ${mediaId.value}" } } } /** * Resets the slot state while keeping the player instance for reuse. */ fun resetSlot() { player?.reset() mediaId = null mediaIndex = null logger.d { "Player slot $poolIndex - reset slot" } } /** * Completely releases the slot, disposing of the player instance. */ fun releaseSlot() { player?.release() player = null mediaId = null mediaIndex = null logger.d { "Player slot $poolIndex - released slot" } } private fun Player.reset() { stop() clearMediaItems() clearVideoSurface() } override fun toString(): String = "PlayerSlot(poolIndex=$poolIndex, mediaId=$mediaId, mediaIndex=$mediaIndex)" @AssistedFactory interface Factory { fun create( index: Int, ): PlayerSlot } }