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

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

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

หากเนื้อหาใช้รูปแบบเสียงที่รองรับ คุณจะเพิ่มเสียงรอบทิศทางลงในแอปได้ตั้งแต่ 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
เปิดใช้การจัดวางเสียงหรือไม่ isEnabled() คือ true
แทร็กเสียงที่มีพารามิเตอร์ที่ระบุสามารถเปลี่ยนเป็นเสียงรอบทิศทางได้ไหม canBeSpatialized() คือ true

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

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

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

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

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

AudioAttributes

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

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

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

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

AudioFormat

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

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

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

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

วิธีนี้มีประโยชน์หากคุณต้องการปรับการเลือกแทร็กระหว่างการเล่นโดยใช้การเรียกกลับของผู้ฟัง เช่น เมื่อผู้ใช้เชื่อมต่อหรือยกเลิกการเชื่อมต่อหูฟังกับอุปกรณ์ แคล็กแบ็ก onSpatializerAvailableChanged จะระบุว่าเอฟเฟกต์การจัดวางเสียงพร้อมใช้งานสำหรับการกำหนดเส้นทางเอาต์พุตเสียงใหม่หรือไม่ เมื่อถึงจุดนี้ คุณอาจพิจารณาอัปเดตตรรกะการเลือกแทร็กของเครื่องเล่นให้ตรงกับความสามารถใหม่ของอุปกรณ์ ดูรายละเอียดเกี่ยวกับลักษณะการเลือกแทร็กใน 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 จะไม่เลือกแทร็กเสียงโดยอัตโนมัติซึ่งตรงกับพร็อพเพอร์ตี้ของโปรแกรมจำลองเสียง 3 มิติของอุปกรณ์ แต่คุณสามารถปรับแต่งตรรกะการเลือกแทร็กได้โดยใช้การตั้งค่าพารามิเตอร์การเลือกแทร็กก่อนหรือระหว่างการเล่น โดยค่าเริ่มต้น 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)