* Re: Questions about writing a new ALSA driver for a very limitted device
[not found] <s5hwt0cvgjg.wl%tiwai@suse.de>
@ 2007-04-19 21:30 ` Tim Harvey
2007-04-24 13:13 ` Takashi Iwai
0 siblings, 1 reply; 4+ messages in thread
From: Tim Harvey @ 2007-04-19 21:30 UTC (permalink / raw)
To: alsa-devel
--- Takashi Iwai <tiwai@suse.de> wrote:
> The "period" defines the frequency to update the status, usually via
> the invokation of interrupts. The "period_size" defines the frame
> sizes corresponding to the "period time". This term corresponds to
> the "fragment size" on OSS. On major sound hardwares, a ring-buffer
> is divided to several parts and an irq is issued on each boundary.
> The period_size defines the size of this chunk.
>
> On some hardwares, the irq is controlled on the basis of a timer. In
> this case, the period is defined as the timer frequency to invoke an
> irq.
>
>
My system has a hardware buffer of 4096 bytes (so I will use an intermediate
buffer ) and is fixed at 8KHz 16bit stereo. The 4K hw buffer would accommodate
128ms of data which is pretty small. Therefore I'll choose to use a 32K
intermediate buffer which will accommodate about 1sec of audio data. My IRQ is
timer based so I will need to decide upon a reasonable period. As the period
seems to dictate the ability for the middle layer to see the status of the
buffer I'll use 4 periods allowing a 250ms granularity in my intermediate
buffer.
I'm assuming that the snd_pcm_hardware struct has a min AND max period_bytes
and periods because the framesize can vary if your hardware supports multiple
configurations. As mine only supports 8Khz 16bit stereo, my min/max values
should all be the same correct?
So using the above info my struct should look like:
static snd_pcm_hardware_t snd_my_playback_hw = {
.info = (SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID),
.formats = SNDRV_PCM_FMTBIT_U16_BE,
.rates = SNDRV_PCM_RATE_8000,
.rate_min = 8000,
.rate_max = 8000,
.channels_min = 2,
.channels_max = 2,
.buffer_bytes_max = 32768,
.period_bytes_min = 8192,
.period_bytes_max = 8192,
.periods_min = 4,
.periods_max = 4,
};
Does this seem reasonable?
Because I'm using a 32K intermediate buffer I'll preallocate it with
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
snd_dma_continuous_data(GFP_KERNEL), 0, 32768);
I want to make sure I'm implementing things properly for full duplex
capability. I'm creating the pcm device via:
snd_pcm_new(card, "my dev", 0, 1 /* play streams */, 1 /* capt streams */,
&pcm)
If I understand this preallocation a 32K DMAable buffer will be allocated by
ALSA for each stream my device can play/capture (= 2 streams, 1 playback and 1
capture). I can obtain the buffer pre-allocated from the runtime data in the
prepare callback and use that buffer as my intermediate buffer correct? I
don't have a great grasp of the 'prepare' callback yet, but because thats the
first time you've got access to valid format/buffer info I'll assume that each
time 'prepare' is called your PCM buffer/hardware/stream should be initialized.
If I understand correctly the pointer callback should return the num of frames
processed in the 'intermediate buffer'. Because this is a virtual ring buffer,
I guess I should simply return the offset in the buffer (divided by my
bytes_per_frame which is 4) that I last pulled data from?
I've looked at the example dealing with the hw interrupt and period_elapsed in
http://www.alsa-project.org/~iwai/writing-an-alsa-driver/x773.htm. The example
doesn't specify where it was getting runtime pointer from so I am assuming that
I'll need to keep a pointer to each (playback and capture) substream so that I
can call period_elapsed appropriately for each if they are concurrent?
Thanks for all the help. I've got rudimentary playback working but I'm pretty
sure I'm not implementing the period_elapsed and the pointer callback correctly
as the relatively simple playback app I'm using sits for a few seconds after
playback of the 2 sec test sample I'm using completes.
Tim
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: Questions about writing a new ALSA driver for a very limitted device
2007-04-19 21:30 ` Questions about writing a new ALSA driver for a very limitted device Tim Harvey
@ 2007-04-24 13:13 ` Takashi Iwai
0 siblings, 0 replies; 4+ messages in thread
From: Takashi Iwai @ 2007-04-24 13:13 UTC (permalink / raw)
To: Tim Harvey; +Cc: alsa-devel
At Thu, 19 Apr 2007 14:30:29 -0700 (PDT),
Tim Harvey wrote:
>
>
> --- Takashi Iwai <tiwai@suse.de> wrote:
>
> > The "period" defines the frequency to update the status, usually via
> > the invokation of interrupts. The "period_size" defines the frame
> > sizes corresponding to the "period time". This term corresponds to
> > the "fragment size" on OSS. On major sound hardwares, a ring-buffer
> > is divided to several parts and an irq is issued on each boundary.
> > The period_size defines the size of this chunk.
> >
> > On some hardwares, the irq is controlled on the basis of a timer. In
> > this case, the period is defined as the timer frequency to invoke an
> > irq.
> >
> >
>
> My system has a hardware buffer of 4096 bytes (so I will use an intermediate
> buffer ) and is fixed at 8KHz 16bit stereo. The 4K hw buffer would accommodate
> 128ms of data which is pretty small. Therefore I'll choose to use a 32K
> intermediate buffer which will accommodate about 1sec of audio data. My IRQ is
> timer based so I will need to decide upon a reasonable period. As the period
> seems to dictate the ability for the middle layer to see the status of the
> buffer I'll use 4 periods allowing a 250ms granularity in my intermediate
> buffer.
>
> I'm assuming that the snd_pcm_hardware struct has a min AND max period_bytes
> and periods because the framesize can vary if your hardware supports multiple
> configurations. As mine only supports 8Khz 16bit stereo, my min/max values
> should all be the same correct?
>
> So using the above info my struct should look like:
>
> static snd_pcm_hardware_t snd_my_playback_hw = {
> .info = (SNDRV_PCM_INFO_MMAP |
> SNDRV_PCM_INFO_INTERLEAVED |
> SNDRV_PCM_INFO_BLOCK_TRANSFER |
> SNDRV_PCM_INFO_MMAP_VALID),
> .formats = SNDRV_PCM_FMTBIT_U16_BE,
> .rates = SNDRV_PCM_RATE_8000,
> .rate_min = 8000,
> .rate_max = 8000,
> .channels_min = 2,
> .channels_max = 2,
> .buffer_bytes_max = 32768,
> .period_bytes_min = 8192,
> .period_bytes_max = 8192,
> .periods_min = 4,
> .periods_max = 4,
> };
>
> Does this seem reasonable?
Should be OK, but maybe more finer periods would be better, I guess.
But this depends on the irq source you can use.
> Because I'm using a 32K intermediate buffer I'll preallocate it with
> snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
> snd_dma_continuous_data(GFP_KERNEL), 0, 32768);
>
> I want to make sure I'm implementing things properly for full duplex
> capability. I'm creating the pcm device via:
>
> snd_pcm_new(card, "my dev", 0, 1 /* play streams */, 1 /* capt streams */,
> &pcm)
>
> If I understand this preallocation a 32K DMAable buffer will be allocated by
> ALSA for each stream my device can play/capture (= 2 streams, 1 playback and 1
> capture). I can obtain the buffer pre-allocated from the runtime data in the
> prepare callback and use that buffer as my intermediate buffer
> correct?
If you call snd_pcm_lib_malloc_pages() in hw_params callback (and
snd_pcm_lib_free_pages() in hw_free callback). Otherwise, the
pre-allocated buffer won't be assigned to the stream at all.
> I
> don't have a great grasp of the 'prepare' callback yet, but because thats the
> first time you've got access to valid format/buffer info I'll assume that each
> time 'prepare' is called your PCM buffer/hardware/stream should be initialized.
>
> If I understand correctly the pointer callback should return the num of frames
> processed in the 'intermediate buffer'. Because this is a virtual ring buffer,
> I guess I should simply return the offset in the buffer (divided by my
> bytes_per_frame which is 4) that I last pulled data from?
Exactly. It's an offset between 0 and (buffer_size-1).
> I've looked at the example dealing with the hw interrupt and period_elapsed in
> http://www.alsa-project.org/~iwai/writing-an-alsa-driver/x773.htm. The example
> doesn't specify where it was getting runtime pointer from so I am assuming that
> I'll need to keep a pointer to each (playback and capture) substream so that I
> can call period_elapsed appropriately for each if they are concurrent?
Yes.
Takashi
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: Questions about writing a new ALSA driver for a very limitted device
@ 2007-04-26 22:30 Tim Harvey
2007-04-27 17:09 ` Takashi Iwai
0 siblings, 1 reply; 4+ messages in thread
From: Tim Harvey @ 2007-04-26 22:30 UTC (permalink / raw)
To: alsa-devel
Thanks to the help I've gotten on this list my alsa driver is working great. I
got a little hung up not realizing that the alsa core basically provides
everything you need to implement your own circular buffer if you need to use an
intermediate buffer.
The only question I still have is that if alsa allocates your DMA buffer for
you based on snd_pcm_hardware_t buffer_bytes_max what exactly does
snd_pcm_lib_preallocate_pages_for_all allocate buffers for? Does this allocate
the buffers that would be passed to the copy callback?
Thanks,
Tim
--- Tim Harvey <tim_harvey@yahoo.com> wrote:
> Greetings,
>
> I'm setting out to write an ALSA driver for a very limited device thats
> behind
> a PLD. The actual codec is a uda1380 and does 16bit MSB stereo
> encode/decode.
> The way the device is driven the sampling rate is limited to 8KHz and data
> transfer to/from the device I have to handle manually.
>
> I've read over the 'writing an ALSA driver' tutorial and have started the
> driver but have run into a few questions:
>
> - for the specs I've given above: 8000Hz sampling rate, 16bit stereo MSB
> samples does the following snd_pcm_hardware_t look right?:
>
> static snd_pcm_hardware_t my_playback_hw = {
> .info = (SNDRV_PCM_INFO_MMAP |
> SNDRV_PCM_INFO_INTERLEAVED |
> SNDRV_PCM_INFO_BLOCK_TRANSFER |
> SNDRV_PCM_INFO_MMAP_VALID),
> .formats = SNDRV_PCM_FMTBIT_U16_BE, // is this 16bit MSB?
> .rates = SNDRV_PCM_RATE_8000, // seems redundant?
> .rate_min = 8000,
> .rate_max = 8000,
> .channels_min = 2,
> .channels_max = 2,
> .buffer_bytes_max = 32768,
> .period_bytes_min = 4096,
> .period_bytes_max = 32768,
> .periods_min = 1,
> .periods_max = 1024,
> };
>
> - I'm a little confused at how to deal with copying data from/to the device.
>
> It looks like I would implement the copy callback and copy the passed buffer
> to
> the device in the device specific manner I need to (playback), but I'm not
> clear where to put data that I receive from the device (capture). I notice
> that when the hw_params callback is called a dma buffer has been created by
> ALSA in the substream->runtime struct. I assume this is created based on hte
> buffer_bytes_max field above and I'm to copy data to this buffer? How do I
> know where to copy it within the buffer and what data ALSA has already
> consumed
> from the buffer?
>
> - I might need to create an intermediate buffer between ALSA's rather large
> buffers and my hardware buffer. Is there any driver that I could look at
> that
> does this? The tutorial talks about the vxpocket driver but that code looks
> very foriegn from the rest of the ALSA drivers.
>
> - I'm not sure I understand what the 'period' is about. Its clear to me
> that
> I need to call snd_pcm_period_elapsed() periodically from either an IRQ or
> other timed callback, but I'm not clear what the hardware pointer is or how
> that converts to 'frames' and 'periods'.
>
> - in general, if my hardware device only allows 16bit MSB 8KHz, does ALSA
> provides a mechanism for converting data from other formats?
>
> Thanks for any pointers,
>
> Tim
>
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: Questions about writing a new ALSA driver for a very limitted device
2007-04-26 22:30 Tim Harvey
@ 2007-04-27 17:09 ` Takashi Iwai
0 siblings, 0 replies; 4+ messages in thread
From: Takashi Iwai @ 2007-04-27 17:09 UTC (permalink / raw)
To: Tim Harvey; +Cc: alsa-devel
At Thu, 26 Apr 2007 15:30:41 -0700 (PDT),
Tim Harvey wrote:
>
> Thanks to the help I've gotten on this list my alsa driver is working great. I
> got a little hung up not realizing that the alsa core basically provides
> everything you need to implement your own circular buffer if you need to use an
> intermediate buffer.
>
> The only question I still have is that if alsa allocates your DMA buffer for
> you based on snd_pcm_hardware_t buffer_bytes_max what exactly does
> snd_pcm_lib_preallocate_pages_for_all allocate buffers for? Does this allocate
> the buffers that would be passed to the copy callback?
hardware.buffer_bytes_max can be really big. Many hardwares have no
hardware limitation, i.e. can be 4GB or more in theory.
The paramters passed to preallocator is the "reasonable" buffer sizes
for normal uses.
Without preallocator, you'll have to allocate buffer at each open.
Particularly in the case of contiguous pages, it gets always more
difficult because the whole memory area gets more fragmented. Thus,
you'd like to preallocate the buffer and keep that area for later
use.
Currently, there is a constraint that the max buffer size is limited
by the preallocated size (if any), so a buffer bigger than
preallocated won't work. I don't know why this constraint exists, and
I believe it's fine to remove it. (You can see FIXME comment there
indeed)
Takashi
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2007-04-27 17:09 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <s5hwt0cvgjg.wl%tiwai@suse.de>
2007-04-19 21:30 ` Questions about writing a new ALSA driver for a very limitted device Tim Harvey
2007-04-24 13:13 ` Takashi Iwai
2007-04-26 22:30 Tim Harvey
2007-04-27 17:09 ` Takashi Iwai
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.