148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho/* 248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho * Copyright (C) 2016 The Android Open Source Project 348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho * 448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho * Licensed under the Apache License, Version 2.0 (the "License"); 548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho * you may not use this file except in compliance with the License. 648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho * You may obtain a copy of the License at 748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho * 848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho * http://www.apache.org/licenses/LICENSE-2.0 948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho * 1048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho * Unless required by applicable law or agreed to in writing, software 1148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho * distributed under the License is distributed on an "AS IS" BASIS, 1248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho * See the License for the specific language governing permissions and 1448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho * limitations under the License. 1548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho */ 1648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 1748dadb49248271b01997862e1335912a4f2e189fYoungsang Chopackage com.android.usbtuner.exoplayer.cache; 1848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 1948dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport android.media.MediaCodec; 2048dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport android.media.MediaFormat; 2148dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport android.os.ConditionVariable; 2248dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport android.support.annotation.IntDef; 2348dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport android.util.Log; 2448dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport android.util.Pair; 2548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 2648dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport com.google.android.exoplayer.C; 2748dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport com.google.android.exoplayer.SampleHolder; 2848dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport com.google.android.exoplayer.SampleSource; 2948dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport com.google.android.exoplayer.util.MimeTypes; 3048dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport com.android.usbtuner.tvinput.PlaybackCacheListener; 3148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 3248dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport java.io.IOException; 3348dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport java.lang.annotation.Retention; 3448dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport java.lang.annotation.RetentionPolicy; 3548dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport java.util.List; 3648dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport java.util.concurrent.TimeUnit; 3748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 3848dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport junit.framework.Assert; 3948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 4048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho/** 4148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho * Handles I/O between {@link com.android.usbtuner.exoplayer.SampleExtractor} and 4248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho * {@link CacheManager}.Reads & writes samples from/to {@link SampleCache} which is backed 4348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho * by physical storage. 4448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho */ 4548dadb49248271b01997862e1335912a4f2e189fYoungsang Chopublic class RecordingSampleBuffer implements CacheManager.SampleBuffer, 4648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho CacheManager.EvictListener { 4748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private static final String TAG = "RecordingSampleBuffer"; 4848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private static final boolean DEBUG = false; 4948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 5048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho @IntDef({CACHE_REASON_LIVE_PLAYBACK, CACHE_REASON_RECORDED_PLAYBACK, CACHE_REASON_RECORDING}) 5148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho @Retention(RetentionPolicy.SOURCE) 5248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public @interface CacheReason {} 5348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 5448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho /** 5548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho * A cache reason for live-stream playback. 5648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho */ 5748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public static final int CACHE_REASON_LIVE_PLAYBACK = 0; 5848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 5948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho /** 6048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho * A cache reason for playback of a recorded program. 6148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho */ 6248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public static final int CACHE_REASON_RECORDED_PLAYBACK = 1; 6348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 6448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho /** 6548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho * A cache reason for recording a program. 6648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho */ 6748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public static final int CACHE_REASON_RECORDING = 2; 6848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 6948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private static final long CACHE_WRITE_TIMEOUT_MS = 10 * 1000; // 10 seconds 7048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private static final long CHUNK_DURATION_US = TimeUnit.MILLISECONDS.toMicros(500); 7148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private static final long LIVE_THRESHOLD_US = TimeUnit.SECONDS.toMicros(1); 7248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 7348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private final CacheManager mCacheManager; 7448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private final PlaybackCacheListener mCacheListener; 7548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private final int mCacheReason; 7648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 7748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private int mTrackCount; 7848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private List<String> mIds; 7948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private List<MediaFormat> mMediaFormats; 8048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private volatile long mCacheDurationUs = 0; 8148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private long[] mCacheEndPositionUs; 8248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho // SampleCache to append the latest live sample. 8348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private SampleCache[] mSampleCaches; 8448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private CachedSampleQueue[] mPlayingSampleQueues; 8548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private final SamplePool mSamplePool = new SamplePool(); 8648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private long mLastBufferedPositionUs = C.UNKNOWN_TIME_US; 8748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private long mCurrentPlaybackPositionUs = 0; 8848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private boolean mEos = false; 8948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 9048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private class CachedSampleQueue extends SampleQueue { 9148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private SampleCache mCache = null; 9248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 9348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public CachedSampleQueue(SamplePool samplePool) { 9448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho super(samplePool); 9548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 9648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 9748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public void setSource(SampleCache newCache) { 9848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho for (SampleCache cache = mCache; cache != null; cache = cache.getNext()) { 9948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho cache.clear(); 10048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho cache.close(); 10148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 10248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mCache = newCache; 10348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho for (SampleCache cache = mCache; cache != null; cache = cache.getNext()) { 10448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho cache.resetRead(); 10548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 10648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 10748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 10848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public boolean maybeReadSample() { 10948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (isDurationGreaterThan(CHUNK_DURATION_US)) { 11048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho return false; 11148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 11248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho SampleHolder sample = mCache.maybeReadSample(); 11348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (sample == null) { 11448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (!mCache.canReadMore() && mCache.getNext() != null) { 11548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mCache.clear(); 11648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mCache.close(); 11748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mCache = mCache.getNext(); 11848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mCache.resetRead(); 11948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho return maybeReadSample(); 12048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } else { 12148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (mCacheReason == CACHE_REASON_RECORDED_PLAYBACK 12248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho && !mCache.canReadMore() && mCache.getNext() == null) { 12348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho // At the end of the recorded playback. 12448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho setEos(); 12548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 12648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho return false; 12748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 12848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } else { 12948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho queueSample(sample); 13048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho return true; 13148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 13248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 13348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 13448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public int dequeueSample(SampleHolder sample) { 13548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho maybeReadSample(); 13648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho return super.dequeueSample(sample); 13748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 13848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 13948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho @Override 14048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public void clear() { 14148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho super.clear(); 14248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho for (SampleCache cache = mCache; cache != null; cache = cache.getNext()) { 14348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho cache.clear(); 14448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho cache.close(); 14548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 14648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mCache = null; 14748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 14848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 14948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public long getSourceStartPositionUs() { 15048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho return mCache == null ? -1 : mCache.getStartPositionUs(); 15148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 15248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 15348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 15448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho /** 15548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho * Creates {@link com.android.usbtuner.exoplayer.cache.CacheManager.SampleBuffer} with 15648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho * cached I/O backed by physical storage (e.g. trickplay,recording,recorded-playback). 15748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho * 15848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho * @param cacheManager 15948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho * @param cacheListener 16048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho * @param enableTrickplay {@code true} when trickplay should be enabled 16148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho * @param cacheReason the reason for caching samples {@link RecordingSampleBuffer.CacheReason} 16248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho */ 16348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public RecordingSampleBuffer(CacheManager cacheManager, PlaybackCacheListener cacheListener, 16448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho boolean enableTrickplay, @CacheReason int cacheReason) { 16548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mCacheManager = cacheManager; 16648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mCacheListener = cacheListener; 16748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (cacheListener != null) { 16848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho cacheListener.onCacheStateChanged(enableTrickplay); 16948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 17048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mCacheReason = cacheReason; 17148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 17248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 17348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private String getTrackId(int index) { 17448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho return mIds.get(index); 17548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 17648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 17748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho @Override 17848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public synchronized void init(List<String> ids, List<MediaFormat> mediaFormats) 17948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho throws IOException { 18048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mTrackCount = ids.size(); 18148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (mTrackCount <= 0) { 18248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho throw new IOException("No tracks to initialize"); 18348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 18448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mIds = ids; 18548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (mCacheReason == CACHE_REASON_RECORDING && mediaFormats == null) { 18648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho throw new IOException("MediaFormat is not provided."); 18748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 18848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mMediaFormats = mediaFormats; 18948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mSampleCaches = new SampleCache[mTrackCount]; 19048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mPlayingSampleQueues = new CachedSampleQueue[mTrackCount]; 19148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mCacheEndPositionUs = new long[mTrackCount]; 19248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho for (int i = 0; i < mTrackCount; i++) { 19348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (mCacheReason != CACHE_REASON_RECORDED_PLAYBACK) { 19448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mSampleCaches[i] = mCacheManager.createNewWriteFile(getTrackId(i), 0, mSamplePool); 19548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mPlayingSampleQueues[i] = null; 19648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mCacheEndPositionUs[i] = CHUNK_DURATION_US; 19748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } else { 19848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mCacheManager.loadTrackFormStorage(mIds.get(i), mSamplePool); 19948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 20048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 20148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 20248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 20348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private boolean isLiveLocked(long positionUs) { 20448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho Long livePositionUs = null; 20548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho for (SampleCache cache : mSampleCaches) { 20648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (livePositionUs == null || livePositionUs < cache.getEndPositionUs()) { 20748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho livePositionUs = cache.getEndPositionUs(); 20848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 20948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 21048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho return (livePositionUs == null 21148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho || Math.abs(livePositionUs - positionUs) < LIVE_THRESHOLD_US); 21248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 21348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 21448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private void seekIndividualTrackLocked(int index, long positionUs, boolean isLive) { 21548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho CachedSampleQueue queue = mPlayingSampleQueues[index]; 21648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (queue == null) { 21748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho return; 21848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 21948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho queue.clear(); 22048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (isLive) { 22148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho queue.setSource(mSampleCaches[index]); 22248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } else { 22348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho queue.setSource(mCacheManager.getReadFile(getTrackId(index), positionUs)); 22448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 22548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho queue.maybeReadSample(); 22648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 22748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 22848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho @Override 22948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public synchronized void selectTrack(int index) { 23048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (mPlayingSampleQueues[index] == null) { 23148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho String trackId = getTrackId(index); 23248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mPlayingSampleQueues[index] = new CachedSampleQueue(mSamplePool); 23348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mCacheManager.registerEvictListener(trackId, this); 23448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho seekIndividualTrackLocked(index, mCurrentPlaybackPositionUs, 23548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mCacheReason != CACHE_REASON_RECORDED_PLAYBACK && isLiveLocked( 23648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mCurrentPlaybackPositionUs)); 23748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mPlayingSampleQueues[index].maybeReadSample(); 23848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 23948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 24048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 24148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho @Override 24248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public synchronized void deselectTrack(int index) { 24348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (mPlayingSampleQueues[index] != null) { 24448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mPlayingSampleQueues[index].clear(); 24548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mPlayingSampleQueues[index] = null; 24648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mCacheManager.unregisterEvictListener(getTrackId(index)); 24748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 24848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 24948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 25048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho @Override 25148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public void writeSample(int index, SampleHolder sample, 25248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho ConditionVariable conditionVariable) throws IOException { 25348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho synchronized (this) { 25448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho SampleCache cache = mSampleCaches[index]; 25548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if ((sample.flags & MediaCodec.BUFFER_FLAG_KEY_FRAME) != 0) { 25648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (sample.timeUs > mCacheDurationUs) { 25748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mCacheDurationUs = sample.timeUs; 25848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 25948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (sample.timeUs >= mCacheEndPositionUs[index]) { 26048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho try { 26148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho SampleCache nextCache = mCacheManager.createNewWriteFile( 26248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho getTrackId(index), mCacheEndPositionUs[index], mSamplePool); 26348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho cache.finishWrite(nextCache); 26448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mSampleCaches[index] = cache = nextCache; 26548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mCacheEndPositionUs[index] = 26648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho ((sample.timeUs / CHUNK_DURATION_US) + 1) * CHUNK_DURATION_US; 26748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } catch (IOException e) { 26848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho cache.finishWrite(null); 26948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho throw e; 27048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 27148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 27248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 27348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho cache.writeSample(sample, conditionVariable); 27448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 27548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 27648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (!conditionVariable.block(CACHE_WRITE_TIMEOUT_MS)) { 27748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho Log.e(TAG, "Error: Serious delay on writing cache"); 27848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho conditionVariable.block(); 27948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 28048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 28148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 28248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho @Override 28348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public boolean isWriteSpeedSlow(int sampleSize, long writeDurationNs) { 28448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (mCacheReason == CACHE_REASON_RECORDED_PLAYBACK) { 28548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho return false; 28648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 28748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mCacheManager.addWriteStat(sampleSize, writeDurationNs); 28848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho return mCacheManager.isWriteSlow(); 28948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 29048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 29148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho @Override 29248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public void handleWriteSpeedSlow() { 29348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho Log.w(TAG, "Disk is too slow for trickplay. Disable trickplay."); 29448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mCacheManager.disable(); 29548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mCacheListener.onDiskTooSlow(); 29648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 29748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 29848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho @Override 29948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public synchronized void setEos() { 30048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mEos = true; 30148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 30248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 30348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private synchronized boolean reachedEos() { 30448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho return mEos; 30548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 30648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 30748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho @Override 30848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public synchronized int readSample(int track, SampleHolder sampleHolder) { 30948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho CachedSampleQueue queue = mPlayingSampleQueues[track]; 31048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho Assert.assertNotNull(queue); 31148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho queue.maybeReadSample(); 31248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho int result = queue.dequeueSample(sampleHolder); 31348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (result != SampleSource.SAMPLE_READ && reachedEos()) { 31448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho return SampleSource.END_OF_STREAM; 31548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 31648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho return result; 31748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 31848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 31948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho @Override 32048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public synchronized void seekTo(long positionUs) { 32148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho boolean isLive = mCacheReason != CACHE_REASON_RECORDED_PLAYBACK && isLiveLocked(positionUs); 32248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 32348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho // Seek video track first 32448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho for (int i = 0; i < mPlayingSampleQueues.length; ++i) { 32548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho CachedSampleQueue queue = mPlayingSampleQueues[i]; 32648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (queue == null) { 32748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho continue; 32848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 32948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho seekIndividualTrackLocked(i, positionUs, isLive); 33048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (DEBUG) { 33148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho Log.d(TAG, "start time = " + queue.getSourceStartPositionUs()); 33248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 33348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 33448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mLastBufferedPositionUs = positionUs; 33548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 33648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 33748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho @Override 33848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public synchronized long getBufferedPositionUs() { 33948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho Long result = null; 34048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho for (CachedSampleQueue queue : mPlayingSampleQueues) { 34148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (queue == null) { 34248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho continue; 34348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 34448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho Long bufferedPositionUs = queue.getEndPositionUs(); 34548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (bufferedPositionUs == null) { 34648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho continue; 34748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 34848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (result == null || result > bufferedPositionUs) { 34948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho result = bufferedPositionUs; 35048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 35148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 35248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (result == null) { 35348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho return mLastBufferedPositionUs; 35448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } else { 35548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho return (mLastBufferedPositionUs = result); 35648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 35748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 35848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 35948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho @Override 36048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public synchronized boolean continueBuffering(long positionUs) { 36148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho boolean hasSamples = true; 36248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mCurrentPlaybackPositionUs = positionUs; 36348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho for (CachedSampleQueue queue : mPlayingSampleQueues) { 36448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (queue == null) { 36548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho continue; 36648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 36748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho queue.maybeReadSample(); 36848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (queue.isEmpty()) { 36948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho hasSamples = false; 37048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 37148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 37248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho return hasSamples; 37348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 37448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 37548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho @Override 37648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public synchronized void release() { 37748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (mSampleCaches == null) { 37848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho return; 37948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 38048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (mCacheReason == CACHE_REASON_RECORDED_PLAYBACK) { 38148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mCacheManager.close(); 38248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 38348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho for (int i = 0; i < mTrackCount; ++i) { 38448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (mCacheReason != CACHE_REASON_RECORDED_PLAYBACK) { 38548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mSampleCaches[i].finishWrite(null); 38648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 38748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mCacheManager.unregisterEvictListener(getTrackId(i)); 38848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 38948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (mCacheReason == CACHE_REASON_RECORDING && mTrackCount > 0) { 39048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho // Saves meta information for recording. 39148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho Pair<String, android.media.MediaFormat> audio = null, video = null; 39248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho for (int i = 0; i < mTrackCount; ++i) { 39348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho MediaFormat mediaFormat = mMediaFormats.get(i); 39448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho String mime = mediaFormat.getString(MediaFormat.KEY_MIME); 39548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mediaFormat.setLong(android.media.MediaFormat.KEY_DURATION, mCacheDurationUs); 39648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (MimeTypes.isAudio(mime)) { 39748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho audio = new Pair<>(getTrackId(i), mediaFormat); 39848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 39948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho else if (MimeTypes.isVideo(mime)) { 40048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho video = new Pair<>(getTrackId(i), mediaFormat); 40148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 40248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 40348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mCacheManager.writeMetaFiles(audio, video); 40448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 40548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 40648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho for (int i = 0; i < mTrackCount; ++i) { 40748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mCacheManager.clearTrack(getTrackId(i)); 40848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 40948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 41048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 41148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho // CacheEvictListener 41248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho @Override 41348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public void onCacheEvicted(String id, long createdTimeMs) { 41448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (mCacheListener != null) { 41548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mCacheListener.onCacheStartTimeChanged( 41648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho createdTimeMs + TimeUnit.MICROSECONDS.toMillis(CHUNK_DURATION_US)); 41748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 41848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 41948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho} 420