AAudio เป็น API เสียงที่เปิดตัวในรุ่น Android 8.0 เวอร์ชัน Android 8.1 มีการปรับปรุงเพื่อลดเวลาในการตอบสนองเมื่อใช้ร่วมกับ HAL และไดรเวอร์ที่รองรับ MMAP เอกสารนี้อธิบายเลเยอร์การแยกแยะฮาร์ดแวร์ (HAL) และการเปลี่ยนแปลงของไดรเวอร์ที่จําเป็นเพื่อรองรับฟีเจอร์ MMAP ของ AAudio ใน Android
การสนับสนุน AAudio MMAP ต้องใช้สิ่งต่อไปนี้
- การรายงานความสามารถ MMAP ของ HAL
- การใช้ฟังก์ชันใหม่ใน HAL
- การใช้ ioctl() ที่กําหนดเองสําหรับบัฟเฟอร์โหมด EXCLUSIVE (ไม่บังคับ)
- ระบุเส้นทางข้อมูลฮาร์ดแวร์เพิ่มเติม
- การตั้งค่าพร็อพเพอร์ตี้ของระบบที่เปิดใช้ฟีเจอร์ MMAP
สถาปัตยกรรม AAudio
AAudio เป็น C API เดิมแบบใหม่ที่ใช้เป็นทางเลือกแทน Open SL ES โดยจะใช้รูปแบบการออกแบบ Builder เพื่อสร้างสตรีมเสียง
AAudio มีเส้นทางข้อมูลที่มีเวลาในการตอบสนองต่ำ ในโหมด EXCLUSIVE ฟีเจอร์นี้อนุญาตให้โค้ดแอปพลิเคชันฝั่งไคลเอ็นต์เขียนลงในบัฟเฟอร์ที่แมปกับหน่วยความจำโดยตรงซึ่งแชร์กับไดรเวอร์ ALSA ในโหมด "ใช้ร่วมกัน" มิกเซอร์ที่ทำงานใน AudioServer จะใช้บัฟเฟอร์ MMAP ในโหมด EXCLUSIVE เวลาในการตอบสนองจะลดลงอย่างมากเนื่องจากข้อมูลจะข้ามมิกเซอร์
ในโหมด EXCLUSIVE บริการจะขอบัฟเฟอร์ MMAP จาก HAL และจัดการทรัพยากร บัฟเฟอร์ MMAP ทำงานในโหมด NOIRQ จึงไม่มีตัวนับการอ่าน/เขียนที่ใช้ร่วมกันเพื่อจัดการการเข้าถึงบัฟเฟอร์ แต่ไคลเอ็นต์จะเก็บรักษารูปแบบเวลาของฮาร์ดแวร์และคาดการณ์ว่าบัฟเฟอร์จะได้รับการอ่านเมื่อใด
ในแผนภาพด้านล่าง เราเห็นข้อมูล Pulse-code modulation (PCM) ไหลผ่าน MMAP FIFO ไปยังไดรเวอร์ ALSA บริการ AAudio จะขอการประทับเวลาเป็นระยะๆ จากนั้นส่งต่อไปยังรูปแบบการจับเวลาของลูกค้าผ่านคิวข้อความแบบอะตอม

ในโหมด "แชร์" ระบบจะใช้รูปแบบการจับเวลาด้วย แต่รูปแบบดังกล่าวจะอยู่ใน AAudioService
สําหรับการบันทึกเสียง ระบบจะใช้รูปแบบที่คล้ายกัน แต่ข้อมูล PCM จะไหลในทิศทางตรงกันข้าม
การเปลี่ยนแปลง HAL
สำหรับ tinyALSA โปรดดูที่
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);
สำหรับ HAL รุ่นเดิม โปรดดูที่
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);
สำหรับ HAL เสียง 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);
รายงานการรองรับ MMAP
ควรตั้งค่าพร็อพเพอร์ตี้ระบบ "aaudio.mmap_policy" เป็น 2 (AAUDIO_POLICY_AUTO) เพื่อให้เฟรมเวิร์กเสียงทราบว่า HAL เสียงรองรับโหมด MMAP (ดู "การเปิดใช้เส้นทางข้อมูล MMAP ของ AAudio" ด้านล่าง)
ไฟล์ audio_policy_configuration.xml ต้องมีโปรไฟล์เอาต์พุตและอินพุตสำหรับโหมด MMAP/NO IRQ โดยเฉพาะเพื่อให้เครื่องมือจัดการนโยบายเสียงทราบว่าควรเปิดสตรีมใดเมื่อสร้างไคลเอ็นต์ 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>
เปิดและปิดสตรีม MMAP
createMmapBuffer(int32_t minSizeFrames) generates (Result retval, MmapBufferInfo info);
สตรีม MMAP เปิดและปิดได้โดยเรียกใช้ฟังก์ชัน Tinyalsa
ตำแหน่ง MMAP ของคำค้นหา
การประทับเวลาที่ส่งกลับไปยังโมเดลการกําหนดเวลาประกอบด้วยตําแหน่งเฟรมและเวลาแบบต่อเนื่องเป็นนาโนวินาที
getMmapPosition() generates (Result retval, MmapPosition position);
HAL สามารถรับข้อมูลนี้จากไดรเวอร์ ALSA ได้โดยเรียกใช้ฟังก์ชัน Tinyalsa ใหม่ ดังนี้
int pcm_mmap_get_hw_ptr(struct pcm* pcm, unsigned int *hw_ptr, struct timespec *tstamp);
ตัวระบุไฟล์สำหรับหน่วยความจำที่ใช้ร่วมกัน
เส้นทางข้อมูล MMAP ของ AAudio ใช้พื้นที่หน่วยความจำที่แชร์ระหว่างฮาร์ดแวร์กับบริการเสียง ระบบจะอ้างอิงหน่วยความจำที่แชร์โดยใช้ตัวระบุไฟล์ที่สร้างขึ้นโดยไดรเวอร์ ALSA
การเปลี่ยนแปลงเคอร์เนล
หากตัวระบุไฟล์เชื่อมโยงโดยตรงกับไฟล์ไดร์ฟเวอร์ /dev/snd/
บริการ AAudio จะใช้ตัวระบุไฟล์ดังกล่าวในโหมดที่แชร์ได้ แต่ไม่สามารถส่งตัวบ่งชี้ไปยังโค้ดไคลเอ็นต์สำหรับโหมด EXCLUSIVE ได้ ตัวระบุไฟล์ /dev/snd/
จะให้การเข้าถึงที่กว้างเกินไปแก่ไคลเอ็นต์ SELinux จึงบล็อกไว้
หากต้องการรองรับโหมด EXCLUSIVE คุณต้องแปลงข้อบ่งชี้ /dev/snd/
เป็นข้อบ่งชี้ไฟล์ anon_inode:dmabuf
SELinux อนุญาตให้ส่งตัวระบุไฟล์นั้นไปยังไคลเอ็นต์ นอกจากนี้ AAudioService ยังใช้ AAudioFormat ได้ด้วย
คุณสามารถสร้างตัวระบุไฟล์ anon_inode:dmabuf
โดยใช้คลังหน่วยความจำ Android Ion
ดูข้อมูลเพิ่มเติมได้ที่แหล่งข้อมูลภายนอกต่อไปนี้
- "The Android ION memory allocator" https://lwn.net/Articles/480055/
- "ภาพรวม ION ของ Android" https://wiki.linaro.org/BenjaminGaignard/ion
- "การผสานรวมตัวจัดสรรหน่วยความจำ ION" https://lwn.net/Articles/565469/
การเปลี่ยนแปลง HAL
บริการ AAudio จำเป็นต้องทราบว่าระบบรองรับ anon_inode:dmabuf
นี้หรือไม่ ก่อนที่จะมี Android 10.0 วิธีเดียวที่จะทำเช่นนั้นได้คือส่งขนาดของบัฟเฟอร์ MMAP เป็นจำนวนติดลบ เช่น -2048 แทน 2048 หากรองรับ ใน Android 10.0 ขึ้นไป คุณตั้งค่า Flag AUDIO_MMAP_APPLICATION_SHAREABLE
ได้
mmapBufferInfo |= AUDIO_MMAP_APPLICATION_SHAREABLE;
การเปลี่ยนแปลงระบบย่อยเสียง
AAudio ต้องใช้เส้นทางข้อมูลเพิ่มเติมที่ส่วนหน้าของเสียงของส่วนย่อยของระบบเสียงเพื่อให้ทำงานควบคู่ไปกับเส้นทาง AudioFlinger เดิมได้ ระบบจะใช้เส้นทางเดิมนั้นสำหรับเสียงของระบบและเสียงของแอปพลิเคชันอื่นๆ ทั้งหมด ฟังก์ชันนี้อาจมาจากมิกเซอร์ซอฟต์แวร์ใน DSP หรือมิกเซอร์ฮาร์ดแวร์ใน SOC
เปิดใช้เส้นทางข้อมูล MMAP ของ AAudio
AAudio จะใช้เส้นทางข้อมูล AudioFlinger แบบเดิมหากระบบไม่รองรับ MMAP หรือเปิดสตรีมไม่สำเร็จ ดังนั้น AAudio จึงจะทำงานร่วมกับอุปกรณ์เสียงที่ไม่รองรับเส้นทาง MMAP/NOIRQ
เมื่อทดสอบการรองรับ MMAP สําหรับ AAudio คุณควรทราบว่าคุณกําลังทดสอบเส้นทางข้อมูล MMAP จริงหรือแค่ทดสอบเส้นทางข้อมูลเดิม ข้อมูลต่อไปนี้อธิบายวิธีเปิดใช้หรือบังคับใช้เส้นทางข้อมูลที่เจาะจง และวิธีค้นหาเส้นทางที่สตรีมใช้
พร็อพเพอร์ตี้ของระบบ
คุณตั้งค่านโยบาย MMAP ผ่านพร็อพเพอร์ตี้ของระบบได้ ดังนี้
- 1 = AAUDIO_POLICY_NEVER - ใช้เฉพาะเส้นทางเดิม อย่าพยายามใช้ MMAP
- 2 = AAUDIO_POLICY_AUTO - ลองใช้ MMAP หากดำเนินการไม่สำเร็จหรือไม่พร้อมใช้งาน ให้ใช้เส้นทางเดิม
- 3 = AAUDIO_POLICY_ALWAYS - ใช้เฉพาะเส้นทาง MMAP อย่ากลับไปใช้เส้นทางเดิม
ซึ่งอาจตั้งค่าไว้ใน Makefile ของอุปกรณ์ ดังนี้
# 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
นอกจากนี้ คุณยังลบล้างค่าเหล่านี้ได้หลังจากที่อุปกรณ์บูตแล้ว คุณจะต้องรีสตาร์ทเซิร์ฟเวอร์เสียงเพื่อให้การเปลี่ยนแปลงมีผล ตัวอย่างเช่น หากต้องการเปิดใช้โหมด AUTO สำหรับ MMAP ให้ทำดังนี้
adb root
adb shell setprop aaudio.mmap_policy 2
adb shell killall audioserver
มีฟังก์ชันที่ระบุไว้ใน ndk/sysroot/usr/include/aaudio/AAudioTesting.h
ซึ่งช่วยให้คุณลบล้างนโยบายสำหรับการใช้เส้นทาง MMAP ได้ ดังนี้
aaudio_result_t AAudio_setMMapPolicy(aaudio_policy_t policy);
หากต้องการดูว่าสตรีมใช้เส้นทาง MMAP หรือไม่ ให้เรียกใช้
bool AAudioStream_isMMapUsed(AAudioStream* stream);