تصحيح أخطاء الصوت

توضّح هذه المقالة بعض النصائح والحيل لتصحيح أخطاء الصوت في Android.

حوض ماء

"tee sink" هو ميزة تصحيح أخطاء AudioFlinger، وهي متوفّرة في الإصدارات المخصّصة فقط، للحفاظ على مقتطف قصير من الصوت الأخير لتحليله لاحقًا. ويتيح ذلك المقارنة بين ما تم تشغيله أو تسجيله في الواقع مقارنةً بما كان متوقّعًا.

لأغراض الخصوصية، يكون مصدر tee غير مفعّل تلقائيًا، سواء في وقت الترجمة أو وقت التشغيل. لاستخدام وحدة معالجة تدفق tee، عليك تفعيلها من خلال إعادة الترجمة، وأيضاً من خلال ضبط خاصية. احرص على إيقاف هذه الميزة بعد انتهاء تصحيح الأخطاء، ويجب عدم إبقاء وحدة معالجة تدفق البيانات مفعّلة في الإصدارات العلنية.

تنطبق التعليمات الواردة في هذا القسم على الإصدار 7.x من Android والإصدارات الأحدث. بالنسبة إلى الإصدارين 5.x و6.x من نظام Android، استبدِل /data/misc/audioserver ب /data/misc/media. بالإضافة إلى ذلك، يجب استخدام إصدار userdebug أو eng. إذا كنت تستخدم إصدار userdebug، يمكنك إيقاف Verity باستخدام:

adb root && adb disable-verity && adb reboot

الإعداد في وقت التجميع

  1. cd frameworks/av/services/audioflinger
  2. تعديل Configuration.h
  3. أزِل التعليق التوضيحي من #define TEE_SINK.
  4. أعِد إنشاء libaudioflinger.so.
  5. adb root
  6. adb remount
  7. ادفع libaudioflinger.so الجديد أو زامِنه مع /system/lib الجهاز.

الإعداد في وقت التشغيل

  1. adb shell getprop | grep ro.debuggable
    تأكّد من أنّ النتيجة هي: [ro.debuggable]: [1]
  2. adb shell
  3. ls -ld /data/misc/audioserver

    تأكَّد من أنّ الإخراج هو:

    drwx------ media media ... media
    

    إذا لم يكن الدليل متوفّرًا، أنشِئه على النحو التالي:

    mkdir /data/misc/audioserver
    chown media:media /data/misc/audioserver
    
  4. echo af.tee=# > /data/local.prop
    حيث تكون قيمة af.tee رقمًا موضّحًا أدناه.
  5. chmod 644 /data/local.prop
  6. reboot

قيم خاصية af.tee

قيمة af.tee هي رقم يتراوح بين 0 و7، ويعبّر عن مجموع عدة بتات، بت واحد لكل ميزة. اطّلِع على الرمز البرمجي في AudioFlinger::AudioFlinger() في AudioFlinger.cpp لشرح كل جزء بشكل موجز:

  • 1 = إدخال
  • 2 = إخراج FastMixer
  • 4 = لكل مقطع صوتي AudioRecord وAudioTrack

لا يتوفّر حاليًا أيّ إعداد لميزة "التخزين المؤقت المتقدّم" أو أداة "المزج العادي"، ولكن يمكنك الحصول على نتائج مشابهة باستخدام "4".

اختبار البيانات واكتساب المعلومات

  1. أجرِ اختبار الصوت.
  2. adb shell dumpsys media.audio_flinger
  3. ابحث عن سطر في إخراج dumpsys على النحو التالي:
    tee copied to /data/misc/audioserver/20131010101147_2.wav
    هذا ملف wav .بتنسيق PCM.
  4. بعد ذلك، adb pull أي ملفات /data/misc/audioserver/*.wav تهمّك، يُرجى العِلم أنّ أسماء ملفات تفريغ البيانات الخاصة بالمسار لا تظهر في dumpsys، ولكن لا يزال يتم حفظها في /data/misc/audioserver عند إغلاق المسار.
  5. راجِع ملفات الذاكرة المؤقتة بحثًا عن أي مشاكل متعلقة بالخصوصية قبل مشاركتها مع الآخرين.

اقتراحات

جرِّب هذه الأفكار للحصول على نتائج أكثر فائدة:

  • أوقِف أصوات اللمس وأصوات النقر على المفاتيح لتقليل الانقطاعات في نتائج الاختبار.
  • زيادة جميع الأحجام إلى أقصى حدّ
  • أوقِف التطبيقات التي تُصدر صوتًا أو تسجِّل من الميكروفون، إذا لم تكن ذات صلة باختبارك.
  • لا يتم حفظ عمليات تفريغ البيانات الخاصة بالمسار إلا عند إغلاق المسار. قد تحتاج إلى إغلاق أحد التطبيقات بشكلٍ قسري لتفريغ بياناته الخاصة بالمسار.
  • عليك إجراء dumpsys بعد الاختبار مباشرةً، لأنّ مساحة التسجيل محدودة.
  • للتأكّد من عدم فقدان ملفات البيانات، حمِّلها إلى المضيف بانتظام. يتم الاحتفاظ بعدد محدود من ملفات الأرشيف، ويتم إزالة ملفات الأرشيف القديمة بعد بلوغ هذا الحدّ.

استعادة

كما هو موضّح أعلاه، يجب عدم إبقاء ميزة "التنقيط" مفعّلة. استعد الإصدار والجهاز باتّباع الخطوات التالية:

  1. أرجِع التغييرات التي أجريتها على رمز المصدر إلى Configuration.h.
  2. أعِد إنشاء libaudioflinger.so.
  3. ادفع libaudioflinger.so المستعادة أو مزامنتها مع /system/lib على الجهاز.
  4. adb shell
  5. rm /data/local.prop
  6. rm /data/misc/audioserver/*.wav
  7. reboot

media.log

وحدات الماكرو ALOGx

واجهة برمجة التطبيقات العادية لتسجيل لغة Java في حزمة تطوير البرامج (SDK) لنظام التشغيل Android هي android.util.Log.

واجهة برمجة التطبيقات المقابلة للغة C في Android NDK هي __android_log_print تمّ تعريفها في <android/log.h>.

ضمن الجزء الأصلي من إطار عمل Android، نفضّل استخدام وحدات الماكرو التي تحمل الأسماء ALOGE وALOGW وALOGI وALOGV وما إلى ذلك. ويتمّ الإعلان عنها في <utils/Log.h>، وسنشير إليها بشكلٍ جماعي باسم ALOGx لأغراض هذه المقالة.

إنّ جميع واجهات برمجة التطبيقات هذه سهلة الاستخدام ومفهومة جيدًا، لذا فهي منتشرة في جميع أنحاء نظام Android الأساسي. وعلى وجه التحديد، تستخدِم عملية mediaserver ALOGx بشكلٍ مكثّف، والتي تتضمّن خادم الصوت AudioFlinger.

ومع ذلك، هناك بعض القيود المفروضة على ALOGx والأصدقاء:

  • وهي عرضة لـ "الرسائل غير المرغوب فيها في السجلّ": فالذاكرة المؤقتة للسجلّ هي مورد مشترَك، وبالتالي يمكن أن تتجاوز سعة التخزين بسهولة بسبب إدخالات السجلّ غير ذات الصلة، ما يؤدي إلى عدم رصد معلومات مهمة. يكون الصيغة ALOGV غير مفعّلة عند compile-time تلقائيًا. ولكن بالطبع، يمكن أن يؤدي ذلك أيضًا إلى زيادة عدد الرسائل غير المرغوب فيها في السجلّ في حال تفعيله.
  • يمكن أن يتم حظر طلبات نظام kernel الأساسية، ما قد يؤدي إلى عكس الأولوية وبالتالي حدوث اضطرابات في القياس وعدم دقة. ويُعدّ ذلك موضع قلق بشكلٍ خاص في سلاسل المحادثات المهمة من حيث التوقيت، مثل FastMixer وFastCapture.
  • إذا تم إيقاف سجلّ معيّن للحد من المحتوى غير المرغوب فيه في السجلّ، سيتم فقدان أي معلومات كان من الممكن تسجيلها في هذا السجلّ. لا يمكن تفعيل سجلّ معيّن بأثر رجعي، بعد أن يتضح أنّه كان من المفيد تفعيله.

NBLOG وmedia.log وMediaLogService

تشكّل واجهات برمجة تطبيقات NBLOG والعمليات media.log والخدمة MediaLogService المرتبطة بها معًا نظام تسجيل أحدث للوسائط، وهي مصمّمة تحديدًا لمعالجة المشاكل المذكورة أعلاه. سنستخدم بشكل فضفاض المصطلح "media.log" للإشارة إلى الثلاثة معًا، ولكن بشكل صارم، NBLOG هو واجهة برمجة تطبيقات تسجيل C++، وmedia.log هو اسم عملية Linux، وMediaLogService هي خدمة ربط Android لفحص السجلّات.

"المخطط الزمني" في media.log هو سلسلة من إدخالات السجلّ يتم الاحتفاظ بترتيبها النسبي. وفقًا للعرف، يجب أن تستخدم كل سلسلة محادثات مخططًا زمنيًا خاصًا بها.

المزايا

تشمل مزايا نظام media.log ما يلي:

  • لا تُرسِل الرسائل غير المرغوب فيها إلى السجلّ الرئيسي إلا عند الحاجة.
  • يمكن فحصها حتى في حال تعطُّل mediaserver أو تعليقه.
  • لا يتم حظر الإعلانات حسب المخطط الزمني.
  • تتسبّب في حدوث اضطراب أقل في الأداء. (بالطبع، لا يمكن أن يكون أي شكل من أشكال التسجيل غير مُزعج تمامًا).

هندسة معمارية

يوضّح الرسم البياني أدناه العلاقة بين عملية mediaserver وعملية init، قبل إدخال media.log:

البنية قبل media.log

الشكل 1: البنية قبل media.log

النقاط البارزة:

  • init عمليات التفريع والتنفيذ mediaserver
  • يرصد init توقُّف mediaserver عن العمل، ويعيد إنشاء الإصدار المشتق منه عند الضرورة.
  • لا يتم عرض تسجيل ALOGx.

يوضّح الرسم البياني أدناه العلاقة الجديدة بين المكوّنات، بعد إضافة media.log إلى البنية:

البنية بعد media.log

الشكل 2: البنية بعد media.log

التغييرات المهمة:

  • يستخدم العملاء واجهة برمجة التطبيقات NBLOG لإنشاء إدخالات السجلّ وإرفاقها بملف تخزين دوار في الذاكرة المشتركة.
  • يمكن لـ MediaLogService تفريغ محتوى المخزن الدائري في أي وقت.
  • تم تصميم المخزن المؤقت الدائري بطريقة لا تؤدي إلى تعطُّل MediaLogService في حال حدوث أي تلف في الذاكرة المشتركة، وسيظل بإمكانه تفريغ أكبر قدر ممكن من المخزن المؤقت الذي لم يتأثّر بالتلف.
  • لا يعرقل المخزن الدائري الأداء ولا يتطلب قفلًا لكل من كتابة الإدخالات الجديدة وقراءة الإدخالات الحالية.
  • لا يلزم إجراء أيّ طلبات نظام للنواة لكتابة البيانات في المخزن الدائري أو قراءتها منه (باستثناء الطوابع الزمنية الاختيارية).

أماكن الاستخدام

اعتبارًا من Android 4.4، تتوفّر بضع نقاط سجلّ فقط في AudioFlinger تستخدم نظام media.log. على الرغم من أنّ واجهات برمجة التطبيقات الجديدة ليست سهلة الاستخدام مثل ALOGx، إلا أنّها ليست صعبة للغاية أيضًا. ننصحك بالتعرّف على نظام التسجيل الجديد في الحالات التي يكون فيها من الضروري استخدام هذا النظام. وعلى وجه الخصوص، ننصح باستخدام هذه الطريقة مع سلاسل مهام AudioFlinger التي يجب تنفيذها بشكل متكرر وبصورة دورية وبدون حظر، مثل سلاسل المهام FastMixer وFastCapture.

كيفية الاستخدام

إضافة سجلّات

أولاً، عليك إضافة سجلّات إلى الرمز البرمجي.

في سلاسل محادثات FastMixer وFastCapture، استخدِم رمزًا مثل هذا:

logWriter->log("string");
logWriter->logf("format", parameters);
logWriter->logTimestamp();

بما أنّ الجدول الزمني NBLog هذا لا يستخدمه سوى سلسلة المحادثات FastMixer و FastCapture، لا حاجة إلى الاستبعاد المتبادل.

في سلاسل محادثات AudioFlinger الأخرى، استخدِم mNBLogWriter:

mNBLogWriter->log("string");
mNBLogWriter->logf("format", parameters);
mNBLogWriter->logTimestamp();

بالنسبة إلى سلاسل المحادثات غير FastMixer وFastCapture، يمكن استخدام المخطط الزمني NBLog الخاص بالسلسلة من خلال السلسلة نفسها وعمليات الربط. لا يوفّر NBLog::Writer أي نوع من المنع المتبادل الضمني لكل مخطط زمني، لذا تأكَّد من أنّ جميع السجلّات تحدث في سياق يتم فيه حجز المفتاح المانع mLock للسلسلة.

بعد إضافة السجلات، أعِد إنشاء AudioFlinger.

ملاحظة: يجب توفير مخطط زمني منفصل NBLog::Writer لكل سلسلة محادثات، لضمان أمان سلسلة المحادثات، لأنّ المخططات الزمنية تحذف قفل المهام المتزامنة بشكلٍ مُصمَّم. إذا كنت تريد استخدام مخطط زمني واحد في أكثر من سلسلة محادثات، يمكنك حمايته باستخدام ملف mLock حالي (كما هو موضّح أعلاه)، أو يمكنك استخدام NBLog::LockedWriter بدلاً من NBLog::Writer. ومع ذلك، ينفي ذلك إحدى المزايا الرئيسية لواجهة برمجة التطبيقات هذه، وهي سلوك عدم الحظر.

يمكنك الاطّلاع على واجهة برمجة التطبيقات NBLog الكاملة على frameworks/av/include/media/nbaio/NBLog.h.

تفعيل ملف media.log

يكون الخيار media.log غير مفعَّل تلقائيًا. ولا يكون نشطًا إلا عندما تكون قيمة السمة ro.test_harness هي 1. يمكنك تفعيلها من خلال:

adb root
adb shell
echo ro.test_harness=1 > /data/local.prop
chmod 644 /data/local.prop
reboot

انقطع الاتصال أثناء إعادة التشغيل، لذا:

adb shell
سيعرض الأمر ps media الآن عمليتَين:
  • media.log
  • mediaserver

دوِّن رقم تعريف العملية mediaserver للرجوع إليه لاحقًا.

عرض الجداول الزمنية

يمكنك طلب الحصول على سجلّ يدويًا في أي وقت. يعرض هذا الأمر السجلات من جميع المخططات الزمنية النشطة والحديثة، ثم يُجري عملية محو لها:

dumpsys media.log

تجدر الإشارة إلى أنّ المخططات الزمنية مستقلة بطبيعتها، ولا تتوفّر إمكانية دمج المخططات الزمنية.

استرداد السجلات بعد إيقاف "خدمة الوسائط"

جرِّب الآن إنهاء عملية mediaserver: kill -9 #، حيث يشير الرقم # إلى رقم تعريف العملية الذي دوّنته سابقًا. من المفترض أن يظهر لك ملف تم إنشاؤه من media.log في logcat الرئيسي، يعرض جميع السجلات التي أدت إلى حدوث العُطل.

dumpsys media.log