6 คะแนน โดย GN⁺ 2025-02-17 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • เมื่อติดตาม 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 ได้แม้ไม่มีเสียงที่เล่นจริง
  • ใน /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 ความคิดเห็น

 
GN⁺ 2025-02-17
ความเห็นจาก Hacker News
  • เรื่องนี้มีการวางแผนไว้แล้ว สำคัญ และตั้งใจว่าจะรีบแก้ถ้าเป็นไปได้ ข้อนี้ถูกเลื่อนมานานแล้ว และก็ขอโทษที่ยังจัดการไม่เสร็จ มันเป็นการแย่งลำดับความสำคัญกันอยู่เสมอ เลยยากที่จะทำให้ทุกคนพอใจได้ทันเวลา แต่ในรายการลำดับความสำคัญส่วนตัวของผม มันอยู่ค่อนข้างสูง
    อย่างที่พอจินตนาการได้ เรื่องนี้ซับซ้อนกว่าการพัก AudioContext เมื่อไม่มีเสียงเป็นระยะเวลาหนึ่งมาก แต่ผมก็คิดว่าแก้ได้อยู่ดี เพราะเบราว์เซอร์อื่นทำไปแล้ว และก็มี ทางประนีประนอม ที่ยอมรับได้
    ที่มา: ผมเป็นคนทำฟีเจอร์แถว ๆ นี้ใน Firefox ไปเยอะ และยังเป็นบรรณาธิการของ มาตรฐาน Web Audio API ด้วย
    • หวังว่าจะไม่มีใครรับคำวิจารณ์แบบนี้เป็นเรื่องส่วนตัว ช่วงไม่นานมานี้มีผู้ดูแลโอเพนซอร์สคนหนึ่งที่รับคำวิจารณ์ลักษณะนี้เป็นความคับข้องใจจนระเบิดออกมาครั้งใหญ่
      คนส่วนใหญ่เข้าใจสถานการณ์ที่อธิบายไว้ตรงนี้ งานที่ต้องทำมีมาก แต่เวลาก็มีจำกัด
      ผมเคยเห็นกับตาว่านักพัฒนา Firefox พยายามเกินความคาดหมายแค่ไหนเพื่อให้เว็บไซต์ยอดนิยมทำงานกับผู้ใช้ได้อย่างถูกต้อง ถ้าปัญหามันกระทบผู้ใช้ ผมรู้ว่าพวกเขายอมไปไกลแค่ไหน เพราะงั้นก็ขอให้สู้ต่อไป
    • ผมอยากเป็นผู้ใช้ Firefox ที่ใช้งานได้เก่งขึ้น เลยอยากลอง ดีบัก ปัญหาที่พบในเครื่องตัวเองบ้าง อยากได้คำแนะนำว่าควรเริ่มจากตรงไหน
  • ที่เว็บไซต์เปิด audio context โดยไม่ได้เล่นเสียงจริง ๆ น่าจะเป็นไปได้มากว่าเพื่อใช้ตรวจจับบอต
    ระบบประมวลผลเสียงถูกติดตั้งต่างกันไปตามเอนจินเบราว์เซอร์และระบบปฏิบัติการ ดังนั้นถ้าเล่นเสียงที่แทบไม่ได้ยินเลย แล้วอัดกลับผ่าน API ก็จะได้ลายเซ็นบางอย่าง
    จากลายเซ็นนั้นก็ใช้ตรวจได้ว่าเบราว์เซอร์ปลอม user agent อยู่หรือเปล่า รันแบบ headless หรือเป็นกรณีแปลก ๆ อื่น ๆ แทนที่จะเป็นผู้ใช้จริงที่กำลังซื้อสินค้า
    https://github.com/fingerprintjs/fingerprintjs/blob/3201a7d6...
    • ฝั่งเบราว์เซอร์/มาตรฐานเว็บเหมือนจะเพิ่ม API กันแบบไม่ยั้ง และไม่ได้คิดให้พอว่าสุดท้ายโลกจะเอาไปใช้ในทางผิดแบบนี้
    • ตอนนี้ก็มีปลั๊กอินสำหรับบอตที่ใช้งานกันจริงแล้ว ซึ่ง จำลอง Audio Context เพื่อหลอกระบบตรวจจับบอต เรื่องมันบ้าดีจริง ๆ
    • แทบรอวันให้ Cloudflare เอาสิ่งนี้มาใช้ เพื่อขัดขวางเสรีภาพในการท่องเว็บมากขึ้นและทำให้เสีย รอบ CPU โดยใช่เหตุไม่ไหวแล้ว
  • ผมเกือบเป็นบ้ามานานเพราะ white noise นี้ แต่หาสาเหตุไม่เจอเลย
    ที่แท็บก็ไม่มีไอคอนว่ากำลังเล่นอยู่ และปิดเสียงแท็บแล้วเสียงรบกวนก็ยังไม่หยุด
    แม้แต่ปิดเสียง Firefox ใน Windows volume mixer แล้ว เสียงก็ยังไม่หาย
    แก้ไข: สำหรับผู้ใช้เดสก์ท็อป ส่วนขยายนี้จริง ๆ ค่อนข้างแย่ เพราะเสียง white noise ที่ติด ๆ ดับ ๆ น่ารำคาญยิ่งกว่าเดิมมาก
    • ถ้าปิดเสียง Firefox ใน Windows volume mixer แล้วยังไม่หยุด ผมสงสัยว่านี่น่าจะเป็นบั๊กที่ลึกกว่า Firefox อีกหรือเปล่า
    • ผมใช้ส่วนขยายนั้นบนเดสก์ท็อปได้ปกติดี ดูเหมือนจะขึ้นอยู่กับว่าเข้าเว็บอะไร สำหรับเว็บที่เล่น/หยุดเสียงบ่อย ๆ ก็คงแค่ปิดส่วนขยายนั้น
  • ถ้าปล่อยให้เอาต์พุตว่างอยู่ สัญญาณ SPDIF ดิจิทัล จะหลุดซิงก์ พอเริ่มเล่นใหม่ การซิงก์กลับไม่ได้เกิดทันที แล้วจะเสียเสียงช่วงวินาทีแรกไปประมาณหนึ่ง
    เพราะอย่างนั้นผมเลยเขียนโปรแกรมเองให้คอยเปิดเอาต์พุตทิ้งไว้ แม้จะไม่ได้ส่งข้อมูลลงไลน์จริง ๆ เพื่อไม่ให้เอาต์พุตเข้าสู่สถานะว่าง
    แต่ในบริบทของโน้ตบุ๊ก มันก็ไม่ค่อยสมเหตุสมผลนัก ดังนั้นกรณีนั้นการประหยัดพลังงานก็ดูเหมาะสม
    • ตอนใช้ FiiO K3 DAC กับ MacBook เรื่องนี้กวนใจไม่รู้จบจริง ๆ เสียงระบบอย่างเสียงแจ้งเตือนแทบไม่ดังออกมาเลยเพราะมีดีเลย์
      ในไดรเวอร์ของ Windows มีตัวเลือกให้ตั้งสตรีมเป็น Always On ได้ อยากให้มีบน macOS เหมือนกัน
    • ผมเคยทำแบบเดียวกันกับ USB DAC มาก่อน เพียงแต่ให้ play -qn & รันขึ้นมาตอนล็อกอินเท่านั้นเอง
  • เหมือนสิ่งนี้จะอธิบายปัญหาบน Android Firefox ที่บางครั้งมือถือผมใช้ ข้อมูล 10GB ต่อวัน แบบสุ่ม ๆ ได้ ค่าบริการมือถือออกมาหนักมาก
    ดูเหมือนว่าเว็บข่าวเปิดเสียงไว้พร้อมกับโหลดโฆษณาใหม่ซ้ำ ๆ และเพราะมีเสียง แท็บจึงไม่เข้าสู่โหมดประหยัดพลังงาน สุดท้ายผมโดนค่าเน็ตเกินแบบไม่คาดคิดอยู่เรื่อย ๆ จนต้องย้ายไปใช้ Chrome
  • ผมก็เคยเห็นอาการแบบนี้หรือคล้ายกันมากบน macOS มาก่อน แต่ไม่แน่ใจว่าเป็นเพราะเว็บเปิด audio context ค้างไว้จริง ๆ หรือเป็นปัญหาภายใน Firefox เอง เพราะมันเกิดกับเว็บอย่าง Youtube ที่ไม่ได้ใช้ Web Audio API ด้วย
    พูดอีกอย่างคือไม่มี white noise แต่มี การใช้พลังงานจากระบบเสียง: https://bugzilla.mozilla.org/show_bug.cgi?id=1821102
    ตอนนี้บน Mac ของผม coreaudiod ก็ยังกิน CPU 20% ทั้งที่ไม่ได้เล่นอะไรเลย มันทำลายอายุแบตเตอรี่จริง ๆ จนผมคิดจะย้ายไปใช้เบราว์เซอร์อื่นชั่วคราวจนกว่าจะมีการแก้ไข แต่ก็ไม่อยากเลิกใช้ Firefox เพราะเรื่องที่ดูเหมือนเล็กน้อยแบบนี้
    อัปเดต: ดูเหมือนจะเกี่ยวข้องกันแต่เป็นบั๊กคนละตัว
  • โค้ดใน Chromium ที่จัดการ การพัก นี้อยู่ตรงนี้:
    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 ผมไม่ได้ยินอะไรเลย
    • ฝั่งผมก็ไม่ได้ยินเสียงเหมือนกัน แต่ถ้ากดปุ่มเล่นเสียงในหน้าเดโมของผู้เขียน การใช้พลังงาน จะเพิ่มขึ้นราว 1W
    • บน Android Firefox ได้ยิน white noise เบา ๆ
  • สิ่งนี้แก้ปัญหาหน้าแรกของ https://www.dr.dk/ ได้แล้ว