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