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

เมื่อคุณพยายามเข้าถึงอุปกรณ์ต่อพ่วงเสียงทาง 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 ตัวอย่างโค้ดต่อไปนี้แสดงวิธีดำเนินการดังกล่าว

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