[alsa-devel] Understanding _snd_pcm_channel_area Struct (PCM Interface)!
![](https://secure.gravatar.com/avatar/3b4305af1fd64ee6f344ff16d689fa7c.jpg?s=120&d=mm&r=g)
Hi all.
I am a bit confused on what I get with this function. I finished my first project but I did not understand what exactly the
_snd_pcm_channel_area at
http://www.alsa-project.org/alsa-doc/alsa-lib/struct__snd__pcm__channel__are...
does.
There are 3 fields in the documentation.
addr, first and step.
It seems that addr is the memory address of the channel samples... so far so good. The "step" is the distance between 2 sample (but I am not sure) and the least, "first", I could not figure out what does it means.
Could I get some help from here?
Thanks in advanced!
Tks!
-------------------
Guilherme Longo Dept. Eng. da Computação Unaerp
Linux User - #484927
*Before Asking http://www.istf.com.br/?page=perguntas
!- I'd rather die on my feet than live on my knees -!
![](https://secure.gravatar.com/avatar/5b19e9d0e834ea10ef75803718ad564b.jpg?s=120&d=mm&r=g)
At Tue, 23 Jun 2009 02:40:35 -0300, Guilherme wrote:
Hi all.
I am a bit confused on what I get with this function. I finished my first project but I did not understand what exactly the
_snd_pcm_channel_area at
http://www.alsa-project.org/alsa-doc/alsa-lib/struct__snd__pcm__channel__are...
does.
There are 3 fields in the documentation.
addr, first and step.
It seems that addr is the memory address of the channel samples... so far so good. The "step" is the distance between 2 sample (but I am not sure) and the least, "first", I could not figure out what does it means.
This information is needed to understand how the multi-channel samples are assigned in a stream. The first is the offset of the channel position to the given addr. The step is the bytes to the next sample of that channel.
For example, suppose you have a 2-channel stereo interleaved stream with 16bit samples. Then you'll have an array of snd_pcm_channel_area with two elements, for left and right channels, containing like
area[0].addr = base_address; addr[0].first = 0; addr[0].step = 4; addr[1].addr = base_address; addr[1].first = 2; addr[1].step = 4;
Both channels share the same base address but have the different "first" offset bytes. The step size is 4 = #chanel * sample-size.
For a non-interleaved stereo stream, it'll look like
addr[0].addr = base_addr_0; addr[0].first = 0; addr[0].step = 2; addr[1].addr = base_addr_1; addr[1].first = 0; addr[1].step = 2;
Thus it looks like two mono streams with 16bit samples.
HTH,
Takashi
![](https://secure.gravatar.com/avatar/3b4305af1fd64ee6f344ff16d689fa7c.jpg?s=120&d=mm&r=g)
Takashi...
The base_address and the step sounds pretty clear to me.... just the offset I could not understand.
What the difference in being .first = 0 or .first = 2??? Could you provide please a more in depth explanation. I tried really hard find this but there is nothing related in the documentation.
area[0].addr = base_address; addr[0].first = 0; addr[0].step = 4; addr[1].addr = base_address; addr[1].first = 2; addr[1].step = 4;
P.S. being a stereo or a mono pipeline I understand... just the way the offset works that is not so clear to me.
Thanks in advanced!
Tks!
-------------------
Guilherme Longo Dept. Eng. da Computação Unaerp
Linux User - #484927
*Before Asking http://www.istf.com.br/?page=perguntas
!- I'd rather die on my feet than live on my knees -!
Takashi Iwai wrote:
At Tue, 23 Jun 2009 02:40:35 -0300, Guilherme wrote:
Hi all.
I am a bit confused on what I get with this function. I finished my first project but I did not understand what exactly the
_snd_pcm_channel_area at
http://www.alsa-project.org/alsa-doc/alsa-lib/struct__snd__pcm__channel__are...
does.
There are 3 fields in the documentation.
addr, first and step.
It seems that addr is the memory address of the channel samples... so far so good. The "step" is the distance between 2 sample (but I am not sure) and the least, "first", I could not figure out what does it means.
This information is needed to understand how the multi-channel samples are assigned in a stream. The first is the offset of the channel position to the given addr. The step is the bytes to the next sample of that channel.
For example, suppose you have a 2-channel stereo interleaved stream with 16bit samples. Then you'll have an array of snd_pcm_channel_area with two elements, for left and right channels, containing like
area[0].addr = base_address; addr[0].first = 0; addr[0].step = 4; addr[1].addr = base_address; addr[1].first = 2; addr[1].step = 4;
Both channels share the same base address but have the different "first" offset bytes. The step size is 4 = #chanel * sample-size.
For a non-interleaved stereo stream, it'll look like
addr[0].addr = base_addr_0; addr[0].first = 0; addr[0].step = 2; addr[1].addr = base_addr_1; addr[1].first = 0; addr[1].step = 2;
Thus it looks like two mono streams with 16bit samples.
HTH,
Takashi
![](https://secure.gravatar.com/avatar/5b19e9d0e834ea10ef75803718ad564b.jpg?s=120&d=mm&r=g)
At Fri, 26 Jun 2009 23:56:43 -0300, Guilherme wrote:
Takashi...
The base_address and the step sounds pretty clear to me.... just the offset I could not understand.
What the difference in being .first = 0 or .first = 2??? Could you provide please a more in depth explanation. I tried really hard find this but there is nothing related in the documentation.
area[0].addr = base_address; addr[0].first = 0; addr[0].step = 4; addr[1].addr = base_address; addr[1].first = 2; addr[1].step = 4;
P.S. being a stereo or a mono pipeline I understand... just the way the offset works that is not so clear to me.
Actually, the non-interleaved formats can be represented also with a single base_address (and is so in the actual implementation).
addr[0].addr = base_addr; addr[0].first = 0; addr[0].step = 2; addr[1].addr = base_addr; addr[1].first = mono_buffer_len; addr[1].step = 2; addr[2].addr = base_addr; addr[2].first = mono_buffer_len * 2; addr[2].step = 2; ...
The "first" is the offset of the first sample. The address of the first sample of the channel is simply calculated as addr + first. This is because just we want to keep the base address same to all channels as much as possible especially in mmap mode.
Takashi
![](https://secure.gravatar.com/avatar/3b4305af1fd64ee6f344ff16d689fa7c.jpg?s=120&d=mm&r=g)
Tks takashi....
The doubt comes from this block of code:
for (chn = 0; chn < channels; chn++) { if ((areas[chn].first % 8) != 0) { printf("areas[%i].first == %i, abortando...\n", chn, areas[chn].first); exit(EXIT_FAILURE); } //pega endereço e offset da area samples[chn] = /*(signed short *)*/(((unsigned char *)areas[chn].addr) + (areas[chn].first / 8));
if ((areas[chn].step % 16) != 0) { printf("areas[%i].step == %i, aborting...\n", chn, areas[chn].step); exit(EXIT_FAILURE); }
steps[chn] = areas[chn].step / 8; samples[chn] += offset * steps[chn]; }
first:
areas[chn].first % 8 ( I am using chn = 1). So for the only area that I have, if I get the value of the parameter 'first' isn't divisible by 8, the program exits. The same doubt happens with "areas[chn].step % 16" and "areas[chn].step / 8".
This is the parameter I am using:
static snd_pcm_format_t format = SND_PCM_FORMAT_S16; //sample format unsigned 16 bit endian
Perhaps with this practical example I can understand better.
Thanks for ur patient!
Tks!
-------------------
Guilherme Longo
Dept. Eng. da Computação Unaerp
Linux User - #484927
*Before Asking http://www.istf.com.br/?page=perguntas
!- I'd rather die on my feet than live on my knees -!
Takashi Iwai wrote:
At Fri, 26 Jun 2009 23:56:43 -0300, Guilherme wrote:
Takashi...
The base_address and the step sounds pretty clear to me.... just the offset I could not understand.
What the difference in being .first = 0 or .first = 2??? Could you provide please a more in depth explanation. I tried really hard find this but there is nothing related in the documentation.
area[0].addr = base_address; addr[0].first = 0; addr[0].step = 4; addr[1].addr = base_address; addr[1].first = 2; addr[1].step = 4;
P.S. being a stereo or a mono pipeline I understand... just the way the offset works that is not so clear to me.
Actually, the non-interleaved formats can be represented also with a single base_address (and is so in the actual implementation).
addr[0].addr = base_addr; addr[0].first = 0; addr[0].step = 2; addr[1].addr = base_addr; addr[1].first = mono_buffer_len; addr[1].step = 2; addr[2].addr = base_addr; addr[2].first = mono_buffer_len * 2; addr[2].step = 2; ...
The "first" is the offset of the first sample. The address of the first sample of the channel is simply calculated as addr + first. This is because just we want to keep the base address same to all channels as much as possible especially in mmap mode.
Takashi
![](https://secure.gravatar.com/avatar/5b19e9d0e834ea10ef75803718ad564b.jpg?s=120&d=mm&r=g)
At Tue, 30 Jun 2009 11:40:20 -0300, Guilherme wrote:
Tks takashi....
The doubt comes from this block of code:
for (chn = 0; chn < channels; chn++) { if ((areas[chn].first % 8) != 0) { printf("areas[%i].first == %i, abortando...\n", chn, areas[chn].first); exit(EXIT_FAILURE); } //pega endereço e offset da area samples[chn] = /*(signed short *)*/(((unsigned char *)areas[chn].addr) + (areas[chn].first / 8));
if ((areas[chn].step % 16) != 0) { printf("areas[%i].step == %i, aborting...\n", chn,
areas[chn].step); exit(EXIT_FAILURE); }
steps[chn] = areas[chn].step / 8; samples[chn] += offset * steps[chn]; }
first:
areas[chn].first % 8 ( I am using chn = 1). So for the only area that I have, if I get the value of the parameter 'first' isn't divisible by 8, the program exits. The same doubt happens with "areas[chn].step % 16" and "areas[chn].step / 8".
This is the parameter I am using:
static snd_pcm_format_t format = SND_PCM_FORMAT_S16; //sample format unsigned 16 bit endian
Perhaps with this practical example I can understand better.
Oops, I wrote wrongly. The first and step fields are not in bytes but bits. That's why 8 and 16 appear there, corresponding to 1 byte and 2 bytes.
Takashi
![](https://secure.gravatar.com/avatar/3b4305af1fd64ee6f344ff16d689fa7c.jpg?s=120&d=mm&r=g)
Hum...
so .. the code
if ((areas[chn].step % 16) !=0 )
is because a 16bits format's been used.
If I wanted a 32bits sample format I should change that for if ((areas[chn].step % 32) !=0 ) ??
and the offset for the first doen's need any changes, is it?
Just a opinion about all this, I think that alsa developers should design graphs for these things, as has in gstreamer documentation. It is a lot easer to understand that way.
It is because I dont understand very well yet, but as I am going to work with sound stuff especially in linux environment, Ill be very soon offering help for this!
;o)
Tks!
-------------------
Guilherme Longo Dept. Eng. da Computação Unaerp
Linux User - #484927
*Before Asking http://www.istf.com.br/?page=perguntas
!- I'd rather die on my feet than live on my knees -!
Takashi Iwai wrote:
At Tue, 30 Jun 2009 11:40:20 -0300, Guilherme wrote:
Tks takashi....
The doubt comes from this block of code:
for (chn = 0; chn < channels; chn++) { if ((areas[chn].first % 8) != 0) { printf("areas[%i].first == %i, abortando...\n", chn, areas[chn].first); exit(EXIT_FAILURE); } //pega endereço e offset da area samples[chn] = /*(signed short *)*/(((unsigned char *)areas[chn].addr) + (areas[chn].first / 8));
if ((areas[chn].step % 16) != 0) { printf("areas[%i].step == %i, aborting...\n", chn,
areas[chn].step); exit(EXIT_FAILURE); }
steps[chn] = areas[chn].step / 8; samples[chn] += offset * steps[chn]; }
first:
areas[chn].first % 8 ( I am using chn = 1). So for the only area that I have, if I get the value of the parameter 'first' isn't divisible by 8, the program exits. The same doubt happens with "areas[chn].step % 16" and "areas[chn].step / 8".
This is the parameter I am using:
static snd_pcm_format_t format = SND_PCM_FORMAT_S16; //sample format unsigned 16 bit endian
Perhaps with this practical example I can understand better.
Oops, I wrote wrongly. The first and step fields are not in bytes but bits. That's why 8 and 16 appear there, corresponding to 1 byte and 2 bytes.
Takashi
![](https://secure.gravatar.com/avatar/5b19e9d0e834ea10ef75803718ad564b.jpg?s=120&d=mm&r=g)
At Tue, 30 Jun 2009 12:01:53 -0300, Guilherme wrote:
Hum...
so .. the code
if ((areas[chn].step % 16) !=0 )
is because a 16bits format's been used.
If I wanted a 32bits sample format I should change that for if ((areas[chn].step % 32) !=0 ) ??
Depends.
The step field doesn't specify the sample format. It specifies the bits to the next sample of the given channel.
For such a purpose, checking the sample format bits via snd_pcm_format_width() or snd_pcm_format_physical_width() would be more suitable.
and the offset for the first doen's need any changes, is it?
Just a opinion about all this, I think that alsa developers should design graphs for these things, as has in gstreamer documentation. It is a lot easer to understand that way.
It is because I dont understand very well yet, but as I am going to work with sound stuff especially in linux environment, Ill be very soon offering help for this!
Well, usually you don't have to care about the channel_info. It's just for mmap, and unless you really do want it inevitably, the mmap access isn't needed.
Takashi
participants (2)
-
Guilherme
-
Takashi Iwai