1c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim/* 2c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * Copyright 2014 The Android Open Source Project 3c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * 4c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * Licensed under the Apache License, Version 2.0 (the "License"); 5c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * you may not use this file except in compliance with the License. 6c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * You may obtain a copy of the License at 7c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * 8c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * http://www.apache.org/licenses/LICENSE-2.0 9c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * 10c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * Unless required by applicable law or agreed to in writing, software 11c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * distributed under the License is distributed on an "AS IS" BASIS, 12c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * See the License for the specific language governing permissions and 14c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * limitations under the License. 15c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim */ 16c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 17c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimpackage com.android.server.tv; 18c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 19d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.TvInputHardwareInfo; 20d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.TvStreamConfig; 21c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimimport android.os.Handler; 229e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kimimport android.os.Message; 2357b37f610d33989f1b23e1b8d9e61fb177456364Wonsik Kimimport android.os.MessageQueue; 249e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kimimport android.util.Slog; 2521aa3467cd14260418cc47334b656adf841a567cWonsik Kimimport android.util.SparseArray; 2621aa3467cd14260418cc47334b656adf841a567cWonsik Kimimport android.util.SparseIntArray; 275b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seoimport android.view.Surface; 289e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim 299e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kimimport java.util.LinkedList; 309e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kimimport java.util.Queue; 31c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 32c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim/** 33c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * Provides access to the low-level TV input hardware abstraction layer. 34c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim */ 359e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kimfinal class TvInputHal implements Handler.Callback { 36ee2ec05ed7c0d3cb9115f4ddd7c3613269c4a57bJae Seo private final static boolean DEBUG = false; 379e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim private final static String TAG = TvInputHal.class.getSimpleName(); 389e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim 39c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public final static int SUCCESS = 0; 40c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public final static int ERROR_NO_INIT = -1; 41c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public final static int ERROR_STALE_CONFIG = -2; 42c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public final static int ERROR_UNKNOWN = -3; 43c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 449e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim public static final int EVENT_DEVICE_AVAILABLE = 1; 459e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim public static final int EVENT_DEVICE_UNAVAILABLE = 2; 469e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim public static final int EVENT_STREAM_CONFIGURATION_CHANGED = 3; 47c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo public static final int EVENT_FIRST_FRAME_CAPTURED = 4; 489e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim 49c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public interface Callback { 506e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo void onDeviceAvailable(TvInputHardwareInfo info, TvStreamConfig[] configs); 516e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo void onDeviceUnavailable(int deviceId); 526e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo void onStreamConfigurationChanged(int deviceId, TvStreamConfig[] configs); 536e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo void onFirstFrameCaptured(int deviceId, int streamId); 54c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 55c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 5657b37f610d33989f1b23e1b8d9e61fb177456364Wonsik Kim private native long nativeOpen(MessageQueue queue); 57c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 588f24a8b60f9afc1aedb89e7ee80ce65515439600Wonsik Kim private static native int nativeAddOrUpdateStream(long ptr, int deviceId, int streamId, 59c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Surface surface); 60839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim private static native int nativeRemoveStream(long ptr, int deviceId, int streamId); 61c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private static native TvStreamConfig[] nativeGetStreamConfigs(long ptr, int deviceId, 62c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim int generation); 63c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private static native void nativeClose(long ptr); 64c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 655b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo private final Object mLock = new Object(); 66610ccd9117fc1611fcc576d1cb1f717f1ef3fcbfWonsik Kim private long mPtr = 0; 67c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private final Callback mCallback; 68c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private final Handler mHandler; 695b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo private final SparseIntArray mStreamConfigGenerations = new SparseIntArray(); 705b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo private final SparseArray<TvStreamConfig[]> mStreamConfigs = new SparseArray<>(); 71c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 72c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public TvInputHal(Callback callback) { 73c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mCallback = callback; 74610ccd9117fc1611fcc576d1cb1f717f1ef3fcbfWonsik Kim mHandler = new Handler(this); 75c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 76c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 7721aa3467cd14260418cc47334b656adf841a567cWonsik Kim public void init() { 7821aa3467cd14260418cc47334b656adf841a567cWonsik Kim synchronized (mLock) { 7957b37f610d33989f1b23e1b8d9e61fb177456364Wonsik Kim mPtr = nativeOpen(mHandler.getLooper().getQueue()); 8021aa3467cd14260418cc47334b656adf841a567cWonsik Kim } 81c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 82c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 838f24a8b60f9afc1aedb89e7ee80ce65515439600Wonsik Kim public int addOrUpdateStream(int deviceId, Surface surface, TvStreamConfig streamConfig) { 8421aa3467cd14260418cc47334b656adf841a567cWonsik Kim synchronized (mLock) { 8521aa3467cd14260418cc47334b656adf841a567cWonsik Kim if (mPtr == 0) { 8621aa3467cd14260418cc47334b656adf841a567cWonsik Kim return ERROR_NO_INIT; 8721aa3467cd14260418cc47334b656adf841a567cWonsik Kim } 8821aa3467cd14260418cc47334b656adf841a567cWonsik Kim int generation = mStreamConfigGenerations.get(deviceId, 0); 8921aa3467cd14260418cc47334b656adf841a567cWonsik Kim if (generation != streamConfig.getGeneration()) { 9021aa3467cd14260418cc47334b656adf841a567cWonsik Kim return ERROR_STALE_CONFIG; 9121aa3467cd14260418cc47334b656adf841a567cWonsik Kim } 928f24a8b60f9afc1aedb89e7ee80ce65515439600Wonsik Kim if (nativeAddOrUpdateStream(mPtr, deviceId, streamConfig.getStreamId(), surface) == 0) { 9321aa3467cd14260418cc47334b656adf841a567cWonsik Kim return SUCCESS; 9421aa3467cd14260418cc47334b656adf841a567cWonsik Kim } else { 9521aa3467cd14260418cc47334b656adf841a567cWonsik Kim return ERROR_UNKNOWN; 9621aa3467cd14260418cc47334b656adf841a567cWonsik Kim } 97839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim } 98839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim } 99839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim 10021aa3467cd14260418cc47334b656adf841a567cWonsik Kim public int removeStream(int deviceId, TvStreamConfig streamConfig) { 10121aa3467cd14260418cc47334b656adf841a567cWonsik Kim synchronized (mLock) { 10221aa3467cd14260418cc47334b656adf841a567cWonsik Kim if (mPtr == 0) { 10321aa3467cd14260418cc47334b656adf841a567cWonsik Kim return ERROR_NO_INIT; 10421aa3467cd14260418cc47334b656adf841a567cWonsik Kim } 10521aa3467cd14260418cc47334b656adf841a567cWonsik Kim int generation = mStreamConfigGenerations.get(deviceId, 0); 10621aa3467cd14260418cc47334b656adf841a567cWonsik Kim if (generation != streamConfig.getGeneration()) { 10721aa3467cd14260418cc47334b656adf841a567cWonsik Kim return ERROR_STALE_CONFIG; 10821aa3467cd14260418cc47334b656adf841a567cWonsik Kim } 10921aa3467cd14260418cc47334b656adf841a567cWonsik Kim if (nativeRemoveStream(mPtr, deviceId, streamConfig.getStreamId()) == 0) { 11021aa3467cd14260418cc47334b656adf841a567cWonsik Kim return SUCCESS; 11121aa3467cd14260418cc47334b656adf841a567cWonsik Kim } else { 11221aa3467cd14260418cc47334b656adf841a567cWonsik Kim return ERROR_UNKNOWN; 11321aa3467cd14260418cc47334b656adf841a567cWonsik Kim } 114c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 115c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 116c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 11721aa3467cd14260418cc47334b656adf841a567cWonsik Kim public void close() { 11821aa3467cd14260418cc47334b656adf841a567cWonsik Kim synchronized (mLock) { 11921aa3467cd14260418cc47334b656adf841a567cWonsik Kim if (mPtr != 0l) { 12021aa3467cd14260418cc47334b656adf841a567cWonsik Kim nativeClose(mPtr); 12121aa3467cd14260418cc47334b656adf841a567cWonsik Kim } 122c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 123c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 124c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 12521aa3467cd14260418cc47334b656adf841a567cWonsik Kim private void retrieveStreamConfigsLocked(int deviceId) { 12621aa3467cd14260418cc47334b656adf841a567cWonsik Kim int generation = mStreamConfigGenerations.get(deviceId, 0) + 1; 12721aa3467cd14260418cc47334b656adf841a567cWonsik Kim mStreamConfigs.put(deviceId, nativeGetStreamConfigs(mPtr, deviceId, generation)); 12821aa3467cd14260418cc47334b656adf841a567cWonsik Kim mStreamConfigGenerations.put(deviceId, generation); 129c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 130c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 131c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim // Called from native 1329e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim private void deviceAvailableFromNative(TvInputHardwareInfo info) { 133610ccd9117fc1611fcc576d1cb1f717f1ef3fcbfWonsik Kim if (DEBUG) { 134610ccd9117fc1611fcc576d1cb1f717f1ef3fcbfWonsik Kim Slog.d(TAG, "deviceAvailableFromNative: info = " + info); 135610ccd9117fc1611fcc576d1cb1f717f1ef3fcbfWonsik Kim } 136610ccd9117fc1611fcc576d1cb1f717f1ef3fcbfWonsik Kim mHandler.obtainMessage(EVENT_DEVICE_AVAILABLE, info).sendToTarget(); 1379e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim } 1389e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim 1399e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim private void deviceUnavailableFromNative(int deviceId) { 140610ccd9117fc1611fcc576d1cb1f717f1ef3fcbfWonsik Kim mHandler.obtainMessage(EVENT_DEVICE_UNAVAILABLE, deviceId, 0).sendToTarget(); 1419e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim } 1429e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim 1439e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim private void streamConfigsChangedFromNative(int deviceId) { 144610ccd9117fc1611fcc576d1cb1f717f1ef3fcbfWonsik Kim mHandler.obtainMessage(EVENT_STREAM_CONFIGURATION_CHANGED, deviceId, 0).sendToTarget(); 1459e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim } 1469e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim 147c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo private void firstFrameCapturedFromNative(int deviceId, int streamId) { 148c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo mHandler.sendMessage( 149c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo mHandler.obtainMessage(EVENT_STREAM_CONFIGURATION_CHANGED, deviceId, streamId)); 150c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 151c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 1529e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim // Handler.Callback implementation 1539e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim 1546e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo private final Queue<Message> mPendingMessageQueue = new LinkedList<>(); 1559e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim 1569e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim @Override 1579e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim public boolean handleMessage(Message msg) { 1589e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim switch (msg.what) { 1599e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim case EVENT_DEVICE_AVAILABLE: { 16021aa3467cd14260418cc47334b656adf841a567cWonsik Kim TvStreamConfig[] configs; 1619e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim TvInputHardwareInfo info = (TvInputHardwareInfo)msg.obj; 16221aa3467cd14260418cc47334b656adf841a567cWonsik Kim synchronized (mLock) { 16321aa3467cd14260418cc47334b656adf841a567cWonsik Kim retrieveStreamConfigsLocked(info.getDeviceId()); 16421aa3467cd14260418cc47334b656adf841a567cWonsik Kim if (DEBUG) { 16521aa3467cd14260418cc47334b656adf841a567cWonsik Kim Slog.d(TAG, "EVENT_DEVICE_AVAILABLE: info = " + info); 16621aa3467cd14260418cc47334b656adf841a567cWonsik Kim } 16721aa3467cd14260418cc47334b656adf841a567cWonsik Kim configs = mStreamConfigs.get(info.getDeviceId()); 168610ccd9117fc1611fcc576d1cb1f717f1ef3fcbfWonsik Kim } 16921aa3467cd14260418cc47334b656adf841a567cWonsik Kim mCallback.onDeviceAvailable(info, configs); 1709e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim break; 171c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 172c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 1739e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim case EVENT_DEVICE_UNAVAILABLE: { 1749e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim int deviceId = msg.arg1; 175610ccd9117fc1611fcc576d1cb1f717f1ef3fcbfWonsik Kim if (DEBUG) { 176610ccd9117fc1611fcc576d1cb1f717f1ef3fcbfWonsik Kim Slog.d(TAG, "EVENT_DEVICE_UNAVAILABLE: deviceId = " + deviceId); 177610ccd9117fc1611fcc576d1cb1f717f1ef3fcbfWonsik Kim } 178d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim mCallback.onDeviceUnavailable(deviceId); 1799e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim break; 180c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 181c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 1829e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim case EVENT_STREAM_CONFIGURATION_CHANGED: { 18321aa3467cd14260418cc47334b656adf841a567cWonsik Kim TvStreamConfig[] configs; 1849e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim int deviceId = msg.arg1; 18521aa3467cd14260418cc47334b656adf841a567cWonsik Kim synchronized (mLock) { 18621aa3467cd14260418cc47334b656adf841a567cWonsik Kim if (DEBUG) { 18721aa3467cd14260418cc47334b656adf841a567cWonsik Kim Slog.d(TAG, "EVENT_STREAM_CONFIGURATION_CHANGED: deviceId = " + deviceId); 18821aa3467cd14260418cc47334b656adf841a567cWonsik Kim } 18921aa3467cd14260418cc47334b656adf841a567cWonsik Kim retrieveStreamConfigsLocked(deviceId); 19021aa3467cd14260418cc47334b656adf841a567cWonsik Kim configs = mStreamConfigs.get(deviceId); 191610ccd9117fc1611fcc576d1cb1f717f1ef3fcbfWonsik Kim } 19221aa3467cd14260418cc47334b656adf841a567cWonsik Kim mCallback.onStreamConfigurationChanged(deviceId, configs); 1939e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim break; 194c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 1959e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim 196c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo case EVENT_FIRST_FRAME_CAPTURED: { 197c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo int deviceId = msg.arg1; 198c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo int streamId = msg.arg2; 199c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo mCallback.onFirstFrameCaptured(deviceId, streamId); 200c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo break; 201c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 202c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 2039e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim default: 2049e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim Slog.e(TAG, "Unknown event: " + msg); 205610ccd9117fc1611fcc576d1cb1f717f1ef3fcbfWonsik Kim return false; 2069e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim } 207610ccd9117fc1611fcc576d1cb1f717f1ef3fcbfWonsik Kim 208610ccd9117fc1611fcc576d1cb1f717f1ef3fcbfWonsik Kim return true; 209c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 210c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim} 211