blob: ebbb8b315d00083a873e213bb5543ba05ec6020b [file] [log] [blame]
Wonsik Kimc22dbb62014-05-26 02:26:04 +00001/*
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
17package com.android.server.tv;
18
Jae Seod5cc4a22014-05-30 16:57:43 -070019import android.media.tv.TvInputHardwareInfo;
20import android.media.tv.TvStreamConfig;
Wonsik Kimc22dbb62014-05-26 02:26:04 +000021import android.os.Handler;
Wonsik Kim9e922ca2014-06-20 17:27:32 +090022import android.os.Message;
Wonsik Kim57b37f62014-12-17 11:18:36 +090023import android.os.MessageQueue;
Wonsik Kim9e922ca2014-06-20 17:27:32 +090024import android.util.Slog;
Wonsik Kim21aa3462014-07-29 16:39:00 +090025import android.util.SparseArray;
26import android.util.SparseIntArray;
Jae Seo5b1caaf2014-08-18 15:03:33 -070027import android.view.Surface;
Wonsik Kim9e922ca2014-06-20 17:27:32 +090028
29import java.util.LinkedList;
30import java.util.Queue;
Wonsik Kimc22dbb62014-05-26 02:26:04 +000031
32/**
33 * Provides access to the low-level TV input hardware abstraction layer.
34 */
Wonsik Kim9e922ca2014-06-20 17:27:32 +090035final class TvInputHal implements Handler.Callback {
Jae Seoee2ec052014-09-14 10:30:05 -070036 private final static boolean DEBUG = false;
Wonsik Kim9e922ca2014-06-20 17:27:32 +090037 private final static String TAG = TvInputHal.class.getSimpleName();
38
Wonsik Kimc22dbb62014-05-26 02:26:04 +000039 public final static int SUCCESS = 0;
40 public final static int ERROR_NO_INIT = -1;
41 public final static int ERROR_STALE_CONFIG = -2;
42 public final static int ERROR_UNKNOWN = -3;
43
Wonsik Kim9e922ca2014-06-20 17:27:32 +090044 public static final int EVENT_DEVICE_AVAILABLE = 1;
45 public static final int EVENT_DEVICE_UNAVAILABLE = 2;
46 public static final int EVENT_STREAM_CONFIGURATION_CHANGED = 3;
Terry Heoc086a3d2014-06-18 14:26:44 +090047 public static final int EVENT_FIRST_FRAME_CAPTURED = 4;
Wonsik Kim9e922ca2014-06-20 17:27:32 +090048
Wonsik Kimc22dbb62014-05-26 02:26:04 +000049 public interface Callback {
Jae Seo6e4cbfd2015-06-21 16:40:34 -070050 void onDeviceAvailable(TvInputHardwareInfo info, TvStreamConfig[] configs);
51 void onDeviceUnavailable(int deviceId);
52 void onStreamConfigurationChanged(int deviceId, TvStreamConfig[] configs);
53 void onFirstFrameCaptured(int deviceId, int streamId);
Wonsik Kimc22dbb62014-05-26 02:26:04 +000054 }
55
Wonsik Kim57b37f62014-12-17 11:18:36 +090056 private native long nativeOpen(MessageQueue queue);
Wonsik Kimc22dbb62014-05-26 02:26:04 +000057
Wonsik Kim8f24a8b2014-10-22 16:27:39 +090058 private static native int nativeAddOrUpdateStream(long ptr, int deviceId, int streamId,
Wonsik Kimc22dbb62014-05-26 02:26:04 +000059 Surface surface);
Wonsik Kim839ae5f2014-07-03 19:06:56 +090060 private static native int nativeRemoveStream(long ptr, int deviceId, int streamId);
Wonsik Kimc22dbb62014-05-26 02:26:04 +000061 private static native TvStreamConfig[] nativeGetStreamConfigs(long ptr, int deviceId,
62 int generation);
63 private static native void nativeClose(long ptr);
64
Jae Seo5b1caaf2014-08-18 15:03:33 -070065 private final Object mLock = new Object();
Wonsik Kim610ccd92014-07-19 18:49:49 +090066 private long mPtr = 0;
Wonsik Kimc22dbb62014-05-26 02:26:04 +000067 private final Callback mCallback;
Wonsik Kimc22dbb62014-05-26 02:26:04 +000068 private final Handler mHandler;
Jae Seo5b1caaf2014-08-18 15:03:33 -070069 private final SparseIntArray mStreamConfigGenerations = new SparseIntArray();
70 private final SparseArray<TvStreamConfig[]> mStreamConfigs = new SparseArray<>();
Wonsik Kimc22dbb62014-05-26 02:26:04 +000071
72 public TvInputHal(Callback callback) {
73 mCallback = callback;
Wonsik Kim610ccd92014-07-19 18:49:49 +090074 mHandler = new Handler(this);
Wonsik Kimc22dbb62014-05-26 02:26:04 +000075 }
76
Wonsik Kim21aa3462014-07-29 16:39:00 +090077 public void init() {
78 synchronized (mLock) {
Wonsik Kim57b37f62014-12-17 11:18:36 +090079 mPtr = nativeOpen(mHandler.getLooper().getQueue());
Wonsik Kim839ae5f2014-07-03 19:06:56 +090080 }
81 }
82
Wonsik Kim8f24a8b2014-10-22 16:27:39 +090083 public int addOrUpdateStream(int deviceId, Surface surface, TvStreamConfig streamConfig) {
Wonsik Kim21aa3462014-07-29 16:39:00 +090084 synchronized (mLock) {
85 if (mPtr == 0) {
86 return ERROR_NO_INIT;
87 }
88 int generation = mStreamConfigGenerations.get(deviceId, 0);
89 if (generation != streamConfig.getGeneration()) {
90 return ERROR_STALE_CONFIG;
91 }
Wonsik Kim8f24a8b2014-10-22 16:27:39 +090092 if (nativeAddOrUpdateStream(mPtr, deviceId, streamConfig.getStreamId(), surface) == 0) {
Wonsik Kim21aa3462014-07-29 16:39:00 +090093 return SUCCESS;
94 } else {
95 return ERROR_UNKNOWN;
96 }
Wonsik Kimc22dbb62014-05-26 02:26:04 +000097 }
98 }
99
Wonsik Kim21aa3462014-07-29 16:39:00 +0900100 public int removeStream(int deviceId, TvStreamConfig streamConfig) {
101 synchronized (mLock) {
102 if (mPtr == 0) {
103 return ERROR_NO_INIT;
104 }
105 int generation = mStreamConfigGenerations.get(deviceId, 0);
106 if (generation != streamConfig.getGeneration()) {
107 return ERROR_STALE_CONFIG;
108 }
109 if (nativeRemoveStream(mPtr, deviceId, streamConfig.getStreamId()) == 0) {
110 return SUCCESS;
111 } else {
112 return ERROR_UNKNOWN;
113 }
Wonsik Kimc22dbb62014-05-26 02:26:04 +0000114 }
115 }
116
Wonsik Kim21aa3462014-07-29 16:39:00 +0900117 public void close() {
118 synchronized (mLock) {
Jae Seo2a2b2992016-01-12 23:13:14 -0800119 if (mPtr != 0L) {
Wonsik Kim21aa3462014-07-29 16:39:00 +0900120 nativeClose(mPtr);
121 }
122 }
123 }
124
125 private void retrieveStreamConfigsLocked(int deviceId) {
126 int generation = mStreamConfigGenerations.get(deviceId, 0) + 1;
127 mStreamConfigs.put(deviceId, nativeGetStreamConfigs(mPtr, deviceId, generation));
128 mStreamConfigGenerations.put(deviceId, generation);
Wonsik Kimc22dbb62014-05-26 02:26:04 +0000129 }
130
131 // Called from native
Wonsik Kim9e922ca2014-06-20 17:27:32 +0900132 private void deviceAvailableFromNative(TvInputHardwareInfo info) {
Wonsik Kim610ccd92014-07-19 18:49:49 +0900133 if (DEBUG) {
134 Slog.d(TAG, "deviceAvailableFromNative: info = " + info);
135 }
136 mHandler.obtainMessage(EVENT_DEVICE_AVAILABLE, info).sendToTarget();
Wonsik Kim9e922ca2014-06-20 17:27:32 +0900137 }
138
139 private void deviceUnavailableFromNative(int deviceId) {
Wonsik Kim610ccd92014-07-19 18:49:49 +0900140 mHandler.obtainMessage(EVENT_DEVICE_UNAVAILABLE, deviceId, 0).sendToTarget();
Wonsik Kim9e922ca2014-06-20 17:27:32 +0900141 }
142
143 private void streamConfigsChangedFromNative(int deviceId) {
Wonsik Kim610ccd92014-07-19 18:49:49 +0900144 mHandler.obtainMessage(EVENT_STREAM_CONFIGURATION_CHANGED, deviceId, 0).sendToTarget();
Wonsik Kim9e922ca2014-06-20 17:27:32 +0900145 }
146
Terry Heoc086a3d2014-06-18 14:26:44 +0900147 private void firstFrameCapturedFromNative(int deviceId, int streamId) {
148 mHandler.sendMessage(
149 mHandler.obtainMessage(EVENT_STREAM_CONFIGURATION_CHANGED, deviceId, streamId));
150 }
151
Wonsik Kim9e922ca2014-06-20 17:27:32 +0900152 // Handler.Callback implementation
153
Jae Seo6e4cbfd2015-06-21 16:40:34 -0700154 private final Queue<Message> mPendingMessageQueue = new LinkedList<>();
Wonsik Kim9e922ca2014-06-20 17:27:32 +0900155
156 @Override
157 public boolean handleMessage(Message msg) {
Wonsik Kim9e922ca2014-06-20 17:27:32 +0900158 switch (msg.what) {
Wonsik Kim9e922ca2014-06-20 17:27:32 +0900159 case EVENT_DEVICE_AVAILABLE: {
Wonsik Kim21aa3462014-07-29 16:39:00 +0900160 TvStreamConfig[] configs;
Wonsik Kim9e922ca2014-06-20 17:27:32 +0900161 TvInputHardwareInfo info = (TvInputHardwareInfo)msg.obj;
Wonsik Kim21aa3462014-07-29 16:39:00 +0900162 synchronized (mLock) {
163 retrieveStreamConfigsLocked(info.getDeviceId());
164 if (DEBUG) {
165 Slog.d(TAG, "EVENT_DEVICE_AVAILABLE: info = " + info);
166 }
167 configs = mStreamConfigs.get(info.getDeviceId());
Wonsik Kim610ccd92014-07-19 18:49:49 +0900168 }
Wonsik Kim21aa3462014-07-29 16:39:00 +0900169 mCallback.onDeviceAvailable(info, configs);
Wonsik Kim9e922ca2014-06-20 17:27:32 +0900170 break;
Wonsik Kimc22dbb62014-05-26 02:26:04 +0000171 }
Wonsik Kimc22dbb62014-05-26 02:26:04 +0000172
Wonsik Kim9e922ca2014-06-20 17:27:32 +0900173 case EVENT_DEVICE_UNAVAILABLE: {
174 int deviceId = msg.arg1;
Wonsik Kim610ccd92014-07-19 18:49:49 +0900175 if (DEBUG) {
176 Slog.d(TAG, "EVENT_DEVICE_UNAVAILABLE: deviceId = " + deviceId);
177 }
Wonsik Kimd7c29182014-05-27 10:38:21 +0900178 mCallback.onDeviceUnavailable(deviceId);
Wonsik Kim9e922ca2014-06-20 17:27:32 +0900179 break;
Wonsik Kimc22dbb62014-05-26 02:26:04 +0000180 }
Wonsik Kimc22dbb62014-05-26 02:26:04 +0000181
Wonsik Kim9e922ca2014-06-20 17:27:32 +0900182 case EVENT_STREAM_CONFIGURATION_CHANGED: {
Wonsik Kim21aa3462014-07-29 16:39:00 +0900183 TvStreamConfig[] configs;
Wonsik Kim9e922ca2014-06-20 17:27:32 +0900184 int deviceId = msg.arg1;
Wonsik Kim21aa3462014-07-29 16:39:00 +0900185 synchronized (mLock) {
186 if (DEBUG) {
187 Slog.d(TAG, "EVENT_STREAM_CONFIGURATION_CHANGED: deviceId = " + deviceId);
188 }
189 retrieveStreamConfigsLocked(deviceId);
190 configs = mStreamConfigs.get(deviceId);
Wonsik Kim610ccd92014-07-19 18:49:49 +0900191 }
Wonsik Kim21aa3462014-07-29 16:39:00 +0900192 mCallback.onStreamConfigurationChanged(deviceId, configs);
Wonsik Kim9e922ca2014-06-20 17:27:32 +0900193 break;
Wonsik Kimc22dbb62014-05-26 02:26:04 +0000194 }
Wonsik Kim9e922ca2014-06-20 17:27:32 +0900195
Terry Heoc086a3d2014-06-18 14:26:44 +0900196 case EVENT_FIRST_FRAME_CAPTURED: {
197 int deviceId = msg.arg1;
198 int streamId = msg.arg2;
199 mCallback.onFirstFrameCaptured(deviceId, streamId);
200 break;
201 }
202
Wonsik Kim9e922ca2014-06-20 17:27:32 +0900203 default:
204 Slog.e(TAG, "Unknown event: " + msg);
Wonsik Kim610ccd92014-07-19 18:49:49 +0900205 return false;
Wonsik Kim9e922ca2014-06-20 17:27:32 +0900206 }
Wonsik Kim610ccd92014-07-19 18:49:49 +0900207
208 return true;
Wonsik Kimc22dbb62014-05-26 02:26:04 +0000209 }
210}