Saat Anda mencoba mengakses langsung periferal audio USB menggunakan API USB, masalah timbul. Masalah ini dapat mencakup: masalah keamanan, pembatasan media pemutaran dari aplikasi lain, dan hilangnya alarm, notifikasi, dan nada dering melalui perangkat USB.
Untuk meningkatkan pemutaran audio, konfigurasikan atribut mixer.
Mengonfigurasi atribut mixer
Dengan menggunakan
AudioMixerAttributes
API,
Anda dapat mengonfigurasi aplikasi dengan
atribut mixer yang disukai melalui USB.
Saat pemutaran aplikasi Anda cocok dengan format encoding, channel mask, dan contoh kecepatan atribut mixer yang diinginkan, pemutaran akan dikaitkan ke audio aliran output yang mixernya dikonfigurasi dengan atribut mixer yang disukai.
Aplikasi Anda dapat melakukan streaming pada konfigurasi apa pun ke abstraksi hardware (HAL) ke perangkat, selama perangkat USB mendukung konfigurasi Anda.
Dua perilaku mixer yang diizinkan di AudioMixerAttributes
adalah DEFAULT
dan
BIT_PERFECT
. Jika perilaku mixer adalah DEFAULT
, hal ini menunjukkan bahwa audio
data dari sumber yang
berbeda dicampur.
Saat perilaku mixer adalah BIT_PERFECT
, tidak ada pencampuran audio, penyesuaian volume,
atau audio yang diproses
akan diterapkan ke pemutaran. Data dikirim sebagai
adalah ke HAL dan terakhir
ke perangkat USB.
Menggunakan BIT_PERFECT
memungkinkan Anda untuk melakukan live stream
digital (DSD) melalui modulasi kode nadi (PCM) di perangkat yang didukung Android.
Contoh kode berikut menunjukkan cara melakukannya:
Kotlin
val EXPECTED_FORMAT: AudioFormat = AudioFormat.Builder() .setEncoding(AudioFormat.ENCODING_PCM_24BIT_PACKED) .setChannelMask(AudioFormat.CHANNEL_OUT_STEREO) .setSampleRate(44100) .build() fun startPlayback() { // Query all supported mixer attributes val mixerAttributesList: List<AudioMixerAttributes?> = mAudioManager.getSupportedMixerAttributes(usbDevice) // Find the wanted mixer attributes val mixerAttributes = mixerAttributesList.stream() .filter { mixerAttr: AudioMixerAttributes? -> EXPECTED_FORMAT.equals( mixerAttr!!.format ) } .findAny() .orElse(null) // Register a listener to mixer attributes changed val listener = MyPreferredMixerAttributesChangedListener() mAudioManager.addOnPreferredMixerAttributesChangedListener( Executors.newSingleThreadExecutor(), listener ) // Currently, only media usage over USB devices will be allowed val attr: AudioAttributes = AudioAttributes.Builder() .setUsage(AudioAttributes.USAGE_MEDIA).build() // Set preferred mixer attributes mAudioManager.setPreferredMixerAttributes( attr, usbDevice, mixerAttributes ) // Start playback, note the playback and the audio format must // match what is set when calling `setPreferredMixerAttriutes` // API. val audioTrack = AudioTrack.Builder() .setAudioAttributes(attr) .setAudioFormat(mixerAttributes!!.format) .build() // Clear all preferred mixer attributes related stuff when // playback task is completed mAudioManager.clearPreferredMixerAttributes(attr, usbDevice) mAudioManager.removeOnPreferredMixerAttributesChangedListener(listener) } private class MyPreferredMixerAttributesChangedListener : AudioManager.OnPreferredMixerAttributesChangedListener { override fun onPreferredMixerAttributesChanged( attributes: AudioAttributes, device: AudioDeviceInfo, mixerAttributes: AudioMixerAttributes?, ) { // Do something when preferred mixer attributes changed } }
Java
final AudioFormat EXPECTED_FORMAT = new AudioFormat.Builder() .setEncoding(AudioFormat.ENCODING_PCM_24BIT_PACKED) .setChannelMask(AudioFormat.CHANNEL_OUT_STEREO) .setSampleRate(44100) .build(); void startPlayback() { // Query all supported mixer attributes List<AudioMixerAttributes> mixerAttributesList = mAudioManager.getSupportedMixerAttributes(usbDevice); // Find the wanted mixer attributes AudioMixerAttributes mixerAttributes = mixerAttributesList.stream() .filter(mixerAttr -> EXPECTED_FORMAT.equals(mixerAttr.getFormat())) .findAny() .orElse(null); // Register a listener to mixer attributes changed MyPreferredMixerAttributesChangedListener listener = new MyPreferredMixerAttributesChangedListener(); mAudioManager.addOnPreferredMixerAttributesChangedListener( Executors.newSingleThreadExecutor(), listener); // Currently, only media usage over USB devices will be allowed AudioAttributes attr = new AudioAttributes.Builder() .setUsage(AudioAttributes.USAGE_MEDIA).build(); // Set preferred mixer attributes mAudioManager.setPreferredMixerAttributes( attr, usbDevice, mixerAttributes); // Start playback, note the playback and the audio format must // match what is set when calling `setPreferredMixerAttriutes` // API. AudioTrack audioTrack = new AudioTrack.Builder() .setAudioAttributes(attr) .setAudioFormat(mixerAttributes.getFormat()) .build(); // Clear all preferred mixer attributes related stuff when // playback task is completed mAudioManager.clearPreferredMixerAttributes(attr, usbDevice); mAudioManager.removeOnPreferredMixerAttributesChangedListener( listener); } private class MyPreferredMixerAttributesChangedListener implements AudioManager.OnPreferredMixerAttributesChangedListener { @Override public void onPreferredMixerAttributesChanged( AudioAttributes attributes, AudioDeviceInfo device, AudioMixerAttributes mixerAttributes) { // Do something when preferred mixer attributes changed } }