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