บทความนี้อธิบายกลเม็ดเคล็ดลับบางอย่างในการแก้ไขข้อบกพร่องของเสียง Android
อ่างทีซิงก์
"อ่างของเสื้อยืด" เท่ากับ ฟีเจอร์การแก้ไขข้อบกพร่องของ AudioFlinger ซึ่งมีอยู่ในบิลด์ที่กำหนดเองเท่านั้น สำหรับเก็บส่วนย่อยของเสียงล่าสุดไว้เพื่อการวิเคราะห์ในภายหลัง ซึ่งช่วยให้เปรียบเทียบสิ่งที่เล่นหรือบันทึกจริงได้ เทียบกับที่คาดไว้
เพื่อความเป็นส่วนตัว ซิงก์เสื้อยืดจะปิดใช้อยู่โดยค่าเริ่มต้นทั้งในเวลาคอมไพล์และ รันไทม์ หากต้องการใช้ซิงก์ท้าย คุณจะต้องเปิดใช้ ด้วยการคอมไพล์อีกครั้ง และโดยการตั้งค่าพร็อพเพอร์ตี้ โปรดปิดใช้ฟีเจอร์นี้หลังจาก แก้ไขข้อบกพร่องเสร็จแล้ว ไม่ควรเปิดใช้ซิงก์เสื้อยืดในบิลด์เวอร์ชันที่ใช้งานจริง
วิธีการในส่วนนี้มีไว้สำหรับ Android 7.x ขึ้นไป สำหรับ Android
5.x และ 6.x แทนที่ /data/misc/audioserver
ด้วย
/data/misc/media
นอกจากนี้คุณต้องใช้โปรแกรมแก้ไขข้อบกพร่องหรือ
การสร้างภาษาอังกฤษ หากคุณใช้บิลด์ userdebug ให้ปิดใช้การยืนยันด้วย:
adb root && adb disable-verity && adb reboot
การตั้งค่าเวลาคอมไพล์
cd frameworks/av/services/audioflinger
- แก้ไข
Configuration.h
- Uncomment
#define TEE_SINK
- สร้าง
libaudioflinger.so
ใหม่ adb root
adb remount
- พุชหรือซิงค์
libaudioflinger.so
ใหม่ไปยัง/system/lib
ของอุปกรณ์
การตั้งค่ารันไทม์
adb shell getprop | grep ro.debuggable
ยืนยันว่าเอาต์พุตเป็น[ro.debuggable]: [1]
adb shell
ls -ld /data/misc/audioserver
ยืนยันว่าเอาต์พุตเป็นดังนี้
drwx------ media media ... media
ถ้าไม่มีไดเรกทอรี ให้สร้างดังนี้
mkdir /data/misc/audioserver
chown media:media /data/misc/audioserver
echo af.tee=# > /data/local.prop
โดยที่ค่าaf.tee
เป็นตัวเลขที่อธิบายไว้ด้านล่างchmod 644 /data/local.prop
reboot
ค่าสำหรับพร็อพเพอร์ตี้ af.tee
ค่าของ af.tee
เป็นตัวเลขระหว่าง 0 ถึง 7 ซึ่งแสดง
ผลรวมของหลายบิต หนึ่งบิตต่อฟีเจอร์
ดูรหัสที่ AudioFlinger::AudioFlinger()
ใน AudioFlinger.cpp
เพื่อดูคำอธิบายของแต่ละบิตโดยสังเขป
- 1 = อินพุต
- 2 = เอาต์พุต FastMixer
- 4 = AudioRecord และ AudioTrack ต่อแทร็ก
ยังไม่มีบิตสำหรับบัฟเฟอร์แบบดีปหรือมิกเซอร์แบบปกติ แต่คุณจะได้รับผลลัพธ์ที่คล้ายกันโดยใช้ "4"
ทดสอบและได้ข้อมูล
- ทดสอบเสียง
adb shell dumpsys media.audio_flinger
- มองหาบรรทัดในเอาต์พุต
dumpsys
เช่น
tee copied to /data/misc/audioserver/20131010101147_2.wav
ไฟล์นี้เป็นไฟล์ PCM .wav - จากนั้น
adb pull
ไฟล์ใดก็ได้/data/misc/audioserver/*.wav
ไฟล์ที่สนใจ โปรดทราบว่าชื่อไฟล์ Dump เฉพาะแทร็กจะไม่ปรากฏในส่วน เอาต์พุตdumpsys
แต่ยังคงบันทึกลงใน/data/misc/audioserver
เมื่อปิดแทร็ก - ตรวจสอบไฟล์ Dump เพื่อหาข้อกังวลด้านความเป็นส่วนตัวก่อนที่จะแชร์กับผู้อื่น
คำแนะนำ
ลองใช้แนวคิดต่อไปนี้เพื่อให้ได้ผลลัพธ์ที่เป็นประโยชน์มากขึ้น
- ปิดใช้เสียงแตะและการคลิกปุ่ม เพื่อลดการขัดจังหวะในเอาต์พุตทดสอบ
- เพิ่มระดับเสียงสูงสุด
- ปิดใช้แอปที่ส่งเสียงหรือบันทึกเสียงจากไมโครโฟน หากไม่สนใจการทดสอบ
- ระบบจะบันทึกข้อมูล Dump เฉพาะแทร็กเมื่อแทร็กปิดอยู่เท่านั้น คุณอาจต้องบังคับปิดแอปเพื่อถ่ายโอนข้อมูลเฉพาะแทร็กของแอปนั้น
- ทำ
dumpsys
ทันทีหลังจากการทดสอบ มีพื้นที่บันทึกจำกัด - เพื่อไม่ให้ไฟล์ Dump สูญหาย อัปโหลดไปยังโฮสต์ของคุณเป็นระยะ สามารถรักษาไฟล์ Dump ไว้ได้ในจำนวนจำกัด ระบบจะนำดัมพ์เก่าออกหลังจากถึงขีดจำกัดแล้ว
คืนค่า
ดังที่กล่าวไว้ข้างต้น ไม่ควรเปิดใช้ฟีเจอร์อ่างทีซิงก์ กู้คืนบิลด์และอุปกรณ์โดยทำดังนี้
- เปลี่ยนกลับการเปลี่ยนแปลงซอร์สโค้ดเป็น
Configuration.h
- สร้าง
libaudioflinger.so
ใหม่ - พุชหรือซิงค์
libaudioflinger.so
ที่กู้คืนแล้ว ไปยัง/system/lib
ของอุปกรณ์ adb shell
rm /data/local.prop
rm /data/misc/audioserver/*.wav
reboot
media.log
มาโคร ALOGx
API การบันทึกภาษา Java มาตรฐานใน Android SDK คือ android.util.Log
API ภาษา C ที่สอดคล้องกันใน Android NDK คือ
__android_log_print
ที่ประกาศใน<android/log.h>
ในส่วนเนทีฟของเฟรมเวิร์ก Android
ต้องการมาโครชื่อ ALOGE
, ALOGW
ALOGI
, ALOGV
ฯลฯ ประกาศใน
<utils/Log.h>
และตามวัตถุประสงค์ของบทความนี้
เราจะเรียกรวมกันว่า ALOGx
API ทั้งหมดนี้ใช้งานง่ายและเข้าใจเป็นอย่างดี ทำให้มีแพร่หลาย
ในทุกแพลตฟอร์ม Android โดยเฉพาะอย่างยิ่ง mediaserver
ซึ่งรวมถึงเซิร์ฟเวอร์เสียง AudioFlinger จะใช้
ALOGx
อย่างมาก
แต่มีข้อจำกัดบางประการสำหรับ ALOGx
และเพื่อนดังนี้
-
มีความเสี่ยงต่อ "สแปมบันทึก": บัฟเฟอร์ไฟล์บันทึกเป็นทรัพยากรที่มีการแชร์
เพื่อให้สามารถใส่รายการเพิ่มเติมได้อย่างง่ายดาย เนื่องจากรายการบันทึกที่ไม่เกี่ยวข้อง ซึ่งส่งผลให้เกิด
ข้อมูลที่ไม่ได้รับ ตัวแปร
ALOGV
ถูกปิดใช้ที่ เวลาคอมไพล์โดยค่าเริ่มต้น แต่แน่นอนว่าผลลัพธ์ที่ได้คือสแปมบันทึก หากเปิดใช้อยู่ -
การเรียกระบบเคอร์เนลที่อยู่เบื้องหลังอาจบล็อก ซึ่งอาจทำให้เกิด
การกลับลำดับความสำคัญ และจากนั้น รบกวนการวัดและ
ความไม่ถูกต้อง นี้ของ
ข้อกังวลพิเศษสำหรับชุดข้อความที่ต้องคำนึงถึงเวลาเป็นสำคัญ เช่น
FastMixer
และFastCapture
- ถ้ามีการปิดใช้บันทึกใดเพื่อลดสแปมบันทึก ข้อมูลใดๆ ที่อาจจะบันทึกไว้โดยบันทึกนั้นจะสูญหายไป คุณไม่สามารถเปิดใช้งานบันทึกบางรายการย้อนหลังได้ หลังเป็นที่ประจักษ์ว่าบันทึกนั้นน่าสนใจ
NBLOG, media.log และ MediaLogService
API ของ NBLOG
และ media.log
ที่เชื่อมโยง
กระบวนการและMediaLogService
เข้าด้วยกัน ทำให้ระบบเก็บบันทึกใหม่ สำหรับสื่อ และ
ที่ออกแบบมาเพื่อแก้ปัญหาข้างต้น โดยเราจะใช้คำว่า
"media.log" จะอ้างอิงถึงทั้ง 3 อย่าง แต่พูดง่ายๆ ก็คือ NBLOG
คือ
API การบันทึกของ C++, media.log
เป็นชื่อกระบวนการของ Linux และ MediaLogService
เป็นบริการ Android Binder สำหรับตรวจสอบบันทึก
"ไทม์ไลน์" media.log
เป็นซีรีส์
ของรายการบันทึกที่มีการเก็บรักษาตามลำดับที่เกี่ยวข้อง
โดยปกติ แต่ละชุดข้อความควรใช้ไทม์ไลน์ของตัวเอง
ข้อดี
ประโยชน์ของระบบ media.log
คือ
- ไม่ส่งสแปมไปยังบันทึกหลัก เว้นแต่และจนกว่าจะจำเป็นต้องใช้
- ตรวจสอบได้แม้ว่า
mediaserver
จะขัดข้องหรือค้าง - ไม่บล็อกต่อไทม์ไลน์
- รบกวนประสิทธิภาพการทำงานน้อยกว่า (แน่นอนว่าการบันทึกทุกรูปแบบจะไม่เป็นการรบกวนแต่อย่างใด)
สถาปัตยกรรม
แผนภาพด้านล่างแสดงความสัมพันธ์ของกระบวนการ mediaserver
และกระบวนการ init
ก่อนการใช้ media.log
![สถาปัตยกรรมก่อนมีเดีย.log](https://source.android.com/static/docs/core/audio/images/medialog_before.png?authuser=4&hl=th)
รูปที่ 1 สถาปัตยกรรมก่อนมีเดีย.log
คะแนนสำคัญ:
init
แยกและผู้บริหารmediaserver
init
ตรวจพบการเสียชีวิตของmediaserver
และแยกออกตามความจำเป็น- ระบบไม่แสดงการบันทึก
ALOGx
แผนภาพด้านล่างแสดงความสัมพันธ์ใหม่ของคอมโพเนนต์
หลังจากเพิ่ม media.log
ในสถาปัตยกรรมแล้ว
![สถาปัตยกรรมหลัง media.log](https://source.android.com/static/docs/core/audio/images/medialog_after.png?authuser=4&hl=th)
รูปที่ 2 สถาปัตยกรรมหลัง media.log
การเปลี่ยนแปลงที่สำคัญ
-
ไคลเอ็นต์ใช้
NBLOG
API เพื่อสร้างรายการบันทึกและนำไปต่อท้าย บัฟเฟอร์รูปวงกลมในหน่วยความจำที่ใช้ร่วมกัน -
MediaLogService
ดัมพ์เนื้อหาของบัฟเฟอร์วงกลมได้ทุกเมื่อ -
บัฟเฟอร์รูปวงกลมถูกออกแบบมาในลักษณะที่ทำให้
หน่วยความจำที่แชร์จะไม่ขัดข้อง
MediaLogService
และจะยังใช้งานต่อไปได้ เพื่อถ่ายโอนบัฟเฟอร์ที่ไม่ได้รับผลกระทบจากความเสียหายนั้นออกไปให้ได้มากที่สุด - บัฟเฟอร์รูปวงกลมไม่บล็อกและไม่มีการล็อกสำหรับทั้งการเขียน รายการใหม่ และการอ่านรายการที่มีอยู่
- ไม่จำเป็นต้องมีการเรียกใช้ระบบเคอร์เนลเพื่อเขียนหรืออ่านจากบัฟเฟอร์วงกลม (นอกเหนือจากการประทับเวลาที่ไม่บังคับ)
ใช้ที่ใดได้บ้าง
ใน Android 4.4 มีเพียงจุดบันทึกไม่กี่จุดใน AudioFlinger
ที่ใช้ระบบ media.log
แม้ว่า API ใหม่จะไม่เหมือน
ที่ใช้งานง่ายด้วย 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
แยกต่างหากต่อชุดข้อความ
เพื่อความปลอดภัยของ Thread เนื่องจากไทม์ไลน์จะไม่มีการปิดเสียงตามที่ควรจะเป็น หากคุณ
ต้องการให้ชุดข้อความมากกว่า 1 รายการใช้ไทม์ไลน์เดียวกัน คุณสามารถป้องกันด้วย
Listener ที่มีอยู่ (ตามที่อธิบายไว้ข้างต้นสำหรับ mLock
) หรือคุณสามารถ
ให้ใช้ Wrapper NBLog::LockedWriter
แทน NBLog::Writer
อย่างไรก็ตาม การทำเช่นนี้ทำให้ประโยชน์หลักของ API นี้ลดลง ซึ่งก็คือการไม่บล็อก
พฤติกรรมของคุณ
API ของ 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
จะแสดงกระบวนการ 2 รายการดังนี้
- media.log
- เซิร์ฟเวอร์สื่อ
จดรหัสกระบวนการของ mediaserver
ไว้ใช้ภายหลัง
แสดงลำดับเวลา
คุณขอดัมพ์บันทึกด้วยตนเองได้ทุกเมื่อ คำสั่งนี้จะแสดงบันทึกจากไทม์ไลน์ที่ใช้งานอยู่และล่าสุดทั้งหมด จากนั้นจะล้างข้อมูลดังนี้
dumpsys media.log
โปรดทราบว่า ลำดับเวลาในการออกแบบเป็นอิสระ และไม่มีบริการ ในการรวมไทม์ไลน์
กู้คืนบันทึกหลังจากเซิร์ฟเวอร์สื่อไม่ทำงาน
ตอนนี้ให้ลองปิดกระบวนการ mediaserver
: kill -9 #
โดยที่ # คือ
รหัสกระบวนการที่คุณจดไว้ก่อนหน้า คุณควรเห็นไฟล์ดัมพ์จาก media.log
ใน logcat
หลัก โดยแสดงบันทึกทั้งหมดที่นำไปสู่ข้อขัดข้อง
dumpsys media.log