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 brillo_audio_client.h
17
18#include "brillo_audio_client.h"
19
20#include <base/logging.h>
21#include <binder/Status.h>
22#include <binderwrapper/binder_wrapper.h>
23
24#include "brillo_audio_client_helpers.h"
25#include "brillo_audio_device_info_def.h"
26#include "brillo_audio_device_info_internal.h"
27
28using android::binder::Status;
29
30namespace brillo {
31
32static const char kBrilloAudioServiceName[] =
33    "android.brillo.brilloaudioservice.BrilloAudioService";
34
35std::shared_ptr<BrilloAudioClient> BrilloAudioClient::instance_ = nullptr;
36
37int BrilloAudioClient::callback_id_counter_ = 1;
38
39BrilloAudioClient::~BrilloAudioClient() {}
40
41std::weak_ptr<BrilloAudioClient> BrilloAudioClient::GetClientInstance() {
42  if (!instance_) {
43    instance_ = std::shared_ptr<BrilloAudioClient>(new BrilloAudioClient());
44    if (!instance_->Initialize()) {
45      LOG(ERROR) << "Could not Initialize the brillo audio client.";
46      instance_.reset();
47      return instance_;
48    }
49  }
50  return instance_;
51}
52
53android::sp<android::IBinder> BrilloAudioClient::ConnectToService(
54    const std::string& service_name, const base::Closure& callback) {
55  android::BinderWrapper* binder_wrapper =
56      android::BinderWrapper::GetOrCreateInstance();
57  auto service = binder_wrapper->GetService(service_name);
58  if (!service.get()) {
59    return service;
60  }
61  binder_wrapper->RegisterForDeathNotifications(service, callback);
62  return service;
63}
64
65void BrilloAudioClient::OnBASDisconnect() {
66  LOG(WARNING) << "The brillo audio service died! Please reset the "
67               << "BAudioManager.";
68  instance_.reset();
69}
70
71bool BrilloAudioClient::Initialize() {
72  auto service = ConnectToService(
73      kBrilloAudioServiceName, base::Bind(&BrilloAudioClient::OnBASDisconnect,
74                                          weak_ptr_factory_.GetWeakPtr()));
75  if (!service.get()) {
76    LOG(ERROR) << "Could not connect to brillo audio service.";
77    return false;
78  }
79  brillo_audio_service_ = android::interface_cast<IBrilloAudioService>(service);
80  return true;
81}
82
83int BrilloAudioClient::GetDevices(int flag, std::vector<int>& devices) {
84  if (!brillo_audio_service_.get()) {
85    OnBASDisconnect();
86    return ECONNABORTED;
87  }
88  auto status = brillo_audio_service_->GetDevices(flag, &devices);
89  return status.serviceSpecificErrorCode();
90}
91
92int BrilloAudioClient::SetDevice(audio_policy_force_use_t usage,
93                                 audio_policy_forced_cfg_t config) {
94  if (!brillo_audio_service_.get()) {
95    OnBASDisconnect();
96    return ECONNABORTED;
97  }
98  auto status = brillo_audio_service_->SetDevice(usage, config);
99  return status.serviceSpecificErrorCode();
100}
101
102int BrilloAudioClient::GetMaxVolumeSteps(BAudioUsage usage, int* max_steps) {
103  if (!brillo_audio_service_.get()) {
104    OnBASDisconnect();
105    return ECONNABORTED;
106  }
107  auto status = brillo_audio_service_->GetMaxVolumeSteps(
108      BrilloAudioClientHelpers::GetStreamType(usage), max_steps);
109  return status.serviceSpecificErrorCode();
110}
111
112int BrilloAudioClient::SetMaxVolumeSteps(BAudioUsage usage, int max_steps) {
113  if (!brillo_audio_service_.get()) {
114    OnBASDisconnect();
115    return ECONNABORTED;
116  }
117  auto status = brillo_audio_service_->SetMaxVolumeSteps(
118      BrilloAudioClientHelpers::GetStreamType(usage), max_steps);
119  return status.serviceSpecificErrorCode();
120}
121
122int BrilloAudioClient::SetVolumeIndex(BAudioUsage usage,
123                                      audio_devices_t device,
124                                      int index) {
125  if (!brillo_audio_service_.get()) {
126    OnBASDisconnect();
127    return ECONNABORTED;
128  }
129  auto status = brillo_audio_service_->SetVolumeIndex(
130      BrilloAudioClientHelpers::GetStreamType(usage), device, index);
131  return status.serviceSpecificErrorCode();
132}
133
134int BrilloAudioClient::GetVolumeIndex(BAudioUsage usage,
135                                      audio_devices_t device,
136                                      int* index) {
137  if (!brillo_audio_service_.get()) {
138    OnBASDisconnect();
139    return ECONNABORTED;
140  }
141  auto status = brillo_audio_service_->GetVolumeIndex(
142      BrilloAudioClientHelpers::GetStreamType(usage), device, index);
143  return status.serviceSpecificErrorCode();
144}
145
146int BrilloAudioClient::GetVolumeControlStream(BAudioUsage* usage) {
147  if (!brillo_audio_service_.get()) {
148    OnBASDisconnect();
149    return ECONNABORTED;
150  }
151  int stream;
152  auto status = brillo_audio_service_->GetVolumeControlStream(&stream);
153  *usage = BrilloAudioClientHelpers::GetBAudioUsage(
154      static_cast<audio_stream_type_t>(stream));
155  return status.serviceSpecificErrorCode();
156}
157
158int BrilloAudioClient::SetVolumeControlStream(BAudioUsage usage) {
159  if (!brillo_audio_service_.get()) {
160    OnBASDisconnect();
161    return ECONNABORTED;
162  }
163  auto status = brillo_audio_service_->SetVolumeControlStream(
164      BrilloAudioClientHelpers::GetStreamType(usage));
165  return status.serviceSpecificErrorCode();
166}
167
168int BrilloAudioClient::IncrementVolume() {
169  if (!brillo_audio_service_.get()) {
170    OnBASDisconnect();
171    return ECONNABORTED;
172  }
173  auto status = brillo_audio_service_->IncrementVolume();
174  return status.serviceSpecificErrorCode();
175}
176
177int BrilloAudioClient::DecrementVolume() {
178  if (!brillo_audio_service_.get()) {
179    OnBASDisconnect();
180    return ECONNABORTED;
181  }
182  auto status = brillo_audio_service_->DecrementVolume();
183  return status.serviceSpecificErrorCode();
184}
185
186int BrilloAudioClient::RegisterAudioCallback(
187    android::sp<AudioServiceCallback> callback, int* callback_id) {
188  if (!brillo_audio_service_.get()) {
189    OnBASDisconnect();
190    return ECONNABORTED;
191  }
192  if (!brillo_audio_service_->RegisterServiceCallback(callback).isOk()) {
193    *callback_id = 0;
194    return ECONNABORTED;
195  }
196  for (auto& entry : callback_map_) {
197    if (entry.second->Equals(callback)) {
198      LOG(ERROR) << "Callback has already been registered.";
199      *callback_id = 0;
200      return EINVAL;
201    }
202  }
203  *callback_id = callback_id_counter_++;
204  callback_map_.emplace(*callback_id, callback);
205  return 0;
206}
207
208int BrilloAudioClient::UnregisterAudioCallback(int callback_id) {
209  if (!brillo_audio_service_.get()) {
210    OnBASDisconnect();
211    return ECONNABORTED;
212  }
213  auto callback_elem = callback_map_.find(callback_id);
214  if (callback_elem == callback_map_.end()) {
215    // If we were passed an invalid callback_id, do nothing.
216    LOG(ERROR) << "Unregister called with invalid callback ID.";
217    return EINVAL;
218  }
219  brillo_audio_service_->UnregisterServiceCallback(callback_elem->second.get());
220  callback_map_.erase(callback_elem);
221  return 0;
222}
223
224}  // namespace brillo
225