@ -36,6 +36,7 @@
# include <inttypes.h>
# include <math.h>
# include <set>
# include <unordered_set>
# include <vector>
@ -907,16 +908,18 @@ status_t AudioPolicyManager::getAudioAttributes(audio_attributes_t *dstAttr,
return NO_ERROR ;
}
status_t AudioPolicyManager : : getOutputForAttrInt ( audio_attributes_t * resultAttr ,
audio_io_handle_t * output ,
audio_session_t session ,
const audio_attributes_t * attr ,
audio_stream_type_t * stream ,
uid_t uid ,
const audio_config_t * config ,
audio_output_flags_t * flags ,
audio_port_handle_t * selectedDeviceId ,
bool * isRequestedDeviceForExclusiveUse )
status_t AudioPolicyManager : : getOutputForAttrInt (
audio_attributes_t * resultAttr ,
audio_io_handle_t * output ,
audio_session_t session ,
const audio_attributes_t * attr ,
audio_stream_type_t * stream ,
uid_t uid ,
const audio_config_t * config ,
audio_output_flags_t * flags ,
audio_port_handle_t * selectedDeviceId ,
bool * isRequestedDeviceForExclusiveUse ,
std : : vector < sp < SwAudioOutputDescriptor > > * secondaryDescs )
{
DeviceVector outputDevices ;
const audio_port_handle_t requestedPortId = * selectedDeviceId ;
@ -935,19 +938,26 @@ status_t AudioPolicyManager::getOutputForAttrInt(audio_attributes_t *resultAttr,
ALOGV ( " %s() attributes=%s stream=%s session %d selectedDeviceId %d " , __func__ ,
toString ( * resultAttr ) . c_str ( ) , toString ( * stream ) . c_str ( ) , session , requestedPortId ) ;
// 1/ First check for explicit routing (eg. setPreferredDevice): NOTE: now handled by engine
// 2/ If no explict route, is there a matching dynamic policy that applies?
// NOTE: new engine product strategy does not make use of dynamic routing, keep it for
// remote-submix and legacy
sp < SwAudioOutputDescriptor > desc ;
if ( requestedDevice = = nullptr & &
mPolicyMixes . getOutputForAttr ( * resultAttr , uid , desc ) = = NO_ERROR ) {
ALOG_ASSERT ( desc ! = 0 , " Invalid desc returned by getOutputForAttr " ) ;
if ( ! audio_has_proportional_frames ( config - > format ) ) {
return BAD_VALUE ;
}
* output = desc - > mIoHandle ;
AudioMix * mix = desc - > mPolicyMix ;
// The primary output is the explicit routing (eg. setPreferredDevice) if specified,
// otherwise, fallback to the dynamic policies, if none match, query the engine.
// Secondary outputs are always found by dynamic policies as the engine do not support them
sp < SwAudioOutputDescriptor > policyDesc ;
if ( mPolicyMixes . getOutputForAttr ( * resultAttr , uid , policyDesc , secondaryDescs ) ! = NO_ERROR ) {
policyDesc = nullptr ; // reset getOutputForAttr in case of failure
secondaryDescs - > clear ( ) ;
}
// Explicit routing is higher priority then any dynamic policy primary output
bool usePrimaryOutputFromPolicyMixes = requestedDevice = = nullptr & & policyDesc ! = nullptr ;
// FIXME: in case of RENDER policy, the output capabilities should be checked
if ( ( usePrimaryOutputFromPolicyMixes | | ! secondaryDescs - > empty ( ) )
& & ! audio_has_proportional_frames ( config - > format ) ) {
ALOGW ( " %s: audio loopback only supports proportional frames " , __func__ ) ;
return BAD_VALUE ;
}
if ( usePrimaryOutputFromPolicyMixes ) {
* output = policyDesc - > mIoHandle ;
AudioMix * mix = policyDesc - > mPolicyMix ;
sp < DeviceDescriptor > deviceDesc =
mAvailableOutputDevices . getDevice ( mix - > mDeviceType ,
mix - > mDeviceAddress ,
@ -1022,7 +1032,8 @@ status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr,
const audio_config_t * config ,
audio_output_flags_t * flags ,
audio_port_handle_t * selectedDeviceId ,
audio_port_handle_t * portId )
audio_port_handle_t * portId ,
std : : vector < audio_io_handle_t > * secondaryOutputs )
{
// The supplied portId must be AUDIO_PORT_HANDLE_NONE
if ( * portId ! = AUDIO_PORT_HANDLE_NONE ) {
@ -1031,11 +1042,18 @@ status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr,
const audio_port_handle_t requestedPortId = * selectedDeviceId ;
audio_attributes_t resultAttr ;
bool isRequestedDeviceForExclusiveUse = false ;
std : : vector < sp < SwAudioOutputDescriptor > > secondaryOutputDescs ;
status_t status = getOutputForAttrInt ( & resultAttr , output , session , attr , stream , uid ,
config , flags , selectedDeviceId , & isRequestedDeviceForExclusiveUse ) ;
config , flags , selectedDeviceId , & isRequestedDeviceForExclusiveUse ,
& secondaryOutputDescs ) ;
if ( status ! = NO_ERROR ) {
return status ;
}
std : : vector < wp < SwAudioOutputDescriptor > > weakSecondaryOutputDescs ;
for ( auto & secondaryDesc : secondaryOutputDescs ) {
secondaryOutputs - > push_back ( secondaryDesc - > mIoHandle ) ;
weakSecondaryOutputDescs . push_back ( secondaryDesc ) ;
}
audio_config_base_t clientConfig = { . sample_rate = config - > sample_rate ,
. format = config - > format ,
@ -1046,7 +1064,8 @@ status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr,
new TrackClientDescriptor ( * portId , uid , session , resultAttr , clientConfig ,
requestedPortId , * stream ,
mEngine - > getProductStrategyForAttributes ( resultAttr ) ,
* flags , isRequestedDeviceForExclusiveUse ) ;
* flags , isRequestedDeviceForExclusiveUse ,
std : : move ( weakSecondaryOutputDescs ) ) ;
sp < SwAudioOutputDescriptor > outputDesc = mOutputs . valueFor ( * output ) ;
outputDesc - > addClient ( clientDesc ) ;
@ -1562,13 +1581,15 @@ status_t AudioPolicyManager::startSource(const sp<SwAudioOutputDescriptor>& outp
policyMix = outputDesc - > mPolicyMix ;
audio_devices_t newDeviceType ;
address = policyMix - > mDeviceAddress . string ( ) ;
if ( ( policyMix - > mRouteFlags & MIX_ROUTE_FLAG_RENDER ) = = MIX_ROUTE_FLAG_RENDER ) {
newDeviceType = policyMix - > mDeviceType ;
} else {
if ( ( policyMix - > mRouteFlags & MIX_ROUTE_FLAG_LOOP_BACK ) = = MIX_ROUTE_FLAG_LOOP_BACK ) {
newDeviceType = AUDIO_DEVICE_OUT_REMOTE_SUBMIX ;
} else {
newDeviceType = policyMix - > mDeviceType ;
}
devices . add ( mAvailableOutputDevices . getDevice ( newDeviceType ,
String8 ( address ) , AUDIO_FORMAT_DEFAULT ) ) ;
sp device = mAvailableOutputDevices . getDevice ( newDeviceType , String8 ( address ) ,
AUDIO_FORMAT_DEFAULT ) ;
ALOG_ASSERT ( device , " %s: no device found t=%u, a=%s " , __func__ , newDeviceType , address ) ;
devices . add ( device ) ;
}
// requiresMuteCheck is false when we can bypass mute strategy.
@ -2609,18 +2630,24 @@ status_t AudioPolicyManager::registerPolicyMixes(const Vector<AudioMix>& mixes)
// examine each mix's route type
for ( size_t i = 0 ; i < mixes . size ( ) ; i + + ) {
AudioMix mix = mixes [ i ] ;
// we only support MIX_ROUTE_FLAG_LOOP_BACK or MIX_ROUTE_FLAG_RENDER, not the combination
if ( ( mix . mRouteFlags & MIX_ROUTE_FLAG_ALL ) = = MIX_ROUTE_FLAG_ALL ) {
// Only capture of playback is allowed in LOOP_BACK & RENDER mode
if ( is_mix_loopback_render ( mix . mRouteFlags ) & & mix . mMixType ! = MIX_TYPE_PLAYERS ) {
ALOGE ( " Unsupported Policy Mix %zu of %zu: "
" Only capture of playback is allowed in LOOP_BACK & RENDER mode " ,
i , mixes . size ( ) ) ;
res = INVALID_OPERATION ;
break ;
}
// LOOP_BACK and LOOP_BACK | RENDER have the same remote submix backend and are handled
// in the same way.
if ( ( mix . mRouteFlags & MIX_ROUTE_FLAG_LOOP_BACK ) = = MIX_ROUTE_FLAG_LOOP_BACK ) {
ALOGV ( " registerPolicyMixes() mix %zu of %zu is LOOP_BACK " , i , mixes . size ( ) ) ;
ALOGV ( " registerPolicyMixes() mix %zu of %zu is LOOP_BACK %d " , i , mixes . size ( ) ,
mix . mRouteFlags ) ;
if ( rSubmixModule = = 0 ) {
rSubmixModule = mHwModules . getModuleFromName (
AUDIO_HARDWARE_MODULE_ID_REMOTE_SUBMIX ) ;
if ( rSubmixModule = = 0 ) {
ALOGE ( " Unable to find audio module for submix, aborting mix %zu registration" ,
ALOGE ( " Unable to find audio module for submix, aborting mix %zu registration" ,
i ) ;
res = INVALID_OPERATION ;
break ;
@ -2635,7 +2662,7 @@ status_t AudioPolicyManager::registerPolicyMixes(const Vector<AudioMix>& mixes)
}
if ( mPolicyMixes . registerMix ( address , mix , 0 /*output desc*/ ) ! = NO_ERROR ) {
ALOGE ( " Error registering mix %zu for address %s" , i , address . string ( ) ) ;
ALOGE ( " Error registering mix %zu for address %s" , i , address . string ( ) ) ;
res = INVALID_OPERATION ;
break ;
}
@ -2679,6 +2706,8 @@ status_t AudioPolicyManager::registerPolicyMixes(const Vector<AudioMix>& mixes)
if ( desc - > supportedDevices ( ) . contains ( device ) ) {
if ( mPolicyMixes . registerMix ( address , mix , desc ) ! = NO_ERROR ) {
ALOGE ( " Could not register mix RENDER, dev=0x%X addr=%s " , type ,
address . string ( ) ) ;
res = INVALID_OPERATION ;
} else {
foundOutput = true ;
@ -2746,7 +2775,7 @@ status_t AudioPolicyManager::unregisterPolicyMixes(Vector<AudioMix> mixes)
rSubmixModule - > removeOutputProfile ( address ) ;
rSubmixModule - > removeInputProfile ( address ) ;
} if ( ( mix . mRouteFlags & MIX_ROUTE_FLAG_RENDER ) = = MIX_ROUTE_FLAG_RENDER ) {
} else if ( ( mix . mRouteFlags & MIX_ROUTE_FLAG_RENDER ) = = MIX_ROUTE_FLAG_RENDER ) {
if ( mPolicyMixes . unregisterMix ( mix . mDeviceAddress ) ! = NO_ERROR ) {
res = INVALID_OPERATION ;
continue ;
@ -3635,9 +3664,11 @@ status_t AudioPolicyManager::connectAudioSource(const sp<SourceClientDescriptor>
audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE ;
audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE ;
bool isRequestedDeviceForExclusiveUse = false ;
std : : vector < sp < SwAudioOutputDescriptor > > secondaryOutputs ;
getOutputForAttrInt ( & resultAttr , & output , AUDIO_SESSION_NONE ,
& attributes , & stream , sourceDesc - > uid ( ) , & config , & flags ,
& selectedDeviceId , & isRequestedDeviceForExclusiveUse ) ;
& selectedDeviceId , & isRequestedDeviceForExclusiveUse ,
& secondaryOutputs ) ;
if ( output = = AUDIO_IO_HANDLE_NONE ) {
ALOGV ( " %s no output for device %08x " , __FUNCTION__ , sinkDevices . types ( ) ) ;
return INVALID_OPERATION ;
@ -4782,6 +4813,7 @@ void AudioPolicyManager::checkForDeviceAndOutputChanges(std::function<bool()> on
// output is suspended before any tracks are moved to it
checkA2dpSuspend ( ) ;
checkOutputForAllStrategies ( ) ;
checkSecondaryOutputs ( ) ;
if ( onOutputsChecked ! = nullptr & & onOutputsChecked ( ) ) checkA2dpSuspend ( ) ;
updateDevicesAndOutputs ( ) ;
if ( mHwModules . getModuleFromName ( AUDIO_HARDWARE_MODULE_ID_MSD ) ! = 0 ) {
@ -4870,6 +4902,29 @@ void AudioPolicyManager::checkOutputForAllStrategies()
}
}
void AudioPolicyManager : : checkSecondaryOutputs ( ) {
std : : set < audio_stream_type_t > streamsToInvalidate ;
for ( size_t i = 0 ; i < mOutputs . size ( ) ; i + + ) {
const sp < SwAudioOutputDescriptor > & outputDescriptor = mOutputs [ i ] ;
for ( const sp < TrackClientDescriptor > & client : outputDescriptor - > getClientIterable ( ) ) {
// FIXME code duplicated from getOutputForAttrInt
sp < SwAudioOutputDescriptor > desc ;
std : : vector < sp < SwAudioOutputDescriptor > > secondaryDescs ;
mPolicyMixes . getOutputForAttr ( client - > attributes ( ) , client - > uid ( ) , desc ,
& secondaryDescs ) ;
if ( ! std : : equal ( client - > getSecondaryOutputs ( ) . begin ( ) ,
client - > getSecondaryOutputs ( ) . end ( ) ,
secondaryDescs . begin ( ) , secondaryDescs . end ( ) ) ) {
streamsToInvalidate . insert ( client - > stream ( ) ) ;
}
}
}
for ( audio_stream_type_t stream : streamsToInvalidate ) {
ALOGD ( " %s Invalidate stream %d due to secondary output change " , __func__ , stream ) ;
mpClientInterface - > invalidateStream ( stream ) ;
}
}
void AudioPolicyManager : : checkA2dpSuspend ( )
{
audio_io_handle_t a2dpOutput = mOutputs . getA2dpOutput ( ) ;