Merge changes from topic 'audio-primary-hal-vts-fix' into oc-dev

am: 257c2f1a43

Change-Id: Ic8850d915b5672e7529f99e7d57845b2de44857a
This commit is contained in:
Kevin Rocard
2017-05-12 06:57:47 +00:00
committed by android-build-merger
8 changed files with 1163 additions and 752 deletions

View File

@@ -1,18 +1,18 @@
/*
* 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.
*/
/*
* 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"
//#define LOG_NDEBUG 0
@@ -30,6 +30,7 @@
#include "HidlUtils.h"
#include "StreamIn.h"
#include "StreamOut.h"
#include "Util.h"
namespace android {
namespace hardware {
@@ -92,7 +93,8 @@ Device::Device(audio_hw_device_t* device, const char* type)
Device::~Device() {
int status = audio_hw_device_close(mDevice);
ALOGW_IF(status, "Error closing audio hw device %p: %s", mDevice, strerror(-status));
ALOGW_IF(status, "Error closing audio hw device %p: %s", mDevice,
strerror(-status));
mDevice = nullptr;
}
@@ -101,12 +103,18 @@ Result Device::analyzeStatus(const char* funcName, int status) {
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;
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;
}
}
@@ -129,59 +137,67 @@ int Device::halSetParameters(const char* keysAndValues) {
}
// Methods from ::android::hardware::audio::V2_0::IDevice follow.
Return<Result> Device::initCheck() {
Return<Result> Device::initCheck() {
return analyzeStatus("init_check", mDevice->init_check(mDevice));
}
Return<Result> 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<Result> Device::setMasterVolume(float volume) {
if (mDevice->set_master_volume == NULL) {
return Result::NOT_SUPPORTED;
}
return retval;
if (!isGainNormalized(volume)) {
ALOGW("Can not set a master volume (%f) outside [0,1]", volume);
return Result::INVALID_ARGUMENTS;
}
return analyzeStatus("set_master_volume",
mDevice->set_master_volume(mDevice, volume));
}
Return<void> Device::getMasterVolume(getMasterVolume_cb _hidl_cb) {
Return<void> 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));
retval = analyzeStatus("get_master_volume",
mDevice->get_master_volume(mDevice, &volume));
}
_hidl_cb(retval, volume);
return Void();
}
Return<Result> Device::setMicMute(bool mute) {
Return<Result> Device::setMicMute(bool mute) {
return analyzeStatus("set_mic_mute", mDevice->set_mic_mute(mDevice, mute));
}
Return<void> Device::getMicMute(getMicMute_cb _hidl_cb) {
Return<void> Device::getMicMute(getMicMute_cb _hidl_cb) {
bool mute = false;
Result retval = analyzeStatus("get_mic_mute", mDevice->get_mic_mute(mDevice, &mute));
Result retval =
analyzeStatus("get_mic_mute", mDevice->get_mic_mute(mDevice, &mute));
_hidl_cb(retval, mute);
return Void();
}
Return<Result> Device::setMasterMute(bool mute) {
Return<Result> 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));
retval = analyzeStatus("set_master_mute",
mDevice->set_master_mute(mDevice, mute));
}
return retval;
}
Return<void> Device::getMasterMute(getMasterMute_cb _hidl_cb) {
Return<void> 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));
retval = analyzeStatus("get_master_mute",
mDevice->get_master_mute(mDevice, &mute));
}
_hidl_cb(retval, mute);
return Void();
}
Return<void> Device::getInputBufferSize(
const AudioConfig& config, getInputBufferSize_cb _hidl_cb) {
Return<void> Device::getInputBufferSize(const AudioConfig& config,
getInputBufferSize_cb _hidl_cb) {
audio_config_t halConfig;
HidlUtils::audioConfigToHal(config, &halConfig);
size_t halBufferSize = mDevice->get_input_buffer_size(mDevice, &halConfig);
@@ -195,29 +211,25 @@ Return<void> Device::getInputBufferSize(
return Void();
}
Return<void> Device::openOutputStream(
int32_t ioHandle,
const DeviceAddress& device,
const AudioConfig& config,
AudioOutputFlag flags,
openOutputStream_cb _hidl_cb) {
Return<void> Device::openOutputStream(int32_t ioHandle,
const DeviceAddress& device,
const AudioConfig& config,
AudioOutputFlag flags,
openOutputStream_cb _hidl_cb) {
audio_config_t halConfig;
HidlUtils::audioConfigToHal(config, &halConfig);
audio_stream_out_t *halStream;
ALOGV("open_output_stream handle: %d devices: %x flags: %#x "
"srate: %d format %#x channels %x address %s",
ioHandle,
static_cast<audio_devices_t>(device.device), static_cast<audio_output_flags_t>(flags),
halConfig.sample_rate, halConfig.format, halConfig.channel_mask,
deviceAddressToHal(device).c_str());
audio_stream_out_t* halStream;
ALOGV(
"open_output_stream handle: %d devices: %x flags: %#x "
"srate: %d format %#x channels %x address %s",
ioHandle, static_cast<audio_devices_t>(device.device),
static_cast<audio_output_flags_t>(flags), halConfig.sample_rate,
halConfig.format, halConfig.channel_mask,
deviceAddressToHal(device).c_str());
int status = mDevice->open_output_stream(
mDevice,
ioHandle,
static_cast<audio_devices_t>(device.device),
static_cast<audio_output_flags_t>(flags),
&halConfig,
&halStream,
deviceAddressToHal(device).c_str());
mDevice, ioHandle, static_cast<audio_devices_t>(device.device),
static_cast<audio_output_flags_t>(flags), &halConfig, &halStream,
deviceAddressToHal(device).c_str());
ALOGV("open_output_stream status %d stream %p", status, halStream);
sp<IStreamOut> streamOut;
if (status == OK) {
@@ -225,35 +237,32 @@ Return<void> Device::openOutputStream(
}
AudioConfig suggestedConfig;
HidlUtils::audioConfigFromHal(halConfig, &suggestedConfig);
_hidl_cb(analyzeStatus("open_output_stream", status), streamOut, suggestedConfig);
_hidl_cb(analyzeStatus("open_output_stream", status), streamOut,
suggestedConfig);
return Void();
}
Return<void> Device::openInputStream(
int32_t ioHandle,
const DeviceAddress& device,
const AudioConfig& config,
AudioInputFlag flags,
AudioSource source,
openInputStream_cb _hidl_cb) {
Return<void> Device::openInputStream(int32_t ioHandle,
const DeviceAddress& device,
const AudioConfig& config,
AudioInputFlag flags, AudioSource source,
openInputStream_cb _hidl_cb) {
audio_config_t halConfig;
HidlUtils::audioConfigToHal(config, &halConfig);
audio_stream_in_t *halStream;
ALOGV("open_input_stream handle: %d devices: %x flags: %#x "
"srate: %d format %#x channels %x address %s source %d",
ioHandle,
static_cast<audio_devices_t>(device.device), static_cast<audio_input_flags_t>(flags),
halConfig.sample_rate, halConfig.format, halConfig.channel_mask,
deviceAddressToHal(device).c_str(), static_cast<audio_source_t>(source));
audio_stream_in_t* halStream;
ALOGV(
"open_input_stream handle: %d devices: %x flags: %#x "
"srate: %d format %#x channels %x address %s source %d",
ioHandle, static_cast<audio_devices_t>(device.device),
static_cast<audio_input_flags_t>(flags), halConfig.sample_rate,
halConfig.format, halConfig.channel_mask,
deviceAddressToHal(device).c_str(),
static_cast<audio_source_t>(source));
int status = mDevice->open_input_stream(
mDevice,
ioHandle,
static_cast<audio_devices_t>(device.device),
&halConfig,
&halStream,
static_cast<audio_input_flags_t>(flags),
deviceAddressToHal(device).c_str(),
static_cast<audio_source_t>(source));
mDevice, ioHandle, static_cast<audio_devices_t>(device.device),
&halConfig, &halStream, static_cast<audio_input_flags_t>(flags),
deviceAddressToHal(device).c_str(),
static_cast<audio_source_t>(source));
ALOGV("open_input_stream status %d stream %p", status, halStream);
sp<IStreamIn> streamIn;
if (status == OK) {
@@ -261,7 +270,8 @@ Return<void> Device::openInputStream(
}
AudioConfig suggestedConfig;
HidlUtils::audioConfigFromHal(halConfig, &suggestedConfig);
_hidl_cb(analyzeStatus("open_input_stream", status), streamIn, suggestedConfig);
_hidl_cb(analyzeStatus("open_input_stream", status), streamIn,
suggestedConfig);
return Void();
}
@@ -269,23 +279,21 @@ Return<bool> Device::supportsAudioPatches() {
return version() >= AUDIO_DEVICE_API_VERSION_3_0;
}
Return<void> Device::createAudioPatch(
const hidl_vec<AudioPortConfig>& sources,
const hidl_vec<AudioPortConfig>& sinks,
createAudioPatch_cb _hidl_cb) {
Return<void> Device::createAudioPatch(const hidl_vec<AudioPortConfig>& sources,
const hidl_vec<AudioPortConfig>& sinks,
createAudioPatch_cb _hidl_cb) {
Result retval(Result::NOT_SUPPORTED);
AudioPatchHandle patch = 0;
if (version() >= AUDIO_DEVICE_API_VERSION_3_0) {
std::unique_ptr<audio_port_config[]> halSources(HidlUtils::audioPortConfigsToHal(sources));
std::unique_ptr<audio_port_config[]> halSinks(HidlUtils::audioPortConfigsToHal(sinks));
std::unique_ptr<audio_port_config[]> halSources(
HidlUtils::audioPortConfigsToHal(sources));
std::unique_ptr<audio_port_config[]> halSinks(
HidlUtils::audioPortConfigsToHal(sinks));
audio_patch_handle_t halPatch = AUDIO_PATCH_HANDLE_NONE;
retval = analyzeStatus(
"create_audio_patch",
mDevice->create_audio_patch(
mDevice,
sources.size(), &halSources[0],
sinks.size(), &halSinks[0],
&halPatch));
"create_audio_patch",
mDevice->create_audio_patch(mDevice, sources.size(), &halSources[0],
sinks.size(), &halSinks[0], &halPatch));
if (retval == Result::OK) {
patch = static_cast<AudioPatchHandle>(halPatch);
}
@@ -294,19 +302,22 @@ Return<void> Device::createAudioPatch(
return Void();
}
Return<Result> Device::releaseAudioPatch(int32_t patch) {
Return<Result> 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<audio_patch_handle_t>(patch)));
"release_audio_patch",
mDevice->release_audio_patch(
mDevice, static_cast<audio_patch_handle_t>(patch)));
}
return Result::NOT_SUPPORTED;
}
Return<void> Device::getAudioPort(const AudioPort& port, getAudioPort_cb _hidl_cb) {
Return<void> Device::getAudioPort(const AudioPort& port,
getAudioPort_cb _hidl_cb) {
audio_port halPort;
HidlUtils::audioPortToHal(port, &halPort);
Result retval = analyzeStatus("get_audio_port", mDevice->get_audio_port(mDevice, &halPort));
Result retval = analyzeStatus("get_audio_port",
mDevice->get_audio_port(mDevice, &halPort));
AudioPort resultPort = port;
if (retval == Result::OK) {
HidlUtils::audioPortFromHal(halPort, &resultPort);
@@ -315,36 +326,39 @@ Return<void> Device::getAudioPort(const AudioPort& port, getAudioPort_cb _hidl_c
return Void();
}
Return<Result> Device::setAudioPortConfig(const AudioPortConfig& config) {
Return<Result> Device::setAudioPortConfig(const AudioPortConfig& config) {
if (version() >= AUDIO_DEVICE_API_VERSION_3_0) {
struct audio_port_config halPortConfig;
HidlUtils::audioPortConfigToHal(config, &halPortConfig);
return analyzeStatus(
"set_audio_port_config", mDevice->set_audio_port_config(mDevice, &halPortConfig));
"set_audio_port_config",
mDevice->set_audio_port_config(mDevice, &halPortConfig));
}
return Result::NOT_SUPPORTED;
}
Return<AudioHwSync> Device::getHwAvSync() {
Return<AudioHwSync> Device::getHwAvSync() {
int halHwAvSync;
Result retval = getParam(AudioParameter::keyHwAvSync, &halHwAvSync);
return retval == Result::OK ? halHwAvSync : AUDIO_HW_SYNC_INVALID;
}
Return<Result> Device::setScreenState(bool turnedOn) {
Return<Result> Device::setScreenState(bool turnedOn) {
return setParam(AudioParameter::keyScreenState, turnedOn);
}
Return<void> Device::getParameters(const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) {
Return<void> Device::getParameters(const hidl_vec<hidl_string>& keys,
getParameters_cb _hidl_cb) {
getParametersImpl(keys, _hidl_cb);
return Void();
}
Return<Result> Device::setParameters(const hidl_vec<ParameterValue>& parameters) {
Return<Result> Device::setParameters(
const hidl_vec<ParameterValue>& parameters) {
return setParametersImpl(parameters);
}
Return<void> Device::debugDump(const hidl_handle& fd) {
Return<void> Device::debugDump(const hidl_handle& fd) {
if (fd.getNativeHandle() != nullptr && fd->numFds == 1) {
analyzeStatus("dump", mDevice->dump(mDevice, fd->data[0]));
}

View File

@@ -22,11 +22,31 @@ namespace audio {
namespace V2_0 {
namespace implementation {
// Static method and not private method to avoid leaking status_t dependency
static Result getHalStatusToResult(status_t status) {
switch (status) {
case OK:
return Result::OK;
case BAD_VALUE: // Nothing was returned, probably because the HAL does
// not handle it
return Result::NOT_SUPPORTED;
case INVALID_OPERATION: // Conversion from string to the requested type
// failed
return Result::INVALID_ARGUMENTS;
default: // Should not happen
ALOGW("Unexpected status returned by getParam: %u", status);
return Result::INVALID_ARGUMENTS;
}
}
Result ParametersUtil::getParam(const char* name, bool* value) {
String8 halValue;
Result retval = getParam(name, &halValue);
*value = false;
if (retval == Result::OK) {
if (halValue.empty()) {
return Result::NOT_SUPPORTED;
}
*value = !(halValue == AudioParameter::valueOff);
}
return retval;
@@ -37,8 +57,7 @@ Result ParametersUtil::getParam(const char* name, int* value) {
AudioParameter keys;
keys.addKey(halName);
std::unique_ptr<AudioParameter> params = getParams(keys);
status_t halStatus = params->getInt(halName, *value);
return halStatus == OK ? Result::OK : Result::INVALID_ARGUMENTS;
return getHalStatusToResult(params->getInt(halName, *value));
}
Result ParametersUtil::getParam(const char* name, String8* value) {
@@ -46,42 +65,41 @@ Result ParametersUtil::getParam(const char* name, String8* value) {
AudioParameter keys;
keys.addKey(halName);
std::unique_ptr<AudioParameter> params = getParams(keys);
status_t halStatus = params->get(halName, *value);
return halStatus == OK ? Result::OK : Result::INVALID_ARGUMENTS;
return getHalStatusToResult(params->get(halName, *value));
}
void ParametersUtil::getParametersImpl(
const hidl_vec<hidl_string>& keys,
std::function<void(Result retval, const hidl_vec<ParameterValue>& parameters)> cb) {
const hidl_vec<hidl_string>& keys,
std::function<void(Result retval,
const hidl_vec<ParameterValue>& parameters)>
cb) {
AudioParameter halKeys;
for (size_t i = 0; i < keys.size(); ++i) {
halKeys.addKey(String8(keys[i].c_str()));
}
std::unique_ptr<AudioParameter> halValues = getParams(halKeys);
Result retval(Result::INVALID_ARGUMENTS);
Result retval =
halValues->size() == keys.size() ? Result::OK : Result::NOT_SUPPORTED;
hidl_vec<ParameterValue> 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;
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);
retval = getHalStatusToResult(status);
break;
}
result[i].key = halKey.string();
result[i].value = halValue.string();
}
cb(retval, result);
}
std::unique_ptr<AudioParameter> ParametersUtil::getParams(const AudioParameter& keys) {
std::unique_ptr<AudioParameter> ParametersUtil::getParams(
const AudioParameter& keys) {
String8 paramsAndValues;
char *halValues = halGetParameters(keys.keysToString().string());
char* halValues = halGetParameters(keys.keysToString().string());
if (halValues != NULL) {
paramsAndValues.setTo(halValues);
free(halValues);
@@ -93,7 +111,8 @@ std::unique_ptr<AudioParameter> ParametersUtil::getParams(const AudioParameter&
Result ParametersUtil::setParam(const char* name, bool value) {
AudioParameter param;
param.add(String8(name), String8(value ? AudioParameter::valueOn : AudioParameter::valueOff));
param.add(String8(name), String8(value ? AudioParameter::valueOn
: AudioParameter::valueOff));
return setParams(param);
}
@@ -109,10 +128,12 @@ Result ParametersUtil::setParam(const char* name, const char* value) {
return setParams(param);
}
Result ParametersUtil::setParametersImpl(const hidl_vec<ParameterValue>& parameters) {
Result ParametersUtil::setParametersImpl(
const hidl_vec<ParameterValue>& 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()));
params.add(String8(parameters[i].key.c_str()),
String8(parameters[i].value.c_str()));
}
return setParams(params);
}

View File

@@ -30,56 +30,52 @@ PrimaryDevice::PrimaryDevice(audio_hw_device_t* device)
PrimaryDevice::~PrimaryDevice() {}
// Methods from ::android::hardware::audio::V2_0::IDevice follow.
Return<Result> PrimaryDevice::initCheck() {
Return<Result> PrimaryDevice::initCheck() {
return mDevice->initCheck();
}
Return<Result> PrimaryDevice::setMasterVolume(float volume) {
Return<Result> PrimaryDevice::setMasterVolume(float volume) {
return mDevice->setMasterVolume(volume);
}
Return<void> PrimaryDevice::getMasterVolume(getMasterVolume_cb _hidl_cb) {
Return<void> PrimaryDevice::getMasterVolume(getMasterVolume_cb _hidl_cb) {
return mDevice->getMasterVolume(_hidl_cb);
}
Return<Result> PrimaryDevice::setMicMute(bool mute) {
Return<Result> PrimaryDevice::setMicMute(bool mute) {
return mDevice->setMicMute(mute);
}
Return<void> PrimaryDevice::getMicMute(getMicMute_cb _hidl_cb) {
Return<void> PrimaryDevice::getMicMute(getMicMute_cb _hidl_cb) {
return mDevice->getMicMute(_hidl_cb);
}
Return<Result> PrimaryDevice::setMasterMute(bool mute) {
Return<Result> PrimaryDevice::setMasterMute(bool mute) {
return mDevice->setMasterMute(mute);
}
Return<void> PrimaryDevice::getMasterMute(getMasterMute_cb _hidl_cb) {
Return<void> PrimaryDevice::getMasterMute(getMasterMute_cb _hidl_cb) {
return mDevice->getMasterMute(_hidl_cb);
}
Return<void> PrimaryDevice::getInputBufferSize(
const AudioConfig& config, getInputBufferSize_cb _hidl_cb) {
Return<void> PrimaryDevice::getInputBufferSize(const AudioConfig& config,
getInputBufferSize_cb _hidl_cb) {
return mDevice->getInputBufferSize(config, _hidl_cb);
}
Return<void> PrimaryDevice::openOutputStream(
int32_t ioHandle,
const DeviceAddress& device,
const AudioConfig& config,
AudioOutputFlag flags,
openOutputStream_cb _hidl_cb) {
Return<void> 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<void> 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);
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<bool> PrimaryDevice::supportsAudioPatches() {
@@ -87,82 +83,97 @@ Return<bool> PrimaryDevice::supportsAudioPatches() {
}
Return<void> PrimaryDevice::createAudioPatch(
const hidl_vec<AudioPortConfig>& sources,
const hidl_vec<AudioPortConfig>& sinks,
createAudioPatch_cb _hidl_cb) {
const hidl_vec<AudioPortConfig>& sources,
const hidl_vec<AudioPortConfig>& sinks, createAudioPatch_cb _hidl_cb) {
return mDevice->createAudioPatch(sources, sinks, _hidl_cb);
}
Return<Result> PrimaryDevice::releaseAudioPatch(int32_t patch) {
Return<Result> PrimaryDevice::releaseAudioPatch(int32_t patch) {
return mDevice->releaseAudioPatch(patch);
}
Return<void> PrimaryDevice::getAudioPort(const AudioPort& port, getAudioPort_cb _hidl_cb) {
Return<void> PrimaryDevice::getAudioPort(const AudioPort& port,
getAudioPort_cb _hidl_cb) {
return mDevice->getAudioPort(port, _hidl_cb);
}
Return<Result> PrimaryDevice::setAudioPortConfig(const AudioPortConfig& config) {
Return<Result> PrimaryDevice::setAudioPortConfig(
const AudioPortConfig& config) {
return mDevice->setAudioPortConfig(config);
}
Return<AudioHwSync> PrimaryDevice::getHwAvSync() {
Return<AudioHwSync> PrimaryDevice::getHwAvSync() {
return mDevice->getHwAvSync();
}
Return<Result> PrimaryDevice::setScreenState(bool turnedOn) {
Return<Result> PrimaryDevice::setScreenState(bool turnedOn) {
return mDevice->setScreenState(turnedOn);
}
Return<void> PrimaryDevice::getParameters(
const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) {
Return<void> PrimaryDevice::getParameters(const hidl_vec<hidl_string>& keys,
getParameters_cb _hidl_cb) {
return mDevice->getParameters(keys, _hidl_cb);
}
Return<Result> PrimaryDevice::setParameters(const hidl_vec<ParameterValue>& parameters) {
Return<Result> PrimaryDevice::setParameters(
const hidl_vec<ParameterValue>& parameters) {
return mDevice->setParameters(parameters);
}
Return<void> PrimaryDevice::debugDump(const hidl_handle& fd) {
Return<void> PrimaryDevice::debugDump(const hidl_handle& fd) {
return mDevice->debugDump(fd);
}
// Methods from ::android::hardware::audio::V2_0::IPrimaryDevice follow.
Return<Result> PrimaryDevice::setVoiceVolume(float volume) {
Return<Result> PrimaryDevice::setVoiceVolume(float volume) {
return mDevice->analyzeStatus(
"set_voice_volume",
mDevice->device()->set_voice_volume(mDevice->device(), volume));
"set_voice_volume",
mDevice->device()->set_voice_volume(mDevice->device(), volume));
}
Return<Result> PrimaryDevice::setMode(AudioMode mode) {
Return<Result> PrimaryDevice::setMode(AudioMode mode) {
// INVALID, CURRENT, CNT, MAX are reserved for internal use.
// TODO: remove the values from the HIDL interface
switch (mode) {
case AudioMode::NORMAL:
case AudioMode::RINGTONE:
case AudioMode::IN_CALL:
case AudioMode::IN_COMMUNICATION:
break; // Valid values
default:
return Result::INVALID_ARGUMENTS;
};
return mDevice->analyzeStatus(
"set_mode",
mDevice->device()->set_mode(mDevice->device(), static_cast<audio_mode_t>(mode)));
"set_mode", mDevice->device()->set_mode(
mDevice->device(), static_cast<audio_mode_t>(mode)));
}
Return<void> PrimaryDevice::getBtScoNrecEnabled(getBtScoNrecEnabled_cb _hidl_cb) {
Return<void> PrimaryDevice::getBtScoNrecEnabled(
getBtScoNrecEnabled_cb _hidl_cb) {
bool enabled;
Result retval = mDevice->getParam(AudioParameter::keyBtNrec, &enabled);
_hidl_cb(retval, enabled);
return Void();
}
Return<Result> PrimaryDevice::setBtScoNrecEnabled(bool enabled) {
Return<Result> PrimaryDevice::setBtScoNrecEnabled(bool enabled) {
return mDevice->setParam(AudioParameter::keyBtNrec, enabled);
}
Return<void> PrimaryDevice::getBtScoWidebandEnabled(getBtScoWidebandEnabled_cb _hidl_cb) {
Return<void> 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<Result> PrimaryDevice::setBtScoWidebandEnabled(bool enabled) {
Return<Result> PrimaryDevice::setBtScoWidebandEnabled(bool enabled) {
return mDevice->setParam(AUDIO_PARAMETER_KEY_BT_SCO_WB, enabled);
}
Return<void> PrimaryDevice::getTtyMode(getTtyMode_cb _hidl_cb) {
Return<void> 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;
@@ -170,18 +181,19 @@ Return<void> PrimaryDevice::getTtyMode(getTtyMode_cb _hidl_cb) {
return Void();
}
Return<Result> PrimaryDevice::setTtyMode(IPrimaryDevice::TtyMode mode) {
return mDevice->setParam(AUDIO_PARAMETER_KEY_TTY_MODE, static_cast<int>(mode));
Return<Result> PrimaryDevice::setTtyMode(IPrimaryDevice::TtyMode mode) {
return mDevice->setParam(AUDIO_PARAMETER_KEY_TTY_MODE,
static_cast<int>(mode));
}
Return<void> PrimaryDevice::getHacEnabled(getHacEnabled_cb _hidl_cb) {
Return<void> PrimaryDevice::getHacEnabled(getHacEnabled_cb _hidl_cb) {
bool enabled;
Result retval = mDevice->getParam(AUDIO_PARAMETER_KEY_HAC, &enabled);
_hidl_cb(retval, enabled);
return Void();
}
Return<Result> PrimaryDevice::setHacEnabled(bool enabled) {
Return<Result> PrimaryDevice::setHacEnabled(bool enabled) {
return mDevice->setParam(AUDIO_PARAMETER_KEY_HAC, enabled);
}

View File

@@ -20,10 +20,11 @@
#include <android/log.h>
#include <hardware/audio.h>
#include <memory>
#include <utils/Trace.h>
#include <memory>
#include "StreamIn.h"
#include "Util.h"
using ::android::hardware::audio::V2_0::MessageQueueFlagBits;
@@ -38,30 +39,26 @@ using ::android::hardware::audio::common::V2_0::ThreadInfo;
namespace {
class ReadThread : public Thread {
public:
public:
// ReadThread's lifespan never exceeds StreamIn's lifespan.
ReadThread(std::atomic<bool>* stop,
audio_stream_in_t* stream,
StreamIn::CommandMQ* commandMQ,
StreamIn::DataMQ* dataMQ,
StreamIn::StatusMQ* statusMQ,
EventFlag* efGroup)
: Thread(false /*canCallJava*/),
mStop(stop),
mStream(stream),
mCommandMQ(commandMQ),
mDataMQ(dataMQ),
mStatusMQ(statusMQ),
mEfGroup(efGroup),
mBuffer(nullptr) {
}
ReadThread(std::atomic<bool>* stop, audio_stream_in_t* stream,
StreamIn::CommandMQ* commandMQ, StreamIn::DataMQ* dataMQ,
StreamIn::StatusMQ* statusMQ, EventFlag* efGroup)
: Thread(false /*canCallJava*/),
mStop(stop),
mStream(stream),
mCommandMQ(commandMQ),
mDataMQ(dataMQ),
mStatusMQ(statusMQ),
mEfGroup(efGroup),
mBuffer(nullptr) {}
bool init() {
mBuffer.reset(new(std::nothrow) uint8_t[mDataMQ->getQuantumCount()]);
mBuffer.reset(new (std::nothrow) uint8_t[mDataMQ->getQuantumCount()]);
return mBuffer != nullptr;
}
virtual ~ReadThread() {}
private:
private:
std::atomic<bool>* mStop;
audio_stream_in_t* mStream;
StreamIn::CommandMQ* mCommandMQ;
@@ -82,8 +79,10 @@ void ReadThread::doRead() {
size_t availableToWrite = mDataMQ->availableToWrite();
size_t requestedToRead = mParameters.params.read;
if (requestedToRead > availableToWrite) {
ALOGW("truncating read data from %d to %d due to insufficient data queue space",
(int32_t)requestedToRead, (int32_t)availableToWrite);
ALOGW(
"truncating read data from %d to %d due to insufficient data queue "
"space",
(int32_t)requestedToRead, (int32_t)availableToWrite);
requestedToRead = availableToWrite;
}
ssize_t readResult = mStream->read(mStream, &mBuffer[0], requestedToRead);
@@ -101,16 +100,20 @@ void ReadThread::doRead() {
void ReadThread::doGetCapturePosition() {
mStatus.retval = StreamIn::getCapturePositionImpl(
mStream, &mStatus.reply.capturePosition.frames, &mStatus.reply.capturePosition.time);
mStream, &mStatus.reply.capturePosition.frames,
&mStatus.reply.capturePosition.time);
}
bool ReadThread::threadLoop() {
// This implementation doesn't return control back to the Thread until it decides to stop,
// This implementation doesn't return control back to the Thread until it
// decides to stop,
// as the Thread uses mutexes, and this can lead to priority inversion.
while(!std::atomic_load_explicit(mStop, std::memory_order_acquire)) {
while (!std::atomic_load_explicit(mStop, std::memory_order_acquire)) {
uint32_t efState = 0;
mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState);
if (!(efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL))) {
mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL),
&efState);
if (!(efState &
static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL))) {
continue; // Nothing to do.
}
if (!mCommandMQ->read(&mParameters)) {
@@ -125,7 +128,8 @@ bool ReadThread::threadLoop() {
doGetCapturePosition();
break;
default:
ALOGE("Unknown read thread command code %d", mParameters.command);
ALOGE("Unknown read thread command code %d",
mParameters.command);
mStatus.retval = Result::NOT_SUPPORTED;
break;
}
@@ -141,11 +145,13 @@ bool ReadThread::threadLoop() {
} // namespace
StreamIn::StreamIn(const sp<Device>& device, audio_stream_in_t* stream)
: mIsClosed(false), mDevice(device), mStream(stream),
mStreamCommon(new Stream(&stream->common)),
mStreamMmap(new StreamMmap<audio_stream_in_t>(stream)),
mEfGroup(nullptr), mStopReadThread(false) {
}
: mIsClosed(false),
mDevice(device),
mStream(stream),
mStreamCommon(new Stream(&stream->common)),
mStreamMmap(new StreamMmap<audio_stream_in_t>(stream)),
mEfGroup(nullptr),
mStopReadThread(false) {}
StreamIn::~StreamIn() {
ATRACE_CALL();
@@ -157,102 +163,108 @@ StreamIn::~StreamIn() {
}
if (mEfGroup) {
status_t status = EventFlag::deleteEventFlag(&mEfGroup);
ALOGE_IF(status, "read MQ event flag deletion error: %s", strerror(-status));
ALOGE_IF(status, "read MQ event flag deletion error: %s",
strerror(-status));
}
mDevice->closeInputStream(mStream);
mStream = nullptr;
}
// Methods from ::android::hardware::audio::V2_0::IStream follow.
Return<uint64_t> StreamIn::getFrameSize() {
Return<uint64_t> StreamIn::getFrameSize() {
return audio_stream_in_frame_size(mStream);
}
Return<uint64_t> StreamIn::getFrameCount() {
Return<uint64_t> StreamIn::getFrameCount() {
return mStreamCommon->getFrameCount();
}
Return<uint64_t> StreamIn::getBufferSize() {
Return<uint64_t> StreamIn::getBufferSize() {
return mStreamCommon->getBufferSize();
}
Return<uint32_t> StreamIn::getSampleRate() {
Return<uint32_t> StreamIn::getSampleRate() {
return mStreamCommon->getSampleRate();
}
Return<void> StreamIn::getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) {
Return<void> StreamIn::getSupportedSampleRates(
getSupportedSampleRates_cb _hidl_cb) {
return mStreamCommon->getSupportedSampleRates(_hidl_cb);
}
Return<Result> StreamIn::setSampleRate(uint32_t sampleRateHz) {
Return<Result> StreamIn::setSampleRate(uint32_t sampleRateHz) {
return mStreamCommon->setSampleRate(sampleRateHz);
}
Return<AudioChannelMask> StreamIn::getChannelMask() {
Return<AudioChannelMask> StreamIn::getChannelMask() {
return mStreamCommon->getChannelMask();
}
Return<void> StreamIn::getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) {
Return<void> StreamIn::getSupportedChannelMasks(
getSupportedChannelMasks_cb _hidl_cb) {
return mStreamCommon->getSupportedChannelMasks(_hidl_cb);
}
Return<Result> StreamIn::setChannelMask(AudioChannelMask mask) {
Return<Result> StreamIn::setChannelMask(AudioChannelMask mask) {
return mStreamCommon->setChannelMask(mask);
}
Return<AudioFormat> StreamIn::getFormat() {
Return<AudioFormat> StreamIn::getFormat() {
return mStreamCommon->getFormat();
}
Return<void> StreamIn::getSupportedFormats(getSupportedFormats_cb _hidl_cb) {
Return<void> StreamIn::getSupportedFormats(getSupportedFormats_cb _hidl_cb) {
return mStreamCommon->getSupportedFormats(_hidl_cb);
}
Return<Result> StreamIn::setFormat(AudioFormat format) {
Return<Result> StreamIn::setFormat(AudioFormat format) {
return mStreamCommon->setFormat(format);
}
Return<void> StreamIn::getAudioProperties(getAudioProperties_cb _hidl_cb) {
Return<void> StreamIn::getAudioProperties(getAudioProperties_cb _hidl_cb) {
return mStreamCommon->getAudioProperties(_hidl_cb);
}
Return<Result> StreamIn::addEffect(uint64_t effectId) {
Return<Result> StreamIn::addEffect(uint64_t effectId) {
return mStreamCommon->addEffect(effectId);
}
Return<Result> StreamIn::removeEffect(uint64_t effectId) {
Return<Result> StreamIn::removeEffect(uint64_t effectId) {
return mStreamCommon->removeEffect(effectId);
}
Return<Result> StreamIn::standby() {
Return<Result> StreamIn::standby() {
return mStreamCommon->standby();
}
Return<AudioDevice> StreamIn::getDevice() {
Return<AudioDevice> StreamIn::getDevice() {
return mStreamCommon->getDevice();
}
Return<Result> StreamIn::setDevice(const DeviceAddress& address) {
Return<Result> StreamIn::setDevice(const DeviceAddress& address) {
return mStreamCommon->setDevice(address);
}
Return<Result> StreamIn::setConnectedState(const DeviceAddress& address, bool connected) {
Return<Result> StreamIn::setConnectedState(const DeviceAddress& address,
bool connected) {
return mStreamCommon->setConnectedState(address, connected);
}
Return<Result> StreamIn::setHwAvSync(uint32_t hwAvSync) {
Return<Result> StreamIn::setHwAvSync(uint32_t hwAvSync) {
return mStreamCommon->setHwAvSync(hwAvSync);
}
Return<void> StreamIn::getParameters(const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) {
Return<void> StreamIn::getParameters(const hidl_vec<hidl_string>& keys,
getParameters_cb _hidl_cb) {
return mStreamCommon->getParameters(keys, _hidl_cb);
}
Return<Result> StreamIn::setParameters(const hidl_vec<ParameterValue>& parameters) {
Return<Result> StreamIn::setParameters(
const hidl_vec<ParameterValue>& parameters) {
return mStreamCommon->setParameters(parameters);
}
Return<void> StreamIn::debugDump(const hidl_handle& fd) {
Return<void> StreamIn::debugDump(const hidl_handle& fd) {
return mStreamCommon->debugDump(fd);
}
@@ -264,16 +276,17 @@ Return<Result> StreamIn::stop() {
return mStreamMmap->stop();
}
Return<void> StreamIn::createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) {
Return<void> StreamIn::createMmapBuffer(int32_t minSizeFrames,
createMmapBuffer_cb _hidl_cb) {
return mStreamMmap->createMmapBuffer(
minSizeFrames, audio_stream_in_frame_size(mStream), _hidl_cb);
minSizeFrames, audio_stream_in_frame_size(mStream), _hidl_cb);
}
Return<void> StreamIn::getMmapPosition(getMmapPosition_cb _hidl_cb) {
return mStreamMmap->getMmapPosition(_hidl_cb);
}
Return<Result> StreamIn::close() {
Return<Result> StreamIn::close() {
if (mIsClosed) return Result::INVALID_STATE;
mIsClosed = true;
if (mReadThread.get()) {
@@ -286,9 +299,10 @@ Return<Result> StreamIn::close() {
}
// Methods from ::android::hardware::audio::V2_0::IStreamIn follow.
Return<void> StreamIn::getAudioSource(getAudioSource_cb _hidl_cb) {
Return<void> StreamIn::getAudioSource(getAudioSource_cb _hidl_cb) {
int halSource;
Result retval = mStreamCommon->getParam(AudioParameter::keyInputSource, &halSource);
Result retval =
mStreamCommon->getParam(AudioParameter::keyInputSource, &halSource);
AudioSource source(AudioSource::DEFAULT);
if (retval == Result::OK) {
source = AudioSource(halSource);
@@ -297,68 +311,89 @@ Return<void> StreamIn::getAudioSource(getAudioSource_cb _hidl_cb) {
return Void();
}
Return<Result> StreamIn::setGain(float gain) {
Return<Result> StreamIn::setGain(float gain) {
if (!isGainNormalized(gain)) {
ALOGW("Can not set a stream input gain (%f) outside [0,1]", gain);
return Result::INVALID_ARGUMENTS;
}
return Stream::analyzeStatus("set_gain", mStream->set_gain(mStream, gain));
}
Return<void> StreamIn::prepareForReading(
uint32_t frameSize, uint32_t framesCount, prepareForReading_cb _hidl_cb) {
Return<void> StreamIn::prepareForReading(uint32_t frameSize,
uint32_t framesCount,
prepareForReading_cb _hidl_cb) {
status_t status;
ThreadInfo threadInfo = { 0, 0 };
ThreadInfo threadInfo = {0, 0};
// Wrap the _hidl_cb to return an error
auto sendError = [this, &threadInfo, &_hidl_cb](Result result) {
_hidl_cb(result, CommandMQ::Descriptor(), DataMQ::Descriptor(),
StatusMQ::Descriptor(), threadInfo);
};
// Create message queues.
if (mDataMQ) {
ALOGE("the client attempts to call prepareForReading twice");
_hidl_cb(Result::INVALID_STATE,
CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo);
sendError(Result::INVALID_STATE);
return Void();
}
std::unique_ptr<CommandMQ> tempCommandMQ(new CommandMQ(1));
if (frameSize > std::numeric_limits<size_t>::max() / framesCount) {
ALOGE("Requested buffer is too big, %d*%d can not fit in size_t", frameSize, framesCount);
_hidl_cb(Result::INVALID_ARGUMENTS,
CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo);
// Check frameSize and framesCount
if (frameSize == 0 || framesCount == 0) {
ALOGE("Null frameSize (%u) or framesCount (%u)", frameSize,
framesCount);
sendError(Result::INVALID_ARGUMENTS);
return Void();
}
std::unique_ptr<DataMQ> tempDataMQ(new DataMQ(frameSize * framesCount, true /* EventFlag */));
// A message queue asserts if it can not handle the requested buffer,
// thus the client has to guess the maximum size it can handle
// Choose an arbitrary margin for the overhead of a message queue
size_t metadataOverhead = 100000;
if (frameSize >
(std::numeric_limits<size_t>::max() - metadataOverhead) / framesCount) {
ALOGE("Buffer too big: %u*%u bytes can not fit in a message queue",
frameSize, framesCount);
sendError(Result::INVALID_ARGUMENTS);
return Void();
}
std::unique_ptr<DataMQ> tempDataMQ(
new DataMQ(frameSize * framesCount, true /* EventFlag */));
std::unique_ptr<StatusMQ> tempStatusMQ(new StatusMQ(1));
if (!tempCommandMQ->isValid() || !tempDataMQ->isValid() || !tempStatusMQ->isValid()) {
if (!tempCommandMQ->isValid() || !tempDataMQ->isValid() ||
!tempStatusMQ->isValid()) {
ALOGE_IF(!tempCommandMQ->isValid(), "command MQ is invalid");
ALOGE_IF(!tempDataMQ->isValid(), "data MQ is invalid");
ALOGE_IF(!tempStatusMQ->isValid(), "status MQ is invalid");
_hidl_cb(Result::INVALID_ARGUMENTS,
CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo);
sendError(Result::INVALID_ARGUMENTS);
return Void();
}
EventFlag* tempRawEfGroup{};
status = EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &tempRawEfGroup);
std::unique_ptr<EventFlag, void(*)(EventFlag*)> tempElfGroup(tempRawEfGroup, [](auto *ef) {
EventFlag::deleteEventFlag(&ef); });
status = EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(),
&tempRawEfGroup);
std::unique_ptr<EventFlag, void (*)(EventFlag*)> tempElfGroup(
tempRawEfGroup, [](auto* ef) { EventFlag::deleteEventFlag(&ef); });
if (status != OK || !tempElfGroup) {
ALOGE("failed creating event flag for data MQ: %s", strerror(-status));
_hidl_cb(Result::INVALID_ARGUMENTS,
CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo);
sendError(Result::INVALID_ARGUMENTS);
return Void();
}
// Create and launch the thread.
auto tempReadThread = std::make_unique<ReadThread>(
&mStopReadThread,
mStream,
tempCommandMQ.get(),
tempDataMQ.get(),
tempStatusMQ.get(),
tempElfGroup.get());
&mStopReadThread, mStream, tempCommandMQ.get(), tempDataMQ.get(),
tempStatusMQ.get(), tempElfGroup.get());
if (!tempReadThread->init()) {
_hidl_cb(Result::INVALID_ARGUMENTS,
CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo);
ALOGW("failed to start reader thread: %s", strerror(-status));
sendError(Result::INVALID_ARGUMENTS);
return Void();
}
status = tempReadThread->run("reader", PRIORITY_URGENT_AUDIO);
if (status != OK) {
ALOGW("failed to start reader thread: %s", strerror(-status));
_hidl_cb(Result::INVALID_ARGUMENTS,
CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo);
sendError(Result::INVALID_ARGUMENTS);
return Void();
}
@@ -369,28 +404,27 @@ Return<void> StreamIn::prepareForReading(
mEfGroup = tempElfGroup.release();
threadInfo.pid = getpid();
threadInfo.tid = mReadThread->getTid();
_hidl_cb(Result::OK,
*mCommandMQ->getDesc(), *mDataMQ->getDesc(), *mStatusMQ->getDesc(),
threadInfo);
_hidl_cb(Result::OK, *mCommandMQ->getDesc(), *mDataMQ->getDesc(),
*mStatusMQ->getDesc(), threadInfo);
return Void();
}
Return<uint32_t> StreamIn::getInputFramesLost() {
Return<uint32_t> StreamIn::getInputFramesLost() {
return mStream->get_input_frames_lost(mStream);
}
// static
Result StreamIn::getCapturePositionImpl(
audio_stream_in_t *stream, uint64_t *frames, uint64_t *time) {
Result StreamIn::getCapturePositionImpl(audio_stream_in_t* stream,
uint64_t* frames, uint64_t* time) {
Result retval(Result::NOT_SUPPORTED);
if (stream->get_capture_position != NULL) return retval;
int64_t halFrames, halTime;
retval = Stream::analyzeStatus(
"get_capture_position",
stream->get_capture_position(stream, &halFrames, &halTime),
// HAL may have a stub function, always returning ENOSYS, don't
// spam the log in this case.
ENOSYS);
"get_capture_position",
stream->get_capture_position(stream, &halFrames, &halTime),
// HAL may have a stub function, always returning ENOSYS, don't
// spam the log in this case.
ENOSYS);
if (retval == Result::OK) {
*frames = halFrames;
*time = halTime;
@@ -398,14 +432,14 @@ Result StreamIn::getCapturePositionImpl(
return retval;
};
Return<void> StreamIn::getCapturePosition(getCapturePosition_cb _hidl_cb) {
Return<void> StreamIn::getCapturePosition(getCapturePosition_cb _hidl_cb) {
uint64_t frames = 0, time = 0;
Result retval = getCapturePositionImpl(mStream, &frames, &time);
_hidl_cb(retval, frames, time);
return Void();
}
} // namespace implementation
} // namespace implementation
} // namespace V2_0
} // namespace audio
} // namespace hardware

View File

@@ -25,6 +25,7 @@
#include <utils/Trace.h>
#include "StreamOut.h"
#include "Util.h"
namespace android {
namespace hardware {
@@ -37,30 +38,26 @@ using ::android::hardware::audio::common::V2_0::ThreadInfo;
namespace {
class WriteThread : public Thread {
public:
public:
// WriteThread's lifespan never exceeds StreamOut's lifespan.
WriteThread(std::atomic<bool>* stop,
audio_stream_out_t* stream,
StreamOut::CommandMQ* commandMQ,
StreamOut::DataMQ* dataMQ,
StreamOut::StatusMQ* statusMQ,
EventFlag* efGroup)
: Thread(false /*canCallJava*/),
mStop(stop),
mStream(stream),
mCommandMQ(commandMQ),
mDataMQ(dataMQ),
mStatusMQ(statusMQ),
mEfGroup(efGroup),
mBuffer(nullptr) {
}
WriteThread(std::atomic<bool>* stop, audio_stream_out_t* stream,
StreamOut::CommandMQ* commandMQ, StreamOut::DataMQ* dataMQ,
StreamOut::StatusMQ* statusMQ, EventFlag* efGroup)
: Thread(false /*canCallJava*/),
mStop(stop),
mStream(stream),
mCommandMQ(commandMQ),
mDataMQ(dataMQ),
mStatusMQ(statusMQ),
mEfGroup(efGroup),
mBuffer(nullptr) {}
bool init() {
mBuffer.reset(new(std::nothrow) uint8_t[mDataMQ->getQuantumCount()]);
mBuffer.reset(new (std::nothrow) uint8_t[mDataMQ->getQuantumCount()]);
return mBuffer != nullptr;
}
virtual ~WriteThread() {}
private:
private:
std::atomic<bool>* mStop;
audio_stream_out_t* mStream;
StreamOut::CommandMQ* mCommandMQ;
@@ -93,9 +90,8 @@ void WriteThread::doWrite() {
void WriteThread::doGetPresentationPosition() {
mStatus.retval = StreamOut::getPresentationPositionImpl(
mStream,
&mStatus.reply.presentationPosition.frames,
&mStatus.reply.presentationPosition.timeStamp);
mStream, &mStatus.reply.presentationPosition.frames,
&mStatus.reply.presentationPosition.timeStamp);
}
void WriteThread::doGetLatency() {
@@ -104,12 +100,15 @@ void WriteThread::doGetLatency() {
}
bool WriteThread::threadLoop() {
// This implementation doesn't return control back to the Thread until it decides to stop,
// This implementation doesn't return control back to the Thread until it
// decides to stop,
// as the Thread uses mutexes, and this can lead to priority inversion.
while(!std::atomic_load_explicit(mStop, std::memory_order_acquire)) {
while (!std::atomic_load_explicit(mStop, std::memory_order_acquire)) {
uint32_t efState = 0;
mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState);
if (!(efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY))) {
mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY),
&efState);
if (!(efState &
static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY))) {
continue; // Nothing to do.
}
if (!mCommandMQ->read(&mStatus.replyTo)) {
@@ -142,11 +141,13 @@ bool WriteThread::threadLoop() {
} // namespace
StreamOut::StreamOut(const sp<Device>& device, audio_stream_out_t* stream)
: mIsClosed(false), mDevice(device), mStream(stream),
mStreamCommon(new Stream(&stream->common)),
mStreamMmap(new StreamMmap<audio_stream_out_t>(stream)),
mEfGroup(nullptr), mStopWriteThread(false) {
}
: mIsClosed(false),
mDevice(device),
mStream(stream),
mStreamCommon(new Stream(&stream->common)),
mStreamMmap(new StreamMmap<audio_stream_out_t>(stream)),
mEfGroup(nullptr),
mStopWriteThread(false) {}
StreamOut::~StreamOut() {
ATRACE_CALL();
@@ -158,7 +159,8 @@ StreamOut::~StreamOut() {
}
if (mEfGroup) {
status_t status = EventFlag::deleteEventFlag(&mEfGroup);
ALOGE_IF(status, "write MQ event flag deletion error: %s", strerror(-status));
ALOGE_IF(status, "write MQ event flag deletion error: %s",
strerror(-status));
}
mCallback.clear();
mDevice->closeOutputStream(mStream);
@@ -166,100 +168,104 @@ StreamOut::~StreamOut() {
}
// Methods from ::android::hardware::audio::V2_0::IStream follow.
Return<uint64_t> StreamOut::getFrameSize() {
Return<uint64_t> StreamOut::getFrameSize() {
return audio_stream_out_frame_size(mStream);
}
Return<uint64_t> StreamOut::getFrameCount() {
Return<uint64_t> StreamOut::getFrameCount() {
return mStreamCommon->getFrameCount();
}
Return<uint64_t> StreamOut::getBufferSize() {
Return<uint64_t> StreamOut::getBufferSize() {
return mStreamCommon->getBufferSize();
}
Return<uint32_t> StreamOut::getSampleRate() {
Return<uint32_t> StreamOut::getSampleRate() {
return mStreamCommon->getSampleRate();
}
Return<void> StreamOut::getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) {
Return<void> StreamOut::getSupportedSampleRates(
getSupportedSampleRates_cb _hidl_cb) {
return mStreamCommon->getSupportedSampleRates(_hidl_cb);
}
Return<Result> StreamOut::setSampleRate(uint32_t sampleRateHz) {
Return<Result> StreamOut::setSampleRate(uint32_t sampleRateHz) {
return mStreamCommon->setSampleRate(sampleRateHz);
}
Return<AudioChannelMask> StreamOut::getChannelMask() {
Return<AudioChannelMask> StreamOut::getChannelMask() {
return mStreamCommon->getChannelMask();
}
Return<void> StreamOut::getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) {
Return<void> StreamOut::getSupportedChannelMasks(
getSupportedChannelMasks_cb _hidl_cb) {
return mStreamCommon->getSupportedChannelMasks(_hidl_cb);
}
Return<Result> StreamOut::setChannelMask(AudioChannelMask mask) {
Return<Result> StreamOut::setChannelMask(AudioChannelMask mask) {
return mStreamCommon->setChannelMask(mask);
}
Return<AudioFormat> StreamOut::getFormat() {
Return<AudioFormat> StreamOut::getFormat() {
return mStreamCommon->getFormat();
}
Return<void> StreamOut::getSupportedFormats(getSupportedFormats_cb _hidl_cb) {
Return<void> StreamOut::getSupportedFormats(getSupportedFormats_cb _hidl_cb) {
return mStreamCommon->getSupportedFormats(_hidl_cb);
}
Return<Result> StreamOut::setFormat(AudioFormat format) {
Return<Result> StreamOut::setFormat(AudioFormat format) {
return mStreamCommon->setFormat(format);
}
Return<void> StreamOut::getAudioProperties(getAudioProperties_cb _hidl_cb) {
Return<void> StreamOut::getAudioProperties(getAudioProperties_cb _hidl_cb) {
return mStreamCommon->getAudioProperties(_hidl_cb);
}
Return<Result> StreamOut::addEffect(uint64_t effectId) {
Return<Result> StreamOut::addEffect(uint64_t effectId) {
return mStreamCommon->addEffect(effectId);
}
Return<Result> StreamOut::removeEffect(uint64_t effectId) {
Return<Result> StreamOut::removeEffect(uint64_t effectId) {
return mStreamCommon->removeEffect(effectId);
}
Return<Result> StreamOut::standby() {
Return<Result> StreamOut::standby() {
return mStreamCommon->standby();
}
Return<AudioDevice> StreamOut::getDevice() {
Return<AudioDevice> StreamOut::getDevice() {
return mStreamCommon->getDevice();
}
Return<Result> StreamOut::setDevice(const DeviceAddress& address) {
Return<Result> StreamOut::setDevice(const DeviceAddress& address) {
return mStreamCommon->setDevice(address);
}
Return<Result> StreamOut::setConnectedState(const DeviceAddress& address, bool connected) {
Return<Result> StreamOut::setConnectedState(const DeviceAddress& address,
bool connected) {
return mStreamCommon->setConnectedState(address, connected);
}
Return<Result> StreamOut::setHwAvSync(uint32_t hwAvSync) {
Return<Result> StreamOut::setHwAvSync(uint32_t hwAvSync) {
return mStreamCommon->setHwAvSync(hwAvSync);
}
Return<void> StreamOut::getParameters(
const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) {
Return<void> StreamOut::getParameters(const hidl_vec<hidl_string>& keys,
getParameters_cb _hidl_cb) {
return mStreamCommon->getParameters(keys, _hidl_cb);
}
Return<Result> StreamOut::setParameters(const hidl_vec<ParameterValue>& parameters) {
Return<Result> StreamOut::setParameters(
const hidl_vec<ParameterValue>& parameters) {
return mStreamCommon->setParameters(parameters);
}
Return<void> StreamOut::debugDump(const hidl_handle& fd) {
Return<void> StreamOut::debugDump(const hidl_handle& fd) {
return mStreamCommon->debugDump(fd);
}
Return<Result> StreamOut::close() {
Return<Result> StreamOut::close() {
if (mIsClosed) return Result::INVALID_STATE;
mIsClosed = true;
if (mWriteThread.get()) {
@@ -272,78 +278,98 @@ Return<Result> StreamOut::close() {
}
// Methods from ::android::hardware::audio::V2_0::IStreamOut follow.
Return<uint32_t> StreamOut::getLatency() {
Return<uint32_t> StreamOut::getLatency() {
return mStream->get_latency(mStream);
}
Return<Result> StreamOut::setVolume(float left, float right) {
Result retval(Result::NOT_SUPPORTED);
if (mStream->set_volume != NULL) {
retval = Stream::analyzeStatus(
"set_volume", mStream->set_volume(mStream, left, right));
Return<Result> StreamOut::setVolume(float left, float right) {
if (mStream->set_volume == NULL) {
return Result::NOT_SUPPORTED;
}
return retval;
if (!isGainNormalized(left)) {
ALOGW("Can not set a stream output volume {%f, %f} outside [0,1]", left,
right);
return Result::INVALID_ARGUMENTS;
}
return Stream::analyzeStatus("set_volume",
mStream->set_volume(mStream, left, right));
}
Return<void> StreamOut::prepareForWriting(
uint32_t frameSize, uint32_t framesCount, prepareForWriting_cb _hidl_cb) {
Return<void> StreamOut::prepareForWriting(uint32_t frameSize,
uint32_t framesCount,
prepareForWriting_cb _hidl_cb) {
status_t status;
ThreadInfo threadInfo = { 0, 0 };
ThreadInfo threadInfo = {0, 0};
// Wrap the _hidl_cb to return an error
auto sendError = [this, &threadInfo, &_hidl_cb](Result result) {
_hidl_cb(result, CommandMQ::Descriptor(), DataMQ::Descriptor(),
StatusMQ::Descriptor(), threadInfo);
};
// Create message queues.
if (mDataMQ) {
ALOGE("the client attempts to call prepareForWriting twice");
_hidl_cb(Result::INVALID_STATE,
CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo);
sendError(Result::INVALID_STATE);
return Void();
}
std::unique_ptr<CommandMQ> tempCommandMQ(new CommandMQ(1));
if (frameSize > std::numeric_limits<size_t>::max() / framesCount) {
ALOGE("Requested buffer is too big, %d*%d can not fit in size_t", frameSize, framesCount);
_hidl_cb(Result::INVALID_ARGUMENTS,
CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo);
// Check frameSize and framesCount
if (frameSize == 0 || framesCount == 0) {
ALOGE("Null frameSize (%u) or framesCount (%u)", frameSize,
framesCount);
sendError(Result::INVALID_ARGUMENTS);
return Void();
}
std::unique_ptr<DataMQ> tempDataMQ(new DataMQ(frameSize * framesCount, true /* EventFlag */));
// A message queue asserts if it can not handle the requested buffer,
// thus the client has to guess the maximum size it can handle
size_t metadataOverhead =
100000; // Arbitrary margin for the overhead of a message queue
if (frameSize >
(std::numeric_limits<size_t>::max() - metadataOverhead) / framesCount) {
ALOGE("Buffer too big: %u*%u bytes can not fit in a message queue",
frameSize, framesCount);
sendError(Result::INVALID_ARGUMENTS);
return Void();
}
std::unique_ptr<DataMQ> tempDataMQ(
new DataMQ(frameSize * framesCount, true /* EventFlag */));
std::unique_ptr<StatusMQ> tempStatusMQ(new StatusMQ(1));
if (!tempCommandMQ->isValid() || !tempDataMQ->isValid() || !tempStatusMQ->isValid()) {
if (!tempCommandMQ->isValid() || !tempDataMQ->isValid() ||
!tempStatusMQ->isValid()) {
ALOGE_IF(!tempCommandMQ->isValid(), "command MQ is invalid");
ALOGE_IF(!tempDataMQ->isValid(), "data MQ is invalid");
ALOGE_IF(!tempStatusMQ->isValid(), "status MQ is invalid");
_hidl_cb(Result::INVALID_ARGUMENTS,
CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo);
sendError(Result::INVALID_ARGUMENTS);
return Void();
}
EventFlag* tempRawEfGroup{};
status = EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &tempRawEfGroup);
std::unique_ptr<EventFlag, void(*)(EventFlag*)> tempElfGroup(tempRawEfGroup,[](auto *ef) {
EventFlag::deleteEventFlag(&ef); });
status = EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(),
&tempRawEfGroup);
std::unique_ptr<EventFlag, void (*)(EventFlag*)> tempElfGroup(
tempRawEfGroup, [](auto* ef) { EventFlag::deleteEventFlag(&ef); });
if (status != OK || !tempElfGroup) {
ALOGE("failed creating event flag for data MQ: %s", strerror(-status));
_hidl_cb(Result::INVALID_ARGUMENTS,
CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo);
sendError(Result::INVALID_ARGUMENTS);
return Void();
}
// Create and launch the thread.
auto tempWriteThread = std::make_unique<WriteThread>(
&mStopWriteThread,
mStream,
tempCommandMQ.get(),
tempDataMQ.get(),
tempStatusMQ.get(),
tempElfGroup.get());
&mStopWriteThread, mStream, tempCommandMQ.get(), tempDataMQ.get(),
tempStatusMQ.get(), tempElfGroup.get());
if (!tempWriteThread->init()) {
_hidl_cb(Result::INVALID_ARGUMENTS,
CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo);
ALOGW("failed to start writer thread: %s", strerror(-status));
sendError(Result::INVALID_ARGUMENTS);
return Void();
}
status = tempWriteThread->run("writer", PRIORITY_URGENT_AUDIO);
if (status != OK) {
ALOGW("failed to start writer thread: %s", strerror(-status));
_hidl_cb(Result::INVALID_ARGUMENTS,
CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo);
sendError(Result::INVALID_ARGUMENTS);
return Void();
}
@@ -354,33 +380,34 @@ Return<void> StreamOut::prepareForWriting(
mEfGroup = tempElfGroup.release();
threadInfo.pid = getpid();
threadInfo.tid = mWriteThread->getTid();
_hidl_cb(Result::OK,
*mCommandMQ->getDesc(), *mDataMQ->getDesc(), *mStatusMQ->getDesc(),
threadInfo);
_hidl_cb(Result::OK, *mCommandMQ->getDesc(), *mDataMQ->getDesc(),
*mStatusMQ->getDesc(), threadInfo);
return Void();
}
Return<void> StreamOut::getRenderPosition(getRenderPosition_cb _hidl_cb) {
Return<void> StreamOut::getRenderPosition(getRenderPosition_cb _hidl_cb) {
uint32_t halDspFrames;
Result retval = Stream::analyzeStatus(
"get_render_position", mStream->get_render_position(mStream, &halDspFrames));
"get_render_position",
mStream->get_render_position(mStream, &halDspFrames));
_hidl_cb(retval, halDspFrames);
return Void();
}
Return<void> StreamOut::getNextWriteTimestamp(getNextWriteTimestamp_cb _hidl_cb) {
Return<void> StreamOut::getNextWriteTimestamp(
getNextWriteTimestamp_cb _hidl_cb) {
Result retval(Result::NOT_SUPPORTED);
int64_t timestampUs = 0;
if (mStream->get_next_write_timestamp != NULL) {
retval = Stream::analyzeStatus(
"get_next_write_timestamp",
mStream->get_next_write_timestamp(mStream, &timestampUs));
"get_next_write_timestamp",
mStream->get_next_write_timestamp(mStream, &timestampUs));
}
_hidl_cb(retval, timestampUs);
return Void();
}
Return<Result> StreamOut::setCallback(const sp<IStreamOutCallback>& callback) {
Return<Result> StreamOut::setCallback(const sp<IStreamOutCallback>& callback) {
if (mStream->set_callback == NULL) return Result::NOT_SUPPORTED;
int result = mStream->set_callback(mStream, StreamOut::asyncCallback, this);
if (result == 0) {
@@ -389,14 +416,15 @@ Return<Result> StreamOut::setCallback(const sp<IStreamOutCallback>& callback) {
return Stream::analyzeStatus("set_callback", result);
}
Return<Result> StreamOut::clearCallback() {
Return<Result> StreamOut::clearCallback() {
if (mStream->set_callback == NULL) return Result::NOT_SUPPORTED;
mCallback.clear();
return Result::OK;
}
// static
int StreamOut::asyncCallback(stream_callback_event_t event, void*, void *cookie) {
int StreamOut::asyncCallback(stream_callback_event_t event, void*,
void* cookie) {
wp<StreamOut> weakSelf(reinterpret_cast<StreamOut*>(cookie));
sp<StreamOut> self = weakSelf.promote();
if (self == nullptr || self->mCallback == nullptr) return 0;
@@ -418,53 +446,57 @@ int StreamOut::asyncCallback(stream_callback_event_t event, void*, void *cookie)
return 0;
}
Return<void> StreamOut::supportsPauseAndResume(supportsPauseAndResume_cb _hidl_cb) {
Return<void> StreamOut::supportsPauseAndResume(
supportsPauseAndResume_cb _hidl_cb) {
_hidl_cb(mStream->pause != NULL, mStream->resume != NULL);
return Void();
}
Return<Result> StreamOut::pause() {
return mStream->pause != NULL ?
Stream::analyzeStatus("pause", mStream->pause(mStream)) :
Result::NOT_SUPPORTED;
Return<Result> StreamOut::pause() {
return mStream->pause != NULL
? Stream::analyzeStatus("pause", mStream->pause(mStream))
: Result::NOT_SUPPORTED;
}
Return<Result> StreamOut::resume() {
return mStream->resume != NULL ?
Stream::analyzeStatus("resume", mStream->resume(mStream)) :
Result::NOT_SUPPORTED;
Return<Result> StreamOut::resume() {
return mStream->resume != NULL
? Stream::analyzeStatus("resume", mStream->resume(mStream))
: Result::NOT_SUPPORTED;
}
Return<bool> StreamOut::supportsDrain() {
Return<bool> StreamOut::supportsDrain() {
return mStream->drain != NULL;
}
Return<Result> StreamOut::drain(AudioDrain type) {
return mStream->drain != NULL ?
Stream::analyzeStatus(
"drain", mStream->drain(mStream, static_cast<audio_drain_type_t>(type))) :
Result::NOT_SUPPORTED;
Return<Result> StreamOut::drain(AudioDrain type) {
return mStream->drain != NULL
? Stream::analyzeStatus(
"drain",
mStream->drain(mStream,
static_cast<audio_drain_type_t>(type)))
: Result::NOT_SUPPORTED;
}
Return<Result> StreamOut::flush() {
return mStream->flush != NULL ?
Stream::analyzeStatus("flush", mStream->flush(mStream)) :
Result::NOT_SUPPORTED;
Return<Result> StreamOut::flush() {
return mStream->flush != NULL
? Stream::analyzeStatus("flush", mStream->flush(mStream))
: Result::NOT_SUPPORTED;
}
// static
Result StreamOut::getPresentationPositionImpl(
audio_stream_out_t *stream, uint64_t *frames, TimeSpec *timeStamp) {
Result StreamOut::getPresentationPositionImpl(audio_stream_out_t* stream,
uint64_t* frames,
TimeSpec* timeStamp) {
Result retval(Result::NOT_SUPPORTED);
if (stream->get_presentation_position == NULL) return retval;
struct timespec halTimeStamp;
retval = Stream::analyzeStatus(
"get_presentation_position",
stream->get_presentation_position(stream, frames, &halTimeStamp),
// Don't logspam on EINVAL--it's normal for get_presentation_position
// to return it sometimes. EAGAIN may be returned by A2DP audio HAL
// implementation.
EINVAL, EAGAIN);
"get_presentation_position",
stream->get_presentation_position(stream, frames, &halTimeStamp),
// Don't logspam on EINVAL--it's normal for get_presentation_position
// to return it sometimes. EAGAIN may be returned by A2DP audio HAL
// implementation.
EINVAL, EAGAIN);
if (retval == Result::OK) {
timeStamp->tvSec = halTimeStamp.tv_sec;
timeStamp->tvNSec = halTimeStamp.tv_nsec;
@@ -472,9 +504,10 @@ Result StreamOut::getPresentationPositionImpl(
return retval;
}
Return<void> StreamOut::getPresentationPosition(getPresentationPosition_cb _hidl_cb) {
Return<void> StreamOut::getPresentationPosition(
getPresentationPosition_cb _hidl_cb) {
uint64_t frames = 0;
TimeSpec timeStamp = { 0, 0 };
TimeSpec timeStamp = {0, 0};
Result retval = getPresentationPositionImpl(mStream, &frames, &timeStamp);
_hidl_cb(retval, frames, timeStamp);
return Void();
@@ -488,9 +521,10 @@ Return<Result> StreamOut::stop() {
return mStreamMmap->stop();
}
Return<void> StreamOut::createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) {
Return<void> StreamOut::createMmapBuffer(int32_t minSizeFrames,
createMmapBuffer_cb _hidl_cb) {
return mStreamMmap->createMmapBuffer(
minSizeFrames, audio_stream_out_frame_size(mStream), _hidl_cb);
minSizeFrames, audio_stream_out_frame_size(mStream), _hidl_cb);
}
Return<void> StreamOut::getMmapPosition(getMmapPosition_cb _hidl_cb) {

37
audio/2.0/default/Util.h Normal file
View File

@@ -0,0 +1,37 @@
/*
* Copyright (C) 2017 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_UTIL_H
#define ANDROID_HARDWARE_AUDIO_V2_0_UTIL_H
namespace android {
namespace hardware {
namespace audio {
namespace V2_0 {
namespace implementation {
/** @return true if gain is between 0 and 1 included. */
constexpr bool isGainNormalized(float gain) {
return gain >= 0.0 && gain <= 1.0;
}
} // namespace implementation
} // namespace V2_0
} // namespace audio
} // namespace hardware
} // namespace android
#endif // ANDROID_HARDWARE_AUDIO_V2_0_UTIL_H

File diff suppressed because it is too large Load Diff

View File

@@ -14,58 +14,105 @@
* limitations under the License.
*/
#include <vector>
#include <algorithm>
#include <vector>
#include <hidl/Status.h>
namespace detail {
// This is a detail namespace, thus it is OK to import a class as nobody else is allowed to use it
// This is a detail namespace, thus it is OK to import a class as nobody else is
// allowed to use it
using ::android::hardware::Return;
using ::android::hardware::audio::V2_0::Result;
inline void assertResult(Result expected, Result result) {
ASSERT_EQ(expected, result);
template <class T>
inline ::testing::AssertionResult assertIsOk(const char* expr,
const Return<T>& ret) {
return ::testing::AssertionResult(ret.isOk())
<< "Expected: " << expr
<< "\n to be an OK Return but it is not: " << ret.description();
}
inline void assertResult(Result expected, const Return<Result> &ret) {
ASSERT_TRUE(ret.isOk());
Result result = ret;
assertResult(expected, result);
// Call continuation if the provided result isOk
template <class T, class Continuation>
inline ::testing::AssertionResult continueIfIsOk(const char* expr,
const Return<T>& ret,
Continuation continuation) {
auto isOkStatus = assertIsOk(expr, ret);
return !isOkStatus ? isOkStatus : continuation();
}
inline void assertResult(const std::vector<Result> &expected, Result result) {
// Expect two equal Results
inline ::testing::AssertionResult assertResult(const char* e_expr,
const char* r_expr,
Result expected, Result result) {
return ::testing::AssertionResult(expected == result)
<< "Value of: " << r_expr
<< "\n Actual: " << ::testing::PrintToString(result)
<< "\nExpected: " << e_expr
<< "\nWhich is: " << ::testing::PrintToString(expected);
}
// Expect two equal Results one being wrapped in an OK Return
inline ::testing::AssertionResult assertResult(const char* e_expr,
const char* r_expr,
Result expected,
const Return<Result>& ret) {
return continueIfIsOk(r_expr, ret, [&] {
return assertResult(e_expr, r_expr, expected, Result{ret});
});
}
// Expect a Result to be part of a list of Results
inline ::testing::AssertionResult assertResult(
const char* e_expr, const char* r_expr, const std::vector<Result>& expected,
Result result) {
if (std::find(expected.begin(), expected.end(), result) != expected.end()) {
return; // result is in expected
return ::testing::AssertionSuccess(); // result is in expected
}
FAIL() << "Expected result " << ::testing::PrintToString(result)
<< " to be one of " << ::testing::PrintToString(expected);
return ::testing::AssertionFailure()
<< "Value of: " << r_expr
<< "\n Actual: " << ::testing::PrintToString(result)
<< "\nExpected one of: " << e_expr
<< "\n Which is: " << ::testing::PrintToString(expected);
}
inline void assertResult(const std::vector<Result> &expected, const Return<Result> &ret) {
ASSERT_TRUE(ret.isOk());
Result result = ret;
assertResult(expected, result);
// Expect a Result wrapped in an OK Return to be part of a list of Results
inline ::testing::AssertionResult assertResult(
const char* e_expr, const char* r_expr, const std::vector<Result>& expected,
const Return<Result>& ret) {
return continueIfIsOk(r_expr, ret, [&] {
return assertResult(e_expr, r_expr, expected, Result{ret});
});
}
inline void assertOk(const Return<void> &ret) {
ASSERT_TRUE(ret.isOk());
inline ::testing::AssertionResult assertOk(const char* expr,
const Return<void>& ret) {
return assertIsOk(expr, ret);
}
inline void assertOk(Result result) {
assertResult(Result::OK, result);
inline ::testing::AssertionResult assertOk(const char* expr, Result result) {
return ::testing::AssertionResult(result == Result::OK)
<< "Expected success: " << expr
<< "\nActual: " << ::testing::PrintToString(result);
}
inline void assertOk(const Return<Result> &ret) {
assertResult(Result::OK, ret);
inline ::testing::AssertionResult assertOk(const char* expr,
const Return<Result>& ret) {
return continueIfIsOk(expr, ret,
[&] { return assertOk(expr, Result{ret}); });
}
}
}
#define ASSERT_IS_OK(ret) ASSERT_PRED_FORMAT1(detail::assertIsOk, ret)
#define EXPECT_IS_OK(ret) EXPECT_PRED_FORMAT1(detail::assertIsOk, ret)
// Test anything provided is and contains only OK
#define ASSERT_OK(ret) ASSERT_NO_FATAL_FAILURE(detail::assertOk(ret))
#define EXPECT_OK(ret) EXPECT_NO_FATAL_FAILURE(detail::assertOk(ret))
#define ASSERT_OK(ret) ASSERT_PRED_FORMAT1(detail::assertOk, ret)
#define EXPECT_OK(ret) EXPECT_PRED_FORMAT1(detail::assertOk, ret)
#define ASSERT_RESULT(expected, ret) ASSERT_NO_FATAL_FAILURE(detail::assertResult(expected, ret))
#define EXPECT_RESULT(expected, ret) EXPECT_NO_FATAL_FAILURE(detail::assertResult(expected, ret))
#define ASSERT_RESULT(expected, ret) \
ASSERT_PRED_FORMAT2(detail::assertResult, expected, ret)
#define EXPECT_RESULT(expected, ret) \
EXPECT_PRED_FORMAT2(detail::assertResult, expected, ret)