Home | History | Annotate | Download | only in tuner
      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.media.tv.TvInputManager;
     21 import android.os.ParcelFileDescriptor;
     22 import android.support.annotation.IntDef;
     23 import android.support.annotation.NonNull;
     24 import android.util.Log;
     25 import com.android.tv.common.recording.RecordingCapability;
     26 import java.lang.annotation.Retention;
     27 import java.lang.annotation.RetentionPolicy;
     28 import java.lang.reflect.InvocationTargetException;
     29 import java.lang.reflect.Method;
     30 import java.util.ArrayList;
     31 import java.util.Collections;
     32 import java.util.List;
     33 import java.util.Locale;
     34 
     35 /** Provides with the file descriptors to access DVB device. */
     36 public class DvbDeviceAccessor {
     37     private static final String TAG = "DvbDeviceAccessor";
     38 
     39     @IntDef({DVB_DEVICE_DEMUX, DVB_DEVICE_DVR, DVB_DEVICE_FRONTEND})
     40     @Retention(RetentionPolicy.SOURCE)
     41     public @interface DvbDevice {}
     42 
     43     public static final int DVB_DEVICE_DEMUX = 0; // TvInputManager.DVB_DEVICE_DEMUX;
     44     public static final int DVB_DEVICE_DVR = 1; // TvInputManager.DVB_DEVICE_DVR;
     45     public static final int DVB_DEVICE_FRONTEND = 2; // TvInputManager.DVB_DEVICE_FRONTEND;
     46 
     47     private static Method sGetDvbDeviceListMethod;
     48     private static Method sOpenDvbDeviceMethod;
     49 
     50     private final TvInputManager mTvInputManager;
     51 
     52     static {
     53         try {
     54             Class tvInputManagerClass = Class.forName("android.media.tv.TvInputManager");
     55             Class dvbDeviceInfoClass = Class.forName("android.media.tv.DvbDeviceInfo");
     56             sGetDvbDeviceListMethod = tvInputManagerClass.getDeclaredMethod("getDvbDeviceList");
     57             sGetDvbDeviceListMethod.setAccessible(true);
     58             sOpenDvbDeviceMethod =
     59                     tvInputManagerClass.getDeclaredMethod(
     60                             "openDvbDevice", dvbDeviceInfoClass, Integer.TYPE);
     61             sOpenDvbDeviceMethod.setAccessible(true);
     62         } catch (ClassNotFoundException e) {
     63             Log.e(TAG, "Couldn't find class", e);
     64         } catch (NoSuchMethodException e) {
     65             Log.e(TAG, "Couldn't find method", e);
     66         }
     67     }
     68 
     69     public DvbDeviceAccessor(Context context) {
     70         mTvInputManager = (TvInputManager) context.getSystemService(Context.TV_INPUT_SERVICE);
     71     }
     72 
     73     public List<DvbDeviceInfoWrapper> getDvbDeviceList() {
     74         try {
     75             List<DvbDeviceInfoWrapper> wrapperList = new ArrayList<>();
     76             List dvbDeviceInfoList = (List) sGetDvbDeviceListMethod.invoke(mTvInputManager);
     77             for (Object dvbDeviceInfo : dvbDeviceInfoList) {
     78                 wrapperList.add(new DvbDeviceInfoWrapper(dvbDeviceInfo));
     79             }
     80             Collections.sort(wrapperList);
     81             return wrapperList;
     82         } catch (IllegalAccessException e) {
     83             Log.e(TAG, "Couldn't access", e);
     84         } catch (InvocationTargetException e) {
     85             Log.e(TAG, "Couldn't invoke", e);
     86         }
     87         return null;
     88     }
     89 
     90     /** Returns the number of currently connected DVB devices. */
     91     public int getNumOfDvbDevices() {
     92         List<DvbDeviceInfoWrapper> dvbDeviceList = getDvbDeviceList();
     93         return dvbDeviceList == null ? 0 : dvbDeviceList.size();
     94     }
     95 
     96     public boolean isDvbDeviceAvailable() {
     97         try {
     98             List dvbDeviceInfoList = (List) sGetDvbDeviceListMethod.invoke(mTvInputManager);
     99             return (!dvbDeviceInfoList.isEmpty());
    100         } catch (IllegalAccessException e) {
    101             Log.e(TAG, "Couldn't access", e);
    102         } catch (InvocationTargetException e) {
    103             Log.e(TAG, "Couldn't invoke", e);
    104         }
    105         return false;
    106     }
    107 
    108     public ParcelFileDescriptor openDvbDevice(
    109             DvbDeviceInfoWrapper deviceInfo, @DvbDevice int device) {
    110         try {
    111             return (ParcelFileDescriptor)
    112                     sOpenDvbDeviceMethod.invoke(
    113                             mTvInputManager, deviceInfo.getDvbDeviceInfo(), device);
    114         } catch (IllegalAccessException e) {
    115             Log.e(TAG, "Couldn't access", e);
    116         } catch (InvocationTargetException e) {
    117             Log.e(TAG, "Couldn't invoke", e);
    118         }
    119         return null;
    120     }
    121 
    122     /**
    123      * Returns the current recording capability for USB tuner.
    124      *
    125      * @param inputId the input id to use.
    126      */
    127     public RecordingCapability getRecordingCapability(String inputId) {
    128         List<DvbDeviceInfoWrapper> deviceList = getDvbDeviceList();
    129         // TODO(DVR) implement accurate capabilities and updating values when needed.
    130         return RecordingCapability.builder()
    131                 .setInputId(inputId)
    132                 .setMaxConcurrentPlayingSessions(1)
    133                 .setMaxConcurrentTunedSessions(deviceList.size())
    134                 .setMaxConcurrentSessionsOfAllTypes(deviceList.size() + 1)
    135                 .build();
    136     }
    137 
    138     public static class DvbDeviceInfoWrapper implements Comparable<DvbDeviceInfoWrapper> {
    139         private static Method sGetAdapterIdMethod;
    140         private static Method sGetDeviceIdMethod;
    141         private final Object mDvbDeviceInfo;
    142         private final int mAdapterId;
    143         private final int mDeviceId;
    144         private final long mId;
    145 
    146         static {
    147             try {
    148                 Class dvbDeviceInfoClass = Class.forName("android.media.tv.DvbDeviceInfo");
    149                 sGetAdapterIdMethod = dvbDeviceInfoClass.getDeclaredMethod("getAdapterId");
    150                 sGetAdapterIdMethod.setAccessible(true);
    151                 sGetDeviceIdMethod = dvbDeviceInfoClass.getDeclaredMethod("getDeviceId");
    152                 sGetDeviceIdMethod.setAccessible(true);
    153             } catch (ClassNotFoundException e) {
    154                 Log.e(TAG, "Couldn't find class", e);
    155             } catch (NoSuchMethodException e) {
    156                 Log.e(TAG, "Couldn't find method", e);
    157             }
    158         }
    159 
    160         public DvbDeviceInfoWrapper(Object dvbDeviceInfo) {
    161             mDvbDeviceInfo = dvbDeviceInfo;
    162             mAdapterId = initAdapterId();
    163             mDeviceId = initDeviceId();
    164             mId = (((long) getAdapterId()) << 32) | (getDeviceId() & 0xffffffffL);
    165         }
    166 
    167         public long getId() {
    168             return mId;
    169         }
    170 
    171         public int getAdapterId() {
    172             return mAdapterId;
    173         }
    174 
    175         private int initAdapterId() {
    176             try {
    177                 return (int) sGetAdapterIdMethod.invoke(mDvbDeviceInfo);
    178             } catch (InvocationTargetException e) {
    179                 Log.e(TAG, "Couldn't invoke", e);
    180             } catch (IllegalAccessException e) {
    181                 Log.e(TAG, "Couldn't access", e);
    182             }
    183             return -1;
    184         }
    185 
    186         public int getDeviceId() {
    187             return mDeviceId;
    188         }
    189 
    190         private int initDeviceId() {
    191             try {
    192                 return (int) sGetDeviceIdMethod.invoke(mDvbDeviceInfo);
    193             } catch (InvocationTargetException e) {
    194                 Log.e(TAG, "Couldn't invoke", e);
    195             } catch (IllegalAccessException e) {
    196                 Log.e(TAG, "Couldn't access", e);
    197             }
    198             return -1;
    199         }
    200 
    201         public Object getDvbDeviceInfo() {
    202             return mDvbDeviceInfo;
    203         }
    204 
    205         @Override
    206         public int compareTo(@NonNull DvbDeviceInfoWrapper another) {
    207             if (getAdapterId() != another.getAdapterId()) {
    208                 return getAdapterId() - another.getAdapterId();
    209             }
    210             return getDeviceId() - another.getDeviceId();
    211         }
    212 
    213         @Override
    214         public String toString() {
    215             return String.format(
    216                     Locale.US,
    217                     "DvbDeviceInfo {adapterId: %d, deviceId: %d}",
    218                     getAdapterId(),
    219                     getDeviceId());
    220         }
    221     }
    222 }
    223