1 /*
2  * Copyright (C) 2016 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.hdhomerun;
18 
19 import android.support.annotation.NonNull;
20 import android.support.annotation.Nullable;
21 import android.support.annotation.WorkerThread;
22 import android.util.Log;
23 import com.android.tv.tuner.hdhomerun.HdHomeRunDiscover.HdHomeRunDiscoverDevice;
24 import java.util.HashSet;
25 import java.util.List;
26 import java.util.Set;
27 
28 /** An interface class provides methods to access physical HDHomeRun devices. */
29 @WorkerThread
30 public class HdHomeRunInterface {
31     private static final String TAG = "HdHomeRunInterface";
32     private static final boolean DEBUG = false;
33 
34     private static final int FETCH_DEVICE_NAME_TRY_NUM = 2;
35     private static final int MAX_DEVICES = 1;
36     private static final boolean DISABLE_CABLE = false;
37 
38     /**
39      * Scans for HDHomeRun devices on the network.
40      *
41      * @param deviceId The target device ID we want to find, scans for all available devices if
42      *     {@code null} or the given ID cannot be found.
43      * @return A set of HDHomeRun devices
44      */
45     @NonNull
scanDevices(Integer deviceId)46     public static Set<HdHomeRunDevice> scanDevices(Integer deviceId) {
47         List<HdHomeRunDiscoverDevice> discoveredDevices = null;
48         if (deviceId != null) {
49             discoveredDevices =
50                     HdHomeRunUtils.findHdHomeRunDevices(
51                             0, HdHomeRunUtils.HDHOMERUN_DEVICE_TYPE_TUNER, deviceId, 1);
52             if (discoveredDevices.isEmpty()) {
53                 Log.i(TAG, "Can't find device with ID: " + deviceId);
54             }
55         }
56         if (discoveredDevices == null || discoveredDevices.isEmpty()) {
57             discoveredDevices =
58                     HdHomeRunUtils.findHdHomeRunDevices(
59                             0,
60                             HdHomeRunUtils.HDHOMERUN_DEVICE_TYPE_TUNER,
61                             HdHomeRunUtils.HDHOMERUN_DEVICE_ID_WILDCARD,
62                             MAX_DEVICES);
63             if (DEBUG) Log.d(TAG, "Found " + discoveredDevices.size() + " devices");
64         }
65         Set<HdHomeRunDevice> result = new HashSet<>();
66         for (HdHomeRunDiscoverDevice discoveredDevice : discoveredDevices) {
67             String model =
68                     fetchDeviceModel(discoveredDevice.mDeviceId, discoveredDevice.mIpAddress);
69             if (model == null) {
70                 Log.e(TAG, "Fetching device model failed: " + discoveredDevice.mDeviceId);
71                 continue;
72             } else if (DEBUG) {
73                 Log.d(TAG, "Fetch Device Model: " + model);
74             }
75             if (DISABLE_CABLE) {
76                 if (model != null && model.contains("cablecard")) {
77                     // filter out CableCARD devices
78                     continue;
79                 }
80             }
81             for (int i = 0; i < discoveredDevice.mTunerCount; i++) {
82                 result.add(
83                         new HdHomeRunDevice(
84                                 discoveredDevice.mIpAddress,
85                                 discoveredDevice.mDeviceType,
86                                 discoveredDevice.mDeviceId,
87                                 i,
88                                 model));
89             }
90         }
91         return result;
92     }
93 
94     /**
95      * Returns {@code true} if the given device IP, ID and tuner index is available for use.
96      *
97      * @param deviceId The target device ID, 0 denotes a wildcard match.
98      * @param deviceIp The target device IP.
99      * @param tunerIndex The target tuner index of the target device. This parameter is only
100      *     meaningful when the target device has multiple tuners.
101      */
isDeviceAvailable(int deviceId, int deviceIp, int tunerIndex)102     public static boolean isDeviceAvailable(int deviceId, int deviceIp, int tunerIndex) {
103         // TODO: check the lock state for the given tuner.
104         if ((deviceId == 0) && (deviceIp == 0)) {
105             return false;
106         }
107         if (HdHomeRunUtils.isIpMulticast(deviceIp)) {
108             return false;
109         }
110         if ((deviceId == 0) || (deviceId == HdHomeRunUtils.HDHOMERUN_DEVICE_ID_WILDCARD)) {
111             try (HdHomeRunControlSocket controlSock =
112                     new HdHomeRunControlSocket(deviceId, deviceIp)) {
113                 deviceId = controlSock.getDeviceId();
114             }
115         }
116         return deviceId != 0;
117     }
118 
119     @Nullable
fetchDeviceModel(int deviceId, int deviceIp)120     private static String fetchDeviceModel(int deviceId, int deviceIp) {
121         for (int i = 0; i < FETCH_DEVICE_NAME_TRY_NUM; i++) {
122             try (HdHomeRunControlSocket controlSock =
123                     new HdHomeRunControlSocket(deviceId, deviceIp)) {
124                 String model = controlSock.get("/sys/model");
125                 if (model != null) {
126                     return model;
127                 }
128             }
129         }
130         return null;
131     }
132 
HdHomeRunInterface()133     private HdHomeRunInterface() {}
134 }
135