AAudio là một API âm thanh được ra mắt trong bản phát hành Android 8.0. Bản phát hành Android 8.1 có các tính năng nâng cao để giảm độ trễ khi sử dụng cùng với HAL và trình điều khiển hỗ trợ MMAP. Tài liệu này mô tả lớp trừu tượng phần cứng (HAL) và các thay đổi về trình điều khiển cần thiết để hỗ trợ tính năng MMAP của AAudio trong Android.
Để hỗ trợ AAudio MMAP, bạn cần:
- báo cáo các chức năng MMAP của HAL
- triển khai các hàm mới trong HAL
- tuỳ ý triển khai ioctl() tuỳ chỉnh cho vùng đệm chế độ EXCLUSIVE
- cung cấp thêm một đường dẫn dữ liệu phần cứng
- thiết lập các thuộc tính hệ thống cho phép tính năng MMAP
Cấu trúc AAudio
AAudio là một API C gốc mới cung cấp giải pháp thay thế cho Open SL ES. Thư viện này sử dụng mẫu thiết kế Trình tạo để tạo luồng âm thanh.
AAudio cung cấp đường dẫn dữ liệu có độ trễ thấp. Ở chế độ EXCLUSIVE, tính năng này cho phép mã ứng dụng của máy khách ghi trực tiếp vào vùng đệm được liên kết với bộ nhớ được chia sẻ với trình điều khiển ALSA. Ở chế độ SHARED, vùng đệm MMAP được một bộ trộn chạy trong AudioServer sử dụng. Ở chế độ EXCLUSIVE, độ trễ sẽ giảm đáng kể vì dữ liệu sẽ bỏ qua bộ trộn.
Ở chế độ EXCLUSIVE, dịch vụ yêu cầu vùng đệm MMAP từ HAL và quản lý tài nguyên. Vùng đệm MMAP đang chạy ở chế độ NOIRQ, vì vậy, không có bộ đếm đọc/ghi dùng chung để quản lý quyền truy cập vào vùng đệm. Thay vào đó, ứng dụng duy trì mô hình thời gian của phần cứng và dự đoán thời điểm đọc vùng đệm.
Trong sơ đồ dưới đây, chúng ta có thể thấy dữ liệu Điều chế xung nhịp (PCM) chảy xuống thông qua MMAP FIFO vào trình điều khiển ALSA. Dịch vụ AAudio định kỳ yêu cầu dấu thời gian, sau đó chuyển đến mô hình thời gian của ứng dụng thông qua hàng đợi thông báo nguyên tử.

Ở chế độ CHIA SẺ, mô hình thời gian cũng được sử dụng, nhưng mô hình này nằm trong AAudioService.
Đối với tính năng ghi âm, một mô hình tương tự được sử dụng, nhưng dữ liệu PCM sẽ chảy theo hướng ngược lại.
Thay đổi về HAL
Đối với tinyALSA, hãy xem:
external/tinyalsa/include/tinyalsa/asoundlib.h external/tinyalsa/include/tinyalsa/pcm.c
int pcm_start(struct pcm *pcm); int pcm_stop(struct pcm *pcm); int pcm_mmap_begin(struct pcm *pcm, void **areas, unsigned int *offset, unsigned int *frames); int pcm_get_poll_fd(struct pcm *pcm); int pcm_mmap_commit(struct pcm *pcm, unsigned int offset, unsigned int frames); int pcm_mmap_get_hw_ptr(struct pcm* pcm, unsigned int *hw_ptr, struct timespec *tstamp);
Đối với HAL cũ, hãy xem:
hardware/libhardware/include/hardware/audio.h hardware/qcom/audio/hal/audio_hw.c
int start(const struct audio_stream_out* stream); int stop(const struct audio_stream_out* stream); int create_mmap_buffer(const struct audio_stream_out *stream, int32_t min_size_frames, struct audio_mmap_buffer_info *info); int get_mmap_position(const struct audio_stream_out *stream, struct audio_mmap_position *position);
Đối với HAL âm thanh HIDL:
hardware/interfaces/audio/2.0/IStream.hal hardware/interfaces/audio/2.0/types.hal hardware/interfaces/audio/2.0/default/Stream.h
start() generates (Result retval); stop() generates (Result retval) ; createMmapBuffer(int32_t minSizeFrames) generates (Result retval, MmapBufferInfo info); getMmapPosition() generates (Result retval, MmapPosition position);
Báo cáo tính năng hỗ trợ MMAP
Bạn nên đặt thuộc tính hệ thống "aaudio.mmap_policy" thành 2 (AAUDIO_POLICY_AUTO) để khung âm thanh biết rằng chế độ MMAP được HAL âm thanh hỗ trợ. (xem phần "Bật đường dẫn dữ liệu AAudio MMAP" bên dưới.)
Tệp audio_policy_configuration.xml cũng phải chứa hồ sơ đầu ra và đầu vào dành riêng cho chế độ MMAP/NO IRQ để Trình quản lý chính sách âm thanh biết luồng nào sẽ mở khi tạo ứng dụng MMAP:
<mixPort name="mmap_no_irq_out" role="source" flags="AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_MMAP_NOIRQ"> <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> </mixPort> <mixPort name="mmap_no_irq_in" role="sink" flags="AUDIO_INPUT_FLAG_MMAP_NOIRQ"> <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_STEREO"/> </mixPort>
Mở và đóng luồng MMAP
createMmapBuffer(int32_t minSizeFrames) generates (Result retval, MmapBufferInfo info);
Bạn có thể mở và đóng luồng MMAP bằng cách gọi các hàm Tinyalsa.
Truy vấn vị trí MMAP
Dấu thời gian được chuyển lại cho Mô hình thời gian chứa vị trí khung và thời gian MONOTONIC tính bằng nano giây:
getMmapPosition() generates (Result retval, MmapPosition position);
HAL có thể lấy thông tin này từ trình điều khiển ALSA bằng cách gọi một hàm Tinyalsa mới:
int pcm_mmap_get_hw_ptr(struct pcm* pcm, unsigned int *hw_ptr, struct timespec *tstamp);
Chỉ số mô tả tệp cho bộ nhớ dùng chung
Đường dẫn dữ liệu MMAP của AAudio sử dụng một vùng bộ nhớ được chia sẻ giữa phần cứng và dịch vụ âm thanh. Bộ nhớ dùng chung được tham chiếu bằng cách sử dụng chỉ số mô tả tệp do trình điều khiển ALSA tạo.
Thay đổi về nhân
Nếu chỉ số mô tả tệp được liên kết trực tiếp với tệp trình điều khiển /dev/snd/
, thì dịch vụ AAudio có thể sử dụng chỉ số mô tả tệp đó ở chế độ SHARED (CHIA SẺ). Tuy nhiên, bạn không thể truyền chỉ số mô tả đến mã ứng dụng cho chế độ EXCLUSIVE. Chỉ số mô tả tệp /dev/snd/
sẽ cung cấp quyền truy cập quá rộng cho ứng dụng, vì vậy, ứng dụng này sẽ bị SELinux chặn.
Để hỗ trợ chế độ EXCLUSIVE, bạn cần chuyển đổi mô tả /dev/snd/
thành mô tả tệp anon_inode:dmabuf
. SELinux cho phép truyền chỉ số mô tả tệp đó đến ứng dụng. AAudioService cũng có thể sử dụng API này.
Bạn có thể tạo chỉ số mô tả tệp anon_inode:dmabuf
bằng cách sử dụng thư viện bộ nhớ Android Ion.
Để biết thêm thông tin, hãy xem các tài nguyên bên ngoài sau:
- "Trình phân bổ bộ nhớ ION của Android" https://lwn.net/Articles/480055/
- "Tổng quan về Android ION" https://wiki.linaro.org/BenjaminGaignard/ion
- "Tích hợp trình phân bổ bộ nhớ ION" https://lwn.net/Articles/565469/
Thay đổi về HAL
Dịch vụ AAudio cần biết liệu anon_inode:dmabuf
này có được hỗ trợ hay không. Trước Android 10.0, cách duy nhất để thực hiện việc đó là truyền kích thước của bộ đệm MMAP dưới dạng số âm, ví dụ: -2048 thay vì 2048, nếu được hỗ trợ. Trong Android 10.0 trở lên, bạn có thể đặt cờ AUDIO_MMAP_APPLICATION_SHAREABLE
.
mmapBufferInfo |= AUDIO_MMAP_APPLICATION_SHAREABLE;
Thay đổi về hệ thống con âm thanh
AAudio yêu cầu một đường dẫn dữ liệu bổ sung ở đầu cuối âm thanh của hệ thống con âm thanh để có thể hoạt động song song với đường dẫn AudioFlinger ban đầu. Đường dẫn cũ đó được dùng cho tất cả âm thanh hệ thống và âm thanh ứng dụng khác. Chức năng này có thể do bộ trộn phần mềm trong DSP hoặc bộ trộn phần cứng trong SOC cung cấp.
Bật đường dẫn dữ liệu AAudio MMAP
AAudio sẽ sử dụng đường dẫn dữ liệu AudioFlinger cũ nếu MMAP không được hỗ trợ hoặc không mở được luồng. Vì vậy, AAudio sẽ hoạt động với một thiết bị âm thanh không hỗ trợ đường dẫn MMAP/NOIRQ.
Khi kiểm thử tính năng hỗ trợ MMAP cho AAudio, điều quan trọng là bạn phải biết liệu mình có thực sự đang kiểm thử đường dẫn dữ liệu MMAP hay chỉ kiểm thử đường dẫn dữ liệu cũ. Phần sau đây mô tả cách bật hoặc buộc các đường dẫn dữ liệu cụ thể và cách truy vấn đường dẫn mà luồng sử dụng.
Thuộc tính hệ thống
Bạn có thể đặt chính sách MMAP thông qua các thuộc tính hệ thống:
- 1 = AAUDIO_POLICY_NEVER – Chỉ sử dụng đường dẫn cũ. Thậm chí đừng cố gắng sử dụng MMAP.
- 2 = AAUDIO_POLICY_AUTO – Thử sử dụng MMAP. Nếu không thành công hoặc không có, hãy sử dụng đường dẫn cũ.
- 3 = AAUDIO_POLICY_ALWAYS – Chỉ sử dụng đường dẫn MMAP. Không quay lại đường dẫn cũ.
Bạn có thể đặt các giá trị này trong Makefile của thiết bị, như sau:
# Enable AAudio MMAP/NOIRQ data path. # 2 is AAUDIO_POLICY_AUTO so it will try MMAP then fallback to Legacy path. PRODUCT_PROPERTY_OVERRIDES += aaudio.mmap_policy=2 # Allow EXCLUSIVE then fall back to SHARED. PRODUCT_PROPERTY_OVERRIDES += aaudio.mmap_exclusive_policy=2
Bạn cũng có thể ghi đè các giá trị này sau khi thiết bị khởi động. Bạn sẽ cần khởi động lại máy chủ âm thanh để thay đổi có hiệu lực. Ví dụ: để bật chế độ AUTO cho MMAP:
adb root
adb shell setprop aaudio.mmap_policy 2
adb shell killall audioserver
Có các hàm được cung cấp trong ndk/sysroot/usr/include/aaudio/AAudioTesting.h
cho phép bạn ghi đè chính sách sử dụng đường dẫn MMAP:
aaudio_result_t AAudio_setMMapPolicy(aaudio_policy_t policy);
Để tìm hiểu xem một luồng có đang sử dụng đường dẫn MMAP hay không, hãy gọi:
bool AAudioStream_isMMapUsed(AAudioStream* stream);