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