เพิ่มเสียงรอบทิศทางลงในแอป XR

อุปกรณ์ XR ที่รองรับ
คำแนะนำนี้จะช่วยคุณสร้างประสบการณ์การใช้งานสำหรับอุปกรณ์ XR ประเภทต่างๆ
ชุดหูฟัง XR
แว่นตา XR แบบมีสาย

ฟีเจอร์เสียงรอบทิศทางใน Jetpack SceneCore ช่วยให้คุณสร้างประสบการณ์การใช้งานเสียงที่สมจริงภายในแอปพลิเคชัน Android XR ได้

เสียงรอบทิศทางจำลองวิธีที่ผู้ใช้รับรู้เสียงในสภาพแวดล้อม 3 มิติ โดยสร้างความรู้สึกว่าเสียงมาจากทุกทิศทาง รวมถึงด้านบนและด้านล่างของผู้ใช้ ระบบจะทำเช่นนี้โดยจำลอง "ลำโพงเสมือน" อย่างน้อย 1 ตัวในตำแหน่งที่เฉพาะเจาะจงในพื้นที่ 3 มิติ

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

ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีที่แอปที่มีอยู่แสดงเสียงรอบทิศทางได้ที่หัวข้อเพิ่มเสียงสเตอริโอ และเสียงเซอร์ราวด์ลงในแอปในหน้านี้

หากคุณกำลังเพิ่มประสิทธิภาพแอปสำหรับ XR, Jetpack SceneCore จะมีเครื่องมือสำหรับการปรับแต่งเสียงรอบทิศทางขั้นสูง คุณสามารถวางตำแหน่งเสียงในสภาพแวดล้อม 3 มิติได้อย่างแม่นยำ ใช้เสียงแบบแอมบิโซนิกเพื่อสร้างสนามเสียงที่สมจริง และใช้ประโยชน์จากการผสานรวมเสียงเซอร์ราวด์ในตัว

ประเภทของเสียงรอบทิศทางที่ใช้ได้ใน Android XR

Android XR รองรับเสียงตามตำแหน่ง เสียงสเตอริโอ เสียงเซอร์ราวด์ และเสียงแบบแอมบิโซนิก

เสียงตามตำแหน่ง

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

เสียงสเตอริโอและเสียงเซอร์ราวด์แบบรอบทิศทาง

แพลตฟอร์ม Android รองรับรูปแบบสื่อทั้งหมดสำหรับเสียงตามตำแหน่ง เสียงสเตอริโอ และ เสียงเซอร์ราวด์ นอกจากรูปแบบเหล่านี้แล้ว อุปกรณ์ Android XR อาจรองรับ Dolby Atmos, Dolby Digital และ Dolby Digital+ รูปแบบเสียง

เสียงสเตอริโอหมายถึงรูปแบบเสียงที่มี 2 ช่องสัญญาณ และเสียงเซอร์ราวด์หมายถึง รูปแบบเสียงที่มีมากกว่า 2 ช่องสัญญาณ เช่น เสียงเซอร์ราวด์ 5.1 หรือ เสียงเซอร์ราวด์ 7.1 การกำหนดค่า ข้อมูลเสียงของแต่ละช่องสัญญาณจะเชื่อมโยงกับลำโพง 1 ตัว ตัวอย่างเช่น เมื่อเล่นเพลงแบบสเตอริโอ ช่องสัญญาณลำโพงด้านซ้ายอาจส่งแทร็กเครื่องดนตรีที่แตกต่างจากด้านขวา

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

เสียงแบบแอมบิโซนิก

เสียงแบบแอมบิโซนิก (หรือแอมบิโซนิก) เปรียบเสมือนท้องฟ้าจำลองสำหรับเสียง ซึ่งมอบทิวทัศน์เสียงที่สมจริงเสมือนจริงให้แก่ผู้ใช้ ใช้เสียงแบบแอมบิโซนิกสำหรับเสียงสภาพแวดล้อมเบื้องหลังหรือสถานการณ์อื่นๆ ที่คุณต้องการจำลองสนามเสียงทรงกลมเต็มรูปแบบที่ล้อมรอบผู้ฟัง Android XR รองรับรูปแบบเสียงแบบแอมบิโซนิก AmbiX ในเสียงแบบแอมบิโซนิกอันดับที่ 1, 2 และ 3 เราขอแนะนำประเภทไฟล์ Opus (.ogg) และ PCM/Wave (.wav)

ใช้เสียงรอบทิศทางกับ Jetpack SceneCore

การใช้เสียงรอบทิศทางกับ Jetpack SceneCore เกี่ยวข้องกับการตรวจสอบความสามารถด้านเสียงรอบทิศทางและการเลือก API สำหรับโหลดเสียงรอบทิศทาง

ตรวจสอบความสามารถด้านเสียงรอบทิศทาง

ก่อนใช้ฟีเจอร์เสียงรอบทิศทาง ให้ตรวจสอบว่า Session รองรับ เสียงรอบทิศทาง ในข้อมูลโค้ดทั้งหมดในส่วนต่อไปนี้ ระบบจะตรวจสอบความสามารถก่อนที่จะพยายามเล่นเสียงรอบทิศทาง

โหลดเสียงรอบทิศทาง

คุณใช้ API ต่อไปนี้เพื่อโหลดเสียงรอบทิศทางสำหรับใช้ใน Jetpack SceneCore ได้

  • SoundPool: เหมาะสำหรับเอฟเฟกต์เสียงสั้นๆ ที่มีขนาดไม่เกิน 1 MB โดยจะโหลดล่วงหน้าและใช้เสียงซ้ำๆ ได้ ซึ่งเป็นวิธีที่ยอดเยี่ยมในการโหลดเสียงสำหรับเสียงตามตำแหน่ง
  • ExoPlayer: เหมาะสำหรับการโหลดเนื้อหาเสียงสเตอริโอและเสียงเซอร์ราวด์ เช่น เพลงและวิดีโอ และยังอนุญาตให้เล่นสื่อในเบื้องหลังได้ด้วย
  • MediaPlayer: เป็นวิธีที่ง่ายที่สุดในการโหลดเสียงแบบแอมบิโซนิก
  • AudioTrack: ให้การควบคุมวิธีโหลดข้อมูลเสียงได้มากที่สุด อนุญาตให้เขียนบัฟเฟอร์เสียงโดยตรง หรือหากคุณสังเคราะห์หรือถอดรหัสไฟล์เสียงของคุณเอง

ตรวจสอบการรองรับรูปแบบสื่อ

แพลตฟอร์ม Android รองรับรูปแบบสื่อบางรูปแบบ อย่างไรก็ตาม อุปกรณ์ Android XR บางรุ่นอาจรองรับรูปแบบเพิ่มเติม เช่น Dolby Atmos หากต้องการค้นหาการรองรับรูปแบบสื่อ ให้ใช้ AudioCapabilities ของ ExoPlayer

val audioCapabilities = AudioCapabilities.getCapabilities(
    context,
    androidx.media3.common.AudioAttributes.DEFAULT,
    null,
    emptyList()
)

if (audioCapabilities.supportsEncoding(C.ENCODING_AC3)) {
    // Device supports playback of the Dolby Digital media format.
}
if (audioCapabilities.supportsEncoding(C.ENCODING_E_AC3)) {
    // Device supports playback of the Dolby Digital Plus media format.
}
if (audioCapabilities.supportsEncoding(C.ENCODING_E_AC3_JOC)) {
    // Device supports playback of the Dolby Digital Plus with Dolby Atmos media format.
}

การตรวจสอบความสามารถเหล่านี้อาจเกี่ยวข้องกับการเรียกที่บล็อก และ ไม่ควรเรียกใช้ในเธรดหลัก

เพิ่มเสียงตามตำแหน่งลงในแอป

แหล่งเสียงตามตำแหน่งกำหนดโดย PointSourceParams และ Entity ที่เชื่อมโยง ตำแหน่งและทิศทางของ Entity จะกำหนดตำแหน่งที่จะแสดง PointSourceParams ในพื้นที่ 3 มิติ เรียกใช้ setPointSourceParams ใน SpatialMediaPlayer เพื่อตั้งค่า PointSourceParams และ entity ที่เชื่อมโยงในอินสแตนซ์ MediaPlayer

ตัวอย่างเสียงตามตำแหน่ง

ตัวอย่างต่อไปนี้จะโหลดไฟล์เสียงเอฟเฟกต์เสียงลงใน Sound Pool และเล่นกลับในตำแหน่งของ Entity

// Check spatial capabilities before using spatial audio
if (session.scene.spatialCapabilities.contains(SpatialCapability.SPATIAL_AUDIO)
) { // The session has spatial audio capabilities
    val maxVolume = 1F
    val lowPriority = 0
    val infiniteLoop = -1
    val normalSpeed = 1F

    val soundPool = SoundPool.Builder()
        .setAudioAttributes(
            AudioAttributes.Builder()
                .setContentType(CONTENT_TYPE_SONIFICATION)
                .setUsage(USAGE_ASSISTANCE_SONIFICATION)
                .build()
        )
        .build()

    val pointSource = PointSourceParams()

    val soundEffect = appContext.assets.openFd("sounds/tiger_16db.mp3")
    val pointSoundId = soundPool.load(soundEffect, lowPriority)

    soundPool.setOnLoadCompleteListener { soundPool, sampleId, status ->
        // wait for the sound file to be loaded into the soundPool
        if (status == 0) {
            SpatialSoundPool.play(
                session = session,
                entity = entity,
                soundPool = soundPool,
                soundID = pointSoundId,
                params = pointSource,
                volume = maxVolume,
                priority = lowPriority,
                loop = infiniteLoop,
                rate = normalSpeed
            )
        }
    }
} else {
    // The session does not have spatial audio capabilities
}

ประเด็นสำคัญเกี่ยวกับโค้ด

  • ขั้นตอนแรกคือการตรวจสอบว่าความสามารถด้านเสียงรอบทิศทางพร้อมใช้งานหรือไม่โดยใช้ spatialCapabilities
  • การตั้งค่า contentType เป็น CONTENT_TYPE_SONIFICATION และการใช้งานเป็น USAGE_ASSISTANCE_SONIFICATION จะทำให้ระบบถือว่าไฟล์เสียงนี้ เป็นเอฟเฟกต์เสียง
  • ตัวอย่างก่อนหน้าจะโหลดไฟล์เสียงลงในพูลทันทีก่อนที่จะใช้เพื่อให้โค้ดอยู่ด้วยกันเพื่อความเรียบง่าย ในทางปฏิบัติ คุณควรโหลดเอฟเฟกต์เสียงทั้งหมดแบบไม่พร้อมกันเมื่อโหลดแอป เพื่อให้ไฟล์เสียงทั้งหมดพร้อมใช้งานในพูลเมื่อคุณต้องการ

เพิ่มเสียงสเตอริโอและเสียงเซอร์ราวด์ลงในแอป

วิธีที่แนะนำในการเพิ่มเสียงสเตอริโอและเสียงเซอร์ราวด์ลงในแอปคือการใช้ Exoplayer ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีใช้เสียงรอบทิศทางกับ Exoplayer, ได้ในคู่มือเสียงรอบทิศทาง

การวางตำแหน่งลำโพงเสียงสเตอริโอและเสียงเซอร์ราวด์

การวางตำแหน่งลำโพงเสียงเซอร์ราวด์จะวางตำแหน่งและกำหนดทิศทางลำโพงเสียงเซอร์ราวด์เสมือน เทียบกับลำโพงตรงกลางรอบๆ ผู้ใช้ในการ กำหนดค่า ITU มาตรฐาน

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

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

หากคุณมีหลายแผงและต้องการเลือกแผงที่จะส่งเสียง หรือหากต้องการให้เสียงสเตอริโอหรือเสียงเซอร์ราวด์แสดงเทียบกับ Entity อื่น คุณสามารถใช้ PointSourceAttributes เพื่อกำหนดตำแหน่งของช่องสัญญาณตรงกลาง ส่วนช่องสัญญาณที่เหลือจะวางตามที่กล่าวไว้ก่อนหน้านี้ ในกรณีเหล่านี้ คุณต้องใช้ MediaPlayer ด้วย

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

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

ตัวอย่างเสียงเซอร์ราวด์

ตัวอย่างต่อไปนี้จะโหลดไฟล์เสียง 5.1 โดยใช้ MediaPlayer และตั้งค่าช่องสัญญาณตรงกลางของไฟล์ให้เป็น Entity

// Check spatial capabilities before using spatial audio
if (session.scene.spatialCapabilities.contains(SpatialCapability.SPATIAL_AUDIO)) {
    // The session has spatial audio capabilities

    val pointSourceAttributes = PointSourceParams()

    val mediaPlayer = MediaPlayer()

    val fivePointOneAudio = appContext.assets.openFd("sounds/aac_51.ogg")
    mediaPlayer.reset()
    mediaPlayer.setDataSource(fivePointOneAudio)

    val audioAttributes =
        AudioAttributes.Builder()
            .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
            .setUsage(AudioAttributes.USAGE_MEDIA)
            .build()

    SpatialMediaPlayer.setPointSourceParams(
        session,
        mediaPlayer,
        pointSourceAttributes,
        entity = session.scene.mainPanelEntity,
    )

    mediaPlayer.setAudioAttributes(audioAttributes)
    mediaPlayer.prepare()
    mediaPlayer.start()
} else {
    // The session does not have spatial audio capabilities
}

ประเด็นสำคัญเกี่ยวกับโค้ด

เพิ่มสนามเสียงแบบแอมบิโซนิกในแอป

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

ตัวอย่างเสียงแบบแอมบิโซนิก

ตัวอย่างต่อไปนี้จะเล่นสนามเสียงแบบแอมบิโซนิกโดยใช้ MediaPlayer

// Check spatial capabilities before using spatial audio
if (session.scene.spatialCapabilities.contains(SpatialCapability.SPATIAL_AUDIO)) {
    // The session has spatial audio capabilities

    val soundFieldAttributes =
        SoundFieldAttributes(SpatializerConstants.AmbisonicsOrder.FIRST_ORDER)

    val mediaPlayer = MediaPlayer()

    val soundFieldAudio = appContext.assets.openFd("sounds/foa_basketball_16bit.wav")

    mediaPlayer.reset()
    mediaPlayer.setDataSource(soundFieldAudio)

    val audioAttributes =
        AudioAttributes.Builder()
            .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
            .setUsage(AudioAttributes.USAGE_MEDIA)
            .build()

    SpatialMediaPlayer.setSoundFieldAttributes(
        session,
        mediaPlayer,
        soundFieldAttributes
    )

    mediaPlayer.setAudioAttributes(audioAttributes)
    mediaPlayer.prepare()
    mediaPlayer.start()
} else {
    // The session does not have spatial audio capabilities
}

ประเด็นสำคัญเกี่ยวกับโค้ด

  • เช่นเดียวกับข้อมูลโค้ดก่อนหน้า ขั้นตอนแรกคือการตรวจสอบว่าความสามารถด้านเสียงรอบทิศทาง พร้อมใช้งานหรือไม่โดยใช้ hasCapability()
  • contentType และการใช้งานเป็นเพียงข้อมูลเท่านั้น
  • AMBISONICS_ORDER_FIRST_ORDER จะส่งสัญญาณไปยัง SceneCore ว่าไฟล์สนามเสียง กำหนดช่องสัญญาณ 4 ช่อง