เสียงรอบทิศทาง

เสียงรอบทิศทางเป็นประสบการณ์เสียงที่สมจริงซึ่งจะทำให้ผู้ใช้รู้สึกเหมือนอยู่ท่ามกลางเหตุการณ์นั้นๆ และทำให้เนื้อหาของคุณมีเสียงที่สมจริงยิ่งขึ้น เสียงจะได้รับการ "ปรับให้เป็นเสียงรอบทิศทาง" เพื่อสร้างเอฟเฟกต์จากลำโพงหลายตัวคล้ายกับการตั้งค่าเสียงเซอร์ราวด์ แต่จะเล่นผ่านหูฟังแทน

ตัวอย่างเช่น ในภาพยนตร์ เสียงจากรถยนต์อาจเริ่มจากด้านหลังของผู้ใช้ เคลื่อนไปข้างหน้า และค่อยๆ เบาลงเมื่อเคลื่อนห่างออกไป ในวิดีโอแชท ระบบจะแยกเสียงและวางไว้รอบๆ ตัวผู้ใช้ ทำให้ระบุผู้พูดได้ง่ายขึ้น

หากเนื้อหาใช้รูปแบบเสียงที่รองรับ คุณสามารถเพิ่มเสียงรอบทิศทางลงในแอปได้ตั้งแต่ Android 13 (ระดับ API 33) เป็นต้นไป

ค้นหาความสามารถ

ใช้คลาส Spatializer เพื่อค้นหาความสามารถและลักษณะการทำงานของระบบเสียงรอบทิศทางของอุปกรณ์ เริ่มต้นด้วยการดึงข้อมูลอินสแตนซ์ของ Spatializer จาก AudioManager:

Kotlin

val spatializer = audioManager.spatializer

Java

Spatializer spatializer = AudioManager.getSpatializer();

หลังจากได้รับ Spatializer แล้ว ให้ตรวจสอบเงื่อนไข 4 ข้อที่ต้องเป็นจริงเพื่อให้อุปกรณ์ส่งออกเสียงรอบทิศทางได้ ดังนี้

เกณฑ์ ตรวจสอบ
อุปกรณ์รองรับการสร้างเสียงรอบทิศทางไหม getImmersiveAudioLevel() ไม่เท่ากับ SPATIALIZER_IMMERSIVE_LEVEL_NONE
มีฟีเจอร์การสร้างเสียงรอบทิศทางไหม
ความพร้อมใช้งานขึ้นอยู่กับความเข้ากันได้กับการกำหนดเส้นทางเอาต์พุตเสียงปัจจุบัน
isAvailable() คือ true
เปิดใช้การแปลงเป็น 3 มิติอยู่ใช่ไหม isEnabled() คือ true
แทร็กเสียงที่มีพารามิเตอร์ที่ระบุสามารถทำให้เป็นเสียงรอบทิศทางได้ไหม canBeSpatialized() คือ true

เงื่อนไขเหล่านี้อาจไม่เป็นไปตามที่กำหนด เช่น หากการสร้างเสียงรอบทิศทางไม่พร้อมใช้งานสำหรับแทร็กเสียงปัจจุบันหรือปิดใช้ในอุปกรณ์เอาต์พุตเสียงทั้งหมด

การติดตามการเคลื่อนไหวของศีรษะ

เมื่อใช้ชุดหูฟังที่รองรับ แพลตฟอร์มจะปรับการสร้างเสียงรอบทิศทางตามตำแหน่งศีรษะของผู้ใช้ได้ หากต้องการตรวจสอบว่ามีเครื่องติดตามการเคลื่อนไหวของศีรษะสำหรับการกำหนดเส้นทางเอาต์พุตเสียงปัจจุบันหรือไม่ ให้เรียกใช้ isHeadTrackerAvailable()

เนื้อหาที่เข้ากันได้

Spatializer.canBeSpatialized() ระบุว่าเสียงที่มีพร็อพเพอร์ตี้ที่ระบุสามารถสร้างเสียงรอบทิศทางด้วยการกำหนดเส้นทางอุปกรณ์เอาต์พุตปัจจุบันได้หรือไม่ เมธอดนี้ใช้ AudioAttributes และ AudioFormat ซึ่งทั้ง 2 รายการมีคำอธิบายโดยละเอียดที่ด้านล่าง

AudioAttributes

ออบเจ็กต์ AudioAttributes อธิบายการใช้งานสตรีมเสียง (เช่น เสียงเกมหรือสื่อมาตรฐาน) พร้อมกับลักษณะการเล่นและประเภทเนื้อหา

เมื่อเรียกใช้ canBeSpatialized() ให้ใช้อินสแตนซ์ AudioAttributes เดียวกันกับที่ตั้งค่าไว้สำหรับ Player ตัวอย่างเช่น หากคุณใช้ไลบรารี Jetpack Media3 และยังไม่ได้ปรับแต่ง AudioAttributes ให้ใช้ AudioAttributes.DEFAULT

กำลังปิดใช้เสียงรอบทิศทาง

หากต้องการระบุว่าเนื้อหาของคุณได้รับการปรับแต่งเสียงรอบทิศทางแล้ว ให้เรียกใช้ setIsContentSpatialized(true) เพื่อไม่ให้ระบบประมวลผลเสียงซ้ำ หรือปรับลักษณะการทำงานของระบบเสียงรอบทิศทางเพื่อปิดใช้ระบบเสียงรอบทิศทางทั้งหมดโดยเรียกใช้ setSpatializationBehavior(AudioAttributes.SPATIALIZATION_BEHAVIOR_NEVER)

AudioFormat

ออบเจ็กต์ AudioFormat อธิบายรายละเอียดเกี่ยวกับรูปแบบและการกำหนดค่าช่องของแทร็กเสียง

เมื่อสร้างอินสแตนซ์ AudioFormat เพื่อส่งไปยัง canBeSpatialized() ให้ตั้งค่าการเข้ารหัสให้เหมือนกับรูปแบบเอาต์พุตที่คาดไว้จากตัวถอดรหัส นอกจากนี้ คุณควรตั้งค่ามาสก์ช่องที่ตรงกับการกำหนดค่าช่องของเนื้อหาด้วย ดูคำแนะนำเกี่ยวกับค่าที่เฉพาะเจาะจงที่จะใช้ได้ที่ส่วนลักษณะการทำงานเชิงพื้นที่เริ่มต้น

คอยฟังการเปลี่ยนแปลงใน Spatializer

หากต้องการฟังการเปลี่ยนแปลงในสถานะของ Spatializer คุณสามารถเพิ่ม Listener ด้วย Spatializer.addOnSpatializerStateChangedListener() ในทำนองเดียวกัน หากต้องการฟังการเปลี่ยนแปลงความพร้อมใช้งานของอุปกรณ์ติดตามการเคลื่อนไหวของศีรษะ ให้เรียกใช้ Spatializer.addOnHeadTrackerAvailableListener()

ซึ่งจะเป็นประโยชน์หากคุณต้องการปรับการเลือกแทร็กระหว่างการเล่นโดยใช้ Callback ของ Listener ตัวอย่างเช่น เมื่อผู้ใช้เชื่อมต่อหรือยกเลิกการเชื่อมต่อชุดหูฟังจากอุปกรณ์ Callback onSpatializerAvailableChanged จะระบุว่าเอฟเฟกต์ Spatializer พร้อมใช้งานสำหรับการกำหนดเส้นทางเอาต์พุตเสียงใหม่หรือไม่ ณ จุดนี้ คุณอาจพิจารณาอัปเดตตรรกะการเลือกแทร็กของเพลเยอร์ให้ตรงกับความสามารถใหม่ของอุปกรณ์ ดูรายละเอียดเกี่ยวกับลักษณะการเลือกแทร็กของ ExoPlayer ได้ที่ส่วน ExoPlayer และเสียงรอบทิศทาง

ExoPlayer และเสียงรอบทิศทาง

ExoPlayer เวอร์ชันล่าสุดช่วยให้ใช้เสียงรอบทิศทางได้ง่ายขึ้น หากคุณใช้ไลบรารี ExoPlayer แบบสแตนด์อโลน (ชื่อแพ็กเกจ com.google.android.exoplayer2) เวอร์ชัน 2.17 จะกำหนดค่าแพลตฟอร์มให้แสดงผลเสียงรอบทิศทาง และเวอร์ชัน 2.18 จะเปิดตัวข้อจำกัดจำนวนช่องเสียง หากคุณใช้โมดูล ExoPlayer จากคลัง Media3 (ชื่อแพ็กเกจ androidx.media3) เวอร์ชัน 1.0.0-beta01 และใหม่กว่าจะมีการอัปเดตแบบเดียวกันนี้

หลังจากอัปเดตทรัพยากร Dependency ของ ExoPlayer เป็นรุ่นล่าสุดแล้ว แอปของคุณเพียงแค่ต้องมีเนื้อหาที่สามารถปรับเสียงตามตำแหน่งได้

ข้อจำกัดจำนวนช่องเสียง

เมื่อเป็นไปตามเงื่อนไขทั้ง 4 ข้อสำหรับเสียงรอบทิศทาง ExoPlayer จะเลือกแทร็กเสียงแบบหลายช่องทาง หากไม่ ExoPlayer จะเลือกแทร็กสเตอริโอแทน หากพร็อพเพอร์ตี้ Spatializer เปลี่ยนแปลง ExoPlayer จะทริกเกอร์การเลือกแทร็กใหม่เพื่อเลือกแทร็กเสียงที่ตรงกับพร็อพเพอร์ตี้ปัจจุบัน โปรดทราบว่าการเลือกแทร็กใหม่นี้อาจทำให้เกิดการบัฟเฟอร์ซ้ำเป็นระยะเวลาสั้นๆ

หากต้องการปิดใช้ข้อจำกัดจำนวนช่องเสียง ให้ตั้งค่าพารามิเตอร์การเลือกแทร็กในเพลเยอร์ดังที่แสดงด้านล่าง

Kotlin

exoPlayer.trackSelectionParameters = DefaultTrackSelector.Parameters.Builder(context)
  .setConstrainAudioChannelCountToDeviceCapabilities(false)
  .build()

Java

exoPlayer.setTrackSelectionParameters(
  new DefaultTrackSelector.Parameters.Builder(context)
    .setConstrainAudioChannelCountToDeviceCapabilities(false)
    .build()
);

ในทำนองเดียวกัน คุณสามารถอัปเดตพารามิเตอร์ของตัวเลือกแทร็กที่มีอยู่เพื่อปิดใช้ข้อจำกัดจำนวนช่องเสียงได้ดังนี้

Kotlin

val trackSelector = DefaultTrackSelector(context)
...
trackSelector.parameters = trackSelector.buildUponParameters()
  .setConstrainAudioChannelCountToDeviceCapabilities(false)
  .build()

Java

DefaultTrackSelector trackSelector = new DefaultTrackSelector(context);
...
trackSelector.setParameters(
  trackSelector
    .buildUponParameters()
    .setConstrainAudioChannelCountToDeviceCapabilities(false)
    .build()
);

เมื่อปิดใช้ข้อจำกัดจำนวนช่องเสียง หากเนื้อหามีแทร็กเสียงหลายแทร็ก ExoPlayer จะเลือกแทร็กที่มีจำนวนช่องสูงสุดและเล่นได้จากอุปกรณ์ในตอนแรก เช่น หากเนื้อหามีแทร็กเสียงแบบหลายช่องทางและแทร็กเสียงแบบสเตอริโอ และอุปกรณ์รองรับการเล่นทั้ง 2 แบบ ExoPlayer จะเลือกแทร็กแบบหลายช่องทาง ดูรายละเอียดเกี่ยวกับวิธีปรับแต่งลักษณะการทำงานนี้ได้ที่การเลือกแทร็กเสียง

การเลือกแทร็กเสียง

เมื่อปิดใช้ลักษณะการทำงานข้อจำกัดจำนวนช่องเสียงของ ExoPlayer แล้ว ExoPlayer จะไม่เลือกแทร็กเสียงที่ตรงกับพร็อพเพอร์ตี้ของ Spatializer ของอุปกรณ์โดยอัตโนมัติ แต่คุณสามารถปรับแต่งตรรกะการเลือกแทร็กของ ExoPlayer ได้โดยตั้งค่าพารามิเตอร์การเลือกแทร็กก่อนหรือระหว่างการเล่น โดยค่าเริ่มต้น ExoPlayer จะเลือกแทร็กเสียงที่เหมือนกับแทร็กเริ่มต้นในแง่ของประเภท MIME (การเข้ารหัส) จำนวนช่อง และอัตราการสุ่มตัวอย่าง

การเปลี่ยนพารามิเตอร์การเลือกแทร็ก

หากต้องการเปลี่ยนพารามิเตอร์การเลือกแทร็กของ ExoPlayer ให้ใช้ Player.setTrackSelectionParameters() ในทำนองเดียวกัน คุณสามารถดูพารามิเตอร์ปัจจุบันของ ExoPlayer ได้ด้วย Player.getTrackSelectionParameters() ตัวอย่างเช่น หากต้องการเลือกแทร็กเสียงสเตอริโอระหว่างการเล่น ให้ทำดังนี้

Kotlin

exoPlayer.trackSelectionParameters = exoPlayer.trackSelectionParameters
  .buildUpon()
  .setMaxAudioChannelCount(2)
  .build()

Java

exoPlayer.setTrackSelectionParameters(
  exoPlayer.getTrackSelectionParameters()
    .buildUpon()
    .setMaxAudioChannelCount(2)
    .build()
);

โปรดทราบว่าการเปลี่ยนพารามิเตอร์การเลือกแทร็กระหว่างการเล่นอาจทำให้การเล่นหยุดชะงัก ดูข้อมูลเพิ่มเติมเกี่ยวกับการปรับพารามิเตอร์การเลือกแทร็กของเพลเยอร์ได้ในส่วนการเลือกแทร็กของเอกสาร ExoPlayer

ลักษณะการทำงานของระบบเสียงรอบทิศทางเริ่มต้น

ลักษณะการทำงานเชิงมิติสัมพันธ์เริ่มต้นใน Android มีลักษณะการทำงานต่อไปนี้ที่ OEM อาจปรับแต่งได้

  • ระบบจะปรับเฉพาะเนื้อหาแบบหลายช่องให้เป็นเสียงรอบทิศทาง ไม่ใช่เนื้อหาแบบสเตอริโอ หากไม่ได้ใช้ ExoPlayer คุณอาจต้องกำหนดค่าจำนวนช่องสูงสุดที่ตัวถอดรหัสเสียงสามารถส่งออกเป็นจำนวนมาก ทั้งนี้ขึ้นอยู่กับรูปแบบของเนื้อหาเสียงแบบหลายช่องทาง ซึ่งจะช่วยให้มั่นใจว่าตัวถอดรหัสเสียงจะส่งออก PCM แบบหลายช่องทางเพื่อให้แพลตฟอร์มสร้างเสียงรอบทิศทางได้

    Kotlin

    val mediaFormat = MediaFormat()
    mediaFormat.setInteger(MediaFormat.KEY_MAX_OUTPUT_CHANNEL_COUNT, 99)

    Java

    MediaFormat mediaFormat = new MediaFormat();
    mediaFormat.setInteger(MediaFormat.KEY_MAX_OUTPUT_CHANNEL_COUNT, 99);

    ดูตัวอย่างการใช้งานจริงได้ที่ MediaCodecAudioRenderer.java ของ ExoPlayer หากต้องการปิดการแปลงเป็นเสียงรอบทิศทางด้วยตนเอง ไม่ว่า OEM จะปรับแต่งอย่างไร โปรดดูหัวข้อการปิดใช้เสียงรอบทิศทาง

  • AudioAttributes: เสียงมีสิทธิ์ใช้การประมวลผลเสียงรอบทิศทางหากตั้งค่า usage เป็น USAGE_MEDIA หรือ USAGE_GAME

  • AudioFormat: ใช้มาสก์ช่องที่มีช่อง AudioFormat.CHANNEL_OUT_QUAD (หน้าซ้าย หน้าขวา หลังซ้าย และหลังขวา) เป็นอย่างน้อยเพื่อให้เสียงมีสิทธิ์ใช้ระบบเสียงรอบทิศทาง ในตัวอย่างด้านล่าง เราใช้ AudioFormat.CHANNEL_OUT_5POINT1 สำหรับแทร็กเสียง 5.1 สำหรับแทร็กเสียงสเตอริโอ ให้ใช้ AudioFormat.CHANNEL_OUT_STEREO

    หากใช้ Media3 คุณสามารถใช้ Util.getAudioTrackChannelConfig(int channelCount) เพื่อแปลงจำนวนช่องเป็นมาสก์ช่องได้

    นอกจากนี้ ให้ตั้งค่าการเข้ารหัสเป็น AudioFormat.ENCODING_PCM_16BIT หากคุณกำหนดค่าตัวถอดรหัสให้ส่งออก PCM แบบหลายช่องทาง

    Kotlin

    val audioFormat = AudioFormat.Builder()
      .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
      .setChannelMask(AudioFormat.CHANNEL_OUT_5POINT1)
      .build()

    Java

    AudioFormat audioFormat = new AudioFormat.Builder()
      .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
      .setChannelMask(AudioFormat.CHANNEL_OUT_5POINT1)
      .build();

ทดสอบเสียงรอบทิศทาง

ตรวจสอบว่าได้เปิดใช้เสียงรอบทิศทางในอุปกรณ์ทดสอบแล้ว โดยทำดังนี้

  • สำหรับชุดหูฟังแบบมีสาย ให้ไปที่การตั้งค่าระบบ > เสียงและการสั่น > เสียงรอบทิศทาง
  • สำหรับชุดหูฟังไร้สาย ให้ไปที่การตั้งค่าระบบ > อุปกรณ์ที่เชื่อมต่อ > ไอคอนรูปเฟืองสำหรับอุปกรณ์ไร้สาย > เสียงรอบทิศทาง

หากต้องการตรวจสอบความพร้อมใช้งานของเสียงรอบทิศทางสำหรับการกำหนดเส้นทางปัจจุบัน ให้เรียกใช้คำสั่ง adb shell dumpsys audio ในอุปกรณ์ คุณควรเห็นพารามิเตอร์ต่อไปนี้ในเอาต์พุตขณะที่การเล่นทำงานอยู่

Spatial audio:
mHasSpatializerEffect:true (effect present)
isSpatializerEnabled:true (routing dependent)