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