Ses özellikleri

Android TV cihazları aynı anda birden fazla ses çıkışına sahip olabilir: TV hoparlörleri, HDMI bağlantılı ev sineması, Bluetooth kulaklıklar vb. Bu ses çıkış cihazları farklı ses özelliklerini destekleyebilir kodlamalar (Dolby Digital+, DTS ve PCM), örnek hızı ve kanallar gibi. Örneğin, HDMI bağlantılı TV'ler çok sayıda kodlamayı destekler. bağlı Bluetooth kulaklıklar ise genellikle yalnızca PCM'yi destekler.

Kullanılabilir ses cihazlarının listesi ve yönlendirilen ses sistemi de değişebilir HDMI cihazları çalışırken takarak, Bluetooth kulaklıkları bağlayarak veya bağlantısını keserek, veya kullanıcının ses ayarlarını değiştirmesini ifade eder. Ses çıkışı özellikleri medya oynatırken bile değişiklik yapabildiği için uygulamaların bu yeni yönlendirilmiş ses cihazında ve cihazda oynatmaya devam edin özellikler. Yanlış ses biçiminin çıkışı, hatalara veya ses çalmıyor.

Uygulamalar aynı içeriği birden fazla kodlamada oluşturabilir. ses cihazına bağlı olarak kullanıcıya en iyi ses deneyimini sunmak özellikler. Örneğin, Dolby Digital kodlamalı bir ses akışı TV destekliyorsa, daha yaygın olarak desteklenen bir PCM ses akışı Dolby Digital için destek sunulmadığında seçilir. Yerleşik Android listesi bir ses akışını PCM'ye dönüştürmek için kullanılan kod çözücüler Desteklenen medya biçimleri.

Yayın uygulaması oynatma sırasında AudioTrack en iyi Çıkış tarafından desteklenen AudioFormat ses sistemi.

Doğru biçime sahip parça oluşturma

Uygulamalar bir AudioTrack oluşturmalı, çalmaya başlamalı ve şunu aramalıdır: getRoutedDevice() seçeneğini belirleyin. Bu, örneğin yalnızca aşağıdaki işlemlerde kullanılan güvenli, kısa sessiz bir PCM kodlamalı parça olabilir: yönlendirilen cihazı ve ses özelliklerini belirler.

Desteklenen kodlamaları alın

Tekliflerinizi otomatikleştirmek ve optimize etmek için getAudioProfiles() (API düzeyi 31 ve üstü) veya getEncodings() (API düzeyi 23 ve üstü) varsayılan ses sistemi.

Desteklenen ses profillerini ve biçimlerini kontrol etme

AudioProfile kullanın (API düzeyi 31 ve üstü) veya isDirectPlaybackSupported() (API düzeyi 29 ve üstü) için desteklenen biçim kombinasyonlarını kontrol edebilirsiniz. kanal sayısı ve örnek hızı.

Bazı Android cihazlar, Android cihazların ötesindeki kodlamaları destekleyebilir ses çıkış cihazı tarafından desteklenir. Bu ek biçimler isDirectPlaybackSupported() aracılığıyla algılandı. Bu durumlarda, ses verileri çıkış ses cihazı tarafından desteklenen bir biçime yeniden kodlanır. Tekliflerinizi otomatikleştirmek ve optimize etmek için İstenen biçimin desteklendiğini doğru bir şekilde kontrol etmek için isDirectPlaybackSupported() (getEncodings() tarafından döndürülen listede bulunmasa bile)

Sesli rota beklentisi

Android 13 (API düzeyi 33) ise beklenti sesli rotalarını kullanıma sundu. Şunları yapabilirsiniz: ses özelliği desteğini tahmin etmek ve etkin ses için parçaları hazırlamak. ses sistemi. Tekliflerinizi otomatikleştirmek ve optimize etmek için getDirectPlaybackSupport() şu anda yönlendirilen seste doğrudan oynatmanın desteklenip desteklenmediğini kontrol etmek için belirli bir biçim ve özellikler için kullanılan cihazlar:

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
}

Alternatif olarak, doğrudan medya için hangi profillerin desteklendiğini sorgulayabilirsiniz yönlendirilmiş olan ses cihazında çalın. Buna tüm profiller dahil değildir desteklenmeyen ya da örneğin, Android tarafından kod geçişi yapılan çerçeve:

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();
}

Bu örnekte preferredFormats, AudioFormat örnek. Sıralandı en az tercih edilen sırada, en sonda ise en az tercih edilene göre. getDirectProfilesForAttributes() desteklenen bir liste döndürür Şu öğe için AudioProfile nesne var: sağlanan AudioAttributes. Görev listesi tercih edilen AudioFormat öğe, bir eşleşme desteklenene kadar tekrarlanır AudioProfile bulundu. Bu AudioProfile, bestAudioProfile olarak depolanıyor. En uygun örnek hızları ve kanal maskeleri, bestAudioProfile üzerinden belirlenir. Son olarak, uygun bir AudioFormat örneği oluşturulur.

Ses parçası oluştur

Uygulamalar bu bilgileri kullanarak bir AudioTrack oluşturmak için varsayılan ses sistemi tarafından desteklenen en yüksek kaliteli AudioFormat (ve seçilen içerik için kullanılabilir).

Ses sistemi değişikliklerine müdahale edin

Ses sistemi değişikliklerine müdahale etmek ve tepki vermek için uygulamalar:

  • 24'e eşit veya 24'ten büyük API düzeyleri için OnRoutingChangedListener ses cihazı değişikliklerini (HDMI, Bluetooth vb.) izlemek için kullanılır.
  • API düzeyi 23 için bir AudioDeviceCallback kullanılabilir ses sistemi listesindeki değişiklikleri almak için.
  • API düzeyleri 21 ve 22 için HDMI fişi etkinlikleri ve yayınlardaki ekstra verileri kullanabilirsiniz.
  • Ayrıca, izlemek için bir BroadcastReceiver kaydedin BluetoothDevice durum değişiklikleri API 23'ten düşük cihazlar için AudioDeviceCallback değil desteklenmemektedir.

AudioTrack için ses sistemi değişikliği algılandığında uygulama güncellenmiş ses özelliklerini kontrol etmeli ve gerekirse ses içeriklerini farklı bir AudioFormat ile AudioTrack. Bunu yapın: Daha kaliteli bir kodlama artık destekleniyor veya daha önce kullanılan kodlama artık desteklenmiyor.

Örnek kod

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);