Âm thanh có độ trễ thấp giúp các trò chơi có cảm giác chân thực và phản hồi nhanh hơn.
Hãy hoàn thành danh sách kiểm tra sau đây để bật âm thanh có độ trễ thấp trong trò chơi của bạn trên Android:
- Sử dụng Oboe
- Yêu cầu chế độ hiệu suất cao có "độ trễ thấp"
- Yêu cầu chế độ chia sẻ "độc quyền"
- Sử dụng 48000 Hz hoặc bộ chuyển đổi tốc độ lấy mẫu Oboe
- Đặt mức sử dụng thành AAUDIO_USAGE_GAME
- Sử dụng các lệnh gọi lại dữ liệu
- Tránh chặn các thao tác trong lệnh gọi lại
- Điều chỉnh dung lượng bộ nhớ đệm thành "vùng đệm kép"
1. Sử dụng API Oboe
API Oboe là một trình bao bọc C++ gọi AAudio trên Android 8.1 (API cấp 27) trở lên. Trên các phiên bản Android cũ, Oboe sử dụng OpenSL ES.
Oboe có trên GitHub hoặc dưới dạng tệp nhị phân tạo sẵn. Oboe cũng có một QuirksManager giúp khắc phục sự cố trên các thiết bị cụ thể, giúp ứng dụng của bạn tương thích với nhiều thiết bị hơn. Nếu bạn không thể sử dụng Oboe, hãy dùng trực tiếp AAudio.
2. Yêu cầu chế độ độ trễ thấp
Với Oboe hoặc AAudio, bạn có thể yêu cầu chế độ độ trễ thấp. Nếu không, bạn sẽ sử dụng chế độ độ trễ cao hơn theo mặc định.
Oboe
builder.setPerformanceMode(oboe::PerformanceMode::LowLatency);
AAudio
AAudioStreamBuilder_setPerformanceMode(builder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
3. Yêu cầu chế độ độc quyền
Bạn cũng có thể yêu cầu quyền truy cập độc quyền vào vùng đệm MMAP. Ứng dụng của bạn có thể không được hưởng quyền truy cập độc quyền, nhưng nếu có quyền truy cập độc quyền, thì ứng dụng sẽ ghi trực tiếp vào vùng đệm mà DSP đọc, giúp ứng dụng có độ trễ thấp nhất có thể.
Oboe
builder.setSharingMode(oboe::SharingMode::Exclusive);
AAudio
AAudioStreamBuilder_setSharingMode(builder, AAUDIO_SHARING_MODE_EXCLUSIVE);
4. Tránh chuyển đổi tốc độ lấy mẫu
Sử dụng tốc độ lấy mẫu tự nhiên của thiết bị. Bạn có thể thực hiện việc này bằng cách không chỉ định tốc độ lấy mẫu và gần như chắc chắn bạn sẽ nhận được 48000 Hz. Nếu bạn chỉ định tốc độ lấy mẫu, khung âm thanh sẽ gửi dữ liệu của bạn trên một đường dẫn khác có thể có độ trễ cao hơn nhiều.
Nếu bạn cần sử dụng một tốc độ lấy mẫu khác, hãy sử dụng Oboe để chuyển đổi tốc độ lấy mẫu:
builder->setSampleRateConversionQuality(oboe::SampleRateConversionQuality::Medium);
5. Khai báo đúng trường hợp sử dụng của bạn
Việc chỉ định lý do ứng dụng phát âm thanh là rất quan trọng để hệ thống áp dụng các chế độ cài đặt định tuyến, âm lượng và hiệu suất phù hợp. Ví dụ: các trò chơi nên chỉ báo mức sử dụng AAUDIO_USAGE_GAME
để tận dụng tối đa tính năng tối ưu hoá độ trễ, đặc biệt là khi kết nối với tai nghe Bluetooth.
Oboe
builder.setUsage(oboe::Usage::Game);
AAudio
AAudioStreamBuilder_setUsage(builder, AAUDIO_USAGE_GAME);
6. Sử dụng một hàm callback
Sử dụng một lệnh gọi lại cho luồng đầu ra. Nếu bạn dùng tính năng ghi chặn và bạn đang sử dụng một thiết bị không hỗ trợ chế độ AAudio MMAP, thì độ trễ có thể cao hơn nhiều.
Oboe
builder.setDataCallback(&myCallbackObject);
AAudio
AAudioStreamBuilder_setDataCallback(builder, &my_callback_proc);
7. Tránh chặn các thao tác trong lệnh gọi lại
Khi bạn sử dụng một luồng có độ trễ thấp, thời gian giữa các lệnh gọi lại có thể rất ngắn, chỉ vài mili giây. Vì vậy, bạn không được làm bất cứ việc gì trong lệnh gọi lại có thể chặn trong thời gian dài. Nếu lệnh gọi lại bị chặn, các vùng đệm sẽ bị tràn và xảy ra sự cố trong âm thanh.
Tránh thực hiện những thao tác sau trong một lệnh gọi lại:
- Phân bổ hoặc giải phóng bộ nhớ
- I/O tệp hoặc mạng
- Đang chờ một mutex hoặc khoá
- Ngủ
- Nhiều phép tính CPU một lần
Các lệnh gọi lại phải xử lý toán học với tốc độ đồng đều để phát mượt mà mà không gặp sự cố.
8. Điều chỉnh dung lượng bộ nhớ đệm
Sau khi ứng dụng mở luồng âm thanh, bạn cần điều chỉnh dung lượng bộ nhớ đệm có thể sử dụng để có độ trễ tối ưu. Oboe tự động đặt dung lượng bộ nhớ đệm thành 2 gói. Nhưng với AAudio, giá trị mặc định sẽ cao hơn nhiều. Sử dụng quy trình lưu vào bộ đệm kép bằng cách đặt dung lượng bộ nhớ đệm gấp đôi kích thước gói. Kích thước gói là kích thước lệnh gọi lại tối đa.
AAudio:
int32_t frames = AAudioStream_getFramesPerBurst() * 2;
AAudioStream_setBufferSizeInFrames(stream, frames);
Nếu dung lượng bộ nhớ đệm quá nhỏ, bạn có thể gặp sự cố do vùng đệm chạy dưới mức thông thường. Bạn có thể xem số sự cố bằng cách gọi AAudioStream_getXRunCount(stream)
. Tăng dung lượng bộ nhớ đệm nếu cần.
Xem Tài liệu về Oboe của GitHub để giải thích thuật ngữ liên quan đến vùng đệm.
OpenSL ES
Nếu đang hỗ trợ các phiên bản Android trước 8.1, bạn phải sử dụng OpenSL ES. Nếu đang sử dụng Oboe, bạn có thể định cấu hình ứng dụng để cải thiện độ trễ. Xem Thu được độ trễ tối ưu trong các tài liệu về GitHub.
Kết quả danh sách kiểm tra
Bảng sau đây chứa các phép đo OboeTester về độ trễ trọn vòng (từ đầu vào đến đầu ra).
Cấu hình | Độ trễ (mili giây) |
---|---|
Làm theo mọi nội dung đề xuất | 20 |
Chế độ hiệu suất cao không có độ trễ thấp | 205 |
Không ĐỘC QUYỀN (ĐÃ CHIA SẺ) | 26 |
44100 Hz (AAudio) | 160 |
44100 Hz (Oboe SRC) | 23 |
Không sử dụng lệnh gọi lại đầu ra (MMAP) | 21 |
Không sử dụng lệnh gọi lại đầu ra (không phải MMAP) | 62 |
Đã đặt dung lượng bộ nhớ đệm thành tối đa | 53 |