From 10548295023bee99108e418499aff09fe578211e Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Mon, 31 Oct 2016 10:39:47 -0700 Subject: [PATCH] Implement audio devices and streams HAL delegating to legacy HAL Changes made to the .hal definition: - introduce Effect ID returned by the IEffectsFactory that needs to be passed to IStream.{add|remove}Effect; otherwise it's impossible to retrieve the underlying HAL effect handle; - change "bus address" in DeviceAddress to "string" type; - fix signature of some methods w.r.t. returning Result; - remove unused "struct AudioPatch". Bug: 30222631 Test: make Change-Id: Icb51729ef57bb2a5b0b78609735e7481bc04f95c --- audio/2.0/IDevice.hal | 11 +- audio/2.0/IStream.hal | 13 +- audio/2.0/IStreamIn.hal | 3 +- audio/2.0/IStreamOut.hal | 10 +- audio/2.0/default/Android.mk | 49 +- audio/2.0/default/Conversions.cpp | 63 +++ audio/2.0/default/Conversions.h | 41 ++ audio/2.0/default/Device.cpp | 534 ++++++++++++++++++ audio/2.0/default/Device.h | 147 +++++ audio/2.0/default/DevicesFactory.cpp | 103 ++++ audio/2.0/default/DevicesFactory.h | 59 ++ audio/2.0/default/ParametersUtil.cpp | 134 +++++ audio/2.0/default/ParametersUtil.h | 66 +++ audio/2.0/default/PrimaryDevice.cpp | 189 +++++++ audio/2.0/default/PrimaryDevice.h | 117 ++++ audio/2.0/default/Stream.cpp | 236 ++++++++ audio/2.0/default/Stream.h | 94 +++ audio/2.0/default/StreamIn.cpp | 191 +++++++ audio/2.0/default/StreamIn.h | 98 ++++ audio/2.0/default/StreamOut.cpp | 275 +++++++++ audio/2.0/default/StreamOut.h | 113 ++++ audio/2.0/default/service.cpp | 27 +- audio/2.0/types.hal | 2 +- audio/common/2.0/default/Android.mk | 29 + audio/common/2.0/default/EffectMap.cpp | 57 ++ audio/common/2.0/default/EffectMap.h | 46 ++ audio/common/2.0/types.hal | 20 +- audio/effect/2.0/IEffectsFactory.hal | 4 +- audio/effect/2.0/default/Android.mk | 1 + audio/effect/2.0/default/Effect.cpp | 2 + audio/effect/2.0/default/EffectsFactory.cpp | 7 +- .../functional/audio_effect_hidl_hal_test.cpp | 15 +- 32 files changed, 2688 insertions(+), 68 deletions(-) create mode 100644 audio/2.0/default/Conversions.cpp create mode 100644 audio/2.0/default/Conversions.h create mode 100644 audio/2.0/default/Device.cpp create mode 100644 audio/2.0/default/Device.h create mode 100644 audio/2.0/default/DevicesFactory.cpp create mode 100644 audio/2.0/default/DevicesFactory.h create mode 100644 audio/2.0/default/ParametersUtil.cpp create mode 100644 audio/2.0/default/ParametersUtil.h create mode 100644 audio/2.0/default/PrimaryDevice.cpp create mode 100644 audio/2.0/default/PrimaryDevice.h create mode 100644 audio/2.0/default/Stream.cpp create mode 100644 audio/2.0/default/Stream.h create mode 100644 audio/2.0/default/StreamIn.cpp create mode 100644 audio/2.0/default/StreamIn.h create mode 100644 audio/2.0/default/StreamOut.cpp create mode 100644 audio/2.0/default/StreamOut.h create mode 100644 audio/common/2.0/default/Android.mk create mode 100644 audio/common/2.0/default/EffectMap.cpp create mode 100644 audio/common/2.0/default/EffectMap.h diff --git a/audio/2.0/IDevice.hal b/audio/2.0/IDevice.hal index 84e0d28aed..38bfe211a4 100644 --- a/audio/2.0/IDevice.hal +++ b/audio/2.0/IDevice.hal @@ -180,19 +180,20 @@ interface IDevice { /* * Gets the HW synchronization source of the device. Calling this method is - * equivalent to getting AUDIO_PARAMETER_STREAM_HW_AV_SYNC on the legacy - * HAL. + * equivalent to getting AUDIO_PARAMETER_HW_AV_SYNC on the legacy HAL. * - * @return retval operation completion status. * @return hwAvSync HW synchronization source */ - getHwAvSync() generates (Result retval, AudioHwSync hwAvSync); + getHwAvSync() generates (AudioHwSync hwAvSync); /* * Sets whether the screen is on. Calling this method is equivalent to * setting AUDIO_PARAMETER_KEY_SCREEN_STATE on the legacy HAL. + * + * @param turnedOn whether the screen is turned on. + * @return retval operation completion status. */ - setScreenState(bool turnedOn); + setScreenState(bool turnedOn) generates (Result retval); /* * Generic method for retrieving vendor-specific parameter values. diff --git a/audio/2.0/IStream.hal b/audio/2.0/IStream.hal index 09ba42a557..dc43346ed2 100644 --- a/audio/2.0/IStream.hal +++ b/audio/2.0/IStream.hal @@ -134,18 +134,20 @@ interface IStream { /* * Applies audio effect to the stream. * - * @param effect the effect to apply. + * @param effectId effect ID (obtained from IEffectsFactory.createEffect) of + * the effect to apply. * @return retval operation completion status. */ - addEffect(IEffect effect) generates (Result retval); + addEffect(uint64_t effectId) generates (Result retval); /* * Stops application of the effect to the stream. * - * @param effect the effect to apply. + * @param effectId effect ID (obtained from IEffectsFactory.createEffect) of + * the effect to remove. * @return retval operation completion status. */ - removeEffect(IEffect effect) generates (Result retval); + removeEffect(uint64_t effectId) generates (Result retval); /* * Put the audio hardware input/output into standby mode. @@ -158,10 +160,9 @@ interface IStream { /* * Return the set of device(s) which this stream is connected to. * - * @return retval operation completion status. * @return device set of device(s) which this stream is connected to. */ - getDevice() generates (Result retval, AudioDevice device); + getDevice() generates (AudioDevice device); /* * Connects the stream to the device. diff --git a/audio/2.0/IStreamIn.hal b/audio/2.0/IStreamIn.hal index 049df75b8d..6cf7425910 100644 --- a/audio/2.0/IStreamIn.hal +++ b/audio/2.0/IStreamIn.hal @@ -61,10 +61,9 @@ interface IStreamIn extends IStream { * typically occurs when the user space process is blocked longer than the * capacity of audio driver buffers. * - * @return retval operation completion status. * @return framesLost the number of input audio frames lost. */ - getInputFramesLost() generates (Result retval, uint32_t framesLost); + getInputFramesLost() generates (uint32_t framesLost); /** * Return a recent count of the number of audio frames received and the diff --git a/audio/2.0/IStreamOut.hal b/audio/2.0/IStreamOut.hal index adce5382a7..55a852d1ca 100644 --- a/audio/2.0/IStreamOut.hal +++ b/audio/2.0/IStreamOut.hal @@ -142,12 +142,12 @@ interface IStreamOut extends IStream { * 'setCallback' has not been called, then 'drain' must block until * completion. * - * If 'type' is 'AUDIO_DRAIN_ALL', the drain completes when all previously - * written data has been played. + * If 'type' is 'ALL', the drain completes when all previously written data + * has been played. * - * If 'type' is 'AUDIO_DRAIN_EARLY_NOTIFY', the drain completes shortly - * before all data for the current track has played to allow time for the - * framework to perform a gapless track switch. + * If 'type' is 'EARLY_NOTIFY', the drain completes shortly before all data + * for the current track has played to allow time for the framework to + * perform a gapless track switch. * * Drain must return immediately on 'stop' and 'flush' calls. * diff --git a/audio/2.0/default/Android.mk b/audio/2.0/default/Android.mk index a987b41a97..a5c0383cb5 100644 --- a/audio/2.0/default/Android.mk +++ b/audio/2.0/default/Android.mk @@ -16,21 +16,54 @@ LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.audio@2.0-impl +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_SRC_FILES := \ + Conversions.cpp \ + Device.cpp \ + DevicesFactory.cpp \ + ParametersUtil.cpp \ + PrimaryDevice.cpp \ + Stream.cpp \ + StreamIn.cpp \ + StreamOut.cpp \ + +LOCAL_SHARED_LIBRARIES := \ + libhidl \ + libhwbinder \ + libutils \ + libhardware \ + liblog \ + android.hardware.audio@2.0 \ + android.hardware.audio.common@2.0 \ + android.hardware.audio.common@2.0-util \ + +LOCAL_WHOLE_STATIC_LIBRARIES := libmedia_helper + +include $(BUILD_SHARED_LIBRARY) + +# +# Service +# + include $(CLEAR_VARS) LOCAL_MODULE := android.hardware.audio@2.0-service LOCAL_INIT_RC := android.hardware.audio@2.0-service.rc LOCAL_MODULE_RELATIVE_PATH := hw LOCAL_SRC_FILES := \ - service.cpp + service.cpp LOCAL_SHARED_LIBRARIES := \ - libhidl \ - liblog \ - libhwbinder \ - libutils \ - libhardware \ - android.hardware.soundtrigger@2.0 \ - android.hardware.audio.common@2.0 + libhidl \ + liblog \ + libhwbinder \ + libutils \ + libhardware \ + android.hardware.audio@2.0 \ + android.hardware.audio.common@2.0 \ + android.hardware.audio.effect@2.0 \ + android.hardware.soundtrigger@2.0 \ ifeq ($(strip $(AUDIOSERVER_MULTILIB)),) LOCAL_MULTILIB := 32 diff --git a/audio/2.0/default/Conversions.cpp b/audio/2.0/default/Conversions.cpp new file mode 100644 index 0000000000..1ba16e1c61 --- /dev/null +++ b/audio/2.0/default/Conversions.cpp @@ -0,0 +1,63 @@ +/* + * 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 + +#include "Conversions.h" + +namespace android { +namespace hardware { +namespace audio { +namespace V2_0 { +namespace implementation { + +std::string deviceAddressToHal(const DeviceAddress& address) { + // HAL assumes that the address is NUL-terminated. + char halAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN]; + memset(halAddress, 0, sizeof(halAddress)); + uint32_t halDevice = static_cast(address.device); + if ((halDevice & AUDIO_DEVICE_OUT_ALL_A2DP) != 0 + || (halDevice & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) != 0) { + snprintf(halAddress, sizeof(halAddress), + "%02X:%02X:%02X:%02X:%02X:%02X", + address.address.mac[0], address.address.mac[1], address.address.mac[2], + address.address.mac[3], address.address.mac[4], address.address.mac[5]); + } else if ((halDevice & AUDIO_DEVICE_OUT_IP) != 0 || (halDevice & AUDIO_DEVICE_IN_IP) != 0) { + snprintf(halAddress, sizeof(halAddress), + "%d.%d.%d.%d", + address.address.ipv4[0], address.address.ipv4[1], + address.address.ipv4[2], address.address.ipv4[3]); + } else if ((halDevice & AUDIO_DEVICE_OUT_ALL_USB) != 0 + || (halDevice & AUDIO_DEVICE_IN_ALL_USB) != 0) { + snprintf(halAddress, sizeof(halAddress), + "card=%d;device=%d", + address.address.alsa.card, address.address.alsa.device); + } else if ((halDevice & AUDIO_DEVICE_OUT_BUS) != 0 || (halDevice & AUDIO_DEVICE_IN_BUS) != 0) { + snprintf(halAddress, sizeof(halAddress), + "%s", address.busAddress.c_str()); + } else if ((halDevice & AUDIO_DEVICE_OUT_REMOTE_SUBMIX) != 0 + || (halDevice & AUDIO_DEVICE_IN_REMOTE_SUBMIX) != 0) { + snprintf(halAddress, sizeof(halAddress), + "%s", address.rSubmixAddress.c_str()); + } + return halAddress; +} + +} // namespace implementation +} // namespace V2_0 +} // namespace audio +} // namespace hardware +} // namespace android diff --git a/audio/2.0/default/Conversions.h b/audio/2.0/default/Conversions.h new file mode 100644 index 0000000000..ebda5c572c --- /dev/null +++ b/audio/2.0/default/Conversions.h @@ -0,0 +1,41 @@ +/* + * 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. + */ + +#ifndef android_hardware_audio_V2_0_Conversions_H_ +#define android_hardware_audio_V2_0_Conversions_H_ + +#include + +#include +#include + +namespace android { +namespace hardware { +namespace audio { +namespace V2_0 { +namespace implementation { + +using ::android::hardware::audio::V2_0::DeviceAddress; + +std::string deviceAddressToHal(const DeviceAddress& address); + +} // namespace implementation +} // namespace V2_0 +} // namespace audio +} // namespace hardware +} // namespace android + +#endif // android_hardware_audio_V2_0_Conversions_H_ diff --git a/audio/2.0/default/Device.cpp b/audio/2.0/default/Device.cpp new file mode 100644 index 0000000000..05824c7fc5 --- /dev/null +++ b/audio/2.0/default/Device.cpp @@ -0,0 +1,534 @@ + /* + * 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. + */ + +#define LOG_TAG "DeviceHAL" + +#include +#include +#include + +#include + +#include "Conversions.h" +#include "Device.h" +#include "StreamIn.h" +#include "StreamOut.h" + +namespace android { +namespace hardware { +namespace audio { +namespace V2_0 { +namespace implementation { + +Device::Device(audio_hw_device_t* device) + : mDevice(device) { +} + +Device::~Device() { + int status = audio_hw_device_close(mDevice); + ALOGW_IF(status, "Error closing audio hw device %p: %s", mDevice, strerror(-status)); + mDevice = nullptr; +} + +// static +void Device::audioConfigToHal(const AudioConfig& config, audio_config_t* halConfig) { + memset(halConfig, 0, sizeof(audio_config_t)); + halConfig->sample_rate = config.sampleRateHz; + halConfig->channel_mask = static_cast(config.channelMask); + halConfig->format = static_cast(config.format); + audioOffloadInfoToHal(config.offloadInfo, &halConfig->offload_info); + halConfig->frame_count = config.frameCount; +} + +// static +void Device::audioGainConfigFromHal( + const struct audio_gain_config& halConfig, AudioGainConfig* config) { + config->index = halConfig.index; + config->mode = AudioGainMode(halConfig.mode); + config->channelMask = AudioChannelMask(halConfig.channel_mask); + for (size_t i = 0; i < sizeof(audio_channel_mask_t) * 8; ++i) { + config->values[i] = halConfig.values[i]; + } + config->rampDurationMs = halConfig.ramp_duration_ms; +} + +// static +void Device::audioGainConfigToHal( + const AudioGainConfig& config, struct audio_gain_config* halConfig) { + halConfig->index = config.index; + halConfig->mode = static_cast(config.mode); + halConfig->channel_mask = static_cast(config.channelMask); + memset(halConfig->values, 0, sizeof(halConfig->values)); + for (size_t i = 0; i < sizeof(audio_channel_mask_t) * 8; ++i) { + halConfig->values[i] = config.values[i]; + } + halConfig->ramp_duration_ms = config.rampDurationMs; +} + +// static +void Device::audioGainFromHal(const struct audio_gain& halGain, AudioGain* gain) { + gain->mode = AudioGainMode(halGain.mode); + gain->channelMask = AudioChannelMask(halGain.channel_mask); + gain->minValue = halGain.min_value; + gain->maxValue = halGain.max_value; + gain->defaultValue = halGain.default_value; + gain->stepValue = halGain.step_value; + gain->minRampMs = halGain.min_ramp_ms; + gain->maxRampMs = halGain.max_ramp_ms; +} + +// static +void Device::audioGainToHal(const AudioGain& gain, struct audio_gain* halGain) { + halGain->mode = static_cast(gain.mode); + halGain->channel_mask = static_cast(gain.channelMask); + halGain->min_value = gain.minValue; + halGain->max_value = gain.maxValue; + halGain->default_value = gain.defaultValue; + halGain->step_value = gain.stepValue; + halGain->min_ramp_ms = gain.minRampMs; + halGain->max_ramp_ms = gain.maxRampMs; +} + +// static +void Device::audioOffloadInfoToHal( + const AudioOffloadInfo& offload, audio_offload_info_t* halOffload) { + *halOffload = AUDIO_INFO_INITIALIZER; + halOffload->sample_rate = offload.sampleRateHz; + halOffload->channel_mask = static_cast(offload.channelMask); + halOffload->stream_type = static_cast(offload.streamType); + halOffload->bit_rate = offload.bitRatePerSecond; + halOffload->duration_us = offload.durationMicroseconds; + halOffload->has_video = offload.hasVideo; + halOffload->is_streaming = offload.isStreaming; +} + +// static +void Device::audioPortConfigFromHal( + const struct audio_port_config& halConfig, AudioPortConfig* config) { + config->id = halConfig.id; + config->role = AudioPortRole(halConfig.role); + config->type = AudioPortType(halConfig.type); + config->configMask = AudioPortConfigMask(halConfig.config_mask); + config->sampleRateHz = halConfig.sample_rate; + config->channelMask = AudioChannelMask(halConfig.channel_mask); + config->format = AudioFormat(halConfig.format); + audioGainConfigFromHal(halConfig.gain, &config->gain); + switch (halConfig.type) { + case AUDIO_PORT_TYPE_NONE: break; + case AUDIO_PORT_TYPE_DEVICE: { + config->ext.device.hwModule = halConfig.ext.device.hw_module; + config->ext.device.type = AudioDevice(halConfig.ext.device.type); + memcpy(config->ext.device.address.data(), + halConfig.ext.device.address, + AUDIO_DEVICE_MAX_ADDRESS_LEN); + break; + } + case AUDIO_PORT_TYPE_MIX: { + config->ext.mix.hwModule = halConfig.ext.mix.hw_module; + config->ext.mix.ioHandle = halConfig.ext.mix.handle; + if (halConfig.role == AUDIO_PORT_ROLE_SOURCE) { + config->ext.mix.useCase.source = AudioSource(halConfig.ext.mix.usecase.source); + } else if (halConfig.role == AUDIO_PORT_ROLE_SINK) { + config->ext.mix.useCase.stream = AudioStreamType(halConfig.ext.mix.usecase.stream); + } + break; + } + case AUDIO_PORT_TYPE_SESSION: { + config->ext.session.session = halConfig.ext.session.session; + break; + } + } +} + +// static +void Device::audioPortConfigToHal( + const AudioPortConfig& config, struct audio_port_config* halConfig) { + memset(halConfig, 0, sizeof(audio_port_config)); + halConfig->id = config.id; + halConfig->role = static_cast(config.role); + halConfig->type = static_cast(config.type); + halConfig->config_mask = static_cast(config.configMask); + halConfig->sample_rate = config.sampleRateHz; + halConfig->channel_mask = static_cast(config.channelMask); + halConfig->format = static_cast(config.format); + audioGainConfigToHal(config.gain, &halConfig->gain); + switch (config.type) { + case AudioPortType::NONE: break; + case AudioPortType::DEVICE: { + halConfig->ext.device.hw_module = config.ext.device.hwModule; + halConfig->ext.device.type = static_cast(config.ext.device.type); + memcpy(halConfig->ext.device.address, + config.ext.device.address.data(), + AUDIO_DEVICE_MAX_ADDRESS_LEN); + break; + } + case AudioPortType::MIX: { + halConfig->ext.mix.hw_module = config.ext.mix.hwModule; + halConfig->ext.mix.handle = config.ext.mix.ioHandle; + if (config.role == AudioPortRole::SOURCE) { + halConfig->ext.mix.usecase.source = + static_cast(config.ext.mix.useCase.source); + } else if (config.role == AudioPortRole::SINK) { + halConfig->ext.mix.usecase.stream = + static_cast(config.ext.mix.useCase.stream); + } + break; + } + case AudioPortType::SESSION: { + halConfig->ext.session.session = + static_cast(config.ext.session.session); + break; + } + } +} + +// static +std::unique_ptr Device::audioPortConfigsToHal( + const hidl_vec& configs) { + std::unique_ptr halConfigs(new audio_port_config[configs.size()]); + for (size_t i = 0; i < configs.size(); ++i) { + audioPortConfigToHal(configs[i], &halConfigs[i]); + } + return halConfigs; +} + +// static +void Device::audioPortFromHal(const struct audio_port& halPort, AudioPort* port) { + port->id = halPort.id; + port->role = AudioPortRole(halPort.role); + port->type = AudioPortType(halPort.type); + port->name.setToExternal(halPort.name, strlen(halPort.name)); + port->sampleRates.resize(halPort.num_sample_rates); + for (size_t i = 0; i < halPort.num_sample_rates; ++i) { + port->sampleRates[i] = halPort.sample_rates[i]; + } + port->channelMasks.resize(halPort.num_channel_masks); + for (size_t i = 0; i < halPort.num_channel_masks; ++i) { + port->channelMasks[i] = AudioChannelMask(halPort.channel_masks[i]); + } + port->formats.resize(halPort.num_formats); + for (size_t i = 0; i < halPort.num_formats; ++i) { + port->formats[i] = AudioFormat(halPort.formats[i]); + } + port->gains.resize(halPort.num_gains); + for (size_t i = 0; i < halPort.num_gains; ++i) { + audioGainFromHal(halPort.gains[i], &port->gains[i]); + } + audioPortConfigFromHal(halPort.active_config, &port->activeConfig); + switch (halPort.type) { + case AUDIO_PORT_TYPE_NONE: break; + case AUDIO_PORT_TYPE_DEVICE: { + port->ext.device.hwModule = halPort.ext.device.hw_module; + port->ext.device.type = AudioDevice(halPort.ext.device.type); + memcpy(port->ext.device.address.data(), + halPort.ext.device.address, + AUDIO_DEVICE_MAX_ADDRESS_LEN); + break; + } + case AUDIO_PORT_TYPE_MIX: { + port->ext.mix.hwModule = halPort.ext.mix.hw_module; + port->ext.mix.ioHandle = halPort.ext.mix.handle; + port->ext.mix.latencyClass = AudioMixLatencyClass(halPort.ext.mix.latency_class); + break; + } + case AUDIO_PORT_TYPE_SESSION: { + port->ext.session.session = halPort.ext.session.session; + break; + } + } +} + +// static +void Device::audioPortToHal(const AudioPort& port, struct audio_port* halPort) { + memset(halPort, 0, sizeof(audio_port)); + halPort->id = port.id; + halPort->role = static_cast(port.role); + halPort->type = static_cast(port.type); + memcpy(halPort->name, + port.name.c_str(), + std::min(port.name.size(), static_cast(AUDIO_PORT_MAX_NAME_LEN))); + halPort->num_sample_rates = + std::min(port.sampleRates.size(), static_cast(AUDIO_PORT_MAX_SAMPLING_RATES)); + for (size_t i = 0; i < halPort->num_sample_rates; ++i) { + halPort->sample_rates[i] = port.sampleRates[i]; + } + halPort->num_channel_masks = + std::min(port.channelMasks.size(), static_cast(AUDIO_PORT_MAX_CHANNEL_MASKS)); + for (size_t i = 0; i < halPort->num_channel_masks; ++i) { + halPort->channel_masks[i] = static_cast(port.channelMasks[i]); + } + halPort->num_formats = + std::min(port.formats.size(), static_cast(AUDIO_PORT_MAX_FORMATS)); + for (size_t i = 0; i < halPort->num_formats; ++i) { + halPort->formats[i] = static_cast(port.formats[i]); + } + halPort->num_gains = std::min(port.gains.size(), static_cast(AUDIO_PORT_MAX_GAINS)); + for (size_t i = 0; i < halPort->num_gains; ++i) { + audioGainToHal(port.gains[i], &halPort->gains[i]); + } + audioPortConfigToHal(port.activeConfig, &halPort->active_config); + switch (port.type) { + case AudioPortType::NONE: break; + case AudioPortType::DEVICE: { + halPort->ext.device.hw_module = port.ext.device.hwModule; + halPort->ext.device.type = static_cast(port.ext.device.type); + memcpy(halPort->ext.device.address, + port.ext.device.address.data(), + AUDIO_DEVICE_MAX_ADDRESS_LEN); + break; + } + case AudioPortType::MIX: { + halPort->ext.mix.hw_module = port.ext.mix.hwModule; + halPort->ext.mix.handle = port.ext.mix.ioHandle; + halPort->ext.mix.latency_class = + static_cast(port.ext.mix.latencyClass); + break; + } + case AudioPortType::SESSION: { + halPort->ext.session.session = static_cast(port.ext.session.session); + break; + } + } +} + +Result Device::analyzeStatus(const char* funcName, int status) { + if (status != 0) { + ALOGW("Device %p %s: %s", mDevice, funcName, strerror(-status)); + } + switch (status) { + case 0: return Result::OK; + case -EINVAL: return Result::INVALID_ARGUMENTS; + case -ENODATA: return Result::INVALID_STATE; + case -ENODEV: return Result::NOT_INITIALIZED; + case -ENOSYS: return Result::NOT_SUPPORTED; + default: return Result::INVALID_STATE; + } +} + +char* Device::halGetParameters(const char* keys) { + return mDevice->get_parameters(mDevice, keys); +} + +int Device::halSetParameters(const char* keysAndValues) { + return mDevice->set_parameters(mDevice, keysAndValues); +} + +// Methods from ::android::hardware::audio::V2_0::IDevice follow. +Return Device::initCheck() { + return analyzeStatus("init_check", mDevice->init_check(mDevice)); +} + +Return Device::setMasterVolume(float volume) { + Result retval(Result::NOT_SUPPORTED); + if (mDevice->set_master_volume != NULL) { + retval = analyzeStatus("set_master_volume", mDevice->set_master_volume(mDevice, volume)); + } + return retval; +} + +Return Device::getMasterVolume(getMasterVolume_cb _hidl_cb) { + Result retval(Result::NOT_SUPPORTED); + float volume = 0; + if (mDevice->get_master_volume != NULL) { + retval = analyzeStatus("get_master_volume", mDevice->get_master_volume(mDevice, &volume)); + } + _hidl_cb(retval, volume); + return Void(); +} + +Return Device::setMicMute(bool mute) { + return analyzeStatus("set_mic_mute", mDevice->set_mic_mute(mDevice, mute)); +} + +Return Device::getMicMute(getMicMute_cb _hidl_cb) { + bool mute = false; + Result retval = analyzeStatus("get_mic_mute", mDevice->get_mic_mute(mDevice, &mute)); + _hidl_cb(retval, mute); + return Void(); +} + +Return Device::setMasterMute(bool mute) { + Result retval(Result::NOT_SUPPORTED); + if (mDevice->set_master_mute != NULL) { + retval = analyzeStatus("set_master_mute", mDevice->set_master_mute(mDevice, mute)); + } + return retval; +} + +Return Device::getMasterMute(getMasterMute_cb _hidl_cb) { + Result retval(Result::NOT_SUPPORTED); + bool mute = false; + if (mDevice->get_master_mute != NULL) { + retval = analyzeStatus("get_master_mute", mDevice->get_master_mute(mDevice, &mute)); + } + _hidl_cb(retval, mute); + return Void(); +} + +Return Device::getInputBufferSize( + const AudioConfig& config, getInputBufferSize_cb _hidl_cb) { + audio_config_t halConfig; + audioConfigToHal(config, &halConfig); + size_t halBufferSize = mDevice->get_input_buffer_size(mDevice, &halConfig); + Result retval(Result::INVALID_ARGUMENTS); + uint64_t bufferSize = 0; + if (halBufferSize != 0) { + retval = Result::OK; + bufferSize = halBufferSize; + } + _hidl_cb(retval, bufferSize); + return Void(); +} + +Return Device::openOutputStream( + int32_t ioHandle, + const DeviceAddress& device, + const AudioConfig& config, + AudioOutputFlag flags, + openOutputStream_cb _hidl_cb) { + audio_config_t halConfig; + audioConfigToHal(config, &halConfig); + audio_stream_out_t *halStream; + int status = mDevice->open_output_stream( + mDevice, + ioHandle, + static_cast(device.device), + static_cast(flags), + &halConfig, + &halStream, + deviceAddressToHal(device).c_str()); + sp streamOut; + if (status == OK) { + streamOut = new StreamOut(mDevice, halStream); + } + _hidl_cb(analyzeStatus("open_output_stream", status), streamOut); + return Void(); +} + +Return Device::openInputStream( + int32_t ioHandle, + const DeviceAddress& device, + const AudioConfig& config, + AudioInputFlag flags, + AudioSource source, + openInputStream_cb _hidl_cb) { + audio_config_t halConfig; + audioConfigToHal(config, &halConfig); + audio_stream_in_t *halStream; + int status = mDevice->open_input_stream( + mDevice, + ioHandle, + static_cast(device.device), + &halConfig, + &halStream, + static_cast(flags), + deviceAddressToHal(device).c_str(), + static_cast(source)); + sp streamIn; + if (status == OK) { + streamIn = new StreamIn(mDevice, halStream); + } + _hidl_cb(analyzeStatus("open_input_stream", status), streamIn); + return Void(); +} + +Return Device::createAudioPatch( + const hidl_vec& sources, + const hidl_vec& sinks, + createAudioPatch_cb _hidl_cb) { + Result retval(Result::NOT_SUPPORTED); + AudioPatchHandle patch = 0; + if (version() >= AUDIO_DEVICE_API_VERSION_3_0) { + std::unique_ptr halSources(audioPortConfigsToHal(sources)); + std::unique_ptr halSinks(audioPortConfigsToHal(sinks)); + audio_patch_handle_t halPatch; + retval = analyzeStatus( + "create_audio_patch", + mDevice->create_audio_patch( + mDevice, + sources.size(), &halSources[0], + sinks.size(), &halSinks[0], + &halPatch)); + if (retval == Result::OK) { + patch = static_cast(halPatch); + } + } + _hidl_cb(retval, patch); + return Void(); +} + +Return Device::releaseAudioPatch(int32_t patch) { + if (version() >= AUDIO_DEVICE_API_VERSION_3_0) { + return analyzeStatus( + "release_audio_patch", + mDevice->release_audio_patch(mDevice, static_cast(patch))); + } + return Result::NOT_SUPPORTED; +} + +Return Device::getAudioPort(const AudioPort& port, getAudioPort_cb _hidl_cb) { + audio_port halPort; + audioPortToHal(port, &halPort); + Result retval = analyzeStatus("get_audio_port", mDevice->get_audio_port(mDevice, &halPort)); + AudioPort resultPort = port; + if (retval == Result::OK) { + audioPortFromHal(halPort, &resultPort); + } + _hidl_cb(retval, resultPort); + return Void(); +} + +Return Device::setAudioPortConfig(const AudioPortConfig& config) { + if (version() >= AUDIO_DEVICE_API_VERSION_3_0) { + struct audio_port_config halPortConfig; + audioPortConfigToHal(config, &halPortConfig); + return analyzeStatus( + "set_audio_port_config", mDevice->set_audio_port_config(mDevice, &halPortConfig)); + } + return Result::NOT_SUPPORTED; +} + +Return Device::getHwAvSync() { + int halHwAvSync; + Result retval = getParam(AudioParameter::keyHwAvSync, &halHwAvSync); + return retval == Result::OK ? halHwAvSync : AUDIO_HW_SYNC_INVALID; +} + +Return Device::setScreenState(bool turnedOn) { + return setParam(AudioParameter::keyScreenState, turnedOn); +} + +Return Device::getParameters(const hidl_vec& keys, getParameters_cb _hidl_cb) { + getParametersImpl(keys, _hidl_cb); + return Void(); +} + +Return Device::setParameters(const hidl_vec& parameters) { + return setParametersImpl(parameters); +} + +Return Device::debugDump(const native_handle_t* fd) { + if (fd->numFds == 1) { + analyzeStatus("dump", mDevice->dump(mDevice, fd->data[0])); + } + return Void(); +} + +} // namespace implementation +} // namespace V2_0 +} // namespace audio +} // namespace hardware +} // namespace android diff --git a/audio/2.0/default/Device.h b/audio/2.0/default/Device.h new file mode 100644 index 0000000000..d7b31287e7 --- /dev/null +++ b/audio/2.0/default/Device.h @@ -0,0 +1,147 @@ +/* + * 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. + */ + +#ifndef HIDL_GENERATED_android_hardware_audio_V2_0_Device_H_ +#define HIDL_GENERATED_android_hardware_audio_V2_0_Device_H_ + +#include + +#include +#include + +#include +#include + +#include + +#include "ParametersUtil.h" + +namespace android { +namespace hardware { +namespace audio { +namespace V2_0 { +namespace implementation { + +using ::android::hardware::audio::common::V2_0::AudioConfig; +using ::android::hardware::audio::common::V2_0::AudioGain; +using ::android::hardware::audio::common::V2_0::AudioGainConfig; +using ::android::hardware::audio::common::V2_0::AudioGainMode; +using ::android::hardware::audio::common::V2_0::AudioHwSync; +using ::android::hardware::audio::common::V2_0::AudioInputFlag; +using ::android::hardware::audio::common::V2_0::AudioMixLatencyClass; +using ::android::hardware::audio::common::V2_0::AudioOffloadInfo; +using ::android::hardware::audio::common::V2_0::AudioOutputFlag; +using ::android::hardware::audio::common::V2_0::AudioPatchHandle; +using ::android::hardware::audio::common::V2_0::AudioPort; +using ::android::hardware::audio::common::V2_0::AudioPortConfig; +using ::android::hardware::audio::common::V2_0::AudioPortConfigMask; +using ::android::hardware::audio::common::V2_0::AudioPortRole; +using ::android::hardware::audio::common::V2_0::AudioPortType; +using ::android::hardware::audio::common::V2_0::AudioSource; +using ::android::hardware::audio::common::V2_0::AudioStreamType; +using ::android::hardware::audio::V2_0::DeviceAddress; +using ::android::hardware::audio::V2_0::IDevice; +using ::android::hardware::audio::V2_0::IStreamIn; +using ::android::hardware::audio::V2_0::IStreamOut; +using ::android::hardware::audio::V2_0::ParameterValue; +using ::android::hardware::audio::V2_0::Result; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +struct Device : public IDevice, public ParametersUtil { + explicit Device(audio_hw_device_t* device); + + // Methods from ::android::hardware::audio::V2_0::IDevice follow. + Return initCheck() override; + Return setMasterVolume(float volume) override; + Return getMasterVolume(getMasterVolume_cb _hidl_cb) override; + Return setMicMute(bool mute) override; + Return getMicMute(getMicMute_cb _hidl_cb) override; + Return setMasterMute(bool mute) override; + Return getMasterMute(getMasterMute_cb _hidl_cb) override; + Return getInputBufferSize( + const AudioConfig& config, getInputBufferSize_cb _hidl_cb) override; + Return openOutputStream( + int32_t ioHandle, + const DeviceAddress& device, + const AudioConfig& config, + AudioOutputFlag flags, + openOutputStream_cb _hidl_cb) override; + Return openInputStream( + int32_t ioHandle, + const DeviceAddress& device, + const AudioConfig& config, + AudioInputFlag flags, + AudioSource source, + openInputStream_cb _hidl_cb) override; + Return createAudioPatch( + const hidl_vec& sources, + const hidl_vec& sinks, + createAudioPatch_cb _hidl_cb) override; + Return releaseAudioPatch(int32_t patch) override; + Return getAudioPort(const AudioPort& port, getAudioPort_cb _hidl_cb) override; + Return setAudioPortConfig(const AudioPortConfig& config) override; + Return getHwAvSync() override; + Return setScreenState(bool turnedOn) override; + Return getParameters( + const hidl_vec& keys, getParameters_cb _hidl_cb) override; + Return setParameters(const hidl_vec& parameters) override; + Return debugDump(const native_handle_t* fd) override; + + // Utility methods for extending interfaces. + Result analyzeStatus(const char* funcName, int status); + audio_hw_device_t* device() const { return mDevice; } + + private: + audio_hw_device_t *mDevice; + + static void audioConfigToHal(const AudioConfig& config, audio_config_t* halConfig); + static void audioGainConfigFromHal( + const struct audio_gain_config& halConfig, AudioGainConfig* config); + static void audioGainConfigToHal( + const AudioGainConfig& config, struct audio_gain_config* halConfig); + static void audioGainFromHal(const struct audio_gain& halGain, AudioGain* gain); + static void audioGainToHal(const AudioGain& gain, struct audio_gain* halGain); + static void audioOffloadInfoToHal( + const AudioOffloadInfo& offload, audio_offload_info_t* halOffload); + static void audioPortConfigFromHal( + const struct audio_port_config& halConfig, AudioPortConfig* config); + static void audioPortConfigToHal( + const AudioPortConfig& config, struct audio_port_config* halConfig); + static std::unique_ptr audioPortConfigsToHal( + const hidl_vec& configs); + static void audioPortFromHal(const struct audio_port& halPort, AudioPort* port); + static void audioPortToHal(const AudioPort& port, struct audio_port* halPort); + + virtual ~Device(); + + // Methods from ParametersUtil. + char* halGetParameters(const char* keys) override; + int halSetParameters(const char* keysAndValues) override; + + uint32_t version() const { return mDevice->common.version; } +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace audio +} // namespace hardware +} // namespace android + +#endif // HIDL_GENERATED_android_hardware_audio_V2_0_Device_H_ diff --git a/audio/2.0/default/DevicesFactory.cpp b/audio/2.0/default/DevicesFactory.cpp new file mode 100644 index 0000000000..1e087f2dd2 --- /dev/null +++ b/audio/2.0/default/DevicesFactory.cpp @@ -0,0 +1,103 @@ +/* + * 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. + */ + +#define LOG_TAG "DevicesFactoryHAL" + +#include + +#include + +#include "Device.h" +#include "DevicesFactory.h" +#include "PrimaryDevice.h" + +namespace android { +namespace hardware { +namespace audio { +namespace V2_0 { +namespace implementation { + +// static +const char* DevicesFactory::deviceToString(IDevicesFactory::Device device) { + switch (device) { + case IDevicesFactory::Device::PRIMARY: return AUDIO_HARDWARE_MODULE_ID_PRIMARY; + case IDevicesFactory::Device::A2DP: return AUDIO_HARDWARE_MODULE_ID_A2DP; + case IDevicesFactory::Device::USB: return AUDIO_HARDWARE_MODULE_ID_USB; + case IDevicesFactory::Device::R_SUBMIX: return AUDIO_HARDWARE_MODULE_ID_REMOTE_SUBMIX; + } +} + +// static +int DevicesFactory::loadAudioInterface(const char *if_name, audio_hw_device_t **dev) +{ + const hw_module_t *mod; + int rc; + + rc = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, if_name, &mod); + if (rc) { + ALOGE("%s couldn't load audio hw module %s.%s (%s)", __func__, + AUDIO_HARDWARE_MODULE_ID, if_name, strerror(-rc)); + goto out; + } + rc = audio_hw_device_open(mod, dev); + if (rc) { + ALOGE("%s couldn't open audio hw device in %s.%s (%s)", __func__, + AUDIO_HARDWARE_MODULE_ID, if_name, strerror(-rc)); + goto out; + } + if ((*dev)->common.version < AUDIO_DEVICE_API_VERSION_MIN) { + ALOGE("%s wrong audio hw device version %04x", __func__, (*dev)->common.version); + rc = -EINVAL; + audio_hw_device_close(*dev); + goto out; + } + return OK; + +out: + *dev = NULL; + return rc; +} + +// Methods from ::android::hardware::audio::V2_0::IDevicesFactory follow. +Return DevicesFactory::openDevice(IDevicesFactory::Device device, openDevice_cb _hidl_cb) { + audio_hw_device_t *halDevice; + int halStatus = loadAudioInterface(deviceToString(device), &halDevice); + Result retval(Result::OK); + sp result; + if (halStatus == OK) { + if (device == IDevicesFactory::Device::PRIMARY) { + result = new PrimaryDevice(halDevice); + } else { + result = new ::android::hardware::audio::V2_0::implementation::Device(halDevice); + } + } else if (halStatus == -EINVAL) { + retval = Result::NOT_INITIALIZED; + } else { + retval = Result::INVALID_ARGUMENTS; + } + _hidl_cb(retval, result); + return Void(); +} + +IDevicesFactory* HIDL_FETCH_IDevicesFactory(const char* /* name */) { + return new DevicesFactory(); +} + +} // namespace implementation +} // namespace V2_0 +} // namespace audio +} // namespace hardware +} // namespace android diff --git a/audio/2.0/default/DevicesFactory.h b/audio/2.0/default/DevicesFactory.h new file mode 100644 index 0000000000..0ea985921d --- /dev/null +++ b/audio/2.0/default/DevicesFactory.h @@ -0,0 +1,59 @@ +/* + * 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. + */ + +#ifndef HIDL_GENERATED_android_hardware_audio_V2_0_DevicesFactory_H_ +#define HIDL_GENERATED_android_hardware_audio_V2_0_DevicesFactory_H_ + +#include + +#include +#include + +#include +namespace android { +namespace hardware { +namespace audio { +namespace V2_0 { +namespace implementation { + +using ::android::hardware::audio::V2_0::IDevice; +using ::android::hardware::audio::V2_0::IDevicesFactory; +using ::android::hardware::audio::V2_0::Result; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +struct DevicesFactory : public IDevicesFactory { + // Methods from ::android::hardware::audio::V2_0::IDevicesFactory follow. + Return openDevice(IDevicesFactory::Device device, openDevice_cb _hidl_cb) override; + + private: + static const char* deviceToString(IDevicesFactory::Device device); + static int loadAudioInterface(const char *if_name, audio_hw_device_t **dev); + +}; + +extern "C" IDevicesFactory* HIDL_FETCH_IDevicesFactory(const char* name); + +} // namespace implementation +} // namespace V2_0 +} // namespace audio +} // namespace hardware +} // namespace android + +#endif // HIDL_GENERATED_android_hardware_audio_V2_0_DevicesFactory_H_ diff --git a/audio/2.0/default/ParametersUtil.cpp b/audio/2.0/default/ParametersUtil.cpp new file mode 100644 index 0000000000..75a60b9b64 --- /dev/null +++ b/audio/2.0/default/ParametersUtil.cpp @@ -0,0 +1,134 @@ +/* + * 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 "ParametersUtil.h" + +namespace android { +namespace hardware { +namespace audio { +namespace V2_0 { +namespace implementation { + +Result ParametersUtil::getParam(const char* name, bool* value) { + String8 halValue; + Result retval = getParam(name, &halValue); + *value = false; + if (retval == Result::OK) { + *value = !(halValue == AudioParameter::valueOff); + } + return retval; +} + +Result ParametersUtil::getParam(const char* name, int* value) { + const String8 halName(name); + AudioParameter keys; + keys.addKey(halName); + std::unique_ptr params = getParams(keys); + status_t halStatus = params->getInt(halName, *value); + return halStatus == OK ? Result::OK : Result::INVALID_ARGUMENTS; +} + +Result ParametersUtil::getParam(const char* name, String8* value) { + const String8 halName(name); + AudioParameter keys; + keys.addKey(halName); + std::unique_ptr params = getParams(keys); + status_t halStatus = params->get(halName, *value); + return halStatus == OK ? Result::OK : Result::INVALID_ARGUMENTS; +} + +void ParametersUtil::getParametersImpl( + const hidl_vec& keys, + std::function& parameters)> cb) { + AudioParameter halKeys; + for (size_t i = 0; i < keys.size(); ++i) { + halKeys.addKey(String8(keys[i].c_str())); + } + std::unique_ptr halValues = getParams(halKeys); + Result retval(Result::INVALID_ARGUMENTS); + hidl_vec result; + if (halValues->size() > 0) { + result.resize(halValues->size()); + String8 halKey, halValue; + for (size_t i = 0; i < halValues->size(); ++i) { + status_t status = halValues->getAt(i, halKey, halValue); + if (status != OK) { + result.resize(0); + break; + } + result[i].key = halKey.string(); + result[i].value = halValue.string(); + } + if (result.size() != 0) { + retval = Result::OK; + } + } + cb(retval, result); +} + +std::unique_ptr ParametersUtil::getParams(const AudioParameter& keys) { + String8 paramsAndValues; + char *halValues = halGetParameters(keys.keysToString().string()); + if (halValues != NULL) { + paramsAndValues.setTo(halValues); + free(halValues); + } else { + paramsAndValues.clear(); + } + return std::unique_ptr(new AudioParameter(paramsAndValues)); +} + +Result ParametersUtil::setParam(const char* name, bool value) { + AudioParameter param; + param.add(String8(name), String8(value ? AudioParameter::valueOn : AudioParameter::valueOff)); + return setParams(param); +} + +Result ParametersUtil::setParam(const char* name, int value) { + AudioParameter param; + param.addInt(String8(name), value); + return setParams(param); +} + +Result ParametersUtil::setParam(const char* name, const char* value) { + AudioParameter param; + param.add(String8(name), String8(value)); + return setParams(param); +} + +Result ParametersUtil::setParametersImpl(const hidl_vec& parameters) { + AudioParameter params; + for (size_t i = 0; i < parameters.size(); ++i) { + params.add(String8(parameters[i].key.c_str()), String8(parameters[i].value.c_str())); + } + return setParams(params); +} + +Result ParametersUtil::setParams(const AudioParameter& param) { + int halStatus = halSetParameters(param.toString().string()); + if (halStatus == OK) + return Result::OK; + else if (halStatus == -ENOSYS) + return Result::INVALID_STATE; + else + return Result::INVALID_ARGUMENTS; +} + +} // namespace implementation +} // namespace V2_0 +} // namespace audio +} // namespace hardware +} // namespace android diff --git a/audio/2.0/default/ParametersUtil.h b/audio/2.0/default/ParametersUtil.h new file mode 100644 index 0000000000..49036dc521 --- /dev/null +++ b/audio/2.0/default/ParametersUtil.h @@ -0,0 +1,66 @@ +/* + * 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. + */ + +#ifndef android_hardware_audio_V2_0_ParametersUtil_H_ +#define android_hardware_audio_V2_0_ParametersUtil_H_ + +#include +#include + +#include +#include +#include + +namespace android { +namespace hardware { +namespace audio { +namespace V2_0 { +namespace implementation { + +using ::android::hardware::audio::V2_0::ParameterValue; +using ::android::hardware::audio::V2_0::Result; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; + +class ParametersUtil { + public: + Result getParam(const char* name, bool* value); + Result getParam(const char* name, int* value); + Result getParam(const char* name, String8* value); + void getParametersImpl( + const hidl_vec& keys, + std::function& parameters)> cb); + std::unique_ptr getParams(const AudioParameter& keys); + Result setParam(const char* name, bool value); + Result setParam(const char* name, int value); + Result setParam(const char* name, const char* value); + Result setParametersImpl(const hidl_vec& parameters); + Result setParams(const AudioParameter& param); + + protected: + virtual ~ParametersUtil() {} + + virtual char* halGetParameters(const char* keys) = 0; + virtual int halSetParameters(const char* keysAndValues) = 0; +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace audio +} // namespace hardware +} // namespace android + +#endif // android_hardware_audio_V2_0_ParametersUtil_H_ diff --git a/audio/2.0/default/PrimaryDevice.cpp b/audio/2.0/default/PrimaryDevice.cpp new file mode 100644 index 0000000000..9f5180cebb --- /dev/null +++ b/audio/2.0/default/PrimaryDevice.cpp @@ -0,0 +1,189 @@ +/* + * 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. + */ + +#define LOG_TAG "PrimaryDeviceHAL" + +#include "PrimaryDevice.h" + +namespace android { +namespace hardware { +namespace audio { +namespace V2_0 { +namespace implementation { + +PrimaryDevice::PrimaryDevice(audio_hw_device_t* device) + : mDevice(new Device(device)) { +} + +PrimaryDevice::~PrimaryDevice() {} + +// Methods from ::android::hardware::audio::V2_0::IDevice follow. +Return PrimaryDevice::initCheck() { + return mDevice->initCheck(); +} + +Return PrimaryDevice::setMasterVolume(float volume) { + return mDevice->setMasterVolume(volume); +} + +Return PrimaryDevice::getMasterVolume(getMasterVolume_cb _hidl_cb) { + return mDevice->getMasterVolume(_hidl_cb); +} + +Return PrimaryDevice::setMicMute(bool mute) { + return mDevice->setMicMute(mute); +} + +Return PrimaryDevice::getMicMute(getMicMute_cb _hidl_cb) { + return mDevice->getMicMute(_hidl_cb); +} + +Return PrimaryDevice::setMasterMute(bool mute) { + return mDevice->setMasterMute(mute); +} + +Return PrimaryDevice::getMasterMute(getMasterMute_cb _hidl_cb) { + return mDevice->getMasterMute(_hidl_cb); +} + +Return PrimaryDevice::getInputBufferSize( + const AudioConfig& config, getInputBufferSize_cb _hidl_cb) { + return mDevice->getInputBufferSize(config, _hidl_cb); +} + +Return PrimaryDevice::openOutputStream( + int32_t ioHandle, + const DeviceAddress& device, + const AudioConfig& config, + AudioOutputFlag flags, + openOutputStream_cb _hidl_cb) { + return mDevice->openOutputStream(ioHandle, device, config, flags, _hidl_cb); +} + +Return PrimaryDevice::openInputStream( + int32_t ioHandle, + const DeviceAddress& device, + const AudioConfig& config, + AudioInputFlag flags, + AudioSource source, + openInputStream_cb _hidl_cb) { + return mDevice->openInputStream(ioHandle, device, config, flags, source, _hidl_cb); +} + +Return PrimaryDevice::createAudioPatch( + const hidl_vec& sources, + const hidl_vec& sinks, + createAudioPatch_cb _hidl_cb) { + return mDevice->createAudioPatch(sources, sinks, _hidl_cb); +} + +Return PrimaryDevice::releaseAudioPatch(int32_t patch) { + return mDevice->releaseAudioPatch(patch); +} + +Return PrimaryDevice::getAudioPort(const AudioPort& port, getAudioPort_cb _hidl_cb) { + return mDevice->getAudioPort(port, _hidl_cb); +} + +Return PrimaryDevice::setAudioPortConfig(const AudioPortConfig& config) { + return mDevice->setAudioPortConfig(config); +} + +Return PrimaryDevice::getHwAvSync() { + return mDevice->getHwAvSync(); +} + +Return PrimaryDevice::setScreenState(bool turnedOn) { + return mDevice->setScreenState(turnedOn); +} + +Return PrimaryDevice::getParameters( + const hidl_vec& keys, getParameters_cb _hidl_cb) { + return mDevice->getParameters(keys, _hidl_cb); +} + +Return PrimaryDevice::setParameters(const hidl_vec& parameters) { + return mDevice->setParameters(parameters); +} + +Return PrimaryDevice::debugDump(const native_handle_t* fd) { + return mDevice->debugDump(fd); +} + + +// Methods from ::android::hardware::audio::V2_0::IPrimaryDevice follow. +Return PrimaryDevice::setVoiceVolume(float volume) { + return mDevice->analyzeStatus( + "set_voice_volume", + mDevice->device()->set_voice_volume(mDevice->device(), volume)); +} + +Return PrimaryDevice::setMode(AudioMode mode) { + return mDevice->analyzeStatus( + "set_mode", + mDevice->device()->set_mode(mDevice->device(), static_cast(mode))); +} + +Return PrimaryDevice::getBtScoNrecEnabled(getBtScoNrecEnabled_cb _hidl_cb) { + bool enabled; + Result retval = mDevice->getParam(AudioParameter::keyBtNrec, &enabled); + _hidl_cb(retval, enabled); + return Void(); +} + +Return PrimaryDevice::setBtScoNrecEnabled(bool enabled) { + return mDevice->setParam(AudioParameter::keyBtNrec, enabled); +} + +Return PrimaryDevice::getBtScoWidebandEnabled(getBtScoWidebandEnabled_cb _hidl_cb) { + bool enabled; + Result retval = mDevice->getParam(AUDIO_PARAMETER_KEY_BT_SCO_WB, &enabled); + _hidl_cb(retval, enabled); + return Void(); +} + +Return PrimaryDevice::setBtScoWidebandEnabled(bool enabled) { + return mDevice->setParam(AUDIO_PARAMETER_KEY_BT_SCO_WB, enabled); +} + +Return PrimaryDevice::getTtyMode(getTtyMode_cb _hidl_cb) { + int halMode; + Result retval = mDevice->getParam(AUDIO_PARAMETER_KEY_TTY_MODE, &halMode); + TtyMode mode = retval == Result::OK ? TtyMode(halMode) : TtyMode::OFF; + _hidl_cb(retval, mode); + return Void(); +} + +Return PrimaryDevice::setTtyMode(IPrimaryDevice::TtyMode mode) { + return mDevice->setParam(AUDIO_PARAMETER_KEY_TTY_MODE, static_cast(mode)); +} + +Return PrimaryDevice::getHacEnabled(getHacEnabled_cb _hidl_cb) { + bool enabled; + Result retval = mDevice->getParam(AUDIO_PARAMETER_KEY_HAC, &enabled); + _hidl_cb(retval, enabled); + return Void(); +} + +Return PrimaryDevice::setHacEnabled(bool enabled) { + return mDevice->setParam(AUDIO_PARAMETER_KEY_HAC, enabled); +} + +} // namespace implementation +} // namespace V2_0 +} // namespace audio +} // namespace hardware +} // namespace android diff --git a/audio/2.0/default/PrimaryDevice.h b/audio/2.0/default/PrimaryDevice.h new file mode 100644 index 0000000000..4c5b590efa --- /dev/null +++ b/audio/2.0/default/PrimaryDevice.h @@ -0,0 +1,117 @@ +/* + * 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. + */ + +#ifndef HIDL_GENERATED_android_hardware_audio_V2_0_PrimaryDevice_H_ +#define HIDL_GENERATED_android_hardware_audio_V2_0_PrimaryDevice_H_ + +#include +#include + +#include + +#include "Device.h" + +namespace android { +namespace hardware { +namespace audio { +namespace V2_0 { +namespace implementation { + +using ::android::hardware::audio::common::V2_0::AudioConfig; +using ::android::hardware::audio::common::V2_0::AudioInputFlag; +using ::android::hardware::audio::common::V2_0::AudioMode; +using ::android::hardware::audio::common::V2_0::AudioOutputFlag; +using ::android::hardware::audio::common::V2_0::AudioPort; +using ::android::hardware::audio::common::V2_0::AudioPortConfig; +using ::android::hardware::audio::common::V2_0::AudioSource; +using ::android::hardware::audio::V2_0::DeviceAddress; +using ::android::hardware::audio::V2_0::IDevice; +using ::android::hardware::audio::V2_0::IPrimaryDevice; +using ::android::hardware::audio::V2_0::IStreamIn; +using ::android::hardware::audio::V2_0::IStreamOut; +using ::android::hardware::audio::V2_0::ParameterValue; +using ::android::hardware::audio::V2_0::Result; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +struct PrimaryDevice : public IPrimaryDevice { + explicit PrimaryDevice(audio_hw_device_t* device); + + // Methods from ::android::hardware::audio::V2_0::IDevice follow. + Return initCheck() override; + Return setMasterVolume(float volume) override; + Return getMasterVolume(getMasterVolume_cb _hidl_cb) override; + Return setMicMute(bool mute) override; + Return getMicMute(getMicMute_cb _hidl_cb) override; + Return setMasterMute(bool mute) override; + Return getMasterMute(getMasterMute_cb _hidl_cb) override; + Return getInputBufferSize( + const AudioConfig& config, getInputBufferSize_cb _hidl_cb) override; + Return openOutputStream( + int32_t ioHandle, + const DeviceAddress& device, + const AudioConfig& config, + AudioOutputFlag flags, + openOutputStream_cb _hidl_cb) override; + Return openInputStream( + int32_t ioHandle, + const DeviceAddress& device, + const AudioConfig& config, + AudioInputFlag flags, + AudioSource source, + openInputStream_cb _hidl_cb) override; + Return createAudioPatch( + const hidl_vec& sources, + const hidl_vec& sinks, + createAudioPatch_cb _hidl_cb) override; + Return releaseAudioPatch(int32_t patch) override; + Return getAudioPort(const AudioPort& port, getAudioPort_cb _hidl_cb) override; + Return setAudioPortConfig(const AudioPortConfig& config) override; + Return getHwAvSync() override; + Return setScreenState(bool turnedOn) override; + Return getParameters( + const hidl_vec& keys, getParameters_cb _hidl_cb) override; + Return setParameters(const hidl_vec& parameters) override; + Return debugDump(const native_handle_t* fd) override; + + // Methods from ::android::hardware::audio::V2_0::IPrimaryDevice follow. + Return setVoiceVolume(float volume) override; + Return setMode(AudioMode mode) override; + Return getBtScoNrecEnabled(getBtScoNrecEnabled_cb _hidl_cb) override; + Return setBtScoNrecEnabled(bool enabled) override; + Return getBtScoWidebandEnabled(getBtScoWidebandEnabled_cb _hidl_cb) override; + Return setBtScoWidebandEnabled(bool enabled) override; + Return getTtyMode(getTtyMode_cb _hidl_cb) override; + Return setTtyMode(IPrimaryDevice::TtyMode mode) override; + Return getHacEnabled(getHacEnabled_cb _hidl_cb) override; + Return setHacEnabled(bool enabled) override; + + private: + sp mDevice; + + virtual ~PrimaryDevice(); +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace audio +} // namespace hardware +} // namespace android + +#endif // HIDL_GENERATED_android_hardware_audio_V2_0_PrimaryDevice_H_ diff --git a/audio/2.0/default/Stream.cpp b/audio/2.0/default/Stream.cpp new file mode 100644 index 0000000000..7616becc9b --- /dev/null +++ b/audio/2.0/default/Stream.cpp @@ -0,0 +1,236 @@ +/* + * 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 + +#define LOG_TAG "StreamHAL" + +#include +#include +#include +#include +#include +#include + +#include "Conversions.h" +#include "EffectMap.h" +#include "Stream.h" + +namespace android { +namespace hardware { +namespace audio { +namespace V2_0 { +namespace implementation { + +Stream::Stream(audio_stream_t* stream) + : mStream(stream) { +} + +Stream::~Stream() { + mStream = nullptr; +} + +Result Stream::analyzeStatus(const char* funcName, int status) { + if (status != 0) { + ALOGW("Stream %p %s: %s", mStream, funcName, strerror(-status)); + } + switch (status) { + case 0: return Result::OK; + case -EINVAL: return Result::INVALID_ARGUMENTS; + case -ENODATA: return Result::INVALID_STATE; + case -ENODEV: return Result::NOT_INITIALIZED; + case -ENOSYS: return Result::NOT_SUPPORTED; + default: return Result::INVALID_STATE; + } +} + +char* Stream::halGetParameters(const char* keys) { + return mStream->get_parameters(mStream, keys); +} + +int Stream::halSetParameters(const char* keysAndValues) { + return mStream->set_parameters(mStream, keysAndValues); +} + +// Methods from ::android::hardware::audio::V2_0::IStream follow. +Return Stream::getFrameSize() { + // Needs to be implemented by interface subclasses. But can't be declared as pure virtual, + // since interface subclasses implementation do not inherit from this class. + LOG_ALWAYS_FATAL("Stream::getFrameSize is pure abstract"); + return uint64_t {}; +} + +Return Stream::getFrameCount() { + int halFrameCount; + Result retval = getParam(AudioParameter::keyFrameCount, &halFrameCount); + return retval == Result::OK ? halFrameCount : 0; +} + +Return Stream::getBufferSize() { + return mStream->get_buffer_size(mStream); +} + +Return Stream::getSampleRate() { + return mStream->get_sample_rate(mStream); +} + +Return Stream::getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) { + String8 halListValue; + Result result = getParam(AudioParameter::keyStreamSupportedSamplingRates, &halListValue); + hidl_vec sampleRates; + SortedVector halSampleRates; + if (result == Result::OK) { + halSampleRates = samplingRatesFromString( + halListValue.string(), AudioParameter::valueListSeparator); + sampleRates.setToExternal(halSampleRates.editArray(), halSampleRates.size()); + } + _hidl_cb(sampleRates); + return Void(); +} + +Return Stream::setSampleRate(uint32_t sampleRateHz) { + return setParam(AudioParameter::keySamplingRate, static_cast(sampleRateHz)); +} + +Return Stream::getChannelMask() { + return AudioChannelMask(mStream->get_channels(mStream)); +} + +Return Stream::getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) { + String8 halListValue; + Result result = getParam(AudioParameter::keyStreamSupportedChannels, &halListValue); + hidl_vec channelMasks; + SortedVector halChannelMasks; + if (result == Result::OK) { + halChannelMasks = channelMasksFromString( + halListValue.string(), AudioParameter::valueListSeparator); + channelMasks.resize(halChannelMasks.size()); + for (size_t i = 0; i < halChannelMasks.size(); ++i) { + channelMasks[i] = AudioChannelMask(halChannelMasks[i]); + } + } + _hidl_cb(channelMasks); + return Void(); +} + +Return Stream::setChannelMask(AudioChannelMask mask) { + return setParam(AudioParameter::keyChannels, static_cast(mask)); +} + +Return Stream::getFormat() { + return AudioFormat(mStream->get_format(mStream)); +} + +Return Stream::getSupportedFormats(getSupportedFormats_cb _hidl_cb) { + String8 halListValue; + Result result = getParam(AudioParameter::keyStreamSupportedFormats, &halListValue); + hidl_vec formats; + Vector halFormats; + if (result == Result::OK) { + halFormats = formatsFromString(halListValue.string(), AudioParameter::valueListSeparator); + formats.resize(halFormats.size()); + for (size_t i = 0; i < halFormats.size(); ++i) { + formats[i] = AudioFormat(halFormats[i]); + } + } + _hidl_cb(formats); + return Void(); +} + +Return Stream::setFormat(AudioFormat format) { + return setParam(AudioParameter::keyFormat, static_cast(format)); +} + +Return Stream::getAudioProperties(getAudioProperties_cb _hidl_cb) { + uint32_t halSampleRate = mStream->get_sample_rate(mStream); + audio_channel_mask_t halMask = mStream->get_channels(mStream); + audio_format_t halFormat = mStream->get_format(mStream); + _hidl_cb(halSampleRate, AudioChannelMask(halMask), AudioFormat(halFormat)); + return Void(); +} + +Return Stream::addEffect(uint64_t effectId) { + effect_handle_t halEffect = EffectMap::getInstance().get(effectId); + if (halEffect != NULL) { + return analyzeStatus("add_audio_effect", mStream->add_audio_effect(mStream, halEffect)); + } else { + ALOGW("Invalid effect ID passed from client: %" PRIu64, effectId); + return Result::INVALID_ARGUMENTS; + } +} + +Return Stream::removeEffect(uint64_t effectId) { + effect_handle_t halEffect = EffectMap::getInstance().get(effectId); + if (halEffect != NULL) { + return analyzeStatus( + "remove_audio_effect", mStream->remove_audio_effect(mStream, halEffect)); + } else { + ALOGW("Invalid effect ID passed from client: %" PRIu64, effectId); + return Result::INVALID_ARGUMENTS; + } +} + +Return Stream::standby() { + return analyzeStatus("standby", mStream->standby(mStream)); +} + +Return Stream::getDevice() { + return AudioDevice(mStream->get_device(mStream)); +} + +Return Stream::setDevice(const DeviceAddress& address) { + char* halDeviceAddress = + audio_device_address_to_parameter( + static_cast(address.device), + deviceAddressToHal(address).c_str()); + AudioParameter params((String8(halDeviceAddress))); + free(halDeviceAddress); + params.addInt( + String8(AudioParameter::keyRouting), static_cast(address.device)); + return setParams(params); +} + +Return Stream::setConnectedState(const DeviceAddress& address, bool connected) { + return setParam( + connected ? AudioParameter::keyStreamConnect : AudioParameter::keyStreamDisconnect, + deviceAddressToHal(address).c_str()); +} + +Return Stream::setHwAvSync(uint32_t hwAvSync) { + return setParam(AudioParameter::keyStreamHwAvSync, static_cast(hwAvSync)); +} + +Return Stream::getParameters(const hidl_vec& keys, getParameters_cb _hidl_cb) { + getParametersImpl(keys, _hidl_cb); + return Void(); +} + +Return Stream::setParameters(const hidl_vec& parameters) { + return setParametersImpl(parameters); +} + +Return Stream::debugDump(const native_handle_t* fd) { + if (fd->numFds == 1) { + analyzeStatus("dump", mStream->dump(mStream, fd->data[0])); + } + return Void(); +} + +} // namespace implementation +} // namespace V2_0 +} // namespace audio +} // namespace hardware +} // namespace android diff --git a/audio/2.0/default/Stream.h b/audio/2.0/default/Stream.h new file mode 100644 index 0000000000..f28fbff0dc --- /dev/null +++ b/audio/2.0/default/Stream.h @@ -0,0 +1,94 @@ +/* + * 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. + */ + +#ifndef HIDL_GENERATED_android_hardware_audio_V2_0_Stream_H_ +#define HIDL_GENERATED_android_hardware_audio_V2_0_Stream_H_ + +#include +#include + +#include + +#include "ParametersUtil.h" + +namespace android { +namespace hardware { +namespace audio { +namespace V2_0 { +namespace implementation { + +using ::android::hardware::audio::common::V2_0::AudioChannelMask; +using ::android::hardware::audio::common::V2_0::AudioDevice; +using ::android::hardware::audio::common::V2_0::AudioFormat; +using ::android::hardware::audio::V2_0::DeviceAddress; +using ::android::hardware::audio::V2_0::IStream; +using ::android::hardware::audio::V2_0::ParameterValue; +using ::android::hardware::audio::V2_0::Result; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +struct Stream : public IStream, public ParametersUtil { + explicit Stream(audio_stream_t* stream); + + // Methods from ::android::hardware::audio::V2_0::IStream follow. + Return getFrameSize() override; + Return getFrameCount() override; + Return getBufferSize() override; + Return getSampleRate() override; + Return getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) override; + Return setSampleRate(uint32_t sampleRateHz) override; + Return getChannelMask() override; + Return getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) override; + Return setChannelMask(AudioChannelMask mask) override; + Return getFormat() override; + Return getSupportedFormats(getSupportedFormats_cb _hidl_cb) override; + Return setFormat(AudioFormat format) override; + Return getAudioProperties(getAudioProperties_cb _hidl_cb) override; + Return addEffect(uint64_t effectId) override; + Return removeEffect(uint64_t effectId) override; + Return standby() override; + Return getDevice() override; + Return setDevice(const DeviceAddress& address) override; + Return setConnectedState(const DeviceAddress& address, bool connected) override; + Return setHwAvSync(uint32_t hwAvSync) override; + Return getParameters( + const hidl_vec& keys, getParameters_cb _hidl_cb) override; + Return setParameters(const hidl_vec& parameters) override; + Return debugDump(const native_handle_t* fd) override; + + // Utility methods for extending interfaces. + Result analyzeStatus(const char* funcName, int status); + + private: + audio_stream_t *mStream; + + virtual ~Stream(); + + // Methods from ParametersUtil. + char* halGetParameters(const char* keys) override; + int halSetParameters(const char* keysAndValues) override; +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace audio +} // namespace hardware +} // namespace android + +#endif // HIDL_GENERATED_android_hardware_audio_V2_0_Stream_H_ diff --git a/audio/2.0/default/StreamIn.cpp b/audio/2.0/default/StreamIn.cpp new file mode 100644 index 0000000000..b590d1a2e9 --- /dev/null +++ b/audio/2.0/default/StreamIn.cpp @@ -0,0 +1,191 @@ +/* + * 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. + */ + +#define LOG_TAG "StreamInHAL" + +#include +#include + +#include "StreamIn.h" + +namespace android { +namespace hardware { +namespace audio { +namespace V2_0 { +namespace implementation { + +StreamIn::StreamIn(audio_hw_device_t* device, audio_stream_in_t* stream) + : mDevice(device), mStream(stream), mStreamCommon(new Stream(&stream->common)) { +} + +StreamIn::~StreamIn() { + mDevice->close_input_stream(mDevice, mStream); + mStream = nullptr; + mDevice = nullptr; +} + +// Methods from ::android::hardware::audio::V2_0::IStream follow. +Return StreamIn::getFrameSize() { + return audio_stream_in_frame_size(mStream); +} + +Return StreamIn::getFrameCount() { + return mStreamCommon->getFrameCount(); +} + +Return StreamIn::getBufferSize() { + return mStreamCommon->getBufferSize(); +} + +Return StreamIn::getSampleRate() { + return mStreamCommon->getSampleRate(); +} + +Return StreamIn::getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) { + return mStreamCommon->getSupportedSampleRates(_hidl_cb); +} + +Return StreamIn::setSampleRate(uint32_t sampleRateHz) { + return mStreamCommon->setSampleRate(sampleRateHz); +} + +Return StreamIn::getChannelMask() { + return mStreamCommon->getChannelMask(); +} + +Return StreamIn::getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) { + return mStreamCommon->getSupportedChannelMasks(_hidl_cb); +} + +Return StreamIn::setChannelMask(AudioChannelMask mask) { + return mStreamCommon->setChannelMask(mask); +} + +Return StreamIn::getFormat() { + return mStreamCommon->getFormat(); +} + +Return StreamIn::getSupportedFormats(getSupportedFormats_cb _hidl_cb) { + return mStreamCommon->getSupportedFormats(_hidl_cb); +} + +Return StreamIn::setFormat(AudioFormat format) { + return mStreamCommon->setFormat(format); +} + +Return StreamIn::getAudioProperties(getAudioProperties_cb _hidl_cb) { + return mStreamCommon->getAudioProperties(_hidl_cb); +} + +Return StreamIn::addEffect(uint64_t effectId) { + return mStreamCommon->addEffect(effectId); +} + +Return StreamIn::removeEffect(uint64_t effectId) { + return mStreamCommon->removeEffect(effectId); +} + +Return StreamIn::standby() { + return mStreamCommon->standby(); +} + +Return StreamIn::getDevice() { + return mStreamCommon->getDevice(); +} + +Return StreamIn::setDevice(const DeviceAddress& address) { + return mStreamCommon->setDevice(address); +} + +Return StreamIn::setConnectedState(const DeviceAddress& address, bool connected) { + return mStreamCommon->setConnectedState(address, connected); +} + +Return StreamIn::setHwAvSync(uint32_t hwAvSync) { + return mStreamCommon->setHwAvSync(hwAvSync); +} + +Return StreamIn::getParameters(const hidl_vec& keys, getParameters_cb _hidl_cb) { + return mStreamCommon->getParameters(keys, _hidl_cb); +} + +Return StreamIn::setParameters(const hidl_vec& parameters) { + return mStreamCommon->setParameters(parameters); +} + +Return StreamIn::debugDump(const native_handle_t* fd) { + return mStreamCommon->debugDump(fd); +} + + +// Methods from ::android::hardware::audio::V2_0::IStreamIn follow. +Return StreamIn::getAudioSource(getAudioSource_cb _hidl_cb) { + int halSource; + Result retval = mStreamCommon->getParam(AudioParameter::keyInputSource, &halSource); + AudioSource source(AudioSource::DEFAULT); + if (retval == Result::OK) { + source = AudioSource(halSource); + } + _hidl_cb(retval, source); + return Void(); +} + +Return StreamIn::setGain(float gain) { + return mStreamCommon->analyzeStatus("set_gain", mStream->set_gain(mStream, gain)); +} + +Return StreamIn::read(uint64_t size, read_cb _hidl_cb) { + // TODO(mnaganov): Replace with FMQ version. + hidl_vec data; + data.resize(size); + Result retval(Result::OK); + ssize_t readResult = mStream->read(mStream, &data[0], data.size()); + if (readResult >= 0 && static_cast(readResult) != data.size()) { + data.resize(readResult); + } else if (readResult < 0) { + data.resize(0); + retval = mStreamCommon->analyzeStatus("read", readResult); + } + _hidl_cb(retval, data); + return Void(); +} + +Return StreamIn::getInputFramesLost() { + return mStream->get_input_frames_lost(mStream); +} + +Return StreamIn::getCapturePosition(getCapturePosition_cb _hidl_cb) { + Result retval(Result::NOT_SUPPORTED); + uint64_t frames = 0, time = 0; + if (mStream->get_capture_position != NULL) { + int64_t halFrames, halTime; + retval = mStreamCommon->analyzeStatus( + "get_capture_position", + mStream->get_capture_position(mStream, &halFrames, &halTime)); + if (retval == Result::OK) { + frames = halFrames; + time = halTime; + } + } + _hidl_cb(retval, frames, time); + return Void(); +} + +} // namespace implementation +} // namespace V2_0 +} // namespace audio +} // namespace hardware +} // namespace android diff --git a/audio/2.0/default/StreamIn.h b/audio/2.0/default/StreamIn.h new file mode 100644 index 0000000000..83f620cdbb --- /dev/null +++ b/audio/2.0/default/StreamIn.h @@ -0,0 +1,98 @@ +/* + * 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. + */ + +#ifndef HIDL_GENERATED_android_hardware_audio_V2_0_StreamIn_H_ +#define HIDL_GENERATED_android_hardware_audio_V2_0_StreamIn_H_ + +#include +#include + +#include + +#include "Stream.h" + +namespace android { +namespace hardware { +namespace audio { +namespace V2_0 { +namespace implementation { + +using ::android::hardware::audio::common::V2_0::AudioChannelMask; +using ::android::hardware::audio::common::V2_0::AudioDevice; +using ::android::hardware::audio::common::V2_0::AudioFormat; +using ::android::hardware::audio::common::V2_0::AudioSource; +using ::android::hardware::audio::V2_0::DeviceAddress; +using ::android::hardware::audio::V2_0::IStream; +using ::android::hardware::audio::V2_0::IStreamIn; +using ::android::hardware::audio::V2_0::ParameterValue; +using ::android::hardware::audio::V2_0::Result; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +struct StreamIn : public IStreamIn { + StreamIn(audio_hw_device_t* device, audio_stream_in_t* stream); + + // Methods from ::android::hardware::audio::V2_0::IStream follow. + Return getFrameSize() override; + Return getFrameCount() override; + Return getBufferSize() override; + Return getSampleRate() override; + Return getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) override; + Return setSampleRate(uint32_t sampleRateHz) override; + Return getChannelMask() override; + Return getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) override; + Return setChannelMask(AudioChannelMask mask) override; + Return getFormat() override; + Return getSupportedFormats(getSupportedFormats_cb _hidl_cb) override; + Return setFormat(AudioFormat format) override; + Return getAudioProperties(getAudioProperties_cb _hidl_cb) override; + Return addEffect(uint64_t effectId) override; + Return removeEffect(uint64_t effectId) override; + Return standby() override; + Return getDevice() override; + Return setDevice(const DeviceAddress& address) override; + Return setConnectedState(const DeviceAddress& address, bool connected) override; + Return setHwAvSync(uint32_t hwAvSync) override; + Return getParameters( + const hidl_vec& keys, getParameters_cb _hidl_cb) override; + Return setParameters(const hidl_vec& parameters) override; + Return debugDump(const native_handle_t* fd) override; + + // Methods from ::android::hardware::audio::V2_0::IStreamIn follow. + Return getAudioSource(getAudioSource_cb _hidl_cb) override; + Return setGain(float gain) override; + Return read(uint64_t size, read_cb _hidl_cb) override; + Return getInputFramesLost() override; + Return getCapturePosition(getCapturePosition_cb _hidl_cb) override; + + private: + audio_hw_device_t *mDevice; + audio_stream_in_t *mStream; + sp mStreamCommon; + + virtual ~StreamIn(); +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace audio +} // namespace hardware +} // namespace android + +#endif // HIDL_GENERATED_android_hardware_audio_V2_0_StreamIn_H_ diff --git a/audio/2.0/default/StreamOut.cpp b/audio/2.0/default/StreamOut.cpp new file mode 100644 index 0000000000..34bae29cc2 --- /dev/null +++ b/audio/2.0/default/StreamOut.cpp @@ -0,0 +1,275 @@ +/* + * 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. + */ + +#define LOG_TAG "StreamOutHAL" + +#include +#include + +#include "StreamOut.h" + +namespace android { +namespace hardware { +namespace audio { +namespace V2_0 { +namespace implementation { + +StreamOut::StreamOut(audio_hw_device_t* device, audio_stream_out_t* stream) + : mDevice(device), mStream(stream), mStreamCommon(new Stream(&stream->common)) { +} + +StreamOut::~StreamOut() { + mCallback.clear(); + mDevice->close_output_stream(mDevice, mStream); + mStream = nullptr; + mDevice = nullptr; +} + +// Methods from ::android::hardware::audio::V2_0::IStream follow. +Return StreamOut::getFrameSize() { + return audio_stream_out_frame_size(mStream); +} + +Return StreamOut::getFrameCount() { + return mStreamCommon->getFrameCount(); +} + +Return StreamOut::getBufferSize() { + return mStreamCommon->getBufferSize(); +} + +Return StreamOut::getSampleRate() { + return mStreamCommon->getSampleRate(); +} + +Return StreamOut::getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) { + return mStreamCommon->getSupportedSampleRates(_hidl_cb); +} + +Return StreamOut::setSampleRate(uint32_t sampleRateHz) { + return mStreamCommon->setSampleRate(sampleRateHz); +} + +Return StreamOut::getChannelMask() { + return mStreamCommon->getChannelMask(); +} + +Return StreamOut::getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) { + return mStreamCommon->getSupportedChannelMasks(_hidl_cb); +} + +Return StreamOut::setChannelMask(AudioChannelMask mask) { + return mStreamCommon->setChannelMask(mask); +} + +Return StreamOut::getFormat() { + return mStreamCommon->getFormat(); +} + +Return StreamOut::getSupportedFormats(getSupportedFormats_cb _hidl_cb) { + return mStreamCommon->getSupportedFormats(_hidl_cb); +} + +Return StreamOut::setFormat(AudioFormat format) { + return mStreamCommon->setFormat(format); +} + +Return StreamOut::getAudioProperties(getAudioProperties_cb _hidl_cb) { + return mStreamCommon->getAudioProperties(_hidl_cb); +} + +Return StreamOut::addEffect(uint64_t effectId) { + return mStreamCommon->addEffect(effectId); +} + +Return StreamOut::removeEffect(uint64_t effectId) { + return mStreamCommon->removeEffect(effectId); +} + +Return StreamOut::standby() { + return mStreamCommon->standby(); +} + +Return StreamOut::getDevice() { + return mStreamCommon->getDevice(); +} + +Return StreamOut::setDevice(const DeviceAddress& address) { + return mStreamCommon->setDevice(address); +} + +Return StreamOut::setConnectedState(const DeviceAddress& address, bool connected) { + return mStreamCommon->setConnectedState(address, connected); +} + +Return StreamOut::setHwAvSync(uint32_t hwAvSync) { + return mStreamCommon->setHwAvSync(hwAvSync); +} + +Return StreamOut::getParameters( + const hidl_vec& keys, getParameters_cb _hidl_cb) { + return mStreamCommon->getParameters(keys, _hidl_cb); +} + +Return StreamOut::setParameters(const hidl_vec& parameters) { + return mStreamCommon->setParameters(parameters); +} + +Return StreamOut::debugDump(const native_handle_t* fd) { + return mStreamCommon->debugDump(fd); +} + + +// Methods from ::android::hardware::audio::V2_0::IStreamOut follow. +Return StreamOut::getLatency() { + return mStream->get_latency(mStream); +} + +Return StreamOut::setVolume(float left, float right) { + Result retval(Result::NOT_SUPPORTED); + if (mStream->set_volume != NULL) { + retval = mStreamCommon->analyzeStatus( + "set_volume", mStream->set_volume(mStream, left, right)); + } + return retval; +} + +Return StreamOut::write(const hidl_vec& data, write_cb _hidl_cb) { + // TODO(mnaganov): Replace with FMQ version. + Result retval(Result::OK); + uint64_t written = 0; + ssize_t writeResult = mStream->write(mStream, &data[0], data.size()); + if (writeResult >= 0) { + written = writeResult; + } else { + retval = mStreamCommon->analyzeStatus("write", writeResult); + written = 0; + } + _hidl_cb(retval, written); + return Void(); +} + +Return StreamOut::getRenderPosition(getRenderPosition_cb _hidl_cb) { + uint32_t halDspFrames; + Result retval = mStreamCommon->analyzeStatus( + "get_render_position", mStream->get_render_position(mStream, &halDspFrames)); + _hidl_cb(retval, halDspFrames); + return Void(); +} + +Return StreamOut::getNextWriteTimestamp(getNextWriteTimestamp_cb _hidl_cb) { + Result retval(Result::NOT_SUPPORTED); + int64_t timestampUs = 0; + if (mStream->get_next_write_timestamp != NULL) { + retval = mStreamCommon->analyzeStatus( + "get_next_write_timestamp", + mStream->get_next_write_timestamp(mStream, ×tampUs)); + } + _hidl_cb(retval, timestampUs); + return Void(); +} + +Return StreamOut::setCallback(const sp& callback) { + if (mStream->set_callback == NULL) return Result::NOT_SUPPORTED; + int result = mStream->set_callback(mStream, StreamOut::asyncCallback, this); + if (result == 0) { + mCallback = callback; + } + return mStreamCommon->analyzeStatus("set_callback", result); +} + +// static +int StreamOut::asyncCallback(stream_callback_event_t event, void*, void *cookie) { + wp weakSelf(reinterpret_cast(cookie)); + sp self = weakSelf.promote(); + if (self == 0) return 0; + sp callback = self->mCallback.promote(); + if (callback == 0) return 0; + ALOGV("asyncCallback() event %d", event); + switch (event) { + case STREAM_CBK_EVENT_WRITE_READY: + callback->onWriteReady(); + break; + case STREAM_CBK_EVENT_DRAIN_READY: + callback->onDrainReady(); + break; + case STREAM_CBK_EVENT_ERROR: + callback->onError(); + break; + default: + ALOGW("asyncCallback() unknown event %d", event); + break; + } + return 0; +} + +Return StreamOut::supportsPauseAndResume(supportsPauseAndResume_cb _hidl_cb) { + _hidl_cb(mStream->pause != NULL, mStream->resume != NULL); + return Void(); +} + +Return StreamOut::pause() { + return mStream->pause != NULL ? + mStreamCommon->analyzeStatus("pause", mStream->pause(mStream)) : + Result::NOT_SUPPORTED; +} + +Return StreamOut::resume() { + return mStream->resume != NULL ? + mStreamCommon->analyzeStatus("resume", mStream->resume(mStream)) : + Result::NOT_SUPPORTED; +} + +Return StreamOut::supportsDrain() { + return mStream->drain != NULL; +} + +Return StreamOut::drain(AudioDrain type) { + return mStream->drain != NULL ? + mStreamCommon->analyzeStatus( + "drain", mStream->drain(mStream, static_cast(type))) : + Result::NOT_SUPPORTED; +} + +Return StreamOut::flush() { + return mStream->flush != NULL ? + mStreamCommon->analyzeStatus("flush", mStream->flush(mStream)) : + Result::NOT_SUPPORTED; +} + +Return StreamOut::getPresentationPosition(getPresentationPosition_cb _hidl_cb) { + Result retval(Result::NOT_SUPPORTED); + uint64_t frames = 0; + TimeSpec timeStamp = { 0, 0 }; + if (mStream->get_presentation_position != NULL) { + struct timespec halTimeStamp; + retval = mStreamCommon->analyzeStatus( + "get_presentation_position", + mStream->get_presentation_position(mStream, &frames, &halTimeStamp)); + if (retval == Result::OK) { + timeStamp.tvSec = halTimeStamp.tv_sec; + timeStamp.tvNSec = halTimeStamp.tv_nsec; + } + } + _hidl_cb(retval, frames, timeStamp); + return Void(); +} + +} // namespace implementation +} // namespace V2_0 +} // namespace audio +} // namespace hardware +} // namespace android diff --git a/audio/2.0/default/StreamOut.h b/audio/2.0/default/StreamOut.h new file mode 100644 index 0000000000..51b7df800b --- /dev/null +++ b/audio/2.0/default/StreamOut.h @@ -0,0 +1,113 @@ +/* + * 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. + */ + +#ifndef HIDL_GENERATED_android_hardware_audio_V2_0_StreamOut_H_ +#define HIDL_GENERATED_android_hardware_audio_V2_0_StreamOut_H_ + +#include +#include + +#include + +#include "Stream.h" + +namespace android { +namespace hardware { +namespace audio { +namespace V2_0 { +namespace implementation { + +using ::android::hardware::audio::common::V2_0::AudioChannelMask; +using ::android::hardware::audio::common::V2_0::AudioDevice; +using ::android::hardware::audio::common::V2_0::AudioFormat; +using ::android::hardware::audio::V2_0::AudioDrain; +using ::android::hardware::audio::V2_0::DeviceAddress; +using ::android::hardware::audio::V2_0::IStream; +using ::android::hardware::audio::V2_0::IStreamOut; +using ::android::hardware::audio::V2_0::IStreamOutCallback; +using ::android::hardware::audio::V2_0::ParameterValue; +using ::android::hardware::audio::V2_0::Result; +using ::android::hardware::audio::V2_0::TimeSpec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +struct StreamOut : public IStreamOut { + StreamOut(audio_hw_device_t* device, audio_stream_out_t* stream); + + // Methods from ::android::hardware::audio::V2_0::IStream follow. + Return getFrameSize() override; + Return getFrameCount() override; + Return getBufferSize() override; + Return getSampleRate() override; + Return getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) override; + Return setSampleRate(uint32_t sampleRateHz) override; + Return getChannelMask() override; + Return getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) override; + Return setChannelMask(AudioChannelMask mask) override; + Return getFormat() override; + Return getSupportedFormats(getSupportedFormats_cb _hidl_cb) override; + Return setFormat(AudioFormat format) override; + Return getAudioProperties(getAudioProperties_cb _hidl_cb) override; + Return addEffect(uint64_t effectId) override; + Return removeEffect(uint64_t effectId) override; + Return standby() override; + Return getDevice() override; + Return setDevice(const DeviceAddress& address) override; + Return setConnectedState(const DeviceAddress& address, bool connected) override; + Return setHwAvSync(uint32_t hwAvSync) override; + Return getParameters( + const hidl_vec& keys, getParameters_cb _hidl_cb) override; + Return setParameters(const hidl_vec& parameters) override; + Return debugDump(const native_handle_t* fd) override; + + // Methods from ::android::hardware::audio::V2_0::IStreamOut follow. + Return getLatency() override; + Return setVolume(float left, float right) override; + Return write(const hidl_vec& data, write_cb _hidl_cb) override; + Return getRenderPosition(getRenderPosition_cb _hidl_cb) override; + Return getNextWriteTimestamp(getNextWriteTimestamp_cb _hidl_cb) override; + Return setCallback(const sp& callback) override; + Return supportsPauseAndResume(supportsPauseAndResume_cb _hidl_cb) override; + Return pause() override; + Return resume() override; + Return supportsDrain() override; + Return drain(AudioDrain type) override; + Return flush() override; + Return getPresentationPosition(getPresentationPosition_cb _hidl_cb) override; + + private: + audio_hw_device_t *mDevice; + audio_stream_out_t *mStream; + sp mStreamCommon; + // Do not store sp<> to avoid creating a reference loop if the entity that holds + // onto the output stream owns or implements the callback. + wp mCallback; + + virtual ~StreamOut(); + + static int asyncCallback(stream_callback_event_t event, void *param, void *cookie); +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace audio +} // namespace hardware +} // namespace android + +#endif // HIDL_GENERATED_android_hardware_audio_V2_0_StreamOut_H_ diff --git a/audio/2.0/default/service.cpp b/audio/2.0/default/service.cpp index 39708c2f01..147f7b920e 100644 --- a/audio/2.0/default/service.cpp +++ b/audio/2.0/default/service.cpp @@ -14,28 +14,23 @@ * limitations under the License. */ -#define LOG_TAG "soundtriggerhal" +#define LOG_TAG "audiohalservice" -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include #include using android::hardware::IPCThreadState; using android::hardware::ProcessState; +using android::hardware::audio::effect::V2_0::IEffectsFactory; +using android::hardware::audio::V2_0::IDevicesFactory; using android::hardware::soundtrigger::V2_0::ISoundTriggerHw; +using android::hardware::registerPassthroughServiceImplementation; int main(int /* argc */, char* /* argv */ []) { - android::sp service = - ISoundTriggerHw::getService("sound_trigger.primary", true /* getStub */); - - service->registerAsService("sound_trigger.primary"); - - ProcessState::self()->setThreadPoolMaxThreadCount(0); - ProcessState::self()->startThreadPool(); - IPCThreadState::self()->joinThreadPool(); + registerPassthroughServiceImplementation("audio_devices_factory"); + registerPassthroughServiceImplementation("audio_effects_factory"); + registerPassthroughServiceImplementation("sound_trigger.primary"); + return android::hardware::launchRpcServer(16); } diff --git a/audio/2.0/types.hal b/audio/2.0/types.hal index 63698854d5..9a5e4f1ade 100644 --- a/audio/2.0/types.hal +++ b/audio/2.0/types.hal @@ -66,7 +66,7 @@ struct DeviceAddress { int32_t card; int32_t device; } alsa; // used for USB_* - int32_t busId; // used for BUS } address; + string busAddress; // used for BUS string rSubmixAddress; // used for REMOTE_SUBMIX }; diff --git a/audio/common/2.0/default/Android.mk b/audio/common/2.0/default/Android.mk new file mode 100644 index 0000000000..aa60eb269f --- /dev/null +++ b/audio/common/2.0/default/Android.mk @@ -0,0 +1,29 @@ +# +# 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. + + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.audio.common@2.0-util +LOCAL_SRC_FILES := \ + EffectMap.cpp \ + +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) + +LOCAL_SHARED_LIBRARIES := \ + libutils \ + +include $(BUILD_SHARED_LIBRARY) diff --git a/audio/common/2.0/default/EffectMap.cpp b/audio/common/2.0/default/EffectMap.cpp new file mode 100644 index 0000000000..703b91cfec --- /dev/null +++ b/audio/common/2.0/default/EffectMap.cpp @@ -0,0 +1,57 @@ +/* + * 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 + +#include "EffectMap.h" + +namespace android { + +ANDROID_SINGLETON_STATIC_INSTANCE(EffectMap); + +// static +const uint64_t EffectMap::INVALID_ID = 0; + +// static +uint64_t EffectMap::makeUniqueId() { + static std::atomic counter{INVALID_ID + 1}; + return counter++; +} + +uint64_t EffectMap::add(effect_handle_t handle) { + uint64_t newId = makeUniqueId(); + std::lock_guard lock(mLock); + mEffects.add(newId, handle); + return newId; +} + +effect_handle_t EffectMap::get(const uint64_t& id) { + std::lock_guard lock(mLock); + ssize_t idx = mEffects.indexOfKey(id); + return idx >= 0 ? mEffects[idx] : NULL; +} + +void EffectMap::remove(effect_handle_t handle) { + std::lock_guard lock(mLock); + for (size_t i = 0; i < mEffects.size(); ++i) { + if (mEffects[i] == handle) { + mEffects.removeItemsAt(i); + break; + } + } +} + +} // namespace android diff --git a/audio/common/2.0/default/EffectMap.h b/audio/common/2.0/default/EffectMap.h new file mode 100644 index 0000000000..82bbb1fb09 --- /dev/null +++ b/audio/common/2.0/default/EffectMap.h @@ -0,0 +1,46 @@ +/* + * 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. + */ + +#ifndef android_hardware_audio_V2_0_EffectMap_H_ +#define android_hardware_audio_V2_0_EffectMap_H_ + +#include + +#include +#include +#include + +namespace android { + +// This class needs to be in 'android' ns because Singleton macros require that. +class EffectMap : public Singleton { + public: + static const uint64_t INVALID_ID; + + uint64_t add(effect_handle_t handle); + effect_handle_t get(const uint64_t& id); + void remove(effect_handle_t handle); + + private: + static uint64_t makeUniqueId(); + + std::mutex mLock; + KeyedVector mEffects; +}; + +} // namespace android + +#endif // android_hardware_audio_V2_0_EffectMap_H_ diff --git a/audio/common/2.0/types.hal b/audio/common/2.0/types.hal index a5ec68d0e7..75fdb52793 100644 --- a/audio/common/2.0/types.hal +++ b/audio/common/2.0/types.hal @@ -555,8 +555,7 @@ enum AudioDevice : uint32_t { IN_IP = BIT_IN | 0x80000, /* audio bus implemented by the audio system (e.g an MOST stereo channel) */ IN_BUS = BIT_IN | 0x100000, - IN_DEFAULT = BIT_IN | - BIT_DEFAULT, + IN_DEFAULT = BIT_IN | BIT_DEFAULT, IN_ALL = (IN_COMMUNICATION | IN_AMBIENT | @@ -798,10 +797,10 @@ struct AudioPortConfig { union UseCase { AudioStreamType stream; AudioSource source; - }; + } useCase; } mix; AudioPortConfigSessionExt session; - }; + } ext; }; /* @@ -849,16 +848,5 @@ struct AudioPort { AudioPortDeviceExt device; AudioPortMixExt mix; AudioPortSessionExt session; - }; -}; - -/* - * An audio patch represents a connection between one or more source ports and - * one or more sink ports. Patches are connected and disconnected by audio - * policy manager or by applications via framework APIs. - */ -struct AudioPatch { - AudioPatchHandle id; - vec sources; - vec sinks; + } ext; }; diff --git a/audio/effect/2.0/IEffectsFactory.hal b/audio/effect/2.0/IEffectsFactory.hal index 6763825665..c82b4a2ebe 100644 --- a/audio/effect/2.0/IEffectsFactory.hal +++ b/audio/effect/2.0/IEffectsFactory.hal @@ -50,9 +50,11 @@ interface IEffectsFactory { * directed to in audio HAL. * @return retval operation completion status. * @return result the interface for the created effect. + * @return effectId the unique ID of the effect to be used with + * IStream::addEffect and IStream::removeEffect methods. */ createEffect(Uuid uid, AudioSession session, AudioIoHandle ioHandle) - generates (Result retval, IEffect result); + generates (Result retval, IEffect result, uint64_t effectId); /* * Dumps information about effects into the provided file descriptor. diff --git a/audio/effect/2.0/default/Android.mk b/audio/effect/2.0/default/Android.mk index 13106f3a4d..50c4bd6d30 100644 --- a/audio/effect/2.0/default/Android.mk +++ b/audio/effect/2.0/default/Android.mk @@ -26,6 +26,7 @@ LOCAL_SHARED_LIBRARIES := \ libeffects \ liblog \ android.hardware.audio.common@2.0 \ + android.hardware.audio.common@2.0-util \ android.hardware.audio.effect@2.0 \ include $(BUILD_SHARED_LIBRARY) diff --git a/audio/effect/2.0/default/Effect.cpp b/audio/effect/2.0/default/Effect.cpp index 8ab0749871..82d0292d4e 100644 --- a/audio/effect/2.0/default/Effect.cpp +++ b/audio/effect/2.0/default/Effect.cpp @@ -23,6 +23,7 @@ #include "Conversions.h" #include "Effect.h" +#include "EffectMap.h" namespace android { namespace hardware { @@ -45,6 +46,7 @@ Effect::Effect(effect_handle_t handle) : mHandle(handle) { Effect::~Effect() { int status = EffectRelease(mHandle); ALOGW_IF(status, "Error releasing effect %p: %s", mHandle, strerror(-status)); + EffectMap::getInstance().remove(mHandle); mHandle = 0; } diff --git a/audio/effect/2.0/default/EffectsFactory.cpp b/audio/effect/2.0/default/EffectsFactory.cpp index f7c5d628b0..30fcb26722 100644 --- a/audio/effect/2.0/default/EffectsFactory.cpp +++ b/audio/effect/2.0/default/EffectsFactory.cpp @@ -36,6 +36,7 @@ #include "EffectsFactory.h" #include "DownmixEffect.h" #include "Effect.h" +#include "EffectMap.h" #include "EnvironmentalReverbEffect.h" #include "EqualizerEffect.h" #include "LoudnessEnhancerEffect.h" @@ -157,12 +158,16 @@ Return EffectsFactory::createEffect( Result retval(Result::OK); status_t status = EffectCreate(&halUuid, session, ioHandle, &handle); sp effect; + uint64_t effectId = EffectMap::INVALID_ID; if (status == OK) { effect_descriptor_t halDescriptor; memset(&halDescriptor, 0, sizeof(effect_descriptor_t)); status = (*handle)->get_descriptor(handle, &halDescriptor); if (status == OK) { effect = dispatchEffectInstanceCreation(halDescriptor, handle); + effectId = EffectMap::getInstance().add(handle); + } else { + EffectRelease(handle); } } if (status != OK) { @@ -173,7 +178,7 @@ Return EffectsFactory::createEffect( retval = Result::NOT_INITIALIZED; } } - _hidl_cb(retval, effect); + _hidl_cb(retval, effect, effectId); return Void(); } diff --git a/audio/effect/2.0/vts/functional/audio_effect_hidl_hal_test.cpp b/audio/effect/2.0/vts/functional/audio_effect_hidl_hal_test.cpp index ddd5eacec3..c7878d541c 100644 --- a/audio/effect/2.0/vts/functional/audio_effect_hidl_hal_test.cpp +++ b/audio/effect/2.0/vts/functional/audio_effect_hidl_hal_test.cpp @@ -84,13 +84,14 @@ TEST_F(AudioEffectHidlTest, CreateEffect) { ASSERT_TRUE(gotEffect); Result retval = Result::NOT_INITIALIZED; sp effect; - ret = effectsFactory->createEffect(effectUuid, 1, 1, - [&](Result r, const sp& result) { - retval = r; - if (r == Result::OK) { - effect = result; - } - }); + ret = effectsFactory->createEffect( + effectUuid, 1 /* session */, 1 /* ioHandle */, + [&](Result r, const sp& result, uint64_t /*effectId*/) { + retval = r; + if (r == Result::OK) { + effect = result; + } + }); EXPECT_EQ(ret.getStatus().exceptionCode(), Status::EX_NONE); EXPECT_EQ(retval, Result::OK); EXPECT_NE(effect, nullptr);