دو یا چند برنامه اندروید می توانند صدا را به طور همزمان در یک جریان خروجی پخش کنند و سیستم همه چیز را با هم ترکیب می کند. اگرچه این از نظر فنی قابل توجه است، اما می تواند برای کاربر بسیار آزاردهنده باشد. برای جلوگیری از پخش همزمان هر برنامه موسیقی، اندروید ایده فوکوس صوتی را معرفی می کند. فقط یک برنامه میتواند فوکوس صوتی را در یک زمان نگه دارد.
وقتی برنامه شما نیاز به خروجی صدا دارد، باید فوکوس صوتی را درخواست کند. وقتی فوکوس داشته باشد، می تواند صدا را پخش کند. با این حال، پس از به دست آوردن فوکوس صوتی، ممکن است نتوانید آن را تا زمانی که بازی را تمام کنید حفظ کنید. برنامه دیگری میتواند فوکوس را درخواست کند، که مانع از توقف فوکوس صوتی شما میشود. اگر این اتفاق بیفتد، برنامه شما باید پخش را متوقف کند یا صدای آن را کاهش دهد تا کاربران راحتتر منبع صوتی جدید را بشنوند.
قبل از Android 12 (سطح API 31)، فوکوس صوتی توسط سیستم مدیریت نمیشود. بنابراین، در حالی که توسعهدهندگان برنامه تشویق میشوند از دستورالعملهای فوکوس صوتی پیروی کنند، اگر برنامهای حتی پس از از دست دادن فوکوس صوتی در دستگاهی که دارای Android 11 (سطح API 30) یا پایینتر است، به پخش با صدای بلند ادامه دهد، سیستم نمیتواند از آن جلوگیری کند. با این حال، این رفتار برنامه منجر به تجربه کاربری بدی میشود و اغلب کاربران را به حذف نصب برنامه نادرست سوق میدهد.
یک برنامه صوتی با طراحی خوب باید فوکوس صوتی را طبق این دستورالعملهای کلی مدیریت کند:
بلافاصله قبل از شروع پخش،
requestAudioFocus()
را فراخوانی کنید و بررسی کنید که تماسAUDIOFOCUS_REQUEST_GRANTED
برمی گردد. در پاسخ به تماسonPlay()
جلسه رسانه خود، باrequestAudioFocus()
تماس بگیرید.وقتی برنامه دیگری فوکوس صوتی را به دست آورد، پخش را متوقف یا مکث کنید، یا صدا را کاهش دهید (یعنی کاهش دهید).
وقتی پخش متوقف شد (مثلاً وقتی برنامه چیزی برای پخش ندارد)، فوکوس صوتی را رها کنید. اگر کاربر پخش را متوقف کند، برنامه شما مجبور نیست فوکوس صوتی را رها کند، اما ممکن است بعداً پخش را از سر بگیرد.
از
AudioAttributes
برای توصیف نوع صدایی که برنامه شما پخش می کند استفاده کنید. برای مثال، برای برنامههایی که گفتار پخش میکنند،CONTENT_TYPE_SPEECH
را مشخص کنید.
با توجه به نسخه اندرویدی که در حال اجرا است، فوکوس صوتی متفاوت است:
- Android 12 (سطح API 31) یا جدیدتر
- فوکوس صوتی توسط سیستم مدیریت می شود. هنگامی که برنامه دیگری فوکوس صوتی را درخواست می کند، سیستم پخش صدا را از یک برنامه مجبور می کند تا محو شود. این سیستم همچنین پخش صدا را هنگام دریافت تماس دریافتی قطع می کند.
- اندروید 8.0 (سطح API 26) تا اندروید 11 (سطح API 30)
- فوکوس صوتی توسط سیستم مدیریت نمیشود، اما شامل تغییراتی است که با شروع اندروید 8.0 (سطح API 26) معرفی شدهاند.
- اندروید 7.1 (سطح API 25) و پایین تر
- فوکوس صوتی توسط سیستم مدیریت نمیشود و برنامهها فوکوس صوتی را با استفاده از
requestAudioFocus()
وabandonAudioFocus()
مدیریت میکنند.
فوکوس صوتی در اندروید 12 و بالاتر
یک برنامه رسانه یا بازی که از فوکوس صوتی استفاده می کند نباید پس از از دست دادن فوکوس صدا را پخش کند. در اندروید 12 (سطح API 31) و بالاتر، سیستم این رفتار را اعمال می کند. هنگامی که یک برنامه فوکوس صوتی را درخواست می کند در حالی که برنامه دیگری فوکوس دارد و در حال پخش است، سیستم برنامه پخش را مجبور می کند تا محو شود. افزودن حالت محو شدن، انتقال نرمتری را هنگام رفتن از یک برنامه به برنامه دیگر فراهم میکند.
این رفتار محو شدن زمانی اتفاق می افتد که شرایط زیر برآورده شود:
اولین برنامه ای که در حال حاضر در حال پخش است، همه این معیارها را برآورده می کند:
- این برنامه دارای ویژگی استفاده
AudioAttributes.USAGE_MEDIA
یاAudioAttributes.USAGE_GAME
است. - برنامه با موفقیت فوکوس صوتی را با
AudioManager.AUDIOFOCUS_GAIN
درخواست کرد. - برنامه صدا با نوع محتوای
AudioAttributes.CONTENT_TYPE_SPEECH
را پخش نمیکند.CONTENT_TYPE_SPEECH.
- این برنامه دارای ویژگی استفاده
برنامه دوم فوکوس صوتی را با
AudioManager.AUDIOFOCUS_GAIN
درخواست میکند.
هنگامی که این شرایط برآورده می شود، سیستم صوتی اولین برنامه را محو می کند. در پایان محو شدن، سیستم اولین برنامه را از از دست دادن فوکوس مطلع می کند. پخشکنندههای برنامه بیصدا میمانند تا زمانی که برنامه دوباره فوکوس صوتی را درخواست کند.
رفتارهای تمرکز صوتی موجود
همچنین باید از این موارد دیگر که شامل سوئیچ در فوکوس صوتی است نیز آگاه باشید.
اردک خودکار
داکینگ خودکار (به طور موقت سطح صدای یک برنامه را کاهش می دهد تا برنامه دیگر به وضوح شنیده شود) در اندروید 8.0 (سطح API 26) معرفی شد.
با اجرای سیستم ducking، نیازی به پیاده سازی ducking در برنامه خود ندارید.
همچنین زمانی که یک اعلان صوتی فوکوس را از یک برنامه در حال پخش می گیرد، ducking خودکار رخ می دهد. شروع پخش اعلان با انتهای سطح شیب دار همگام می شود.
جوجه کشی خودکار زمانی اتفاق می افتد که شرایط زیر وجود داشته باشد:
اولین برنامه ای که در حال پخش است، همه این معیارها را برآورده می کند:
- این برنامه با موفقیت فوکوس صوتی را با هر نوع افزایش فوکوس درخواست کرد.
- برنامه صدا با نوع محتوای
AudioAttributes.CONTENT_TYPE_SPEECH
را پخش نمیکند.CONTENT_TYPE_SPEECH. - برنامه
AudioFocusRequest.Builder.setWillPauseWhenDucked(true)
را تنظیم نکرده است.
برنامه دوم فوکوس صوتی را با
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
درخواست میکند.
هنگامی که این شرایط برآورده می شود، سیستم صوتی همه پخش کننده های فعال برنامه اول را حذف می کند در حالی که برنامه دوم فوکوس دارد. هنگامی که برنامه دوم فوکوس را رها می کند، آنها را از بین می برد. اولین برنامه زمانی که تمرکز خود را از دست می دهد مطلع نمی شود، بنابراین نیازی به انجام کاری ندارد.
توجه داشته باشید که زمانی که کاربر در حال گوش دادن به محتوای گفتاری است، داک کردن خودکار انجام نمی شود، زیرا ممکن است کاربر برخی از برنامه را از دست بدهد. به عنوان مثال، راهنمای صوتی برای مسیرهای رانندگی نادیده گرفته می شود.
پخش صدای فعلی را برای تماس های تلفنی دریافتی قطع کنید
برخی از برنامهها به درستی عمل نمیکنند و در طول تماسهای تلفنی به پخش صدا ادامه میدهند. این وضعیت کاربر را مجبور میکند تا اپلیکیشن توهینآمیز را پیدا کند و بیصدا کند یا از آن خارج شود تا تماس خود را بشنود. برای جلوگیری از این امر، سیستم می تواند صدای برنامه های دیگر را در زمانی که تماس دریافتی وجود دارد، قطع کند. هنگامی که یک تماس تلفنی دریافتی دریافت می شود و یک برنامه دارای شرایط زیر است، سیستم این ویژگی را فرا می خواند:
- این برنامه دارای ویژگی استفاده
AudioAttributes.USAGE_MEDIA
یاAudioAttributes.USAGE_GAME
است. - برنامه با موفقیت فوکوس صوتی (هر گونه افزایش فوکوس) را درخواست کرد و در حال پخش صدا است.
اگر برنامه ای در حین تماس به پخش ادامه دهد، پخش آن تا پایان تماس قطع می شود. با این حال، اگر برنامهای در حین تماس شروع به پخش کند، با این فرض که کاربر عمداً پخش را شروع کرده است، پخشکننده خاموش نمیشود.
فوکوس صوتی در اندروید 8.0 تا اندروید 11
با شروع Android 8.0 (سطح API 26)، هنگام فراخوانی requestAudioFocus()
باید یک پارامتر AudioFocusRequest
ارائه دهید. AudioFocusRequest
حاوی اطلاعاتی درباره زمینه صوتی و قابلیت های برنامه شما است. سیستم از این اطلاعات برای مدیریت افزایش و از دست دادن فوکوس صوتی به صورت خودکار استفاده می کند. برای انتشار فوکوس صوتی، متد abandonAudioFocusRequest()
را فراخوانی کنید که یک AudioFocusRequest
را نیز به عنوان آرگومان خود در نظر می گیرد. از همان نمونه AudioFocusRequest
هم هنگام درخواست و هم در هنگام رها کردن فوکوس استفاده کنید.
برای ایجاد AudioFocusRequest
، از AudioFocusRequest.Builder
استفاده کنید. از آنجایی که یک درخواست فوکوس باید همیشه نوع درخواست را مشخص کند، نوع در سازنده برای سازنده گنجانده شده است. از متدهای سازنده برای تنظیم سایر فیلدهای درخواست استفاده کنید.
فیلد FocusGain
الزامی است. تمام فیلدهای دیگر اختیاری هستند.
روش | یادداشت ها |
---|---|
setFocusGain() | این فیلد در هر درخواست الزامی است. مقادیر مشابه durationHint استفاده شده در فراخوانی قبل از Android 8.0 برای requestAudioFocus() را می گیرد: AUDIOFOCUS_GAIN ، AUDIOFOCUS_GAIN_TRANSIENT ، AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK ، یا AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE . |
setAudioAttributes() | AudioAttributes کاربرد برنامه شما را شرح می دهد. زمانی که برنامه فوکوس صوتی را از دست میدهد، سیستم به آنها نگاه میکند. ویژگی ها جایگزین مفهوم نوع جریان می شوند. در Android 8.0 (سطح API 26) و جدیدتر، انواع پخش جریانی برای هر عملیاتی غیر از کنترلهای میزان صدا منسوخ شدهاند. از همان ویژگی هایی در درخواست فوکوس استفاده کنید که در پخش کننده صوتی خود استفاده می کنید (همانطور که در مثال زیر این جدول نشان داده شده است). ابتدا از یک اگر مشخص نشده باشد، |
setWillPauseWhenDucked() | وقتی برنامه دیگری فوکوس با AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK را درخواست میکند، برنامهای که فوکوس دارد معمولاً یک تماس onAudioFocusChange() دریافت نمیکند، زیرا سیستم میتواند به تنهایی کار را انجام دهد . هنگامی که به جای کاهش صدا نیاز به توقف پخش دارید، setWillPauseWhenDucked(true) را فراخوانی کنید و یک OnAudioFocusChangeListener ایجاد و تنظیم کنید، همانطور که در ducking خودکار توضیح داده شده است. |
setAcceptsDelayedFocusGain() | هنگامی که فوکوس توسط برنامه دیگری قفل شود، درخواست فوکوس صوتی ممکن است با شکست مواجه شود. این روش فوکوس با تأخیر را فعال می کند: توانایی به دست آوردن فوکوس به صورت ناهمزمان هنگامی که در دسترس قرار می گیرد. توجه داشته باشید که افزایش تمرکز با تأخیر تنها در صورتی کار میکند که یک |
setOnAudioFocusChangeListener() | OnAudioFocusChangeListener فقط در صورتی مورد نیاز است که در درخواست willPauseWhenDucked(true) یا setAcceptsDelayedFocusGain(true) نیز مشخص کنید. دو روش برای تنظیم شنونده وجود دارد: یکی با و دیگری بدون آرگومان کنترل کننده. کنترل کننده رشته ای است که شنونده بر روی آن حرکت می کند. اگر یک کنترل کننده را مشخص نکنید، از کنترل کننده مرتبط با |
مثال زیر نحوه استفاده از AudioFocusRequest.Builder
برای ساخت AudioFocusRequest
و درخواست و رها کردن فوکوس صوتی را نشان می دهد:
کاتلین
// initializing variables for audio focus and playback management audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager focusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN).run { setAudioAttributes(AudioAttributes.Builder().run { setUsage(AudioAttributes.USAGE_GAME) setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) build() }) setAcceptsDelayedFocusGain(true) setOnAudioFocusChangeListener(afChangeListener, handler) build() } val focusLock = Any() var playbackDelayed = false var playbackNowAuthorized = false // requesting audio focus and processing the response val res = audioManager.requestAudioFocus(focusRequest) synchronized(focusLock) { playbackNowAuthorized = when (res) { AudioManager.AUDIOFOCUS_REQUEST_FAILED -> false AudioManager.AUDIOFOCUS_REQUEST_GRANTED -> { playbackNow() true } AudioManager.AUDIOFOCUS_REQUEST_DELAYED -> { playbackDelayed = true false } else -> false } } // implementing OnAudioFocusChangeListener to react to focus changes override fun onAudioFocusChange(focusChange: Int) { when (focusChange) { AudioManager.AUDIOFOCUS_GAIN -> if (playbackDelayed || resumeOnFocusGain) { synchronized(focusLock) { playbackDelayed = false resumeOnFocusGain = false } playbackNow() } AudioManager.AUDIOFOCUS_LOSS -> { synchronized(focusLock) { resumeOnFocusGain = false playbackDelayed = false } pausePlayback() } AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> { synchronized(focusLock) { // only resume if playback is being interrupted resumeOnFocusGain = isPlaying() playbackDelayed = false } pausePlayback() } AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> { // ... pausing or ducking depends on your app } } }
جاوا
// initializing variables for audio focus and playback management audioManager = (AudioManager) Context.getSystemService(Context.AUDIO_SERVICE); playbackAttributes = new AudioAttributes.Builder() .setUsage(AudioAttributes.USAGE_GAME) .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) .build(); focusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN) .setAudioAttributes(playbackAttributes) .setAcceptsDelayedFocusGain(true) .setOnAudioFocusChangeListener(afChangeListener, handler) .build(); final Object focusLock = new Object(); boolean playbackDelayed = false; boolean playbackNowAuthorized = false; // requesting audio focus and processing the response int res = audioManager.requestAudioFocus(focusRequest); synchronized(focusLock) { if (res == AudioManager.AUDIOFOCUS_REQUEST_FAILED) { playbackNowAuthorized = false; } else if (res == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { playbackNowAuthorized = true; playbackNow(); } else if (res == AudioManager.AUDIOFOCUS_REQUEST_DELAYED) { playbackDelayed = true; playbackNowAuthorized = false; } } // implementing OnAudioFocusChangeListener to react to focus changes @Override public void onAudioFocusChange(int focusChange) { switch (focusChange) { case AudioManager.AUDIOFOCUS_GAIN: if (playbackDelayed || resumeOnFocusGain) { synchronized(focusLock) { playbackDelayed = false; resumeOnFocusGain = false; } playbackNow(); } break; case AudioManager.AUDIOFOCUS_LOSS: synchronized(focusLock) { resumeOnFocusGain = false; playbackDelayed = false; } pausePlayback(); break; case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: synchronized(focusLock) { // only resume if playback is being interrupted resumeOnFocusGain = isPlaying(); playbackDelayed = false; } pausePlayback(); break; case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: // ... pausing or ducking depends on your app break; } } }
اردک خودکار
در Android 8.0 (سطح API 26)، هنگامی که برنامه دیگری درخواست فوکوس با AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
را میکند، سیستم میتواند صدا را بدون فراخوانی پاسخ تماس onAudioFocusChange()
آن را کاهش داده و بازیابی کند.
در حالی که دویدن خودکار برای برنامههای پخش موسیقی و ویدیو قابل قبول است، اما هنگام پخش محتوای گفتاری، مانند برنامههای کتاب صوتی، مفید نیست. در این حالت، برنامه باید به جای آن مکث کند.
اگر میخواهید از برنامهتان بهجای کاهش حجم صدا، زمانی که از برنامهتان خواسته میشود مکث کند، یک OnAudioFocusChangeListener
با یک onAudioFocusChange()
ایجاد کنید که رفتار مکث/رزومه مورد نظر را پیادهسازی میکند. برای ثبت شنونده، setOnAudioFocusChangeListener()
را صدا کنید و setWillPauseWhenDucked(true)
را فراخوانی کنید تا به سیستم بگویید به جای اجرای خودکار ducking از پاسخ تماس شما استفاده کند.
افزایش تمرکز با تاخیر
گاهی اوقات سیستم نمیتواند درخواستی برای فوکوس صوتی بدهد زیرا فوکوس توسط برنامه دیگری قفل میشود، مثلاً در حین تماس تلفنی. در این مورد، requestAudioFocus()
AUDIOFOCUS_REQUEST_FAILED
را برمی گرداند. هنگامی که این اتفاق می افتد، برنامه شما نباید به پخش صدا ادامه دهد زیرا تمرکز نمی کند.
روش، setAcceptsDelayedFocusGain(true)
، که به برنامه شما امکان می دهد درخواست فوکوس را به صورت ناهمزمان انجام دهد. با این مجموعه پرچم، درخواستی که وقتی فوکوس قفل است، AUDIOFOCUS_REQUEST_DELAYED
را برمیگرداند. هنگامی که شرایطی که فوکوس صوتی را قفل کرده است دیگر وجود نداشته باشد، مانند زمانی که یک تماس تلفنی به پایان می رسد، سیستم درخواست فوکوس معلق را می دهد و با onAudioFocusChange()
تماس می گیرد تا به برنامه شما اطلاع دهد.
برای کنترل تمرکز تأخیر، باید یک OnAudioFocusChangeListener
با متد onAudioFocusChange()
ایجاد کنید که رفتار مورد نظر را پیاده سازی کند و شنونده را با فراخوانی setOnAudioFocusChangeListener()
ثبت کند.
فوکوس صوتی در اندروید 7.1 و پایین تر
هنگام فراخوانی requestAudioFocus()
باید یک اشاره مدت زمان مشخص کنید، که ممکن است توسط برنامه دیگری که در حال حاضر فوکوس را نگه داشته و پخش می کند، مشخص شود:
- هنگامی که میخواهید صدا را برای آینده قابل پیشبینی پخش کنید (مثلاً هنگام پخش موسیقی) و انتظار دارید که دارنده قبلی فوکوس صوتی پخش را متوقف کند، فوکوس صوتی دائمی (
AUDIOFOCUS_GAIN
) را درخواست کنید. - زمانی که انتظار دارید صدا را فقط برای مدت کوتاهی پخش کنید و انتظار دارید دارنده قبلی پخش را متوقف کند، فوکوس موقت (
AUDIOFOCUS_GAIN_TRANSIENT
) را درخواست کنید. - فوکوس گذرا با داکینگ (
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
) را درخواست کنید تا نشان دهد که انتظار دارید فقط برای مدت کوتاهی صدا پخش شود و اگر صاحب فوکوس قبلی صدای خروجی خود را کاهش دهد (کاهش دهد) خوب است به پخش ادامه دهد. هر دو خروجی صدا در جریان صدا ترکیب می شوند. داکینگ مخصوصاً برای برنامههایی که از جریان صوتی به طور متناوب استفاده میکنند، مانند مسیرهای رانندگی قابل شنیدن، مناسب است.
متد requestAudioFocus()
نیز به AudioManager.OnAudioFocusChangeListener
نیاز دارد. این شنونده باید در همان فعالیت یا سرویسی ایجاد شود که دارای جلسه رسانه شما است. این فراخوانی onAudioFocusChange()
را اجرا می کند که برنامه شما زمانی که برنامه دیگری فوکوس صوتی را بدست می آورد یا رها می کند، دریافت می کند.
قطعه زیر فوکوس دائمی صوتی را روی جریان STREAM_MUSIC
درخواست میکند و یک OnAudioFocusChangeListener
را برای مدیریت تغییرات بعدی در فوکوس صوتی ثبت میکند. (شنونده تغییر در پاسخ به تغییر فوکوس صوتی بحث شده است.)
کاتلین
audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager lateinit var afChangeListener AudioManager.OnAudioFocusChangeListener ... // Request audio focus for playback val result: Int = audioManager.requestAudioFocus( afChangeListener, // Use the music stream. AudioManager.STREAM_MUSIC, // Request permanent focus. AudioManager.AUDIOFOCUS_GAIN ) if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { // Start playback }
جاوا
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); AudioManager.OnAudioFocusChangeListener afChangeListener; ... // Request audio focus for playback int result = audioManager.requestAudioFocus(afChangeListener, // Use the music stream. AudioManager.STREAM_MUSIC, // Request permanent focus. AudioManager.AUDIOFOCUS_GAIN); if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { // Start playback }
پس از اتمام پخش، abandonAudioFocus()
را فراخوانی کنید.
کاتلین
audioManager.abandonAudioFocus(afChangeListener)
جاوا
// Abandon audio focus when playback complete audioManager.abandonAudioFocus(afChangeListener);
این به سیستم اطلاع میدهد که دیگر نیازی به تمرکز ندارید و OnAudioFocusChangeListener
مرتبط را لغو ثبت میکند. اگر فوکوس گذرا را درخواست کردید، به برنامهای که مکث کرده یا متوقف شده اطلاع میدهد که ممکن است به پخش ادامه دهد یا حجم آن را بازیابی کند.
پاسخ به تغییر فوکوس صوتی
هنگامی که یک برنامه فوکوس صوتی را بدست می آورد، باید بتواند زمانی که برنامه دیگری فوکوس صوتی را برای خود درخواست می کند، آن را آزاد کند. هنگامی که این اتفاق میافتد، برنامه شما با متد onAudioFocusChange()
در AudioFocusChangeListener
تماسی دریافت میکند که هنگام فراخوانی برنامه requestAudioFocus()
مشخص کردهاید.
پارامتر focusChange
که به onAudioFocusChange()
ارسال می شود، نوع تغییری را که در حال وقوع است نشان می دهد. این با اشاره به مدت زمان استفاده شده توسط برنامه ای که تمرکز دارد مطابقت دارد. برنامه شما باید به درستی پاسخ دهد.
- از دست دادن گذرا تمرکز
- اگر تغییر فوکوس گذرا باشد (
AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK
یاAUDIOFOCUS_LOSS_TRANSIENT
)، برنامه شما باید متوقف شود (اگر به داک خودکار متکی نیستید) یا پخش را متوقف کند، اما در غیر این صورت همان حالت را حفظ کند.در حین از دست دادن گذرا فوکوس صدا، باید به نظارت بر تغییرات فوکوس صوتی ادامه دهید و آماده باشید تا زمانی که فوکوس را دوباره به دست آوردید، پخش عادی را از سر بگیرید. وقتی برنامه مسدودکننده فوکوس را رها میکند، یک تماس پاسخ دریافت میکنید (
AUDIOFOCUS_GAIN
). در این مرحله می توانید صدا را به سطح عادی برگردانید یا پخش را مجدداً شروع کنید. - از دست دادن دائمی تمرکز
- اگر از دست دادن فوکوس صدا دائمی باشد (
AUDIOFOCUS_LOSS
)، برنامه دیگری در حال پخش صدا است. برنامه شما باید فوراً پخش را متوقف کند، زیرا هرگز پاسخ تماسAUDIOFOCUS_GAIN
را دریافت نخواهد کرد. برای شروع مجدد پخش، کاربر باید یک اقدام صریح انجام دهد، مانند فشار دادن کنترل حمل و نقل پخش در یک اعلان یا رابط کاربری برنامه.
قطعه کد زیر نحوه پیاده سازی OnAudioFocusChangeListener
و onAudioFocusChange()
آن را نشان می دهد. به استفاده از Handler
برای به تاخیر انداختن توقف تماس در صورت از دست دادن دائمی فوکوس صوتی توجه کنید.
کاتلین
private val handler = Handler() private val afChangeListener = AudioManager.OnAudioFocusChangeListener { focusChange -> when (focusChange) { AudioManager.AUDIOFOCUS_LOSS -> { // Permanent loss of audio focus // Pause playback immediately mediaController.transportControls.pause() // Wait 30 seconds before stopping playback handler.postDelayed(delayedStopRunnable, TimeUnit.SECONDS.toMillis(30)) } AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> { // Pause playback } AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> { // Lower the volume, keep playing } AudioManager.AUDIOFOCUS_GAIN -> { // Your app has been granted audio focus again // Raise volume to normal, restart playback if necessary } } }
جاوا
private Handler handler = new Handler(); AudioManager.OnAudioFocusChangeListener afChangeListener = new AudioManager.OnAudioFocusChangeListener() { public void onAudioFocusChange(int focusChange) { if (focusChange == AudioManager.AUDIOFOCUS_LOSS) { // Permanent loss of audio focus // Pause playback immediately mediaController.getTransportControls().pause(); // Wait 30 seconds before stopping playback handler.postDelayed(delayedStopRunnable, TimeUnit.SECONDS.toMillis(30)); } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) { // Pause playback } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) { // Lower the volume, keep playing } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) { // Your app has been granted audio focus again // Raise volume to normal, restart playback if necessary } } };
کنترل کننده از یک Runnable
استفاده می کند که به شکل زیر است:
کاتلین
private var delayedStopRunnable = Runnable { mediaController.transportControls.stop() }
جاوا
private Runnable delayedStopRunnable = new Runnable() { @Override public void run() { getMediaController().getTransportControls().stop(); } };
برای اطمینان از اینکه در صورت شروع مجدد پخش توسط کاربر، توقف تاخیری شروع نمی شود، در پاسخ به هرگونه تغییر حالت، mHandler.removeCallbacks(mDelayedStopRunnable)
را فراخوانی کنید. برای مثال، removeCallbacks()
را در Callback onPlay()
, onSkipToNext()
و غیره فراخوانی کنید. همچنین باید این روش را در هنگام پاکسازی منابع مورد استفاده توسط سرویس خود در onDestroy()
سرویس خود فراخوانی کنید.