summaryrefslogtreecommitdiffstats
path: root/services/audiopolicy/AudioPolicyManager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'services/audiopolicy/AudioPolicyManager.cpp')
-rw-r--r--services/audiopolicy/AudioPolicyManager.cpp1081
1 files changed, 905 insertions, 176 deletions
diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp
index 536987a..3cd5fb2 100644
--- a/services/audiopolicy/AudioPolicyManager.cpp
+++ b/services/audiopolicy/AudioPolicyManager.cpp
@@ -26,7 +26,7 @@
// A device mask for all audio input devices that are considered "virtual" when evaluating
// active inputs in getActiveInput()
-#define APM_AUDIO_IN_DEVICE_VIRTUAL_ALL AUDIO_DEVICE_IN_REMOTE_SUBMIX
+#define APM_AUDIO_IN_DEVICE_VIRTUAL_ALL (AUDIO_DEVICE_IN_REMOTE_SUBMIX|AUDIO_DEVICE_IN_FM_TUNER)
// A device mask for all audio output devices that are considered "remote" when evaluating
// active output devices in isStreamActiveRemotely()
#define APM_AUDIO_OUT_DEVICE_REMOTE_ALL AUDIO_DEVICE_OUT_REMOTE_SUBMIX
@@ -43,6 +43,7 @@
#include <hardware/audio.h>
#include <hardware/audio_effect.h>
#include <media/AudioParameter.h>
+#include <media/AudioPolicyHelper.h>
#include <soundtrigger/SoundTrigger.h>
#include "AudioPolicyManager.h"
#include "audio_policy_conf.h"
@@ -210,12 +211,15 @@ bool AudioPolicyManager::stringToBool(const char *value)
// AudioPolicyInterface implementation
// ----------------------------------------------------------------------------
-
status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device,
audio_policy_dev_state_t state,
const char *device_address)
{
String8 address = (device_address == NULL) ? String8("") : String8(device_address);
+ // handle legacy remote submix case where the address was not always specified
+ if (deviceDistinguishesOnAddress(device) && (address.length() == 0)) {
+ address = String8("0");
+ }
ALOGV("setDeviceConnectionState() device: %x, state %d, address %s",
device, state, address.string());
@@ -419,6 +423,10 @@ audio_policy_dev_state_t AudioPolicyManager::getDeviceConnectionState(audio_devi
audio_policy_dev_state_t state = AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE;
sp<DeviceDescriptor> devDesc = new DeviceDescriptor(String8(""), device);
devDesc->mAddress = (device_address == NULL) ? String8("") : String8(device_address);
+ // handle legacy remote submix case where the address was not always specified
+ if (deviceDistinguishesOnAddress(device) && (devDesc->mAddress.length() == 0)) {
+ devDesc->mAddress = String8("0");
+ }
ssize_t index;
DeviceVector *deviceVector;
@@ -576,6 +584,9 @@ void AudioPolicyManager::setPhoneState(audio_mode_t state)
if (isInCall()) {
ALOGV("setPhoneState() in call state management: new state is %d", state);
for (int stream = 0; stream < AUDIO_STREAM_CNT; stream++) {
+ if (stream == AUDIO_STREAM_PATCH) {
+ continue;
+ }
handleIncallSonification((audio_stream_type_t)stream, false, true);
}
}
@@ -673,6 +684,9 @@ void AudioPolicyManager::setPhoneState(audio_mode_t state)
if (isStateInCall(state)) {
ALOGV("setPhoneState() in call state management: new state is %d", state);
for (int stream = 0; stream < AUDIO_STREAM_CNT; stream++) {
+ if (stream == AUDIO_STREAM_PATCH) {
+ continue;
+ }
handleIncallSonification((audio_stream_type_t)stream, true, true);
}
}
@@ -707,7 +721,7 @@ void AudioPolicyManager::setForceUse(audio_policy_force_use_t usage,
config != AUDIO_POLICY_FORCE_WIRED_ACCESSORY &&
config != AUDIO_POLICY_FORCE_ANALOG_DOCK &&
config != AUDIO_POLICY_FORCE_DIGITAL_DOCK && config != AUDIO_POLICY_FORCE_NONE &&
- config != AUDIO_POLICY_FORCE_NO_BT_A2DP) {
+ config != AUDIO_POLICY_FORCE_NO_BT_A2DP && config != AUDIO_POLICY_FORCE_SPEAKER ) {
ALOGW("setForceUse() invalid config %d for FOR_MEDIA", config);
return;
}
@@ -803,7 +817,7 @@ sp<AudioPolicyManager::IOProfile> AudioPolicyManager::getProfileForDirectOutput(
}
for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) {
sp<IOProfile> profile = mHwModules[i]->mOutputProfiles[j];
- bool found = profile->isCompatibleProfile(device, samplingRate,
+ bool found = profile->isCompatibleProfile(device, String8(""), samplingRate,
NULL /*updatedSamplingRate*/, format, channelMask,
flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD ?
AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD : AUDIO_OUTPUT_FLAG_DIRECT);
@@ -822,48 +836,113 @@ audio_io_handle_t AudioPolicyManager::getOutput(audio_stream_type_t stream,
audio_output_flags_t flags,
const audio_offload_info_t *offloadInfo)
{
-
routing_strategy strategy = getStrategy(stream);
audio_devices_t device = getDeviceForStrategy(strategy, false /*fromCache*/);
ALOGV("getOutput() device %d, stream %d, samplingRate %d, format %x, channelMask %x, flags %x",
device, stream, samplingRate, format, channelMask, flags);
- return getOutputForDevice(device, stream, samplingRate,format, channelMask, flags,
- offloadInfo);
-}
+ return getOutputForDevice(device, AUDIO_SESSION_ALLOCATE,
+ stream, samplingRate,format, channelMask,
+ flags, offloadInfo);
+}
+
+status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr,
+ audio_io_handle_t *output,
+ audio_session_t session,
+ audio_stream_type_t *stream,
+ uint32_t samplingRate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
+ audio_output_flags_t flags,
+ const audio_offload_info_t *offloadInfo)
+{
+ audio_attributes_t attributes;
+ 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);
+ }
-audio_io_handle_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr,
- uint32_t samplingRate,
- audio_format_t format,
- audio_channel_mask_t channelMask,
- audio_output_flags_t flags,
- const audio_offload_info_t *offloadInfo)
-{
- if (attr == NULL) {
- ALOGE("getOutputForAttr() called with NULL audio attributes");
- return 0;
+ for (size_t i = 0; i < mPolicyMixes.size(); i++) {
+ sp<AudioOutputDescriptor> desc;
+ if (mPolicyMixes[i]->mMix.mMixType == MIX_TYPE_PLAYERS) {
+ for (size_t j = 0; j < mPolicyMixes[i]->mMix.mCriteria.size(); j++) {
+ if ((RULE_MATCH_ATTRIBUTE_USAGE == mPolicyMixes[i]->mMix.mCriteria[j].mRule &&
+ mPolicyMixes[i]->mMix.mCriteria[j].mAttr.mUsage == attributes.usage) ||
+ (RULE_EXCLUDE_ATTRIBUTE_USAGE == mPolicyMixes[i]->mMix.mCriteria[j].mRule &&
+ mPolicyMixes[i]->mMix.mCriteria[j].mAttr.mUsage != attributes.usage)) {
+ desc = mPolicyMixes[i]->mOutput;
+ break;
+ }
+ if (strncmp(attributes.tags, "addr=", strlen("addr=")) == 0 &&
+ strncmp(attributes.tags + strlen("addr="),
+ mPolicyMixes[i]->mMix.mRegistrationId.string(),
+ AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - strlen("addr=") - 1) == 0) {
+ desc = mPolicyMixes[i]->mOutput;
+ break;
+ }
+ }
+ } else if (mPolicyMixes[i]->mMix.mMixType == MIX_TYPE_RECORDERS) {
+ if (attributes.usage == AUDIO_USAGE_VIRTUAL_SOURCE &&
+ strncmp(attributes.tags, "addr=", strlen("addr=")) == 0 &&
+ strncmp(attributes.tags + strlen("addr="),
+ mPolicyMixes[i]->mMix.mRegistrationId.string(),
+ AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - strlen("addr=") - 1) == 0) {
+ desc = mPolicyMixes[i]->mOutput;
+ }
+ }
+ if (desc != 0) {
+ if (!audio_is_linear_pcm(format)) {
+ return BAD_VALUE;
+ }
+ desc->mPolicyMix = &mPolicyMixes[i]->mMix;
+ *stream = streamTypefromAttributesInt(&attributes);
+ *output = desc->mIoHandle;
+ ALOGV("getOutputForAttr() returns output %d", *output);
+ return NO_ERROR;
+ }
+ }
+ if (attributes.usage == AUDIO_USAGE_VIRTUAL_SOURCE) {
+ ALOGW("getOutputForAttr() no policy mix found for usage AUDIO_USAGE_VIRTUAL_SOURCE");
+ return BAD_VALUE;
}
+
ALOGV("getOutputForAttr() usage=%d, content=%d, tag=%s flags=%08x",
- attr->usage, attr->content_type, attr->tags, attr->flags);
+ attributes.usage, attributes.content_type, attributes.tags, attributes.flags);
- // TODO this is where filtering for custom policies (rerouting, dynamic sources) will go
- routing_strategy strategy = (routing_strategy) getStrategyForAttr(attr);
+ routing_strategy strategy = (routing_strategy) getStrategyForAttr(&attributes);
audio_devices_t device = getDeviceForStrategy(strategy, false /*fromCache*/);
- if ((attr->flags & AUDIO_FLAG_HW_AV_SYNC) != 0) {
+ if ((attributes.flags & AUDIO_FLAG_HW_AV_SYNC) != 0) {
flags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_HW_AV_SYNC);
}
- ALOGV("getOutputForAttr() device %d, samplingRate %d, format %x, channelMask %x, flags %x",
+ ALOGV("getOutputForAttr() device 0x%x, samplingRate %d, format %x, channelMask %x, flags %x",
device, samplingRate, format, channelMask, flags);
- audio_stream_type_t stream = streamTypefromAttributesInt(attr);
- return getOutputForDevice(device, stream, samplingRate, format, channelMask, flags,
- offloadInfo);
+ *stream = streamTypefromAttributesInt(&attributes);
+ *output = getOutputForDevice(device, session, *stream,
+ samplingRate, format, channelMask,
+ flags, offloadInfo);
+ if (*output == AUDIO_IO_HANDLE_NONE) {
+ return INVALID_OPERATION;
+ }
+ return NO_ERROR;
}
audio_io_handle_t AudioPolicyManager::getOutputForDevice(
audio_devices_t device,
+ audio_session_t session __unused,
audio_stream_type_t stream,
uint32_t samplingRate,
audio_format_t format,
@@ -926,6 +1005,10 @@ audio_io_handle_t AudioPolicyManager::getOutputForDevice(
if ((flags & AUDIO_OUTPUT_FLAG_HW_AV_SYNC) != 0) {
flags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_DIRECT);
}
+ // only allow deep buffering for music stream type
+ if (stream != AUDIO_STREAM_MUSIC) {
+ flags = (audio_output_flags_t)(flags &~AUDIO_OUTPUT_FLAG_DEEP_BUFFER);
+ }
sp<IOProfile> profile;
@@ -1110,7 +1193,7 @@ audio_io_handle_t AudioPolicyManager::selectOutput(const SortedVector<audio_io_h
status_t AudioPolicyManager::startOutput(audio_io_handle_t output,
audio_stream_type_t stream,
- int session)
+ audio_session_t session)
{
ALOGV("startOutput() output %d, stream %d, session %d", output, stream, session);
ssize_t index = mOutputs.indexOfKey(output);
@@ -1119,6 +1202,20 @@ status_t AudioPolicyManager::startOutput(audio_io_handle_t output,
return BAD_VALUE;
}
+ // cannot start playback of STREAM_TTS if any other output is being used
+ uint32_t beaconMuteLatency = 0;
+ if (stream == AUDIO_STREAM_TTS) {
+ ALOGV("\t found BEACON stream");
+ if (isAnyOutputActive(AUDIO_STREAM_TTS /*streamToIgnore*/)) {
+ return INVALID_OPERATION;
+ } else {
+ beaconMuteLatency = handleEventForBeacon(STARTING_BEACON);
+ }
+ } else {
+ // some playback other than beacon starts
+ beaconMuteLatency = handleEventForBeacon(STARTING_OUTPUT);
+ }
+
sp<AudioOutputDescriptor> outputDesc = mOutputs.valueAt(index);
// increment usage count for this stream on the requested output:
@@ -1127,11 +1224,18 @@ status_t AudioPolicyManager::startOutput(audio_io_handle_t output,
outputDesc->changeRefCount(stream, 1);
if (outputDesc->mRefCount[stream] == 1) {
- audio_devices_t newDevice = getNewOutputDevice(output, false /*fromCache*/);
+ // starting an output being rerouted?
+ audio_devices_t newDevice;
+ if (outputDesc->mPolicyMix != NULL) {
+ newDevice = AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
+ } else {
+ newDevice = getNewOutputDevice(output, false /*fromCache*/);
+ }
routing_strategy strategy = getStrategy(stream);
bool shouldWait = (strategy == STRATEGY_SONIFICATION) ||
- (strategy == STRATEGY_SONIFICATION_RESPECTFUL);
- uint32_t waitMs = 0;
+ (strategy == STRATEGY_SONIFICATION_RESPECTFUL) ||
+ (beaconMuteLatency > 0);
+ uint32_t waitMs = beaconMuteLatency;
bool force = false;
for (size_t i = 0; i < mOutputs.size(); i++) {
sp<AudioOutputDescriptor> desc = mOutputs.valueAt(i);
@@ -1145,7 +1249,8 @@ status_t AudioPolicyManager::startOutput(audio_io_handle_t output,
force = true;
}
// wait for audio on other active outputs to be presented when starting
- // a notification so that audio focus effect can propagate.
+ // a notification so that audio focus effect can propagate, or that a mute/unmute
+ // event occurred for beacon
uint32_t latency = desc->latency();
if (shouldWait && desc->isActive(latency * 2) && (waitMs < latency)) {
waitMs = latency;
@@ -1168,6 +1273,16 @@ status_t AudioPolicyManager::startOutput(audio_io_handle_t output,
// update the outputs if starting an output with a stream that can affect notification
// routing
handleNotificationRoutingForStream(stream);
+
+ // Automatically enable the remote submix input when output is started on a re routing mix
+ // of type MIX_TYPE_RECORDERS
+ if (audio_is_remote_submix_device(newDevice) && outputDesc->mPolicyMix != NULL &&
+ outputDesc->mPolicyMix->mMixType == MIX_TYPE_RECORDERS) {
+ setDeviceConnectionState(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
+ AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+ outputDesc->mPolicyMix->mRegistrationId);
+ }
+
if (waitMs > muteWaitMs) {
usleep((waitMs - muteWaitMs) * 2 * 1000);
}
@@ -1178,7 +1293,7 @@ status_t AudioPolicyManager::startOutput(audio_io_handle_t output,
status_t AudioPolicyManager::stopOutput(audio_io_handle_t output,
audio_stream_type_t stream,
- int session)
+ audio_session_t session)
{
ALOGV("stopOutput() output %d, stream %d, session %d", output, stream, session);
ssize_t index = mOutputs.indexOfKey(output);
@@ -1189,6 +1304,9 @@ status_t AudioPolicyManager::stopOutput(audio_io_handle_t output,
sp<AudioOutputDescriptor> outputDesc = mOutputs.valueAt(index);
+ // always handle stream stop, check which stream type is stopping
+ handleEventForBeacon(stream == AUDIO_STREAM_TTS ? STOPPING_BEACON : STOPPING_OUTPUT);
+
// handle special case for sonification while in call
if (isInCall()) {
handleIncallSonification(stream, false, false);
@@ -1199,6 +1317,16 @@ status_t AudioPolicyManager::stopOutput(audio_io_handle_t output,
outputDesc->changeRefCount(stream, -1);
// store time at which the stream was stopped - see isStreamActive()
if (outputDesc->mRefCount[stream] == 0) {
+ // Automatically disable the remote submix input when output is stopped on a
+ // re routing mix of type MIX_TYPE_RECORDERS
+ if (audio_is_remote_submix_device(outputDesc->mDevice) &&
+ outputDesc->mPolicyMix != NULL &&
+ outputDesc->mPolicyMix->mMixType == MIX_TYPE_RECORDERS) {
+ setDeviceConnectionState(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
+ AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+ outputDesc->mPolicyMix->mRegistrationId);
+ }
+
outputDesc->mStopTime[stream] = systemTime();
audio_devices_t newDevice = getNewOutputDevice(output, false /*fromCache*/);
// delay the device switch by twice the latency because stopOutput() is executed when
@@ -1233,7 +1361,9 @@ status_t AudioPolicyManager::stopOutput(audio_io_handle_t output,
}
}
-void AudioPolicyManager::releaseOutput(audio_io_handle_t output)
+void AudioPolicyManager::releaseOutput(audio_io_handle_t output,
+ audio_stream_type_t stream __unused,
+ audio_session_t session __unused)
{
ALOGV("releaseOutput() %d", output);
ssize_t index = mOutputs.indexOfKey(output);
@@ -1276,79 +1406,99 @@ void AudioPolicyManager::releaseOutput(audio_io_handle_t output)
}
-audio_io_handle_t AudioPolicyManager::getInput(audio_source_t inputSource,
- uint32_t samplingRate,
- audio_format_t format,
- audio_channel_mask_t channelMask,
- audio_session_t session,
- audio_input_flags_t flags)
+status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
+ audio_io_handle_t *input,
+ audio_session_t session,
+ uint32_t samplingRate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
+ audio_input_flags_t flags)
{
- ALOGV("getInput() inputSource %d, samplingRate %d, format %d, channelMask %x, session %d, "
- "flags %#x",
- inputSource, samplingRate, format, channelMask, session, flags);
-
- audio_devices_t device = getDeviceForInputSource(inputSource);
-
- if (device == AUDIO_DEVICE_NONE) {
- ALOGW("getInput() could not find device for inputSource %d", inputSource);
- return AUDIO_IO_HANDLE_NONE;
- }
-
- // adapt channel selection to input source
- switch (inputSource) {
- case AUDIO_SOURCE_VOICE_UPLINK:
- channelMask = AUDIO_CHANNEL_IN_VOICE_UPLINK;
- break;
- case AUDIO_SOURCE_VOICE_DOWNLINK:
- channelMask = AUDIO_CHANNEL_IN_VOICE_DNLINK;
- break;
- case AUDIO_SOURCE_VOICE_CALL:
- channelMask = AUDIO_CHANNEL_IN_VOICE_UPLINK | AUDIO_CHANNEL_IN_VOICE_DNLINK;
- break;
- default:
- break;
- }
+ ALOGV("getInputForAttr() source %d, samplingRate %d, format %d, channelMask %x,"
+ "session %d, flags %#x",
+ attr->source, samplingRate, format, channelMask, session, flags);
- audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
+ *input = AUDIO_IO_HANDLE_NONE;
+ audio_devices_t device;
+ // handle legacy remote submix case where the address was not always specified
+ String8 address = String8("");
bool isSoundTrigger = false;
- audio_source_t halInputSource = inputSource;
- if (inputSource == AUDIO_SOURCE_HOTWORD) {
- ssize_t index = mSoundTriggerSessions.indexOfKey(session);
- if (index >= 0) {
- input = mSoundTriggerSessions.valueFor(session);
- isSoundTrigger = true;
- flags = (audio_input_flags_t)(flags | AUDIO_INPUT_FLAG_HW_HOTWORD);
- ALOGV("SoundTrigger capture on session %d input %d", session, input);
- } else {
- halInputSource = AUDIO_SOURCE_VOICE_RECOGNITION;
+ audio_source_t halInputSource = attr->source;
+ AudioMix *policyMix = NULL;
+
+ if (attr->source == AUDIO_SOURCE_REMOTE_SUBMIX &&
+ strncmp(attr->tags, "addr=", strlen("addr=")) == 0) {
+ device = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
+ address = String8(attr->tags + strlen("addr="));
+ ssize_t index = mPolicyMixes.indexOfKey(address);
+ if (index < 0) {
+ ALOGW("getInputForAttr() no policy for address %s", address.string());
+ return BAD_VALUE;
+ }
+ if (mPolicyMixes[index]->mMix.mMixType != MIX_TYPE_PLAYERS) {
+ ALOGW("getInputForAttr() bad policy mix type for address %s", address.string());
+ return BAD_VALUE;
+ }
+ policyMix = &mPolicyMixes[index]->mMix;
+ } else {
+ device = getDeviceForInputSource(attr->source, &policyMix);
+ if (device == AUDIO_DEVICE_NONE) {
+ ALOGW("getInputForAttr() could not find device for source %d", attr->source);
+ return BAD_VALUE;
+ }
+ if (policyMix != NULL) {
+ address = policyMix->mRegistrationId;
+ } else if (audio_is_remote_submix_device(device)) {
+ address = String8("0");
+ }
+ // adapt channel selection to input source
+ switch (attr->source) {
+ case AUDIO_SOURCE_VOICE_UPLINK:
+ channelMask = AUDIO_CHANNEL_IN_VOICE_UPLINK;
+ break;
+ case AUDIO_SOURCE_VOICE_DOWNLINK:
+ channelMask = AUDIO_CHANNEL_IN_VOICE_DNLINK;
+ break;
+ case AUDIO_SOURCE_VOICE_CALL:
+ channelMask = AUDIO_CHANNEL_IN_VOICE_UPLINK | AUDIO_CHANNEL_IN_VOICE_DNLINK;
+ break;
+ default:
+ break;
+ }
+ if (attr->source == AUDIO_SOURCE_HOTWORD) {
+ ssize_t index = mSoundTriggerSessions.indexOfKey(session);
+ if (index >= 0) {
+ *input = mSoundTriggerSessions.valueFor(session);
+ isSoundTrigger = true;
+ flags = (audio_input_flags_t)(flags | AUDIO_INPUT_FLAG_HW_HOTWORD);
+ ALOGV("SoundTrigger capture on session %d input %d", session, *input);
+ } else {
+ halInputSource = AUDIO_SOURCE_VOICE_RECOGNITION;
+ }
}
}
- sp<IOProfile> profile = getInputProfile(device,
- samplingRate,
- format,
- channelMask,
- flags);
+ sp<IOProfile> profile = getInputProfile(device, address,
+ samplingRate, format, channelMask,
+ flags);
if (profile == 0) {
//retry without flags
audio_input_flags_t log_flags = flags;
flags = AUDIO_INPUT_FLAG_NONE;
- profile = getInputProfile(device,
- samplingRate,
- format,
- channelMask,
- flags);
+ profile = getInputProfile(device, address,
+ samplingRate, format, channelMask,
+ flags);
if (profile == 0) {
- ALOGW("getInput() could not find profile for device 0x%X, samplingRate %u, format %#x, "
- "channelMask 0x%X, flags %#x",
+ ALOGW("getInputForAttr() could not find profile for device 0x%X, samplingRate %u,"
+ "format %#x, channelMask 0x%X, flags %#x",
device, samplingRate, format, channelMask, log_flags);
- return AUDIO_IO_HANDLE_NONE;
+ return BAD_VALUE;
}
}
if (profile->mModule->mHandle == 0) {
- ALOGE("getInput(): HW module %s not opened", profile->mModule->mName);
- return AUDIO_IO_HANDLE_NONE;
+ ALOGE("getInputForAttr(): HW module %s not opened", profile->mModule->mName);
+ return NO_INIT;
}
audio_config_t config = AUDIO_CONFIG_INITIALIZER;
@@ -1357,28 +1507,28 @@ audio_io_handle_t AudioPolicyManager::getInput(audio_source_t inputSource,
config.format = format;
status_t status = mpClientInterface->openInput(profile->mModule->mHandle,
- &input,
+ input,
&config,
&device,
- String8(""),
+ address,
halInputSource,
flags);
// only accept input with the exact requested set of parameters
- if (status != NO_ERROR ||
+ if (status != NO_ERROR || *input == AUDIO_IO_HANDLE_NONE ||
(samplingRate != config.sample_rate) ||
(format != config.format) ||
(channelMask != config.channel_mask)) {
- ALOGW("getInput() failed opening input: samplingRate %d, format %d, channelMask %x",
+ ALOGW("getInputForAttr() failed opening input: samplingRate %d, format %d, channelMask %x",
samplingRate, format, channelMask);
- if (input != AUDIO_IO_HANDLE_NONE) {
- mpClientInterface->closeInput(input);
+ if (*input != AUDIO_IO_HANDLE_NONE) {
+ mpClientInterface->closeInput(*input);
}
- return AUDIO_IO_HANDLE_NONE;
+ return BAD_VALUE;
}
sp<AudioInputDescriptor> inputDesc = new AudioInputDescriptor(profile);
- inputDesc->mInputSource = inputSource;
+ inputDesc->mInputSource = attr->source;
inputDesc->mRefCount = 0;
inputDesc->mOpenRefCount = 1;
inputDesc->mSamplingRate = samplingRate;
@@ -1387,10 +1537,11 @@ audio_io_handle_t AudioPolicyManager::getInput(audio_source_t inputSource,
inputDesc->mDevice = device;
inputDesc->mSessions.add(session);
inputDesc->mIsSoundTrigger = isSoundTrigger;
+ inputDesc->mPolicyMix = policyMix;
- addInput(input, inputDesc);
+ addInput(*input, inputDesc);
mpClientInterface->onAudioPortListUpdate();
- return input;
+ return NO_ERROR;
}
status_t AudioPolicyManager::startInput(audio_io_handle_t input,
@@ -1437,11 +1588,21 @@ status_t AudioPolicyManager::startInput(audio_io_handle_t input,
}
setInputDevice(input, getNewInputDevice(input), true /* force */);
- // Automatically enable the remote submix output when input is started.
+ // automatically enable the remote submix output when input is started if not
+ // used by a policy mix of type MIX_TYPE_RECORDERS
// For remote submix (a virtual device), we open only one input per capture request.
if (audio_is_remote_submix_device(inputDesc->mDevice)) {
- setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
- AUDIO_POLICY_DEVICE_STATE_AVAILABLE, AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS);
+ String8 address = String8("");
+ if (inputDesc->mPolicyMix == NULL) {
+ address = String8("0");
+ } else if (inputDesc->mPolicyMix->mMixType == MIX_TYPE_PLAYERS) {
+ address = inputDesc->mPolicyMix->mRegistrationId;
+ }
+ if (address != "") {
+ setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+ AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+ address);
+ }
}
}
@@ -1476,10 +1637,20 @@ status_t AudioPolicyManager::stopInput(audio_io_handle_t input,
inputDesc->mRefCount--;
if (inputDesc->mRefCount == 0) {
- // automatically disable the remote submix output when input is stopped
+ // automatically disable the remote submix output when input is stopped if not
+ // used by a policy mix of type MIX_TYPE_RECORDERS
if (audio_is_remote_submix_device(inputDesc->mDevice)) {
- setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
- AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS);
+ String8 address = String8("");
+ if (inputDesc->mPolicyMix == NULL) {
+ address = String8("0");
+ } else if (inputDesc->mPolicyMix->mMixType == MIX_TYPE_PLAYERS) {
+ address = inputDesc->mPolicyMix->mRegistrationId;
+ }
+ if (address != "") {
+ setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+ AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+ address);
+ }
}
resetInputDevice(input);
@@ -1557,6 +1728,11 @@ void AudioPolicyManager::initStreamVolume(audio_stream_type_t stream,
}
mStreams[stream].mIndexMin = indexMin;
mStreams[stream].mIndexMax = indexMax;
+ //FIXME: AUDIO_STREAM_ACCESSIBILITY volume follows AUDIO_STREAM_MUSIC for now
+ if (stream == AUDIO_STREAM_MUSIC) {
+ mStreams[AUDIO_STREAM_ACCESSIBILITY].mIndexMin = indexMin;
+ mStreams[AUDIO_STREAM_ACCESSIBILITY].mIndexMax = indexMax;
+ }
}
status_t AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream,
@@ -1584,17 +1760,35 @@ status_t AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream,
}
mStreams[stream].mIndexCur.add(device, index);
- // compute and apply stream volume on all outputs according to connected device
+ // update volume on all outputs whose current device is also selected by the same
+ // strategy as the device specified by the caller
+ audio_devices_t strategyDevice = getDeviceForStrategy(getStrategy(stream), true /*fromCache*/);
+
+
+ //FIXME: AUDIO_STREAM_ACCESSIBILITY volume follows AUDIO_STREAM_MUSIC for now
+ audio_devices_t accessibilityDevice = AUDIO_DEVICE_NONE;
+ if (stream == AUDIO_STREAM_MUSIC) {
+ mStreams[AUDIO_STREAM_ACCESSIBILITY].mIndexCur.add(device, index);
+ accessibilityDevice = getDeviceForStrategy(STRATEGY_ACCESSIBILITY, true /*fromCache*/);
+ }
+ if ((device != AUDIO_DEVICE_OUT_DEFAULT) &&
+ (device & (strategyDevice | accessibilityDevice)) == 0) {
+ return NO_ERROR;
+ }
status_t status = NO_ERROR;
for (size_t i = 0; i < mOutputs.size(); i++) {
audio_devices_t curDevice =
getDeviceForVolume(mOutputs.valueAt(i)->device());
- if ((device == AUDIO_DEVICE_OUT_DEFAULT) || (device == curDevice)) {
+ if ((device == AUDIO_DEVICE_OUT_DEFAULT) || ((curDevice & strategyDevice) != 0)) {
status_t volStatus = checkAndSetVolume(stream, index, mOutputs.keyAt(i), curDevice);
if (volStatus != NO_ERROR) {
status = volStatus;
}
}
+ if ((device == AUDIO_DEVICE_OUT_DEFAULT) || ((curDevice & accessibilityDevice) != 0)) {
+ status_t volStatus = checkAndSetVolume(AUDIO_STREAM_ACCESSIBILITY,
+ index, mOutputs.keyAt(i), curDevice);
+ }
}
return status;
}
@@ -1814,7 +2008,11 @@ bool AudioPolicyManager::isStreamActiveRemotely(audio_stream_type_t stream,
const sp<AudioOutputDescriptor> outputDesc = mOutputs.valueAt(i);
if (((outputDesc->device() & APM_AUDIO_OUT_DEVICE_REMOTE_ALL) != 0) &&
outputDesc->isStreamActive(stream, inPastMs, sysTime)) {
- return true;
+ // do not consider re routing (when the output is going to a dynamic policy)
+ // as "remote playback"
+ if (outputDesc->mPolicyMix == NULL) {
+ return true;
+ }
}
}
return false;
@@ -1834,6 +2032,127 @@ bool AudioPolicyManager::isSourceActive(audio_source_t source) const
return false;
}
+// Register a list of custom mixes with their attributes and format.
+// When a mix is registered, corresponding input and output profiles are
+// added to the remote submix hw module. The profile contains only the
+// parameters (sampling rate, format...) specified by the mix.
+// The corresponding input remote submix device is also connected.
+//
+// When a remote submix device is connected, the address is checked to select the
+// appropriate profile and the corresponding input or output stream is opened.
+//
+// When capture starts, getInputForAttr() will:
+// - 1 look for a mix matching the address passed in attribtutes tags if any
+// - 2 if none found, getDeviceForInputSource() will:
+// - 2.1 look for a mix matching the attributes source
+// - 2.2 if none found, default to device selection by policy rules
+// At this time, the corresponding output remote submix device is also connected
+// and active playback use cases can be transferred to this mix if needed when reconnecting
+// after AudioTracks are invalidated
+//
+// When playback starts, getOutputForAttr() will:
+// - 1 look for a mix matching the address passed in attribtutes tags if any
+// - 2 if none found, look for a mix matching the attributes usage
+// - 3 if none found, default to device and output selection by policy rules.
+
+status_t AudioPolicyManager::registerPolicyMixes(Vector<AudioMix> mixes)
+{
+ sp<HwModule> module;
+ for (size_t i = 0; i < mHwModules.size(); i++) {
+ if (strcmp(AUDIO_HARDWARE_MODULE_ID_REMOTE_SUBMIX, mHwModules[i]->mName) == 0 &&
+ mHwModules[i]->mHandle != 0) {
+ module = mHwModules[i];
+ break;
+ }
+ }
+
+ if (module == 0) {
+ return INVALID_OPERATION;
+ }
+
+ ALOGV("registerPolicyMixes() num mixes %d", mixes.size());
+
+ for (size_t i = 0; i < mixes.size(); i++) {
+ String8 address = mixes[i].mRegistrationId;
+ ssize_t index = mPolicyMixes.indexOfKey(address);
+ if (index >= 0) {
+ ALOGE("registerPolicyMixes(): mix for address %s already registered", address.string());
+ continue;
+ }
+ audio_config_t outputConfig = mixes[i].mFormat;
+ audio_config_t inputConfig = mixes[i].mFormat;
+ // NOTE: audio flinger mixer does not support mono output: configure remote submix HAL in
+ // stereo and let audio flinger do the channel conversion if needed.
+ outputConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+ inputConfig.channel_mask = AUDIO_CHANNEL_IN_STEREO;
+ module->addOutputProfile(address, &outputConfig,
+ AUDIO_DEVICE_OUT_REMOTE_SUBMIX, address);
+ module->addInputProfile(address, &inputConfig,
+ AUDIO_DEVICE_IN_REMOTE_SUBMIX, address);
+ sp<AudioPolicyMix> policyMix = new AudioPolicyMix();
+ policyMix->mMix = mixes[i];
+ mPolicyMixes.add(address, policyMix);
+ if (mixes[i].mMixType == MIX_TYPE_PLAYERS) {
+ setDeviceConnectionState(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
+ AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+ address.string());
+ } else {
+ setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+ AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+ address.string());
+ }
+ }
+ return NO_ERROR;
+}
+
+status_t AudioPolicyManager::unregisterPolicyMixes(Vector<AudioMix> mixes)
+{
+ sp<HwModule> module;
+ for (size_t i = 0; i < mHwModules.size(); i++) {
+ if (strcmp(AUDIO_HARDWARE_MODULE_ID_REMOTE_SUBMIX, mHwModules[i]->mName) == 0 &&
+ mHwModules[i]->mHandle != 0) {
+ module = mHwModules[i];
+ break;
+ }
+ }
+
+ if (module == 0) {
+ return INVALID_OPERATION;
+ }
+
+ ALOGV("unregisterPolicyMixes() num mixes %d", mixes.size());
+
+ for (size_t i = 0; i < mixes.size(); i++) {
+ String8 address = mixes[i].mRegistrationId;
+ ssize_t index = mPolicyMixes.indexOfKey(address);
+ if (index < 0) {
+ ALOGE("unregisterPolicyMixes(): mix for address %s not registered", address.string());
+ continue;
+ }
+
+ mPolicyMixes.removeItemsAt(index);
+
+ if (getDeviceConnectionState(AUDIO_DEVICE_IN_REMOTE_SUBMIX, address.string()) ==
+ AUDIO_POLICY_DEVICE_STATE_AVAILABLE)
+ {
+ setDeviceConnectionState(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
+ AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+ address.string());
+ }
+
+ if (getDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX, address.string()) ==
+ AUDIO_POLICY_DEVICE_STATE_AVAILABLE)
+ {
+ setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+ AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+ address.string());
+ }
+ module->removeOutputProfile(address);
+ module->removeInputProfile(address);
+ }
+ return NO_ERROR;
+}
+
status_t AudioPolicyManager::dump(int fd)
{
@@ -2234,6 +2553,7 @@ status_t AudioPolicyManager::createAudioPatch(const struct audio_patch *patch,
}
if (!outputDesc->mProfile->isCompatibleProfile(devDesc->mDeviceType,
+ devDesc->mAddress,
patch->sources[0].sample_rate,
NULL, // updatedSamplingRate
patch->sources[0].format,
@@ -2288,13 +2608,14 @@ status_t AudioPolicyManager::createAudioPatch(const struct audio_patch *patch,
}
if (!inputDesc->mProfile->isCompatibleProfile(devDesc->mDeviceType,
- patch->sinks[0].sample_rate,
- NULL, /*updatedSampleRate*/
- patch->sinks[0].format,
- patch->sinks[0].channel_mask,
- // FIXME for the parameter type,
- // and the NONE
- (audio_output_flags_t)
+ devDesc->mAddress,
+ patch->sinks[0].sample_rate,
+ NULL, /*updatedSampleRate*/
+ patch->sinks[0].format,
+ patch->sinks[0].channel_mask,
+ // FIXME for the parameter type,
+ // and the NONE
+ (audio_output_flags_t)
AUDIO_INPUT_FLAG_NONE)) {
return INVALID_OPERATION;
}
@@ -2561,13 +2882,10 @@ status_t AudioPolicyManager::setAudioPortConfig(const struct audio_port_config *
void AudioPolicyManager::clearAudioPatches(uid_t uid)
{
- for (ssize_t i = 0; i < (ssize_t)mAudioPatches.size(); i++) {
+ for (ssize_t i = (ssize_t)mAudioPatches.size() - 1; i >= 0; i--) {
sp<AudioPatch> patchDesc = mAudioPatches.valueAt(i);
if (patchDesc->mUid == uid) {
- // releaseAudioPatch() removes the patch from mAudioPatches
- if (releaseAudioPatch(mAudioPatches.keyAt(i), uid) == NO_ERROR) {
- i--;
- }
+ releaseAudioPatch(mAudioPatches.keyAt(i), uid);
}
}
}
@@ -2653,7 +2971,10 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa
mTotalEffectsCpuLoad(0), mTotalEffectsMemory(0),
mA2dpSuspended(false),
mSpeakerDrcEnabled(false), mNextUniqueId(1),
- mAudioPortGeneration(1)
+ mAudioPortGeneration(1),
+ mBeaconMuteRefCount(0),
+ mBeaconPlayingRefCount(0),
+ mBeaconMuted(false)
{
mUidCached = getuid();
mpClientInterface = clientInterface;
@@ -2787,6 +3108,14 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa
inputDesc->mInputSource = AUDIO_SOURCE_MIC;
inputDesc->mDevice = profileType;
+ // find the address
+ DeviceVector inputDevices = mAvailableInputDevices.getDevicesFromType(profileType);
+ // the inputs vector must be of size 1, but we don't want to crash here
+ String8 address = inputDevices.size() > 0 ? inputDevices.itemAt(0)->mAddress
+ : String8("");
+ ALOGV(" for input device 0x%x using address %s", profileType, address.string());
+ ALOGE_IF(inputDevices.size() == 0, "Input device list is empty!");
+
audio_config_t config = AUDIO_CONFIG_INITIALIZER;
config.sample_rate = inputDesc->mSamplingRate;
config.channel_mask = inputDesc->mChannelMask;
@@ -2796,7 +3125,7 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa
&input,
&config,
&inputDesc->mDevice,
- String8(""),
+ address,
AUDIO_SOURCE_MIC,
AUDIO_INPUT_FLAG_NONE);
@@ -3128,9 +3457,13 @@ status_t AudioPolicyManager::checkOutputsForDevice(const sp<DeviceDescriptor> de
}
for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++)
{
- if (mHwModules[i]->mOutputProfiles[j]->mSupportedDevices.types() & device) {
- ALOGV("checkOutputsForDevice(): adding profile %zu from module %zu", j, i);
- profiles.add(mHwModules[i]->mOutputProfiles[j]);
+ sp<IOProfile> profile = mHwModules[i]->mOutputProfiles[j];
+ if (profile->mSupportedDevices.types() & device) {
+ if (!deviceDistinguishesOnAddress(device) ||
+ address == profile->mSupportedDevices[0]->mAddress) {
+ profiles.add(profile);
+ ALOGV("checkOutputsForDevice(): adding profile %zu from module %zu", j, i);
+ }
}
}
}
@@ -3262,7 +3595,18 @@ status_t AudioPolicyManager::checkOutputsForDevice(const sp<DeviceDescriptor> de
if (output != AUDIO_IO_HANDLE_NONE) {
addOutput(output, desc);
- if ((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0) {
+ if (deviceDistinguishesOnAddress(device) && address != "0") {
+ ssize_t index = mPolicyMixes.indexOfKey(address);
+ if (index >= 0) {
+ mPolicyMixes[index]->mOutput = desc;
+ desc->mPolicyMix = &mPolicyMixes[index]->mMix;
+ } else {
+ ALOGE("checkOutputsForDevice() cannot find policy for address %s",
+ address.string());
+ }
+ } else if ((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0) {
+ // no duplicated output for direct outputs and
+ // outputs used by dynamic policy mixes
audio_io_handle_t duplicatedOutput = AUDIO_IO_HANDLE_NONE;
// set initial stream volume for device
@@ -3325,15 +3669,15 @@ status_t AudioPolicyManager::checkOutputsForDevice(const sp<DeviceDescriptor> de
for (size_t i = 0; i < mOutputs.size(); i++) {
desc = mOutputs.valueAt(i);
if (!desc->isDuplicated()) {
- if (!(desc->mProfile->mSupportedDevices.types()
+ // exact match on device
+ if (deviceDistinguishesOnAddress(device) &&
+ (desc->mProfile->mSupportedDevices.types() == device)) {
+ findIoHandlesByAddress(desc, address, outputs);
+ } else if (!(desc->mProfile->mSupportedDevices.types()
& mAvailableOutputDevices.types())) {
ALOGV("checkOutputsForDevice(): disconnecting adding output %d",
mOutputs.keyAt(i));
outputs.add(mOutputs.keyAt(i));
- } else if (deviceDistinguishesOnAddress(device) &&
- // exact match on device
- (desc->mProfile->mSupportedDevices.types() == device)) {
- findIoHandlesByAddress(desc, address, outputs);
}
}
}
@@ -3395,11 +3739,15 @@ status_t AudioPolicyManager::checkInputsForDevice(audio_devices_t device,
profile_index < mHwModules[module_idx]->mInputProfiles.size();
profile_index++)
{
- if (mHwModules[module_idx]->mInputProfiles[profile_index]->mSupportedDevices.types()
- & (device & ~AUDIO_DEVICE_BIT_IN)) {
- ALOGV("checkInputsForDevice(): adding profile %zu from module %zu",
- profile_index, module_idx);
- profiles.add(mHwModules[module_idx]->mInputProfiles[profile_index]);
+ sp<IOProfile> profile = mHwModules[module_idx]->mInputProfiles[profile_index];
+
+ if (profile->mSupportedDevices.types() & (device & ~AUDIO_DEVICE_BIT_IN)) {
+ if (!deviceDistinguishesOnAddress(device) ||
+ address == profile->mSupportedDevices[0]->mAddress) {
+ profiles.add(profile);
+ ALOGV("checkInputsForDevice(): adding profile %zu from module %zu",
+ profile_index, module_idx);
+ }
}
}
}
@@ -3517,7 +3865,8 @@ status_t AudioPolicyManager::checkInputsForDevice(audio_devices_t device,
// check if one opened input is not needed any more after disconnecting one device
for (size_t input_index = 0; input_index < mInputs.size(); input_index++) {
desc = mInputs.valueAt(input_index);
- if (!(desc->mProfile->mSupportedDevices.types() & mAvailableInputDevices.types())) {
+ if (!(desc->mProfile->mSupportedDevices.types() & mAvailableInputDevices.types() &
+ ~AUDIO_DEVICE_BIT_IN)) {
ALOGV("checkInputsForDevice(): disconnecting adding input %d",
mInputs.keyAt(input_index));
inputs.add(mInputs.keyAt(input_index));
@@ -3532,7 +3881,7 @@ status_t AudioPolicyManager::checkInputsForDevice(audio_devices_t device,
profile_index < mHwModules[module_index]->mInputProfiles.size();
profile_index++) {
sp<IOProfile> profile = mHwModules[module_index]->mInputProfiles[profile_index];
- if (profile->mSupportedDevices.types() & device) {
+ if (profile->mSupportedDevices.types() & device & ~AUDIO_DEVICE_BIT_IN) {
ALOGV("checkInputsForDevice(): clearing direct input profile %zu on module %zu",
profile_index, module_index);
if (profile->mSamplingRates[0] == 0) {
@@ -3566,6 +3915,12 @@ void AudioPolicyManager::closeOutput(audio_io_handle_t output)
return;
}
+ for (size_t i = 0; i < mPolicyMixes.size(); i++) {
+ if (mPolicyMixes[i]->mOutput == outputDesc) {
+ mPolicyMixes[i]->mOutput.clear();
+ }
+ }
+
// look for duplicated outputs connected to the output being removed.
for (size_t i = 0; i < mOutputs.size(); i++) {
sp<AudioOutputDescriptor> dupOutputDesc = mOutputs.valueAt(i);
@@ -3708,6 +4063,9 @@ void AudioPolicyManager::checkOutputForStrategy(routing_strategy strategy)
}
// Move tracks associated to this strategy from previous output to new output
for (int i = 0; i < AUDIO_STREAM_CNT; i++) {
+ if (i == AUDIO_STREAM_PATCH) {
+ continue;
+ }
if (getStrategy((audio_stream_type_t)i) == strategy) {
mpClientInterface->invalidateStream((audio_stream_type_t)i);
}
@@ -3724,8 +4082,10 @@ void AudioPolicyManager::checkOutputForAllStrategies()
checkOutputForStrategy(STRATEGY_ENFORCED_AUDIBLE);
checkOutputForStrategy(STRATEGY_SONIFICATION);
checkOutputForStrategy(STRATEGY_SONIFICATION_RESPECTFUL);
+ checkOutputForStrategy(STRATEGY_ACCESSIBILITY);
checkOutputForStrategy(STRATEGY_MEDIA);
checkOutputForStrategy(STRATEGY_DTMF);
+ checkOutputForStrategy(STRATEGY_REROUTING);
}
audio_io_handle_t AudioPolicyManager::getA2dpOutput()
@@ -3749,7 +4109,9 @@ void AudioPolicyManager::checkA2dpSuspend()
}
bool isScoConnected =
- (mAvailableInputDevices.types() & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) != 0;
+ ((mAvailableInputDevices.types() & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET &
+ ~AUDIO_DEVICE_BIT_IN) != 0) ||
+ ((mAvailableOutputDevices.types() & AUDIO_DEVICE_OUT_ALL_SCO) != 0);
// suspend A2DP output if:
// (NOT already suspended) &&
// ((SCO device is connected &&
@@ -3812,10 +4174,14 @@ audio_devices_t AudioPolicyManager::getNewOutputDevice(audio_io_handle_t output,
// use device for strategy sonification
// 5: the strategy "respectful" sonification is active on the output:
// use device for strategy "respectful" sonification
- // 6: the strategy media is active on the output:
+ // 6: the strategy accessibility is active on the output:
+ // use device for strategy accessibility
+ // 7: the strategy media is active on the output:
// use device for strategy media
- // 7: the strategy DTMF is active on the output:
+ // 8: the strategy DTMF is active on the output:
// use device for strategy DTMF
+ // 9: the strategy for beacon, a.k.a. "transmitted through speaker" is active on the output:
+ // use device for strategy t-t-s
if (outputDesc->isStrategyActive(STRATEGY_ENFORCED_AUDIBLE) &&
mForceUse[AUDIO_POLICY_FORCE_FOR_SYSTEM] == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED) {
device = getDeviceForStrategy(STRATEGY_ENFORCED_AUDIBLE, fromCache);
@@ -3828,10 +4194,16 @@ audio_devices_t AudioPolicyManager::getNewOutputDevice(audio_io_handle_t output,
device = getDeviceForStrategy(STRATEGY_SONIFICATION, fromCache);
} else if (outputDesc->isStrategyActive(STRATEGY_SONIFICATION_RESPECTFUL)) {
device = getDeviceForStrategy(STRATEGY_SONIFICATION_RESPECTFUL, fromCache);
+ } else if (outputDesc->isStrategyActive(STRATEGY_ACCESSIBILITY)) {
+ device = getDeviceForStrategy(STRATEGY_ACCESSIBILITY, fromCache);
} else if (outputDesc->isStrategyActive(STRATEGY_MEDIA)) {
device = getDeviceForStrategy(STRATEGY_MEDIA, fromCache);
} else if (outputDesc->isStrategyActive(STRATEGY_DTMF)) {
device = getDeviceForStrategy(STRATEGY_DTMF, fromCache);
+ } else if (outputDesc->isStrategyActive(STRATEGY_TRANSMITTED_THROUGH_SPEAKER)) {
+ device = getDeviceForStrategy(STRATEGY_TRANSMITTED_THROUGH_SPEAKER, fromCache);
+ } else if (outputDesc->isStrategyActive(STRATEGY_REROUTING)) {
+ device = getDeviceForStrategy(STRATEGY_REROUTING, fromCache);
}
ALOGV("getNewOutputDevice() selected device %x", device);
@@ -3866,7 +4238,7 @@ audio_devices_t AudioPolicyManager::getDevicesForStream(audio_stream_type_t stre
// By checking the range of stream before calling getStrategy, we avoid
// getStrategy's behavior for invalid streams. getStrategy would do a ALOGE
// and then return STRATEGY_MEDIA, but we want to return the empty set.
- if (stream < (audio_stream_type_t) 0 || stream >= AUDIO_STREAM_CNT) {
+ if (stream < (audio_stream_type_t) 0 || stream >= AUDIO_STREAM_PUBLIC_CNT) {
return AUDIO_DEVICE_NONE;
}
audio_devices_t devices;
@@ -3893,6 +4265,9 @@ audio_devices_t AudioPolicyManager::getDevicesForStream(audio_stream_type_t stre
AudioPolicyManager::routing_strategy AudioPolicyManager::getStrategy(
audio_stream_type_t stream) {
+
+ ALOG_ASSERT(stream != AUDIO_STREAM_PATCH,"getStrategy() called for AUDIO_STREAM_PATCH");
+
// stream to strategy mapping
switch (stream) {
case AUDIO_STREAM_VOICE_CALL:
@@ -3906,29 +4281,45 @@ AudioPolicyManager::routing_strategy AudioPolicyManager::getStrategy(
case AUDIO_STREAM_DTMF:
return STRATEGY_DTMF;
default:
- ALOGE("unknown stream type");
+ ALOGE("unknown stream type %d", stream);
case AUDIO_STREAM_SYSTEM:
// NOTE: SYSTEM stream uses MEDIA strategy because muting music and switching outputs
// while key clicks are played produces a poor result
- case AUDIO_STREAM_TTS:
case AUDIO_STREAM_MUSIC:
return STRATEGY_MEDIA;
case AUDIO_STREAM_ENFORCED_AUDIBLE:
return STRATEGY_ENFORCED_AUDIBLE;
+ case AUDIO_STREAM_TTS:
+ return STRATEGY_TRANSMITTED_THROUGH_SPEAKER;
+ case AUDIO_STREAM_ACCESSIBILITY:
+ return STRATEGY_ACCESSIBILITY;
+ case AUDIO_STREAM_REROUTING:
+ return STRATEGY_REROUTING;
}
}
uint32_t AudioPolicyManager::getStrategyForAttr(const audio_attributes_t *attr) {
// flags to strategy mapping
+ if ((attr->flags & AUDIO_FLAG_BEACON) == AUDIO_FLAG_BEACON) {
+ return (uint32_t) STRATEGY_TRANSMITTED_THROUGH_SPEAKER;
+ }
if ((attr->flags & AUDIO_FLAG_AUDIBILITY_ENFORCED) == AUDIO_FLAG_AUDIBILITY_ENFORCED) {
return (uint32_t) STRATEGY_ENFORCED_AUDIBLE;
}
// usage to strategy mapping
switch (attr->usage) {
+ case AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY:
+ if (isStreamActive(AUDIO_STREAM_RING) || isStreamActive(AUDIO_STREAM_ALARM)) {
+ return (uint32_t) STRATEGY_SONIFICATION;
+ }
+ if (isInCall()) {
+ return (uint32_t) STRATEGY_PHONE;
+ }
+ return (uint32_t) STRATEGY_ACCESSIBILITY;
+
case AUDIO_USAGE_MEDIA:
case AUDIO_USAGE_GAME:
- case AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY:
case AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
case AUDIO_USAGE_ASSISTANCE_SONIFICATION:
return (uint32_t) STRATEGY_MEDIA;
@@ -3967,6 +4358,74 @@ void AudioPolicyManager::handleNotificationRoutingForStream(audio_stream_type_t
}
}
+bool AudioPolicyManager::isAnyOutputActive(audio_stream_type_t streamToIgnore) {
+ for (size_t s = 0 ; s < AUDIO_STREAM_CNT ; s++) {
+ if (s == (size_t) streamToIgnore) {
+ continue;
+ }
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ const sp<AudioOutputDescriptor> outputDesc = mOutputs.valueAt(i);
+ if (outputDesc->mRefCount[s] != 0) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+uint32_t AudioPolicyManager::handleEventForBeacon(int event) {
+ switch(event) {
+ case STARTING_OUTPUT:
+ mBeaconMuteRefCount++;
+ break;
+ case STOPPING_OUTPUT:
+ if (mBeaconMuteRefCount > 0) {
+ mBeaconMuteRefCount--;
+ }
+ break;
+ case STARTING_BEACON:
+ mBeaconPlayingRefCount++;
+ break;
+ case STOPPING_BEACON:
+ if (mBeaconPlayingRefCount > 0) {
+ mBeaconPlayingRefCount--;
+ }
+ break;
+ }
+
+ if (mBeaconMuteRefCount > 0) {
+ // any playback causes beacon to be muted
+ return setBeaconMute(true);
+ } else {
+ // no other playback: unmute when beacon starts playing, mute when it stops
+ return setBeaconMute(mBeaconPlayingRefCount == 0);
+ }
+}
+
+uint32_t AudioPolicyManager::setBeaconMute(bool mute) {
+ ALOGV("setBeaconMute(%d) mBeaconMuteRefCount=%d mBeaconPlayingRefCount=%d",
+ mute, mBeaconMuteRefCount, mBeaconPlayingRefCount);
+ // keep track of muted state to avoid repeating mute/unmute operations
+ if (mBeaconMuted != mute) {
+ // mute/unmute AUDIO_STREAM_TTS on all outputs
+ ALOGV("\t muting %d", mute);
+ uint32_t maxLatency = 0;
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ sp<AudioOutputDescriptor> desc = mOutputs.valueAt(i);
+ setStreamMute(AUDIO_STREAM_TTS, mute/*on*/,
+ desc->mIoHandle,
+ 0 /*delay*/, AUDIO_DEVICE_NONE);
+ const uint32_t latency = desc->latency() * 2;
+ if (latency > maxLatency) {
+ maxLatency = latency;
+ }
+ }
+ mBeaconMuted = mute;
+ return maxLatency;
+ }
+ return 0;
+}
+
audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strategy,
bool fromCache)
{
@@ -3980,6 +4439,14 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate
audio_devices_t availableOutputDeviceTypes = mAvailableOutputDevices.types();
switch (strategy) {
+ case STRATEGY_TRANSMITTED_THROUGH_SPEAKER:
+ device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_SPEAKER;
+ if (!device) {
+ ALOGE("getDeviceForStrategy() no device found for "\
+ "STRATEGY_TRANSMITTED_THROUGH_SPEAKER");
+ }
+ break;
+
case STRATEGY_SONIFICATION_RESPECTFUL:
if (isInCall()) {
device = getDeviceForStrategy(STRATEGY_SONIFICATION, false /*fromCache*/);
@@ -4052,7 +4519,7 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate
// when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP
if (!isInCall() &&
(mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA] != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
- (getA2dpOutput() != 0) && !mA2dpSuspended) {
+ (getA2dpOutput() != 0)) {
device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
if (device) break;
device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
@@ -4087,7 +4554,7 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate
// A2DP speaker when forcing to speaker output
if (!isInCall() &&
(mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA] != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
- (getA2dpOutput() != 0) && !mA2dpSuspended) {
+ (getA2dpOutput() != 0)) {
device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
if (device) break;
}
@@ -4141,15 +4608,35 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate
// The second device used for sonification is the same as the device used by media strategy
// FALL THROUGH
+ // FIXME: STRATEGY_ACCESSIBILITY and STRATEGY_REROUTING follow STRATEGY_MEDIA for now
+ case STRATEGY_ACCESSIBILITY:
+ if (strategy == STRATEGY_ACCESSIBILITY) {
+ // do not route accessibility prompts to a digital output currently configured with a
+ // compressed format as they would likely not be mixed and dropped.
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ sp<AudioOutputDescriptor> desc = mOutputs.valueAt(i);
+ audio_devices_t devices = desc->device() &
+ (AUDIO_DEVICE_OUT_HDMI | AUDIO_DEVICE_OUT_SPDIF | AUDIO_DEVICE_OUT_HDMI_ARC);
+ if (desc->isActive() && !audio_is_linear_pcm(desc->mFormat) &&
+ devices != AUDIO_DEVICE_NONE) {
+ availableOutputDeviceTypes = availableOutputDeviceTypes & ~devices;
+ }
+ }
+ }
+ // FALL THROUGH
+
+ case STRATEGY_REROUTING:
case STRATEGY_MEDIA: {
uint32_t device2 = AUDIO_DEVICE_NONE;
if (strategy != STRATEGY_SONIFICATION) {
// no sonification on remote submix (e.g. WFD)
- device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
+ if (mAvailableOutputDevices.getDevice(AUDIO_DEVICE_OUT_REMOTE_SUBMIX, String8("0")) != 0) {
+ device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
+ }
}
if ((device2 == AUDIO_DEVICE_NONE) &&
(mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA] != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
- (getA2dpOutput() != 0) && !mA2dpSuspended) {
+ (getA2dpOutput() != 0)) {
device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
if (device2 == AUDIO_DEVICE_NONE) {
device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
@@ -4158,6 +4645,10 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate
device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
}
}
+ if ((device2 == AUDIO_DEVICE_NONE) &&
+ (mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA] == AUDIO_POLICY_FORCE_SPEAKER)) {
+ device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_SPEAKER;
+ }
if (device2 == AUDIO_DEVICE_NONE) {
device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
}
@@ -4248,6 +4739,7 @@ uint32_t AudioPolicyManager::checkDeviceMuteStrategies(sp<AudioOutputDescriptor>
for (size_t i = 0; i < NUM_STRATEGIES; i++) {
audio_devices_t curDevice = getDeviceForStrategy((routing_strategy)i, false /*fromCache*/);
+ curDevice = curDevice & outputDesc->mProfile->mSupportedDevices.types();
bool mute = shouldMute && (curDevice & device) && (curDevice != device);
bool doMute = false;
@@ -4348,11 +4840,15 @@ uint32_t AudioPolicyManager::setOutputDevice(audio_io_handle_t output,
muteWaitMs = checkDeviceMuteStrategies(outputDesc, prevDevice, delayMs);
// Do not change the routing if:
- // - the requested device is AUDIO_DEVICE_NONE
- // - the requested device is the same as current device and force is not specified.
+ // the requested device is AUDIO_DEVICE_NONE
+ // OR the requested device is the same as current device
+ // AND force is not specified
+ // AND the output is connected by a valid audio patch.
// Doing this check here allows the caller to call setOutputDevice() without conditions
- if ((device == AUDIO_DEVICE_NONE || device == prevDevice) && !force) {
- ALOGV("setOutputDevice() setting same device %04x or null device for output %d", device, output);
+ if ((device == AUDIO_DEVICE_NONE || device == prevDevice) && !force &&
+ outputDesc->mPatchHandle != 0) {
+ ALOGV("setOutputDevice() setting same device %04x or null device for output %d",
+ device, output);
return muteWaitMs;
}
@@ -4546,6 +5042,7 @@ status_t AudioPolicyManager::resetInputDevice(audio_io_handle_t input,
}
sp<AudioPolicyManager::IOProfile> AudioPolicyManager::getInputProfile(audio_devices_t device,
+ String8 address,
uint32_t& samplingRate,
audio_format_t format,
audio_channel_mask_t channelMask,
@@ -4563,9 +5060,10 @@ sp<AudioPolicyManager::IOProfile> AudioPolicyManager::getInputProfile(audio_devi
{
sp<IOProfile> profile = mHwModules[i]->mInputProfiles[j];
// profile->log();
- if (profile->isCompatibleProfile(device, samplingRate,
+ if (profile->isCompatibleProfile(device, address, samplingRate,
&samplingRate /*updatedSamplingRate*/,
format, channelMask, (audio_output_flags_t) flags)) {
+
return profile;
}
}
@@ -4573,11 +5071,33 @@ sp<AudioPolicyManager::IOProfile> AudioPolicyManager::getInputProfile(audio_devi
return NULL;
}
-audio_devices_t AudioPolicyManager::getDeviceForInputSource(audio_source_t inputSource)
+audio_devices_t AudioPolicyManager::getDeviceForInputSource(audio_source_t inputSource,
+ AudioMix **policyMix)
{
uint32_t device = AUDIO_DEVICE_NONE;
audio_devices_t availableDeviceTypes = mAvailableInputDevices.types() &
~AUDIO_DEVICE_BIT_IN;
+
+ for (size_t i = 0; i < mPolicyMixes.size(); i++) {
+ if (mPolicyMixes[i]->mMix.mMixType != MIX_TYPE_RECORDERS) {
+ continue;
+ }
+ for (size_t j = 0; j < mPolicyMixes[i]->mMix.mCriteria.size(); j++) {
+ if ((RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET == mPolicyMixes[i]->mMix.mCriteria[j].mRule &&
+ mPolicyMixes[i]->mMix.mCriteria[j].mAttr.mSource == inputSource) ||
+ (RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET == mPolicyMixes[i]->mMix.mCriteria[j].mRule &&
+ mPolicyMixes[i]->mMix.mCriteria[j].mAttr.mSource != inputSource)) {
+ if (availableDeviceTypes & AUDIO_DEVICE_IN_REMOTE_SUBMIX) {
+ if (policyMix != NULL) {
+ *policyMix = &mPolicyMixes[i]->mMix;
+ }
+ return AUDIO_DEVICE_IN_REMOTE_SUBMIX;
+ }
+ break;
+ }
+ }
+ }
+
switch (inputSource) {
case AUDIO_SOURCE_VOICE_UPLINK:
if (availableDeviceTypes & AUDIO_DEVICE_IN_VOICE_CALL) {
@@ -4667,6 +5187,11 @@ audio_devices_t AudioPolicyManager::getDeviceForInputSource(audio_source_t input
device = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
}
break;
+ case AUDIO_SOURCE_FM_TUNER:
+ if (availableDeviceTypes & AUDIO_DEVICE_IN_FM_TUNER) {
+ device = AUDIO_DEVICE_IN_FM_TUNER;
+ }
+ break;
default:
ALOGW("getDeviceForInputSource() invalid input source %d", inputSource);
break;
@@ -4686,7 +5211,7 @@ bool AudioPolicyManager::isVirtualInputDevice(audio_devices_t device)
}
bool AudioPolicyManager::deviceDistinguishesOnAddress(audio_devices_t device) {
- return ((device & APM_AUDIO_DEVICE_MATCH_ADDRESS_ALL) != 0);
+ return ((device & APM_AUDIO_DEVICE_MATCH_ADDRESS_ALL & ~AUDIO_DEVICE_BIT_IN) != 0);
}
audio_io_handle_t AudioPolicyManager::getActiveInput(bool ignoreVirtualInputs)
@@ -4778,6 +5303,7 @@ AudioPolicyManager::device_category AudioPolicyManager::getDeviceCategory(audio_
}
}
+/* static */
float AudioPolicyManager::volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc,
int indexInUi)
{
@@ -4891,6 +5417,21 @@ const AudioPolicyManager::VolumeCurvePoint
};
const AudioPolicyManager::VolumeCurvePoint
+ AudioPolicyManager::sLinearVolumeCurve[AudioPolicyManager::VOLCNT] = {
+ {0, -96.0f}, {33, -68.0f}, {66, -34.0f}, {100, 0.0f}
+};
+
+const AudioPolicyManager::VolumeCurvePoint
+ AudioPolicyManager::sSilentVolumeCurve[AudioPolicyManager::VOLCNT] = {
+ {0, -96.0f}, {1, -96.0f}, {2, -96.0f}, {100, -96.0f}
+};
+
+const AudioPolicyManager::VolumeCurvePoint
+ AudioPolicyManager::sFullScaleVolumeCurve[AudioPolicyManager::VOLCNT] = {
+ {0, 0.0f}, {1, 0.0f}, {2, 0.0f}, {100, 0.0f}
+};
+
+const AudioPolicyManager::VolumeCurvePoint
*AudioPolicyManager::sVolumeProfiles[AUDIO_STREAM_CNT]
[AudioPolicyManager::DEVICE_CATEGORY_CNT] = {
{ // AUDIO_STREAM_VOICE_CALL
@@ -4948,11 +5489,30 @@ const AudioPolicyManager::VolumeCurvePoint
sExtMediaSystemVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
},
{ // AUDIO_STREAM_TTS
+ // "Transmitted Through Speaker": always silent except on DEVICE_CATEGORY_SPEAKER
+ sSilentVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ sLinearVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ sSilentVolumeCurve, // DEVICE_CATEGORY_EARPIECE
+ sSilentVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
+ },
+ { // AUDIO_STREAM_ACCESSIBILITY
sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_HEADSET
sSpeakerMediaVolumeCurve, // DEVICE_CATEGORY_SPEAKER
sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_EARPIECE
sDefaultMediaVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
},
+ { // AUDIO_STREAM_REROUTING
+ sFullScaleVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ sFullScaleVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ sFullScaleVolumeCurve, // DEVICE_CATEGORY_EARPIECE
+ sFullScaleVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
+ },
+ { // AUDIO_STREAM_PATCH
+ sFullScaleVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ sFullScaleVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ sFullScaleVolumeCurve, // DEVICE_CATEGORY_EARPIECE
+ sFullScaleVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
+ },
};
void AudioPolicyManager::initializeVolumeCurves()
@@ -4976,6 +5536,8 @@ void AudioPolicyManager::initializeVolumeCurves()
sSpeakerSonificationVolumeCurveDrc;
mStreams[AUDIO_STREAM_MUSIC].mVolumeCurve[DEVICE_CATEGORY_SPEAKER] =
sSpeakerMediaVolumeCurveDrc;
+ mStreams[AUDIO_STREAM_ACCESSIBILITY].mVolumeCurve[DEVICE_CATEGORY_SPEAKER] =
+ sSpeakerMediaVolumeCurveDrc;
}
}
@@ -5059,6 +5621,18 @@ status_t AudioPolicyManager::checkAndSetVolume(audio_stream_type_t stream,
}
float volume = computeVolume(stream, index, output, device);
+ // unit gain if rerouting to external policy
+ if (device == AUDIO_DEVICE_OUT_REMOTE_SUBMIX) {
+ ssize_t index = mOutputs.indexOfKey(output);
+ if (index >= 0) {
+ sp<AudioOutputDescriptor> outputDesc = mOutputs.valueAt(index);
+ if (outputDesc->mPolicyMix != NULL) {
+ ALOGV("max gain when rerouting for output=%d", output);
+ volume = 1.0f;
+ }
+ }
+
+ }
// We actually change the volume if:
// - the float value returned by computeVolume() changed
// - the force flag is set
@@ -5101,6 +5675,9 @@ void AudioPolicyManager::applyStreamVolumes(audio_io_handle_t output,
ALOGVV("applyStreamVolumes() for output %d and device %x", output, device);
for (int stream = 0; stream < AUDIO_STREAM_CNT; stream++) {
+ if (stream == AUDIO_STREAM_PATCH) {
+ continue;
+ }
checkAndSetVolume((audio_stream_type_t)stream,
mStreams[stream].getVolumeIndex(device),
output,
@@ -5118,6 +5695,9 @@ void AudioPolicyManager::setStrategyMute(routing_strategy strategy,
{
ALOGVV("setStrategyMute() strategy %d, mute %d, output %d", strategy, on, output);
for (int stream = 0; stream < AUDIO_STREAM_CNT; stream++) {
+ if (stream == AUDIO_STREAM_PATCH) {
+ continue;
+ }
if (getStrategy((audio_stream_type_t)stream) == strategy) {
setStreamMute((audio_stream_type_t)stream, on, output, delayMs, device);
}
@@ -5235,7 +5815,8 @@ uint32_t AudioPolicyManager::getMaxEffectsMemory()
AudioPolicyManager::AudioOutputDescriptor::AudioOutputDescriptor(
const sp<IOProfile>& profile)
: mId(0), mIoHandle(0), mLatency(0),
- mFlags((audio_output_flags_t)0), mDevice(AUDIO_DEVICE_NONE), mPatchHandle(0),
+ mFlags((audio_output_flags_t)0), mDevice(AUDIO_DEVICE_NONE), mPolicyMix(NULL),
+ mPatchHandle(0),
mOutput1(0), mOutput2(0), mProfile(profile), mDirectOpenCount(0)
{
// clear usage count for all stream types
@@ -5329,6 +5910,9 @@ bool AudioPolicyManager::AudioOutputDescriptor::isStrategyActive(routing_strateg
sysTime = systemTime();
}
for (int i = 0; i < (int)AUDIO_STREAM_CNT; i++) {
+ if (i == AUDIO_STREAM_PATCH) {
+ continue;
+ }
if (((getStrategy((audio_stream_type_t)i) == strategy) ||
(NUM_STRATEGIES == strategy)) &&
isStreamActive((audio_stream_type_t)i, inPastMs, sysTime)) {
@@ -5427,7 +6011,7 @@ status_t AudioPolicyManager::AudioOutputDescriptor::dump(int fd)
AudioPolicyManager::AudioInputDescriptor::AudioInputDescriptor(const sp<IOProfile>& profile)
: mId(0), mIoHandle(0),
- mDevice(AUDIO_DEVICE_NONE), mPatchHandle(0), mRefCount(0),
+ mDevice(AUDIO_DEVICE_NONE), mPolicyMix(NULL), mPatchHandle(0), mRefCount(0),
mInputSource(AUDIO_SOURCE_DEFAULT), mProfile(profile), mIsSoundTrigger(false)
{
if (profile != NULL) {
@@ -5717,6 +6301,69 @@ status_t AudioPolicyManager::HwModule::loadDevice(cnode *root)
return NO_ERROR;
}
+status_t AudioPolicyManager::HwModule::addOutputProfile(String8 name, const audio_config_t *config,
+ audio_devices_t device, String8 address)
+{
+ sp<IOProfile> profile = new IOProfile(name, AUDIO_PORT_ROLE_SOURCE, this);
+
+ profile->mSamplingRates.add(config->sample_rate);
+ profile->mChannelMasks.add(config->channel_mask);
+ profile->mFormats.add(config->format);
+
+ sp<DeviceDescriptor> devDesc = new DeviceDescriptor(String8(""), device);
+ devDesc->mAddress = address;
+ profile->mSupportedDevices.add(devDesc);
+
+ mOutputProfiles.add(profile);
+
+ return NO_ERROR;
+}
+
+status_t AudioPolicyManager::HwModule::removeOutputProfile(String8 name)
+{
+ for (size_t i = 0; i < mOutputProfiles.size(); i++) {
+ if (mOutputProfiles[i]->mName == name) {
+ mOutputProfiles.removeAt(i);
+ break;
+ }
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioPolicyManager::HwModule::addInputProfile(String8 name, const audio_config_t *config,
+ audio_devices_t device, String8 address)
+{
+ sp<IOProfile> profile = new IOProfile(name, AUDIO_PORT_ROLE_SINK, this);
+
+ profile->mSamplingRates.add(config->sample_rate);
+ profile->mChannelMasks.add(config->channel_mask);
+ profile->mFormats.add(config->format);
+
+ sp<DeviceDescriptor> devDesc = new DeviceDescriptor(String8(""), device);
+ devDesc->mAddress = address;
+ profile->mSupportedDevices.add(devDesc);
+
+ ALOGV("addInputProfile() name %s rate %d mask 0x08", name.string(), config->sample_rate, config->channel_mask);
+
+ mInputProfiles.add(profile);
+
+ return NO_ERROR;
+}
+
+status_t AudioPolicyManager::HwModule::removeInputProfile(String8 name)
+{
+ for (size_t i = 0; i < mInputProfiles.size(); i++) {
+ if (mInputProfiles[i]->mName == name) {
+ mInputProfiles.removeAt(i);
+ break;
+ }
+ }
+
+ return NO_ERROR;
+}
+
+
void AudioPolicyManager::HwModule::dump(int fd)
{
const size_t SIZE = 256;
@@ -5843,12 +6490,28 @@ void AudioPolicyManager::AudioPort::importAudioPort(const sp<AudioPort> port) {
}
}
}
+ for (size_t k = 0 ; k < port->mGains.size() ; k++) {
+ sp<AudioGain> gain = port->mGains.itemAt(k);
+ if (gain != 0) {
+ bool hasGain = false;
+ for (size_t l = 0 ; l < mGains.size() ; l++) {
+ if (gain == mGains.itemAt(l)) {
+ hasGain = true;
+ break;
+ }
+ }
+ if (!hasGain) { // never import a gain twice
+ mGains.add(gain);
+ }
+ }
+ }
}
void AudioPolicyManager::AudioPort::clearCapabilities() {
mChannelMasks.clear();
mFormats.clear();
mSamplingRates.clear();
+ mGains.clear();
}
void AudioPolicyManager::AudioPort::loadSamplingRates(char *name)
@@ -6018,6 +6681,10 @@ void AudioPolicyManager::AudioPort::loadGains(cnode *root)
status_t AudioPolicyManager::AudioPort::checkExactSamplingRate(uint32_t samplingRate) const
{
+ if (mSamplingRates.isEmpty()) {
+ return NO_ERROR;
+ }
+
for (size_t i = 0; i < mSamplingRates.size(); i ++) {
if (mSamplingRates[i] == samplingRate) {
return NO_ERROR;
@@ -6029,6 +6696,10 @@ status_t AudioPolicyManager::AudioPort::checkExactSamplingRate(uint32_t sampling
status_t AudioPolicyManager::AudioPort::checkCompatibleSamplingRate(uint32_t samplingRate,
uint32_t *updatedSamplingRate) const
{
+ if (mSamplingRates.isEmpty()) {
+ return NO_ERROR;
+ }
+
// Search for the closest supported sampling rate that is above (preferred)
// or below (acceptable) the desired sampling rate, within a permitted ratio.
// The sampling rates do not need to be sorted in ascending order.
@@ -6087,6 +6758,10 @@ status_t AudioPolicyManager::AudioPort::checkCompatibleSamplingRate(uint32_t sam
status_t AudioPolicyManager::AudioPort::checkExactChannelMask(audio_channel_mask_t channelMask) const
{
+ if (mChannelMasks.isEmpty()) {
+ return NO_ERROR;
+ }
+
for (size_t i = 0; i < mChannelMasks.size(); i++) {
if (mChannelMasks[i] == channelMask) {
return NO_ERROR;
@@ -6098,6 +6773,10 @@ status_t AudioPolicyManager::AudioPort::checkExactChannelMask(audio_channel_mask
status_t AudioPolicyManager::AudioPort::checkCompatibleChannelMask(audio_channel_mask_t channelMask)
const
{
+ if (mChannelMasks.isEmpty()) {
+ return NO_ERROR;
+ }
+
const bool isRecordThread = mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SINK;
for (size_t i = 0; i < mChannelMasks.size(); i ++) {
// FIXME Does not handle multi-channel automatic conversions yet
@@ -6121,6 +6800,10 @@ status_t AudioPolicyManager::AudioPort::checkCompatibleChannelMask(audio_channel
status_t AudioPolicyManager::AudioPort::checkFormat(audio_format_t format) const
{
+ if (mFormats.isEmpty()) {
+ return NO_ERROR;
+ }
+
for (size_t i = 0; i < mFormats.size(); i ++) {
if (mFormats[i] == format) {
return NO_ERROR;
@@ -6587,17 +7270,18 @@ AudioPolicyManager::IOProfile::~IOProfile()
// Sampling rate, format and channel mask must be specified in order to
// get a valid a match
bool AudioPolicyManager::IOProfile::isCompatibleProfile(audio_devices_t device,
- uint32_t samplingRate,
- uint32_t *updatedSamplingRate,
- audio_format_t format,
- audio_channel_mask_t channelMask,
- uint32_t flags) const
+ String8 address,
+ uint32_t samplingRate,
+ uint32_t *updatedSamplingRate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
+ uint32_t flags) const
{
const bool isPlaybackThread = mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SOURCE;
const bool isRecordThread = mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SINK;
ALOG_ASSERT(isPlaybackThread != isRecordThread);
- if ((mSupportedDevices.types() & device) != device) {
+ if (device != AUDIO_DEVICE_NONE && mSupportedDevices.getDevice(device, address) == 0) {
return false;
}
@@ -6791,7 +7475,12 @@ void AudioPolicyManager::DeviceVector::loadDevicesFromName(char *name,
ARRAY_SIZE(sDeviceNameToEnumTable),
devName);
if (type != AUDIO_DEVICE_NONE) {
- add(new DeviceDescriptor(String8(""), type));
+ sp<DeviceDescriptor> dev = new DeviceDescriptor(String8(""), type);
+ if (type == AUDIO_DEVICE_IN_REMOTE_SUBMIX ||
+ type == AUDIO_DEVICE_OUT_REMOTE_SUBMIX ) {
+ dev->mAddress = String8("0");
+ }
+ add(dev);
} else {
sp<DeviceDescriptor> deviceDesc =
declaredDevices.getDeviceFromName(String8(devName));
@@ -6800,7 +7489,7 @@ void AudioPolicyManager::DeviceVector::loadDevicesFromName(char *name,
}
}
}
- devName = strtok(NULL, "|");
+ devName = strtok(NULL, "|");
}
}
@@ -6810,13 +7499,15 @@ sp<AudioPolicyManager::DeviceDescriptor> AudioPolicyManager::DeviceVector::getDe
sp<DeviceDescriptor> device;
for (size_t i = 0; i < size(); i++) {
if (itemAt(i)->mDeviceType == type) {
- device = itemAt(i);
- if (itemAt(i)->mAddress = address) {
- break;
+ if (address == "" || itemAt(i)->mAddress == address) {
+ device = itemAt(i);
+ if (itemAt(i)->mAddress == address) {
+ break;
+ }
}
}
}
- ALOGV("DeviceVector::getDevice() for type %d address %s found %p",
+ ALOGV("DeviceVector::getDevice() for type %08x address %s found %p",
type, address.string(), device.get());
return device;
}
@@ -6854,13 +7545,9 @@ AudioPolicyManager::DeviceVector AudioPolicyManager::DeviceVector::getDevicesFro
audio_devices_t type, String8 address) const
{
DeviceVector devices;
- //ALOGV(" looking for device=%x, addr=%s", type, address.string());
for (size_t i = 0; i < size(); i++) {
- //ALOGV(" at i=%d: device=%x, addr=%s",
- // i, itemAt(i)->mDeviceType, itemAt(i)->mAddress.string());
if (itemAt(i)->mDeviceType == type) {
if (itemAt(i)->mAddress == address) {
- //ALOGV(" found matching address %s", address.string());
devices.add(itemAt(i));
}
}
@@ -7226,9 +7913,19 @@ audio_stream_type_t AudioPolicyManager::streamTypefromAttributesInt(const audio_
switch (attr->usage) {
case AUDIO_USAGE_MEDIA:
case AUDIO_USAGE_GAME:
- case AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY:
case AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
return AUDIO_STREAM_MUSIC;
+ case AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY:
+ if (isStreamActive(AUDIO_STREAM_ALARM)) {
+ return AUDIO_STREAM_ALARM;
+ }
+ if (isStreamActive(AUDIO_STREAM_RING)) {
+ return AUDIO_STREAM_RING;
+ }
+ if (isInCall()) {
+ return AUDIO_STREAM_VOICE_CALL;
+ }
+ return AUDIO_STREAM_ACCESSIBILITY;
case AUDIO_USAGE_ASSISTANCE_SONIFICATION:
return AUDIO_STREAM_SYSTEM;
case AUDIO_USAGE_VOICE_COMMUNICATION:
@@ -7254,4 +7951,36 @@ audio_stream_type_t AudioPolicyManager::streamTypefromAttributesInt(const audio_
return AUDIO_STREAM_MUSIC;
}
}
+
+bool AudioPolicyManager::isValidAttributes(const audio_attributes_t *paa) {
+ // has flags that map to a strategy?
+ if ((paa->flags & (AUDIO_FLAG_AUDIBILITY_ENFORCED | AUDIO_FLAG_SCO | AUDIO_FLAG_BEACON)) != 0) {
+ return true;
+ }
+
+ // has known usage?
+ switch (paa->usage) {
+ case AUDIO_USAGE_UNKNOWN:
+ case AUDIO_USAGE_MEDIA:
+ case AUDIO_USAGE_VOICE_COMMUNICATION:
+ case AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING:
+ case AUDIO_USAGE_ALARM:
+ case AUDIO_USAGE_NOTIFICATION:
+ case AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE:
+ case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
+ case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
+ case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
+ case AUDIO_USAGE_NOTIFICATION_EVENT:
+ case AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY:
+ case AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
+ case AUDIO_USAGE_ASSISTANCE_SONIFICATION:
+ case AUDIO_USAGE_GAME:
+ case AUDIO_USAGE_VIRTUAL_SOURCE:
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
}; // namespace android