Rephrasing my ALSA question - Does the example code work ?

Hello all,

I've found a simple tutorial here

formatting link
and have a bit of a problem with listing #3.

First off , when I executed the program it had a long delay executing the "snd_pcm_hw_params_set_rate_near()" function, which turned out to be related to the "dir" argument not being initialised (with Zero).

#1: I'm using gcc on a Raspberry Pi in geany. Is there some sort of setting I should add to have gcc include code to automatically clear declared variables ?

Or should I assume that the code simply isn't complete (would explain a few things).

#2: The length out the outputted sample doesn't seem to be five seconds, even when the code promises it to be.

1) I checked that by clearing the buffer and only execute "rc = read(0, buffer, size);" when the "loops" counter was zero. No sound was to be heard.

2) when I added an "usleep()" of a second before the "snd_pcm_drain()" call I did hear something (read: the data was there, just not outputted)

3) I've measure the time starting just befor the loop to just after the "snd_pcm_drain()" call using "gettimeofday()" like described here
formatting link
, and the measured time is indeed less than the promised five seconds.

#3: The problem gets even more pronounced when I changed the sampling rate from 44100 to 8000. After that change the sound is outputted for less than a single second (time measured using the above method). :-(

Using the same 1) and 2) checks I found that the full five seconds of sound data was again there, but those four seconds worth of it just doesn't get outputted.

Can anyone confirm this behaviour (read: its just some incomplete example code) ? And most important: What is missing from that code that causes the sound output the be cut-off like that ?

I've been searching my ass off for quite some time now, but have not been able to find anything that could shed some light on it. :-(

Regards, Rudy Wieser

Reply to
R.Wieser
Loading thread data ...

I copied the example program you referenced. Compiled it and ran

$ time cat /dev/zero | ./simple_alsa_play

real 0m5.028s user 0m0.396s sys 0m0.000s

But this is not on a raspberry pi, it's on a PC. But the program compiled just fine. The whole point of the ALSA setup is that as long as the kernel has the ALSA support, an alsa program should run. So I would _expect_ the platform to make no difference. But as they say. shit happens!

Whether you compile using geany or whatever or from the command line (as I did) doesn't make any difference.

Jim

Reply to
Jim Jackson

Jim,

:-) I gave that reference so you would know what I'm using, and maybe know thats something works different.

In your case your compiler must have automatically zeroed that "dir" var out, or you where incredibly lucky, and that multiple times. Guess what I think.

In other words: your setup is different than mine.

Are those numbers for both the origional as well as the 8000 bitrate ?

It compiled just fine here too. The problems only became appearant when running it, with the above mentioned uninitialized "dir" variable being the first one.

Nope. As long as the same arguments are used ofcourse. But I wondered if my, or rather Geany's calling of gcc missed a "clear declared variables" flag (which is why I specifically mentioned what I was using, and how).

There also seems to be a difference between the compiler you used and the gcc one I've got here, as yours seems to done that clearing automatically.

But, thank you for mentioning that you've done your testing on a PC platform. It seems to suggest that the ALSA version on the Raspberry Pi has a flaw that the PC version doesn't.

I mean, otherwise the program should work exactly the same on both our machines, right ?

Regards, Rudy Wieser

Reply to
R.Wieser

On Wed, 22 Jan 2020 11:34:29 +0100, "R.Wieser" declaimed the following:

Well, you could add compile option

-Wuninitialized """ Warn if an automatic variable is used without first being initialized. """

and find most of those conditions. NOTE that there likely isn't any option to force memory to 0 on first usage since so much of C is stack based and zeroing stack memory each time a function returns (shrinking the stack) would be a costly overhead... cf:

formatting link
""" C99: If an object that has automatic storage duration is not initialized explicitly, its value is indeterminate. """

--
	Wulfraed                 Dennis Lee Bieber         AF6VN 
	wlfraed@ix.netcom.com    http://wlfraed.microdiversity.freeddns.org/
Reply to
Dennis Lee Bieber

Dennis,

In other words, the example code I referred to is indeed incomplete, as it should have contained a line clearing that "dir" variable. Thats :-((

Regards, Rudy Wieser

Reply to
R.Wieser

The error return value from most of those sound functions is not being checked. You have no idea if the function worked in this case, possibly because the input parameters were not set correctly.

The ALSA project API web page has links to example programs that do use the error return value:

e.g. /* set the stream rate */ rrate = rate; err = snd_pcm_hw_params_set_rate_near(handle, params, &rrate, 0); if (err < 0) { printf("Rate %uHz not available for playback: %s\n", rate, snd_strerror(err));

I would always check the return values when trying new API calls I was not extremely familiar in using because it's simplicity to bollox up the input parameters when learning. When everything is working all lovely-jubbly I would still check the error values 'coz I'm not a script-kiddie. YMMV

Does the hardware you are using support 8000Hz sample rate?

Does aplay and arecord work with the sample rates you want to use?

Reply to
mm0fmf

mm0fmf,

:-) That doesn't mean I, in the course of trying to find the problem, didn't do that myself. None of the functions returned a negative result.

I have no idea. The "snd_pcm_hw_params_set_rate_near()" function seems to think so though (no negative result), "val" is unchanged. My guess therefore is that it does.

I tested aplay, and it it does. Even down to 4000.

Just one question: Do you have a Raspberry Pi (3b+), and if so could you PLEASE test if you can reproduce my problem.

I need to know if its just a (lack of) code problem, or if should replace my currently used software (ALSA, OS, anything else ?)

Regards, Rudy Wieser

Reply to
R.Wieser

No. The value of dir is set by the function - that's why you pass it the address of dir. It's returned value for the function "snd_pcm_hw_params_set_rate_near" is

int dir; /* exact_rate == rate --> dir = 0 */ /* exact_rate < rate --> dir = -1 */ /* exact_rate > rate --> dir = 1 */

according to some code I found on git hub.

I haven't edited the sample code you referenced - so 44100

How did that show itself?

gcc -c simple_alsa_play.c gcc -o simple_alsa_play simple_alsa_play.o -lasound

gcc 4.6.3 - yeah it's an old version.

Jim

Reply to
Jim Jackson

Sorry only a B+ and a Zero_W or I would have tried.

Maybe try the example programs linked on the ALSA API pages?

Reply to
mm0fmf

Jim,

Here at my end a "val" of 8000 with "dir" being given a positive number causes a seconds long delay, "val" returns 8001 and "dir" returns 0. Using a "dir" of zero doesn't cause a delay and "var" and "dir" stay unchanged. Using a negative "dir" doesn't causes a delay either, "val" returns 7999 and "dir" returns 0.

In other words, here that "dir" argument goes, just like the "val" one, in BOTH directions. Interresting, no ? :-(

Can you do that now ? Maybe testing different a negative and positive value for "dir" too ?

Nope, no extra setting used.

I think we can conclude that the ALSA version you are using on the PC seems to be different from mine on the RPi.

Do you have an RPi that you can re-do the check on ? The result from that would mean a lot more.

Regards, Rudy Wieser

Reply to
R.Wieser

mm0fmf,

I've been scouring the web for days at end, and have found very little in regard to example programs. Could you post the URL to them ?

By the way, I did find source code to stuff like "speaker-test", but those where way too complex for what I need (trying to strip them down to its basics would most likely cause its own problems).

Regards, Rudy Wieser

Reply to
R.Wieser

Ok instead of playing guessing games I briefly looked at the source code for libasound, and you are right - it does interrogate the value, probably to guide the finding of the best match to our given samplerate. I say probable, because I didn't have the energy to follow the code through completely. But interestingly you can pass a null pointer there. Given the simple code you want I suggest you do that. You can always check the returned value against a copy of the given value to find out if it is > , < or = to what you wanted.

So with dir uninitialised you can get problems. My advice is to ignore it, use a null pointer for that parameter, and let the code select a samplerate close to what you requested.

Reply to
Jim Jackson

Jim,

I know. But that was not the point I tried to make.

To me was an indication that whomever wrote that code took a bit of a "it works for me" swing at it, and could have forgotten, or even cut corners in relation to the bitrate.

Than again, that very same code worked alright for you. Although, you only tested for a 44100 bitrate ...

However, the actual problem is why the "snd_pcm_drain()" function does not live up to its purpose. Does it simply malfunction (on the RPi), or does it need other data (in the 'snd_pcm_hw_params_t' record?) to be set up too ?

I have no clue, and I can't seem to find any kind of example or information in that regard. And I've spend quite a while googeling for it, believe me. :-\

Regards, Rudy Wieser

Reply to
R.Wieser

formatting link

Did you try these complex examples? Did they work?

If they did then you have a working example and simplifying the example is just a small matter of programming and anyone can program.

Reply to
mm0fmf

mm0fmf,

:-) After my last post I found that page too (don't quite remember what the exact search terms where though).

Nope. They use a different approach, so they are useless to compare with.

There is another simple example in that list, named "pwm_min". It "works" as long as you (again) do not look to closely:

1) It seems to be missing a "snd_pwm_drain()" call. Thats OK ? Don't know. 2) 16*1024 (buffer size) *16 (loops) / 48000 (bitrate) equals 5.46 seconds. Running "time ./pwm_min" shows 5.09 seconds. Thats 17824 frames missing (more than one buffers worth)...

In other words, the same "too short" problem.

I tried putting that "snd_pwm_drain()" function before closing the handle here too, but that didn't fix it.

They dont, and thats the problem.

:-) Just compare "pwm.c" and "pwn_min.c" examples with each other. I dare you to simplify the first into something that is as concise as the second. :-p (and no, I do not really expect you to do so)

@all: But I /really/ would like one of the other RPi 3B(+) board owners to try to recreate the problem and confirm its not just my combination of board, OS and code.

Regards Rudy Wieser

Reply to
R.Wieser

How long does the sound play for?

Reply to
mm0fmf

mm0fmf,

:-( Re-read my post please.

Regards, Rudy Wieser

Reply to
R.Wieser

Re-read the question because you haven't given that information.

Reply to
mm0fmf

mm0fmf,

[quote] Running "time ./pwm_min" shows 5.09 seconds [/quote]

Unless you intended to ask something else.

Regards, Rudy Wieser

Reply to
R.Wieser

I am. How long does the sound play NOT how long does the program take to execute.

Reply to
mm0fmf

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.