التركيز على الصوت

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

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

التفاعلات التي تركّز على

لتلبية احتياجات AAOS، تتم معالجة طلبات تركيز الصوت استنادًا إلى التفاعلات المحدّدة مسبقًا بين CarAudioContext للطلب وCarAudioContext لمالكي تركيز الصوت الحاليين. هناك ثلاثة أنواع من التفاعلات: حصرية ورفض ومتزامنة.

تفاعل حصري

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

رفض التفاعل

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

التفاعل المتزامن

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

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

التعامل مع أحداث البث المتزامنة

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

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

مصفوفة التفاعل

يعرض الجدول التالي مصفوفة التفاعل كما حدّدها CarAudioService. تمثّل الصفوف CarAudioContext لحامل التركيز الحالي، بينما تمثّل الأعمدة CarAudioContext للطلب الوافد.

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

بسبب التفاعلات المتزامنة، من الممكن أن يكون هناك أكثر من عنصر واحد يجذب انتباه المستخدمين. في هذه الحالة، تتم مقارنة طلب التركيز الوافد مع كل ملف شخصي حالي يحمل علامة "التركيز" قبل تحديد نوع التفاعل الذي سيتم تطبيقه. في هذه الحالة، يفوز التفاعل الأكثر تحفظًا (الرفض، ثم الحظر، ثم المنع المتزامن).

في الجدول التالي، يتم عرض تفاعلات التركيز بين CarAudioContext لطلب تركيز وارد (الأعمدة) وسياق حاملي التركيز الحاليين (الصفوف). تمثّل كل خلية نوع التفاعل المتوقّع للسياقَين.

التفاعلات مع ميزة "التركيز على الصوت"

الشكل 1: التفاعلات مع ميزة "التركيز على الصوت"

في Android 11، تمّ تقديم إعداد جديد للمستخدمين للسماح لهم بتغيير سلوك التفاعل بين التنقّل والمكالمات الهاتفية. عند ضبط القيمة android.car.KEY_AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL، تتغيّر التفاعل بين طلبات التركيز الواردة من NAVIGATION وأصحاب CALL الحاليين من متزامن إلى رفض. وبالتالي، إذا كان المستخدم يفضّل عدم مقاطعة مكالمته بتعليمات التنقّل، يمكنه تفعيل هذا الإعداد. ويتم الاحتفاظ بهذه القيمة للمستخدم، ويمكن ضبطها ديناميكيًا حتى تراعي طلبات التركيز اللاحقة قيمة الإعداد الجديدة.

ميزة "التركيز على الصوت" التي يمكن تأخيرها

في نظام Android 11، أضافت AAOS إمكانية طلب ميزة "التركيز على الصوت" التي يمكن تأخيرها. يتيح ذلك تأخير طلبات التركيز غير المؤقتة عندما يؤدي تفاعلها مع حائزي التركيز الحاليين عادةً إلى رفضها. بعد أن يؤدّي تغيير في التركيز إلى حالة يمكن فيها للطلب المتأخر الحصول على التركيز، يتم منحه.

قواعد طلبات التركيز على الصوت المتأخرة

  • الطلبات غير المؤقتة فقط: كما ذكرنا سابقًا، لا يمكن تقديم طلب متأخر إلا للمصادر غير المؤقتة. ويهدف ذلك إلى تجنُّب تشغيل صوت مؤقت بعد وقت طويل من انتهاء المقطع الذي يرتبط به.
  • يمكن تأخير طلب واحد فقط في كل مرة: إذا تم تقديم طلب قابل للتأخير عندما يكون هناك طلب متأخر، يتلقّى الطلب الأصلي المتأخر حدث تغيير AUDIOFOCUS_LOSS، ويتلقّى الطلب الجديد استجابة متزامنة AUDIOFOCUS_REQUEST_DELAYED.
  • يجب أن تتضمّن الطلبات التي يمكن تأخيرها OnAudioFocusChangeListener. بعد تأخير الطلب، يتم استخدام المستمع لإشعار مقدّم الطلب عند منح الطلب في نهاية المطاف (AUDIOFOCUS_GAIN)، أو إذا تم رفضه في وقت لاحق (AUDIOFOCUS_LOSS).

طلب التركيز الذي يمكن تأخيره

لإنشاء طلب يمكن تأخيره، استخدِم AudioFocusRequest.Builder#setAcceptsDelayedFocusGain:

mMediaWithDelayedFocusListener = new MediaWithDelayedFocusListener();

mDelayedFocusRequest = new AudioFocusRequest
     .Builder(AudioManager.AUDIOFOCUS_GAIN)
     .setAudioAttributes(mMusicAudioAttrib)
     .setOnAudioFocusChangeListener(mMediaWithDelayedFocusListener)
     .setForceDucking(false)
     .setWillPauseWhenDucked(false)
     .setAcceptsDelayedFocusGain(true)
     .build();

بعد ذلك، عند تقديم الطلب، عليك معالجة الردّ AUDIOFOCUS_REQUEST_DELAYED:

int delayedFocusRequestResults = mAudioManager.requestAudioFocus(mDelayedFocusRequest);
if (delayedFocusRequestResults == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
// start audio playback
return;
}
if (delayedFocusRequestResults == AudioManager.AUDIOFOCUS_REQUEST_DELAYED) {
     // audio playback delayed to audio focus listener
     return;
}

عندما يتأخّر الطلب، يكون مستمع التركيز مسؤولاً عن التعامل مع التغييرات في التركيز:

private final class MediaWithDelayedFocusListener implements
OnAudioFocusChangeListener {
       @Override
       public void onAudioFocusChange(int focusChange) {
           synchronized (mLock) {
               switch (focusChange) {
                   case AudioManager.AUDIOFOCUS_GAIN:
                        // Start focus playback
                   case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
                        // Pause media transiently
                   case AudioManager.AUDIOFOCUS_LOSS:
                        // Stop media

إدارة التركيز على مناطق متعدّدة

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

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

طلب الصوت من مناطق متعددة في الوقت نفسه

إذا أراد تطبيق تشغيل الصوت في مناطق متعدّدة في الوقت نفسه، يجب أن يطلب التركيز على كل منطقة من خلال تضمين AUDIOFOCUS_EXTRA_REQUEST_ZONE_ID في الحِزمة:

// Create attribute with bundle and AUDIOFOCUS_EXTRA_REQUEST_ZONE_ID
Bundle bundle = new Bundle();
bundle.putInt(CarAudioManager.AUDIOFOCUS_EXTRA_REQUEST_ZONE_ID,
               zoneId);

AudioAttributes attributesWithZone = new AudioAttributes.Builder()
     .setUsage(AudioAttributes.USAGE_MEDIA)
     .addBundle(bundle)
     .build();

// Create focus request using built attributesWithZone

تسمح مَعلمة الحِزمة هذه للمُقدّم بالتجاوز للتعيينات التلقائية لمناطق الصوت واستخدام معرّف المنطقة المحدّد بدلاً من ذلك. وبالتالي، يمكن للتطبيق تقديم طلبات منفصلة للمناطق الصوتية المختلفة.

التركيز على الصوت في HAL

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

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

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

AudioControl@2.0

يقدّم الإصدار 2.0 من AudioControl HAL العديد من واجهات برمجة التطبيقات الجديدة:

واجهة برمجة التطبيقات الغرض
IAudioControl#registerFocusListener تسجيل مثيل IFocusListener باستخدام AudioControl HAL يتيح هذا المستمع لوحدة HAL طلب تركيز الصوت والتخلي عنه. من المتوقّع أن يوفّر ICloseHandle مثيلًا ICloseHandle ليستخدمه Android لإلغاء تسجيل المستمع.
IAudioControl#onAudioFocusChange إرسال إشعارات إلى HAL بالتغييرات في حالة طلبات التركيز التي يقدّمها HAL من خلال العنصر IFocusListener ويشمل ذلك الردود على طلبات التركيز الأولية.
IFocusListener#requestAudioFocus تطلب HAL التركيز نيابةً عنها لاستخدام محدّد ورقم تعريف منطقة ونوع اكتساب تركيز محدّد.
IFocusListener#abandonAudioFocus يتخلّى عن طلبات التركيز الحالية في HAL للاستخدام والمعرّف المحدّدَين للمنطقة.

يمكن أن يتضمّن HAL طلبات تركيز متعددة في الوقت نفسه، ولكن يقتصر على طلب واحد لكل إقران بين الاستخدام ورقم تعريف المنطقة. يُرجى العِلم أنّ نظام التشغيل Android يفترض أنّ HAL يبدأ على الفور في تشغيل الأصوات لاستخدام معيّن بعد تقديم طلب، ويواصل ذلك إلى أن يتخلّى عن التركيز.

باستثناء registerFocusListener، تكون جميع هذه الطلبات oneway لضمان عدم تأخير Android لوحدة HAL أثناء معالجة طلب التركيز. يجب ألا ينتظر HAL اكتمال التركيز قبل تشغيل الأصوات المهمة للسلامة. ‫ يمكن أن يستمع HAL إلى التغييرات في تركيز الصوت ويستجيب لها من خلال IAudioControl#onAudioFocusChange، ولكن يُنصح بذلك عند الاقتضاء.