กำลังแชร์อินพุตเสียง

โดยปกติแล้ว อินพุตเสียงจะมาจากไมโครโฟนในตัว ไมโครโฟนภายนอก หรืออินเทอร์เฟซเสียงที่เชื่อมต่อกับอุปกรณ์ นอกจากนี้ อินพุตเสียงยังอาจมาจากการสนทนาทางโทรศัพท์ได้ด้วย

บางครั้งแอปตั้งแต่ 2 แอปขึ้นไปอาจต้องการ "บันทึก" อินพุตเสียงเดียวกัน โดยอาจทำงานที่แตกต่างกัน ตัวอย่างเช่น แอปบางแอปที่รับเสียงอาจกำลัง "บันทึก" เช่น โปรแกรมบันทึกเสียงธรรมดา ขณะที่แอปอื่นๆ อาจกำลัง "ฟัง" เช่น Google Assistant หรือบริการการช่วยเหลือพิเศษที่ตอบสนองต่อคำสั่งเสียง

ไม่ว่าในกรณีใดก็ตาม แอปเหล่านี้ต้องการรับอินพุตเสียง ในหน้านี้ เราจะใช้คำว่า "บันทึก" ไม่ว่าแอปจะบันทึกหรือแค่ฟังก็ตาม

หากแอปตั้งแต่ 2 แอปขึ้นไปต้องการบันทึกเสียงพร้อมกัน อาจเกิดปัญหาในการส่งสัญญาณเสียงจากแหล่งที่มาเดียวกันไปยังแอปทั้งหมด หน้านี้อธิบายวิธีที่ระบบ Android แชร์อินพุตเสียงระหว่างแอปหลายแอปที่บันทึกเสียง

ลักษณะการทำงานก่อน Android 10

ก่อน Android 10 สตรีมเสียงอินพุตจะบันทึกได้โดยแอปเดียวเท่านั้นในแต่ละครั้ง หากมีแอปบางแอปกำลังบันทึกหรือฟังเสียงอยู่แล้ว แอปของคุณจะสร้างออบเจ็กต์ AudioRecord ได้ แต่ระบบจะแสดงข้อผิดพลาดเมื่อคุณเรียกใช้ AudioRecord.startRecording() และการบันทึกจะไม่เริ่มขึ้น

ข้อยกเว้นหนึ่งของกฎนี้คือเมื่อแอปที่มีสิทธิ์ (เช่น Google Assistant หรือบริการการช่วยเหลือพิเศษ) มีสิทธิ์ android.permission.CAPTURE_AUDIO_HOTWORD และใช้แหล่งที่มาของเสียงประเภท HOTWORD ในกรณีนี้ แอปอื่นอาจเริ่มบันทึกได้ เมื่อเกิดเหตุการณ์ดังกล่าว แอปที่มีสิทธิ์จะสิ้นสุดลงและแอปใหม่จะบันทึกอินพุต

การเปลี่ยนแปลงอีกอย่างหนึ่งที่เพิ่มเข้ามาใน Android 9 คือมีเพียงแอปที่ทำงานอยู่เบื้องหน้า (หรือบริการที่ทำงานอยู่เบื้องหน้า) เท่านั้นที่สามารถบันทึกอินพุตเสียงได้ เมื่อแอปที่ไม่มีบริการที่ทำงานอยู่เบื้องหน้าหรือคอมโพเนนต์ UI ที่ทำงานอยู่เบื้องหน้าเริ่มบันทึก แอปจะยังคงทำงานต่อไปแต่จะได้รับเสียงเงียบ แม้ว่าจะเป็นแอปเดียวที่บันทึกเสียงอยู่ในขณะนั้นก็ตาม

ลักษณะการทำงานของ Android 10

ลักษณะการทำงานก่อน Android 10 คือ "มาก่อนได้ก่อน" เมื่อแอปเริ่มบันทึกเสียงแล้ว แอปอื่นๆ จะเข้าถึงอินพุตเสียงไม่ได้จนกว่าแอปที่บันทึกเสียงจะหยุดทำงาน

Android 10 กำหนดรูปแบบลำดับความสำคัญที่สามารถสลับสตรีมเสียงอินพุตระหว่างแอปต่างๆ ขณะที่แอปทำงานอยู่ ในกรณีส่วนใหญ่ หากแอปใหม่ได้รับอินพุตเสียง แอปที่บันทึกก่อนหน้านี้จะยังคงทำงานต่อไป แต่จะได้รับความเงียบ ในบางกรณี ระบบจะยังคงส่งเสียงไปยังทั้ง 2 แอปต่อไป สถานการณ์การแชร์ต่างๆ มีคำอธิบายดังนี้

รูปแบบนี้คล้ายกับวิธีที่โฟกัสเสียงจัดการกับแอปหลายแอปที่แข่งขันกันเพื่อใช้เอาต์พุตเสียง อย่างไรก็ตาม โฟกัสเสียงจะได้รับการจัดการโดยคำขอแบบเป็นโปรแกรมเพื่อรับและปล่อยโฟกัส ในขณะที่รูปแบบการสลับอินพุตที่อธิบายไว้ที่นี่จะอิงตามนโยบายการจัดลำดับความสำคัญซึ่งจะใช้โดยอัตโนมัติเมื่อใดก็ตามที่แอปใหม่เริ่มบันทึกเสียง

Android แยกแยะแอปออกเป็น 2 ประเภทเพื่อวัตถุประสงค์ในการบันทึกเสียง ดังนี้

  • แอป "ทั่วไป" คือแอปที่ผู้ใช้ติดตั้ง
  • แอป "ที่มีสิทธิ์พิเศษ" จะติดตั้งไว้ล่วงหน้าในอุปกรณ์ ซึ่งรวมถึง Google Assistant และบริการการช่วยเหลือพิเศษทั้งหมด

นอกจากนี้ ระบบจะจัดการแอปแตกต่างออกไปหากแอปใช้แหล่งที่มาของเสียงที่ "มีความละเอียดอ่อนด้านความเป็นส่วนตัว" ได้แก่ CAMCORDER หรือ VOICE_COMMUNICATION

กฎการจัดลำดับความสำคัญสำหรับการใช้และการแชร์อินพุตเสียงมีดังนี้

  • แอปที่มีสิทธิ์พิเศษจะมีลำดับความสำคัญสูงกว่าแอปทั่วไป
  • แอปที่มี UI เบื้องหน้าที่มองเห็นได้จะมีลำดับความสำคัญสูงกว่าแอปที่ทำงานอยู่เบื้องหลัง
  • แอปที่บันทึกเสียงจากแหล่งที่มาที่มีความละเอียดอ่อนด้านความเป็นส่วนตัวจะมีลำดับความสำคัญสูงกว่าแอปที่ไม่ได้บันทึกเสียงจากแหล่งที่มาดังกล่าว
  • แอปทั่วไป 2 แอปจะบันทึกเสียงพร้อมกันไม่ได้
  • ในบางสถานการณ์ แอปที่มีสิทธิ์พิเศษสามารถแชร์อินพุตเสียงกับแอปอื่นได้
  • หากแอปที่ทำงานอยู่เบื้องหลัง 2 แอปซึ่งมีลำดับความสำคัญเท่ากันกำลังบันทึกเสียง แอปที่เริ่มทำงานทีหลังจะมีลำดับความสำคัญสูงกว่า

สถานการณ์การแชร์

เมื่อแอป 2 แอปพยายามบันทึกเสียง ทั้ง 2 แอปอาจรับสัญญาณอินพุตได้ หรือแอปใดแอปหนึ่งอาจไม่ได้รับสัญญาณเสียง

โดยมี 4 สถานการณ์หลักๆ ดังนี้

  • Assistant + แอปทั่วไป
  • บริการการช่วยเหลือพิเศษ + แอปทั่วไป
  • แอปธรรมดา 2 แอป
  • การโทรด้วยเสียง + แอปทั่วไป

Assistant + แอปทั่วไป

Assistant เป็นแอปที่มีสิทธิ์พิเศษเนื่องจากมีการติดตั้งไว้ล่วงหน้าและมีบทบาท RoleManager.ROLE_ASSISTANT แอปอื่นๆ ที่ติดตั้งไว้ล่วงหน้าซึ่งมีบทบาทนี้จะได้รับการปฏิบัติในลักษณะเดียวกัน

Android จะแชร์เสียงที่ป้อนตามกฎต่อไปนี้

  • Assistant จะรับเสียงได้ (ไม่ว่าจะอยู่เบื้องหน้าหรือเบื้องหลัง) เว้นแต่ว่าแอปอื่นที่ใช้แหล่งที่มาของเสียงที่มีความละเอียดอ่อนด้านความเป็นส่วนตัวกำลังบันทึกเสียงอยู่

  • แอปจะได้รับเสียง เว้นแต่ Assistant จะมีคอมโพเนนต์ UI ที่มองเห็นได้ที่ด้านบนของหน้าจอ

โปรดทราบว่าทั้ง 2 แอปจะได้รับเสียงเฉพาะเมื่อ Assistant อยู่ในเบื้องหลังและแอปอื่นไม่ได้บันทึกจากแหล่งที่มาของเสียงที่ละเอียดอ่อนด้านความเป็นส่วนตัว

บริการการช่วยเหลือพิเศษ + แอปทั่วไป

AccessibilityService ต้องมีการประกาศที่เข้มงวด

Android จะแชร์เสียงที่ป้อนตามกฎต่อไปนี้

  • หาก UI ของบริการอยู่ด้านบน ทั้งบริการและแอปจะได้รับอินพุตเสียง ลักษณะการทำงานนี้มีฟังก์ชันต่างๆ เช่น การควบคุมการโทรด้วยเสียงหรือการจับภาพวิดีโอด้วยคำสั่งเสียง

  • หากบริการไม่ได้อยู่ด้านบน ระบบจะถือว่ากรณีนี้เหมือนกับกรณี 2 แอปทั่วไปด้านล่าง

แอปธรรมดา 2 แอป

เมื่อแอป 2 แอปบันทึกเสียงพร้อมกัน จะมีเพียงแอปเดียวที่ได้รับเสียง ส่วนอีกแอปจะไม่มีเสียง

Android จะแชร์เสียงที่ป้อนตามกฎต่อไปนี้

  • หากทั้ง 2 แอปไม่มีความละเอียดอ่อนด้านความเป็นส่วนตัว แอปที่มี UI อยู่ด้านบนจะได้รับเสียง หากไม่มีแอปใดมี UI แอปที่เริ่มบันทึกเสียงล่าสุดจะได้รับเสียง
  • หากแอปใดแอปหนึ่งมีความละเอียดอ่อนด้านความเป็นส่วนตัว แอปนั้นจะได้รับเสียงและแอปอื่นๆ จะไม่ได้รับเสียง แม้ว่าจะมี UI อยู่ด้านบนหรือเริ่มบันทึกเสียงเมื่อเร็วๆ นี้ก็ตาม
  • หากทั้ง 2 แอปมีความละเอียดอ่อนด้านความเป็นส่วนตัว แอปที่เริ่มบันทึกเสียงล่าสุดจะได้รับเสียง และอีกแอปหนึ่งจะไม่มีเสียง

การโทรด้วยเสียง + แอปทั่วไป

การโทรด้วยเสียงจะทำงานอยู่หากโหมดเสียงที่ AudioManager.getMode() แสดงผลเป็น MODE_IN_CALL หรือ MODE_IN_COMMUNICATION

Android จะแชร์เสียงที่ป้อนตามกฎต่อไปนี้

ลักษณะการทำงานของ Android 11

Android 11 (ระดับ API 30) จะใช้รูปแบบลำดับความสำคัญของ Android 10 ที่อธิบายไว้ข้างต้น นอกจากนี้ ยังมีเมธอดใหม่ใน AudioRecord, MediaRecorder และ AAudioStream ที่เปิดและปิดใช้ความสามารถในการบันทึกเสียงพร้อมกัน ไม่ว่าจะเลือก Use Case ใดก็ตาม

วิธีการใหม่มีดังนี้

เมื่อ setPrivacySensitive() เป็น true กรณีการใช้งานการบันทึกจะเป็นแบบส่วนตัว และแม้แต่ Assistant ที่มีสิทธิ์ก็ไม่สามารถบันทึกพร้อมกันได้ การตั้งค่านี้จะลบล้างลักษณะการทำงานเริ่มต้นที่ขึ้นอยู่กับแหล่งที่มาของเสียง ตัวอย่างเช่น VOICE_COMMUNICATION จะเป็นแบบส่วนตัวโดยค่าเริ่มต้น แต่ UNPROCESSED ไม่ใช่

การเปลี่ยนแปลงการกำหนดค่า

เมื่อมีแอปหลายแอปกำลังบันทึกเสียงพร้อมกัน จะมีเพียงแอปเดียวหรือ 2 แอปเท่านั้นที่ "ทำงานอยู่" (รับเสียง) ส่วนแอปอื่นๆ จะปิดเสียง (รับความเงียบ) เมื่อแอปที่ใช้งานอยู่มีการเปลี่ยนแปลง เฟรมเวิร์กเสียงอาจกำหนดค่าเส้นทางเสียงใหม่ตามกฎต่อไปนี้

  • อุปกรณ์อินพุตเสียงสำหรับแต่ละแอปที่ใช้งานอยู่อาจมีการเปลี่ยนแปลง (เช่น จากไมโครโฟนในตัวเป็นชุดหูฟังบลูทูธที่เชื่อมต่ออยู่)
  • ระบบจะเปิดใช้การประมวลผลล่วงหน้าที่เชื่อมโยงกับแอปที่ใช้งานอยู่ซึ่งมีลำดับความสำคัญสูงสุด ระบบจะไม่สนใจการประมวลผลล่วงหน้าอื่นๆ ทั้งหมด

เนื่องจากแอปที่ทำงานอยู่อาจถูกปิดเสียงเมื่อแอปที่มีลำดับความสำคัญสูงกว่าเริ่มทำงาน คุณจึงสามารถลงทะเบียน AudioManager.AudioRecordingCallback ในออบเจ็กต์ AudioRecord หรือ MediaRecorder เพื่อรับการแจ้งเตือนเมื่อการกำหนดค่าเปลี่ยนแปลง การเปลี่ยนแปลงที่อาจเกิดขึ้นมีดังนี้

  • จับภาพแบบปิดเสียงหรือเปิดเสียง
  • เปลี่ยนอุปกรณ์แล้ว
  • มีการเปลี่ยนแปลงการประมวลผลล่วงหน้า
  • พร็อพเพอร์ตี้ของสตรีมมีการเปลี่ยนแปลง (อัตราการสุ่มตัวอย่าง, มาสก์ช่อง, รูปแบบตัวอย่าง)

คุณต้องเรียกใช้ AudioRecord.registerAudioRecordingCallback() ก่อนเริ่มการจับภาพ ระบบจะเรียกกลับเฉพาะเมื่อแอปได้รับเสียงและมีการเปลี่ยนแปลงเกิดขึ้นเท่านั้น

เมธอด onRecordingConfigChanged() จะแสดงผล AudioRecordingConfiguration ที่มีสถานะการบันทึกเสียงปัจจุบัน ใช้วิธีการต่อไปนี้เพื่อดูข้อมูลเกี่ยวกับการเปลี่ยนแปลง

isClientSilenced()
แสดงผลเป็น "จริง" หากเสียงที่ส่งกลับไปยังไคลเอ็นต์ถูกปิดเสียงอยู่เนื่องจากนโยบายการบันทึก
getAudioDevice()
แสดงผลอุปกรณ์เสียงที่ใช้งานอยู่
getEffects()
แสดงผลเอฟเฟกต์การประมวลผลล่วงหน้าที่ใช้งานอยู่ โปรดทราบว่าเอฟเฟกต์ที่ใช้งานอยู่อาจไม่เหมือนกับเอฟเฟกต์ที่ getClientEffects() แสดงผลหากไคลเอ็นต์ไม่ใช่แอปที่ใช้งานอยู่ซึ่งมีลำดับความสำคัญสูงสุด
getFormat()
แสดงพร็อพเพอร์ตี้ของสตรีม โปรดทราบว่าข้อมูลเสียงจริงที่ไคลเอ็นต์ได้รับจะเป็นไปตามรูปแบบที่กำหนดซึ่ง getClientFormat() แสดงผลเสมอ เฟรมเวิร์กจะทำการสุ่มตัวอย่างใหม่ การแปลงช่อง และการแปลงรูปแบบที่จำเป็นโดยอัตโนมัติจากรูปแบบที่ใช้ในอินเทอร์เฟซฮาร์ดแวร์เป็นรูปแบบที่ไคลเอ็นต์ระบุ
AudioRecord.getActiveRecordingConfiguration()
แสดงผลการกำหนดค่าการบันทึกที่ใช้งานอยู่

คุณดูภาพรวมของการบันทึกที่ทำงานอยู่ทั้งหมดในอุปกรณ์ได้โดยเรียกใช้ AudioManager.getActiveRecordingConfigurations()