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

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

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

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

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

ลักษณะการจำลองเสียง 3 มิติเริ่มต้น

ลักษณะการจำลองเสียงเชิงพื้นที่เริ่มต้นใน 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)