Home | History | Annotate | Download | only in usbtuner
      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      */
     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 
     82     protected TunerHal(Context context) {
     83         mIsStreaming = false;
     84         mFrequency = -1;
     85         mModulation = null;
     86     }
     87 
     88     protected boolean isStreaming() {
     89         return mIsStreaming;
     90     }
     91 
     92     @Override
     93     protected void finalize() throws Throwable {
     94         super.finalize();
     95         close();
     96     }
     97 
     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      */
    106     protected abstract boolean openFirstAvailable();
    107 
    108     protected abstract boolean isDeviceOpen();
    109 
    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      */
    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 
    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      */
    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 
    172     protected native void nativeAddPidFilter(long deviceId, int pid, @FilterType int filterType);
    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      */
    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 
    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      */
    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 
    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      */
    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      */
    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      */
    234     protected int openDvbDvrFd() {
    235         return -1;
    236     }
    237 }
    238