Análisis de Audio Focus basado en la plataforma Android O (principalmente combinado con Car) (abajo)

Relacionado con el coche

Después de buscar un poco, solo este lugar tiene configurado mFocusListener, usemos Car para investigar.

paquetes/servicios/Coche/servicio/src/com/android/coche/CarAudioService.java

 inicio vacío  público () {
    
   
AudioPolicy . Constructor constructor = nueva AudioPolicy . Constructor ( mContexto ); ... constructor . setAudioPolicyFocusListener ( mSystemFocusListener ); ... }        
    
        
    

mSystemFocusListener

//SystemFocusListener是CarAudioService的内部类
private  class  SystemFocusListener  extends  AudioPolicyFocusListener {
    
   
@Override public void onAudioFocusGrant ( AudioFocusInfo afi , int requestResult ) {
        ... if ( requestResult == AudioManager . AUDIOFOCUS_REQUEST_GRANTED ) {
    sincronizado ( mLock ) {
    mPending FocusChanges . agregarPrimero ( afi );                 } mFocusHandler  
      
   

        
   
                
   
                    

                .handleAndroidFocusChange (); 
            } 
    ... 
  } 
@Override public void onAudioFocusLoss ( AudioFocusInfo afi , boolean wasNotified ) {
    // No entiendo el motivo, en resumen, es seguro ignorar la pérdida como ganancia de seguimiento en este lugar. suficiente. Al menos el oyente inferior estará // siempre allí y recibiendo la concesión de atención. Por lo tanto, es seguro ignorar esto aquí.         } }  
  
            
   
            
            
            

Definición de mFocusHandler:

mFocusHandlerThread  =  nuevo  HandlerThread ( CarLog . TAG_AUDIO ); 
mFocusHandler  =  new  CarAudioFocusChangeHandler ( mFocusHandlerThread . getLooper ());

mFocusHandler.handleAndroidFocusChange

privado  void  handleAndroidFocusChange () {
    
   
cancelFocusReleaseRequest (); Mensaje msg = obtener Mensaje ( MSG_ANDROID_FOCUS_CHANGE ); enviarMensaje ( mensaje );         }            
               
            
case  MSG_ANDROID_FOCUS_CHANGE : 
doHandleAndroidFocusChange ( false /* triggerByStreamChange * /); romper ;                     
                    

Encontré una función más complicada doHandleAndroidFocusChange@CarAudioService

private  void  doHandleAndroidFocusChange ( boolean  triggerByStreamChange ) {
    
   
... //Se realizó durante onAudioFocusGrant@SystemFocusListener antes de //mPendingFocusChanges.addFirst(afi); newTopInfo = mPendingFocusChanges .getFirst (); //Esta es una LinkedList . No sé por qué mPendingFocusChanges debe borrarse inmediatamente después de getFirst .clear (); ... if ( newTopInfo ! = null ) {
    if ( newTopInfo . getGainRequest () == AudioManager .    
        
        
          
            
            
        
          
      
               
                    AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK ) {
    
   
//La nueva solicitud es para obtener un pato temporal //Deje que el antiguo jefe baje de categoría a adjunto mSecondaryFocusInfo = mPrimaryFocusInfo ; } else {
    //De lo contrario, no establezca el adjunto mSecondaryFocusInfo = null ;                 } //El nuevo se convierte en el jefe mPrimaryFocusInfo = newTopInfo ;           } //Consulte el análisis más adelante focusRequested = handleCarFocusRequestAndResponseLocked ();     ... //Si hay una respuesta, o es obligatorio un tiempo de espera if ( focusRequested ) {
    doHandleCarFocusChange ();         }                    
                    
                      
                
   
                    
                      

                
                  

        
           

        
        
   
            

}

newTopInfo se remonta a mFocusStack.peek().toAudioFocusInfo() de MediaFocusControl, que en realidad es la información actual del propietario del enfoque de audio en la parte superior de la pila mFocusStack.

Aquí primero hacemos un análisis de handleCarFocusRequestAndResponseLocked

private  boolean  handleCarFocusRequestAndResponseLocked () {
    
   
boolean focusRequested = reevaluateCarAudioFocusAndSendFocusLocked (); if ( focusRequested ) {
        ... // envía el cambio de contexto después de obtener la respuesta de enfoque. //处理context的改变!关键的新概念,CarAudioContext if ( mCarAudioContextChangeHandler != null ) {
    mCarAudioContextChangeHandler . requestContextChangeNotification ( mAudioContextChangeListener , mCurrentPrimaryAudioContext , mCurrentPrimaryPhysicalStream );     
  
   

      
      
        
   
                
                        
                        
      } 
// ¿Comprobar el estado de funcionamiento del bus can? checkCanStatus ();   } devuelve foco solicitado ; }    
      

   

Esta función finalmente devuelve focusRequested, devuelto desde reevaluateCarAudioFocusAndSendFocusLocked

Echemos un vistazo a esta enorme función.

reevaluarCarAudioFocusAndSendFocusLocked@CarAudioService

if ( mPrimaryFocusInfo  ==  null ) {
    
   
if ( mSystemSoundPhysicalStreamActive ) {
    // finalmente llamado mVehicleHal.set(AUDIO_FOCUS).to(payload); //payload = { request, streams, extFocus, audioContexts }; return requestFocusForSystemSoundOnlyCaseLocked ();    } . .. } ... // Después de una sección de evaluación del cálculo y la asignación, asigne //focusToRequest, streamsToRequest, extFocus, //audioContexts, routeHintChanged estos parámetros ... return sendFocusRequestToCarIfNecessaryLocked ( focusToRequest , streamsToRequest , extFocus ,   
   
        
        
      

    


    
    
    

  contextos de audio , rutaHintChanged ); 
}

Y sendFocusRequestToCarIfNecessaryLocked también llama

maudiohal . requestAudioFocusChange ( 
focusToRequest , streamsToRequest , extFocus , audioContexts );                    
                    
                    
                    

Entonces

int [] carga útil  = { solicitud , flujos , extFocus , audioContexts }; 
mVehicleHal . establecer ( AUDIO_ENFOQUE ). a ( carga útil );

Dado que se han analizado llamadas similares anteriormente, se requiere que el proveedor lo implemente más adelante.

hardware/interfaces/automoción/vehículo/2.0/tipos.hal

La primera son sus anotaciones (no se publica el texto original, hay demasiadas)

AUDIO_FOCUS  = ( 
0x0900 | VehiclePropertyGroup : SYSTEM | VehiclePropertyType : INT32_VEC | VehicleArea : GLOBAL ),        
         
         
         

Representa el estado del foco de audio en el lado de Android. Tenga en cuenta que el módulo de audio del automóvil debe tener foco de audio y otorgar (¿permiso, liberación?) foco de audio al lado de Android (cuando lo solicite el lado de Android). El foco tiene características de transmisión y características globales.

preguntar:

La solicitud de enfoque (obtener de esta propiedad) debe tener el siguiente formato (el índice definido en VehicleAudioFocusIndex) (al igual que la llamada anterior)

int32Values[0]: VehicleAudioFocusRequest tipo

int32Values[1]: indicadores de bit de flujos solicitados por esta solicitud de enfoque.

Puede haber hasta 32 flujos.

int32Values[2]:Indicadores de estado de foco externo....

int32Values[3]:Contextos de audio que desean estar activos....

respuesta:

Respuesta de enfoque (devolución de llamada establecida y de suscripción para esta propiedad)

int32Values[0]: tipo VehicleAudioFocusState

int32Values[1]: indicadores de bits de flujos permitidos.

int32Values[2]: Estado de foco externo...(GANANCIA,GANANCIA_TRANSIENT,PÉRDIDA,PÉRDIDA_TRANSIENT)

int32Values[3]: contexto(s) de audio que pueden estar activos. Al responder positivamente a un

solicitud de enfoque de Android, el contexto original de la solicitud debe ser

repetido aquí. Al desviar el foco, o negar una solicitud, el

el contexto rechazado o detenido tendría su bit correspondiente borrado.

Contexto de audio: Cuando se aprueba, repite la solicitud, si se rechaza o se detiene, el contexto debe borrar el bit correspondiente.

Cada solicitud de enfoque debe tener una respuesta de enfoque, incluso si el estado de enfoque no ha cambiado. Esto puede suceder en el caso de una solicitud de enfoque

solo implica un cambio de contexto donde el lado de Android todavía necesita una respuesta de enfoque coincidente para confirmar que el módulo de audio ha realizado los cambios necesarios (contexto 有变化的时候).

Si el automóvil no es compatible con AUDIO_FOCUS, se supone que siempre se otorga el enfoque.

//Una propiedad para permitir que un componente externo controle el foco de audio. 
//No sé qué hacer.//El 
formato de datos es el mismo que la propiedad AUDIO_FOCUS.(El formato de datos es el mismo que AUDIO_FOCUS) 
AUDIO_FOCUS_EXT_SYNC  = ( 
0x0910 | VehiclePropertyGroup : SYSTEM | VehiclePropertyType : INT32_VEC | VehicleArea : GLOBAL ),        
         
         
         

El VehicleAudioFocusIndex mencionado en los comentarios

/** 
* Índice en int32Values ​​para la propiedad VehicleProperty#AUDIO_FOCUS. */ enum VehicleAudioFocusIndex : int32_t {
    FOCUS = 0 , FLUJOS = 1 , EXTERNAL_FOCUS_STATE = 2 , AUDIO_CONTEXTS = 3 , }; 
 
 
   
      
      
      
      

Ejemplo de VehicleAudioFocusIndex (la definición de VehicleAudioFocusIndex se genera automáticamente):

servicios/Coche/servicio/src/com/android/coche/hal/AudioHalService.java

... 
int focusState = vec . get ( VehículoAudioFocusIndex . FOCUS ); flujos int = vec . get ( VehículoAudioFocusIndex . FLUJOS ); int focoexterno = vec . get ( VehicleAudioFocusIndex . EXTERNAL_FOCUS_STATE ); ...       
       
       

Ejemplo de uso de AudioContext:

/packages/services/Car/service/src/com/android/car/VolumeUtils.java

public  static  final  int [] CAR_AUDIO_CONTEXT  = {
    
   
VehicleAudioContextFlag . MUSIC_FLAG , VehicleAudioContextFlag . NAVIGATION_FLAG , VehicleAudioContextFlag . VOICE_COMMAND_FLAG , VehicleAudioContextFlag . CALL_FLAG , Indicador de contexto de audio del vehículo . ALARM_FLAG Indicador de contexto de audio del vehículo . NOTIFICATION_FLAG , VehicleAudioContextFlag . UNKNOWN_FLAG , VehicleAudioContextFlag . SAFETY_ALERT_BANDERA    
    
    
    
    
    
    
    , 
Indicador de contexto de audio del vehículo . CD_ROM_FLAG , VehicleAudioContextFlag . AUX_AUDIO_FLAG , Indicador de contexto de audio del vehículo . SYSTEM_SOUND_FLAG , VehicleAudioContextFlag . RADIO_BANDERA }; //Android传统的stream到CarContext的转换public static int androidStreamToCarContext ( int logicalAndroidStream ) {
    switch ( logicalAndroidStream ) {
    case AudioManager . STREAM_VOICE_CALL : devuelve VehicleAudioContextFlag .    
    
    
    


    
   
        
   
             
                 LLAMADA_BANDERA ; 
caso AudioManager . STREAM_SYSTEM : devuelve VehicleAudioContextFlag . SISTEMA_SONIDO_BANDERA ; caso AudioManager . STREAM_RING : devuelve VehicleAudioContextFlag . LLAMADA_BANDERA ; caso AudioManager . STREAM_MUSIC : devuelve VehicleAudioContextFlag . MÚSICA_BANDERA ; caso AudioManager . STREAM_ALARM : devuelve VehicleAudioContextFlag . ALARMA_BANDERA ;             
                 
             
                 
             
                 
             
                 
            caso  AudioManager . STREAM_NOTIFICATION : 
devuelve VehicleAudioContextFlag . NOTIFICACIÓN_BANDERA ; caso AudioManager . STREAM_DTMF : devuelve VehicleAudioContextFlag . SISTEMA_SONIDO_BANDERA ; predeterminado : devuelve VehicleAudioContextFlag . BANDERA_DESCONOCIDA ;         } }                     
             
                 
            
                 


Vi el ejemplo de mVehicleHal.set(AUDIO_FOCUS).to(payload) anteriormente. Averigüemos de nuevo, el proceso de respuesta en el lado del vehículo.

onPropertyEvent@VehicleHal

@Override 
public  void  onPropertyEvent ( ArrayList < VehiclePropValue >  propValues ​​) {
    
   
for ( VehiclePropValue v : propValues ​​) {
    //mPropertyHandlers已经存有对应关系HalServiceBase service = mPropertyHandlers . obtener ( v . prop ); servicio _ getDispatchList (). agregar ( v ); mServicesToDispatch . agregar ( servicio );   }   
   
    
       
    
    

  ... 
para ( HalServiceBase s : mServicesToDispatch ) {
    s . handleHalEvents ( s . getDispatchList ());            ...   } }   
   
            


Debido a que VehicleHal ya ha atado las propiedades que le importan a cada servicio al llamar a init, por lo que cuando haya un evento popValues ​​en este lugar, puede encontrar el servicio correspondiente.Si no me cree, eche un vistazo:

//init@VehicleHal 
Collection < VehiclePropConfig >  tomado  =  servicio . TakeSupportedProperties ( propiedades ); 
for ( VehiclePropConfig p : tomado ) {
    mPropertyHandlers . agregar ( p . prop , servicio ); }  
   
   

takeSupportedProperties@AudioHalService

@Override 
public sincronizado Collection < VehiclePropConfig > takeSupportedProperties ( Collection < VehiclePropConfig > allProperties ) {
    for ( VehiclePropConfig p : allProperties ) {
    switch ( p . prop ) {
    //Estos son todos los accesorios que le interesan a nuestro AudioHalService. case Vehicle AUDProperty_ . : case VehicleProperty AUDIO_VOLUME : case VehicleProperty _       
             
   
         
   
            
   
                
                 
                 
                 . AUDIO_VOLUME_LIMIT : 
caso VehicleProperty . AUDIO_HW_VARIANT : caso PropiedadVehículo . AUDIO_EXT_ROUTING_HINT : caso VehicleProperty . AUDIO_PARAMETERS : case VehicleProperty . AUDIO_STREAM_STATE : mProperties . poner ( p . prop , p ); romper ;             }         } devuelve nueva ArrayList <> ( mProperties . valores                 
                 
                 
                 
                    
                    


          ()); 
    }

El anterior s.handleHalEvents es

handleHalEvents@AudioHalService

@Override 
public void handleHalEvents ( List < VehiclePropValue > valores ) {
    AudioHalFocusListener focusListener ; AudioHalVolumeListener volumenListener ; OnParameterChangeListener parámetroListener ; sincronizado ( esto ) {
    focusListener = mFocusListener ; VolumeListener = mVolumeListener ; parameterListener = mOnParameterChangeListener ;         } DispatchEventToListener (       
   
         
         
         
        
   
              
              
              

        focusListener , volumenListener , parámetroListener , valores ); 
    }

El VehicleAudioFocusIndex mencionado anteriormente aparecerá pronto

dispatchEventToListener@AudioHalService

... 
caso PropiedadVehículo . AUDIO_FOCUS : {
    ArrayList < Integer > vec = v . valor _ int32Valores ; //即是types.hal中定义的AUDIO_FOCUS的response方式(¿dónde está Audio Context?) int focusState = vec . get ( VehículoAudioFocusIndex . FOCUS ); flujos int = vec . get ( VehículoAudioFocusIndex . FLUJOS ); int externalFocus = vec   
   
           
        
           
           
           . get ( VehicleAudioFocusIndex . EXTERNAL_FOCUS_STATE ); 
if ( focusListener != null ) {
    focusListener . onFocusChange ( focusState , streams , externalFocus );         }   } ...          
   
           


Quien es este Listrner, no te lo pienses, eso es todo

onFocusChange@CarAudioService

@Override 
public void onFocusChange ( int focusState , int streams , int externalFocus ) {
    sincronizado ( mLock ) {
    mFocusReceived = FocusState . crear ( focusState , streams , externalFocus ); // activa el subproceso esperando la respuesta del foco. mlock . notificar a todos ();         }                                                 mFocusHandler . manejarCambioEnfoque ();         
   
        
   
              
            
            

        
    }

Después de omitir algunos pasos, aquí estamos.

doHandleCarFocusChange@CarAudioService

private  void  doHandleCarFocusChange () {
    
   
  ... 
newFocusState = ???     ... switch ( newFocusState ) {
    case AudioHalService . VEHICLE_AUDIO_FOCUS_STATE_GAIN : doHandleFocusGainFromCar ( mCurrentFocusState , topInfo , systemSoundActive ); romper ; caso AudioHalService . VEHICLE_AUDIO_FOCUS_STATE_GAIN_TRANSIENT : doHandleFocusGainTransientFromCar ( mCurrentFocusState , topInfo ,      

    
   
             
                
                
             
                sonido del sistema activo ); 
romper ; caso AudioHalService . VEHICLE_AUDIO_FOCUS_STATE_LOSS : doHandleFocusLossFromCar ( mCurrentFocusState , topInfo ); romper ; caso AudioHalService . VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT : doHandleFocusLossTransientFromCar ( mCurrentFocusState ); romper ; caso AudioHalService . VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT_CAN_DUCK : doHandleFocusLossTransientCanDuckFromCar ( mCurrentFocusState                
             
                
                
             
                
                
             
                ); 
romper ; caso AudioHalService . VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT_EXLCUSIVE : doHandleFocusLossTransientExclusiveFromCar ( mCurrentFocusState ); romper ;         } }                
             
                
                

Llame a doHandleFocus (Ganancia/Ganancia transitoria/Pérdida/Pérdida transitoria/LossTransientCanDuck/

LossTransientExclusive)FromCar Esta serie de funciones básicamente llama a mAudioManager.abandonAudioFocus y otras funciones tradicionales.

Supongo que te gusta

Origin blog.csdn.net/bberdong/article/details/79268379
Recomendado
Clasificación