• 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.usbtuner;
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 com.android.usbtuner.util.TisConfiguration;
25 
26 import java.lang.annotation.Retention;
27 import java.lang.annotation.RetentionPolicy;
28 import java.util.Objects;
29 
30 /**
31  * A base class to handle a hardware tuner device.
32  */
33 public abstract class TunerHal implements AutoCloseable {
34     protected static final String TAG = "TunerHal";
35     protected static final boolean DEBUG = false;
36 
37     @IntDef({ FILTER_TYPE_OTHER, FILTER_TYPE_AUDIO, FILTER_TYPE_VIDEO, FILTER_TYPE_PCR })
38     @Retention(RetentionPolicy.SOURCE)
39     public @interface FilterType {}
40     public static final int FILTER_TYPE_OTHER = 0;
41     public static final int FILTER_TYPE_AUDIO = 1;
42     public static final int FILTER_TYPE_VIDEO = 2;
43     public static final int FILTER_TYPE_PCR = 3;
44 
45     @StringDef({ MODULATION_8VSB, MODULATION_QAM256 })
46     @Retention(RetentionPolicy.SOURCE)
47     public @interface ModulationType {}
48     public static final String MODULATION_8VSB = "8VSB";
49     public static final String MODULATION_QAM256 = "QAM256";
50 
51     protected static final int PID_PAT = 0;
52     protected static final int PID_ATSC_SI_BASE = 0x1ffb;
53     protected static final int DEFAULT_VSB_TUNE_TIMEOUT_MS = 2000;
54     protected static final int DEFAULT_QAM_TUNE_TIMEOUT_MS = 4000; // Some device takes time for
55                                                                    // QAM256 tuning.
56     private boolean mIsStreaming;
57     private int mFrequency;
58     private String mModulation;
59 
60     static {
61         System.loadLibrary("tunertvinput_jni");
62     }
63 
64     /**
65      * Creates a TunerHal instance.
66      * @param context context for creating the TunerHal instance
67      * @return the TunerHal instance
68      */
createInstance(Context context)69     public static TunerHal createInstance(Context context) {
70         TunerHal tunerHal;
71         if (TisConfiguration.isPackagedWithLiveChannels(context)) {
72             tunerHal = new UsbTunerHal(context);
73         } else {
74             tunerHal = new InternalTunerHal(context);
75         }
76         if (tunerHal.openFirstAvailable()) {
77             return tunerHal;
78         }
79         return null;
80     }
81 
TunerHal(Context context)82     protected TunerHal(Context context) {
83         mIsStreaming = false;
84         mFrequency = -1;
85         mModulation = null;
86     }
87 
isStreaming()88     protected boolean isStreaming() {
89         return mIsStreaming;
90     }
91 
92     @Override
finalize()93     protected void finalize() throws Throwable {
94         super.finalize();
95         close();
96     }
97 
nativeFinalize(long deviceId)98     protected native void nativeFinalize(long deviceId);
99 
100     /**
101      * Acquires the first available tuner device. If there is a tuner device that is available, the
102      * tuner device will be locked to the current instance.
103      *
104      * @return {@code true} if the operation was successful, {@code false} otherwise
105      */
openFirstAvailable()106     protected abstract boolean openFirstAvailable();
107 
isDeviceOpen()108     protected abstract boolean isDeviceOpen();
109 
getDeviceId()110     protected abstract long getDeviceId();
111 
112     /**
113      * Sets the tuner channel. This should be called after acquiring a tuner device.
114      *
115      * @param frequency a frequency of the channel to tune to
116      * @param modulation a modulation method of the channel to tune to
117      * @return {@code true} if the operation was successful, {@code false} otherwise
118      */
tune(int frequency, @ModulationType String modulation)119     public boolean tune(int frequency, @ModulationType String modulation) {
120         if (!isDeviceOpen()) {
121             Log.e(TAG, "There's no available device");
122             return false;
123         }
124         if (mIsStreaming) {
125             nativeCloseAllPidFilters(getDeviceId());
126             mIsStreaming = false;
127         }
128 
129         // When tuning to a new channel in the same frequency, there's no need to stop current tuner
130         // device completely and the only thing necessary for tuning is reopening pid filters.
131         if (mFrequency == frequency && Objects.equals(mModulation, modulation)) {
132             addPidFilter(PID_PAT, FILTER_TYPE_OTHER);
133             addPidFilter(PID_ATSC_SI_BASE, FILTER_TYPE_OTHER);
134             mIsStreaming = true;
135             return true;
136         }
137         int timeout_ms = modulation.equals(MODULATION_8VSB) ? DEFAULT_VSB_TUNE_TIMEOUT_MS
138                 : DEFAULT_QAM_TUNE_TIMEOUT_MS;
139         if (nativeTune(getDeviceId(), frequency, modulation, timeout_ms)) {
140             addPidFilter(PID_PAT, FILTER_TYPE_OTHER);
141             addPidFilter(PID_ATSC_SI_BASE, FILTER_TYPE_OTHER);
142             mFrequency = frequency;
143             mModulation = modulation;
144             mIsStreaming = true;
145             return true;
146         }
147         return false;
148     }
149 
nativeTune(long deviceId, int frequency, @ModulationType String modulation, int timeout_ms)150     protected native boolean nativeTune(long deviceId, int frequency,
151             @ModulationType String modulation, int timeout_ms);
152 
153     /**
154      * Sets a pid filter. This should be set after setting a channel.
155      *
156      * @param pid a pid number to be added to filter list
157      * @param filterType a type of pid. Must be one of (FILTER_TYPE_XXX)
158      * @return {@code true} if the operation was successful, {@code false} otherwise
159      */
addPidFilter(int pid, @FilterType int filterType)160     public boolean addPidFilter(int pid, @FilterType int filterType) {
161         if (!isDeviceOpen()) {
162             Log.e(TAG, "There's no available device");
163             return false;
164         }
165         if (pid >= 0 && pid <= 0x1fff) {
166             nativeAddPidFilter(getDeviceId(), pid, filterType);
167             return true;
168         }
169         return false;
170     }
171 
nativeAddPidFilter(long deviceId, int pid, @FilterType int filterType)172     protected native void nativeAddPidFilter(long deviceId, int pid, @FilterType int filterType);
nativeCloseAllPidFilters(long deviceId)173     protected native void nativeCloseAllPidFilters(long deviceId);
174 
175     /**
176      * Stops current tuning. The tuner device and pid filters will be reset by this call and make
177      * the tuner ready to accept another tune request.
178      */
stopTune()179     public void stopTune() {
180         if (isDeviceOpen()) {
181             if (mIsStreaming) {
182                 nativeCloseAllPidFilters(getDeviceId());
183             }
184             nativeStopTune(getDeviceId());
185         }
186         mIsStreaming = false;
187         mFrequency = -1;
188         mModulation = null;
189     }
190 
nativeStopTune(long deviceId)191     protected native void nativeStopTune(long deviceId);
192 
193     /**
194      * This method must be called after {@link TunerHal#tune} and before
195      * {@link TunerHal#stopStreaming}. Writes at most maxSize TS frames in a buffer
196      * provided by the user. The frames employ MPEG encoding.
197      *
198      * @param javaBuffer a buffer to write the video data in
199      * @param javaBufferSize the max amount of bytes to write in this buffer. Usually this number
200      *            should be equal to the length of the buffer.
201      * @return the amount of bytes written in the buffer. Note that this value could be 0 if no new
202      *         frames have been obtained since the last call.
203      */
readTsStream(byte[] javaBuffer, int javaBufferSize)204     public int readTsStream(byte[] javaBuffer, int javaBufferSize) {
205         if (isDeviceOpen()) {
206             return nativeWriteInBuffer(getDeviceId(), javaBuffer, javaBufferSize);
207         } else {
208             return 0;
209         }
210     }
211 
nativeWriteInBuffer(long deviceId, byte[] javaBuffer, int javaBufferSize)212     protected native int nativeWriteInBuffer(long deviceId, byte[] javaBuffer, int javaBufferSize);
213 
214     /**
215      * Opens Linux DVB frontend device. This method is called from native JNI and used only for
216      * UsbTunerHal.
217      */
openDvbFrontEndFd()218     protected int openDvbFrontEndFd() {
219         return -1;
220     }
221 
222     /**
223      * Opens Linux DVB demux device. This method is called from native JNI and used only for
224      * UsbTunerHal.
225      */
openDvbDemuxFd()226     protected int openDvbDemuxFd() {
227         return -1;
228     }
229 
230     /**
231      * Opens Linux DVB dvr device. This method is called from native JNI and used only for
232      * UsbTunerHal.
233      */
openDvbDvrFd()234     protected int openDvbDvrFd() {
235         return -1;
236     }
237 }
238