1 /* 2 * Copyright 2014 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.server.tv; 18 19 import android.hardware.tv.input.V1_0.Constants; 20 import android.media.tv.TvInputHardwareInfo; 21 import android.media.tv.TvStreamConfig; 22 import android.os.Bundle; 23 import android.os.Handler; 24 import android.os.Message; 25 import android.os.MessageQueue; 26 import android.util.Slog; 27 import android.util.SparseArray; 28 import android.util.SparseIntArray; 29 import android.view.Surface; 30 31 /** 32 * Provides access to the low-level TV input hardware abstraction layer. 33 */ 34 final class TvInputHal implements Handler.Callback { 35 private final static boolean DEBUG = false; 36 private final static String TAG = TvInputHal.class.getSimpleName(); 37 38 public final static int SUCCESS = 0; 39 public final static int ERROR_NO_INIT = -1; 40 public final static int ERROR_STALE_CONFIG = -2; 41 public final static int ERROR_UNKNOWN = -3; 42 43 public static final int EVENT_DEVICE_AVAILABLE = Constants.EVENT_DEVICE_AVAILABLE; 44 public static final int EVENT_DEVICE_UNAVAILABLE = Constants.EVENT_DEVICE_UNAVAILABLE; 45 public static final int EVENT_STREAM_CONFIGURATION_CHANGED = 46 Constants.EVENT_STREAM_CONFIGURATIONS_CHANGED; 47 public static final int EVENT_FIRST_FRAME_CAPTURED = 4; 48 49 public static final int EVENT_TV_MESSAGE = 5; 50 51 public interface Callback { onDeviceAvailable(TvInputHardwareInfo info, TvStreamConfig[] configs)52 void onDeviceAvailable(TvInputHardwareInfo info, TvStreamConfig[] configs); onDeviceUnavailable(int deviceId)53 void onDeviceUnavailable(int deviceId); onStreamConfigurationChanged(int deviceId, TvStreamConfig[] configs, int cableConnectionStatus)54 void onStreamConfigurationChanged(int deviceId, TvStreamConfig[] configs, 55 int cableConnectionStatus); onFirstFrameCaptured(int deviceId, int streamId)56 void onFirstFrameCaptured(int deviceId, int streamId); onTvMessage(int deviceId, int type, Bundle data)57 void onTvMessage(int deviceId, int type, Bundle data); 58 } 59 nativeOpen(MessageQueue queue)60 private native long nativeOpen(MessageQueue queue); 61 nativeAddOrUpdateStream(long ptr, int deviceId, int streamId, Surface surface)62 private static native int nativeAddOrUpdateStream(long ptr, int deviceId, int streamId, 63 Surface surface); nativeRemoveStream(long ptr, int deviceId, int streamId)64 private static native int nativeRemoveStream(long ptr, int deviceId, int streamId); nativeGetStreamConfigs(long ptr, int deviceId, int generation)65 private static native TvStreamConfig[] nativeGetStreamConfigs(long ptr, int deviceId, 66 int generation); nativeClose(long ptr)67 private static native void nativeClose(long ptr); nativeSetTvMessageEnabled(long ptr, int deviceId, int streamId, int type, boolean enabled)68 private static native int nativeSetTvMessageEnabled(long ptr, int deviceId, int streamId, 69 int type, boolean enabled); 70 71 private final Object mLock = new Object(); 72 private long mPtr = 0; 73 private final Callback mCallback; 74 private final Handler mHandler; 75 private final SparseIntArray mStreamConfigGenerations = new SparseIntArray(); 76 private final SparseArray<TvStreamConfig[]> mStreamConfigs = new SparseArray<>(); 77 TvInputHal(Callback callback)78 public TvInputHal(Callback callback) { 79 mCallback = callback; 80 mHandler = new Handler(this); 81 } 82 init()83 public void init() { 84 synchronized (mLock) { 85 mPtr = nativeOpen(mHandler.getLooper().getQueue()); 86 } 87 } 88 addOrUpdateStream(int deviceId, Surface surface, TvStreamConfig streamConfig)89 public int addOrUpdateStream(int deviceId, Surface surface, TvStreamConfig streamConfig) { 90 synchronized (mLock) { 91 if (mPtr == 0) { 92 return ERROR_NO_INIT; 93 } 94 int generation = mStreamConfigGenerations.get(deviceId, 0); 95 if (generation != streamConfig.getGeneration()) { 96 return ERROR_STALE_CONFIG; 97 } 98 if (nativeAddOrUpdateStream(mPtr, deviceId, streamConfig.getStreamId(), surface) == 0) { 99 return SUCCESS; 100 } else { 101 return ERROR_UNKNOWN; 102 } 103 } 104 } 105 setTvMessageEnabled(int deviceId, TvStreamConfig streamConfig, int type, boolean enabled)106 public int setTvMessageEnabled(int deviceId, TvStreamConfig streamConfig, int type, 107 boolean enabled) { 108 synchronized (mLock) { 109 if (mPtr == 0) { 110 return ERROR_NO_INIT; 111 } 112 int generation = mStreamConfigGenerations.get(deviceId, 0); 113 if (generation != streamConfig.getGeneration()) { 114 return ERROR_STALE_CONFIG; 115 } 116 if (nativeSetTvMessageEnabled(mPtr, deviceId, streamConfig.getStreamId(), type, 117 enabled) == 0) { 118 return SUCCESS; 119 } else { 120 return ERROR_UNKNOWN; 121 } 122 } 123 } 124 removeStream(int deviceId, TvStreamConfig streamConfig)125 public int removeStream(int deviceId, TvStreamConfig streamConfig) { 126 synchronized (mLock) { 127 if (mPtr == 0) { 128 return ERROR_NO_INIT; 129 } 130 int generation = mStreamConfigGenerations.get(deviceId, 0); 131 if (generation != streamConfig.getGeneration()) { 132 return ERROR_STALE_CONFIG; 133 } 134 if (nativeRemoveStream(mPtr, deviceId, streamConfig.getStreamId()) == 0) { 135 return SUCCESS; 136 } else { 137 return ERROR_UNKNOWN; 138 } 139 } 140 } 141 close()142 public void close() { 143 synchronized (mLock) { 144 if (mPtr != 0L) { 145 nativeClose(mPtr); 146 } 147 } 148 } 149 retrieveStreamConfigsLocked(int deviceId)150 private void retrieveStreamConfigsLocked(int deviceId) { 151 int generation = mStreamConfigGenerations.get(deviceId, 0) + 1; 152 mStreamConfigs.put(deviceId, nativeGetStreamConfigs(mPtr, deviceId, generation)); 153 mStreamConfigGenerations.put(deviceId, generation); 154 } 155 156 // Called from native deviceAvailableFromNative(TvInputHardwareInfo info)157 private void deviceAvailableFromNative(TvInputHardwareInfo info) { 158 if (DEBUG) { 159 Slog.d(TAG, "deviceAvailableFromNative: info = " + info); 160 } 161 mHandler.obtainMessage(EVENT_DEVICE_AVAILABLE, info).sendToTarget(); 162 } 163 deviceUnavailableFromNative(int deviceId)164 private void deviceUnavailableFromNative(int deviceId) { 165 mHandler.obtainMessage(EVENT_DEVICE_UNAVAILABLE, deviceId, 0).sendToTarget(); 166 } 167 streamConfigsChangedFromNative(int deviceId, int cableConnectionStatus)168 private void streamConfigsChangedFromNative(int deviceId, int cableConnectionStatus) { 169 mHandler.obtainMessage(EVENT_STREAM_CONFIGURATION_CHANGED, deviceId, 170 cableConnectionStatus).sendToTarget(); 171 } 172 firstFrameCapturedFromNative(int deviceId, int streamId)173 private void firstFrameCapturedFromNative(int deviceId, int streamId) { 174 mHandler.sendMessage( 175 mHandler.obtainMessage(EVENT_STREAM_CONFIGURATION_CHANGED, deviceId, streamId)); 176 } 177 tvMessageReceivedFromNative(int deviceId, int type, Bundle data)178 private void tvMessageReceivedFromNative(int deviceId, int type, Bundle data) { 179 mHandler.obtainMessage(EVENT_TV_MESSAGE, deviceId, type, data).sendToTarget(); 180 } 181 182 // Handler.Callback implementation 183 184 @Override handleMessage(Message msg)185 public boolean handleMessage(Message msg) { 186 switch (msg.what) { 187 case EVENT_DEVICE_AVAILABLE: { 188 TvStreamConfig[] configs; 189 TvInputHardwareInfo info = (TvInputHardwareInfo)msg.obj; 190 synchronized (mLock) { 191 retrieveStreamConfigsLocked(info.getDeviceId()); 192 if (DEBUG) { 193 Slog.d(TAG, "EVENT_DEVICE_AVAILABLE: info = " + info); 194 } 195 configs = mStreamConfigs.get(info.getDeviceId()); 196 } 197 mCallback.onDeviceAvailable(info, configs); 198 break; 199 } 200 201 case EVENT_DEVICE_UNAVAILABLE: { 202 int deviceId = msg.arg1; 203 if (DEBUG) { 204 Slog.d(TAG, "EVENT_DEVICE_UNAVAILABLE: deviceId = " + deviceId); 205 } 206 mCallback.onDeviceUnavailable(deviceId); 207 break; 208 } 209 210 case EVENT_STREAM_CONFIGURATION_CHANGED: { 211 TvStreamConfig[] configs; 212 int deviceId = msg.arg1; 213 int cableConnectionStatus = msg.arg2; 214 synchronized (mLock) { 215 if (DEBUG) { 216 Slog.d(TAG, "EVENT_STREAM_CONFIGURATION_CHANGED: deviceId = " + deviceId); 217 } 218 retrieveStreamConfigsLocked(deviceId); 219 configs = mStreamConfigs.get(deviceId); 220 } 221 mCallback.onStreamConfigurationChanged(deviceId, configs, cableConnectionStatus); 222 break; 223 } 224 225 case EVENT_FIRST_FRAME_CAPTURED: { 226 int deviceId = msg.arg1; 227 int streamId = msg.arg2; 228 mCallback.onFirstFrameCaptured(deviceId, streamId); 229 break; 230 } 231 232 case EVENT_TV_MESSAGE: { 233 int deviceId = msg.arg1; 234 int type = msg.arg2; 235 Bundle data = (Bundle) msg.obj; 236 mCallback.onTvMessage(deviceId, type, data); 237 break; 238 } 239 240 default: 241 Slog.e(TAG, "Unknown event: " + msg); 242 return false; 243 } 244 245 return true; 246 } 247 } 248