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 <media/AudioSystem.h>
23
24 namespace brillo {
25
26 static const char kH2WStateFile[] = "/sys/class/switch/h2w/state";
27
AudioDeviceHandler()28 AudioDeviceHandler::AudioDeviceHandler() {
29 headphone_ = false;
30 microphone_ = false;
31 }
32
~AudioDeviceHandler()33 AudioDeviceHandler::~AudioDeviceHandler() {}
34
APSDisconnect()35 void AudioDeviceHandler::APSDisconnect() {
36 aps_.clear();
37 }
38
APSConnect(android::sp<android::IAudioPolicyService> aps)39 void AudioDeviceHandler::APSConnect(
40 android::sp<android::IAudioPolicyService> aps) {
41 aps_ = aps;
42 // Reset the state
43 connected_input_devices_.clear();
44 connected_output_devices_.clear();
45 // Inform audio policy service about the currently connected devices.
46 VLOG(1) << "Calling GetInitialAudioDeviceState on APSConnect.";
47 GetInitialAudioDeviceState(base::FilePath(kH2WStateFile));
48 }
49
Init(android::sp<android::IAudioPolicyService> aps)50 void AudioDeviceHandler::Init(android::sp<android::IAudioPolicyService> aps) {
51 aps_ = aps;
52 // Reset audio policy service state in case this service crashed and there is
53 // a mismatch between the current system state and what audio policy service
54 // was previously told.
55 VLOG(1) << "Calling DisconnectAllSupportedDevices.";
56 DisconnectAllSupportedDevices();
57
58 // Get headphone jack state and update audio policy service with new state.
59 VLOG(1) << "Calling ReadInitialAudioDeviceState.";
60 GetInitialAudioDeviceState(base::FilePath(kH2WStateFile));
61 }
62
GetInitialAudioDeviceState(const base::FilePath & path)63 void AudioDeviceHandler::GetInitialAudioDeviceState(
64 const base::FilePath& path) {
65 base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
66 if (!file.IsValid()) {
67 LOG(WARNING) << "Kernel does not have wired headset support. Could not "
68 << "open " << path.value() << "( "
69 << base::File::ErrorToString(file.error_details()) << " ).";
70 return;
71 }
72 int state = 0;
73 int bytes_read = file.ReadAtCurrentPos(reinterpret_cast<char*>(&state), 1);
74 state -= '0';
75 if (bytes_read == 0) {
76 LOG(WARNING) << "Could not read from " << path.value();
77 return;
78 }
79 VLOG(1) << "Initial audio jack state is " << state;
80 static const int kHeadPhoneMask = 0x1;
81 bool headphone = state & kHeadPhoneMask;
82 static const int kMicrophoneMask = 0x2;
83 bool microphone = (state & kMicrophoneMask) >> 1;
84
85 UpdateAudioSystem(headphone, microphone);
86 }
87
NotifyAudioPolicyService(audio_devices_t device,audio_policy_dev_state_t state)88 void AudioDeviceHandler::NotifyAudioPolicyService(
89 audio_devices_t device, audio_policy_dev_state_t state) {
90 if (aps_ == nullptr) {
91 LOG(INFO) << "Audio device handler cannot call audio policy service. Will "
92 << "try again later.";
93 return;
94 }
95 VLOG(1) << "Calling Audio Policy Service to change " << device << " to state "
96 << state;
97 aps_->setDeviceConnectionState(device, state, "", "");
98 }
99
ConnectAudioDevice(audio_devices_t device)100 void AudioDeviceHandler::ConnectAudioDevice(audio_devices_t device) {
101 audio_policy_dev_state_t state = AUDIO_POLICY_DEVICE_STATE_AVAILABLE;
102 NotifyAudioPolicyService(device, state);
103 if (audio_is_input_device(device))
104 connected_input_devices_.insert(device);
105 else
106 connected_output_devices_.insert(device);
107 }
108
DisconnectAudioDevice(audio_devices_t device)109 void AudioDeviceHandler::DisconnectAudioDevice(audio_devices_t device) {
110 audio_policy_dev_state_t state = AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE;
111 NotifyAudioPolicyService(device, state);
112 if (audio_is_input_device(device))
113 connected_input_devices_.erase(device);
114 else
115 connected_output_devices_.erase(device);
116 }
117
DisconnectAllSupportedDevices()118 void AudioDeviceHandler::DisconnectAllSupportedDevices() {
119 for (auto device : kSupportedInputDevices_) {
120 DisconnectAudioDevice(device);
121 }
122 for (auto device : kSupportedOutputDevices_) {
123 DisconnectAudioDevice(device);
124 }
125 }
126
DisconnectAllConnectedDevices()127 void AudioDeviceHandler::DisconnectAllConnectedDevices() {
128 while (!connected_input_devices_.empty()) {
129 audio_devices_t device = *(connected_input_devices_.begin());
130 DisconnectAudioDevice(device);
131 }
132 while (!connected_output_devices_.empty()) {
133 audio_devices_t device = *(connected_output_devices_.begin());
134 DisconnectAudioDevice(device);
135 }
136 }
137
UpdateAudioSystem(bool headphone,bool microphone)138 void AudioDeviceHandler::UpdateAudioSystem(bool headphone, bool microphone) {
139 if (microphone) {
140 ConnectAudioDevice(AUDIO_DEVICE_IN_WIRED_HEADSET);
141 }
142 if (headphone && microphone) {
143 ConnectAudioDevice(AUDIO_DEVICE_OUT_WIRED_HEADSET);
144 } else if (headphone) {
145 ConnectAudioDevice(AUDIO_DEVICE_OUT_WIRED_HEADPHONE);
146 } else if (!microphone) {
147 // No devices are connected. Inform the audio policy service that all
148 // connected devices have been disconnected.
149 DisconnectAllConnectedDevices();
150 }
151 }
152
ProcessEvent(const struct input_event & event)153 void AudioDeviceHandler::ProcessEvent(const struct input_event& event) {
154 VLOG(1) << event.type << " " << event.code << " " << event.value;
155 if (event.type == EV_SW) {
156 switch (event.code) {
157 case SW_HEADPHONE_INSERT:
158 headphone_ = event.value;
159 break;
160 case SW_MICROPHONE_INSERT:
161 microphone_ = event.value;
162 break;
163 default:
164 // This event code is not supported by this handler.
165 break;
166 }
167 } else if (event.type == EV_SYN) {
168 // We have received all input events. Update the audio system.
169 UpdateAudioSystem(headphone_, microphone_);
170 // Reset the headphone and microphone flags that are used to track
171 // information across multiple calls to ProcessEvent.
172 headphone_ = false;
173 microphone_ = false;
174 }
175 }
176
177 } // namespace brillo
178