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

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

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

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

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

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

AudioAttributes

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

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

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

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

AudioFormat

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

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

คอยติดตามการเปลี่ยนแปลงใน Spatializer

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

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

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

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

หลังจากอัปเดตการอ้างอิง 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)