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
AudioDeviceHandler()37 AudioDeviceHandler::AudioDeviceHandler() {
38 headphone_ = false;
39 microphone_ = false;
40 }
41
~AudioDeviceHandler()42 AudioDeviceHandler::~AudioDeviceHandler() {}
43
GetInputDevices(std::vector<int> * devices_list)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
GetOutputDevices(std::vector<int> * devices_list)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
RegisterDeviceCallback(base::Callback<void (DeviceConnectionState,const std::vector<int> &)> & callback)56 void AudioDeviceHandler::RegisterDeviceCallback(
57 base::Callback<void(DeviceConnectionState,
58 const std::vector<int>& )>& callback) {
59 callback_ = callback;
60 }
61
TriggerCallback(DeviceConnectionState state)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
APSDisconnect()73 void AudioDeviceHandler::APSDisconnect() {
74 aps_.clear();
75 }
76
APSConnect(android::sp<android::IAudioPolicyService> aps)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
Init(android::sp<android::IAudioPolicyService> aps)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
GetInitialAudioDeviceState(const base::FilePath & path)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
NotifyAudioPolicyService(audio_devices_t device,audio_policy_dev_state_t state)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
SetDevice(audio_policy_force_use_t usage,audio_policy_forced_cfg_t config)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
ConnectAudioDevice(audio_devices_t device)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
DisconnectAudioDevice(audio_devices_t device)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
DisconnectAllSupportedDevices()170 void AudioDeviceHandler::DisconnectAllSupportedDevices() {
171 for (auto device : kSupportedInputDevices_) {
172 DisconnectAudioDevice(device);
173 }
174 for (auto device : kSupportedOutputDevices_) {
175 DisconnectAudioDevice(device);
176 }
177 }
178
DisconnectAllConnectedDevices()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
UpdateAudioSystem(bool headphone,bool microphone)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
ProcessEvent(const struct input_event & event)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