TvInputHardwareManager.java revision e92f857d50d7259a4cf7ef5b88309e098338c9c1
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; 2461daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jangimport android.hardware.hdmi.HdmiControlManager; 2561f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jangimport android.hardware.hdmi.HdmiDeviceInfo; 26969167dc05a6485a32d160895871cff46fd81884Wonsik Kimimport android.hardware.hdmi.HdmiHotplugEvent; 277474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kimimport android.hardware.hdmi.IHdmiControlService; 28187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kimimport android.hardware.hdmi.IHdmiDeviceEventListener; 297474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kimimport android.hardware.hdmi.IHdmiHotplugEventListener; 307474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kimimport android.hardware.hdmi.IHdmiInputChangeListener; 311f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jangimport android.hardware.hdmi.IHdmiSystemAudioModeChangeListener; 32d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kimimport android.media.AudioDevicePort; 33ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kimimport android.media.AudioFormat; 348e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kimimport android.media.AudioGain; 358e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kimimport android.media.AudioGainConfig; 36d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kimimport android.media.AudioManager; 37d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kimimport android.media.AudioPatch; 38d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kimimport android.media.AudioPort; 39d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kimimport android.media.AudioPortConfig; 40d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.ITvInputHardware; 41d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.ITvInputHardwareCallback; 42b2b3151a42bd563669b222b82efb64e294dc9049Jinsuk Kimimport android.media.tv.TvContract; 43546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seoimport android.media.tv.TvInputHardwareInfo; 44969167dc05a6485a32d160895871cff46fd81884Wonsik Kimimport android.media.tv.TvInputInfo; 45d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.TvStreamConfig; 46969167dc05a6485a32d160895871cff46fd81884Wonsik Kimimport android.os.Handler; 47c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimimport android.os.IBinder; 48969167dc05a6485a32d160895871cff46fd81884Wonsik Kimimport android.os.Message; 49c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimimport android.os.RemoteException; 507474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kimimport android.os.ServiceManager; 514f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Leeimport android.util.ArrayMap; 52c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimimport android.util.Slog; 53c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimimport android.util.SparseArray; 54969167dc05a6485a32d160895871cff46fd81884Wonsik Kimimport android.util.SparseBooleanArray; 55c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimimport android.view.KeyEvent; 56c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimimport android.view.Surface; 57c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 58e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kimimport com.android.internal.os.SomeArgs; 59969167dc05a6485a32d160895871cff46fd81884Wonsik Kimimport com.android.server.SystemService; 60969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 61c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimimport java.util.ArrayList; 628e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kimimport java.util.Arrays; 634f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Leeimport java.util.Collections; 64d922a546b94119217fb790113d0001cad0432060Wonsik Kimimport java.util.Iterator; 65d922a546b94119217fb790113d0001cad0432060Wonsik Kimimport java.util.LinkedList; 66c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimimport java.util.List; 674f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Leeimport java.util.Map; 68c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 69c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim/** 70c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * A helper class for TvInputManagerService to handle TV input hardware. 71c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * 72c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * This class does a basic connection management and forwarding calls to TvInputHal which eventually 73c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * calls to tv_input HAL module. 74c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * 75c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * @hide 76c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim */ 777474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kimclass TvInputHardwareManager implements TvInputHal.Callback { 78c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private static final String TAG = TvInputHardwareManager.class.getSimpleName(); 794f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee 804f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee private final Context mContext; 814f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee private final Listener mListener; 82c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private final TvInputHal mHal = new TvInputHal(this); 83d922a546b94119217fb790113d0001cad0432060Wonsik Kim private final SparseArray<Connection> mConnections = new SparseArray<>(); 84d922a546b94119217fb790113d0001cad0432060Wonsik Kim private final List<TvInputHardwareInfo> mHardwareList = new ArrayList<>(); 85546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo private final List<HdmiDeviceInfo> mHdmiDeviceList = new LinkedList<>(); 864f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee /* A map from a device ID to the matching TV input ID. */ 87d922a546b94119217fb790113d0001cad0432060Wonsik Kim private final SparseArray<String> mHardwareInputIdMap = new SparseArray<>(); 884f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee /* A map from a HDMI logical address to the matching TV input ID. */ 89546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo private final SparseArray<String> mHdmiInputIdMap = new SparseArray<>(); 90d922a546b94119217fb790113d0001cad0432060Wonsik Kim private final Map<String, TvInputInfo> mInputMap = new ArrayMap<>(); 914f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee 92d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim private final AudioManager mAudioManager; 934f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee private IHdmiControlService mHdmiControlService; 947474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim private final IHdmiHotplugEventListener mHdmiHotplugEventListener = 957474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim new HdmiHotplugEventListener(); 964f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee private final IHdmiDeviceEventListener mHdmiDeviceEventListener = new HdmiDeviceEventListener(); 971f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang private final IHdmiSystemAudioModeChangeListener mHdmiSystemAudioModeChangeListener = 981f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang new HdmiSystemAudioModeChangeListener(); 99d38bf476f6a31602e92a3207a4ceb29bf965f9aaJinsuk Kim 100d922a546b94119217fb790113d0001cad0432060Wonsik Kim // TODO: Should handle STANDBY case. 1014f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee private final SparseBooleanArray mHdmiStateMap = new SparseBooleanArray(); 102d922a546b94119217fb790113d0001cad0432060Wonsik Kim private final List<Message> mPendingHdmiDeviceEvents = new LinkedList<>(); 103969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 104187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim // Calls to mListener should happen here. 105187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim private final Handler mHandler = new ListenerHandler(); 106c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 107c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private final Object mLock = new Object(); 108c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 109187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim public TvInputHardwareManager(Context context, Listener listener) { 110c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mContext = context; 111187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim mListener = listener; 112d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); 113c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mHal.init(); 114969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 115969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 116969167dc05a6485a32d160895871cff46fd81884Wonsik Kim public void onBootPhase(int phase) { 117969167dc05a6485a32d160895871cff46fd81884Wonsik Kim if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { 1184f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mHdmiControlService = IHdmiControlService.Stub.asInterface(ServiceManager.getService( 1194f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee Context.HDMI_CONTROL_SERVICE)); 1204f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee if (mHdmiControlService != null) { 1217474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim try { 1224f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mHdmiControlService.addHotplugEventListener(mHdmiHotplugEventListener); 1234f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mHdmiControlService.addDeviceEventListener(mHdmiDeviceEventListener); 1241f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang mHdmiControlService.addSystemAudioModeChangeListener( 1251f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang mHdmiSystemAudioModeChangeListener); 126546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo mHdmiDeviceList.addAll(mHdmiControlService.getInputDevices()); 1277474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim } catch (RemoteException e) { 1284f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee Slog.w(TAG, "Error registering listeners to HdmiControlService:", e); 1297474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim } 1307474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim } 131969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 132c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 133c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 134c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim @Override 1354f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee public void onDeviceAvailable(TvInputHardwareInfo info, TvStreamConfig[] configs) { 136c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mLock) { 137c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Connection connection = new Connection(info); 138c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim connection.updateConfigsLocked(configs); 139c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mConnections.put(info.getDeviceId(), connection); 140d922a546b94119217fb790113d0001cad0432060Wonsik Kim buildHardwareListLocked(); 141187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim mHandler.obtainMessage( 142187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim ListenerHandler.HARDWARE_DEVICE_ADDED, 0, 0, info).sendToTarget(); 143d922a546b94119217fb790113d0001cad0432060Wonsik Kim if (info.getType() == TvInputHardwareInfo.TV_INPUT_TYPE_HDMI) { 144d922a546b94119217fb790113d0001cad0432060Wonsik Kim processPendingHdmiDeviceEventsLocked(); 145d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 146c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 147c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 148c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 149d922a546b94119217fb790113d0001cad0432060Wonsik Kim private void buildHardwareListLocked() { 150d922a546b94119217fb790113d0001cad0432060Wonsik Kim mHardwareList.clear(); 151c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim for (int i = 0; i < mConnections.size(); ++i) { 152d922a546b94119217fb790113d0001cad0432060Wonsik Kim mHardwareList.add(mConnections.valueAt(i).getHardwareInfoLocked()); 153c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 154c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 155c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 156c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim @Override 157c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public void onDeviceUnavailable(int deviceId) { 158c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mLock) { 159c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Connection connection = mConnections.get(deviceId); 160c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (connection == null) { 161c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Slog.e(TAG, "onDeviceUnavailable: Cannot find a connection with " + deviceId); 162c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return; 163c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 164969167dc05a6485a32d160895871cff46fd81884Wonsik Kim connection.resetLocked(null, null, null, null, null); 165c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mConnections.remove(deviceId); 166d922a546b94119217fb790113d0001cad0432060Wonsik Kim buildHardwareListLocked(); 1674f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee TvInputHardwareInfo info = connection.getHardwareInfoLocked(); 168d922a546b94119217fb790113d0001cad0432060Wonsik Kim if (info.getType() == TvInputHardwareInfo.TV_INPUT_TYPE_HDMI) { 169546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo // Remove HDMI devices linked with this hardware. 170546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo for (Iterator<HdmiDeviceInfo> it = mHdmiDeviceList.iterator(); it.hasNext();) { 17161f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo deviceInfo = it.next(); 172d922a546b94119217fb790113d0001cad0432060Wonsik Kim if (deviceInfo.getPortId() == info.getHdmiPortId()) { 173546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo mHandler.obtainMessage(ListenerHandler.HDMI_DEVICE_REMOVED, 0, 0, 174d922a546b94119217fb790113d0001cad0432060Wonsik Kim deviceInfo).sendToTarget(); 175d922a546b94119217fb790113d0001cad0432060Wonsik Kim it.remove(); 176d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 177d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 178d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 179187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim mHandler.obtainMessage( 1804f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee ListenerHandler.HARDWARE_DEVICE_REMOVED, 0, 0, info).sendToTarget(); 181c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 182c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 183c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 184c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim @Override 185c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public void onStreamConfigurationChanged(int deviceId, TvStreamConfig[] configs) { 186c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mLock) { 187c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Connection connection = mConnections.get(deviceId); 188c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (connection == null) { 189c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Slog.e(TAG, "StreamConfigurationChanged: Cannot find a connection with " 190c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim + deviceId); 191c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return; 192c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 193c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim connection.updateConfigsLocked(configs); 194c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim try { 195c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim connection.getCallbackLocked().onStreamConfigChanged(configs); 196c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } catch (RemoteException e) { 1974f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee Slog.e(TAG, "error in onStreamConfigurationChanged", e); 198c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 199c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 200c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 201c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 202c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo @Override 203c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo public void onFirstFrameCaptured(int deviceId, int streamId) { 204c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo synchronized (mLock) { 205c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Connection connection = mConnections.get(deviceId); 206c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (connection == null) { 207c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Slog.e(TAG, "FirstFrameCaptured: Cannot find a connection with " 208c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo + deviceId); 209c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return; 210c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 211c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Runnable runnable = connection.getOnFirstFrameCapturedLocked(); 212c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (runnable != null) { 213c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo runnable.run(); 214c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo connection.setOnFirstFrameCapturedLocked(null); 215c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 216c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 217c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 218c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 219c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public List<TvInputHardwareInfo> getHardwareList() { 220c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mLock) { 221d922a546b94119217fb790113d0001cad0432060Wonsik Kim return Collections.unmodifiableList(mHardwareList); 222c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 223c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 224c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 225546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo public List<HdmiDeviceInfo> getHdmiDeviceList() { 226d922a546b94119217fb790113d0001cad0432060Wonsik Kim synchronized (mLock) { 227546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo return Collections.unmodifiableList(mHdmiDeviceList); 2284f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 2294f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 2304f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee 231e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim private boolean checkUidChangedLocked( 232e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim Connection connection, int callingUid, int resolvedUserId) { 233e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim Integer connectionCallingUid = connection.getCallingUidLocked(); 234e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim Integer connectionResolvedUserId = connection.getResolvedUserIdLocked(); 235e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim if (connectionCallingUid == null || connectionResolvedUserId == null) { 236e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim return true; 237e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim } 238e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim if (connectionCallingUid != callingUid || connectionResolvedUserId != resolvedUserId) { 239e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim return true; 240e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim } 241e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim return false; 242e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim } 243e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim 244969167dc05a6485a32d160895871cff46fd81884Wonsik Kim private int convertConnectedToState(boolean connected) { 245969167dc05a6485a32d160895871cff46fd81884Wonsik Kim if (connected) { 246969167dc05a6485a32d160895871cff46fd81884Wonsik Kim return INPUT_STATE_CONNECTED; 247969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } else { 248969167dc05a6485a32d160895871cff46fd81884Wonsik Kim return INPUT_STATE_DISCONNECTED; 249969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 250969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 251969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 2524f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee public void addHardwareTvInput(int deviceId, TvInputInfo info) { 253969167dc05a6485a32d160895871cff46fd81884Wonsik Kim synchronized (mLock) { 2544f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee String oldInputId = mHardwareInputIdMap.get(deviceId); 2554f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee if (oldInputId != null) { 256969167dc05a6485a32d160895871cff46fd81884Wonsik Kim Slog.w(TAG, "Trying to override previous registration: old = " 2574f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee + mInputMap.get(oldInputId) + ":" + deviceId + ", new = " 258969167dc05a6485a32d160895871cff46fd81884Wonsik Kim + info + ":" + deviceId); 259969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 2604f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mHardwareInputIdMap.put(deviceId, info.getId()); 2614f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mInputMap.put(info.getId(), info); 262969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 263969167dc05a6485a32d160895871cff46fd81884Wonsik Kim for (int i = 0; i < mHdmiStateMap.size(); ++i) { 264d922a546b94119217fb790113d0001cad0432060Wonsik Kim TvInputHardwareInfo hardwareInfo = 265d922a546b94119217fb790113d0001cad0432060Wonsik Kim findHardwareInfoForHdmiPortLocked(mHdmiStateMap.keyAt(i)); 266d922a546b94119217fb790113d0001cad0432060Wonsik Kim if (hardwareInfo == null) { 267d922a546b94119217fb790113d0001cad0432060Wonsik Kim continue; 268d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 269d922a546b94119217fb790113d0001cad0432060Wonsik Kim String inputId = mHardwareInputIdMap.get(hardwareInfo.getDeviceId()); 270969167dc05a6485a32d160895871cff46fd81884Wonsik Kim if (inputId != null && inputId.equals(info.getId())) { 271187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim mHandler.obtainMessage(ListenerHandler.STATE_CHANGED, 272969167dc05a6485a32d160895871cff46fd81884Wonsik Kim convertConnectedToState(mHdmiStateMap.valueAt(i)), 0, 273969167dc05a6485a32d160895871cff46fd81884Wonsik Kim inputId).sendToTarget(); 274969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 275969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 276969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 277969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 278969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 27938feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim private static <T> int indexOfEqualValue(SparseArray<T> map, T value) { 28038feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim for (int i = 0; i < map.size(); ++i) { 28138feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim if (map.valueAt(i).equals(value)) { 28238feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim return i; 28338feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim } 28438feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim } 28538feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim return -1; 28638feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim } 28738feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim 288546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo public void addHdmiTvInput(int logicalAddress, TvInputInfo info) { 2894f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee if (info.getType() != TvInputInfo.TYPE_HDMI) { 2904f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee throw new IllegalArgumentException("info (" + info + ") has non-HDMI type."); 2914f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 2924f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee synchronized (mLock) { 2934f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee String parentId = info.getParentId(); 29438feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim int parentIndex = indexOfEqualValue(mHardwareInputIdMap, parentId); 29538feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim if (parentIndex < 0) { 2964f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee throw new IllegalArgumentException("info (" + info + ") has invalid parentId."); 2974f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 298546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo String oldInputId = mHdmiInputIdMap.get(logicalAddress); 2994f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee if (oldInputId != null) { 3004f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee Slog.w(TAG, "Trying to override previous registration: old = " 3014f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee + mInputMap.get(oldInputId) + ":" + logicalAddress + ", new = " 3024f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee + info + ":" + logicalAddress); 3034f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 304546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo mHdmiInputIdMap.put(logicalAddress, info.getId()); 3054f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mInputMap.put(info.getId(), info); 3064f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 3074f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 3084f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee 3094f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee public void removeTvInput(String inputId) { 3104f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee synchronized (mLock) { 3114f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mInputMap.remove(inputId); 31238feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim int hardwareIndex = indexOfEqualValue(mHardwareInputIdMap, inputId); 3134f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee if (hardwareIndex >= 0) { 3144f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mHardwareInputIdMap.removeAt(hardwareIndex); 3154f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 316546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo int deviceIndex = indexOfEqualValue(mHdmiInputIdMap, inputId); 317546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo if (deviceIndex >= 0) { 318546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo mHdmiInputIdMap.removeAt(deviceIndex); 3194f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 3204f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 3214f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 3224f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee 323c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim /** 324c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * Create a TvInputHardware object with a specific deviceId. One service at a time can access 325c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * the object, and if more than one process attempts to create hardware with the same deviceId, 326c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * the latest service will get the object and all the other hardware are released. The 327c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * release is notified via ITvInputHardwareCallback.onReleased(). 328c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim */ 329c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public ITvInputHardware acquireHardware(int deviceId, ITvInputHardwareCallback callback, 330969167dc05a6485a32d160895871cff46fd81884Wonsik Kim TvInputInfo info, int callingUid, int resolvedUserId) { 331c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (callback == null) { 332c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim throw new NullPointerException(); 333c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 334c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mLock) { 335c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Connection connection = mConnections.get(deviceId); 336c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (connection == null) { 337c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Slog.e(TAG, "Invalid deviceId : " + deviceId); 338c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return null; 339c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 340e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim if (checkUidChangedLocked(connection, callingUid, resolvedUserId)) { 341969167dc05a6485a32d160895871cff46fd81884Wonsik Kim TvInputHardwareImpl hardware = 342969167dc05a6485a32d160895871cff46fd81884Wonsik Kim new TvInputHardwareImpl(connection.getHardwareInfoLocked()); 343c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim try { 344c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim callback.asBinder().linkToDeath(connection, 0); 345c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } catch (RemoteException e) { 346c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim hardware.release(); 347c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return null; 348c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 349969167dc05a6485a32d160895871cff46fd81884Wonsik Kim connection.resetLocked(hardware, callback, info, callingUid, resolvedUserId); 350c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 351c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return connection.getHardwareLocked(); 352c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 353c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 354c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 355c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim /** 356c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * Release the specified hardware. 357c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim */ 358c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public void releaseHardware(int deviceId, ITvInputHardware hardware, int callingUid, 359c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim int resolvedUserId) { 360c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mLock) { 361c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Connection connection = mConnections.get(deviceId); 362c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (connection == null) { 363c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Slog.e(TAG, "Invalid deviceId : " + deviceId); 364c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return; 365c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 366c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (connection.getHardwareLocked() != hardware 367e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim || checkUidChangedLocked(connection, callingUid, resolvedUserId)) { 368c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return; 369c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 370969167dc05a6485a32d160895871cff46fd81884Wonsik Kim connection.resetLocked(null, null, null, null, null); 371969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 372969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 373969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 374d922a546b94119217fb790113d0001cad0432060Wonsik Kim private TvInputHardwareInfo findHardwareInfoForHdmiPortLocked(int port) { 375d922a546b94119217fb790113d0001cad0432060Wonsik Kim for (TvInputHardwareInfo hardwareInfo : mHardwareList) { 376969167dc05a6485a32d160895871cff46fd81884Wonsik Kim if (hardwareInfo.getType() == TvInputHardwareInfo.TV_INPUT_TYPE_HDMI 377969167dc05a6485a32d160895871cff46fd81884Wonsik Kim && hardwareInfo.getHdmiPortId() == port) { 378d922a546b94119217fb790113d0001cad0432060Wonsik Kim return hardwareInfo; 379969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 380969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 381969167dc05a6485a32d160895871cff46fd81884Wonsik Kim return null; 382969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 383969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 384c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo private int findDeviceIdForInputIdLocked(String inputId) { 385c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo for (int i = 0; i < mConnections.size(); ++i) { 386c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Connection connection = mConnections.get(i); 387c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (connection.getInfoLocked().getId().equals(inputId)) { 388c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return i; 389c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 390c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 391c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return -1; 392c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 393c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 394c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo /** 395c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo * Get the list of TvStreamConfig which is buffered mode. 396c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo */ 397c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo public List<TvStreamConfig> getAvailableTvStreamConfigList(String inputId, int callingUid, 398c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo int resolvedUserId) { 399c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo List<TvStreamConfig> configsList = new ArrayList<TvStreamConfig>(); 400c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo synchronized (mLock) { 401c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo int deviceId = findDeviceIdForInputIdLocked(inputId); 402c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (deviceId < 0) { 403c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Slog.e(TAG, "Invalid inputId : " + inputId); 404c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return configsList; 405c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 406c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Connection connection = mConnections.get(deviceId); 407c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo for (TvStreamConfig config : connection.getConfigsLocked()) { 408c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (config.getType() == TvStreamConfig.STREAM_TYPE_BUFFER_PRODUCER) { 409c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo configsList.add(config); 410c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 411c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 412c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 413c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return configsList; 414c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 415c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 416c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo /** 417c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo * Take a snapshot of the given TV input into the provided Surface. 418c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo */ 419c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo public boolean captureFrame(String inputId, Surface surface, final TvStreamConfig config, 420c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo int callingUid, int resolvedUserId) { 421c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo synchronized (mLock) { 422c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo int deviceId = findDeviceIdForInputIdLocked(inputId); 423c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (deviceId < 0) { 424c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Slog.e(TAG, "Invalid inputId : " + inputId); 425c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return false; 426c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 427c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Connection connection = mConnections.get(deviceId); 428c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo final TvInputHardwareImpl hardwareImpl = connection.getHardwareImplLocked(); 429c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (hardwareImpl != null) { 430c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo // Stop previous capture. 431c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Runnable runnable = connection.getOnFirstFrameCapturedLocked(); 432c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (runnable != null) { 433c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo runnable.run(); 434c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo connection.setOnFirstFrameCapturedLocked(null); 435c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 436c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 437c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo boolean result = hardwareImpl.startCapture(surface, config); 438c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (result) { 439c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo connection.setOnFirstFrameCapturedLocked(new Runnable() { 440c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo @Override 441c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo public void run() { 442c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo hardwareImpl.stopCapture(config); 443c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 444c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo }); 445c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 446c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return result; 447c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 448c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 449c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return false; 450c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 451c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 452d922a546b94119217fb790113d0001cad0432060Wonsik Kim private void processPendingHdmiDeviceEventsLocked() { 453d922a546b94119217fb790113d0001cad0432060Wonsik Kim for (Iterator<Message> it = mPendingHdmiDeviceEvents.iterator(); it.hasNext(); ) { 454d922a546b94119217fb790113d0001cad0432060Wonsik Kim Message msg = it.next(); 45561f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo deviceInfo = (HdmiDeviceInfo) msg.obj; 456d922a546b94119217fb790113d0001cad0432060Wonsik Kim TvInputHardwareInfo hardwareInfo = 457d922a546b94119217fb790113d0001cad0432060Wonsik Kim findHardwareInfoForHdmiPortLocked(deviceInfo.getPortId()); 458d922a546b94119217fb790113d0001cad0432060Wonsik Kim if (hardwareInfo != null) { 459d922a546b94119217fb790113d0001cad0432060Wonsik Kim msg.sendToTarget(); 460d922a546b94119217fb790113d0001cad0432060Wonsik Kim it.remove(); 461d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 462d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 463d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 464d922a546b94119217fb790113d0001cad0432060Wonsik Kim 465c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private class Connection implements IBinder.DeathRecipient { 466969167dc05a6485a32d160895871cff46fd81884Wonsik Kim private final TvInputHardwareInfo mHardwareInfo; 467969167dc05a6485a32d160895871cff46fd81884Wonsik Kim private TvInputInfo mInfo; 468c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private TvInputHardwareImpl mHardware = null; 469c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private ITvInputHardwareCallback mCallback; 470c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private TvStreamConfig[] mConfigs = null; 471c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private Integer mCallingUid = null; 472c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private Integer mResolvedUserId = null; 473c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo private Runnable mOnFirstFrameCaptured; 474c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 475969167dc05a6485a32d160895871cff46fd81884Wonsik Kim public Connection(TvInputHardwareInfo hardwareInfo) { 476969167dc05a6485a32d160895871cff46fd81884Wonsik Kim mHardwareInfo = hardwareInfo; 477c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 478c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 479c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim // *Locked methods assume TvInputHardwareManager.mLock is held. 480c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 481969167dc05a6485a32d160895871cff46fd81884Wonsik Kim public void resetLocked(TvInputHardwareImpl hardware, ITvInputHardwareCallback callback, 482969167dc05a6485a32d160895871cff46fd81884Wonsik Kim TvInputInfo info, Integer callingUid, Integer resolvedUserId) { 483c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (mHardware != null) { 484c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim try { 485c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mCallback.onReleased(); 486c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } catch (RemoteException e) { 4874f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee Slog.e(TAG, "error in Connection::resetLocked", e); 488c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 489c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mHardware.release(); 490c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 491c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mHardware = hardware; 492c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mCallback = callback; 493969167dc05a6485a32d160895871cff46fd81884Wonsik Kim mInfo = info; 494c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mCallingUid = callingUid; 495c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mResolvedUserId = resolvedUserId; 496c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo mOnFirstFrameCaptured = null; 497c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 498c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (mHardware != null && mCallback != null) { 499c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim try { 500c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mCallback.onStreamConfigChanged(getConfigsLocked()); 501c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } catch (RemoteException e) { 5024f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee Slog.e(TAG, "error in Connection::resetLocked", e); 503c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 504c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 505c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 506c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 507c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public void updateConfigsLocked(TvStreamConfig[] configs) { 508c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mConfigs = configs; 509c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 510c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 511969167dc05a6485a32d160895871cff46fd81884Wonsik Kim public TvInputHardwareInfo getHardwareInfoLocked() { 512969167dc05a6485a32d160895871cff46fd81884Wonsik Kim return mHardwareInfo; 513969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 514969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 515969167dc05a6485a32d160895871cff46fd81884Wonsik Kim public TvInputInfo getInfoLocked() { 516c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return mInfo; 517c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 518c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 519c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public ITvInputHardware getHardwareLocked() { 520c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return mHardware; 521c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 522c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 523c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo public TvInputHardwareImpl getHardwareImplLocked() { 524c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return mHardware; 525c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 526c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 527c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public ITvInputHardwareCallback getCallbackLocked() { 528c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return mCallback; 529c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 530c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 531c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public TvStreamConfig[] getConfigsLocked() { 532c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return mConfigs; 533c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 534c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 535e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim public Integer getCallingUidLocked() { 536c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return mCallingUid; 537c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 538c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 539e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim public Integer getResolvedUserIdLocked() { 540c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return mResolvedUserId; 541c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 542c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 543c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo public void setOnFirstFrameCapturedLocked(Runnable runnable) { 544c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo mOnFirstFrameCaptured = runnable; 545c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 546c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 547c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo public Runnable getOnFirstFrameCapturedLocked() { 548c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return mOnFirstFrameCaptured; 549c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 550c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 551c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim @Override 552c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public void binderDied() { 553c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mLock) { 554969167dc05a6485a32d160895871cff46fd81884Wonsik Kim resetLocked(null, null, null, null, null); 555c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 556c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 557c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 558c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 559c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private class TvInputHardwareImpl extends ITvInputHardware.Stub { 560c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private final TvInputHardwareInfo mInfo; 561c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private boolean mReleased = false; 562c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private final Object mImplLock = new Object(); 563c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 56406c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim private final AudioManager.OnAudioPortUpdateListener mAudioListener = 56506c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim new AudioManager.OnAudioPortUpdateListener() { 56606c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim @Override 56706c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim public void onAudioPortListUpdate(AudioPort[] portList) { 56806c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim synchronized (mImplLock) { 5697587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim updateAudioConfigLocked(); 57006c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 57106c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 57206c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim 57306c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim @Override 57406c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim public void onAudioPatchListUpdate(AudioPatch[] patchList) { 57506c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim // No-op 57606c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 57706c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim 57806c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim @Override 57906c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim public void onServiceDied() { 58006c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim synchronized (mImplLock) { 58106c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim mAudioSource = null; 58206c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim mAudioSink = null; 58306c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim mAudioPatch = null; 58406c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 58506c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 58606c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim }; 58706c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim private int mOverrideAudioType = AudioManager.DEVICE_NONE; 58806c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim private String mOverrideAudioAddress = ""; 58906c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim private AudioDevicePort mAudioSource; 590ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim private AudioDevicePort mAudioSink; 591d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim private AudioPatch mAudioPatch = null; 5928e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim private float mCommittedVolume = 0.0f; 5938e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim private float mVolume = 0.0f; 594d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim 595839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim private TvStreamConfig mActiveConfig = null; 596839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim 597ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim private int mDesiredSamplingRate = 0; 598ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim private int mDesiredChannelMask = AudioFormat.CHANNEL_OUT_DEFAULT; 599ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim private int mDesiredFormat = AudioFormat.ENCODING_DEFAULT; 600ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim 601c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public TvInputHardwareImpl(TvInputHardwareInfo info) { 602c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mInfo = info; 60306c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim mAudioManager.registerAudioPortUpdateListener(mAudioListener); 604d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim if (mInfo.getAudioType() != AudioManager.DEVICE_NONE) { 60506c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim mAudioSource = findAudioDevicePort(mInfo.getAudioType(), mInfo.getAudioAddress()); 606ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim mAudioSink = findAudioSinkFromAudioPolicy(); 607ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 608ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 609ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim 610ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim private AudioDevicePort findAudioSinkFromAudioPolicy() { 611ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim ArrayList<AudioPort> devicePorts = new ArrayList<AudioPort>(); 612ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim if (mAudioManager.listAudioDevicePorts(devicePorts) == AudioManager.SUCCESS) { 613ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim int sinkDevice = mAudioManager.getDevicesForStream(AudioManager.STREAM_MUSIC); 614ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim for (AudioPort port : devicePorts) { 615ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim AudioDevicePort devicePort = (AudioDevicePort) port; 6161f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang if ((devicePort.type() & sinkDevice) != 0) { 617ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim return devicePort; 618d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim } 619d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim } 620d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim } 621ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim return null; 622ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 623ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim 624ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim private AudioDevicePort findAudioDevicePort(int type, String address) { 625ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim if (type == AudioManager.DEVICE_NONE) { 626ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim return null; 627ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 628ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim ArrayList<AudioPort> devicePorts = new ArrayList<AudioPort>(); 629ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim if (mAudioManager.listAudioDevicePorts(devicePorts) != AudioManager.SUCCESS) { 630ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim return null; 631ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 632ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim for (AudioPort port : devicePorts) { 633ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim AudioDevicePort devicePort = (AudioDevicePort) port; 634ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim if (devicePort.type() == type && devicePort.address().equals(address)) { 635ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim return devicePort; 636ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 637ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 638ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim return null; 639c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 640c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 641c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public void release() { 642c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mImplLock) { 64306c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim mAudioManager.unregisterAudioPortUpdateListener(mAudioListener); 644d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim if (mAudioPatch != null) { 645d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim mAudioManager.releaseAudioPatch(mAudioPatch); 646d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim mAudioPatch = null; 647d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim } 648c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mReleased = true; 649c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 650c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 651c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 652839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim // A TvInputHardwareImpl object holds only one active session. Therefore, if a client 653839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim // attempts to call setSurface with different TvStreamConfig objects, the last call will 654839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim // prevail. 655c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim @Override 656c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public boolean setSurface(Surface surface, TvStreamConfig config) 657c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim throws RemoteException { 658c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mImplLock) { 659c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (mReleased) { 660c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim throw new IllegalStateException("Device already released."); 661c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 662839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim if (surface != null && config == null) { 663839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim return false; 664839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim } 665839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim if (surface == null && mActiveConfig == null) { 666839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim return false; 667839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim } 6687587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim 669839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim int result = TvInputHal.ERROR_UNKNOWN; 670839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim if (surface == null) { 671839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim result = mHal.removeStream(mInfo.getDeviceId(), mActiveConfig); 672839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim mActiveConfig = null; 673839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim } else { 674839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim if (config != mActiveConfig && mActiveConfig != null) { 675839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim result = mHal.removeStream(mInfo.getDeviceId(), mActiveConfig); 676839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim if (result != TvInputHal.SUCCESS) { 677839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim mActiveConfig = null; 678839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim return false; 679839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim } 680839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim } 681839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim result = mHal.addStream(mInfo.getDeviceId(), surface, config); 682839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim if (result == TvInputHal.SUCCESS) { 683839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim mActiveConfig = config; 684839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim } 685839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim } 6867587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim updateAudioConfigLocked(); 687839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim return result == TvInputHal.SUCCESS; 688c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 689c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 690c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 6917587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim /** 6927587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim * Update audio configuration (source, sink, patch) all up to current state. 6937587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim */ 6947587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim private void updateAudioConfigLocked() { 6957587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim boolean sinkUpdated = updateAudioSinkLocked(); 6967587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim boolean sourceUpdated = updateAudioSourceLocked(); 6977587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim // We can't do updated = updateAudioSinkLocked() || updateAudioSourceLocked() here 6987587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim // because Java won't evaluate the latter if the former is true. 6997587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim 7007587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim if (mAudioSource == null || mAudioSink == null || mActiveConfig == null) { 70106c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim if (mAudioPatch != null) { 7027587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim mAudioManager.releaseAudioPatch(mAudioPatch); 7037587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim mAudioPatch = null; 70406c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 70506c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim return; 70606c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 70706c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim 7088e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim AudioGainConfig sourceGainConfig = null; 7098e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim if (mAudioSource.gains().length > 0 && mVolume != mCommittedVolume) { 7108e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim AudioGain sourceGain = null; 7118e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim for (AudioGain gain : mAudioSource.gains()) { 7128e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim if ((gain.mode() & AudioGain.MODE_JOINT) != 0) { 7138e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim sourceGain = gain; 7148e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim break; 7158e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim } 7168e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim } 7178e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim // NOTE: we only change the source gain in MODE_JOINT here. 7188e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim if (sourceGain != null) { 7198e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim int steps = (sourceGain.maxValue() - sourceGain.minValue()) 7208e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim / sourceGain.stepValue(); 7218e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim int gainValue = sourceGain.minValue(); 7228e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim if (mVolume < 1.0f) { 7238e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim gainValue += sourceGain.stepValue() * (int) (mVolume * steps + 0.5); 7248e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim } else { 7258e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim gainValue = sourceGain.maxValue(); 7268e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim } 7278e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim int numChannels = 0; 7288e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim for (int mask = sourceGain.channelMask(); mask > 0; mask >>= 1) { 7298e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim numChannels += (mask & 1); 7308e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim } 7318e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim int[] gainValues = new int[numChannels]; 7328e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim Arrays.fill(gainValues, gainValue); 7338e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim sourceGainConfig = sourceGain.buildConfig(AudioGain.MODE_JOINT, 7348e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim sourceGain.channelMask(), gainValues, 0); 7358e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim } else { 7368e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim Slog.w(TAG, "No audio source gain with MODE_JOINT support exists."); 7378e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim } 7388e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim } 7398e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim 740ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim AudioPortConfig sourceConfig = mAudioSource.activeConfig(); 741ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim AudioPortConfig sinkConfig = mAudioSink.activeConfig(); 742ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim AudioPatch[] audioPatchArray = new AudioPatch[] { mAudioPatch }; 7437587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim boolean shouldRecreateAudioPatch = sourceUpdated || sinkUpdated; 744ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim if (sinkConfig == null 745ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim || (mDesiredSamplingRate != 0 746ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim && sinkConfig.samplingRate() != mDesiredSamplingRate) 747ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim || (mDesiredChannelMask != AudioFormat.CHANNEL_OUT_DEFAULT 748ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim && sinkConfig.channelMask() != mDesiredChannelMask) 749ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim || (mDesiredFormat != AudioFormat.ENCODING_DEFAULT 750ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim && sinkConfig.format() != mDesiredFormat)) { 751ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim sinkConfig = mAudioSource.buildConfig(mDesiredSamplingRate, mDesiredChannelMask, 752ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim mDesiredFormat, null); 7538e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim shouldRecreateAudioPatch = true; 754ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 7558e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim if (sourceConfig == null || sourceGainConfig != null) { 756ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim sourceConfig = mAudioSource.buildConfig(sinkConfig.samplingRate(), 7578e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim sinkConfig.channelMask(), sinkConfig.format(), sourceGainConfig); 7588e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim shouldRecreateAudioPatch = true; 7598e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim } 7608e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim if (shouldRecreateAudioPatch) { 7618e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim mCommittedVolume = mVolume; 7628e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim mAudioManager.createAudioPatch( 7638e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim audioPatchArray, 7648e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim new AudioPortConfig[] { sourceConfig }, 7658e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim new AudioPortConfig[] { sinkConfig }); 7668e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim mAudioPatch = audioPatchArray[0]; 767ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 768ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 769ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim 770c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim @Override 7718e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim public void setStreamVolume(float volume) throws RemoteException { 772c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mImplLock) { 773c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (mReleased) { 774c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim throw new IllegalStateException("Device already released."); 775c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 7768e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim mVolume = volume; 7777587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim updateAudioConfigLocked(); 778c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 779c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 780c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 781c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim @Override 782c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public boolean dispatchKeyEventToHdmi(KeyEvent event) throws RemoteException { 783c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mImplLock) { 784c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (mReleased) { 785c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim throw new IllegalStateException("Device already released."); 786c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 787c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 788610ccd9117fc1611fcc576d1cb1f717f1ef3fcbfWonsik Kim if (mInfo.getType() != TvInputHardwareInfo.TV_INPUT_TYPE_HDMI) { 789c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return false; 790c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 791c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim // TODO(hdmi): mHdmiClient.sendKeyEvent(event); 792c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return false; 793c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 794c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 795c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo private boolean startCapture(Surface surface, TvStreamConfig config) { 796c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo synchronized (mImplLock) { 797c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (mReleased) { 798c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return false; 799c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 800c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (surface == null || config == null) { 801c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return false; 802c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 803c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (config.getType() != TvStreamConfig.STREAM_TYPE_BUFFER_PRODUCER) { 804c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return false; 805c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 806c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 807c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo int result = mHal.addStream(mInfo.getDeviceId(), surface, config); 808c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return result == TvInputHal.SUCCESS; 809c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 810c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 811c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 812c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo private boolean stopCapture(TvStreamConfig config) { 813c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo synchronized (mImplLock) { 814c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (mReleased) { 815c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return false; 816c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 817c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (config == null) { 818c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return false; 819c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 820c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 821c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo int result = mHal.removeStream(mInfo.getDeviceId(), config); 822c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return result == TvInputHal.SUCCESS; 823c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 824c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 825ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim 8267587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim private boolean updateAudioSourceLocked() { 82706c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim if (mInfo.getAudioType() == AudioManager.DEVICE_NONE) { 8287587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim return false; 82906c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 8307587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim AudioDevicePort previousSource = mAudioSource; 8317587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim mAudioSource = findAudioDevicePort(mInfo.getAudioType(), mInfo.getAudioAddress()); 8327587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim return mAudioSource == null ? (previousSource != null) 8337587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim : !mAudioSource.equals(previousSource); 8347587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim } 8357587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim 8367587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim private boolean updateAudioSinkLocked() { 8377587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim if (mInfo.getAudioType() == AudioManager.DEVICE_NONE) { 8387587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim return false; 8397587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim } 8407587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim AudioDevicePort previousSink = mAudioSink; 84106c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim if (mOverrideAudioType == AudioManager.DEVICE_NONE) { 84206c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim mAudioSink = findAudioSinkFromAudioPolicy(); 84306c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } else { 84406c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim AudioDevicePort audioSink = 84506c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim findAudioDevicePort(mOverrideAudioType, mOverrideAudioAddress); 84606c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim if (audioSink != null) { 84706c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim mAudioSink = audioSink; 84806c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 84906c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 8507587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim return mAudioSink == null ? (previousSink != null) : !mAudioSink.equals(previousSink); 85106c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 85206c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim 8531f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang private void handleAudioSinkUpdated() { 8541f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang synchronized (mImplLock) { 8557587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim updateAudioConfigLocked(); 8561f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang } 8571f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang } 8581f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang 859ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim @Override 860ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim public void overrideAudioSink(int audioType, String audioAddress, int samplingRate, 861ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim int channelMask, int format) { 862ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim synchronized (mImplLock) { 86306c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim mOverrideAudioType = audioType; 86406c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim mOverrideAudioAddress = audioAddress; 86506c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim 866ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim mDesiredSamplingRate = samplingRate; 867ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim mDesiredChannelMask = channelMask; 868ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim mDesiredFormat = format; 869ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim 8707587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim updateAudioConfigLocked(); 871ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 872ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 873c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 874969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 875187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim interface Listener { 876187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim public void onStateChanged(String inputId, int state); 877187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim public void onHardwareDeviceAdded(TvInputHardwareInfo info); 8784f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee public void onHardwareDeviceRemoved(TvInputHardwareInfo info); 879546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo public void onHdmiDeviceAdded(HdmiDeviceInfo device); 880546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo public void onHdmiDeviceRemoved(HdmiDeviceInfo device); 881e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim public void onHdmiDeviceUpdated(String inputId, HdmiDeviceInfo device); 882187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 883969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 884187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim private class ListenerHandler extends Handler { 885187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim private static final int STATE_CHANGED = 1; 886187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim private static final int HARDWARE_DEVICE_ADDED = 2; 887187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim private static final int HARDWARE_DEVICE_REMOVED = 3; 888546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo private static final int HDMI_DEVICE_ADDED = 4; 889546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo private static final int HDMI_DEVICE_REMOVED = 5; 89061daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang private static final int HDMI_DEVICE_UPDATED = 6; 891969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 892969167dc05a6485a32d160895871cff46fd81884Wonsik Kim @Override 893969167dc05a6485a32d160895871cff46fd81884Wonsik Kim public final void handleMessage(Message msg) { 894969167dc05a6485a32d160895871cff46fd81884Wonsik Kim switch (msg.what) { 895187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim case STATE_CHANGED: { 896969167dc05a6485a32d160895871cff46fd81884Wonsik Kim String inputId = (String) msg.obj; 897969167dc05a6485a32d160895871cff46fd81884Wonsik Kim int state = msg.arg1; 898187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim mListener.onStateChanged(inputId, state); 899187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim break; 900187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 901187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim case HARDWARE_DEVICE_ADDED: { 902187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim TvInputHardwareInfo info = (TvInputHardwareInfo) msg.obj; 903187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim mListener.onHardwareDeviceAdded(info); 904187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim break; 905187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 906187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim case HARDWARE_DEVICE_REMOVED: { 9074f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee TvInputHardwareInfo info = (TvInputHardwareInfo) msg.obj; 9084f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mListener.onHardwareDeviceRemoved(info); 909187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim break; 910187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 911546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo case HDMI_DEVICE_ADDED: { 91261f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo info = (HdmiDeviceInfo) msg.obj; 913546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo mListener.onHdmiDeviceAdded(info); 914187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim break; 915187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 916546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo case HDMI_DEVICE_REMOVED: { 91761f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo info = (HdmiDeviceInfo) msg.obj; 918546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo mListener.onHdmiDeviceRemoved(info); 919969167dc05a6485a32d160895871cff46fd81884Wonsik Kim break; 920969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 92161daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang case HDMI_DEVICE_UPDATED: { 922e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim SomeArgs args = (SomeArgs) msg.obj; 923e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim String inputId = (String) args.arg1; 924e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim HdmiDeviceInfo info = (HdmiDeviceInfo) args.arg2; 925e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim args.recycle(); 926e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim mListener.onHdmiDeviceUpdated(inputId, info); 92761daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang } 928969167dc05a6485a32d160895871cff46fd81884Wonsik Kim default: { 929969167dc05a6485a32d160895871cff46fd81884Wonsik Kim Slog.w(TAG, "Unhandled message: " + msg); 930969167dc05a6485a32d160895871cff46fd81884Wonsik Kim break; 931969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 932969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 933969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 934969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 935187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim 9367474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim // Listener implementations for HdmiControlService 9377474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim 9387474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim private final class HdmiHotplugEventListener extends IHdmiHotplugEventListener.Stub { 9397474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim @Override 9407474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim public void onReceived(HdmiHotplugEvent event) { 9417474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim synchronized (mLock) { 9427474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim mHdmiStateMap.put(event.getPort(), event.isConnected()); 943d922a546b94119217fb790113d0001cad0432060Wonsik Kim TvInputHardwareInfo hardwareInfo = 944d922a546b94119217fb790113d0001cad0432060Wonsik Kim findHardwareInfoForHdmiPortLocked(event.getPort()); 945d922a546b94119217fb790113d0001cad0432060Wonsik Kim if (hardwareInfo == null) { 946d922a546b94119217fb790113d0001cad0432060Wonsik Kim return; 947d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 948d922a546b94119217fb790113d0001cad0432060Wonsik Kim String inputId = mHardwareInputIdMap.get(hardwareInfo.getDeviceId()); 9497474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim if (inputId == null) { 9507474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim return; 9517474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim } 9527474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim mHandler.obtainMessage(ListenerHandler.STATE_CHANGED, 9537474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim convertConnectedToState(event.isConnected()), 0, inputId).sendToTarget(); 9547474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim } 9557474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim } 9567474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim } 9577474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim 958187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim private final class HdmiDeviceEventListener extends IHdmiDeviceEventListener.Stub { 959187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim @Override 96061daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang public void onStatusChanged(HdmiDeviceInfo deviceInfo, int status) { 961d922a546b94119217fb790113d0001cad0432060Wonsik Kim synchronized (mLock) { 96261daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang int messageType = 0; 963e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim Object obj = null; 96461daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang switch (status) { 96561daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang case HdmiControlManager.DEVICE_EVENT_ADD_DEVICE: { 96661daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang if (!mHdmiDeviceList.contains(deviceInfo)) { 96761daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang mHdmiDeviceList.add(deviceInfo); 96861daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang } else { 96961daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang Slog.w(TAG, "The list already contains " + deviceInfo + "; ignoring."); 97061daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang return; 97161daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang } 97261daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang messageType = ListenerHandler.HDMI_DEVICE_ADDED; 973e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim obj = deviceInfo; 97461daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang break; 975d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 97661daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang case HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE: { 97761daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang if (!mHdmiDeviceList.remove(deviceInfo)) { 97861daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang Slog.w(TAG, "The list doesn't contain " + deviceInfo + "; ignoring."); 97961daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang return; 98061daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang } 98161daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang messageType = ListenerHandler.HDMI_DEVICE_REMOVED; 982e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim obj = deviceInfo; 98361daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang break; 98461daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang } 98561daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang case HdmiControlManager.DEVICE_EVENT_UPDATE_DEVICE: { 98661daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang if (!mHdmiDeviceList.remove(deviceInfo)) { 98761daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang Slog.w(TAG, "The list doesn't contain " + deviceInfo + "; ignoring."); 98861daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang return; 98961daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang } 99061daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang mHdmiDeviceList.add(deviceInfo); 99161daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang messageType = ListenerHandler.HDMI_DEVICE_UPDATED; 992e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim String inputId = mHdmiInputIdMap.get(deviceInfo.getLogicalAddress()); 993e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim SomeArgs args = SomeArgs.obtain(); 994e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim args.arg1 = inputId; 995e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim args.arg2 = deviceInfo; 996e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim obj = args; 99761daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang break; 998d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 999d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 100061daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang 1001e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim Message msg = mHandler.obtainMessage(messageType, 0, 0, obj); 1002d922a546b94119217fb790113d0001cad0432060Wonsik Kim if (findHardwareInfoForHdmiPortLocked(deviceInfo.getPortId()) != null) { 1003d922a546b94119217fb790113d0001cad0432060Wonsik Kim msg.sendToTarget(); 1004d922a546b94119217fb790113d0001cad0432060Wonsik Kim } else { 1005d922a546b94119217fb790113d0001cad0432060Wonsik Kim mPendingHdmiDeviceEvents.add(msg); 1006d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 1007d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 1008187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 1009187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 10107474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim 10111f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang private final class HdmiSystemAudioModeChangeListener extends 10121f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang IHdmiSystemAudioModeChangeListener.Stub { 10131f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang @Override 10141f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang public void onStatusChanged(boolean enabled) throws RemoteException { 10151f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang synchronized (mLock) { 10161f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang for (int i = 0; i < mConnections.size(); ++i) { 10171f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang TvInputHardwareImpl impl = mConnections.valueAt(i).getHardwareImplLocked(); 10181f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang impl.handleAudioSinkUpdated(); 10191f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang } 10201f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang } 10211f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang } 10221f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang } 1023c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim} 1024