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

Trong chế độ CHIA SẺ, một mô hình định thời cũng được sử dụng, nhưng nó nằm trong AAudioService.
Đối với thu âm thanh, một mô hình tương tự được sử dụng, nhưng dữ liệu PCM chuyển theo hướng ngược lại.
HAL thay đổi
Đố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 kế thừa, 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 âm thanh HIDL HAL:
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 hỗ trợ MMAP
Thuộc tính hệ thống "aaudio.mmap_policy" phải được đặt thành 2 (AAUDIO_POLICY_AUTO) để khung âm thanh biết rằng chế độ MMAP được hỗ trợ bởi HAL âm thanh. (xem "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 cấu hình đầu ra và đầu vào cụ thể 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 ứng dụng khách MMAP được tạo:
<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);
Luồng MMAP có thể được mở và đóng 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 trở lại 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);
Bộ mô tả tệp cho bộ nhớ dùng chung
Đường dẫn dữ liệu AAudio MMAP sử dụng 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 bộ mô tả tệp được tạo bởi trình điều khiển ALSA.
Thay đổi nhân
Nếu bộ mô tả tệp được liên kết trực tiếp với tệp /dev/snd/
driver, thì dịch vụ AAudio có thể sử dụng nó ở chế độ CHIA SẺ. Nhưng không thể chuyển bộ mô tả tới mã máy khách cho chế độ ĐỘC QUYỀN. Bộ mô tả /dev/snd/
file sẽ cung cấp quá nhiều quyền truy cập cho máy khách, vì vậy nó bị chặn bởi SELinux.
Để hỗ trợ chế độ EXCLUSIVE, cần phải chuyển đổi /dev/snd/
descriptor thành một bộ mô tả tệp anon_inode:dmabuf
. SELinux cho phép chuyển bộ mô tả tệp đó cho máy khách. Nó cũng có thể được sử dụng bởi AAudioService.
Có thể tạo bộ mô tả tệp anon_inode:dmabuf
bằ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 cấp phát bộ nhớ ION của Android" https://lwn.net/Articles/480055/
- "Tổng quan về ION của Android" https://wiki.linaro.org/BenjaminGaignard/ion
- "Tích hợp trình cấp phát bộ nhớ ION" https://lwn.net/Articles/565469/
HAL thay đổi
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 để làm điều đó là chuyển kích thước của bộ đệm MMAP dưới dạng số âm, chẳng hạn. -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 hệ thống phụ â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 phụ âm thanh để nó có thể hoạt động song song với đường dẫn AudioFlinger ban đầu. Đường dẫn kế thừa đó được sử dụng cho tất cả các âm thanh hệ thống và âm thanh ứng dụng khác. Chức năng này có thể được cung cấp bởi bộ trộn phần mềm trong DSP hoặc bộ trộn phần cứng trong SOC.
Bật đường dẫn dữ liệu AAudio MMAP
AAudio sẽ sử dụng đường dẫn dữ liệu AudioFlinger kế thừa 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 thiết bị âm thanh không hỗ trợ đường dẫn MMAP / NOIRQ.
Khi thử nghiệm hỗ trợ MMAP cho AAudio, điều quan trọng là phải biết liệu bạn đang thực sự thử nghiệm đường dẫn dữ liệu MMAP hay chỉ đơn thuần là thử nghiệm đường dẫn dữ liệu kế thừa. Phần sau 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 được một 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 kế thừa. Thậm chí không cố gắng sử dụng MMAP.
- 2 = AAUDIO_POLICY_AUTO - Hãy thử sử dụng MMAP. Nếu không thành công hoặc không có sẵn, hãy sử dụng đường dẫn kế thừa.
- 3 = AAUDIO_POLICY_ALWAYS - Chỉ sử dụng đường dẫn MMAP. Đừng quay trở lại con đường kế thừa.
Chúng có thể được đặt 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 bộ âm thanh để thay đổi có hiệu lực. Ví dụ: để bật chế độ TỰ ĐỘNG cho MMAP:
adb root
adb shell setprop aaudio.mmap_policy 2
adb shell killall audioserver
Có các chức năng đượ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);