[alsa-devel] Questions about writing a new ALSA driver for a very limitted device
Takashi Iwai
tiwai at suse.de
Tue Apr 24 15:13:15 CEST 2007
At Thu, 19 Apr 2007 14:30:29 -0700 (PDT),
Tim Harvey wrote:
>
>
> --- Takashi Iwai <tiwai at 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
More information about the Alsa-devel
mailing list