11abddd9f6225298066094e20a6c29061b6af4590Nick Chalko/*
21abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * Copyright (C) 2015 The Android Open Source Project
31abddd9f6225298066094e20a6c29061b6af4590Nick Chalko *
41abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * Licensed under the Apache License, Version 2.0 (the "License");
51abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * you may not use this file except in compliance with the License.
61abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * You may obtain a copy of the License at
71abddd9f6225298066094e20a6c29061b6af4590Nick Chalko *
81abddd9f6225298066094e20a6c29061b6af4590Nick Chalko *      http://www.apache.org/licenses/LICENSE-2.0
91abddd9f6225298066094e20a6c29061b6af4590Nick Chalko *
101abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * Unless required by applicable law or agreed to in writing, software
111abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * distributed under the License is distributed on an "AS IS" BASIS,
121abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * See the License for the specific language governing permissions and
141abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * limitations under the License.
151abddd9f6225298066094e20a6c29061b6af4590Nick Chalko */
161abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
171abddd9f6225298066094e20a6c29061b6af4590Nick Chalkopackage com.android.usbtuner;
181abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
191abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.media.MediaDataSource;
201abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.util.Log;
211abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
221abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport com.android.usbtuner.ChannelScanFileParser.ScanChannel;
231abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport com.android.usbtuner.data.Channel;
241abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport com.android.usbtuner.data.TunerChannel;
251abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport com.android.usbtuner.tvinput.EventDetector;
261abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport com.android.usbtuner.tvinput.EventDetector.EventListener;
271abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport com.android.usbtuner.tvinput.UsbTunerDebug;
281abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
291abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport java.io.IOException;
301abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport java.util.Locale;
311abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport java.util.concurrent.atomic.AtomicLong;
321abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
331abddd9f6225298066094e20a6c29061b6af4590Nick Chalko/**
3448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho * A {@link MediaDataSource} implementation which provides the mpeg2ts stream from the tuner device
3548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho * to {@link MediaExtractor}.
361abddd9f6225298066094e20a6c29061b6af4590Nick Chalko */
371abddd9f6225298066094e20a6c29061b6af4590Nick Chalkopublic class UsbTunerDataSource extends MediaDataSource implements InputStreamSource {
381abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    private static final String TAG = "UsbTunerDataSource";
391abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
401abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    private static final int MIN_READ_UNIT = 1500;
411abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    private static final int READ_BUFFER_SIZE = MIN_READ_UNIT * 10; // ~15KB
421abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    private static final int CIRCULAR_BUFFER_SIZE = MIN_READ_UNIT * 20000;  // ~ 30MB
431abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
441abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    private static final int READ_TIMEOUT_MS = 5000; // 5 secs.
4548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho    private static final int BUFFER_UNDERRUN_SLEEP_MS = 10;
461abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
471abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    private static final int CACHE_KEY_VERSION = 1;
481abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
491abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    // UTCK stands for USB Tuner Cache Key.
501abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    private static final String CACHE_KEY_PREFIX = "UTCK";
511abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
521abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    private final Object mCircularBufferMonitor = new Object();
531abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    private final byte[] mCircularBuffer = new byte[CIRCULAR_BUFFER_SIZE];
541abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    private long mBytesFetched;
551abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    private final AtomicLong mLastReadPosition = new AtomicLong();
561abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    private boolean mEndOfStreamSent;
571abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    private boolean mStreaming;
581abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
59ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    private final TunerHal mTunerHal;
601abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    private Thread mStreamingThread;
611abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    private boolean mDeviceConfigured;
621abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    private EventDetector mEventDetector;
631abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
64ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    public UsbTunerDataSource(TunerHal tunerHal, EventListener eventListener) {
65ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        mTunerHal = tunerHal;
66ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        mEventDetector = new EventDetector(mTunerHal, eventListener);
671abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    }
681abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
691abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    /**
701abddd9f6225298066094e20a6c29061b6af4590Nick Chalko     * Starts the streaming of a configured program. Throws a runtime exception if no channel and
711abddd9f6225298066094e20a6c29061b6af4590Nick Chalko     * program have successfully been configured yet.
721abddd9f6225298066094e20a6c29061b6af4590Nick Chalko     */
731abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    @Override
741abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    public void startStream() {
751abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        if (!mDeviceConfigured) {
761abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            throw new RuntimeException("Channel and program not configured!");
771abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        }
781abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
791abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        synchronized (mCircularBufferMonitor) {
801abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            if (mStreaming) {
811abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                Log.w(TAG, "Streaming should be stopped before start streaming");
821abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                return;
831abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            }
841abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            mStreaming = true;
851abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            mBytesFetched = 0;
861abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            mLastReadPosition.set(0L);
871abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            mEndOfStreamSent = false;
881abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        }
891abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
901abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        mStreamingThread = new StreamingThread();
911abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        mStreamingThread.start();
921abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        Log.i(TAG, "Streaming started");
931abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    }
941abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
951abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    /**
961abddd9f6225298066094e20a6c29061b6af4590Nick Chalko     * Sets the channel required to start streaming from this device. Afterwards, prepares the tuner
971abddd9f6225298066094e20a6c29061b6af4590Nick Chalko     * device for streaming. Package retrieval can be made at any time after invoking this method
981abddd9f6225298066094e20a6c29061b6af4590Nick Chalko     * and before stopping the stream.
991abddd9f6225298066094e20a6c29061b6af4590Nick Chalko     *
1001abddd9f6225298066094e20a6c29061b6af4590Nick Chalko     * @param channel a {@link TunerChannel} instance tune to
1011abddd9f6225298066094e20a6c29061b6af4590Nick Chalko     * @return {@code true} if the entire operation was successful; {@code false} otherwise
1021abddd9f6225298066094e20a6c29061b6af4590Nick Chalko     */
1031abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    @Override
1041abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    public boolean tuneToChannel(TunerChannel channel) {
105ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        if (mTunerHal.tune(channel.getFrequency(), channel.getModulation())) {
1061abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            if (channel.hasVideo()) {
107ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko                mTunerHal.addPidFilter(channel.getVideoPid(),
108ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko                        TunerHal.FILTER_TYPE_VIDEO);
1091abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            }
1101abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            if (channel.hasAudio()) {
111ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko                mTunerHal.addPidFilter(channel.getAudioPid(),
112ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko                        TunerHal.FILTER_TYPE_AUDIO);
1131abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            }
114ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko            mTunerHal.addPidFilter(channel.getPcrPid(),
115ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko                    TunerHal.FILTER_TYPE_PCR);
1161abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            if (mEventDetector != null) {
1171abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                mEventDetector.startDetecting(channel.getFrequency(), channel.getModulation());
1181abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            }
1191abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            mDeviceConfigured = true;
1201abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            return true;
1211abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        }
1221abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        return false;
1231abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    }
1241abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
1251abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    /**
1261abddd9f6225298066094e20a6c29061b6af4590Nick Chalko     * Blocks the current thread until the streaming thread stops. In rare cases when the tuner
1271abddd9f6225298066094e20a6c29061b6af4590Nick Chalko     * device is overloaded this can take a while, but usually it returns pretty quickly.
1281abddd9f6225298066094e20a6c29061b6af4590Nick Chalko     */
1291abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    @Override
1301abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    public void stopStream() {
1311abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        synchronized (mCircularBufferMonitor) {
1321abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            mStreaming = false;
1331abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            mCircularBufferMonitor.notify();
1341abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        }
1351abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
1361abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        try {
1371abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            if (mStreamingThread != null) {
1381abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                mStreamingThread.join();
1391abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            }
1401abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        } catch (InterruptedException e) {
14148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho            Thread.currentThread().interrupt();
14248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho        } finally {
14348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho            mTunerHal.stopTune();
1441abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        }
1451abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    }
1461abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
1471abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    @Override
1481abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    public long getLimit() {
1491abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        synchronized (mCircularBufferMonitor) {
1501abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            return mBytesFetched;
1511abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        }
1521abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    }
1531abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
1541abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    @Override
1551abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    public long getPosition() {
1561abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        return mLastReadPosition.get();
1571abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    }
1581abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
1591abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    private class StreamingThread extends Thread {
1601abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        @Override
1611abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        public void run() {
1621abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            // Buffers for streaming data from the tuner and the internal buffer.
1631abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            byte[] dataBuffer = new byte[READ_BUFFER_SIZE];
1641abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
1651abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            while (true) {
1661abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                synchronized (mCircularBufferMonitor) {
1671abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                    if (!mStreaming) {
1681abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                        break;
1691abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                    }
1701abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                }
1711abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
172ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko                int bytesWritten = mTunerHal.readTsStream(dataBuffer, dataBuffer.length);
1731abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                if (bytesWritten <= 0) {
17448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho                    try {
17548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho                        // When buffer is underrun, we sleep for short time to prevent
17648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho                        // unnecessary CPU draining.
17748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho                        sleep(BUFFER_UNDERRUN_SLEEP_MS);
17848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho                    } catch (InterruptedException e) {
17948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho                        Thread.currentThread().interrupt();
18048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho                    }
1811abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                    continue;
1821abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                }
1831abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
1841abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                if (mEventDetector != null) {
1851abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                    mEventDetector.feedTSStream(dataBuffer, 0, bytesWritten);
1861abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                }
1871abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                synchronized (mCircularBufferMonitor) {
1881abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                    int posInBuffer = (int) (mBytesFetched % CIRCULAR_BUFFER_SIZE);
1891abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                    int bytesToCopyInFirstPass = bytesWritten;
1901abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                    if (posInBuffer + bytesToCopyInFirstPass > mCircularBuffer.length) {
1911abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                        bytesToCopyInFirstPass = mCircularBuffer.length - posInBuffer;
1921abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                    }
1931abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                    System.arraycopy(dataBuffer, 0, mCircularBuffer, posInBuffer,
1941abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                            bytesToCopyInFirstPass);
1951abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                    if (bytesToCopyInFirstPass < bytesWritten) {
1961abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                        System.arraycopy(dataBuffer, bytesToCopyInFirstPass, mCircularBuffer, 0,
1971abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                                bytesWritten - bytesToCopyInFirstPass);
1981abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                    }
1991abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                    mBytesFetched += bytesWritten;
2001abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                    mCircularBufferMonitor.notify();
2011abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                }
2021abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            }
2031abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
2041abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            Log.i(TAG, "Streaming stopped");
2051abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        }
2061abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    }
2071abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
2081abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    @Override
2091abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    public int readAt(long pos, byte[] buffer, int offset, int amount) throws IOException {
2101abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        synchronized (mCircularBufferMonitor) {
2111abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            if (mEndOfStreamSent) {
2121abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                // Nothing was received during READ_TIMEOUT_MS before.
2131abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                return -1;
2141abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            }
2151abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            if (mBytesFetched - CIRCULAR_BUFFER_SIZE > pos) {
2161abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                // Not available at circular buffer.
2171abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                Log.w(TAG, "Not available at circular buffer");
2181abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                return -1;
2191abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            }
2201abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            long initialBytesFetched = mBytesFetched;
2211abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            while (mBytesFetched < pos + amount && mStreaming) {
2221abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                try {
2231abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                    mCircularBufferMonitor.wait(READ_TIMEOUT_MS);
2241abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                } catch (InterruptedException e) {
2251abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                    // Wait again.
22648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho                    Thread.currentThread().interrupt();
2271abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                }
2281abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                if (initialBytesFetched == mBytesFetched) {
2291abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                    Log.w(TAG, "No data update for " + READ_TIMEOUT_MS + "ms. returning -1.");
2301abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
2311abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                    // Returning -1 will make demux report EOS so that the input service can retry
2321abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                    // the playback.
2331abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                    mEndOfStreamSent = true;
2341abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                    return -1;
2351abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                }
2361abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            }
2371abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            if (!mStreaming) {
2381abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                Log.w(TAG, "Stream is already stopped.");
2391abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                return -1;
2401abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            }
2411abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            if (mBytesFetched - CIRCULAR_BUFFER_SIZE > pos) {
2421abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                Log.e(TAG, "Demux is requesting the data which is already overwritten.");
2431abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                return -1;
2441abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            }
2451abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            int posInBuffer = (int) (pos % CIRCULAR_BUFFER_SIZE);
2461abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            int bytesToCopyInFirstPass = amount;
2471abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            if (posInBuffer + bytesToCopyInFirstPass > mCircularBuffer.length) {
2481abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                bytesToCopyInFirstPass = mCircularBuffer.length - posInBuffer;
2491abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            }
2501abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            System.arraycopy(mCircularBuffer, posInBuffer, buffer, offset, bytesToCopyInFirstPass);
2511abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            if (bytesToCopyInFirstPass < amount) {
2521abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                System.arraycopy(mCircularBuffer, 0, buffer, offset + bytesToCopyInFirstPass,
2531abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                        amount - bytesToCopyInFirstPass);
2541abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            }
2551abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            mLastReadPosition.set(pos + amount);
2561abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            mCircularBufferMonitor.notify();
2571abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
2581abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            if (UsbTunerDebug.ENABLED) {
2591abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                UsbTunerDebug.setBytesInQueue((int) (mBytesFetched - mLastReadPosition.get()));
2601abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            }
2611abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
2621abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            return amount;
2631abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        }
2641abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    }
2651abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
2661abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    @Override
2671abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    public long getSize() throws IOException {
2681abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        return -1;
2691abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    }
2701abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
2711abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    @Override
272ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    public void close() {
27348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho        // Called from system MediaExtractor. All the resource should be closed
27448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho        // in stopStream() already.
2751abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    }
2761abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
2771abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    @Override
2781abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    public int getType() {
2791abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        return Channel.TYPE_TUNER;
2801abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    }
2811abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
2821abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    @Override
2831abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    public boolean setScanChannel(ScanChannel channel) {
2841abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        return false;
2851abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    }
2861abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
2871abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    public static String generateCacheKey(TunerChannel channel, long timestampMs) {
2881abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        return String.format(Locale.ENGLISH, "%s-%x-%x-%x-%x", CACHE_KEY_PREFIX, CACHE_KEY_VERSION,
2891abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                channel.getFrequency(), channel.getProgramNumber(), timestampMs);
2901abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    }
2911abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
2921abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    /**
2931abddd9f6225298066094e20a6c29061b6af4590Nick Chalko     * Parses the timestamp from a cache key generated by {@link #generateCacheKey}.
2941abddd9f6225298066094e20a6c29061b6af4590Nick Chalko     *
2951abddd9f6225298066094e20a6c29061b6af4590Nick Chalko     * @param cacheKey a cache key generated by {@link #generateCacheKey}
2961abddd9f6225298066094e20a6c29061b6af4590Nick Chalko     * @return the timestamp parsed from the given cache key. {@code -1} if unable to parse.
2971abddd9f6225298066094e20a6c29061b6af4590Nick Chalko     */
2981abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    public static long parseTimestampFromCacheKey(String cacheKey) {
2991abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        String[] tokens = cacheKey.split("-");
3001abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        if (tokens.length < 2 || !tokens[0].equals(CACHE_KEY_PREFIX)) {
3011abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            return -1;
3021abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        }
3031abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        int version = Integer.parseInt(tokens[1], 16);
3041abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        if (version == 1) {
3051abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            return Long.parseLong(tokens[4], 16);
3061abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        } else {
3071abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            return -1;
3081abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        }
3091abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    }
3101abddd9f6225298066094e20a6c29061b6af4590Nick Chalko}
311