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 mNumOfSeekIteration; 34 private long mSeekTimeUs; 35 private final long mSeed; 36 private boolean mSeekDone; 37 SeekTestPlayerListener(int numOfSeekIteration, long seekTimeUs, long sendMessagePosition)38 public SeekTestPlayerListener(int numOfSeekIteration, long seekTimeUs, 39 long sendMessagePosition) { 40 super(); 41 this.mNumOfSeekIteration = numOfSeekIteration; 42 this.mSeekTimeUs = seekTimeUs; 43 this.mSeed = getSeed(); 44 this.mSendMessagePosition = sendMessagePosition; 45 } 46 47 /** 48 * Returns seed for Seek test. 49 */ getSeed()50 private long getSeed() { 51 // Truncate time to the nearest day. 52 long seed = Clock.tick(Clock.systemUTC(), Duration.ofDays(1)).instant().toEpochMilli(); 53 Log.d(LOG_TAG, "Random seed = " + seed); 54 return seed; 55 } 56 57 /** 58 * Seek the player. 59 */ seek()60 private void seek() { 61 Random random = new Random(mSeed); 62 // If number of seek requested is one then seek forward or backward alternatively for 63 // mSeekTimeUs on given media list. 64 // If number of seek requested is 30 then seek for mSeekTimeUs- forward 10 times, 65 // backward 10 times and then randomly backwards or forwards 10 times on each 66 // media item. 67 for (int i = 0; i < mNumOfSeekIteration; i++) { 68 mActivity.mPlayer.seekTo(mActivity.mPlayer.getCurrentPosition() + mSeekTimeUs); 69 if (mNumOfSeekIteration == 1 || i == 10) { 70 mSeekTimeUs *= -1; 71 } else if (i >= 20) { 72 mSeekTimeUs *= random.nextBoolean() ? -1 : 1; 73 } 74 } 75 mSeekDone = true; 76 } 77 78 @Override getTestType()79 public TestType getTestType() { 80 return TestType.SEEK_TEST; 81 } 82 83 @Override onEventsPlaybackStateChanged(@onNull Player player)84 public void onEventsPlaybackStateChanged(@NonNull Player player) { 85 if (player.getPlaybackState() == Player.STATE_READY) { 86 // Add change in duration due to seek 87 if (mSeekDone) { 88 mExpectedTotalTime += (mSendMessagePosition - player.getCurrentPosition()); 89 mSeekDone = false; 90 } else { 91 // At the first media transition player is not ready. So, add duration of 92 // first clip when player is ready 93 mExpectedTotalTime += player.getDuration(); 94 } 95 } 96 } 97 98 @Override onEventsMediaItemTransition(@onNull Player player)99 public void onEventsMediaItemTransition(@NonNull Player player) { 100 mActivity.mPlayer.createMessage((messageType, payload) -> { 101 seek(); 102 }).setLooper(Looper.getMainLooper()).setPosition(mSendMessagePosition) 103 .setDeleteAfterDelivery(true) 104 .send(); 105 } 106 } 107