|
|
|
@ -780,17 +780,39 @@ audio_io_handle_t AudioPolicyManager::getOutput(audio_stream_type_t stream)
|
|
|
|
|
return output;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr,
|
|
|
|
|
audio_io_handle_t *output,
|
|
|
|
|
audio_session_t session,
|
|
|
|
|
audio_stream_type_t *stream,
|
|
|
|
|
uid_t uid,
|
|
|
|
|
const audio_config_t *config,
|
|
|
|
|
audio_output_flags_t *flags,
|
|
|
|
|
audio_port_handle_t *selectedDeviceId,
|
|
|
|
|
audio_port_handle_t *portId)
|
|
|
|
|
status_t AudioPolicyManager::getAudioAttributes(audio_attributes_t *dstAttr,
|
|
|
|
|
const audio_attributes_t *srcAttr,
|
|
|
|
|
audio_stream_type_t srcStream)
|
|
|
|
|
{
|
|
|
|
|
if (srcAttr != NULL) {
|
|
|
|
|
if (!isValidAttributes(srcAttr)) {
|
|
|
|
|
ALOGE("%s invalid attributes: usage=%d content=%d flags=0x%x tags=[%s]",
|
|
|
|
|
__func__,
|
|
|
|
|
srcAttr->usage, srcAttr->content_type, srcAttr->flags,
|
|
|
|
|
srcAttr->tags);
|
|
|
|
|
return BAD_VALUE;
|
|
|
|
|
}
|
|
|
|
|
*dstAttr = *srcAttr;
|
|
|
|
|
} else {
|
|
|
|
|
if (srcStream < AUDIO_STREAM_MIN || srcStream >= AUDIO_STREAM_PUBLIC_CNT) {
|
|
|
|
|
ALOGE("%s: invalid stream type", __func__);
|
|
|
|
|
return BAD_VALUE;
|
|
|
|
|
}
|
|
|
|
|
stream_type_to_audio_attributes(srcStream, dstAttr);
|
|
|
|
|
}
|
|
|
|
|
return NO_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
status_t AudioPolicyManager::getOutputForAttrInt(audio_attributes_t *resultAttr,
|
|
|
|
|
audio_io_handle_t *output,
|
|
|
|
|
audio_session_t session,
|
|
|
|
|
const audio_attributes_t *attr,
|
|
|
|
|
audio_stream_type_t *stream,
|
|
|
|
|
uid_t uid,
|
|
|
|
|
const audio_config_t *config,
|
|
|
|
|
audio_output_flags_t *flags,
|
|
|
|
|
audio_port_handle_t *selectedDeviceId)
|
|
|
|
|
{
|
|
|
|
|
audio_attributes_t attributes;
|
|
|
|
|
DeviceVector outputDevices;
|
|
|
|
|
routing_strategy strategy;
|
|
|
|
|
audio_devices_t device;
|
|
|
|
@ -798,35 +820,20 @@ status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr,
|
|
|
|
|
audio_devices_t msdDevice =
|
|
|
|
|
getModuleDeviceTypes(mAvailableOutputDevices, AUDIO_HARDWARE_MODULE_ID_MSD);
|
|
|
|
|
|
|
|
|
|
// The supplied portId must be AUDIO_PORT_HANDLE_NONE
|
|
|
|
|
if (*portId != AUDIO_PORT_HANDLE_NONE) {
|
|
|
|
|
return INVALID_OPERATION;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (attr != NULL) {
|
|
|
|
|
if (!isValidAttributes(attr)) {
|
|
|
|
|
ALOGE("getOutputForAttr() invalid attributes: usage=%d content=%d flags=0x%x tags=[%s]",
|
|
|
|
|
attr->usage, attr->content_type, attr->flags,
|
|
|
|
|
attr->tags);
|
|
|
|
|
return BAD_VALUE;
|
|
|
|
|
}
|
|
|
|
|
attributes = *attr;
|
|
|
|
|
} else {
|
|
|
|
|
if (*stream < AUDIO_STREAM_MIN || *stream >= AUDIO_STREAM_PUBLIC_CNT) {
|
|
|
|
|
ALOGE("getOutputForAttr(): invalid stream type");
|
|
|
|
|
return BAD_VALUE;
|
|
|
|
|
}
|
|
|
|
|
stream_type_to_audio_attributes(*stream, &attributes);
|
|
|
|
|
status_t status = getAudioAttributes(resultAttr, attr, *stream);
|
|
|
|
|
if (status != NO_ERROR) {
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ALOGV("getOutputForAttr() usage=%d, content=%d, tag=%s flags=%08x"
|
|
|
|
|
ALOGV("%s usage=%d, content=%d, tag=%s flags=%08x"
|
|
|
|
|
" session %d selectedDeviceId %d",
|
|
|
|
|
attributes.usage, attributes.content_type, attributes.tags, attributes.flags,
|
|
|
|
|
__func__,
|
|
|
|
|
resultAttr->usage, resultAttr->content_type, resultAttr->tags, resultAttr->flags,
|
|
|
|
|
session, requestedDeviceId);
|
|
|
|
|
|
|
|
|
|
*stream = streamTypefromAttributesInt(&attributes);
|
|
|
|
|
*stream = streamTypefromAttributesInt(resultAttr);
|
|
|
|
|
|
|
|
|
|
strategy = getStrategyForAttr(&attributes);
|
|
|
|
|
strategy = getStrategyForAttr(resultAttr);
|
|
|
|
|
|
|
|
|
|
// First check for explicit routing (eg. setPreferredDevice)
|
|
|
|
|
if (requestedDeviceId != AUDIO_PORT_HANDLE_NONE) {
|
|
|
|
@ -836,30 +843,30 @@ status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr,
|
|
|
|
|
} else {
|
|
|
|
|
// If no explict route, is there a matching dynamic policy that applies?
|
|
|
|
|
sp<SwAudioOutputDescriptor> desc;
|
|
|
|
|
if (mPolicyMixes.getOutputForAttr(attributes, uid, desc) == NO_ERROR) {
|
|
|
|
|
if (mPolicyMixes.getOutputForAttr(*resultAttr, uid, desc) == NO_ERROR) {
|
|
|
|
|
ALOG_ASSERT(desc != 0, "Invalid desc returned by getOutputForAttr");
|
|
|
|
|
if (!audio_has_proportional_frames(config->format)) {
|
|
|
|
|
return BAD_VALUE;
|
|
|
|
|
}
|
|
|
|
|
*stream = streamTypefromAttributesInt(&attributes);
|
|
|
|
|
*stream = streamTypefromAttributesInt(resultAttr);
|
|
|
|
|
*output = desc->mIoHandle;
|
|
|
|
|
AudioMix *mix = desc->mPolicyMix;
|
|
|
|
|
sp<DeviceDescriptor> deviceDesc =
|
|
|
|
|
mAvailableOutputDevices.getDevice(mix->mDeviceType, mix->mDeviceAddress);
|
|
|
|
|
*selectedDeviceId = deviceDesc != 0 ? deviceDesc->getId() : AUDIO_PORT_HANDLE_NONE;
|
|
|
|
|
ALOGV("getOutputForAttr() returns output %d", *output);
|
|
|
|
|
goto exit;
|
|
|
|
|
ALOGV("%s returns output %d", __func__, *output);
|
|
|
|
|
return NO_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Virtual sources must always be dynamicaly or explicitly routed
|
|
|
|
|
if (attributes.usage == AUDIO_USAGE_VIRTUAL_SOURCE) {
|
|
|
|
|
ALOGW("getOutputForAttr() no policy mix found for usage AUDIO_USAGE_VIRTUAL_SOURCE");
|
|
|
|
|
if (resultAttr->usage == AUDIO_USAGE_VIRTUAL_SOURCE) {
|
|
|
|
|
ALOGW("%s no policy mix found for usage AUDIO_USAGE_VIRTUAL_SOURCE", __func__);
|
|
|
|
|
return BAD_VALUE;
|
|
|
|
|
}
|
|
|
|
|
device = getDeviceForStrategy(strategy, false /*fromCache*/);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((attributes.flags & AUDIO_FLAG_HW_AV_SYNC) != 0) {
|
|
|
|
|
if ((resultAttr->flags & AUDIO_FLAG_HW_AV_SYNC) != 0) {
|
|
|
|
|
*flags = (audio_output_flags_t)(*flags | AUDIO_OUTPUT_FLAG_HW_AV_SYNC);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -869,7 +876,7 @@ status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr,
|
|
|
|
|
// to getOutputForDevice.
|
|
|
|
|
// TODO: Remove check of AUDIO_STREAM_MUSIC once migration is completed on the app side.
|
|
|
|
|
if (device == AUDIO_DEVICE_OUT_TELEPHONY_TX &&
|
|
|
|
|
(*stream == AUDIO_STREAM_MUSIC || attributes.usage == AUDIO_USAGE_VOICE_COMMUNICATION) &&
|
|
|
|
|
(*stream == AUDIO_STREAM_MUSIC || resultAttr->usage == AUDIO_USAGE_VOICE_COMMUNICATION) &&
|
|
|
|
|
audio_is_linear_pcm(config->format) &&
|
|
|
|
|
isInCall()) {
|
|
|
|
|
if (requestedDeviceId != AUDIO_PORT_HANDLE_NONE) {
|
|
|
|
@ -880,9 +887,9 @@ status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ALOGV("getOutputForAttr() device 0x%x, sampling rate %d, format %#x, channel mask %#x, "
|
|
|
|
|
ALOGV("%s device 0x%x, sampling rate %d, format %#x, channel mask %#x, "
|
|
|
|
|
"flags %#x",
|
|
|
|
|
device, config->sample_rate, config->format, config->channel_mask, *flags);
|
|
|
|
|
__func__, device, config->sample_rate, config->format, config->channel_mask, *flags);
|
|
|
|
|
|
|
|
|
|
*output = AUDIO_IO_HANDLE_NONE;
|
|
|
|
|
if (msdDevice != AUDIO_DEVICE_NONE) {
|
|
|
|
@ -906,22 +913,48 @@ status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr,
|
|
|
|
|
*selectedDeviceId = outputDevices.size() > 0 ? outputDevices.itemAt(0)->getId()
|
|
|
|
|
: AUDIO_PORT_HANDLE_NONE;
|
|
|
|
|
|
|
|
|
|
exit:
|
|
|
|
|
ALOGV("%s returns output %d selectedDeviceId %d", __func__, *output, *selectedDeviceId);
|
|
|
|
|
|
|
|
|
|
return NO_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr,
|
|
|
|
|
audio_io_handle_t *output,
|
|
|
|
|
audio_session_t session,
|
|
|
|
|
audio_stream_type_t *stream,
|
|
|
|
|
uid_t uid,
|
|
|
|
|
const audio_config_t *config,
|
|
|
|
|
audio_output_flags_t *flags,
|
|
|
|
|
audio_port_handle_t *selectedDeviceId,
|
|
|
|
|
audio_port_handle_t *portId)
|
|
|
|
|
{
|
|
|
|
|
// The supplied portId must be AUDIO_PORT_HANDLE_NONE
|
|
|
|
|
if (*portId != AUDIO_PORT_HANDLE_NONE) {
|
|
|
|
|
return INVALID_OPERATION;
|
|
|
|
|
}
|
|
|
|
|
const audio_port_handle_t requestedDeviceId = *selectedDeviceId;
|
|
|
|
|
audio_attributes_t resultAttr;
|
|
|
|
|
status_t status = getOutputForAttrInt(&resultAttr, output, session, attr, stream, uid,
|
|
|
|
|
config, flags, selectedDeviceId);
|
|
|
|
|
if (status != NO_ERROR) {
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
audio_config_base_t clientConfig = {.sample_rate = config->sample_rate,
|
|
|
|
|
.format = config->format,
|
|
|
|
|
.channel_mask = config->channel_mask };
|
|
|
|
|
*portId = AudioPort::getNextUniqueId();
|
|
|
|
|
|
|
|
|
|
sp<TrackClientDescriptor> clientDesc =
|
|
|
|
|
new TrackClientDescriptor(*portId, uid, session, attributes, clientConfig,
|
|
|
|
|
new TrackClientDescriptor(*portId, uid, session, resultAttr, clientConfig,
|
|
|
|
|
requestedDeviceId, *stream,
|
|
|
|
|
getStrategyForAttr(&attributes),
|
|
|
|
|
getStrategyForAttr(&resultAttr),
|
|
|
|
|
*flags);
|
|
|
|
|
sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(*output);
|
|
|
|
|
outputDesc->addClient(clientDesc);
|
|
|
|
|
|
|
|
|
|
ALOGV(" getOutputForAttr() returns output %d selectedDeviceId %d for port ID %d",
|
|
|
|
|
*output, *selectedDeviceId, *portId);
|
|
|
|
|
ALOGV("%s returns output %d selectedDeviceId %d for port ID %d",
|
|
|
|
|
__func__, *output, requestedDeviceId, *portId);
|
|
|
|
|
|
|
|
|
|
return NO_ERROR;
|
|
|
|
|
}
|
|
|
|
@ -3400,11 +3433,20 @@ status_t AudioPolicyManager::connectAudioSource(const sp<SourceClientDescriptor>
|
|
|
|
|
srcDeviceDesc->getAudioPort()->mModule->getHalVersionMajor() >= 3 &&
|
|
|
|
|
srcDeviceDesc->getAudioPort()->mGains.size() > 0) {
|
|
|
|
|
ALOGV("%s AUDIO_DEVICE_API_VERSION_3_0", __FUNCTION__);
|
|
|
|
|
// create patch between src device and output device
|
|
|
|
|
// create Hwoutput and add to mHwOutputs
|
|
|
|
|
// 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 {
|
|
|
|
|
SortedVector<audio_io_handle_t> outputs = getOutputsForDevice(sinkDevice, mOutputs);
|
|
|
|
|
audio_io_handle_t output = selectOutput(outputs);
|
|
|
|
|
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;
|
|
|
|
|
getOutputForAttrInt(&resultAttr, &output, AUDIO_SESSION_NONE,
|
|
|
|
|
&attributes, &stream, sourceDesc->uid(), &config, &flags, &selectedDeviceId);
|
|
|
|
|
if (output == AUDIO_IO_HANDLE_NONE) {
|
|
|
|
|
ALOGV("%s no output for device %08x", __FUNCTION__, sinkDevice);
|
|
|
|
|
return INVALID_OPERATION;
|
|
|
|
@ -3437,6 +3479,13 @@ status_t AudioPolicyManager::connectAudioSource(const sp<SourceClientDescriptor>
|
|
|
|
|
__FUNCTION__, status);
|
|
|
|
|
return INVALID_OPERATION;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (outputDesc->getClient(sourceDesc->portId()) != nullptr) {
|
|
|
|
|
ALOGW("%s source portId has already been attached to outputDesc", __func__);
|
|
|
|
|
return INVALID_OPERATION;
|
|
|
|
|
}
|
|
|
|
|
outputDesc->addClient(sourceDesc);
|
|
|
|
|
|
|
|
|
|
uint32_t delayMs = 0;
|
|
|
|
|
status = startSource(outputDesc, sourceDesc, &delayMs);
|
|
|
|
|
|
|
|
|
|