USB API를 사용하여 USB 오디오 주변기기에 직접 액세스하려고 하면 문제가 발생합니다. 이러한 문제에는 보안 문제, 다른 앱의 미디어 재생 제한, USB 기기를 통한 알람, 알림 및 벨소리 손실이 포함될 수 있습니다.
오디오 재생을 개선하려면 대신 믹서 속성을 구성합니다.
믹서 속성 구성
AudioMixerAttributes
API를 사용하면 USB보다 선호하는 믹서 속성으로 앱을 구성할 수 있습니다.
앱 재생이 기본 믹서 속성의 인코딩 형식, 채널 마스크, 샘플링 레이트와 일치하면 믹서가 기본 믹서 속성으로 구성된 오디오 출력 스트림에 재생이 연결됩니다.
USB 기기가 구성을 지원하는 한 앱은 모든 구성에서 하드웨어 추상화 계층 (HAL) 및 기기로 스트리밍할 수 있습니다.
AudioMixerAttributes
에서 허용되는 두 가지 믹서 동작은 DEFAULT
와 BIT_PERFECT
입니다. 믹서 동작이 DEFAULT
인 경우 여러 소스의 오디오 데이터가 혼합됨을 나타냅니다.
믹서 동작이 BIT_PERFECT
이면 오디오 믹싱, 볼륨 조정 또는 오디오 처리 효과가 재생에 적용되지 않습니다. 데이터는 있는 그대로 HAL로 전송되고 최종적으로 USB 기기로 전송됩니다.
BIT_PERFECT
를 사용하면 Android 지원 기기에서 펄스 코드 변조 (PCM)를 통해 DSD (DSD)를 직접 스트리밍할 수 있습니다.
다음 코드 샘플은 이 작업을 실행하는 방법을 보여줍니다.
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 } }