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 1939f285d5a75f653d2d2309b47cfaa143da42a0caShubangimport android.hardware.tv.input.V1_0.Constants; 20d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.TvInputHardwareInfo; 21d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.TvStreamConfig; 22c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimimport android.os.Handler; 239e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kimimport android.os.Message; 2457b37f610d33989f1b23e1b8d9e61fb177456364Wonsik Kimimport android.os.MessageQueue; 259e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kimimport android.util.Slog; 2621aa3467cd14260418cc47334b656adf841a567cWonsik Kimimport android.util.SparseArray; 2721aa3467cd14260418cc47334b656adf841a567cWonsik Kimimport android.util.SparseIntArray; 285b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seoimport android.view.Surface; 299e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim 309e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kimimport java.util.LinkedList; 319e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kimimport java.util.Queue; 32c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 33c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim/** 34c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * Provides access to the low-level TV input hardware abstraction layer. 35c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim */ 369e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kimfinal class TvInputHal implements Handler.Callback { 37ee2ec05ed7c0d3cb9115f4ddd7c3613269c4a57bJae Seo private final static boolean DEBUG = false; 389e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim private final static String TAG = TvInputHal.class.getSimpleName(); 399e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim 40c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public final static int SUCCESS = 0; 41c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public final static int ERROR_NO_INIT = -1; 42c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public final static int ERROR_STALE_CONFIG = -2; 43c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public final static int ERROR_UNKNOWN = -3; 44c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 4539f285d5a75f653d2d2309b47cfaa143da42a0caShubang public static final int EVENT_DEVICE_AVAILABLE = Constants.EVENT_DEVICE_AVAILABLE; 4639f285d5a75f653d2d2309b47cfaa143da42a0caShubang public static final int EVENT_DEVICE_UNAVAILABLE = Constants.EVENT_DEVICE_UNAVAILABLE; 4739f285d5a75f653d2d2309b47cfaa143da42a0caShubang public static final int EVENT_STREAM_CONFIGURATION_CHANGED = 4839f285d5a75f653d2d2309b47cfaa143da42a0caShubang Constants.EVENT_STREAM_CONFIGURATIONS_CHANGED; 49c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo public static final int EVENT_FIRST_FRAME_CAPTURED = 4; 509e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim 51c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public interface Callback { 526e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo void onDeviceAvailable(TvInputHardwareInfo info, TvStreamConfig[] configs); 536e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo void onDeviceUnavailable(int deviceId); 546e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo void onStreamConfigurationChanged(int deviceId, TvStreamConfig[] configs); 556e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo void onFirstFrameCaptured(int deviceId, int streamId); 56c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 57c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 5857b37f610d33989f1b23e1b8d9e61fb177456364Wonsik Kim private native long nativeOpen(MessageQueue queue); 59c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 608f24a8b60f9afc1aedb89e7ee80ce65515439600Wonsik Kim private static native int nativeAddOrUpdateStream(long ptr, int deviceId, int streamId, 61c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Surface surface); 62839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim private static native int nativeRemoveStream(long ptr, int deviceId, int streamId); 63c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private static native TvStreamConfig[] nativeGetStreamConfigs(long ptr, int deviceId, 64c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim int generation); 65c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private static native void nativeClose(long ptr); 66c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 675b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo private final Object mLock = new Object(); 68610ccd9117fc1611fcc576d1cb1f717f1ef3fcbfWonsik Kim private long mPtr = 0; 69c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private final Callback mCallback; 70c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private final Handler mHandler; 715b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo private final SparseIntArray mStreamConfigGenerations = new SparseIntArray(); 725b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo private final SparseArray<TvStreamConfig[]> mStreamConfigs = new SparseArray<>(); 73c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 74c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public TvInputHal(Callback callback) { 75c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mCallback = callback; 76610ccd9117fc1611fcc576d1cb1f717f1ef3fcbfWonsik Kim mHandler = new Handler(this); 77c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 78c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 7921aa3467cd14260418cc47334b656adf841a567cWonsik Kim public void init() { 8021aa3467cd14260418cc47334b656adf841a567cWonsik Kim synchronized (mLock) { 8157b37f610d33989f1b23e1b8d9e61fb177456364Wonsik Kim mPtr = nativeOpen(mHandler.getLooper().getQueue()); 8221aa3467cd14260418cc47334b656adf841a567cWonsik Kim } 83c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 84c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 858f24a8b60f9afc1aedb89e7ee80ce65515439600Wonsik Kim public int addOrUpdateStream(int deviceId, Surface surface, TvStreamConfig streamConfig) { 8621aa3467cd14260418cc47334b656adf841a567cWonsik Kim synchronized (mLock) { 8721aa3467cd14260418cc47334b656adf841a567cWonsik Kim if (mPtr == 0) { 8821aa3467cd14260418cc47334b656adf841a567cWonsik Kim return ERROR_NO_INIT; 8921aa3467cd14260418cc47334b656adf841a567cWonsik Kim } 9021aa3467cd14260418cc47334b656adf841a567cWonsik Kim int generation = mStreamConfigGenerations.get(deviceId, 0); 9121aa3467cd14260418cc47334b656adf841a567cWonsik Kim if (generation != streamConfig.getGeneration()) { 9221aa3467cd14260418cc47334b656adf841a567cWonsik Kim return ERROR_STALE_CONFIG; 9321aa3467cd14260418cc47334b656adf841a567cWonsik Kim } 948f24a8b60f9afc1aedb89e7ee80ce65515439600Wonsik Kim if (nativeAddOrUpdateStream(mPtr, deviceId, streamConfig.getStreamId(), surface) == 0) { 9521aa3467cd14260418cc47334b656adf841a567cWonsik Kim return SUCCESS; 9621aa3467cd14260418cc47334b656adf841a567cWonsik Kim } else { 9721aa3467cd14260418cc47334b656adf841a567cWonsik Kim return ERROR_UNKNOWN; 9821aa3467cd14260418cc47334b656adf841a567cWonsik Kim } 99839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim } 100839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim } 101839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim 10221aa3467cd14260418cc47334b656adf841a567cWonsik Kim public int removeStream(int deviceId, TvStreamConfig streamConfig) { 10321aa3467cd14260418cc47334b656adf841a567cWonsik Kim synchronized (mLock) { 10421aa3467cd14260418cc47334b656adf841a567cWonsik Kim if (mPtr == 0) { 10521aa3467cd14260418cc47334b656adf841a567cWonsik Kim return ERROR_NO_INIT; 10621aa3467cd14260418cc47334b656adf841a567cWonsik Kim } 10721aa3467cd14260418cc47334b656adf841a567cWonsik Kim int generation = mStreamConfigGenerations.get(deviceId, 0); 10821aa3467cd14260418cc47334b656adf841a567cWonsik Kim if (generation != streamConfig.getGeneration()) { 10921aa3467cd14260418cc47334b656adf841a567cWonsik Kim return ERROR_STALE_CONFIG; 11021aa3467cd14260418cc47334b656adf841a567cWonsik Kim } 11121aa3467cd14260418cc47334b656adf841a567cWonsik Kim if (nativeRemoveStream(mPtr, deviceId, streamConfig.getStreamId()) == 0) { 11221aa3467cd14260418cc47334b656adf841a567cWonsik Kim return SUCCESS; 11321aa3467cd14260418cc47334b656adf841a567cWonsik Kim } else { 11421aa3467cd14260418cc47334b656adf841a567cWonsik Kim return ERROR_UNKNOWN; 11521aa3467cd14260418cc47334b656adf841a567cWonsik Kim } 116c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 117c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 118c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 11921aa3467cd14260418cc47334b656adf841a567cWonsik Kim public void close() { 12021aa3467cd14260418cc47334b656adf841a567cWonsik Kim synchronized (mLock) { 1212a2b299dca20b151d5dc5bda3d068d70e6f15f6cJae Seo if (mPtr != 0L) { 12221aa3467cd14260418cc47334b656adf841a567cWonsik Kim nativeClose(mPtr); 12321aa3467cd14260418cc47334b656adf841a567cWonsik Kim } 124c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 125c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 126c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 12721aa3467cd14260418cc47334b656adf841a567cWonsik Kim private void retrieveStreamConfigsLocked(int deviceId) { 12821aa3467cd14260418cc47334b656adf841a567cWonsik Kim int generation = mStreamConfigGenerations.get(deviceId, 0) + 1; 12921aa3467cd14260418cc47334b656adf841a567cWonsik Kim mStreamConfigs.put(deviceId, nativeGetStreamConfigs(mPtr, deviceId, generation)); 13021aa3467cd14260418cc47334b656adf841a567cWonsik Kim mStreamConfigGenerations.put(deviceId, generation); 131c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 132c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 133c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim // Called from native 1349e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim private void deviceAvailableFromNative(TvInputHardwareInfo info) { 135610ccd9117fc1611fcc576d1cb1f717f1ef3fcbfWonsik Kim if (DEBUG) { 136610ccd9117fc1611fcc576d1cb1f717f1ef3fcbfWonsik Kim Slog.d(TAG, "deviceAvailableFromNative: info = " + info); 137610ccd9117fc1611fcc576d1cb1f717f1ef3fcbfWonsik Kim } 138610ccd9117fc1611fcc576d1cb1f717f1ef3fcbfWonsik Kim mHandler.obtainMessage(EVENT_DEVICE_AVAILABLE, info).sendToTarget(); 1399e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim } 1409e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim 1419e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim private void deviceUnavailableFromNative(int deviceId) { 142610ccd9117fc1611fcc576d1cb1f717f1ef3fcbfWonsik Kim mHandler.obtainMessage(EVENT_DEVICE_UNAVAILABLE, deviceId, 0).sendToTarget(); 1439e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim } 1449e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim 1459e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim private void streamConfigsChangedFromNative(int deviceId) { 146610ccd9117fc1611fcc576d1cb1f717f1ef3fcbfWonsik Kim mHandler.obtainMessage(EVENT_STREAM_CONFIGURATION_CHANGED, deviceId, 0).sendToTarget(); 1479e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim } 1489e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim 149c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo private void firstFrameCapturedFromNative(int deviceId, int streamId) { 150c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo mHandler.sendMessage( 151c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo mHandler.obtainMessage(EVENT_STREAM_CONFIGURATION_CHANGED, deviceId, streamId)); 152c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 153c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 1549e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim // Handler.Callback implementation 1559e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim 1566e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo private final Queue<Message> mPendingMessageQueue = new LinkedList<>(); 1579e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim 1589e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim @Override 1599e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim public boolean handleMessage(Message msg) { 1609e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim switch (msg.what) { 1619e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim case EVENT_DEVICE_AVAILABLE: { 16221aa3467cd14260418cc47334b656adf841a567cWonsik Kim TvStreamConfig[] configs; 1639e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim TvInputHardwareInfo info = (TvInputHardwareInfo)msg.obj; 16421aa3467cd14260418cc47334b656adf841a567cWonsik Kim synchronized (mLock) { 16521aa3467cd14260418cc47334b656adf841a567cWonsik Kim retrieveStreamConfigsLocked(info.getDeviceId()); 16621aa3467cd14260418cc47334b656adf841a567cWonsik Kim if (DEBUG) { 16721aa3467cd14260418cc47334b656adf841a567cWonsik Kim Slog.d(TAG, "EVENT_DEVICE_AVAILABLE: info = " + info); 16821aa3467cd14260418cc47334b656adf841a567cWonsik Kim } 16921aa3467cd14260418cc47334b656adf841a567cWonsik Kim configs = mStreamConfigs.get(info.getDeviceId()); 170610ccd9117fc1611fcc576d1cb1f717f1ef3fcbfWonsik Kim } 17121aa3467cd14260418cc47334b656adf841a567cWonsik Kim mCallback.onDeviceAvailable(info, configs); 1729e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim break; 173c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 174c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 1759e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim case EVENT_DEVICE_UNAVAILABLE: { 1769e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim int deviceId = msg.arg1; 177610ccd9117fc1611fcc576d1cb1f717f1ef3fcbfWonsik Kim if (DEBUG) { 178610ccd9117fc1611fcc576d1cb1f717f1ef3fcbfWonsik Kim Slog.d(TAG, "EVENT_DEVICE_UNAVAILABLE: deviceId = " + deviceId); 179610ccd9117fc1611fcc576d1cb1f717f1ef3fcbfWonsik Kim } 180d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim mCallback.onDeviceUnavailable(deviceId); 1819e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim break; 182c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 183c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 1849e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim case EVENT_STREAM_CONFIGURATION_CHANGED: { 18521aa3467cd14260418cc47334b656adf841a567cWonsik Kim TvStreamConfig[] configs; 1869e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim int deviceId = msg.arg1; 18721aa3467cd14260418cc47334b656adf841a567cWonsik Kim synchronized (mLock) { 18821aa3467cd14260418cc47334b656adf841a567cWonsik Kim if (DEBUG) { 18921aa3467cd14260418cc47334b656adf841a567cWonsik Kim Slog.d(TAG, "EVENT_STREAM_CONFIGURATION_CHANGED: deviceId = " + deviceId); 19021aa3467cd14260418cc47334b656adf841a567cWonsik Kim } 19121aa3467cd14260418cc47334b656adf841a567cWonsik Kim retrieveStreamConfigsLocked(deviceId); 19221aa3467cd14260418cc47334b656adf841a567cWonsik Kim configs = mStreamConfigs.get(deviceId); 193610ccd9117fc1611fcc576d1cb1f717f1ef3fcbfWonsik Kim } 19421aa3467cd14260418cc47334b656adf841a567cWonsik Kim mCallback.onStreamConfigurationChanged(deviceId, configs); 1959e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim break; 196c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 1979e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim 198c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo case EVENT_FIRST_FRAME_CAPTURED: { 199c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo int deviceId = msg.arg1; 200c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo int streamId = msg.arg2; 201c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo mCallback.onFirstFrameCaptured(deviceId, streamId); 202c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo break; 203c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 204c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 2059e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim default: 2069e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim Slog.e(TAG, "Unknown event: " + msg); 207610ccd9117fc1611fcc576d1cb1f717f1ef3fcbfWonsik Kim return false; 2089e922ca97097cb1aa67ff53219d874ea2503a80dWonsik Kim } 209610ccd9117fc1611fcc576d1cb1f717f1ef3fcbfWonsik Kim 210610ccd9117fc1611fcc576d1cb1f717f1ef3fcbfWonsik Kim return true; 211c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 212c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim} 213