1,移植基礎:
(1)核心聲音驅動和alsa驅動
(2)alsa-lib和alsa-utils庫移植
這兩部分上一節已經介紹過了。
2,android的audio最核心的部分是audioflinger,audioflinger向上處理來自於應用程式的聲音相關的所有請求
向下通過AudioHardwareInterface訪問硬體,android的audio架構如下所示:
Applications
|
Frameworks
|
JNI
|
AudioFlinger
|
AudioHardwareInterface
| | |
專有audio庫 | alsa使用者庫
| |
/dev/eac /dev/snd/*
| |
核心eac驅動 核心alsa驅動
AudioHardwareInterface是audioflinger和硬體驅動之間的橋樑,android預設編譯的是generic audio,此時
AudioHardwareInterface直接指向了/dev/eac驅動,它通過eac驅動來操作音效卡,android audio移植就是要讓
AudioHardwareInterface直接或者間接指向我們自己定義的聲音驅動,一般都採用alsa聲音體系,所以我們的目的就是
要讓AudioHardwareInterface指向alsa使用者庫。下面的內容開始移植alsa-audio
3,修改vendor/ardent/merlin/BoardConfig.mk檔案內容如下:
BOARD_USES_GENERIC_AUDIO := false
BOARD_USES_ALSA_AUDIO := true
BUILD_WITH_ALSA_UTILS := true
上面配置的目的就是為了讓要讓AudioHardwareInterface指向alsa使用者庫
4,下面來添加audio庫的編譯
在vendor/ardent/merlin目錄下建立一個libaudio目錄,修改AndroidBoard.mk檔案,添加編譯路徑如下:
LOCAL_PATH := $(call my-dir)
L_PATH := $(LOCAL_PATH)
include $(L_PATH)/libaudio/Mdroid.mk
5,vendor/ardent/merlin/libaudio目錄下建立一個Mdroid.mk檔案,內容如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libaudio
LOCAL_SHARED_LIBRARIES := /
libcutils /
libutils /
libmedia /
libhardware
LOCAL_SRC_FILES += AudioHardwareMerlin.cpp
LOCAL_CFLAGS +=
LOCAL_C_INCLUDES +=
LOCAL_STATIC_LIBRARIES += libaudiointerface
include $(BUILD_SHARED_LIBRARY)
6,android audio的實現方法,我們現看看介面部分,上面有說道audioflinger是通過AudioHardwareInterface指向驅動的
AudioHardwareInterface類的代碼在frameworks/base/libs/audioflinger/AudioHardwareInterface.cpp檔案中
該檔案中的create函數中定義了AudioHardwareInterface指向驅動的代碼如下:
AudioHardwareInterface* hw = 0;
char value[PROPERTY_VALUE_MAX];
#ifdef GENERIC_AUDIO
hw = new AudioHardwareGeneric();
#else
// if running in emulation - use the emulator driver
if (property_get("ro.kernel.qemu", value, 0)) {
LOGD("Running in emulation - using generic audio driver");
hw = new AudioHardwareGeneric();
}
else {
LOGV("Creating Vendor Specific AudioHardware");
hw = createAudioHardware();
}
#endif
return hw;
當系統為generic audio的時候此函數返回的是一個指向AudioHardwareGeneric對象的指標,其實是返回一個指向AudioHardwareInterface對象
的指標,因為AudioHardwareGeneric是AudioHardwareInterface的子類,繼承關係如下:
AudioHardwareInterface->AudioHardwareBase->AudioHardwareGeneric
如果系統不是generic audio,則通過調用createAudioHardware函數來返回一個指向一個指向AudioHardwareInterface對象的指標,
所以,簡單的將,我們要做的事情就是實現這個函數以及它相關的內容即可。createAudioHardware函數我們可以在
hardware/libhardware_legacy/include/hardware_legacy/AudioHardwareInterface.h中也就是AudioHardwareInterface
的聲明中找到原型如下:
extern "C" AudioHardwareInterface* createAudioHardware(void);
7,通過6我們不難知道,我們實現自己的audio介面完全可以模仿generic audio的做法,只是要多實現一個createAudioHardware函數而已,
因此我們將frameworks/base/libs/audioflinger/AudioHardwareInterface.h檔案複製到
vendor/ardent/merlin/libaudio目錄下,改名為AudioHardwareMerlin.h,然後將此檔案中所有的Generic欄位通通替換成Merlin
然後將frameworks/base/libs/audioflinger/AudioHardwareInterface.cpp複製到
vendor/ardent/merlin/libaudio目錄下,改名為AudioHardwareMerlin.cpp,然後將此檔案中所有的Generic欄位通通替換成Merlin
最後在AudioHardwareMerlin.cpp中定義createAudioHardware函數如下:
extern "C" AudioHardwareInterface* createAudioHardware(void)
{
return new AudioHardwareMerlin();
}
8,進行到7後直接編譯,發現編譯不過,錯誤如下
target thumb C++: libaudioflinger <= frameworks/base/libs/audioflinger/AudioFlinger.cpp
make: *** 沒有規則可以建立“out/target/product/merlin/obj/SHARED_LIBRARIES/libaudioflinger_intermediates/LINKED/libaudioflinger.so”需要的目標“out/target/product/merlin/obj/lib/libaudiopolicy.so”。 停止。
原來是編譯audioflinger的時候需要libaudiopolicy.so的支援
查看frameworks/base/libs/audioflinger/Android.mk檔案,發現有如下內容:
ifeq ($(strip $(BOARD_USES_GENERIC_AUDIO)),true)
LOCAL_STATIC_LIBRARIES += libaudiointerface libaudiopolicybase
LOCAL_CFLAGS += -DGENERIC_AUDIO
else
LOCAL_SHARED_LIBRARIES += libaudio libaudiopolicy
endif
看來generic audio的時候需要的是libaudiointerface和libaudiopolicybase靜態庫,否則需要libaudio和libaudiopolicy動態庫
libaudio庫上面我們已經實現,看來下面的內容就是要實現libaudiopolicy庫了
9,audio policy介面的調用在frameworks/base/libs/audioflinger/AudioPolicyService.cpp檔案中的AudioPolicyService類
的建構函式中,如下:
#if (defined GENERIC_AUDIO) || (defined AUDIO_POLICY_TEST)
mpPolicyManager = new AudioPolicyManagerBase(this);
LOGV("build for GENERIC_AUDIO - using generic audio policy");
#else
// if running in emulation - use the emulator driver
if (property_get("ro.kernel.qemu", value, 0)) {
LOGV("Running in emulation - using generic audio policy");
mpPolicyManager = new AudioPolicyManagerBase(this);
}
else {
LOGV("Using hardware specific audio policy");
mpPolicyManager = createAudioPolicyManager(this);
}
#endif
該目錄下的AudioPolicyService.h檔案中定義了mpPolicyManager如下:
AudioPolicyInterface* mpPolicyManager; // the platform specific policy manager
可見,當系統為generic audio或者運行在模擬器上時,mpPolicyManager是一個指向AudioPolicyManagerBase對象的指標
否則就要通過createAudioPolicyManager函數來返回。
AudioPolicyInterface類和AudioPolicyManagerBase類聲明在hardware/libhardware_legacy/include/hardware_legacy
目錄下的AudioPolicyInterface.h和AudioPolicyManagerBase.h檔案中,而且AudioPolicyManagerBase類是AudioPolicyInterface
的子類。
10,實現libaudiopolicy庫
libaudiopolicy庫的實現我們也可以模仿generic audio的實現方式,從8我們可以看出,generic audio的時候audiopolicy用的是
靜態libaudiopolicybase庫,從frameworks/base/libs/audioflinger/Android.mk檔案可以找到該靜態庫的編譯內容如下:
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= /
AudioPolicyManagerBase.cpp
LOCAL_SHARED_LIBRARIES := /
libcutils /
libutils /
libmedia
ifeq ($(TARGET_SIMULATOR),true)
LOCAL_LDLIBS += -ldl
else
LOCAL_SHARED_LIBRARIES += libdl
endif
LOCAL_MODULE:= libaudiopolicybase
ifeq ($(BOARD_HAVE_BLUETOOTH),true)
LOCAL_CFLAGS += -DWITH_A2DP
endif
ifeq ($(AUDIO_POLICY_TEST),true)
LOCAL_CFLAGS += -DAUDIO_POLICY_TEST
endif
include $(BUILD_STATIC_LIBRARY)
由此可見,libaudiopolicybase靜態庫編譯的就是frameworks/base/libs/audioflinger/AudioPolicyManagerBase.cpp檔案
11,通過9和10的分析,結合libaudio庫的寫法,要完成libaudiopolicy庫,我們可以將AudioPolicyManagerBase.cpp
和AudioPolicyManagerBase.h複製到vendor/ardent/merlin/libaudio目錄下,然後將這兩個檔案名稱改成和其中的內容作
一定修改,讓它變成兩外一個類如AudioPolicyManagerMerlin類的定義,然後在cpp檔案中定義介面函數createAudioPolicyManager如下:
extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface)
{
return new AudioPolicyManagerMerlin(clientInterface);
}
然後再修改相關Mdroid.mk檔案編譯成libaudiopolicy.so即可
採用這種方法可以實現,但是卻不必要,因為generic audio所用的AudioPolicyManagerBase已經非常完善,所以我們只需要直接繼承這個類即可
下面來實現它。
12,在vendor/ardent/merlin/libaudio目錄下建立一個AudioPolicyManagerMerlin.h檔案,內容如下:
#include <stdint.h>
#include <sys/types.h>
#include <utils/Timers.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <hardware_legacy/AudioPolicyManagerBase.h>
namespace android {
class AudioPolicyManagerMerlin: public AudioPolicyManagerBase
{
public:
AudioPolicyManagerMerlin(AudioPolicyClientInterface *clientInterface)
: AudioPolicyManagerBase(clientInterface) {}
virtual ~AudioPolicyManagerMerlin() {}
};
};
主要是聲明我們所用的AudioPolicyManagerMerlin,通過直接繼承generic audio所用AudioPolicyManagerBase類來實現
13,在vendor/ardent/merlin/libaudio目錄下建立一個AudioPolicyManagerMerlin.cpp檔案,內容如下:
#include "AudioPolicyManagerMerlin.h"
#include <media/mediarecorder.h>
namespace android {
extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface)
{
return new AudioPolicyManagerMerlin(clientInterface);
}
}; // namespace android
主要就是定義了介面函數createAudioPolicyManager
14,修改vendor/ardent/merlin/libaudio/Mdroid.mk函數,添加libaudiopolicy的編譯如下:
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= /
AudioPolicyManagerMerlin.cpp
LOCAL_SHARED_LIBRARIES := /
libcutils /
libutils /
libmedia
LOCAL_STATIC_LIBRARIES += libaudiopolicybase
LOCAL_MODULE:= libaudiopolicy
include $(BUILD_SHARED_LIBRARY)
經過以上過程再修改一些小錯誤,基本上就能編譯通過,聲音的架構也已經起來了,但是系統還是沒喲聲音,因為還需要進一步的工作,
下一節繼續。
自己補充,需要關注的檔案:
system/core/init/device.c /dev/snd 的添加
build/tartget/board/generic/BoardConfig.mk 使用ALSA宏配置
asound.conf 設定檔
init.rc節點許可權