ALSA(二), makefile, Autotools, premake
http://antkillerfarm.github.io/
從Gstreamer到ALSA(續(xù))
4.SOC_SINGLE類宏
這里對SOC_SINGLE類的宏,詳細說明一下,因為只有這些宏才是真正需要驅(qū)動開發(fā)者添加或修改的。
例如如下的代碼:
SOC_DOUBLE_R_TLV("Digital Playback Volume", JZCODEC_DACLVOL, JZCODEC_DACRVOL,0, 255, 0, jzcodec_tlv),使用amixer命令觀察該代碼的效果:
Simple mixer control 'Digital',0Capabilities: pvolumePlayback channels: Front Left - Front RightLimits: Playback 0 - 255Mono:Front Left: Playback 255 [100%] [0.00dB]Front Right: Playback 255 [100%] [0.00dB]從中可以看出snd_kcontrol_new的name成員的名字是有特定含義的,不能隨便定。
有的音頻芯片,如TAS5086,它的音量寄存器用0xFF表示靜音,而用0x0表示最大音量,這種情況下需要將SOC_SINGLE類宏的invert參數(shù)設(shè)為1。
5.SOC_SINGLE_TLV類宏
除了SOC_SINGLE類宏之外,還有SOC_SINGLE_TLV類宏。后者和前者的主要區(qū)別在于:用TLV數(shù)組完成音量到寄存器值之間的轉(zhuǎn)換。
例如如下代碼:
static const DECLARE_TLV_DB_SCALE(tas5086_dac_tlv, -10350, 50, 1);-10350是音量的最小值,表示-103.5dB。50是相鄰的兩個寄存器值之間的音量差(即步長),這里表示0.5dB。也就是說這個宏設(shè)定的音量值的單位都是0.01dB。
ASOC對多Codec的支持
音頻設(shè)計方案
ASOC在Linux 3.X時代最大的改進就是添加了對多codec的支持。這里我們首先描述一下多Codec在音頻設(shè)備設(shè)計中的意義,以及它的一些實現(xiàn)方案。
上圖是實現(xiàn)方案A,它的特點是:
1.1個MCU通過2個Codec,間接連接了4個Speaker。在當前的音頻設(shè)計中,音箱的揚聲器個數(shù)越來越多,但是單個Codec所能提供的聲道數(shù)量有限。當揚聲器個數(shù)超過這一數(shù)量限制時,就需要采用多Codec方案了。
2.兩個Codec有獨立的I2C控制通道。這里的“獨立”是邏輯意義上的。在物理上,兩個Codec可掛在同一條I2C總線上,以不同的從機地址加以區(qū)分。
3.兩個Codec共享I2S輸入。
上圖是實現(xiàn)方案B,它和方案A的區(qū)別為:兩個Codec有獨立的I2S輸入。方案B根據(jù)用途,又可分為兩種子方案:
1.方案B1:兩個I2S的輸入相同。
2.方案B2:兩個I2S的輸入不同。
方案A的代碼實現(xiàn)
1.首先討論I2C控制的實現(xiàn),這里以TAS5731M芯片為例。
在board初始化階段,為兩個codec各自生成一個I2C設(shè)備。
static struct i2c_board_info __initdata rtl819xd_i2c_devices[] = {{I2C_BOARD_INFO("tas5731", 0x1a), //TAS5731M Master},{I2C_BOARD_INFO("tas5731", 0x1b), //TAS5731M Sub}, };2.方案A由于共享I2S,因此在驅(qū)動角度,必須將兩個codec驅(qū)動整合到一個card之中。
相應的machine代碼為:
static struct snd_soc_dai_link rtl819xd_jzcodec_dai[] = {{.name = "JZCODEC_MASTER",.stream_name = "JZCODEC_MASTER",.cpu_dai_name = "rtl8197d-i2s",.codec_name = "tas5731.0-001a",.codec_dai_name = "tas5731_master",.init = rtl819xd_jzcodec_jzcodec_init,.ops = &rtl819xd_jzcodec_ops,.platform_name = "rtl819x-pcm-audio",},{.name = "JZCODEC_SUB",.stream_name = "JZCODEC_SUB",.cpu_dai_name = "rtl8197d-i2s",.codec_name = "tas5731.0-001b",.codec_dai_name = "tas5731_sub",.init = rtl819xd_jzcodec_jzcodec_init,.ops = &rtl819xd_jzcodec_ops,} };相應的codec代碼為:
static struct snd_soc_dai_driver tas5731_dai[] = {{.name = "tas5731_master",.id = 0,.playback = {.stream_name = "Playback",.channels_min = 2,.channels_max = 6,.rates = TAS5731_PCM_RATES,.formats = TAS5731_PCM_FORMATS,},.ops = &tas5731_dai_ops,},{.name = "tas5731_sub",.id = 1,.playback = {.stream_name = "Playback",.channels_min = 2,.channels_max = 6,.rates = TAS5731_PCM_RATES,.formats = TAS5731_PCM_FORMATS,},.ops = &tas5731_dai_ops,} };這里對代碼的要點做一個解釋:
1)codec_name的命名規(guī)則。codec_name一般以X.Y-Z的形式命名。
其中X為codec的I2C driver名稱。注意這里的名稱和I2C_BOARD_INFO中定義的名稱不同,后者是根據(jù)i2c_device_id中定義的名稱來命名的。
Y表示I2C總線號。如果MCU有超過一條I2C總線的話,需要使用總線號加以區(qū)分。
Z表示Codec設(shè)備的從機地址。
2)由于兩個Codec共享I2S輸入,因此只需要其中一個Codec定義platform_name即可。
方案B1的代碼實現(xiàn)
和方案A的差別在于:兩個Codec都需要定義自己的platform_name。
方案B2的代碼實現(xiàn)
這種情況用兩個獨立的card來解決就可以了。
makefile
簡單的規(guī)則可以查看《GNU makefile指南》一文,Goerge Foot寫的。地址就不貼了,中文版基本到處都是。但是該文只是入門級的,最專業(yè)的還是GNU官方的手冊:
http://www.gnu.org/software/make/manual/html_node/index.html
應該說make的語法,除了規(guī)則依賴之外,大多數(shù)與bash相同。但是make也有一些內(nèi)置函數(shù),它們的用法就不在bash的范疇了,比如call函數(shù)。碰到這樣的情況,可以查閱以下網(wǎng)頁,以快速定位幫助文檔的位置:
http://www.gnu.org/software/make/manual/html_node/Quick-Reference.html
Autotools
概述
autotools是GNU提供的一系列自動配置工具的集合,其主要包括autoconf、automake、pkg-config和libtool等工具。
Makefile雖然規(guī)則簡單,但手工書寫makefile卻不是一件容易的事。我這里的不容易指的是:編寫符合規(guī)范的makefile不容易。如果只是那種自己平時demo的話,可能還是直接makefile更簡單。畢竟autotools包含那么多工具,每個工具的規(guī)則都不盡相同,學習門檻比makefile高多了。如果針對小工程,還不一定有直接makefile來的快。
那么autotools的優(yōu)點在哪里呢?
1.針對大工程時,手工編寫量較小。比如需要添加的源文件和頭文件,直接autoscan就出來了,不用一個一個的寫。
2.可以檢查編譯環(huán)境。這個手工寫,難度太大,我是不會寫的。
3.可移植好。由于第2點的存在,autotools生成的makefile的可移植性非常好。這個優(yōu)點在本地編譯的時候,體現(xiàn)的并不十分明顯,但如果交叉編譯的話,就很突出了。
參考文檔:
https://autotools.io/index.html
這個網(wǎng)站基本上每個工具都講到了,非常值得一看。
autoconf&automake
這兩個工具是整個autotools工具集的核心,使用的流程也比較復雜。教程中最經(jīng)典的是:
http://www.ibm.com/developerworks/cn/linux/l-makefile/index.html
但是,這個教程比較老了,有的地方的處理并不符合當前的版本,以下針對這些新老版本的差異,做一個說明。
1.首先給出新版本(2016.2)的示例代碼:
https://github.com/antkillerfarm/antkillerfarm_crazy/tree/master/gtk_browser/autotool
2.configure.in在新版本中改叫configure.ac。其中,AM_INIT_AUTOMAKE宏的格式已經(jīng)和老的不同了。AC_OUTPUT宏雖然還存在,但是部分功能分解給AC_CONFIG_FILES宏。
3.拷貝depcomp和complie文件的過程,現(xiàn)在可以通過命令自動完成,無須手動拷貝。
4.運行automake之前,需要先用autoheader生成config.h文件。
從整個流程來說,autotools相比Cmake無疑復雜的多了。但實際使用中,由于這幾個步驟都是流程化的,簡化起來也比較容易。因此新版本提供了autoreconf命令,用來一站式生成所需的編譯配置文件。其示例如下:
autoreconf -fi
pkg-config
一般來說,如果庫的頭文件不在/usr/include目錄中,那么在編譯的時候需要用-I參數(shù)指定其路徑。由于同一個庫在不同系統(tǒng)上可能位于不同的目錄下,用戶安裝庫的時候也可以將庫安裝在不同的目錄下,所以即使使用同一個庫,由于庫的路徑的不同,造成了用-I參數(shù)指定的頭文件的路徑和在連接時使用-L參數(shù)指定lib庫的路徑都可能不同,其結(jié)果就是造成了編譯命令界面的不統(tǒng)一??赡苡捎诰幾g,連接的不一致,造成同一份程序從一臺機器copy到另一臺機器時就可能會出現(xiàn)問題。
pkg-config就是用來解決編譯連接界面不統(tǒng)一問題的一個工具。
它的基本思想:pkg-config是通過庫提供的一個.pc文件獲得庫的各種必要信息的,包括版本信息、編譯和連接需要的參數(shù)等。需要的時候可以通過pkg-config提供的參數(shù)(–cflags, –libs),將所需信息提取出來供編譯和連接使用。這樣,不管庫文件安裝在哪,通過庫對應的.pc文件就可以準確定位,可以使用相同的編譯和連接命令,使得編譯和連接界面統(tǒng)一。
參見:
http://www.mike.org.cn/articles/description-configure-pkg-config-pkg_config_path-of-the-relations-between/
autoconf&automake與pkg-config的協(xié)同工作
由于pkg-config是一系列Glib派生項目(如Gstreamer、GTK)所用的配置工具。因此,如何讓autoconf&automake與pkg-config協(xié)同工作就成為了一個很重要的課題。多數(shù)autotools教程由于只是helloworld型的,并沒有涉及到這方面的內(nèi)容。
這里仍然使用上一節(jié)的示例代碼,進行講解。
協(xié)同工作的關(guān)鍵在于PKG_CHECK_MODULES宏,這個宏的語法為:
PKG_CHECK_MODULES(prefix, list-of-modules, action-if-found, action-if-not-found)
該宏被執(zhí)行后,會生成prefix_CFLAGS和prefix_LIBS兩個全局變量。它們在Makefile.am中會用到。
這里的AC_SUBST宏,主要是針對老版本的pkg-config所做的修改,在pkg-config v0.24以后的版本中,加不加都無所謂。
這方面更復雜的例子,可以查看Totem項目的代碼,該項目復雜度中等。如果這個例子還不夠用的話,那就直接查看GTK項目的代碼吧。我相信絕大多數(shù)的人,都不可能開發(fā)出一個比它更大的項目來。
CMake和pkg-config的協(xié)同工作
Cmake雖然主要用于Qt項目,但用于GTK項目,實際上也沒有什么問題。
Cmake使用的pkg_check_modules宏,和上面的PKG_CHECK_MODULES宏,從原理來說,是類似的。這里不再贅述。
參考文檔:
http://francesco-cek.com/cmake-and-gtk-3-the-easy-way/
示例代碼:
https://github.com/antkillerfarm/antkillerfarm_crazy/tree/master/gtk_browser/cmake
Autotools細節(jié)匯總
1.dnl vs #
dnl和#在autoconf中,都是注釋開始的標志。區(qū)別在于,dnl注釋的東西,不會出現(xiàn)在最終的configure腳本中。
2.設(shè)置debug版本
CFLAGS的默認設(shè)置是-g -O2,可用以下命令修改之:
./configure CFLAGS="-g -O0"
或者也可以用./configure --help查看支持的編譯選項。
比如生成靜態(tài)鏈接庫,可使用以下命令:
./configure --enable-shared=no --enable-static=yes
3.設(shè)定so文件的導出符號表
libtool --mode=link gcc -o libfoo.la foo.lo -export-symbols=foo.sym
premake
premake是一個輕量級的構(gòu)建系統(tǒng)。這里所謂的輕量級是和Autotools、CMake相比。
Autotools在Unix平臺的功能最為全面。CMake添加了對Windows平臺的支持,但在Unix平臺上,仍不得不借助部分Autotools工具的功能,比如pkg-config。
這兩個重量級工具,都有很多重量級的使用者,一般不必擔心功能不夠使的情況。它們的缺點是,使用了特殊的DSL(Domain Specific Language),用戶需要花費額外的學習時間來學習這些DSL。
premake使用lua語言編寫,語法比CMake更簡單。它的官網(wǎng)是:
http://premake.github.io/
premake的缺點在于,它基本上是個人作品,全職開發(fā)人員太少,導致功能有限,目前尚無特大項目使用該系統(tǒng),其功能和可靠性受到質(zhì)疑。
總結(jié)
以上是生活随笔為你收集整理的ALSA(二), makefile, Autotools, premake的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: cocos2d, Box2D
- 下一篇: DLNA, PulseAudio, di