Cody Schuffelen | 134ff03 | 2019-11-22 00:25:32 -0800 | [diff] [blame^] | 1 | /* |
| 2 | * Copyright (C) 2016 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 | #include "guest/hals/audio/legacy/audio_hal.h" |
| 17 | |
| 18 | #include <inttypes.h> |
| 19 | #include <stdio.h> |
| 20 | #include <stdlib.h> |
| 21 | #include <sys/time.h> |
| 22 | #include <fcntl.h> |
| 23 | |
| 24 | extern "C" { |
| 25 | #include <cutils/str_parms.h> |
| 26 | } |
| 27 | |
| 28 | #include "common/libs/auto_resources/auto_resources.h" |
| 29 | #include "common/libs/fs/shared_select.h" |
| 30 | #include "common/libs/threads/cuttlefish_thread.h" |
| 31 | #include "common/libs/threads/thunkers.h" |
| 32 | #include "common/vsoc/lib/circqueue_impl.h" |
| 33 | #include "guest/hals/audio/legacy/vsoc_audio.h" |
| 34 | #include "guest/hals/audio/legacy/vsoc_audio_input_stream.h" |
| 35 | #include "guest/hals/audio/legacy/vsoc_audio_output_stream.h" |
| 36 | #include "guest/libs/remoter/remoter_framework_pkt.h" |
| 37 | |
| 38 | using cvd::LockGuard; |
| 39 | using cvd::Mutex; |
| 40 | |
| 41 | namespace cvd { |
| 42 | |
| 43 | GceAudio::~GceAudio() { } |
| 44 | |
| 45 | int GceAudio::Close() { |
| 46 | D("GceAudio::%s", __FUNCTION__); |
| 47 | { |
| 48 | LockGuard<Mutex> guard(lock_); |
| 49 | for (std::list<GceAudioOutputStream*>::iterator it = output_list_.begin(); |
| 50 | it != output_list_.end(); ++it) { |
| 51 | delete *it; |
| 52 | } |
| 53 | for (input_map_t::iterator it = input_map_.begin(); |
| 54 | it != input_map_.end(); ++it) { |
| 55 | delete it->second; |
| 56 | } |
| 57 | } |
| 58 | delete this; |
| 59 | return 0; |
| 60 | } |
| 61 | |
| 62 | size_t GceAudio::GetInputBufferSize(const audio_config*) const { |
| 63 | return IN_BUFFER_BYTES; |
| 64 | } |
| 65 | |
| 66 | uint32_t GceAudio::GetSupportedDevices() const { |
| 67 | return AUDIO_DEVICE_OUT_EARPIECE | |
| 68 | AUDIO_DEVICE_OUT_SPEAKER | |
| 69 | AUDIO_DEVICE_OUT_DEFAULT | |
| 70 | AUDIO_DEVICE_IN_COMMUNICATION | |
| 71 | AUDIO_DEVICE_IN_BUILTIN_MIC | |
| 72 | AUDIO_DEVICE_IN_WIRED_HEADSET | |
| 73 | AUDIO_DEVICE_IN_VOICE_CALL | |
| 74 | AUDIO_DEVICE_IN_DEFAULT; |
| 75 | } |
| 76 | |
| 77 | int GceAudio::InitCheck() const { |
| 78 | D("GceAudio::%s", __FUNCTION__); |
| 79 | return 0; |
| 80 | } |
| 81 | |
| 82 | int GceAudio::SetMicMute(bool state) { |
| 83 | D("GceAudio::%s", __FUNCTION__); |
| 84 | LockGuard<Mutex> guard(lock_); |
| 85 | mic_muted_ = state; |
| 86 | return 0; |
| 87 | } |
| 88 | |
| 89 | int GceAudio::GetMicMute(bool *state) const { |
| 90 | D("GceAudio::%s", __FUNCTION__); |
| 91 | LockGuard<Mutex> guard(lock_); |
| 92 | *state = mic_muted_; |
| 93 | return 0; |
| 94 | } |
| 95 | |
| 96 | int GceAudio::OpenInputStream(audio_io_handle_t handle, |
| 97 | audio_devices_t devices, |
| 98 | audio_config *config, |
| 99 | audio_stream_in **stream_in, |
| 100 | audio_input_flags_t /*flags*/, |
| 101 | const char * /*address*/, |
| 102 | audio_source_t /*source*/) { |
| 103 | GceAudioInputStream* new_stream; |
| 104 | int rval = GceAudioInputStream::Open( |
| 105 | this, handle, devices, *config, &new_stream); |
| 106 | uint32_t stream_number; |
| 107 | if (new_stream) { |
| 108 | LockGuard<Mutex> guard(lock_); |
| 109 | stream_number = next_stream_number_++; |
| 110 | input_map_[stream_number] = new_stream; |
| 111 | } |
| 112 | // This should happen after the lock is released, hence the double check |
| 113 | if (new_stream) { |
| 114 | SendStreamUpdate(new_stream->GetStreamDescriptor( |
| 115 | stream_number, gce_audio_message::OPEN_INPUT_STREAM), MSG_DONTWAIT); |
| 116 | } |
| 117 | *stream_in = new_stream; |
| 118 | return rval; |
| 119 | } |
| 120 | |
| 121 | |
| 122 | void GceAudio::CloseInputStream(audio_stream_in *stream) { |
| 123 | GceAudioInputStream* astream = static_cast<GceAudioInputStream*>(stream); |
| 124 | gce_audio_message descriptor; |
| 125 | { |
| 126 | LockGuard<Mutex> guard(lock_); |
| 127 | // TODO(ghartman): This could be optimized if stream knew it's number. |
| 128 | for (input_map_t::iterator it = input_map_.begin(); |
| 129 | it != input_map_.end(); ++it) { |
| 130 | if (it->second == stream) { |
| 131 | descriptor = it->second->GetStreamDescriptor( |
| 132 | it->first, gce_audio_message::CLOSE_INPUT_STREAM); |
| 133 | input_map_.erase(it); |
| 134 | break; |
| 135 | } |
| 136 | } |
| 137 | } |
| 138 | SendStreamUpdate(descriptor, MSG_DONTWAIT); |
| 139 | delete astream; |
| 140 | } |
| 141 | |
| 142 | |
| 143 | int GceAudio::OpenOutputStream(audio_io_handle_t handle, |
| 144 | audio_devices_t devices, |
| 145 | audio_output_flags_t flags, |
| 146 | audio_config *config, |
| 147 | audio_stream_out **stream_out, |
| 148 | const char * /*address*/) { |
| 149 | GceAudioOutputStream* new_stream; |
| 150 | int rval; |
| 151 | { |
| 152 | LockGuard<Mutex> guard(lock_); |
| 153 | rval = GceAudioOutputStream::Open( |
| 154 | this, handle, devices, flags, config, next_stream_number_++, |
| 155 | &new_stream); |
| 156 | if (new_stream) { |
| 157 | output_list_.push_back(new_stream); |
| 158 | } |
| 159 | } |
| 160 | if (new_stream) { |
| 161 | SendStreamUpdate(new_stream->GetStreamDescriptor( |
| 162 | gce_audio_message::OPEN_OUTPUT_STREAM), MSG_DONTWAIT); |
| 163 | } |
| 164 | *stream_out = new_stream; |
| 165 | return rval; |
| 166 | } |
| 167 | |
| 168 | void GceAudio::CloseOutputStream(audio_stream_out *stream) { |
| 169 | GceAudioOutputStream* astream = static_cast<GceAudioOutputStream*>(stream); |
| 170 | gce_audio_message close; |
| 171 | { |
| 172 | LockGuard<Mutex> guard(lock_); |
| 173 | output_list_.remove(astream); |
| 174 | close = astream->GetStreamDescriptor( |
| 175 | gce_audio_message::CLOSE_OUTPUT_STREAM); |
| 176 | } |
| 177 | SendStreamUpdate(close, MSG_DONTWAIT); |
| 178 | delete astream; |
| 179 | } |
| 180 | |
| 181 | int GceAudio::Dump(int fd) const { |
| 182 | LockGuard<Mutex> guard(lock_); |
| 183 | dprintf( |
| 184 | fd, |
| 185 | "\nadev_dump:\n" |
| 186 | "\tmic_mute: %s\n" |
| 187 | "\tnum_outputs: %zu\n" |
| 188 | "\tnum_inputs: %zu\n\n", |
| 189 | mic_muted_ ? "true": "false", |
| 190 | output_list_.size(), input_map_.size()); |
| 191 | |
| 192 | for (std::list<GceAudioOutputStream*>::const_iterator it = |
| 193 | output_list_.begin(); |
| 194 | it != output_list_.end(); ++it) { |
| 195 | (*it)->common.dump(&(*it)->common, fd); |
| 196 | } |
| 197 | |
| 198 | for (input_map_t::const_iterator it = input_map_.begin(); |
| 199 | it != input_map_.end(); ++it) { |
| 200 | (*it).second->common.dump(&(*it).second->common, fd); |
| 201 | } |
| 202 | |
| 203 | return 0; |
| 204 | } |
| 205 | |
| 206 | ssize_t GceAudio::SendMsg(const msghdr& msg, int /* flags */) { |
| 207 | intptr_t res = audio_data_rv_->data()->audio_queue.Writev( |
| 208 | audio_data_rv_, |
| 209 | msg.msg_iov, |
| 210 | msg.msg_iovlen, |
| 211 | true /* non_blocking */); |
| 212 | |
| 213 | if (res < 0) { |
| 214 | ALOGV("GceAudio::%s: CircularPacketQueue::Write returned %" PRIiPTR, |
| 215 | __FUNCTION__, |
| 216 | res); |
| 217 | } |
| 218 | |
| 219 | return static_cast<ssize_t>(res); |
| 220 | } |
| 221 | |
| 222 | ssize_t GceAudio::SendStreamUpdate( |
| 223 | const gce_audio_message& stream_info, int flags) { |
| 224 | msghdr msg; |
| 225 | iovec msg_iov[1]; |
| 226 | msg_iov[0].iov_base = const_cast<gce_audio_message*>(&stream_info); |
| 227 | msg_iov[0].iov_len = sizeof(gce_audio_message); |
| 228 | msg.msg_name = NULL; |
| 229 | msg.msg_namelen = 0; |
| 230 | msg.msg_iov = msg_iov; |
| 231 | msg.msg_iovlen = arraysize(msg_iov); |
| 232 | msg.msg_control = NULL; |
| 233 | msg.msg_controllen = 0; |
| 234 | msg.msg_flags = 0; |
| 235 | return SendMsg(msg, flags); |
| 236 | } |
| 237 | |
| 238 | int GceAudio::SetVoiceVolume(float volume) { |
| 239 | D("GceAudio::%s: set voice volume %f", __FUNCTION__, volume); |
| 240 | voice_volume_ = volume; |
| 241 | return 0; |
| 242 | } |
| 243 | |
| 244 | int GceAudio::SetMasterVolume(float volume) { |
| 245 | D("GceAudio::%s: set master volume %f", __FUNCTION__, volume); |
| 246 | master_volume_ = volume; |
| 247 | return 0; |
| 248 | } |
| 249 | |
| 250 | int GceAudio::GetMasterVolume(float* volume) { |
| 251 | D("GceAudio::%s: get master volume %f", __FUNCTION__, master_volume_); |
| 252 | *volume = master_volume_; |
| 253 | return 0; |
| 254 | } |
| 255 | |
| 256 | int GceAudio::SetMasterMute(bool muted) { |
| 257 | D("GceAudio::%s: set master muted %d", __FUNCTION__, muted); |
| 258 | master_muted_ = muted; |
| 259 | return 0; |
| 260 | } |
| 261 | |
| 262 | int GceAudio::GetMasterMute(bool* muted) { |
| 263 | D("GceAudio::%s: get master muted %d", __FUNCTION__, master_muted_); |
| 264 | *muted = master_muted_; |
| 265 | return 0; |
| 266 | } |
| 267 | |
| 268 | int GceAudio::SetMode(audio_mode_t mode) { |
| 269 | D("GceAudio::%s: new mode %d", __FUNCTION__, mode); |
| 270 | mode_ = mode; |
| 271 | return 0; |
| 272 | } |
| 273 | |
| 274 | int GceAudio::Open(const hw_module_t* module, const char* name, |
| 275 | hw_device_t** device) { |
| 276 | D("GceAudio::%s", __FUNCTION__); |
| 277 | |
| 278 | if (strcmp(name, AUDIO_HARDWARE_INTERFACE)) { |
| 279 | ALOGE("GceAudio::%s: invalid module name %s (expected %s)", |
| 280 | __FUNCTION__, name, AUDIO_HARDWARE_INTERFACE); |
| 281 | return -EINVAL; |
| 282 | } |
| 283 | |
| 284 | GceAudio* rval = new GceAudio; |
| 285 | |
| 286 | rval->audio_data_rv_ = AudioDataRegionView::GetInstance(); |
| 287 | rval->audio_worker_ = rval->audio_data_rv_->StartWorker(); |
| 288 | |
| 289 | rval->common.tag = HARDWARE_DEVICE_TAG; |
| 290 | rval->common.version = version_; |
| 291 | rval->common.module = const_cast<hw_module_t *>(module); |
| 292 | rval->common.close = cvd::thunk<hw_device_t, &GceAudio::Close>; |
| 293 | |
| 294 | #if !defined(AUDIO_DEVICE_API_VERSION_2_0) |
| 295 | // This HAL entry is supported only on AUDIO_DEVICE_API_VERSION_1_0. |
| 296 | // In fact, with version 2.0 the device numbers were orgainized in a |
| 297 | // way that makes the return value nonsense. |
| 298 | // Skipping the assignment is ok: the memset in the constructor already |
| 299 | // put a NULL here. |
| 300 | rval->get_supported_devices = |
| 301 | cvd::thunk<audio_hw_device, &GceAudio::GetSupportedDevices>; |
| 302 | #endif |
| 303 | rval->init_check = cvd::thunk<audio_hw_device, &GceAudio::InitCheck>; |
| 304 | |
| 305 | rval->set_voice_volume = |
| 306 | cvd::thunk<audio_hw_device, &GceAudio::SetVoiceVolume>; |
| 307 | rval->set_master_volume = |
| 308 | cvd::thunk<audio_hw_device, &GceAudio::SetMasterVolume>; |
| 309 | rval->get_master_volume = |
| 310 | cvd::thunk<audio_hw_device, &GceAudio::GetMasterVolume>; |
| 311 | |
| 312 | #if defined(AUDIO_DEVICE_API_VERSION_2_0) |
| 313 | rval->set_master_mute = |
| 314 | cvd::thunk<audio_hw_device, &GceAudio::SetMasterMute>; |
| 315 | rval->get_master_mute = |
| 316 | cvd::thunk<audio_hw_device, &GceAudio::GetMasterMute>; |
| 317 | #endif |
| 318 | |
| 319 | rval->set_mode = cvd::thunk<audio_hw_device, &GceAudio::SetMode>; |
| 320 | rval->set_mic_mute = cvd::thunk<audio_hw_device, &GceAudio::SetMicMute>; |
| 321 | rval->get_mic_mute = cvd::thunk<audio_hw_device, &GceAudio::GetMicMute>; |
| 322 | |
| 323 | rval->set_parameters = cvd::thunk<audio_hw_device, &GceAudio::SetParameters>; |
| 324 | rval->get_parameters = cvd::thunk<audio_hw_device, &GceAudio::GetParameters>; |
| 325 | |
| 326 | rval->get_input_buffer_size = |
| 327 | cvd::thunk<audio_hw_device, &GceAudio::GetInputBufferSize>; |
| 328 | |
| 329 | rval->open_input_stream = |
| 330 | cvd::thunk<audio_hw_device, &GceAudio::OpenInputStreamCurrentHAL>; |
| 331 | rval->close_input_stream = |
| 332 | cvd::thunk<audio_hw_device, &GceAudio::CloseInputStream>; |
| 333 | |
| 334 | rval->open_output_stream = |
| 335 | cvd::thunk<audio_hw_device, &GceAudio::OpenOutputStreamCurrentHAL>; |
| 336 | rval->close_output_stream = |
| 337 | cvd::thunk<audio_hw_device, &GceAudio::CloseOutputStream>; |
| 338 | |
| 339 | rval->dump = cvd::thunk<audio_hw_device, &GceAudio::Dump>; |
| 340 | |
| 341 | *device = &rval->common; |
| 342 | return 0; |
| 343 | } |
| 344 | |
| 345 | int GceAudio::SetParameters(const char *kvpairs) { |
| 346 | ALOGE("GceAudio::%s: not implemented", __FUNCTION__); |
| 347 | if (kvpairs) D("GceAudio::%s: kvpairs %s", __FUNCTION__, kvpairs); |
| 348 | return 0; |
| 349 | } |
| 350 | |
| 351 | |
| 352 | char* GceAudio::GetParameters(const char *keys) const { |
| 353 | ALOGE("GceAudio::%s: not implemented", __FUNCTION__); |
| 354 | if (keys) D("GceAudio::%s: kvpairs %s", __FUNCTION__, keys); |
| 355 | return strdup(""); |
| 356 | } |
| 357 | |
| 358 | int GceAudio::SetStreamParameters( |
| 359 | struct audio_stream *stream, const char *kv_pairs) { |
| 360 | struct str_parms *parms = str_parms_create_str(kv_pairs); |
| 361 | if (!parms) { |
| 362 | return 0; |
| 363 | } |
| 364 | int sample_rate; |
| 365 | if (str_parms_get_int(parms, AUDIO_PARAMETER_STREAM_SAMPLING_RATE, |
| 366 | &sample_rate) >= 0) { |
| 367 | stream->set_sample_rate(stream, sample_rate); |
| 368 | } |
| 369 | int format; |
| 370 | if (str_parms_get_int(parms, AUDIO_PARAMETER_STREAM_FORMAT, |
| 371 | &format) >= 0) { |
| 372 | stream->set_format(stream, static_cast<audio_format_t>(format)); |
| 373 | } |
| 374 | int routing; |
| 375 | if (str_parms_get_int(parms, AUDIO_PARAMETER_STREAM_ROUTING, |
| 376 | &routing) >= 0) { |
| 377 | stream->set_device(stream, static_cast<audio_devices_t>(routing)); |
| 378 | } |
| 379 | if (str_parms_get_int(parms, AUDIO_PARAMETER_STREAM_INPUT_SOURCE, |
| 380 | &routing) >= 0) { |
| 381 | stream->set_device(stream, static_cast<audio_devices_t>(routing)); |
| 382 | } |
| 383 | str_parms_destroy(parms); |
| 384 | return 0; |
| 385 | } |
| 386 | |
| 387 | } |