عندما تحاول الوصول مباشرةً إلى جهاز USB الصوتي الملحق باستخدام واجهات برمجة تطبيقات USB، تنشأ مشكلات. يمكن أن تتضمن هذه المشكلات: المشكلات الأمنية، تقييد الوسائط التشغيل من التطبيقات الأخرى، وفقدان المنبّهات والإشعارات ونغمات الرنين أجهزة USB.
لتحسين تشغيل الصوت، يمكنك بدلاً من ذلك ضبط سمات الخلاط.
إعداد سمات الخلاط
من خلال استخدام
AudioMixerAttributes
واجهات برمجة التطبيقات،
يمكنك إعداد تطبيقك باستخدام سمات المزج المفضّلة عبر USB.
عندما يتطابق تشغيل التطبيق مع تنسيق الترميز وقناع القناة والعيّنة لخصائص الخلاط المفضلة، يتم إرفاق التشغيل بالصوت بث المخرجات الذي تم ضبط الخلاط فيه بسمات المزج المفضلة.
يمكن لتطبيقك البث بأي إعداد وفقًا لتجريد الأجهزة. (HAL) وعلى الجهاز، ما دام جهاز USB يتوافق مع التكوين.
سلوكا المزج المسموح به في AudioMixerAttributes
هما DEFAULT
و
BIT_PERFECT
عندما يكون سلوك أداة المزج DEFAULT
، يعني ذلك أن الصوت
تكون البيانات من مصادر مختلفة مختلطة.
عندما يكون سلوك أداة المزج BIT_PERFECT
، لا يتم مزج الصوت أو ضبط مستوى الصوت،
أو التأثير الصوتي الذي تمت معالجته على التشغيل. يتم إرسال البيانات على النحو التالي:
إلى HAL وأخيرًا إلى جهاز USB.
يتيح لك استخدام BIT_PERFECT
إمكانية البث المباشر.
تقنية تعديل الرموز الرقمية (DSD) بالرمز النبضي (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 } }