#define ALOGVV(a...) do { } while(0)
#endif
+// 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
+// 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
+
#include <utils/Log.h>
#include <hardware_legacy/AudioPolicyManagerBase.h>
#include <hardware/audio_effect.h>
// ----------------------------------------------------------------------------
-status_t AudioPolicyManagerBase::setDeviceConnectionState(AudioSystem::audio_devices device,
+status_t AudioPolicyManagerBase::setDeviceConnectionState(audio_devices_t device,
AudioSystem::device_connection_state state,
const char *device_address)
{
ALOGV("setDeviceConnectionState() device: %x, state %d, address %s", device, state, device_address);
// connect/disconnect only 1 device at a time
- if (AudioSystem::popCount(device) != 1) return BAD_VALUE;
+ if (!audio_is_output_device(device) && !audio_is_input_device(device)) return BAD_VALUE;
if (strlen(device_address) >= MAX_DEVICE_ADDRESS_LEN) {
ALOGE("setDeviceConnectionState() invalid address: %s", device_address);
}
// handle output devices
- if (AudioSystem::isOutputDevice(device)) {
+ if (audio_is_output_device(device)) {
- if (!mHasA2dp && AudioSystem::isA2dpDevice(device)) {
- ALOGE("setDeviceConnectionState() invalid device: %x", device);
+ if (!mHasA2dp && audio_is_a2dp_device(device)) {
+ ALOGE("setDeviceConnectionState() invalid A2DP device: %x", device);
+ return BAD_VALUE;
+ }
+ if (!mHasUsb && audio_is_usb_device(device)) {
+ ALOGE("setDeviceConnectionState() invalid USB audio device: %x", device);
return BAD_VALUE;
}
- if (!mHasUsb && audio_is_usb_device((audio_devices_t)device)) {
- ALOGE("setDeviceConnectionState() invalid device: %x", device);
+ if (!mHasRemoteSubmix && audio_is_remote_submix_device((audio_devices_t)device)) {
+ ALOGE("setDeviceConnectionState() invalid remote submix audio device: %x", device);
return BAD_VALUE;
}
+ // save a copy of the opened output descriptors before any output is opened or closed
+ // by checkOutputsForDevice(). This will be needed by checkOutputForAllStrategies()
+ mPreviousOutputs = mOutputs;
switch (state)
{
// handle output device connection
}
ALOGV("setDeviceConnectionState() connecting device %x", device);
- if (checkOutputsForDevice((audio_devices_t)device, state, outputs) != NO_ERROR) {
+ if (checkOutputsForDevice(device, state, outputs) != NO_ERROR) {
return INVALID_OPERATION;
}
ALOGV("setDeviceConnectionState() checkOutputsForDevice() returned %d outputs",
if (!outputs.isEmpty()) {
String8 paramStr;
- if (mHasA2dp && AudioSystem::isA2dpDevice(device)) {
+ if (mHasA2dp && audio_is_a2dp_device(device)) {
// handle A2DP device connection
AudioParameter param;
param.add(String8(AUDIO_PARAMETER_A2DP_SINK_ADDRESS), String8(device_address));
paramStr = param.toString();
mA2dpDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
mA2dpSuspended = false;
- } else if (AudioSystem::isBluetoothScoDevice(device)) {
+ } else if (audio_is_bluetooth_sco_device(device)) {
// handle SCO device connection
mScoDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
- } else if (mHasUsb && audio_is_usb_device((audio_devices_t)device)) {
+ } else if (mHasUsb && audio_is_usb_device(device)) {
// handle USB device connection
mUsbCardAndDevice = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
paramStr = mUsbCardAndDevice;
}
+ // not currently handling multiple simultaneous submixes: ignoring remote submix
+ // case and address
if (!paramStr.isEmpty()) {
for (size_t i = 0; i < outputs.size(); i++) {
mpClientInterface->setParameters(outputs[i], paramStr);
// remove device from available output devices
mAvailableOutputDevices = (audio_devices_t)(mAvailableOutputDevices & ~device);
- checkOutputsForDevice((audio_devices_t)device, state, outputs);
- if (mHasA2dp && AudioSystem::isA2dpDevice(device)) {
+ checkOutputsForDevice(device, state, outputs);
+ if (mHasA2dp && audio_is_a2dp_device(device)) {
// handle A2DP device disconnection
mA2dpDeviceAddress = "";
mA2dpSuspended = false;
- } else if (AudioSystem::isBluetoothScoDevice(device)) {
+ } else if (audio_is_bluetooth_sco_device(device)) {
// handle SCO device disconnection
mScoDeviceAddress = "";
- } else if (mHasUsb && audio_is_usb_device((audio_devices_t)device)) {
+ } else if (mHasUsb && audio_is_usb_device(device)) {
// handle USB device disconnection
mUsbCardAndDevice = "";
}
+ // not currently handling multiple simultaneous submixes: ignoring remote submix
+ // case and address
} break;
default:
}
}
- updateDeviceForStrategy();
+ updateDevicesAndOutputs();
for (size_t i = 0; i < mOutputs.size(); i++) {
- setOutputDevice(mOutputs.keyAt(i), getNewDevice(mOutputs.keyAt(i), true /*fromCache*/));
- }
-
- if (device == AudioSystem::DEVICE_OUT_WIRED_HEADSET) {
- device = AudioSystem::DEVICE_IN_WIRED_HEADSET;
- } else if (device == AudioSystem::DEVICE_OUT_BLUETOOTH_SCO ||
- device == AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET ||
- device == AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT) {
- device = AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+ // do not force device change on duplicated output because if device is 0, it will
+ // also force a device 0 for the two outputs it is duplicated to which may override
+ // a valid device selection on those outputs.
+ setOutputDevice(mOutputs.keyAt(i),
+ getNewDevice(mOutputs.keyAt(i), true /*fromCache*/),
+ !mOutputs.valueAt(i)->isDuplicated(),
+ 0);
+ }
+
+ if (device == AUDIO_DEVICE_OUT_WIRED_HEADSET) {
+ device = AUDIO_DEVICE_IN_WIRED_HEADSET;
+ } else if (device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO ||
+ device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET ||
+ device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT) {
+ device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
} else {
return NO_ERROR;
}
}
// handle input devices
- if (AudioSystem::isInputDevice(device)) {
+ if (audio_is_input_device(device)) {
switch (state)
{
ALOGW("setDeviceConnectionState() device already connected: %d", device);
return INVALID_OPERATION;
}
- mAvailableInputDevices = (audio_devices_t)(mAvailableInputDevices | device);
+ mAvailableInputDevices = mAvailableInputDevices | (device & ~AUDIO_DEVICE_BIT_IN);
}
break;
if (activeInput != 0) {
AudioInputDescriptor *inputDesc = mInputs.valueFor(activeInput);
audio_devices_t newDevice = getDeviceForInputSource(inputDesc->mInputSource);
- if ((newDevice != 0) && (newDevice != inputDesc->mDevice)) {
+ if ((newDevice != AUDIO_DEVICE_NONE) && (newDevice != inputDesc->mDevice)) {
ALOGV("setDeviceConnectionState() changing device from %x to %x for input %d",
inputDesc->mDevice, newDevice, activeInput);
inputDesc->mDevice = newDevice;
return BAD_VALUE;
}
-AudioSystem::device_connection_state AudioPolicyManagerBase::getDeviceConnectionState(AudioSystem::audio_devices device,
+AudioSystem::device_connection_state AudioPolicyManagerBase::getDeviceConnectionState(audio_devices_t device,
const char *device_address)
{
AudioSystem::device_connection_state state = AudioSystem::DEVICE_STATE_UNAVAILABLE;
String8 address = String8(device_address);
- if (AudioSystem::isOutputDevice(device)) {
+ if (audio_is_output_device(device)) {
if (device & mAvailableOutputDevices) {
- if (AudioSystem::isA2dpDevice(device) &&
+ if (audio_is_a2dp_device(device) &&
(!mHasA2dp || (address != "" && mA2dpDeviceAddress != address))) {
return state;
}
- if (AudioSystem::isBluetoothScoDevice(device) &&
+ if (audio_is_bluetooth_sco_device(device) &&
address != "" && mScoDeviceAddress != address) {
return state;
}
- if (audio_is_usb_device((audio_devices_t)device) &&
+ if (audio_is_usb_device(device) &&
(!mHasUsb || (address != "" && mUsbCardAndDevice != address))) {
- ALOGE("setDeviceConnectionState() invalid device: %x", device);
+ ALOGE("getDeviceConnectionState() invalid device: %x", device);
+ return state;
+ }
+ if (audio_is_remote_submix_device((audio_devices_t)device) && !mHasRemoteSubmix) {
return state;
}
state = AudioSystem::DEVICE_STATE_AVAILABLE;
}
- } else if (AudioSystem::isInputDevice(device)) {
+ } else if (audio_is_input_device(device)) {
if (device & mAvailableInputDevices) {
state = AudioSystem::DEVICE_STATE_AVAILABLE;
}
void AudioPolicyManagerBase::setPhoneState(int state)
{
ALOGV("setPhoneState() state %d", state);
- audio_devices_t newDevice = (audio_devices_t)0;
+ audio_devices_t newDevice = AUDIO_DEVICE_NONE;
if (state < 0 || state >= AudioSystem::NUM_MODES) {
ALOGW("setPhoneState() invalid state %d", state);
return;
newDevice = getNewDevice(mPrimaryOutput, false /*fromCache*/);
checkA2dpSuspend();
checkOutputForAllStrategies();
- updateDeviceForStrategy();
+ updateDevicesAndOutputs();
AudioOutputDescriptor *hwOutputDesc = mOutputs.valueFor(mPrimaryOutput);
// force routing command to audio hardware when ending call
// even if no device change is needed
- if (isStateInCall(oldState) && newDevice == 0) {
+ if (isStateInCall(oldState) && newDevice == AUDIO_DEVICE_NONE) {
newDevice = hwOutputDesc->device();
}
setStreamMute(AudioSystem::RING, true, mPrimaryOutput);
}
+ if (isStateInCall(state)) {
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ AudioOutputDescriptor *desc = mOutputs.valueAt(i);
+ //take the biggest latency for all outputs
+ if (delayMs < (int)desc->mLatency*2) {
+ delayMs = desc->mLatency*2;
+ }
+ //mute STRATEGY_MEDIA on all outputs
+ if (desc->strategyRefCount(STRATEGY_MEDIA) != 0) {
+ setStrategyMute(STRATEGY_MEDIA, true, mOutputs.keyAt(i));
+ setStrategyMute(STRATEGY_MEDIA, false, mOutputs.keyAt(i), MUTE_TIME_MS,
+ getDeviceForStrategy(STRATEGY_MEDIA, true /*fromCache*/));
+ }
+ }
+ }
+
// change routing is necessary
setOutputDevice(mPrimaryOutput, newDevice, force, delayMs);
forceVolumeReeval = true;
mForceUse[usage] = config;
break;
+ case AudioSystem::FOR_SYSTEM:
+ if (config != AudioSystem::FORCE_NONE &&
+ config != AudioSystem::FORCE_SYSTEM_ENFORCED) {
+ ALOGW("setForceUse() invalid config %d for FOR_SYSTEM", config);
+ }
+ forceVolumeReeval = true;
+ mForceUse[usage] = config;
+ break;
default:
ALOGW("setForceUse() invalid usage %d", usage);
break;
// check for device and output changes triggered by new force usage
checkA2dpSuspend();
checkOutputForAllStrategies();
- updateDeviceForStrategy();
+ updateDevicesAndOutputs();
for (size_t i = 0; i < mOutputs.size(); i++) {
audio_io_handle_t output = mOutputs.keyAt(i);
audio_devices_t newDevice = getNewDevice(output, true /*fromCache*/);
- setOutputDevice(output, newDevice, true);
- if (forceVolumeReeval) {
+ setOutputDevice(output, newDevice, (newDevice != AUDIO_DEVICE_NONE));
+ if (forceVolumeReeval && (newDevice != AUDIO_DEVICE_NONE)) {
applyStreamVolumes(output, newDevice, 0, true);
}
}
if (activeInput != 0) {
AudioInputDescriptor *inputDesc = mInputs.valueFor(activeInput);
audio_devices_t newDevice = getDeviceForInputSource(inputDesc->mInputSource);
- if ((newDevice != 0) && (newDevice != inputDesc->mDevice)) {
+ if ((newDevice != AUDIO_DEVICE_NONE) && (newDevice != inputDesc->mDevice)) {
ALOGV("setForceUse() changing device from %x to %x for input %d",
inputDesc->mDevice, newDevice, activeInput);
inputDesc->mDevice = newDevice;
void AudioPolicyManagerBase::setSystemProperty(const char* property, const char* value)
{
ALOGV("setSystemProperty() property %s, value %s", property, value);
- if (strcmp(property, "ro.camera.sound.forced") == 0) {
- if (atoi(value)) {
- ALOGV("ENFORCED_AUDIBLE cannot be muted");
- mStreams[AudioSystem::ENFORCED_AUDIBLE].mCanBeMuted = false;
- } else {
- ALOGV("ENFORCED_AUDIBLE can be muted");
- mStreams[AudioSystem::ENFORCED_AUDIBLE].mCanBeMuted = true;
- }
- }
}
AudioPolicyManagerBase::IOProfile *AudioPolicyManagerBase::getProfileForDirectOutput(
// get which output is suitable for the specified stream. The actual routing change will happen
// when startOutput() will be called
- SortedVector<audio_io_handle_t> outputs = getOutputsForDevice(device);
+ SortedVector<audio_io_handle_t> outputs = getOutputsForDevice(device, mOutputs);
output = selectOutput(outputs, flags);
outputDesc->changeRefCount(stream, 1);
if (outputDesc->mRefCount[stream] == 1) {
- audio_devices_t prevDevice = outputDesc->device();
audio_devices_t newDevice = getNewDevice(output, false /*fromCache*/);
routing_strategy strategy = getStrategy(stream);
bool shouldWait = (strategy == STRATEGY_SONIFICATION) ||
}
// wait for audio on other active outputs to be presented when starting
// a notification so that audio focus effect can propagate.
- if (shouldWait && (desc->refCount() != 0) && (waitMs < desc->latency())) {
- waitMs = desc->latency();
+ uint32_t latency = desc->latency();
+ if (shouldWait && desc->isActive(latency * 2) && (waitMs < latency)) {
+ waitMs = latency;
}
}
}
// apply volume rules for current stream and device if necessary
checkAndSetVolume(stream,
- mStreams[stream].getVolumeIndex((audio_devices_t)newDevice),
+ mStreams[stream].getVolumeIndex(newDevice),
output,
newDevice);
mpClientInterface->closeOutput(output);
delete mOutputs.valueAt(index);
mOutputs.removeItem(output);
+ mPreviousOutputs = mOutputs;
}
}
ALOGV("getInput() inputSource %d, samplingRate %d, format %d, channelMask %x, acoustics %x",
inputSource, samplingRate, format, channelMask, acoustics);
- if (device == 0) {
+ if (device == AUDIO_DEVICE_NONE) {
ALOGW("getInput() could not find device for inputSource %d", inputSource);
return 0;
}
status_t status = NO_ERROR;
for (size_t i = 0; i < mOutputs.size(); i++) {
audio_devices_t curDevice =
- getDeviceForVolume((audio_devices_t)mOutputs.valueAt(i)->device());
+ getDeviceForVolume(mOutputs.valueAt(i)->device());
if (device == curDevice) {
status_t volStatus = checkAndSetVolume(stream, index, mOutputs.keyAt(i), curDevice);
if (volStatus != NO_ERROR) {
// if device is AUDIO_DEVICE_OUT_DEFAULT, return volume for device corresponding to
// the strategy the stream belongs to.
if (device == AUDIO_DEVICE_OUT_DEFAULT) {
- device = (audio_devices_t)getDeviceForStrategy(getStrategy(stream), true /*fromCache*/);
+ device = getDeviceForStrategy(getStrategy(stream), true /*fromCache*/);
}
device = getDeviceForVolume(device);
return NO_ERROR;
}
-audio_io_handle_t AudioPolicyManagerBase::getOutputForEffect(effect_descriptor_t *desc)
+audio_io_handle_t AudioPolicyManagerBase::getOutputForEffect(const effect_descriptor_t *desc)
{
ALOGV("getOutputForEffect()");
// apply simple rule where global effects are attached to the same output as MUSIC streams
routing_strategy strategy = getStrategy(AudioSystem::MUSIC);
audio_devices_t device = getDeviceForStrategy(strategy, false /*fromCache*/);
- SortedVector<audio_io_handle_t> dstOutputs = getOutputsForDevice(device);
+ SortedVector<audio_io_handle_t> dstOutputs = getOutputsForDevice(device, mOutputs);
int outIdx = 0;
for (size_t i = 0; i < dstOutputs.size(); i++) {
AudioOutputDescriptor *desc = mOutputs.valueFor(dstOutputs[i]);
return dstOutputs[outIdx];
}
-status_t AudioPolicyManagerBase::registerEffect(effect_descriptor_t *desc,
+status_t AudioPolicyManagerBase::registerEffect(const effect_descriptor_t *desc,
audio_io_handle_t io,
uint32_t strategy,
int session,
return false;
}
+bool AudioPolicyManagerBase::isStreamActiveRemotely(int stream, uint32_t inPastMs) const
+{
+ nsecs_t sysTime = systemTime();
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ const AudioOutputDescriptor *outputDesc = mOutputs.valueAt(i);
+ if ((outputDesc->mRefCount[stream] != 0 ||
+ ns2ms(sysTime - outputDesc->mStopTime[stream]) < inPastMs)
+ && ((outputDesc->device() & APM_AUDIO_OUT_DEVICE_REMOTE_ALL) != 0) ) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool AudioPolicyManagerBase::isSourceActive(audio_source_t source) const
+{
+ for (size_t i = 0; i < mInputs.size(); i++) {
+ const AudioInputDescriptor * inputDescriptor = mInputs.valueAt(i);
+ if ((inputDescriptor->mInputSource == (int) source)
+ && (inputDescriptor->mRefCount > 0)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
status_t AudioPolicyManagerBase::dump(int fd)
{
result.append(buffer);
snprintf(buffer, SIZE, " Force use for dock %d\n", mForceUse[AudioSystem::FOR_DOCK]);
result.append(buffer);
+ snprintf(buffer, SIZE, " Force use for system %d\n", mForceUse[AudioSystem::FOR_SYSTEM]);
+ result.append(buffer);
write(fd, result.string(), result.size());
Thread(false),
#endif //AUDIO_POLICY_TEST
mPrimaryOutput((audio_io_handle_t)0),
- mAvailableOutputDevices((audio_devices_t)0),
+ mAvailableOutputDevices(AUDIO_DEVICE_NONE),
mPhoneState(AudioSystem::MODE_NORMAL),
mLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f),
mTotalEffectsCpuLoad(0), mTotalEffectsMemory(0),
- mA2dpSuspended(false), mHasA2dp(false), mHasUsb(false)
+ mA2dpSuspended(false), mHasA2dp(false), mHasUsb(false), mHasRemoteSubmix(false)
{
mpClientInterface = clientInterface;
ALOGE_IF((mPrimaryOutput == 0), "Failed to open primary output");
- updateDeviceForStrategy();
+ updateDevicesAndOutputs();
#ifdef AUDIO_POLICY_TEST
if (mPrimaryOutput != 0) {
outputCmd.addInt(String8("set_id"), 0);
mpClientInterface->setParameters(mPrimaryOutput, outputCmd.toString());
- mTestDevice = AudioSystem::DEVICE_OUT_SPEAKER;
+ mTestDevice = AUDIO_DEVICE_OUT_SPEAKER;
mTestSamplingRate = 44100;
mTestFormat = AudioSystem::PCM_16_BIT;
mTestChannels = AudioSystem::CHANNEL_OUT_STEREO;
mOutputs.removeItem(mPrimaryOutput);
AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(NULL);
- outputDesc->mDevice = (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER;
+ outputDesc->mDevice = AUDIO_DEVICE_OUT_SPEAKER;
mPrimaryOutput = mpClientInterface->openOutput(moduleHandle,
&outputDesc->mDevice,
&outputDesc->mSamplingRate,
// nothing to do if one output is already opened for this profile
size_t j;
- for (j = 0; j < outputs.size(); j++) {
+ for (j = 0; j < mOutputs.size(); j++) {
desc = mOutputs.valueAt(j);
if (!desc->isDuplicated() && desc->mProfile == profile) {
break;
}
}
- if (j != outputs.size()) {
+ if (j != mOutputs.size()) {
continue;
}
reply.string());
value = strpbrk((char *)reply.string(), "=");
if (value != NULL) {
- loadSamplingRates(value, profile);
+ loadSamplingRates(value + 1, profile);
}
}
if (profile->mFormats[0] == 0) {
reply.string());
value = strpbrk((char *)reply.string(), "=");
if (value != NULL) {
- loadFormats(value, profile);
+ loadFormats(value + 1, profile);
}
}
if (profile->mChannelMasks[0] == 0) {
((profile->mFormats[0] == 0) &&
(profile->mChannelMasks.size() < 2))) {
ALOGW("checkOutputsForDevice() direct output missing param");
+ mpClientInterface->closeOutput(output);
output = 0;
} else {
addOutput(output, desc);
// add output descriptor
addOutput(output, desc);
// set initial stream volume for device
- applyStreamVolumes(output, device);
+ applyStreamVolumes(output, device, 0, true);
//TODO: configure audio effect output stage here
dupOutputDesc->mChannelMask = desc->mChannelMask;
dupOutputDesc->mLatency = desc->mLatency;
addOutput(duplicatedOutput, dupOutputDesc);
- applyStreamVolumes(duplicatedOutput, device);
+ applyStreamVolumes(duplicatedOutput, device, 0, true);
} else {
ALOGW("checkOutputsForDevice() could not open dup output for %d and %d",
mPrimaryOutput, output);
mOutputs.removeItem(output);
}
-SortedVector<audio_io_handle_t> AudioPolicyManagerBase::getOutputsForDevice(audio_devices_t device)
+SortedVector<audio_io_handle_t> AudioPolicyManagerBase::getOutputsForDevice(audio_devices_t device,
+ DefaultKeyedVector<audio_io_handle_t, AudioOutputDescriptor *> openOutputs)
{
SortedVector<audio_io_handle_t> outputs;
ALOGVV("getOutputsForDevice() device %04x", device);
- for (size_t i = 0; i < mOutputs.size(); i++) {
+ for (size_t i = 0; i < openOutputs.size(); i++) {
ALOGVV("output %d isDuplicated=%d device=%04x",
- i, mOutputs.valueAt(i)->isDuplicated(), mOutputs.valueAt(i)->supportedDevices());
- if ((device & mOutputs.valueAt(i)->supportedDevices()) == device) {
- ALOGVV("getOutputsForDevice() found output %d", mOutputs.keyAt(i));
- outputs.add(mOutputs.keyAt(i));
+ i, openOutputs.valueAt(i)->isDuplicated(), openOutputs.valueAt(i)->supportedDevices());
+ if ((device & openOutputs.valueAt(i)->supportedDevices()) == device) {
+ ALOGVV("getOutputsForDevice() found output %d", openOutputs.keyAt(i));
+ outputs.add(openOutputs.keyAt(i));
}
}
return outputs;
{
audio_devices_t oldDevice = getDeviceForStrategy(strategy, true /*fromCache*/);
audio_devices_t newDevice = getDeviceForStrategy(strategy, false /*fromCache*/);
- SortedVector<audio_io_handle_t> srcOutputs = getOutputsForDevice(oldDevice);
- SortedVector<audio_io_handle_t> dstOutputs = getOutputsForDevice(newDevice);
+ SortedVector<audio_io_handle_t> srcOutputs = getOutputsForDevice(oldDevice, mPreviousOutputs);
+ SortedVector<audio_io_handle_t> dstOutputs = getOutputsForDevice(newDevice, mOutputs);
if (!vectorsEqual(srcOutputs,dstOutputs)) {
ALOGV("checkOutputForStrategy() strategy %d, moving from output %d to output %d",
strategy, srcOutputs[0], dstOutputs[0]);
// mute strategy while moving tracks from one output to another
for (size_t i = 0; i < srcOutputs.size(); i++) {
- setStrategyMute(strategy, true, srcOutputs[i]);
- setStrategyMute(strategy, false, srcOutputs[i], MUTE_TIME_MS, newDevice);
+ AudioOutputDescriptor *desc = mOutputs.valueFor(srcOutputs[i]);
+ if (desc->strategyRefCount(strategy) != 0) {
+ setStrategyMute(strategy, true, srcOutputs[i]);
+ setStrategyMute(strategy, false, srcOutputs[i], MUTE_TIME_MS, newDevice);
+ }
}
// Move effects associated to this strategy from previous output to new output
audio_devices_t AudioPolicyManagerBase::getNewDevice(audio_io_handle_t output, bool fromCache)
{
- audio_devices_t device = (audio_devices_t)0;
+ audio_devices_t device = AUDIO_DEVICE_NONE;
AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
// check the following by order of priority to request a routing change if necessary:
// 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 < (AudioSystem::stream_type) 0 || stream >= AudioSystem::NUM_STREAM_TYPES) {
- devices = (audio_devices_t)0;
+ devices = AUDIO_DEVICE_NONE;
} else {
AudioPolicyManagerBase::routing_strategy strategy = getStrategy(stream);
devices = getDeviceForStrategy(strategy, true /*fromCache*/);
switch(stream) {
case AudioSystem::MUSIC:
checkOutputForStrategy(STRATEGY_SONIFICATION_RESPECTFUL);
- updateDeviceForStrategy();
+ updateDevicesAndOutputs();
break;
default:
break;
audio_devices_t AudioPolicyManagerBase::getDeviceForStrategy(routing_strategy strategy,
bool fromCache)
{
- uint32_t device = 0;
+ uint32_t device = AUDIO_DEVICE_NONE;
if (fromCache) {
ALOGVV("getDeviceForStrategy() from cache strategy %d, device %x",
case STRATEGY_SONIFICATION_RESPECTFUL:
if (isInCall()) {
device = getDeviceForStrategy(STRATEGY_SONIFICATION, false /*fromCache*/);
+ } else if (isStreamActiveRemotely(AudioSystem::MUSIC,
+ SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
+ // while media is playing on a remote device, use the the sonification behavior.
+ // Note that we test this usecase before testing if media is playing because
+ // the isStreamActive() method only informs about the activity of a stream, not
+ // if it's for local playback. Note also that we use the same delay between both tests
+ device = getDeviceForStrategy(STRATEGY_SONIFICATION, false /*fromCache*/);
} else if (isStreamActive(AudioSystem::MUSIC, SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
// while media is playing (or has recently played), use the same device
device = getDeviceForStrategy(STRATEGY_MEDIA, false /*fromCache*/);
switch (mForceUse[AudioSystem::FOR_COMMUNICATION]) {
case AudioSystem::FORCE_BT_SCO:
if (!isInCall() || strategy != STRATEGY_DTMF) {
- device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
if (device) break;
}
- device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
if (device) break;
- device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_SCO;
if (device) break;
// if SCO device is requested but no SCO device is available, fall back to default case
// FALL THROUGH
if (mHasA2dp && !isInCall() &&
(mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) &&
(getA2dpOutput() != 0) && !mA2dpSuspended) {
- device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
if (device) break;
- device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
if (device) break;
}
- device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
if (device) break;
- device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADSET;
if (device) break;
- device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY;
- if (device) break;
- device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE;
- if (device) break;
- device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET;
- if (device) break;
- device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_AUX_DIGITAL;
- if (device) break;
- device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET;
- if (device) break;
- device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_EARPIECE;
+ if (mPhoneState != AudioSystem::MODE_IN_CALL) {
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
+ if (device) break;
+ }
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_EARPIECE;
if (device) break;
device = mDefaultOutputDevice;
- if (device == 0) {
+ if (device == AUDIO_DEVICE_NONE) {
ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE");
}
break;
if (mHasA2dp && !isInCall() &&
(mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) &&
(getA2dpOutput() != 0) && !mA2dpSuspended) {
- device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
if (device) break;
}
- device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY;
- if (device) break;
- device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE;
- if (device) break;
- device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET;
- if (device) break;
- device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_AUX_DIGITAL;
- if (device) break;
- device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET;
- if (device) break;
- device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER;
+ if (mPhoneState != AudioSystem::MODE_IN_CALL) {
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
+ if (device) break;
+ }
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER;
if (device) break;
device = mDefaultOutputDevice;
- if (device == 0) {
+ if (device == AUDIO_DEVICE_NONE) {
ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE, FORCE_SPEAKER");
}
break;
// - when in call where it doesn't default to STRATEGY_PHONE behavior
// - in countries where not enforced in which case it follows STRATEGY_MEDIA
- if (strategy == STRATEGY_SONIFICATION ||
- !mStreams[AUDIO_STREAM_ENFORCED_AUDIBLE].mCanBeMuted) {
- device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER;
- if (device == 0) {
+ if ((strategy == STRATEGY_SONIFICATION) ||
+ (mForceUse[AudioSystem::FOR_SYSTEM] == AudioSystem::FORCE_SYSTEM_ENFORCED)) {
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER;
+ if (device == AUDIO_DEVICE_NONE) {
ALOGE("getDeviceForStrategy() speaker device not found for STRATEGY_SONIFICATION");
}
}
// FALL THROUGH
case STRATEGY_MEDIA: {
- uint32_t device2 = 0;
- if (mHasA2dp && (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) &&
+ uint32_t device2 = AUDIO_DEVICE_NONE;
+ if (strategy != STRATEGY_SONIFICATION) {
+ // no sonification on remote submix (e.g. WFD)
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
+ }
+ if ((device2 == AUDIO_DEVICE_NONE) &&
+ mHasA2dp && (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) &&
(getA2dpOutput() != 0) && !mA2dpSuspended) {
- device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP;
- if (device2 == 0) {
- device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
}
- if (device2 == 0) {
- device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
}
}
- if (device2 == 0) {
- device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE;
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
}
- if (device2 == 0) {
- device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET;
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADSET;
}
- if (device2 == 0) {
+ if (device2 == AUDIO_DEVICE_NONE) {
device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY;
}
- if (device2 == 0) {
+ if (device2 == AUDIO_DEVICE_NONE) {
device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE;
}
- if (device2 == 0) {
- device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET;
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
}
- if (device2 == 0) {
- device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_AUX_DIGITAL;
+ if ((device2 == AUDIO_DEVICE_NONE) && (strategy != STRATEGY_SONIFICATION)) {
+ // no sonification on aux digital (e.g. HDMI)
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL;
}
- if (device2 == 0) {
- device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET;
+ if ((device2 == AUDIO_DEVICE_NONE) &&
+ (mForceUse[AudioSystem::FOR_DOCK] == AudioSystem::FORCE_ANALOG_DOCK)) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
}
- if (device2 == 0) {
- device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER;
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER;
}
// device is DEVICE_OUT_SPEAKER if we come from case STRATEGY_SONIFICATION or
- // STRATEGY_ENFORCED_AUDIBLE, 0 otherwise
+ // STRATEGY_ENFORCED_AUDIBLE, AUDIO_DEVICE_NONE otherwise
device |= device2;
if (device) break;
device = mDefaultOutputDevice;
- if (device == 0) {
+ if (device == AUDIO_DEVICE_NONE) {
ALOGE("getDeviceForStrategy() no device found for STRATEGY_MEDIA");
}
} break;
}
ALOGVV("getDeviceForStrategy() strategy %d, device %x", strategy, device);
- return (audio_devices_t)device;
+ return device;
}
-void AudioPolicyManagerBase::updateDeviceForStrategy()
+void AudioPolicyManagerBase::updateDevicesAndOutputs()
{
for (int i = 0; i < NUM_STRATEGIES; i++) {
mDeviceForStrategy[i] = getDeviceForStrategy((routing_strategy)i, false /*fromCache*/);
}
+ mPreviousOutputs = mOutputs;
}
uint32_t AudioPolicyManagerBase::checkDeviceMuteStrategies(AudioOutputDescriptor *outputDesc,
if (doMute || tempMute) {
for (size_t j = 0; j < mOutputs.size(); j++) {
AudioOutputDescriptor *desc = mOutputs.valueAt(j);
- if ((desc->supportedDevices() & outputDesc->supportedDevices()) == 0) {
+ if ((desc->supportedDevices() & outputDesc->supportedDevices())
+ == AUDIO_DEVICE_NONE) {
continue;
}
audio_io_handle_t curOutput = mOutputs.keyAt(j);
ALOGV("setOutputDevice() prevDevice %04x", prevDevice);
- if (device != 0) {
+ if (device != AUDIO_DEVICE_NONE) {
outputDesc->mDevice = device;
}
muteWaitMs = checkDeviceMuteStrategies(outputDesc, prevDevice, delayMs);
// Do not change the routing if:
- // - the requested device is 0
+ // - the requested device is AUDIO_DEVICE_NONE
// - the requested device is the same as current device and force is not specified.
// Doing this check here allows the caller to call setOutputDevice() without conditions
- if ((device == 0 || device == prevDevice) && !force) {
+ if ((device == AUDIO_DEVICE_NONE || device == prevDevice) && !force) {
ALOGV("setOutputDevice() setting same device %04x or null device for output %d", device, output);
return muteWaitMs;
}
audio_devices_t AudioPolicyManagerBase::getDeviceForInputSource(int inputSource)
{
- uint32_t device = 0;
+ uint32_t device = AUDIO_DEVICE_NONE;
switch(inputSource) {
case AUDIO_SOURCE_DEFAULT:
case AUDIO_SOURCE_VOICE_RECOGNITION:
case AUDIO_SOURCE_VOICE_COMMUNICATION:
if (mForceUse[AudioSystem::FOR_RECORD] == AudioSystem::FORCE_BT_SCO &&
- mAvailableInputDevices & AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
- device = AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET;
- } else if (mAvailableInputDevices & AudioSystem::DEVICE_IN_WIRED_HEADSET) {
- device = AudioSystem::DEVICE_IN_WIRED_HEADSET;
- } else if (mAvailableInputDevices & AudioSystem::DEVICE_IN_BUILTIN_MIC) {
- device = AudioSystem::DEVICE_IN_BUILTIN_MIC;
+ mAvailableInputDevices & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
+ device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+ } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+ device = AUDIO_DEVICE_IN_WIRED_HEADSET;
+ } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+ device = AUDIO_DEVICE_IN_BUILTIN_MIC;
}
break;
case AUDIO_SOURCE_CAMCORDER:
- if (mAvailableInputDevices & AudioSystem::DEVICE_IN_BACK_MIC) {
- device = AudioSystem::DEVICE_IN_BACK_MIC;
- } else if (mAvailableInputDevices & AudioSystem::DEVICE_IN_BUILTIN_MIC) {
- device = AudioSystem::DEVICE_IN_BUILTIN_MIC;
+ if (mAvailableInputDevices & AUDIO_DEVICE_IN_BACK_MIC) {
+ device = AUDIO_DEVICE_IN_BACK_MIC;
+ } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+ device = AUDIO_DEVICE_IN_BUILTIN_MIC;
}
break;
case AUDIO_SOURCE_VOICE_UPLINK:
case AUDIO_SOURCE_VOICE_DOWNLINK:
case AUDIO_SOURCE_VOICE_CALL:
- if (mAvailableInputDevices & AudioSystem::DEVICE_IN_VOICE_CALL) {
- device = AudioSystem::DEVICE_IN_VOICE_CALL;
+ if (mAvailableInputDevices & AUDIO_DEVICE_IN_VOICE_CALL) {
+ device = AUDIO_DEVICE_IN_VOICE_CALL;
+ }
+ break;
+ case AUDIO_SOURCE_REMOTE_SUBMIX:
+ if (mAvailableInputDevices & AUDIO_DEVICE_IN_REMOTE_SUBMIX) {
+ device = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
}
break;
default:
break;
}
ALOGV("getDeviceForInputSource()input source %d, device %08x", inputSource, device);
- return (audio_devices_t)device;
+ return device;
+}
+
+bool AudioPolicyManagerBase::isVirtualInputDevice(audio_devices_t device)
+{
+ if ((device & AUDIO_DEVICE_BIT_IN) != 0) {
+ device &= ~AUDIO_DEVICE_BIT_IN;
+ if ((popcount(device) == 1) && ((device & ~APM_AUDIO_IN_DEVICE_VIRTUAL_ALL) == 0))
+ return true;
+ }
+ return false;
}
-audio_io_handle_t AudioPolicyManagerBase::getActiveInput()
+audio_io_handle_t AudioPolicyManagerBase::getActiveInput(bool ignoreVirtualInputs)
{
for (size_t i = 0; i < mInputs.size(); i++) {
- if (mInputs.valueAt(i)->mRefCount > 0) {
+ const AudioInputDescriptor * input_descriptor = mInputs.valueAt(i);
+ if ((input_descriptor->mRefCount > 0)
+ && (!ignoreVirtualInputs || !isVirtualInputDevice(input_descriptor->mDevice))) {
return mInputs.keyAt(i);
}
}
audio_devices_t AudioPolicyManagerBase::getDeviceForVolume(audio_devices_t device)
{
- if (device == 0) {
+ if (device == AUDIO_DEVICE_NONE) {
// this happens when forcing a route update and no track is active on an output.
// In this case the returned category is not important.
device = AUDIO_DEVICE_OUT_SPEAKER;
case AUDIO_DEVICE_OUT_AUX_DIGITAL:
case AUDIO_DEVICE_OUT_USB_ACCESSORY:
case AUDIO_DEVICE_OUT_USB_DEVICE:
+ case AUDIO_DEVICE_OUT_REMOTE_SUBMIX:
default:
return DEVICE_CATEGORY_SPEAKER;
}
// AUDIO_STREAM_SYSTEM, AUDIO_STREAM_ENFORCED_AUDIBLE and AUDIO_STREAM_DTMF volume tracks
// AUDIO_STREAM_RING on phones and AUDIO_STREAM_MUSIC on tablets (See AudioService.java).
-// The range is constrained between -30dB and -12dB over speaker and -30dB and -18dB over headset.
+// The range is constrained between -24dB and -6dB over speaker and -30dB and -18dB over headset.
const AudioPolicyManagerBase::VolumeCurvePoint
AudioPolicyManagerBase::sDefaultSystemVolumeCurve[AudioPolicyManagerBase::VOLCNT] = {
- {1, -30.0f}, {33, -24.0f}, {66, -18.0f}, {100, -12.0f}
+ {1, -24.0f}, {33, -18.0f}, {66, -12.0f}, {100, -6.0f}
};
const AudioPolicyManagerBase::VolumeCurvePoint
};
const AudioPolicyManagerBase::VolumeCurvePoint
+ AudioPolicyManagerBase::sDefaultVoiceVolumeCurve[AudioPolicyManagerBase::VOLCNT] = {
+ {0, -42.0f}, {33, -28.0f}, {66, -14.0f}, {100, 0.0f}
+};
+
+const AudioPolicyManagerBase::VolumeCurvePoint
+ AudioPolicyManagerBase::sSpeakerVoiceVolumeCurve[AudioPolicyManagerBase::VOLCNT] = {
+ {0, -24.0f}, {33, -16.0f}, {66, -8.0f}, {100, 0.0f}
+};
+
+const AudioPolicyManagerBase::VolumeCurvePoint
*AudioPolicyManagerBase::sVolumeProfiles[AUDIO_STREAM_CNT]
[AudioPolicyManagerBase::DEVICE_CATEGORY_CNT] = {
{ // AUDIO_STREAM_VOICE_CALL
- sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET
- sDefaultVolumeCurve, // DEVICE_CATEGORY_SPEAKER
- sDefaultVolumeCurve // DEVICE_CATEGORY_EARPIECE
+ sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ sSpeakerVoiceVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ sDefaultVoiceVolumeCurve // DEVICE_CATEGORY_EARPIECE
},
{ // AUDIO_STREAM_SYSTEM
sHeadsetSystemVolumeCurve, // DEVICE_CATEGORY_HEADSET
sDefaultVolumeCurve // DEVICE_CATEGORY_EARPIECE
},
{ // AUDIO_STREAM_BLUETOOTH_SCO
- sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET
- sDefaultVolumeCurve, // DEVICE_CATEGORY_SPEAKER
- sDefaultVolumeCurve // DEVICE_CATEGORY_EARPIECE
+ sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ sSpeakerVoiceVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ sDefaultVoiceVolumeCurve // DEVICE_CATEGORY_EARPIECE
},
{ // AUDIO_STREAM_ENFORCED_AUDIBLE
sHeadsetSystemVolumeCurve, // DEVICE_CATEGORY_HEADSET
AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
StreamDescriptor &streamDesc = mStreams[stream];
- if (device == 0) {
+ if (device == AUDIO_DEVICE_NONE) {
device = outputDesc->device();
}
// - if music is playing, always limit the volume to current music volume,
// with a minimum threshold at -36dB so that notification is always perceived.
const routing_strategy stream_strategy = getStrategy((AudioSystem::stream_type)stream);
- if ((device & (AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP |
- AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
- AudioSystem::DEVICE_OUT_WIRED_HEADSET |
- AudioSystem::DEVICE_OUT_WIRED_HEADPHONE)) &&
+ if ((device & (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
+ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
+ AUDIO_DEVICE_OUT_WIRED_HEADSET |
+ AUDIO_DEVICE_OUT_WIRED_HEADPHONE)) &&
((stream_strategy == STRATEGY_SONIFICATION)
|| (stream_strategy == STRATEGY_SONIFICATION_RESPECTFUL)
- || (stream == AudioSystem::SYSTEM)) &&
+ || (stream == AudioSystem::SYSTEM)
+ || ((stream_strategy == STRATEGY_ENFORCED_AUDIBLE) &&
+ (mForceUse[AudioSystem::FOR_SYSTEM] == AudioSystem::FORCE_NONE))) &&
streamDesc.mCanBeMuted) {
volume *= SONIFICATION_HEADSET_VOLUME_FACTOR;
// when the phone is ringing we must consider that music could have been paused just before
// by the music application and behave as if music was active if the last music track was
// just stopped
- if (outputDesc->mRefCount[AudioSystem::MUSIC] || mLimitRingtoneVolume) {
+ if (isStreamActive(AudioSystem::MUSIC, SONIFICATION_HEADSET_MUSIC_DELAY) ||
+ mLimitRingtoneVolume) {
+ audio_devices_t musicDevice = getDeviceForStrategy(STRATEGY_MEDIA, true /*fromCache*/);
float musicVol = computeVolume(AudioSystem::MUSIC,
- mStreams[AudioSystem::MUSIC].getVolumeIndex(device),
+ mStreams[AudioSystem::MUSIC].getVolumeIndex(musicDevice),
output,
- device);
+ musicDevice);
float minVol = (musicVol > SONIFICATION_HEADSET_VOLUME_MIN) ?
musicVol : SONIFICATION_HEADSET_VOLUME_MIN;
if (volume > minVol) {
force) {
mOutputs.valueFor(output)->mCurVolume[stream] = volume;
ALOGVV("checkAndSetVolume() for output %d stream %d, volume %f, delay %d", output, stream, volume, delayMs);
- if (stream == AudioSystem::VOICE_CALL ||
- stream == AudioSystem::DTMF ||
- stream == AudioSystem::BLUETOOTH_SCO) {
- // offset value to reflect actual hardware volume that never reaches 0
- // 1% corresponds roughly to first step in VOICE_CALL stream volume setting (see AudioService.java)
- volume = 0.01 + 0.99 * volume;
- // Force VOICE_CALL to track BLUETOOTH_SCO stream volume when bluetooth audio is
- // enabled
- if (stream == AudioSystem::BLUETOOTH_SCO) {
- mpClientInterface->setStreamVolume(AudioSystem::VOICE_CALL, volume, output, delayMs);
- }
+ // Force VOICE_CALL to track BLUETOOTH_SCO stream volume when bluetooth audio is
+ // enabled
+ if (stream == AudioSystem::BLUETOOTH_SCO) {
+ mpClientInterface->setStreamVolume(AudioSystem::VOICE_CALL, volume, output, delayMs);
}
-
mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output, delayMs);
}
{
StreamDescriptor &streamDesc = mStreams[stream];
AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
- if (device == 0) {
+ if (device == AUDIO_DEVICE_NONE) {
device = outputDesc->device();
}
if (on) {
if (outputDesc->mMuteCount[stream] == 0) {
- if (streamDesc.mCanBeMuted) {
+ if (streamDesc.mCanBeMuted &&
+ ((stream != AudioSystem::ENFORCED_AUDIBLE) ||
+ (mForceUse[AudioSystem::FOR_SYSTEM] == AudioSystem::FORCE_NONE))) {
checkAndSetVolume(stream, 0, output, device, delayMs);
}
}
}
if (--outputDesc->mMuteCount[stream] == 0) {
checkAndSetVolume(stream,
- streamDesc.getVolumeIndex((audio_devices_t)device),
+ streamDesc.getVolumeIndex(device),
output,
device,
delayMs);
const IOProfile *profile)
: mId(0), mSamplingRate(0), mFormat((audio_format_t)0),
mChannelMask((audio_channel_mask_t)0), mLatency(0),
- mFlags((audio_output_flags_t)0), mDevice((audio_devices_t)0),
+ mFlags((audio_output_flags_t)0), mDevice(AUDIO_DEVICE_NONE),
mOutput1(0), mOutput2(0), mProfile(profile)
{
// clear usage count for all stream types
mMuteCount[i] = 0;
mStopTime[i] = 0;
}
+ for (int i = 0; i < NUM_STRATEGIES; i++) {
+ mStrategyMutedByDevice[i] = false;
+ }
if (profile != NULL) {
mSamplingRate = profile->mSamplingRates[0];
mFormat = profile->mFormats[0];
}
}
-audio_devices_t AudioPolicyManagerBase::AudioOutputDescriptor::device()
+audio_devices_t AudioPolicyManagerBase::AudioOutputDescriptor::device() const
{
if (isDuplicated()) {
return (audio_devices_t)(mOutput1->mDevice | mOutput2->mDevice);
}
}
+bool AudioPolicyManagerBase::AudioOutputDescriptor::isActive(uint32_t inPastMs) const
+{
+ nsecs_t sysTime = systemTime();
+ for (int i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) {
+ if (mRefCount[i] != 0 ||
+ ns2ms(sysTime - mStopTime[i]) < inPastMs) {
+ return true;
+ }
+ }
+ return false;
+}
+
status_t AudioPolicyManagerBase::AudioOutputDescriptor::dump(int fd)
{
const size_t SIZE = 256;
AudioPolicyManagerBase::AudioInputDescriptor::AudioInputDescriptor(const IOProfile *profile)
: mSamplingRate(0), mFormat((audio_format_t)0), mChannelMask((audio_channel_mask_t)0),
- mDevice((audio_devices_t)0), mRefCount(0),
+ mDevice(AUDIO_DEVICE_NONE), mRefCount(0),
mInputSource(0), mProfile(profile)
{
}
STRING_TO_ENUM(AUDIO_DEVICE_OUT_USB_DEVICE),
STRING_TO_ENUM(AUDIO_DEVICE_OUT_USB_ACCESSORY),
STRING_TO_ENUM(AUDIO_DEVICE_OUT_ALL_USB),
+ STRING_TO_ENUM(AUDIO_DEVICE_OUT_REMOTE_SUBMIX),
STRING_TO_ENUM(AUDIO_DEVICE_IN_BUILTIN_MIC),
STRING_TO_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET),
STRING_TO_ENUM(AUDIO_DEVICE_IN_WIRED_HEADSET),
STRING_TO_ENUM(AUDIO_DEVICE_IN_AUX_DIGITAL),
STRING_TO_ENUM(AUDIO_DEVICE_IN_VOICE_CALL),
STRING_TO_ENUM(AUDIO_DEVICE_IN_BACK_MIC),
+ STRING_TO_ENUM(AUDIO_DEVICE_IN_REMOTE_SUBMIX),
+ STRING_TO_ENUM(AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET),
+ STRING_TO_ENUM(AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET),
+ STRING_TO_ENUM(AUDIO_DEVICE_IN_USB_ACCESSORY),
};
const struct StringToEnum sFlagNameToEnumTable[] = {
const struct StringToEnum sInChannelsNameToEnumTable[] = {
STRING_TO_ENUM(AUDIO_CHANNEL_IN_MONO),
STRING_TO_ENUM(AUDIO_CHANNEL_IN_STEREO),
+ STRING_TO_ENUM(AUDIO_CHANNEL_IN_FRONT_BACK),
};
}
devName = strtok(NULL, "|");
}
- return (audio_devices_t)device;
+ return device;
}
void AudioPolicyManagerBase::loadSamplingRates(char *name, IOProfile *profile)
}
node = node->next;
}
- ALOGW_IF(profile->mSupportedDevices == (audio_devices_t)0,
+ ALOGW_IF(profile->mSupportedDevices == AUDIO_DEVICE_NONE,
"loadInput() invalid supported devices");
ALOGW_IF(profile->mChannelMasks.size() == 0,
"loadInput() invalid supported channel masks");
"loadInput() invalid supported sampling rates");
ALOGW_IF(profile->mFormats.size() == 0,
"loadInput() invalid supported formats");
- if ((profile->mSupportedDevices != (audio_devices_t)0) &&
+ if ((profile->mSupportedDevices != AUDIO_DEVICE_NONE) &&
(profile->mChannelMasks.size() != 0) &&
(profile->mSamplingRates.size() != 0) &&
(profile->mFormats.size() != 0)) {
}
node = node->next;
}
- ALOGW_IF(profile->mSupportedDevices == (audio_devices_t)0,
+ ALOGW_IF(profile->mSupportedDevices == AUDIO_DEVICE_NONE,
"loadOutput() invalid supported devices");
ALOGW_IF(profile->mChannelMasks.size() == 0,
"loadOutput() invalid supported channel masks");
"loadOutput() invalid supported sampling rates");
ALOGW_IF(profile->mFormats.size() == 0,
"loadOutput() invalid supported formats");
- if ((profile->mSupportedDevices != (audio_devices_t)0) &&
+ if ((profile->mSupportedDevices != AUDIO_DEVICE_NONE) &&
(profile->mChannelMasks.size() != 0) &&
(profile->mSamplingRates.size() != 0) &&
(profile->mFormats.size() != 0)) {
mHasA2dp = true;
} else if (strcmp(root->name, AUDIO_HARDWARE_MODULE_ID_USB) == 0) {
mHasUsb = true;
+ } else if (strcmp(root->name, AUDIO_HARDWARE_MODULE_ID_REMOTE_SUBMIX) == 0) {
+ mHasRemoteSubmix = true;
}
node = node->first_child;
while (node) {
if (strcmp(ATTACHED_OUTPUT_DEVICES_TAG, node->name) == 0) {
mAttachedOutputDevices = parseDeviceNames((char *)node->value);
- ALOGW_IF(mAttachedOutputDevices == 0, "loadGlobalConfig() no attached output devices");
+ ALOGW_IF(mAttachedOutputDevices == AUDIO_DEVICE_NONE,
+ "loadGlobalConfig() no attached output devices");
ALOGV("loadGlobalConfig() mAttachedOutputDevices %04x", mAttachedOutputDevices);
} else if (strcmp(DEFAULT_OUTPUT_DEVICE_TAG, node->name) == 0) {
mDefaultOutputDevice = (audio_devices_t)stringToEnum(sDeviceNameToEnumTable,
ARRAY_SIZE(sDeviceNameToEnumTable),
(char *)node->value);
- ALOGW_IF(mDefaultOutputDevice == 0, "loadGlobalConfig() default device not specified");
+ ALOGW_IF(mDefaultOutputDevice == AUDIO_DEVICE_NONE,
+ "loadGlobalConfig() default device not specified");
ALOGV("loadGlobalConfig() mDefaultOutputDevice %04x", mDefaultOutputDevice);
} else if (strcmp(ATTACHED_INPUT_DEVICES_TAG, node->name) == 0) {
- mAvailableInputDevices = parseDeviceNames((char *)node->value);
+ mAvailableInputDevices = parseDeviceNames((char *)node->value) & ~AUDIO_DEVICE_BIT_IN;
ALOGV("loadGlobalConfig() mAvailableInputDevices %04x", mAvailableInputDevices);
}
node = node->next;
mDefaultOutputDevice = AUDIO_DEVICE_OUT_SPEAKER;
mAttachedOutputDevices = AUDIO_DEVICE_OUT_SPEAKER;
- mAvailableInputDevices = AUDIO_DEVICE_IN_BUILTIN_MIC;
+ mAvailableInputDevices = AUDIO_DEVICE_IN_BUILTIN_MIC & ~AUDIO_DEVICE_BIT_IN;
module = new HwModule("primary");