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) ने पहले से तैयार ऑडियो रूट की सुविधा जोड़ी. आप
डिवाइस के ऑडियो एट्रिब्यूट की सहायता का अनुमान लगाएं और ऐक्टिव मोड के लिए ट्रैक तैयार करें
ऑडियो डिवाइस. इस्तेमाल करने के लिए
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);