1 /** 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.media.cujcommon.cts; 18 19 import android.os.Looper; 20 import android.util.Log; 21 22 import androidx.annotation.NonNull; 23 import androidx.media3.common.Player; 24 25 import java.time.Clock; 26 import java.time.Duration; 27 import java.util.Random; 28 29 public class SeekTestPlayerListener extends PlayerListener { 30 31 private static final String LOG_TAG = SeekTestPlayerListener.class.getSimpleName(); 32 33 private final int mNumOfSeekIterationsPerClip; 34 private Duration mSeekDuration; 35 private final long mSeed; 36 SeekTestPlayerListener(int numOfSeekIterationsPerClip, Duration seekDuration, Duration sendMessagePosition)37 public SeekTestPlayerListener(int numOfSeekIterationsPerClip, Duration seekDuration, 38 Duration sendMessagePosition) { 39 super(); 40 this.mNumOfSeekIterationsPerClip = numOfSeekIterationsPerClip; 41 this.mSeekDuration = seekDuration; 42 this.mSeed = getSeed(); 43 this.mSendMessagePosition = sendMessagePosition; 44 } 45 46 /** 47 * Returns seed for Seek test. 48 */ getSeed()49 private long getSeed() { 50 // Truncate time to the nearest day. 51 long seed = Clock.tick(Clock.systemUTC(), Duration.ofDays(1)).instant().toEpochMilli(); 52 Log.d(LOG_TAG, "Random seed = " + seed); 53 return seed; 54 } 55 56 /** 57 * Seek the player. 58 */ seek()59 private void seek() { 60 Random random = new Random(mSeed); 61 // In case of small test, number of seek requested (i.e. mNumOfSeekIterationsPerClip) is one 62 // per clip. We seek forward and backward alternatively for mSeekDuration for all the clips in 63 // the given media list. 64 // In case of large test, number of seek requested (i.e. mNumOfSeekIterationsPerClip) is 30 per 65 // clip. We seek forward 10 times, backward 10 times or vice-versa (i.e. backward 10 times and 66 // forward 10 times) and then randomly backwards or forwards 10 times for mSeekDuration for all 67 // the clips in the given media l̥ist. 68 for (int i = 0; i < mNumOfSeekIterationsPerClip; i++) { 69 mActivity.mPlayer.seekTo(mActivity.mPlayer.getCurrentPosition() + mSeekDuration.toMillis()); 70 // Update expected total time due to seek 71 mExpectedTotalTime -= mSeekDuration.toMillis(); 72 mTotalSeekOverhead = mTotalSeekOverhead.plus(CujTestBase.OVERHEAD_PER_SEEK); 73 if (mNumOfSeekIterationsPerClip == 1 || i == 9) { 74 mSeekDuration = mSeekDuration.multipliedBy(-1); 75 } else if (i >= 19) { 76 mSeekDuration = 77 random.nextBoolean() ? mSeekDuration.multipliedBy(-1) : mSeekDuration.multipliedBy(1); 78 } 79 } 80 } 81 82 @Override getTestType()83 public TestType getTestType() { 84 return TestType.SEEK_TEST; 85 } 86 87 @Override onEventsPlaybackStateChanged(@onNull Player player)88 public void onEventsPlaybackStateChanged(@NonNull Player player) { 89 if (mExpectedTotalTime == 0 && player.getPlaybackState() == Player.STATE_READY) { 90 // At the first media transition player is not ready. So, add duration of 91 // first clip when player is ready 92 mExpectedTotalTime += player.getDuration(); 93 } 94 } 95 96 @Override onEventsMediaItemTransition(@onNull Player player)97 public void onEventsMediaItemTransition(@NonNull Player player) { 98 mActivity.mPlayer.createMessage((messageType, payload) -> { 99 seek(); 100 }).setLooper(Looper.getMainLooper()).setPosition(mSendMessagePosition.toMillis()) 101 .setDeleteAfterDelivery(true) 102 .send(); 103 } 104 } 105