1 /*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "AudioControlServer.h"
18
19 #include <deque>
20 #include <string>
21 #include <thread>
22
23 #include <android-base/logging.h>
24 #include <android-base/parseint.h>
25 #include <android-base/strings.h>
26 #include <grpc++/grpc++.h>
27
28 #include <aidl/android/hardware/automotive/audiocontrol/AudioFocusChange.h>
29 #include <aidl/android/hardware/automotive/audiocontrol/BnAudioControl.h>
30 #include <aidl/android/hardware/automotive/audiocontrol/DuckingInfo.h>
31 #include <aidl/android/hardware/automotive/audiocontrol/IFocusListener.h>
32
33 #include <android_audio_policy_configuration_V7_0.h>
34
35 #include "AudioFocusControl.grpc.pb.h"
36 #include "AudioFocusControl.pb.h"
37 #include "libandroid_audio_controller/utils.h"
38
39 using std::literals::chrono_literals::operator""s;
40
41 namespace xsd {
42 using namespace ::android::audio::policy::configuration::V7_0;
43 }
44
45 using xsd::AudioUsage;
46
47 namespace aidl::android::hardware::automotive::audiocontrol {
48
49 class AudioControlServerImpl : public AudioControlServer,
50 audio_focus_control_proto::AudioFocusControlServer::Service {
51 public:
52 explicit AudioControlServerImpl(const std::string& addr);
53
54 ~AudioControlServerImpl();
55
RegisterFocusListener(std::shared_ptr<IFocusListener> focusListener)56 close_handle_func_t RegisterFocusListener(std::shared_ptr<IFocusListener> focusListener) override {
57 std::lock_guard<std::mutex> lock(mFocusListenerMutex);
58 mFocusListener = focusListener;
59
60 return [this, focusListener]() {
61 std::lock_guard<std::mutex> lock(mFocusListenerMutex);
62 if (mFocusListener == focusListener) {
63 mFocusListener = nullptr;
64 }
65 };
66 }
67
68 grpc::Status AudioRequests(::grpc::ServerContext* context,
69 const audio_focus_control_proto::AudioFocusControlMessage* message,
70 ::google::protobuf::Empty*) override;
71
72 void Start() override;
73
74 void Join() override;
75
76 private:
77 void RequestWorker();
78
79 void CheckSessionHeartbeats(std::chrono::steady_clock::time_point current_timestamp);
80
81 void HandleHeartbeat(aafc_session_id_t session,
82 std::chrono::steady_clock::time_point timestamp);
83
84 void HandleAcquiring(audio_focus_control_proto::AudioFocusRequest&& acquire_request,
85 std::chrono::steady_clock::time_point timestamp);
86
87 void HandleReleasing(aafc_session_id_t release_session);
88
89 void RequestAudioFocus(aafc_audio_usage_t usage, aafc_zone_id_t zone,
90 AudioFocusChange focus_change);
91
92 void AbandonAudioFocus(aafc_audio_usage_t usage, aafc_zone_id_t zone);
93
94 using grpc_request_t = audio_focus_control_proto::AudioFocusControlMessage;
95 using focus_listener_request_key_t = std::pair<aafc_audio_usage_t, aafc_zone_id_t>;
96
97 struct AudioFocusSession {
98 audio_focus_control_proto::AudioFocusRequest mRequest;
99 std::chrono::steady_clock::time_point mLastHeartbeat;
100
101 focus_listener_request_key_t GetRequestKey() const;
102 AudioFocusChange GetFocusChange() const;
103 };
104
105 using session_pool_t = std::map<aafc_session_id_t, AudioFocusSession>;
106
107 // data members
108
109 std::string mServiceAddr;
110 std::unique_ptr<::grpc::Server> mGrpcServer;
111 std::shared_ptr<IFocusListener> mFocusListener{nullptr};
112
113 // grpc request queue
114 std::deque<grpc_request_t> mRequestQueue;
115
116 // On the focus listener side, the usage/zone pair is used as the key,
117 // and acquiring focus multiple times on the same usage and zone will
118 // be treated as once, so we have to maintain the "sessions" and ref count
119 // by ourselves here.
120 //
121 // Active audio focus sessions from grpc clients
122 session_pool_t mSessionPool;
123
124 // ref counts of usage/zone pair
125 std::map<focus_listener_request_key_t, unsigned> mAudioFocusCount;
126
127 std::atomic<bool> mShutdownFlag{false};
128 std::thread mRequestWorker;
129
130 mutable std::mutex mFocusListenerMutex;
131 mutable std::mutex mRequestQueueMutex;
132
133 std::condition_variable mRequestQueueCV;
134 };
135
getServerCredentials()136 static std::shared_ptr<::grpc::ServerCredentials> getServerCredentials() {
137 // TODO(chenhaosjtuacm): get secured credentials here
138 return ::grpc::InsecureServerCredentials();
139 }
140
AudioControlServerImpl(const std::string & addr)141 AudioControlServerImpl::AudioControlServerImpl(const std::string& addr) : mServiceAddr(addr) {}
142
~AudioControlServerImpl()143 AudioControlServerImpl::~AudioControlServerImpl() {
144 mShutdownFlag.store(true);
145 if (mRequestWorker.joinable()) {
146 mRequestWorker.join();
147 }
148 }
149
Start()150 void AudioControlServerImpl::Start() {
151 if (mGrpcServer) {
152 LOG(WARNING) << __func__ << ": GRPC Server is running.";
153 return;
154 }
155
156 ::grpc::ServerBuilder builder;
157 builder.RegisterService(this);
158 builder.AddListeningPort(mServiceAddr, getServerCredentials());
159
160 mGrpcServer = builder.BuildAndStart();
161
162 if (!mGrpcServer) {
163 LOG(ERROR) << __func__ << ": failed to create the GRPC server, "
164 << "please make sure the configuration and permissions are correct.";
165 return;
166 }
167
168 mRequestWorker = std::thread(std::bind(&AudioControlServerImpl::RequestWorker, this));
169 }
170
Join()171 void AudioControlServerImpl::Join() {
172 if (!mGrpcServer) {
173 LOG(WARNING) << __func__ << ": GRPC Server is not running.";
174 return;
175 }
176 mGrpcServer->Wait();
177 }
178
AudioRequests(::grpc::ServerContext * context,const audio_focus_control_proto::AudioFocusControlMessage * message,::google::protobuf::Empty *)179 grpc::Status AudioControlServerImpl::AudioRequests(
180 ::grpc::ServerContext* context,
181 const audio_focus_control_proto::AudioFocusControlMessage* message,
182 ::google::protobuf::Empty*) {
183 {
184 std::lock_guard<std::mutex> lock(mRequestQueueMutex);
185 mRequestQueue.emplace_back(*message);
186 }
187 mRequestQueueCV.notify_all();
188 return ::grpc::Status::OK;
189 }
190
RequestWorker()191 void AudioControlServerImpl::RequestWorker() {
192 constexpr auto kCheckHeartbeatFreq = 1s;
193 auto nextHeartbeatCheckTime = std::chrono::steady_clock::now();
194 while (!mShutdownFlag.load()) {
195 std::optional<grpc_request_t> message;
196 {
197 std::unique_lock<std::mutex> lock(mRequestQueueMutex);
198 if (mRequestQueue.empty()) {
199 mRequestQueueCV.wait_until(lock, nextHeartbeatCheckTime,
200 [this]() { return !mRequestQueue.empty(); });
201 }
202 if (!mRequestQueue.empty()) {
203 message = std::move(*mRequestQueue.begin());
204 mRequestQueue.pop_front();
205 }
206 }
207
208 auto current_timestamp = std::chrono::steady_clock::now();
209 if (message) {
210 for (auto&& active_session : message->active_sessions()) {
211 HandleHeartbeat(active_session, current_timestamp);
212 }
213
214 for (auto&& acquire_request : *message->mutable_acquire_requests()) {
215 HandleAcquiring(std::move(acquire_request), current_timestamp);
216 }
217
218 for (auto&& release_session : message->release_requests()) {
219 HandleReleasing(release_session);
220 }
221 }
222 if (current_timestamp >= nextHeartbeatCheckTime) {
223 nextHeartbeatCheckTime += kCheckHeartbeatFreq;
224 CheckSessionHeartbeats(current_timestamp);
225 }
226 }
227 }
228
HandleHeartbeat(aafc_session_id_t session,std::chrono::steady_clock::time_point timestamp)229 void AudioControlServerImpl::HandleHeartbeat(aafc_session_id_t session,
230 std::chrono::steady_clock::time_point timestamp) {
231 auto session_search = mSessionPool.find(session);
232 if (session_search == mSessionPool.end()) {
233 LOG(ERROR) << __func__ << ": unknown session ID: " << session;
234 return;
235 }
236 auto& session_info = session_search->second;
237 session_info.mLastHeartbeat = timestamp;
238 }
239
HandleAcquiring(audio_focus_control_proto::AudioFocusRequest && acquire_request,std::chrono::steady_clock::time_point timestamp)240 void AudioControlServerImpl::HandleAcquiring(
241 audio_focus_control_proto::AudioFocusRequest&& acquire_request,
242 std::chrono::steady_clock::time_point timestamp) {
243 const auto session_id = acquire_request.session_id();
244 const auto session_emplace = mSessionPool.emplace(
245 session_id, AudioFocusSession{std::move(acquire_request), timestamp});
246 if (session_emplace.second == false) {
247 LOG(ERROR) << __func__ << ": duplicate session ID: " << session_id;
248 return;
249 }
250
251 const auto& session_emplace_iter = session_emplace.first;
252 const auto& session_info = session_emplace_iter->second;
253 const auto request_key = session_info.GetRequestKey();
254 const auto focus_change = session_info.GetFocusChange();
255 const auto ref_count_search = mAudioFocusCount.find(request_key);
256 const auto& [audio_usage, zone_id] = request_key;
257 LOG(DEBUG) << __func__ << ": acquiring: " << toString(static_cast<AudioUsage>(audio_usage))
258 << " " << zone_id << " " << toString(focus_change);
259
260 const bool not_found = ref_count_search == mAudioFocusCount.end();
261 const bool count_zero = !not_found && ref_count_search->second == 0;
262
263 if (count_zero) {
264 LOG(WARNING) << __func__ << ": unexcepted unremoved zero ref count, treating as missing.";
265 }
266
267 if (not_found || count_zero) {
268 mAudioFocusCount[request_key] = 1;
269 RequestAudioFocus(audio_usage, zone_id, focus_change);
270 } else {
271 ++ref_count_search->second;
272 }
273 }
274
HandleReleasing(aafc_session_id_t release_session)275 void AudioControlServerImpl::HandleReleasing(aafc_session_id_t release_session) {
276 const auto session_search = mSessionPool.find(release_session);
277 if (session_search == mSessionPool.end()) {
278 LOG(ERROR) << __func__ << ": unknown session ID: " << release_session;
279 return;
280 }
281 const auto& session_info = session_search->second;
282 const auto request_key = session_info.GetRequestKey();
283 const auto& [audio_usage, zone_id] = request_key;
284 mSessionPool.erase(session_search);
285 LOG(DEBUG) << __func__ << ": releasing: " << toString(static_cast<AudioUsage>(audio_usage))
286 << " " << zone_id;
287
288 const auto ref_count_search = mAudioFocusCount.find(request_key);
289 if (ref_count_search == mAudioFocusCount.end()) {
290 LOG(ERROR) << __func__ << ": unknown request, audio usage: "
291 << toString(static_cast<AudioUsage>(audio_usage)) << ", zone: " << zone_id;
292 return;
293 }
294 auto& request_ref_count = ref_count_search->second;
295 if (--request_ref_count == 0) {
296 AbandonAudioFocus(audio_usage, zone_id);
297 mAudioFocusCount.erase(ref_count_search);
298 }
299 }
300
RequestAudioFocus(aafc_audio_usage_t usage,aafc_zone_id_t zone,AudioFocusChange focus_change)301 void AudioControlServerImpl::RequestAudioFocus(aafc_audio_usage_t usage, aafc_zone_id_t zone,
302 AudioFocusChange focus_change) {
303 std::lock_guard<std::mutex> lock(mFocusListenerMutex);
304 auto listener = mFocusListener;
305 const auto audio_usage = static_cast<AudioUsage>(usage);
306 LOG(DEBUG) << __func__
307 << ": requesting focus, usage: " << toString(audio_usage)
308 << ", zone: " << zone
309 << ", focus change: " << toString(static_cast<AudioFocusChange>(focus_change));
310 if (!listener) {
311 LOG(ERROR) << __func__ << ": audio focus listener has not been registered.";
312 return;
313 }
314 listener->requestAudioFocus(toString(audio_usage), zone, focus_change);
315 }
316
AbandonAudioFocus(aafc_audio_usage_t usage,aafc_zone_id_t zone)317 void AudioControlServerImpl::AbandonAudioFocus(aafc_audio_usage_t usage, aafc_zone_id_t zone) {
318 std::lock_guard<std::mutex> lock(mFocusListenerMutex);
319 auto listener = mFocusListener;
320 const auto audio_usage = static_cast<AudioUsage>(usage);
321 LOG(DEBUG) << __func__
322 << ": abandoning focus, usage: " << toString(audio_usage)
323 << ", zone: " << zone;
324 if (!listener) {
325 LOG(ERROR) << __func__ << ": audio focus listener has not been registered.";
326 return;
327 }
328 listener->abandonAudioFocus(toString(audio_usage), zone);
329 }
330
CheckSessionHeartbeats(std::chrono::steady_clock::time_point current_timestamp)331 void AudioControlServerImpl::CheckSessionHeartbeats(
332 std::chrono::steady_clock::time_point current_timestamp) {
333 constexpr auto kSessionHeartbeatTimeout = 5s;
334 const auto timestamp_to_sec = [](auto&& timestamp) {
335 return std::chrono::duration_cast<std::chrono::duration<double>>(
336 timestamp.time_since_epoch())
337 .count();
338 };
339
340 constexpr size_t max_timeout_session_num = 256;
341 std::array<aafc_session_id_t, max_timeout_session_num> timeout_sessions;
342 size_t num_of_timeout_sessions = 0;
343
344 for (auto&& current_session : mSessionPool) {
345 const auto& current_session_id = current_session.first;
346 const auto& current_session_info = current_session.second;
347 if (current_session_info.mLastHeartbeat + kSessionHeartbeatTimeout < current_timestamp) {
348 if (num_of_timeout_sessions >= max_timeout_session_num) {
349 LOG(ERROR) << __func__ << ": timeout session number exceeds the limit: "
350 << max_timeout_session_num;
351 break;
352 }
353 LOG(WARNING) << __func__ << ": timeout on session " << current_session_id
354 << ", last heartbeat at "
355 << timestamp_to_sec(current_session_info.mLastHeartbeat)
356 << ", current timestamp is " << timestamp_to_sec(current_timestamp)
357 << ", timeout limit " << kSessionHeartbeatTimeout.count() << "s";
358 timeout_sessions[num_of_timeout_sessions++] = current_session_id;
359 }
360 }
361
362 for (int i = 0; i < num_of_timeout_sessions; ++i) {
363 HandleReleasing(timeout_sessions[i]);
364 }
365 }
366
367 AudioControlServerImpl::focus_listener_request_key_t
GetRequestKey() const368 AudioControlServerImpl::AudioFocusSession::GetRequestKey() const {
369 return {mRequest.audio_usage(), mRequest.zone_id()};
370 }
371
GetFocusChange() const372 AudioFocusChange AudioControlServerImpl::AudioFocusSession::GetFocusChange() const {
373 constexpr auto cast_to_bitfield = [](auto&& focus_change) {
374 return static_cast<AudioFocusChange>(focus_change);
375 };
376 if (!mRequest.is_transient()) {
377 return cast_to_bitfield(AudioFocusChange::GAIN);
378 }
379 if (mRequest.is_exclusive()) {
380 return cast_to_bitfield(AudioFocusChange::GAIN_TRANSIENT_EXCLUSIVE);
381 }
382 if (mRequest.allow_duck()) {
383 return cast_to_bitfield(AudioFocusChange::GAIN_TRANSIENT_MAY_DUCK);
384 }
385 return cast_to_bitfield(AudioFocusChange::GAIN_TRANSIENT);
386 }
387
MakeAudioControlServer(const std::string & addr)388 std::unique_ptr<AudioControlServer> MakeAudioControlServer(const std::string& addr) {
389 return std::make_unique<AudioControlServerImpl>(addr);
390 }
391
392 } // namespace aidl::android::hardware::automotive::audiocontrol
393