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