TvInputHal.java revision 839ae5f460caadf8580b7e0ab77e255d7a1ddae5
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 private final static String TAG = TvInputHal.class.getSimpleName(); 35 36 public final static int SUCCESS = 0; 37 public final static int ERROR_NO_INIT = -1; 38 public final static int ERROR_STALE_CONFIG = -2; 39 public final static int ERROR_UNKNOWN = -3; 40 41 public static final int TYPE_HDMI = 1; 42 public static final int TYPE_BUILT_IN_TUNER = 2; 43 public static final int TYPE_PASSTHROUGH = 3; 44 45 public static final int EVENT_OPEN = 0; 46 // Below should be in sync with hardware/libhardware/include/hardware/tv_input.h 47 public static final int EVENT_DEVICE_AVAILABLE = 1; 48 public static final int EVENT_DEVICE_UNAVAILABLE = 2; 49 public static final int EVENT_STREAM_CONFIGURATION_CHANGED = 3; 50 51 public interface Callback { 52 public void onDeviceAvailable( 53 TvInputHardwareInfo info, TvStreamConfig[] configs); 54 public void onDeviceUnavailable(int deviceId); 55 public void onStreamConfigurationChanged(int deviceId, TvStreamConfig[] configs); 56 } 57 58 private native long nativeOpen(); 59 60 private static native int nativeAddStream(long ptr, int deviceId, int streamId, 61 Surface surface); 62 private static native int nativeRemoveStream(long ptr, int deviceId, int streamId); 63 private static native TvStreamConfig[] nativeGetStreamConfigs(long ptr, int deviceId, 64 int generation); 65 private static native void nativeClose(long ptr); 66 67 private volatile long mPtr = 0; 68 private final Callback mCallback; 69 private final HandlerThread mThread = new HandlerThread("TV input HAL event thread"); 70 private final Handler mHandler; 71 private int mStreamConfigGeneration = 0; 72 private TvStreamConfig[] mStreamConfigs; 73 74 public TvInputHal(Callback callback) { 75 mCallback = callback; 76 mThread.start(); 77 mHandler = new Handler(mThread.getLooper(), this); 78 } 79 80 public void init() { 81 mPtr = nativeOpen(); 82 mHandler.sendEmptyMessage(EVENT_OPEN); 83 } 84 85 public int addStream(int deviceId, Surface surface, TvStreamConfig streamConfig) { 86 long ptr = mPtr; 87 if (ptr == 0) { 88 return ERROR_NO_INIT; 89 } 90 if (mStreamConfigGeneration != streamConfig.getGeneration()) { 91 return ERROR_STALE_CONFIG; 92 } 93 if (nativeAddStream(ptr, deviceId, streamConfig.getStreamId(), surface) == 0) { 94 return SUCCESS; 95 } else { 96 return ERROR_UNKNOWN; 97 } 98 } 99 100 public int removeStream(int deviceId, TvStreamConfig streamConfig) { 101 long ptr = mPtr; 102 if (ptr == 0) { 103 return ERROR_NO_INIT; 104 } 105 if (mStreamConfigGeneration != streamConfig.getGeneration()) { 106 return ERROR_STALE_CONFIG; 107 } 108 if (nativeRemoveStream(ptr, deviceId, streamConfig.getStreamId()) == 0) { 109 return SUCCESS; 110 } else { 111 return ERROR_UNKNOWN; 112 } 113 } 114 115 public void close() { 116 long ptr = mPtr; 117 if (ptr != 0l) { 118 nativeClose(ptr); 119 mThread.quitSafely(); 120 } 121 } 122 123 private synchronized void retrieveStreamConfigs(long ptr, int deviceId) { 124 ++mStreamConfigGeneration; 125 mStreamConfigs = nativeGetStreamConfigs(ptr, deviceId, mStreamConfigGeneration); 126 } 127 128 // Called from native 129 private void deviceAvailableFromNative(TvInputHardwareInfo info) { 130 mHandler.sendMessage( 131 mHandler.obtainMessage(EVENT_DEVICE_AVAILABLE, info)); 132 } 133 134 private void deviceUnavailableFromNative(int deviceId) { 135 mHandler.sendMessage( 136 mHandler.obtainMessage(EVENT_DEVICE_UNAVAILABLE, deviceId, 0)); 137 } 138 139 private void streamConfigsChangedFromNative(int deviceId) { 140 mHandler.sendMessage( 141 mHandler.obtainMessage(EVENT_STREAM_CONFIGURATION_CHANGED, deviceId, 0)); 142 } 143 144 // Handler.Callback implementation 145 146 private Queue<Message> mPendingMessageQueue = new LinkedList<Message>(); 147 148 @Override 149 public boolean handleMessage(Message msg) { 150 long ptr = mPtr; 151 if (ptr == 0) { 152 mPendingMessageQueue.add(msg); 153 return true; 154 } 155 while (!mPendingMessageQueue.isEmpty()) { 156 handleMessageInternal(ptr, mPendingMessageQueue.remove()); 157 } 158 handleMessageInternal(ptr, msg); 159 return true; 160 } 161 162 private void handleMessageInternal(long ptr, Message msg) { 163 switch (msg.what) { 164 case EVENT_OPEN: 165 // No-op 166 break; 167 168 case EVENT_DEVICE_AVAILABLE: { 169 TvInputHardwareInfo info = (TvInputHardwareInfo)msg.obj; 170 retrieveStreamConfigs(ptr, info.getDeviceId()); 171 mCallback.onDeviceAvailable(info, mStreamConfigs); 172 break; 173 } 174 175 case EVENT_DEVICE_UNAVAILABLE: { 176 int deviceId = msg.arg1; 177 mCallback.onDeviceUnavailable(deviceId); 178 break; 179 } 180 181 case EVENT_STREAM_CONFIGURATION_CHANGED: { 182 int deviceId = msg.arg1; 183 retrieveStreamConfigs(ptr, deviceId); 184 mCallback.onStreamConfigurationChanged(deviceId, mStreamConfigs); 185 break; 186 } 187 188 default: 189 Slog.e(TAG, "Unknown event: " + msg); 190 break; 191 } 192 } 193} 194