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