TvInputHardwareManager.java revision d38bf476f6a31602e92a3207a4ceb29bf965f9aa
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 58969167dc05a6485a32d160895871cff46fd81884Wonsik Kimimport com.android.server.SystemService; 59969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 60c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimimport java.util.ArrayList; 618e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kimimport java.util.Arrays; 624f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Leeimport java.util.Collections; 63d922a546b94119217fb790113d0001cad0432060Wonsik Kimimport java.util.Iterator; 64d922a546b94119217fb790113d0001cad0432060Wonsik Kimimport java.util.LinkedList; 65c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimimport java.util.List; 664f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Leeimport java.util.Map; 67c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 68c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim/** 69c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * A helper class for TvInputManagerService to handle TV input hardware. 70c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * 71c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * This class does a basic connection management and forwarding calls to TvInputHal which eventually 72c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * calls to tv_input HAL module. 73c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * 74c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * @hide 75c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim */ 767474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kimclass TvInputHardwareManager implements TvInputHal.Callback { 77c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private static final String TAG = TvInputHardwareManager.class.getSimpleName(); 784f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee 794f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee private final Context mContext; 804f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee private final Listener mListener; 81c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private final TvInputHal mHal = new TvInputHal(this); 82d922a546b94119217fb790113d0001cad0432060Wonsik Kim private final SparseArray<Connection> mConnections = new SparseArray<>(); 83d922a546b94119217fb790113d0001cad0432060Wonsik Kim private final List<TvInputHardwareInfo> mHardwareList = new ArrayList<>(); 84546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo private final List<HdmiDeviceInfo> mHdmiDeviceList = new LinkedList<>(); 854f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee /* A map from a device ID to the matching TV input ID. */ 86d922a546b94119217fb790113d0001cad0432060Wonsik Kim private final SparseArray<String> mHardwareInputIdMap = new SparseArray<>(); 874f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee /* A map from a HDMI logical address to the matching TV input ID. */ 88546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo private final SparseArray<String> mHdmiInputIdMap = new SparseArray<>(); 89d922a546b94119217fb790113d0001cad0432060Wonsik Kim private final Map<String, TvInputInfo> mInputMap = new ArrayMap<>(); 904f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee 91d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim private final AudioManager mAudioManager; 924f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee private IHdmiControlService mHdmiControlService; 937474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim private final IHdmiHotplugEventListener mHdmiHotplugEventListener = 947474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim new HdmiHotplugEventListener(); 954f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee private final IHdmiDeviceEventListener mHdmiDeviceEventListener = new HdmiDeviceEventListener(); 961f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang private final IHdmiSystemAudioModeChangeListener mHdmiSystemAudioModeChangeListener = 971f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang new HdmiSystemAudioModeChangeListener(); 98d38bf476f6a31602e92a3207a4ceb29bf965f9aaJinsuk Kim 99d922a546b94119217fb790113d0001cad0432060Wonsik Kim // TODO: Should handle STANDBY case. 1004f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee private final SparseBooleanArray mHdmiStateMap = new SparseBooleanArray(); 101d922a546b94119217fb790113d0001cad0432060Wonsik Kim private final List<Message> mPendingHdmiDeviceEvents = new LinkedList<>(); 102969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 103187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim // Calls to mListener should happen here. 104187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim private final Handler mHandler = new ListenerHandler(); 105c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 106c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private final Object mLock = new Object(); 107c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 108187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim public TvInputHardwareManager(Context context, Listener listener) { 109c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mContext = context; 110187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim mListener = listener; 111d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); 112c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mHal.init(); 113969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 114969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 115969167dc05a6485a32d160895871cff46fd81884Wonsik Kim public void onBootPhase(int phase) { 116969167dc05a6485a32d160895871cff46fd81884Wonsik Kim if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { 1174f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mHdmiControlService = IHdmiControlService.Stub.asInterface(ServiceManager.getService( 1184f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee Context.HDMI_CONTROL_SERVICE)); 1194f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee if (mHdmiControlService != null) { 1207474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim try { 1214f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mHdmiControlService.addHotplugEventListener(mHdmiHotplugEventListener); 1224f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mHdmiControlService.addDeviceEventListener(mHdmiDeviceEventListener); 1231f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang mHdmiControlService.addSystemAudioModeChangeListener( 1241f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang mHdmiSystemAudioModeChangeListener); 125546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo mHdmiDeviceList.addAll(mHdmiControlService.getInputDevices()); 1267474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim } catch (RemoteException e) { 1274f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee Slog.w(TAG, "Error registering listeners to HdmiControlService:", e); 1287474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim } 1297474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim } 130969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 131c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 132c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 133c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim @Override 1344f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee public void onDeviceAvailable(TvInputHardwareInfo info, TvStreamConfig[] configs) { 135c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mLock) { 136c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Connection connection = new Connection(info); 137c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim connection.updateConfigsLocked(configs); 138c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mConnections.put(info.getDeviceId(), connection); 139d922a546b94119217fb790113d0001cad0432060Wonsik Kim buildHardwareListLocked(); 140187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim mHandler.obtainMessage( 141187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim ListenerHandler.HARDWARE_DEVICE_ADDED, 0, 0, info).sendToTarget(); 142d922a546b94119217fb790113d0001cad0432060Wonsik Kim if (info.getType() == TvInputHardwareInfo.TV_INPUT_TYPE_HDMI) { 143d922a546b94119217fb790113d0001cad0432060Wonsik Kim processPendingHdmiDeviceEventsLocked(); 144d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 145c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 146c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 147c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 148d922a546b94119217fb790113d0001cad0432060Wonsik Kim private void buildHardwareListLocked() { 149d922a546b94119217fb790113d0001cad0432060Wonsik Kim mHardwareList.clear(); 150c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim for (int i = 0; i < mConnections.size(); ++i) { 151d922a546b94119217fb790113d0001cad0432060Wonsik Kim mHardwareList.add(mConnections.valueAt(i).getHardwareInfoLocked()); 152c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 153c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 154c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 155c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim @Override 156c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public void onDeviceUnavailable(int deviceId) { 157c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mLock) { 158c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Connection connection = mConnections.get(deviceId); 159c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (connection == null) { 160c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Slog.e(TAG, "onDeviceUnavailable: Cannot find a connection with " + deviceId); 161c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return; 162c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 163969167dc05a6485a32d160895871cff46fd81884Wonsik Kim connection.resetLocked(null, null, null, null, null); 164c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mConnections.remove(deviceId); 165d922a546b94119217fb790113d0001cad0432060Wonsik Kim buildHardwareListLocked(); 1664f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee TvInputHardwareInfo info = connection.getHardwareInfoLocked(); 167d922a546b94119217fb790113d0001cad0432060Wonsik Kim if (info.getType() == TvInputHardwareInfo.TV_INPUT_TYPE_HDMI) { 168546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo // Remove HDMI devices linked with this hardware. 169546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo for (Iterator<HdmiDeviceInfo> it = mHdmiDeviceList.iterator(); it.hasNext();) { 17061f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo deviceInfo = it.next(); 171d922a546b94119217fb790113d0001cad0432060Wonsik Kim if (deviceInfo.getPortId() == info.getHdmiPortId()) { 172546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo mHandler.obtainMessage(ListenerHandler.HDMI_DEVICE_REMOVED, 0, 0, 173d922a546b94119217fb790113d0001cad0432060Wonsik Kim deviceInfo).sendToTarget(); 174d922a546b94119217fb790113d0001cad0432060Wonsik Kim it.remove(); 175d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 176d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 177d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 178187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim mHandler.obtainMessage( 1794f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee ListenerHandler.HARDWARE_DEVICE_REMOVED, 0, 0, info).sendToTarget(); 180c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 181c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 182c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 183c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim @Override 184c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public void onStreamConfigurationChanged(int deviceId, TvStreamConfig[] configs) { 185c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mLock) { 186c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Connection connection = mConnections.get(deviceId); 187c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (connection == null) { 188c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Slog.e(TAG, "StreamConfigurationChanged: Cannot find a connection with " 189c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim + deviceId); 190c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return; 191c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 192c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim connection.updateConfigsLocked(configs); 193c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim try { 194c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim connection.getCallbackLocked().onStreamConfigChanged(configs); 195c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } catch (RemoteException e) { 1964f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee Slog.e(TAG, "error in onStreamConfigurationChanged", e); 197c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 198c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 199c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 200c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 201c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo @Override 202c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo public void onFirstFrameCaptured(int deviceId, int streamId) { 203c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo synchronized (mLock) { 204c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Connection connection = mConnections.get(deviceId); 205c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (connection == null) { 206c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Slog.e(TAG, "FirstFrameCaptured: Cannot find a connection with " 207c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo + deviceId); 208c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return; 209c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 210c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Runnable runnable = connection.getOnFirstFrameCapturedLocked(); 211c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (runnable != null) { 212c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo runnable.run(); 213c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo connection.setOnFirstFrameCapturedLocked(null); 214c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 215c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 216c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 217c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 218c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public List<TvInputHardwareInfo> getHardwareList() { 219c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mLock) { 220d922a546b94119217fb790113d0001cad0432060Wonsik Kim return Collections.unmodifiableList(mHardwareList); 221c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 222c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 223c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 224546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo public List<HdmiDeviceInfo> getHdmiDeviceList() { 225d922a546b94119217fb790113d0001cad0432060Wonsik Kim synchronized (mLock) { 226546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo return Collections.unmodifiableList(mHdmiDeviceList); 2274f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 2284f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 2294f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee 230e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim private boolean checkUidChangedLocked( 231e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim Connection connection, int callingUid, int resolvedUserId) { 232e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim Integer connectionCallingUid = connection.getCallingUidLocked(); 233e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim Integer connectionResolvedUserId = connection.getResolvedUserIdLocked(); 234e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim if (connectionCallingUid == null || connectionResolvedUserId == null) { 235e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim return true; 236e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim } 237e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim if (connectionCallingUid != callingUid || connectionResolvedUserId != resolvedUserId) { 238e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim return true; 239e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim } 240e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim return false; 241e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim } 242e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim 243969167dc05a6485a32d160895871cff46fd81884Wonsik Kim private int convertConnectedToState(boolean connected) { 244969167dc05a6485a32d160895871cff46fd81884Wonsik Kim if (connected) { 245969167dc05a6485a32d160895871cff46fd81884Wonsik Kim return INPUT_STATE_CONNECTED; 246969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } else { 247969167dc05a6485a32d160895871cff46fd81884Wonsik Kim return INPUT_STATE_DISCONNECTED; 248969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 249969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 250969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 2514f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee public void addHardwareTvInput(int deviceId, TvInputInfo info) { 252969167dc05a6485a32d160895871cff46fd81884Wonsik Kim synchronized (mLock) { 2534f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee String oldInputId = mHardwareInputIdMap.get(deviceId); 2544f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee if (oldInputId != null) { 255969167dc05a6485a32d160895871cff46fd81884Wonsik Kim Slog.w(TAG, "Trying to override previous registration: old = " 2564f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee + mInputMap.get(oldInputId) + ":" + deviceId + ", new = " 257969167dc05a6485a32d160895871cff46fd81884Wonsik Kim + info + ":" + deviceId); 258969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 2594f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mHardwareInputIdMap.put(deviceId, info.getId()); 2604f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mInputMap.put(info.getId(), info); 261969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 262969167dc05a6485a32d160895871cff46fd81884Wonsik Kim for (int i = 0; i < mHdmiStateMap.size(); ++i) { 263d922a546b94119217fb790113d0001cad0432060Wonsik Kim TvInputHardwareInfo hardwareInfo = 264d922a546b94119217fb790113d0001cad0432060Wonsik Kim findHardwareInfoForHdmiPortLocked(mHdmiStateMap.keyAt(i)); 265d922a546b94119217fb790113d0001cad0432060Wonsik Kim if (hardwareInfo == null) { 266d922a546b94119217fb790113d0001cad0432060Wonsik Kim continue; 267d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 268d922a546b94119217fb790113d0001cad0432060Wonsik Kim String inputId = mHardwareInputIdMap.get(hardwareInfo.getDeviceId()); 269969167dc05a6485a32d160895871cff46fd81884Wonsik Kim if (inputId != null && inputId.equals(info.getId())) { 270187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim mHandler.obtainMessage(ListenerHandler.STATE_CHANGED, 271969167dc05a6485a32d160895871cff46fd81884Wonsik Kim convertConnectedToState(mHdmiStateMap.valueAt(i)), 0, 272969167dc05a6485a32d160895871cff46fd81884Wonsik Kim inputId).sendToTarget(); 273969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 274969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 275969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 276969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 277969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 27838feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim private static <T> int indexOfEqualValue(SparseArray<T> map, T value) { 27938feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim for (int i = 0; i < map.size(); ++i) { 28038feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim if (map.valueAt(i).equals(value)) { 28138feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim return i; 28238feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim } 28338feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim } 28438feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim return -1; 28538feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim } 28638feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim 287546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo public void addHdmiTvInput(int logicalAddress, TvInputInfo info) { 2884f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee if (info.getType() != TvInputInfo.TYPE_HDMI) { 2894f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee throw new IllegalArgumentException("info (" + info + ") has non-HDMI type."); 2904f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 2914f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee synchronized (mLock) { 2924f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee String parentId = info.getParentId(); 29338feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim int parentIndex = indexOfEqualValue(mHardwareInputIdMap, parentId); 29438feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim if (parentIndex < 0) { 2954f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee throw new IllegalArgumentException("info (" + info + ") has invalid parentId."); 2964f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 297546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo String oldInputId = mHdmiInputIdMap.get(logicalAddress); 2984f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee if (oldInputId != null) { 2994f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee Slog.w(TAG, "Trying to override previous registration: old = " 3004f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee + mInputMap.get(oldInputId) + ":" + logicalAddress + ", new = " 3014f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee + info + ":" + logicalAddress); 3024f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 303546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo mHdmiInputIdMap.put(logicalAddress, info.getId()); 3044f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mInputMap.put(info.getId(), info); 3054f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 3064f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 3074f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee 3084f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee public void removeTvInput(String inputId) { 3094f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee synchronized (mLock) { 3104f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mInputMap.remove(inputId); 31138feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim int hardwareIndex = indexOfEqualValue(mHardwareInputIdMap, inputId); 3124f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee if (hardwareIndex >= 0) { 3134f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mHardwareInputIdMap.removeAt(hardwareIndex); 3144f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 315546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo int deviceIndex = indexOfEqualValue(mHdmiInputIdMap, inputId); 316546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo if (deviceIndex >= 0) { 317546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo mHdmiInputIdMap.removeAt(deviceIndex); 3184f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 3194f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 3204f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 3214f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee 322c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim /** 323c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * Create a TvInputHardware object with a specific deviceId. One service at a time can access 324c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * the object, and if more than one process attempts to create hardware with the same deviceId, 325c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * the latest service will get the object and all the other hardware are released. The 326c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * release is notified via ITvInputHardwareCallback.onReleased(). 327c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim */ 328c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public ITvInputHardware acquireHardware(int deviceId, ITvInputHardwareCallback callback, 329969167dc05a6485a32d160895871cff46fd81884Wonsik Kim TvInputInfo info, int callingUid, int resolvedUserId) { 330c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (callback == null) { 331c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim throw new NullPointerException(); 332c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 333c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mLock) { 334c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Connection connection = mConnections.get(deviceId); 335c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (connection == null) { 336c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Slog.e(TAG, "Invalid deviceId : " + deviceId); 337c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return null; 338c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 339e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim if (checkUidChangedLocked(connection, callingUid, resolvedUserId)) { 340969167dc05a6485a32d160895871cff46fd81884Wonsik Kim TvInputHardwareImpl hardware = 341969167dc05a6485a32d160895871cff46fd81884Wonsik Kim new TvInputHardwareImpl(connection.getHardwareInfoLocked()); 342c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim try { 343c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim callback.asBinder().linkToDeath(connection, 0); 344c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } catch (RemoteException e) { 345c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim hardware.release(); 346c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return null; 347c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 348969167dc05a6485a32d160895871cff46fd81884Wonsik Kim connection.resetLocked(hardware, callback, info, callingUid, resolvedUserId); 349c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 350c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return connection.getHardwareLocked(); 351c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 352c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 353c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 354c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim /** 355c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * Release the specified hardware. 356c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim */ 357c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public void releaseHardware(int deviceId, ITvInputHardware hardware, int callingUid, 358c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim int resolvedUserId) { 359c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mLock) { 360c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Connection connection = mConnections.get(deviceId); 361c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (connection == null) { 362c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Slog.e(TAG, "Invalid deviceId : " + deviceId); 363c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return; 364c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 365c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (connection.getHardwareLocked() != hardware 366e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim || checkUidChangedLocked(connection, callingUid, resolvedUserId)) { 367c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return; 368c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 369969167dc05a6485a32d160895871cff46fd81884Wonsik Kim connection.resetLocked(null, null, null, null, null); 370969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 371969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 372969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 373d922a546b94119217fb790113d0001cad0432060Wonsik Kim private TvInputHardwareInfo findHardwareInfoForHdmiPortLocked(int port) { 374d922a546b94119217fb790113d0001cad0432060Wonsik Kim for (TvInputHardwareInfo hardwareInfo : mHardwareList) { 375969167dc05a6485a32d160895871cff46fd81884Wonsik Kim if (hardwareInfo.getType() == TvInputHardwareInfo.TV_INPUT_TYPE_HDMI 376969167dc05a6485a32d160895871cff46fd81884Wonsik Kim && hardwareInfo.getHdmiPortId() == port) { 377d922a546b94119217fb790113d0001cad0432060Wonsik Kim return hardwareInfo; 378969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 379969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 380969167dc05a6485a32d160895871cff46fd81884Wonsik Kim return null; 381969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 382969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 383c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo private int findDeviceIdForInputIdLocked(String inputId) { 384c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo for (int i = 0; i < mConnections.size(); ++i) { 385c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Connection connection = mConnections.get(i); 386c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (connection.getInfoLocked().getId().equals(inputId)) { 387c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return i; 388c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 389c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 390c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return -1; 391c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 392c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 393c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo /** 394c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo * Get the list of TvStreamConfig which is buffered mode. 395c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo */ 396c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo public List<TvStreamConfig> getAvailableTvStreamConfigList(String inputId, int callingUid, 397c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo int resolvedUserId) { 398c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo List<TvStreamConfig> configsList = new ArrayList<TvStreamConfig>(); 399c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo synchronized (mLock) { 400c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo int deviceId = findDeviceIdForInputIdLocked(inputId); 401c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (deviceId < 0) { 402c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Slog.e(TAG, "Invalid inputId : " + inputId); 403c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return configsList; 404c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 405c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Connection connection = mConnections.get(deviceId); 406c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo for (TvStreamConfig config : connection.getConfigsLocked()) { 407c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (config.getType() == TvStreamConfig.STREAM_TYPE_BUFFER_PRODUCER) { 408c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo configsList.add(config); 409c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 410c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 411c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 412c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return configsList; 413c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 414c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 415c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo /** 416c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo * Take a snapshot of the given TV input into the provided Surface. 417c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo */ 418c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo public boolean captureFrame(String inputId, Surface surface, final TvStreamConfig config, 419c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo int callingUid, int resolvedUserId) { 420c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo synchronized (mLock) { 421c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo int deviceId = findDeviceIdForInputIdLocked(inputId); 422c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (deviceId < 0) { 423c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Slog.e(TAG, "Invalid inputId : " + inputId); 424c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return false; 425c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 426c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Connection connection = mConnections.get(deviceId); 427c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo final TvInputHardwareImpl hardwareImpl = connection.getHardwareImplLocked(); 428c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (hardwareImpl != null) { 429c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo // Stop previous capture. 430c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Runnable runnable = connection.getOnFirstFrameCapturedLocked(); 431c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (runnable != null) { 432c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo runnable.run(); 433c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo connection.setOnFirstFrameCapturedLocked(null); 434c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 435c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 436c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo boolean result = hardwareImpl.startCapture(surface, config); 437c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (result) { 438c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo connection.setOnFirstFrameCapturedLocked(new Runnable() { 439c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo @Override 440c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo public void run() { 441c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo hardwareImpl.stopCapture(config); 442c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 443c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo }); 444c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 445c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return result; 446c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 447c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 448c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return false; 449c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 450c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 451d922a546b94119217fb790113d0001cad0432060Wonsik Kim private void processPendingHdmiDeviceEventsLocked() { 452d922a546b94119217fb790113d0001cad0432060Wonsik Kim for (Iterator<Message> it = mPendingHdmiDeviceEvents.iterator(); it.hasNext(); ) { 453d922a546b94119217fb790113d0001cad0432060Wonsik Kim Message msg = it.next(); 45461f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo deviceInfo = (HdmiDeviceInfo) msg.obj; 455d922a546b94119217fb790113d0001cad0432060Wonsik Kim TvInputHardwareInfo hardwareInfo = 456d922a546b94119217fb790113d0001cad0432060Wonsik Kim findHardwareInfoForHdmiPortLocked(deviceInfo.getPortId()); 457d922a546b94119217fb790113d0001cad0432060Wonsik Kim if (hardwareInfo != null) { 458d922a546b94119217fb790113d0001cad0432060Wonsik Kim msg.sendToTarget(); 459d922a546b94119217fb790113d0001cad0432060Wonsik Kim it.remove(); 460d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 461d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 462d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 463d922a546b94119217fb790113d0001cad0432060Wonsik Kim 464c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private class Connection implements IBinder.DeathRecipient { 465969167dc05a6485a32d160895871cff46fd81884Wonsik Kim private final TvInputHardwareInfo mHardwareInfo; 466969167dc05a6485a32d160895871cff46fd81884Wonsik Kim private TvInputInfo mInfo; 467c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private TvInputHardwareImpl mHardware = null; 468c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private ITvInputHardwareCallback mCallback; 469c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private TvStreamConfig[] mConfigs = null; 470c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private Integer mCallingUid = null; 471c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private Integer mResolvedUserId = null; 472c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo private Runnable mOnFirstFrameCaptured; 473c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 474969167dc05a6485a32d160895871cff46fd81884Wonsik Kim public Connection(TvInputHardwareInfo hardwareInfo) { 475969167dc05a6485a32d160895871cff46fd81884Wonsik Kim mHardwareInfo = hardwareInfo; 476c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 477c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 478c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim // *Locked methods assume TvInputHardwareManager.mLock is held. 479c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 480969167dc05a6485a32d160895871cff46fd81884Wonsik Kim public void resetLocked(TvInputHardwareImpl hardware, ITvInputHardwareCallback callback, 481969167dc05a6485a32d160895871cff46fd81884Wonsik Kim TvInputInfo info, Integer callingUid, Integer resolvedUserId) { 482c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (mHardware != null) { 483c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim try { 484c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mCallback.onReleased(); 485c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } catch (RemoteException e) { 4864f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee Slog.e(TAG, "error in Connection::resetLocked", e); 487c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 488c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mHardware.release(); 489c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 490c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mHardware = hardware; 491c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mCallback = callback; 492969167dc05a6485a32d160895871cff46fd81884Wonsik Kim mInfo = info; 493c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mCallingUid = callingUid; 494c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mResolvedUserId = resolvedUserId; 495c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo mOnFirstFrameCaptured = null; 496c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 497c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (mHardware != null && mCallback != null) { 498c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim try { 499c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mCallback.onStreamConfigChanged(getConfigsLocked()); 500c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } catch (RemoteException e) { 5014f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee Slog.e(TAG, "error in Connection::resetLocked", e); 502c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 503c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 504c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 505c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 506c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public void updateConfigsLocked(TvStreamConfig[] configs) { 507c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mConfigs = configs; 508c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 509c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 510969167dc05a6485a32d160895871cff46fd81884Wonsik Kim public TvInputHardwareInfo getHardwareInfoLocked() { 511969167dc05a6485a32d160895871cff46fd81884Wonsik Kim return mHardwareInfo; 512969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 513969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 514969167dc05a6485a32d160895871cff46fd81884Wonsik Kim public TvInputInfo getInfoLocked() { 515c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return mInfo; 516c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 517c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 518c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public ITvInputHardware getHardwareLocked() { 519c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return mHardware; 520c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 521c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 522c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo public TvInputHardwareImpl getHardwareImplLocked() { 523c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return mHardware; 524c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 525c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 526c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public ITvInputHardwareCallback getCallbackLocked() { 527c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return mCallback; 528c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 529c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 530c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public TvStreamConfig[] getConfigsLocked() { 531c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return mConfigs; 532c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 533c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 534e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim public Integer getCallingUidLocked() { 535c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return mCallingUid; 536c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 537c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 538e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim public Integer getResolvedUserIdLocked() { 539c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return mResolvedUserId; 540c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 541c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 542c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo public void setOnFirstFrameCapturedLocked(Runnable runnable) { 543c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo mOnFirstFrameCaptured = runnable; 544c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 545c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 546c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo public Runnable getOnFirstFrameCapturedLocked() { 547c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return mOnFirstFrameCaptured; 548c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 549c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 550c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim @Override 551c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public void binderDied() { 552c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mLock) { 553969167dc05a6485a32d160895871cff46fd81884Wonsik Kim resetLocked(null, null, null, null, null); 554c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 555c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 556c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 557c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 558c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private class TvInputHardwareImpl extends ITvInputHardware.Stub { 559c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private final TvInputHardwareInfo mInfo; 560c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private boolean mReleased = false; 561c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private final Object mImplLock = new Object(); 562c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 56306c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim private final AudioManager.OnAudioPortUpdateListener mAudioListener = 56406c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim new AudioManager.OnAudioPortUpdateListener() { 56506c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim @Override 56606c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim public void onAudioPortListUpdate(AudioPort[] portList) { 56706c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim synchronized (mImplLock) { 56806c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim updateAudioSinkLocked(); 56906c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim if (mInfo.getAudioType() != AudioManager.DEVICE_NONE && mAudioSource == null) { 57006c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim mAudioSource = findAudioDevicePort(mInfo.getAudioType(), 57106c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim mInfo.getAudioAddress()); 57206c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim if (mActiveConfig != null) { 57306c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim updateAudioPatchLocked(); 57406c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 57506c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 57606c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 57706c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 57806c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim 57906c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim @Override 58006c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim public void onAudioPatchListUpdate(AudioPatch[] patchList) { 58106c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim // No-op 58206c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 58306c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim 58406c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim @Override 58506c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim public void onServiceDied() { 58606c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim synchronized (mImplLock) { 58706c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim mAudioSource = null; 58806c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim mAudioSink = null; 58906c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim mAudioPatch = null; 59006c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 59106c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 59206c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim }; 59306c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim private int mOverrideAudioType = AudioManager.DEVICE_NONE; 59406c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim private String mOverrideAudioAddress = ""; 59506c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim private AudioDevicePort mAudioSource; 596ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim private AudioDevicePort mAudioSink; 597d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim private AudioPatch mAudioPatch = null; 5988e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim private float mCommittedVolume = 0.0f; 5998e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim private float mVolume = 0.0f; 600d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim 601839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim private TvStreamConfig mActiveConfig = null; 602839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim 603ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim private int mDesiredSamplingRate = 0; 604ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim private int mDesiredChannelMask = AudioFormat.CHANNEL_OUT_DEFAULT; 605ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim private int mDesiredFormat = AudioFormat.ENCODING_DEFAULT; 606ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim 607c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public TvInputHardwareImpl(TvInputHardwareInfo info) { 608c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mInfo = info; 60906c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim mAudioManager.registerAudioPortUpdateListener(mAudioListener); 610d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim if (mInfo.getAudioType() != AudioManager.DEVICE_NONE) { 61106c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim mAudioSource = findAudioDevicePort(mInfo.getAudioType(), mInfo.getAudioAddress()); 612ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim mAudioSink = findAudioSinkFromAudioPolicy(); 613ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 614ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 615ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim 616ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim private AudioDevicePort findAudioSinkFromAudioPolicy() { 617ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim ArrayList<AudioPort> devicePorts = new ArrayList<AudioPort>(); 618ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim if (mAudioManager.listAudioDevicePorts(devicePorts) == AudioManager.SUCCESS) { 619ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim int sinkDevice = mAudioManager.getDevicesForStream(AudioManager.STREAM_MUSIC); 620ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim for (AudioPort port : devicePorts) { 621ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim AudioDevicePort devicePort = (AudioDevicePort) port; 6221f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang if ((devicePort.type() & sinkDevice) != 0) { 623ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim return devicePort; 624d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim } 625d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim } 626d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim } 627ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim return null; 628ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 629ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim 630ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim private AudioDevicePort findAudioDevicePort(int type, String address) { 631ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim if (type == AudioManager.DEVICE_NONE) { 632ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim return null; 633ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 634ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim ArrayList<AudioPort> devicePorts = new ArrayList<AudioPort>(); 635ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim if (mAudioManager.listAudioDevicePorts(devicePorts) != AudioManager.SUCCESS) { 636ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim return null; 637ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 638ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim for (AudioPort port : devicePorts) { 639ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim AudioDevicePort devicePort = (AudioDevicePort) port; 640ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim if (devicePort.type() == type && devicePort.address().equals(address)) { 641ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim return devicePort; 642ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 643ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 644ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim return null; 645c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 646c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 647c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public void release() { 648c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mImplLock) { 64906c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim mAudioManager.unregisterAudioPortUpdateListener(mAudioListener); 650d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim if (mAudioPatch != null) { 651d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim mAudioManager.releaseAudioPatch(mAudioPatch); 652d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim mAudioPatch = null; 653d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim } 654c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mReleased = true; 655c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 656c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 657c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 658839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim // A TvInputHardwareImpl object holds only one active session. Therefore, if a client 659839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim // attempts to call setSurface with different TvStreamConfig objects, the last call will 660839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim // prevail. 661c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim @Override 662c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public boolean setSurface(Surface surface, TvStreamConfig config) 663c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim throws RemoteException { 664c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mImplLock) { 665c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (mReleased) { 666c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim throw new IllegalStateException("Device already released."); 667c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 668839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim if (surface != null && config == null) { 669839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim return false; 670839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim } 671839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim if (surface == null && mActiveConfig == null) { 672839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim return false; 673839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim } 674d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim if (mAudioSource != null && mAudioSink != null) { 675d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim if (surface != null) { 676ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim updateAudioPatchLocked(); 677d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim } else { 678d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim mAudioManager.releaseAudioPatch(mAudioPatch); 679d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim mAudioPatch = null; 680d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim } 681d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim } 682839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim int result = TvInputHal.ERROR_UNKNOWN; 683839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim if (surface == null) { 684839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim result = mHal.removeStream(mInfo.getDeviceId(), mActiveConfig); 685839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim mActiveConfig = null; 686839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim } else { 687839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim if (config != mActiveConfig && mActiveConfig != null) { 688839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim result = mHal.removeStream(mInfo.getDeviceId(), mActiveConfig); 689839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim if (result != TvInputHal.SUCCESS) { 690839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim mActiveConfig = null; 691839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim return false; 692839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim } 693839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim } 694839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim result = mHal.addStream(mInfo.getDeviceId(), surface, config); 695839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim if (result == TvInputHal.SUCCESS) { 696839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim mActiveConfig = config; 697839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim } 698839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim } 699839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim return result == TvInputHal.SUCCESS; 700c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 701c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 702c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 703ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim private void updateAudioPatchLocked() { 70406c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim if (mAudioSource == null || mAudioSink == null) { 70506c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim if (mAudioPatch != null) { 70606c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim throw new IllegalStateException("Audio patch should be null if audio source " 70706c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim + "or sink is null."); 70806c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 70906c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim return; 71006c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 71106c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim 7128e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim AudioGainConfig sourceGainConfig = null; 7138e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim if (mAudioSource.gains().length > 0 && mVolume != mCommittedVolume) { 7148e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim AudioGain sourceGain = null; 7158e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim for (AudioGain gain : mAudioSource.gains()) { 7168e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim if ((gain.mode() & AudioGain.MODE_JOINT) != 0) { 7178e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim sourceGain = gain; 7188e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim break; 7198e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim } 7208e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim } 7218e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim // NOTE: we only change the source gain in MODE_JOINT here. 7228e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim if (sourceGain != null) { 7238e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim int steps = (sourceGain.maxValue() - sourceGain.minValue()) 7248e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim / sourceGain.stepValue(); 7258e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim int gainValue = sourceGain.minValue(); 7268e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim if (mVolume < 1.0f) { 7278e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim gainValue += sourceGain.stepValue() * (int) (mVolume * steps + 0.5); 7288e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim } else { 7298e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim gainValue = sourceGain.maxValue(); 7308e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim } 7318e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim int numChannels = 0; 7328e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim for (int mask = sourceGain.channelMask(); mask > 0; mask >>= 1) { 7338e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim numChannels += (mask & 1); 7348e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim } 7358e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim int[] gainValues = new int[numChannels]; 7368e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim Arrays.fill(gainValues, gainValue); 7378e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim sourceGainConfig = sourceGain.buildConfig(AudioGain.MODE_JOINT, 7388e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim sourceGain.channelMask(), gainValues, 0); 7398e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim } else { 7408e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim Slog.w(TAG, "No audio source gain with MODE_JOINT support exists."); 7418e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim } 7428e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim } 7438e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim 744ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim AudioPortConfig sourceConfig = mAudioSource.activeConfig(); 745ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim AudioPortConfig sinkConfig = mAudioSink.activeConfig(); 746ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim AudioPatch[] audioPatchArray = new AudioPatch[] { mAudioPatch }; 7478e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim boolean shouldRecreateAudioPatch = false; 748ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim if (sinkConfig == null 749ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim || (mDesiredSamplingRate != 0 750ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim && sinkConfig.samplingRate() != mDesiredSamplingRate) 751ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim || (mDesiredChannelMask != AudioFormat.CHANNEL_OUT_DEFAULT 752ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim && sinkConfig.channelMask() != mDesiredChannelMask) 753ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim || (mDesiredFormat != AudioFormat.ENCODING_DEFAULT 754ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim && sinkConfig.format() != mDesiredFormat)) { 755ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim sinkConfig = mAudioSource.buildConfig(mDesiredSamplingRate, mDesiredChannelMask, 756ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim mDesiredFormat, null); 7578e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim shouldRecreateAudioPatch = true; 758ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 7598e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim if (sourceConfig == null || sourceGainConfig != null) { 760ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim sourceConfig = mAudioSource.buildConfig(sinkConfig.samplingRate(), 7618e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim sinkConfig.channelMask(), sinkConfig.format(), sourceGainConfig); 7628e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim shouldRecreateAudioPatch = true; 7638e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim } 7648e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim if (shouldRecreateAudioPatch) { 7658e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim mCommittedVolume = mVolume; 7668e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim mAudioManager.createAudioPatch( 7678e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim audioPatchArray, 7688e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim new AudioPortConfig[] { sourceConfig }, 7698e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim new AudioPortConfig[] { sinkConfig }); 7708e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim mAudioPatch = audioPatchArray[0]; 771ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 772ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 773ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim 774c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim @Override 7758e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim public void setStreamVolume(float volume) throws RemoteException { 776c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mImplLock) { 777c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (mReleased) { 778c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim throw new IllegalStateException("Device already released."); 779c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 7808e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim mVolume = volume; 7818e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim updateAudioPatchLocked(); 782c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 783c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 784c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 785c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim @Override 786c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public boolean dispatchKeyEventToHdmi(KeyEvent event) throws RemoteException { 787c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mImplLock) { 788c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (mReleased) { 789c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim throw new IllegalStateException("Device already released."); 790c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 791c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 792610ccd9117fc1611fcc576d1cb1f717f1ef3fcbfWonsik Kim if (mInfo.getType() != TvInputHardwareInfo.TV_INPUT_TYPE_HDMI) { 793c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return false; 794c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 795c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim // TODO(hdmi): mHdmiClient.sendKeyEvent(event); 796c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return false; 797c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 798c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 799c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo private boolean startCapture(Surface surface, TvStreamConfig config) { 800c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo synchronized (mImplLock) { 801c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (mReleased) { 802c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return false; 803c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 804c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (surface == null || config == null) { 805c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return false; 806c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 807c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (config.getType() != TvStreamConfig.STREAM_TYPE_BUFFER_PRODUCER) { 808c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return false; 809c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 810c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 811c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo int result = mHal.addStream(mInfo.getDeviceId(), surface, config); 812c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return result == TvInputHal.SUCCESS; 813c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 814c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 815c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 816c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo private boolean stopCapture(TvStreamConfig config) { 817c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo synchronized (mImplLock) { 818c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (mReleased) { 819c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return false; 820c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 821c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (config == null) { 822c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return false; 823c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 824c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 825c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo int result = mHal.removeStream(mInfo.getDeviceId(), config); 826c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return result == TvInputHal.SUCCESS; 827c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 828c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 829ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim 83006c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim private void updateAudioSinkLocked() { 83106c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim if (mInfo.getAudioType() == AudioManager.DEVICE_NONE) { 83206c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim return; 83306c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 83406c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim if (mOverrideAudioType == AudioManager.DEVICE_NONE) { 83506c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim mAudioSink = findAudioSinkFromAudioPolicy(); 83606c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } else { 83706c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim AudioDevicePort audioSink = 83806c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim findAudioDevicePort(mOverrideAudioType, mOverrideAudioAddress); 83906c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim if (audioSink != null) { 84006c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim mAudioSink = audioSink; 84106c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 84206c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 84306c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 84406c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim 8451f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang private void handleAudioSinkUpdated() { 8461f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang synchronized (mImplLock) { 8471f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang updateAudioSinkLocked(); 8481f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang updateAudioPatchLocked(); 8491f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang } 8501f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang } 8511f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang 852ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim @Override 853ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim public void overrideAudioSink(int audioType, String audioAddress, int samplingRate, 854ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim int channelMask, int format) { 855ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim synchronized (mImplLock) { 85606c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim mOverrideAudioType = audioType; 85706c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim mOverrideAudioAddress = audioAddress; 85806c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim updateAudioSinkLocked(); 85906c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim 860ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim mDesiredSamplingRate = samplingRate; 861ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim mDesiredChannelMask = channelMask; 862ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim mDesiredFormat = format; 863ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim 864ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim if (mAudioPatch != null) { 865ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim updateAudioPatchLocked(); 866ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 867ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 868ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 869c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 870969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 871187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim interface Listener { 872187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim public void onStateChanged(String inputId, int state); 873187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim public void onHardwareDeviceAdded(TvInputHardwareInfo info); 8744f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee public void onHardwareDeviceRemoved(TvInputHardwareInfo info); 875546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo public void onHdmiDeviceAdded(HdmiDeviceInfo device); 876546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo public void onHdmiDeviceRemoved(HdmiDeviceInfo device); 87761daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang public void onHdmiDeviceUpdated(HdmiDeviceInfo device); 878187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 879969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 880187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim private class ListenerHandler extends Handler { 881187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim private static final int STATE_CHANGED = 1; 882187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim private static final int HARDWARE_DEVICE_ADDED = 2; 883187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim private static final int HARDWARE_DEVICE_REMOVED = 3; 884546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo private static final int HDMI_DEVICE_ADDED = 4; 885546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo private static final int HDMI_DEVICE_REMOVED = 5; 88661daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang private static final int HDMI_DEVICE_UPDATED = 6; 887969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 888969167dc05a6485a32d160895871cff46fd81884Wonsik Kim @Override 889969167dc05a6485a32d160895871cff46fd81884Wonsik Kim public final void handleMessage(Message msg) { 890969167dc05a6485a32d160895871cff46fd81884Wonsik Kim switch (msg.what) { 891187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim case STATE_CHANGED: { 892969167dc05a6485a32d160895871cff46fd81884Wonsik Kim String inputId = (String) msg.obj; 893969167dc05a6485a32d160895871cff46fd81884Wonsik Kim int state = msg.arg1; 894187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim mListener.onStateChanged(inputId, state); 895187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim break; 896187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 897187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim case HARDWARE_DEVICE_ADDED: { 898187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim TvInputHardwareInfo info = (TvInputHardwareInfo) msg.obj; 899187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim mListener.onHardwareDeviceAdded(info); 900187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim break; 901187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 902187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim case HARDWARE_DEVICE_REMOVED: { 9034f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee TvInputHardwareInfo info = (TvInputHardwareInfo) msg.obj; 9044f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mListener.onHardwareDeviceRemoved(info); 905187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim break; 906187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 907546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo case HDMI_DEVICE_ADDED: { 90861f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo info = (HdmiDeviceInfo) msg.obj; 909546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo mListener.onHdmiDeviceAdded(info); 910187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim break; 911187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 912546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo case HDMI_DEVICE_REMOVED: { 91361f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo info = (HdmiDeviceInfo) msg.obj; 914546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo mListener.onHdmiDeviceRemoved(info); 915969167dc05a6485a32d160895871cff46fd81884Wonsik Kim break; 916969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 91761daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang case HDMI_DEVICE_UPDATED: { 91861daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang HdmiDeviceInfo info = (HdmiDeviceInfo) msg.obj; 91961daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang mListener.onHdmiDeviceUpdated(info); 92061daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang } 921969167dc05a6485a32d160895871cff46fd81884Wonsik Kim default: { 922969167dc05a6485a32d160895871cff46fd81884Wonsik Kim Slog.w(TAG, "Unhandled message: " + msg); 923969167dc05a6485a32d160895871cff46fd81884Wonsik Kim break; 924969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 925969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 926969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 927969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 928187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim 9297474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim // Listener implementations for HdmiControlService 9307474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim 9317474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim private final class HdmiHotplugEventListener extends IHdmiHotplugEventListener.Stub { 9327474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim @Override 9337474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim public void onReceived(HdmiHotplugEvent event) { 9347474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim synchronized (mLock) { 9357474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim mHdmiStateMap.put(event.getPort(), event.isConnected()); 936d922a546b94119217fb790113d0001cad0432060Wonsik Kim TvInputHardwareInfo hardwareInfo = 937d922a546b94119217fb790113d0001cad0432060Wonsik Kim findHardwareInfoForHdmiPortLocked(event.getPort()); 938d922a546b94119217fb790113d0001cad0432060Wonsik Kim if (hardwareInfo == null) { 939d922a546b94119217fb790113d0001cad0432060Wonsik Kim return; 940d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 941d922a546b94119217fb790113d0001cad0432060Wonsik Kim String inputId = mHardwareInputIdMap.get(hardwareInfo.getDeviceId()); 9427474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim if (inputId == null) { 9437474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim return; 9447474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim } 9457474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim mHandler.obtainMessage(ListenerHandler.STATE_CHANGED, 9467474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim convertConnectedToState(event.isConnected()), 0, inputId).sendToTarget(); 9477474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim } 9487474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim } 9497474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim } 9507474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim 951187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim private final class HdmiDeviceEventListener extends IHdmiDeviceEventListener.Stub { 952187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim @Override 95361daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang public void onStatusChanged(HdmiDeviceInfo deviceInfo, int status) { 954d922a546b94119217fb790113d0001cad0432060Wonsik Kim synchronized (mLock) { 95561daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang int messageType = 0; 95661daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang switch (status) { 95761daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang case HdmiControlManager.DEVICE_EVENT_ADD_DEVICE: { 95861daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang if (!mHdmiDeviceList.contains(deviceInfo)) { 95961daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang mHdmiDeviceList.add(deviceInfo); 96061daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang } else { 96161daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang Slog.w(TAG, "The list already contains " + deviceInfo + "; ignoring."); 96261daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang return; 96361daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang } 96461daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang messageType = ListenerHandler.HDMI_DEVICE_ADDED; 96561daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang break; 966d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 96761daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang case HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE: { 96861daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang if (!mHdmiDeviceList.remove(deviceInfo)) { 96961daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang Slog.w(TAG, "The list doesn't contain " + deviceInfo + "; ignoring."); 97061daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang return; 97161daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang } 97261daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang messageType = ListenerHandler.HDMI_DEVICE_REMOVED; 97361daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang break; 97461daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang } 97561daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang case HdmiControlManager.DEVICE_EVENT_UPDATE_DEVICE: { 97661daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang if (!mHdmiDeviceList.remove(deviceInfo)) { 97761daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang Slog.w(TAG, "The list doesn't contain " + deviceInfo + "; ignoring."); 97861daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang return; 97961daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang } 98061daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang mHdmiDeviceList.add(deviceInfo); 98161daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang messageType = ListenerHandler.HDMI_DEVICE_UPDATED; 98261daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang break; 983d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 984d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 98561daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang 98661daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang Message msg = mHandler.obtainMessage(messageType, 0, 0, deviceInfo); 987d922a546b94119217fb790113d0001cad0432060Wonsik Kim if (findHardwareInfoForHdmiPortLocked(deviceInfo.getPortId()) != null) { 988d922a546b94119217fb790113d0001cad0432060Wonsik Kim msg.sendToTarget(); 989d922a546b94119217fb790113d0001cad0432060Wonsik Kim } else { 990d922a546b94119217fb790113d0001cad0432060Wonsik Kim mPendingHdmiDeviceEvents.add(msg); 991d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 992d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 993187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 994187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 9957474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim 9961f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang private final class HdmiSystemAudioModeChangeListener extends 9971f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang IHdmiSystemAudioModeChangeListener.Stub { 9981f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang @Override 9991f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang public void onStatusChanged(boolean enabled) throws RemoteException { 10001f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang synchronized (mLock) { 10011f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang for (int i = 0; i < mConnections.size(); ++i) { 10021f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang TvInputHardwareImpl impl = mConnections.valueAt(i).getHardwareImplLocked(); 10031f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang impl.handleAudioSinkUpdated(); 10041f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang } 10051f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang } 10061f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang } 10071f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang } 1008c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim} 1009