if (outputDesc->mRefCount[stream] == 1) {
audio_devices_t prevDevice = outputDesc->device();
audio_devices_t newDevice = getNewDevice(output, false /*fromCache*/);
-
- // force a device change if any other output is active, is managed by the same and hw
- // module and has a current device selection that differs from newly selected device.
- // In this case, the audio HAL must receive the new device selection so that it can
- // change the device currently selected by the other active output.
+ routing_strategy strategy = getStrategy(stream);
+ bool shouldWait = (strategy == STRATEGY_SONIFICATION) ||
+ (strategy == STRATEGY_SONIFICATION_RESPECTFUL);
+ uint32_t waitMs = 0;
bool force = false;
for (size_t i = 0; i < mOutputs.size(); i++) {
AudioOutputDescriptor *desc = mOutputs.valueAt(i);
- if (output != mOutputs.keyAt(i) &&
- desc->refCount() != 0 &&
- outputDesc->sharesHwModuleWith(desc) &&
+ if (desc != outputDesc) {
+ // force a device change if any other output is managed by the same hw
+ // module and has a current device selection that differs from selected device.
+ // In this case, the audio HAL must receive the new device selection so that it can
+ // change the device currently selected by the other active output.
+ if (outputDesc->sharesHwModuleWith(desc) &&
desc->device() != newDevice) {
- force = true;
- break;
+ force = true;
+ }
+ // 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();
+ }
}
}
- setOutputDevice(output, newDevice, force);
+ uint32_t muteWaitMs = setOutputDevice(output, newDevice, force);
// handle special case for sonification while in call
if (isInCall()) {
// update the outputs if starting an output with a stream that can affect notification
// routing
handleNotificationRoutingForStream(stream);
+ if (waitMs > muteWaitMs) {
+ usleep((waitMs - muteWaitMs) * 2 * 1000);
+ }
}
return NO_ERROR;
}
}
}
-void AudioPolicyManagerBase::checkDeviceMuteStrategies(AudioOutputDescriptor *outputDesc,
+uint32_t AudioPolicyManagerBase::checkDeviceMuteStrategies(AudioOutputDescriptor *outputDesc,
uint32_t delayMs)
{
- // mute/unmute strategies using an incompatible device combination
- // if muting, wait for the audio in pcm buffer to be drained before proceeding
- // if unmuting, unmute only after the specified delay
-
if (outputDesc->isDuplicated()) {
- return;
+ return 0;
}
uint32_t muteWaitMs = 0;
muteWaitMs *= 2;
// wait for the PCM output buffers to empty before proceeding with the rest of the command
if (muteWaitMs > delayMs) {
- usleep((muteWaitMs - delayMs)*1000);
+ muteWaitMs -= delayMs;
+ usleep(muteWaitMs * 1000);
+ return muteWaitMs;
}
+ return 0;
}
-void AudioPolicyManagerBase::setOutputDevice(audio_io_handle_t output,
+uint32_t AudioPolicyManagerBase::setOutputDevice(audio_io_handle_t output,
audio_devices_t device,
bool force,
int delayMs)
ALOGV("setOutputDevice() output %d device %04x delayMs %d", output, device, delayMs);
AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
AudioParameter param;
+ uint32_t muteWaitMs = 0;
if (outputDesc->isDuplicated()) {
- setOutputDevice(outputDesc->mOutput1->mId, device, force, delayMs);
- setOutputDevice(outputDesc->mOutput2->mId, device, force, delayMs);
- return;
+ muteWaitMs = setOutputDevice(outputDesc->mOutput1->mId, device, force, delayMs);
+ muteWaitMs += setOutputDevice(outputDesc->mOutput2->mId, device, force, delayMs);
+ return muteWaitMs;
}
// filter devices according to output selected
device = (audio_devices_t)(device & outputDesc->mProfile->mSupportedDevices);
if (device != 0) {
outputDesc->mDevice = device;
}
- checkDeviceMuteStrategies(outputDesc, delayMs);
+ muteWaitMs = checkDeviceMuteStrategies(outputDesc, delayMs);
// Do not change the routing if:
// - the requested device is 0
// Doing this check here allows the caller to call setOutputDevice() without conditions
if ((device == 0 || device == prevDevice) && !force) {
ALOGV("setOutputDevice() setting same device %04x or null device for output %d", device, output);
- return;
+ return muteWaitMs;
}
ALOGV("setOutputDevice() changing device");
// update stream volumes according to new device
applyStreamVolumes(output, device, delayMs);
+
+ return muteWaitMs;
}
AudioPolicyManagerBase::IOProfile *AudioPolicyManagerBase::getInputProfile(audio_devices_t device,
const struct StringToEnum sFlagNameToEnumTable[] = {
STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DIRECT),
STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_PRIMARY),
+ STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_FAST),
+ STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DEEP_BUFFER),
};
const struct StringToEnum sFormatNameToEnumTable[] = {
virtual audio_devices_t getDeviceForStrategy(routing_strategy strategy,
bool fromCache);
- // change the route of the specified output
- void setOutputDevice(audio_io_handle_t output,
+ // change the route of the specified output. Returns the number of ms we have slept to
+ // allow new routing to take effect in certain cases.
+ uint32_t setOutputDevice(audio_io_handle_t output,
audio_devices_t device,
bool force = false,
int delayMs = 0);
bool vectorsEqual(SortedVector<audio_io_handle_t>& outputs1,
SortedVector<audio_io_handle_t>& outputs2);
- void checkDeviceMuteStrategies(AudioOutputDescriptor *outputDesc,
+ // mute/unmute strategies using an incompatible device combination
+ // if muting, wait for the audio in pcm buffer to be drained before proceeding
+ // if unmuting, unmute only after the specified delay
+ // Returns the number of ms waited
+ uint32_t checkDeviceMuteStrategies(AudioOutputDescriptor *outputDesc,
uint32_t delayMs);
audio_io_handle_t selectOutput(const SortedVector<audio_io_handle_t>& outputs,