Âm thanh ô tô

Android Automotive OS (AAOS) được xây dựng dựa trên ngăn xếp âm thanh cốt lõi của Android để hỗ trợ các trường hợp sử dụng khi hoạt động như hệ thống thông tin giải trí trong ô tô. AAOS chịu trách nhiệm về âm thanh thông tin giải trí (tức là âm thanh đa phương tiện, chỉ đường và giao tiếp) nhưng không trực tiếp chịu trách nhiệm về chuông báo và cảnh báo có yêu cầu nghiêm ngặt về thời gian và phạm vi cung cấp. Mặc dù AAOS cung cấp các tín hiệu và cơ chế để giúp xe quản lý âm thanh, nhưng cuối cùng, xe sẽ quyết định âm thanh nào sẽ phát cho người lái xe và hành khách, đảm bảo âm thanh quan trọng về an toàn và âm thanh theo quy định được nghe đúng cách mà không bị gián đoạn.

Vì Android quản lý trải nghiệm đa phương tiện của xe, nên các nguồn nội dung đa phương tiện bên ngoài (chẳng hạn như bộ thu sóng) phải được các ứng dụng đại diện. Các ứng dụng này có thể xử lý tiêu điểm âm thanh và sự kiện phím đa phương tiện cho nguồn.

Android 11 có các thay đổi sau đây đối với tính năng hỗ trợ âm thanh liên quan đến ô tô:

Âm thanh và luồng Android

Hệ thống âm thanh trên ô tô xử lý các âm thanh và luồng sau:

Sơ đồ cấu trúc tập trung vào luồng

Hình 1. Sơ đồ cấu trúc tập trung vào luồng

Android quản lý âm thanh phát ra từ các ứng dụng Android, kiểm soát các ứng dụng đó và định tuyến âm thanh của các ứng dụng đó đến các thiết bị đầu ra tại HAL dựa trên loại âm thanh:

  • Luồng logic (còn gọi là nguồn trong cách gọi tên âm thanh cốt lõi) được gắn thẻ Thuộc tính âm thanh.
  • Luồng thực (còn gọi là thiết bị trong cách gọi tên âm thanh cốt lõi) không có thông tin ngữ cảnh sau khi trộn.

Để đảm bảo độ tin cậy, âm thanh bên ngoài (đến từ các nguồn độc lập như chuông cảnh báo thắt dây an toàn) được quản lý bên ngoài Android, bên dưới HAL hoặc thậm chí trong phần cứng riêng biệt. Người triển khai hệ thống phải cung cấp một bộ trộn chấp nhận một hoặc nhiều luồng đầu vào âm thanh từ Android, sau đó kết hợp các luồng đó theo cách phù hợp với các nguồn âm thanh bên ngoài mà xe yêu cầu.

Việc triển khai HAL và bộ trộn bên ngoài chịu trách nhiệm đảm bảo âm thanh bên ngoài quan trọng về an toàn được nghe thấy, cũng như trộn các luồng do Android cung cấp và định tuyến các luồng đó đến loa phù hợp.

Âm thanh Android

Ứng dụng có thể có một hoặc nhiều trình phát tương tác thông qua các API Android tiêu chuẩn (ví dụ: AudioManager để kiểm soát tiêu điểm hoặc MediaPlayer để truyền trực tuyến) để phát một hoặc nhiều luồng dữ liệu âm thanh logic. Dữ liệu này có thể là âm thanh đơn âm một kênh hoặc âm thanh vòm 7.1, nhưng được định tuyến và coi là một nguồn duy nhất. Luồng ứng dụng được liên kết với AudioAttributes để đưa ra gợi ý cho hệ thống về cách thể hiện âm thanh.

Các luồng logic được gửi qua AudioService và được định tuyến đến một (và chỉ một) luồng đầu ra vật lý có sẵn, mỗi luồng là đầu ra của một bộ trộn trong AudioFlinger. Sau khi các thuộc tính âm thanh được kết hợp thành một luồng thực, các thuộc tính đó sẽ không còn nữa.

Sau đó, mỗi luồng thực sẽ được phân phối đến Audio HAL để kết xuất trên phần cứng. Trong các ứng dụng ô tô, phần cứng kết xuất có thể là bộ mã hoá và giải mã cục bộ (tương tự như thiết bị di động) hoặc bộ xử lý từ xa trên mạng thực của xe. Dù bằng cách nào, việc triển khai Audio HAL cũng là để phân phối dữ liệu mẫu thực tế và giúp dữ liệu đó trở nên nghe được.

Luồng bên ngoài

Các luồng âm thanh không được định tuyến qua Android (vì lý do chứng nhận hoặc thời gian) có thể được gửi trực tiếp đến bộ trộn bên ngoài. Kể từ Android 11, HAL hiện có thể yêu cầu tiêu điểm cho những âm thanh bên ngoài này để thông báo cho Android để có thể thực hiện các hành động thích hợp như tạm dừng nội dung nghe nhìn hoặc ngăn các âm thanh khác lấy tiêu điểm.

Nếu luồng bên ngoài là nguồn nội dung nghe nhìn cần tương tác với môi trường âm thanh mà Android đang tạo (ví dụ: dừng phát MP3 khi bật bộ chỉnh âm bên ngoài), thì các luồng bên ngoài đó phải được biểu thị bằng ứng dụng Android. Ứng dụng như vậy sẽ thay mặt nguồn nội dung nghe nhìn yêu cầu quyền phát âm thanh thay vì HAL và sẽ phản hồi thông báo về quyền phát bằng cách bắt đầu/dừng nguồn bên ngoài nếu cần để phù hợp với chính sách về quyền phát của Android. Ứng dụng cũng chịu trách nhiệm xử lý các sự kiện nhấn phím đa phương tiện như phát/tạm dừng. Một cơ chế được đề xuất để điều khiển các thiết bị bên ngoài như vậy là HwAudioSource.

Thiết bị đầu ra

Ở cấp độ Audio HAL, loại thiết bị AUDIO_DEVICE_OUT_BUS cung cấp một thiết bị đầu ra chung để sử dụng trong hệ thống âm thanh trên ô tô. Thiết bị bus hỗ trợ các cổng có thể định địa chỉ (trong đó mỗi cổng là điểm cuối của luồng vật lý) và dự kiến sẽ là loại thiết bị đầu ra duy nhất được hỗ trợ trong xe.

Việc triển khai hệ thống có thể sử dụng một cổng bus cho tất cả âm thanh trên Android, trong trường hợp này, Android sẽ kết hợp mọi thứ lại với nhau và phân phối dưới dạng một luồng. Ngoài ra, HAL có thể cung cấp một cổng bus cho mỗi CarAudioContext để cho phép phân phối đồng thời mọi loại âm thanh. Điều này cho phép việc triển khai HAL kết hợp và giảm âm lượng các âm thanh khác nhau theo ý muốn.

Việc chỉ định ngữ cảnh âm thanh cho thiết bị đầu ra được thực hiện thông qua car_audio_configuration.xml.

Đầu vào micrô

Khi ghi âm, Audio HAL sẽ nhận được lệnh gọi openInputStream có đối số AudioSource cho biết cách xử lý đầu vào micrô.

Nguồn VOICE_RECOGNITION (cụ thể là Trợ lý Google) dự kiến một luồng micrô âm thanh nổi có hiệu ứng loại bỏ tiếng vọng (nếu có) nhưng không áp dụng bất kỳ quy trình xử lý nào khác cho luồng đó. Trợ lý dự kiến sẽ thực hiện tính năng định hướng chùm.

Đầu vào micrô nhiều kênh

Để ghi âm từ một thiết bị có nhiều hơn hai kênh (âm thanh nổi), hãy sử dụng mặt nạ chỉ mục kênh thay vì mặt nạ chỉ mục vị trí (chẳng hạn như CHANNEL_IN_LEFT). Ví dụ:

final AudioFormat audioFormat = new AudioFormat.Builder()
    .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
    .setSampleRate(44100)
    .setChannelIndexMask(0xf /* 4 channels, 0..3 */)
    .build();
final AudioRecord audioRecord = new AudioRecord.Builder()
    .setAudioFormat(audioFormat)
    .build();
audioRecord.setPreferredDevice(someAudioDeviceInfo);

Khi bạn đặt cả setChannelMasksetChannelIndexMask, AudioRecord chỉ sử dụng giá trị do setChannelMask đặt (tối đa là hai kênh).

Chụp đồng thời

Kể từ Android 10, khung Android hỗ trợ tính năng ghi lại đồng thời các dữ liệu đầu vào, nhưng có các quy định hạn chế để bảo vệ quyền riêng tư của người dùng. Trong số các quy định hạn chế này, các nguồn ảo như AUDIO_SOURCE_FM_TUNER sẽ bị bỏ qua và do đó được phép ghi lại đồng thời với một đầu vào thông thường (chẳng hạn như micrô). HwAudioSources cũng không được coi là một phần của các quy định hạn chế về việc chụp đồng thời.

Các ứng dụng được thiết kế để hoạt động với thiết bị AUDIO_DEVICE_IN_BUS hoặc với thiết bị AUDIO_DEVICE_IN_FM_TUNER phụ phải dựa vào việc xác định rõ ràng các thiết bị đó và sử dụng AudioRecord.setPreferredDevice() để bỏ qua logic lựa chọn nguồn mặc định của Android.

Cách sử dụng âm thanh

AAOS chủ yếu sử dụng AudioAttributes.AttributeUsages để định tuyến, điều chỉnh âm lượng và quản lý tiêu điểm. Lượt sử dụng là một đại diện cho "lý do" luồng đang được phát. Do đó, tất cả các luồng và yêu cầu lấy tiêu điểm âm thanh phải chỉ định cách sử dụng để phát âm thanh. Khi không được đặt cụ thể khi tạo đối tượng AudioAttributes, chế độ sử dụng sẽ được đặt mặc định thành USAGE_UNKNOWN. Mặc dù hiện tại, hành vi này được xử lý giống như USAGE_MEDIA, nhưng bạn không nên dựa vào hành vi này để phát nội dung nghe nhìn.

Mức sử dụng hệ thống

Trong Android 11, chúng tôi đã giới thiệu các mức sử dụng hệ thống. Các cách sử dụng này hoạt động tương tự như các cách sử dụng đã thiết lập trước đó, ngoại trừ việc chúng yêu cầu các API hệ thống cũng như android.permission.MODIFY_AUDIO_ROUTING. Các cách sử dụng hệ thống mới là:

  • USAGE_EMERGENCY
  • USAGE_SAFETY
  • USAGE_VEHICLE_STATUS
  • USAGE_ANNOUNCEMENT

Để tạo một AudioAttributes có mức sử dụng hệ thống, hãy sử dụng AudioAttributes.Builder#setSystemUsage thay vì setUsage. Việc gọi phương thức này với mục đích sử dụng không phải của hệ thống sẽ dẫn đến việc IllegalArgumentException bị gửi đi. Ngoài ra, nếu bạn đã đặt cả mức sử dụng hệ thống và mức sử dụng trên một trình tạo, thì trình tạo đó sẽ gửi một IllegalArgumentException khi tạo.

Để kiểm tra mức sử dụng được liên kết với một thực thể AudioAttributes, hãy gọi AudioAttributes#getSystemUsage. Thao tác này sẽ trả về mức sử dụng hoặc mức sử dụng hệ thống được liên kết.

Ngữ cảnh âm thanh

Để đơn giản hoá cấu hình âm thanh AAOS, các cách sử dụng tương tự đã được nhóm vào CarAudioContext. Các ngữ cảnh âm thanh này được sử dụng trong toàn bộ CarAudioService để xác định việc định tuyến, nhóm âm lượng và quản lý tiêu điểm âm thanh.

Các ngữ cảnh âm thanh trong Android 11 là:

CarAudioContext Các AttributeUsages được liên kết
MUSIC UNKNOWN, GAME, MEDIA
NAVIGATION ASSISTANCE_NAVIGATION_GUIDANCE
VOICE_COMMAND ASSISTANT, ASSISTANCE_ACCESSIBILITY
CALL_RING NOTIFICATION_RINGTONE
CALL VOICE_COMMUNICATION, VOICE_COMMUNICATION_SIGNALING
ALARM ALARM
NOTIFICATION NOTIFICATION, NOTIFICATION_*
SYSTEM_SOUND ASSISTANCE_SONIFICATION
EMERGENCY EMERGENCY
SAFETY SAFETY
VEHICLE_STATUS VEHICLE_STATUS
ANNOUNCEMENT ANNOUNCEMENT

Ánh xạ giữa ngữ cảnh âm thanh và cách sử dụng. Các hàng được làm nổi bật là dành cho các cách sử dụng hệ thống mới.

Âm thanh nhiều vùng

Với ngành ô tô, bạn có một bộ trường hợp sử dụng mới liên quan đến việc người dùng đồng thời tương tác với nền tảng và muốn sử dụng nội dung nghe nhìn riêng biệt. Ví dụ: người lái xe có thể phát nhạc trong khoang cabin trong khi hành khách ở ghế sau đang xem video trên YouTube trên màn hình sau. Âm thanh nhiều vùng cho phép điều này bằng cách cho phép nhiều nguồn âm thanh phát đồng thời qua nhiều khu vực của xe.

Tính năng âm thanh nhiều vùng bắt đầu từ Android 10 cho phép nhà sản xuất thiết bị gốc (OEM) định cấu hình âm thanh thành các vùng riêng biệt. Mỗi vùng là một tập hợp các thiết bị trong xe với các nhóm âm lượng, cấu hình định tuyến cho ngữ cảnh và chức năng quản lý tiêu điểm riêng. Theo cách này, khoang chính có thể được định cấu hình là một vùng âm thanh, trong khi giắc cắm tai nghe của màn hình sau được định cấu hình là vùng thứ hai.

Các vùng được xác định là một phần của car_audio_configuration.xml. Sau đó, CarAudioService sẽ đọc cấu hình và giúp AudioService định tuyến luồng âm thanh dựa trên vùng liên kết của chúng. Mỗi vùng vẫn xác định các quy tắc định tuyến dựa trên ngữ cảnh và uid của ứng dụng. Khi một trình phát được tạo, CarAudioService sẽ xác định trình phát được liên kết với vùng nào, sau đó dựa trên mức sử dụng, AudioFlinger sẽ định tuyến âm thanh đến thiết bị nào.

Tiêu điểm cũng được duy trì độc lập cho từng vùng âm thanh. Điều này cho phép các ứng dụng ở các vùng khác nhau tạo âm thanh độc lập mà không gây cản trở cho nhau, trong khi các ứng dụng vẫn tuân theo các thay đổi về tiêu điểm trong vùng của chúng. CarZonesAudioFocus trong CarAudioService chịu trách nhiệm quản lý tiêu điểm cho từng vùng.

Định cấu hình âm thanh nhiều vùng

Hình 2. Định cấu hình âm thanh nhiều vùng

Audio HAL

Việc triển khai âm thanh trên ô tô dựa vào HAL Âm thanh Android tiêu chuẩn, bao gồm:

  • IDevice.hal. Tạo luồng đầu vào và đầu ra, xử lý âm lượng chính và tắt tiếng, đồng thời sử dụng:
    • createAudioPatch. Để tạo bản vá bên ngoài-bên ngoài giữa các thiết bị.
    • IDevice.setAudioPortConfig() để cung cấp âm lượng cho mỗi luồng thực.
  • IStream.hal. Cùng với các biến thể đầu vào và đầu ra, quản lý việc truyền trực tuyến các mẫu âm thanh đến và đi từ phần cứng.

Các loại thiết bị ô tô

Các loại thiết bị sau đây phù hợp với nền tảng ô tô.

Loại thiết bị Mô tả
AUDIO_DEVICE_OUT_BUS Đầu ra chính từ Android (đây là cách tất cả âm thanh từ Android được phân phối đến xe). Được dùng làm địa chỉ để phân biệt luồng cho từng ngữ cảnh.
AUDIO_DEVICE_OUT_TELEPHONY_TX Dùng cho âm thanh được định tuyến đến đài phát thanh di động để truyền.
AUDIO_DEVICE_IN_BUS Dùng cho dữ liệu đầu vào không được phân loại theo cách khác.
AUDIO_DEVICE_IN_FM_TUNER Chỉ dùng cho đầu vào đài phát thanh truyền hình.
AUDIO_DEVICE_IN_TV_TUNER Dùng cho thiết bị TV (nếu có).
AUDIO_DEVICE_IN_LINE Dùng cho giắc cắm đầu vào AUX.
AUDIO_DEVICE_IN_BLUETOOTH_A2DP Nhạc nhận được qua Bluetooth.
AUDIO_DEVICE_IN_TELEPHONY_RX Dùng cho âm thanh nhận được từ đài phát thanh di động liên kết với một cuộc gọi điện thoại.

Định cấu hình thiết bị âm thanh

Các thiết bị âm thanh hiển thị với Android phải được xác định trong /audio_policy_configuration.xml, bao gồm các thành phần sau:

  • tên mô-đun. Hỗ trợ "chính" (dùng cho các trường hợp sử dụng trong ô tô), "A2DP", "remote_submix" và "USB". Tên mô-đun và trình điều khiển âm thanh tương ứng phải được biên dịch thành audio.primary.$(variant).so.
  • devicePorts. Chứa danh sách chỉ số mô tả thiết bị cho tất cả thiết bị đầu vào và đầu ra (bao gồm cả thiết bị được gắn vĩnh viễn và thiết bị có thể tháo rời) có thể truy cập được từ mô-đun này.
    • Đối với mỗi thiết bị đầu ra, bạn có thể xác định chế độ điều khiển độ lợi bao gồm các giá trị tối thiểu/tối đa/mặc định/bước tính bằng millibel (1 millibel = 1/100 dB = 1/1000 bel).
    • Bạn có thể dùng thuộc tính địa chỉ trên một thực thể devicePort để tìm thiết bị, ngay cả khi có nhiều thiết bị có cùng loại thiết bị với AUDIO_DEVICE_OUT_BUS.
  • mixPorts. Chứa danh sách tất cả luồng đầu ra và đầu vào do HAL âm thanh hiển thị. Mỗi thực thể mixPort có thể được coi là một luồng thực tế đến Android AudioService.
  • tuyến đường. Xác định danh sách các kết nối có thể có giữa thiết bị đầu vào và đầu ra hoặc giữa luồng và thiết bị.

Ví dụ sau đây xác định một thiết bị đầu ra bus0_phone_out, trong đó tất cả luồng âm thanh Android được trộn bằng mixer_bus0_phone_out. Tuyến này sẽ lấy dòng đầu ra của mixer_bus0_phone_out đến thiết bị bus0_phone_out.

<audioPolicyConfiguration version="1.0" xmlns:xi="http://www.w3.org/2001/XInclude">
    <modules>
        <module name="primary" halVersion="3.0">
            <attachedDevices>
                <item>bus0_phone_out</item>
<defaultOutputDevice>bus0_phone_out</defaultOutputDevice>
            <mixPorts>
                <mixPort name="mixport_bus0_phone_out"
                         role="source"
                         flags="AUDIO_OUTPUT_FLAG_PRIMARY">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                            samplingRates="48000"
                            channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                </mixPort>
            </mixPorts>
            <devicePorts>
                <devicePort tagName="bus0_phone_out"
                            role="sink"
                            type="AUDIO_DEVICE_OUT_BUS"
                            address="BUS00_PHONE">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                            samplingRates="48000"
                            channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                    <gains>
                        <gain name="" mode="AUDIO_GAIN_MODE_JOINT"
                                minValueMB="-8400"
                                maxValueMB="4000"
                                defaultValueMB="0"
                                stepValueMB="100"/>
                    </gains>
                </devicePort>
            </devicePorts>
            <routes>
                <route type="mix" sink="bus0_phone_out"
                       sources="mixport_bus0_phone_out"/>
            </routes>
        </module>
    </modules>
</audioPolicyConfiguration>