অডিও প্লেব্যাক উন্নত করুন

আপনি যখন USB API ব্যবহার করে সরাসরি USB অডিও পেরিফেরাল অ্যাক্সেস করার চেষ্টা করেন, তখন সমস্যা দেখা দেয়। এই সমস্যাগুলির মধ্যে অন্তর্ভুক্ত থাকতে পারে: নিরাপত্তা সমস্যা, অন্যান্য অ্যাপ থেকে মিডিয়া প্লেব্যাক সীমিত করা এবং ইউএসবি ডিভাইসে অ্যালার্ম, বিজ্ঞপ্তি এবং রিংটোন হারানো।

অডিও প্লেব্যাক উন্নত করতে, পরিবর্তে মিক্সার বৈশিষ্ট্যগুলি কনফিগার করুন৷

মিক্সার অ্যাট্রিবিউট কনফিগার করুন

AudioMixerAttributes APIs ব্যবহার করে, আপনি USB-এর মাধ্যমে পছন্দের মিক্সার অ্যাট্রিবিউট দিয়ে আপনার অ্যাপ কনফিগার করতে পারেন।

যখন আপনার অ্যাপ প্লেব্যাক এনকোডিং ফর্ম্যাট, চ্যানেল মাস্ক এবং পছন্দের মিক্সার অ্যাট্রিবিউটের নমুনা হারের সাথে মেলে, তখন প্লেব্যাকটি অডিও আউটপুট স্ট্রীমের সাথে সংযুক্ত থাকে যার মিক্সারটি পছন্দের মিক্সার অ্যাট্রিবিউটের সাথে কনফিগার করা হয়।

আপনার অ্যাপ যে কোনো কনফিগারেশনে হার্ডওয়্যার অ্যাবস্ট্রাকশন লেয়ার (HAL) এবং ডিভাইসে স্ট্রিম করতে পারে, যতক্ষণ না USB ডিভাইস কনফিগারেশন সমর্থন করে।

AudioMixerAttributes এ দুটি অনুমোদিত মিক্সার আচরণ হল DEFAULT এবং BIT_PERFECT । যখন মিক্সার আচরণ DEFAULT হয়, তখন এটি নির্দেশ করে যে বিভিন্ন উত্স থেকে অডিও ডেটা মিশ্রিত হয়েছে৷

যখন মিক্সারের আচরণ BIT_PERFECT হয়, তখন প্লেব্যাকে কোনো অডিও মিক্সিং, ভলিউম সমন্বয় বা অডিও প্রক্রিয়াজাত প্রভাব প্রয়োগ করা হয় না। ডেটা পাঠানো হয় HAL-এ এবং অবশেষে USB ডিভাইসে পাঠানো হয়।

BIT_PERFECT ব্যবহার করে আপনি অ্যান্ড্রয়েড-চালিত ডিভাইসগুলিতে পালস কোড মড্যুলেশন (পিসিএম) এর মাধ্যমে ডিজিটাল স্ট্রিম (ডিএসডি) সরাসরি করতে পারবেন। নিম্নলিখিত কোড নমুনা দেখায় কিভাবে এটি সম্পন্ন করা যেতে পারে:

কোটলিন

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