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

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

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

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

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

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

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

    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 หากต้องการปิดการแปลงเป็น 3 มิติด้วยตนเองโดยไม่คำนึงถึงการปรับแต่งของ 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)