ऑडियो की सुविधाएं

Android TV डिवाइसों में, एक समय पर कई ऑडियो आउटपुट कनेक्ट किए जा सकते हैं: टीवी के स्पीकर, एचडीएमआई से कनेक्ट किया गया होम सिनेमा, ब्लूटूथ हेडफ़ोन वगैरह. इन ऑडियो आउटपुट डिवाइसों में, अलग-अलग तरह की ऑडियो सुविधाएं, जैसे, एन्कोडिंग (Dolby Digital+, DTS, और PCM), सैंपल रेट, और चैनल. उदाहरण के लिए, एचडीएमआई से कनेक्ट किए गए टीवी में, कोड में बदलने के कई तरीके काम करते हैं जबकि कनेक्ट किए गए ब्लूटूथ हेडफ़ोन आम तौर पर सिर्फ़ PCM के साथ काम करते हैं.

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

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

प्लेबैक के समय, स्ट्रीमिंग ऐप्लिकेशन को AudioTrack सबसे अच्छे आउटपुट में AudioFormat काम करता है ऑडियो डिवाइस.

सही फ़ॉर्मैट में ट्रैक बनाएं

ऐप्लिकेशन को एक AudioTrack बनाना चाहिए, उसे चलाना शुरू करना चाहिए, और कॉल करना चाहिए getRoutedDevice() का इस्तेमाल करें. उदाहरण के लिए, यह एक सुरक्षित छोटा साइलेंस पीसीएम एन्कोडेड ट्रैक हो सकता है जिसका इस्तेमाल सिर्फ़ रूट किए गए डिवाइस और उसकी ऑडियो क्षमताओं का पता लगा सकता है.

समर्थित एन्कोडिंग पाएं

इस्तेमाल की जाने वाली चीज़ें getAudioProfiles() (एपीआई लेवल 31 और उसके बाद के लेवल) या getEncodings() (एपीआई लेवल 23 और उसके बाद के लेवल) को, एपीआई लेवल 36 के साथ उपलब्ध ऑडियो फ़ॉर्मैट डिफ़ॉल्ट ऑडियो डिवाइस.

इस सुविधा के साथ काम करने वाली ऑडियो प्रोफ़ाइलों और फ़ॉर्मैट की जांच करना

AudioProfile का इस्तेमाल करें (एपीआई लेवल 31 और उसके बाद के लेवल) या isDirectPlaybackSupported() (एपीआई लेवल 29 और उसके बाद के वर्शन), दोनों के साथ काम करने वाले फ़ॉर्मैट के कॉम्बिनेशन की जांच करने के लिए, और सैंपल रेट.

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

आने वाले ऑडियो का रूट

Android 13 (एपीआई लेवल 33) ने पहले से तैयार ऑडियो रूट की सुविधा जोड़ी. आप डिवाइस के ऑडियो एट्रिब्यूट की सहायता का अनुमान लगाएं और ऐक्टिव मोड के लिए ट्रैक तैयार करें ऑडियो डिवाइस. Google Analytics 4 पर माइग्रेट करने के लिए, getDirectPlaybackSupport() यह देखने के लिए कि रूट किए जा रहे मौजूदा ऑडियो पर डायरेक्ट प्लेबैक काम करता है या नहीं दिए गए फ़ॉर्मैट और एट्रिब्यूट के लिए:

Kotlin

val format = AudioFormat.Builder()
    .setEncoding(AudioFormat.ENCODING_E_AC3)
    .setChannelMask(AudioFormat.CHANNEL_OUT_5POINT1)
    .setSampleRate(48000)
    .build()
val attributes = AudioAttributes.Builder()
    .setUsage(AudioAttributes.USAGE_MEDIA)
    .build()

if (AudioManager.getDirectPlaybackSupport(format, attributes) !=
    AudioManager.DIRECT_PLAYBACK_NOT_SUPPORTED
) {
    // The format and attributes are supported for direct playback
    // on the currently active routed audio path
} else {
    // The format and attributes are NOT supported for direct playback
    // on the currently active routed audio path
}

Java

AudioFormat format = new AudioFormat.Builder()
        .setEncoding(AudioFormat.ENCODING_E_AC3)
        .setChannelMask(AudioFormat.CHANNEL_OUT_5POINT1)
        .setSampleRate(48000)
        .build();
AudioAttributes attributes = new AudioAttributes.Builder()
        .setUsage(AudioAttributes.USAGE_MEDIA)
        .build();

if (AudioManager.getDirectPlaybackSupport(format, attributes) !=
        AudioManager.DIRECT_PLAYBACK_NOT_SUPPORTED) {
    // The format and attributes are supported for direct playback
    // on the currently active routed audio path
} else {
    // The format and attributes are NOT supported for direct playback
    // on the currently active routed audio path
}

इसके अलावा, आपके पास यह क्वेरी करने का भी विकल्प है कि डायरेक्ट मीडिया के लिए कौनसी प्रोफ़ाइलें काम करती हैं रूट किए जा रहे मौजूदा ऑडियो डिवाइस पर वीडियो चलाना. इसमें कोई भी प्रोफ़ाइल शामिल नहीं है जो काम नहीं करते हों या जिन्हें, उदाहरण के लिए, Android फ़्रेमवर्क:

Kotlin

private fun findBestAudioFormat(audioAttributes: AudioAttributes): AudioFormat {
    val preferredFormats = listOf(
        AudioFormat.ENCODING_E_AC3,
        AudioFormat.ENCODING_AC3,
        AudioFormat.ENCODING_PCM_16BIT,
        AudioFormat.ENCODING_DEFAULT
    )
    val audioProfiles = audioManager.getDirectProfilesForAttributes(audioAttributes)
    val bestAudioProfile = preferredFormats.firstNotNullOf { format ->
        audioProfiles.firstOrNull { it.format == format }
    }
    val sampleRate = findBestSampleRate(bestAudioProfile)
    val channelMask = findBestChannelMask(bestAudioProfile)
    return AudioFormat.Builder()
        .setEncoding(bestAudioProfile.format)
        .setSampleRate(sampleRate)
        .setChannelMask(channelMask)
        .build()
}

Java

private AudioFormat findBestAudioFormat(AudioAttributes audioAttributes) {
    Stream<Integer> preferredFormats = Stream.<Integer>builder()
            .add(AudioFormat.ENCODING_E_AC3)
            .add(AudioFormat.ENCODING_AC3)
            .add(AudioFormat.ENCODING_PCM_16BIT)
            .add(AudioFormat.ENCODING_DEFAULT)
            .build();
    Stream<AudioProfile> audioProfiles =
            audioManager.getDirectProfilesForAttributes(audioAttributes).stream();
    AudioProfile bestAudioProfile = (AudioProfile) preferredFormats.map(format ->
            audioProfiles.filter(profile -> profile.getFormat() == format)
                    .findFirst()
                    .orElseThrow(NoSuchElementException::new)
    );
    Integer sampleRate = findBestSampleRate(bestAudioProfile);
    Integer channelMask = findBestChannelMask(bestAudioProfile);
    return new AudioFormat.Builder()
            .setEncoding(bestAudioProfile.getFormat())
            .setSampleRate(sampleRate)
            .setChannelMask(channelMask)
            .build();
}

इस उदाहरण में, preferredFormats AudioFormat इंस्टेंस. इसे ऑर्डर किया गया सूची में सबसे ज़्यादा पसंदीदा पहले और सबसे कम पसंदीदा आखिरी को चुनें. getDirectProfilesForAttributes() इस्तेमाल की जा सकने वाली फ़ाइलों की सूची दिखाता है AudioProfile ऑब्जेक्ट के लिए वर्तमान में सप्लाई के साथ रूट किया गया ऑडियो डिवाइस AudioAttributes. इसकी सूची पसंदीदा AudioFormat आइटम को तब तक दोहराया जाता है, जब तक उससे मेल खाने वाली वैल्यू नहीं मिल जाती AudioProfile मिल गया. इस AudioProfile को bestAudioProfile के तौर पर सेव किया गया है. बेहतर सैंपल रेट और चैनल मास्क bestAudioProfile से तय किए जाते हैं. आखिर में, सही AudioFormat इंस्टेंस बनाया जाता है.

ऑडियो ट्रैक बनाएं

ऐप्लिकेशन को इस जानकारी का इस्तेमाल,AudioTrack डिफ़ॉल्ट ऑडियो डिवाइस के लिए, सबसे अच्छी क्वालिटी वाला AudioFormat (और यह चुनिंदा कॉन्टेंट के लिए उपलब्ध है).

ऑडियो डिवाइस में होने वाले बदलावों को रोकें

ऑडियो डिवाइस में होने वाले बदलावों को रोकने और उन पर प्रतिक्रिया देने के लिए, ऐप्लिकेशन को:

  • अगर एपीआई लेवल 24 या उससे ज़्यादा के हैं, तो OnRoutingChangedListener का इस्तेमाल करके ऑडियो डिवाइस में होने वाले बदलावों (एचडीएमआई, ब्लूटूथ वगैरह) पर नज़र रखी जा सकती है.
  • एपीआई लेवल 23 के लिए, AudioDeviceCallback उपलब्ध ऑडियो डिवाइस की सूची में बदलाव पाने के लिए.
  • एपीआई लेवल 21 और 22 के लिए, एचडीएमआई प्लग इवेंट और ब्रॉडकास्ट के अतिरिक्त डेटा का इस्तेमाल करता है.
  • मॉनिटर करने के लिए, BroadcastReceiver को भी रजिस्टर करें BluetoothDevice की स्थिति में बदलाव एपीआई 23 से कम के वर्शन वाले डिवाइसों के लिए. AudioDeviceCallback नहीं है अभी तक काम नहीं कर रहा है.

AudioTrack के लिए ऑडियो डिवाइस में बदलाव का पता चलने पर, ऐप्लिकेशन को अपडेट की गई ऑडियो क्षमताओं की जाँच करनी चाहिए और ज़रूरत पड़ने पर, किसी दूसरे AudioFormat के साथ AudioTrack. ऐसा तब करें, जब अच्छी क्वालिटी वाली एन्कोडिंग अब समर्थित है या पहले उपयोग की गई एन्कोडिंग है अब उपलब्ध नहीं है.

नमूना कोड

Kotlin

// audioPlayer is a wrapper around an AudioTrack
// which calls a callback for an AudioTrack write error
audioPlayer.addAudioTrackWriteErrorListener {
    // error code can be checked here,
    // in case of write error try to recreate the audio track
    restartAudioTrack(findDefaultAudioDeviceInfo())
}

audioPlayer.audioTrack.addOnRoutingChangedListener({ audioRouting ->
    audioRouting?.routedDevice?.let { audioDeviceInfo ->
        // use the updated audio routed device to determine
        // what audio format should be used
        if (needsAudioFormatChange(audioDeviceInfo)) {
            restartAudioTrack(audioDeviceInfo)
        }
    }
}, handler)

Java

// audioPlayer is a wrapper around an AudioTrack
// which calls a callback for an AudioTrack write error
audioPlayer.addAudioTrackWriteErrorListener(new AudioTrackPlayer.AudioTrackWriteError() {
    @Override
    public void audioTrackWriteError(int errorCode) {
        // error code can be checked here,
        // in case of write error try to recreate the audio track
        restartAudioTrack(findDefaultAudioDeviceInfo());
    }
});

audioPlayer.getAudioTrack().addOnRoutingChangedListener(new AudioRouting.OnRoutingChangedListener() {
    @Override
    public void onRoutingChanged(AudioRouting audioRouting) {
        if (audioRouting != null && audioRouting.getRoutedDevice() != null) {
            AudioDeviceInfo audioDeviceInfo = audioRouting.getRoutedDevice();
            // use the updated audio routed device to determine
            // what audio format should be used
            if (needsAudioFormatChange(audioDeviceInfo)) {
                restartAudioTrack(audioDeviceInfo);
            }
        }
    }
}, handler);