• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.tv.tuner;
18 
19 import android.content.Context;
20 import android.support.annotation.IntDef;
21 import android.support.annotation.StringDef;
22 import android.util.Log;
23 
24 import java.lang.annotation.Retention;
25 import java.lang.annotation.RetentionPolicy;
26 import java.util.Objects;
27 
28 /**
29  * A base class to handle a hardware tuner device.
30  */
31 public abstract class TunerHal implements AutoCloseable {
32     protected static final String TAG = "TunerHal";
33     protected static final boolean DEBUG = false;
34 
35     @IntDef({ FILTER_TYPE_OTHER, FILTER_TYPE_AUDIO, FILTER_TYPE_VIDEO, FILTER_TYPE_PCR })
36     @Retention(RetentionPolicy.SOURCE)
37     public @interface FilterType {}
38     public static final int FILTER_TYPE_OTHER = 0;
39     public static final int FILTER_TYPE_AUDIO = 1;
40     public static final int FILTER_TYPE_VIDEO = 2;
41     public static final int FILTER_TYPE_PCR = 3;
42 
43     @StringDef({ MODULATION_8VSB, MODULATION_QAM256 })
44     @Retention(RetentionPolicy.SOURCE)
45     public @interface ModulationType {}
46     public static final String MODULATION_8VSB = "8VSB";
47     public static final String MODULATION_QAM256 = "QAM256";
48 
49     public static final int TUNER_TYPE_BUILT_IN = 1;
50     public static final int TUNER_TYPE_USB = 2;
51 
52     protected static final int PID_PAT = 0;
53     protected static final int PID_ATSC_SI_BASE = 0x1ffb;
54     protected static final int DEFAULT_VSB_TUNE_TIMEOUT_MS = 2000;
55     protected static final int DEFAULT_QAM_TUNE_TIMEOUT_MS = 4000; // Some device takes time for
56                                                                    // QAM256 tuning.
57     private boolean mIsStreaming;
58     private int mFrequency;
59     private String mModulation;
60 
61     static {
62         System.loadLibrary("tunertvinput_jni");
63     }
64 
65     /**
66      * Creates a TunerHal instance.
67      * @param context context for creating the TunerHal instance
68      * @return the TunerHal instance
69      */
createInstance(Context context)70     public synchronized static TunerHal createInstance(Context context) {
71         TunerHal tunerHal = null;
72         if (getTunerType(context) == TUNER_TYPE_BUILT_IN) {
73         }
74         if (tunerHal == null) {
75             tunerHal = new UsbTunerHal(context);
76         }
77         if (tunerHal.openFirstAvailable()) {
78             return tunerHal;
79         }
80         return null;
81     }
82 
83     /**
84      * Gets the number of tuner devices currently present.
85      */
getTunerCount(Context context)86     public static int getTunerCount(Context context) {
87         if (getTunerType(context) == TUNER_TYPE_BUILT_IN) {
88         }
89         return UsbTunerHal.getNumberOfDevices(context);
90     }
91 
92     /**
93      * Gets the type of tuner devices currently used.
94      */
getTunerType(Context context)95     public static int getTunerType(Context context) {
96         return TUNER_TYPE_USB;
97     }
98 
TunerHal(Context context)99     protected TunerHal(Context context) {
100         mIsStreaming = false;
101         mFrequency = -1;
102         mModulation = null;
103     }
104 
isStreaming()105     protected boolean isStreaming() {
106         return mIsStreaming;
107     }
108 
109     @Override
finalize()110     protected void finalize() throws Throwable {
111         super.finalize();
112         close();
113     }
114 
nativeFinalize(long deviceId)115     protected native void nativeFinalize(long deviceId);
116 
117     /**
118      * Acquires the first available tuner device. If there is a tuner device that is available, the
119      * tuner device will be locked to the current instance.
120      *
121      * @return {@code true} if the operation was successful, {@code false} otherwise
122      */
openFirstAvailable()123     protected abstract boolean openFirstAvailable();
124 
isDeviceOpen()125     protected abstract boolean isDeviceOpen();
126 
getDeviceId()127     protected abstract long getDeviceId();
128 
129     /**
130      * Sets the tuner channel. This should be called after acquiring a tuner device.
131      *
132      * @param frequency a frequency of the channel to tune to
133      * @param modulation a modulation method of the channel to tune to
134      * @return {@code true} if the operation was successful, {@code false} otherwise
135      */
tune(int frequency, @ModulationType String modulation)136     public synchronized boolean tune(int frequency, @ModulationType String modulation) {
137         if (!isDeviceOpen()) {
138             Log.e(TAG, "There's no available device");
139             return false;
140         }
141         if (mIsStreaming) {
142             nativeCloseAllPidFilters(getDeviceId());
143             mIsStreaming = false;
144         }
145 
146         // When tuning to a new channel in the same frequency, there's no need to stop current tuner
147         // device completely and the only thing necessary for tuning is reopening pid filters.
148         if (mFrequency == frequency && Objects.equals(mModulation, modulation)) {
149             addPidFilter(PID_PAT, FILTER_TYPE_OTHER);
150             addPidFilter(PID_ATSC_SI_BASE, FILTER_TYPE_OTHER);
151             mIsStreaming = true;
152             return true;
153         }
154         int timeout_ms = modulation.equals(MODULATION_8VSB) ? DEFAULT_VSB_TUNE_TIMEOUT_MS
155                 : DEFAULT_QAM_TUNE_TIMEOUT_MS;
156         if (nativeTune(getDeviceId(), frequency, modulation, timeout_ms)) {
157             addPidFilter(PID_PAT, FILTER_TYPE_OTHER);
158             addPidFilter(PID_ATSC_SI_BASE, FILTER_TYPE_OTHER);
159             mFrequency = frequency;
160             mModulation = modulation;
161             mIsStreaming = true;
162             return true;
163         }
164         return false;
165     }
166 
nativeTune(long deviceId, int frequency, @ModulationType String modulation, int timeout_ms)167     protected native boolean nativeTune(long deviceId, int frequency,
168             @ModulationType String modulation, int timeout_ms);
169 
170     /**
171      * Sets a pid filter. This should be set after setting a channel.
172      *
173      * @param pid a pid number to be added to filter list
174      * @param filterType a type of pid. Must be one of (FILTER_TYPE_XXX)
175      * @return {@code true} if the operation was successful, {@code false} otherwise
176      */
addPidFilter(int pid, @FilterType int filterType)177     public synchronized boolean addPidFilter(int pid, @FilterType int filterType) {
178         if (!isDeviceOpen()) {
179             Log.e(TAG, "There's no available device");
180             return false;
181         }
182         if (pid >= 0 && pid <= 0x1fff) {
183             nativeAddPidFilter(getDeviceId(), pid, filterType);
184             return true;
185         }
186         return false;
187     }
188 
nativeAddPidFilter(long deviceId, int pid, @FilterType int filterType)189     protected native void nativeAddPidFilter(long deviceId, int pid, @FilterType int filterType);
nativeCloseAllPidFilters(long deviceId)190     protected native void nativeCloseAllPidFilters(long deviceId);
nativeSetHasPendingTune(long deviceId, boolean hasPendingTune)191     protected native void nativeSetHasPendingTune(long deviceId, boolean hasPendingTune);
192 
193     /**
194      * Stops current tuning. The tuner device and pid filters will be reset by this call and make
195      * the tuner ready to accept another tune request.
196      */
stopTune()197     public synchronized void stopTune() {
198         if (isDeviceOpen()) {
199             if (mIsStreaming) {
200                 nativeCloseAllPidFilters(getDeviceId());
201             }
202             nativeStopTune(getDeviceId());
203         }
204         mIsStreaming = false;
205         mFrequency = -1;
206         mModulation = null;
207     }
208 
setHasPendingTune(boolean hasPendingTune)209     public void setHasPendingTune(boolean hasPendingTune) {
210         nativeSetHasPendingTune(getDeviceId(), hasPendingTune);
211     }
212 
nativeStopTune(long deviceId)213     protected native void nativeStopTune(long deviceId);
214 
215     /**
216      * This method must be called after {@link TunerHal#tune} and before
217      * {@link TunerHal#stopTune}. Writes at most maxSize TS frames in a buffer
218      * provided by the user. The frames employ MPEG encoding.
219      *
220      * @param javaBuffer a buffer to write the video data in
221      * @param javaBufferSize the max amount of bytes to write in this buffer. Usually this number
222      *            should be equal to the length of the buffer.
223      * @return the amount of bytes written in the buffer. Note that this value could be 0 if no new
224      *         frames have been obtained since the last call.
225      */
readTsStream(byte[] javaBuffer, int javaBufferSize)226     public synchronized int readTsStream(byte[] javaBuffer, int javaBufferSize) {
227         if (isDeviceOpen()) {
228             return nativeWriteInBuffer(getDeviceId(), javaBuffer, javaBufferSize);
229         } else {
230             return 0;
231         }
232     }
233 
nativeWriteInBuffer(long deviceId, byte[] javaBuffer, int javaBufferSize)234     protected native int nativeWriteInBuffer(long deviceId, byte[] javaBuffer, int javaBufferSize);
235 
236     /**
237      * Opens Linux DVB frontend device. This method is called from native JNI and used only for
238      * UsbTunerHal.
239      */
openDvbFrontEndFd()240     protected int openDvbFrontEndFd() {
241         return -1;
242     }
243 
244     /**
245      * Opens Linux DVB demux device. This method is called from native JNI and used only for
246      * UsbTunerHal.
247      */
openDvbDemuxFd()248     protected int openDvbDemuxFd() {
249         return -1;
250     }
251 
252     /**
253      * Opens Linux DVB dvr device. This method is called from native JNI and used only for
254      * UsbTunerHal.
255      */
openDvbDvrFd()256     protected int openDvbDvrFd() {
257         return -1;
258     }
259 }
260