- เมื่อติดตาม white noise บนแล็ปท็อป Linux ก็พบปัญหาว่าแม้ไม่มีเสียงจริง แท็บ Firefox ก็ยังปลุก audio sink ของ PulseAudio ไว้อย่างต่อเนื่อง
module-suspend-on-idleถูกตั้งค่าให้หยุดอุปกรณ์เสียงหลังผ่านไป 10 วินาที แต่เมื่อเว็บไซต์สร้าง AudioContext ขึ้นมา sink จะไม่ลดสถานะลงไปเป็นIDLE/SUSPENDED- พบอาการเดียวกันกับการแจ้งเตือนบน Outlook เว็บ, การคลิกบน x.com, การเล่นเสียงบน Google Translate และ Discord เว็บแอป และเพียงแค่
new AudioContext()ก็ทำให้เริ่มมี noise ได้แล้ว - จากการวัด เมื่อไม่มี noise ค่า CPU ของ
pulseaudioอยู่ที่ 0.0% แต่เมื่อมี noise จะขึ้นไปที่ 4.7% และพลังงานรวมของระบบเพิ่มขึ้นราว 1.5W AudioContext.suspend()สามารถหยุดการเข้าถึงฮาร์ดแวร์เสียงเพื่อลดการใช้ CPU/แบตเตอรี่ได้ แต่ Firefox ไม่ได้หยุดความสิ้นเปลืองนี้ให้อัตโนมัติหลังผ่านไประยะหนึ่งเหมือน Chrome
ปัญหา audio sink ไม่ยอมหลับ
- บนแล็ปท็อปเครื่องใหม่ แม้ตอนที่ไม่มีการเล่นเพลงหรือเสียงใด ๆ ก็ยังได้ยิน white noise เบา ๆ แต่ชวนรำคาญจากลำโพง
- ใช้
pactl list sinks shortเพื่อตรวจสอบสถานะของ PulseAudio บน Linux- สถานะของ audio sink จะแสดงเป็น
IDLE,SUSPENDEDหรือRUNNING - เมื่อตัว sink อยู่ในสถานะ
SUSPENDEDลำโพงจะเงียบ - เมื่ออยู่ในสถานะ
IDLEหรือRUNNINGก็อาจเกิด white noise ได้แม้ไม่มีเสียงที่เล่นจริง
- สถานะของ audio sink จะแสดงเป็น
- ใน
/etc/pulse/default.paและ/etc/pulse/system.paมีการโหลดmodule-suspend-on-idleอยู่- ตามการตั้งค่า หากไม่มีการใช้งาน 10 วินาที audio sink ควรถูกหยุดอัตโนมัติ
- แต่ในบางสถานการณ์ sink ไม่ยอมลงไปเป็น
IDLEจึงไปไม่ถึงSUSPENDED
ทำไมเสียงว่างงานถึงกินพลังงาน
module-suspend-on-idleจะตัดการเชื่อม sink และ source ที่ไม่ได้เชื่อมกับสตรีมใด ๆ ออกจากแบ็กเอนด์หลังผ่านไประยะหนึ่ง- ผลสำคัญคือ ประหยัดพลังงาน
- หาก PulseAudio ยังส่งข้อมูลว่างไปยังซาวด์การ์ดในช่วง idle, ALSA จะใช้ CPU cycle มากขึ้น
- หากไม่ได้ตั้งใจให้มีสตรีมที่ทำงานตลอดเวลา การตั้งเวลาให้สั้นลงจะช่วยประหยัดพลังงานได้มากกว่า
ต้นเหตุถูกไล่แคบลงมาที่แท็บ Firefox และเว็บไซต์
- ทุกครั้งที่ได้ยิน white noise มีการใช้
pactl list sink-inputsเพื่อตรวจสอบว่าโปรแกรมใดกำลังใช้ audio sink - ต้นเหตุคือ Firefox ทุกครั้ง
- ในแท็บที่เปิดอยู่ ไม่มีแท็บใดที่ควรเล่นเสียงจริง
- ไม่มีวิดีโอที่ถูกปิดเสียงไว้ด้วย
- มีการเพิ่มสคริปต์เล็ก ๆ ลงในแถบสถานะ i3 เพื่อให้ขึ้นสัญลักษณ์สีแดงเมื่อ audio sink เปลี่ยนเป็น
RUNNING - ตอนแรกดูเหมือนว่าเสียงแจ้งเตือนจาก outlook.office.com ที่ปักหมุดไว้เป็นต้นเหตุ
- เมื่อมีอีเมลเข้า white noise จะเริ่มทันที
- และจะไม่หยุดจนกว่าจะรีเฟรชแท็บหรือรีสตาร์ต Firefox
- ต่อมาพบอาการเดียวกันบนเว็บไซต์อื่นด้วย
- x.com แค่คลิกที่ใดก็ได้ noise ก็เริ่ม
- ตอนฟังเสียงแปลบน translate.google.com ก็เกิด noise เช่นกัน
- Discord เว็บแอป แค่เปิดทิ้งไว้ก็ทำให้เกิดผลเดียวกัน
ผลการวัด CPU และพลังงาน
- เมื่อไม่มี white noise การใช้ CPU ของ
pulseaudioแสดงเป็น 0.0% - ในสภาพแวดล้อมเดียวกัน ค่าการใช้พลังงานโดยรวมมักอยู่ในช่วง 4.2~5.1W
- เมื่อมี white noise การใช้ CPU ของ
pulseaudioเพิ่มเป็น 4.7% - ในตอนนั้น ค่าการใช้พลังงานโดยรวมมักอยู่ในช่วง 5.8~6.7W
- ความต่างนี้ไม่ใช่ระดับ “แทบไม่มีอะไร” แต่สรุปได้ว่ามีการเพิ่มขึ้นราว 1.5W
WebAudio API และ AudioContext
- วิธีเล่นเสียงใน HTML/JavaScript แบ่งได้เป็นสองแบบคือแท็ก
<audio>และ WebAudio API - กรณีที่ต้องเล่นเสียงแบบไดนามิกอย่าง Outlook จะใช้ WebAudio API และก่อนทำงานด้านเสียงต้องสร้าง
AudioContextขึ้นมาก่อน - ปัญหาคือเพียงรัน
const audioCtx = new AudioContext();ก็ทำให้ลำโพงเกิด white noise ได้แล้ว - มีหน้าเว็บทดสอบให้ที่ https://editor.43z.one/sqare/i
AudioContext.suspend()จะหยุดการเดินของเวลาใน audio context และพักการเข้าถึงฮาร์ดแวร์เสียงไว้ชั่วคราวเพื่อลดการใช้ CPU/แบตเตอรี่AudioContext.resume()จะเริ่มการเดินของเวลาใน audio context ที่ถูกหยุดไว้ขึ้นมาอีกครั้ง
ความต่างระหว่าง Firefox กับ Chrome
- หลายเว็บไซต์สร้าง
AudioContextไว้แม้ยังไม่จำเป็นต้องส่งเสียงทันที และหลังจากนั้นก็ไม่ได้ suspend มัน - Chrome จะหยุดความสิ้นเปลืองของ CPU/แบตเตอรี่โดยอัตโนมัติเมื่อผ่านไประยะหนึ่ง
- แต่ Firefox ไม่หยุดให้อัตโนมัติ และยังคงอยู่ในสภาพที่สร้าง white noise ต่อไป
- แม้เว็บไซต์จะเป็นสาเหตุโดยตรง แต่ก็ยังมีข้อบ่นว่า Firefox ไม่สามารถปกป้องผู้ใช้จากการสิ้นเปลืองทรัพยากรแบบนี้ได้
- ยังมีข้อสงสัยว่าแม้ตอนเชื่อมต่อหูฟัง Bluetooth การคลิก x.com ก็อาจเริ่มส่ง white noise ไปยังหูฟังและทำให้แบตเตอรี่ของหูฟังหมดเปลืองได้เช่นกัน
วิธีรับมือชั่วคราว: AudioContext Suspender
- เพื่อบรรเทาปัญหา จึงมีการทำส่วนขยายที่คอยหยุด
AudioContextโดยอัตโนมัติ และจะพยายามเริ่มใหม่เมื่อเว็บไซต์ต้องการเล่นเสียง - ส่วนขยายนี้ไม่ได้สมบูรณ์แบบ
- ใช้เวลาเล็กน้อยกว่าจะเริ่มใหม่
- เส้นทางในการเริ่มเสียงมีหลายแบบ จึงอาจไม่ได้กลับมาทำงานทุกครั้ง
- ถึงอย่างนั้นก็ยังเพียงพอต่อจุดประสงค์การใช้งาน
- ลิงก์ที่เกี่ยวข้อง
- ประเด็นใน Bugzilla ที่เกี่ยวข้อง
1 ความคิดเห็น
ความเห็นจาก Hacker News
อย่างที่พอจินตนาการได้ เรื่องนี้ซับซ้อนกว่าการพัก
AudioContextเมื่อไม่มีเสียงเป็นระยะเวลาหนึ่งมาก แต่ผมก็คิดว่าแก้ได้อยู่ดี เพราะเบราว์เซอร์อื่นทำไปแล้ว และก็มี ทางประนีประนอม ที่ยอมรับได้ที่มา: ผมเป็นคนทำฟีเจอร์แถว ๆ นี้ใน Firefox ไปเยอะ และยังเป็นบรรณาธิการของ มาตรฐาน Web Audio API ด้วย
คนส่วนใหญ่เข้าใจสถานการณ์ที่อธิบายไว้ตรงนี้ งานที่ต้องทำมีมาก แต่เวลาก็มีจำกัด
ผมเคยเห็นกับตาว่านักพัฒนา Firefox พยายามเกินความคาดหมายแค่ไหนเพื่อให้เว็บไซต์ยอดนิยมทำงานกับผู้ใช้ได้อย่างถูกต้อง ถ้าปัญหามันกระทบผู้ใช้ ผมรู้ว่าพวกเขายอมไปไกลแค่ไหน เพราะงั้นก็ขอให้สู้ต่อไป
ระบบประมวลผลเสียงถูกติดตั้งต่างกันไปตามเอนจินเบราว์เซอร์และระบบปฏิบัติการ ดังนั้นถ้าเล่นเสียงที่แทบไม่ได้ยินเลย แล้วอัดกลับผ่าน API ก็จะได้ลายเซ็นบางอย่าง
จากลายเซ็นนั้นก็ใช้ตรวจได้ว่าเบราว์เซอร์ปลอม user agent อยู่หรือเปล่า รันแบบ headless หรือเป็นกรณีแปลก ๆ อื่น ๆ แทนที่จะเป็นผู้ใช้จริงที่กำลังซื้อสินค้า
https://github.com/fingerprintjs/fingerprintjs/blob/3201a7d6...
ที่แท็บก็ไม่มีไอคอนว่ากำลังเล่นอยู่ และปิดเสียงแท็บแล้วเสียงรบกวนก็ยังไม่หยุด
แม้แต่ปิดเสียง Firefox ใน Windows volume mixer แล้ว เสียงก็ยังไม่หาย
แก้ไข: สำหรับผู้ใช้เดสก์ท็อป ส่วนขยายนี้จริง ๆ ค่อนข้างแย่ เพราะเสียง white noise ที่ติด ๆ ดับ ๆ น่ารำคาญยิ่งกว่าเดิมมาก
เพราะอย่างนั้นผมเลยเขียนโปรแกรมเองให้คอยเปิดเอาต์พุตทิ้งไว้ แม้จะไม่ได้ส่งข้อมูลลงไลน์จริง ๆ เพื่อไม่ให้เอาต์พุตเข้าสู่สถานะว่าง
แต่ในบริบทของโน้ตบุ๊ก มันก็ไม่ค่อยสมเหตุสมผลนัก ดังนั้นกรณีนั้นการประหยัดพลังงานก็ดูเหมาะสม
ในไดรเวอร์ของ Windows มีตัวเลือกให้ตั้งสตรีมเป็น Always On ได้ อยากให้มีบน macOS เหมือนกัน
play -qn &รันขึ้นมาตอนล็อกอินเท่านั้นเองดูเหมือนว่าเว็บข่าวเปิดเสียงไว้พร้อมกับโหลดโฆษณาใหม่ซ้ำ ๆ และเพราะมีเสียง แท็บจึงไม่เข้าสู่โหมดประหยัดพลังงาน สุดท้ายผมโดนค่าเน็ตเกินแบบไม่คาดคิดอยู่เรื่อย ๆ จนต้องย้ายไปใช้ Chrome
พูดอีกอย่างคือไม่มี white noise แต่มี การใช้พลังงานจากระบบเสียง: https://bugzilla.mozilla.org/show_bug.cgi?id=1821102
ตอนนี้บน Mac ของผม
coreaudiodก็ยังกิน CPU 20% ทั้งที่ไม่ได้เล่นอะไรเลย มันทำลายอายุแบตเตอรี่จริง ๆ จนผมคิดจะย้ายไปใช้เบราว์เซอร์อื่นชั่วคราวจนกว่าจะมีการแก้ไข แต่ก็ไม่อยากเลิกใช้ Firefox เพราะเรื่องที่ดูเหมือนเล็กน้อยแบบนี้อัปเดต: ดูเหมือนจะเกี่ยวข้องกันแต่เป็นบั๊กคนละตัว
https://source.chromium.org/chromium/chromium/src/+/main:med...
โดยพื้นฐานแล้ว ถ้าตรวจพบว่าเงียบประมาณ 30 วินาที จะสลับจาก sink ที่รองรับโดยอุปกรณ์เสียงของระบบปฏิบัติการไปเป็น null sink
เพื่ออ้างอิง วิธีนี้ใช้สัญญาณนาฬิกาคนละตัวกับอุปกรณ์เสียง จึงเคยมีรายงานอยู่สองสามครั้งว่าเมื่อ context ถูกนำมาใช้จริงภายหลัง จะเกิดความเพี้ยนกับบางโทนเสียง วิธีหลีกเลี่ยงคือให้เว็บไซต์ใช้ suspend/resume API ที่บทความพูดถึง
audioContextถูกติดตั้งอย่างไร แต่ดูเหมือนมีชิ้นส่วนที่ฉลาดและพยายามจัดการแบบไดนามิกอยู่ไม่น้อย การเล่นเสียงแจ้งเตือนดูคล้ายกับการวาด SVG ด้วย D3 แทนที่จะใช้img href *.svgเลยสงสัยว่าจะมีอะไรอย่าง hook ของ Service Worker ไหม ที่เอาไว้ลงทะเบียนสิ่งง่าย ๆ และทำซ้ำได้อย่างตัวจัดการการแจ้งเตือน ให้ไปทำผ่าน API ระดับล่างที่มีประสิทธิภาพกว่านี้
บน Firefox 134.0.1 ของ MacOS ผมไม่ได้ยินอะไรเลย