ऑडियो फ़ोकस को मैनेज करें

Android के दो या इससे ज़्यादा ऐप्लिकेशन, एक ही आउटपुट स्ट्रीम पर एक साथ ऑडियो चला सकते हैं. साथ ही, सिस्टम इन सभी को एक साथ मिक्स कर देता है. तकनीकी तौर पर यह सुविधा भले ही अच्छी हो, लेकिन इससे उपयोगकर्ता को काफ़ी परेशानी हो सकती है. एक ही समय पर सभी संगीत ऐप्लिकेशन के चलने से बचने के लिए, Android में ऑडियो फ़ोकस की सुविधा जोड़ी गई है. एक समय पर, सिर्फ़ एक ऐप्लिकेशन के पास ऑडियो फ़ोकस हो सकता है.

जब आपके ऐप्लिकेशन को ऑडियो आउटपुट करना हो, तो उसे ऑडियो फ़ोकस का अनुरोध करना चाहिए. फ़ोकस मिलने पर, वह आवाज़ चला सकता है. हालांकि, ऑडियो फ़ोकस पाने के बाद, हो सकता है कि आपके पास इसे तब तक बनाए रखने का विकल्प न हो, जब तक ऑडियो चलता रहे. कोई दूसरा ऐप्लिकेशन, फ़ोकस का अनुरोध कर सकता है. इससे आपके पास मौजूद ऑडियो फ़ोकस खत्म हो जाता है. ऐसा होने पर, आपके ऐप्लिकेशन को ऑडियो चलाना बंद कर देना चाहिए या उसकी आवाज़ कम कर देनी चाहिए, ताकि उपयोगकर्ता नए ऑडियो सोर्स को आसानी से सुन सकें.

Android 12 (एपीआई लेवल 31) से पहले, ऑडियो फ़ोकस को सिस्टम मैनेज नहीं करता था. इसलिए, ऐप्लिकेशन डेवलपर को ऑडियो फ़ोकस के दिशा-निर्देशों का पालन करने के लिए कहा जाता है. हालांकि, अगर Android 11 (एपीआई लेवल 30) या इससे पहले के वर्शन पर चलने वाले किसी डिवाइस पर, ऑडियो फ़ोकस खत्म होने के बाद भी कोई ऐप्लिकेशन तेज़ आवाज़ में चलता रहता है, तो सिस्टम उसे रोक नहीं सकता. हालांकि, ऐप्लिकेशन के इस रवैये से उपयोगकर्ता को खराब अनुभव मिलता है. साथ ही, अक्सर उपयोगकर्ता ऐसे ऐप्लिकेशन को अनइंस्टॉल कर देते हैं.

ऑडियो ऐप्लिकेशन को अच्छी तरह से डिज़ाइन किया जाना चाहिए. साथ ही, उसे ऑडियो फ़ोकस को इन सामान्य दिशा-निर्देशों के मुताबिक मैनेज करना चाहिए:

  • ऑडियो चलाना शुरू करने से ठीक पहले, requestAudioFocus() को कॉल करें और पुष्टि करें कि कॉल से AUDIOFOCUS_REQUEST_GRANTED मिलता है. अपने मीडिया सेशन के onPlay() कॉलबैक में, requestAudioFocus() को कॉल करें.

  • जब किसी दूसरे ऐप्लिकेशन को ऑडियो फ़ोकस मिलता है, तो ऑडियो चलाना बंद करें या रोकें. इसके अलावा, आवाज़ कम करें.

  • जब प्लेबैक बंद हो जाता है (उदाहरण के लिए, जब ऐप्लिकेशन के पास चलाने के लिए कुछ नहीं बचता), तो ऑडियो फ़ोकस छोड़ दें. अगर उपयोगकर्ता प्लेबैक को रोकता है, लेकिन बाद में प्लेबैक फिर से शुरू कर सकता है, तो आपके ऐप्लिकेशन को ऑडियो फ़ोकस छोड़ने की ज़रूरत नहीं है.

  • AudioAttributes का इस्तेमाल करके, यह बताएं कि आपका ऐप्लिकेशन किस तरह का ऑडियो चला रहा है. उदाहरण के लिए, आवाज़ चलाने वाले ऐप्लिकेशन के लिए, तय करें CONTENT_TYPE_SPEECH.

Android के वर्शन के हिसाब से, ऑडियो फ़ोकस को अलग-अलग तरीके से मैनेज किया जाता है:

Android 12 (एपीआई लेवल 31) या इसके बाद का वर्शन
ऑडियो फ़ोकस को सिस्टम मैनेज करता है. जब कोई दूसरा ऐप्लिकेशन, ऑडियो फ़ोकस का अनुरोध करता है, तो सिस्टम किसी ऐप्लिकेशन से ऑडियो प्लेबैक को फ़ेड आउट कर देता है. कॉल आने पर, सिस्टम ऑडियो प्लेबैक को म्यूट भी कर देता है.
Android 8.0 (एपीआई लेवल 26) से लेकर Android 11 (एपीआई लेवल 30) तक
ऑडियो फ़ोकस को सिस्टम मैनेज नहीं करता. हालांकि, इसमें Android 8.0 (एपीआई लेवल 26) से शुरू किए गए कुछ बदलाव शामिल हैं.
Android 7.1 (एपीआई लेवल 25) और इससे पहले के वर्शन
ऑडियो फ़ोकस को सिस्टम मैनेज नहीं करता. साथ ही, ऐप्लिकेशन, requestAudioFocus() और abandonAudioFocus() का इस्तेमाल करके ऑडियो फ़ोकस को मैनेज करते हैं.

Android 12 और इसके बाद के वर्शन में ऑडियो फ़ोकस

मीडिया या गेम ऐप्लिकेशन को ऑडियो फ़ोकस का इस्तेमाल करने के बाद, फ़ोकस खत्म होने पर ऑडियो नहीं चलाना चाहिए. Android 12 (एपीआई लेवल 31) और इसके बाद के वर्शन में, सिस्टम इस सेटिंग को लागू करता है. जब कोई ऐप्लिकेशन, ऑडियो फ़ोकस का अनुरोध करता है और किसी दूसरे ऐप्लिकेशन के पास फ़ोकस होता है और वह ऑडियो चला रहा होता है, तो सिस्टम, ऑडियो चला रहे ऐप्लिकेशन को फ़ेड आउट कर देता है. फ़ेड आउट की सुविधा जोड़ने से, एक ऐप्लिकेशन से दूसरे ऐप्लिकेशन पर जाने पर बेहतर ट्रांज़िशन मिलता है.

फ़ेड आउट की सुविधा तब काम करती है, जब ये शर्तें पूरी होती हैं:

  1. फ़िलहाल, ऑडियो चला रहा पहला ऐप्लिकेशन, इन सभी शर्तों को पूरा करता हो:

  2. कोई दूसरा ऐप्लिकेशन, AudioManager.AUDIOFOCUS_GAIN के साथ ऑडियो फ़ोकस का अनुरोध करता हो.

ये शर्तें पूरी होने पर, ऑडियो सिस्टम पहले ऐप्लिकेशन को फ़ेड आउट कर देता है. फ़ेड आउट होने के बाद, सिस्टम पहले ऐप्लिकेशन को फ़ोकस खत्म होने की सूचना देता है. जब तक ऐप्लिकेशन, ऑडियो फ़ोकस का अनुरोध नहीं करता, तब तक उसके प्लेयर म्यूट रहते हैं.

ऑडियो फ़ोकस के मौजूदा तरीके

आपको इन अन्य मामलों के बारे में भी पता होना चाहिए, जिनमें ऑडियो फ़ोकस में बदलाव होता है.

ऑटोमैटिक डकिंग

ऑटोमैटिक डकिंग (किसी एक ऐप्लिकेशन के ऑडियो लेवल को कुछ समय के लिए कम करना, ताकि दूसरे ऐप्लिकेशन का ऑडियो साफ़ तौर पर सुना जा सके) की सुविधा, Android 8.0 (एपीआई लेवल 26) में जोड़ी गई थी.

सिस्टम से डकिंग की सुविधा लागू कराने पर, आपको अपने ऐप्लिकेशन में डकिंग की सुविधा लागू नहीं करनी पड़ती.

ऑटोमैटिक डकिंग तब भी होती है, जब कोई ऑडियो सूचना, ऑडियो चला रहे ऐप्लिकेशन से फ़ोकस छीन लेती है. सूचना के प्लेबैक की शुरुआत, डकिंग रैंप के खत्म होने के साथ सिंक होती है.

ऑटोमैटिक डकिंग तब होती है, जब ये शर्तें पूरी होती हैं:

  1. फ़िलहाल, ऑडियो चला रहा पहला ऐप्लिकेशन, इन सभी शर्तों को पूरा करता हो:

    • ऐप्लिकेशन ने किसी भी तरह के फ़ोकस गेन के साथ ऑडियो फ़ोकस का अनुरोध किया हो.
    • ऐप्लिकेशन, AudioAttributes.CONTENT_TYPE_SPEECH कॉन्टेंट टाइप के साथ ऑडियो न चला रहा हो.
    • ऐप्लिकेशन ने AudioFocusRequest.Builder.setWillPauseWhenDucked(true) सेट न किया हो.
  2. कोई दूसरा ऐप्लिकेशन, AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK के साथ ऑडियो फ़ोकस का अनुरोध करता हो.

ये शर्तें पूरी होने पर, ऑडियो सिस्टम पहले ऐप्लिकेशन के सभी ऐक्टिव प्लेयर को डक कर देता है. ऐसा तब तक होता है, जब तक दूसरे ऐप्लिकेशन के पास फ़ोकस रहता है. जब दूसरा ऐप्लिकेशन, फ़ोकस छोड़ता है, तो वह उन्हें अनडक कर देता है. पहले ऐप्लिकेशन को फ़ोकस खत्म होने की सूचना नहीं मिलती. इसलिए, उसे कुछ करने की ज़रूरत नहीं होती.

ध्यान दें कि जब उपयोगकर्ता, आवाज़ वाला कॉन्टेंट सुन रहा होता है, तब ऑटोमैटिक डकिंग की सुविधा काम नहीं करती. ऐसा इसलिए, क्योंकि हो सकता है कि उपयोगकर्ता, प्रोग्राम का कुछ हिस्सा न सुन पाए. उदाहरण के लिए, ड्राइविंग के निर्देशों के लिए वॉइस गाइडेंस को डक नहीं किया जाता.

कॉल आने पर, फ़िलहाल चल रहे ऑडियो प्लेबैक को म्यूट करना

कुछ ऐप्लिकेशन ठीक से काम नहीं करते और कॉल के दौरान भी ऑडियो चलाते रहते हैं. इस स्थिति में, उपयोगकर्ता को कॉल सुनने के लिए, गड़बड़ी करने वाले ऐप्लिकेशन को ढूंढकर उसे म्यूट करना पड़ता है या बंद करना पड़ता है. इसे रोकने के लिए, सिस्टम, कॉल आने पर अन्य ऐप्लिकेशन के ऑडियो को म्यूट कर सकता है. जब कॉल आता है और कोई ऐप्लिकेशन इन शर्तों को पूरा करता है, तो सिस्टम इस सुविधा को लागू करता है:

  • ऐप्लिकेशन में, AudioAttributes.USAGE_MEDIA या AudioAttributes.USAGE_GAME का इस्तेमाल किया गया हो.
  • ऐप्लिकेशन ने ऑडियो फ़ोकस (किसी भी तरह का फ़ोकस गेन) का अनुरोध किया हो और वह ऑडियो चला रहा हो.

अगर कोई ऐप्लिकेशन, कॉल के दौरान ऑडियो चलाता रहता है, तो कॉल खत्म होने तक उसका प्लेबैक म्यूट रहता है. हालांकि, अगर कोई ऐप्लिकेशन, कॉल के दौरान ऑडियो चलाना शुरू करता है, तो उस प्लेयर को म्यूट नहीं किया जाता. ऐसा इसलिए, क्योंकि यह माना जाता है कि उपयोगकर्ता ने जान-बूझकर प्लेबैक शुरू किया है.

Android 8.0 से लेकर Android 11 तक में ऑडियो फ़ोकस

Android 8.0 (एपीआई लेवल 26) से शुरू होने वाले वर्शन में, requestAudioFocus() को कॉल करते समय, आपको AudioFocusRequest पैरामीटर देना होगा. AudioFocusRequest में, आपके ऐप्लिकेशन के ऑडियो कॉन्टेक्स्ट और क्षमताओं के बारे में जानकारी होती है. सिस्टम इस जानकारी का इस्तेमाल करके, ऑडियो फ़ोकस के गेन और लॉस को अपने-आप मैनेज करता है. ऑडियो फ़ोकस को रिलीज़ करने के लिए, तरीके को कॉल करें abandonAudioFocusRequest() जो अपने आर्ग्युमेंट के तौर पर AudioFocusRequest भी लेता है. फ़ोकस का अनुरोध करते और छोड़ते समय, AudioFocusRequest के एक ही इंस्टेंस का इस्तेमाल करें.

AudioFocusRequest बनाने के लिए, AudioFocusRequest.Builder का इस्तेमाल करें. चूंकि फ़ोकस के अनुरोध में, अनुरोध का टाइप हमेशा तय करना होता है. इसलिए, टाइप को बिल्डर के कंस्ट्रक्टर में शामिल किया जाता है. अनुरोध के अन्य फ़ील्ड सेट करने के लिए, बिल्डर के तरीकों का इस्तेमाल करें.

FocusGain फ़ील्ड ज़रूरी है. बाकी सभी फ़ील्ड ज़रूरी नहीं हैं.

तरीकानोट
setFocusGain() हर अनुरोध में यह फ़ील्ड ज़रूरी है. यह वही वैल्यू लेता है जो Android 8.0 से पहले के वर्शन में, durationHint को कॉल करने के लिए इस्तेमाल किए जाने वाले requestAudioFocus() में इस्तेमाल की जाती हैं: AUDIOFOCUS_GAIN, AUDIOFOCUS_GAIN_TRANSIENT, AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, या AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE.
setAudioAttributes() AudioAttributes से पता चलता है कि आपका ऐप्लिकेशन किस तरह के इस्तेमाल के लिए है. जब कोई ऐप्लिकेशन, ऑडियो फ़ोकस पाता है और छोड़ता है, तो सिस्टम इन पर नज़र रखता है. एट्रिब्यूट, स्ट्रीम टाइप की जगह लेते हैं. Android 8.0 (एपीआई लेवल 26) और इसके बाद के वर्शन में, वॉल्यूम कंट्रोल के अलावा किसी भी कार्रवाई के लिए स्ट्रीम टाइप काम नहीं करते. फ़ोकस के अनुरोध में, वही एट्रिब्यूट इस्तेमाल करें जो अपने ऑडियो प्लेयर में इस्तेमाल किए जाते हैं. इस टेबल के बाद दिए गए उदाहरण में, इसे दिखाया गया है.

सबसे पहले, एट्रिब्यूट तय करने के लिए AudioAttributes.Builder का इस्तेमाल करें. इसके बाद, अनुरोध में एट्रिब्यूट असाइन करने के लिए इस तरीके का इस्तेमाल करें.

अगर कोई एट्रिब्यूट तय नहीं किया जाता है, तो AudioAttributes डिफ़ॉल्ट तौर पर AudioAttributes.USAGE_MEDIA पर सेट होता है.

setWillPauseWhenDucked() जब कोई दूसरा ऐप्लिकेशन, AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK के साथ फ़ोकस का अनुरोध करता है, तो आम तौर पर फ़ोकस वाले ऐप्लिकेशन को onAudioFocusChange() कॉलबैक नहीं मिलता. ऐसा इसलिए, क्योंकि सिस्टम खुद ही डकिंग कर सकता है. जब आपको आवाज़ कम करने के बजाय प्लेबैक रोकना हो, तो setWillPauseWhenDucked(true) को कॉल करें. साथ ही, ऑटोमैटिक डकिंग में बताए गए तरीके से, OnAudioFocusChangeListener बनाएं और सेट करें.
setAcceptsDelayedFocusGain() ऑडियो फ़ोकस का अनुरोध तब पूरा नहीं हो सकता, जब फ़ोकस किसी दूसरे ऐप्लिकेशन ने लॉक किया हो. यह तरीका, फ़ोकस गेन में देरी की सुविधा चालू करता है. इसका मतलब है कि फ़ोकस उपलब्ध होने पर, एसिंक्रोनस तरीके से फ़ोकस पाया जा सकता है.

ध्यान दें कि फ़ोकस गेन में देरी की सुविधा सिर्फ़ तब काम करती है, जब ऑडियो के अनुरोध में AudioManager.OnAudioFocusChangeListener भी तय किया गया हो. ऐसा इसलिए, क्योंकि आपके ऐप्लिकेशन को यह जानने के लिए कॉलबैक मिलना ज़रूरी है कि फ़ोकस दिया गया है.

setOnAudioFocusChangeListener() OnAudioFocusChangeListener की ज़रूरत सिर्फ़ तब होती है, जब अनुरोध में willPauseWhenDucked(true) या setAcceptsDelayedFocusGain(true) भी तय किया गया हो.

लिसनर सेट करने के दो तरीके हैं: एक में हैंडलर आर्ग्युमेंट होता है और दूसरे में नहीं. हैंडलर वह थ्रेड होता है जिस पर लिसनर चलता है. अगर कोई हैंडलर तय नहीं किया जाता है, तो मुख्य Looper से जुड़ा हैंडलर इस्तेमाल किया जाता है.

यहां दिए गए उदाहरण में, AudioFocusRequest.Builder बनाने और एक AudioFocusRequest और ऑडियो फ़ोकस का अनुरोध करने और उसे छोड़ने के लिए, का इस्तेमाल करने का तरीका बताया गया है:

Kotlin

// 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
        }
    }
}

Java

// 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 (एपीआई लेवल 26) में, जब कोई दूसरा ऐप्लिकेशन, AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK के साथ फ़ोकस का अनुरोध करता है, तो सिस्टम, ऐप्लिकेशन के onAudioFocusChange() कॉलबैक को कॉल किए बिना, आवाज़ को डक और रीस्टोर कर सकता है.

ऑटोमैटिक डकिंग की सुविधा, संगीत और वीडियो प्लेबैक ऐप्लिकेशन के लिए ठीक है. हालांकि, यह सुविधा, आवाज़ वाला कॉन्टेंट चलाने पर काम की नहीं होती. जैसे, ऑडियो बुक ऐप्लिकेशन. इस मामले में, ऐप्लिकेशन को ऑडियो चलाने के बजाय उसे रोकना चाहिए.

अगर आपको आवाज़ कम करने के बजाय, डक करने के लिए कहे जाने पर अपने ऐप्लिकेशन को रोकना है, तो onAudioFocusChange() कॉलबैक वाले OnAudioFocusChangeListener को बनाएं. इसमें, रोकने/फिर से शुरू करने का तरीका लागू किया गया हो. लिसनर को रजिस्टर करने के लिए, setOnAudioFocusChangeListener() को कॉल करें. साथ ही, सिस्टम को ऑटोमैटिक डकिंग के बजाय, अपने कॉलबैक का इस्तेमाल करने के लिए बताने के लिए, setWillPauseWhenDucked(true) को कॉल करें.

फ़ोकस गेन में देरी

कभी-कभी सिस्टम, ऑडियो फ़ोकस के अनुरोध को पूरा नहीं कर पाता. ऐसा इसलिए, क्योंकि फ़ोकस किसी दूसरे ऐप्लिकेशन ने "लॉक" किया होता है. जैसे, कॉल के दौरान. इस मामले में, requestAudioFocus() से AUDIOFOCUS_REQUEST_FAILED मिलता है. ऐसा होने पर, आपके ऐप्लिकेशन को ऑडियो प्लेबैक जारी नहीं रखना चाहिए. ऐसा इसलिए, क्योंकि उसे फ़ोकस नहीं मिला.

तरीका, setAcceptsDelayedFocusGain(true), आपके ऐप्लिकेशन को एसिंक्रोनस तरीके से फ़ोकस के अनुरोध को हैंडल करने की अनुमति देता है. इस फ़्लैग के सेट होने पर, फ़ोकस लॉक होने पर किए गए अनुरोध से AUDIOFOCUS_REQUEST_DELAYED मिलता है. जब ऑडियो फ़ोकस को लॉक करने वाली शर्त मौजूद नहीं रहती, जैसे कि कॉल खत्म होने पर, सिस्टम, फ़ोकस के लंबित अनुरोध को पूरा करता है और आपके ऐप्लिकेशन को सूचना देने के लिए, onAudioFocusChange() को कॉल करता है.

फ़ोकस के गेन में देरी को हैंडल करने के लिए, आपको OnAudioFocusChangeListener को onAudioFocusChange() कॉलबैक वाले बनाना होगा. इसमें, मनचाहा तरीका लागू किया गया हो. साथ ही, setOnAudioFocusChangeListener() को कॉल करके लिसनर को रजिस्टर करना होगा.

Android 7.1 और इससे पहले के वर्शन में ऑडियो फ़ोकस

`requestAudioFocus()` को कॉल करते समय, आपको अवधि का हिंट तय करना होगा. इसका पालन, फ़िलहाल फ़ोकस रखने और ऑडियो चलाने वाले किसी दूसरे ऐप्लिकेशन को करना पड़ सकता है:requestAudioFocus()

  • ऑडियो फ़ोकस के लिए स्थायी अनुरोध (AUDIOFOCUS_GAIN) तब करें, जब आपको आने वाले समय में ऑडियो चलाना हो. जैसे, संगीत चलाते समय. साथ ही, आपको उम्मीद हो कि ऑडियो फ़ोकस का पिछला होल्डर, ऑडियो चलाना बंद कर देगा.
  • ऑडियो फ़ोकस के लिए अस्थायी अनुरोध (AUDIOFOCUS_GAIN_TRANSIENT) तब करें, जब आपको सिर्फ़ कुछ समय के लिए ऑडियो चलाना हो. साथ ही, आपको उम्मीद हो कि पिछला होल्डर, ऑडियो चलाना रोक देगा.
  • डकिंग (AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK) के साथ अस्थायी फ़ोकस का अनुरोध करें. इससे यह पता चलता है कि आपको सिर्फ़ कुछ समय के लिए ऑडियो चलाना है. साथ ही, अगर पिछला फ़ोकस ओनर, अपने ऑडियो आउटपुट को "डक" (कम) करता है, तो वह ऑडियो चला सकता है. दोनों ऑडियो आउटपुट को ऑडियो स्ट्रीम में मिक्स किया जाता है. डकिंग की सुविधा, उन ऐप्लिकेशन के लिए खास तौर पर काम की है जो ऑडियो स्ट्रीम का इस्तेमाल रुक-रुक कर करते हैं. जैसे, ड्राइविंग के निर्देशों के लिए ऑडियो.

requestAudioFocus() तरीके के लिए, AudioManager.OnAudioFocusChangeListener की भी ज़रूरत होती है. इस लिसनर को उसी ऐक्टिविटी या सेवा में बनाना चाहिए जो आपके मीडिया सेशन की मालिक है. यह onAudioFocusChange() कॉलबैक को लागू करता है. यह कॉलबैक, आपके ऐप्लिकेशन को तब मिलता है, जब कोई दूसरा ऐप्लिकेशन, ऑडियो फ़ोकस पाता है या छोड़ता है.

यहां दिए गए स्निपेट में, STREAM_MUSIC स्ट्रीम पर स्थायी ऑडियो फ़ोकस का अनुरोध किया गया है. साथ ही, ऑडियो फ़ोकस में होने वाले बाद के बदलावों को हैंडल करने के लिए, OnAudioFocusChangeListener रजिस्टर किया गया है. (बदलाव के लिसनर के बारे में, ऑडियो फ़ोकस में होने वाले बदलाव का जवाब देना में बताया गया है.)

Kotlin

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
}

Java

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() को कॉल करें.

Kotlin

audioManager.abandonAudioFocus(afChangeListener)

Java

// Abandon audio focus when playback complete
audioManager.abandonAudioFocus(afChangeListener);

इससे सिस्टम को सूचना मिलती है कि अब आपको फ़ोकस की ज़रूरत नहीं है. साथ ही, इससे जुड़े OnAudioFocusChangeListener का रजिस्ट्रेशन रद्द हो जाता है. अगर आपने अस्थायी फ़ोकस का अनुरोध किया है, तो इससे उस ऐप्लिकेशन को सूचना मिलेगी जिसने ऑडियो चलाना रोका था या आवाज़ कम की थी. अब वह ऑडियो चलाना जारी रख सकता है या उसकी आवाज़ को रीस्टोर कर सकता है.

ऑडियो फ़ोकस में होने वाले बदलाव का जवाब देना

जब कोई ऐप्लिकेशन, ऑडियो फ़ोकस पाता है, तो उसे तब छोड़ना होगा, जब कोई दूसरा ऐप्लिकेशन, अपने लिए ऑडियो फ़ोकस का अनुरोध करता है. ऐसा होने पर, आपके ऐप्लिकेशन को onAudioFocusChange() तरीके के लिए कॉल मिलता है. यह AudioFocusChangeListener , तब तय किया जाता है, जब ऐप्लिकेशन, requestAudioFocus() को कॉल करता है.

onAudioFocusChange() को पास किया गया focusChange पैरामीटर, यह दिखाता है कि किस तरह का बदलाव हो रहा है. यह उस अवधि के हिंट से मेल खाता है जिसका इस्तेमाल, फ़ोकस पाने वाले ऐप्लिकेशन ने किया है. आपके ऐप्लिकेशन को सही तरीके से जवाब देना चाहिए.

फ़ोकस का अस्थायी तौर पर खत्म होना
अगर फ़ोकस में होने वाला बदलाव अस्थायी है (AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK या AUDIOFOCUS_LOSS_TRANSIENT), तो आपके ऐप्लिकेशन को आवाज़ कम करनी चाहिए. हालांकि, अगर ऑटोमैटिक डकिंग की सुविधा का इस्तेमाल नहीं किया जा रहा है, तो ऑडियो चलाना रोकें. इसके अलावा, वही स्थिति बनाए रखें.

ऑडियो फ़ोकस के अस्थायी तौर पर खत्म होने के दौरान, आपको ऑडियो फ़ोकस में होने वाले बदलावों पर नज़र रखनी चाहिए. साथ ही, फ़ोकस वापस मिलने पर, सामान्य प्लेबैक फिर से शुरू करने के लिए तैयार रहना चाहिए. जब ब्लॉक करने वाला ऐप्लिकेशन, फ़ोकस छोड़ता है, तो आपको कॉलबैक (AUDIOFOCUS_GAIN) मिलता है. इस समय, आवाज़ को सामान्य लेवल पर रीस्टोर किया जा सकता है या प्लेबैक फिर से शुरू किया जा सकता है.

फ़ोकस का स्थायी तौर पर खत्म होना
अगर ऑडियो फ़ोकस का स्थायी तौर पर खत्म होता है (AUDIOFOCUS_LOSS), तो कोई दूसरा ऐप्लिकेशन, ऑडियो चला रहा है. आपके ऐप्लिकेशन को तुरंत प्लेबैक रोकना चाहिए, क्योंकि उसे कभी भी AUDIOFOCUS_GAIN कॉलबैक नहीं मिलेगा. प्लेबैक फिर से शुरू करने के लिए, उपयोगकर्ता को साफ़ तौर पर कोई कार्रवाई करनी होगी. जैसे, सूचना या ऐप्लिकेशन यूज़र इंटरफ़ेस (यूआई) में, प्ले ट्रांसपोर्ट कंट्रोल को दबाना.

यहां दिए गए कोड स्निपेट में, OnAudioFocusChangeListener और उसके onAudioFocusChange() कॉलबैक को लागू करने का तरीका बताया गया है. ऑडियो फ़ोकस के स्थायी तौर पर खत्म होने पर, स्टॉप कॉलबैक में देरी करने के लिए, Handler के इस्तेमाल पर ध्यान दें.

Kotlin

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
        }
    }
}

Java

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 का इस्तेमाल करता है. यह कुछ ऐसा दिखता है:

Kotlin

private var delayedStopRunnable = Runnable {
    mediaController.transportControls.stop()
}

Java

private Runnable delayedStopRunnable = new Runnable() {
    @Override
    public void run() {
        getMediaController().getTransportControls().stop();
    }
};

यह पक्का करने के लिए कि उपयोगकर्ता के प्लेबैक फिर से शुरू करने पर, स्टॉप में देरी न हो, किसी भी स्थिति में होने वाले बदलावों के जवाब में, mHandler.removeCallbacks(mDelayedStopRunnable) को कॉल करें. उदाहरण के लिए, अपने कॉलबैक के onPlay(), onSkipToNext() वगैरह में, removeCallbacks() को कॉल करें. आपको अपनी सेवा के onDestroy() कॉलबैक में भी इस तरीके को कॉल करना चाहिए. ऐसा तब करें, जब आपकी सेवा के इस्तेमाल किए गए संसाधनों को साफ़ किया जा रहा हो.