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