صوت AAudio وMMAP

AAudio هي واجهة برمجة تطبيقات للصوت تم تقديمها في إصدار Android 8.0. الإصدار 8.1 من نظام التشغيل Android يحتوي الإصدار على تحسينات لتقليل وقت الاستجابة عند استخدامه مع طبقة تجريد الأجهزة (HAL) وبرنامج تشغيل يدعم MMAP. يصف هذا المستند تجريد الأجهزة الطبقة (HAL) وتغييرات برنامج التشغيل اللازمة لدعم ميزة MMAP في AAudio في Android

يتطلب دعم AAudio MMAP ما يلي:

  • الإبلاغ عن إمكانات MMAP في HAL
  • فإن تنفيذ دوال جديدة في دالة HAL
  • تنفيذ ioctl() مخصص اختياريًا للمخزن المؤقت للوضع "حصري"
  • توفير مسار إضافي لبيانات الأجهزة
  • إعداد خصائص النظام التي تمكّن ميزة MMAP

بنية الصوت Aالصوت

الصوت فقط هي واجهة برمجة تطبيقات جديدة أصلية من C API توفّر بديلاً لـ Open SL ES. تستخدم أنماط تصميم لإنشاء عمليات بث صوتي

يوفر AAudio مسار بيانات في وقت الاستجابة المنخفض. في الوضع الحصري، تستخدم الميزة يسمح لرمز تطبيق العميل بالكتابة مباشرةً في مخزن مؤقت تم تعيين الذاكرة الذي تتم مشاركته مع برنامج تشغيل ALSA. في الوضع المشترك، يتم استخدام المخزن المؤقت MMAP من قِبل جهاز مزج يعمل في AudioServer. وفي الوضع الحصري، يبلغ وقت الاستجابة أقل بكثير لأن البيانات تتجاوز الخلاط.

في الوضع الحصري، تطلب الخدمة المخزن المؤقت MMAP من HAL وتديره الموارد. يعمل المخزن المؤقت MMAP في وضع NOIRQ، لذا لا تتوفر عدّادات القراءة/الكتابة لإدارة الوصول إلى المخزن المؤقت. بدلاً من ذلك، لا يحتاج العميل على نموذج التوقيت للجهاز والتنبؤ بوقت تخزين المخزن المؤقت تَقْرَأ

في الرسم التخطيطي أدناه، يمكننا رؤية تدفق بيانات تعديل رمز النبض (PCM) عبر MMAP FIFO إلى برنامج تشغيل ALSA. يتم إدراج الطوابع الزمنية بشكل دوري طلبت خدمة AAudio ثم تمريرها إلى نموذج توقيت العميل من خلال قائمة انتظار بسيطة للرسائل

مخطط تدفق بيانات PCM.
الشكل 1. تدفق بيانات PCM من خلال FIFO إلى ALSA

في الوضع المشترك، يتم أيضًا استخدام نموذج توقيت، ولكنه موجود في 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);

لـ HIDL Audio 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);

الإبلاغ عن دعم MMAP

خاصية النظام "aaudio.mmap_policy" على 2 (AAUDIO_POLICY_Auto) يعرف إطار العمل الصوتي أن وضع MMAP المتوافق مع الصوت هو HAL. (يُرجى الاطّلاع على تفعيل مسار بيانات AAudio MMAP" below.)

يجب أن يحتوي ملف 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 في طلب البحث

يحتوي الطابع الزمني الذي تم تمريره إلى نموذج الوقت على موضع إطار زمن MONOTONIC بالثواني:

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);

أدوات وصف الملفات للذاكرة المشتركة

يستخدم مسار بيانات AAudio MMAP منطقة ذاكرة تتم مشاركتها بين الأجهزة وخدمة الصوت. تتم الإشارة إلى الذكرى المشتركة باستخدام واصف ملف الذي يُنشئه برنامج تشغيل ALSA.

تغييرات النواة

إذا كان واصف الملف مرتبطًا بشكل مباشر ملف برنامج تشغيل /dev/snd/، فيمكن استخدامه من خلال خدمة AAudio في الوضع المشترك. ولكن لا يمكن تمرير الواصف إلى رمز العميل الوضع الحصري. سيوفر واصف ملف /dev/snd/ أيضًا على نطاق واسع من الوصول إلى العميل، لذلك يتم حظره بواسطة SELinux.

لإتاحة الوضع الحصري، يجب تحويل أداة وصف /dev/snd/ إلى ملف anon_inode:dmabuf واصف البيانات. يسمح SELinux بتمرير واصف الملف هذا إلى العميل. أُنشأها جون هنتر، الذي كان متخصصًا كما يمكن استخدامه أيضًا بواسطة AAudioService.

يمكن إنشاء واصف ملف anon_inode:dmabuf باستخدام مكتبة ذاكرة Android Ion

للحصول على معلومات إضافية، اطلع على هذه الموارد الخارجية:

  1. "تخصيص ذاكرة Android ION" https://lwn.net/Articles/480055/
  2. "نظرة عامة على Android ION" https://wiki.linaro.org/BenjaminGaignard/ion
  3. "دمج أداة تخصيص ذاكرة ION" https://lwn.net/Articles/565469/

التغييرات على HAL

تحتاج خدمة AAudio إلى معرفة ما إذا كان anon_inode:dmabuf هذا قبل الإصدار Android 10.0، كانت الطريقة الوحيدة لإجراء ذلك هي تمرير حجم MMAP. المخزن المؤقت كرقم سالب، مثل -2048 بدلاً من 2048، إذا كان ذلك متاحًا. على الإصدار 10.0 من نظام Android والإصدارات الأحدث يمكنك وضع العلامة AUDIO_MMAP_APPLICATION_SHAREABLE.

mmapBufferInfo |= AUDIO_MMAP_APPLICATION_SHAREABLE;

تغييرات في النظام الفرعي للصوت

يتطلّب AAudio مسار بيانات إضافيًا في الواجهة الأمامية للصوت. بحيث يعمل بالتوازي مع مسار AudioFlinger الأصلي. يُستخدم هذا المسار القديم مع كل أصوات النظام وأصوات التطبيقات الأخرى. يمكن توفير هذه الوظيفة بواسطة برنامج مزج البرامج في وسيط عرض الطلب (DSP) أو أحد الأجهزة في SOC.

تفعيل مسار بيانات AAudio MMAP

سيستخدم 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

ويمكنك أيضًا إلغاء هذه القيم بعد تشغيل الجهاز. يجب إعادة تشغيل الخادم الصوتي كي تدخل التغييرات حيز التنفيذ. على سبيل المثال، لتفعيل الوضع "تلقائي" لملف 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);