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 2249e559353278a56963596d652af26fe1f886a280Wonsik Kimimport android.content.BroadcastReceiver; 23c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimimport android.content.Context; 2449e559353278a56963596d652af26fe1f886a280Wonsik Kimimport android.content.Intent; 2549e559353278a56963596d652af26fe1f886a280Wonsik Kimimport android.content.IntentFilter; 2661daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jangimport android.hardware.hdmi.HdmiControlManager; 2761f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jangimport android.hardware.hdmi.HdmiDeviceInfo; 28969167dc05a6485a32d160895871cff46fd81884Wonsik Kimimport android.hardware.hdmi.HdmiHotplugEvent; 297474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kimimport android.hardware.hdmi.IHdmiControlService; 30187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kimimport android.hardware.hdmi.IHdmiDeviceEventListener; 317474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kimimport android.hardware.hdmi.IHdmiHotplugEventListener; 321f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jangimport android.hardware.hdmi.IHdmiSystemAudioModeChangeListener; 33d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kimimport android.media.AudioDevicePort; 34ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kimimport android.media.AudioFormat; 358e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kimimport android.media.AudioGain; 368e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kimimport android.media.AudioGainConfig; 37d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kimimport android.media.AudioManager; 38d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kimimport android.media.AudioPatch; 39d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kimimport android.media.AudioPort; 40d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kimimport android.media.AudioPortConfig; 41d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.ITvInputHardware; 42d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.ITvInputHardwareCallback; 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 8049e559353278a56963596d652af26fe1f886a280Wonsik Kim 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(); 9949e559353278a56963596d652af26fe1f886a280Wonsik Kim private final BroadcastReceiver mVolumeReceiver = new BroadcastReceiver() { 10049e559353278a56963596d652af26fe1f886a280Wonsik Kim @Override 10149e559353278a56963596d652af26fe1f886a280Wonsik Kim public void onReceive(Context context, Intent intent) { 10249e559353278a56963596d652af26fe1f886a280Wonsik Kim handleVolumeChange(context, intent); 10349e559353278a56963596d652af26fe1f886a280Wonsik Kim } 10449e559353278a56963596d652af26fe1f886a280Wonsik Kim }; 10549e559353278a56963596d652af26fe1f886a280Wonsik Kim private int mCurrentIndex = 0; 10649e559353278a56963596d652af26fe1f886a280Wonsik Kim private int mCurrentMaxIndex = 0; 10749e559353278a56963596d652af26fe1f886a280Wonsik Kim private final boolean mUseMasterVolume; 108d38bf476f6a31602e92a3207a4ceb29bf965f9aaJinsuk Kim 109d922a546b94119217fb790113d0001cad0432060Wonsik Kim // TODO: Should handle STANDBY case. 1104f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee private final SparseBooleanArray mHdmiStateMap = new SparseBooleanArray(); 111d922a546b94119217fb790113d0001cad0432060Wonsik Kim private final List<Message> mPendingHdmiDeviceEvents = new LinkedList<>(); 112969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 113187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim // Calls to mListener should happen here. 114187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim private final Handler mHandler = new ListenerHandler(); 115c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 116c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private final Object mLock = new Object(); 117c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 118187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim public TvInputHardwareManager(Context context, Listener listener) { 11949e559353278a56963596d652af26fe1f886a280Wonsik Kim mContext = context; 120187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim mListener = listener; 121d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); 12249e559353278a56963596d652af26fe1f886a280Wonsik Kim mUseMasterVolume = mContext.getResources().getBoolean( 12349e559353278a56963596d652af26fe1f886a280Wonsik Kim com.android.internal.R.bool.config_useMasterVolume); 124c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mHal.init(); 125969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 126969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 127969167dc05a6485a32d160895871cff46fd81884Wonsik Kim public void onBootPhase(int phase) { 128969167dc05a6485a32d160895871cff46fd81884Wonsik Kim if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { 1294f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mHdmiControlService = IHdmiControlService.Stub.asInterface(ServiceManager.getService( 1304f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee Context.HDMI_CONTROL_SERVICE)); 1314f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee if (mHdmiControlService != null) { 1327474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim try { 1334f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mHdmiControlService.addHotplugEventListener(mHdmiHotplugEventListener); 1344f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mHdmiControlService.addDeviceEventListener(mHdmiDeviceEventListener); 1351f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang mHdmiControlService.addSystemAudioModeChangeListener( 1361f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang mHdmiSystemAudioModeChangeListener); 137546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo mHdmiDeviceList.addAll(mHdmiControlService.getInputDevices()); 1387474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim } catch (RemoteException e) { 1394f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee Slog.w(TAG, "Error registering listeners to HdmiControlService:", e); 1407474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim } 14108f1ab02d6de42756825a2dfa7027137ff959bd8Jinsuk Kim } else { 14208f1ab02d6de42756825a2dfa7027137ff959bd8Jinsuk Kim Slog.w(TAG, "HdmiControlService is not available"); 1437474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim } 14449e559353278a56963596d652af26fe1f886a280Wonsik Kim if (!mUseMasterVolume) { 14549e559353278a56963596d652af26fe1f886a280Wonsik Kim final IntentFilter filter = new IntentFilter(); 14649e559353278a56963596d652af26fe1f886a280Wonsik Kim filter.addAction(AudioManager.VOLUME_CHANGED_ACTION); 14749e559353278a56963596d652af26fe1f886a280Wonsik Kim filter.addAction(AudioManager.STREAM_MUTE_CHANGED_ACTION); 14849e559353278a56963596d652af26fe1f886a280Wonsik Kim mContext.registerReceiver(mVolumeReceiver, filter); 14949e559353278a56963596d652af26fe1f886a280Wonsik Kim } 15049e559353278a56963596d652af26fe1f886a280Wonsik Kim updateVolume(); 151969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 152c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 153c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 154c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim @Override 1554f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee public void onDeviceAvailable(TvInputHardwareInfo info, TvStreamConfig[] configs) { 156c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mLock) { 157c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Connection connection = new Connection(info); 158c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim connection.updateConfigsLocked(configs); 159c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mConnections.put(info.getDeviceId(), connection); 160d922a546b94119217fb790113d0001cad0432060Wonsik Kim buildHardwareListLocked(); 161187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim mHandler.obtainMessage( 162187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim ListenerHandler.HARDWARE_DEVICE_ADDED, 0, 0, info).sendToTarget(); 163d922a546b94119217fb790113d0001cad0432060Wonsik Kim if (info.getType() == TvInputHardwareInfo.TV_INPUT_TYPE_HDMI) { 164d922a546b94119217fb790113d0001cad0432060Wonsik Kim processPendingHdmiDeviceEventsLocked(); 165d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 166c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 167c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 168c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 169d922a546b94119217fb790113d0001cad0432060Wonsik Kim private void buildHardwareListLocked() { 170d922a546b94119217fb790113d0001cad0432060Wonsik Kim mHardwareList.clear(); 171c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim for (int i = 0; i < mConnections.size(); ++i) { 172d922a546b94119217fb790113d0001cad0432060Wonsik Kim mHardwareList.add(mConnections.valueAt(i).getHardwareInfoLocked()); 173c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 174c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 175c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 176c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim @Override 177c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public void onDeviceUnavailable(int deviceId) { 178c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mLock) { 179c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Connection connection = mConnections.get(deviceId); 180c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (connection == null) { 181c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Slog.e(TAG, "onDeviceUnavailable: Cannot find a connection with " + deviceId); 182c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return; 183c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 184969167dc05a6485a32d160895871cff46fd81884Wonsik Kim connection.resetLocked(null, null, null, null, null); 185c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mConnections.remove(deviceId); 186d922a546b94119217fb790113d0001cad0432060Wonsik Kim buildHardwareListLocked(); 1874f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee TvInputHardwareInfo info = connection.getHardwareInfoLocked(); 188d922a546b94119217fb790113d0001cad0432060Wonsik Kim if (info.getType() == TvInputHardwareInfo.TV_INPUT_TYPE_HDMI) { 189546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo // Remove HDMI devices linked with this hardware. 190546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo for (Iterator<HdmiDeviceInfo> it = mHdmiDeviceList.iterator(); it.hasNext();) { 19161f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo deviceInfo = it.next(); 192d922a546b94119217fb790113d0001cad0432060Wonsik Kim if (deviceInfo.getPortId() == info.getHdmiPortId()) { 193546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo mHandler.obtainMessage(ListenerHandler.HDMI_DEVICE_REMOVED, 0, 0, 194d922a546b94119217fb790113d0001cad0432060Wonsik Kim deviceInfo).sendToTarget(); 195d922a546b94119217fb790113d0001cad0432060Wonsik Kim it.remove(); 196d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 197d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 198d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 199187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim mHandler.obtainMessage( 2004f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee ListenerHandler.HARDWARE_DEVICE_REMOVED, 0, 0, info).sendToTarget(); 201c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 202c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 203c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 204c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim @Override 205c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public void onStreamConfigurationChanged(int deviceId, TvStreamConfig[] configs) { 206c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mLock) { 207c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Connection connection = mConnections.get(deviceId); 208c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (connection == null) { 209c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Slog.e(TAG, "StreamConfigurationChanged: Cannot find a connection with " 210c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim + deviceId); 211c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return; 212c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 213c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim connection.updateConfigsLocked(configs); 2149a1036575182705bc27c6bf255dd17669821181dWonsik Kim String inputId = mHardwareInputIdMap.get(deviceId); 2159a1036575182705bc27c6bf255dd17669821181dWonsik Kim if (inputId != null) { 2169a1036575182705bc27c6bf255dd17669821181dWonsik Kim mHandler.obtainMessage(ListenerHandler.STATE_CHANGED, 2175b820a8aa1a200824e44aede6bc1e381a6d69dd5Wonsik Kim convertConnectedToState(configs.length > 0), 0, inputId).sendToTarget(); 2189a1036575182705bc27c6bf255dd17669821181dWonsik Kim } 219017bb8523dd7c3dbfd00c055fde241de4dca9da2Dongwon Kang ITvInputHardwareCallback callback = connection.getCallbackLocked(); 220017bb8523dd7c3dbfd00c055fde241de4dca9da2Dongwon Kang if (callback != null) { 221017bb8523dd7c3dbfd00c055fde241de4dca9da2Dongwon Kang try { 222017bb8523dd7c3dbfd00c055fde241de4dca9da2Dongwon Kang callback.onStreamConfigChanged(configs); 223017bb8523dd7c3dbfd00c055fde241de4dca9da2Dongwon Kang } catch (RemoteException e) { 224017bb8523dd7c3dbfd00c055fde241de4dca9da2Dongwon Kang Slog.e(TAG, "error in onStreamConfigurationChanged", e); 225017bb8523dd7c3dbfd00c055fde241de4dca9da2Dongwon Kang } 226c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 227c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 228c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 229c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 230c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo @Override 231c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo public void onFirstFrameCaptured(int deviceId, int streamId) { 232c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo synchronized (mLock) { 233c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Connection connection = mConnections.get(deviceId); 234c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (connection == null) { 235c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Slog.e(TAG, "FirstFrameCaptured: Cannot find a connection with " 236c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo + deviceId); 237c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return; 238c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 239c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Runnable runnable = connection.getOnFirstFrameCapturedLocked(); 240c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (runnable != null) { 241c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo runnable.run(); 242c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo connection.setOnFirstFrameCapturedLocked(null); 243c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 244c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 245c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 246c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 247c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public List<TvInputHardwareInfo> getHardwareList() { 248c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mLock) { 249d922a546b94119217fb790113d0001cad0432060Wonsik Kim return Collections.unmodifiableList(mHardwareList); 250c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 251c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 252c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 253546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo public List<HdmiDeviceInfo> getHdmiDeviceList() { 254d922a546b94119217fb790113d0001cad0432060Wonsik Kim synchronized (mLock) { 255546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo return Collections.unmodifiableList(mHdmiDeviceList); 2564f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 2574f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 2584f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee 259e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim private boolean checkUidChangedLocked( 260e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim Connection connection, int callingUid, int resolvedUserId) { 261e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim Integer connectionCallingUid = connection.getCallingUidLocked(); 262e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim Integer connectionResolvedUserId = connection.getResolvedUserIdLocked(); 263e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim if (connectionCallingUid == null || connectionResolvedUserId == null) { 264e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim return true; 265e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim } 266e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim if (connectionCallingUid != callingUid || connectionResolvedUserId != resolvedUserId) { 267e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim return true; 268e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim } 269e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim return false; 270e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim } 271e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim 272969167dc05a6485a32d160895871cff46fd81884Wonsik Kim private int convertConnectedToState(boolean connected) { 273969167dc05a6485a32d160895871cff46fd81884Wonsik Kim if (connected) { 274969167dc05a6485a32d160895871cff46fd81884Wonsik Kim return INPUT_STATE_CONNECTED; 275969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } else { 276969167dc05a6485a32d160895871cff46fd81884Wonsik Kim return INPUT_STATE_DISCONNECTED; 277969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 278969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 279969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 2804f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee public void addHardwareTvInput(int deviceId, TvInputInfo info) { 281969167dc05a6485a32d160895871cff46fd81884Wonsik Kim synchronized (mLock) { 2824f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee String oldInputId = mHardwareInputIdMap.get(deviceId); 2834f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee if (oldInputId != null) { 284969167dc05a6485a32d160895871cff46fd81884Wonsik Kim Slog.w(TAG, "Trying to override previous registration: old = " 2854f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee + mInputMap.get(oldInputId) + ":" + deviceId + ", new = " 286969167dc05a6485a32d160895871cff46fd81884Wonsik Kim + info + ":" + deviceId); 287969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 2884f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mHardwareInputIdMap.put(deviceId, info.getId()); 2894f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mInputMap.put(info.getId(), info); 290969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 2919a1036575182705bc27c6bf255dd17669821181dWonsik Kim // Process pending state changes 2929a1036575182705bc27c6bf255dd17669821181dWonsik Kim 2939a1036575182705bc27c6bf255dd17669821181dWonsik Kim // For logical HDMI devices, they have information from HDMI CEC signals. 294969167dc05a6485a32d160895871cff46fd81884Wonsik Kim for (int i = 0; i < mHdmiStateMap.size(); ++i) { 295d922a546b94119217fb790113d0001cad0432060Wonsik Kim TvInputHardwareInfo hardwareInfo = 296d922a546b94119217fb790113d0001cad0432060Wonsik Kim findHardwareInfoForHdmiPortLocked(mHdmiStateMap.keyAt(i)); 297d922a546b94119217fb790113d0001cad0432060Wonsik Kim if (hardwareInfo == null) { 298d922a546b94119217fb790113d0001cad0432060Wonsik Kim continue; 299d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 300d922a546b94119217fb790113d0001cad0432060Wonsik Kim String inputId = mHardwareInputIdMap.get(hardwareInfo.getDeviceId()); 301969167dc05a6485a32d160895871cff46fd81884Wonsik Kim if (inputId != null && inputId.equals(info.getId())) { 302187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim mHandler.obtainMessage(ListenerHandler.STATE_CHANGED, 303969167dc05a6485a32d160895871cff46fd81884Wonsik Kim convertConnectedToState(mHdmiStateMap.valueAt(i)), 0, 304969167dc05a6485a32d160895871cff46fd81884Wonsik Kim inputId).sendToTarget(); 3059a1036575182705bc27c6bf255dd17669821181dWonsik Kim return; 306969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 307969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 3089a1036575182705bc27c6bf255dd17669821181dWonsik Kim // For the rest of the devices, we can tell by the number of available streams. 3099a1036575182705bc27c6bf255dd17669821181dWonsik Kim Connection connection = mConnections.get(deviceId); 3109a1036575182705bc27c6bf255dd17669821181dWonsik Kim if (connection != null) { 3119a1036575182705bc27c6bf255dd17669821181dWonsik Kim mHandler.obtainMessage(ListenerHandler.STATE_CHANGED, 3129a1036575182705bc27c6bf255dd17669821181dWonsik Kim convertConnectedToState(connection.getConfigsLocked().length > 0), 0, 3139a1036575182705bc27c6bf255dd17669821181dWonsik Kim info.getId()).sendToTarget(); 3149a1036575182705bc27c6bf255dd17669821181dWonsik Kim return; 3159a1036575182705bc27c6bf255dd17669821181dWonsik Kim } 316969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 317969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 318969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 31938feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim private static <T> int indexOfEqualValue(SparseArray<T> map, T value) { 32038feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim for (int i = 0; i < map.size(); ++i) { 32138feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim if (map.valueAt(i).equals(value)) { 32238feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim return i; 32338feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim } 32438feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim } 32538feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim return -1; 32638feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim } 32738feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim 32871dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim private static boolean intArrayContains(int[] array, int value) { 32971dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim for (int element : array) { 33071dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim if (element == value) return true; 33171dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim } 33271dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim return false; 33371dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim } 33471dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim 3358960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim public void addHdmiTvInput(int id, TvInputInfo info) { 3364f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee if (info.getType() != TvInputInfo.TYPE_HDMI) { 3374f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee throw new IllegalArgumentException("info (" + info + ") has non-HDMI type."); 3384f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 3394f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee synchronized (mLock) { 3404f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee String parentId = info.getParentId(); 34138feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim int parentIndex = indexOfEqualValue(mHardwareInputIdMap, parentId); 34238feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim if (parentIndex < 0) { 3434f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee throw new IllegalArgumentException("info (" + info + ") has invalid parentId."); 3444f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 3458960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim String oldInputId = mHdmiInputIdMap.get(id); 3464f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee if (oldInputId != null) { 3474f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee Slog.w(TAG, "Trying to override previous registration: old = " 3488960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim + mInputMap.get(oldInputId) + ":" + id + ", new = " 3498960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim + info + ":" + id); 3504f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 3518960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim mHdmiInputIdMap.put(id, info.getId()); 3524f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mInputMap.put(info.getId(), info); 3534f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 3544f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 3554f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee 3564f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee public void removeTvInput(String inputId) { 3574f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee synchronized (mLock) { 3584f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mInputMap.remove(inputId); 35938feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim int hardwareIndex = indexOfEqualValue(mHardwareInputIdMap, inputId); 3604f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee if (hardwareIndex >= 0) { 3614f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mHardwareInputIdMap.removeAt(hardwareIndex); 3624f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 363546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo int deviceIndex = indexOfEqualValue(mHdmiInputIdMap, inputId); 364546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo if (deviceIndex >= 0) { 365546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo mHdmiInputIdMap.removeAt(deviceIndex); 3664f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 3674f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 3684f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 3694f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee 370c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim /** 371c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * Create a TvInputHardware object with a specific deviceId. One service at a time can access 372c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * the object, and if more than one process attempts to create hardware with the same deviceId, 373c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * the latest service will get the object and all the other hardware are released. The 374c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * release is notified via ITvInputHardwareCallback.onReleased(). 375c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim */ 376c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public ITvInputHardware acquireHardware(int deviceId, ITvInputHardwareCallback callback, 377969167dc05a6485a32d160895871cff46fd81884Wonsik Kim TvInputInfo info, int callingUid, int resolvedUserId) { 378c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (callback == null) { 379c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim throw new NullPointerException(); 380c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 381c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mLock) { 382c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Connection connection = mConnections.get(deviceId); 383c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (connection == null) { 384c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Slog.e(TAG, "Invalid deviceId : " + deviceId); 385c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return null; 386c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 387e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim if (checkUidChangedLocked(connection, callingUid, resolvedUserId)) { 388969167dc05a6485a32d160895871cff46fd81884Wonsik Kim TvInputHardwareImpl hardware = 389969167dc05a6485a32d160895871cff46fd81884Wonsik Kim new TvInputHardwareImpl(connection.getHardwareInfoLocked()); 390c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim try { 391c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim callback.asBinder().linkToDeath(connection, 0); 392c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } catch (RemoteException e) { 393c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim hardware.release(); 394c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return null; 395c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 396969167dc05a6485a32d160895871cff46fd81884Wonsik Kim connection.resetLocked(hardware, callback, info, callingUid, resolvedUserId); 397c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 398c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return connection.getHardwareLocked(); 399c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 400c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 401c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 402c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim /** 403c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * Release the specified hardware. 404c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim */ 405c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public void releaseHardware(int deviceId, ITvInputHardware hardware, int callingUid, 406c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim int resolvedUserId) { 407c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mLock) { 408c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Connection connection = mConnections.get(deviceId); 409c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (connection == null) { 410c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Slog.e(TAG, "Invalid deviceId : " + deviceId); 411c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return; 412c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 413c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (connection.getHardwareLocked() != hardware 414e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim || checkUidChangedLocked(connection, callingUid, resolvedUserId)) { 415c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return; 416c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 417969167dc05a6485a32d160895871cff46fd81884Wonsik Kim connection.resetLocked(null, null, null, null, null); 418969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 419969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 420969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 421d922a546b94119217fb790113d0001cad0432060Wonsik Kim private TvInputHardwareInfo findHardwareInfoForHdmiPortLocked(int port) { 422d922a546b94119217fb790113d0001cad0432060Wonsik Kim for (TvInputHardwareInfo hardwareInfo : mHardwareList) { 423969167dc05a6485a32d160895871cff46fd81884Wonsik Kim if (hardwareInfo.getType() == TvInputHardwareInfo.TV_INPUT_TYPE_HDMI 424969167dc05a6485a32d160895871cff46fd81884Wonsik Kim && hardwareInfo.getHdmiPortId() == port) { 425d922a546b94119217fb790113d0001cad0432060Wonsik Kim return hardwareInfo; 426969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 427969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 428969167dc05a6485a32d160895871cff46fd81884Wonsik Kim return null; 429969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 430969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 431c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo private int findDeviceIdForInputIdLocked(String inputId) { 432c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo for (int i = 0; i < mConnections.size(); ++i) { 433c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Connection connection = mConnections.get(i); 434c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (connection.getInfoLocked().getId().equals(inputId)) { 435c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return i; 436c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 437c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 438c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return -1; 439c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 440c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 441c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo /** 442c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo * Get the list of TvStreamConfig which is buffered mode. 443c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo */ 444c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo public List<TvStreamConfig> getAvailableTvStreamConfigList(String inputId, int callingUid, 445c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo int resolvedUserId) { 446c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo List<TvStreamConfig> configsList = new ArrayList<TvStreamConfig>(); 447c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo synchronized (mLock) { 448c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo int deviceId = findDeviceIdForInputIdLocked(inputId); 449c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (deviceId < 0) { 450c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Slog.e(TAG, "Invalid inputId : " + inputId); 451c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return configsList; 452c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 453c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Connection connection = mConnections.get(deviceId); 454c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo for (TvStreamConfig config : connection.getConfigsLocked()) { 455c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (config.getType() == TvStreamConfig.STREAM_TYPE_BUFFER_PRODUCER) { 456c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo configsList.add(config); 457c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 458c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 459c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 460c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return configsList; 461c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 462c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 463c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo /** 464c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo * Take a snapshot of the given TV input into the provided Surface. 465c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo */ 466c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo public boolean captureFrame(String inputId, Surface surface, final TvStreamConfig config, 467c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo int callingUid, int resolvedUserId) { 468c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo synchronized (mLock) { 469c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo int deviceId = findDeviceIdForInputIdLocked(inputId); 470c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (deviceId < 0) { 471c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Slog.e(TAG, "Invalid inputId : " + inputId); 472c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return false; 473c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 474c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Connection connection = mConnections.get(deviceId); 475c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo final TvInputHardwareImpl hardwareImpl = connection.getHardwareImplLocked(); 476c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (hardwareImpl != null) { 477c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo // Stop previous capture. 478c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Runnable runnable = connection.getOnFirstFrameCapturedLocked(); 479c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (runnable != null) { 480c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo runnable.run(); 481c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo connection.setOnFirstFrameCapturedLocked(null); 482c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 483c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 484c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo boolean result = hardwareImpl.startCapture(surface, config); 485c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (result) { 486c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo connection.setOnFirstFrameCapturedLocked(new Runnable() { 487c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo @Override 488c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo public void run() { 489c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo hardwareImpl.stopCapture(config); 490c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 491c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo }); 492c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 493c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return result; 494c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 495c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 496c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return false; 497c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 498c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 499d922a546b94119217fb790113d0001cad0432060Wonsik Kim private void processPendingHdmiDeviceEventsLocked() { 500d922a546b94119217fb790113d0001cad0432060Wonsik Kim for (Iterator<Message> it = mPendingHdmiDeviceEvents.iterator(); it.hasNext(); ) { 501d922a546b94119217fb790113d0001cad0432060Wonsik Kim Message msg = it.next(); 50261f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo deviceInfo = (HdmiDeviceInfo) msg.obj; 503d922a546b94119217fb790113d0001cad0432060Wonsik Kim TvInputHardwareInfo hardwareInfo = 504d922a546b94119217fb790113d0001cad0432060Wonsik Kim findHardwareInfoForHdmiPortLocked(deviceInfo.getPortId()); 505d922a546b94119217fb790113d0001cad0432060Wonsik Kim if (hardwareInfo != null) { 506d922a546b94119217fb790113d0001cad0432060Wonsik Kim msg.sendToTarget(); 507d922a546b94119217fb790113d0001cad0432060Wonsik Kim it.remove(); 508d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 509d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 510d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 511d922a546b94119217fb790113d0001cad0432060Wonsik Kim 51249e559353278a56963596d652af26fe1f886a280Wonsik Kim private void updateVolume() { 51349e559353278a56963596d652af26fe1f886a280Wonsik Kim mCurrentMaxIndex = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); 51449e559353278a56963596d652af26fe1f886a280Wonsik Kim mCurrentIndex = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC); 51549e559353278a56963596d652af26fe1f886a280Wonsik Kim } 51649e559353278a56963596d652af26fe1f886a280Wonsik Kim 51749e559353278a56963596d652af26fe1f886a280Wonsik Kim private void handleVolumeChange(Context context, Intent intent) { 51849e559353278a56963596d652af26fe1f886a280Wonsik Kim String action = intent.getAction(); 51949e559353278a56963596d652af26fe1f886a280Wonsik Kim if (action.equals(AudioManager.VOLUME_CHANGED_ACTION)) { 52049e559353278a56963596d652af26fe1f886a280Wonsik Kim int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1); 52149e559353278a56963596d652af26fe1f886a280Wonsik Kim if (streamType != AudioManager.STREAM_MUSIC) { 52249e559353278a56963596d652af26fe1f886a280Wonsik Kim return; 52349e559353278a56963596d652af26fe1f886a280Wonsik Kim } 52449e559353278a56963596d652af26fe1f886a280Wonsik Kim int index = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, 0); 52549e559353278a56963596d652af26fe1f886a280Wonsik Kim if (index == mCurrentIndex) { 52649e559353278a56963596d652af26fe1f886a280Wonsik Kim return; 52749e559353278a56963596d652af26fe1f886a280Wonsik Kim } 52849e559353278a56963596d652af26fe1f886a280Wonsik Kim mCurrentIndex = index; 52949e559353278a56963596d652af26fe1f886a280Wonsik Kim } else if (action.equals(AudioManager.STREAM_MUTE_CHANGED_ACTION)) { 53049e559353278a56963596d652af26fe1f886a280Wonsik Kim int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1); 53149e559353278a56963596d652af26fe1f886a280Wonsik Kim if (streamType != AudioManager.STREAM_MUSIC) { 53249e559353278a56963596d652af26fe1f886a280Wonsik Kim return; 53349e559353278a56963596d652af26fe1f886a280Wonsik Kim } 53449e559353278a56963596d652af26fe1f886a280Wonsik Kim // volume index will be updated at onMediaStreamVolumeChanged() through updateVolume(). 53549e559353278a56963596d652af26fe1f886a280Wonsik Kim } else { 53649e559353278a56963596d652af26fe1f886a280Wonsik Kim Slog.w(TAG, "Unrecognized intent: " + intent); 53749e559353278a56963596d652af26fe1f886a280Wonsik Kim return; 53849e559353278a56963596d652af26fe1f886a280Wonsik Kim } 53949e559353278a56963596d652af26fe1f886a280Wonsik Kim synchronized (mLock) { 54049e559353278a56963596d652af26fe1f886a280Wonsik Kim for (int i = 0; i < mConnections.size(); ++i) { 54149e559353278a56963596d652af26fe1f886a280Wonsik Kim TvInputHardwareImpl hardwareImpl = mConnections.valueAt(i).getHardwareImplLocked(); 54249e559353278a56963596d652af26fe1f886a280Wonsik Kim if (hardwareImpl != null) { 54349e559353278a56963596d652af26fe1f886a280Wonsik Kim hardwareImpl.onMediaStreamVolumeChanged(); 54449e559353278a56963596d652af26fe1f886a280Wonsik Kim } 54549e559353278a56963596d652af26fe1f886a280Wonsik Kim } 54649e559353278a56963596d652af26fe1f886a280Wonsik Kim } 54749e559353278a56963596d652af26fe1f886a280Wonsik Kim } 54849e559353278a56963596d652af26fe1f886a280Wonsik Kim 54949e559353278a56963596d652af26fe1f886a280Wonsik Kim private float getMediaStreamVolume() { 55049e559353278a56963596d652af26fe1f886a280Wonsik Kim return mUseMasterVolume ? 1.0f : ((float) mCurrentIndex / (float) mCurrentMaxIndex); 55149e559353278a56963596d652af26fe1f886a280Wonsik Kim } 55249e559353278a56963596d652af26fe1f886a280Wonsik Kim 553c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private class Connection implements IBinder.DeathRecipient { 554969167dc05a6485a32d160895871cff46fd81884Wonsik Kim private final TvInputHardwareInfo mHardwareInfo; 555969167dc05a6485a32d160895871cff46fd81884Wonsik Kim private TvInputInfo mInfo; 556c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private TvInputHardwareImpl mHardware = null; 557c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private ITvInputHardwareCallback mCallback; 558c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private TvStreamConfig[] mConfigs = null; 559c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private Integer mCallingUid = null; 560c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private Integer mResolvedUserId = null; 561c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo private Runnable mOnFirstFrameCaptured; 562c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 563969167dc05a6485a32d160895871cff46fd81884Wonsik Kim public Connection(TvInputHardwareInfo hardwareInfo) { 564969167dc05a6485a32d160895871cff46fd81884Wonsik Kim mHardwareInfo = hardwareInfo; 565c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 566c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 567c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim // *Locked methods assume TvInputHardwareManager.mLock is held. 568c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 569969167dc05a6485a32d160895871cff46fd81884Wonsik Kim public void resetLocked(TvInputHardwareImpl hardware, ITvInputHardwareCallback callback, 570969167dc05a6485a32d160895871cff46fd81884Wonsik Kim TvInputInfo info, Integer callingUid, Integer resolvedUserId) { 571c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (mHardware != null) { 572c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim try { 573c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mCallback.onReleased(); 574c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } catch (RemoteException e) { 5754f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee Slog.e(TAG, "error in Connection::resetLocked", e); 576c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 577c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mHardware.release(); 578c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 579c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mHardware = hardware; 580c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mCallback = callback; 581969167dc05a6485a32d160895871cff46fd81884Wonsik Kim mInfo = info; 582c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mCallingUid = callingUid; 583c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mResolvedUserId = resolvedUserId; 584c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo mOnFirstFrameCaptured = null; 585c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 586c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (mHardware != null && mCallback != null) { 587c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim try { 588c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mCallback.onStreamConfigChanged(getConfigsLocked()); 589c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } catch (RemoteException e) { 5904f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee Slog.e(TAG, "error in Connection::resetLocked", e); 591c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 592c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 593c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 594c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 595c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public void updateConfigsLocked(TvStreamConfig[] configs) { 596c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mConfigs = configs; 597c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 598c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 599969167dc05a6485a32d160895871cff46fd81884Wonsik Kim public TvInputHardwareInfo getHardwareInfoLocked() { 600969167dc05a6485a32d160895871cff46fd81884Wonsik Kim return mHardwareInfo; 601969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 602969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 603969167dc05a6485a32d160895871cff46fd81884Wonsik Kim public TvInputInfo getInfoLocked() { 604c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return mInfo; 605c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 606c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 607c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public ITvInputHardware getHardwareLocked() { 608c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return mHardware; 609c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 610c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 611c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo public TvInputHardwareImpl getHardwareImplLocked() { 612c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return mHardware; 613c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 614c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 615c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public ITvInputHardwareCallback getCallbackLocked() { 616c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return mCallback; 617c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 618c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 619c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public TvStreamConfig[] getConfigsLocked() { 620c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return mConfigs; 621c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 622c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 623e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim public Integer getCallingUidLocked() { 624c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return mCallingUid; 625c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 626c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 627e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim public Integer getResolvedUserIdLocked() { 628c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return mResolvedUserId; 629c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 630c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 631c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo public void setOnFirstFrameCapturedLocked(Runnable runnable) { 632c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo mOnFirstFrameCaptured = runnable; 633c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 634c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 635c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo public Runnable getOnFirstFrameCapturedLocked() { 636c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return mOnFirstFrameCaptured; 637c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 638c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 639c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim @Override 640c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public void binderDied() { 641c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mLock) { 642969167dc05a6485a32d160895871cff46fd81884Wonsik Kim resetLocked(null, null, null, null, null); 643c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 644c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 645c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 646c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 647c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private class TvInputHardwareImpl extends ITvInputHardware.Stub { 648c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private final TvInputHardwareInfo mInfo; 649c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private boolean mReleased = false; 650c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private final Object mImplLock = new Object(); 651c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 65206c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim private final AudioManager.OnAudioPortUpdateListener mAudioListener = 65306c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim new AudioManager.OnAudioPortUpdateListener() { 65406c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim @Override 65506c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim public void onAudioPortListUpdate(AudioPort[] portList) { 65606c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim synchronized (mImplLock) { 6577587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim updateAudioConfigLocked(); 65806c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 65906c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 66006c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim 66106c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim @Override 66206c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim public void onAudioPatchListUpdate(AudioPatch[] patchList) { 66306c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim // No-op 66406c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 66506c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim 66606c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim @Override 66706c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim public void onServiceDied() { 66806c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim synchronized (mImplLock) { 66906c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim mAudioSource = null; 670b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim mAudioSink.clear(); 67106c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim mAudioPatch = null; 67206c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 67306c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 67406c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim }; 67506c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim private int mOverrideAudioType = AudioManager.DEVICE_NONE; 67606c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim private String mOverrideAudioAddress = ""; 67706c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim private AudioDevicePort mAudioSource; 678b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim private List<AudioDevicePort> mAudioSink = new ArrayList<>(); 679d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim private AudioPatch mAudioPatch = null; 680485e7e13f410072c7c79368338ec3eba92c39169Wonsik Kim // Set to an invalid value for a volume, so that current volume can be applied at the 681485e7e13f410072c7c79368338ec3eba92c39169Wonsik Kim // first call to updateAudioConfigLocked(). 682485e7e13f410072c7c79368338ec3eba92c39169Wonsik Kim private float mCommittedVolume = -1f; 68349e559353278a56963596d652af26fe1f886a280Wonsik Kim private float mSourceVolume = 0.0f; 684d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim 685839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim private TvStreamConfig mActiveConfig = null; 686839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim 687ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim private int mDesiredSamplingRate = 0; 688ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim private int mDesiredChannelMask = AudioFormat.CHANNEL_OUT_DEFAULT; 689ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim private int mDesiredFormat = AudioFormat.ENCODING_DEFAULT; 690ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim 691c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public TvInputHardwareImpl(TvInputHardwareInfo info) { 692c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mInfo = info; 69306c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim mAudioManager.registerAudioPortUpdateListener(mAudioListener); 694d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim if (mInfo.getAudioType() != AudioManager.DEVICE_NONE) { 69506c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim mAudioSource = findAudioDevicePort(mInfo.getAudioType(), mInfo.getAudioAddress()); 696b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim findAudioSinkFromAudioPolicy(mAudioSink); 697ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 698ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 699ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim 700b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim private void findAudioSinkFromAudioPolicy(List<AudioDevicePort> sinks) { 701b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim sinks.clear(); 702ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim ArrayList<AudioPort> devicePorts = new ArrayList<AudioPort>(); 703b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim if (mAudioManager.listAudioDevicePorts(devicePorts) != AudioManager.SUCCESS) { 704b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim return; 705b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim } 706b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim int sinkDevice = mAudioManager.getDevicesForStream(AudioManager.STREAM_MUSIC); 707b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim for (AudioPort port : devicePorts) { 708b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim AudioDevicePort devicePort = (AudioDevicePort) port; 709b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim if ((devicePort.type() & sinkDevice) != 0) { 710b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim sinks.add(devicePort); 711d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim } 712d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim } 713ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 714ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim 715ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim private AudioDevicePort findAudioDevicePort(int type, String address) { 716ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim if (type == AudioManager.DEVICE_NONE) { 717ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim return null; 718ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 719ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim ArrayList<AudioPort> devicePorts = new ArrayList<AudioPort>(); 720ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim if (mAudioManager.listAudioDevicePorts(devicePorts) != AudioManager.SUCCESS) { 721ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim return null; 722ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 723ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim for (AudioPort port : devicePorts) { 724ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim AudioDevicePort devicePort = (AudioDevicePort) port; 725ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim if (devicePort.type() == type && devicePort.address().equals(address)) { 726ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim return devicePort; 727ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 728ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 729ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim return null; 730c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 731c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 732c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public void release() { 733c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mImplLock) { 73406c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim mAudioManager.unregisterAudioPortUpdateListener(mAudioListener); 735d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim if (mAudioPatch != null) { 736d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim mAudioManager.releaseAudioPatch(mAudioPatch); 737d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim mAudioPatch = null; 738d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim } 739c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mReleased = true; 740c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 741c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 742c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 743839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim // A TvInputHardwareImpl object holds only one active session. Therefore, if a client 744839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim // attempts to call setSurface with different TvStreamConfig objects, the last call will 745839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim // prevail. 746c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim @Override 747c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public boolean setSurface(Surface surface, TvStreamConfig config) 748c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim throws RemoteException { 749c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mImplLock) { 750c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (mReleased) { 751c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim throw new IllegalStateException("Device already released."); 752c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 7537587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim 754102670f16a44d4b25d7e3a252bedee0208b68c55Wonsik Kim int result = TvInputHal.SUCCESS; 755839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim if (surface == null) { 756b683e6e4c70da3644427cb5ec6a8342b3a91bb23Wonsik Kim // The value of config is ignored when surface == null. 757b683e6e4c70da3644427cb5ec6a8342b3a91bb23Wonsik Kim if (mActiveConfig != null) { 758b683e6e4c70da3644427cb5ec6a8342b3a91bb23Wonsik Kim result = mHal.removeStream(mInfo.getDeviceId(), mActiveConfig); 759b683e6e4c70da3644427cb5ec6a8342b3a91bb23Wonsik Kim mActiveConfig = null; 760b683e6e4c70da3644427cb5ec6a8342b3a91bb23Wonsik Kim } else { 761b683e6e4c70da3644427cb5ec6a8342b3a91bb23Wonsik Kim // We already have no active stream. 762b683e6e4c70da3644427cb5ec6a8342b3a91bb23Wonsik Kim return true; 763b683e6e4c70da3644427cb5ec6a8342b3a91bb23Wonsik Kim } 764839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim } else { 765b683e6e4c70da3644427cb5ec6a8342b3a91bb23Wonsik Kim // It's impossible to set a non-null surface with a null config. 766b683e6e4c70da3644427cb5ec6a8342b3a91bb23Wonsik Kim if (config == null) { 767b683e6e4c70da3644427cb5ec6a8342b3a91bb23Wonsik Kim return false; 768b683e6e4c70da3644427cb5ec6a8342b3a91bb23Wonsik Kim } 769b683e6e4c70da3644427cb5ec6a8342b3a91bb23Wonsik Kim // Remove stream only if we have an existing active configuration. 770b683e6e4c70da3644427cb5ec6a8342b3a91bb23Wonsik Kim if (mActiveConfig != null && !config.equals(mActiveConfig)) { 771839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim result = mHal.removeStream(mInfo.getDeviceId(), mActiveConfig); 772839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim if (result != TvInputHal.SUCCESS) { 773839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim mActiveConfig = null; 774839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim } 775839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim } 776b683e6e4c70da3644427cb5ec6a8342b3a91bb23Wonsik Kim // Proceed only if all previous operations succeeded. 777839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim if (result == TvInputHal.SUCCESS) { 778b683e6e4c70da3644427cb5ec6a8342b3a91bb23Wonsik Kim result = mHal.addOrUpdateStream(mInfo.getDeviceId(), surface, config); 779b683e6e4c70da3644427cb5ec6a8342b3a91bb23Wonsik Kim if (result == TvInputHal.SUCCESS) { 780b683e6e4c70da3644427cb5ec6a8342b3a91bb23Wonsik Kim mActiveConfig = config; 781b683e6e4c70da3644427cb5ec6a8342b3a91bb23Wonsik Kim } 782839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim } 783839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim } 7847587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim updateAudioConfigLocked(); 785839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim return result == TvInputHal.SUCCESS; 786c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 787c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 788c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 7897587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim /** 7907587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim * Update audio configuration (source, sink, patch) all up to current state. 7917587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim */ 7927587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim private void updateAudioConfigLocked() { 7937587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim boolean sinkUpdated = updateAudioSinkLocked(); 7947587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim boolean sourceUpdated = updateAudioSourceLocked(); 7957587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim // We can't do updated = updateAudioSinkLocked() || updateAudioSourceLocked() here 7967587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim // because Java won't evaluate the latter if the former is true. 7977587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim 798b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim if (mAudioSource == null || mAudioSink.isEmpty() || mActiveConfig == null) { 79906c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim if (mAudioPatch != null) { 8007587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim mAudioManager.releaseAudioPatch(mAudioPatch); 8017587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim mAudioPatch = null; 80206c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 80306c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim return; 80406c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 80506c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim 80649e559353278a56963596d652af26fe1f886a280Wonsik Kim updateVolume(); 80749e559353278a56963596d652af26fe1f886a280Wonsik Kim float volume = mSourceVolume * getMediaStreamVolume(); 8088e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim AudioGainConfig sourceGainConfig = null; 80949e559353278a56963596d652af26fe1f886a280Wonsik Kim if (mAudioSource.gains().length > 0 && volume != mCommittedVolume) { 8108e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim AudioGain sourceGain = null; 8118e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim for (AudioGain gain : mAudioSource.gains()) { 8128e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim if ((gain.mode() & AudioGain.MODE_JOINT) != 0) { 8138e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim sourceGain = gain; 8148e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim break; 8158e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim } 8168e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim } 8178e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim // NOTE: we only change the source gain in MODE_JOINT here. 8188e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim if (sourceGain != null) { 8198e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim int steps = (sourceGain.maxValue() - sourceGain.minValue()) 8208e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim / sourceGain.stepValue(); 8218e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim int gainValue = sourceGain.minValue(); 82249e559353278a56963596d652af26fe1f886a280Wonsik Kim if (volume < 1.0f) { 82349e559353278a56963596d652af26fe1f886a280Wonsik Kim gainValue += sourceGain.stepValue() * (int) (volume * steps + 0.5); 8248e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim } else { 8258e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim gainValue = sourceGain.maxValue(); 8268e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim } 82749e559353278a56963596d652af26fe1f886a280Wonsik Kim // size of gain values is 1 in MODE_JOINT 82849e559353278a56963596d652af26fe1f886a280Wonsik Kim int[] gainValues = new int[] { gainValue }; 8298e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim sourceGainConfig = sourceGain.buildConfig(AudioGain.MODE_JOINT, 8308e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim sourceGain.channelMask(), gainValues, 0); 8318e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim } else { 8328e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim Slog.w(TAG, "No audio source gain with MODE_JOINT support exists."); 8338e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim } 8348e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim } 8358e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim 836ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim AudioPortConfig sourceConfig = mAudioSource.activeConfig(); 837b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim List<AudioPortConfig> sinkConfigs = new ArrayList<>(); 838ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim AudioPatch[] audioPatchArray = new AudioPatch[] { mAudioPatch }; 8397587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim boolean shouldRecreateAudioPatch = sourceUpdated || sinkUpdated; 84071dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim 841b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim for (AudioDevicePort audioSink : mAudioSink) { 842b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim AudioPortConfig sinkConfig = audioSink.activeConfig(); 843b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim int sinkSamplingRate = mDesiredSamplingRate; 844b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim int sinkChannelMask = mDesiredChannelMask; 845b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim int sinkFormat = mDesiredFormat; 846b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim // If sinkConfig != null and values are set to default, 847b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim // fill in the sinkConfig values. 848b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim if (sinkConfig != null) { 849b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim if (sinkSamplingRate == 0) { 850b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim sinkSamplingRate = sinkConfig.samplingRate(); 851b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim } 852b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim if (sinkChannelMask == AudioFormat.CHANNEL_OUT_DEFAULT) { 853b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim sinkChannelMask = sinkConfig.channelMask(); 854b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim } 855b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim if (sinkFormat == AudioFormat.ENCODING_DEFAULT) { 856b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim sinkChannelMask = sinkConfig.format(); 857b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim } 85871dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim } 85971dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim 860b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim if (sinkConfig == null 861b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim || sinkConfig.samplingRate() != sinkSamplingRate 862b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim || sinkConfig.channelMask() != sinkChannelMask 863b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim || sinkConfig.format() != sinkFormat) { 864b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim // Check for compatibility and reset to default if necessary. 865b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim if (!intArrayContains(audioSink.samplingRates(), sinkSamplingRate) 866b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim && audioSink.samplingRates().length > 0) { 867b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim sinkSamplingRate = audioSink.samplingRates()[0]; 868b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim } 869b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim if (!intArrayContains(audioSink.channelMasks(), sinkChannelMask)) { 870b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim sinkChannelMask = AudioFormat.CHANNEL_OUT_DEFAULT; 871b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim } 872b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim if (!intArrayContains(audioSink.formats(), sinkFormat)) { 873b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim sinkFormat = AudioFormat.ENCODING_DEFAULT; 874b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim } 875b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim sinkConfig = audioSink.buildConfig(sinkSamplingRate, sinkChannelMask, 876b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim sinkFormat, null); 877b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim shouldRecreateAudioPatch = true; 87871dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim } 879b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim sinkConfigs.add(sinkConfig); 880ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 881b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim // sinkConfigs.size() == mAudioSink.size(), and mAudioSink is guaranteed to be 882b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim // non-empty at the beginning of this method. 883b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim AudioPortConfig sinkConfig = sinkConfigs.get(0); 8848e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim if (sourceConfig == null || sourceGainConfig != null) { 88571dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim int sourceSamplingRate = 0; 88671dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim if (intArrayContains(mAudioSource.samplingRates(), sinkConfig.samplingRate())) { 88771dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim sourceSamplingRate = sinkConfig.samplingRate(); 88871dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim } else if (mAudioSource.samplingRates().length > 0) { 88971dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim // Use any sampling rate and hope audio patch can handle resampling... 89071dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim sourceSamplingRate = mAudioSource.samplingRates()[0]; 89171dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim } 89271dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim int sourceChannelMask = AudioFormat.CHANNEL_IN_DEFAULT; 89371dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim for (int inChannelMask : mAudioSource.channelMasks()) { 89471dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim if (AudioFormat.channelCountFromOutChannelMask(sinkConfig.channelMask()) 89571dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim == AudioFormat.channelCountFromInChannelMask(inChannelMask)) { 89671dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim sourceChannelMask = inChannelMask; 89771dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim break; 89871dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim } 89971dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim } 90071dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim int sourceFormat = AudioFormat.ENCODING_DEFAULT; 90171dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim if (intArrayContains(mAudioSource.formats(), sinkConfig.format())) { 90271dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim sourceFormat = sinkConfig.format(); 90371dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim } 90471dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim sourceConfig = mAudioSource.buildConfig(sourceSamplingRate, sourceChannelMask, 90571dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim sourceFormat, sourceGainConfig); 9068e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim shouldRecreateAudioPatch = true; 9078e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim } 9088e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim if (shouldRecreateAudioPatch) { 90949e559353278a56963596d652af26fe1f886a280Wonsik Kim mCommittedVolume = volume; 9108e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim mAudioManager.createAudioPatch( 9118e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim audioPatchArray, 9128e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim new AudioPortConfig[] { sourceConfig }, 913b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim sinkConfigs.toArray(new AudioPortConfig[0])); 9148e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim mAudioPatch = audioPatchArray[0]; 91571dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim if (sourceGainConfig != null) { 91671dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim mAudioManager.setAudioPortGain(mAudioSource, sourceGainConfig); 91771dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim } 918ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 919ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 920ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim 921c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim @Override 9228e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim public void setStreamVolume(float volume) throws RemoteException { 923c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mImplLock) { 924c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (mReleased) { 925c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim throw new IllegalStateException("Device already released."); 926c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 92749e559353278a56963596d652af26fe1f886a280Wonsik Kim mSourceVolume = volume; 9287587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim updateAudioConfigLocked(); 929c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 930c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 931c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 932c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim @Override 933c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public boolean dispatchKeyEventToHdmi(KeyEvent event) throws RemoteException { 934c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mImplLock) { 935c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (mReleased) { 936c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim throw new IllegalStateException("Device already released."); 937c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 938c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 939610ccd9117fc1611fcc576d1cb1f717f1ef3fcbfWonsik Kim if (mInfo.getType() != TvInputHardwareInfo.TV_INPUT_TYPE_HDMI) { 940c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return false; 941c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 942c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim // TODO(hdmi): mHdmiClient.sendKeyEvent(event); 943c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return false; 944c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 945c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 946c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo private boolean startCapture(Surface surface, TvStreamConfig config) { 947c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo synchronized (mImplLock) { 948c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (mReleased) { 949c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return false; 950c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 951c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (surface == null || config == null) { 952c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return false; 953c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 954c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (config.getType() != TvStreamConfig.STREAM_TYPE_BUFFER_PRODUCER) { 955c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return false; 956c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 957c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 9588f24a8b60f9afc1aedb89e7ee80ce65515439600Wonsik Kim int result = mHal.addOrUpdateStream(mInfo.getDeviceId(), surface, config); 959c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return result == TvInputHal.SUCCESS; 960c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 961c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 962c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 963c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo private boolean stopCapture(TvStreamConfig config) { 964c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo synchronized (mImplLock) { 965c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (mReleased) { 966c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return false; 967c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 968c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (config == null) { 969c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return false; 970c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 971c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 972c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo int result = mHal.removeStream(mInfo.getDeviceId(), config); 973c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return result == TvInputHal.SUCCESS; 974c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 975c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 976ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim 9777587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim private boolean updateAudioSourceLocked() { 97806c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim if (mInfo.getAudioType() == AudioManager.DEVICE_NONE) { 9797587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim return false; 98006c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 9817587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim AudioDevicePort previousSource = mAudioSource; 9827587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim mAudioSource = findAudioDevicePort(mInfo.getAudioType(), mInfo.getAudioAddress()); 9837587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim return mAudioSource == null ? (previousSource != null) 9847587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim : !mAudioSource.equals(previousSource); 9857587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim } 9867587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim 9877587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim private boolean updateAudioSinkLocked() { 9887587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim if (mInfo.getAudioType() == AudioManager.DEVICE_NONE) { 9897587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim return false; 9907587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim } 991b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim List<AudioDevicePort> previousSink = mAudioSink; 992b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim mAudioSink = new ArrayList<>(); 99306c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim if (mOverrideAudioType == AudioManager.DEVICE_NONE) { 994b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim findAudioSinkFromAudioPolicy(mAudioSink); 99506c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } else { 99606c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim AudioDevicePort audioSink = 99706c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim findAudioDevicePort(mOverrideAudioType, mOverrideAudioAddress); 99806c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim if (audioSink != null) { 999b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim mAudioSink.add(audioSink); 100006c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 100106c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 1002b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim 1003b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim // Returns true if mAudioSink and previousSink differs. 1004b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim if (mAudioSink.size() != previousSink.size()) { 1005b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim return true; 1006b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim } 1007b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim previousSink.removeAll(mAudioSink); 1008b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim return !previousSink.isEmpty(); 100906c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 101006c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim 10111f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang private void handleAudioSinkUpdated() { 10121f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang synchronized (mImplLock) { 10137587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim updateAudioConfigLocked(); 10141f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang } 10151f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang } 10161f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang 1017ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim @Override 1018ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim public void overrideAudioSink(int audioType, String audioAddress, int samplingRate, 1019ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim int channelMask, int format) { 1020ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim synchronized (mImplLock) { 102106c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim mOverrideAudioType = audioType; 102206c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim mOverrideAudioAddress = audioAddress; 102306c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim 1024ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim mDesiredSamplingRate = samplingRate; 1025ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim mDesiredChannelMask = channelMask; 1026ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim mDesiredFormat = format; 1027ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim 10287587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim updateAudioConfigLocked(); 102949e559353278a56963596d652af26fe1f886a280Wonsik Kim } 103049e559353278a56963596d652af26fe1f886a280Wonsik Kim } 103149e559353278a56963596d652af26fe1f886a280Wonsik Kim 103249e559353278a56963596d652af26fe1f886a280Wonsik Kim public void onMediaStreamVolumeChanged() { 103349e559353278a56963596d652af26fe1f886a280Wonsik Kim synchronized (mImplLock) { 103449e559353278a56963596d652af26fe1f886a280Wonsik Kim updateAudioConfigLocked(); 1035ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 1036ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 1037c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 1038969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 1039187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim interface Listener { 1040187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim public void onStateChanged(String inputId, int state); 1041187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim public void onHardwareDeviceAdded(TvInputHardwareInfo info); 10424f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee public void onHardwareDeviceRemoved(TvInputHardwareInfo info); 1043546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo public void onHdmiDeviceAdded(HdmiDeviceInfo device); 1044546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo public void onHdmiDeviceRemoved(HdmiDeviceInfo device); 1045e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim public void onHdmiDeviceUpdated(String inputId, HdmiDeviceInfo device); 1046187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 1047969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 1048187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim private class ListenerHandler extends Handler { 1049187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim private static final int STATE_CHANGED = 1; 1050187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim private static final int HARDWARE_DEVICE_ADDED = 2; 1051187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim private static final int HARDWARE_DEVICE_REMOVED = 3; 1052546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo private static final int HDMI_DEVICE_ADDED = 4; 1053546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo private static final int HDMI_DEVICE_REMOVED = 5; 105461daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang private static final int HDMI_DEVICE_UPDATED = 6; 1055969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 1056969167dc05a6485a32d160895871cff46fd81884Wonsik Kim @Override 1057969167dc05a6485a32d160895871cff46fd81884Wonsik Kim public final void handleMessage(Message msg) { 1058969167dc05a6485a32d160895871cff46fd81884Wonsik Kim switch (msg.what) { 1059187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim case STATE_CHANGED: { 1060969167dc05a6485a32d160895871cff46fd81884Wonsik Kim String inputId = (String) msg.obj; 1061969167dc05a6485a32d160895871cff46fd81884Wonsik Kim int state = msg.arg1; 1062187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim mListener.onStateChanged(inputId, state); 1063187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim break; 1064187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 1065187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim case HARDWARE_DEVICE_ADDED: { 1066187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim TvInputHardwareInfo info = (TvInputHardwareInfo) msg.obj; 1067187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim mListener.onHardwareDeviceAdded(info); 1068187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim break; 1069187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 1070187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim case HARDWARE_DEVICE_REMOVED: { 10714f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee TvInputHardwareInfo info = (TvInputHardwareInfo) msg.obj; 10724f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mListener.onHardwareDeviceRemoved(info); 1073187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim break; 1074187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 1075546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo case HDMI_DEVICE_ADDED: { 107661f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo info = (HdmiDeviceInfo) msg.obj; 1077546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo mListener.onHdmiDeviceAdded(info); 1078187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim break; 1079187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 1080546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo case HDMI_DEVICE_REMOVED: { 108161f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo info = (HdmiDeviceInfo) msg.obj; 1082546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo mListener.onHdmiDeviceRemoved(info); 1083969167dc05a6485a32d160895871cff46fd81884Wonsik Kim break; 1084969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 108561daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang case HDMI_DEVICE_UPDATED: { 1086184a6d69b1dbab8059e4f81d5674adde8e344aa3Wonsik Kim HdmiDeviceInfo info = (HdmiDeviceInfo) msg.obj; 1087184a6d69b1dbab8059e4f81d5674adde8e344aa3Wonsik Kim String inputId = null; 1088184a6d69b1dbab8059e4f81d5674adde8e344aa3Wonsik Kim synchronized (mLock) { 1089184a6d69b1dbab8059e4f81d5674adde8e344aa3Wonsik Kim inputId = mHdmiInputIdMap.get(info.getId()); 1090184a6d69b1dbab8059e4f81d5674adde8e344aa3Wonsik Kim } 1091184a6d69b1dbab8059e4f81d5674adde8e344aa3Wonsik Kim if (inputId != null) { 1092184a6d69b1dbab8059e4f81d5674adde8e344aa3Wonsik Kim mListener.onHdmiDeviceUpdated(inputId, info); 1093184a6d69b1dbab8059e4f81d5674adde8e344aa3Wonsik Kim } else { 1094184a6d69b1dbab8059e4f81d5674adde8e344aa3Wonsik Kim Slog.w(TAG, "Could not resolve input ID matching the device info; " 1095184a6d69b1dbab8059e4f81d5674adde8e344aa3Wonsik Kim + "ignoring."); 1096184a6d69b1dbab8059e4f81d5674adde8e344aa3Wonsik Kim } 1097184a6d69b1dbab8059e4f81d5674adde8e344aa3Wonsik Kim break; 109861daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang } 1099969167dc05a6485a32d160895871cff46fd81884Wonsik Kim default: { 1100969167dc05a6485a32d160895871cff46fd81884Wonsik Kim Slog.w(TAG, "Unhandled message: " + msg); 1101969167dc05a6485a32d160895871cff46fd81884Wonsik Kim break; 1102969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 1103969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 1104969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 1105969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 1106187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim 11077474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim // Listener implementations for HdmiControlService 11087474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim 11097474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim private final class HdmiHotplugEventListener extends IHdmiHotplugEventListener.Stub { 11107474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim @Override 11117474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim public void onReceived(HdmiHotplugEvent event) { 11127474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim synchronized (mLock) { 11137474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim mHdmiStateMap.put(event.getPort(), event.isConnected()); 1114d922a546b94119217fb790113d0001cad0432060Wonsik Kim TvInputHardwareInfo hardwareInfo = 1115d922a546b94119217fb790113d0001cad0432060Wonsik Kim findHardwareInfoForHdmiPortLocked(event.getPort()); 1116d922a546b94119217fb790113d0001cad0432060Wonsik Kim if (hardwareInfo == null) { 1117d922a546b94119217fb790113d0001cad0432060Wonsik Kim return; 1118d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 1119d922a546b94119217fb790113d0001cad0432060Wonsik Kim String inputId = mHardwareInputIdMap.get(hardwareInfo.getDeviceId()); 11207474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim if (inputId == null) { 11217474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim return; 11227474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim } 11237474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim mHandler.obtainMessage(ListenerHandler.STATE_CHANGED, 11247474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim convertConnectedToState(event.isConnected()), 0, inputId).sendToTarget(); 11257474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim } 11267474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim } 11277474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim } 11287474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim 1129187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim private final class HdmiDeviceEventListener extends IHdmiDeviceEventListener.Stub { 1130187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim @Override 113161daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang public void onStatusChanged(HdmiDeviceInfo deviceInfo, int status) { 113298d760e1c3123e6db8459f605d59a5689d56268cJinsuk Kim if (!deviceInfo.isSourceType()) return; 1133d922a546b94119217fb790113d0001cad0432060Wonsik Kim synchronized (mLock) { 113461daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang int messageType = 0; 1135e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim Object obj = null; 113661daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang switch (status) { 113761daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang case HdmiControlManager.DEVICE_EVENT_ADD_DEVICE: { 1138cf445877c60396cac1e8ecef75287952d2580db6Jungshik Jang if (findHdmiDeviceInfo(deviceInfo.getId()) == null) { 113961daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang mHdmiDeviceList.add(deviceInfo); 114061daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang } else { 114161daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang Slog.w(TAG, "The list already contains " + deviceInfo + "; ignoring."); 114261daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang return; 114361daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang } 114461daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang messageType = ListenerHandler.HDMI_DEVICE_ADDED; 1145e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim obj = deviceInfo; 114661daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang break; 1147d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 114861daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang case HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE: { 1149cf445877c60396cac1e8ecef75287952d2580db6Jungshik Jang HdmiDeviceInfo originalDeviceInfo = findHdmiDeviceInfo(deviceInfo.getId()); 1150cf445877c60396cac1e8ecef75287952d2580db6Jungshik Jang if (!mHdmiDeviceList.remove(originalDeviceInfo)) { 115161daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang Slog.w(TAG, "The list doesn't contain " + deviceInfo + "; ignoring."); 115261daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang return; 115361daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang } 115461daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang messageType = ListenerHandler.HDMI_DEVICE_REMOVED; 1155e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim obj = deviceInfo; 115661daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang break; 115761daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang } 115861daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang case HdmiControlManager.DEVICE_EVENT_UPDATE_DEVICE: { 1159cf445877c60396cac1e8ecef75287952d2580db6Jungshik Jang HdmiDeviceInfo originalDeviceInfo = findHdmiDeviceInfo(deviceInfo.getId()); 1160cf445877c60396cac1e8ecef75287952d2580db6Jungshik Jang if (!mHdmiDeviceList.remove(originalDeviceInfo)) { 116161daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang Slog.w(TAG, "The list doesn't contain " + deviceInfo + "; ignoring."); 116261daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang return; 116361daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang } 116461daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang mHdmiDeviceList.add(deviceInfo); 116561daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang messageType = ListenerHandler.HDMI_DEVICE_UPDATED; 1166184a6d69b1dbab8059e4f81d5674adde8e344aa3Wonsik Kim obj = deviceInfo; 116761daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang break; 1168d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 1169d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 117061daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang 1171e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim Message msg = mHandler.obtainMessage(messageType, 0, 0, obj); 1172d922a546b94119217fb790113d0001cad0432060Wonsik Kim if (findHardwareInfoForHdmiPortLocked(deviceInfo.getPortId()) != null) { 1173d922a546b94119217fb790113d0001cad0432060Wonsik Kim msg.sendToTarget(); 1174d922a546b94119217fb790113d0001cad0432060Wonsik Kim } else { 1175d922a546b94119217fb790113d0001cad0432060Wonsik Kim mPendingHdmiDeviceEvents.add(msg); 1176d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 1177d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 1178187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 1179cf445877c60396cac1e8ecef75287952d2580db6Jungshik Jang 1180cf445877c60396cac1e8ecef75287952d2580db6Jungshik Jang private HdmiDeviceInfo findHdmiDeviceInfo(int id) { 1181cf445877c60396cac1e8ecef75287952d2580db6Jungshik Jang for (HdmiDeviceInfo info : mHdmiDeviceList) { 1182cf445877c60396cac1e8ecef75287952d2580db6Jungshik Jang if (info.getId() == id) { 1183cf445877c60396cac1e8ecef75287952d2580db6Jungshik Jang return info; 1184cf445877c60396cac1e8ecef75287952d2580db6Jungshik Jang } 1185cf445877c60396cac1e8ecef75287952d2580db6Jungshik Jang } 1186cf445877c60396cac1e8ecef75287952d2580db6Jungshik Jang return null; 1187cf445877c60396cac1e8ecef75287952d2580db6Jungshik Jang } 1188187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 11897474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim 11901f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang private final class HdmiSystemAudioModeChangeListener extends 11911f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang IHdmiSystemAudioModeChangeListener.Stub { 11921f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang @Override 11931f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang public void onStatusChanged(boolean enabled) throws RemoteException { 11941f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang synchronized (mLock) { 11951f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang for (int i = 0; i < mConnections.size(); ++i) { 11961f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang TvInputHardwareImpl impl = mConnections.valueAt(i).getHardwareImplLocked(); 119744bb3a5bd630cfe0a4813586e840d59b9cbc9f64Jungshik Jang if (impl != null) { 119844bb3a5bd630cfe0a4813586e840d59b9cbc9f64Jungshik Jang impl.handleAudioSinkUpdated(); 119944bb3a5bd630cfe0a4813586e840d59b9cbc9f64Jungshik Jang } 12001f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang } 12011f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang } 12021f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang } 12031f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang } 1204c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim} 1205