Cải thiện tính năng phát âm thanh
Sử dụng bộ sưu tập để sắp xếp ngăn nắp các trang
Lưu và phân loại nội dung dựa trên lựa chọn ưu tiên của bạn.
Khi bạn cố gắng truy cập trực tiếp vào thiết bị ngoại vi âm thanh USB bằng API USB,
vấn đề phát sinh. Những vấn đề này có thể bao gồm: vấn đề bảo mật, giới hạn nội dung nghe nhìn
phát từ các ứng dụng khác và mất báo thức, thông báo và nhạc chuông
Thiết bị USB.
Để cải thiện tính năng phát âm thanh, hãy định cấu hình các thuộc tính bộ trộn.
Bằng cách sử dụng
Các API AudioMixerAttributes
,
bạn có thể định cấu hình ứng dụng bằng các thuộc tính bộ trộn ưu tiên qua USB.
Khi chế độ phát ứng dụng của bạn khớp với định dạng mã hoá, mặt nạ kênh và mẫu
tốc độ của các thuộc tính bộ trộn ưu tiên, bản phát đi kèm với âm thanh
luồng đầu ra có bộ trộn được định cấu hình bằng các thuộc tính bộ trộn ưu tiên.
Ứng dụng của bạn có thể truyền trực tuyến ở bất kỳ cấu hình nào đến mô hình trừu tượng phần cứng
(HAL) và đến thiết bị, miễn là thiết bị USB hỗ trợ
.
Hai hành vi trình kết hợp được phép trong AudioMixerAttributes
là DEFAULT
và
BIT_PERFECT
. Khi hành vi của bộ trộn là DEFAULT
, điều này cho biết rằng âm thanh
dữ liệu từ nhiều nguồn khác nhau.
Khi hành vi của bộ trộn là BIT_PERFECT
, sẽ không trộn âm thanh, điều chỉnh âm lượng,
hoặc hiệu ứng đã xử lý âm thanh sẽ được áp dụng cho nội dung phát. Dữ liệu được gửi dưới dạng
là đến HAL và cuối cùng là xuống thiết bị USB.
Việc sử dụng BIT_PERFECT
cho phép bạn phát trực tiếp
kỹ thuật số (DSD) qua điều chế mã xung (PCM) trên các thiết bị chạy Android.
Mã mẫu sau đây cho thấy cách thực hiện điều này:
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
}
}
Nội dung và mã mẫu trên trang này phải tuân thủ các giấy phép như mô tả trong phần Giấy phép nội dung. Java và OpenJDK là nhãn hiệu hoặc nhãn hiệu đã đăng ký của Oracle và/hoặc đơn vị liên kết của Oracle.
Cập nhật lần gần đây nhất: 2025-07-27 UTC.
[[["Dễ hiểu","easyToUnderstand","thumb-up"],["Giúp tôi giải quyết được vấn đề","solvedMyProblem","thumb-up"],["Khác","otherUp","thumb-up"]],[["Thiếu thông tin tôi cần","missingTheInformationINeed","thumb-down"],["Quá phức tạp/quá nhiều bước","tooComplicatedTooManySteps","thumb-down"],["Đã lỗi thời","outOfDate","thumb-down"],["Vấn đề về bản dịch","translationIssue","thumb-down"],["Vấn đề về mẫu/mã","samplesCodeIssue","thumb-down"],["Khác","otherDown","thumb-down"]],["Cập nhật lần gần đây nhất: 2025-07-27 UTC."],[],[],null,["# Improve audio playback\n\nWhen you try to directly access the USB audio peripheral using the USB APIs,\nproblems arise. These problems can include: security issues, limiting media\nplayback from other apps, and loss of alarms, notifications, and ringtones over\nUSB devices.\n\nTo improve audio playback, instead configure the mixer attributes.\n\n### Configure mixer attributes\n\nBy using the\n[`AudioMixerAttributes`](/reference/android/media/AudioMixerAttributes) APIs,\nyou can configure your app with preferred mixer attributes over USB.\n\nWhen your app playback matches the encoding format, channel mask, and sample\nrate of the preferred mixer attributes, the playback is attached to the audio\noutput stream whose mixer is configured with the preferred mixer attributes.\n\nYour app can stream at any configuration to the hardware abstraction\nlayer (HAL), and to the device, as long as the USB device supports the\nconfiguration.\n\nThe two allowed mixer behaviors in `AudioMixerAttributes` are `DEFAULT` and\n`BIT_PERFECT`. When the mixer behavior is `DEFAULT`, it indicates that audio\ndata from different sources is mixed.\n\nWhen the mixer behavior is `BIT_PERFECT`, no audio mixing, volume adjustment,\nor audio processed effect is applied to the playback. The data is sent as\nis to the HAL and finally down to the USB device.\n\nUsing `BIT_PERFECT` lets you direct stream\ndigital (DSD) over pulse code modulation (PCM) on Android-powered devices.\nThe following code sample shows how this can be accomplished: \n\n### Kotlin\n\n```kotlin\nval EXPECTED_FORMAT: AudioFormat = AudioFormat.Builder()\n .setEncoding(AudioFormat.ENCODING_PCM_24BIT_PACKED)\n .setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)\n .setSampleRate(44100)\n .build()\n\nfun startPlayback() {\n // Query all supported mixer attributes\n val mixerAttributesList: List\u003cAudioMixerAttributes?\u003e =\n mAudioManager.getSupportedMixerAttributes(usbDevice)\n\n // Find the wanted mixer attributes\n val mixerAttributes = mixerAttributesList.stream()\n .filter { mixerAttr: AudioMixerAttributes? -\u003e\n EXPECTED_FORMAT.equals(\n mixerAttr!!.format\n )\n }\n .findAny()\n .orElse(null)\n\n // Register a listener to mixer attributes changed\n val listener = MyPreferredMixerAttributesChangedListener()\n mAudioManager.addOnPreferredMixerAttributesChangedListener(\n Executors.newSingleThreadExecutor(), listener\n )\n\n // Currently, only media usage over USB devices will be allowed\n val attr: AudioAttributes = AudioAttributes.Builder()\n .setUsage(AudioAttributes.USAGE_MEDIA).build()\n // Set preferred mixer attributes\n mAudioManager.setPreferredMixerAttributes(\n attr, usbDevice, mixerAttributes\n )\n\n // Start playback, note the playback and the audio format must\n // match what is set when calling `setPreferredMixerAttriutes`\n // API.\n val audioTrack = AudioTrack.Builder()\n .setAudioAttributes(attr)\n .setAudioFormat(mixerAttributes!!.format)\n .build()\n\n // Clear all preferred mixer attributes related stuff when\n // playback task is completed\n mAudioManager.clearPreferredMixerAttributes(attr, usbDevice)\n mAudioManager.removeOnPreferredMixerAttributesChangedListener(listener)\n}\n\nprivate class MyPreferredMixerAttributesChangedListener :\n AudioManager.OnPreferredMixerAttributesChangedListener {\n override fun onPreferredMixerAttributesChanged(\n attributes: AudioAttributes,\n device: AudioDeviceInfo,\n mixerAttributes: AudioMixerAttributes?,\n ) {\n // Do something when preferred mixer attributes changed\n }\n}\n```\n\n### Java\n\n```java\nfinal AudioFormat EXPECTED_FORMAT = new AudioFormat.Builder()\n .setEncoding(AudioFormat.ENCODING_PCM_24BIT_PACKED)\n .setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)\n .setSampleRate(44100)\n .build();\n\nvoid startPlayback() {\n // Query all supported mixer attributes\n List\u003cAudioMixerAttributes\u003e mixerAttributesList =\n mAudioManager.getSupportedMixerAttributes(usbDevice);\n\n // Find the wanted mixer attributes\n AudioMixerAttributes mixerAttributes =\n mixerAttributesList.stream()\n .filter(mixerAttr -\u003e EXPECTED_FORMAT.equals(mixerAttr.getFormat()))\n .findAny()\n .orElse(null);\n\n // Register a listener to mixer attributes changed\n MyPreferredMixerAttributesChangedListener listener =\n new MyPreferredMixerAttributesChangedListener();\n mAudioManager.addOnPreferredMixerAttributesChangedListener(\n Executors.newSingleThreadExecutor(), listener);\n\n // Currently, only media usage over USB devices will be allowed\n AudioAttributes attr = new AudioAttributes.Builder()\n .setUsage(AudioAttributes.USAGE_MEDIA).build();\n // Set preferred mixer attributes\n mAudioManager.setPreferredMixerAttributes(\n attr, usbDevice, mixerAttributes);\n\n // Start playback, note the playback and the audio format must\n // match what is set when calling `setPreferredMixerAttriutes`\n // API.\n AudioTrack audioTrack = new AudioTrack.Builder()\n .setAudioAttributes(attr)\n .setAudioFormat(mixerAttributes.getFormat())\n .build();\n\n // Clear all preferred mixer attributes related stuff when\n // playback task is completed\n mAudioManager.clearPreferredMixerAttributes(attr, usbDevice);\n mAudioManager.removeOnPreferredMixerAttributesChangedListener(\n listener);\n}\n\nprivate class MyPreferredMixerAttributesChangedListener\n implements AudioManager.OnPreferredMixerAttributesChangedListener {\n @Override\n public void onPreferredMixerAttributesChanged(\n AudioAttributes attributes,\n AudioDeviceInfo device,\n AudioMixerAttributes mixerAttributes) {\n // Do something when preferred mixer attributes changed\n }\n}\n```"]]