Âm thanh không gian

Âm thanh không gian là một trải nghiệm âm thanh sống động lấy người dùng làm trung tâm để thực hiện hành động, giúp nội dung của bạn nghe chân thực hơn. Âm thanh được "không gian" để tạo ra hiệu ứng nhiều loa, tương tự như khi thiết lập âm thanh vòm, nhưng thay vào đó là thông qua tai nghe.

Ví dụ: trong một bộ phim, âm thanh từ một chiếc ô tô có thể bắt đầu phát ra phía sau người dùng, di chuyển về phía trước và di chuyển ra xa. Trong cuộc trò chuyện video, giọng nói có thể được tách riêng và đặt xung quanh người dùng, giúp xác định người nói dễ dàng hơn.

Nếu nội dung của bạn sử dụng định dạng âm thanh được hỗ trợ, thì bạn có thể thêm âm thanh không gian vào ứng dụng của mình kể từ Android 13 (API cấp 33).

Truy vấn chức năng

Sử dụng lớp Spatializer để truy vấn khả năng và hành vi về không gian của thiết bị. Bắt đầu bằng cách truy xuất một thực thể của Spatializer từ AudioManager:

Kotlin

val spatializer = audioManager.spatializer

Java

Spatializer spatializer = AudioManager.getSpatializer();

Sau khi bạn nhận được Spatializer, hãy kiểm tra 4 điều kiện phải đúng để thiết bị phát ra âm thanh không gian:

Tiêu chí Kiểm tra
Thiết bị có hỗ trợ tính năng không gian không? getImmersiveAudioLevel() không phải là SPATIALIZER_IMMERSIVE_LEVEL_NONE
Công nghệ không gian có sẵn không?
Khả năng tương thích phụ thuộc vào khả năng tương thích với định tuyến đầu ra âm thanh hiện tại.
isAvailable() hiện là true
Tính năng không gian đã được bật chưa? isEnabled() hiện là true
Có thể tạo không gian cho một bản âm thanh có các thông số nhất định không? canBeSpatialized() hiện là true

Các điều kiện này có thể không được đáp ứng, chẳng hạn như nếu bản nhạc hiện tại không hỗ trợ tính năng tạo không gian hoặc bị tắt hoàn toàn trên thiết bị đầu ra âm thanh.

Theo dõi chuyển động của đầu

Với tai nghe được hỗ trợ, nền tảng có thể điều chỉnh không gian của âm thanh dựa trên vị trí đầu của người dùng. Để kiểm tra xem có thiết bị theo dõi chuyển động nào để định tuyến đầu ra âm thanh hiện tại hay không, hãy gọi isHeadTrackerAvailable().

Nội dung tương thích

Spatializer.canBeSpatialized() cho biết liệu âm thanh có các thuộc tính cho trước có thể được tạo không gian bằng cách định tuyến thiết bị đầu ra hiện tại hay không. Phương thức này sử dụng AudioAttributesAudioFormat, cả hai đều được mô tả chi tiết hơn dưới đây.

AudioAttributes

Đối tượng AudioAttributes mô tả cách sử dụng của luồng âm thanh (ví dụ: âm thanh trò chơi hoặc nội dung nghe nhìn chuẩn), cùng với hành vi phát và loại nội dung.

Khi gọi canBeSpatialized(), hãy sử dụng cùng một thực thể AudioAttributes như đã thiết lập cho Player. Ví dụ: nếu bạn đang sử dụng thư viện Jetpack Media3 và chưa tuỳ chỉnh AudioAttributes, hãy sử dụng AudioAttributes.DEFAULT.

Tắt âm thanh không gian

Để cho biết rằng nội dung của bạn đã được tạo không gian, hãy gọi setIsContentSpatialized(true) để âm thanh không được xử lý hai lần. Ngoài ra, bạn có thể điều chỉnh hành vi không gian để tắt hoàn toàn tính năng không gian bằng cách gọi setSpatializationBehavior(AudioAttributes.SPATIALIZATION_BEHAVIOR_NEVER).

AudioFormat

Đối tượng AudioFormat mô tả thông tin chi tiết về định dạng và cấu hình kênh của bản âm thanh.

Khi tạo thực thể cho AudioFormat để truyền vào canBeSpatialized(), hãy đặt mã hoá về định dạng đầu ra giống với định dạng đầu ra dự kiến từ bộ giải mã. Bạn cũng nên đặt mặt nạ kênh phù hợp với cấu hình kênh của nội dung. Hãy tham khảo phần Hành vi không gian mặc định để xem hướng dẫn về các giá trị cụ thể cần sử dụng.

Theo dõi các thay đổi đối với Spatializer

Để theo dõi các thay đổi về trạng thái của Spatializer, bạn có thể thêm một trình nghe bằng Spatializer.addOnSpatializerStateChangedListener(). Tương tự, để theo dõi những thay đổi về khả năng sử dụng của trình theo dõi chuyển động của đầu, hãy gọi Spatializer.addOnHeadTrackerAvailableListener().

Điều này có thể hữu ích nếu bạn muốn điều chỉnh lựa chọn bản nhạc trong quá trình phát bằng cách sử dụng lệnh gọi lại của trình nghe. Ví dụ: khi người dùng kết nối hoặc ngắt kết nối tai nghe khỏi thiết bị, lệnh gọi lại onSpatializerAvailableChanged sẽ cho biết liệu hiệu ứng tạo âm thanh không gian có dùng được cho tính năng định tuyến đầu ra âm thanh mới hay không. Tại thời điểm này, bạn có thể cân nhắc việc cập nhật logic lựa chọn bản nhạc của người chơi cho phù hợp với các tính năng mới của thiết bị. Để biết thông tin chi tiết về hành vi chọn bản nhạc của ExoPlayer, vui lòng tham khảo phần ExoPlayer và âm thanh không gian.

ExoPlayer và âm thanh không gian

Các bản phát hành gần đây của ExoPlayer giúp bạn dễ dàng sử dụng âm thanh không gian. Nếu bạn sử dụng thư viện ExoPlayer độc lập (tên gói com.google.android.exoplayer2), phiên bản 2.17 sẽ định cấu hình nền tảng để xuất âm thanh không gian, và phiên bản 2.18 ra mắt các quy tắc hạn chế về số lượng kênh âm thanh. Nếu bạn sử dụng mô-đun ExoPlayer từ thư viện Media3, (tên gói androidx.media3), các phiên bản 1.0.0-beta01 và mới hơn sẽ bao gồm các bản cập nhật tương tự này.

Sau khi cập nhật phần phụ thuộc ExoPlayer lên bản phát hành mới nhất, ứng dụng của bạn chỉ cần đưa vào nội dung có thể được khoa học về không gian.

Các quy tắc ràng buộc về số lượng kênh âm thanh

Khi đáp ứng cả 4 điều kiện dành cho âm thanh không gian, ExoPlayer sẽ chọn một bản âm thanh đa kênh. Nếu không, ExoPlayer sẽ chọn một bản âm thanh nổi để thay thế. Nếu thuộc tính Spatializer thay đổi, ExoPlayer sẽ kích hoạt lựa chọn bản nhạc mới để chọn bản âm thanh khớp với các thuộc tính hiện tại. Xin lưu ý rằng lựa chọn mới này cho bản nhạc có thể tạo ra một khoảng thời gian lưu vào bộ đệm lại ngắn.

Để tắt các quy tắc ràng buộc về số lượng kênh âm thanh, hãy đặt các tham số lựa chọn bản nhạc trên trình phát như minh hoạ dưới đây:

Kotlin

exoPlayer.trackSelectionParameters = DefaultTrackSelector.Parameters.Builder(context)
  .setConstrainAudioChannelCountToDeviceCapabilities(false)
  .build()

Java

exoPlayer.setTrackSelectionParameters(
  new DefaultTrackSelector.Parameters.Builder(context)
    .setConstrainAudioChannelCountToDeviceCapabilities(false)
    .build()
);

Tương tự, bạn có thể cập nhật các tham số của bộ chọn bản nhạc hiện có để tắt các quy tắc ràng buộc đối với số lượng kênh âm thanh như sau:

Kotlin

val trackSelector = DefaultTrackSelector(context)
...
trackSelector.parameters = trackSelector.buildUponParameters()
  .setConstrainAudioChannelCountToDeviceCapabilities(false)
  .build()

Java

DefaultTrackSelector trackSelector = new DefaultTrackSelector(context);
...
trackSelector.setParameters(
  trackSelector
    .buildUponParameters()
    .setConstrainAudioChannelCountToDeviceCapabilities(false)
    .build()
);

Khi tắt các quy tắc ràng buộc về số lượng kênh âm thanh, nếu nội dung có nhiều bản âm thanh thì ban đầu, ExoPlayer sẽ chọn bản nhạc có nhiều kênh nhất và có thể phát được trên thiết bị. Ví dụ: nếu nội dung chứa một bản âm thanh đa kênh và một bản âm thanh nổi, đồng thời thiết bị hỗ trợ phát cả hai, thì ExoPlayer sẽ chọn bản đa kênh đó. Hãy xem phần Lựa chọn bản âm thanh để biết thông tin chi tiết về cách tuỳ chỉnh hành vi này.

Chọn bản âm thanh

Khi tắt hành vi quy tắc ràng buộc về số lượng kênh âm thanh của ExoPlayer, ExoPlayer sẽ không tự động chọn bản âm thanh khớp với các thuộc tính của bộ tạo không gian trên thiết bị. Thay vào đó, bạn có thể tuỳ chỉnh logic lựa chọn bản nhạc của ExoPlayer bằng cách thiết lập các tham số lựa chọn bản nhạc trước hoặc trong khi phát. Theo mặc định, ExoPlayer chọn các bản âm thanh giống với bản nhạc ban đầu liên quan đến loại MIME (mã hoá), số lượng kênh và tốc độ lấy mẫu.

Thay đổi thông số lựa chọn bản nhạc

Để thay đổi các tham số lựa chọn bản nhạc của ExoPlayer, hãy sử dụng Player.setTrackSelectionParameters(). Tương tự, bạn có thể lấy các tham số hiện tại của ExoPlayer bằng Player.getTrackSelectionParameters(). Ví dụ: để chọn bản âm thanh nổi khi phát lại:

Kotlin

exoPlayer.trackSelectionParameters = exoPlayer.trackSelectionParameters
  .buildUpon()
  .setMaxAudioChannelCount(2)
  .build()

Java

exoPlayer.setTrackSelectionParameters(
  exoPlayer.getTrackSelectionParameters()
    .buildUpon()
    .setMaxAudioChannelCount(2)
    .build()
);

Xin lưu ý rằng việc thay đổi các tham số lựa chọn bản nhạc trong quá trình phát có thể gây gián đoạn quá trình phát. Bạn có thể tìm thêm thông tin về cách điều chỉnh tham số lựa chọn bản nhạc của người chơi trong phần chọn bản nhạc của tài liệu về ExoPlayer.

Hành vi xác định không gian mặc định

Hành vi xác định không gian mặc định trong Android bao gồm các hành vi sau đây mà OEM có thể tuỳ chỉnh:

  • Chỉ nội dung đa kênh mới được tạo không gian, chứ không phải nội dung âm thanh nổi. Nếu không sử dụng ExoPlayer, thì tuỳ thuộc vào định dạng của nội dung âm thanh đa kênh, bạn có thể cần định cấu hình số lượng kênh tối đa mà bộ giải mã âm thanh có thể phát ra với một số lượng lớn. Điều này đảm bảo rằng bộ giải mã âm thanh xuất ra PCM đa kênh để nền tảng tạo không gian.

    Kotlin

    val mediaFormat = MediaFormat()
    mediaFormat.setInteger(MediaFormat.KEY_MAX_OUTPUT_CHANNEL_COUNT, 99)
    

    Java

    MediaFormat mediaFormat = new MediaFormat();
    mediaFormat.setInteger(MediaFormat.KEY_MAX_OUTPUT_CHANNEL_COUNT, 99);
    

    Để xem ví dụ thực tế, hãy xem MediaCodecAudioRenderer.java của ExoPlayer. Để tự tắt tính năng tạo không gian, bất kể chế độ tuỳ chỉnh của nhà sản xuất thiết bị gốc (OEM), hãy xem bài viết Tắt âm thanh không gian.

  • AudioAttributes: Âm thanh đủ điều kiện để tạo không gian nếu bạn đặt usage thành USAGE_MEDIA hoặc USAGE_GAME.

  • AudioFormat: Sử dụng mặt nạ kênh chứa ít nhất các kênh AudioFormat.CHANNEL_OUT_QUAD (trước – bên trái, trước-phải, sau trái và sau bên phải) để âm thanh đủ điều kiện phân bổ không gian. Trong ví dụ bên dưới, chúng tôi sử dụng AudioFormat.CHANNEL_OUT_5POINT1 cho bản âm thanh 5.1. Đối với bản âm thanh nổi, hãy sử dụng AudioFormat.CHANNEL_OUT_STEREO.

    Nếu đang sử dụng Media3, bạn có thể dùng Util.getAudioTrackChannelConfig(int channelCount) để chuyển đổi số lượng kênh thành mặt nạ kênh.

    Ngoài ra, hãy đặt phương thức mã hoá thành AudioFormat.ENCODING_PCM_16BIT nếu bạn đã định cấu hình bộ giải mã để xuất PCM đa kênh.

    Kotlin

    val audioFormat = AudioFormat.Builder()
      .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
      .setChannelMask(AudioFormat.CHANNEL_OUT_5POINT1)
      .build()
    

    Java

    AudioFormat audioFormat = new AudioFormat.Builder()
      .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
      .setChannelMask(AudioFormat.CHANNEL_OUT_5POINT1)
      .build();
    

Kiểm thử âm thanh không gian

Đảm bảo rằng tính năng âm thanh không gian đã bật trên thiết bị thử nghiệm của bạn:

  • Đối với tai nghe có dây, hãy chuyển đến phần Cài đặt hệ thống > Âm thanh và rung > Âm thanh không gian.
  • Đối với tai nghe không dây, hãy chuyển đến phần Cài đặt hệ thống > Thiết bị đã kết nối > Biểu tượng bánh răng cho thiết bị không dây của bạn > Âm thanh không gian.

Để kiểm tra xem tính năng Âm thanh không gian có dùng được cho định tuyến hiện tại hay không, hãy chạy lệnh adb shell dumpsys audio trên thiết bị của bạn. Bạn sẽ thấy các thông số sau trong đầu ra khi tính năng phát đang hoạt động:

Spatial audio:
mHasSpatializerEffect:true (effect present)
isSpatializerEnabled:true (routing dependent)