1 // Copyright 2016 The Android Open Source Project 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 16 // Implementation of audio_device_handler.h 17 18 #include "audio_device_handler.h" 19 20 #include <base/files/file.h> 21 #include <base/logging.h> 22 #include <brillo/message_loops/message_loop.h> 23 #include <media/AudioSystem.h> 24 25 namespace brillo { 26 27 // All input devices currently supported by AudioDeviceHandler. 28 const std::vector<audio_devices_t> AudioDeviceHandler::kSupportedInputDevices_ = 29 {AUDIO_DEVICE_IN_WIRED_HEADSET}; 30 31 const std::vector<audio_devices_t> 32 AudioDeviceHandler::kSupportedOutputDevices_ = { 33 AUDIO_DEVICE_OUT_WIRED_HEADSET, AUDIO_DEVICE_OUT_WIRED_HEADPHONE}; 34 35 static const char kH2WStateFile[] = "/sys/class/switch/h2w/state"; 36 37 AudioDeviceHandler::AudioDeviceHandler() { 38 headphone_ = false; 39 microphone_ = false; 40 } 41 42 AudioDeviceHandler::~AudioDeviceHandler() {} 43 44 void AudioDeviceHandler::GetInputDevices(std::vector<int>* devices_list) { 45 std::copy(connected_input_devices_.begin(), 46 connected_input_devices_.end(), 47 std::back_inserter(*devices_list)); 48 } 49 50 void AudioDeviceHandler::GetOutputDevices(std::vector<int>* devices_list) { 51 std::copy(connected_output_devices_.begin(), 52 connected_output_devices_.end(), 53 std::back_inserter(*devices_list)); 54 } 55 56 void AudioDeviceHandler::RegisterDeviceCallback( 57 base::Callback<void(DeviceConnectionState, 58 const std::vector<int>& )>& callback) { 59 callback_ = callback; 60 } 61 62 void AudioDeviceHandler::TriggerCallback(DeviceConnectionState state) { 63 // If no devices have changed, don't bother triggering a callback. 64 if (changed_devices_.size() == 0) 65 return; 66 base::Closure closure = base::Bind(callback_, state, changed_devices_); 67 MessageLoop::current()->PostTask(closure); 68 // We can clear changed_devices_ here since base::Bind makes a copy of 69 // changed_devices_. 70 changed_devices_.clear(); 71 } 72 73 void AudioDeviceHandler::APSDisconnect() { 74 aps_.clear(); 75 } 76 77 void AudioDeviceHandler::APSConnect( 78 android::sp<android::IAudioPolicyService> aps) { 79 aps_ = aps; 80 // Reset the state 81 connected_input_devices_.clear(); 82 connected_output_devices_.clear(); 83 // Inform audio policy service about the currently connected devices. 84 VLOG(1) << "Calling GetInitialAudioDeviceState on APSConnect."; 85 GetInitialAudioDeviceState(base::FilePath(kH2WStateFile)); 86 } 87 88 void AudioDeviceHandler::Init(android::sp<android::IAudioPolicyService> aps) { 89 aps_ = aps; 90 // Reset audio policy service state in case this service crashed and there is 91 // a mismatch between the current system state and what audio policy service 92 // was previously told. 93 VLOG(1) << "Calling DisconnectAllSupportedDevices."; 94 DisconnectAllSupportedDevices(); 95 TriggerCallback(kDevicesDisconnected); 96 97 // Get headphone jack state and update audio policy service with new state. 98 VLOG(1) << "Calling ReadInitialAudioDeviceState."; 99 GetInitialAudioDeviceState(base::FilePath(kH2WStateFile)); 100 } 101 102 void AudioDeviceHandler::GetInitialAudioDeviceState( 103 const base::FilePath& path) { 104 base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ); 105 if (!file.IsValid()) { 106 LOG(WARNING) << "Kernel does not have wired headset support. Could not " 107 << "open " << path.value() << " (" 108 << base::File::ErrorToString(file.error_details()) << ")."; 109 return; 110 } 111 int state = 0; 112 int bytes_read = file.ReadAtCurrentPos(reinterpret_cast<char*>(&state), 1); 113 state -= '0'; 114 if (bytes_read == 0) { 115 LOG(WARNING) << "Could not read from " << path.value(); 116 return; 117 } 118 VLOG(1) << "Initial audio jack state is " << state; 119 static const int kHeadPhoneMask = 0x1; 120 bool headphone = state & kHeadPhoneMask; 121 static const int kMicrophoneMask = 0x2; 122 bool microphone = (state & kMicrophoneMask) >> 1; 123 124 UpdateAudioSystem(headphone, microphone); 125 } 126 127 void AudioDeviceHandler::NotifyAudioPolicyService( 128 audio_devices_t device, audio_policy_dev_state_t state) { 129 if (aps_ == nullptr) { 130 LOG(INFO) << "Audio device handler cannot call audio policy service. Will " 131 << "try again later."; 132 return; 133 } 134 VLOG(1) << "Calling Audio Policy Service to change " << device << " to state " 135 << state; 136 aps_->setDeviceConnectionState(device, state, "", ""); 137 } 138 139 int AudioDeviceHandler::SetDevice(audio_policy_force_use_t usage, 140 audio_policy_forced_cfg_t config) { 141 if (aps_ == nullptr) { 142 LOG(WARNING) << "Audio policy service cannot be reached. Please try again."; 143 return EAGAIN; 144 } 145 VLOG(1) << "Calling audio policy service to set " << usage << " to " 146 << config; 147 return aps_->setForceUse(usage, config); 148 } 149 150 void AudioDeviceHandler::ConnectAudioDevice(audio_devices_t device) { 151 audio_policy_dev_state_t state = AUDIO_POLICY_DEVICE_STATE_AVAILABLE; 152 NotifyAudioPolicyService(device, state); 153 if (audio_is_input_device(device)) 154 connected_input_devices_.insert(device); 155 else 156 connected_output_devices_.insert(device); 157 changed_devices_.push_back(device); 158 } 159 160 void AudioDeviceHandler::DisconnectAudioDevice(audio_devices_t device) { 161 audio_policy_dev_state_t state = AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE; 162 NotifyAudioPolicyService(device, state); 163 if (audio_is_input_device(device)) 164 connected_input_devices_.erase(device); 165 else 166 connected_output_devices_.erase(device); 167 changed_devices_.push_back(device); 168 } 169 170 void AudioDeviceHandler::DisconnectAllSupportedDevices() { 171 for (auto device : kSupportedInputDevices_) { 172 DisconnectAudioDevice(device); 173 } 174 for (auto device : kSupportedOutputDevices_) { 175 DisconnectAudioDevice(device); 176 } 177 } 178 179 void AudioDeviceHandler::DisconnectAllConnectedDevices() { 180 while (!connected_input_devices_.empty()) { 181 audio_devices_t device = *(connected_input_devices_.begin()); 182 DisconnectAudioDevice(device); 183 } 184 while (!connected_output_devices_.empty()) { 185 audio_devices_t device = *(connected_output_devices_.begin()); 186 DisconnectAudioDevice(device); 187 } 188 } 189 190 void AudioDeviceHandler::UpdateAudioSystem(bool headphone, bool microphone) { 191 if (microphone) { 192 ConnectAudioDevice(AUDIO_DEVICE_IN_WIRED_HEADSET); 193 } 194 if (headphone && microphone) { 195 ConnectAudioDevice(AUDIO_DEVICE_OUT_WIRED_HEADSET); 196 } else if (headphone) { 197 ConnectAudioDevice(AUDIO_DEVICE_OUT_WIRED_HEADPHONE); 198 } else if (!microphone) { 199 // No devices are connected. Inform the audio policy service that all 200 // connected devices have been disconnected. 201 DisconnectAllConnectedDevices(); 202 TriggerCallback(kDevicesDisconnected); 203 return; 204 } 205 TriggerCallback(kDevicesConnected); 206 return; 207 } 208 209 void AudioDeviceHandler::ProcessEvent(const struct input_event& event) { 210 VLOG(1) << event.type << " " << event.code << " " << event.value; 211 if (event.type == EV_SW) { 212 switch (event.code) { 213 case SW_HEADPHONE_INSERT: 214 headphone_ = event.value; 215 break; 216 case SW_MICROPHONE_INSERT: 217 microphone_ = event.value; 218 break; 219 default: 220 // This event code is not supported by this handler. 221 break; 222 } 223 } else if (event.type == EV_SYN) { 224 // We have received all input events. Update the audio system. 225 UpdateAudioSystem(headphone_, microphone_); 226 // Reset the headphone and microphone flags that are used to track 227 // information across multiple calls to ProcessEvent. 228 headphone_ = false; 229 microphone_ = false; 230 } 231 } 232 233 } // namespace brillo 234