Android O プラットフォーム (主に Car と組み合わせたもの) に基づく Audio Focus 分析 (以下)

車関連

調べてみると、mFocusListener が設定されているのはここだけなので、Car を使って調べてみましょう。

パッケージ/サービス/車/サービス/src/com/android/car/CarAudioService.java

public  void  init () {
    
   
AudioPolicy . ビルダービルダー=新しいAudioPolicy . ビルダー( mContext ); ...ビルダーsetAudioPolicyFocusListener ( mSystemFocusListener ); ... }        
    
        
    

mSystemFocusListener

//SystemFocusListenerはCarAudioServiceの内部类
private  class  SystemFocusListener  extends  AudioPolicyFocusListener {
    
   
@Override public void onAudioFocusGrant ( AudioFocusInfo afi , int requestResult ) {
        ... if ( requestResult == AudioManager . AUDIOFOCUS_REQUEST_GRANTED ) {
    synchronized ( mLock ) {
    mPendingFocusChanges . addFirst ( afi );                 mFocusHandler _  
      
   

        
   
                
   
                    

                .handleAndroidFocusChange (); 
            } 
    ... 
  } 
@Override public void onAudioFocusLoss ( AudioFocusInfo afi , boolean wasNotified ) {
    // 理由がわかりません。要するに、この場所ではトラッキング ゲインとしてロスを無視しても安全です。少なくとも一番下のリスナーは// 常にそこにあり、フォーカス許可を取得します. したがって、ここではこれを無視しても安全です.         } }  
  
            
   
            
            
            

mFocusHandler の定義:

mFocusHandlerThread  = 新しい HandlerThread ( CarLog . TAG_AUDIO ); 
mFocusHandler  =  new  CarAudioFocusChangeHandler ( mFocusHandlerThread . getLooper ());

mFocusHandler.handleAndroidFocusChange

private  void  handleAndroidFocusChange () {
    
   
cancelFocusReleaseRequest (); メッセージmsg = getsMessage ( MSG_ANDROID_FOCUS_CHANGE ); sendMessage (メッセージ);         }            
               
            
case  MSG_ANDROID_FOCUS_CHANGE : 
doHandleAndroidFocusChange ( false /* triggerByStreamChange * / ); 休憩;                     
                    

より複雑な関数 doHandleAndroidFocusChange@CarAudioService に遭遇しました

private  void  doHandleAndroidFocusChange ( boolean  triggerByStreamChange ) {
    
   
... //mPendingFocusChanges.addFirst(afi ); newTopInfo = mPendingFocusChanges .getFirst (); //これは LinkedList ですgetFirst . clear (); ... if ( newTopInfo != null ) {
    if ( newTopInfo . getGainRequest () == AudioManager .    
        
        
          
            
            
        
          
      
               
                    AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK ) {
    
   
//新しいリクエストは、一時的なアヒルを取得することです//前のボスを代理人に降格させますmSecondaryFocusInfo = mPrimaryFocusInfo ; } else {
    //それ以外の場合、代理人を設定しないでくださいmSecondaryFocusInfo = null ;                 } //新しいものボスになるmPrimaryFocusInfo = newTopInfo ;           } //後で解析を参照してくださいfocusRequested = handleCarFocusRequestAndResponseLocked ();     ... //応答がある場合、またはタイムアウトが必須if ( focusRequested ) {
    doHandleCarFocusChange ();         }                    
                    
                      
                
   
                    
                      

                
                  

        
           

        
        
   
            

}

newTopInfo は MediaFocusControl の mFocusStack.peek().toAudioFocusInfo() までさかのぼります。これは、実際には mFocusStack スタックの一番上にある現在のオーディオ フォーカス所有者情報です!

ここでは、最初に handleCarFocusRequestAndResponseLocked の分析を行います

private  boolean  handleCarFocusRequestAndResponseLocked () {
    
   
boolean focusRequested = reevaluateCarAudioFocusAndSendFocusLocked (); if ( focusRequested ) {
        ... // フォーカス応答を取得した後、コンテキスト変更を送信します。关键的新概念,CarAudioContext if ( mCarAudioContextChangeHandler != null ) {
    mCarAudioContextChangeHandler . requestContextChangeNotification ( mAudioContextChangeListenermCurrentPrimaryAudioContextmCurrentPrimaryPhysicalStream );     
  
   

      
      
        
   
                
                        
                        
      } 
// キャンバスの稼働状況をチェック?checkCanStatus ();   } return focusRequested ; }    
      

   

この関数は最後に、reevaluateCarAudioFocusAndSendFocusLocked から返された focusRequested を返します。

この巨大な関数を見てみましょう。

reevaluateCarAudioFocusAndSendFocusLocked@CarAudioService

if ( mPrimaryFocusInfo  ==  null ) {
    
   
if ( mSystemSoundPhysicalStreamActive ) {
    // 最後に mVehicleHal.set(AUDIO_FOCUS).to(payload) を呼び出し; //payload = { リクエスト、ストリーム、extFocus、audioContexts }; return requestFocusForSystemSoundOnlyCaseLocked ();    } . .. } ... // 計算と割り当てを判断するセクションの後、割り当て//focusToRequest、streamsToRequest、extFocus、//audioContexts、routingHintChanged これらのパラメータ... return sendFocusRequestToCarIfNecessaryLocked ( focusToRequest , streamsToRequest , extFocus ,   
   
        
        
      

    


    
    
    

  audioContextsroutingHintChanged ); 
}

そして sendFocusRequestToCarIfNecessaryLocked も呼び出します

mAudioHal . requestAudioFocusChange ( 
focusToRequeststreamToRequestextFocusaudioContexts );                    
                    
                    
                    

それから

int []ペイロード = {リクエストストリームextFocusaudioContexts }; 
mVehicleHal . 設定( AUDIO_FOCUS )。(ペイロード);

同様の呼び出しが以前に分析されているため、ベンダーはそれをさらに下に実装する必要があります。

ハードウェア/インターフェース/自動車/車両/2.0/types.hal

最初はその注釈です(原文は掲載されていません、多すぎます)

AUDIO_FOCUS  = ( 
0x0900 | VehiclePropertyGroup :システム| VehiclePropertyType : INT32_VEC | VehicleArea : GLOBAL ),        
         
         
         

Android 側のオーディオ フォーカス ステータスを表します。車のオーディオ モジュールにはオーディオ フォーカスが必要であり、Android 側にオーディオ フォーカスを付与 (許可、解放?) する必要があることに注意してください (Android 側から要求された場合)。フォーカスには、ストリーム特性と両方の特性があります。グローバルな特徴。

聞く:

フォーカス リクエスト (このプロパティの取得) は、次の形式 (VehicleAudioFocusIndex で定義されたインデックス) である必要があります (上記の呼び出しと同様)。

int32Values[0]: VehicleAudioFocusRequest タイプ

int32Values[1]: このフォーカス要求によって要求されたストリームのビット フラグ。

最大 32 のストリームが存在できます。

int32Values[2]: 外部フォーカス状態フラグ....

int32Values[3]:アクティブになりたいオーディオ コンテキスト....

応答:

フォーカス レスポンス (このプロパティの設定およびサブスクリプション コールバック)

int32Values[0]: VehicleAudioFocusState タイプ

int32Values[1]: 許可されるストリームのビット フラグ。

int32Values[2]: 外部フォーカス状態...(GAIN,GAIN_TRANSIENT,LOSS,LOSS_TRANSIENT)

int32Values[3]:アクティブにできるオーディオ コンテキスト。

Android からのフォーカス リクエストの場合、リクエストの元のコンテキストは

ここで繰り返されます。フォーカスを外したり、リクエストを拒否したりすると、

拒否または停止されたコンテキストでは、対応するビットがクリアされます。

オーディオ コンテキスト: 承認された場合は、要求を繰り返します。拒否または停止された場合、コンテキストは対応するビットをクリアする必要があります。

フォーカス状態が変更されていない場合でも、各フォーカス リクエストにはフォーカス レスポンスが必要です。これは、フォーカス リクエストのような場合に発生する可能性があります。

オーディオモジュールが必要な変更を行ったことを確認するために、Android側で一致するフォーカス応答が必要なコンテキストの変更のみを伴います(context有变化的時候)。

車が AUDIO_FOCUS をサポートしていない場合、フォーカスは常に許可されていると見なされます。

//外部コンポーネントがオーディオフォーカスを制御できるようにするためのプロパティ
//どうしたらいいのかわからない//データ
形式はAUDIO_FOCUSプロパティと同じ (データ形式はAUDIO_FOCUSと同じ) 
AUDIO_FOCUS_EXT_SYNC  = ( 
0x0910 | VehiclePropertyGroup : SYSTEM | VehiclePropertyType : INT32_VEC | VehicleArea : GLOBAL )、        
         
         
         

コメントに記載されている VehicleAudioFocusIndex

/** 
* VehicleProperty#AUDIO_FOCUS プロパティの int32Values のインデックス。*/ enum VehicleAudioFocusIndex : int32_t {
    FOCUS = 0 , STREAMS = 1 , EXTERNAL_FOCUS_STATE = 2 , AUDIO_CONTEXTS = 3 , }; 
 
 
   
      
      
      
      

VehicleAudioFocusIndex の例 (VehicleAudioFocusIndex の定義は自動的に生成されます):

サービス/車/サービス/src/com/android/車/hal/AudioHalService.java

... 
int focusState = vec . get ( VehicleAudioFocusIndex . FOCUS ); intストリーム= vec . get ( VehicleAudioFocusIndex . STREAMS ); int externalFocus = vec . get ( VehicleAudioFocusIndex . EXTERNAL_FOCUS_STATE ); ...       
       
       

AudioContext の使用例:

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

public  static  final  int [] CAR_AUDIO_CONTEXT  = {
    
   
VehicleAudioContextFlag . MUSIC_FLAGVehicleAudioContextFlagNAVIGATION_FLAGVehicleAudioContextFlagVOICE_COMMAND_FLAGVehicleAudioContextFlagCALL_FLAGVehicleAudioContextFlagALARM_FLAG VehicleAudioContextFlagNOTIFICATION_FLAGVehicleAudioContextFlagUNKNOWN_FLAGVehicleAudioContextFlagSAFETY_ALERT_FLAG    
    
    
    
    
    
    
    
VehicleAudioContextFlagCD_ROM_FLAGVehicleAudioContextFlagAUX_AUDIO_FLAGVehicleAudioContextFlagSYSTEM_SOUND_FLAGVehicleAudioContextFlagRADIO_FLAG }; //android传统的ストリームがCarContextに到達する转换public static int androidStreamToCarContext ( int logicalAndroidStream ) {
    switch ( logicalAndroidStream ) {
    case AudioManager . STREAM_VOICE_CALL : VehicleAudioContextFlagを返します    
    
    
    


    
   
        
   
             
                 CALL_FLAG ; 
ケースAudioManagerSTREAM_SYSTEM : VehicleAudioContextFlagを返しますSYSTEM_SOUND_FLAG ; ケースAudioManagerSTREAM_RING : VehicleAudioContextFlagを返しますRINGTONE_FLAG ; ケースAudioManagerSTREAM_MUSIC : VehicleAudioContextFlagを返しますMUSIC_FLAG ; ケースAudioManagerSTREAM_ALARM : VehicleAudioContextFlagを返しますALARM_FLAG ;             
                 
             
                 
             
                 
             
                 
            ケース AudioManagerSTREAM_NOTIFICATION : 
VehicleAudioContextFlagを返しますNOTIFICATION_FLAG ; ケースAudioManagerSTREAM_DTMF : VehicleAudioContextFlagを返しますSYSTEM_SOUND_FLAG ; デフォルト: VehicleAudioContextFlagを返しますUNKNOWN_FLAG ;         } }                     
             
                 
            
                 


先ほどmVehicleHal.set(AUDIO_FOCUS).to(payload)の例を見ましたが、改めて車両側の応答の流れを見てみましょう。

onPropertyEvent@VehicleHal

@Override 
public  void  onPropertyEvent ( ArrayList < VehiclePropValue >  propValues ) {
    
   
for ( VehiclePropValue v : propValues ) {
    //mPropertyHandlers已经存有対応关系HalServiceBase service = mPropertyHandlers . get ( v . prop ); サービスgetDispatchList ()。追加( v ); mServicesToDispatch追加(サービス);   }   
   
    
       
    
    

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


VehicleHal は init を呼び出すときに各サービスが気にするプロパティを既にバインドしているため、この場所に popValues イベントがあると、対応するサービスを見つけることができます。

//init@VehicleHal
コレクション< VehiclePropConfig > 取得 = サービス. takeSupportedProperties (プロパティ); 
for ( VehiclePropConfig p :取得) {
    mPropertyHandlers . append ( p . prop , service ); }  
   
   

takeSupportedProperties@AudioHalService

@Override 
public synchronized Collection < VehiclePropConfig > takeSupportedProperties ( Collection < VehiclePropConfig > allProperties ) {
    for ( VehiclePropConfig p : allProperties ) {
    switch ( p . prop ) {
    //AudioHalService が気にするすべての props. case Vehicle AUDProperty_ . : case VehicleProperty . AUDIO_VOLUME : case VehicleProperty       
             
   
         
   
            
   
                
                 
                 
                 . AUDIO_VOLUME_LIMIT :
車両プロパティの場合AUDIO_HW_VARIANT :ケースVehiclePropertyAUDIO_EXT_ROUTING_HINT :ケースVehiclePropertyAUDIO_PARAMETERS : case VehicleProperty . AUDIO_STREAM_STATE : mProperties . put ( p . prop , p ); 休憩;             }         }新しいArrayList <>を返します( mProperties . values                 
                 
                 
                 
                    
                    


          ()); 
    }

上記の s.handleHalEvents は

handleHalEvents@AudioHalService

@Override 
public void handleHalEvents ( List < VehiclePropValue >) {
    AudioHalFocusListener focusListener ; AudioHalVolumeListenerボリュームリスナー; OnParameterChangeListener parameterListener ; 同期(これ) {
    focusListener = mFocusListener ; volumeListener = mVolumeListener ; parameterListener = mOnParameterChangeListener ;         } dispatchEventToListener (       
   
         
         
         
        
   
              
              
              

        focusListenervolumeListenerparameterListener); 
    }

上記の VehicleAudioFocusIndex はまもなく登場します

dispatchEventToListener@AudioHalService


場合_ AUDIO_FOCUS : {
    ArrayList <整数> vec = v . int32Values ; //即是types.halで定義されたAUDIO_FOCUSの応答方法(Audio Contextはどこ?) int focusState = vec . get ( VehicleAudioFocusIndex . FOCUS ); intストリーム= vec . get ( VehicleAudioFocusIndex . STREAMS ); int externalFocus = vec   
   
           
        
           
           
           . get ( VehicleAudioFocusIndex . EXTERNAL_FOCUS_STATE ); 
if ( focusListener != null ) {
    focusListener . onFocusChange ( focusStateストリームexternalFocus );         }   } ...          
   
           


このListrnerは誰ですか、考えないでください、それだけです

onFocusChange@CarAudioService

@Override 
public void onFocusChange ( int focusState , int stream , int externalFocus ) {
    synchronized ( mLock ) {
    mFocusReceived = FocusState . 作成( focusStateストリームexternalFocus ); // フォーカス応答を待っているスレッドを起動します。mロック通知すべて();         mFocusHandler                                                 . _ handleFocusChange ();         
   
        
   
              
            
            

        
    }

いくつかの手順を省略した後、ここにあります

doHandleCarFocusChange@CarAudioService

private  void  doHandleCarFocusChange () {
    
   
  ... 
newFocusState = ???     ... switch ( newFocusState ) {
    case AudioHalService . VEHICLE_AUDIO_FOCUS_STATE_GAIN : doHandleFocusGainFromCar ( mCurrentFocusState , topInfo , systemSoundActive ); 休憩; ケースAudioHalServiceVEHICLE_AUDIO_FOCUS_STATE_GAIN_TRANSIENT : doHandleFocusGainTransientFromCar ( mCurrentFocusState , topInfo ,      

    
   
             
                
                
             
                システムサウンドアクティブ); 
休憩; ケースAudioHalServiceVEHICLE_AUDIO_FOCUS_STATE_LOSS : doHandleFocusLossFromCar ( mCurrentFocusState , topInfo ); 休憩; ケースAudioHalServiceVEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT : doHandleFocusLossTransientFromCar ( mCurrentFocusState ); 休憩; ケースAudioHalServiceVEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT_CAN_DUCK : doHandleFocusLossTransientCanDuckFromCar ( mCurrentFocusState                
             
                
                
             
                
                
             
                ); 
休憩; ケースAudioHalServiceVEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT_EXLCUSIVE : doHandleFocusLossTransientExclusiveFromCar ( mCurrentFocusState ); 休憩;         } }                
             
                
                

doHandleFocus(Gain/GainTransient/Loss/LossTransient/LossTransientCanDuck/を呼び出す

LossTransientExclusive)FromCar この一連の関数は、基本的に mAudioManager.abandonAudioFocus およびその他の従来の関数を呼び出します。

おすすめ

転載: blog.csdn.net/bberdong/article/details/79268379