mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-02 05:56:34 +00:00
Merge changes from topic 'audio-primary-hal-vts-fix' into oc-dev
am: 257c2f1a43
Change-Id: Ic8850d915b5672e7529f99e7d57845b2de44857a
This commit is contained in:
@@ -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]));
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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, ×tampUs));
|
||||
"get_next_write_timestamp",
|
||||
mStream->get_next_write_timestamp(mStream, ×tampUs));
|
||||
}
|
||||
_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
37
audio/2.0/default/Util.h
Normal 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
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user