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

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

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

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

ฟังการเปลี่ยนแปลงใน 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)