日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

android 4.0 电话录音,ANDROID音频系统散记之四:4.0音频系统HAL初探

發布時間:2024/2/28 windows 58 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android 4.0 电话录音,ANDROID音频系统散记之四:4.0音频系统HAL初探 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

昨天(2011-11-15)發布了Android4.0的源碼,今天download下來,開始挺進4.0時代。簡單看了一下,發現音頻系統方面與2.3的有較多地方不同,下面逐一描述。

一、代碼模塊位置

1、AudioFlinger

frameworks/base/services/audioflinger/

+--?Android.mk

+--?AudioBufferProvider.h

+--?AudioFlinger.cpp

+--?AudioFlinger.h

+--?AudioMixer.cpp

+--?AudioMixer.h

+--?AudioPolicyService.cpp

+--?AudioPolicyService.h

+--?AudioResampler.cpp

+--?AudioResamplerCubic.cpp

+--?AudioResamplerCubic.h

+--?AudioResampler.h

+--?AudioResamplerSinc.cpp

+--?AudioResamplerSinc.hAudioFlinger相關代碼,好像這部分與2.3相差不大,至少接口是兼容的。值得注意的是:2.3位于這里的還有AudioHardwareGeneric、AudioHardwareInterface、A2dpAudioInterface等一系列接口代碼,現在都移除了。實際上,這些接口變更為legacy(有另外更好的實現方式,但也兼容之前的方法),取而代之的是要實現hardware/libhardware/include/hardware/audio.h提供的接口,這是一個較大的變化。

兩種Audio Hardware HAL接口定義:

1/ legacy:hardware/libhardware_legacy/include/hardware_legacy/AudioHardwareInterface.h

2/ 非legacy:hardware/libhardware/include/hardware/audio.h

2、audio_hw

hardware/libhardware_legacy/audio/

+--?A2dpAudioInterface.cpp

+--?A2dpAudioInterface.h

+--?Android.mk

+--?AudioDumpInterface.cpp

+--?AudioDumpInterface.h

+--?AudioHardwareGeneric.cpp

+--?AudioHardwareGeneric.h

+--?AudioHardwareInterface.cpp

+--?AudioHardwareStub.cpp

+--?AudioHardwareStub.h

+--?audio_hw_hal.cpp

+--?AudioPolicyCompatClient.cpp

+--?AudioPolicyCompatClient.h

+--?audio_policy_hal.cpp

+--?AudioPolicyManagerBase.cpp

+--?AudioPolicyManagerDefault.cpp

+--?AudioPolicyManagerDefault.h上面提及的AudioHardwareGeneric、AudioHardwareInterface、A2dpAudioInterface等都放到libhardware_legacy里。

事實上legacy也要封裝成非legacy中的audio.h,確切的說需要一個聯系legacy interface和not legacy interface的中間層,這里的audio_hw_hal.cpp就充當這樣的一個角色了。因此,我們其實也可以把2.3之前的alsa_sound這一套東西也搬過來。

hardware/libhardware/modules/audio/

+--?Android.mk

+--?audio_hw.c

+--?audio_policy.c這是一個stub(類似于2.3中的AudioHardwareStub),大多數函數只是簡單的返回一個值,并沒有實際操作,只是保證Android能得到一個audio hardware hal實例,從而啟動運行,當然聲音沒有輸出到外設的。在底層音頻驅動或audio hardware hal還沒有實現好的情況下,可以使用這個stub device,先讓Android跑起來。

device/samsung/tuna/audio/

+--?Android.mk

+--?audio_hw.c

+--?ril_interface.c

+--?ril_interface.h這是Samsung Tuna的音頻設備抽象層,很有參考價值,計劃以后就在它的基礎上進行移植。它調用tinyalsa的接口,可見這個方案的底層音頻驅動是alsa。

3、tinyalsa

external/tinyalsa/

+--?Android.mk

+--?include

|???+--?tinyalsa

|???????+--?asoundlib.h

+--?mixer.c??????##類alsa-lib的control,作用音頻部件開關、音量調節等

+--?pcm.c????????##類alsa-lib的pcm,作用音頻pcm數據回放錄制

+--?README

+--?tinycap.c????##類alsa_arecord

+--?tinymix.c????##類alsa_amixer

+--?tinyplay.c???##類alsa_aplay在2.3時代,Android還隱晦把它放在android2.3.1-gingerbread/device/samsung/crespo/libaudio,現在終于把alsa-lib一腳踢開,小三變正室了,正名tinyalsa。

這其實是歷史的必然了,alsa-lib太過復雜繁瑣了,我看得也很不爽;更重要的商業上面的考慮,必須移除被GNU GPL授權證所約束的部份,alsa-lib并不是個例。

注意:上面的hardware/libhardware_legacy/audio/、hardware/libhardware/modules/audio/、device/samsung/tuna/audio/是同層的。之一是legacy audio,用于兼容2.2時代的alsa_sound;之二是stub audio接口;之三是Samsung Tuna的音頻抽象層實現。調用層次:AudioFlinger -> audio_hw -> tinyalsa。

二、Audio Hardware HAL加載

1、AudioFlinger

//加載audio?hardware?hal

staticintload_audio_interface(constchar*if_name,consthw_module_t?**mod,

audio_hw_device_t?**dev)

{

intrc;

//根據classid和if_name找到指定的動態庫并加載,這里加載的是音頻動態庫,如libaudio.primary.tuna.so

rc?=?hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID,?if_name,?mod);

if(rc)

gotoout;

//加載好的動態庫模塊必有個open方法,調用open方法打開音頻設備模塊

rc?=?audio_hw_device_open(*mod,?dev);

LOGE_IF(rc,?"couldn't?open?audio?hw?device?in?%s.%s?(%s)",

AUDIO_HARDWARE_MODULE_ID,?if_name,?strerror(-rc));

if(rc)

gotoout;

return0;

out:

*mod?=?NULL;

*dev?=?NULL;

returnrc;

}

//音頻設備接口,hw_get_module_by_class需要根據這些字符串找到相關的音頻模塊庫

staticconstchar*audio_interfaces[]?=?{

"primary",//主音頻設備,一般為本機codec

"a2dp",//a2dp設備,藍牙高保真音頻

"usb",//usb-audio設備,這個東東我2.3就考慮要實現了,現在終于支持了

};

#define?ARRAY_SIZE(x)?(sizeof((x))/sizeof(((x)[0])))

//?----------------------------------------------------------------------------

AudioFlinger::AudioFlinger()

:?BnAudioFlinger(),

mPrimaryHardwareDev(0),?mMasterVolume(1.0f),?mMasterMute(false),?mNextUniqueId(1),

mBtNrecIsOff(false)

{

}

voidAudioFlinger::onFirstRef()

{

intrc?=?0;

Mutex::Autolock?_l(mLock);

/*?TODO:?move?all?this?work?into?an?Init()?function?*/

mHardwareStatus?=?AUDIO_HW_IDLE;

//打開audio_interfaces數組定義的所有音頻設備

for(size_ti?=?0;?i

consthw_module_t?*mod;

audio_hw_device_t?*dev;

rc?=?load_audio_interface(audio_interfaces[i],?&mod,?&dev);

if(rc)

continue;

LOGI("Loaded?%s?audio?interface?from?%s?(%s)",?audio_interfaces[i],

mod->name,?mod->id);

mAudioHwDevs.push(dev);?//mAudioHwDevs是一個Vector,存儲已打開的audio?hw?devices

if(!mPrimaryHardwareDev)?{

mPrimaryHardwareDev?=?dev;

LOGI("Using?'%s'?(%s.%s)?as?the?primary?audio?interface",

mod->name,?mod->id,?audio_interfaces[i]);

}

}

mHardwareStatus?=?AUDIO_HW_INIT;

if(!mPrimaryHardwareDev?||?mAudioHwDevs.size()?==?0)?{

LOGE("Primary?audio?interface?not?found");

return;

}

//對audio?hw?devices進行一些初始化,如mode、master?volume的設置

for(size_ti?=?0;?i

audio_hw_device_t?*dev?=?mAudioHwDevs[i];

mHardwareStatus?=?AUDIO_HW_INIT;

rc?=?dev->init_check(dev);

if(rc?==?0)?{

AutoMutex?lock(mHardwareLock);

mMode?=?AUDIO_MODE_NORMAL;

mHardwareStatus?=?AUDIO_HW_SET_MODE;

dev->set_mode(dev,?mMode);

mHardwareStatus?=?AUDIO_HW_SET_MASTER_VOLUME;

dev->set_master_volume(dev,?1.0f);

mHardwareStatus?=?AUDIO_HW_IDLE;

}

}

}

以上對AudioFlinger進行的分析,主要是通過hw_get_module_by_class()找到模塊接口名字if_name相匹配的模塊庫,加載,然后audio_hw_device_open()調用模塊的open方法,完成音頻設備模塊的初始化。

留意AudioFlinger的構造函數只有簡單的私有變量的初始化操作了,把音頻設備初始化放到onFirstRef(),Android終于改進了這一點,好的設計根本不應該把可能會失敗的操作放到構造函數中。onFirstRef是RefBase類的一個虛函數,在構造sp的時候就會被調用。因此,在構造sp的時候就會觸發onFirstRef方法,從而完成音頻設備模塊初始化。

2、hw_get_module_by_class

我們接下來看看hw_get_module_by_class,實現在hardware/libhardware/ hardware.c中,它作用加載指定名字的模塊庫(.so文件),這個應該是用于加載所有硬件設備相關的庫文件,并不只是音頻設備。

inthw_get_module_by_class(constchar*class_id,constchar*inst,

conststructhw_module_t?**module)

{

intstatus;

inti;

conststructhw_module_t?*hmi?=?NULL;

charprop[PATH_MAX];

charpath[PATH_MAX];

charname[PATH_MAX];

if(inst)

snprintf(name,?PATH_MAX,?"%s.%s",?class_id,?inst);

else

strlcpy(name,?class_id,?PATH_MAX);

//這里我們以音頻庫為例,AudioFlinger調用到這個函數時,

//class_id=AUDIO_HARDWARE_MODULE_ID="audio",inst="primary"(或"a2dp"或"usb")

//那么此時name="audio.primary"

/*

*?Here?we?rely?on?the?fact?that?calling?dlopen?multiple?times?on

*?the?same?.so?will?simply?increment?a?refcount?(and?not?load

*?a?new?copy?of?the?library).

*?We?also?assume?that?dlopen()?is?thread-safe.

*/

/*?Loop?through?the?configuration?variants?looking?for?a?module?*/

for(i=0?;?i

if(i

//通過property_get找到廠家標記如"ro.product.board=tuna",這時prop="tuna"

if(property_get(variant_keys[i],?prop,?NULL)?==?0)?{

continue;

}

snprintf(path,?sizeof(path),"%s/%s.%s.so",

HAL_LIBRARY_PATH2,?name,?prop);?//#define?HAL_LIBRARY_PATH2?"/vendor/lib/hw"

if(access(path,?R_OK)?==?0)break;

snprintf(path,?sizeof(path),"%s/%s.%s.so",

HAL_LIBRARY_PATH1,?name,?prop);?//#define?HAL_LIBRARY_PATH1?"/system/lib/hw"

if(access(path,?R_OK)?==?0)break;

}?else{

snprintf(path,?sizeof(path),"%s/%s.default.so",//如沒有指定的庫文件,則加載default.so,即stub-device

HAL_LIBRARY_PATH1,?name);

if(access(path,?R_OK)?==?0)break;

}

}

//到這里,完成一個模塊庫的完整路徑名稱,如path="/system/lib/hw/audio.primary.tuna.so"

//如何生成audio.primary.tuna.so?請看相關的Android.mk文件,其中有定義LOCAL_MODULE?:=?audio.primary.tuna

status?=?-ENOENT;

if(i

/*?load?the?module,?if?this?fails,?we're?doomed,?and?we?should?not?try

*?to?load?a?different?variant.?*/

status?=?load(class_id,?path,?module);?//加載模塊庫

}

returnstatus;

}

load()函數不詳細分析了,它通過dlopen加載庫文件,然后dlsym找到hal_module_info的首地址。我們先看看hal_module_info的定義:

/**

*?Every?hardware?module?must?have?a?data?structure?named?HAL_MODULE_INFO_SYM

*?and?the?fields?of?this?data?structure?must?begin?with?hw_module_t

*?followed?by?module?specific?information.

*/

typedefstructhw_module_t?{

/**?tag?must?be?initialized?to?HARDWARE_MODULE_TAG?*/

uint32_t?tag;

/**?major?version?number?for?the?module?*/

uint16_t?version_major;

/**?minor?version?number?of?the?module?*/

uint16_t?version_minor;

/**?Identifier?of?module?*/

constchar*id;

/**?Name?of?this?module?*/

constchar*name;

/**?Author/owner/implementor?of?the?module?*/

constchar*author;

/**?Modules?methods?*/

structhw_module_methods_t*?methods;

/**?module's?dso?*/

void*?dso;

/**?padding?to?128?bytes,?reserved?for?future?use?*/

uint32_t?reserved[32-7];

}?hw_module_t;

typedefstructhw_module_methods_t?{

/**?Open?a?specific?device?*/

int(*open)(conststructhw_module_t*?module,constchar*?id,

structhw_device_t**?device);

}?hw_module_methods_t;這個結構體很重要,注釋很詳細。dlsym拿到這個結構體的首地址后,就可以調用Modules methods進行設備模塊的初始化了。設備模塊中,都應該按照這個格式初始化好這個結構體,否則dlsym找不到它,也就無法調用Modules methods進行初始化了。

例如,在audio_hw.c中,它是這樣定義的:

staticstructhw_module_methods_t?hal_module_methods?=?{

.open?=?adev_open,

};

structaudio_module?HAL_MODULE_INFO_SYM?=?{

.common?=?{

.tag?=?HARDWARE_MODULE_TAG,

.version_major?=?1,

.version_minor?=?0,

.id?=?AUDIO_HARDWARE_MODULE_ID,

.name?=?"Tuna?audio?HW?HAL",

.author?=?"The?Android?Open?Source?Project",

.methods?=?&hal_module_methods,

},

};3、audio_hw

好了,經過一番周折,又dlopen又dlsym的,終于進入我們的audio_hw。這部分沒什么好說的,按照hardware/libhardware/include/hardware/audio.h定義的接口實現就行了。這些接口全扔到一個結構體里面的,這樣做的好處是:不必用大量的dlsym來獲取各個接口函數的地址,只需找到這個結構體即可,從易用性和可擴充性來說,都是首選方式。

接口定義如下:

structaudio_hw_device?{

structhw_device_t?common;

/**

*?used?by?audio?flinger?to?enumerate?what?devices?are?supported?by

*?each?audio_hw_device?implementation.

*

*?Return?value?is?a?bitmask?of?1?or?more?values?of?audio_devices_t

*/

uint32_t?(*get_supported_devices)(conststructaudio_hw_device?*dev);

/**

*?check?to?see?if?the?audio?hardware?interface?has?been?initialized.

*?returns?0?on?success,?-ENODEV?on?failure.

*/

int(*init_check)(conststructaudio_hw_device?*dev);

/**?set?the?audio?volume?of?a?voice?call.?Range?is?between?0.0?and?1.0?*/

int(*set_voice_volume)(structaudio_hw_device?*dev,floatvolume);

/**

*?set?the?audio?volume?for?all?audio?activities?other?than?voice?call.

*?Range?between?0.0?and?1.0.?If?any?value?other?than?0?is?returned,

*?the?software?mixer?will?emulate?this?capability.

*/

int(*set_master_volume)(structaudio_hw_device?*dev,floatvolume);

/**

*?setMode?is?called?when?the?audio?mode?changes.?AUDIO_MODE_NORMAL?mode

*?is?for?standard?audio?playback,?AUDIO_MODE_RINGTONE?when?a?ringtone?is

*?playing,?and?AUDIO_MODE_IN_CALL?when?a?call?is?in?progress.

*/

int(*set_mode)(structaudio_hw_device?*dev,intmode);

/*?mic?mute?*/

int(*set_mic_mute)(structaudio_hw_device?*dev,boolstate);

int(*get_mic_mute)(conststructaudio_hw_device?*dev,bool*state);

/*?set/get?global?audio?parameters?*/

int(*set_parameters)(structaudio_hw_device?*dev,constchar*kv_pairs);

/*

*?Returns?a?pointer?to?a?heap?allocated?string.?The?caller?is?responsible

*?for?freeing?the?memory?for?it.

*/

char*?(*get_parameters)(conststructaudio_hw_device?*dev,

constchar*keys);

/*?Returns?audio?input?buffer?size?according?to?parameters?passed?or

*?0?if?one?of?the?parameters?is?not?supported

*/

size_t(*get_input_buffer_size)(conststructaudio_hw_device?*dev,

uint32_t?sample_rate,?intformat,

intchannel_count);

/**?This?method?creates?and?opens?the?audio?hardware?output?stream?*/

int(*open_output_stream)(structaudio_hw_device?*dev,?uint32_t?devices,

int*format,?uint32_t?*channels,

uint32_t?*sample_rate,

structaudio_stream_out?**out);

void(*close_output_stream)(structaudio_hw_device?*dev,

structaudio_stream_out*?out);

/**?This?method?creates?and?opens?the?audio?hardware?input?stream?*/

int(*open_input_stream)(structaudio_hw_device?*dev,?uint32_t?devices,

int*format,?uint32_t?*channels,

uint32_t?*sample_rate,

audio_in_acoustics_t?acoustics,

structaudio_stream_in?**stream_in);

void(*close_input_stream)(structaudio_hw_device?*dev,

structaudio_stream_in?*in);

/**?This?method?dumps?the?state?of?the?audio?hardware?*/

int(*dump)(conststructaudio_hw_device?*dev,intfd);

};

typedefstructaudio_hw_device?audio_hw_device_t;

注:這是比較標準的C接口設計方法了,但是個人感覺還是用C++比較好,直觀易讀。2.3之前都是用C++實現這些接口設計的,到了4.0,不知道為何采納用C?不會理由是做底層的不懂C++吧?!三、Audio Hardware HAL的legacy實現

之前提到兩種Audio Hardware HAL接口定義:

1/ legacy:hardware/libhardware_legacy/include/hardware_legacy/AudioHardwareInterface.h

2/ 非legacy:hardware/libhardware/include/hardware/audio.h

前者是2.3及之前的音頻設備接口定義,后者是4.0的接口定義。

為了兼容以前的設計,4.0實現一個中間層:hardware/libhardware_legacy/audio/audio_hw_hal.cpp,結構與其他的audio_hw.c大同小異,差別在于open方法:

staticintlegacy_adev_open(consthw_module_t*?module,constchar*?name,

hw_device_t**?device)

{

......

ladev->hwif?=?createAudioHardware();

if(!ladev->hwif)?{

ret?=?-EIO;

gotoerr_create_audio_hw;

}

......

}看到那個熟悉的createAudioHardware()沒有?這是以前我提到的Vendor Specific Audio接口,然后新的接口再調用ladev->hwif的函數就是了。

因此老一套的alsa-lib、alsa-utils和alsa_sound也可以照搬過來,這里的文件被編譯成靜態庫的,因此你需要修改alsa_sound里面的Android.mk文件,鏈接這個靜態庫。還有alsa_sound的命名空間原來是“android”,現在需要改成“android_audio_legacy”。

四、a2dp Audio HAL的實現

4.0的a2dp audio hal放到bluez里實現了,我找了好一會才找到:

external/Bluetooth/bluez/audio/android_audio_hw.c

大致與上面提到的audio_hw.c類似,因為都是基于audio.h定義的接口來實現的。

如果需要編譯這個庫,須在BoardConfig.mk里定義:

BOARD_HAVE_BLUETOOTH := true

開始還提到現在支持3種audio設備了,分別是primary、a2dp和usb。目前剩下usb audio hal我沒有找到,不知是否需要自己去實現?其實alsa-driver都支持大部分的usb-audio設備了,因此上層也可調用tinyalsa的接口,就像samsung tuna的audio_hw.c那樣。

五、音質改進???

可使用audio echo cancel和更好的resampler(SRC)???

--to be continued…

總結

以上是生活随笔為你收集整理的android 4.0 电话录音,ANDROID音频系统散记之四:4.0音频系统HAL初探的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。