"الصوت المكاني" هو تجربة صوتية غامرة تضع المستخدمين في قلب الحدث، ما يجعل الصوت في المحتوى أكثر واقعية. يتم "توزيع" الصوت لإنشاء تأثير مكبّرات صوت متعددة، على غرار إعداد الصوت المحيطي، ولكن من خلال سمّاعات الرأس بدلاً من ذلك.
على سبيل المثال، في فيلم، قد يبدأ صوت سيارة من خلف المستخدم، ثم يتحرّك إلى الأمام، ويتلاشى في المسافة البعيدة. في محادثة فيديو، يمكن فصل الأصوات وتوزيعها حول المستخدم، ما يسهّل التعرّف على المتحدّثين.
إذا كان المحتوى الخاص بك يستخدم تنسيق صوت متوافقًا، يمكنك إضافة ميزة "الصوت المكاني" إلى تطبيقك بدءًا من Android 13 (المستوى 33 لواجهة برمجة التطبيقات).
طلب البحث عن الإمكانات
استخدِم فئة Spatializer
للاستعلام عن إمكانات الجهاز وسلوكه في ما يتعلّق بالصوت المكاني. ابدأ باسترداد نسخة من Spatializer
من AudioManager
:
Kotlin
val spatializer = audioManager.spatializer
Java
Spatializer spatializer = AudioManager.getSpatializer();
بعد الحصول على Spatializer
، تحقَّق من توفّر الشروط الأربعة التالية التي يجب أن تكون صحيحة
لكي يتمكّن الجهاز من إخراج صوت مكاني:
المعايير | شيك |
---|---|
هل يتيح الجهاز ميزة "تجسيم الصوت"؟ |
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)
حتى لا تتم معالجة الصوت مرتين. بدلاً من ذلك، يمكنك تعديل سلوك التجسيم لإيقافه تمامًا من خلال استدعاء setSpatializationBehavior(AudioAttributes.SPATIALIZATION_BEHAVIOR_NEVER)
.
AudioFormat
يصف العنصر AudioFormat
تفاصيل حول تنسيق المقطع الصوتي وإعدادات القناة.
عند إنشاء AudioFormat
لتمريره إلى canBeSpatialized()
،
اضبط الترميز
ليكون مطابقًا لتنسيق الإخراج المتوقّع من برنامج الترميز. عليك أيضًا ضبط قناع قناة يتطابق مع إعدادات قناة المحتوى. راجِع قسم السلوك التلقائي للتجسيم الصوتي للحصول على إرشادات حول القيم المحدّدة التي يجب استخدامها.
الاستماع إلى التغييرات في Spatializer
للاستماع إلى التغييرات في حالة Spatializer
، يمكنك إضافة أداة معالجة باستخدام Spatializer.addOnSpatializerStateChangedListener()
.
وبالمثل، للاستماع إلى التغييرات في مدى توفّر أداة تتبُّع حركة الرأس، استخدِم الدالة Spatializer.addOnHeadTrackerAvailableListener()
.
يمكن أن يكون ذلك مفيدًا إذا كنت تريد تعديل اختيار الأغنية أثناء التشغيل
باستخدام عمليات معاودة الاتصال الخاصة بالمستمع. على سبيل المثال، عندما يوصّل المستخدم سماعة الرأس بالجهاز أو يفصلها عنه، يشير رد الاتصال onSpatializerAvailableChanged
إلى ما إذا كان تأثير الصوت المكاني متاحًا لتوجيه إخراج الصوت الجديد. في هذه المرحلة، يمكنك تعديل منطق اختيار المسار الخاص بالمشغّل ليتوافق مع الإمكانات الجديدة للجهاز. للحصول على تفاصيل حول سلوك اختيار المقاطع الصوتية في ExoPlayer، يُرجى الرجوع إلى قسم ExoPlayer والصوت المكاني.
ExoPlayer والصوت المكاني
تسهّل الإصدارات الأخيرة من ExoPlayer استخدام الصوت المكاني. إذا كنت تستخدم مكتبة ExoPlayer المستقلة (اسم الحزمة com.google.android.exoplayer2
)، يضبط الإصدار 2.17 النظام الأساسي لإخراج صوت مكاني، ويقدّم الإصدار 2.18 قيودًا على عدد القنوات الصوتية.
إذا كنت تستخدم وحدة ExoPlayer من مكتبة Media3 (اسم الحزمة
androidx.media3
)، تتضمّن الإصدارات 1.0.0-beta01
والإصدارات الأحدث هذه التحديثات نفسها.
بعد تعديل تبعية ExoPlayer إلى أحدث إصدار، ما عليك سوى تضمين محتوى يمكن تحويله إلى صوت مكاني في تطبيقك.
قيود عدد القنوات الصوتية
عند استيفاء جميع الشروط الأربعة المتعلقة بالصوت المكاني، يختار 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 السلوكيات التالية التي يمكن لمصنّعي المعدات الأصلية تخصيصها:
يتم تحويل المحتوى المتعدد القنوات إلى صوت مكاني، وليس المحتوى المجسم. إذا كنت لا تستخدم 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. لإيقاف ميزة "تجسيم الصوت" بنفسك، بغض النظر عن التخصيص الذي يوفّره مصنّع المعدات الأصلية، اطّلِع على إيقاف ميزة "الصوت المكاني".
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)