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

दो या इससे ज़्यादा 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 से पहले के वर्शन में, requestAudioFocus() को कॉल करने के लिए इस्तेमाल किए गए durationHint में इस्तेमाल की जाती थी: 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() को कॉल करते समय, आपको अवधि का संकेत देना होगा. ऐसा हो सकता है कि फ़िलहाल फ़ोकस में मौजूद और ऑडियो चला रहा कोई दूसरा ऐप्लिकेशन, इस संकेत का पालन करे:

  • जब आपको आने वाले समय में ऑडियो चलाना हो (उदाहरण के लिए, संगीत चलाते समय) और आपको ऑडियो फ़ोकस के पिछले होल्डर से ऑडियो चलाना बंद करने की उम्मीद हो, तो स्थायी ऑडियो फ़ोकस (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 अनरजिस्टर हो जाता है. अगर आपने ट्रांज़िएंट फ़ोकस का अनुरोध किया है, तो इससे उस ऐप्लिकेशन को सूचना मिलेगी जिसने ऑडियो को रोका या डक किया है. इससे उसे ऑडियो को फिर से चलाने या उसकी आवाज़ को पहले जैसा करने की अनुमति मिल जाएगी.

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

जब कोई ऐप्लिकेशन ऑडियो फ़ोकस हासिल करता है, तो उसे ऑडियो फ़ोकस को रिलीज़ करने में सक्षम होना चाहिए, जब कोई दूसरा ऐप्लिकेशन खुद के लिए ऑडियो फ़ोकस का अनुरोध करता है. ऐसा होने पर, आपके ऐप्लिकेशन को AudioFocusChangeListener में onAudioFocusChange() तरीके के लिए एक कॉल मिलता है. यह वही तरीका है जो आपने तब तय किया था, जब ऐप्लिकेशन ने 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() कॉलबैक में भी इस तरीके को कॉल करना चाहिए.