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