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; 2071d5c76f19e8714102073bf774c025d5ccdebc11Shubangimport static android.media.tv.TvInputManager.INPUT_STATE_CONNECTED_STANDBY; 21969167dc05a6485a32d160895871cff46fd81884Wonsik Kimimport static android.media.tv.TvInputManager.INPUT_STATE_DISCONNECTED; 22969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 2349e559353278a56963596d652af26fe1f886a280Wonsik Kimimport android.content.BroadcastReceiver; 24c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimimport android.content.Context; 2549e559353278a56963596d652af26fe1f886a280Wonsik Kimimport android.content.Intent; 2649e559353278a56963596d652af26fe1f886a280Wonsik Kimimport android.content.IntentFilter; 278d718e1c96fd11ba9c956fbb66247b06142fda2dyangrenimport android.content.pm.PackageManager; 2861daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jangimport android.hardware.hdmi.HdmiControlManager; 2961f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jangimport android.hardware.hdmi.HdmiDeviceInfo; 30969167dc05a6485a32d160895871cff46fd81884Wonsik Kimimport android.hardware.hdmi.HdmiHotplugEvent; 317474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kimimport android.hardware.hdmi.IHdmiControlService; 32187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kimimport android.hardware.hdmi.IHdmiDeviceEventListener; 337474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kimimport android.hardware.hdmi.IHdmiHotplugEventListener; 341f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jangimport android.hardware.hdmi.IHdmiSystemAudioModeChangeListener; 35d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kimimport android.media.AudioDevicePort; 36ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kimimport android.media.AudioFormat; 378e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kimimport android.media.AudioGain; 388e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kimimport android.media.AudioGainConfig; 39d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kimimport android.media.AudioManager; 40d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kimimport android.media.AudioPatch; 41d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kimimport android.media.AudioPort; 42d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kimimport android.media.AudioPortConfig; 43ad36f647380ca54e49e851b6aab19c06cf6d02c4Wally Yauimport android.media.AudioSystem; 44d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.ITvInputHardware; 45d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.ITvInputHardwareCallback; 46546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seoimport android.media.tv.TvInputHardwareInfo; 47969167dc05a6485a32d160895871cff46fd81884Wonsik Kimimport android.media.tv.TvInputInfo; 48d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.TvStreamConfig; 498d718e1c96fd11ba9c956fbb66247b06142fda2dyangrenimport android.os.Binder; 50969167dc05a6485a32d160895871cff46fd81884Wonsik Kimimport android.os.Handler; 51c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimimport android.os.IBinder; 52969167dc05a6485a32d160895871cff46fd81884Wonsik Kimimport android.os.Message; 53c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimimport android.os.RemoteException; 547474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kimimport android.os.ServiceManager; 554f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Leeimport android.util.ArrayMap; 56c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimimport android.util.Slog; 57c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimimport android.util.SparseArray; 58969167dc05a6485a32d160895871cff46fd81884Wonsik Kimimport android.util.SparseBooleanArray; 59c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimimport android.view.KeyEvent; 60c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimimport android.view.Surface; 61c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 62fe9a53bc45fd0124a876dc0a49680aaf86641d3eJeff Sharkeyimport com.android.internal.util.DumpUtils; 638d718e1c96fd11ba9c956fbb66247b06142fda2dyangrenimport com.android.internal.util.IndentingPrintWriter; 64969167dc05a6485a32d160895871cff46fd81884Wonsik Kimimport com.android.server.SystemService; 65969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 668d718e1c96fd11ba9c956fbb66247b06142fda2dyangrenimport java.io.FileDescriptor; 678d718e1c96fd11ba9c956fbb66247b06142fda2dyangrenimport java.io.PrintWriter; 68c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimimport java.util.ArrayList; 698d718e1c96fd11ba9c956fbb66247b06142fda2dyangrenimport java.util.Arrays; 704f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Leeimport java.util.Collections; 71d922a546b94119217fb790113d0001cad0432060Wonsik Kimimport java.util.Iterator; 72d922a546b94119217fb790113d0001cad0432060Wonsik Kimimport java.util.LinkedList; 73c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kimimport java.util.List; 744f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Leeimport java.util.Map; 75c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 76c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim/** 77c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * A helper class for TvInputManagerService to handle TV input hardware. 78c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * 79c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * This class does a basic connection management and forwarding calls to TvInputHal which eventually 80c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * calls to tv_input HAL module. 81c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * 82c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * @hide 83c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim */ 847474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kimclass TvInputHardwareManager implements TvInputHal.Callback { 85c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private static final String TAG = TvInputHardwareManager.class.getSimpleName(); 864f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee 8749e559353278a56963596d652af26fe1f886a280Wonsik Kim private final Context mContext; 884f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee private final Listener mListener; 89c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private final TvInputHal mHal = new TvInputHal(this); 90d922a546b94119217fb790113d0001cad0432060Wonsik Kim private final SparseArray<Connection> mConnections = new SparseArray<>(); 91d922a546b94119217fb790113d0001cad0432060Wonsik Kim private final List<TvInputHardwareInfo> mHardwareList = new ArrayList<>(); 92546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo private final List<HdmiDeviceInfo> mHdmiDeviceList = new LinkedList<>(); 934f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee /* A map from a device ID to the matching TV input ID. */ 94d922a546b94119217fb790113d0001cad0432060Wonsik Kim private final SparseArray<String> mHardwareInputIdMap = new SparseArray<>(); 954f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee /* A map from a HDMI logical address to the matching TV input ID. */ 96546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo private final SparseArray<String> mHdmiInputIdMap = new SparseArray<>(); 97d922a546b94119217fb790113d0001cad0432060Wonsik Kim private final Map<String, TvInputInfo> mInputMap = new ArrayMap<>(); 984f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee 99d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim private final AudioManager mAudioManager; 1007474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim private final IHdmiHotplugEventListener mHdmiHotplugEventListener = 1017474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim new HdmiHotplugEventListener(); 1024f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee private final IHdmiDeviceEventListener mHdmiDeviceEventListener = new HdmiDeviceEventListener(); 1031f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang private final IHdmiSystemAudioModeChangeListener mHdmiSystemAudioModeChangeListener = 1041f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang new HdmiSystemAudioModeChangeListener(); 10549e559353278a56963596d652af26fe1f886a280Wonsik Kim private final BroadcastReceiver mVolumeReceiver = new BroadcastReceiver() { 10649e559353278a56963596d652af26fe1f886a280Wonsik Kim @Override 10749e559353278a56963596d652af26fe1f886a280Wonsik Kim public void onReceive(Context context, Intent intent) { 10849e559353278a56963596d652af26fe1f886a280Wonsik Kim handleVolumeChange(context, intent); 10949e559353278a56963596d652af26fe1f886a280Wonsik Kim } 11049e559353278a56963596d652af26fe1f886a280Wonsik Kim }; 11149e559353278a56963596d652af26fe1f886a280Wonsik Kim private int mCurrentIndex = 0; 11249e559353278a56963596d652af26fe1f886a280Wonsik Kim private int mCurrentMaxIndex = 0; 113d38bf476f6a31602e92a3207a4ceb29bf965f9aaJinsuk Kim 1144f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee private final SparseBooleanArray mHdmiStateMap = new SparseBooleanArray(); 115d922a546b94119217fb790113d0001cad0432060Wonsik Kim private final List<Message> mPendingHdmiDeviceEvents = new LinkedList<>(); 116969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 117187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim // Calls to mListener should happen here. 118187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim private final Handler mHandler = new ListenerHandler(); 119c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 120c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private final Object mLock = new Object(); 121c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 122187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim public TvInputHardwareManager(Context context, Listener listener) { 12349e559353278a56963596d652af26fe1f886a280Wonsik Kim mContext = context; 124187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim mListener = listener; 125d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); 126c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mHal.init(); 127969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 128969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 129969167dc05a6485a32d160895871cff46fd81884Wonsik Kim public void onBootPhase(int phase) { 130969167dc05a6485a32d160895871cff46fd81884Wonsik Kim if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { 13138b3257b7c0d80d282f1a1f7e1dd9c47e77c1081Jae Seo IHdmiControlService hdmiControlService = IHdmiControlService.Stub.asInterface( 13238b3257b7c0d80d282f1a1f7e1dd9c47e77c1081Jae Seo ServiceManager.getService(Context.HDMI_CONTROL_SERVICE)); 13338b3257b7c0d80d282f1a1f7e1dd9c47e77c1081Jae Seo if (hdmiControlService != null) { 1347474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim try { 13538b3257b7c0d80d282f1a1f7e1dd9c47e77c1081Jae Seo hdmiControlService.addHotplugEventListener(mHdmiHotplugEventListener); 13638b3257b7c0d80d282f1a1f7e1dd9c47e77c1081Jae Seo hdmiControlService.addDeviceEventListener(mHdmiDeviceEventListener); 13738b3257b7c0d80d282f1a1f7e1dd9c47e77c1081Jae Seo hdmiControlService.addSystemAudioModeChangeListener( 1381f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang mHdmiSystemAudioModeChangeListener); 13938b3257b7c0d80d282f1a1f7e1dd9c47e77c1081Jae Seo mHdmiDeviceList.addAll(hdmiControlService.getInputDevices()); 1407474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim } catch (RemoteException e) { 1414f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee Slog.w(TAG, "Error registering listeners to HdmiControlService:", e); 1427474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim } 14308f1ab02d6de42756825a2dfa7027137ff959bd8Jinsuk Kim } else { 14408f1ab02d6de42756825a2dfa7027137ff959bd8Jinsuk Kim Slog.w(TAG, "HdmiControlService is not available"); 1457474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim } 146ee5ad729b90deff435f9875337cbc434be4f8fe7John Spurlock final IntentFilter filter = new IntentFilter(); 147ee5ad729b90deff435f9875337cbc434be4f8fe7John Spurlock filter.addAction(AudioManager.VOLUME_CHANGED_ACTION); 148ee5ad729b90deff435f9875337cbc434be4f8fe7John Spurlock filter.addAction(AudioManager.STREAM_MUTE_CHANGED_ACTION); 149ee5ad729b90deff435f9875337cbc434be4f8fe7John Spurlock mContext.registerReceiver(mVolumeReceiver, filter); 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 } 21371d5c76f19e8714102073bf774c025d5ccdebc11Shubang int previousConfigsLength = connection.getConfigsLengthLocked(); 214c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim connection.updateConfigsLocked(configs); 2159a1036575182705bc27c6bf255dd17669821181dWonsik Kim String inputId = mHardwareInputIdMap.get(deviceId); 21671d5c76f19e8714102073bf774c025d5ccdebc11Shubang if (inputId != null 21771d5c76f19e8714102073bf774c025d5ccdebc11Shubang && (previousConfigsLength == 0) != (connection.getConfigsLengthLocked() == 0)) { 2189a1036575182705bc27c6bf255dd17669821181dWonsik Kim mHandler.obtainMessage(ListenerHandler.STATE_CHANGED, 21971d5c76f19e8714102073bf774c025d5ccdebc11Shubang connection.getInputStateLocked(), 0, inputId).sendToTarget(); 2209a1036575182705bc27c6bf255dd17669821181dWonsik Kim } 221017bb8523dd7c3dbfd00c055fde241de4dca9da2Dongwon Kang ITvInputHardwareCallback callback = connection.getCallbackLocked(); 222017bb8523dd7c3dbfd00c055fde241de4dca9da2Dongwon Kang if (callback != null) { 223017bb8523dd7c3dbfd00c055fde241de4dca9da2Dongwon Kang try { 224017bb8523dd7c3dbfd00c055fde241de4dca9da2Dongwon Kang callback.onStreamConfigChanged(configs); 225017bb8523dd7c3dbfd00c055fde241de4dca9da2Dongwon Kang } catch (RemoteException e) { 226017bb8523dd7c3dbfd00c055fde241de4dca9da2Dongwon Kang Slog.e(TAG, "error in onStreamConfigurationChanged", e); 227017bb8523dd7c3dbfd00c055fde241de4dca9da2Dongwon Kang } 228c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 229c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 230c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 231c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 232c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo @Override 233c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo public void onFirstFrameCaptured(int deviceId, int streamId) { 234c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo synchronized (mLock) { 235c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Connection connection = mConnections.get(deviceId); 236c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (connection == null) { 237c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Slog.e(TAG, "FirstFrameCaptured: Cannot find a connection with " 238c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo + deviceId); 239c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return; 240c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 241c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Runnable runnable = connection.getOnFirstFrameCapturedLocked(); 242c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (runnable != null) { 243c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo runnable.run(); 244c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo connection.setOnFirstFrameCapturedLocked(null); 245c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 246c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 247c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 248c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 249c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public List<TvInputHardwareInfo> getHardwareList() { 250c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mLock) { 251d922a546b94119217fb790113d0001cad0432060Wonsik Kim return Collections.unmodifiableList(mHardwareList); 252c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 253c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 254c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 255546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo public List<HdmiDeviceInfo> getHdmiDeviceList() { 256d922a546b94119217fb790113d0001cad0432060Wonsik Kim synchronized (mLock) { 257546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo return Collections.unmodifiableList(mHdmiDeviceList); 2584f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 2594f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 2604f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee 261e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim private boolean checkUidChangedLocked( 262e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim Connection connection, int callingUid, int resolvedUserId) { 263e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim Integer connectionCallingUid = connection.getCallingUidLocked(); 264e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim Integer connectionResolvedUserId = connection.getResolvedUserIdLocked(); 2656e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo return connectionCallingUid == null || connectionResolvedUserId == null 2666e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo || connectionCallingUid != callingUid || connectionResolvedUserId != resolvedUserId; 267e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim } 268e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim 2691abbbcd33efb8e5897c0fad5b6dd3af9a6b49b0dJae Seo public void addHardwareInput(int deviceId, TvInputInfo info) { 270969167dc05a6485a32d160895871cff46fd81884Wonsik Kim synchronized (mLock) { 2714f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee String oldInputId = mHardwareInputIdMap.get(deviceId); 2724f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee if (oldInputId != null) { 273969167dc05a6485a32d160895871cff46fd81884Wonsik Kim Slog.w(TAG, "Trying to override previous registration: old = " 2744f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee + mInputMap.get(oldInputId) + ":" + deviceId + ", new = " 275969167dc05a6485a32d160895871cff46fd81884Wonsik Kim + info + ":" + deviceId); 276969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 2774f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mHardwareInputIdMap.put(deviceId, info.getId()); 2784f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mInputMap.put(info.getId(), info); 279969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 2809a1036575182705bc27c6bf255dd17669821181dWonsik Kim // Process pending state changes 2819a1036575182705bc27c6bf255dd17669821181dWonsik Kim 2829a1036575182705bc27c6bf255dd17669821181dWonsik Kim // For logical HDMI devices, they have information from HDMI CEC signals. 283969167dc05a6485a32d160895871cff46fd81884Wonsik Kim for (int i = 0; i < mHdmiStateMap.size(); ++i) { 284d922a546b94119217fb790113d0001cad0432060Wonsik Kim TvInputHardwareInfo hardwareInfo = 285d922a546b94119217fb790113d0001cad0432060Wonsik Kim findHardwareInfoForHdmiPortLocked(mHdmiStateMap.keyAt(i)); 286d922a546b94119217fb790113d0001cad0432060Wonsik Kim if (hardwareInfo == null) { 287d922a546b94119217fb790113d0001cad0432060Wonsik Kim continue; 288d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 289d922a546b94119217fb790113d0001cad0432060Wonsik Kim String inputId = mHardwareInputIdMap.get(hardwareInfo.getDeviceId()); 290969167dc05a6485a32d160895871cff46fd81884Wonsik Kim if (inputId != null && inputId.equals(info.getId())) { 29171d5c76f19e8714102073bf774c025d5ccdebc11Shubang // No HDMI hotplug does not necessarily mean disconnected, as old devices may 29271d5c76f19e8714102073bf774c025d5ccdebc11Shubang // not report hotplug state correctly. Using INPUT_STATE_CONNECTED_STANDBY to 29371d5c76f19e8714102073bf774c025d5ccdebc11Shubang // denote unknown state. 29471d5c76f19e8714102073bf774c025d5ccdebc11Shubang int state = mHdmiStateMap.valueAt(i) 29571d5c76f19e8714102073bf774c025d5ccdebc11Shubang ? INPUT_STATE_CONNECTED 29671d5c76f19e8714102073bf774c025d5ccdebc11Shubang : INPUT_STATE_CONNECTED_STANDBY; 29771d5c76f19e8714102073bf774c025d5ccdebc11Shubang mHandler.obtainMessage( 29871d5c76f19e8714102073bf774c025d5ccdebc11Shubang ListenerHandler.STATE_CHANGED, state, 0, inputId).sendToTarget(); 2999a1036575182705bc27c6bf255dd17669821181dWonsik Kim return; 300969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 301969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 30271d5c76f19e8714102073bf774c025d5ccdebc11Shubang // For the rest of the devices, we can tell by the cable connection status. 3039a1036575182705bc27c6bf255dd17669821181dWonsik Kim Connection connection = mConnections.get(deviceId); 3049a1036575182705bc27c6bf255dd17669821181dWonsik Kim if (connection != null) { 3059a1036575182705bc27c6bf255dd17669821181dWonsik Kim mHandler.obtainMessage(ListenerHandler.STATE_CHANGED, 30671d5c76f19e8714102073bf774c025d5ccdebc11Shubang connection.getInputStateLocked(), 0, info.getId()).sendToTarget(); 3079a1036575182705bc27c6bf255dd17669821181dWonsik Kim } 308969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 309969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 310969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 31138feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim private static <T> int indexOfEqualValue(SparseArray<T> map, T value) { 31238feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim for (int i = 0; i < map.size(); ++i) { 31338feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim if (map.valueAt(i).equals(value)) { 31438feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim return i; 31538feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim } 31638feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim } 31738feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim return -1; 31838feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim } 31938feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim 32071dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim private static boolean intArrayContains(int[] array, int value) { 32171dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim for (int element : array) { 32271dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim if (element == value) return true; 32371dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim } 32471dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim return false; 32571dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim } 32671dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim 3271abbbcd33efb8e5897c0fad5b6dd3af9a6b49b0dJae Seo public void addHdmiInput(int id, TvInputInfo info) { 3284f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee if (info.getType() != TvInputInfo.TYPE_HDMI) { 3294f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee throw new IllegalArgumentException("info (" + info + ") has non-HDMI type."); 3304f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 3314f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee synchronized (mLock) { 3324f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee String parentId = info.getParentId(); 33338feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim int parentIndex = indexOfEqualValue(mHardwareInputIdMap, parentId); 33438feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim if (parentIndex < 0) { 3354f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee throw new IllegalArgumentException("info (" + info + ") has invalid parentId."); 3364f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 3378960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim String oldInputId = mHdmiInputIdMap.get(id); 3384f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee if (oldInputId != null) { 3394f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee Slog.w(TAG, "Trying to override previous registration: old = " 3408960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim + mInputMap.get(oldInputId) + ":" + id + ", new = " 3418960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim + info + ":" + id); 3424f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 3438960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim mHdmiInputIdMap.put(id, info.getId()); 3444f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mInputMap.put(info.getId(), info); 3454f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 3464f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 3474f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee 3481abbbcd33efb8e5897c0fad5b6dd3af9a6b49b0dJae Seo public void removeHardwareInput(String inputId) { 3494f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee synchronized (mLock) { 3504f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mInputMap.remove(inputId); 35138feae971c43700c9cb15aafbf8bd37340675a50Wonsik Kim int hardwareIndex = indexOfEqualValue(mHardwareInputIdMap, inputId); 3524f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee if (hardwareIndex >= 0) { 3534f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mHardwareInputIdMap.removeAt(hardwareIndex); 3544f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 355546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo int deviceIndex = indexOfEqualValue(mHdmiInputIdMap, inputId); 356546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo if (deviceIndex >= 0) { 357546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo mHdmiInputIdMap.removeAt(deviceIndex); 3584f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 3594f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 3604f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 3614f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee 362c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim /** 363c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * Create a TvInputHardware object with a specific deviceId. One service at a time can access 364c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * the object, and if more than one process attempts to create hardware with the same deviceId, 365c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * the latest service will get the object and all the other hardware are released. The 366c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * release is notified via ITvInputHardwareCallback.onReleased(). 367c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim */ 368c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public ITvInputHardware acquireHardware(int deviceId, ITvInputHardwareCallback callback, 369969167dc05a6485a32d160895871cff46fd81884Wonsik Kim TvInputInfo info, int callingUid, int resolvedUserId) { 370c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (callback == null) { 371c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim throw new NullPointerException(); 372c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 373c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mLock) { 374c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Connection connection = mConnections.get(deviceId); 375c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (connection == null) { 376c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Slog.e(TAG, "Invalid deviceId : " + deviceId); 377c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return null; 378c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 379e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim if (checkUidChangedLocked(connection, callingUid, resolvedUserId)) { 380969167dc05a6485a32d160895871cff46fd81884Wonsik Kim TvInputHardwareImpl hardware = 381969167dc05a6485a32d160895871cff46fd81884Wonsik Kim new TvInputHardwareImpl(connection.getHardwareInfoLocked()); 382c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim try { 383c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim callback.asBinder().linkToDeath(connection, 0); 384c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } catch (RemoteException e) { 385c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim hardware.release(); 386c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return null; 387c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 388969167dc05a6485a32d160895871cff46fd81884Wonsik Kim connection.resetLocked(hardware, callback, info, callingUid, resolvedUserId); 389c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 390c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return connection.getHardwareLocked(); 391c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 392c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 393c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 394c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim /** 395c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim * Release the specified hardware. 396c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim */ 397c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public void releaseHardware(int deviceId, ITvInputHardware hardware, int callingUid, 398c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim int resolvedUserId) { 399c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mLock) { 400c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Connection connection = mConnections.get(deviceId); 401c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (connection == null) { 402c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Slog.e(TAG, "Invalid deviceId : " + deviceId); 403c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return; 404c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 405c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (connection.getHardwareLocked() != hardware 406e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim || checkUidChangedLocked(connection, callingUid, resolvedUserId)) { 407c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return; 408c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 409969167dc05a6485a32d160895871cff46fd81884Wonsik Kim connection.resetLocked(null, null, null, null, null); 410969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 411969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 412969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 413d922a546b94119217fb790113d0001cad0432060Wonsik Kim private TvInputHardwareInfo findHardwareInfoForHdmiPortLocked(int port) { 414d922a546b94119217fb790113d0001cad0432060Wonsik Kim for (TvInputHardwareInfo hardwareInfo : mHardwareList) { 415969167dc05a6485a32d160895871cff46fd81884Wonsik Kim if (hardwareInfo.getType() == TvInputHardwareInfo.TV_INPUT_TYPE_HDMI 416969167dc05a6485a32d160895871cff46fd81884Wonsik Kim && hardwareInfo.getHdmiPortId() == port) { 417d922a546b94119217fb790113d0001cad0432060Wonsik Kim return hardwareInfo; 418969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 419969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 420969167dc05a6485a32d160895871cff46fd81884Wonsik Kim return null; 421969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 422969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 423c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo private int findDeviceIdForInputIdLocked(String inputId) { 424c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo for (int i = 0; i < mConnections.size(); ++i) { 425c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Connection connection = mConnections.get(i); 426c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (connection.getInfoLocked().getId().equals(inputId)) { 427c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return i; 428c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 429c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 430c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return -1; 431c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 432c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 433c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo /** 434c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo * Get the list of TvStreamConfig which is buffered mode. 435c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo */ 436c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo public List<TvStreamConfig> getAvailableTvStreamConfigList(String inputId, int callingUid, 437c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo int resolvedUserId) { 4386e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo List<TvStreamConfig> configsList = new ArrayList<>(); 439c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo synchronized (mLock) { 440c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo int deviceId = findDeviceIdForInputIdLocked(inputId); 441c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (deviceId < 0) { 442c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Slog.e(TAG, "Invalid inputId : " + inputId); 443c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return configsList; 444c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 445c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Connection connection = mConnections.get(deviceId); 446c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo for (TvStreamConfig config : connection.getConfigsLocked()) { 447c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (config.getType() == TvStreamConfig.STREAM_TYPE_BUFFER_PRODUCER) { 448c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo configsList.add(config); 449c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 450c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 451c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 452c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return configsList; 453c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 454c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 455c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo /** 456c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo * Take a snapshot of the given TV input into the provided Surface. 457c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo */ 458c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo public boolean captureFrame(String inputId, Surface surface, final TvStreamConfig config, 459c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo int callingUid, int resolvedUserId) { 460c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo synchronized (mLock) { 461c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo int deviceId = findDeviceIdForInputIdLocked(inputId); 462c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (deviceId < 0) { 463c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Slog.e(TAG, "Invalid inputId : " + inputId); 464c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return false; 465c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 466c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Connection connection = mConnections.get(deviceId); 467c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo final TvInputHardwareImpl hardwareImpl = connection.getHardwareImplLocked(); 468c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (hardwareImpl != null) { 469c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo // Stop previous capture. 470c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo Runnable runnable = connection.getOnFirstFrameCapturedLocked(); 471c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (runnable != null) { 472c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo runnable.run(); 473c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo connection.setOnFirstFrameCapturedLocked(null); 474c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 475c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 476c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo boolean result = hardwareImpl.startCapture(surface, config); 477c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (result) { 478c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo connection.setOnFirstFrameCapturedLocked(new Runnable() { 479c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo @Override 480c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo public void run() { 481c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo hardwareImpl.stopCapture(config); 482c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 483c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo }); 484c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 485c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return result; 486c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 487c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 488c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return false; 489c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 490c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 491d922a546b94119217fb790113d0001cad0432060Wonsik Kim private void processPendingHdmiDeviceEventsLocked() { 492d922a546b94119217fb790113d0001cad0432060Wonsik Kim for (Iterator<Message> it = mPendingHdmiDeviceEvents.iterator(); it.hasNext(); ) { 493d922a546b94119217fb790113d0001cad0432060Wonsik Kim Message msg = it.next(); 49461f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo deviceInfo = (HdmiDeviceInfo) msg.obj; 495d922a546b94119217fb790113d0001cad0432060Wonsik Kim TvInputHardwareInfo hardwareInfo = 496d922a546b94119217fb790113d0001cad0432060Wonsik Kim findHardwareInfoForHdmiPortLocked(deviceInfo.getPortId()); 497d922a546b94119217fb790113d0001cad0432060Wonsik Kim if (hardwareInfo != null) { 498d922a546b94119217fb790113d0001cad0432060Wonsik Kim msg.sendToTarget(); 499d922a546b94119217fb790113d0001cad0432060Wonsik Kim it.remove(); 500d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 501d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 502d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 503d922a546b94119217fb790113d0001cad0432060Wonsik Kim 50449e559353278a56963596d652af26fe1f886a280Wonsik Kim private void updateVolume() { 50549e559353278a56963596d652af26fe1f886a280Wonsik Kim mCurrentMaxIndex = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); 50649e559353278a56963596d652af26fe1f886a280Wonsik Kim mCurrentIndex = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC); 50749e559353278a56963596d652af26fe1f886a280Wonsik Kim } 50849e559353278a56963596d652af26fe1f886a280Wonsik Kim 50949e559353278a56963596d652af26fe1f886a280Wonsik Kim private void handleVolumeChange(Context context, Intent intent) { 51049e559353278a56963596d652af26fe1f886a280Wonsik Kim String action = intent.getAction(); 5116e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo switch (action) { 5126e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo case AudioManager.VOLUME_CHANGED_ACTION: { 5136e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1); 5146e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo if (streamType != AudioManager.STREAM_MUSIC) { 5156e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo return; 5166e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo } 5176e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo int index = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, 0); 5186e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo if (index == mCurrentIndex) { 5196e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo return; 5206e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo } 5216e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo mCurrentIndex = index; 5226e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo break; 52349e559353278a56963596d652af26fe1f886a280Wonsik Kim } 5246e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo case AudioManager.STREAM_MUTE_CHANGED_ACTION: { 5256e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1); 5266e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo if (streamType != AudioManager.STREAM_MUSIC) { 5276e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo return; 5286e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo } 5296e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo // volume index will be updated at onMediaStreamVolumeChanged() through 5306e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo // updateVolume(). 5316e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo break; 53249e559353278a56963596d652af26fe1f886a280Wonsik Kim } 5336e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo default: 5346e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo Slog.w(TAG, "Unrecognized intent: " + intent); 53549e559353278a56963596d652af26fe1f886a280Wonsik Kim return; 53649e559353278a56963596d652af26fe1f886a280Wonsik Kim } 53749e559353278a56963596d652af26fe1f886a280Wonsik Kim synchronized (mLock) { 53849e559353278a56963596d652af26fe1f886a280Wonsik Kim for (int i = 0; i < mConnections.size(); ++i) { 53949e559353278a56963596d652af26fe1f886a280Wonsik Kim TvInputHardwareImpl hardwareImpl = mConnections.valueAt(i).getHardwareImplLocked(); 54049e559353278a56963596d652af26fe1f886a280Wonsik Kim if (hardwareImpl != null) { 54149e559353278a56963596d652af26fe1f886a280Wonsik Kim hardwareImpl.onMediaStreamVolumeChanged(); 54249e559353278a56963596d652af26fe1f886a280Wonsik Kim } 54349e559353278a56963596d652af26fe1f886a280Wonsik Kim } 54449e559353278a56963596d652af26fe1f886a280Wonsik Kim } 54549e559353278a56963596d652af26fe1f886a280Wonsik Kim } 54649e559353278a56963596d652af26fe1f886a280Wonsik Kim 54749e559353278a56963596d652af26fe1f886a280Wonsik Kim private float getMediaStreamVolume() { 548ee5ad729b90deff435f9875337cbc434be4f8fe7John Spurlock return (float) mCurrentIndex / (float) mCurrentMaxIndex; 54949e559353278a56963596d652af26fe1f886a280Wonsik Kim } 55049e559353278a56963596d652af26fe1f886a280Wonsik Kim 5518d718e1c96fd11ba9c956fbb66247b06142fda2dyangren public void dump(FileDescriptor fd, final PrintWriter writer, String[] args) { 5528d718e1c96fd11ba9c956fbb66247b06142fda2dyangren final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); 553fe9a53bc45fd0124a876dc0a49680aaf86641d3eJeff Sharkey if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; 5548d718e1c96fd11ba9c956fbb66247b06142fda2dyangren 5558d718e1c96fd11ba9c956fbb66247b06142fda2dyangren synchronized (mLock) { 5568d718e1c96fd11ba9c956fbb66247b06142fda2dyangren pw.println("TvInputHardwareManager Info:"); 5578d718e1c96fd11ba9c956fbb66247b06142fda2dyangren pw.increaseIndent(); 5588d718e1c96fd11ba9c956fbb66247b06142fda2dyangren pw.println("mConnections: deviceId -> Connection"); 5598d718e1c96fd11ba9c956fbb66247b06142fda2dyangren pw.increaseIndent(); 5608d718e1c96fd11ba9c956fbb66247b06142fda2dyangren for (int i = 0; i < mConnections.size(); i++) { 5618d718e1c96fd11ba9c956fbb66247b06142fda2dyangren int deviceId = mConnections.keyAt(i); 5628d718e1c96fd11ba9c956fbb66247b06142fda2dyangren Connection mConnection = mConnections.valueAt(i); 5638d718e1c96fd11ba9c956fbb66247b06142fda2dyangren pw.println(deviceId + ": " + mConnection); 5648d718e1c96fd11ba9c956fbb66247b06142fda2dyangren 5658d718e1c96fd11ba9c956fbb66247b06142fda2dyangren } 5668d718e1c96fd11ba9c956fbb66247b06142fda2dyangren pw.decreaseIndent(); 5678d718e1c96fd11ba9c956fbb66247b06142fda2dyangren 5688d718e1c96fd11ba9c956fbb66247b06142fda2dyangren pw.println("mHardwareList:"); 5698d718e1c96fd11ba9c956fbb66247b06142fda2dyangren pw.increaseIndent(); 5708d718e1c96fd11ba9c956fbb66247b06142fda2dyangren for (TvInputHardwareInfo tvInputHardwareInfo : mHardwareList) { 5718d718e1c96fd11ba9c956fbb66247b06142fda2dyangren pw.println(tvInputHardwareInfo); 5728d718e1c96fd11ba9c956fbb66247b06142fda2dyangren } 5738d718e1c96fd11ba9c956fbb66247b06142fda2dyangren pw.decreaseIndent(); 5748d718e1c96fd11ba9c956fbb66247b06142fda2dyangren 5758d718e1c96fd11ba9c956fbb66247b06142fda2dyangren pw.println("mHdmiDeviceList:"); 5768d718e1c96fd11ba9c956fbb66247b06142fda2dyangren pw.increaseIndent(); 5778d718e1c96fd11ba9c956fbb66247b06142fda2dyangren for (HdmiDeviceInfo hdmiDeviceInfo : mHdmiDeviceList) { 5788d718e1c96fd11ba9c956fbb66247b06142fda2dyangren pw.println(hdmiDeviceInfo); 5798d718e1c96fd11ba9c956fbb66247b06142fda2dyangren } 5808d718e1c96fd11ba9c956fbb66247b06142fda2dyangren pw.decreaseIndent(); 5818d718e1c96fd11ba9c956fbb66247b06142fda2dyangren 5828d718e1c96fd11ba9c956fbb66247b06142fda2dyangren pw.println("mHardwareInputIdMap: deviceId -> inputId"); 5838d718e1c96fd11ba9c956fbb66247b06142fda2dyangren pw.increaseIndent(); 5848d718e1c96fd11ba9c956fbb66247b06142fda2dyangren for (int i = 0 ; i < mHardwareInputIdMap.size(); i++) { 5858d718e1c96fd11ba9c956fbb66247b06142fda2dyangren int deviceId = mHardwareInputIdMap.keyAt(i); 5868d718e1c96fd11ba9c956fbb66247b06142fda2dyangren String inputId = mHardwareInputIdMap.valueAt(i); 5878d718e1c96fd11ba9c956fbb66247b06142fda2dyangren pw.println(deviceId + ": " + inputId); 5888d718e1c96fd11ba9c956fbb66247b06142fda2dyangren } 5898d718e1c96fd11ba9c956fbb66247b06142fda2dyangren pw.decreaseIndent(); 5908d718e1c96fd11ba9c956fbb66247b06142fda2dyangren 5918d718e1c96fd11ba9c956fbb66247b06142fda2dyangren pw.println("mHdmiInputIdMap: id -> inputId"); 5928d718e1c96fd11ba9c956fbb66247b06142fda2dyangren pw.increaseIndent(); 5938d718e1c96fd11ba9c956fbb66247b06142fda2dyangren for (int i = 0; i < mHdmiInputIdMap.size(); i++) { 5948d718e1c96fd11ba9c956fbb66247b06142fda2dyangren int id = mHdmiInputIdMap.keyAt(i); 5958d718e1c96fd11ba9c956fbb66247b06142fda2dyangren String inputId = mHdmiInputIdMap.valueAt(i); 5968d718e1c96fd11ba9c956fbb66247b06142fda2dyangren pw.println(id + ": " + inputId); 5978d718e1c96fd11ba9c956fbb66247b06142fda2dyangren } 5988d718e1c96fd11ba9c956fbb66247b06142fda2dyangren pw.decreaseIndent(); 5998d718e1c96fd11ba9c956fbb66247b06142fda2dyangren 6008d718e1c96fd11ba9c956fbb66247b06142fda2dyangren pw.println("mInputMap: inputId -> inputInfo"); 6018d718e1c96fd11ba9c956fbb66247b06142fda2dyangren pw.increaseIndent(); 6028d718e1c96fd11ba9c956fbb66247b06142fda2dyangren for(Map.Entry<String, TvInputInfo> entry : mInputMap.entrySet()) { 6038d718e1c96fd11ba9c956fbb66247b06142fda2dyangren pw.println(entry.getKey() + ": " + entry.getValue()); 6048d718e1c96fd11ba9c956fbb66247b06142fda2dyangren } 6058d718e1c96fd11ba9c956fbb66247b06142fda2dyangren pw.decreaseIndent(); 6068d718e1c96fd11ba9c956fbb66247b06142fda2dyangren pw.decreaseIndent(); 6078d718e1c96fd11ba9c956fbb66247b06142fda2dyangren } 6088d718e1c96fd11ba9c956fbb66247b06142fda2dyangren } 6098d718e1c96fd11ba9c956fbb66247b06142fda2dyangren 610c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private class Connection implements IBinder.DeathRecipient { 611969167dc05a6485a32d160895871cff46fd81884Wonsik Kim private final TvInputHardwareInfo mHardwareInfo; 612969167dc05a6485a32d160895871cff46fd81884Wonsik Kim private TvInputInfo mInfo; 613c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private TvInputHardwareImpl mHardware = null; 614c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private ITvInputHardwareCallback mCallback; 615c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private TvStreamConfig[] mConfigs = null; 616c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private Integer mCallingUid = null; 617c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private Integer mResolvedUserId = null; 618c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo private Runnable mOnFirstFrameCaptured; 619c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 620969167dc05a6485a32d160895871cff46fd81884Wonsik Kim public Connection(TvInputHardwareInfo hardwareInfo) { 621969167dc05a6485a32d160895871cff46fd81884Wonsik Kim mHardwareInfo = hardwareInfo; 622c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 623c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 624c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim // *Locked methods assume TvInputHardwareManager.mLock is held. 625c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 626969167dc05a6485a32d160895871cff46fd81884Wonsik Kim public void resetLocked(TvInputHardwareImpl hardware, ITvInputHardwareCallback callback, 627969167dc05a6485a32d160895871cff46fd81884Wonsik Kim TvInputInfo info, Integer callingUid, Integer resolvedUserId) { 628c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (mHardware != null) { 629c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim try { 630c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mCallback.onReleased(); 631c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } catch (RemoteException e) { 6324f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee Slog.e(TAG, "error in Connection::resetLocked", e); 633c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 634c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mHardware.release(); 635c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 636c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mHardware = hardware; 637c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mCallback = callback; 638969167dc05a6485a32d160895871cff46fd81884Wonsik Kim mInfo = info; 639c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mCallingUid = callingUid; 640c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mResolvedUserId = resolvedUserId; 641c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo mOnFirstFrameCaptured = null; 642c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 643c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (mHardware != null && mCallback != null) { 644c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim try { 645c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mCallback.onStreamConfigChanged(getConfigsLocked()); 646c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } catch (RemoteException e) { 6474f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee Slog.e(TAG, "error in Connection::resetLocked", e); 648c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 649c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 650c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 651c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 652c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public void updateConfigsLocked(TvStreamConfig[] configs) { 653c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mConfigs = configs; 654c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 655c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 656969167dc05a6485a32d160895871cff46fd81884Wonsik Kim public TvInputHardwareInfo getHardwareInfoLocked() { 657969167dc05a6485a32d160895871cff46fd81884Wonsik Kim return mHardwareInfo; 658969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 659969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 660969167dc05a6485a32d160895871cff46fd81884Wonsik Kim public TvInputInfo getInfoLocked() { 661c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return mInfo; 662c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 663c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 664c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public ITvInputHardware getHardwareLocked() { 665c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return mHardware; 666c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 667c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 668c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo public TvInputHardwareImpl getHardwareImplLocked() { 669c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return mHardware; 670c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 671c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 672c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public ITvInputHardwareCallback getCallbackLocked() { 673c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return mCallback; 674c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 675c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 676c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public TvStreamConfig[] getConfigsLocked() { 677c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return mConfigs; 678c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 679c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 680e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim public Integer getCallingUidLocked() { 681c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return mCallingUid; 682c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 683c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 684e7ae0ce53b6e1ddee3e456d2a69eebcd5a196b1fWonsik Kim public Integer getResolvedUserIdLocked() { 685c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return mResolvedUserId; 686c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 687c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 688c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo public void setOnFirstFrameCapturedLocked(Runnable runnable) { 689c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo mOnFirstFrameCaptured = runnable; 690c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 691c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 692c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo public Runnable getOnFirstFrameCapturedLocked() { 693c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return mOnFirstFrameCaptured; 694c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 695c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 696c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim @Override 697c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public void binderDied() { 698c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mLock) { 699969167dc05a6485a32d160895871cff46fd81884Wonsik Kim resetLocked(null, null, null, null, null); 700c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 701c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 7028d718e1c96fd11ba9c956fbb66247b06142fda2dyangren 7038d718e1c96fd11ba9c956fbb66247b06142fda2dyangren public String toString() { 7048d718e1c96fd11ba9c956fbb66247b06142fda2dyangren return "Connection{" 7058d718e1c96fd11ba9c956fbb66247b06142fda2dyangren + " mHardwareInfo: " + mHardwareInfo 7068d718e1c96fd11ba9c956fbb66247b06142fda2dyangren + ", mInfo: " + mInfo 7078d718e1c96fd11ba9c956fbb66247b06142fda2dyangren + ", mCallback: " + mCallback 7088d718e1c96fd11ba9c956fbb66247b06142fda2dyangren + ", mConfigs: " + Arrays.toString(mConfigs) 7098d718e1c96fd11ba9c956fbb66247b06142fda2dyangren + ", mCallingUid: " + mCallingUid 7108d718e1c96fd11ba9c956fbb66247b06142fda2dyangren + ", mResolvedUserId: " + mResolvedUserId 7118d718e1c96fd11ba9c956fbb66247b06142fda2dyangren + " }"; 7128d718e1c96fd11ba9c956fbb66247b06142fda2dyangren } 71371d5c76f19e8714102073bf774c025d5ccdebc11Shubang 71471d5c76f19e8714102073bf774c025d5ccdebc11Shubang private int getConfigsLengthLocked() { 71571d5c76f19e8714102073bf774c025d5ccdebc11Shubang return mConfigs == null ? 0 : mConfigs.length; 71671d5c76f19e8714102073bf774c025d5ccdebc11Shubang } 71771d5c76f19e8714102073bf774c025d5ccdebc11Shubang 71871d5c76f19e8714102073bf774c025d5ccdebc11Shubang private int getInputStateLocked() { 71971d5c76f19e8714102073bf774c025d5ccdebc11Shubang int configsLength = getConfigsLengthLocked(); 72071d5c76f19e8714102073bf774c025d5ccdebc11Shubang if (configsLength > 0) { 72171d5c76f19e8714102073bf774c025d5ccdebc11Shubang return INPUT_STATE_CONNECTED; 72271d5c76f19e8714102073bf774c025d5ccdebc11Shubang } 72371d5c76f19e8714102073bf774c025d5ccdebc11Shubang switch (mHardwareInfo.getCableConnectionStatus()) { 72471d5c76f19e8714102073bf774c025d5ccdebc11Shubang case TvInputHardwareInfo.CABLE_CONNECTION_STATUS_CONNECTED: 72571d5c76f19e8714102073bf774c025d5ccdebc11Shubang return INPUT_STATE_CONNECTED; 72671d5c76f19e8714102073bf774c025d5ccdebc11Shubang case TvInputHardwareInfo.CABLE_CONNECTION_STATUS_DISCONNECTED: 72771d5c76f19e8714102073bf774c025d5ccdebc11Shubang return INPUT_STATE_DISCONNECTED; 72871d5c76f19e8714102073bf774c025d5ccdebc11Shubang case TvInputHardwareInfo.CABLE_CONNECTION_STATUS_UNKNOWN: 72971d5c76f19e8714102073bf774c025d5ccdebc11Shubang default: 73071d5c76f19e8714102073bf774c025d5ccdebc11Shubang return INPUT_STATE_CONNECTED_STANDBY; 73171d5c76f19e8714102073bf774c025d5ccdebc11Shubang } 73271d5c76f19e8714102073bf774c025d5ccdebc11Shubang } 733c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 734c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 735c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private class TvInputHardwareImpl extends ITvInputHardware.Stub { 736c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private final TvInputHardwareInfo mInfo; 737c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private boolean mReleased = false; 738c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private final Object mImplLock = new Object(); 739c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 74006c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim private final AudioManager.OnAudioPortUpdateListener mAudioListener = 74106c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim new AudioManager.OnAudioPortUpdateListener() { 74206c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim @Override 74306c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim public void onAudioPortListUpdate(AudioPort[] portList) { 74406c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim synchronized (mImplLock) { 7457587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim updateAudioConfigLocked(); 74606c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 74706c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 74806c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim 74906c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim @Override 75006c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim public void onAudioPatchListUpdate(AudioPatch[] patchList) { 75106c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim // No-op 75206c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 75306c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim 75406c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim @Override 75506c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim public void onServiceDied() { 75606c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim synchronized (mImplLock) { 75706c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim mAudioSource = null; 758b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim mAudioSink.clear(); 759ee32ede54063415fd6c48742ff6a2bf407adf971Jae Seo if (mAudioPatch != null) { 760ee32ede54063415fd6c48742ff6a2bf407adf971Jae Seo mAudioManager.releaseAudioPatch(mAudioPatch); 761ee32ede54063415fd6c48742ff6a2bf407adf971Jae Seo mAudioPatch = null; 762ee32ede54063415fd6c48742ff6a2bf407adf971Jae Seo } 76306c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 76406c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 76506c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim }; 76606c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim private int mOverrideAudioType = AudioManager.DEVICE_NONE; 76706c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim private String mOverrideAudioAddress = ""; 76806c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim private AudioDevicePort mAudioSource; 769b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim private List<AudioDevicePort> mAudioSink = new ArrayList<>(); 770d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim private AudioPatch mAudioPatch = null; 771485e7e13f410072c7c79368338ec3eba92c39169Wonsik Kim // Set to an invalid value for a volume, so that current volume can be applied at the 772485e7e13f410072c7c79368338ec3eba92c39169Wonsik Kim // first call to updateAudioConfigLocked(). 773485e7e13f410072c7c79368338ec3eba92c39169Wonsik Kim private float mCommittedVolume = -1f; 77449e559353278a56963596d652af26fe1f886a280Wonsik Kim private float mSourceVolume = 0.0f; 775d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim 776839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim private TvStreamConfig mActiveConfig = null; 777839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim 778ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim private int mDesiredSamplingRate = 0; 779ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim private int mDesiredChannelMask = AudioFormat.CHANNEL_OUT_DEFAULT; 780ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim private int mDesiredFormat = AudioFormat.ENCODING_DEFAULT; 781ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim 782c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public TvInputHardwareImpl(TvInputHardwareInfo info) { 783c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mInfo = info; 78406c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim mAudioManager.registerAudioPortUpdateListener(mAudioListener); 785d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim if (mInfo.getAudioType() != AudioManager.DEVICE_NONE) { 78606c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim mAudioSource = findAudioDevicePort(mInfo.getAudioType(), mInfo.getAudioAddress()); 787b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim findAudioSinkFromAudioPolicy(mAudioSink); 788ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 789ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 790ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim 791b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim private void findAudioSinkFromAudioPolicy(List<AudioDevicePort> sinks) { 792b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim sinks.clear(); 7936e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo ArrayList<AudioDevicePort> devicePorts = new ArrayList<>(); 794b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim if (mAudioManager.listAudioDevicePorts(devicePorts) != AudioManager.SUCCESS) { 795b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim return; 796b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim } 797b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim int sinkDevice = mAudioManager.getDevicesForStream(AudioManager.STREAM_MUSIC); 798ceb47aae5a045856ad13a5534a4d96f9b36c9a65Paul McLean for (AudioDevicePort port : devicePorts) { 799ad36f647380ca54e49e851b6aab19c06cf6d02c4Wally Yau if ((port.type() & sinkDevice) != 0 && 800ad36f647380ca54e49e851b6aab19c06cf6d02c4Wally Yau (port.type() & AudioSystem.DEVICE_BIT_IN) == 0) { 801ceb47aae5a045856ad13a5534a4d96f9b36c9a65Paul McLean sinks.add(port); 802d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim } 803d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim } 804ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 805ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim 806ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim private AudioDevicePort findAudioDevicePort(int type, String address) { 807ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim if (type == AudioManager.DEVICE_NONE) { 808ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim return null; 809ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 8106e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo ArrayList<AudioDevicePort> devicePorts = new ArrayList<>(); 811ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim if (mAudioManager.listAudioDevicePorts(devicePorts) != AudioManager.SUCCESS) { 812ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim return null; 813ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 814ceb47aae5a045856ad13a5534a4d96f9b36c9a65Paul McLean for (AudioDevicePort port : devicePorts) { 815ceb47aae5a045856ad13a5534a4d96f9b36c9a65Paul McLean if (port.type() == type && port.address().equals(address)) { 816ceb47aae5a045856ad13a5534a4d96f9b36c9a65Paul McLean return port; 817ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 818ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 819ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim return null; 820c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 821c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 822c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public void release() { 823c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mImplLock) { 82406c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim mAudioManager.unregisterAudioPortUpdateListener(mAudioListener); 825d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim if (mAudioPatch != null) { 826d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim mAudioManager.releaseAudioPatch(mAudioPatch); 827d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim mAudioPatch = null; 828d7c29189aa639bfac1e6efcd222e65c2c8ecf3f1Wonsik Kim } 829c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mReleased = true; 830c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 831c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 832c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 833839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim // A TvInputHardwareImpl object holds only one active session. Therefore, if a client 834839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim // attempts to call setSurface with different TvStreamConfig objects, the last call will 835839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim // prevail. 836c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim @Override 837c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public boolean setSurface(Surface surface, TvStreamConfig config) 838c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim throws RemoteException { 839c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mImplLock) { 840c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (mReleased) { 841c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim throw new IllegalStateException("Device already released."); 842c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 8437587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim 844102670f16a44d4b25d7e3a252bedee0208b68c55Wonsik Kim int result = TvInputHal.SUCCESS; 845839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim if (surface == null) { 846b683e6e4c70da3644427cb5ec6a8342b3a91bb23Wonsik Kim // The value of config is ignored when surface == null. 847b683e6e4c70da3644427cb5ec6a8342b3a91bb23Wonsik Kim if (mActiveConfig != null) { 848b683e6e4c70da3644427cb5ec6a8342b3a91bb23Wonsik Kim result = mHal.removeStream(mInfo.getDeviceId(), mActiveConfig); 849b683e6e4c70da3644427cb5ec6a8342b3a91bb23Wonsik Kim mActiveConfig = null; 850b683e6e4c70da3644427cb5ec6a8342b3a91bb23Wonsik Kim } else { 851b683e6e4c70da3644427cb5ec6a8342b3a91bb23Wonsik Kim // We already have no active stream. 852b683e6e4c70da3644427cb5ec6a8342b3a91bb23Wonsik Kim return true; 853b683e6e4c70da3644427cb5ec6a8342b3a91bb23Wonsik Kim } 854839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim } else { 855b683e6e4c70da3644427cb5ec6a8342b3a91bb23Wonsik Kim // It's impossible to set a non-null surface with a null config. 856b683e6e4c70da3644427cb5ec6a8342b3a91bb23Wonsik Kim if (config == null) { 857b683e6e4c70da3644427cb5ec6a8342b3a91bb23Wonsik Kim return false; 858b683e6e4c70da3644427cb5ec6a8342b3a91bb23Wonsik Kim } 859b683e6e4c70da3644427cb5ec6a8342b3a91bb23Wonsik Kim // Remove stream only if we have an existing active configuration. 860b683e6e4c70da3644427cb5ec6a8342b3a91bb23Wonsik Kim if (mActiveConfig != null && !config.equals(mActiveConfig)) { 861839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim result = mHal.removeStream(mInfo.getDeviceId(), mActiveConfig); 862839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim if (result != TvInputHal.SUCCESS) { 863839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim mActiveConfig = null; 864839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim } 865839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim } 866b683e6e4c70da3644427cb5ec6a8342b3a91bb23Wonsik Kim // Proceed only if all previous operations succeeded. 867839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim if (result == TvInputHal.SUCCESS) { 868b683e6e4c70da3644427cb5ec6a8342b3a91bb23Wonsik Kim result = mHal.addOrUpdateStream(mInfo.getDeviceId(), surface, config); 869b683e6e4c70da3644427cb5ec6a8342b3a91bb23Wonsik Kim if (result == TvInputHal.SUCCESS) { 870b683e6e4c70da3644427cb5ec6a8342b3a91bb23Wonsik Kim mActiveConfig = config; 871b683e6e4c70da3644427cb5ec6a8342b3a91bb23Wonsik Kim } 872839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim } 873839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim } 8747587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim updateAudioConfigLocked(); 875839ae5f460caadf8580b7e0ab77e255d7a1ddae5Wonsik Kim return result == TvInputHal.SUCCESS; 876c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 877c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 878c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 8797587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim /** 8807587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim * Update audio configuration (source, sink, patch) all up to current state. 8817587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim */ 8827587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim private void updateAudioConfigLocked() { 8837587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim boolean sinkUpdated = updateAudioSinkLocked(); 8847587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim boolean sourceUpdated = updateAudioSourceLocked(); 8857587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim // We can't do updated = updateAudioSinkLocked() || updateAudioSourceLocked() here 8867587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim // because Java won't evaluate the latter if the former is true. 8877587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim 888b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim if (mAudioSource == null || mAudioSink.isEmpty() || mActiveConfig == null) { 88906c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim if (mAudioPatch != null) { 8907587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim mAudioManager.releaseAudioPatch(mAudioPatch); 8917587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim mAudioPatch = null; 89206c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 89306c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim return; 89406c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 89506c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim 89649e559353278a56963596d652af26fe1f886a280Wonsik Kim updateVolume(); 89749e559353278a56963596d652af26fe1f886a280Wonsik Kim float volume = mSourceVolume * getMediaStreamVolume(); 8988e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim AudioGainConfig sourceGainConfig = null; 89949e559353278a56963596d652af26fe1f886a280Wonsik Kim if (mAudioSource.gains().length > 0 && volume != mCommittedVolume) { 9008e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim AudioGain sourceGain = null; 9018e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim for (AudioGain gain : mAudioSource.gains()) { 9028e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim if ((gain.mode() & AudioGain.MODE_JOINT) != 0) { 9038e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim sourceGain = gain; 9048e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim break; 9058e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim } 9068e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim } 9078e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim // NOTE: we only change the source gain in MODE_JOINT here. 9088e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim if (sourceGain != null) { 9098e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim int steps = (sourceGain.maxValue() - sourceGain.minValue()) 9108e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim / sourceGain.stepValue(); 9118e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim int gainValue = sourceGain.minValue(); 91249e559353278a56963596d652af26fe1f886a280Wonsik Kim if (volume < 1.0f) { 91349e559353278a56963596d652af26fe1f886a280Wonsik Kim gainValue += sourceGain.stepValue() * (int) (volume * steps + 0.5); 9148e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim } else { 9158e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim gainValue = sourceGain.maxValue(); 9168e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim } 91749e559353278a56963596d652af26fe1f886a280Wonsik Kim // size of gain values is 1 in MODE_JOINT 91849e559353278a56963596d652af26fe1f886a280Wonsik Kim int[] gainValues = new int[] { gainValue }; 9198e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim sourceGainConfig = sourceGain.buildConfig(AudioGain.MODE_JOINT, 9208e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim sourceGain.channelMask(), gainValues, 0); 9218e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim } else { 9228e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim Slog.w(TAG, "No audio source gain with MODE_JOINT support exists."); 9238e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim } 9248e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim } 9258e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim 926ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim AudioPortConfig sourceConfig = mAudioSource.activeConfig(); 927b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim List<AudioPortConfig> sinkConfigs = new ArrayList<>(); 928ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim AudioPatch[] audioPatchArray = new AudioPatch[] { mAudioPatch }; 9297587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim boolean shouldRecreateAudioPatch = sourceUpdated || sinkUpdated; 93071dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim 931b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim for (AudioDevicePort audioSink : mAudioSink) { 932b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim AudioPortConfig sinkConfig = audioSink.activeConfig(); 933b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim int sinkSamplingRate = mDesiredSamplingRate; 934b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim int sinkChannelMask = mDesiredChannelMask; 935b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim int sinkFormat = mDesiredFormat; 936b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim // If sinkConfig != null and values are set to default, 937b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim // fill in the sinkConfig values. 938b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim if (sinkConfig != null) { 939b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim if (sinkSamplingRate == 0) { 940b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim sinkSamplingRate = sinkConfig.samplingRate(); 941b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim } 942b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim if (sinkChannelMask == AudioFormat.CHANNEL_OUT_DEFAULT) { 943b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim sinkChannelMask = sinkConfig.channelMask(); 944b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim } 945b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim if (sinkFormat == AudioFormat.ENCODING_DEFAULT) { 946b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim sinkChannelMask = sinkConfig.format(); 947b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim } 94871dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim } 94971dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim 950b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim if (sinkConfig == null 951b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim || sinkConfig.samplingRate() != sinkSamplingRate 952b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim || sinkConfig.channelMask() != sinkChannelMask 953b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim || sinkConfig.format() != sinkFormat) { 954b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim // Check for compatibility and reset to default if necessary. 955b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim if (!intArrayContains(audioSink.samplingRates(), sinkSamplingRate) 956b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim && audioSink.samplingRates().length > 0) { 957b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim sinkSamplingRate = audioSink.samplingRates()[0]; 958b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim } 959b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim if (!intArrayContains(audioSink.channelMasks(), sinkChannelMask)) { 960b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim sinkChannelMask = AudioFormat.CHANNEL_OUT_DEFAULT; 961b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim } 962b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim if (!intArrayContains(audioSink.formats(), sinkFormat)) { 963b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim sinkFormat = AudioFormat.ENCODING_DEFAULT; 964b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim } 965b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim sinkConfig = audioSink.buildConfig(sinkSamplingRate, sinkChannelMask, 966b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim sinkFormat, null); 967b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim shouldRecreateAudioPatch = true; 96871dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim } 969b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim sinkConfigs.add(sinkConfig); 970ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 971b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim // sinkConfigs.size() == mAudioSink.size(), and mAudioSink is guaranteed to be 972b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim // non-empty at the beginning of this method. 973b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim AudioPortConfig sinkConfig = sinkConfigs.get(0); 9748e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim if (sourceConfig == null || sourceGainConfig != null) { 97571dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim int sourceSamplingRate = 0; 97671dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim if (intArrayContains(mAudioSource.samplingRates(), sinkConfig.samplingRate())) { 97771dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim sourceSamplingRate = sinkConfig.samplingRate(); 97871dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim } else if (mAudioSource.samplingRates().length > 0) { 97971dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim // Use any sampling rate and hope audio patch can handle resampling... 98071dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim sourceSamplingRate = mAudioSource.samplingRates()[0]; 98171dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim } 98271dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim int sourceChannelMask = AudioFormat.CHANNEL_IN_DEFAULT; 98371dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim for (int inChannelMask : mAudioSource.channelMasks()) { 98471dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim if (AudioFormat.channelCountFromOutChannelMask(sinkConfig.channelMask()) 98571dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim == AudioFormat.channelCountFromInChannelMask(inChannelMask)) { 98671dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim sourceChannelMask = inChannelMask; 98771dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim break; 98871dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim } 98971dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim } 99071dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim int sourceFormat = AudioFormat.ENCODING_DEFAULT; 99171dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim if (intArrayContains(mAudioSource.formats(), sinkConfig.format())) { 99271dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim sourceFormat = sinkConfig.format(); 99371dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim } 99471dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim sourceConfig = mAudioSource.buildConfig(sourceSamplingRate, sourceChannelMask, 99571dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim sourceFormat, sourceGainConfig); 9968e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim shouldRecreateAudioPatch = true; 9978e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim } 9988e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim if (shouldRecreateAudioPatch) { 99949e559353278a56963596d652af26fe1f886a280Wonsik Kim mCommittedVolume = volume; 1000ee32ede54063415fd6c48742ff6a2bf407adf971Jae Seo if (mAudioPatch != null) { 1001ee32ede54063415fd6c48742ff6a2bf407adf971Jae Seo mAudioManager.releaseAudioPatch(mAudioPatch); 1002ee32ede54063415fd6c48742ff6a2bf407adf971Jae Seo } 10038e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim mAudioManager.createAudioPatch( 10048e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim audioPatchArray, 10058e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim new AudioPortConfig[] { sourceConfig }, 100693ff14b7a5d1a9b4d3f57da85b286069fe9d8303Jae Seo sinkConfigs.toArray(new AudioPortConfig[sinkConfigs.size()])); 10078e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim mAudioPatch = audioPatchArray[0]; 100871dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim if (sourceGainConfig != null) { 100971dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim mAudioManager.setAudioPortGain(mAudioSource, sourceGainConfig); 101071dfa96f536e2ee6fbd4c5b0e517afcc1086d1fbWonsik Kim } 1011ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 1012ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 1013ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim 1014c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim @Override 10158e45a33ca8cb6b6a0cf75edf52ffdf86ffe3dd31Wonsik Kim public void setStreamVolume(float volume) throws RemoteException { 1016c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mImplLock) { 1017c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (mReleased) { 1018c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim throw new IllegalStateException("Device already released."); 1019c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 102049e559353278a56963596d652af26fe1f886a280Wonsik Kim mSourceVolume = volume; 10217587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim updateAudioConfigLocked(); 1022c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 1023c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 1024c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 1025c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim @Override 1026c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public boolean dispatchKeyEventToHdmi(KeyEvent event) throws RemoteException { 1027c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim synchronized (mImplLock) { 1028c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (mReleased) { 1029c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim throw new IllegalStateException("Device already released."); 1030c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 1031c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 1032610ccd9117fc1611fcc576d1cb1f717f1ef3fcbfWonsik Kim if (mInfo.getType() != TvInputHardwareInfo.TV_INPUT_TYPE_HDMI) { 1033c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return false; 1034c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 1035c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim // TODO(hdmi): mHdmiClient.sendKeyEvent(event); 1036c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return false; 1037c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 1038c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 1039c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo private boolean startCapture(Surface surface, TvStreamConfig config) { 1040c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo synchronized (mImplLock) { 1041c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (mReleased) { 1042c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return false; 1043c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 1044c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (surface == null || config == null) { 1045c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return false; 1046c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 1047c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (config.getType() != TvStreamConfig.STREAM_TYPE_BUFFER_PRODUCER) { 1048c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return false; 1049c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 1050c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 10518f24a8b60f9afc1aedb89e7ee80ce65515439600Wonsik Kim int result = mHal.addOrUpdateStream(mInfo.getDeviceId(), surface, config); 1052c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return result == TvInputHal.SUCCESS; 1053c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 1054c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 1055c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 1056c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo private boolean stopCapture(TvStreamConfig config) { 1057c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo synchronized (mImplLock) { 1058c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (mReleased) { 1059c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return false; 1060c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 1061c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo if (config == null) { 1062c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return false; 1063c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 1064c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo 1065c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo int result = mHal.removeStream(mInfo.getDeviceId(), config); 1066c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo return result == TvInputHal.SUCCESS; 1067c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 1068c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo } 1069ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim 10707587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim private boolean updateAudioSourceLocked() { 107106c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim if (mInfo.getAudioType() == AudioManager.DEVICE_NONE) { 10727587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim return false; 107306c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 10747587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim AudioDevicePort previousSource = mAudioSource; 10757587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim mAudioSource = findAudioDevicePort(mInfo.getAudioType(), mInfo.getAudioAddress()); 10767587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim return mAudioSource == null ? (previousSource != null) 10777587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim : !mAudioSource.equals(previousSource); 10787587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim } 10797587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim 10807587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim private boolean updateAudioSinkLocked() { 10817587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim if (mInfo.getAudioType() == AudioManager.DEVICE_NONE) { 10827587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim return false; 10837587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim } 1084b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim List<AudioDevicePort> previousSink = mAudioSink; 1085b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim mAudioSink = new ArrayList<>(); 108606c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim if (mOverrideAudioType == AudioManager.DEVICE_NONE) { 1087b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim findAudioSinkFromAudioPolicy(mAudioSink); 108806c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } else { 108906c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim AudioDevicePort audioSink = 109006c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim findAudioDevicePort(mOverrideAudioType, mOverrideAudioAddress); 109106c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim if (audioSink != null) { 1092b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim mAudioSink.add(audioSink); 109306c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 109406c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 1095b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim 1096b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim // Returns true if mAudioSink and previousSink differs. 1097b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim if (mAudioSink.size() != previousSink.size()) { 1098b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim return true; 1099b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim } 1100b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim previousSink.removeAll(mAudioSink); 1101b2b85f9576645e601dd38d1af83ad2737d8463d7Wonsik Kim return !previousSink.isEmpty(); 110206c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim } 110306c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim 11041f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang private void handleAudioSinkUpdated() { 11051f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang synchronized (mImplLock) { 11067587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim updateAudioConfigLocked(); 11071f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang } 11081f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang } 11091f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang 1110ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim @Override 1111ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim public void overrideAudioSink(int audioType, String audioAddress, int samplingRate, 1112ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim int channelMask, int format) { 1113ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim synchronized (mImplLock) { 111406c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim mOverrideAudioType = audioType; 111506c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim mOverrideAudioAddress = audioAddress; 111606c41a3e7ffd26894b6df3a0e4bfcfa47c48c739Wonsik Kim 1117ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim mDesiredSamplingRate = samplingRate; 1118ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim mDesiredChannelMask = channelMask; 1119ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim mDesiredFormat = format; 1120ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim 11217587d298c9dccbcf425204a9879b5c9e6d2a1a7eWonsik Kim updateAudioConfigLocked(); 112249e559353278a56963596d652af26fe1f886a280Wonsik Kim } 112349e559353278a56963596d652af26fe1f886a280Wonsik Kim } 112449e559353278a56963596d652af26fe1f886a280Wonsik Kim 112549e559353278a56963596d652af26fe1f886a280Wonsik Kim public void onMediaStreamVolumeChanged() { 112649e559353278a56963596d652af26fe1f886a280Wonsik Kim synchronized (mImplLock) { 112749e559353278a56963596d652af26fe1f886a280Wonsik Kim updateAudioConfigLocked(); 1128ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 1129ca17a9029dd7b1b87c155e68476eae5ee4efbedeWonsik Kim } 1130c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 1131969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 1132187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim interface Listener { 11336e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo void onStateChanged(String inputId, int state); 11346e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo void onHardwareDeviceAdded(TvInputHardwareInfo info); 11356e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo void onHardwareDeviceRemoved(TvInputHardwareInfo info); 11366e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo void onHdmiDeviceAdded(HdmiDeviceInfo device); 11376e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo void onHdmiDeviceRemoved(HdmiDeviceInfo device); 11386e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo void onHdmiDeviceUpdated(String inputId, HdmiDeviceInfo device); 1139187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 1140969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 1141187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim private class ListenerHandler extends Handler { 1142187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim private static final int STATE_CHANGED = 1; 1143187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim private static final int HARDWARE_DEVICE_ADDED = 2; 1144187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim private static final int HARDWARE_DEVICE_REMOVED = 3; 1145546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo private static final int HDMI_DEVICE_ADDED = 4; 1146546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo private static final int HDMI_DEVICE_REMOVED = 5; 114761daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang private static final int HDMI_DEVICE_UPDATED = 6; 1148969167dc05a6485a32d160895871cff46fd81884Wonsik Kim 1149969167dc05a6485a32d160895871cff46fd81884Wonsik Kim @Override 1150969167dc05a6485a32d160895871cff46fd81884Wonsik Kim public final void handleMessage(Message msg) { 1151969167dc05a6485a32d160895871cff46fd81884Wonsik Kim switch (msg.what) { 1152187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim case STATE_CHANGED: { 1153969167dc05a6485a32d160895871cff46fd81884Wonsik Kim String inputId = (String) msg.obj; 1154969167dc05a6485a32d160895871cff46fd81884Wonsik Kim int state = msg.arg1; 1155187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim mListener.onStateChanged(inputId, state); 1156187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim break; 1157187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 1158187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim case HARDWARE_DEVICE_ADDED: { 1159187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim TvInputHardwareInfo info = (TvInputHardwareInfo) msg.obj; 1160187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim mListener.onHardwareDeviceAdded(info); 1161187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim break; 1162187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 1163187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim case HARDWARE_DEVICE_REMOVED: { 11644f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee TvInputHardwareInfo info = (TvInputHardwareInfo) msg.obj; 11654f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mListener.onHardwareDeviceRemoved(info); 1166187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim break; 1167187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 1168546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo case HDMI_DEVICE_ADDED: { 116961f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo info = (HdmiDeviceInfo) msg.obj; 1170546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo mListener.onHdmiDeviceAdded(info); 1171187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim break; 1172187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 1173546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo case HDMI_DEVICE_REMOVED: { 117461f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo info = (HdmiDeviceInfo) msg.obj; 1175546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo mListener.onHdmiDeviceRemoved(info); 1176969167dc05a6485a32d160895871cff46fd81884Wonsik Kim break; 1177969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 117861daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang case HDMI_DEVICE_UPDATED: { 1179184a6d69b1dbab8059e4f81d5674adde8e344aa3Wonsik Kim HdmiDeviceInfo info = (HdmiDeviceInfo) msg.obj; 11806e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo String inputId; 1181184a6d69b1dbab8059e4f81d5674adde8e344aa3Wonsik Kim synchronized (mLock) { 1182184a6d69b1dbab8059e4f81d5674adde8e344aa3Wonsik Kim inputId = mHdmiInputIdMap.get(info.getId()); 1183184a6d69b1dbab8059e4f81d5674adde8e344aa3Wonsik Kim } 1184184a6d69b1dbab8059e4f81d5674adde8e344aa3Wonsik Kim if (inputId != null) { 1185184a6d69b1dbab8059e4f81d5674adde8e344aa3Wonsik Kim mListener.onHdmiDeviceUpdated(inputId, info); 1186184a6d69b1dbab8059e4f81d5674adde8e344aa3Wonsik Kim } else { 1187184a6d69b1dbab8059e4f81d5674adde8e344aa3Wonsik Kim Slog.w(TAG, "Could not resolve input ID matching the device info; " 1188184a6d69b1dbab8059e4f81d5674adde8e344aa3Wonsik Kim + "ignoring."); 1189184a6d69b1dbab8059e4f81d5674adde8e344aa3Wonsik Kim } 1190184a6d69b1dbab8059e4f81d5674adde8e344aa3Wonsik Kim break; 119161daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang } 1192969167dc05a6485a32d160895871cff46fd81884Wonsik Kim default: { 1193969167dc05a6485a32d160895871cff46fd81884Wonsik Kim Slog.w(TAG, "Unhandled message: " + msg); 1194969167dc05a6485a32d160895871cff46fd81884Wonsik Kim break; 1195969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 1196969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 1197969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 1198969167dc05a6485a32d160895871cff46fd81884Wonsik Kim } 1199187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim 12007474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim // Listener implementations for HdmiControlService 12017474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim 12027474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim private final class HdmiHotplugEventListener extends IHdmiHotplugEventListener.Stub { 12037474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim @Override 12047474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim public void onReceived(HdmiHotplugEvent event) { 12057474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim synchronized (mLock) { 12067474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim mHdmiStateMap.put(event.getPort(), event.isConnected()); 1207d922a546b94119217fb790113d0001cad0432060Wonsik Kim TvInputHardwareInfo hardwareInfo = 1208d922a546b94119217fb790113d0001cad0432060Wonsik Kim findHardwareInfoForHdmiPortLocked(event.getPort()); 1209d922a546b94119217fb790113d0001cad0432060Wonsik Kim if (hardwareInfo == null) { 1210d922a546b94119217fb790113d0001cad0432060Wonsik Kim return; 1211d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 1212d922a546b94119217fb790113d0001cad0432060Wonsik Kim String inputId = mHardwareInputIdMap.get(hardwareInfo.getDeviceId()); 12137474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim if (inputId == null) { 12147474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim return; 12157474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim } 121671d5c76f19e8714102073bf774c025d5ccdebc11Shubang // No HDMI hotplug does not necessarily mean disconnected, as old devices may 121771d5c76f19e8714102073bf774c025d5ccdebc11Shubang // not report hotplug state correctly. Using INPUT_STATE_CONNECTED_STANDBY to 121871d5c76f19e8714102073bf774c025d5ccdebc11Shubang // denote unknown state. 121971d5c76f19e8714102073bf774c025d5ccdebc11Shubang int state = event.isConnected() 122071d5c76f19e8714102073bf774c025d5ccdebc11Shubang ? INPUT_STATE_CONNECTED 122171d5c76f19e8714102073bf774c025d5ccdebc11Shubang : INPUT_STATE_CONNECTED_STANDBY; 122271d5c76f19e8714102073bf774c025d5ccdebc11Shubang mHandler.obtainMessage( 122371d5c76f19e8714102073bf774c025d5ccdebc11Shubang ListenerHandler.STATE_CHANGED, state, 0, inputId).sendToTarget(); 12247474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim } 12257474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim } 12267474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim } 12277474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim 1228187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim private final class HdmiDeviceEventListener extends IHdmiDeviceEventListener.Stub { 1229187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim @Override 123061daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang public void onStatusChanged(HdmiDeviceInfo deviceInfo, int status) { 123198d760e1c3123e6db8459f605d59a5689d56268cJinsuk Kim if (!deviceInfo.isSourceType()) return; 1232d922a546b94119217fb790113d0001cad0432060Wonsik Kim synchronized (mLock) { 123361daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang int messageType = 0; 1234e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim Object obj = null; 123561daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang switch (status) { 123661daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang case HdmiControlManager.DEVICE_EVENT_ADD_DEVICE: { 1237cf445877c60396cac1e8ecef75287952d2580db6Jungshik Jang if (findHdmiDeviceInfo(deviceInfo.getId()) == null) { 123861daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang mHdmiDeviceList.add(deviceInfo); 123961daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang } else { 124061daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang Slog.w(TAG, "The list already contains " + deviceInfo + "; ignoring."); 124161daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang return; 124261daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang } 124361daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang messageType = ListenerHandler.HDMI_DEVICE_ADDED; 1244e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim obj = deviceInfo; 124561daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang break; 1246d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 124761daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang case HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE: { 1248cf445877c60396cac1e8ecef75287952d2580db6Jungshik Jang HdmiDeviceInfo originalDeviceInfo = findHdmiDeviceInfo(deviceInfo.getId()); 1249cf445877c60396cac1e8ecef75287952d2580db6Jungshik Jang if (!mHdmiDeviceList.remove(originalDeviceInfo)) { 125061daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang Slog.w(TAG, "The list doesn't contain " + deviceInfo + "; ignoring."); 125161daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang return; 125261daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang } 125361daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang messageType = ListenerHandler.HDMI_DEVICE_REMOVED; 1254e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim obj = deviceInfo; 125561daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang break; 125661daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang } 125761daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang case HdmiControlManager.DEVICE_EVENT_UPDATE_DEVICE: { 1258cf445877c60396cac1e8ecef75287952d2580db6Jungshik Jang HdmiDeviceInfo originalDeviceInfo = findHdmiDeviceInfo(deviceInfo.getId()); 1259cf445877c60396cac1e8ecef75287952d2580db6Jungshik Jang if (!mHdmiDeviceList.remove(originalDeviceInfo)) { 126061daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang Slog.w(TAG, "The list doesn't contain " + deviceInfo + "; ignoring."); 126161daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang return; 126261daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang } 126361daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang mHdmiDeviceList.add(deviceInfo); 126461daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang messageType = ListenerHandler.HDMI_DEVICE_UPDATED; 1265184a6d69b1dbab8059e4f81d5674adde8e344aa3Wonsik Kim obj = deviceInfo; 126661daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang break; 1267d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 1268d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 126961daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang 1270e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim Message msg = mHandler.obtainMessage(messageType, 0, 0, obj); 1271d922a546b94119217fb790113d0001cad0432060Wonsik Kim if (findHardwareInfoForHdmiPortLocked(deviceInfo.getPortId()) != null) { 1272d922a546b94119217fb790113d0001cad0432060Wonsik Kim msg.sendToTarget(); 1273d922a546b94119217fb790113d0001cad0432060Wonsik Kim } else { 1274d922a546b94119217fb790113d0001cad0432060Wonsik Kim mPendingHdmiDeviceEvents.add(msg); 1275d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 1276d922a546b94119217fb790113d0001cad0432060Wonsik Kim } 1277187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 1278cf445877c60396cac1e8ecef75287952d2580db6Jungshik Jang 1279cf445877c60396cac1e8ecef75287952d2580db6Jungshik Jang private HdmiDeviceInfo findHdmiDeviceInfo(int id) { 1280cf445877c60396cac1e8ecef75287952d2580db6Jungshik Jang for (HdmiDeviceInfo info : mHdmiDeviceList) { 1281cf445877c60396cac1e8ecef75287952d2580db6Jungshik Jang if (info.getId() == id) { 1282cf445877c60396cac1e8ecef75287952d2580db6Jungshik Jang return info; 1283cf445877c60396cac1e8ecef75287952d2580db6Jungshik Jang } 1284cf445877c60396cac1e8ecef75287952d2580db6Jungshik Jang } 1285cf445877c60396cac1e8ecef75287952d2580db6Jungshik Jang return null; 1286cf445877c60396cac1e8ecef75287952d2580db6Jungshik Jang } 1287187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 12887474faca5bab2fba5749cff7ed15558231307e38Jinsuk Kim 12891f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang private final class HdmiSystemAudioModeChangeListener extends 12901f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang IHdmiSystemAudioModeChangeListener.Stub { 12911f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang @Override 12921f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang public void onStatusChanged(boolean enabled) throws RemoteException { 12931f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang synchronized (mLock) { 12941f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang for (int i = 0; i < mConnections.size(); ++i) { 12951f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang TvInputHardwareImpl impl = mConnections.valueAt(i).getHardwareImplLocked(); 129644bb3a5bd630cfe0a4813586e840d59b9cbc9f64Jungshik Jang if (impl != null) { 129744bb3a5bd630cfe0a4813586e840d59b9cbc9f64Jungshik Jang impl.handleAudioSinkUpdated(); 129844bb3a5bd630cfe0a4813586e840d59b9cbc9f64Jungshik Jang } 12991f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang } 13001f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang } 13011f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang } 13021f819bbfc80f0ae9de120e9b81250db36629a0b1Jungshik Jang } 1303c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim} 1304