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