/* * Copyright (C) 2016 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 "guest/hals/audio/audio_hal.h" #include <inttypes.h> #include <stdio.h> #include <stdlib.h> #include <sys/time.h> #include <fcntl.h> extern "C" { #include <cutils/str_parms.h> } #include "common/libs/auto_resources/auto_resources.h" #include "common/libs/fs/shared_select.h" #include "common/libs/threads/cuttlefish_thread.h" #include "common/libs/threads/thunkers.h" #include "common/vsoc/lib/circqueue_impl.h" #include "guest/hals/audio/vsoc_audio.h" #include "guest/hals/audio/vsoc_audio_input_stream.h" #include "guest/hals/audio/vsoc_audio_output_stream.h" #include "guest/libs/platform_support/api_level_fixes.h" #include "guest/libs/remoter/remoter_framework_pkt.h" using cvd::LockGuard; using cvd::Mutex; namespace cvd { namespace { template <typename F> struct HWDeviceThunker : ThunkerBase<hw_device_t, GceAudio, F>{}; template <typename F> struct AudioThunker : ThunkerBase<audio_hw_device, GceAudio, F>{}; template <typename F> struct AudioThreadThunker : ThunkerBase<void, GceAudio, F>{}; } GceAudio::~GceAudio() { } int GceAudio::Close() { D("GceAudio::%s", __FUNCTION__); { LockGuard<Mutex> guard(lock_); for (std::list<GceAudioOutputStream*>::iterator it = output_list_.begin(); it != output_list_.end(); ++it) { delete *it; } for (input_map_t::iterator it = input_map_.begin(); it != input_map_.end(); ++it) { delete it->second; } } delete this; return 0; } size_t GceAudio::GetInputBufferSize(const audio_config*) const { return IN_BUFFER_BYTES; } uint32_t GceAudio::GetSupportedDevices() const { return AUDIO_DEVICE_OUT_EARPIECE | AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_DEFAULT | AUDIO_DEVICE_IN_COMMUNICATION | AUDIO_DEVICE_IN_BUILTIN_MIC | AUDIO_DEVICE_IN_WIRED_HEADSET | AUDIO_DEVICE_IN_VOICE_CALL | AUDIO_DEVICE_IN_DEFAULT; } int GceAudio::InitCheck() const { D("GceAudio::%s", __FUNCTION__); return 0; } int GceAudio::SetMicMute(bool state) { D("GceAudio::%s", __FUNCTION__); LockGuard<Mutex> guard(lock_); mic_muted_ = state; return 0; } int GceAudio::GetMicMute(bool *state) const { D("GceAudio::%s", __FUNCTION__); LockGuard<Mutex> guard(lock_); *state = mic_muted_; return 0; } int GceAudio::OpenInputStream(audio_io_handle_t handle, audio_devices_t devices, audio_config *config, audio_stream_in **stream_in, audio_input_flags_t /*flags*/, const char * /*address*/, audio_source_t /*source*/) { GceAudioInputStream* new_stream; int rval = GceAudioInputStream::Open( this, handle, devices, *config, &new_stream); uint32_t stream_number; if (new_stream) { LockGuard<Mutex> guard(lock_); stream_number = next_stream_number_++; input_map_[stream_number] = new_stream; } // This should happen after the lock is released, hence the double check if (new_stream) { SendStreamUpdate(new_stream->GetStreamDescriptor( stream_number, gce_audio_message::OPEN_INPUT_STREAM), MSG_DONTWAIT); } *stream_in = new_stream; return rval; } void GceAudio::CloseInputStream(audio_stream_in *stream) { GceAudioInputStream* astream = static_cast<GceAudioInputStream*>(stream); gce_audio_message descriptor; { LockGuard<Mutex> guard(lock_); // TODO(ghartman): This could be optimized if stream knew it's number. for (input_map_t::iterator it = input_map_.begin(); it != input_map_.end(); ++it) { if (it->second == stream) { descriptor = it->second->GetStreamDescriptor( it->first, gce_audio_message::CLOSE_INPUT_STREAM); input_map_.erase(it); break; } } } SendStreamUpdate(descriptor, MSG_DONTWAIT); delete astream; } int GceAudio::OpenOutputStream(audio_io_handle_t handle, audio_devices_t devices, audio_output_flags_t flags, audio_config *config, audio_stream_out **stream_out, const char * /*address*/) { GceAudioOutputStream* new_stream; int rval; { LockGuard<Mutex> guard(lock_); rval = GceAudioOutputStream::Open( this, handle, devices, flags, config, next_stream_number_++, &new_stream); if (new_stream) { output_list_.push_back(new_stream); } } if (new_stream) { SendStreamUpdate(new_stream->GetStreamDescriptor( gce_audio_message::OPEN_OUTPUT_STREAM), MSG_DONTWAIT); } *stream_out = new_stream; return rval; } void GceAudio::CloseOutputStream(audio_stream_out *stream) { GceAudioOutputStream* astream = static_cast<GceAudioOutputStream*>(stream); gce_audio_message close; { LockGuard<Mutex> guard(lock_); output_list_.remove(astream); close = astream->GetStreamDescriptor( gce_audio_message::CLOSE_OUTPUT_STREAM); } SendStreamUpdate(close, MSG_DONTWAIT); delete astream; } int GceAudio::Dump(int fd) const { LockGuard<Mutex> guard(lock_); VSOC_FDPRINTF( fd, "\nadev_dump:\n" "\tmic_mute: %s\n" "\tnum_outputs: %zu\n" "\tnum_inputs: %zu\n\n", mic_muted_ ? "true": "false", output_list_.size(), input_map_.size()); for (std::list<GceAudioOutputStream*>::const_iterator it = output_list_.begin(); it != output_list_.end(); ++it) { (*it)->common.dump(&(*it)->common, fd); } for (input_map_t::const_iterator it = input_map_.begin(); it != input_map_.end(); ++it) { (*it).second->common.dump(&(*it).second->common, fd); } return 0; } ssize_t GceAudio::SendMsg(const msghdr& msg, int /* flags */) { intptr_t res = audio_data_rv_->data()->audio_queue.Writev( audio_data_rv_, msg.msg_iov, msg.msg_iovlen, true /* non_blocking */); if (res < 0) { ALOGV("GceAudio::%s: CircularPacketQueue::Write returned %" PRIiPTR, __FUNCTION__, res); } return static_cast<ssize_t>(res); } ssize_t GceAudio::SendStreamUpdate( const gce_audio_message& stream_info, int flags) { msghdr msg; iovec msg_iov[1]; msg_iov[0].iov_base = const_cast<gce_audio_message*>(&stream_info); msg_iov[0].iov_len = sizeof(gce_audio_message); msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = msg_iov; msg.msg_iovlen = arraysize(msg_iov); msg.msg_control = NULL; msg.msg_controllen = 0; msg.msg_flags = 0; return SendMsg(msg, flags); } int GceAudio::SetVoiceVolume(float volume) { D("GceAudio::%s: set voice volume %f", __FUNCTION__, volume); voice_volume_ = volume; return 0; } int GceAudio::SetMasterVolume(float volume) { D("GceAudio::%s: set master volume %f", __FUNCTION__, volume); master_volume_ = volume; return 0; } int GceAudio::GetMasterVolume(float* volume) { D("GceAudio::%s: get master volume %f", __FUNCTION__, master_volume_); *volume = master_volume_; return 0; } int GceAudio::SetMasterMute(bool muted) { D("GceAudio::%s: set master muted %d", __FUNCTION__, muted); master_muted_ = muted; return 0; } int GceAudio::GetMasterMute(bool* muted) { D("GceAudio::%s: get master muted %d", __FUNCTION__, master_muted_); *muted = master_muted_; return 0; } int GceAudio::SetMode(audio_mode_t mode) { D("GceAudio::%s: new mode %d", __FUNCTION__, mode); mode_ = mode; return 0; } int GceAudio::Open(const hw_module_t* module, const char* name, hw_device_t** device) { D("GceAudio::%s", __FUNCTION__); if (strcmp(name, AUDIO_HARDWARE_INTERFACE)) { ALOGE("GceAudio::%s: invalid module name %s (expected %s)", __FUNCTION__, name, AUDIO_HARDWARE_INTERFACE); return -EINVAL; } GceAudio* rval = new GceAudio; rval->audio_data_rv_ = AudioDataRegionView::GetInstance(); rval->audio_worker_ = rval->audio_data_rv_->StartWorker(); rval->common.tag = HARDWARE_DEVICE_TAG; rval->common.version = version_; rval->common.module = const_cast<hw_module_t *>(module); rval->common.close = HWDeviceThunker<int()>::call<&GceAudio::Close>; #if !defined(AUDIO_DEVICE_API_VERSION_2_0) // This HAL entry is supported only on AUDIO_DEVICE_API_VERSION_1_0. // In fact, with version 2.0 the device numbers were orgainized in a // way that makes the return value nonsense. // Skipping the assignment is ok: the memset in the constructor already // put a NULL here. rval->get_supported_devices = AudioThunker<uint32_t()>::call<&GceAudio::GetSupportedDevices>; #endif rval->init_check = AudioThunker<int()>::call<&GceAudio::InitCheck>; rval->set_voice_volume = AudioThunker<int(float)>::call<&GceAudio::SetVoiceVolume>; rval->set_master_volume = AudioThunker<int(float)>::call<&GceAudio::SetMasterVolume>; rval->get_master_volume = AudioThunker<int(float*)>::call<&GceAudio::GetMasterVolume>; #if defined(AUDIO_DEVICE_API_VERSION_2_0) rval->set_master_mute = AudioThunker<int(bool)>::call<&GceAudio::SetMasterMute>; rval->get_master_mute = AudioThunker<int(bool*)>::call<&GceAudio::GetMasterMute>; #endif rval->set_mode = AudioThunker<int(audio_mode_t)>::call<&GceAudio::SetMode>; rval->set_mic_mute = AudioThunker<int(bool)>::call<&GceAudio::SetMicMute>; rval->get_mic_mute = AudioThunker<int(bool*)>::call<&GceAudio::GetMicMute>; rval->set_parameters = AudioThunker<int(const char*)>::call<&GceAudio::SetParameters>; rval->get_parameters = AudioThunker<char*(const char*)>::call<&GceAudio::GetParameters>; rval->get_input_buffer_size = AudioThunker<size_t(const audio_config*)>::call< &GceAudio::GetInputBufferSize>; rval->open_input_stream = AudioThunker<GceAudio::OpenInputStreamHAL_t>::call< &GceAudio::OpenInputStreamCurrentHAL>; rval->close_input_stream = AudioThunker<void(audio_stream_in*)>::call<&GceAudio::CloseInputStream>; rval->open_output_stream = AudioThunker<GceAudio::OpenOutputStreamHAL_t>::call< &GceAudio::OpenOutputStreamCurrentHAL>; rval->close_output_stream = AudioThunker<void(audio_stream_out*)>::call<&GceAudio::CloseOutputStream>; rval->dump = AudioThunker<int(int)>::call<&GceAudio::Dump>; *device = &rval->common; return 0; } int GceAudio::SetParameters(const char *kvpairs) { ALOGE("GceAudio::%s: not implemented", __FUNCTION__); if (kvpairs) D("GceAudio::%s: kvpairs %s", __FUNCTION__, kvpairs); return 0; } char* GceAudio::GetParameters(const char *keys) const { ALOGE("GceAudio::%s: not implemented", __FUNCTION__); if (keys) D("GceAudio::%s: kvpairs %s", __FUNCTION__, keys); return strdup(""); } int GceAudio::SetStreamParameters( struct audio_stream *stream, const char *kv_pairs) { struct str_parms *parms = str_parms_create_str(kv_pairs); if (!parms) { return 0; } int sample_rate; if (str_parms_get_int(parms, AUDIO_PARAMETER_STREAM_SAMPLING_RATE, &sample_rate) >= 0) { stream->set_sample_rate(stream, sample_rate); } int format; if (str_parms_get_int(parms, AUDIO_PARAMETER_STREAM_FORMAT, &format) >= 0) { stream->set_format(stream, static_cast<audio_format_t>(format)); } int routing; if (str_parms_get_int(parms, AUDIO_PARAMETER_STREAM_ROUTING, &routing) >= 0) { stream->set_device(stream, static_cast<audio_devices_t>(routing)); } if (str_parms_get_int(parms, AUDIO_PARAMETER_STREAM_INPUT_SOURCE, &routing) >= 0) { stream->set_device(stream, static_cast<audio_devices_t>(routing)); } str_parms_destroy(parms); return 0; } }