โดยปกติแล้ว อินพุตเสียงจะมาจากไมโครโฟนในตัว ไมโครโฟนภายนอก หรืออินเทอร์เฟซเสียงที่เชื่อมต่อกับอุปกรณ์ นอกจากนี้ อินพุตเสียงยังอาจมาจากการสนทนาทางโทรศัพท์ได้ด้วย
บางครั้งแอปตั้งแต่ 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 จะแชร์เสียงที่ป้อนตามกฎต่อไปนี้
- การโทรจะได้รับเสียงเสมอ
- แอปจะบันทึกเสียงได้หากเป็นบริการการช่วยเหลือพิเศษ
แอปจะบันทึกการโทรด้วยเสียงได้หากเป็นแอปที่มีสิทธิ์ (ติดตั้งไว้ล่วงหน้า) ซึ่งมีสิทธิ์
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 ไม่ใช่
การเปลี่ยนแปลงการกำหนดค่า
เมื่อมีแอปหลายแอปกำลังบันทึกเสียงพร้อมกัน จะมีเพียงแอปเดียวหรือ 2 แอปเท่านั้นที่ "ทำงานอยู่" (รับเสียง) ส่วนแอปอื่นๆ จะปิดเสียง (รับความเงียบ) เมื่อแอปที่ใช้งานอยู่มีการเปลี่ยนแปลง เฟรมเวิร์กเสียงอาจกำหนดค่าเส้นทางเสียงใหม่ตามกฎต่อไปนี้
- อุปกรณ์อินพุตเสียงสำหรับแต่ละแอปที่ใช้งานอยู่อาจมีการเปลี่ยนแปลง (เช่น จากไมโครโฟนในตัวเป็นชุดหูฟังบลูทูธที่เชื่อมต่ออยู่)
- ระบบจะเปิดใช้การประมวลผลล่วงหน้าที่เชื่อมโยงกับแอปที่ใช้งานอยู่ซึ่งมีลำดับความสำคัญสูงสุด ระบบจะไม่สนใจการประมวลผลล่วงหน้าอื่นๆ ทั้งหมด
เนื่องจากแอปที่ทำงานอยู่อาจถูกปิดเสียงเมื่อแอปที่มีลำดับความสำคัญสูงกว่าเริ่มทำงาน คุณจึงสามารถลงทะเบียน AudioManager.AudioRecordingCallback ในออบเจ็กต์ AudioRecord หรือ MediaRecorder เพื่อรับการแจ้งเตือนเมื่อการกำหนดค่าเปลี่ยนแปลง การเปลี่ยนแปลงที่อาจเกิดขึ้นมีดังนี้
- จับภาพแบบปิดเสียงหรือเปิดเสียง
- เปลี่ยนอุปกรณ์แล้ว
- มีการเปลี่ยนแปลงการประมวลผลล่วงหน้า
- พร็อพเพอร์ตี้ของสตรีมมีการเปลี่ยนแปลง (อัตราการสุ่มตัวอย่าง, มาสก์ช่อง, รูปแบบตัวอย่าง)
คุณต้องเรียกใช้ AudioRecord.registerAudioRecordingCallback() ก่อนเริ่มการจับภาพ ระบบจะเรียกกลับเฉพาะเมื่อแอปได้รับเสียงและมีการเปลี่ยนแปลงเกิดขึ้นเท่านั้น
เมธอด onRecordingConfigChanged() จะแสดงผล AudioRecordingConfiguration ที่มีสถานะการบันทึกเสียงปัจจุบัน
ใช้วิธีการต่อไปนี้เพื่อดูข้อมูลเกี่ยวกับการเปลี่ยนแปลง
isClientSilenced()- แสดงผลเป็น "จริง" หากเสียงที่ส่งกลับไปยังไคลเอ็นต์ถูกปิดเสียงอยู่เนื่องจากนโยบายการบันทึก
getAudioDevice()- แสดงผลอุปกรณ์เสียงที่ใช้งานอยู่
getEffects()- แสดงผลเอฟเฟกต์การประมวลผลล่วงหน้าที่ใช้งานอยู่ โปรดทราบว่าเอฟเฟกต์ที่ใช้งานอยู่อาจไม่เหมือนกับเอฟเฟกต์ที่
getClientEffects()แสดงผลหากไคลเอ็นต์ไม่ใช่แอปที่ใช้งานอยู่ซึ่งมีลำดับความสำคัญสูงสุด getFormat()- แสดงพร็อพเพอร์ตี้ของสตรีม โปรดทราบว่าข้อมูลเสียงจริงที่ไคลเอ็นต์ได้รับจะเป็นไปตามรูปแบบที่กำหนดซึ่ง
getClientFormat()แสดงผลเสมอ เฟรมเวิร์กจะทำการสุ่มตัวอย่างใหม่ การแปลงช่อง และการแปลงรูปแบบที่จำเป็นโดยอัตโนมัติจากรูปแบบที่ใช้ในอินเทอร์เฟซฮาร์ดแวร์เป็นรูปแบบที่ไคลเอ็นต์ระบุ AudioRecord.getActiveRecordingConfiguration()- แสดงผลการกำหนดค่าการบันทึกที่ใช้งานอยู่
คุณดูภาพรวมของการบันทึกที่ทำงานอยู่ทั้งหมดในอุปกรณ์ได้โดยเรียกใช้ AudioManager.getActiveRecordingConfigurations()