[alsa-devel] Audio DMA buffer layout

Markus Korber korbse at gmx.at
Thu May 10 12:52:20 CEST 2007


Thus spake Takashi Iwai:

First of all, thanks for your answer.  However, 

> At Tue, 08 May 2007 13:47:47 +0200,
> Markus Korber wrote:
>>
>>
>>      IRQ1 +----------------+
>>           | page_3 (right) |\
>>           +----------------+ > double buffer 1
>>           | page_2 (left)  |/
>>      IRQ0 +----------------+
>>           | page_1 (right) |\
>>           +----------------+ > double buffer 0
>>           | page_0 (left)  |/
>>           +----------------+
>
> If I understand correctly, the samples for a channel (e.g. left) is
> practically split to two regions, page 0 and page 2 in the above?

Correct.

> If yes, this h/w design is hard to implement mmap mode
> straightforwardly because the alsa-lib (and apps) assume "linear"
> buffers.  For normal read/write without mmap, this shouldn't be that
> hard as you guess, though.

Are there any drawbacks if I use the R/W mode without mmap, regarding
applications (mplayer), dmix, etc.?

Furthermore, in mmap mode, I think I could use an intermediate buffer
(with the layout as above), where I copy the data from the (linear)
mmap'd buffer to, could I?  Maybe using helpers from struct
pcm-indirect.h?  But this is not very beautiful.

> A workaround would be to use SG-buffer (if possible).  The constraint
> is thta both double buffers above have to be aligned in PAGE_SIZE
> (depending on architecture, 4KB mostly).

It's a custom chip with an ARM core and an AMBA-AHB bus.  PAGE_SIZE
alignment wouldn't be a problem, although then buffer_size would be
fixed to multiples of PAGE_SIZE, i guess?

I'm not quite sure how to implement this:

chip_pcm_new
        - snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
                snd_dma_continuous_data(GFP_KERNEL), PAGE_SIZE, PAGE_SIZE)

chip_hw_params
        - snd_pcm_lib_malloc_pages(substream,
                                   params_buffer_bytes(hw_params))
        - map sg-pages with snd_pcm_sgbuf_get_addr()
        
        Why/How?

I mean, my hardware DMA layout is fixed (apart from the double buffer
page sizes, which should be a multiple of PAGE_SIZE).  
So do I have to call snd_pcm_lib_malloc_pages() and/or do I need to call
dma_map_sg() with a scatterlist?  Or how do I tell ALSA about my DMA
layout?  And how is the application informed about this?

> For implementing a SG buffer, you can use either mmap or page pcm_ops.
> The mmap is to do the whole mmap operation, so you can do all what
> you'd like.

My understanding is, that the application mmap's my allocated buffer
(currently allocated with dma_alloc_writecombine) and the ALSA library
tells it, where it is allowed to put its data.  (ALSA gets this info
through the pointer() callback and calls to snd_pcm_period_elapsed.)
Thus, this mmap() callback is only called once in normal mmap mode.

Now, if I would use a SG approach, how would I handle this mmap
operation in my callback?  I guess, I have to provide similar
functionality as in dma_mmap() but with 2 different base addresses?

> The page is a callback used by the default ALSA mmap handler and you
> can return the page pointer corresponding to the given buffer offset.

This approach looks easier to me.  Am I right, that here I would just
call snd_pcm_sgbuf_ops_page() from my page() callback handler?  What
else do I need to do in this case to let the application know which
buffer it should fill?

Regards,
Markus Korber


More information about the Alsa-devel mailing list