Files
hardware_interfaces/audio/2.0/default/ParametersUtil.cpp
Kevin Rocard 574cc909d4 Audio: setParam improve status_t to Result consistency
The rest of the API (*::analyseStatus) returns NOT_SUPPORTED
when the legacy API returns -ENOSYS.

setParameter legacy -> treble shim did not follow this
conversion due to the legacy API stating that for get_paramers,
-ENOSYS should be returned if
"the implementation does not accept a parameter change while the
 output is active but the parameter is acceptable otherwise",
aka INVALID_STATE.

Thus setParameter shim used to return
 - OK for OK
 - INVALID_STATE for -ENOSYS
 - INVALID_ARGUMENTS for everything else

This leads to several problems:
 - an implementation of the legacy API can not report NOT_SUPPORTED
 - is inconsistent with the rest of the status_t conversion methods
 - shim methods implemented over getParameter can not distinguish
   failures error required by the .hal documentation

Most importantly, on the system side, the Result is transformed to a
status_t again but without any special logic for methods wrapping
getParameter in the shim.
See: analyzeResult in
     frameworks/av/media/libaudiohal/2.0/ConversionHelperHidl.cpp
This can not be changed as the system can not know which methods
are implemented with a legacy wrapper under the Treble API boundary.

This mean that if:
 - hal return -ENOSYS ()
 - shim converts it to INVALID_STATE
 - libaudiohal converts it to NOT_ENOUGH_DATA ()
Thus the checkForNewParameter_l's "status == INVALID_OPERATION"
test in frameworks/av/services/audioflinger/Threads.cpp
are now always false and broken.
This has been broken since the introduction of the Treble shim for O.

Thus setParam now converts status_t to Result in the same way
as all the other shim methods.

Bug: 72873273
Bug: 69811500
Bug: 69010523
Test: playback and record for media and voice call
Change-Id: I41204c0807d2bd4675e941771cbc9a43d7d14855
Merged-In: I41328afce56ce31d4a26159ca2d4b16d14cce05b
Signed-off-by: Kevin Rocard <krocard@google.com>
2018-04-20 23:30:28 +00:00

153 lines
4.9 KiB
C++

/*
* 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"
#include "Util.h"
namespace android {
namespace hardware {
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;
}
Result ParametersUtil::getParam(const char* name, int* value) {
const String8 halName(name);
AudioParameter keys;
keys.addKey(halName);
std::unique_ptr<AudioParameter> params = getParams(keys);
return getHalStatusToResult(params->getInt(halName, *value));
}
Result ParametersUtil::getParam(const char* name, String8* value) {
const String8 halName(name);
AudioParameter keys;
keys.addKey(halName);
std::unique_ptr<AudioParameter> params = getParams(keys);
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) {
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 = (keys.size() == 0 || halValues->size() != 0)
? Result::OK
: Result::NOT_SUPPORTED;
hidl_vec<ParameterValue> result;
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) {
String8 paramsAndValues;
char* halValues = halGetParameters(keys.keysToString().string());
if (halValues != NULL) {
paramsAndValues.setTo(halValues);
free(halValues);
} else {
paramsAndValues.clear();
}
return std::unique_ptr<AudioParameter>(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<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()));
}
return setParams(params);
}
Result ParametersUtil::setParams(const AudioParameter& param) {
int halStatus = halSetParameters(param.toString().string());
return util::analyzeStatus(halStatus);
}
} // namespace implementation
} // namespace V2_0
} // namespace audio
} // namespace hardware
} // namespace android