TvInputHardwareManager.java revision d922a546b94119217fb790113d0001cad0432060
1c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim/* 2c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * Copyright (C) 2014 The Android Open Source Project 3c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * 4c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * Licensed under the Apache License, Version 2.0 (the "License"); 5c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * you may not use this file except in compliance with the License. 6c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * You may obtain a copy of the License at 7c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * 8c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * http://www.apache.org/licenses/LICENSE-2.0 9c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * 10c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * Unless required by applicable law or agreed to in writing, software 11c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * distributed under the License is distributed on an "AS IS" BASIS, 12c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * See the License for the specific language governing permissions and 14c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * limitations under the License. 15c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim */ 16c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 17c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimpackage com.android.server.tv; 18c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 19969167dc05a6485a32d160895871cff46fd81884Wonsik Kimimport static android.media.tv.TvInputManager.INPUT_STATE_CONNECTED; 20969167dc05a6485a32d160895871cff46fd81884Wonsik Kimimport static android.media.tv.TvInputManager.INPUT_STATE_DISCONNECTED; 21969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 22c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimimport android.content.Context; 23b2b3151a42bd563669b222b82efb64e294dc9049Jinsuk Kimimport android.content.Intent; 24187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kimimport android.hardware.hdmi.HdmiCecDeviceInfo; 25969167dc05a6485a32d160895871cff46fd81884Wonsik Kimimport android.hardware.hdmi.HdmiHotplugEvent; 267474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kimimport android.hardware.hdmi.IHdmiControlService; 27187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kimimport android.hardware.hdmi.IHdmiDeviceEventListener; 287474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kimimport android.hardware.hdmi.IHdmiHotplugEventListener; 297474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kimimport android.hardware.hdmi.IHdmiInputChangeListener; 30d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kimimport android.media.AudioDevicePort; 31d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kimimport android.media.AudioManager; 32d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kimimport android.media.AudioPatch; 33d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kimimport android.media.AudioPort; 34d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kimimport android.media.AudioPortConfig; 35d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.ITvInputHardware; 36d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.ITvInputHardwareCallback; 37d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.TvInputHardwareInfo; 38b2b3151a42bd563669b222b82efb64e294dc9049Jinsuk Kimimport android.media.tv.TvContract; 39969167dc05a6485a32d160895871cff46fd81884Wonsik Kimimport android.media.tv.TvInputInfo; 40d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.TvStreamConfig; 41969167dc05a6485a32d160895871cff46fd81884Wonsik Kimimport android.os.Handler; 42c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimimport android.os.IBinder; 43969167dc05a6485a32d160895871cff46fd81884Wonsik Kimimport android.os.Looper; 44969167dc05a6485a32d160895871cff46fd81884Wonsik Kimimport android.os.Message; 45c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimimport android.os.RemoteException; 467474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kimimport android.os.ServiceManager; 474f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Leeimport android.util.ArrayMap; 48c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimimport android.util.Slog; 49c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimimport android.util.SparseArray; 50969167dc05a6485a32d160895871cff46fd81884Wonsik Kimimport android.util.SparseBooleanArray; 51c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimimport android.view.KeyEvent; 52c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimimport android.view.Surface; 53c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 54969167dc05a6485a32d160895871cff46fd81884Wonsik Kimimport com.android.server.SystemService; 55969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 56c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimimport java.util.ArrayList; 574f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Leeimport java.util.Collections; 58c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimimport java.util.HashSet; 59d922a546b94119217fb790113d0001cad0432060Wonsik Kimimport java.util.Iterator; 60d922a546b94119217fb790113d0001cad0432060Wonsik Kimimport java.util.LinkedList; 61c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimimport java.util.List; 624f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Leeimport java.util.Map; 63c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimimport java.util.Set; 64c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 65c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim/** 66c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * A helper class for TvInputManagerService to handle TV input hardware. 67c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * 68c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * This class does a basic connection management and forwarding calls to TvInputHal which eventually 69c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * calls to tv_input HAL module. 70c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * 71c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * @hide 72c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim */ 737474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kimclass TvInputHardwareManager implements TvInputHal.Callback { 74c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private static final String TAG = TvInputHardwareManager.class.getSimpleName(); 754f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee 764f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee private final Context mContext; 774f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee private final Listener mListener; 78c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private final TvInputHal mHal = new TvInputHal(this); 79d922a546b94119217fb790113d0001cad0432060Wonsik Kim private final SparseArray<Connection> mConnections = new SparseArray<>(); 80d922a546b94119217fb790113d0001cad0432060Wonsik Kim private final List<TvInputHardwareInfo> mHardwareList = new ArrayList<>(); 81d922a546b94119217fb790113d0001cad0432060Wonsik Kim private List<HdmiCecDeviceInfo> mHdmiCecDeviceList = new LinkedList<>(); 824f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee /* A map from a device ID to the matching TV input ID. */ 83d922a546b94119217fb790113d0001cad0432060Wonsik Kim private final SparseArray<String> mHardwareInputIdMap = new SparseArray<>(); 844f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee /* A map from a HDMI logical address to the matching TV input ID. */ 85d922a546b94119217fb790113d0001cad0432060Wonsik Kim private final SparseArray<String> mHdmiCecInputIdMap = new SparseArray<>(); 86d922a546b94119217fb790113d0001cad0432060Wonsik Kim private final Map<String, TvInputInfo> mInputMap = new ArrayMap<>(); 874f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee 88d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim private final AudioManager mAudioManager; 894f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee private IHdmiControlService mHdmiControlService; 907474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim private final IHdmiHotplugEventListener mHdmiHotplugEventListener = 917474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim new HdmiHotplugEventListener(); 924f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee private final IHdmiDeviceEventListener mHdmiDeviceEventListener = new HdmiDeviceEventListener(); 937474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim private final IHdmiInputChangeListener mHdmiInputChangeListener = new HdmiInputChangeListener(); 94d922a546b94119217fb790113d0001cad0432060Wonsik Kim // TODO: Should handle STANDBY case. 954f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee private final SparseBooleanArray mHdmiStateMap = new SparseBooleanArray(); 96d922a546b94119217fb790113d0001cad0432060Wonsik Kim private final List<Message> mPendingHdmiDeviceEvents = new LinkedList<>(); 97969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 98187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim // Calls to mListener should happen here. 99187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim private final Handler mHandler = new ListenerHandler(); 100c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 101c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private final Object mLock = new Object(); 102c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 103187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim public TvInputHardwareManager(Context context, Listener listener) { 104c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mContext = context; 105187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim mListener = listener; 106d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); 107c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mHal.init(); 108969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 109969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 110969167dc05a6485a32d160895871cff46fd81884Wonsik Kim public void onBootPhase(int phase) { 111969167dc05a6485a32d160895871cff46fd81884Wonsik Kim if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { 1124f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mHdmiControlService = IHdmiControlService.Stub.asInterface(ServiceManager.getService( 1134f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee Context.HDMI_CONTROL_SERVICE)); 1144f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee if (mHdmiControlService != null) { 1157474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim try { 1164f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mHdmiControlService.addHotplugEventListener(mHdmiHotplugEventListener); 1174f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mHdmiControlService.addDeviceEventListener(mHdmiDeviceEventListener); 118d922a546b94119217fb790113d0001cad0432060Wonsik Kim mHdmiCecDeviceList.addAll(mHdmiControlService.getInputDevices()); 1194f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mHdmiControlService.setInputChangeListener(mHdmiInputChangeListener); 1207474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim } catch (RemoteException e) { 1214f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee Slog.w(TAG, "Error registering listeners to HdmiControlService:", e); 1227474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim } 1237474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim } 124969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 125c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 126c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 127c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim @Override 1284f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee public void onDeviceAvailable(TvInputHardwareInfo info, TvStreamConfig[] configs) { 129c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mLock) { 130c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Connection connection = new Connection(info); 131c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim connection.updateConfigsLocked(configs); 132c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mConnections.put(info.getDeviceId(), connection); 133d922a546b94119217fb790113d0001cad0432060Wonsik Kim buildHardwareListLocked(); 134187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim mHandler.obtainMessage( 135187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim ListenerHandler.HARDWARE_DEVICE_ADDED, 0, 0, info).sendToTarget(); 136d922a546b94119217fb790113d0001cad0432060Wonsik Kim if (info.getType() == TvInputHardwareInfo.TV_INPUT_TYPE_HDMI) { 137d922a546b94119217fb790113d0001cad0432060Wonsik Kim processPendingHdmiDeviceEventsLocked(); 138d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 139c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 140c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 141c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 142d922a546b94119217fb790113d0001cad0432060Wonsik Kim private void buildHardwareListLocked() { 143d922a546b94119217fb790113d0001cad0432060Wonsik Kim mHardwareList.clear(); 144c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim for (int i = 0; i < mConnections.size(); ++i) { 145d922a546b94119217fb790113d0001cad0432060Wonsik Kim mHardwareList.add(mConnections.valueAt(i).getHardwareInfoLocked()); 146c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 147c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 148c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 149c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim @Override 150c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public void onDeviceUnavailable(int deviceId) { 151c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mLock) { 152c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Connection connection = mConnections.get(deviceId); 153c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (connection == null) { 154c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Slog.e(TAG, "onDeviceUnavailable: Cannot find a connection with " + deviceId); 155c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return; 156c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 157969167dc05a6485a32d160895871cff46fd81884Wonsik Kim connection.resetLocked(null, null, null, null, null); 158c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mConnections.remove(deviceId); 159d922a546b94119217fb790113d0001cad0432060Wonsik Kim buildHardwareListLocked(); 1604f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee TvInputHardwareInfo info = connection.getHardwareInfoLocked(); 161d922a546b94119217fb790113d0001cad0432060Wonsik Kim if (info.getType() == TvInputHardwareInfo.TV_INPUT_TYPE_HDMI) { 162d922a546b94119217fb790113d0001cad0432060Wonsik Kim // Remove HDMI CEC devices linked with this hardware. 163d922a546b94119217fb790113d0001cad0432060Wonsik Kim for (Iterator<HdmiCecDeviceInfo> it = mHdmiCecDeviceList.iterator(); 164d922a546b94119217fb790113d0001cad0432060Wonsik Kim it.hasNext(); ) { 165d922a546b94119217fb790113d0001cad0432060Wonsik Kim HdmiCecDeviceInfo deviceInfo = it.next(); 166d922a546b94119217fb790113d0001cad0432060Wonsik Kim if (deviceInfo.getPortId() == info.getHdmiPortId()) { 167d922a546b94119217fb790113d0001cad0432060Wonsik Kim mHandler.obtainMessage(ListenerHandler.HDMI_CEC_DEVICE_REMOVED, 0, 0, 168d922a546b94119217fb790113d0001cad0432060Wonsik Kim deviceInfo).sendToTarget(); 169d922a546b94119217fb790113d0001cad0432060Wonsik Kim it.remove(); 170d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 171d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 172d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 173187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim mHandler.obtainMessage( 1744f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee ListenerHandler.HARDWARE_DEVICE_REMOVED, 0, 0, info).sendToTarget(); 175c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 176c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 177c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 178c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim @Override 179c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public void onStreamConfigurationChanged(int deviceId, TvStreamConfig[] configs) { 180c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mLock) { 181c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Connection connection = mConnections.get(deviceId); 182c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (connection == null) { 183c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Slog.e(TAG, "StreamConfigurationChanged: Cannot find a connection with " 184c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim + deviceId); 185c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return; 186c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 187c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim connection.updateConfigsLocked(configs); 188c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim try { 189c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim connection.getCallbackLocked().onStreamConfigChanged(configs); 190c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } catch (RemoteException e) { 1914f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee Slog.e(TAG, "error in onStreamConfigurationChanged", e); 192c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 193c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 194c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 195c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 196c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo @Override 197c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo public void onFirstFrameCaptured(int deviceId, int streamId) { 198c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo synchronized (mLock) { 199c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Connection connection = mConnections.get(deviceId); 200c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (connection == null) { 201c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Slog.e(TAG, "FirstFrameCaptured: Cannot find a connection with " 202c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo + deviceId); 203c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return; 204c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 205c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Runnable runnable = connection.getOnFirstFrameCapturedLocked(); 206c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (runnable != null) { 207c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo runnable.run(); 208c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo connection.setOnFirstFrameCapturedLocked(null); 209c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 210c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 211c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 212c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 213c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public List<TvInputHardwareInfo> getHardwareList() { 214c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mLock) { 215d922a546b94119217fb790113d0001cad0432060Wonsik Kim return Collections.unmodifiableList(mHardwareList); 216c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 217c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 218c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 2194f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee public List<HdmiCecDeviceInfo> getHdmiCecInputDeviceList() { 220d922a546b94119217fb790113d0001cad0432060Wonsik Kim synchronized (mLock) { 221d922a546b94119217fb790113d0001cad0432060Wonsik Kim return Collections.unmodifiableList(mHdmiCecDeviceList); 2224f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 2234f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 2244f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee 225e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim private boolean checkUidChangedLocked( 226e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim Connection connection, int callingUid, int resolvedUserId) { 227e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim Integer connectionCallingUid = connection.getCallingUidLocked(); 228e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim Integer connectionResolvedUserId = connection.getResolvedUserIdLocked(); 229e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim if (connectionCallingUid == null || connectionResolvedUserId == null) { 230e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim return true; 231e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim } 232e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim if (connectionCallingUid != callingUid || connectionResolvedUserId != resolvedUserId) { 233e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim return true; 234e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim } 235e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim return false; 236e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim } 237e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim 238969167dc05a6485a32d160895871cff46fd81884Wonsik Kim private int convertConnectedToState(boolean connected) { 239969167dc05a6485a32d160895871cff46fd81884Wonsik Kim if (connected) { 240969167dc05a6485a32d160895871cff46fd81884Wonsik Kim return INPUT_STATE_CONNECTED; 241969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } else { 242969167dc05a6485a32d160895871cff46fd81884Wonsik Kim return INPUT_STATE_DISCONNECTED; 243969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 244969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 245969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 2464f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee public void addHardwareTvInput(int deviceId, TvInputInfo info) { 247969167dc05a6485a32d160895871cff46fd81884Wonsik Kim synchronized (mLock) { 2484f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee String oldInputId = mHardwareInputIdMap.get(deviceId); 2494f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee if (oldInputId != null) { 250969167dc05a6485a32d160895871cff46fd81884Wonsik Kim Slog.w(TAG, "Trying to override previous registration: old = " 2514f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee + mInputMap.get(oldInputId) + ":" + deviceId + ", new = " 252969167dc05a6485a32d160895871cff46fd81884Wonsik Kim + info + ":" + deviceId); 253969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 2544f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mHardwareInputIdMap.put(deviceId, info.getId()); 2554f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mInputMap.put(info.getId(), info); 256969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 257969167dc05a6485a32d160895871cff46fd81884Wonsik Kim for (int i = 0; i < mHdmiStateMap.size(); ++i) { 258d922a546b94119217fb790113d0001cad0432060Wonsik Kim TvInputHardwareInfo hardwareInfo = 259d922a546b94119217fb790113d0001cad0432060Wonsik Kim findHardwareInfoForHdmiPortLocked(mHdmiStateMap.keyAt(i)); 260d922a546b94119217fb790113d0001cad0432060Wonsik Kim if (hardwareInfo == null) { 261d922a546b94119217fb790113d0001cad0432060Wonsik Kim continue; 262d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 263d922a546b94119217fb790113d0001cad0432060Wonsik Kim String inputId = mHardwareInputIdMap.get(hardwareInfo.getDeviceId()); 264969167dc05a6485a32d160895871cff46fd81884Wonsik Kim if (inputId != null && inputId.equals(info.getId())) { 265187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim mHandler.obtainMessage(ListenerHandler.STATE_CHANGED, 266969167dc05a6485a32d160895871cff46fd81884Wonsik Kim convertConnectedToState(mHdmiStateMap.valueAt(i)), 0, 267969167dc05a6485a32d160895871cff46fd81884Wonsik Kim inputId).sendToTarget(); 268969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 269969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 270969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 271969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 272969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 27338feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim private static <T> int indexOfEqualValue(SparseArray<T> map, T value) { 27438feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim for (int i = 0; i < map.size(); ++i) { 27538feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim if (map.valueAt(i).equals(value)) { 27638feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim return i; 27738feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim } 27838feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim } 27938feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim return -1; 28038feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim } 28138feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim 2824f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee public void addHdmiCecTvInput(int logicalAddress, TvInputInfo info) { 2834f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee if (info.getType() != TvInputInfo.TYPE_HDMI) { 2844f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee throw new IllegalArgumentException("info (" + info + ") has non-HDMI type."); 2854f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 2864f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee synchronized (mLock) { 2874f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee String parentId = info.getParentId(); 28838feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim int parentIndex = indexOfEqualValue(mHardwareInputIdMap, parentId); 28938feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim if (parentIndex < 0) { 2904f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee throw new IllegalArgumentException("info (" + info + ") has invalid parentId."); 2914f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 2924f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee String oldInputId = mHdmiCecInputIdMap.get(logicalAddress); 2934f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee if (oldInputId != null) { 2944f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee Slog.w(TAG, "Trying to override previous registration: old = " 2954f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee + mInputMap.get(oldInputId) + ":" + logicalAddress + ", new = " 2964f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee + info + ":" + logicalAddress); 2974f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 2984f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mHdmiCecInputIdMap.put(logicalAddress, info.getId()); 2994f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mInputMap.put(info.getId(), info); 3004f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 3014f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 3024f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee 3034f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee public void removeTvInput(String inputId) { 3044f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee synchronized (mLock) { 3054f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mInputMap.remove(inputId); 30638feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim int hardwareIndex = indexOfEqualValue(mHardwareInputIdMap, inputId); 3074f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee if (hardwareIndex >= 0) { 3084f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mHardwareInputIdMap.removeAt(hardwareIndex); 3094f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 31038feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim int cecIndex = indexOfEqualValue(mHdmiCecInputIdMap, inputId); 3114f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee if (cecIndex >= 0) { 3124f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mHdmiCecInputIdMap.removeAt(cecIndex); 3134f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 3144f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 3154f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 3164f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee 317c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim /** 318c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * Create a TvInputHardware object with a specific deviceId. One service at a time can access 319c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * the object, and if more than one process attempts to create hardware with the same deviceId, 320c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * the latest service will get the object and all the other hardware are released. The 321c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * release is notified via ITvInputHardwareCallback.onReleased(). 322c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim */ 323c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public ITvInputHardware acquireHardware(int deviceId, ITvInputHardwareCallback callback, 324969167dc05a6485a32d160895871cff46fd81884Wonsik Kim TvInputInfo info, int callingUid, int resolvedUserId) { 325c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (callback == null) { 326c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim throw new NullPointerException(); 327c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 328c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mLock) { 329c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Connection connection = mConnections.get(deviceId); 330c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (connection == null) { 331c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Slog.e(TAG, "Invalid deviceId : " + deviceId); 332c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return null; 333c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 334e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim if (checkUidChangedLocked(connection, callingUid, resolvedUserId)) { 335969167dc05a6485a32d160895871cff46fd81884Wonsik Kim TvInputHardwareImpl hardware = 336969167dc05a6485a32d160895871cff46fd81884Wonsik Kim new TvInputHardwareImpl(connection.getHardwareInfoLocked()); 337c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim try { 338c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim callback.asBinder().linkToDeath(connection, 0); 339c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } catch (RemoteException e) { 340c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim hardware.release(); 341c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return null; 342c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 343969167dc05a6485a32d160895871cff46fd81884Wonsik Kim connection.resetLocked(hardware, callback, info, callingUid, resolvedUserId); 344c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 345c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return connection.getHardwareLocked(); 346c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 347c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 348c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 349c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim /** 350c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * Release the specified hardware. 351c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim */ 352c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public void releaseHardware(int deviceId, ITvInputHardware hardware, int callingUid, 353c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim int resolvedUserId) { 354c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mLock) { 355c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Connection connection = mConnections.get(deviceId); 356c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (connection == null) { 357c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Slog.e(TAG, "Invalid deviceId : " + deviceId); 358c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return; 359c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 360c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (connection.getHardwareLocked() != hardware 361e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim || checkUidChangedLocked(connection, callingUid, resolvedUserId)) { 362c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return; 363c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 364969167dc05a6485a32d160895871cff46fd81884Wonsik Kim connection.resetLocked(null, null, null, null, null); 365969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 366969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 367969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 368d922a546b94119217fb790113d0001cad0432060Wonsik Kim private TvInputHardwareInfo findHardwareInfoForHdmiPortLocked(int port) { 369d922a546b94119217fb790113d0001cad0432060Wonsik Kim for (TvInputHardwareInfo hardwareInfo : mHardwareList) { 370969167dc05a6485a32d160895871cff46fd81884Wonsik Kim if (hardwareInfo.getType() == TvInputHardwareInfo.TV_INPUT_TYPE_HDMI 371969167dc05a6485a32d160895871cff46fd81884Wonsik Kim && hardwareInfo.getHdmiPortId() == port) { 372d922a546b94119217fb790113d0001cad0432060Wonsik Kim return hardwareInfo; 373969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 374969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 375969167dc05a6485a32d160895871cff46fd81884Wonsik Kim return null; 376969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 377969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 378c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo private int findDeviceIdForInputIdLocked(String inputId) { 379c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo for (int i = 0; i < mConnections.size(); ++i) { 380c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Connection connection = mConnections.get(i); 381c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (connection.getInfoLocked().getId().equals(inputId)) { 382c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return i; 383c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 384c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 385c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return -1; 386c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 387c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 388c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo /** 389c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo * Get the list of TvStreamConfig which is buffered mode. 390c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo */ 391c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo public List<TvStreamConfig> getAvailableTvStreamConfigList(String inputId, int callingUid, 392c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo int resolvedUserId) { 393c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo List<TvStreamConfig> configsList = new ArrayList<TvStreamConfig>(); 394c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo synchronized (mLock) { 395c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo int deviceId = findDeviceIdForInputIdLocked(inputId); 396c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (deviceId < 0) { 397c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Slog.e(TAG, "Invalid inputId : " + inputId); 398c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return configsList; 399c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 400c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Connection connection = mConnections.get(deviceId); 401c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo for (TvStreamConfig config : connection.getConfigsLocked()) { 402c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (config.getType() == TvStreamConfig.STREAM_TYPE_BUFFER_PRODUCER) { 403c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo configsList.add(config); 404c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 405c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 406c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 407c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return configsList; 408c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 409c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 410c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo /** 411c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo * Take a snapshot of the given TV input into the provided Surface. 412c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo */ 413c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo public boolean captureFrame(String inputId, Surface surface, final TvStreamConfig config, 414c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo int callingUid, int resolvedUserId) { 415c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo synchronized (mLock) { 416c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo int deviceId = findDeviceIdForInputIdLocked(inputId); 417c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (deviceId < 0) { 418c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Slog.e(TAG, "Invalid inputId : " + inputId); 419c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return false; 420c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 421c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Connection connection = mConnections.get(deviceId); 422c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo final TvInputHardwareImpl hardwareImpl = connection.getHardwareImplLocked(); 423c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (hardwareImpl != null) { 424c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo // Stop previous capture. 425c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Runnable runnable = connection.getOnFirstFrameCapturedLocked(); 426c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (runnable != null) { 427c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo runnable.run(); 428c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo connection.setOnFirstFrameCapturedLocked(null); 429c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 430c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 431c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo boolean result = hardwareImpl.startCapture(surface, config); 432c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (result) { 433c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo connection.setOnFirstFrameCapturedLocked(new Runnable() { 434c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo @Override 435c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo public void run() { 436c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo hardwareImpl.stopCapture(config); 437c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 438c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo }); 439c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 440c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return result; 441c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 442c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 443c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return false; 444c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 445c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 446d922a546b94119217fb790113d0001cad0432060Wonsik Kim private void processPendingHdmiDeviceEventsLocked() { 447d922a546b94119217fb790113d0001cad0432060Wonsik Kim for (Iterator<Message> it = mPendingHdmiDeviceEvents.iterator(); it.hasNext(); ) { 448d922a546b94119217fb790113d0001cad0432060Wonsik Kim Message msg = it.next(); 449d922a546b94119217fb790113d0001cad0432060Wonsik Kim HdmiCecDeviceInfo deviceInfo = (HdmiCecDeviceInfo) msg.obj; 450d922a546b94119217fb790113d0001cad0432060Wonsik Kim TvInputHardwareInfo hardwareInfo = 451d922a546b94119217fb790113d0001cad0432060Wonsik Kim findHardwareInfoForHdmiPortLocked(deviceInfo.getPortId()); 452d922a546b94119217fb790113d0001cad0432060Wonsik Kim if (hardwareInfo != null) { 453d922a546b94119217fb790113d0001cad0432060Wonsik Kim msg.sendToTarget(); 454d922a546b94119217fb790113d0001cad0432060Wonsik Kim it.remove(); 455d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 456d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 457d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 458d922a546b94119217fb790113d0001cad0432060Wonsik Kim 459c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private class Connection implements IBinder.DeathRecipient { 460969167dc05a6485a32d160895871cff46fd81884Wonsik Kim private final TvInputHardwareInfo mHardwareInfo; 461969167dc05a6485a32d160895871cff46fd81884Wonsik Kim private TvInputInfo mInfo; 462c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private TvInputHardwareImpl mHardware = null; 463c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private ITvInputHardwareCallback mCallback; 464c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private TvStreamConfig[] mConfigs = null; 465c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private Integer mCallingUid = null; 466c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private Integer mResolvedUserId = null; 467c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo private Runnable mOnFirstFrameCaptured; 468c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 469969167dc05a6485a32d160895871cff46fd81884Wonsik Kim public Connection(TvInputHardwareInfo hardwareInfo) { 470969167dc05a6485a32d160895871cff46fd81884Wonsik Kim mHardwareInfo = hardwareInfo; 471c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 472c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 473c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim // *Locked methods assume TvInputHardwareManager.mLock is held. 474c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 475969167dc05a6485a32d160895871cff46fd81884Wonsik Kim public void resetLocked(TvInputHardwareImpl hardware, ITvInputHardwareCallback callback, 476969167dc05a6485a32d160895871cff46fd81884Wonsik Kim TvInputInfo info, Integer callingUid, Integer resolvedUserId) { 477c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (mHardware != null) { 478c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim try { 479c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mCallback.onReleased(); 480c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } catch (RemoteException e) { 4814f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee Slog.e(TAG, "error in Connection::resetLocked", e); 482c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 483c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mHardware.release(); 484c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 485c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mHardware = hardware; 486c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mCallback = callback; 487969167dc05a6485a32d160895871cff46fd81884Wonsik Kim mInfo = info; 488c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mCallingUid = callingUid; 489c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mResolvedUserId = resolvedUserId; 490c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo mOnFirstFrameCaptured = null; 491c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 492c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (mHardware != null && mCallback != null) { 493c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim try { 494c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mCallback.onStreamConfigChanged(getConfigsLocked()); 495c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } catch (RemoteException e) { 4964f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee Slog.e(TAG, "error in Connection::resetLocked", e); 497c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 498c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 499c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 500c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 501c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public void updateConfigsLocked(TvStreamConfig[] configs) { 502c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mConfigs = configs; 503c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 504c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 505969167dc05a6485a32d160895871cff46fd81884Wonsik Kim public TvInputHardwareInfo getHardwareInfoLocked() { 506969167dc05a6485a32d160895871cff46fd81884Wonsik Kim return mHardwareInfo; 507969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 508969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 509969167dc05a6485a32d160895871cff46fd81884Wonsik Kim public TvInputInfo getInfoLocked() { 510c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return mInfo; 511c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 512c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 513c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public ITvInputHardware getHardwareLocked() { 514c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return mHardware; 515c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 516c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 517c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo public TvInputHardwareImpl getHardwareImplLocked() { 518c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return mHardware; 519c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 520c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 521c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public ITvInputHardwareCallback getCallbackLocked() { 522c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return mCallback; 523c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 524c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 525c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public TvStreamConfig[] getConfigsLocked() { 526c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return mConfigs; 527c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 528c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 529e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim public Integer getCallingUidLocked() { 530c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return mCallingUid; 531c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 532c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 533e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim public Integer getResolvedUserIdLocked() { 534c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return mResolvedUserId; 535c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 536c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 537c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo public void setOnFirstFrameCapturedLocked(Runnable runnable) { 538c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo mOnFirstFrameCaptured = runnable; 539c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 540c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 541c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo public Runnable getOnFirstFrameCapturedLocked() { 542c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return mOnFirstFrameCaptured; 543c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 544c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 545c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim @Override 546c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public void binderDied() { 547c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mLock) { 548969167dc05a6485a32d160895871cff46fd81884Wonsik Kim resetLocked(null, null, null, null, null); 549c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 550c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 551c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 552c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 553c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private class TvInputHardwareImpl extends ITvInputHardware.Stub { 554c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private final TvInputHardwareInfo mInfo; 555c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private boolean mReleased = false; 556c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private final Object mImplLock = new Object(); 557c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 558d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim private final AudioDevicePort mAudioSource; 559d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim private final AudioDevicePort mAudioSink; 560d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim private AudioPatch mAudioPatch = null; 561d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim 562839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim private TvStreamConfig mActiveConfig = null; 563839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim 564c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public TvInputHardwareImpl(TvInputHardwareInfo info) { 565c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mInfo = info; 566d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim AudioDevicePort audioSource = null; 567d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim AudioDevicePort audioSink = null; 568d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim if (mInfo.getAudioType() != AudioManager.DEVICE_NONE) { 569d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim ArrayList<AudioPort> devicePorts = new ArrayList<AudioPort>(); 570d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim if (mAudioManager.listAudioDevicePorts(devicePorts) == AudioManager.SUCCESS) { 571d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim // Find source 572d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim for (AudioPort port : devicePorts) { 573d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim AudioDevicePort devicePort = (AudioDevicePort) port; 574d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim if (devicePort.type() == mInfo.getAudioType() && 575d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim devicePort.address().equals(mInfo.getAudioAddress())) { 576d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim audioSource = devicePort; 577d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim break; 578d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim } 579d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim } 580d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim // Find sink 581d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim // TODO: App may want to specify sink device? 582d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim int sinkDevices = mAudioManager.getDevicesForStream(AudioManager.STREAM_MUSIC); 583d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim for (AudioPort port : devicePorts) { 584d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim AudioDevicePort devicePort = (AudioDevicePort) port; 585d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim if (devicePort.type() == sinkDevices) { 586d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim audioSink = devicePort; 587d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim break; 588d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim } 589d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim } 590d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim } 591d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim } 592d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim mAudioSource = audioSource; 593d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim mAudioSink = audioSink; 594c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 595c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 596c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public void release() { 597c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mImplLock) { 598d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim if (mAudioPatch != null) { 599d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim mAudioManager.releaseAudioPatch(mAudioPatch); 600d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim mAudioPatch = null; 601d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim } 602c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mReleased = true; 603c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 604c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 605c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 606839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim // A TvInputHardwareImpl object holds only one active session. Therefore, if a client 607839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim // attempts to call setSurface with different TvStreamConfig objects, the last call will 608839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim // prevail. 609c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim @Override 610c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public boolean setSurface(Surface surface, TvStreamConfig config) 611c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim throws RemoteException { 612c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mImplLock) { 613c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (mReleased) { 614c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim throw new IllegalStateException("Device already released."); 615c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 616839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim if (surface != null && config == null) { 617839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim return false; 618839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim } 619839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim if (surface == null && mActiveConfig == null) { 620839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim return false; 621839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim } 622d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim if (mAudioSource != null && mAudioSink != null) { 623d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim if (surface != null) { 624d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim AudioPortConfig sourceConfig = mAudioSource.activeConfig(); 625d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim AudioPortConfig sinkConfig = mAudioSink.activeConfig(); 626d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim AudioPatch[] audioPatchArray = new AudioPatch[] { mAudioPatch }; 627d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim // TODO: build config if activeConfig() == null 628d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim mAudioManager.createAudioPatch( 629d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim audioPatchArray, 630d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim new AudioPortConfig[] { sourceConfig }, 631d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim new AudioPortConfig[] { sinkConfig }); 632d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim mAudioPatch = audioPatchArray[0]; 633d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim } else { 634d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim mAudioManager.releaseAudioPatch(mAudioPatch); 635d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim mAudioPatch = null; 636d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim } 637d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim } 638839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim int result = TvInputHal.ERROR_UNKNOWN; 639839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim if (surface == null) { 640839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim result = mHal.removeStream(mInfo.getDeviceId(), mActiveConfig); 641839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim mActiveConfig = null; 642839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim } else { 643839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim if (config != mActiveConfig && mActiveConfig != null) { 644839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim result = mHal.removeStream(mInfo.getDeviceId(), mActiveConfig); 645839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim if (result != TvInputHal.SUCCESS) { 646839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim mActiveConfig = null; 647839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim return false; 648839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim } 649839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim } 650839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim result = mHal.addStream(mInfo.getDeviceId(), surface, config); 651839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim if (result == TvInputHal.SUCCESS) { 652839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim mActiveConfig = config; 653839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim } 654839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim } 655839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim return result == TvInputHal.SUCCESS; 656c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 657c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 658c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 659c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim @Override 660c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public void setVolume(float volume) throws RemoteException { 661c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mImplLock) { 662c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (mReleased) { 663c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim throw new IllegalStateException("Device already released."); 664c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 665c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 666d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim // TODO: Use AudioGain? 667c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 668c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 669c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim @Override 670c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public boolean dispatchKeyEventToHdmi(KeyEvent event) throws RemoteException { 671c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mImplLock) { 672c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (mReleased) { 673c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim throw new IllegalStateException("Device already released."); 674c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 675c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 676610ccd9117fc1611fcc576d1cb1f717f1ef3fcbfWonsik Kim if (mInfo.getType() != TvInputHardwareInfo.TV_INPUT_TYPE_HDMI) { 677c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return false; 678c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 679c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim // TODO(hdmi): mHdmiClient.sendKeyEvent(event); 680c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return false; 681c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 682c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 683c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo private boolean startCapture(Surface surface, TvStreamConfig config) { 684c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo synchronized (mImplLock) { 685c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (mReleased) { 686c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return false; 687c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 688c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (surface == null || config == null) { 689c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return false; 690c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 691c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (config.getType() != TvStreamConfig.STREAM_TYPE_BUFFER_PRODUCER) { 692c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return false; 693c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 694c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 695c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo int result = mHal.addStream(mInfo.getDeviceId(), surface, config); 696c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return result == TvInputHal.SUCCESS; 697c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 698c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 699c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 700c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo private boolean stopCapture(TvStreamConfig config) { 701c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo synchronized (mImplLock) { 702c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (mReleased) { 703c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return false; 704c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 705c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (config == null) { 706c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return false; 707c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 708c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 709c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo int result = mHal.removeStream(mInfo.getDeviceId(), config); 710c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return result == TvInputHal.SUCCESS; 711c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 712c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 713c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 714969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 715187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim interface Listener { 716187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim public void onStateChanged(String inputId, int state); 717187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim public void onHardwareDeviceAdded(TvInputHardwareInfo info); 7184f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee public void onHardwareDeviceRemoved(TvInputHardwareInfo info); 719187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim public void onHdmiCecDeviceAdded(HdmiCecDeviceInfo cecDevice); 720187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim public void onHdmiCecDeviceRemoved(HdmiCecDeviceInfo cecDevice); 721187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 722969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 723187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim private class ListenerHandler extends Handler { 724187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim private static final int STATE_CHANGED = 1; 725187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim private static final int HARDWARE_DEVICE_ADDED = 2; 726187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim private static final int HARDWARE_DEVICE_REMOVED = 3; 7274f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee private static final int HDMI_CEC_DEVICE_ADDED = 4; 7284f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee private static final int HDMI_CEC_DEVICE_REMOVED = 5; 729969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 730969167dc05a6485a32d160895871cff46fd81884Wonsik Kim @Override 731969167dc05a6485a32d160895871cff46fd81884Wonsik Kim public final void handleMessage(Message msg) { 732969167dc05a6485a32d160895871cff46fd81884Wonsik Kim switch (msg.what) { 733187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim case STATE_CHANGED: { 734969167dc05a6485a32d160895871cff46fd81884Wonsik Kim String inputId = (String) msg.obj; 735969167dc05a6485a32d160895871cff46fd81884Wonsik Kim int state = msg.arg1; 736187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim mListener.onStateChanged(inputId, state); 737187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim break; 738187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 739187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim case HARDWARE_DEVICE_ADDED: { 740187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim TvInputHardwareInfo info = (TvInputHardwareInfo) msg.obj; 741187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim mListener.onHardwareDeviceAdded(info); 742187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim break; 743187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 744187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim case HARDWARE_DEVICE_REMOVED: { 7454f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee TvInputHardwareInfo info = (TvInputHardwareInfo) msg.obj; 7464f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mListener.onHardwareDeviceRemoved(info); 747187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim break; 748187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 7494f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee case HDMI_CEC_DEVICE_ADDED: { 750187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim HdmiCecDeviceInfo info = (HdmiCecDeviceInfo) msg.obj; 751187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim mListener.onHdmiCecDeviceAdded(info); 752187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim break; 753187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 7544f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee case HDMI_CEC_DEVICE_REMOVED: { 755187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim HdmiCecDeviceInfo info = (HdmiCecDeviceInfo) msg.obj; 756187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim mListener.onHdmiCecDeviceRemoved(info); 757969167dc05a6485a32d160895871cff46fd81884Wonsik Kim break; 758969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 759969167dc05a6485a32d160895871cff46fd81884Wonsik Kim default: { 760969167dc05a6485a32d160895871cff46fd81884Wonsik Kim Slog.w(TAG, "Unhandled message: " + msg); 761969167dc05a6485a32d160895871cff46fd81884Wonsik Kim break; 762969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 763969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 764969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 765969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 766187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim 7677474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim // Listener implementations for HdmiControlService 7687474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim 7697474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim private final class HdmiHotplugEventListener extends IHdmiHotplugEventListener.Stub { 7707474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim @Override 7717474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim public void onReceived(HdmiHotplugEvent event) { 7727474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim synchronized (mLock) { 7737474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim mHdmiStateMap.put(event.getPort(), event.isConnected()); 774d922a546b94119217fb790113d0001cad0432060Wonsik Kim TvInputHardwareInfo hardwareInfo = 775d922a546b94119217fb790113d0001cad0432060Wonsik Kim findHardwareInfoForHdmiPortLocked(event.getPort()); 776d922a546b94119217fb790113d0001cad0432060Wonsik Kim if (hardwareInfo == null) { 777d922a546b94119217fb790113d0001cad0432060Wonsik Kim return; 778d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 779d922a546b94119217fb790113d0001cad0432060Wonsik Kim String inputId = mHardwareInputIdMap.get(hardwareInfo.getDeviceId()); 7807474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim if (inputId == null) { 7817474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim return; 7827474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim } 7837474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim mHandler.obtainMessage(ListenerHandler.STATE_CHANGED, 7847474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim convertConnectedToState(event.isConnected()), 0, inputId).sendToTarget(); 7857474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim } 7867474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim } 7877474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim } 7887474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim 789187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim private final class HdmiDeviceEventListener extends IHdmiDeviceEventListener.Stub { 790187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim @Override 791187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim public void onStatusChanged(HdmiCecDeviceInfo deviceInfo, boolean activated) { 792d922a546b94119217fb790113d0001cad0432060Wonsik Kim synchronized (mLock) { 793d922a546b94119217fb790113d0001cad0432060Wonsik Kim if (activated) { 794d922a546b94119217fb790113d0001cad0432060Wonsik Kim if (!mHdmiCecDeviceList.contains(deviceInfo)) { 795d922a546b94119217fb790113d0001cad0432060Wonsik Kim mHdmiCecDeviceList.add(deviceInfo); 796d922a546b94119217fb790113d0001cad0432060Wonsik Kim } else { 797d922a546b94119217fb790113d0001cad0432060Wonsik Kim Slog.w(TAG, "The list already contains " + deviceInfo + "; ignoring."); 798d922a546b94119217fb790113d0001cad0432060Wonsik Kim return; 799d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 800d922a546b94119217fb790113d0001cad0432060Wonsik Kim } else { 801d922a546b94119217fb790113d0001cad0432060Wonsik Kim if (!mHdmiCecDeviceList.remove(deviceInfo)) { 802d922a546b94119217fb790113d0001cad0432060Wonsik Kim Slog.w(TAG, "The list doesn't contain " + deviceInfo + "; ignoring."); 803d922a546b94119217fb790113d0001cad0432060Wonsik Kim return; 804d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 805d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 806d922a546b94119217fb790113d0001cad0432060Wonsik Kim Message msg = mHandler.obtainMessage( 807d922a546b94119217fb790113d0001cad0432060Wonsik Kim activated ? ListenerHandler.HDMI_CEC_DEVICE_ADDED 808d922a546b94119217fb790113d0001cad0432060Wonsik Kim : ListenerHandler.HDMI_CEC_DEVICE_REMOVED, 809d922a546b94119217fb790113d0001cad0432060Wonsik Kim 0, 0, deviceInfo); 810d922a546b94119217fb790113d0001cad0432060Wonsik Kim if (findHardwareInfoForHdmiPortLocked(deviceInfo.getPortId()) != null) { 811d922a546b94119217fb790113d0001cad0432060Wonsik Kim msg.sendToTarget(); 812d922a546b94119217fb790113d0001cad0432060Wonsik Kim } else { 813d922a546b94119217fb790113d0001cad0432060Wonsik Kim mPendingHdmiDeviceEvents.add(msg); 814d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 815d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 816187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 817187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 8187474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim 8197474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim private final class HdmiInputChangeListener extends IHdmiInputChangeListener.Stub { 8207474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim @Override 8217474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim public void onChanged(HdmiCecDeviceInfo device) throws RemoteException { 822b2b3151a42bd563669b222b82efb64e294dc9049Jinsuk Kim String inputId; 823b2b3151a42bd563669b222b82efb64e294dc9049Jinsuk Kim synchronized (mLock) { 824b2b3151a42bd563669b222b82efb64e294dc9049Jinsuk Kim if (device.isCecDevice()) { 825b2b3151a42bd563669b222b82efb64e294dc9049Jinsuk Kim inputId = mHdmiCecInputIdMap.get(device.getLogicalAddress()); 826b2b3151a42bd563669b222b82efb64e294dc9049Jinsuk Kim } else { 827d922a546b94119217fb790113d0001cad0432060Wonsik Kim TvInputHardwareInfo hardwareInfo = 828d922a546b94119217fb790113d0001cad0432060Wonsik Kim findHardwareInfoForHdmiPortLocked(device.getPortId()); 829d922a546b94119217fb790113d0001cad0432060Wonsik Kim inputId = (hardwareInfo == null) ? null 830d922a546b94119217fb790113d0001cad0432060Wonsik Kim : mHardwareInputIdMap.get(hardwareInfo.getDeviceId()); 831b2b3151a42bd563669b222b82efb64e294dc9049Jinsuk Kim } 832b2b3151a42bd563669b222b82efb64e294dc9049Jinsuk Kim } 833b2b3151a42bd563669b222b82efb64e294dc9049Jinsuk Kim if (inputId != null) { 834b2b3151a42bd563669b222b82efb64e294dc9049Jinsuk Kim Intent intent = new Intent(Intent.ACTION_VIEW); 835b2b3151a42bd563669b222b82efb64e294dc9049Jinsuk Kim intent.setData(TvContract.buildChannelUriForPassthroughTvInput(inputId)); 836b2b3151a42bd563669b222b82efb64e294dc9049Jinsuk Kim mContext.startActivity(intent); 837b2b3151a42bd563669b222b82efb64e294dc9049Jinsuk Kim } else { 838b2b3151a42bd563669b222b82efb64e294dc9049Jinsuk Kim Slog.w(TAG, "onChanged: InputId cannot be found for :" + device); 839b2b3151a42bd563669b222b82efb64e294dc9049Jinsuk Kim } 8407474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim } 8417474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim } 842c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim} 843