summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHao Chen <chenhaosjtuacm@google.com>2020-06-30 21:36:21 -0700
committerHao Chen <chenhaosjtuacm@google.com>2020-07-09 16:35:41 -0700
commit4a3edafb5591a1899b029edd9919acb28a0e2339 (patch)
treea93c0e69ca2481ff8115b3dae43463514a86c518
parent66d53b741fbce15bbc539d86e1c94667fb269b8d (diff)
downloaddevice_google_trout-4a3edafb5591a1899b029edd9919acb28a0e2339.tar.gz
device_google_trout-4a3edafb5591a1899b029edd9919acb28a0e2339.tar.bz2
device_google_trout-4a3edafb5591a1899b029edd9919acb28a0e2339.zip
Audio Control Server on Android Side Receiving Focus Requests
Test: Build; see pa/1722029 Bug: 141473213 Change-Id: Ic30061041da8fae5ab16d83ea10413c9ccb61de9
-rw-r--r--hal/audiocontrol/2.0/Android.bp76
-rw-r--r--hal/audiocontrol/2.0/AudioControlServer.cpp376
-rw-r--r--hal/audiocontrol/2.0/AudioControlServer.h42
-rw-r--r--hal/audiocontrol/2.0/libandroid_audio_controller/android_audio_controller.cpp36
-rw-r--r--hal/audiocontrol/2.0/libandroid_audio_controller/android_audio_controller.h7
-rw-r--r--hal/audiocontrol/2.0/proto/AudioFocusControl.proto1
6 files changed, 528 insertions, 10 deletions
diff --git a/hal/audiocontrol/2.0/Android.bp b/hal/audiocontrol/2.0/Android.bp
index 4f77ef6..e796929 100644
--- a/hal/audiocontrol/2.0/Android.bp
+++ b/hal/audiocontrol/2.0/Android.bp
@@ -14,9 +14,77 @@
* limitations under the License.
*/
+cc_defaults {
+ name: "audio_control_hal_v2_0_default_trout",
+ defaults: [
+ "hidl_defaults",
+ ],
+ shared_libs: [
+ "android.hardware.automotive.audiocontrol@2.0",
+ "libbase",
+ "libhidlbase",
+ "liblog",
+ "libutils",
+ ],
+}
+
+genrule {
+ name: "AudioFocusControlProtoStub_h",
+ tools: [
+ "aprotoc",
+ "protoc-gen-grpc-cpp-plugin",
+ ],
+ cmd: "$(location aprotoc) -I$$(dirname $(in)) -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)",
+ srcs: [
+ "proto/AudioFocusControl.proto",
+ ],
+ out: [
+ "AudioFocusControl.pb.h",
+ "AudioFocusControl.grpc.pb.h",
+ ],
+}
+
+genrule {
+ name: "AudioFocusControlProtoStub_cc",
+ tools: [
+ "aprotoc",
+ "protoc-gen-grpc-cpp-plugin",
+ ],
+ cmd: "$(location aprotoc) -I$$(dirname $(in)) -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)",
+ srcs: [
+ "proto/AudioFocusControl.proto",
+ ],
+ out: [
+ "AudioFocusControl.pb.cc",
+ "AudioFocusControl.grpc.pb.cc",
+ ],
+}
+
+cc_library {
+ name: "android.hardware.audiocontrol@2.0-service-audio-control-grpc-server",
+ vendor: true,
+ defaults: ["audio_control_hal_v2_0_default_trout"],
+ srcs: [
+ "AudioControlServer.cpp",
+ ],
+ generated_headers: [
+ "AudioFocusControlProtoStub_h",
+ ],
+ generated_sources: [
+ "AudioFocusControlProtoStub_cc",
+ ],
+ shared_libs: [
+ "libgrpc++",
+ "libprotobuf-cpp-full",
+ ],
+ cflags: [
+ "-Wno-unused-parameter",
+ ],
+}
+
cc_binary {
name: "android.hardware.audiocontrol@2.0-service.trout",
- defaults: ["hidl_defaults"],
+ defaults: ["audio_control_hal_v2_0_default_trout"],
vendor: true,
relative_install_path: "hw",
srcs: [
@@ -26,14 +94,10 @@ cc_binary {
],
init_rc: ["android.hardware.audiocontrol@2.0-service.trout.rc"],
shared_libs: [
- "android.hardware.automotive.audiocontrol@2.0",
+ "android.hardware.audiocontrol@2.0-service-audio-control-grpc-server",
"android.hardware.automotive.utils.watchdog",
"carwatchdog_aidl_interface-ndk_platform",
- "libbase",
"libbinder_ndk",
- "libhidlbase",
- "liblog",
- "libutils",
],
vintf_fragments: ["manifest_android.hardware.audiocontrol@2.0-service.trout.xml"],
}
diff --git a/hal/audiocontrol/2.0/AudioControlServer.cpp b/hal/audiocontrol/2.0/AudioControlServer.cpp
new file mode 100644
index 0000000..1452549
--- /dev/null
+++ b/hal/audiocontrol/2.0/AudioControlServer.cpp
@@ -0,0 +1,376 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "AudioControlServer.h"
+
+#include <deque>
+#include <string>
+#include <thread>
+
+#include <android-base/logging.h>
+#include <grpc++/grpc++.h>
+
+#include "AudioFocusControl.grpc.pb.h"
+#include "AudioFocusControl.pb.h"
+#include "libandroid_audio_controller/utils.h"
+
+using android::hardware::audio::common::V6_0::AudioUsage;
+using std::literals::chrono_literals::operator""s;
+
+namespace android::hardware::automotive::audiocontrol::V2_0::implementation {
+
+class AudioControlServerImpl : public AudioControlServer,
+ audio_focus_control_proto::AudioFocusControlServer::Service {
+ public:
+ explicit AudioControlServerImpl(const std::string& addr);
+
+ ~AudioControlServerImpl();
+
+ close_handle_func_t RegisterFocusListener(const sp<IFocusListener>& focusListener) override;
+
+ grpc::Status AudioRequests(::grpc::ServerContext* context,
+ const audio_focus_control_proto::AudioFocusControlMessage* message,
+ ::google::protobuf::Empty*) override;
+
+ void Start() override;
+
+ void Join() override;
+
+ private:
+ void RequestWorker();
+
+ void CheckSessionHeartbeats(std::chrono::steady_clock::time_point current_timestamp);
+
+ void HandleHeartbeat(aafc_session_id_t session,
+ std::chrono::steady_clock::time_point timestamp);
+
+ void HandleAcquiring(audio_focus_control_proto::AudioFocusRequest&& acquire_request,
+ std::chrono::steady_clock::time_point timestamp);
+
+ void HandleReleasing(aafc_session_id_t release_session);
+
+ void RequestAudioFocus(aafc_audio_usage_t usage, aafc_zone_id_t zone,
+ hidl_bitfield<AudioFocusChange> focus_change);
+
+ void AbandonAudioFocus(aafc_audio_usage_t usage, aafc_zone_id_t zone);
+
+ using grpc_request_t = audio_focus_control_proto::AudioFocusControlMessage;
+ using focus_listener_request_key_t = std::pair<aafc_audio_usage_t, aafc_zone_id_t>;
+
+ struct AudioFocusSession {
+ audio_focus_control_proto::AudioFocusRequest mRequest;
+ std::chrono::steady_clock::time_point mLastHeartbeat;
+
+ focus_listener_request_key_t GetRequestKey() const;
+ hidl_bitfield<AudioFocusChange> GetFocusChange() const;
+ };
+
+ using session_pool_t = std::map<aafc_session_id_t, AudioFocusSession>;
+
+ // data members
+
+ std::string mServiceAddr;
+ std::unique_ptr<::grpc::Server> mGrpcServer;
+ sp<IFocusListener> mFocusListener{nullptr};
+
+ // grpc request queue
+ std::deque<grpc_request_t> mRequestQueue;
+
+ // On the focus listener side, the usage/zone pair is used as the key,
+ // and acquiring focus multiple times on the same usage and zone will
+ // be treated as once, so we have to maintain the "sessions" and ref count
+ // by ourselves here.
+ //
+ // Active audio focus sessions from grpc clients
+ session_pool_t mSessionPool;
+
+ // ref counts of usage/zone pair
+ std::map<focus_listener_request_key_t, unsigned> mAudioFocusCount;
+
+ std::atomic<bool> mShutdownFlag{false};
+ std::thread mRequestWorker;
+
+ mutable std::mutex mFocusListenerMutex;
+ mutable std::mutex mRequestQueueMutex;
+
+ std::condition_variable mRequestQueueCV;
+};
+
+static std::shared_ptr<::grpc::ServerCredentials> getServerCredentials() {
+ // TODO(chenhaosjtuacm): get secured credentials here
+ return ::grpc::InsecureServerCredentials();
+}
+
+AudioControlServerImpl::AudioControlServerImpl(const std::string& addr) : mServiceAddr(addr) {}
+
+AudioControlServerImpl::~AudioControlServerImpl() {
+ mShutdownFlag.store(true);
+ if (mRequestWorker.joinable()) {
+ mRequestWorker.join();
+ }
+}
+
+AudioControlServer::close_handle_func_t AudioControlServerImpl::RegisterFocusListener(
+ const sp<IFocusListener>& focusListener) {
+ std::lock_guard<std::mutex> lock(mFocusListenerMutex);
+ mFocusListener = focusListener;
+
+ return [this, focusListener]() {
+ std::lock_guard<std::mutex> lock(mFocusListenerMutex);
+ if (mFocusListener == focusListener) {
+ mFocusListener = nullptr;
+ }
+ };
+}
+
+void AudioControlServerImpl::Start() {
+ if (mGrpcServer) {
+ LOG(WARNING) << __func__ << ": GRPC Server is running.";
+ return;
+ }
+
+ ::grpc::ServerBuilder builder;
+ builder.RegisterService(this);
+ builder.AddListeningPort(mServiceAddr, getServerCredentials());
+
+ mGrpcServer = builder.BuildAndStart();
+
+ CHECK(mGrpcServer) << __func__ << ": failed to create the GRPC server, "
+ << "please make sure the configuration and permissions are correct.";
+
+ mRequestWorker = std::thread(std::bind(&AudioControlServerImpl::RequestWorker, this));
+}
+
+void AudioControlServerImpl::Join() {
+ if (!mGrpcServer) {
+ LOG(WARNING) << __func__ << ": GRPC Server is not running.";
+ return;
+ }
+ mGrpcServer->Wait();
+}
+
+grpc::Status AudioControlServerImpl::AudioRequests(
+ ::grpc::ServerContext* context,
+ const audio_focus_control_proto::AudioFocusControlMessage* message,
+ ::google::protobuf::Empty*) {
+ {
+ std::lock_guard<std::mutex> lock(mRequestQueueMutex);
+ mRequestQueue.emplace_back(*message);
+ }
+ mRequestQueueCV.notify_all();
+ return ::grpc::Status::OK;
+}
+
+void AudioControlServerImpl::RequestWorker() {
+ constexpr auto kCheckHeartbeatFreq = 1s;
+ auto nextHeartbeatCheckTime = std::chrono::steady_clock::now();
+ while (!mShutdownFlag.load()) {
+ std::optional<grpc_request_t> message;
+ {
+ std::unique_lock<std::mutex> lock(mRequestQueueMutex);
+ if (mRequestQueue.empty()) {
+ mRequestQueueCV.wait_until(lock, nextHeartbeatCheckTime,
+ [this]() { return !mRequestQueue.empty(); });
+ }
+ if (!mRequestQueue.empty()) {
+ message = std::move(*mRequestQueue.begin());
+ mRequestQueue.pop_front();
+ }
+ }
+
+ auto current_timestamp = std::chrono::steady_clock::now();
+ if (message) {
+ for (auto&& active_session : message->active_sessions()) {
+ HandleHeartbeat(active_session, current_timestamp);
+ }
+
+ for (auto&& acquire_request : *message->mutable_acquire_requests()) {
+ HandleAcquiring(std::move(acquire_request), current_timestamp);
+ }
+
+ for (auto&& release_session : message->release_requests()) {
+ HandleReleasing(release_session);
+ }
+ }
+ if (current_timestamp >= nextHeartbeatCheckTime) {
+ nextHeartbeatCheckTime += kCheckHeartbeatFreq;
+ CheckSessionHeartbeats(current_timestamp);
+ }
+ }
+}
+
+void AudioControlServerImpl::HandleHeartbeat(aafc_session_id_t session,
+ std::chrono::steady_clock::time_point timestamp) {
+ auto session_search = mSessionPool.find(session);
+ if (session_search == mSessionPool.end()) {
+ LOG(ERROR) << __func__ << ": unknown session ID: " << session;
+ return;
+ }
+ auto& session_info = session_search->second;
+ session_info.mLastHeartbeat = timestamp;
+}
+
+void AudioControlServerImpl::HandleAcquiring(
+ audio_focus_control_proto::AudioFocusRequest&& acquire_request,
+ std::chrono::steady_clock::time_point timestamp) {
+ const auto session_id = acquire_request.session_id();
+ const auto session_emplace = mSessionPool.emplace(
+ session_id, AudioFocusSession{std::move(acquire_request), timestamp});
+ if (session_emplace.second == false) {
+ LOG(ERROR) << __func__ << ": duplicate session ID: " << session_id;
+ return;
+ }
+
+ const auto& session_emplace_iter = session_emplace.first;
+ const auto& session_info = session_emplace_iter->second;
+ const auto request_key = session_info.GetRequestKey();
+ const auto focus_change = session_info.GetFocusChange();
+ const auto ref_count_search = mAudioFocusCount.find(request_key);
+ const auto& [audio_usage, zone_id] = request_key;
+ LOG(DEBUG) << __func__ << ": acquiring: " << toString(static_cast<AudioUsage>(audio_usage))
+ << " " << zone_id << " " << focus_change;
+
+ const bool not_found = ref_count_search == mAudioFocusCount.end();
+ const bool count_zero = !not_found && ref_count_search->second == 0;
+
+ if (count_zero) {
+ LOG(WARNING) << __func__ << ": unexcepted unremoved zero ref count, treating as missing.";
+ }
+
+ if (not_found || count_zero) {
+ mAudioFocusCount[request_key] = 1;
+ RequestAudioFocus(audio_usage, zone_id, focus_change);
+ } else {
+ ++ref_count_search->second;
+ }
+}
+
+void AudioControlServerImpl::HandleReleasing(aafc_session_id_t release_session) {
+ const auto session_search = mSessionPool.find(release_session);
+ if (session_search == mSessionPool.end()) {
+ LOG(ERROR) << __func__ << ": unknown session ID: " << release_session;
+ return;
+ }
+ const auto& session_info = session_search->second;
+ const auto request_key = session_info.GetRequestKey();
+ const auto& [audio_usage, zone_id] = request_key;
+ mSessionPool.erase(session_search);
+ LOG(DEBUG) << __func__ << ": releasing: " << toString(static_cast<AudioUsage>(audio_usage))
+ << " " << zone_id;
+
+ const auto ref_count_search = mAudioFocusCount.find(request_key);
+ if (ref_count_search == mAudioFocusCount.end()) {
+ LOG(ERROR) << __func__ << ": unknown request, audio usage: "
+ << toString(static_cast<AudioUsage>(audio_usage)) << ", zone: " << zone_id;
+ return;
+ }
+ auto& request_ref_count = ref_count_search->second;
+ if (--request_ref_count == 0) {
+ AbandonAudioFocus(audio_usage, zone_id);
+ mAudioFocusCount.erase(ref_count_search);
+ }
+}
+
+void AudioControlServerImpl::RequestAudioFocus(aafc_audio_usage_t usage, aafc_zone_id_t zone,
+ hidl_bitfield<AudioFocusChange> focus_change) {
+ std::lock_guard<std::mutex> lock(mFocusListenerMutex);
+ auto listener = mFocusListener;
+ LOG(DEBUG) << __func__
+ << ": requesting focus, usage: " << toString(static_cast<AudioUsage>(usage))
+ << ", zone: " << zone
+ << ", focus change: " << toString(static_cast<AudioFocusChange>(focus_change));
+ if (!listener) {
+ LOG(ERROR) << __func__ << ": audio focus listener has not been registered.";
+ return;
+ }
+ listener->requestAudioFocus(usage, zone, focus_change);
+}
+
+void AudioControlServerImpl::AbandonAudioFocus(aafc_audio_usage_t usage, aafc_zone_id_t zone) {
+ std::lock_guard<std::mutex> lock(mFocusListenerMutex);
+ auto listener = mFocusListener;
+ LOG(DEBUG) << __func__
+ << ": abandoning focus, usage: " << toString(static_cast<AudioUsage>(usage))
+ << ", zone: " << zone;
+ if (!listener) {
+ LOG(ERROR) << __func__ << ": audio focus listener has not been registered.";
+ return;
+ }
+ listener->abandonAudioFocus(usage, zone);
+}
+
+void AudioControlServerImpl::CheckSessionHeartbeats(
+ std::chrono::steady_clock::time_point current_timestamp) {
+ constexpr auto kSessionHeartbeatTimeout = 5s;
+ const auto timestamp_to_sec = [](auto&& timestamp) {
+ return std::chrono::duration_cast<std::chrono::duration<double>>(
+ timestamp.time_since_epoch())
+ .count();
+ };
+
+ constexpr size_t max_timeout_session_num = 256;
+ std::array<aafc_session_id_t, max_timeout_session_num> timeout_sessions;
+ size_t num_of_timeout_sessions = 0;
+
+ for (auto&& current_session : mSessionPool) {
+ const auto& current_session_id = current_session.first;
+ const auto& current_session_info = current_session.second;
+ if (current_session_info.mLastHeartbeat + kSessionHeartbeatTimeout < current_timestamp) {
+ if (num_of_timeout_sessions >= max_timeout_session_num) {
+ LOG(ERROR) << __func__ << ": timeout session number exceeds the limit: "
+ << max_timeout_session_num;
+ break;
+ }
+ LOG(WARNING) << __func__ << ": timeout on session " << current_session_id
+ << ", last heartbeat at "
+ << timestamp_to_sec(current_session_info.mLastHeartbeat)
+ << ", current timestamp is " << timestamp_to_sec(current_timestamp)
+ << ", timeout limit " << kSessionHeartbeatTimeout.count() << "s";
+ timeout_sessions[num_of_timeout_sessions++] = current_session_id;
+ }
+ }
+
+ for (int i = 0; i < num_of_timeout_sessions; ++i) {
+ HandleReleasing(timeout_sessions[i]);
+ }
+}
+
+AudioControlServerImpl::focus_listener_request_key_t
+AudioControlServerImpl::AudioFocusSession::GetRequestKey() const {
+ return {mRequest.audio_usage(), mRequest.zone_id()};
+}
+
+hidl_bitfield<AudioFocusChange> AudioControlServerImpl::AudioFocusSession::GetFocusChange() const {
+ constexpr auto cast_to_bitfield = [](auto&& focus_change) {
+ return static_cast<hidl_bitfield<AudioFocusChange>>(focus_change);
+ };
+ if (!mRequest.is_transient()) {
+ return cast_to_bitfield(AudioFocusChange::GAIN);
+ }
+ if (mRequest.is_exclusive()) {
+ return cast_to_bitfield(AudioFocusChange::GAIN_TRANSIENT_EXCLUSIVE);
+ }
+ if (mRequest.allow_duck()) {
+ return cast_to_bitfield(AudioFocusChange::GAIN_TRANSIENT_MAY_DUCK);
+ }
+ return cast_to_bitfield(AudioFocusChange::GAIN_TRANSIENT);
+}
+
+std::unique_ptr<AudioControlServer> MakeAudioControlServer(const std::string& addr) {
+ return std::make_unique<AudioControlServerImpl>(addr);
+}
+
+} // namespace android::hardware::automotive::audiocontrol::V2_0::implementation
diff --git a/hal/audiocontrol/2.0/AudioControlServer.h b/hal/audiocontrol/2.0/AudioControlServer.h
new file mode 100644
index 0000000..b0cc60b
--- /dev/null
+++ b/hal/audiocontrol/2.0/AudioControlServer.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <functional>
+#include <memory>
+#include <string>
+
+#include <android/hardware/automotive/audiocontrol/2.0/IFocusListener.h>
+
+namespace android::hardware::automotive::audiocontrol::V2_0::implementation {
+
+class AudioControlServer {
+ public:
+ using close_handle_func_t = std::function<void()>;
+
+ virtual ~AudioControlServer() = default;
+
+ virtual close_handle_func_t RegisterFocusListener(const sp<IFocusListener>& focusListener) = 0;
+
+ virtual void Start() = 0;
+
+ virtual void Join() = 0;
+};
+
+std::unique_ptr<AudioControlServer> MakeAudioControlServer(const std::string& addr);
+
+} // namespace android::hardware::automotive::audiocontrol::V2_0::implementation
diff --git a/hal/audiocontrol/2.0/libandroid_audio_controller/android_audio_controller.cpp b/hal/audiocontrol/2.0/libandroid_audio_controller/android_audio_controller.cpp
index d68a3a6..ecfc8cc 100644
--- a/hal/audiocontrol/2.0/libandroid_audio_controller/android_audio_controller.cpp
+++ b/hal/audiocontrol/2.0/libandroid_audio_controller/android_audio_controller.cpp
@@ -16,7 +16,9 @@
#include "android_audio_controller.h"
-#include <cutils/threads.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
#include <chrono>
#include <condition_variable>
@@ -34,6 +36,16 @@ namespace android::hardware::automotive::audiocontrol::V2_0::implementation {
using std::literals::chrono_literals::operator""s;
+static pid_t getCurrentThreadID() {
+#ifdef gettid
+ return gettid();
+#elif defined(SYS_gettid)
+ return syscall(SYS_gettid);
+#else
+ return getpid();
+#endif
+}
+
class AudioFocusControllerImpl {
public:
static AudioFocusControllerImpl* GetInstance();
@@ -86,6 +98,23 @@ static std::shared_ptr<::grpc::ChannelCredentials> getChannelCredentials() {
return ::grpc::InsecureChannelCredentials();
}
+static void validateRequest(aafc_audio_focus_request_t* request) {
+ if (!request) {
+ std::cerr << "Validate null request is a no-op";
+ return;
+ }
+ if (!request->is_transient && (request->allow_duck || request->is_exclusive)) {
+ std::cerr << "If request is not transient, allow_duck and "
+ "exclusive options will be ignored."
+ << std::endl;
+ } else if (request->allow_duck && request->is_exclusive) {
+ std::cerr << "allow_duck and is_exclusive cannot be set together, "
+ "disabled ducking."
+ << std::endl;
+ request->allow_duck = false;
+ }
+}
+
AudioFocusControllerImpl::AudioFocusControllerImpl()
: mRequestWorkerThread(std::bind(&AudioFocusControllerImpl::RequestWorker, this)) {}
@@ -120,7 +149,7 @@ AudioFocusControllerImpl* AudioFocusControllerImpl::GetInstance() {
}
aafc_session_id_t AudioFocusControllerImpl::GetNewUniqueSessionID() {
- static const auto tid = static_cast<uint64_t>(gettid());
+ static const auto tid = static_cast<uint64_t>(getCurrentThreadID());
// 48 bits for timestamp (in nanoseconds), so a session ID
// within a thread is guaranteed not to reappear in about 3 days,
@@ -139,6 +168,8 @@ aafc_session_id_t AudioFocusControllerImpl::GetNewUniqueSessionID() {
}
aafc_session_id_t AudioFocusControllerImpl::AcquireFocus(aafc_audio_focus_request_t&& request) {
+ validateRequest(&request);
+
auto session_id = AAFC_SESSION_ID_INVALID;
{
@@ -226,6 +257,7 @@ void AudioFocusControllerImpl::RequestWorker() {
acquire_request.set_zone_id(request.request.zone_id);
acquire_request.set_allow_duck(request.request.allow_duck);
acquire_request.set_is_transient(request.request.is_transient);
+ acquire_request.set_is_exclusive(request.request.is_exclusive);
}
for (auto session_id : mSessionsReleaseRequests) {
audio_requests.add_release_requests(session_id);
diff --git a/hal/audiocontrol/2.0/libandroid_audio_controller/android_audio_controller.h b/hal/audiocontrol/2.0/libandroid_audio_controller/android_audio_controller.h
index ee44317..2d5311d 100644
--- a/hal/audiocontrol/2.0/libandroid_audio_controller/android_audio_controller.h
+++ b/hal/audiocontrol/2.0/libandroid_audio_controller/android_audio_controller.h
@@ -16,6 +16,8 @@
#pragma once
+#include <stdbool.h>
+
#include "utils.h"
#ifdef __cplusplus
@@ -25,8 +27,9 @@ extern "C" {
typedef struct {
aafc_audio_usage_t audio_usage;
aafc_zone_id_t zone_id;
- int allow_duck;
- int is_transient;
+ bool allow_duck;
+ bool is_transient;
+ bool is_exclusive;
} aafc_audio_focus_request_t;
/* Initialize the audio focus controller before using, return 0 when success.
diff --git a/hal/audiocontrol/2.0/proto/AudioFocusControl.proto b/hal/audiocontrol/2.0/proto/AudioFocusControl.proto
index 1887cae..04db33d 100644
--- a/hal/audiocontrol/2.0/proto/AudioFocusControl.proto
+++ b/hal/audiocontrol/2.0/proto/AudioFocusControl.proto
@@ -26,6 +26,7 @@ message AudioFocusRequest {
int32 zone_id = 3;
bool allow_duck = 4;
bool is_transient = 5;
+ bool is_exclusive = 6;
}
message AudioFocusControlMessage {