简介
goldfish是google为android提供的一个模拟器。包含内核、aosp等部分。最近用到audio相关知识,学习下goldfish中的设计。
goldfish在hw的模拟在/device/generic/goldfish目录中,其中目录对应相应的模块(本文中列出的代码是aosp9中的)。
代码及关键点
查看模块从脚本开始
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_VENDOR_MODULE := true
LOCAL_MODULE := audio.primary.goldfish
LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_MODULE_TAGS := optional
LOCAL_SHARED_LIBRARIES := libcutils liblog
LOCAL_SRC_FILES := audio_hw.c
.....
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_VENDOR_MODULE := true
LOCAL_MODULE := audio.primary.goldfish_legacy
LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_MODULE_TAGS := optional
LOCAL_SHARED_LIBRARIES := libcutils liblog
LOCAL_SRC_FILES := audio_hw_legacy.c
...
include $(BUILD_SHARED_LIBRARY)
从mk中可以看到包含两个module audio.primary.goldfish和 audio.primary.goldfish_legacy,legacy可以认为是老式的实现, in和out分别代表的音频的输入和输出。
对比legacy中对音频设备的描述:
legacy:
struct generic_audio_device {
struct audio_hw_device device;
pthread_mutex_t lock;
struct audio_stream_out *output;
struct audio_stream_in *input;
int fd;
bool mic_mute;
};
struct generic_audio_device {
struct audio_hw_device device; // Constant after init
pthread_mutex_t lock;
bool mic_mute; // Proteced by this->lock
struct mixer* mixer; // Proteced by this->lock
};
stream的描述:
legacy:
struct generic_stream_out {
struct audio_stream_out stream;
struct generic_audio_device *dev;
audio_devices_t device;
uint32_t sample_rate;
};
struct generic_stream_in {
struct audio_stream_in stream;
struct generic_audio_device *dev;
audio_devices_t device;
};
struct generic_stream_out {
struct audio_stream_out stream; // Constant after init
pthread_mutex_t lock;
struct generic_audio_device *dev; // Constant after init
audio_devices_t device; // Protected by this->lock
struct audio_config req_config; // Constant after init
struct pcm_config pcm_config; // Constant after init
audio_vbuffer_t buffer; // Constant after init
// Time & Position Keeping
bool standby; // Protected by this->lock
uint64_t underrun_position; // Protected by this->lock
struct timespec underrun_time; // Protected by this->lock
uint64_t last_write_time_us; // Protected by this->lock
uint64_t frames_total_buffered; // Protected by this->lock
uint64_t frames_written; // Protected by this->lock
uint64_t frames_rendered; // Protected by this->lock
// Worker
pthread_t worker_thread; // Constant after init
pthread_cond_t worker_wake; // Protected by this->lock
bool worker_standby; // Protected by this->lock
bool worker_exit; // Protected by this->lock
};
struct generic_stream_in {
struct audio_stream_in stream; // Constant after init
pthread_mutex_t lock;
struct generic_audio_device *dev; // Constant after init
audio_devices_t device; // Protected by this->lock
struct audio_config req_config; // Constant after init
struct pcm *pcm; // Protected by this->lock
struct pcm_config pcm_config; // Constant after init
int16_t *stereo_to_mono_buf; // Protected by this->lock
size_t stereo_to_mono_buf_size; // Protected by this->lock
audio_vbuffer_t buffer; // Protected by this->lock
// Time & Position Keeping
bool standby; // Protected by this->lock
int64_t standby_position; // Protected by this->lock
struct timespec standby_exit_time;// Protected by this->lock
int64_t standby_frames_read; // Protected by this->lock
// Worker
pthread_t worker_thread; // Constant after init
pthread_cond_t worker_wake; // Protected by this->lock
bool worker_standby; // Protected by this->lock
bool worker_exit; // Protected by this->lock
};
可以看出,legacy的实现先对简单,较新的实现,音频的读写采用了线程和vbuffer。至于vbuffer是什么?通过查看可以看出是个缓冲区:
typedef struct audio_vbuffer {
pthread_mutex_t lock;
uint8_t * data;
size_t frame_size;
size_t frame_count;
size_t head;
size_t tail;
size_t live;
} audio_vbuffer_t;
两者的函数映射都是在dev_open中执行:
static int adev_open(const hw_module_t* module, const char* name,
hw_device_t** device)
{
....
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; // no op
adev->device.set_voice_volume = adev_set_voice_volume; // no op
adev->device.set_master_volume = adev_set_master_volume; // no op
adev->device.get_master_volume = adev_get_master_volume; // no op
adev->device.set_master_mute = adev_set_master_mute; // no op
adev->device.get_master_mute = adev_get_master_mute; // no op
adev->device.set_mode = adev_set_mode; // no op
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; // no op
adev->device.get_parameters = adev_get_parameters; // no op
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;
*device = &adev->device.common;
adev->mixer = mixer_open(PCM_CARD);
struct mixer_ctl *ctl;
// Set default mixer ctls
// Enable channels and set volume
...
audio_device_ref_count++;
unlock:
pthread_mutex_unlock(&adev_init_lock);
return 0;
}
static int adev_open(const hw_module_t* module, const char* name,
hw_device_t** device)
{
......
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.get_master_volume = adev_get_master_volume;
adev->device.set_master_mute = adev_set_master_mute;
adev->device.get_master_mute = adev_get_master_mute;
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;
*device = &adev->device.common;
return 0;
}
实际读写的线程在out_write_worker和in_read_worker中可以看到相关的实现。采用线程明显效率高一些。
其他
- android HAL 接口
音频的hal分为
-
Core HAL
AudioFlinger(音频服务)用于播放音频和控制音频路由的主要 API。 -
Effects HAL
主要用于控制音频效果,例如自动增益控制和噪声抑制。 -
Common HAL
是为core HAL API和Effects HAL API 提供数据支持,定义了一些相关的数据结构。
根据官网上列出的音频hal接口版本:
Android 13 7.1
Android 12 7.0
Android 11 6.0
Android 10 5.0
Android 9 4.0
Android 8 2.0
可查看代码/hardware/interfaces/audio/
目录下内容。
-
采样率转换
Android中有些地方要用到重采样。例如MP3的采样率为44.1KHZ,但Android设备中需要支持48kHZ的音频。从44.1KHZ到48KHZ的转换就相当于重采样。
参考官方的重采样特征包含以下:- 信号整体幅度的保存程度
- 信号频率带宽的保存程度(受设备采样率的限制)
- 通过重采样器的整体延迟时间
- 有关频率的一致相位和群组延迟
- 计算复杂度(以 CPU 周期或功耗表示)
- 允许的源采样率和设备采样率的比率
- 动态更改采样率比率的能力
- 支持的数字音频采样格式
常见的采样率有线性、立方、具有原始系数的 sinc和具有修订系数的 sinc。