ปรับปรุงการเล่นเสียง

เมื่อคุณพยายามเข้าถึงอุปกรณ์ต่อพ่วงเสียงทาง USB โดยตรงโดยใช้ API ของ USB มีปัญหาเกิดขึ้น ปัญหาเหล่านี้อาจรวมถึงปัญหาด้านความปลอดภัย การจำกัดสื่อ การเล่นจากแอปอื่นและการปลุก การแจ้งเตือน และเสียงเรียกเข้า อุปกรณ์ USB

หากต้องการปรับปรุงการเล่นเสียง ให้กำหนดค่าแอตทริบิวต์มิกเซอร์แทน

กำหนดค่าแอตทริบิวต์เครื่องผสม

โดยการใช้ AudioMixerAttributes API คุณจะกำหนดค่าแอปด้วยแอตทริบิวต์มิกเซอร์ที่ต้องการผ่านทาง USB ได้

เมื่อการเล่นแอปของคุณตรงกับรูปแบบการเข้ารหัส มาสก์ช่อง และตัวอย่าง ของแอตทริบิวต์มิกเซอร์ที่ต้องการ การเล่นจะแนบอยู่กับเสียง สตรีมเอาต์พุตที่มีการกำหนดค่าเครื่องผสมด้วยแอตทริบิวต์มิกเซอร์ที่ต้องการ

แอปสามารถสตรีมการกำหนดค่าการแอบสแตรกของฮาร์ดแวร์ได้ทุกเมื่อ (HAL) กับอุปกรณ์ตราบใดที่อุปกรณ์ USB รองรับ การกำหนดค่า

ลักษณะการทำงานของมิกเซอร์ที่อนุญาต 2 รายการใน AudioMixerAttributes คือ DEFAULT และ BIT_PERFECT เมื่อมิกเซอร์ทำงานเป็น DEFAULT แสดงว่าเสียง ข้อมูลจากแหล่งต่างๆ จะปะปนกัน

เมื่อการทำงานของมิกเซอร์คือ BIT_PERFECT จะไม่มีการมิกซ์เสียง ปรับระดับเสียง หรือเสียงที่ประมวลผลแล้ว กับการเล่น ข้อมูลจะส่งในรูปแบบ คือ HAL และสุดท้ายก็ลงสู่อุปกรณ์ USB

เมื่อใช้ BIT_PERFECT คุณจะสตรีมได้โดยตรง ดิจิทัล (DSD) ผ่านการปรับโค้ด Pulse (PCM) บนอุปกรณ์ที่ใช้ Android ตัวอย่างโค้ดต่อไปนี้แสดงวิธีดำเนินการดังกล่าว

KotlinJava
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
 
}
}
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
   
}
}