Audio Session เป็นกลไกสำคัญของ iOS สำหรับจัดการพฤติกรรมเสียงของแอปพลิเคชัน: การโต้ตอบกับระบบ การจัดการการขัดจังหวะ และการกำหนดเส้นทางเสียง แอปพลิเคชัน iOS แต่ละตัวจะได้รับเซสชันเสียงเดียวที่กำหนดว่าเสียงจะทำงานอย่างไรเมื่อหน้าจอถูกล็อก ระหว่างการโทร และเมื่อเชื่อมต่อ Bluetooth ตาม Apple Developer Documentation, 2026 Audio Session ได้รับการกำหนดค่าผ่านหมวดหมู่และโหมด — หากไม่มีการกำหนดค่าที่ถูกต้อง แอปพลิเคชันอาจไม่เล่นเสียงในพื้นหลัง
ประเด็นสำคัญ
Audio Session เป็นอินสแตนซ์ AVAudioSession เดียวที่สร้างขึ้นโดยระบบเมื่อแอปพลิเคชันเริ่มทำงานและมีอยู่ตลอดวงจรชีวิตของมัน มันทำหน้าที่เป็นตัวกลางระหว่างแอปพลิเคชันและระบบเสียงของ iOS: การกำหนดค่าหมวดหมู่จะกำหนดว่าแอปพลิเคชันได้รับอนุญาตให้เล่นเสียงในพื้นหลังหรือไม่ เสียงจะถูกปิดระหว่างการโทรหรือไม่ และอุปกรณ์ใดที่จะส่งเสียงออก
แตกต่างจาก Android Audio Focus ที่แอปพลิเคชันแต่ละตัวร้องขอและปล่อยโฟกัสอย่างอิสระ iOS Audio Session จะถูกจัดการจากส่วนกลางผ่านหนึ่งเซสชันต่อแอปพลิเคชัน เมื่อเซสชันถูกเปิดใช้งาน ระบบจะปิดการใช้งานเซสชันของแอปพลิเคชันก่อนหน้าโดยอัตโนมัติ พร้อมส่งการแจ้งเตือนการขัดจังหวะไปให้ ความแตกต่างทางสถาปัตยกรรมนี้กำหนดแนวทางการจัดการเสียงที่แตกต่างกันบนสองแพลตฟอร์ม
ตาม WWDC 2024 Session 211 ประมาณ 40% ของปัญหาเสียงในแอปพลิเคชัน iOS เกิดจากการกำหนดค่า Audio Session ที่ไม่ถูกต้อง ข้อผิดพลาดที่พบบ่อยที่สุดคือการเลือกหมวดหมู่ ambient แทน playback ซึ่งทำให้เสียงหายไปเมื่อหน้าจอถูกล็อก
เมื่อเริ่มทำงาน แอปพลิเคชันจะได้รับ sharedInstance ของเซสชัน ตั้งค่าหมวดหมู่ผ่านการเรียก setCategory(_:mode:options:) และเปิดใช้งานเซสชันผ่าน setActive(true) หลังจากเปิดใช้งาน iOS จะพิจารณานโยบายหมวดหมู่สำหรับการกำหนดเส้นทาง หากแอปพลิเคชันอื่นเปิดใช้งานเซสชันของมัน เซสชันปัจจุบันจะได้รับการแจ้งเตือน AudioSessionInterruptionType.began ผ่าน Notification.Name.AVAudioSessionInterruption
หมวดหมู่เป็นพารามิเตอร์หลักของ Audio Session ซึ่งกำหนดตัวเลือกพฤติกรรมที่กำหนดไว้ล่วงหน้าหกแบบ การเลือกหมวดหมู่เป็นการตัดสินใจแรกและสำคัญที่สุดเมื่อตั้งค่าเสียงใน iOS
| หมวดหมู่ | เมื่อใดควรใช้ | เสียงพื้นหลัง | สวิตช์ปิดเสียงมีผล |
|---|---|---|---|
| ambient | เกม เอฟเฟกต์พื้นหลัง | ไม่ | ใช่ |
| playback | เพลง พอดแคสต์ หนังสือเสียง | ใช่ | ไม่ |
| record | บันทึกเสียง อัดเสียง | ไม่ | ไม่มี |
| playAndRecord | VoIP ข้อความเสียง | ใช่ | ไม่ |
| multiRoute | มิกเซอร์ DJ คาราโอเกะ | ใช่ | ไม่ |
| soloAmbient | ค่าเริ่มต้น (iOS default) | ไม่ | ใช่ |
สำหรับเครื่องเล่นเพลงและวิดีโอ ให้ใช้ playback เสมอ หมวดหมู่นี้อนุญาตให้เล่นเสียงเมื่อหน้าจอถูกล็อก เมื่อสวิตช์ปิดเสียงปิดอยู่ (ปุ่มจริงบน iPhone) และเมื่อแอปพลิเคชันอยู่ในพื้นหลัง หากไม่มีหมวดหมู่ playback เซสชันจะถูกปิดใช้งานเมื่อหน้าจอถูกล็อกหรือแอปพลิเคชันถูกย่อ
หมวดหมู่ ambient เหมาะสำหรับเกมและแอปพลิเคชันที่มีเสียงพื้นหลัง — อนุญาตให้แอปพลิเคชันอื่นเล่นต่อได้ ตัวอย่างเช่น หากผู้ใช้กำลังฟังเพลงและเปิดเกมที่มีเซสชัน ambient เพลงจะยังคงเล่นทับเสียงเกมต่อไป นี่เป็นความแตกต่างพื้นฐานจาก Android ซึ่งสถานการณ์ดังกล่าวต้องได้รับอนุญาต duck อย่างชัดแจ้ง
การกำหนดค่า Audio Session ควรทำก่อนเริ่มการเล่นใดๆ ขอแนะนำให้กำหนดค่าเซสชันในเมธอด application(_:didFinishLaunchingWithOptions:) หรือในตัวเริ่มต้นของเครื่องเล่น หลังจากตั้งค่าหมวดหมู่แล้ว ต้องเปิดใช้งานเซสชัน
import AVFAudio
let session = AVAudioSession.sharedInstance
do {
try session.setCategory(
playback,
mode: default,
options: [allowBluetooth, defaultToSpeaker]
)
try session.setActive(true)
} catch {
print("การตั้งค่า Audio Session ล้มเหลว: \(error.localizedDescription)")
}
พารามิเตอร์ options รวมถึง allowBluetooth (ส่งออกไปยังหูฟัง Bluetooth) และ defaultToSpeaker (เล่นผ่านลำโพงแทนหูฟัง) ตัวเลือก allowBluetooth เป็นสิ่งจำเป็นสำหรับแอปพลิเคชันที่รองรับหูฟัง Bluetooth — หากไม่มีตัวเลือกนี้ เสียงอาจถูกส่งไปยังลำโพงในตัวแม้เมื่อเชื่อมต่อหูฟังอยู่
let session = AVAudioSession.sharedInstance
try session.setCategory(
playAndRecord,
mode: voiceChat,
options: [allowBluetooth, allowBluetoothA2DP]
)
try session.overrideOutputAudioPort(speaker)
try session.setActive(true)
หมวดหมู่ playAndRecord กับโหมด voiceChat ปรับเส้นทางเสียงให้เหมาะสมสำหรับการสื่อสารด้วยเสียง: เปิดใช้งานการตัดเสียงก้อง การควบคุมเกนอัตโนมัติ (AGC) และเลือกโคเดกที่เหมาะสมที่สุด OverrideOutputAudioPort(.speaker) บังคับให้ส่งออกผ่านลำโพงแม้เมื่อเชื่อมต่อหูฟังอยู่ — มีประโยชน์สำหรับลำโพง
การเรียก setActive(true) จะเปิดใช้งานเซสชันและแจ้งระบบว่าแอปพลิเคชันจะใช้เสียง เมื่อหยุดเล่นชั่วคราว ขอแนะนำให้ปิดใช้งานเซสชันเพื่อให้แอปพลิเคชันอื่นสามารถรับสตรีมเสียงได้ ข้อยกเว้นคือแอปพลิเคชันที่มีการเล่นพื้นหลังเป็นเวลานาน (เพลง พอดแคสต์) ซึ่งเซสชันจะยังคงทำงานตลอดทั้งแทร็ก
สิ่งสำคัญคือต้องจัดการข้อผิดพลาดเมื่อเรียก setActive หากเซสชันอื่นที่มีลำดับความสำคัญสูงกำลังทำงานอยู่ (เช่น โทรศัพท์ระหว่างการโทร) setActive อาจทำให้เกิดข้อผิดพลาด ในกรณีนี้ ให้รอการแจ้งเตือน AudioSessionInterruptionType.ended และลองเปิดใช้งานอีกครั้ง
โหมดปรับแต่งหมวดหมู่และปรับเส้นทางเสียงให้เหมาะสมสำหรับกรณีการใช้งานเฉพาะ แต่ละโหมดจะเปลี่ยนพฤติกรรมของ AGC การตัดเสียงก้อง และโคเดก โหมดไม่ได้แทนที่หมวดหมู่แต่เสริมหมวดหมู่ — หนึ่งหมวดหมู่สามารถทำงานกับโหมดต่างๆ ได้
ตัวเลือกให้การปรับแต่งพฤติกรรมเซสชันอย่างละเอียด แต่ละตัวเลือกเป็นแฟล็กที่สามารถรวมกับตัวเลือกอื่นในอาร์เรย์ได้ ตัวอย่างเช่น [.allowBluetooth, .defaultToSpeaker, .interruptSpokenAudioAndMix] อนุญาตให้ส่งเสียงไปยังหูฟัง Bluetooth ใช้ลำโพงเป็นค่าเริ่มต้น และผสมกับหนังสือเสียง
บน iOS 17+ มีตัวเลือก spatialAudio ซึ่งเปิดใช้งานเสียงรอบทิศทางเฉพาะบุคคลสำหรับ AirPods ผ่าน AVAudioSessionSpatialPreferences ตาม WWDC 2024 เสียงรอบทิศทางเพิ่มการมีส่วนร่วมของผู้ใช้ในแอปพลิเคชันเพลง 25% ในการทดสอบของ Apple
การขัดจังหวะเป็นความแตกต่างสำคัญระหว่าง Audio Session และ Android Audio Focus ใน iOS การขัดจังหวะจะถูกจัดการผ่าน NotificationCenter โดยสมัครรับ AVAudioSession.interruptionNotification การแจ้งเตือนประกอบด้วยพจนานุกรมพร้อมประเภทการขัดจังหวะ: began หรือ ended
override func viewDidLoad() {
super.viewDidLoad()
let center = NotificationCenter.default
center.addObserver(
self,
selector: #selector(handleInterruption),
name: AVAudioSession.interruptionNotification,
object: nil
)
}
@objc func handleInterruption(_ notification: Notification) {
guard let userInfo = notification.userInfo,
let type = userInfo[AVAudioSession.interruptionTypeKey]
as? AVAudioSessionInterruptionType
else { return }
switch type {
case began:
pausePlayback()
case ended:
guard let options = userInfo[AVAudioSession.interruptionOptionKey]
as? AVAudioSessionInterruptionOptions
else { return }
if options.contains(shouldResume) {
resumePlayback()
}
}
เมื่อได้รับ interruptionType.began เครื่องเล่นควรหยุดเล่นชั่วคราว เมื่อได้รับ interruptionType.ended คุณสมบัติ interruptionOptionKey จะบ่งชี้ว่าเครื่องเล่นสามารถเล่นต่อโดยอัตโนมัติได้หรือไม่ (shouldResume) หากผู้ใช้ปฏิเสธการโทร shouldResume = true หากการโทรสิ้นสุดด้วยการหมดเวลา — shouldResume = false ไม่อนุญาตให้เล่นต่อ
เมื่อแอปพลิเคชันอื่นเปิดใช้งาน Audio Session ด้วยหมวดหมู่ playback เซสชันปัจจุบันจะได้รับการแจ้งเตือนการขัดจังหวะ หากแอปพลิเคชันอื่นใช้ ambient จะไม่เกิดการขัดจังหวะ — เสียงจะถูกผสมกัน พฤติกรรมนี้แตกต่างอย่างมากจาก Android ซึ่งการเปิดใช้งาน Audio Focus ใดๆ จะทำให้เกิดเหตุการณ์ LOSS
สำหรับแอปพลิเคชันที่ต้องเล่นต่อเมื่อเซสชันอื่นถูกเปิดใช้งาน (ตัวอย่างเช่น การนำทางขณะที่เพลงกำลังเล่น) ให้ใช้ตัวเลือก .mixWithOthers ตัวเลือกนี้อนุญาตให้ผสมเสียงกับแอปพลิเคชันอื่น และจะไม่ส่งการขัดจังหวะใดๆ MixWithOthers คือสิ่งที่เทียบเท่ากับโหมด duck ใน Android บน iOS
Audio Session จัดการการกำหนดเส้นทางเสียงระหว่างลำโพงในตัว หูฟัง หูฟัง Bluetooth และอุปกรณ์ AirPlay โดยอัตโนมัติ แอปพลิเคชันสามารถติดตามเส้นทางปัจจุบันผ่านคุณสมบัติ currentRoute และรับการแจ้งเตือนเกี่ยวกับการเปลี่ยนแปลงผ่าน AVAudioSession.routeChangeNotification
เมื่อเชื่อมต่อหูฟัง Bluetooth iOS จะเปลี่ยนเส้นทางเสียงไปยังหูฟังโดยอัตโนมัติหากเซสชันถูกกำหนดค่าด้วยตัวเลือก allowBluetooth หากไม่มีตัวเลือกนี้ เสียงจะยังคงผ่านลำโพงในตัว ตั้งแต่ iOS 16 เป็นต้นไป เมื่อเชื่อมต่อ AirPods Pro ระบบจะเปิดใช้งานการซิงค์ ProMotion โดยอัตโนมัติเพื่อลดความหน่วง
การสมัครรับ routeChangeNotification ช่วยให้ตอบสนองต่อการเชื่อมต่อและตัดการเชื่อมต่อของหูฟัง เมื่อหูฟัง Bluetooth ถูกตัดการเชื่อมต่อ เครื่องเล่นควรหยุดเล่นชั่วคราว — ผู้ใช้อาจไม่คาดหวังว่าเสียงจะเริ่มออกจากลำโพงโทรศัพท์ ตาม Apple HIG (2026) นี่เป็นพฤติกรรมที่จำเป็นสำหรับแอปพลิเคชันเพลง
คุณสมบัติ availableInputs และ availableOutputs ส่งคืนรายการอุปกรณ์เสียงที่มีอยู่พร้อมประเภท (builtInSpeaker, headphones, bluetoothA2DP, hdmi) นักพัฒนาสามารถเลือกอุปกรณ์เฉพาะโดยทางโปรแกรมผ่าน overrideOutputAudioPort สำหรับสถานการณ์การกำหนดเส้นทางที่กำหนดเอง
คำถามที่พบบ่อย
ความแตกต่างสำคัญคือ สถาปัตยกรรม Audio Session เป็นเซสชันรวมศูนย์เดียวต่อแอปพลิเคชันที่กำหนดค่าครั้งเดียว Android Audio Focus ต้องการการขอโฟกัสด้วยตนเองทุกครั้งที่เล่น นอกจากนี้ iOS รองรับการผสมผ่านตัวเลือก mixWithOthers ในขณะที่ Android duck เป็นทางเลือกเดียวในการหยุดทั้งหมด
สาเหตุที่พบบ่อยที่สุดคือ หมวดหมู่ Audio Session ไม่ถูกต้อง หากเลือก ambient หรือ soloAmbient เสียงจะหยุดเมื่อหน้าจอถูกล็อก เปลี่ยนหมวดหมู่เป็น playback และตรวจสอบให้แน่ใจว่าได้เพิ่ม Background Modes — Audio, AirPlay, and Picture in Picture ใน Info.plist
เพิ่มตัวเลือก .mixWithOthers ใน setCategory ซึ่งจะอนุญาตให้ผสมเสียงของแอปพลิเคชันของคุณกับเซสชันที่ทำงานอยู่อื่นๆ หากไม่มีตัวเลือกนี้ แอปพลิเคชันใหม่จะขัดจังหวะแอปพลิเคชันปัจจุบัน MixWithOthers เป็นสิ่งที่คล้ายกับโหมด duck ใน Android แต่คงระดับเสียงไว้เต็มที่
ใช้ overrideOutputAudioPort พร้อม nil เพื่อเลือกอัตโนมัติ สำหรับการส่งออกแบบบังคับไปยัง Bluetooth: รับ AVAudioSessionRouteDescription จาก availableOutputs เลือกพอร์ตที่มีประเภท .bluetoothA2DP และส่งต่อไปยัง overrideOutputAudioPort ตรวจสอบให้แน่ใจว่าเซสชันถูกกำหนดค่าด้วย allowBluetooth
สำหรับแอปพลิเคชันส่วนใหญ่ — ใช่ การปิดใช้งานเซสชันเมื่อหยุดชั่วคราวช่วยให้แอปพลิเคชันอื่นได้รับโฟกัสเสียง ข้อยกเว้นคือเครื่องเล่นเพลงที่มีการเล่นพื้นหลังเป็นเวลานาน หากการหยุดชั่วคราวสั้น (น้อยกว่า 5 วินาที) ควรรักษาเซสชันให้ทำงานเพื่อเริ่มเล่นต่ออย่างรวดเร็ว
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม