android音訊hal層簡介
如下圖為android音訊hal層所處的位置:
從上圖可以看出,HAL層下面使用TiniAlsa(Android下一個簡約的Alsa版本)。HAL層分為兩部分,一部分為各種音訊裝置,每種音訊裝置由一個獨立的庫檔案實現:如audio.a2dp.default.so(管理藍芽a2dp音訊),audio.usb.default.so(管理usb外接的音訊),audio.primary.default.so(管理裝置上的大部分音訊)。另一部分為廠家自己實現的音訊策略,Android下提供了預設一套音訊策略,當廠家有特殊的音訊策略時,可以在這部分修改實現。HAL層上面就是音訊系統的核心AudioFlinger,這裡實現了各種輸入、輸出音訊流的管理,管理實時可用的音訊通道,為各種音訊流選擇音訊通道,實現多個音訊流的混音等。
這裡只介紹HAL中各種音訊裝置的管理,如何確定各種音訊裝置支援哪些輸入、輸出音訊等。AudioFlinger在載入音訊裝置庫檔案時,從/system/lib/hw/下查詢以audio開頭的庫,同時根據audio_policy.conf中定義的音訊裝置名(如a2dp、usb、primary)作為庫的第二部分名稱,對於沒有特別指定的,庫的第三部分名稱就是default,所以載入音訊裝置庫的名稱就可以確定了,如:audio.a2dp.default.so。每個音訊庫的實現介面都是一樣的,這樣就可以讓AudioFlinger使用相同的介面呼叫不同音訊裝置。
android\external\bluetooth\bluedroid\audio_a2dp_hw\Audio_a2dp_hw.c
/* 音訊open函式,用於確定音訊輸入輸出流的實現介面,各種音訊資料格式的設定獲取介面 */
static int adev_open(const hw_module_t* module, const char* name,
hw_device_t** device)
{
struct a2dp_audio_device *adev;
int ret;
INFO(" adev_open in A2dp_hw module");
FNLOG();
if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)
{
ERROR("interface %s not matching [%s]", name, AUDIO_HARDWARE_INTERFACE);
return -EINVAL;
}
adev = calloc(1, sizeof(struct a2dp_audio_device));
if (!adev)
return -ENOMEM;
adev->device.common.tag = HARDWARE_DEVICE_TAG;
adev->device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
adev->device.common.module = (struct hw_module_t *) module;
adev->device.common.close = adev_close;
adev->device.init_check = adev_init_check;
adev->device.set_voice_volume = adev_set_voice_volume;
adev->device.set_master_volume = adev_set_master_volume;
adev->device.set_mode = adev_set_mode;
adev->device.set_mic_mute = adev_set_mic_mute;
adev->device.get_mic_mute = adev_get_mic_mute;
adev->device.set_parameters = adev_set_parameters;
adev->device.get_parameters = adev_get_parameters;
adev->device.get_input_buffer_size = adev_get_input_buffer_size;
adev->device.open_output_stream = adev_open_output_stream;
adev->device.close_output_stream = adev_close_output_stream;
adev->device.open_input_stream = adev_open_input_stream;
adev->device.close_input_stream = adev_close_input_stream;
adev->device.dump = adev_dump;
adev->output = NULL;
*device = &adev->device.common;
return 0;
}
/* 音訊模組open介面函式 */
static struct hw_module_methods_t hal_module_methods = {
.open = adev_open,
};
/* 定義的音訊模組 */
struct audio_module HAL_MODULE_INFO_SYM = {
.common = {
.tag = HARDWARE_MODULE_TAG,
.version_major = 1,
.version_minor = 0,
.id = AUDIO_HARDWARE_MODULE_ID,
.name = "A2DP Audio HW HAL",
.author = "The Android Open Source Project",
.methods = &hal_module_methods,
},
};
在音訊裝置庫的實現程式碼裡,沒有看到該音訊裝置庫支援哪些音訊輸入、輸出裝置,音訊裝置支援的輸入、輸出裝置不是在程式碼裡面寫死的,而是通過audio_policy.conf檔案進行配置的。如下面的一份配置檔案。
audio_hw_modules {
primary { /* 主音訊配置檔案 */
global_configuration {
attached_output_devices AUDIO_DEVICE_OUT_SPEAKER
default_output_device AUDIO_DEVICE_OUT_SPEAKER
attached_input_devices AUDIO_DEVICE_IN_BUILTIN_MIC
audio_hal_version 3.0
}
devices {
speaker {
type AUDIO_DEVICE_OUT_SPEAKER
gains {
gain_1 {
mode AUDIO_GAIN_MODE_JOINT
min_value_mB -8400
max_value_mB 4000
default_value_mB 0
step_value_mB 100
}
}
}
}
outputs {
primary {
sampling_rates 48000
channel_masks AUDIO_CHANNEL_OUT_STEREO
formats AUDIO_FORMAT_PCM_16_BIT
devices AUDIO_DEVICE_OUT_EARPIECE|AUDIO_DEVICE_OUT_SPEAKER|AUDIO_DEVICE_OUT_WIRED_HEADSET|AUDIO_DEVICE_OUT_WIRED_HEADPHONE|AUDIO_DEVICE_OUT_AUX_DIGITAL|AUDIO_DEVICE_OUT_ALL_SCO
flags AUDIO_OUTPUT_FLAG_PRIMARY
}
}
inputs {
primary {
sampling_rates 8000|16000
channel_masks AUDIO_CHANNEL_IN_MONO
formats AUDIO_FORMAT_PCM_16_BIT
devices AUDIO_DEVICE_IN_BUILTIN_MIC|AUDIO_DEVICE_IN_ALL_SCO
}
}
}
a2dp { /* a2dp音訊配置檔案 */
global_configuration {
attached_output_devices AUDIO_DEVICE_OUT_BLUETOOTH_A2DP
audio_hal_version 2.0
}
outputs {
a2dp {
sampling_rates 44100
channel_masks AUDIO_CHANNEL_OUT_STEREO
formats AUDIO_FORMAT_PCM_16_BIT
devices AUDIO_DEVICE_OUT_BLUETOOTH_A2DP|AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES|AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER
}
}
}
usb { /* usb音訊配置檔案 */
global_configuration {
attached_output_devices AUDIO_DEVICE_OUT_USB_ACCESSORY
audio_hal_version 2.0
}
outputs {
usb_accessory {
sampling_rates 44100
channel_masks AUDIO_CHANNEL_OUT_STEREO
formats AUDIO_FORMAT_PCM_16_BIT
devices AUDIO_DEVICE_OUT_USB_ACCESSORY
}
usb_device {
sampling_rates 44100
channel_masks AUDIO_CHANNEL_OUT_STEREO
formats AUDIO_FORMAT_PCM_16_BIT
devices AUDIO_DEVICE_OUT_USB_DEVICE
}
}
}
}
可以看到對於a2dp來說,只支援音訊輸出,不支援音訊輸入,所以只有outputs device,沒有inputs device,而對於主音訊裝置、就有inputs device。然後在device中就會配置該音訊裝置支援的輸入、輸出音訊,如a2dp的輸出音訊就支援:AUDIO_DEVICE_OUT_BLUETOOTH_A2DP|AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES|AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER。支援的輸入音訊裝置定義也類似,如主音訊中inputs device中的定義。
Android下各種音訊輸入、輸出裝置定義如下:
android/system/core/include/system/audio.h
enum {
AUDIO_DEVICE_NONE = 0x0,
/* reserved bits */
AUDIO_DEVICE_BIT_IN = 0x80000000,
AUDIO_DEVICE_BIT_DEFAULT = 0x40000000,
/* output devices */
AUDIO_DEVICE_OUT_EARPIECE = 0x1,
AUDIO_DEVICE_OUT_SPEAKER = 0x2,
AUDIO_DEVICE_OUT_WIRED_HEADSET = 0x4,
AUDIO_DEVICE_OUT_WIRED_HEADPHONE = 0x8,
AUDIO_DEVICE_OUT_BLUETOOTH_SCO = 0x10,
AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20,
AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 0x40,
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP = 0x80,
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100,
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200,
AUDIO_DEVICE_OUT_AUX_DIGITAL = 0x400,
AUDIO_DEVICE_OUT_HDMI = AUDIO_DEVICE_OUT_AUX_DIGITAL,
/* uses an analog connection (multiplexed over the USB connector pins for instance) */
AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET = 0x800,
AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET = 0x1000,
/* USB accessory mode: your Android device is a USB device and the dock is a USB host */
AUDIO_DEVICE_OUT_USB_ACCESSORY = 0x2000,
/* USB host mode: your Android device is a USB host and the dock is a USB device */
AUDIO_DEVICE_OUT_USB_DEVICE = 0x4000,
AUDIO_DEVICE_OUT_REMOTE_SUBMIX = 0x8000,
/* Telephony voice TX path */
AUDIO_DEVICE_OUT_TELEPHONY_TX = 0x10000,
/* Analog jack with line impedance detected */
AUDIO_DEVICE_OUT_LINE = 0x20000,
/* HDMI Audio Return Channel */
AUDIO_DEVICE_OUT_HDMI_ARC = 0x40000,
/* S/PDIF out */
AUDIO_DEVICE_OUT_SPDIF = 0x80000,
/* FM transmitter out */
AUDIO_DEVICE_OUT_FM = 0x100000,
/* Line out for av devices */
AUDIO_DEVICE_OUT_AUX_LINE = 0x200000,
/* limited-output speaker device for acoustic safety */
AUDIO_DEVICE_OUT_SPEAKER_SAFE = 0x400000,
AUDIO_DEVICE_OUT_DEFAULT = AUDIO_DEVICE_BIT_DEFAULT,
AUDIO_DEVICE_OUT_ALL = (AUDIO_DEVICE_OUT_EARPIECE |
AUDIO_DEVICE_OUT_SPEAKER |
AUDIO_DEVICE_OUT_WIRED_HEADSET |
AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
AUDIO_DEVICE_OUT_BLUETOOTH_SCO |
AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET |
AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT |
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER |
AUDIO_DEVICE_OUT_HDMI |
AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET |
AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET |
AUDIO_DEVICE_OUT_USB_ACCESSORY |
AUDIO_DEVICE_OUT_USB_DEVICE |
AUDIO_DEVICE_OUT_REMOTE_SUBMIX |
AUDIO_DEVICE_OUT_TELEPHONY_TX |
AUDIO_DEVICE_OUT_LINE |
AUDIO_DEVICE_OUT_HDMI_ARC |
AUDIO_DEVICE_OUT_SPDIF |
AUDIO_DEVICE_OUT_FM |
AUDIO_DEVICE_OUT_AUX_LINE |
AUDIO_DEVICE_OUT_SPEAKER_SAFE |
AUDIO_DEVICE_OUT_DEFAULT),
AUDIO_DEVICE_OUT_ALL_A2DP = (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER),
AUDIO_DEVICE_OUT_ALL_SCO = (AUDIO_DEVICE_OUT_BLUETOOTH_SCO |
AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET |
AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT),
AUDIO_DEVICE_OUT_ALL_USB = (AUDIO_DEVICE_OUT_USB_ACCESSORY |
AUDIO_DEVICE_OUT_USB_DEVICE),
/* input devices */
AUDIO_DEVICE_IN_COMMUNICATION = AUDIO_DEVICE_BIT_IN | 0x1,
AUDIO_DEVICE_IN_AMBIENT = AUDIO_DEVICE_BIT_IN | 0x2,
AUDIO_DEVICE_IN_BUILTIN_MIC = AUDIO_DEVICE_BIT_IN | 0x4,
AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET = AUDIO_DEVICE_BIT_IN | 0x8,
AUDIO_DEVICE_IN_WIRED_HEADSET = AUDIO_DEVICE_BIT_IN | 0x10,
AUDIO_DEVICE_IN_AUX_DIGITAL = AUDIO_DEVICE_BIT_IN | 0x20,
AUDIO_DEVICE_IN_HDMI = AUDIO_DEVICE_IN_AUX_DIGITAL,
/* Telephony voice RX path */
AUDIO_DEVICE_IN_VOICE_CALL = AUDIO_DEVICE_BIT_IN | 0x40,
AUDIO_DEVICE_IN_TELEPHONY_RX = AUDIO_DEVICE_IN_VOICE_CALL,
AUDIO_DEVICE_IN_BACK_MIC = AUDIO_DEVICE_BIT_IN | 0x80,
AUDIO_DEVICE_IN_REMOTE_SUBMIX = AUDIO_DEVICE_BIT_IN | 0x100,
AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET = AUDIO_DEVICE_BIT_IN | 0x200,
AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET = AUDIO_DEVICE_BIT_IN | 0x400,
AUDIO_DEVICE_IN_USB_ACCESSORY = AUDIO_DEVICE_BIT_IN | 0x800,
AUDIO_DEVICE_IN_USB_DEVICE = AUDIO_DEVICE_BIT_IN | 0x1000,
/* FM tuner input */
AUDIO_DEVICE_IN_FM_TUNER = AUDIO_DEVICE_BIT_IN | 0x2000,
/* TV tuner input */
AUDIO_DEVICE_IN_TV_TUNER = AUDIO_DEVICE_BIT_IN | 0x4000,
/* Analog jack with line impedance detected */
AUDIO_DEVICE_IN_LINE = AUDIO_DEVICE_BIT_IN | 0x8000,
/* S/PDIF in */
AUDIO_DEVICE_IN_SPDIF = AUDIO_DEVICE_BIT_IN | 0x10000,
AUDIO_DEVICE_IN_BLUETOOTH_A2DP = AUDIO_DEVICE_BIT_IN | 0x20000,
AUDIO_DEVICE_IN_LOOPBACK = AUDIO_DEVICE_BIT_IN | 0x40000,
AUDIO_DEVICE_IN_DEFAULT = AUDIO_DEVICE_BIT_IN | AUDIO_DEVICE_BIT_DEFAULT,
AUDIO_DEVICE_IN_ALL = (AUDIO_DEVICE_IN_COMMUNICATION |
AUDIO_DEVICE_IN_AMBIENT |
AUDIO_DEVICE_IN_BUILTIN_MIC |
AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET |
AUDIO_DEVICE_IN_WIRED_HEADSET |
AUDIO_DEVICE_IN_HDMI |
AUDIO_DEVICE_IN_TELEPHONY_RX |
AUDIO_DEVICE_IN_BACK_MIC |
AUDIO_DEVICE_IN_REMOTE_SUBMIX |
AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET |
AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET |
AUDIO_DEVICE_IN_USB_ACCESSORY |
AUDIO_DEVICE_IN_USB_DEVICE |
AUDIO_DEVICE_IN_FM_TUNER |
AUDIO_DEVICE_IN_TV_TUNER |
AUDIO_DEVICE_IN_LINE |
AUDIO_DEVICE_IN_SPDIF |
AUDIO_DEVICE_IN_BLUETOOTH_A2DP |
AUDIO_DEVICE_IN_LOOPBACK |
AUDIO_DEVICE_IN_DEFAULT),
AUDIO_DEVICE_IN_ALL_SCO = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET,
AUDIO_DEVICE_IN_ALL_USB = (AUDIO_DEVICE_IN_USB_ACCESSORY |
AUDIO_DEVICE_IN_USB_DEVICE),
};
這樣,有了音訊裝置庫及音訊配置檔案,就可以確定各個音訊裝置支援哪些輸入、輸出音訊了。這樣當上層需要輸出一個聲音時,就可以根據策略層選擇的輸出音訊裝置,選擇該輸出音訊裝置對應音訊裝置庫介面。
現在再看一下主音訊裝置,在主音訊裝置支援音訊輸出中,既有AUDIO_DEVICE_OUT_SPEAKER(喇叭),又有AUDIO_DEVICE_OUT_WIRED_HEADSET (有線耳機)AUDIO_DEVICE_OUT_ALL_SCO(藍芽通話PCM),而在音訊裝置庫中只有一個adev_open_output_stream介面,這時,就需要在adev_open_output_stream中根據實際的音訊輸出裝置進行不同的操作了。
如下面一個例子程式碼:
static int adev_open_output_stream(struct audio_hw_device *dev,
audio_io_handle_t handle,
audio_devices_t devices,
audio_output_flags_t flags,
struct audio_config *config,
struct audio_stream_out **stream_out,
const char *address __unused)
{
struct audio_device *adev = (struct audio_device *)dev;
struct stream_out *out;
int i, ret;
ALOGV("%s: enter: sample_rate(%d) channel_mask(%#x) devices(%#x) flags(%#x)",
__func__, config->sample_rate, config->channel_mask, devices, flags);
*stream_out = NULL;
out = (struct stream_out *)calloc(1, sizeof(struct stream_out));
if (devices == AUDIO_DEVICE_NONE)
devices = AUDIO_DEVICE_OUT_SPEAKER;
out->flags = flags;
out->devices = devices;
out->dev = adev;
out->format = config->format;
out->sample_rate = config->sample_rate;
out->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_STEREO;
out->handle = handle;
/* Init use case and pcm_config */
if (out->devices & AUDIO_DEVICE_OUT_SPEAKER) {
/* AUDIO_DEVICE_OUT_SPEAKER(喇叭輸出時處理) */
/* 省略程式碼 */
} else if (out->devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
/* AUDIO_DEVICE_OUT_WIRED_HEADSET (有線耳機輸出時處理) */
/* 省略程式碼 */
} else if (out->devices & AUDIO_DEVICE_OUT_ALL_SCO) {
/* AUDIO_DEVICE_OUT_ALL_SCO (藍芽PCM輸出時處理) */
/* 省略程式碼 */
} else {
/* 省略程式碼 */
}
相關文章
- Android Framework 音訊子系統(12)HAL層分析AndroidFramework音訊
- android HAL層程式碼Android
- Android音訊驅動學習(一) Audio HALAndroid音訊
- HAL 硬體抽象層介紹抽象
- Android HAL 層框架分析以及程式碼示例Android框架
- HTML5 Audio(音訊)簡介HTML音訊
- Android硬體抽象層(HAL)模組編寫規範Android抽象
- Android 11(R) Power HAL AIDL簡析 -- 基本介面AndroidAI
- 音訊處理開源庫webrtc(1)簡介音訊Web
- android Palette簡介Android
- Android LowMemoryKiller 簡介Android
- yaml語音簡介YAML
- 音視訊技術:視訊質量評價方法簡介
- android音視訊指南-管理音訊焦點Android音訊
- AI 聲音:數字音訊、語音識別、TTS 簡介與使用示例AI音訊TTS
- android 音訊播放 SoundPoolAndroid音訊
- Android音訊(三)AudioPolicyServiceAndroid音訊
- 高通QCC3006藍芽5.0音訊晶片簡介藍芽音訊晶片
- Android 音視訊 - MediaCodec 編解碼音視訊Android
- Android Audio HAL 介面介紹之 adev_set_parameters()和out_set_parameters()Androiddev
- android studio模版功能簡介Android
- Android 音訊應用框架Android音訊框架
- Android音視訊之AudioRecordAndroid
- Android Framework中的Application Framework層介紹AndroidFrameworkAPP
- WebRTC – Agora (聲網)簡介與實現音視訊通話WebGo
- 簡單介紹三層交換
- Android Thermal HAL 降龍十八掌Android
- Android音訊處理知識(一)MediaRecorder錄製音訊Android音訊
- Android 音視訊開發 視訊編碼,音訊編碼格式Android音訊
- 【Android系統】Android系統架構簡介Android架構
- Android入門教程 | SharedPreferences 簡介Android
- Android 圖形架構簡介Android架構
- Android音訊視覺化操作Android音訊視覺化
- android音視訊指南-MediaPlayer概述Android
- android音視訊指南-MediaRecorder概述Android
- Android訊息機制,從Java層到Native層剖析AndroidJava
- 【Camera專題】Qcom-Camera驅動框架淺析(Hal層->Driver層)框架
- Android HAL模組的載入過程Android
- android音視訊指南-處理音訊輸出的變化Android音訊