@ -1084,7 +1084,7 @@ status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr,
new TrackClientDescriptor ( * portId , uid , session , resultAttr , clientConfig ,
sanitizedRequestedPortId , * stream ,
mEngine - > getProductStrategyForAttributes ( resultAttr ) ,
s treamT oVolumeSource( * stream ) ,
toVolumeSource( re sultAt tr) ,
* flags , isRequestedDeviceForExclusiveUse ,
std : : move ( weakSecondaryOutputDescs ) ) ;
sp < SwAudioOutputDescriptor > outputDesc = mOutputs . valueFor ( * output ) ;
@ -1694,8 +1694,9 @@ status_t AudioPolicyManager::startSource(const sp<SwAudioOutputDescriptor>& outp
setOutputDevices ( outputDesc , devices , force , 0 , NULL , requiresMuteCheck ) ;
// apply volume rules for current stream and device if necessary
checkAndSetVolume ( stream ,
getVolumeCurves ( stream ) . getVolumeIndex ( outputDesc - > devices ( ) . types ( ) ) ,
auto & curves = getVolumeCurves ( client - > attributes ( ) ) ;
checkAndSetVolume ( curves , client - > volumeSource ( ) ,
curves . getVolumeIndex ( outputDesc - > devices ( ) . types ( ) ) ,
outputDesc ,
outputDesc - > devices ( ) . types ( ) ) ;
@ -2384,107 +2385,27 @@ status_t AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream,
int index ,
audio_devices_t device )
{
auto & curves = getVolumeCurves ( stream ) ;
// VOICE_CALL and BLUETOOTH_SCO stream have minVolumeIndex > 0 but
// can be muted directly by an app that has MODIFY_PHONE_STATE permission.
if ( ( ( index < curves . getVolumeIndexMin ( ) ) & &
! ( ( stream = = AUDIO_STREAM_VOICE_CALL | | stream = = AUDIO_STREAM_BLUETOOTH_SCO ) & &
index = = 0 ) ) | |
( index > curves . getVolumeIndexMax ( ) ) ) {
return BAD_VALUE ;
}
if ( ! audio_is_output_device ( device ) ) {
auto attributes = mEngine - > getAttributesForStreamType ( stream ) ;
auto volumeGroup = mEngine - > getVolumeGroupForStreamType ( stream ) ;
if ( volumeGroup = = VOLUME_GROUP_NONE ) {
ALOGE ( " %s: no group matching with stream %s " , __FUNCTION__ , toString ( stream ) . c_str ( ) ) ;
return BAD_VALUE ;
}
// Force max volume if stream cannot be muted
if ( ! curves . canBeMuted ( ) ) index = curves . getVolumeIndexMax ( ) ;
ALOGV ( " setStreamVolumeIndex() stream %d, device %08x, index %d " ,
stream , device , index ) ;
// update other private stream volumes which follow this one
for ( int curStream = 0 ; curStream < AUDIO_STREAM_FOR_POLICY_CNT ; curStream + + ) {
if ( ! streamsMatchForvolume ( stream , ( audio_stream_type_t ) curStream ) ) {
continue ;
}
auto & curCurves = getVolumeCurves ( static_cast < audio_stream_type_t > ( curStream ) ) ;
curCurves . addCurrentVolumeIndex ( device , index ) ;
}
// update volume on all outputs and streams matching the following:
// - The requested stream (or a stream matching for volume control) is active on the output
// - The device (or devices) selected by the engine for this stream includes
// the requested device
// - For non default requested device, currently selected device on the output is either the
// requested device or one of the devices selected by the engine for this stream
// - For default requested device (AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME), apply volume only if
// no specific device volume value exists for currently selected device.
status_t status = NO_ERROR ;
for ( size_t i = 0 ; i < mOutputs . size ( ) ; i + + ) {
sp < SwAudioOutputDescriptor > desc = mOutputs . valueAt ( i ) ;
audio_devices_t curDevice = desc - > devices ( ) . types ( ) ;
for ( int curStream = 0 ; curStream < AUDIO_STREAM_FOR_POLICY_CNT ; curStream + + ) {
if ( ! ( streamsMatchForvolume ( stream , ( audio_stream_type_t ) curStream ) ) ) {
continue ;
}
if ( ! ( desc - > isActive ( streamToVolumeSource ( ( audio_stream_type_t ) curStream ) ) | | isInCall ( ) ) ) {
continue ;
}
audio_devices_t curStreamDevice = Volume : : getDeviceForVolume (
mEngine - > getOutputDevicesForStream ( ( audio_stream_type_t ) curStream ,
false /*fromCache*/ ) . types ( ) ) ;
if ( ( device ! = AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME ) & &
( ( curStreamDevice & device ) = = 0 ) ) {
continue ;
}
bool applyVolume ;
if ( device ! = AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME ) {
curStreamDevice | = device ;
applyVolume = ( Volume : : getDeviceForVolume ( curDevice ) & curStreamDevice ) ! = 0 ;
} else {
applyVolume = ! curves . hasVolumeIndexForDevice ( curStreamDevice ) ;
}
// rescale index before applying to curStream as ranges may be different for
// stream and curStream
int idx = rescaleVolumeIndex ( index , stream , ( audio_stream_type_t ) curStream ) ;
if ( applyVolume ) {
//FIXME: workaround for truncated touch sounds
// delayed volume change for system stream to be removed when the problem is
// handled by system UI
status_t volStatus = checkAndSetVolume (
( audio_stream_type_t ) curStream , idx , desc , curDevice ,
( stream = = AUDIO_STREAM_SYSTEM ) ?
TOUCH_SOUND_FIXED_DELAY_MS : 0 ) ;
if ( volStatus ! = NO_ERROR ) {
status = volStatus ;
}
}
}
}
return status ;
ALOGV ( " %s: stream %s attributes=%s " , __func__ ,
toString ( stream ) . c_str ( ) , toString ( attributes ) . c_str ( ) ) ;
return setVolumeGroupIndex ( getVolumeCurves ( stream ) , volumeGroup , index , device , attributes ) ;
}
status_t AudioPolicyManager : : getStreamVolumeIndex ( audio_stream_type_t stream ,
int * index ,
audio_devices_t device )
int * index ,
audio_devices_t device )
{
if ( index = = NULL ) {
return BAD_VALUE ;
}
if ( ! audio_is_output_device ( device ) ) {
return BAD_VALUE ;
}
// if device is AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME, return volume for device selected for this
// stream by the engine.
if ( device = = AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME ) {
device = mEngine - > getOutputDevicesForStream ( stream , true /*fromCache*/ ) . types ( ) ;
}
device = Volume : : getDeviceForVolume ( device ) ;
* index = getVolumeCurves ( stream ) . getVolumeIndex ( device ) ;
ALOGV ( " getStreamVolumeIndex() stream %d device %08x index %d " , stream , device , * index ) ;
return NO_ERROR ;
return getVolumeIndex ( getVolumeCurves ( stream ) , * index , device ) ;
}
status_t AudioPolicyManager : : setVolumeIndexForAttributes ( const audio_attributes_t & attr ,
@ -2497,18 +2418,25 @@ status_t AudioPolicyManager::setVolumeIndexForAttributes(const audio_attributes_
ALOGD ( " %s: could not find group matching with %s " , __FUNCTION__ , toString ( attr ) . c_str ( ) ) ;
return BAD_VALUE ;
}
ALOG D( " %s: FOUND group %d matching with %s" , __FUNCTION__ , volumeGroup , toString ( attr ) . c_str ( ) ) ;
ALOG V( " %s: group %d matching with %s" , __FUNCTION__ , volumeGroup , toString ( attr ) . c_str ( ) ) ;
return setVolumeGroupIndex ( getVolumeCurves ( attr ) , volumeGroup , index , device , attr ) ;
}
status_t AudioPolicyManager : : setVolumeGroupIndex ( IVolumeCurves & curves , volume_group_t group ,
int index ,
audio_devices_t device ,
const audio_attributes_t /*attributes*/ )
const audio_attributes_t attributes )
{
ALOGVV ( " %s: group=%d " , __func__ , group ) ;
status_t status = NO_ERROR ;
setVolumeCurveIndex ( group , index , device , curves ) ;
VolumeSource vs = toVolumeSource ( group ) ;
product_strategy_t strategy = mEngine - > getProductStrategyForAttributes ( attributes ) ;
status = setVolumeCurveIndex ( index , device , curves ) ;
if ( status ! = NO_ERROR ) {
ALOGE ( " %s failed to set curve index for group %d device 0x%X " , __func__ , group , device ) ;
return status ;
}
// update volume on all outputs and streams matching the following:
// - The requested stream (or a stream matching for volume control) is active on the output
// - The device (or devices) selected by the engine for this stream includes
@ -2517,21 +2445,116 @@ status_t AudioPolicyManager::setVolumeGroupIndex(IVolumeCurves &curves, volume_g
// requested device or one of the devices selected by the engine for this stream
// - For default requested device (AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME), apply volume only if
// no specific device volume value exists for currently selected device.
// @TODO
for ( size_t i = 0 ; i < mOutputs . size ( ) ; i + + ) {
sp < SwAudioOutputDescriptor > desc = mOutputs . valueAt ( i ) ;
audio_devices_t curDevice = Volume : : getDeviceForVolume ( desc - > devices ( ) . types ( ) ) ;
// Inter / intra volume group priority management: Loop on strategies arranged by priority
// If a higher priority strategy is active, and the output is routed to a device with a
// HW Gain management, do not change the volume
bool applyVolume = false ;
if ( desc - > useHwGain ( ) ) {
if ( ! ( desc - > isActive ( group ) | | isInCall ( ) ) ) {
continue ;
}
for ( const auto & productStrategy : mEngine - > getOrderedProductStrategies ( ) ) {
auto activeClients = desc - > clientsList ( true /*activeOnly*/ , productStrategy ,
false /*preferredDevice*/ ) ;
if ( activeClients . empty ( ) ) {
continue ;
}
bool isPreempted = false ;
bool isHigherPriority = productStrategy < strategy ;
for ( const auto & client : activeClients ) {
if ( isHigherPriority & & ( client - > volumeSource ( ) ! = vs ) ) {
ALOGV ( " %s: Strategy=%d ( \n requester: \n "
" group %d, volumeGroup=%d attributes=%s) \n "
" higher priority source active: \n "
" volumeGroup=%d attributes=%s) \n "
" on output %zu, bailing out " , __func__ , productStrategy ,
group , group , toString ( attributes ) . c_str ( ) ,
client - > volumeSource ( ) , toString ( client - > attributes ( ) ) . c_str ( ) , i ) ;
applyVolume = false ;
isPreempted = true ;
break ;
}
// However, continue for loop to ensure no higher prio clients running on output
if ( client - > volumeSource ( ) = = vs ) {
applyVolume = true ;
}
}
if ( isPreempted | | applyVolume ) {
break ;
}
}
if ( ! applyVolume ) {
continue ; // next output
}
status_t volStatus = checkAndSetVolume ( curves , vs , index , desc , curDevice ,
( vs = = toVolumeSource ( AUDIO_STREAM_SYSTEM ) ?
TOUCH_SOUND_FIXED_DELAY_MS : 0 ) ) ;
if ( volStatus ! = NO_ERROR ) {
status = volStatus ;
}
continue ;
}
for ( auto curVolGroup : getVolumeGroups ( ) ) {
VolumeSource curVolSrc = toVolumeSource ( curVolGroup ) ;
if ( ! ( curVolSrc = = vs | | isInCall ( ) ) ) {
continue ;
}
if ( ! ( desc - > isActive ( vs ) | | isInCall ( ) ) ) {
continue ;
}
audio_devices_t curSrcDevice ;
auto & curCurves = getVolumeCurves ( curVolSrc ) ;
auto curCurvAttrs = curCurves . getAttributes ( ) ;
if ( ! curCurvAttrs . empty ( ) & & curCurvAttrs . front ( ) ! = defaultAttr ) {
auto attr = curCurvAttrs . front ( ) ;
curSrcDevice = mEngine - > getOutputDevicesForAttributes ( attr , nullptr , false ) . types ( ) ;
} else if ( ! curCurves . getStreamTypes ( ) . empty ( ) ) {
auto stream = curCurves . getStreamTypes ( ) . front ( ) ;
curSrcDevice = mEngine - > getOutputDevicesForStream ( stream , false ) . types ( ) ;
} else {
ALOGE ( " %s: Invalid src %d: no valid attributes nor stream " , __func__ , curVolSrc ) ;
continue ;
}
curSrcDevice = Volume : : getDeviceForVolume ( curSrcDevice ) ;
if ( ( device ! = AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME ) & & ( ( curDevice & device ) = = 0 ) ) {
continue ;
}
if ( device ! = AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME ) {
curSrcDevice | = device ;
applyVolume = ( curDevice & curSrcDevice ) ! = 0 ;
} else {
applyVolume = ! curves . hasVolumeIndexForDevice ( curSrcDevice ) ;
}
if ( applyVolume ) {
//FIXME: workaround for truncated touch sounds
// delayed volume change for system stream to be removed when the problem is
// handled by system UI
status_t volStatus = checkAndSetVolume (
curCurves , curVolSrc , index , desc , curDevice ,
( ( vs = = toVolumeSource ( AUDIO_STREAM_SYSTEM ) ) ?
TOUCH_SOUND_FIXED_DELAY_MS : 0 ) ) ;
if ( volStatus ! = NO_ERROR ) {
status = volStatus ;
}
}
}
}
mpClientInterface - > onAudioVolumeGroupChanged ( group , 0 /*flags*/ ) ;
return status ;
}
status_t AudioPolicyManager : : setVolumeCurveIndex ( volume_group_t volumeGroup ,
int index ,
status_t AudioPolicyManager : : setVolumeCurveIndex ( int index ,
audio_devices_t device ,
IVolumeCurves & volumeCurves )
{
// VOICE_CALL stream has minVolumeIndex > 0 but can be muted directly by an
// app that has MODIFY_PHONE_STATE permission.
// If voice is member of the volume group, it will contaminate all the member of this group
auto streams = mEngine - > getStreamTypesForVolumeGroup ( volumeGroup ) ;
if ( ( ( index < volumeCurves . getVolumeIndexMin ( ) ) & & ! ( hasVoiceStream ( streams ) & & index = = 0 ) ) | |
bool hasVoice = hasVoiceStream ( volumeCurves . getStreamTypes ( ) ) ;
if ( ( ( index < volumeCurves . getVolumeIndexMin ( ) ) & & ! ( hasVoice & & index = = 0 ) ) | |
( index > volumeCurves . getVolumeIndexMax ( ) ) ) {
ALOGD ( " %s: wrong index %d min=%d max=%d " , __FUNCTION__ , index ,
volumeCurves . getVolumeIndexMin ( ) , volumeCurves . getVolumeIndexMax ( ) ) ;
@ -2544,7 +2567,7 @@ status_t AudioPolicyManager::setVolumeCurveIndex(volume_group_t volumeGroup,
// Force max volume if stream cannot be muted
if ( ! volumeCurves . canBeMuted ( ) ) index = volumeCurves . getVolumeIndexMax ( ) ;
ALOG D ( " %s device %08x, index %d " , __FUNCTION__ , device , index ) ;
ALOG V ( " %s device %08x, index %d " , __FUNCTION__ , device , index ) ;
volumeCurves . addCurrentVolumeIndex ( device , index ) ;
return NO_ERROR ;
}
@ -2706,19 +2729,12 @@ status_t AudioPolicyManager::setEffectEnabled(int id, bool enabled)
bool AudioPolicyManager : : isStreamActive ( audio_stream_type_t stream , uint32_t inPastMs ) const
{
bool active = false ;
for ( int curStream = 0 ; curStream < AUDIO_STREAM_FOR_POLICY_CNT & & ! active ; curStream + + ) {
if ( ! streamsMatchForvolume ( stream , ( audio_stream_type_t ) curStream ) ) {
continue ;
}
active = mOutputs . isActive ( streamToVolumeSource ( ( audio_stream_type_t ) curStream ) , inPastMs ) ;
}
return active ;
return mOutputs . isActive ( toVolumeSource ( stream ) , inPastMs ) ;
}
bool AudioPolicyManager : : isStreamActiveRemotely ( audio_stream_type_t stream , uint32_t inPastMs ) const
{
return mOutputs . isActiveRemotely ( s treamT oVolumeSource( ( audio_stream_type_t ) stream ) , inPastMs ) ;
return mOutputs . isActiveRemotely ( toVolumeSource ( stream ) , inPastMs ) ;
}
bool AudioPolicyManager : : isSourceActive ( audio_source_t source ) const
@ -3747,11 +3763,11 @@ status_t AudioPolicyManager::startAudioSource(const struct audio_port_config *so
struct audio_patch dummyPatch = { } ;
sp < AudioPatch > patchDesc = new AudioPatch ( & dummyPatch , uid ) ;
sp < SourceClientDescriptor > sourceDesc = new SourceClientDescriptor (
* portId , uid , * attributes , patchDesc , srcDevice ,
mEngine - > getStreamTypeForAttributes ( * attributes ) ,
mEngine - > getProductStrategyForAttributes ( * attributes ) ,
s treamT oVolumeSource( mEngine - > getStreamTypeForAttributes ( * attributes ) ) ) ;
sp < SourceClientDescriptor > sourceDesc =
new SourceClientDescriptor ( * portId , uid , * attributes , patchDesc , srcDevice ,
mEngine - > getStreamTypeForAttributes ( * attributes ) ,
mEngine - > getProductStrategyForAttributes ( * attributes ) ,
toVolumeSource( * attributes ) ) ;
status_t status = connectAudioSource ( sourceDesc ) ;
if ( status = = NO_ERROR ) {
@ -3916,7 +3932,7 @@ status_t AudioPolicyManager::getMasterMono(bool *mono)
float AudioPolicyManager : : getStreamVolumeDB (
audio_stream_type_t stream , int index , audio_devices_t device )
{
return computeVolume ( stream, index , device ) ;
return computeVolume ( getVolumeCurves( stream) , toVolumeSource ( stream ) , index , device ) ;
}
status_t AudioPolicyManager : : getSurroundFormats ( unsigned int * numSurroundFormats ,
@ -5292,11 +5308,10 @@ uint32_t AudioPolicyManager::setBeaconMute(bool mute) {
// mute/unmute AUDIO_STREAM_TTS on all outputs
ALOGV ( " \t muting %d " , mute ) ;
uint32_t maxLatency = 0 ;
auto ttsVolumeSource = toVolumeSource ( AUDIO_STREAM_TTS ) ;
for ( size_t i = 0 ; i < mOutputs . size ( ) ; i + + ) {
sp < SwAudioOutputDescriptor > desc = mOutputs . valueAt ( i ) ;
setStreamMute ( AUDIO_STREAM_TTS , mute /*on*/ ,
desc ,
0 /*delay*/ , AUDIO_DEVICE_NONE ) ;
setVolumeSourceMute ( ttsVolumeSource , mute /*on*/ , desc , 0 /*delay*/ , AUDIO_DEVICE_NONE ) ;
const uint32_t latency = desc - > latency ( ) * 2 ;
if ( latency > maxLatency ) {
maxLatency = latency ;
@ -5380,15 +5395,12 @@ uint32_t AudioPolicyManager::checkDeviceMuteStrategies(const sp<AudioOutputDescr
if ( muteWaitMs < tempMuteWaitMs ) {
muteWaitMs = tempMuteWaitMs ;
}
for ( const auto & productStrategy : productStrategies ) {
if ( outputDesc - > isStrategyActive ( productStrategy ) ) {
// make sure that we do not start the temporary mute period too early in case of
// delayed device change
setStrategyMute ( productStrategy , true , outputDesc , delayMs ) ;
setStrategyMute ( productStrategy , false , outputDesc , delayMs + tempMuteDurationMs ,
for ( const auto & activeVs : outputDesc - > getActiveVolumeSources ( ) ) {
// make sure that we do not start the temporary mute period too early in case of
// delayed device change
setVolumeSourceMute ( activeVs , true , outputDesc , delayMs ) ;
setVolumeSourceMute ( activeVs , false , outputDesc , delayMs + tempMuteDurationMs ,
devices . types ( ) ) ;
}
}
}
@ -5612,51 +5624,51 @@ sp<IOProfile> AudioPolicyManager::getInputProfile(const sp<DeviceDescriptor> &de
return NULL ;
}
float AudioPolicyManager : : computeVolume ( audio_stream_type_t stream ,
float AudioPolicyManager : : computeVolume ( IVolumeCurves & curves ,
VolumeSource volumeSource ,
int index ,
audio_devices_t device )
{
auto & curves = getVolumeCurves ( stream ) ;
float volumeDb = curves . volIndexToDb ( Volume : : getDeviceCategory ( device ) , index ) ;
// handle the case of accessibility active while a ringtone is playing: if the ringtone is much
// louder than the accessibility prompt, the prompt cannot be heard, thus masking the touch
// exploration of the dialer UI. In this situation, bring the accessibility volume closer to
// the ringtone volume
if ( ( stream = = AUDIO_STREAM_ACCESSIBILITY )
& & ( AUDIO_MODE_RINGTONE = = mEngine - > getPhoneState ( ) )
& & isStreamActive ( AUDIO_STREAM_RING , 0 ) ) {
const float ringVolumeDB = computeVolume ( AUDIO_STREAM_RING , index , device ) ;
return ringVolumeDB - 4 > volumeDb ? ringVolumeDB - 4 : volumeDb ;
const auto callVolumeSrc = toVolumeSource ( AUDIO_STREAM_VOICE_CALL ) ;
const auto ringVolumeSrc = toVolumeSource ( AUDIO_STREAM_RING ) ;
const auto musicVolumeSrc = toVolumeSource ( AUDIO_STREAM_MUSIC ) ;
const auto alarmVolumeSrc = toVolumeSource ( AUDIO_STREAM_ALARM ) ;
if ( volumeSource = = toVolumeSource ( AUDIO_STREAM_ACCESSIBILITY )
& & ( AUDIO_MODE_RINGTONE = = mEngine - > getPhoneState ( ) ) & &
mOutputs . isActive ( ringVolumeSrc , 0 ) ) {
auto & ringCurves = getVolumeCurves ( AUDIO_STREAM_RING ) ;
const float ringVolumeDb = computeVolume ( ringCurves , ringVolumeSrc , index , device ) ;
return ringVolumeDb - 4 > volumeDb ? ringVolumeDb - 4 : volumeDb ;
}
// in-call: always cap volume by voice volume + some low headroom
if ( ( stream ! = AUDIO_STREAM_VOICE_CALL ) & &
( isInCall ( ) | | mOutputs . isActiveLocally ( streamToVolumeSource ( AUDIO_STREAM_VOICE_CALL ) ) ) ) {
switch ( stream ) {
case AUDIO_STREAM_SYSTEM :
case AUDIO_STREAM_RING :
case AUDIO_STREAM_MUSIC :
case AUDIO_STREAM_ALARM :
case AUDIO_STREAM_NOTIFICATION :
case AUDIO_STREAM_ENFORCED_AUDIBLE :
case AUDIO_STREAM_DTMF :
case AUDIO_STREAM_ACCESSIBILITY : {
int voiceVolumeIndex = getVolumeCurves ( AUDIO_STREAM_VOICE_CALL ) . getVolumeIndex ( device ) ;
const float maxVoiceVolDb =
computeVolume ( AUDIO_STREAM_VOICE_CALL , voiceVolumeIndex , device )
if ( ( volumeSource ! = callVolumeSrc & & ( isInCall ( ) | |
mOutputs . isActiveLocally ( callVolumeSrc ) ) ) & &
( volumeSource = = toVolumeSource ( AUDIO_STREAM_SYSTEM ) | |
volumeSource = = ringVolumeSrc | | volumeSource = = musicVolumeSrc | |
volumeSource = = alarmVolumeSrc | |
volumeSource = = toVolumeSource ( AUDIO_STREAM_NOTIFICATION ) | |
volumeSource = = toVolumeSource ( AUDIO_STREAM_ENFORCED_AUDIBLE ) | |
volumeSource = = toVolumeSource ( AUDIO_STREAM_DTMF ) | |
volumeSource = = toVolumeSource ( AUDIO_STREAM_ACCESSIBILITY ) ) ) {
auto & voiceCurves = getVolumeCurves ( callVolumeSrc ) ;
int voiceVolumeIndex = voiceCurves . getVolumeIndex ( device ) ;
const float maxVoiceVolDb =
computeVolume ( voiceCurves , callVolumeSrc , voiceVolumeIndex , device )
+ IN_CALL_EARPIECE_HEADROOM_DB ;
if ( volumeDb > maxVoiceVolDb ) {
ALOGV ( " computeVolume() stream %d at vol=%f overriden by stream %d at vol=%f " ,
stream , volumeDb , AUDIO_STREAM_VOICE_CALL , maxVoiceVolDb ) ;
volumeDb = maxVoiceVolDb ;
}
} break ;
default :
break ;
if ( volumeDb > maxVoiceVolDb ) {
ALOGV ( " %s volume source %d at vol=%f overriden by volume group %d at vol=%f " , __func__ ,
volumeSource , volumeDb , callVolumeSrc , maxVoiceVolDb ) ;
volumeDb = maxVoiceVolDb ;
}
}
// if a headset is connected, apply the following rules to ring tones and notifications
// to avoid sound level bursts in user's ears:
// - always attenuate notifications volume by 6dB
@ -5664,19 +5676,17 @@ float AudioPolicyManager::computeVolume(audio_stream_type_t stream,
// speaker is part of the select devices
// - if music is playing, always limit the volume to current music volume,
// with a minimum threshold at -36dB so that notification is always perceived.
if ( ( device & ( AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
AUDIO_DEVICE_OUT_WIRED_HEADSET |
AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
AUDIO_DEVICE_OUT_USB_HEADSET |
AUDIO_DEVICE_OUT_HEARING_AID ) ) & &
( ( stream = = AUDIO_STREAM_ALARM | | stream = = AUDIO_STREAM_RING )
| | ( stream = = AUDIO_STREAM_NOTIFICATION )
| | ( stream = = AUDIO_STREAM_SYSTEM )
| | ( ( stream = = AUDIO_STREAM_ENFORCED_AUDIBLE ) & &
( mEngine - > getForceUse ( AUDIO_POLICY_FORCE_FOR_SYSTEM ) = =
AUDIO_POLICY_FORCE_NONE ) ) ) & &
getVolumeCurves ( stream ) . canBeMuted ( ) ) {
if ( ( device & ( AUDIO_DEVICE_OUT_BLUETOOTH_A2DP | AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
AUDIO_DEVICE_OUT_WIRED_HEADSET | AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
AUDIO_DEVICE_OUT_USB_HEADSET | AUDIO_DEVICE_OUT_HEARING_AID ) ) & &
( ( volumeSource = = alarmVolumeSrc | |
volumeSource = = ringVolumeSrc ) | |
( volumeSource = = toVolumeSource ( AUDIO_STREAM_NOTIFICATION ) ) | |
( volumeSource = = toVolumeSource ( AUDIO_STREAM_SYSTEM ) ) | |
( ( volumeSource = = toVolumeSource ( AUDIO_STREAM_ENFORCED_AUDIBLE ) ) & &
( mEngine - > getForceUse ( AUDIO_POLICY_FORCE_FOR_SYSTEM ) = = AUDIO_POLICY_FORCE_NONE ) ) ) & &
curves . canBeMuted ( ) ) {
// 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
@ -5686,29 +5696,29 @@ float AudioPolicyManager::computeVolume(audio_stream_type_t stream,
audio_devices_t musicDevice =
mEngine - > getOutputDevicesForAttributes ( attributes_initializer ( AUDIO_USAGE_MEDIA ) ,
nullptr , true /*fromCache*/ ) . types ( ) ;
float musicVolDB = computeVolume ( AUDIO_STREAM_MUSIC ,
getVolumeCurves ( AUDIO_STREAM_MUSIC ) . getVolumeIndex ( musicDevice ) ,
musicDevice ) ;
float minVolD B = ( musicVolDB > SONIFICATION_HEADSET_VOLUME_MIN_DB ) ?
musicVolDB : SONIFICATION_HEADSET_VOLUME_MIN_DB ;
if ( volumeDb > minVolD B ) {
volumeDb = minVolD B ;
ALOGV ( " computeVolume limiting volume to %f musicVol %f " , minVolD B, musicVolDB ) ;
auto & musicCurves = getVolumeCurves ( AUDIO_STREAM_MUSIC ) ;
float musicVolDb = computeVolume ( musicCurves , musicVolumeSrc ,
musicCurves . getVolumeIndex ( musicDevice ) , musicDevice ) ;
float minVolD b = ( musicVolDb > SONIFICATION_HEADSET_VOLUME_MIN_DB ) ?
musicVolDb : SONIFICATION_HEADSET_VOLUME_MIN_DB ;
if ( volumeDb > minVolD b ) {
volumeDb = minVolD b ;
ALOGV ( " computeVolume limiting volume to %f musicVol %f " , minVolD b, musicVolDb ) ;
}
if ( device & ( AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES ) ) {
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES ) ) {
// on A2DP, also ensure notification volume is not too low compared to media when
// intended to be played
if ( ( volumeDb > - 96.0f ) & &
( musicVolD B - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB > volumeDb ) ) {
ALOGV ( " computeVolume increasing volume for stream =%d device=0x%X from %f to %f" ,
stream , device ,
volumeDb , musicVolDB - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB ) ;
volumeDb = musicVolD B - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB ;
( musicVolD b - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB > volumeDb ) ) {
ALOGV ( " %s increasing volume for volume source =%d device=0x%X from %f to %f" ,
__func__ , volumeSource , device , volumeDb ,
musicVolDb - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB ) ;
volumeDb = musicVolD b - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB ;
}
}
} else if ( ( Volume : : getDeviceForVolume ( device ) ! = AUDIO_DEVICE_OUT_SPEAKER ) | |
( stream ! = AUDIO_STREAM_ALARM & & stream ! = AUDIO_STREAM_RING ) ) {
( ! ( volumeSource = = alarmVolumeSrc | | volumeSource = = ringVolumeSrc ) ) ) {
volumeDb + = SONIFICATION_HEADSET_VOLUME_FACTOR_DB ;
}
}
@ -5742,58 +5752,61 @@ int AudioPolicyManager::rescaleVolumeIndex(int srcIndex,
return ( int ) ( minDst + ( ( srcIndex - minSrc ) * ( maxDst - minDst ) ) / ( maxSrc - minSrc ) ) ;
}
status_t AudioPolicyManager : : checkAndSetVolume ( audio_stream_type_t stream ,
status_t AudioPolicyManager : : checkAndSetVolume ( IVolumeCurves & curves ,
VolumeSource volumeSource ,
int index ,
const sp < AudioOutputDescriptor > & outputDesc ,
audio_devices_t device ,
int delayMs ,
bool force )
{
// do not change actual stream volume if the stream is muted
if ( outputDesc - > isMuted ( streamToVolumeSource ( stream ) ) ) {
ALOGVV ( " %s() stream %d muted count %d " , __func__ , stream , outputDesc - > getMuteCount ( stream ) ) ;
// do not change actual attributes volume if the attributes is muted
if ( outputDesc - > isMuted ( volumeSource ) ) {
ALOGVV ( " %s: volume source %d muted count %d active=%d " , __func__ , volumeSource ,
outputDesc - > getMuteCount ( volumeSource ) , outputDesc - > isActive ( volumeSource ) ) ;
return NO_ERROR ;
}
VolumeSource callVolSrc = toVolumeSource ( AUDIO_STREAM_VOICE_CALL ) ;
VolumeSource btScoVolSrc = toVolumeSource ( AUDIO_STREAM_BLUETOOTH_SCO ) ;
bool isVoiceVolSrc = callVolSrc = = volumeSource ;
bool isBtScoVolSrc = btScoVolSrc = = volumeSource ;
audio_policy_forced_cfg_t forceUseForComm =
mEngine - > getForceUse ( AUDIO_POLICY_FORCE_FOR_COMMUNICATION ) ;
// do not change in call volume if bluetooth is connected and vice versa
if ( ( stream = = AUDIO_STREAM_VOICE_CALL & & forceUseForComm = = AUDIO_POLICY_FORCE_BT_SCO ) | |
( stream = = AUDIO_STREAM_BLUETOOTH_SCO & & forceUseForComm ! = AUDIO_POLICY_FORCE_BT_SCO ) ) {
ALOGV ( " checkAndSetVolume() cannot set stream %d volume with force use = %d for comm " ,
stream , forceUseForComm ) ;
// if sco and call follow same curves, bypass forceUseForComm
if ( ( callVolSrc ! = btScoVolSrc ) & &
( ( isVoiceVolSrc & & forceUseForComm = = AUDIO_POLICY_FORCE_BT_SCO ) | |
( isBtScoVolSrc & & forceUseForComm ! = AUDIO_POLICY_FORCE_BT_SCO ) ) ) {
ALOGV ( " %s cannot set volume group %d volume with force use = %d for comm " , __func__ ,
volumeSource , forceUseForComm ) ;
return INVALID_OPERATION ;
}
if ( device = = AUDIO_DEVICE_NONE ) {
device = outputDesc - > devices ( ) . types ( ) ;
}
float volumeDb = computeVolume ( stream , index , device ) ;
float volumeDb = computeVolume ( curves, volumeSource , index , device ) ;
if ( outputDesc - > isFixedVolume ( device ) | |
// Force VoIP volume to max for bluetooth SCO
( ( stream = = AUDIO_STREAM_VOICE_CALL | | stream = = AUDIO_STREAM_BLUETOOTH_SCO ) & &
( device & AUDIO_DEVICE_OUT_ALL_SCO ) ! = 0 ) ) {
( ( isVoiceVolSrc | | isBtScoVolSrc ) & & ( device & AUDIO_DEVICE_OUT_ALL_SCO ) ! = 0 ) ) {
volumeDb = 0.0f ;
}
outputDesc - > setVolume ( volumeDb , volumeSource , curves . getStreamTypes ( ) , device , delayMs , force ) ;
outputDesc - > setVolume ( volumeDb , stream , device , delayMs , force ) ;
if ( stream = = AUDIO_STREAM_VOICE_CALL | |
stream = = AUDIO_STREAM_BLUETOOTH_SCO ) {
if ( isVoiceVolSrc | | isBtScoVolSrc ) {
float voiceVolume ;
// Force voice volume to max for bluetooth SCO as volume is managed by the headset
if ( stream = = AUDIO_STREAM_VOICE_CALL ) {
voiceVolume = ( float ) index / ( float ) getVolumeCurves( stream ) . getVolumeIndexMax ( ) ;
if ( isVoiceVolSrc ) {
voiceVolume = ( float ) index / ( float ) curves . getVolumeIndexMax ( ) ;
} else {
voiceVolume = 1.0 ;
}
if ( voiceVolume ! = mLastVoiceVolume ) {
mpClientInterface - > setVoiceVolume ( voiceVolume , delayMs ) ;
mLastVoiceVolume = voiceVolume ;
}
}
return NO_ERROR ;
}
@ -5803,14 +5816,10 @@ void AudioPolicyManager::applyStreamVolumes(const sp<AudioOutputDescriptor>& out
bool force )
{
ALOGVV ( " applyStreamVolumes() for device %08x " , device ) ;
for ( int stream = 0 ; stream < AUDIO_STREAM_FOR_POLICY_CNT ; stream + + ) {
checkAndSetVolume ( ( audio_stream_type_t ) stream ,
getVolumeCurves ( ( audio_stream_type_t ) stream ) . getVolumeIndex ( device ) ,
outputDesc ,
device ,
delayMs ,
force ) ;
for ( const auto & volumeGroup : mEngine - > getVolumeGroups ( ) ) {
auto & curves = getVolumeCurves ( toVolumeSource ( volumeGroup ) ) ;
checkAndSetVolume ( curves , toVolumeSource ( volumeGroup ) ,
curves . getVolumeIndex ( device ) , outputDesc , device , delayMs , force ) ;
}
}
@ -5820,43 +5829,54 @@ void AudioPolicyManager::setStrategyMute(product_strategy_t strategy,
int delayMs ,
audio_devices_t device )
{
for ( auto stream : mEngine - > getStreamTypesForProductStrategy ( strategy ) ) {
ALOGVV ( " %s() stream %d, mute %d, output ID %d " , __FUNCTION__ , stream , on ,
outputDesc - > getId ( ) ) ;
setStreamMute ( stream , on , outputDesc , delayMs , device ) ;
std : : vector < VolumeSource > sourcesToMute ;
for ( auto attributes : mEngine - > getAllAttributesForProductStrategy ( strategy ) ) {
ALOGVV ( " %s() attributes %s, mute %d, output ID %d " , __func__ ,
toString ( attributes ) . c_str ( ) , on , outputDesc - > getId ( ) ) ;
VolumeSource source = toVolumeSource ( attributes ) ;
if ( std : : find ( begin ( sourcesToMute ) , end ( sourcesToMute ) , source ) = = end ( sourcesToMute ) ) {
sourcesToMute . push_back ( source ) ;
}
}
for ( auto source : sourcesToMute ) {
setVolumeSourceMute ( source , on , outputDesc , delayMs , device ) ;
}
}
void AudioPolicyManager : : setStreamMute ( audio_stream_type_t stream ,
bool on ,
const sp < AudioOutputDescriptor > & outputDesc ,
int delayMs ,
audio_devices_t device )
void AudioPolicyManager : : setVolumeSourceMute ( VolumeSource volumeSource ,
bool on ,
const sp < AudioOutputDescriptor > & outputDesc ,
int delayMs ,
audio_devices_t device ,
bool activeOnly )
{
if ( activeOnly & & ! outputDesc - > isActive ( volumeSource ) ) {
return ;
}
if ( device = = AUDIO_DEVICE_NONE ) {
device = outputDesc - > devices ( ) . types ( ) ;
}
ALOGVV ( " setStreamMute() stream %d, mute %d, mMuteCount %d device %04x " ,
stream , on , outputDesc - > getMuteCount ( stream ) , device ) ;
auto & curves = getVolumeCurves ( stream ) ;
auto & curves = getVolumeCurves ( volumeSource ) ;
if ( on ) {
if ( ! outputDesc - > isMuted ( streamToVolumeSource( stream ) ) ) {
if ( ! outputDesc - > isMuted ( volumeSource ) ) {
if ( curves . canBeMuted ( ) & &
( ( stream ! = AUDIO_STREAM_ENFORCED_AUDIBLE ) | |
( mEngine - > getForceUse ( AUDIO_POLICY_FORCE_FOR_SYSTEM ) = = AUDIO_POLICY_FORCE_NONE ) ) ) {
checkAndSetVolume ( stream , 0 , outputDesc , device , delayMs ) ;
( volumeSource ! = toVolumeSource ( AUDIO_STREAM_ENFORCED_AUDIBLE ) | |
( mEngine - > getForceUse ( AUDIO_POLICY_FORCE_FOR_SYSTEM ) = =
AUDIO_POLICY_FORCE_NONE ) ) ) {
checkAndSetVolume ( curves , volumeSource , 0 , outputDesc , device , delayMs ) ;
}
}
// increment mMuteCount after calling checkAndSetVolume() so that volume change is not ignored
outputDesc - > incMuteCount ( streamToVolumeSource ( stream ) ) ;
// increment mMuteCount after calling checkAndSetVolume() so that volume change is not
// ignored
outputDesc - > incMuteCount ( volumeSource ) ;
} else {
if ( ! outputDesc - > isMuted ( streamToVolumeSource( stream ) ) ) {
ALOGV ( " setStreamMute() unmuting non muted stream!" ) ;
if ( ! outputDesc - > isMuted ( volumeSource ) ) {
ALOGV ( " %s unmuting non muted attributes!" , __func__ ) ;
return ;
}
if ( outputDesc - > decMuteCount ( streamToVolumeSource( stream ) ) = = 0 ) {
checkAndSetVolume ( stream ,
if ( outputDesc - > decMuteCount ( volumeSource ) = = 0 ) {
checkAndSetVolume ( curves, volumeSource ,
curves . getVolumeIndex ( device ) ,
outputDesc ,
device ,