TvInputHal.java revision c086a3df3b28996cd10ebe42c5f59035d054aa0d
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
17package com.android.server.tv;
18
19import android.media.tv.TvInputHardwareInfo;
20import android.media.tv.TvStreamConfig;
21import android.os.Handler;
22import android.os.HandlerThread;
23import android.os.Message;
24import android.view.Surface;
25import android.util.Slog;
26
27import java.util.LinkedList;
28import java.util.Queue;
29
30/**
31 * Provides access to the low-level TV input hardware abstraction layer.
32 */
33final class TvInputHal implements Handler.Callback {
34    // STOPSHIP: Turn debugging off
35    private final static boolean DEBUG = true;
36    private final static String TAG = TvInputHal.class.getSimpleName();
37
38    public final static int SUCCESS = 0;
39    public final static int ERROR_NO_INIT = -1;
40    public final static int ERROR_STALE_CONFIG = -2;
41    public final static int ERROR_UNKNOWN = -3;
42
43    public static final int EVENT_DEVICE_AVAILABLE = 1;
44    public static final int EVENT_DEVICE_UNAVAILABLE = 2;
45    public static final int EVENT_STREAM_CONFIGURATION_CHANGED = 3;
46    public static final int EVENT_FIRST_FRAME_CAPTURED = 4;
47
48    public interface Callback {
49        public void onDeviceAvailable(
50                TvInputHardwareInfo info, TvStreamConfig[] configs);
51        public void onDeviceUnavailable(int deviceId);
52        public void onStreamConfigurationChanged(int deviceId, TvStreamConfig[] configs);
53        public void onFirstFrameCaptured(int deviceId, int streamId);
54    }
55
56    private native long nativeOpen();
57
58    private static native int nativeAddStream(long ptr, int deviceId, int streamId,
59            Surface surface);
60    private static native int nativeRemoveStream(long ptr, int deviceId, int streamId);
61    private static native TvStreamConfig[] nativeGetStreamConfigs(long ptr, int deviceId,
62            int generation);
63    private static native void nativeClose(long ptr);
64
65    private long mPtr = 0;
66    private final Callback mCallback;
67    private final Handler mHandler;
68    private int mStreamConfigGeneration = 0;
69    private TvStreamConfig[] mStreamConfigs;
70
71    public TvInputHal(Callback callback) {
72        mCallback = callback;
73        mHandler = new Handler(this);
74    }
75
76    public synchronized void init() {
77        mPtr = nativeOpen();
78    }
79
80    public synchronized int addStream(int deviceId, Surface surface, TvStreamConfig streamConfig) {
81        if (mPtr == 0) {
82            return ERROR_NO_INIT;
83        }
84        if (mStreamConfigGeneration != streamConfig.getGeneration()) {
85            return ERROR_STALE_CONFIG;
86        }
87        if (nativeAddStream(mPtr, deviceId, streamConfig.getStreamId(), surface) == 0) {
88            return SUCCESS;
89        } else {
90            return ERROR_UNKNOWN;
91        }
92    }
93
94    public synchronized int removeStream(int deviceId, TvStreamConfig streamConfig) {
95        if (mPtr == 0) {
96            return ERROR_NO_INIT;
97        }
98        if (mStreamConfigGeneration != streamConfig.getGeneration()) {
99            return ERROR_STALE_CONFIG;
100        }
101        if (nativeRemoveStream(mPtr, deviceId, streamConfig.getStreamId()) == 0) {
102            return SUCCESS;
103        } else {
104            return ERROR_UNKNOWN;
105        }
106    }
107
108    public synchronized void close() {
109        if (mPtr != 0l) {
110            nativeClose(mPtr);
111        }
112    }
113
114    private synchronized void retrieveStreamConfigs(int deviceId) {
115        ++mStreamConfigGeneration;
116        mStreamConfigs = nativeGetStreamConfigs(mPtr, deviceId, mStreamConfigGeneration);
117    }
118
119    // Called from native
120    private void deviceAvailableFromNative(TvInputHardwareInfo info) {
121        if (DEBUG) {
122            Slog.d(TAG, "deviceAvailableFromNative: info = " + info);
123        }
124        mHandler.obtainMessage(EVENT_DEVICE_AVAILABLE, info).sendToTarget();
125    }
126
127    private void deviceUnavailableFromNative(int deviceId) {
128        mHandler.obtainMessage(EVENT_DEVICE_UNAVAILABLE, deviceId, 0).sendToTarget();
129    }
130
131    private void streamConfigsChangedFromNative(int deviceId) {
132        mHandler.obtainMessage(EVENT_STREAM_CONFIGURATION_CHANGED, deviceId, 0).sendToTarget();
133    }
134
135    private void firstFrameCapturedFromNative(int deviceId, int streamId) {
136        mHandler.sendMessage(
137                mHandler.obtainMessage(EVENT_STREAM_CONFIGURATION_CHANGED, deviceId, streamId));
138    }
139
140    // Handler.Callback implementation
141
142    private Queue<Message> mPendingMessageQueue = new LinkedList<Message>();
143
144    @Override
145    public boolean handleMessage(Message msg) {
146        switch (msg.what) {
147            case EVENT_DEVICE_AVAILABLE: {
148                TvInputHardwareInfo info = (TvInputHardwareInfo)msg.obj;
149                retrieveStreamConfigs(info.getDeviceId());
150                if (DEBUG) {
151                    Slog.d(TAG, "EVENT_DEVICE_AVAILABLE: info = " + info);
152                }
153                mCallback.onDeviceAvailable(info, mStreamConfigs);
154                break;
155            }
156
157            case EVENT_DEVICE_UNAVAILABLE: {
158                int deviceId = msg.arg1;
159                if (DEBUG) {
160                    Slog.d(TAG, "EVENT_DEVICE_UNAVAILABLE: deviceId = " + deviceId);
161                }
162                mCallback.onDeviceUnavailable(deviceId);
163                break;
164            }
165
166            case EVENT_STREAM_CONFIGURATION_CHANGED: {
167                int deviceId = msg.arg1;
168                if (DEBUG) {
169                    Slog.d(TAG, "EVENT_STREAM_CONFIGURATION_CHANGED: deviceId = " + deviceId);
170                }
171                retrieveStreamConfigs(deviceId);
172                mCallback.onStreamConfigurationChanged(deviceId, mStreamConfigs);
173                break;
174            }
175
176            case EVENT_FIRST_FRAME_CAPTURED: {
177                int deviceId = msg.arg1;
178                int streamId = msg.arg2;
179                mCallback.onFirstFrameCaptured(deviceId, streamId);
180                break;
181            }
182
183            default:
184                Slog.e(TAG, "Unknown event: " + msg);
185                return false;
186        }
187
188        return true;
189    }
190}
191