2013-04-04 33 views
9

Tôi có một ứng dụng mà tôi sử dụng chế độ phát trực tuyến AudioTrack để phát âm thanh được tạo động. Ứng dụng không phải trả lời tức thời các đầu vào, do đó, các vấn đề về độ trễ không làm phiền tôi cho phía đó của chương trình.Làm cách nào để xác định độ trễ âm thanh (AudioTrack) trên Android?

Vấn đề là tôi có hoạt ảnh cần phải chính xác 'đồng bộ' càng tốt với âm thanh và có vẻ như các thiết bị khác nhau có lượng thời gian khác nhau giữa thời điểm khi AudioTrack dừng chặn cuộc gọi write() và yêu cầu để biết thêm dữ liệu và khi âm thanh đó được phát từ loa.

Giải pháp hiện tại của tôi mang lại cho tôi hầu hết cách đó - Tôi đếm số khung hình mà tôi đã chuyển đến số AudioTrack cho đến nay và so sánh nó với getPlaybackHeadPosition(). Về cơ bản, nó trông giống như:

long currentTimeInFrames = 0; 
while(playingAudio) { 
    currentTimeInFrames += numberOfFramesToWrite; 
    long delayInFrames = (currentTimeInFrames - audioTrack.getPlaybackHeadPosition()); 
    audioTrack.write(frameBuffer,0,sampleSize); 
    doAnimationAfterDelay(delayInFrames); 
} 

Tuy nhiên, vẫn còn một số độ trễ mà getPlaybackHeadPosition() dường như không tính đến điều đó thay đổi theo thiết bị.

Có cách nào để thăm dò ý kiến ​​hệ thống về độ trễ của AudioTrack không?

Trả lời

1

Cân nhắc độ trễ của trình điều khiển. Có chức năng ẩn AudioManager.getOutputLatency (int) để có được điều này.

Gọi nó như thế này:

AudioManager am = (AudioManager)getSystemService(Context.AUDIO_SERVICE); 
try{ 
    Method m = am.getClass().getMethod("getOutputLatency", int.class); 
    latency = (Integer)m.invoke(am, AudioManager.STREAM_MUSIC); 
}catch(Exception e){ 
} 

tôi nhận được khoảng 45 - 50 ms trên các thiết bị khác nhau. Sử dụng kết quả tính toán của bạn.

+0

Lưu ý rằng trên một số thiết bị sẽ phát 'MethodNotFoundException' – zella

0

Bạn nên tính đến bộ đệm bạn đã chuyển vào trong quá trình tạo AudioTrack.

final int minBufSize = AudioTrack.getMinBufferSize(Application.PLAYRATE, 
AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT); 

out=new AudioTrack(AudioManager.STREAM_MUSIC, Application.PLAYRATE, 
AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT, minBufSize, 
AudioTrack.MODE_STREAM); 

extraLatencyFrames = minBufSize/4; 
+0

Hmm .. bây giờ tôi nghĩ lại. Nó sẽ là lạ nếu kích thước bộ đệm tối thiểu không được tính ở vị trí đầu. –

0

OK, đây là chìa khóa. Trước tiên, bạn cần phải mở rộng lớp Audiotrack, và sau đó sử dụng getNativeFrameCount để có một xấp xỉ về độ trễ liên quan đến phía gốc của sự vật.

class MyAudioTrack extends AudioTrack 
{ 
    public MyAudioTrack(int streamType, int sampleRateInHz, int channelConfig, 
      int audioFormat, int bufferSizeInBytes, int mode) 
      throws IllegalArgumentException { 
     super(streamType, sampleRateInHz, channelConfig, audioFormat, 
       bufferSizeInBytes, mode); 
     System.out.println("Native framecount "+getNativeFrameCount()); 
    } 
    public int getFrameCount() 
    { 
     return getNativeFrameCount(); 
    } 
} 
1

Cấp API 19 thêm phương thức trong AudioTrack được gọi là getTimeStamp(). Từ tài liệu:

Thăm dò dấu thời gian theo yêu cầu. Nếu bạn cần theo dõi dấu thời gian trong khi khởi động hoặc sau khi định tuyến hoặc thay đổi chế độ, bạn nên yêu cầu dấu thời gian định kỳ cho đến khi dấu thời gian báo cáo cho biết vị trí khung đang tiến hoặc cho đến khi dấu thời gian không có sẵn tuyến đường này.

Bạn chỉ định đối tượng AudioTimestamp làm tham số của hàm và nó sẽ điền vào vị trí khung "được trình bày" gần đây nhất cùng với dấu thời gian "ước tính" tính bằng nano giây. Giá trị nano giây tương ứng với giá trị mili giây được trả về bởi SystemClock.uptimeMillis().

Sau đó, bạn có thể xác định độ trễ bằng cách tìm ra khi bạn đã viết khung cụ thể đó thành AudioTrack so với khi getTimestamp() nghĩ rằng nó thực sự được trình bày. Tôi đã tìm thấy phương pháp này chính xác hơn các phương pháp khác được đề cập ở trên.

Bạn phải cẩn thận. Tài liệu hướng dẫn cho biết getTimeStamp() không được hỗ trợ trên tất cả các nền tảng hoặc tất cả các tuyến đường. Bạn có thể xác định xem cuộc gọi có thành công hay không bằng cách kiểm tra giá trị trả về boolean. Tôi đã tìm thấy với các thiết bị tôi đã thử nghiệm rằng hàm trả về false cho đến khi âm thanh bắt đầu trình bày, và sau đó các cuộc gọi tiếp theo trả về true. Tôi chỉ được thử nghiệm với AudioTrack ở chế độ STREAM_MUSIC. Số dặm của bạn có thể thay đổi.

Các vấn đề liên quan