165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko/*
265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko * Copyright (C) 2016 The Android Open Source Project
365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko *
465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko * Licensed under the Apache License, Version 2.0 (the "License");
565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko * you may not use this file except in compliance with the License.
665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko * You may obtain a copy of the License at
765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko *
865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko *      http://www.apache.org/licenses/LICENSE-2.0
965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko *
1065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko * Unless required by applicable law or agreed to in writing, software
1165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko * distributed under the License is distributed on an "AS IS" BASIS,
1265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko * See the License for the specific language governing permissions and
1465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko * limitations under the License.
1565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko */
1665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
1765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkopackage com.android.tv.tuner.exoplayer.buffer;
1865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
1965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport android.support.annotation.Nullable;
2065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport android.support.annotation.VisibleForTesting;
2165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport android.util.Log;
2265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
2365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport com.google.android.exoplayer.SampleHolder;
2465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
2565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport java.io.File;
2665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport java.io.IOException;
2765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport java.io.RandomAccessFile;
2865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport java.nio.channels.FileChannel;
2965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
3065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko/**
3165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko * {@link SampleChunk} stores samples into file and makes them available for read.
3265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko * Stored file = { Header, Sample } * N
3365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko * Header = sample size : int, sample flag : int, sample PTS in micro second : long
3465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko */
3565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkopublic class SampleChunk {
3665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private static final String TAG = "SampleChunk";
3765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private static final boolean DEBUG = false;
3865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
3965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private final long mCreatedTimeMs;
4065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private final long mStartPositionUs;
4165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private SampleChunk mNextChunk;
4265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
4365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    // Header = sample size : int, sample flag : int, sample PTS in micro second : long
4465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private static final int SAMPLE_HEADER_LENGTH = 16;
4565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
4665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private final File mFile;
4765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private final ChunkCallback mChunkCallback;
4865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private final SamplePool mSamplePool;
4965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private RandomAccessFile mAccessFile;
5065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private long mWriteOffset;
5165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private boolean mWriteFinished;
5265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private boolean mIsReading;
5365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private boolean mIsWriting;
5465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
5565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    /**
5665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     * A callback for chunks being committed to permanent storage.
5765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     */
5865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    public static abstract class ChunkCallback {
5965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
6065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        /**
6165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         * Notifies when writing a SampleChunk is completed.
6265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         *
6365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         * @param chunk SampleChunk which is written completely
6465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         */
6565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        public void onChunkWrite(SampleChunk chunk) {
6665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
6765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
6865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
6965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        /**
7065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         * Notifies when a SampleChunk is deleted.
7165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         *
7265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         * @param chunk SampleChunk which is deleted from storage
7365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         */
7465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        public void onChunkDelete(SampleChunk chunk) {
7565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
7665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
7765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
7865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    /**
7965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     * A class for SampleChunk creation.
8065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     */
8165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    public static class SampleChunkCreator {
8265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
8365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        /**
8465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         * Returns a newly created SampleChunk to read & write samples.
8565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         *
8665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         * @param samplePool sample allocator
8765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         * @param file filename which will be created newly
8865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         * @param startPositionUs the start position of the earliest sample to be stored
8965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         * @param chunkCallback for total storage usage change notification
9065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         */
9165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        SampleChunk createSampleChunk(SamplePool samplePool, File file,
9265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                long startPositionUs, ChunkCallback chunkCallback) {
9365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            return new SampleChunk(samplePool, file, startPositionUs, System.currentTimeMillis(),
9465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                    chunkCallback);
9565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
9665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
9765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        /**
9865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         * Returns a newly created SampleChunk which is backed by an existing file.
9965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         * Created SampleChunk is read-only.
10065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         *
10165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         * @param samplePool sample allocator
10265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         * @param bufferDir the directory where the file to read is located
10365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         * @param filename the filename which will be read afterwards
10465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         * @param startPositionUs the start position of the earliest sample in the file
10565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         * @param chunkCallback for total storage usage change notification
10665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         * @param prev the previous SampleChunk just before the newly created SampleChunk
10765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         * @throws IOException
10865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         */
10965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        SampleChunk loadSampleChunkFromFile(SamplePool samplePool, File bufferDir,
11065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                String filename, long startPositionUs, ChunkCallback chunkCallback,
11165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                SampleChunk prev) throws IOException {
11265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            File file = new File(bufferDir, filename);
11365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            SampleChunk chunk =
11465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                    new SampleChunk(samplePool, file, startPositionUs, chunkCallback);
11565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            if (prev != null) {
11665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                prev.mNextChunk = chunk;
11765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            }
11865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            return chunk;
11965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
12065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
12165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
12265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    /**
12365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     * Handles I/O for SampleChunk.
12465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     * Maintains current SampleChunk and the current offset for next I/O operation.
12565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     */
12665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    static class IoState {
12765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        private SampleChunk mChunk;
12865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        private long mCurrentOffset;
12965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
13065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        private boolean equals(SampleChunk chunk, long offset) {
13165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            return chunk == mChunk && mCurrentOffset == offset;
13265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
13365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
13465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        /**
13565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         * Returns whether read I/O operation is finished.
13665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         */
13765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        boolean isReadFinished() {
13865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            return mChunk == null;
13965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
14065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
14165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        /**
14265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         * Returns the start position of the current SampleChunk
14365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         */
14465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        long getStartPositionUs() {
14565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            return mChunk == null ? 0 : mChunk.getStartPositionUs();
14665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
14765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
14865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        private void reset(@Nullable SampleChunk chunk) {
14965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            mChunk = chunk;
15065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            mCurrentOffset = 0;
15165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
15265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
1536ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        private void reset(SampleChunk chunk, long offset) {
1546ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            mChunk = chunk;
1556ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            mCurrentOffset = offset;
1566ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        }
1576ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
15865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        /**
15965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         * Prepares for read I/O operation from a new SampleChunk.
16065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         *
16165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         * @param chunk the new SampleChunk to read from
16265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         * @throws IOException
16365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         */
1646ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        void openRead(SampleChunk chunk, long offset) throws IOException {
16565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            if (mChunk != null) {
16665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                mChunk.closeRead();
16765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            }
16865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            chunk.openRead();
1696ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            reset(chunk, offset);
17065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
17165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
17265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        /**
17365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         * Prepares for write I/O operation to a new SampleChunk.
17465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         *
17565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         * @param chunk the new SampleChunk to write samples afterwards
17665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         * @throws IOException
17765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         */
17865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        void openWrite(SampleChunk chunk) throws IOException{
17965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            if (mChunk != null) {
18065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                mChunk.closeWrite(chunk);
18165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            }
18265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            chunk.openWrite();
18365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            reset(chunk);
18465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
18565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
18665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        /**
18765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         * Reads a sample if it is available.
18865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         *
18965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         * @return Returns a sample if it is available, null otherwise.
19065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         * @throws IOException
19165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         */
19265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        SampleHolder read() throws IOException {
19365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            if (mChunk != null && mChunk.isReadFinished(this)) {
19465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                SampleChunk next = mChunk.mNextChunk;
19565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                mChunk.closeRead();
19665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                if (next != null) {
19765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                    next.openRead();
19865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                }
19965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                reset(next);
20065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            }
20165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            if (mChunk != null) {
20265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                try {
20365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                    return mChunk.read(this);
20465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                } catch (IllegalStateException e) {
20565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                    // Write is finished and there is no additional buffer to read.
20665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                    Log.w(TAG, "Tried to read sample over EOS.");
20765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                    return null;
20865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                }
20965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            } else {
21065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                return null;
21165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            }
21265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
21365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
21465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        /**
21565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         * Writes a sample.
21665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         *
21765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         * @param sample to write
21865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         * @param nextChunk if this is {@code null} writes at the current SampleChunk,
21965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         *             otherwise close current SampleChunk and writes at this
22065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         * @throws IOException
22165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         */
22265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        void write(SampleHolder sample, SampleChunk nextChunk)
22365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                throws IOException {
22465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            if (nextChunk != null) {
22565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                if (mChunk == null || mChunk.mNextChunk != null) {
22665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                    throw new IllegalStateException("Requested write for wrong SampleChunk");
22765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                }
22865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                mChunk.closeWrite(nextChunk);
22965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                mChunk.mChunkCallback.onChunkWrite(mChunk);
23065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                nextChunk.openWrite();
23165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                reset(nextChunk);
23265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            }
23365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            mChunk.write(sample, this);
23465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
23565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
23665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        /**
23765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         * Finishes write I/O operation.
23865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         *
23965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         * @throws IOException
24065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         */
24165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        void closeWrite() throws IOException {
24265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            if (mChunk != null) {
24365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                mChunk.closeWrite(null);
24465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            }
24565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
24665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
24765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        /**
2486ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko         * Returns the current SampleChunk for subsequent I/O operation.
2496ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko         */
2506ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        SampleChunk getChunk() {
2516ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            return mChunk;
2526ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        }
2536ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
2546ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        /**
2556ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko         * Returns the current offset of the current SampleChunk for subsequent I/O operation.
2566ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko         */
2576ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        long getOffset() {
2586ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            return mCurrentOffset;
2596ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        }
2606ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
2616ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        /**
26265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         * Releases SampleChunk. the SampleChunk will not be used anymore.
26365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         *
26465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         * @param chunk to release
26565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         * @param delete {@code true} when the backed file needs to be deleted,
26665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         *        {@code false} otherwise.
26765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko         */
26865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        static void release(SampleChunk chunk, boolean delete) {
26965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            chunk.release(delete);
27065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
27165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
27265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
27365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    @VisibleForTesting
27465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    protected SampleChunk(SamplePool samplePool, File file, long startPositionUs,
27565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            long createdTimeMs, ChunkCallback chunkCallback) {
27665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mStartPositionUs = startPositionUs;
27765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mCreatedTimeMs = createdTimeMs;
27865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mSamplePool = samplePool;
27965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mFile = file;
28065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mChunkCallback = chunkCallback;
28165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
28265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
28365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    // Constructor of SampleChunk which is backed by the given existing file.
28465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private SampleChunk(SamplePool samplePool, File file, long startPositionUs,
28565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            ChunkCallback chunkCallback) throws IOException {
28665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mStartPositionUs = startPositionUs;
28765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mCreatedTimeMs = mStartPositionUs / 1000;
28865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mSamplePool = samplePool;
28965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mFile = file;
29065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mChunkCallback = chunkCallback;
29165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mWriteFinished = true;
29265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
29365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
29465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private void openRead() throws IOException {
29565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (!mIsReading) {
29665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            if (mAccessFile == null) {
29765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                mAccessFile = new RandomAccessFile(mFile, "r");
29865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            }
29965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            if (mWriteFinished && mWriteOffset == 0) {
30065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                // Lazy loading of write offset, in order not to load
30165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                // all SampleChunk's write offset at start time of recorded playback.
30265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                mWriteOffset = mAccessFile.length();
30365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            }
30465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            mIsReading = true;
30565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
30665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
30765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
30865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private void openWrite() throws IOException {
30965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (mWriteFinished) {
31065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            throw new IllegalStateException("Opened for write though write is already finished");
31165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
31265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (!mIsWriting) {
31365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            if (mIsReading) {
31465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                throw new IllegalStateException("Write is requested for "
31565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                        + "an already opened SampleChunk");
31665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            }
31765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            mAccessFile = new RandomAccessFile(mFile, "rw");
31865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            mIsWriting = true;
31965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
32065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
32165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
32265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private void CloseAccessFileIfNeeded() throws IOException {
32365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (!mIsReading && !mIsWriting) {
32465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            try {
32565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                if (mAccessFile != null) {
32665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                    mAccessFile.close();
32765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                }
32865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            } finally {
32965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                mAccessFile = null;
33065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            }
33165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
33265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
33365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
33465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private void closeRead() throws IOException{
33565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (mIsReading) {
33665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            mIsReading = false;
33765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            CloseAccessFileIfNeeded();
33865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
33965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
34065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
34165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private void closeWrite(SampleChunk nextChunk)
34265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            throws IOException {
34365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (mIsWriting) {
34465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            mNextChunk = nextChunk;
34565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            mIsWriting = false;
34665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            mWriteFinished = true;
34765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            CloseAccessFileIfNeeded();
34865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
34965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
35065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
35165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private boolean isReadFinished(IoState state) {
35265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        return mWriteFinished && state.equals(this, mWriteOffset);
35365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
35465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
35565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private SampleHolder read(IoState state) throws IOException {
35665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (mAccessFile == null || state.mChunk != this) {
35765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            throw new IllegalStateException("Requested read for wrong SampleChunk");
35865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
35965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        long offset = state.mCurrentOffset;
36065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (offset >= mWriteOffset) {
36165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            if (mWriteFinished) {
36265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                throw new IllegalStateException("Requested read for wrong range");
36365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            } else {
36465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                if (offset != mWriteOffset) {
36565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                    Log.e(TAG, "This should not happen!");
36665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                }
36765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                return null;
36865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            }
36965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
37065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mAccessFile.seek(offset);
37165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        int size = mAccessFile.readInt();
37265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        SampleHolder sample = mSamplePool.acquireSample(size);
37365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        sample.size = size;
37465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        sample.flags = mAccessFile.readInt();
37565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        sample.timeUs = mAccessFile.readLong();
37665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        sample.clearData();
37765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        sample.data.put(mAccessFile.getChannel().map(FileChannel.MapMode.READ_ONLY,
37865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                offset + SAMPLE_HEADER_LENGTH, sample.size));
37965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        offset += sample.size + SAMPLE_HEADER_LENGTH;
38065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        state.mCurrentOffset = offset;
38165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        return sample;
38265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
38365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
38465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    @VisibleForTesting
38565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    protected void write(SampleHolder sample, IoState state)
38665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            throws IOException {
38765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (mAccessFile == null || mNextChunk != null || !state.equals(this, mWriteOffset)) {
38865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            throw new IllegalStateException("Requested write for wrong SampleChunk");
38965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
39065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
39165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mAccessFile.seek(mWriteOffset);
39265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mAccessFile.writeInt(sample.size);
39365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mAccessFile.writeInt(sample.flags);
39465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mAccessFile.writeLong(sample.timeUs);
39565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        sample.data.position(0).limit(sample.size);
39665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mAccessFile.getChannel().position(mWriteOffset + SAMPLE_HEADER_LENGTH).write(sample.data);
39765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mWriteOffset += sample.size + SAMPLE_HEADER_LENGTH;
39865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        state.mCurrentOffset = mWriteOffset;
39965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
40065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
40165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private void release(boolean delete) {
40265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mWriteFinished = true;
40365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mIsReading = mIsWriting = false;
40465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        try {
40565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            if (mAccessFile != null) {
40665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                mAccessFile.close();
40765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            }
40865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        } catch (IOException e) {
40965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            // Since the SampleChunk will not be reused, ignore exception.
41065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
41165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (delete) {
41265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            mFile.delete();
41365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            mChunkCallback.onChunkDelete(this);
41465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
41565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
41665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
41765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    /**
41865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     * Returns the start position.
41965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     */
42065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    public long getStartPositionUs() {
42165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        return mStartPositionUs;
42265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
42365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
42465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    /**
42565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     * Returns the creation time.
42665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     */
42765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    public long getCreatedTimeMs() {
42865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        return mCreatedTimeMs;
42965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
43065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
43165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    /**
43265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     * Returns the current size.
43365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     */
43465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    public long getSize() {
43565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        return mWriteOffset;
43665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
43765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko}
438