Skip to content

Commit

Permalink
Preserve playback speed between videos
Browse files Browse the repository at this point in the history
- Update the PlaybackController to internally track the last playback
speed, but still treat it as a black box from all external callers
- Add a test we don't throw a NPE trying to set it before init
- There's no test for checking this value gets forwarded (see below)
- Change the activity to create the speed controller whilst the
ControlGlue is being created.

This is unfortunately a bit of a hack. There isn't a signal for
onPlaybackStarted or similar we can attach to from the playback
controller so we have to mess with the internals. Something I've tried
to avoid greatly.

I've tried adding a unit test with mocks, which was surprisingly going
well. Until we create LibVLC objects mid-way. These needs some sort of
factory pattern to inject mocks else it will query Android for playback
capabilities failing the test.

I'm going to leave this particular test as a manual case as I extracting
factories out with the pending rewrite is a futile effort.
  • Loading branch information
DavidFair committed Dec 23, 2021
1 parent 51e094b commit b3b0a39
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ public class PlaybackController {
private VideoOptions mCurrentOptions;
private int mDefaultSubIndex = -1;
private int mDefaultAudioIndex = -1;
private double mRequestedPlaybackSpeed = -1.0;

private PlayMethod mPlaybackMethod = PlayMethod.Transcode;

Expand Down Expand Up @@ -154,7 +155,10 @@ public void setPlaybackMethod(PlayMethod value) {
}

public void setPlaybackSpeed(Double speed){
mVideoManager.setPlaybackSpeed(speed);
mRequestedPlaybackSpeed = speed;
if (hasInitializedVideoManager()) {
mVideoManager.setPlaybackSpeed(speed);
}
}

public BaseItemDto getCurrentlyPlayingItem() {
Expand Down Expand Up @@ -676,6 +680,7 @@ private void startItem(BaseItemDto item, long position, StreamInfo response) {

// get subtitle info
mSubtitleStreams = response.GetSubtitleProfiles(false, apiClient.getValue().getApiUrl(), apiClient.getValue().getAccessToken());
mVideoManager.setPlaybackSpeed(mRequestedPlaybackSpeed);

if (mFragment != null) mFragment.updateDisplay();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ private void initActions(Context context) {
selectAudioAction.setLabels(new String[]{context.getString(R.string.lbl_audio_track)});
closedCaptionsAction = new ClosedCaptionsAction(context, this);
closedCaptionsAction.setLabels(new String[]{context.getString(R.string.lbl_subtitle_track)});
playbackSpeedAction = new PlaybackSpeedAction(context, this);
playbackSpeedAction = new PlaybackSpeedAction(context, this, playbackController);
playbackSpeedAction.setLabels(new String[]{context.getString(R.string.lbl_playback_speed)});
adjustAudioDelayAction = new AdjustAudioDelayAction(context, this);
adjustAudioDelayAction.setLabels(new String[]{context.getString(R.string.lbl_audio_delay)});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ import org.jellyfin.androidtv.ui.playback.VideoSpeedController

class PlaybackSpeedAction(
context: Context,
customPlaybackTransportControlGlue: CustomPlaybackTransportControlGlue
customPlaybackTransportControlGlue: CustomPlaybackTransportControlGlue,
playbackController: PlaybackController
) : CustomAction(context, customPlaybackTransportControlGlue) {
private val speedController = VideoSpeedController(playbackController)
private val speeds = VideoSpeedController.Companion.SpeedSteps.values()

init {
Expand All @@ -26,11 +28,10 @@ class PlaybackSpeedAction(
leanbackOverlayFragment: LeanbackOverlayFragment,
context: Context, view: View
) {
val speedController = VideoSpeedController(playbackController)
val speedMenu = populateMenu(context, view, speedController)

speedMenu.setOnDismissListener { leanbackOverlayFragment.setFading(true) }

speedMenu.setOnMenuItemClickListener { menuItem ->
speedController.setNewSpeed(speeds[menuItem.itemId])
speedMenu.dismiss()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ import io.mockk.*
import org.jellyfin.androidtv.preference.Preference
import org.jellyfin.androidtv.preference.UserPreferences
import org.jellyfin.androidtv.preference.constant.PreferredVideoPlayer
import org.jellyfin.androidtv.util.Utils
import org.jellyfin.apiclient.interaction.ApiClient
import org.jellyfin.apiclient.model.dto.BaseItemDto
import org.jellyfin.apiclient.model.dto.BaseItemType
import org.jellyfin.apiclient.model.entities.LocationType
import org.jellyfin.apiclient.model.library.PlayAccess
import org.junit.After
import org.junit.Assert.*
import org.junit.Before
Expand All @@ -17,21 +22,26 @@ import org.koin.test.KoinTest

class PlaybackControllerTest : KoinTest {
// Mockk managed deps
private val mockBaseItems = mockk<List<BaseItemDto>>()
private val mockBaseItems = listOf(mockk<BaseItemDto>())
private val mockFragment = mockk<IPlaybackOverlayFragment>()

lateinit var playbackController: PlaybackController

// Koin managed modules
lateinit var mockApiClient: ApiClient
lateinit var mockUserPreferences: UserPreferences

private fun prepDiMocks(): Module {
mockApiClient = mockk(relaxed = true)
mockUserPreferences = mockk(relaxed = true)

// Required in the constructor
every {
mockUserPreferences.get(any<Preference<PreferredVideoPlayer>>())
} returns PreferredVideoPlayer.EXOPLAYER

return module {
single<ApiClient> { mockApiClient }
single<UserPreferences> { mockUserPreferences }
}
}
Expand All @@ -58,9 +68,17 @@ class PlaybackControllerTest : KoinTest {
doubleArrayOf(0.25, 0.5, 1.0, 2.5, 200.0).forEach { i ->
val mockVideoManager = mockk<VideoManager>(relaxed = true)
playbackController.mVideoManager = mockVideoManager
every { mockVideoManager.isInitialized } returns true

playbackController.setPlaybackSpeed(i)

verify { mockVideoManager.setPlaybackSpeed(i) }
}
}

@Test
fun testSetupPlaybackSpeedHandlesNoVideo() {
playbackController.mVideoManager = null
playbackController.setPlaybackSpeed(2.0)
}
}

0 comments on commit b3b0a39

Please sign in to comment.