อินพุตเสียงมักจะมาจากไมโครโฟนในตัว ไมค์ภายนอก หรือ อินเทอร์เฟซเสียงที่เชื่อมต่อกับอุปกรณ์ อินพุตเสียงยังอาจมาจาก การสนทนาทางโทรศัพท์
บางครั้ง แอปตั้งแต่ 2 แอปขึ้นไปอาจต้องการ "จับภาพ" อินพุตเสียงเดียวกัน โดยพวกเขาอาจทำงานที่ต่างกัน เช่น แอปบางแอปที่รับเสียงอาจ "กำลังบันทึกเสียง" เหมือนโปรแกรมอัดเสียงธรรมดา ในขณะที่แอปอื่นๆ อาจ "กำลังฟัง" เช่น Google Assistant หรือบริการการช่วยเหลือพิเศษที่ ตอบสนองต่อคำสั่งเสียง
แต่ไม่ว่าในกรณีใด แอปเหล่านี้จะต้องการรับอินพุตเสียง ตลอดทั้งหน้านี้ เราจะใช้คำว่า "capture" โดยไม่คำนึงว่า แอปกำลังบันทึกเสียงหรือเพียงแค่ฟัง
อาจเกิดปัญหาหากมีแอปตั้งแต่ 2 แอปขึ้นไปเพื่อบันทึกเสียงพร้อมกัน ส่งสัญญาณเสียงจาก แหล่งเดียวกัน ให้กับทุกอุปกรณ์ หน้านี้อธิบายถึง วิธีที่ระบบ Android แชร์อินพุตเสียงระหว่างแอปต่างๆ ที่บันทึกเสียง
ลักษณะการทำงานก่อน Android 10
ก่อน Android 10 สตรีมเสียงอินพุตสามารถบันทึกได้โดยแอปเพียง 1 แอปที่
หากมีบางแอปบันทึกหรือฟังเสียงอยู่แล้ว แอปอาจ
สร้างออบเจ็กต์ AudioRecord
แต่ระบบจะแสดงข้อผิดพลาดเมื่อคุณเรียกใช้
AudioRecord.startRecording()
และการบันทึกจะไม่เริ่มขึ้น
กฎนี้มีข้อยกเว้นอย่างหนึ่งคือ เมื่อแอปที่ได้รับสิทธิ์ (เช่น Google Assistant หรือ
บริการการเข้าถึง) ได้รับสิทธิ์
android.permission.CAPTURE_AUDIO_HOTWORD
และใช้แหล่งที่มาของเสียงในประเภท
HOTWORD
ในกรณีนี้ แอปอื่นอาจเริ่มบันทึก เมื่อเกิดเหตุการณ์ดังกล่าวขึ้น
แอปที่เป็นสิทธิ์เฉพาะบุคคลสิ้นสุดลง และแอปใหม่ได้เก็บบันทึกอินพุตแล้ว
มีการเพิ่มการเปลี่ยนแปลงอีก 1 รายการใน Android 9: เฉพาะแอปที่ทํางานในเบื้องหน้า (หรือ บริการที่ทำงานอยู่เบื้องหน้า) สามารถจับอินพุตเสียงได้ เมื่อแอปที่ไม่มี บริการที่ทำงานอยู่เบื้องหน้าหรือคอมโพเนนต์ UI ที่ทำงานอยู่เบื้องหน้าเริ่มจับภาพแล้ว, แอป ยังคงทำงานต่อไปแต่ยังคงไม่มีเสียงใดๆ แม้ว่าจะเป็นเพียงแอปเดียวที่จับภาพ เสียงในช่วงเวลานั้น
ลักษณะการทำงานของ Android 10
ลักษณะการทำงานที่เกิดขึ้นก่อน Android 10 คือ "มาก่อนได้ก่อน" เมื่อแอปเริ่มบันทึกเสียง แอปอื่นๆ จะไม่สามารถเข้าถึงแอป อินพุตเสียงจนกว่าแอปที่กำลังบันทึกเสียงอยู่จะหยุดทำงาน
Android 10 กำหนดรูปแบบลำดับความสำคัญที่เปลี่ยนสตรีมเสียงอินพุตได้ ระหว่างแอปขณะทำงานอยู่ได้ ในกรณีส่วนใหญ่ หากแอปใหม่ได้อินพุตเสียงมา แอปการจับภาพก่อนหน้านี้จะยังคงทำงานต่อไป แต่จะได้รับการปิดเสียง ในบางส่วน เพื่อให้ระบบสามารถนำส่งเสียงไปยังทั้ง 2 แอปได้ต่อไป ฟีเจอร์ต่างๆ สถานการณ์ในการแชร์ได้อธิบายไว้ด้านล่างนี้
รูปแบบนี้คล้ายกับวิธีที่การโฟกัสเสียงจัดการแอปหลายรายการ แข่งขันกันเพื่อใช้เอาต์พุตเสียง อย่างไรก็ตาม การโฟกัสเสียงได้รับการจัดการโดย คำขอแบบเป็นโปรแกรมที่จะได้รับและปล่อยโฟกัส ขณะที่การเปลี่ยนอินพุต ที่อธิบายไว้ ณ ที่นี้เป็นไปตามนโยบายการจัดลำดับความสำคัญที่บังคับใช้ โดยอัตโนมัติเมื่อใดก็ตามที่แอปใหม่เริ่มบันทึกเสียง
สำหรับวัตถุประสงค์ในการจับเสียง Android จะจำแนกแอป 2 ประเภทต่อไปนี้
- "ปกติ" ที่ผู้ใช้ติดตั้ง
- "เป็นสิทธิ์เฉพาะบุคคล" มีการติดตั้งแอปไว้ล่วงหน้าแล้วในอุปกรณ์ ซึ่งรวมถึง Google Assistant และบริการการช่วยเหลือพิเศษทั้งหมด
นอกจากนี้ ระบบยังดำเนินการกับแอปแตกต่างออกไป
หากวิดีโอนั้นใช้เนื้อหาที่ "คำนึงถึงความเป็นส่วนตัว" แหล่งที่มาของเสียง:
CAMCORDER
หรือ VOICE_COMMUNICATION
กฎการจัดลำดับความสำคัญในการใช้และแชร์อินพุตเสียงมีดังนี้
- แอปที่ได้รับสิทธิ์มีลำดับความสำคัญสูงกว่าแอปทั่วไป
- แอปที่มี UI ในเบื้องหน้าที่มองเห็นได้จะมีความสำคัญสูงกว่าแอปเบื้องหลัง
- แอปที่บันทึกเสียงจากแหล่งที่มาที่มีความละเอียดอ่อนด้านความเป็นส่วนตัวจะมีลำดับความสำคัญสูงกว่าแอปที่ไม่มี
- แอปทั่วไป 2 แอปบันทึกเสียงพร้อมกันไม่ได้
- ในบางสถานการณ์ แอปที่ได้รับสิทธิ์สามารถแชร์อินพุตเสียงกับแอปอื่นได้
- หากแอปพื้นหลัง 2 แอปที่มีลำดับความสำคัญเท่ากันกำลังบันทึกเสียง แอปสุดท้ายที่เริ่มใช้งานจะมีลำดับความสำคัญสูงกว่า
สถานการณ์การแชร์
เมื่อแอป 2 แอปพยายามบันทึกเสียง ทั้งคู่สามารถรับสัญญาณอินพุตได้ หรือหนึ่งในนั้นอาจได้รับสัญญาณอินพุต เงียบๆ
สถานการณ์หลักๆ มี 4 กรณีดังนี้
- Assistant + แอปทั่วไป
- บริการการช่วยเหลือพิเศษ + แอปทั่วไป
- แอปทั่วไป 2 แอป
- การโทรด้วยเสียง + แอปทั่วไป
Assistant + แอปทั่วไป
Assistant เป็นแอปที่ได้รับสิทธิ์เพราะมีการติดตั้งไว้ล่วงหน้าและเก็บเอาไว้
RoleManager.ROLE_ASSISTANT
แอปอื่นๆ ที่ติดตั้งไว้ล่วงหน้าที่มีบทบาทนี้จะได้รับการดำเนินการในลักษณะเดียวกัน
Android จะใช้อินพุตเสียงตามกฎต่อไปนี้
Assistant รับเสียงได้ (ไม่ว่าจะอยู่เบื้องหน้าหรือเบื้องหลัง) เว้นแต่ว่าแอปอื่นที่ใช้แหล่งที่มาของเสียงที่ละเอียดอ่อนด้านความเป็นส่วนตัวกำลังบันทึกอยู่
แอปจะได้รับเสียง เว้นแต่ Assistant จะมี UI ที่มองเห็นได้ ที่ด้านบนของหน้าจอ
โปรดทราบว่าทั้ง 2 แอปจะได้รับเสียงเฉพาะเมื่อ Assistant อยู่ในเบื้องหลัง และอีกแอปไม่ได้บันทึกจากแหล่งเสียงที่มีความละเอียดอ่อนต่อความเป็นส่วนตัว
บริการการช่วยเหลือพิเศษ + แอปทั่วไป
AccessibilityService
ต้องมีการประกาศที่เข้มงวด
Android จะแชร์เสียงอินพุตตามกฎต่อไปนี้
หาก UI ของบริการอยู่ด้านบน ทั้งบริการและแอปจะได้รับ อินพุตเสียง ลักษณะการทำงานนี้จะมีฟังก์ชันการทำงานอย่างเช่นการควบคุมการโทรด้วยเสียงหรือวิดีโอคอล บันทึกด้วยคำสั่งเสียง
หากบริการไม่ได้อยู่ด้านบนสุด ระบบจะถือว่ากรณีนี้เป็นกรณีปกติของ 2 แอปด้านล่าง
แอปทั่วไป 2 แอป
เมื่อแอป 2 แอปกำลังจับภาพพร้อมกัน จะมีเพียงแอปเดียวที่ได้รับเสียงและอีกแอปหนึ่งปิดเสียง
Android จะแชร์เสียงอินพุตตามกฎต่อไปนี้
- หากไม่มีแอปใดที่คำนึงถึงความเป็นส่วนตัว แอปที่มี UI ที่ด้านบนจะรับเสียงได้ หากแอปใดไม่มี UI แอปที่เริ่มจับแอปล่าสุดจะได้รับเสียง
- หากแอปใดแอปหนึ่งมีความละเอียดอ่อนด้านความเป็นส่วนตัว แอปจะรับเสียงและ แอปอื่นๆ จะปิดเสียงแม้ว่าจะมี UI อยู่ด้านบนหรือเริ่มจับภาพแล้วก็ตาม ล่าสุด
- หากทั้ง 2 แอปคำนึงถึงความเป็นส่วนตัว แอปที่ทำให้เกิด Conversion มากที่สุด ได้รับเสียงเมื่อเร็วๆ นี้และอีกรายการหนึ่งไม่มีเสียง
การโทรด้วยเสียง + แอปทั่วไป
การโทรด้วยเสียงจะทำงานเมื่อโหมดเสียงแสดงผลโดย
AudioManager.getMode()
คือ
MODE_IN_CALL
หรือ
MODE_IN_COMMUNICATION
Android จะแชร์เสียงอินพุตตามกฎต่อไปนี้
- การโทรจะได้รับเสียงเสมอ
- แอปจะบันทึกเสียงได้หากเป็น บริการการช่วยเหลือพิเศษ
แอปสามารถบันทึกสายโทรเข้าได้หากเป็นสิทธิ์เฉพาะบุคคล แอป (ติดตั้งล่วงหน้า) ที่มีสิทธิ์
CAPTURE_AUDIO_OUTPUT
หากต้องการจับอัปลิงก์ (TX), ลิงก์ขาลง (RX) หรือทั้ง 2 แบบ แอปจะต้อง ระบุแหล่งที่มาของเสียง
MediaRecorder.AudioSource.VOICE_UPLINK
หรือMediaRecorder.AudioSource.VOICE_DOWNLINK
และ/หรืออุปกรณ์AudioDeviceInfo.TYPE_TELEPHONY
ลักษณะการทำงานของ Android 11
Android 11 (API ระดับ 30) ดำเนินการตามรูปแบบลำดับความสำคัญของ Android 10
ที่อธิบายไว้ข้างต้น นอกจากนี้ยังมีเมธอดใหม่ๆ ใน AudioRecord
, MediaRecorder
และ
AAudioStream
ที่เปิดและปิดความสามารถในการบันทึกเสียงพร้อมกัน
โดยไม่คำนึงถึง Use Case ที่เลือก
วิธีการใหม่มีดังนี้
AudioRecord.Builder.setPrivacySensitive()
AudioRecord.isPrivacySensitive()
MediaRecorder.setPrivacySensitive()
MediaRecorder.isPrivacySensitive()
AAudioStreamBuilder_setPrivacySensitive()
AAudioStream_isPrivacySensitive()
เมื่อ setPrivacySensitive()
คือ true
กรณีการใช้งานการจับภาพจะเป็นแบบส่วนตัวและ
Assistant ที่ได้รับสิทธิ์จะไม่สามารถจับภาพพร้อมกัน การตั้งค่านี้จะลบล้าง
การทำงานเริ่มต้นโดยขึ้นอยู่กับแหล่งที่มาของเสียง ตัวอย่างเช่น
VOICE_COMMUNICATION
เป็นแบบส่วนตัวโดยค่าเริ่มต้น แต่ UNPROCESSED
ไม่ได้เป็นแบบส่วนตัว
การเปลี่ยนแปลงการกำหนดค่า
เมื่อหลายแอปบันทึกเสียงพร้อมกัน จะมีเพียง 1 หรือ 2 แอปเท่านั้น "ใช้งานอยู่" (การรับเสียง) ส่วนคนอื่นๆ จะถูกปิดเสียง (เปิดเสียง) เมื่อ แอปที่ใช้งานอยู่เปลี่ยนแปลง เฟรมเวิร์กเสียงอาจกำหนดค่าเส้นทางเสียงใหม่ ตามกฎเหล่านี้
- อุปกรณ์อินพุตเสียงสำหรับแต่ละแอปที่ใช้งานอยู่อาจเปลี่ยนไป (เช่น จาก ไมโครโฟนในตัวกับชุดหูฟังบลูทูธที่เชื่อมต่ออยู่)
- มีการเปิดใช้การประมวลผลล่วงหน้าที่เชื่อมโยงกับแอปที่มีลำดับความสำคัญสูงสุดที่ใช้งานอยู่ ทั้งหมด การประมวลผลล่วงหน้าอื่นๆ จะไม่มีผล
เนื่องจากแอปที่ใช้งานอยู่อาจถูกปิดเสียงเมื่อแอปที่มีลำดับความสำคัญสูงกว่าเปิดใช้งาน
คุณสามารถลงทะเบียน
AudioManager.AudioRecordingCallback
ในAudioRecord
หรือ MediaRecorder
ที่จะมีการแจ้งเตือนเมื่อการกำหนดค่ามีการเปลี่ยนแปลง
การเปลี่ยนแปลงที่เป็นไปได้มีดังนี้
- จับภาพเสียงที่ไม่ปิดเสียงหรือไม่ปิดเสียง
- เปลี่ยนอุปกรณ์แล้ว
- เปลี่ยนการประมวลผลล่วงหน้าแล้ว
- เปลี่ยนแปลงพร็อพเพอร์ตี้ของสตรีม (อัตราการสุ่มตัวอย่าง มาสก์ช่อง รูปแบบตัวอย่าง)
คุณต้องโทร
AudioRecord.registerAudioRecordingCallback()
ก่อนจะเริ่มจับภาพ
การเรียกกลับจะดำเนินการเมื่อแอปได้รับเสียงเท่านั้นและมีการเปลี่ยนแปลงเกิดขึ้น
เมธอด onRecordingConfigChanged()
จะแสดงผล AudioRecordingConfiguration
ที่มีสถานะการบันทึกเสียงปัจจุบัน ใช้รายการต่อไปนี้
เพื่อเรียนรู้เกี่ยวกับการเปลี่ยนแปลง
isClientSilenced()
- แสดงผลเป็น "จริง" หากเสียงที่ส่งกลับไปยังไคลเอ็นต์กำลังปิดเสียงอยู่เนื่องจากนโยบายการบันทึก
getAudioDevice()
- ส่งคืนอุปกรณ์เสียงที่ใช้งานอยู่
getEffects()
- แสดงผลเอฟเฟกต์การประมวลผลล่วงหน้าที่ใช้งานอยู่ โปรดทราบว่าผลกระทบที่ใช้งานอยู่อาจไม่เหมือนกับผลลัพธ์ที่
getClientEffects()
แสดงผล หากไคลเอ็นต์ไม่ใช่แอปที่มีลำดับความสำคัญสูงสุด getFormat()
- แสดงผลพร็อพเพอร์ตี้ของสตรีม โปรดทราบว่าข้อมูลเสียงจริงที่ลูกค้าได้รับจะยึดตามรูปแบบที่กำหนดซึ่งแสดงผลโดย
getClientFormat()
เสมอ เฟรมเวิร์กจะทำการแปลงตัวอย่าง ช่องทาง และการเปลี่ยนรูปแบบที่จำเป็นโดยอัตโนมัติจากรูปแบบที่ใช้ในอินเทอร์เฟซของฮาร์ดแวร์ให้อยู่ในรูปแบบที่ลูกค้าระบุ AudioRecord.getActiveRecordingConfiguration()
- แสดงผลการกำหนดค่าการบันทึกที่ใช้งานอยู่
คุณสามารถดูมุมมองทั่วไปของไฟล์บันทึกเสียงที่ใช้งานอยู่ทั้งหมดในอุปกรณ์โดยการโทร
AudioManager.getActiveRecordingConfigurations()