إضافة ميزة "الصوت المكاني" إلى تطبيق الواقع المعزّز

أجهزة XR المشمولة
تساعدك هذه الإرشادات في إنشاء تجارب لهذه الأنواع من أجهزة XR.
سماعات الرأس بنظام الواقع الممتد
نظارات سلكية بنظام الواقع الممتد

تمنحك ميزات الصوت المكاني في Jetpack SceneCore إمكانية إنشاء تجارب صوتية غامرة ضمن تطبيقات Android XR.

يحاكي الصوت المكاني كيفية إدراك المستخدمين للصوت في بيئة ثلاثية الأبعاد. ويمنحك إحساسًا بأنّ الصوت ينبعث من جميع الاتجاهات، بما في ذلك من أعلى المستخدم وأسفله. ويتم ذلك من خلال محاكاة مكبّر صوت افتراضي واحد أو أكثر في مواقع معيّنة في مساحة ثلاثية الأبعاد.

يتم تلقائيًا تحويل الصوت إلى صوت مكاني في Android XR للتطبيقات الحالية التي لم يتم تصميمها أو تعديلها لنظام Android XR. وأثناء تحرّك المستخدم في مساحته، سيصدر كل الصوت من التطبيق من اللوحة التي يتم عرض واجهة مستخدم التطبيق عليها. على سبيل المثال، إذا رنّ مؤقت من تطبيق ساعة، سيبدو الصوت وكأنّه صادر من موضع لوحة التطبيق. سيغيّر Android XR الصوت تلقائيًا لجعله أكثر واقعية من حيث الموضع. على سبيل المثال، ستؤثر المسافة التي يدركها المستخدم بين لوحة التطبيق والمستخدم بشكل طفيف في مستوى الصوت لزيادة الإحساس بالواقعية.

لمزيد من المعلومات حول كيفية عرض التطبيقات الحالية للصوت المكاني، يُرجى قراءة مقالة إضافة صوت الاستيريو والصوت المحيطي إلى تطبيقك على هذه الصفحة.

إذا كنت تعمل على تحسين تطبيقك لتجربة الواقع الممتد، يوفّر Jetpack SceneCore أدوات لتخصيص الصوت المكاني بشكل متقدّم. يمكنك تحديد موضع الأصوات بدقة في البيئة الثلاثية الأبعاد، واستخدام الصوت المحيطي لإنشاء حقول صوتية واقعية، والاستفادة من ميزة التكامل المضمّنة للصوت المحيطي.

أنواع الصوت المكاني المتاحة في Android XR

يتوافق Android XR مع الصوت الموضعي وصوت الاستيريو والصوت المحيطي والصوت المحيطي متعدد القنوات.

الصوت الموضعي

يمكن تحديد موضع الصوت الموضعي لتشغيله من نقطة معيّنة في مساحة ثلاثية الأبعاد. على سبيل المثال، يمكنك عرض نموذج ثلاثي الأبعاد لكلب ينبح في زاوية بيئتك الافتراضية. يمكنك أن تجعل عدة عناصر تصدر صوتًا من كل من مواضعها. لعرض الصوت الموضعي، يجب أن تكون الملفات أحادية أو ثنائية القنوات.

صوت الاستيريو والصوت المحيطي المحوَّلان إلى صوت مكاني

تتوافق منصة Android مع جميع تنسيقات الوسائط للصوت الموضعي وصوت الاستيريو و الصوت المحيطي. بالإضافة إلى هذه التنسيقات، قد تتيح أجهزة Android XR تنسيقات الصوت Dolby Atmos وDolby Digital وDolby Digital+‎.

يشير صوت الاستيريو إلى التنسيقات الصوتية التي تتضمّن قناتَين، ويشير الصوت المحيطي إلى التنسيقات الصوتية التي تتضمّن أكثر من قناتَين، مثل الصوت المحيطي 5.1 أو الصوت المحيطي 7.1 إعدادات. ترتبط بيانات الصوت لكل قناة بمكبّر صوت واحد. على سبيل المثال، عند تشغيل الموسيقى بصوت الاستيريو، قد يصدر من قناة مكبّر الصوت الأيسر مسارات آلات مختلفة عن تلك التي تصدر من القناة اليمنى.

يُستخدم الصوت المحيطي غالبًا في الأفلام والبرامج التلفزيونية لتعزيز الواقعية والانغماس من خلال استخدام قنوات متعدّدة لمكبّرات الصوت. على سبيل المثال، غالبًا ما يتم تشغيل الحوار من قناة مكبّر الصوت المركزي، بينما قد يستخدم صوت طائرة هليكوبتر تحلق قنوات مختلفة بالتسلسل لمنحك الإحساس بأنّ الطائرة تحلق حول مساحتك الثلاثية الأبعاد.

الصوت المحيطي متعدد القنوات

يشبه الصوت المحيطي متعدد القنوات (أو الصوت المحيطي) صندوق السماء للصوت، ما يوفّر مشهدًا صوتيًا غامرًا للمستخدمين. يمكنك استخدام الصوت المحيطي متعدد القنوات للأصوات البيئية في الخلفية أو في سيناريوهات أخرى تريد فيها تكرار حقل صوتي كروي كامل يحيط بالمتتبِّع. يتوافق Android XR مع تنسيق الصوت المحيطي متعدد القنوات AmbiX في الصوت المحيطي متعدد القنوات من الدرجة الأولى والثانية والثالثة. ننصحك باستخدام أنواع الملفات Opus ‏ (.ogg) و PCM/Wave ‏ (.wav).

استخدام الصوت المكاني مع Jetpack SceneCore

يتضمّن تنفيذ الصوت المكاني باستخدام Jetpack SceneCore التحقّق من الإمكانات المكانية واختيار واجهة برمجة تطبيقات لتحميل الصوت المكاني.

التحقّق من الإمكانات المكانية

قبل استخدام ميزات الصوت المكاني، تأكَّد من أنّ Session يتيح استخدام الصوت المكاني. في جميع مقتطفات الرموز البرمجية في الأقسام التالية، يتم التحقّق من الإمكانات قبل محاولة تشغيل الصوت المحوَّل إلى صوت مكاني.

تحميل الصوت المكاني

يمكنك استخدام أي من واجهات برمجة التطبيقات التالية لتحميل الصوت المكاني لاستخدامه في Jetpack SceneCore.

  • SoundPool: مثالية للمؤثرات الصوتية القصيرة التي يقل حجمها عن ميغابايت واحد، ويتم تحميلها مسبقًا ويمكن استخدام الأصوات بشكل متكرّر. هذه طريقة رائعة لتحميل الصوت من أجل الصوت الموضعي.
  • ExoPlayer: مثالية لتحميل محتوى صوت الاستيريو والصوت المحيطي، مثل الموسيقى والفيديو. تتيح أيضًا تشغيل الوسائط في الخلفية.
  • MediaPlayer: توفّر أبسط طريقة لتحميل الصوت المحيطي متعدد القنوات.
  • AudioTrack: توفّر أكبر قدر من التحكّم في كيفية تحميل البيانات الصوتية. تتيح كتابة المخازن المؤقتة للصوت مباشرةً أو إذا كنت قد ركّبت أو فككت ترميز ملفاتك الصوتية.

التحقّق من إمكانية استخدام تنسيق الوسائط

تتيح منصة Android بعض تنسيقات الوسائط المدعومة. ومع ذلك، قد يتيح جهاز Android XR معيّن تنسيقات إضافية، مثل Dolby Atmos. للاستعلام عن إمكانية استخدام تنسيق الوسائط، استخدِم ExoPlayer's AudioCapabilities:

val audioCapabilities = AudioCapabilities.getCapabilities(context, androidx.media3.common.AudioAttributes.DEFAULT, null)
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 في مساحة ثلاثية الأبعاد. يمكنك استدعاء setPointSourceParams على الـ SpatialMediaPlayer لضبط الـ PointSourceParams و الـ entity المرتبط به على مثيل MediaPlayer.

مثال على الصوت الموضعي

يحمّل المثال التالي ملفًا صوتيًا للمؤثرات الصوتية في مجموعة صوتية ويشغّله في موضع 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(entity)

    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,
                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` على 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(session.scene.mainPanelEntity)

    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
    )

    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 و`usage` هما معلومات فقط.
  • يشير AMBISONICS_ORDER_FIRST_ORDER إلى SceneCore بأنّ ملف الحقل الصوتي يحدّد أربع قنوات.