Merge changes I249d9ef1,I2c75b4bf,I0da109d6,I82738d11

* changes:
  [AudioPolicyService] Add creation of DeviceEffects
  [audioeffect] add support of device effect in config parser
  audioeffect: add missing sources to deserializer config file
  audiopolicy: apm: factorize internal patch creation/release
gugelfrei
Eric Laurent 5 years ago committed by Android (Google) Code Review
commit 90c5793536

@ -13,6 +13,8 @@ cc_library {
shared_libs: [
"liblog",
"libtinyxml2",
"libutils",
"libmedia_helper",
],
header_libs: ["libaudio_system_headers"],

@ -76,6 +76,10 @@ struct Stream {
using OutputStream = Stream<audio_stream_type_t>;
using InputStream = Stream<audio_source_t>;
struct DeviceEffects : Stream<audio_devices_t> {
std::string address;
};
/** Parsed configuration.
* Intended to be a transient structure only used for deserialization.
* Note: Everything is copied in the configuration from the xml dom.
@ -89,6 +93,7 @@ struct Config {
Effects effects;
std::vector<OutputStream> postprocess;
std::vector<InputStream> preprocess;
std::vector<DeviceEffects> deviceprocess;
};
/** Result of `parse(const char*)` */

@ -26,6 +26,7 @@
#include <log/log.h>
#include <media/EffectsConfig.h>
#include <media/TypeConverter.h>
using namespace tinyxml2;
@ -117,6 +118,8 @@ constexpr std::pair<audio_source_t, const char*> STREAM_NAME_MAP<audio_source_t>
{AUDIO_SOURCE_VOICE_COMMUNICATION, "voice_communication"},
{AUDIO_SOURCE_UNPROCESSED, "unprocessed"},
{AUDIO_SOURCE_VOICE_PERFORMANCE, "voice_performance"},
{AUDIO_SOURCE_ECHO_REFERENCE, "echo_reference"},
{AUDIO_SOURCE_FM_TUNER, "fm_tuner"},
};
/** Find the stream type enum corresponding to the stream type name or return false */
@ -132,6 +135,11 @@ bool stringToStreamType(const char *streamName, Type* type)
return false;
}
template <>
bool stringToStreamType(const char *streamName, audio_devices_t* type) {
return deviceFromString(streamName, *type);
}
/** Parse a library xml note and push the result in libraries or return false on failure. */
bool parseLibrary(const XMLElement& xmlLibrary, Libraries* libraries) {
const char* name = xmlLibrary.Attribute("name");
@ -219,7 +227,7 @@ bool parseEffect(const XMLElement& xmlEffect, Libraries& libraries, Effects* eff
return true;
}
/** Parse an stream from an xml element describing it.
/** Parse an <Output|Input>stream or a device from an xml element describing it.
* @return true and pushes the stream in streams on success,
* false on failure. */
template <class Stream>
@ -231,14 +239,14 @@ bool parseStream(const XMLElement& xmlStream, Effects& effects, std::vector<Stre
}
Stream stream;
if (!stringToStreamType(streamType, &stream.type)) {
ALOGE("Invalid stream type %s: %s", streamType, dump(xmlStream));
ALOGE("Invalid <stream|device> type %s: %s", streamType, dump(xmlStream));
return false;
}
for (auto& xmlApply : getChildren(xmlStream, "apply")) {
const char* effectName = xmlApply.get().Attribute("effect");
if (effectName == nullptr) {
ALOGE("stream/apply must have reference an effect: %s", dump(xmlApply));
ALOGE("<stream|device>/apply must have reference an effect: %s", dump(xmlApply));
return false;
}
auto* effect = findByName(effectName, effects);
@ -252,6 +260,21 @@ bool parseStream(const XMLElement& xmlStream, Effects& effects, std::vector<Stre
return true;
}
bool parseDeviceEffects(
const XMLElement& xmlDevice, Effects& effects, std::vector<DeviceEffects>* deviceEffects) {
const char* address = xmlDevice.Attribute("address");
if (address == nullptr) {
ALOGE("device must have an address: %s", dump(xmlDevice));
return false;
}
if (!parseStream(xmlDevice, effects, deviceEffects)) {
return false;
}
deviceEffects->back().address = address;
return true;
}
/** Internal version of the public parse(const char* path) where path always exist. */
ParsingResult parseWithPath(std::string&& path) {
XMLDocument doc;
@ -296,6 +319,14 @@ ParsingResult parseWithPath(std::string&& path) {
registerFailure(parseStream(xmlStream, config->effects, &config->postprocess));
}
}
// Parse device effect chains
for (auto& xmlDeviceEffects : getChildren(xmlConfig, "deviceEffects")) {
for (auto& xmlDevice : getChildren(xmlDeviceEffects, "devicePort")) {
registerFailure(
parseDeviceEffects(xmlDevice, config->effects, &config->deviceprocess));
}
}
}
return {std::move(config), nbSkippedElements, std::move(path)};
}

@ -99,4 +99,31 @@
</postprocess>
-->
<!-- Device pre/post processor configurations.
The device pre/post processor configuration is described in a deviceEffects element and
consists in a list of elements each describing pre/post proecessor settings for a given
device or "devicePort".
Each devicePort element has a "type" attribute corresponding to the device type (e.g.
speaker, bus), an "address" attribute corresponding to the device address and contains a
list of "apply" elements indicating one effect to apply.
If the device is a source, only pre processing effects are expected, if the
device is a sink, only post processing effects are expected.
The effect to apply is designated by its name in the "effects" elements.
The effect will be enabled by default and the audio framework will automatically add
and activate the effect if the given port is involved in an audio patch.
If the patch is "HW", the effect must be HW accelerated.
<deviceEffects>
<devicePort type="AUDIO_DEVICE_OUT_BUS" address="BUS00_USAGE_MAIN">
<apply effect="equalizer"/>
</devicePort>
<devicePort type="AUDIO_DEVICE_OUT_BUS" address="BUS04_USAGE_VOICE">
<apply effect="volume"/>
</devicePort>
<devicePort type="AUDIO_DEVICE_IN_BUILTIN_MIC" address="bottom">
<apply effect="agc"/>
</devicePort>
</deviceEffects>
-->
</audio_effects_conf>

@ -31,12 +31,24 @@ class AudioPatch : public RefBase, private HandleGenerator<audio_patch_handle_t>
public:
AudioPatch(const struct audio_patch *patch, uid_t uid);
audio_patch_handle_t getHandle() const { return mHandle; }
audio_patch_handle_t getAfHandle() const { return mAfPatchHandle; }
void setAfHandle(audio_patch_handle_t afHandle) { mAfPatchHandle = afHandle; }
uid_t getUid() const { return mUid; }
void setUid(uid_t uid) { mUid = uid; }
void dump(String8 *dst, int spaces, int index) const;
audio_patch_handle_t mHandle;
struct audio_patch mPatch;
private:
const audio_patch_handle_t mHandle;
uid_t mUid;
audio_patch_handle_t mAfPatchHandle;
audio_patch_handle_t mAfPatchHandle = AUDIO_PATCH_HANDLE_NONE;
};
class AudioPatchCollection : public DefaultKeyedVector<audio_patch_handle_t, sp<AudioPatch> >

@ -183,13 +183,17 @@ class SourceClientDescriptor: public TrackClientDescriptor
{
public:
SourceClientDescriptor(audio_port_handle_t portId, uid_t uid, audio_attributes_t attributes,
const sp<AudioPatch>& patchDesc, const sp<DeviceDescriptor>& srcDevice,
const struct audio_port_config &config,
const sp<DeviceDescriptor>& srcDevice,
audio_stream_type_t stream, product_strategy_t strategy,
VolumeSource volumeSource);
~SourceClientDescriptor() override = default;
sp<AudioPatch> patchDesc() const { return mPatchDesc; }
sp<DeviceDescriptor> srcDevice() const { return mSrcDevice; };
audio_patch_handle_t getPatchHandle() const { return mPatchHandle; }
void setPatchHandle(audio_patch_handle_t patchHandle) { mPatchHandle = patchHandle; }
sp<DeviceDescriptor> srcDevice() const { return mSrcDevice; }
wp<SwAudioOutputDescriptor> swOutput() const { return mSwOutput; }
void setSwOutput(const sp<SwAudioOutputDescriptor>& swOutput);
wp<HwAudioOutputDescriptor> hwOutput() const { return mHwOutput; }
@ -199,7 +203,7 @@ public:
void dump(String8 *dst, int spaces, int index) const override;
private:
const sp<AudioPatch> mPatchDesc;
audio_patch_handle_t mPatchHandle = AUDIO_PATCH_HANDLE_NONE;
const sp<DeviceDescriptor> mSrcDevice;
wp<SwAudioOutputDescriptor> mSwOutput;
wp<HwAudioOutputDescriptor> mHwOutput;

@ -26,10 +26,9 @@
namespace android {
AudioPatch::AudioPatch(const struct audio_patch *patch, uid_t uid) :
mHandle(HandleGenerator<audio_patch_handle_t>::getNextHandle()),
mPatch(*patch),
mUid(uid),
mAfPatchHandle(AUDIO_PATCH_HANDLE_NONE)
mHandle(HandleGenerator<audio_patch_handle_t>::getNextHandle()),
mUid(uid)
{
}
@ -68,7 +67,7 @@ status_t AudioPatchCollection::addAudioPatch(audio_patch_handle_t handle,
add(handle, patch);
ALOGV("addAudioPatch() handle %d af handle %d num_sources %d num_sinks %d source handle %d"
"sink handle %d",
handle, patch->mAfPatchHandle, patch->mPatch.num_sources, patch->mPatch.num_sinks,
handle, patch->getAfHandle(), patch->mPatch.num_sources, patch->mPatch.num_sinks,
patch->mPatch.sources[0].id, patch->mPatch.sinks[0].id);
return NO_ERROR;
}
@ -81,7 +80,7 @@ status_t AudioPatchCollection::removeAudioPatch(audio_patch_handle_t handle)
ALOGW("removeAudioPatch() patch %d not in", handle);
return ALREADY_EXISTS;
}
ALOGV("removeAudioPatch() handle %d af handle %d", handle, valueAt(index)->mAfPatchHandle);
ALOGV("removeAudioPatch() handle %d af handle %d", handle, valueAt(index)->getAfHandle());
removeItemsAt(index);
return NO_ERROR;
}
@ -123,7 +122,7 @@ status_t AudioPatchCollection::listAudioPatches(unsigned int *num_patches,
}
if (patchesWritten < patchesMax) {
patches[patchesWritten] = patch->mPatch;
patches[patchesWritten++].id = patch->mHandle;
patches[patchesWritten++].id = patch->getHandle();
}
(*num_patches)++;
ALOGV("listAudioPatches() patch %zu num_sources %d num_sinks %d",

@ -82,14 +82,13 @@ void RecordClientDescriptor::dump(String8 *dst, int spaces, int index) const
}
SourceClientDescriptor::SourceClientDescriptor(audio_port_handle_t portId, uid_t uid,
audio_attributes_t attributes, const sp<AudioPatch>& patchDesc,
audio_attributes_t attributes, const struct audio_port_config &config,
const sp<DeviceDescriptor>& srcDevice, audio_stream_type_t stream,
product_strategy_t strategy, VolumeSource volumeSource) :
TrackClientDescriptor::TrackClientDescriptor(portId, uid, AUDIO_SESSION_NONE, attributes,
AUDIO_CONFIG_BASE_INITIALIZER, AUDIO_PORT_HANDLE_NONE,
{config.sample_rate, config.channel_mask, config.format}, AUDIO_PORT_HANDLE_NONE,
stream, strategy, volumeSource, AUDIO_OUTPUT_FLAG_NONE, false,
{} /* Sources do not support secondary outputs*/),
mPatchDesc(patchDesc), mSrcDevice(srcDevice)
{} /* Sources do not support secondary outputs*/), mSrcDevice(srcDevice)
{
}

@ -525,12 +525,12 @@ uint32_t AudioPolicyManager::updateCallRouting(const DeviceVector &rxDevices, ui
// release existing RX patch if any
if (mCallRxPatch != 0) {
mpClientInterface->releaseAudioPatch(mCallRxPatch->mAfPatchHandle, 0);
releaseAudioPatchInternal(mCallRxPatch->getHandle());
mCallRxPatch.clear();
}
// release TX patch if any
if (mCallTxPatch != 0) {
mpClientInterface->releaseAudioPatch(mCallTxPatch->mAfPatchHandle, 0);
releaseAudioPatchInternal(mCallTxPatch->getHandle());
mCallTxPatch.clear();
}
@ -556,11 +556,9 @@ uint32_t AudioPolicyManager::updateCallRouting(const DeviceVector &rxDevices, ui
ALOGE("updateCallRouting() no telephony Tx and/or RX device");
return muteWaitMs;
}
// do not create a patch (aka Sw Bridging) if Primary HW module has declared supporting a
// route between telephony RX to Sink device and Source device to telephony TX
const auto &primaryModule = telephonyRxModule;
createRxPatch = !primaryModule->supportsPatch(rxSourceDevice, rxDevices.itemAt(0));
createTxPatch = !primaryModule->supportsPatch(txSourceDevice, txSinkDevice);
// createAudioPatchInternal now supports both HW / SW bridging
createRxPatch = true;
createTxPatch = true;
} else {
// If the RX device is on the primary HW module, then use legacy routing method for
// voice calls via setOutputDevice() on primary output.
@ -584,6 +582,15 @@ uint32_t AudioPolicyManager::updateCallRouting(const DeviceVector &rxDevices, ui
// assuming the device uses audio HAL V5.0 and above
}
if (createTxPatch) { // create TX path audio patch
// terminate active capture if on the same HW module as the call TX source device
// FIXME: would be better to refine to only inputs whose profile connects to the
// call TX device but this information is not in the audio patch and logic here must be
// symmetric to the one in startInput()
for (const auto& activeDesc : mInputs.getActiveInputs()) {
if (activeDesc->hasSameHwModuleAs(txSourceDevice)) {
closeActiveClients(activeDesc);
}
}
mCallTxPatch = createTelephonyPatch(false /*isRx*/, txSourceDevice, delayMs);
}
@ -597,6 +604,8 @@ sp<AudioPatch> AudioPolicyManager::createTelephonyPatch(
if (device == nullptr) {
return nullptr;
}
// @TODO: still ignoring the address, or not dealing platform with multiple telephony devices
if (isRx) {
patchBuilder.addSink(device).
addSource(mAvailableInputDevices.getDevice(
@ -607,45 +616,15 @@ sp<AudioPatch> AudioPolicyManager::createTelephonyPatch(
AUDIO_DEVICE_OUT_TELEPHONY_TX, String8(), AUDIO_FORMAT_DEFAULT));
}
// @TODO: still ignoring the address, or not dealing platform with mutliple telephonydevices
const sp<DeviceDescriptor> outputDevice = isRx ?
device : mAvailableOutputDevices.getDevice(
AUDIO_DEVICE_OUT_TELEPHONY_TX, String8(), AUDIO_FORMAT_DEFAULT);
SortedVector<audio_io_handle_t> outputs =
getOutputsForDevices(DeviceVector(outputDevice), mOutputs);
const audio_io_handle_t output = selectOutput(outputs);
// request to reuse existing output stream if one is already opened to reach the target device
if (output != AUDIO_IO_HANDLE_NONE) {
sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
ALOG_ASSERT(!outputDesc->isDuplicated(), "%s() %s device output %d is duplicated", __func__,
outputDevice->toString().c_str(), output);
patchBuilder.addSource(outputDesc, { .stream = AUDIO_STREAM_PATCH });
}
if (!isRx) {
// terminate active capture if on the same HW module as the call TX source device
// FIXME: would be better to refine to only inputs whose profile connects to the
// call TX device but this information is not in the audio patch and logic here must be
// symmetric to the one in startInput()
for (const auto& activeDesc : mInputs.getActiveInputs()) {
if (activeDesc->hasSameHwModuleAs(device)) {
closeActiveClients(activeDesc);
}
}
}
audio_patch_handle_t afPatchHandle = AUDIO_PATCH_HANDLE_NONE;
status_t status = mpClientInterface->createAudioPatch(
patchBuilder.patch(), &afPatchHandle, delayMs);
ALOGW_IF(status != NO_ERROR,
"%s() error %d creating %s audio patch", __func__, status, isRx ? "RX" : "TX");
sp<AudioPatch> audioPatch;
if (status == NO_ERROR) {
audioPatch = new AudioPatch(patchBuilder.patch(), mUidCached);
audioPatch->mAfPatchHandle = afPatchHandle;
audioPatch->mUid = mUidCached;
audio_patch_handle_t patchHandle = AUDIO_PATCH_HANDLE_NONE;
status_t status =
createAudioPatchInternal(patchBuilder.patch(), &patchHandle, mUidCached, delayMs);
ssize_t index = mAudioPatches.indexOfKey(patchHandle);
if (status != NO_ERROR || index < 0) {
ALOGW("%s() error %d creating %s audio patch", __func__, status, isRx ? "RX" : "TX");
return nullptr;
}
return audioPatch;
return mAudioPatches.valueAt(index);
}
bool AudioPolicyManager::isDeviceOfModule(
@ -728,11 +707,11 @@ void AudioPolicyManager::setPhoneState(audio_mode_t state)
updateCallRouting(rxDevices, delayMs);
} else if (oldState == AUDIO_MODE_IN_CALL) {
if (mCallRxPatch != 0) {
mpClientInterface->releaseAudioPatch(mCallRxPatch->mAfPatchHandle, 0);
releaseAudioPatchInternal(mCallRxPatch->getHandle());
mCallRxPatch.clear();
}
if (mCallTxPatch != 0) {
mpClientInterface->releaseAudioPatch(mCallTxPatch->mAfPatchHandle, 0);
releaseAudioPatchInternal(mCallTxPatch->getHandle());
mCallTxPatch.clear();
}
setOutputDevices(mPrimaryOutput, rxDevices, force, 0);
@ -1225,7 +1204,7 @@ audio_io_handle_t AudioPolicyManager::getOutputForDevices(
devices.containsDeviceWithType(sink->ext.device.type) &&
(address.isEmpty() || strncmp(sink->ext.device.address, address.string(),
AUDIO_DEVICE_MAX_ADDRESS_LEN) == 0)) {
releaseAudioPatch(patch->mHandle, mUidCached);
releaseAudioPatch(patch->getHandle(), mUidCached);
break;
}
}
@ -1312,7 +1291,7 @@ const AudioPatchCollection AudioPolicyManager::getMsdPatches() const {
const struct audio_port_config *source = &patch->mPatch.sources[j];
if (source->type == AUDIO_PORT_TYPE_DEVICE &&
source->ext.device.hw_module == msdModule->getHandle()) {
msdPatches.addAudioPatch(patch->mHandle, patch);
msdPatches.addAudioPatch(patch->getHandle(), patch);
}
}
}
@ -1442,7 +1421,7 @@ status_t AudioPolicyManager::setMsdPatch(const sp<DeviceDescriptor> &outputDevic
if (audio_patches_are_equal(&currentPatch->mPatch, patch)) {
return NO_ERROR;
}
releaseAudioPatch(currentPatch->mHandle, mUidCached);
releaseAudioPatch(currentPatch->getHandle(), mUidCached);
}
status_t status = installPatch(__func__, -1 /*index*/, nullptr /*patchHandle*/,
patch, 0 /*delayMs*/, mUidCached, nullptr /*patchDescPtr*/);
@ -3440,16 +3419,16 @@ status_t AudioPolicyManager::getAudioPort(struct audio_port *port)
return BAD_VALUE;
}
status_t AudioPolicyManager::createAudioPatch(const struct audio_patch *patch,
audio_patch_handle_t *handle,
uid_t uid)
status_t AudioPolicyManager::createAudioPatchInternal(const struct audio_patch *patch,
audio_patch_handle_t *handle,
uid_t uid, uint32_t delayMs,
const sp<SourceClientDescriptor>& sourceDesc)
{
ALOGV("createAudioPatch()");
ALOGV("%s", __func__);
if (handle == NULL || patch == NULL) {
return BAD_VALUE;
}
ALOGV("createAudioPatch() num sources %d num sinks %d", patch->num_sources, patch->num_sinks);
ALOGV("%s num sources %d num sinks %d", __func__, patch->num_sources, patch->num_sinks);
if (!audio_patch_is_valid(patch)) {
return BAD_VALUE;
@ -3471,22 +3450,22 @@ status_t AudioPolicyManager::createAudioPatch(const struct audio_patch *patch,
sp<AudioPatch> patchDesc;
ssize_t index = mAudioPatches.indexOfKey(*handle);
ALOGV("createAudioPatch source id %d role %d type %d", patch->sources[0].id,
patch->sources[0].role,
patch->sources[0].type);
ALOGV("%s source id %d role %d type %d", __func__, patch->sources[0].id,
patch->sources[0].role,
patch->sources[0].type);
#if LOG_NDEBUG == 0
for (size_t i = 0; i < patch->num_sinks; i++) {
ALOGV("createAudioPatch sink %zu: id %d role %d type %d", i, patch->sinks[i].id,
patch->sinks[i].role,
patch->sinks[i].type);
ALOGV("%s sink %zu: id %d role %d type %d", __func__ ,i, patch->sinks[i].id,
patch->sinks[i].role,
patch->sinks[i].type);
}
#endif
if (index >= 0) {
patchDesc = mAudioPatches.valueAt(index);
ALOGV("createAudioPatch() mUidCached %d patchDesc->mUid %d uid %d",
mUidCached, patchDesc->mUid, uid);
if (patchDesc->mUid != mUidCached && uid != patchDesc->mUid) {
ALOGV("%s mUidCached %d patchDesc->mUid %d uid %d",
__func__, mUidCached, patchDesc->getUid(), uid);
if (patchDesc->getUid() != mUidCached && uid != patchDesc->getUid()) {
return INVALID_OPERATION;
}
} else {
@ -3496,15 +3475,15 @@ status_t AudioPolicyManager::createAudioPatch(const struct audio_patch *patch,
if (patch->sources[0].type == AUDIO_PORT_TYPE_MIX) {
sp<SwAudioOutputDescriptor> outputDesc = mOutputs.getOutputFromId(patch->sources[0].id);
if (outputDesc == NULL) {
ALOGV("createAudioPatch() output not found for id %d", patch->sources[0].id);
ALOGV("%s output not found for id %d", __func__, patch->sources[0].id);
return BAD_VALUE;
}
ALOG_ASSERT(!outputDesc->isDuplicated(),"duplicated output %d in source in ports",
outputDesc->mIoHandle);
if (patchDesc != 0) {
if (patchDesc->mPatch.sources[0].id != patch->sources[0].id) {
ALOGV("createAudioPatch() source id differs for patch current id %d new id %d",
patchDesc->mPatch.sources[0].id, patch->sources[0].id);
ALOGV("%s source id differs for patch current id %d new id %d",
__func__, patchDesc->mPatch.sources[0].id, patch->sources[0].id);
return BAD_VALUE;
}
}
@ -3513,13 +3492,13 @@ status_t AudioPolicyManager::createAudioPatch(const struct audio_patch *patch,
// Only support mix to devices connection
// TODO add support for mix to mix connection
if (patch->sinks[i].type != AUDIO_PORT_TYPE_DEVICE) {
ALOGV("createAudioPatch() source mix but sink is not a device");
ALOGV("%s source mix but sink is not a device", __func__);
return INVALID_OPERATION;
}
sp<DeviceDescriptor> devDesc =
mAvailableOutputDevices.getDeviceFromId(patch->sinks[i].id);
if (devDesc == 0) {
ALOGV("createAudioPatch() out device not found for id %d", patch->sinks[i].id);
ALOGV("%s out device not found for id %d", __func__, patch->sinks[i].id);
return BAD_VALUE;
}
@ -3531,8 +3510,7 @@ status_t AudioPolicyManager::createAudioPatch(const struct audio_patch *patch,
patch->sources[0].channel_mask,
NULL, // updatedChannelMask
AUDIO_OUTPUT_FLAG_NONE /*FIXME*/)) {
ALOGV("createAudioPatch() profile not supported for device %08x",
devDesc->type());
ALOGV("%s profile not supported for device %08x", __func__, devDesc->type());
return INVALID_OPERATION;
}
devices.add(devDesc);
@ -3542,19 +3520,19 @@ status_t AudioPolicyManager::createAudioPatch(const struct audio_patch *patch,
}
// TODO: reconfigure output format and channels here
ALOGV("createAudioPatch() setting device %s on output %d",
dumpDeviceTypes(devices.types()).c_str(), outputDesc->mIoHandle);
ALOGV("%s setting device %s on output %d",
__func__, dumpDeviceTypes(devices.types()).c_str(), outputDesc->mIoHandle);
setOutputDevices(outputDesc, devices, true, 0, handle);
index = mAudioPatches.indexOfKey(*handle);
if (index >= 0) {
if (patchDesc != 0 && patchDesc != mAudioPatches.valueAt(index)) {
ALOGW("createAudioPatch() setOutputDevice() did not reuse the patch provided");
ALOGW("%s setOutputDevice() did not reuse the patch provided", __func__);
}
patchDesc = mAudioPatches.valueAt(index);
patchDesc->mUid = uid;
ALOGV("createAudioPatch() success");
patchDesc->setUid(uid);
ALOGV("%s success", __func__);
} else {
ALOGW("createAudioPatch() setOutputDevice() failed to create a patch");
ALOGW("%s setOutputDevice() failed to create a patch", __func__);
return INVALID_OPERATION;
}
} else if (patch->sources[0].type == AUDIO_PORT_TYPE_DEVICE) {
@ -3593,19 +3571,19 @@ status_t AudioPolicyManager::createAudioPatch(const struct audio_patch *patch,
return INVALID_OPERATION;
}
// TODO: reconfigure output format and channels here
ALOGV("%s() setting device %s on output %d", __func__,
ALOGV("%s setting device %s on output %d", __func__,
device->toString().c_str(), inputDesc->mIoHandle);
setInputDevice(inputDesc->mIoHandle, device, true, handle);
index = mAudioPatches.indexOfKey(*handle);
if (index >= 0) {
if (patchDesc != 0 && patchDesc != mAudioPatches.valueAt(index)) {
ALOGW("createAudioPatch() setInputDevice() did not reuse the patch provided");
ALOGW("%s setInputDevice() did not reuse the patch provided", __func__);
}
patchDesc = mAudioPatches.valueAt(index);
patchDesc->mUid = uid;
ALOGV("createAudioPatch() success");
patchDesc->setUid(uid);
ALOGV("%s success", __func__);
} else {
ALOGW("createAudioPatch() setInputDevice() failed to create a patch");
ALOGW("%s setInputDevice() failed to create a patch", __func__);
return INVALID_OPERATION;
}
} else if (patch->sinks[0].type == AUDIO_PORT_TYPE_DEVICE) {
@ -3623,55 +3601,97 @@ status_t AudioPolicyManager::createAudioPatch(const struct audio_patch *patch,
//update source and sink with our own data as the data passed in the patch may
// be incomplete.
struct audio_patch newPatch = *patch;
srcDevice->toAudioPortConfig(&newPatch.sources[0], &patch->sources[0]);
PatchBuilder patchBuilder;
audio_port_config sourcePortConfig = {};
srcDevice->toAudioPortConfig(&sourcePortConfig, &patch->sources[0]);
patchBuilder.addSource(sourcePortConfig);
for (size_t i = 0; i < patch->num_sinks; i++) {
if (patch->sinks[i].type != AUDIO_PORT_TYPE_DEVICE) {
ALOGV("createAudioPatch() source device but one sink is not a device");
ALOGV("%s source device but one sink is not a device", __func__);
return INVALID_OPERATION;
}
sp<DeviceDescriptor> sinkDevice =
mAvailableOutputDevices.getDeviceFromId(patch->sinks[i].id);
if (sinkDevice == 0) {
return BAD_VALUE;
}
sinkDevice->toAudioPortConfig(&newPatch.sinks[i], &patch->sinks[i]);
audio_port_config sinkPortConfig = {};
sinkDevice->toAudioPortConfig(&sinkPortConfig, &patch->sinks[i]);
patchBuilder.addSink(sinkPortConfig);
// create a software bridge in PatchPanel if:
// - source and sink devices are on different HW modules OR
// - audio HAL version is < 3.0
// - audio HAL version is >= 3.0 but no route has been declared between devices
// - called from startAudioSource (aka sourceDesc != nullptr) and source device does
// not have a gain controller
if (!srcDevice->hasSameHwModuleAs(sinkDevice) ||
(srcDevice->getModuleVersionMajor() < 3) ||
!srcDevice->getModule()->supportsPatch(srcDevice, sinkDevice)) {
!srcDevice->getModule()->supportsPatch(srcDevice, sinkDevice) ||
(sourceDesc != nullptr &&
srcDevice->getAudioPort()->getGains().size() == 0)) {
// support only one sink device for now to simplify output selection logic
if (patch->num_sinks > 1) {
return INVALID_OPERATION;
}
SortedVector<audio_io_handle_t> outputs =
getOutputsForDevices(DeviceVector(sinkDevice), mOutputs);
// if the sink device is reachable via an opened output stream, request to go via
// this output stream by adding a second source to the patch description
const audio_io_handle_t output = selectOutput(outputs);
audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
if (sourceDesc != nullptr) {
// take care of dynamic routing for SwOutput selection,
audio_attributes_t attributes = sourceDesc->attributes();
audio_stream_type_t stream = sourceDesc->stream();
audio_attributes_t resultAttr;
audio_config_t config = AUDIO_CONFIG_INITIALIZER;
config.sample_rate = sourceDesc->config().sample_rate;
config.channel_mask = sourceDesc->config().channel_mask;
config.format = sourceDesc->config().format;
audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE;
audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
bool isRequestedDeviceForExclusiveUse = false;
std::vector<sp<SwAudioOutputDescriptor>> secondaryOutputs;
output_type_t outputType;
getOutputForAttrInt(&resultAttr, &output, AUDIO_SESSION_NONE, &attributes,
&stream, sourceDesc->uid(), &config, &flags,
&selectedDeviceId, &isRequestedDeviceForExclusiveUse,
&secondaryOutputs, &outputType);
if (output == AUDIO_IO_HANDLE_NONE) {
ALOGV("%s no output for device %s",
__FUNCTION__, sinkDevice->toString().c_str());
return INVALID_OPERATION;
}
} else {
SortedVector<audio_io_handle_t> outputs =
getOutputsForDevices(DeviceVector(sinkDevice), mOutputs);
// if the sink device is reachable via an opened output stream, request to
// go via this output stream by adding a second source to the patch
// description
output = selectOutput(outputs);
}
if (output != AUDIO_IO_HANDLE_NONE) {
sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
if (outputDesc->isDuplicated()) {
ALOGV("%s output for device %s is duplicated",
__FUNCTION__, sinkDevice->toString().c_str());
return INVALID_OPERATION;
}
outputDesc->toAudioPortConfig(&newPatch.sources[1], &patch->sources[0]);
newPatch.sources[1].ext.mix.usecase.stream = AUDIO_STREAM_PATCH;
newPatch.num_sources = 2;
audio_port_config srcMixPortConfig = {};
outputDesc->toAudioPortConfig(&srcMixPortConfig, &patch->sources[0]);
if (sourceDesc != nullptr) {
sourceDesc->setSwOutput(outputDesc);
}
// for volume control, we may need a valid stream
srcMixPortConfig.ext.mix.usecase.stream = sourceDesc != nullptr ?
sourceDesc->stream() : AUDIO_STREAM_PATCH;
patchBuilder.addSource(srcMixPortConfig);
}
}
}
// TODO: check from routing capabilities in config file and other conflicting patches
status_t status = installPatch(__func__, index, handle, &newPatch, 0, uid, &patchDesc);
status_t status = installPatch(
__func__, index, handle, patchBuilder.patch(), delayMs, uid, &patchDesc);
if (status != NO_ERROR) {
ALOGW("createAudioPatch() patch panel could not connect device patch, error %d",
status);
ALOGW("%s patch panel could not connect device patch, error %d", __func__, status);
return INVALID_OPERATION;
}
} else {
@ -3694,18 +3714,29 @@ status_t AudioPolicyManager::releaseAudioPatch(audio_patch_handle_t handle,
return BAD_VALUE;
}
sp<AudioPatch> patchDesc = mAudioPatches.valueAt(index);
ALOGV("releaseAudioPatch() mUidCached %d patchDesc->mUid %d uid %d",
mUidCached, patchDesc->mUid, uid);
if (patchDesc->mUid != mUidCached && uid != patchDesc->mUid) {
ALOGV("%s() mUidCached %d patchDesc->mUid %d uid %d",
__func__, mUidCached, patchDesc->getUid(), uid);
if (patchDesc->getUid() != mUidCached && uid != patchDesc->getUid()) {
return INVALID_OPERATION;
}
return releaseAudioPatchInternal(handle);
}
status_t AudioPolicyManager::releaseAudioPatchInternal(audio_patch_handle_t handle,
uint32_t delayMs)
{
ALOGV("%s patch %d", __func__, handle);
if (mAudioPatches.indexOfKey(handle) < 0) {
ALOGE("%s: no patch found with handle=%d", __func__, handle);
return BAD_VALUE;
}
sp<AudioPatch> patchDesc = mAudioPatches.valueFor(handle);
struct audio_patch *patch = &patchDesc->mPatch;
patchDesc->mUid = mUidCached;
patchDesc->setUid(mUidCached);
if (patch->sources[0].type == AUDIO_PORT_TYPE_MIX) {
sp<SwAudioOutputDescriptor> outputDesc = mOutputs.getOutputFromId(patch->sources[0].id);
if (outputDesc == NULL) {
ALOGV("releaseAudioPatch() output not found for id %d", patch->sources[0].id);
ALOGV("%s output not found for id %d", __func__, patch->sources[0].id);
return BAD_VALUE;
}
@ -3718,7 +3749,7 @@ status_t AudioPolicyManager::releaseAudioPatch(audio_patch_handle_t handle,
if (patch->sinks[0].type == AUDIO_PORT_TYPE_MIX) {
sp<AudioInputDescriptor> inputDesc = mInputs.getInputFromId(patch->sinks[0].id);
if (inputDesc == NULL) {
ALOGV("releaseAudioPatch() input not found for id %d", patch->sinks[0].id);
ALOGV("%s input not found for id %d", __func__, patch->sinks[0].id);
return BAD_VALUE;
}
setInputDevice(inputDesc->mIoHandle,
@ -3726,10 +3757,11 @@ status_t AudioPolicyManager::releaseAudioPatch(audio_patch_handle_t handle,
true,
NULL);
} else if (patch->sinks[0].type == AUDIO_PORT_TYPE_DEVICE) {
status_t status = mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
ALOGV("releaseAudioPatch() patch panel returned %d patchHandle %d",
status, patchDesc->mAfPatchHandle);
removeAudioPatch(patchDesc->mHandle);
status_t status =
mpClientInterface->releaseAudioPatch(patchDesc->getAfHandle(), delayMs);
ALOGV("%s patch panel returned %d patchHandle %d",
__func__, status, patchDesc->getAfHandle());
removeAudioPatch(patchDesc->getHandle());
nextAudioPortGeneration();
mpClientInterface->onAudioPatchListUpdate();
} else {
@ -3827,7 +3859,7 @@ void AudioPolicyManager::clearAudioPatches(uid_t uid)
{
for (ssize_t i = (ssize_t)mAudioPatches.size() - 1; i >= 0; i--) {
sp<AudioPatch> patchDesc = mAudioPatches.valueAt(i);
if (patchDesc->mUid == uid) {
if (patchDesc->getUid() == uid) {
releaseAudioPatch(mAudioPatches.keyAt(i), uid);
}
}
@ -3963,11 +3995,8 @@ status_t AudioPolicyManager::startAudioSource(const struct audio_port_config *so
*portId = PolicyAudioPort::getNextUniqueId();
struct audio_patch dummyPatch = {};
sp<AudioPatch> patchDesc = new AudioPatch(&dummyPatch, uid);
sp<SourceClientDescriptor> sourceDesc =
new SourceClientDescriptor(*portId, uid, *attributes, patchDesc, srcDevice,
new SourceClientDescriptor(*portId, uid, *attributes, *source, srcDevice,
mEngine->getStreamTypeForAttributes(*attributes),
mEngine->getProductStrategyForAttributes(*attributes),
toVolumeSource(*attributes));
@ -3987,7 +4016,6 @@ status_t AudioPolicyManager::connectAudioSource(const sp<SourceClientDescriptor>
disconnectAudioSource(sourceDesc);
audio_attributes_t attributes = sourceDesc->attributes();
audio_stream_type_t stream = sourceDesc->stream();
sp<DeviceDescriptor> srcDevice = sourceDesc->srcDevice();
DeviceVector sinkDevices =
@ -3997,92 +4025,55 @@ status_t AudioPolicyManager::connectAudioSource(const sp<SourceClientDescriptor>
ALOG_ASSERT(mAvailableOutputDevices.contains(sinkDevice), "%s: Device %s not available",
__FUNCTION__, sinkDevice->toString().c_str());
audio_patch_handle_t afPatchHandle = AUDIO_PATCH_HANDLE_NONE;
if (srcDevice->hasSameHwModuleAs(sinkDevice) &&
srcDevice->getModuleVersionMajor() >= 3 &&
sinkDevice->getModule()->supportsPatch(srcDevice, sinkDevice) &&
srcDevice->getAudioPort()->getGains().size() > 0) {
ALOGV("%s Device to Device route supported by >=3.0 HAL", __FUNCTION__);
// TODO: may explicitly specify whether we should use HW or SW patch
// create patch between src device and output device
// create Hwoutput and add to mHwOutputs
} else {
audio_attributes_t resultAttr;
audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
audio_config_t config = AUDIO_CONFIG_INITIALIZER;
config.sample_rate = sourceDesc->config().sample_rate;
config.channel_mask = sourceDesc->config().channel_mask;
config.format = sourceDesc->config().format;
audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE;
audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
bool isRequestedDeviceForExclusiveUse = false;
std::vector<sp<SwAudioOutputDescriptor>> secondaryOutputs;
output_type_t outputType;
getOutputForAttrInt(&resultAttr, &output, AUDIO_SESSION_NONE,
&attributes, &stream, sourceDesc->uid(), &config, &flags,
&selectedDeviceId, &isRequestedDeviceForExclusiveUse,
&secondaryOutputs, &outputType);
if (output == AUDIO_IO_HANDLE_NONE) {
ALOGV("%s no output for device %s",
__FUNCTION__, dumpDeviceTypes(sinkDevices.types()).c_str());
return INVALID_OPERATION;
}
sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
if (outputDesc->isDuplicated()) {
ALOGV("%s output for device %s is duplicated",
__FUNCTION__, dumpDeviceTypes(sinkDevices.types()).c_str());
return INVALID_OPERATION;
}
status_t status = outputDesc->start();
if (status != NO_ERROR) {
return status;
}
// create a special patch with no sink and two sources:
// - the second source indicates to PatchPanel through which output mix this patch should
// be connected as well as the stream type for volume control
// - the sink is defined by whatever output device is currently selected for the output
// though which this patch is routed.
PatchBuilder patchBuilder;
patchBuilder.addSource(srcDevice).addSource(outputDesc, { .stream = stream });
status = mpClientInterface->createAudioPatch(patchBuilder.patch(),
&afPatchHandle,
0);
ALOGV("%s patch panel returned %d patchHandle %d", __FUNCTION__,
status, afPatchHandle);
sourceDesc->patchDesc()->mPatch = *patchBuilder.patch();
PatchBuilder patchBuilder;
patchBuilder.addSink(sinkDevice).addSource(srcDevice);
audio_patch_handle_t handle = AUDIO_PATCH_HANDLE_NONE;
status_t status =
createAudioPatchInternal(patchBuilder.patch(), &handle, mUidCached, 0, sourceDesc);
if (status != NO_ERROR || mAudioPatches.indexOfKey(handle) < 0) {
ALOGW("%s patch panel could not connect device patch, error %d", __func__, status);
return INVALID_OPERATION;
}
sourceDesc->setPatchHandle(handle);
// SW Bridge? (@todo: HW bridge, keep track of HwOutput for device selection "reconsideration")
sp<SwAudioOutputDescriptor> swOutput = sourceDesc->swOutput().promote();
if (swOutput != 0) {
status = swOutput->start();
if (status != NO_ERROR) {
ALOGW("%s patch panel could not connect device patch, error %d",
__FUNCTION__, status);
return INVALID_OPERATION;
goto FailureSourceAdded;
}
if (outputDesc->getClient(sourceDesc->portId()) != nullptr) {
if (swOutput->getClient(sourceDesc->portId()) != nullptr) {
ALOGW("%s source portId has already been attached to outputDesc", __func__);
return INVALID_OPERATION;
goto FailureReleasePatch;
}
outputDesc->addClient(sourceDesc);
swOutput->addClient(sourceDesc);
uint32_t delayMs = 0;
status = startSource(outputDesc, sourceDesc, &delayMs);
status = startSource(swOutput, sourceDesc, &delayMs);
if (status != NO_ERROR) {
mpClientInterface->releaseAudioPatch(sourceDesc->patchDesc()->mAfPatchHandle, 0);
outputDesc->removeClient(sourceDesc->portId());
outputDesc->stop();
return status;
ALOGW("%s failed to start source, error %d", __FUNCTION__, status);
goto FailureSourceActive;
}
sourceDesc->setSwOutput(outputDesc);
if (delayMs != 0) {
usleep(delayMs * 1000);
}
} else {
sp<HwAudioOutputDescriptor> hwOutputDesc = sourceDesc->hwOutput().promote();
if (hwOutputDesc != 0) {
// create Hwoutput and add to mHwOutputs
} else {
ALOGW("%s source has neither SW nor HW output", __FUNCTION__);
}
}
sourceDesc->patchDesc()->mAfPatchHandle = afPatchHandle;
addAudioPatch(sourceDesc->patchDesc()->mHandle, sourceDesc->patchDesc());
return NO_ERROR;
FailureSourceActive:
swOutput->stop();
releaseOutput(sourceDesc->portId());
FailureSourceAdded:
sourceDesc->setSwOutput(nullptr);
FailureReleasePatch:
releaseAudioPatchInternal(handle);
return INVALID_OPERATION;
}
status_t AudioPolicyManager::stopAudioSource(audio_port_handle_t portId)
@ -4326,33 +4317,22 @@ bool AudioPolicyManager::isCallScreenModeSupported()
status_t AudioPolicyManager::disconnectAudioSource(const sp<SourceClientDescriptor>& sourceDesc)
{
ALOGV("%s port Id %d", __FUNCTION__, sourceDesc->portId());
sp<AudioPatch> patchDesc = mAudioPatches.valueFor(sourceDesc->patchDesc()->mHandle);
if (patchDesc == 0) {
ALOGW("%s source has no patch with handle %d", __FUNCTION__,
sourceDesc->patchDesc()->mHandle);
return BAD_VALUE;
}
removeAudioPatch(sourceDesc->patchDesc()->mHandle);
sp<SwAudioOutputDescriptor> swOutputDesc = sourceDesc->swOutput().promote();
if (swOutputDesc != 0) {
status_t status = stopSource(swOutputDesc, sourceDesc);
sp<SwAudioOutputDescriptor> swOutput = sourceDesc->swOutput().promote();
if (swOutput != 0) {
status_t status = stopSource(swOutput, sourceDesc);
if (status == NO_ERROR) {
swOutputDesc->stop();
swOutput->stop();
}
swOutputDesc->removeClient(sourceDesc->portId());
mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
releaseOutput(sourceDesc->portId());
} else {
sp<HwAudioOutputDescriptor> hwOutputDesc = sourceDesc->hwOutput().promote();
if (hwOutputDesc != 0) {
// release patch between src device and output device
// close Hwoutput and remove from mHwOutputs
} else {
ALOGW("%s source has neither SW nor HW output", __FUNCTION__);
}
}
return NO_ERROR;
return releaseAudioPatchInternal(sourceDesc->getPatchHandle());
}
sp<SourceClientDescriptor> AudioPolicyManager::getSourceForAttributesOnOutput(
@ -5060,7 +5040,8 @@ void AudioPolicyManager::closeOutput(audio_io_handle_t output)
ssize_t index = mAudioPatches.indexOfKey(closingOutput->getPatchHandle());
if (index >= 0) {
sp<AudioPatch> patchDesc = mAudioPatches.valueAt(index);
(void) /*status_t status*/ mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
(void) /*status_t status*/ mpClientInterface->releaseAudioPatch(
patchDesc->getAfHandle(), 0);
mAudioPatches.removeItemsAt(index);
mpClientInterface->onAudioPatchListUpdate();
}
@ -5106,7 +5087,8 @@ void AudioPolicyManager::closeInput(audio_io_handle_t input)
ssize_t index = mAudioPatches.indexOfKey(inputDesc->getPatchHandle());
if (index >= 0) {
sp<AudioPatch> patchDesc = mAudioPatches.valueAt(index);
(void) /*status_t status*/ mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
(void) /*status_t status*/ mpClientInterface->releaseAudioPatch(
patchDesc->getAfHandle(), 0);
mAudioPatches.removeItemsAt(index);
mpClientInterface->onAudioPatchListUpdate();
}
@ -5357,7 +5339,7 @@ DeviceVector AudioPolicyManager::getNewOutputDevices(const sp<SwAudioOutputDescr
ssize_t index = mAudioPatches.indexOfKey(outputDesc->getPatchHandle());
if (index >= 0) {
sp<AudioPatch> patchDesc = mAudioPatches.valueAt(index);
if (patchDesc->mUid != mUidCached) {
if (patchDesc->getUid() != mUidCached) {
ALOGV("%s device %s forced by patch %d", __func__,
outputDesc->devices().toString().c_str(), outputDesc->getPatchHandle());
return outputDesc->devices();
@ -5408,7 +5390,7 @@ sp<DeviceDescriptor> AudioPolicyManager::getNewInputDevice(
ssize_t index = mAudioPatches.indexOfKey(inputDesc->getPatchHandle());
if (index >= 0) {
sp<AudioPatch> patchDesc = mAudioPatches.valueAt(index);
if (patchDesc->mUid != mUidCached) {
if (patchDesc->getUid() != mUidCached) {
ALOGV("getNewInputDevice() device %s forced by patch %d",
inputDesc->getDevice()->toString().c_str(), inputDesc->getPatchHandle());
return inputDesc->getDevice();
@ -5764,10 +5746,10 @@ status_t AudioPolicyManager::resetOutputDevice(const sp<AudioOutputDescriptor>&
return INVALID_OPERATION;
}
sp< AudioPatch> patchDesc = mAudioPatches.valueAt(index);
status_t status = mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, delayMs);
status_t status = mpClientInterface->releaseAudioPatch(patchDesc->getAfHandle(), delayMs);
ALOGV("resetOutputDevice() releaseAudioPatch returned %d", status);
outputDesc->setPatchHandle(AUDIO_PATCH_HANDLE_NONE);
removeAudioPatch(patchDesc->mHandle);
removeAudioPatch(patchDesc->getHandle());
nextAudioPortGeneration();
mpClientInterface->onAudioPatchListUpdate();
return status;
@ -5817,10 +5799,10 @@ status_t AudioPolicyManager::resetInputDevice(audio_io_handle_t input,
return INVALID_OPERATION;
}
sp< AudioPatch> patchDesc = mAudioPatches.valueAt(index);
status_t status = mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
status_t status = mpClientInterface->releaseAudioPatch(patchDesc->getAfHandle(), 0);
ALOGV("resetInputDevice() releaseAudioPatch returned %d", status);
inputDesc->setPatchHandle(AUDIO_PATCH_HANDLE_NONE);
removeAudioPatch(patchDesc->mHandle);
removeAudioPatch(patchDesc->getHandle());
nextAudioPortGeneration();
mpClientInterface->onAudioPatchListUpdate();
return status;
@ -6246,8 +6228,8 @@ void AudioPolicyManager::cleanUpForDevice(const sp<DeviceDescriptor>& deviceDesc
}
}
if (release) {
ALOGV("%s releasing patch %u", __FUNCTION__, patchDesc->mHandle);
releaseAudioPatch(patchDesc->mHandle, patchDesc->mUid);
ALOGV("%s releasing patch %u", __FUNCTION__, patchDesc->getHandle());
releaseAudioPatch(patchDesc->getHandle(), patchDesc->getUid());
}
}
@ -6422,7 +6404,7 @@ status_t AudioPolicyManager::installPatch(const char *caller,
status_t status = installPatch(
caller, index, patchHandle, patch, delayMs, mUidCached, &patchDesc);
if (status == NO_ERROR) {
ioDescriptor->setPatchHandle(patchDesc->mHandle);
ioDescriptor->setPatchHandle(patchDesc->getHandle());
}
return status;
}
@ -6439,7 +6421,7 @@ status_t AudioPolicyManager::installPatch(const char *caller,
audio_patch_handle_t afPatchHandle = AUDIO_PATCH_HANDLE_NONE;
if (index >= 0) {
patchDesc = mAudioPatches.valueAt(index);
afPatchHandle = patchDesc->mAfPatchHandle;
afPatchHandle = patchDesc->getAfHandle();
}
status_t status = mpClientInterface->createAudioPatch(patch, &afPatchHandle, delayMs);
@ -6448,13 +6430,13 @@ status_t AudioPolicyManager::installPatch(const char *caller,
if (status == NO_ERROR) {
if (index < 0) {
patchDesc = new AudioPatch(patch, uid);
addAudioPatch(patchDesc->mHandle, patchDesc);
addAudioPatch(patchDesc->getHandle(), patchDesc);
} else {
patchDesc->mPatch = *patch;
}
patchDesc->mAfPatchHandle = afPatchHandle;
patchDesc->setAfHandle(afPatchHandle);
if (patchHandle) {
*patchHandle = patchDesc->mHandle;
*patchHandle = patchDesc->getHandle();
}
nextAudioPortGeneration();
mpClientInterface->onAudioPatchListUpdate();

@ -238,7 +238,10 @@ public:
virtual status_t getAudioPort(struct audio_port *port);
virtual status_t createAudioPatch(const struct audio_patch *patch,
audio_patch_handle_t *handle,
uid_t uid);
uid_t uid) {
return createAudioPatchInternal(patch, handle, uid);
}
virtual status_t releaseAudioPatch(audio_patch_handle_t handle,
uid_t uid);
virtual status_t listAudioPatches(unsigned int *num_patches,
@ -881,6 +884,29 @@ private:
param.addInt(String8(AudioParameter::keyMonoOutput), (int)mMasterMono);
mpClientInterface->setParameters(output, param.toString());
}
/**
* @brief createAudioPatchInternal internal function to manage audio patch creation
* @param[in] patch structure containing sink and source ports configuration
* @param[out] handle patch handle to be provided if patch installed correctly
* @param[in] uid of the client
* @param[in] delayMs if required
* @param[in] sourceDesc [optional] in case of external source, source client to be
* configured by the patch, i.e. assigning an Output (HW or SW)
* @return NO_ERROR if patch installed correctly, error code otherwise.
*/
status_t createAudioPatchInternal(const struct audio_patch *patch,
audio_patch_handle_t *handle,
uid_t uid, uint32_t delayMs = 0,
const sp<SourceClientDescriptor>& sourceDesc = nullptr);
/**
* @brief releaseAudioPatchInternal internal function to remove an audio patch
* @param[in] handle of the patch to be removed
* @param[in] delayMs if required
* @return NO_ERROR if patch removed correctly, error code otherwise.
*/
status_t releaseAudioPatchInternal(audio_patch_handle_t handle, uint32_t delayMs = 0);
status_t installPatch(const char *caller,
audio_patch_handle_t *patchHandle,
AudioIODescriptorInterface *ioDescriptor,

@ -42,7 +42,10 @@ namespace android {
AudioPolicyEffects::AudioPolicyEffects()
{
status_t loadResult = loadAudioEffectXmlConfig();
if (loadResult < 0) {
if (loadResult == NO_ERROR) {
mDefaultDeviceEffectFuture = std::async(
std::launch::async, &AudioPolicyEffects::initDefaultDeviceEffects, this);
} else if (loadResult < 0) {
ALOGW("Failed to load XML effect configuration, fallback to .conf");
// load automatic audio effect modules
if (access(AUDIO_EFFECT_VENDOR_CONFIG_FILE, R_OK) == 0) {
@ -908,8 +911,24 @@ status_t AudioPolicyEffects::loadAudioEffectXmlConfig() {
streams.add(stream.type, effectDescs.release());
}
};
auto loadDeviceProcessingChain = [](auto &processingChain, auto& devicesEffects) {
for (auto& deviceProcess : processingChain) {
auto effectDescs = std::make_unique<EffectDescVector>();
for (auto& effect : deviceProcess.effects) {
effectDescs->mEffects.add(
new EffectDesc{effect.get().name.c_str(), effect.get().uuid});
}
auto deviceEffects = std::make_unique<DeviceEffects>(
std::move(effectDescs), deviceProcess.type, deviceProcess.address);
devicesEffects.emplace(deviceProcess.address, std::move(deviceEffects));
}
};
loadProcessingChain(result.parsedConfig->preprocess, mInputSources);
loadProcessingChain(result.parsedConfig->postprocess, mOutputStreams);
loadDeviceProcessingChain(result.parsedConfig->deviceprocess, mDeviceEffects);
// Casting from ssize_t to status_t is probably safe, there should not be more than 2^31 errors
return result.nbSkippedElement;
}
@ -942,5 +961,32 @@ status_t AudioPolicyEffects::loadAudioEffectConfig(const char *path)
return NO_ERROR;
}
void AudioPolicyEffects::initDefaultDeviceEffects()
{
Mutex::Autolock _l(mLock);
for (const auto& deviceEffectsIter : mDeviceEffects) {
const auto& deviceEffects = deviceEffectsIter.second;
for (const auto& effectDesc : deviceEffects->mEffectDescriptors->mEffects) {
auto fx = std::make_unique<AudioEffect>(
EFFECT_UUID_NULL, String16("android"), &effectDesc->mUuid, 0, nullptr,
nullptr, AUDIO_SESSION_DEVICE, AUDIO_IO_HANDLE_NONE,
AudioDeviceTypeAddr{deviceEffects->getDeviceType(),
deviceEffects->getDeviceAddress()});
status_t status = fx->initCheck();
if (status != NO_ERROR && status != ALREADY_EXISTS) {
ALOGE("%s(): failed to create Fx %s on port type=%d address=%s", __func__,
effectDesc->mName, deviceEffects->getDeviceType(),
deviceEffects->getDeviceAddress().c_str());
// fx goes out of scope and strong ref on AudioEffect is released
continue;
}
fx->setEnabled(true);
ALOGV("%s(): create Fx %s added on port type=%d address=%s", __func__,
effectDesc->mName, deviceEffects->getDeviceType(),
deviceEffects->getDeviceAddress().c_str());
deviceEffects->mEffects.push_back(std::move(fx));
}
}
}
} // namespace android

@ -25,6 +25,9 @@
#include <system/audio.h>
#include <utils/Vector.h>
#include <utils/SortedVector.h>
#include <android-base/thread_annotations.h>
#include <future>
namespace android {
@ -104,6 +107,7 @@ public:
status_t removeStreamDefaultEffect(audio_unique_id_t id);
private:
void initDefaultDeviceEffects();
// class to store the description of an effects and its parameters
// as defined in audio_effects.conf
@ -192,6 +196,28 @@ private:
Vector< sp<AudioEffect> >mEffects;
};
/**
* @brief The DeviceEffects class stores the effects associated to a given Device Port.
*/
class DeviceEffects {
public:
DeviceEffects(std::unique_ptr<EffectDescVector> effectDescriptors,
audio_devices_t device, const std::string& address) :
mEffectDescriptors(std::move(effectDescriptors)),
mDeviceType(device), mDeviceAddress(address) {}
/*virtual*/ ~DeviceEffects() = default;
std::vector<std::unique_ptr<AudioEffect>> mEffects;
audio_devices_t getDeviceType() const { return mDeviceType; }
std::string getDeviceAddress() const { return mDeviceAddress; }
const std::unique_ptr<EffectDescVector> mEffectDescriptors;
private:
const audio_devices_t mDeviceType;
const std::string mDeviceAddress;
};
static const char * const kInputSourceNames[AUDIO_SOURCE_CNT -1];
static audio_source_t inputSourceNameToEnum(const char *name);
@ -237,6 +263,19 @@ private:
KeyedVector< audio_stream_type_t, EffectDescVector* > mOutputStreams;
// Automatic output effects are unique for audiosession ID
KeyedVector< audio_session_t, EffectVector* > mOutputSessions;
/**
* @brief mDeviceEffects map of device effects indexed by the device address
*/
std::map<std::string, std::unique_ptr<DeviceEffects>> mDeviceEffects GUARDED_BY(mLock);
/**
* Device Effect initialization must be asynchronous: the audio_policy service parses and init
* effect on first reference. AudioFlinger will handle effect creation and register these
* effect on audio_policy service.
* We must store the reference of the furture garantee real asynchronous operation.
*/
std::future<void> mDefaultDeviceEffectFuture;
};
} // namespace android

Loading…
Cancel
Save