ก่อนเริ่มสตรีมแบบลอจิคัล แอปควรขอโฟกัสเสียงโดยใช้แอตทริบิวต์เสียงเดียวกับที่ใช้สำหรับสตรีมแบบลอจิคัล แม้ว่าเราจะแนะนำให้ส่งคำขอโฟกัสดังกล่าว แต่ระบบก็ไม่ได้บังคับ แอปบางแอปอาจข้ามการส่งคำขออย่างชัดเจนเพื่อให้ได้ลักษณะการทำงานที่เฉพาะเจาะจง (เช่น เพื่อเล่นเสียงในระหว่างการโทร)
ด้วยเหตุนี้ คุณจึงควรพิจารณาโฟกัสเป็นวิธีควบคุมและแก้ไขการเล่นที่ขัดแย้งกันโดยอ้อม ไม่ใช่เป็นกลไกการควบคุมเสียงหลัก เนื่องจากยานพาหนะไม่ควรขึ้นอยู่กับระบบโฟกัสสำหรับการทำงานของระบบย่อยเสียง
การโต้ตอบกับโฟกัส
ระบบจะจัดการคำขอโฟกัสเสียงตามการโต้ตอบที่กําหนดไว้ล่วงหน้าระหว่าง CarAudioContext
ของคําขอกับ CarAudioContext
ของผู้ที่มีโฟกัสอยู่ในปัจจุบัน เพื่อรองรับความต้องการของ AAOS การโต้ตอบมี 3 ประเภท ได้แก่ ยกเว้น ปฏิเสธ และพร้อมกัน
การโต้ตอบแบบพิเศษ
ในการโต้ตอบแบบพิเศษ ระบบจะอนุญาตให้แอปพลิเคชันหนึ่งๆ ยึดโฟกัสได้ครั้งละ 1 แอปเท่านั้น
ดังนั้น คำขอโฟกัสที่เข้ามาจะได้รับโฟกัส ส่วนโฟกัสของผู้ที่มีโฟกัสอยู่แล้วจะหายไป ตัวอย่างเช่น เมื่อผู้ใช้เริ่มแอปพลิเคชันเพลงใหม่ขณะที่เพลงเล่นอยู่ในแอปพลิเคชันที่มีอยู่ เนื่องจากทั้ง 2 แอปเล่นสื่ออยู่ ระบบจึงอนุญาตให้แอปพลิเคชันใดแอปพลิเคชันหนึ่งโฟกัสได้ครั้งละ 1 แอปเท่านั้น ด้วยเหตุนี้ คำขอโฟกัสของแอปพลิเคชันที่เพิ่งเริ่มต้นจึงแสดงผลเป็น AUDIOFOCUS_REQUEST_GRANTED
และแอปพลิเคชันที่เล่นเพลงอยู่จะได้รับเหตุการณ์การเปลี่ยนแปลงโฟกัสที่มีสถานะ "สูญเสีย" ซึ่งสอดคล้องกับประเภทคำขอที่ส่ง รูปแบบการโต้ตอบนี้พบได้บ่อยที่สุดกับ Android
ปฏิเสธการโต้ตอบ
เมื่อใช้การปฏิเสธการโต้ตอบ ระบบจะปฏิเสธคําขอขาเข้าเสมอ การพยายามเล่นเพลงขณะโทรอยู่เป็นตัวอย่างของการโต้ตอบที่ถูกปฏิเสธ ในกรณีนี้ หากเครื่องมือโทรกำลังโฟกัสเสียงสำหรับการโทรอยู่และแอปพลิเคชันที่สองขอโฟกัสเพื่อเล่นเพลง แอปพลิเคชันเพลงจะได้รับ AUDIOFOCUS_REQUEST_FAILED
เพื่อตอบสนองต่อคำขอ เนื่องจากคำขอโฟกัสถูกปฏิเสธ ระบบจะไม่ส่งการสูญเสียโฟกัสประเภทใดๆ ไปยังผู้ถือโฟกัสปัจจุบัน
การโต้ตอบพร้อมกัน
สิ่งสำคัญที่สุดที่ AAOS มีคือการทำงานพร้อมกัน ซึ่งจะช่วยให้แอปพลิเคชันที่ขอโฟกัสเสียงในรถสามารถโฟกัสได้พร้อมกันกับแอปพลิเคชันอื่นๆ เงื่อนไขต่อไปนี้ต้องได้รับการปฏิบัติตามเพื่อให้เกิดการโต้ตอบพร้อมกัน ข้อมูลต่อไปนี้
- คำขอโฟกัสขาเข้าต้องขอ
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
- ตัวยึดโฟกัสปัจจุบันไม่
setPauseWhenDucked(true)
- ผู้ถือโฟกัสปัจจุบันไม่ได้เลือกรับเหตุการณ์ Duck
หากเป็นไปตามเกณฑ์เหล่านี้ คำขอโฟกัสจะแสดงผลพร้อม AUDIOFOCUS_REQUEST_GRANTED
ขณะที่โฟกัสของโฮลเดอร์โฟกัสปัจจุบันจะไม่มีการเปลี่ยนแปลง อย่างไรก็ตาม หากโฟกัสที่ใช้งานอยู่เลือกรับเหตุการณ์การซ่อนหรือหยุดชั่วคราวเมื่อมีการซ่อน โฟกัสที่ใช้งานอยู่จะเสียโฟกัสเช่นเดียวกับการโต้ตอบแบบผูกขาด
การจัดการสตรีมพร้อมกัน
แม้ว่าการโต้ตอบพร้อมกันจะมีแอปพลิเคชันมีประโยชน์มากมาย แต่ OEM จะต้องจัดการการผสมและการตัดเสียงที่ระดับฮาร์ดแวร์ในอุปกรณ์เอาต์พุตต่างๆ ด้วยเหตุนี้ เราจึงขอแนะนำอย่างยิ่งให้กําหนดเส้นทาง CarAudioContext
ไปยังอุปกรณ์เอาต์พุตเดียวกับ CarAudioContext
ที่เล่นพร้อมกันไม่ได้เท่านั้น การมีอุปกรณ์เอาต์พุตแยกต่างหากสำหรับสตรีมพร้อมกันจะช่วยให้ HAL สามารถลดระดับเสียงสตรีมใดสตรีมหนึ่งก่อนที่จะผสมเข้าด้วยกัน หรือกำหนดเส้นทางสตรีมจริงไปยังลำโพงต่างๆ ในยานพาหนะ หากสตรีมเชิงตรรกะผสมกันใน Android ระบบจะไม่เปลี่ยนแปลงอัตราขยายและส่งสตรีมเป็นส่วนหนึ่งของสตรีมจริงเดียวกัน
ตัวอย่างเช่น เมื่อนำทางและสื่อไปพร้อมกัน ระบบอาจลดระดับสัญญาณของสตรีมสื่อชั่วคราว (ลดเสียง) เพื่อให้ได้ยินคำแนะนำในการไปยังส่วนต่างๆ อย่างชัดเจนยิ่งขึ้น หรือจะส่งสตรีมการนำทางไปยังลำโพงด้านคนขับขณะที่สื่อเล่นต่อไปในห้องโดยสารส่วนที่เหลือก็ได้
เมทริกซ์การโต้ตอบ
ตารางด้านล่างแสดงเมทริกซ์การโต้ตอบตามที่ CarAudioService
กำหนด
แถวแสดง CarAudioContext
ของผู้ถือโฟกัสปัจจุบันและคอลัมน์แสดง CarAudioContext
ของคําขอขาเข้า
มาดูตัวอย่างกัน เมื่อแอปสื่อเพลงมีโฟกัสอยู่และแอปการนําทางขอโฟกัส ตารางแสดงว่าการโต้ตอบ 2 รายการสามารถเล่นพร้อมกันได้ โดยสมมติว่าเป็นไปตามเกณฑ์อื่นๆ สําหรับการโต้ตอบพร้อมกัน
เนื่องจากการโต้ตอบเกิดขึ้นพร้อมกัน จึงอาจมีโฟกัสโฮลเดอร์มากกว่า 1 ราย ในกรณีนี้ ระบบจะเปรียบเทียบคำขอโฟกัสขาเข้ากับผู้ถือโฟกัสปัจจุบันแต่ละรายก่อนตัดสินใจว่าจะใช้การโต้ตอบประเภทใด ในกรณีนี้ การโต้ตอบแบบอนุรักษ์นิยมที่สุดจะเป็นผู้ชนะ (ปฏิเสธ ตามด้วยเฉพาะเจาะจง และสุดท้ายคือพร้อมกัน)
ในตารางต่อไปนี้ มีการระบุการโต้ตอบโฟกัสระหว่าง CarAudioContext สําหรับคําขอโฟกัสขาเข้า (คอลัมน์) กับบริบทของผู้ถือโฟกัสที่มีอยู่ (แถว) แต่ละเซลล์แสดงประเภทการโต้ตอบที่คาดไว้สําหรับบริบท 2 รายการ
รูปที่ 1 การโต้ตอบกับโฟกัสเสียง
การนําทางระหว่างการโทร
ใน Android 11 มีการเปิดตัวการตั้งค่าผู้ใช้ใหม่เพื่อให้ผู้ใช้เปลี่ยนแปลงลักษณะการโต้ตอบระหว่างการไปยังส่วนต่างๆ และการโทรได้ เมื่อตั้งค่าแล้ว android.car.KEY_AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL
จะเปลี่ยนการโต้ตอบระหว่างคำขอโฟกัส NAVIGATION
ขาเข้ากับผู้ถือโฟกัส CALL
ปัจจุบันจากพร้อมกันเป็นปฏิเสธ
ดังนั้นหากผู้ใช้ไม่ต้องการให้คําแนะนําการนําทางขัดจังหวะการโทร ผู้ใช้ก็สามารถเปิดใช้การตั้งค่านี้ได้ ค่านี้จะคงอยู่สำหรับผู้ใช้และสามารถตั้งค่าแบบไดนามิกได้เพื่อให้คำขอโฟกัสที่ตามมาใช้ค่าการตั้งค่าใหม่
โฟกัสเสียงที่เลื่อนเวลาได้
ใน Android 11 AAOS ได้เพิ่มการรองรับการขอโฟกัสเสียงที่เลื่อนเวลาได้ ซึ่งจะช่วยให้คำขอโฟกัสแบบถาวรล่าช้าได้เมื่อการโต้ตอบกับโฟกัสที่ถือครองอยู่ในปัจจุบันตามปกติแล้วจะทำให้คำขอถูกปฏิเสธ เมื่อการเปลี่ยนแปลงโฟกัสส่งผลให้มีสถานะที่คำขอที่เลื่อนเวลาไว้ได้รับโฟกัส คำขอดังกล่าวจะได้รับอนุมัติ
กฎสำหรับคำขอโฟกัสเสียงที่ล่าช้า
- คำขอแบบถาวรเท่านั้น - ดังที่ได้กล่าวไว้ก่อนหน้านี้ คำขอที่เลื่อนเวลาไว้จะใช้ได้กับแหล่งที่มาแบบถาวรเท่านั้น วิธีนี้ช่วยหลีกเลี่ยงไม่ให้เสียงชั่วคราวเล่นนานหลังจากที่ไม่เกี่ยวข้องแล้ว
- คุณเลื่อนเวลาคำขอได้เพียงครั้งละ 1 รายการ - หากมีคำขอที่เลื่อนเวลาได้เกิดขึ้นขณะที่มีคำขอที่เลื่อนเวลาอยู่แล้ว คำขอที่เลื่อนเวลาไว้ก่อนหน้านี้จะได้รับเหตุการณ์การเปลี่ยนแปลง
AUDIOFOCUS_LOSS
และคำขอใหม่จะได้รับการตอบกลับแบบซิงค์ของAUDIOFOCUS_REQUEST_DELAYED
- คำขอที่เลื่อนเวลาได้ต้องมี
OnAudioFocusChangeListener
เมื่อคำขอถูกเลื่อนออกไป จะใช้ Listener เพื่อแจ้งให้ผู้ขอทราบเมื่อคำขอได้รับอนุมัติในที่สุด (AUDIOFOCUS_GAIN
) หรือหากถูกปฏิเสธในภายหลัง (AUDIOFOCUS_LOSS
)
ขอโฟกัสที่เลื่อนเวลาได้
หากต้องการสร้างคำขอที่เลื่อนเวลาได้ ให้ใช้ตัวเลือกต่อไปนี้
AudioFocusRequest.Builder#setAcceptsDelayedFocusGain
mMediaWithDelayedFocusListener = new MediaWithDelayedFocusListener(); mDelayedFocusRequest = new AudioFocusRequest .Builder(AudioManager.AUDIOFOCUS_GAIN) .setAudioAttributes(mMusicAudioAttrib) .setOnAudioFocusChangeListener(mMediaWithDelayedFocusListener) .setForceDucking(false) .setWillPauseWhenDucked(false) .setAcceptsDelayedFocusGain(true) .build();
จากนั้นเมื่อส่งคำขอ ให้จัดการกับคําตอบ AUDIOFOCUS_REQUEST_DELAYED
ดังนี้
int delayedFocusRequestResults = mAudioManager.requestAudioFocus(mDelayedFocusRequest); if (delayedFocusRequestResults == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { // start audio playback return; } if (delayedFocusRequestResults == AudioManager.AUDIOFOCUS_REQUEST_DELAYED) { // audio playback delayed to audio focus listener return; }
เมื่อคำขอล่าช้า ผู้ฟังโฟกัสมีหน้าที่รับผิดชอบในการจัดการการเปลี่ยนแปลงโฟกัส ดังนี้
private final class MediaWithDelayedFocusListener implements OnAudioFocusChangeListener { @Override public void onAudioFocusChange(int focusChange) { synchronized (mLock) { switch (focusChange) { case AudioManager.AUDIOFOCUS_GAIN: … // Start focus playback case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: … // Pause media transiently case AudioManager.AUDIOFOCUS_LOSS: … // Stop media
การจัดการโฟกัสแบบหลายโซน
สำหรับยานพาหนะที่มีหลายโซนเสียง ระบบจะจัดการโฟกัสเสียงสำหรับแต่ละโซนแยกกัน ดังนั้น คำขอไปยังโซนหนึ่งจะไม่คำนึงถึงสิ่งที่โฟกัสอยู่ในโซนอื่น และไม่ทำให้โฟกัสในโซนอื่นเสียโฟกัส ฟีเจอร์นี้ช่วยให้คุณจัดการโฟกัสของห้องโดยสารหลักแยกจากระบบความบันเทิงสำหรับเบาะหลังได้ จึงหลีกเลี่ยงการหยุดเล่นเสียงในโซนหนึ่งเนื่องจากการเปลี่ยนแปลงโฟกัสในอีกโซนหนึ่ง
สำหรับแอปพลิเคชันทั้งหมด CarAudioService
จะจัดการโฟกัสโดยอัตโนมัติ ระบบจะกำหนดโซนเสียงของคำขอโฟกัสตาม UserId
หรือ UID
ที่เชื่อมโยง โปรดดูรายละเอียดที่หัวข้อการกำหนดเส้นทางเสียง
การขอเสียงจากหลายโซนพร้อมกัน
หากแอปต้องการเล่นเสียงในหลายโซนพร้อมกัน จะต้องขอโฟกัสสำหรับแต่ละโซนโดยใส่ AUDIOFOCUS_EXTRA_REQUEST_ZONE_ID
ไว้ในแพ็กเกจ
// Create attribute with bundle and AUDIOFOCUS_EXTRA_REQUEST_ZONE_ID Bundle bundle = new Bundle(); bundle.putInt(CarAudioManager.AUDIOFOCUS_EXTRA_REQUEST_ZONE_ID, zoneId); AudioAttributes attributesWithZone = new AudioAttributes.Builder() .setUsage(AudioAttributes.USAGE_MEDIA) .addBundle(bundle) .build(); // Create focus request using built attributesWithZone
พารามิเตอร์กลุ่มนี้ช่วยให้ผู้ขอลบล้างการแมปโซนเสียงอัตโนมัติเพื่อใช้รหัสโซนที่ระบุแทน ดังนั้น แอปจึงสามารถส่งคำขอแยกต่างหากสำหรับโซนเสียงแต่ละโซนได้
โฟกัสเสียง HAL
ตั้งแต่ Android 11 เป็นต้นไป HAL จะเปิดใช้เพื่อขอโฟกัสในนามของสตรีมภายนอก แม้ว่าจะเป็น API ที่ไม่บังคับ แต่เราขอแนะนำให้ใช้ API เหล่านี้เพื่อให้เสียงภายนอกมีส่วนร่วมในระบบนิเวศ Android ได้ดียิ่งขึ้นและมอบประสบการณ์การใช้งานที่ราบรื่นยิ่งขึ้นแก่ผู้ใช้
โปรดทราบว่า HAL ยังคงต้องรับผิดชอบในการตัดสินใจขั้นสุดท้ายว่าเสียงใดควรมีลําดับความสําคัญมากกว่า ด้วยเหตุนี้ ระบบจึงควรเล่นเสียงฉุกเฉินและเสียงที่สำคัญต่อความปลอดภัย ไม่ว่า HAL จะได้รับโฟกัสเสียงหรือไม่ก็ตาม และควรเล่นเสียงต่อไปตามความเหมาะสมแม้ว่า HAL จะเสียโฟกัสเสียงก็ตาม เสียงใดๆ ก็ตามที่จําเป็นตามกฎระเบียบก็เช่นเดียวกัน
ในทำนองเดียวกัน HAL ควรปิดเสียงสตรีม Android อย่างสม่ำเสมอตามความเหมาะสมเมื่อเล่นเสียงฉุกเฉินหรือเสียงที่สำคัญต่อความปลอดภัยเพื่อให้ได้ยินเสียงดังกล่าวอย่างชัดเจน
AudioControl@2.0
AudioControl HAL เวอร์ชัน 2.0 เปิดตัว API ใหม่หลายรายการ ดังนี้
API | วัตถุประสงค์ |
---|---|
IAudioControl#registerFocusListener |
ลงทะเบียนอินสแตนซ์ของ IFocusListener กับ HAL ของ AudioControl
โปรแกรมรับฟังนี้ช่วยให้ HAL สามารถขอและยกเลิกโฟกัสเสียงได้ โดย HAl ควรจะระบุอินสแตนซ์ ICloseHandle เพื่อให้ Android ใช้ยกเลิกการลงทะเบียนตัวรับฟัง
|
IAudioControl#onAudioFocusChange |
แจ้ง HAL เกี่ยวกับการเปลี่ยนแปลงสถานะเพื่อโฟกัสคำขอที่ HAL ส่งผ่านIFocusListener ซึ่งรวมถึงการตอบกลับคำขอโฟกัสครั้งแรก
|
IFocusListener#requestAudioFocus |
ส่งคําขอโฟกัสในนามของ HAL สําหรับการใช้งาน รหัสโซน และประเภทการเพิ่มความคมชัดที่ระบุ |
IFocusListener#abandonAudioFocus |
ยกเลิกคำขอโฟกัส HAL ที่มีอยู่สำหรับการใช้งานและรหัสโซนที่ระบุ |
HAL อาจมีคำขอโฟกัสหลายรายการพร้อมกัน แต่จำกัดไว้ที่ 1 คำขอต่อการใช้งานและการจับคู่รหัสโซน โปรดทราบว่า Android จะถือว่า HAL เริ่มเล่นเสียงสำหรับการใช้งานทันทีเมื่อมีคำขอ และเล่นต่อไปจนกว่าจะยกเลิกโฟกัส
นอกเหนือจาก registerFocusListener
แล้ว คำขอเหล่านี้ทั้งหมดจะเป็น oneway
เพื่อให้ Android ไม่เลื่อนเวลา HAL ขณะประมวลผลคำขอโฟกัส HALไม่ควรรอรับโฟกัสก่อนเล่นเสียงที่สำคัญต่อความปลอดภัย HAL จะฟังและตอบสนองต่อการเปลี่ยนแปลงโฟกัสเสียงผ่าน IAudioControl#onAudioFocusChange
หรือไม่ก็ได้ แต่เราขอแนะนำให้ทำเมื่อเหมาะสม