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