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

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

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

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

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

เมื่อข้อจำกัดจำนวนช่องสัญญาณเสียงของ 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

ลักษณะการทำงานเริ่มต้นของการแบ่งพื้นที่

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