Android Pのオーディオアーキテクチャ(二)


Android Pのオーディオ戦略分析
本文は主にAudioPolicy部分を説明して、オーディオの策略の流れの分析に対して、オーディオの策略のコードはframeworksavservicesaudiopolicyの中で.
AudioPolicyService
AudioPolicyServiceはAndroidオーディオシステムの2つの大きなサービスの1つで、パスはframeworksavservicesaudiopolicyserviceAudioPolicyServiceです.cpp
AudioPolicyServiceは主に次のタスクを完了します.
  • JAVAアプリケーション層はJNIを介してIAudioPolicyServiceインターフェースを介してAudioPolicyServiceが提供するサービス
  • にアクセスする.
  • 入出力装置の接続状態
  • システムのルーティングポリシーの切り替え
  • 音量パラメータの設定
  • AudioPolicyServiceの詳細:
  • AudioPolicyServiceはAudioPolicyClientInterfaceクラスも継承しています.彼はAudioPolicyInterfaceクラスのメンバーポインタmAudioPolicyManagerを持っています.実際にはAudioPolicyManagerを指しています.
  • AudioPolicyManagerクラスは、AudioPolicyInterfaceクラスを継承してAudioPolicyServiceにサービスを提供する.逆に、構造関数で初期化され、AudioPolicyServiceを指すAudioPolicyClientInterfaceポインタもある.実際には、AudioPolicyServiceはメンバーポインタmAudioPolicyManagerを介してAudioPolicyManagerにアクセスする.AudioPolicyManagerはAudioPolicyClientInterface(mpClientInterface)を通じてAudioPolicyServiceにアクセスします.
  • AudioPolicyServiceには内部スレッドクラスAudioCommandThreadがあり、その名の通り、すべてのコマンド(ボリューム制御、入出力の切り替えなど)が最終的にこのスレッドに並んで実行されます.

  • AudioPolicyServiceの管理作業の大部分はAudioPolicyManagerで行われています.ボリューム管理、ルーティングポリシー管理、入出力装置管理を含む.次に、AudioPolicyManagerを重点的に見てみましょう.cppファイル
    AudioPolicyManager
    AudioPolicyManagerは主にルーティングポリシー管理と入出力デバイスの管理を完了し、そのパスはframeworksavservicesaudiopolicymanagerdefaultAudioPolicyManagerである.cpp
    一、入出力設備管理
    Audioシステムでは、ファイルaudio-baseに定義されたいくつかの入出力装置が定義.hで、このファイルのパスは、systemmediaaudioincludesystemaudio-base.h
    次のように定義します.
    enum {
        AUDIO_DEVICE_NONE                          = 0x0u,
        AUDIO_DEVICE_BIT_IN                        = 0x80000000u,
        AUDIO_DEVICE_BIT_DEFAULT                   = 0x40000000u,
    
        AUDIO_DEVICE_OUT_EARPIECE                  = 0x1u,		//  
        AUDIO_DEVICE_OUT_SPEAKER                   = 0x2u,		//   
        AUDIO_DEVICE_OUT_WIRED_HEADSET             = 0x4u,		//      
        AUDIO_DEVICE_OUT_WIRED_HEADPHONE           = 0x8u,		//       
        AUDIO_DEVICE_OUT_BLUETOOTH_SCO             = 0x10u,		//  ,    (SCO)  ,        
        AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET     = 0x20u,		//    ,   
        AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT      = 0x40u,		//      
        AUDIO_DEVICE_OUT_BLUETOOTH_A2DP            = 0x80u,		//     
        AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100u,	//        
        AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER    = 0x200u,	//     
        AUDIO_DEVICE_OUT_AUX_DIGITAL               = 0x400u,	//Aux
        AUDIO_DEVICE_OUT_HDMI                      = 0x400u,      // OUT_AUX_DIGITAL
        AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET         = 0x800u,
        AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET         = 0x1000u,
        AUDIO_DEVICE_OUT_USB_ACCESSORY             = 0x2000u,
        AUDIO_DEVICE_OUT_USB_DEVICE                = 0x4000u,
        AUDIO_DEVICE_OUT_REMOTE_SUBMIX             = 0x8000u,
        AUDIO_DEVICE_OUT_TELEPHONY_TX              = 0x10000u,
        AUDIO_DEVICE_OUT_LINE                      = 0x20000u,
        AUDIO_DEVICE_OUT_HDMI_ARC                  = 0x40000u,
        AUDIO_DEVICE_OUT_SPDIF                     = 0x80000u,
        AUDIO_DEVICE_OUT_FM                        = 0x100000u,
        AUDIO_DEVICE_OUT_AUX_LINE                  = 0x200000u,
        AUDIO_DEVICE_OUT_SPEAKER_SAFE              = 0x400000u,
        AUDIO_DEVICE_OUT_IP                        = 0x800000u,
        AUDIO_DEVICE_OUT_BUS                       = 0x1000000u,
        AUDIO_DEVICE_OUT_PROXY                     = 0x2000000u,
        AUDIO_DEVICE_OUT_USB_HEADSET               = 0x4000000u,
        AUDIO_DEVICE_OUT_HEARING_AID               = 0x8000000u,
        AUDIO_DEVICE_OUT_ECHO_CANCELLER            = 0x10000000u,
        AUDIO_DEVICE_OUT_DEFAULT                   = 0x40000000u, // BIT_DEFAULT
    
        AUDIO_DEVICE_IN_COMMUNICATION              = 0x80000001u, // BIT_IN | 0x1
        AUDIO_DEVICE_IN_AMBIENT                    = 0x80000002u, // BIT_IN | 0x2
        AUDIO_DEVICE_IN_BUILTIN_MIC                = 0x80000004u, // BIT_IN | 0x4
        AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET      = 0x80000008u, // BIT_IN | 0x8
        AUDIO_DEVICE_IN_WIRED_HEADSET              = 0x80000010u, // BIT_IN | 0x10
        AUDIO_DEVICE_IN_AUX_DIGITAL                = 0x80000020u, // BIT_IN | 0x20
        AUDIO_DEVICE_IN_HDMI                       = 0x80000020u, // IN_AUX_DIGITAL
        AUDIO_DEVICE_IN_VOICE_CALL                 = 0x80000040u, // BIT_IN | 0x40
        AUDIO_DEVICE_IN_TELEPHONY_RX               = 0x80000040u, // IN_VOICE_CALL
        AUDIO_DEVICE_IN_BACK_MIC                   = 0x80000080u, // BIT_IN | 0x80
        AUDIO_DEVICE_IN_REMOTE_SUBMIX              = 0x80000100u, // BIT_IN | 0x100
        AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET          = 0x80000200u, // BIT_IN | 0x200
        AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET          = 0x80000400u, // BIT_IN | 0x400
        AUDIO_DEVICE_IN_USB_ACCESSORY              = 0x80000800u, // BIT_IN | 0x800
        AUDIO_DEVICE_IN_USB_DEVICE                 = 0x80001000u, // BIT_IN | 0x1000
        AUDIO_DEVICE_IN_FM_TUNER                   = 0x80002000u, // BIT_IN | 0x2000
        AUDIO_DEVICE_IN_TV_TUNER                   = 0x80004000u, // BIT_IN | 0x4000
        AUDIO_DEVICE_IN_LINE                       = 0x80008000u, // BIT_IN | 0x8000
        AUDIO_DEVICE_IN_SPDIF                      = 0x80010000u, // BIT_IN | 0x10000
        AUDIO_DEVICE_IN_BLUETOOTH_A2DP             = 0x80020000u, // BIT_IN | 0x20000
        AUDIO_DEVICE_IN_LOOPBACK                   = 0x80040000u, // BIT_IN | 0x40000
        AUDIO_DEVICE_IN_IP                         = 0x80080000u, // BIT_IN | 0x80000
        AUDIO_DEVICE_IN_BUS                        = 0x80100000u, // BIT_IN | 0x100000
        AUDIO_DEVICE_IN_PROXY                      = 0x81000000u, // BIT_IN | 0x1000000
        AUDIO_DEVICE_IN_USB_HEADSET                = 0x82000000u, // BIT_IN | 0x2000000
        AUDIO_DEVICE_IN_BLUETOOTH_BLE              = 0x84000000u, // BIT_IN | 0x4000000
        AUDIO_DEVICE_IN_DEFAULT                    = 0xC0000000u, // BIT_IN | BIT_DEFAULT
    };
    

    1.audio_についてpolicy_configuration.xmlファイルの解析
    Android Pは、オーディオトポロジを記述するための新しいオーディオポリシープロファイルフォーマット(XML)を導入した.
    新しいXMLファイルは、出力入力ストリームプロファイル、再生およびキャプチャに使用できるデバイス、およびオーディオ属性の数とタイプを定義することをサポートします.さらに、XML形式では、次のような拡張機能も用意されています.
  • オーディオプロファイルの現在の構造は、HDMIの単純オーディオ記述子と同様であり、各オーディオフォーマットが異なるサンプリングレート/チャネルマスクのセットを使用することをサポートする.
  • デバイスとストリームとの間のすべての接続の明示的な定義.従来、暗黙的なルールにより、同じHALモジュールに接続されたすべてのデバイスを相互接続することができ、オーディオポリシー制御がオーディオパッチAPI要求を使用する接続を阻止することができた.ここで、XMLフォーマットでは、トポロジ記述が接続制限を定義します.
  • の「含む」サポートにより、標準A 2 DP、USB、またはコミット定義の再ガイドが繰り返されることを回避できます.
  • でカスタマイズ可能なボリュームカーブ.従来、ボリュームテーブルはハードコーディング形式を採用していた.XML形式では、音量テーブルは記述によって定義され、カスタマイズ可能である.

  • オーディオ入出力のxmlプロファイルのデフォルトパスは、frameworksavservicesaudiopolicyconfigaudio_です.policy_configuration.xml; しかし、実際の開発プラットフォームは異なり、オーディオデバイスは異なり、プロファイルの経路は一般的に開発プラットフォームに基づいてdeviceディレクトリの下に置かれ、例えば:devicefslimx 8 qmek_8q\audio_policy_configuration.xml、このディレクトリのファイルはデフォルトのパスの下のファイルを上書きし、有効なファイルになります.
    //audio_policy_configuration.xml  
    <audioPolicyConfiguration version="1.0" xmlns:xi="http://www.w3.org/2001/XInclude">
        <globalConfiguration speaker_drc_enabled="true"/>
        <modules>
        	//     HwModule  
            <module name="primary" halVersion="2.0">
            	//         ,      ,     
                <attachedDevices>
                    <item>Speaker</item>
                    <item>Built-In Mic</item>
                </attachedDevices>
                //           ,        
                <defaultOutputDevice>Speaker</defaultOutputDevice>
                <mixPorts>
                	//       :primary ouput 
                	//      HAL                。   mixPort          Android AudioService       
                	//role="source"         ,          
                	//flags="AUDIO_OUTPUT_FLAG_PRIMARY"          
                	//
                    <mixPort name="primary output" role="source" flags="AUDIO_OUTPUT_FLAG_PRIMARY">
                        <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                                 samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                    </mixPort>
                    //       :esai output
                    <mixPort name="esai output" role="source" flags="AUDIO_OUTPUT_FLAG_DIRECT">
                        <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                                 samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_5POINT1,AUDIO_CHANNEL_OUT_7POINT1"/>
                    </mixPort>
                    //       :primary input
                    <mixPort name="primary input" role="sink">
                        <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                                 samplingRates="8000,11025,16000,22050,24000,32000,44100,48000"
                                 channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO"/>
                    </mixPort>
                </mixPorts>
                <devicePorts>
                	//      ,        
                	//                   (               )        
                	//role="sink",           ,            
                	//type,          
                    <devicePort tagName="Speaker" type="AUDIO_DEVICE_OUT_SPEAKER" role="sink" >
                    </devicePort>
                    <devicePort tagName="Wired Headset" type="AUDIO_DEVICE_OUT_WIRED_HEADSET" role="sink">
                    </devicePort>
                    <devicePort tagName="Wired Headphones" type="AUDIO_DEVICE_OUT_WIRED_HEADPHONE" role="sink">
                    </devicePort>
                	//role="sink",         ,            
                    <devicePort tagName="Built-In Mic" type="AUDIO_DEVICE_IN_BUILTIN_MIC" role="source">
                    </devicePort>
                    <devicePort tagName="Wired Headset Mic" type="AUDIO_DEVICE_IN_WIRED_HEADSET" role="source">
                    </devicePort>
                    <devicePort tagName="Spdif-In" type="AUDIO_DEVICE_IN_AUX_DIGITAL" role="source">
                    </devicePort>
                </devicePorts>
                <routes>
                	//    
                	//                              
                	//sink    role="sink" 
                	//sources            sink   ,  sink      sources
                    <route type="mix" sink="Speaker"
                           sources="esai output,primary output"/>
                    <route type="mix" sink="Wired Headset"
                           sources="primary output"/>
                    <route type="mix" sink="Wired Headphones"
                           sources="primary output"/>
                    <route type="mix" sink="primary input"
                           sources="Built-In Mic,Wired Headset Mic,Spdif-In"/>
                </routes>
            </module>
            //  a2dp HwModule
            <!-- A2dp Audio HAL -->
            <xi:include href="a2dp_audio_policy_configuration.xml"/>
            
            //  usb HwModule
            <!-- Usb Audio HAL -->
            <xi:include href="usb_audio_policy_configuration.xml"/>
            
            //  r_submix HwModule
            <!-- Remote Submix Audio HAL -->
            <xi:include href="r_submix_audio_policy_configuration.xml"/>
        </modules>
        
        //    
        <!-- Volume section -->
        <xi:include href="audio_policy_volumes.xml"/>
        <xi:include href="default_volume_tables.xml"/>
    </audioPolicyConfiguration>
    

    audio_policy_configuration.xml階層:
  • xmlには他のモジュールが含まれており、各modulesには複数のmoduleメンバーが含まれており、各moduleはAudio HALオブジェクト(対応コードのHwModuleクラス)である.
  • 各moduleには複数の階層が含まれており、PolicySerializer::deserialize関数からandroidがmoduleを先に解析し、他のモジュールを解析することがわかり、moduleモジュールの解析過程を重点的に分析しています.

  • audio_policy_configuration.xmlファイルの解析は、AudioPolicyManagerのコンストラクション関数で行います.主なロジックは次のとおりです.
    AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterface)
            : AudioPolicyManager(clientInterface, false /*forTesting*/)
    {
    	//     \frameworks\av\services\audiopolicy\common\managerdefinitions\src\Serializer.cpp  
    	//PolicySerializer::deserialize()  xml  
        loadConfig();		//  audio_policy_configuration.xml   ,   mConfig 
        
        initialize();		//  xml    ,        
    }
    
    //AudioPolicyManager.h      mOutputs
    SwAudioOutputCollection mOutputs;
    
    status_t AudioPolicyManager::initialize() {
    	//            mOutputs 
    }
    

    PolicySerializer::deserialize()分析:
    \frameworks\av\services\audiopolicy\common\managerdefinitions\src\Serializer.cppファイル:
    status_t PolicySerializer::deserialize(const char *configFile, AudioPolicyConfig &config)
    {
    	//       
       	...
       	
       	//    Modules   
        // Lets deserialize children
        // Modules
        ModuleTraits::Collection modules;
        deserializeCollection<ModuleTraits>(doc, cur, modules, &config);
        config.setHwModules(modules);	//          config 
    
    	//       
       	...
       	
    	//...
    	//  Volumes   
    	//       
       
    }
    
    static status_t deserializeCollection(_xmlDoc *doc, const _xmlNode *cur,
                                          typename Trait::Collection &collection,
                                          typename Trait::PtrSerializingCtx serializingContext)
    {
    	//       
       	...
       	
    	//     ,          deserializeCollection
    	//          ,        ModuleTraits::deserialize   , add   collection 
    	//        AudioPolicyConfig &config
    	while (child != NULL) {
    		if (!xmlStrcmp(child->name, (const xmlChar *)Trait::tag)) {
    			typename Trait::PtrElement element;
    			//  ModuleTraits::deserialize,   Modules     child
    			status_t status = Trait::deserialize(doc, child, element, serializingContext);
    			if (status != NO_ERROR) {
    			return status;
    		}
    		if (collection.add(element) < 0) {
    			ALOGE("%s: could not add element to %s collection", __FUNCTION__,
    			     Trait::collectionTag);
    			}
    		}
    		child = child->next;
    	}
    	
    	//       
       	...
       	
    }
    
    status_t ModuleTraits::deserialize(xmlDocPtr doc, const xmlNode *root, PtrElement &module,
                                       PtrSerializingCtx ctx)
    {
    	//       
       	...
       	
    	// Modules      
    	// Deserialize childrens: Audio Mix Port, Audio Device Ports (Source/Sink), Audio Routes
    	
    	//MixPorts
    	//      HAL                。   mixPort          Android AudioService       。
        MixPortTraits::Collection mixPorts;
        deserializeCollection<MixPortTraits>(doc, root, mixPorts, NULL);
        module->setProfiles(mixPorts);
    
    	//DevicePorts
    	//                   (               )        
        DevicePortTraits::Collection devicePorts;
        deserializeCollection<DevicePortTraits>(doc, root, devicePorts, NULL);
        module->setDeclaredDevices(devicePorts);
    
    	//Routes:
    	//                              。
        RouteTraits::Collection routes;
        deserializeCollection<RouteTraits>(doc, root, routes, module.get());
        module->setRoutes(routes);
    
    	//MixPort,DevicePorts Routes             
        //     MixPortTraits::deserialize、DevicePortTraits::deserialize、RouteTraits::deserialize     
        
        while (children != NULL) {
            if (!xmlStrcmp(children->name, (const xmlChar *)childAttachedDevicesTag)) {
                ALOGV("%s: %s %s found", __FUNCTION__, tag, childAttachedDevicesTag);
                const xmlNode *child = children->xmlChildrenNode;
                while (child != NULL) {
                    if (!xmlStrcmp(child->name, (const xmlChar *)childAttachedDeviceTag)) {
                        xmlChar *attachedDevice = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
                        if (attachedDevice != NULL) {
                            ALOGV("%s: %s %s=%s", __FUNCTION__, tag, childAttachedDeviceTag,(const char*)attachedDevice);
                            sp<DeviceDescriptor> device = module->getDeclaredDevices().getDeviceFromTagName(String8((const char*)attachedDevice));
    
    						//        AudioPolicyConfig(mConfig) 
                            ctx->addAvailableDevice(device);
                            xmlFree(attachedDevice);
                        }
                    }
                    child = child->next;
                }
            }
            if (!xmlStrcmp(children->name, (const xmlChar *)childDefaultOutputDeviceTag)) {
                xmlChar *defaultOutputDevice = xmlNodeListGetString(doc, children->xmlChildrenNode, 1);;
                if (defaultOutputDevice != NULL) {
                    ALOGV("%s: %s %s=%s", __FUNCTION__, tag, childDefaultOutputDeviceTag,
                          (const char*)defaultOutputDevice);
                    sp<DeviceDescriptor> device =
                            module->getDeclaredDevices().getDeviceFromTagName(String8((const char*)defaultOutputDevice));
                    if (device != 0 && ctx->getDefaultOutputDevice() == 0) {
                        ctx->setDefaultOutputDevice(device);
                        ALOGV("%s: default is %08x", __FUNCTION__, ctx->getDefaultOutputDevice()->type());
                    }
                    xmlFree(defaultOutputDevice);
                }
            }
            children = children->next;
        }
        
    	//       
       	...
       	
    }
    
    

    AudioPolicyManager.hにおけるmConfigの定義は、AudioPolicyConfig mConfig;
    2.AudioPolicyConfigファイル分析
    AudioPolicyConfigファイルには、HwModuleのセットと使用可能な入出力デバイスコンテナが含まれています.
    private:
        HwModuleCollection &mHwModules; 		//Module   ,         ,  ,     
        DeviceVector &mAvailableOutputDevices;	//         
        DeviceVector &mAvailableInputDevices;	//         
        sp<DeviceDescriptor> &mDefaultOutputDevices;	//      ,AudioPolicy           
        VolumeCurvesCollection *mVolumeCurves;			//       
        // TODO: remove when legacy conf file is removed. true on devices that use DRC on the
        // DEVICE_CATEGORY_SPEAKER path to boost soft sounds, used to adjust volume curves accordingly.
        // Note: remove also speaker_drc_enabled from global configuration of XML config file.
        bool mIsSpeakerDrcEnabled;
    

    3.HwModuleファイル分析
    HwModuleファイルでは、Moduleに含まれるプロパティについて説明します.
    private:
    	const String8 mName; 			//   Module      (primary, a2dp ...)
    	audio_module_handle_t mHandle;	//     Module        
    	OutputProfileCollection mOutputProfiles; //             
    	InputProfileCollection mInputProfiles;   //             
    	uint32_t mHalVersion; 					 // HAL  API   
    	DeviceVector mDeclaredDevices; 			 //  audio_policy_configuration.xml          
    	AudioRouteVector mRoutes;				 //  audio_policy_configuration.xml          
    	AudioPortVector mPorts;					 //  audio_policy_configuration.xml            
    

    二、ルート管理
    オーディオアーキテクチャ(一)では、AudioFlingerはAudioPolicyManager::getoutputForAttr()のメソッドを呼び出す.
    status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr,
                                                  audio_io_handle_t *output,
                                                  audio_session_t session,
                                                  audio_stream_type_t *stream,
                                                  uid_t uid,
                                                  const audio_config_t *config,
                                                  audio_output_flags_t *flags,
                                                  audio_port_handle_t *selectedDeviceId,
                                                  audio_port_handle_t *portId)
    {
    
    	//       
       	...
       	
    	//    app   streamType       
        mOutputRoutes.addRoute(session, *stream, SessionRoute::SOURCE_TYPE_NA, deviceDesc, uid);
    
    	//    app  attributes       
    	//            frameworks\av\services\audiopolicy\common\include\RoutingStrategy.h
    	//	enum routing_strategy {
        //		STRATEGY_MEDIA,
        //		STRATEGY_PHONE,
        //		STRATEGY_SONIFICATION,
        //		STRATEGY_SONIFICATION_RESPECTFUL,
        //		STRATEGY_DTMF,
        //		STRATEGY_ENFORCED_AUDIBLE,
        //		STRATEGY_TRANSMITTED_THROUGH_SPEAKER,
        //		STRATEGY_ACCESSIBILITY,
        //		STRATEGY_REROUTING,
        //		NUM_STRATEGIES
    	//	};
        routing_strategy strategy = (routing_strategy) getStrategyForAttr(&attributes);
        
        //              
    	audio_devices_t device = getDeviceForStrategy(strategy, false /*fromCache*/);
    
    	//
        *output = getOutputForDevice(device, session, *stream, config, flags);
        if (*output == AUDIO_IO_HANDLE_NONE) {
            mOutputRoutes.removeRoute(session);
            return INVALID_OPERATION;
        }
    
    	//       
       	...
    }