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