2013-02-07 26 views
7

Tôi cố gắng sử dụng ALSA để lấy đầu vào từ thiết bị âm thanh USB và ghi nó ra đĩa dưới dạng một loạt giá trị signed short. Những gì tôi kết thúc với là những khối có vẻ là dữ liệu hợp lệ xen kẽ với các khối không lớn. Tôi đoán rằng tôi có bộ đệm của tôi thiết lập không chính xác và không sử dụng ánh xạ bộ nhớ đúng cách.Ghi âm từ ALSA - hiểu bản đồ bộ nhớ

Những gì tôi đang cố gắng:

  • mẫu tỷ lệ: 8K (điều này được buộc bởi các thiết bị)
  • kích thước bộ đệm: 2048
  • kích thước khoảng thời gian: 512
  • một kênh

Thiết bị có vẻ như đã được mở rly và chấp nhận các thông số khác nhau. Sau khi thiết lập một số vòng lặp chạy như sau:

snd_pcm_avail_update 
snd_pcm_mmap_begin 
    memcpy data from mmap buffer to array of short 
snd_pcm_mmap_commit 

Memcpy là một con trỏ tới mảng ngắn và được tăng lên bởi số khung được trả về mỗi lần truyền.

Sau khi bản ghi này trong vài giây, tôi đóng nó và ghi bộ đệm tiếp theo vào đĩa dưới dạng một giá trị ngắn trên mỗi dòng. Những gì tôi mong đợi là một hoặc hai giây dữ liệu PCM thay đổi từ 1200 đến 2300 Hz. Những gì tôi nhận được là một số dữ liệu với nhiều số không.

Điều tôi đang tự hỏi là: giá trị của tôi cho bộ đệm và thời gian hợp lý? Có ai đã thành công trong việc sử dụng đầu ra được ánh xạ bộ nhớ từ ALSA không?

EDIT: Một số mã

const snd_pcm_channel_area_t *areas; 
snd_pcm_uframes_t offset, frames, size; 
short* pCID = (short*)malloc(50000 * sizeof(short)); 
short* ppCID = pCID; 
while(size > 0) 
{ 
    frames = size; 
    snd_pcm_mmap_begin (device, &areas, &offset, &frames);  
    short* pd = (short*)areas[0].addr; 
    memcpy(ppCID, (pd + (offset*sizeof(short))), frames * sizeof(short)); 
    ppCID += frames; 
    snd_pcm_mmap_commit(device, offset, frames); 

    size -= frames; 
} 

(kiểm tra lỗi xóa do rõ ràng)
Khi tất cả được nói và làm tôi vòng qua PCID và ghi vào đĩa. Một giá trị trên mỗi dòng.

Trả lời

5

Có một known bug bằng trình điều khiển âm thanh USB trên ARM, nơi bản đồ của hạt nhân và bản đồ của cùng một bộ đệm có thể không phải là bộ nhớ cache kết hợp.

Sử dụng chức năng ánh xạ bộ nhớ ALSA chỉ có nghĩa là chỉ khi mã có thể xử lý trực tiếp mẫu mà không cần sao chép chúng vào bộ đệm khác. Nếu bạn sao chép chúng, bạn đang thực hiện chính xác cùng một sốsnd_pcm_readi đã làm. Nói cách khác, chỉ cần không sử dụng ánh xạ bộ nhớ.

Khi chụp, kích thước bộ đệm không ảnh hưởng đến độ trễ, vì vậy bạn nên làm cho nó càng lớn càng tốt để tránh có thể bị tràn ngập.

Kích thước khoảng thời gian nhỏ hơn cho bạn độ trễ thấp hơn, nhưng chương trình của bạn không liên quan gì đến thời gian thực, vì vậy bạn có thể sử dụng kích thước khoảng thời gian lớn hơn để tiết kiệm một chút năng lượng.

1

Từ documentation: "Cần gọi hàm snd_pcm_avail_update() ngay trước cuộc gọi này. Nếu không, hàm này có thể trả về số lượng khung hình khả dụng sai". Tôi cho rằng vấn đề là snd_pcm_mmap_begin đang báo cáo nhầm số lượng khung hình sẵn có và do đó bạn đang đọc từ một khu vực chưa được ghi vào.

Ngoài ra, tôi không tích cực, nhưng tôi không nghĩ rằng các hàm alsa mmap sẽ chặn cho đến khi có dữ liệu, mặc dù có thể được bao phủ bởi mã khác mà tôi không thấy ở đây. Nó không hoàn toàn giống như một tập tin mmap, do đó, không bắt đầu nghĩ rằng nó được. Nếu quạt của bạn bắt đầu phát điên và mọi thứ trở nên chậm chạp, rất có thể mã của bạn đang chuyển từ ứng dụng sang ngữ cảnh hạt nhân và lại liên tục khi không có byte nào được đọc.

Như áp phích trước đã lưu ý, đây là trường hợp sử dụng hoàn hảo cho snd_pcm_readi, vì vậy hãy sử dụng nó.

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