TvInputHal.java revision 610ccd9117fc1611fcc576d1cb1f717f1ef3fcbf
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    // Below should be in sync with hardware/libhardware/include/hardware/tv_input.h
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
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    }
54
55    private native long nativeOpen();
56
57    private static native int nativeAddStream(long ptr, int deviceId, int streamId,
58            Surface surface);
59    private static native int nativeRemoveStream(long ptr, int deviceId, int streamId);
60    private static native TvStreamConfig[] nativeGetStreamConfigs(long ptr, int deviceId,
61            int generation);
62    private static native void nativeClose(long ptr);
63
64    private long mPtr = 0;
65    private final Callback mCallback;
66    private final Handler mHandler;
67    private int mStreamConfigGeneration = 0;
68    private TvStreamConfig[] mStreamConfigs;
69
70    public TvInputHal(Callback callback) {
71        mCallback = callback;
72        mHandler = new Handler(this);
73    }
74
75    public synchronized void init() {
76        mPtr = nativeOpen();
77    }
78
79    public synchronized int addStream(int deviceId, Surface surface, TvStreamConfig streamConfig) {
80        if (mPtr == 0) {
81            return ERROR_NO_INIT;
82        }
83        if (mStreamConfigGeneration != streamConfig.getGeneration()) {
84            return ERROR_STALE_CONFIG;
85        }
86        if (nativeAddStream(mPtr, deviceId, streamConfig.getStreamId(), surface) == 0) {
87            return SUCCESS;
88        } else {
89            return ERROR_UNKNOWN;
90        }
91    }
92
93    public synchronized int removeStream(int deviceId, TvStreamConfig streamConfig) {
94        if (mPtr == 0) {
95            return ERROR_NO_INIT;
96        }
97        if (mStreamConfigGeneration != streamConfig.getGeneration()) {
98            return ERROR_STALE_CONFIG;
99        }
100        if (nativeRemoveStream(mPtr, deviceId, streamConfig.getStreamId()) == 0) {
101            return SUCCESS;
102        } else {
103            return ERROR_UNKNOWN;
104        }
105    }
106
107    public synchronized void close() {
108        if (mPtr != 0l) {
109            nativeClose(mPtr);
110        }
111    }
112
113    private synchronized void retrieveStreamConfigs(int deviceId) {
114        ++mStreamConfigGeneration;
115        mStreamConfigs = nativeGetStreamConfigs(mPtr, deviceId, mStreamConfigGeneration);
116    }
117
118    // Called from native
119    private void deviceAvailableFromNative(TvInputHardwareInfo info) {
120        if (DEBUG) {
121            Slog.d(TAG, "deviceAvailableFromNative: info = " + info);
122        }
123        mHandler.obtainMessage(EVENT_DEVICE_AVAILABLE, info).sendToTarget();
124    }
125
126    private void deviceUnavailableFromNative(int deviceId) {
127        mHandler.obtainMessage(EVENT_DEVICE_UNAVAILABLE, deviceId, 0).sendToTarget();
128    }
129
130    private void streamConfigsChangedFromNative(int deviceId) {
131        mHandler.obtainMessage(EVENT_STREAM_CONFIGURATION_CHANGED, deviceId, 0).sendToTarget();
132    }
133
134    // Handler.Callback implementation
135
136    private Queue<Message> mPendingMessageQueue = new LinkedList<Message>();
137
138    @Override
139    public boolean handleMessage(Message msg) {
140        switch (msg.what) {
141            case EVENT_DEVICE_AVAILABLE: {
142                TvInputHardwareInfo info = (TvInputHardwareInfo)msg.obj;
143                retrieveStreamConfigs(info.getDeviceId());
144                if (DEBUG) {
145                    Slog.d(TAG, "EVENT_DEVICE_AVAILABLE: info = " + info);
146                }
147                mCallback.onDeviceAvailable(info, mStreamConfigs);
148                break;
149            }
150
151            case EVENT_DEVICE_UNAVAILABLE: {
152                int deviceId = msg.arg1;
153                if (DEBUG) {
154                    Slog.d(TAG, "EVENT_DEVICE_UNAVAILABLE: deviceId = " + deviceId);
155                }
156                mCallback.onDeviceUnavailable(deviceId);
157                break;
158            }
159
160            case EVENT_STREAM_CONFIGURATION_CHANGED: {
161                int deviceId = msg.arg1;
162                if (DEBUG) {
163                    Slog.d(TAG, "EVENT_STREAM_CONFIGURATION_CHANGED: deviceId = " + deviceId);
164                }
165                retrieveStreamConfigs(deviceId);
166                mCallback.onStreamConfigurationChanged(deviceId, mStreamConfigs);
167                break;
168            }
169
170            default:
171                Slog.e(TAG, "Unknown event: " + msg);
172                return false;
173        }
174
175        return true;
176    }
177}
178