LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Software (https://www.linuxquestions.org/questions/linux-software-2/)
-   -   ALSA: snd_pcm_hw_params() failure - Invalid argument (https://www.linuxquestions.org/questions/linux-software-2/alsa-snd_pcm_hw_params-failure-invalid-argument-805660/)

aayu09 05-03-2010 10:32 AM

ALSA: snd_pcm_hw_params() failure - Invalid argument
 
I am working on a ALSA project, and I have a TV tunner card plugged intot the PCI interface. I try to capture the audio from the tunner card, and the followings are the code:

Code:


int main()
{
....
snd_pcm_t *tunerAudioHandle = NULL;
snd_pcm_hw_params_t *tunerAudioParams = NULL;
int err;
int blocksz = 32000;
char block[blocksz];
unsigned sampleValue = 32000;

if ((err = snd_pcm_open(&tunerAudioHandle, "hw:1,0", SND_PCM_STREAM_CAPTURE, 0)) < 0)
        {
                printf("could not open tunerAudio device hw:1,0, tunerAudioHandle:%s\n",snd_strerror(err));
                exit (-1);
        }

        if ((err = snd_pcm_hw_params_malloc(&tunerAudioParams)) < 0)
        {
                  printf("could not allocate tunerAudio hardware parameter structur:%s\n",snd_strerror(err));
                  exit (-1);
        }

        if ((err = snd_pcm_hw_params_any(tunerAudioHandle, tunerAudioParams)) < 0)
        {
                printf("could not initialize tunerAudio parameter structure:%s\n",snd_strerror(err));
                exit (-1);
        }


        if ((err = snd_pcm_hw_params_set_format(tunerAudioHandle, tunerAudioParams, SND_PCM_FORMAT_S16_LE)) < 0)
        {
                printf("could not set TunerAudio sample format:%s\n",snd_strerror(err));
                exit (-1);
        }

        if ((err = snd_pcm_hw_params_set_rate_near(tunerAudioHandle, tunerAudioParams, &sampleValue, 0)) < 0)
        {
                printf("could not set audioTuner sample rate:%s\n",snd_strerror(err));
                exit (-1);
        }

        if ((err = snd_pcm_hw_params_set_channels(tunerAudioHandle, tunerAudioParams, 2)) < 0)
        {
                  printf("could not set tunerAudio channels:%s\n",snd_strerror(err));
                  exit (-1);
        }

        printf("set audioTunner channels success!\n");

        if ((err = snd_pcm_hw_params(tunerAudioHandle, tunerAudioParams)) < 0)
        {
                  printf("could not set audioTuner parameter:%s\n",snd_strerror(err));
                  exit (-1);
        }
        printf("set autioTunner pameter success!!\n");
...
}  //end of main

I got the following error message:

Code:

set audioTunner channels success!
could not set audioTuner parameter:Invalid argument

Not sure why failed to set hw parameters for the device. Any help will be appriciated.

-ay

piotreks 05-03-2010 03:36 PM

Quote:

Originally Posted by aayu09 (Post 3955751)
I am working on a ALSA project, and I have a TV tunner card plugged intot the PCI interface. I try to capture the audio from the tunner card, and the followings are the code:

Code:


...
unsigned sampleValue = 32000;
...
        if ((err = snd_pcm_hw_params_set_rate_near(tunerAudioHandle, tunerAudioParams, &sampleValue, 0)) < 0)
        {
                printf("could not set audioTuner sample rate:%s\n",snd_strerror(err));
                exit (-1);
        }
...
        if ((err = snd_pcm_hw_params(tunerAudioHandle, tunerAudioParams)) < 0)
        {
                  printf("could not set audioTuner parameter:%s\n",snd_strerror(err));
                  exit (-1);
        }

I got the following error message:

Code:

set audioTunner channels success!
could not set audioTuner parameter:Invalid argument

Not sure why failed to set hw parameters for the device.

Are you sure the device supports a sampling rate of 32kHz with little-endian 16-bit signed integer sample?

One thing you can try to narrow down the cause is to print out the actual value of the error from 'err = snd_pcm_hw_params...' and then look it up in errno.h.

Good luck.
Pete

aayu09 05-03-2010 05:14 PM

Pete:

Thanks for your suggestion. I just confirmed that audio data of S16_LE (signed 16, little-endian) is correct, 32K sample rate is also fine. I just printed out the err num = -22. I did a search and have not found errno.h yet. Do you happen to have the link for errno.h? I am using Fedora Linux 2.6.

Thanks again,

-ay

piotreks 05-04-2010 06:49 AM

Quote:

Originally Posted by aayu09 (Post 3956148)
Pete:

Thanks for your suggestion. I just confirmed that audio data of S16_LE (signed 16, little-endian) is correct, 32K sample rate is also fine. I just printed out the err num = -22. I did a search and have not found errno.h yet. Do you happen to have the link for errno.h? I am using Fedora Linux 2.6.

The error code corresponds to the negative of EINVAL #define in /usr/include/asm-generic/errno-base.h.

Here are a few more things to try:
1) Make sure you have access mode set to interleaved, like so:
Code:

if ((err = snd_pcm_hw_params_set_access (capture_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
                        fprintf (stderr, "cannot set access type (%s)\n",
                                snd_strerror (err));
                        exit (1);
                }

The above excerpt was taken from here.

2) After setting all the values in the hw_params, try getting them via their corresponding functions and printing them out before sending them to the handle. This way, you'll be sure that all the values you set are there.

Good luck!
Pete

aayu09 05-04-2010 12:39 PM

I have added a few printf commands to query the tv tuner card status. Please see the code and the output.

Code:

//open tunerAudio and set parameters
        if ((err = snd_pcm_open(&tunerAudioHandle, "hw:1,0", SND_PCM_STREAM_CAPTURE, 0)) < 0)
        {
                printf("could not open tunerAudio device hw:1,0, tunerAudioHandle:%s\n",snd_strerror(err));
                exit (-1);
        }

        if ((err = snd_pcm_hw_params_malloc(&tunerAudioParams)) < 0)
        {
                  printf("could not allocate tunerAudio hardware parameter structur:%s\n",snd_strerror(err));
                  exit (-1);
        }

        if ((err = snd_pcm_hw_params_any(tunerAudioHandle, tunerAudioParams)) < 0)
        {
                printf("could not initialize tunerAudio parameter structure:%s\n",snd_strerror(err));
                exit (-1);
        }

        if (( err = snd_pcm_hw_params_set_access(tunerAudioHandle, tunerAudioParams, SND_PCM_ACCESS_RW_INTERLEAVED)) <0 )
        {
            printf("could not set access mode as INTERLEAVED.\n");
            exit(-1);
        }
        printf("access mode set as INTERLEAVED success!\n");

        if ((err = snd_pcm_hw_params_set_format(tunerAudioHandle, tunerAudioParams, SND_PCM_FORMAT_S16_LE)) < 0)
        {
                printf("could not set TunerAudio sample format:%s\n",snd_strerror(err));
                exit (-1);
        }

        exactRate = sampleRate;
        if ((err = snd_pcm_hw_params_set_rate_near(tunerAudioHandle, tunerAudioParams, &exactRate, 0)) < 0)
        {
                printf("could not set tuneAudio sample rate:%s\n",snd_strerror(err));
                exit (-1);
        }

        if (sampleRate != exactRate)
        {
            printf("The rate %d Hz is not supported by your hardware. \n ==> Using %d Hz insteatd.\n",
                sampleRate, exactRate);
            exit(-1);

        }
        printf("Set tunerAudio rate success! \n");


        if ((err = snd_pcm_hw_params_set_channels(tunerAudioHandle, tunerAudioParams, 2)) < 0)
        {
                  printf("could not set tunerAudio channels:%s\n",snd_strerror(err));
                  exit (-1);
        }

        printf("set audioTunner channels success!\n");

        //set buffer sieze
        if ((err = snd_pcm_hw_params_set_buffer_size(tunerAudioHandle, tunerAudioParams, (periodsize*periods) >> 2)) < 0)
          {
            printf("could not set buffersize.\n");
            exit(-1);
          }
        printf("set tunerAudio buffersize success!\n");

        unsigned int val;
        unsigned int dir, frames;

        //display tunerAudio card parameters
        printf("tunerAudio card handler name = %s\n", snd_pcm_name(tunerAudioHandle));
        printf("tunerAudio pcm state = %s\n",
            snd_pcm_state_name(snd_pcm_state(tunerAudioHandle)));

        snd_pcm_hw_params_get_access(tunerAudioParams, (snd_pcm_access_t *) &val);
        printf("tunerAudio access type = %s\n", snd_pcm_access_name((snd_pcm_access_t)val));

        snd_pcm_hw_params_get_format(tunerAudioParams, &val);
        printf("tunerAudio format = %s (%s)\n", snd_pcm_format_name((snd_pcm_format_t) val),
            snd_pcm_format_description((snd_pcm_format_t) val));

        snd_pcm_hw_params_get_format(tunerAudioParams, &val);
        printf("format = '%s' (%s)\n", snd_pcm_format_name((snd_pcm_format_t)val),
            snd_pcm_format_description((snd_pcm_format_t)val));

        snd_pcm_hw_params_get_subformat(tunerAudioParams, (snd_pcm_subformat_t *)&val);
        printf("subformat = '%s' (%s)\n", snd_pcm_subformat_name((snd_pcm_subformat_t)val),
            snd_pcm_subformat_description((snd_pcm_subformat_t)val));

        snd_pcm_hw_params_get_channels(tunerAudioParams, &val);
        printf("channels = %d\n", val);

        snd_pcm_hw_params_get_rate(tunerAudioParams, &val, &dir);
        printf("rate = %d bps\n", val);

        snd_pcm_hw_params_get_period_time(tunerAudioParams, &val, &dir);
        printf("period time = %d us\n", val);

        snd_pcm_hw_params_get_period_size(tunerAudioParams, &frames, &dir);
        printf("period size = %d frames\n", (int)frames);

        snd_pcm_hw_params_get_buffer_time(tunerAudioParams, &val, &dir);
        printf("buffer time = %d us\n", val);

        snd_pcm_hw_params_get_buffer_size(tunerAudioParams,(snd_pcm_uframes_t *) &val);
        printf("buffer size = %d frames\n", val);

        snd_pcm_hw_params_get_periods(tunerAudioParams, &val, &dir);
        printf("periods per buffer = %d frames\n", val);


        //set number of periods
  /*    if ((err = snd_pcm_hw_params_set_periods(tunerAudioHandle, tunerAudioParams, (snd_pcm_uframes_t){ 512 }, 0)) < 0)
          {
            printf("could not set tunerAudio periods.\n");
            exit(-1);
          }
        printf("set tunerAudio periods success!\n");
*/
        if ((err = snd_pcm_hw_params(tunerAudioHandle, tunerAudioParams)) < 0)
        {
                  printf("could not set audioTuner HW parameter:%s, error num = %d\n",snd_strerror(err), err);
                  exit (-1);
        }
        printf("set autioTunner HW pameter success!!\n");
        snd_pcm_hw_params_free(tunerAudioParams);

The output are as follows:

Code:

[root@mu153097 dtvScan]# ./kwaud
access mode set as INTERLEAVED success!
Set tunerAudio rate success!
set audioTunner channels success!
set tunerAudio buffersize success!
tunerAudio card handler name = hw:1,0
tunerAudio pcm state = OPEN
tunerAudio access type = RW_INTERLEAVED
tunerAudio format = S16_LE (Signed 16 bit Little Endian)
format = 'S16_LE' (Signed 16 bit Little Endian)
subformat = 'STD' (Standard)
channels = 2
rate = 32000 bps
period time = 32000 us
period size = 11452372 frames
buffer time = 128000 us
buffer size = 4096 frames
periods per buffer = 4096 frames
could not set audioTuner HW parameter:Invalid argument, error num = -22

I suspect that the error might be related to the setting of those parameters, e.g. rate, period time, period size, buffer size etc. But I am not sure about that.

aayu09 05-04-2010 04:19 PM

I found the problem was caused by not setting the proper buffersize and period size. After calling the snd_pcm_hw_params_set_buffer_size() and snd_pcm_hw_params_set_period_size(). It worked fine. See the following output:
Code:

access mode set as INTERLEAVED success!
Set tunerAudio rate success!
set audioTunner channels success!
set tunerAudio buffer size success!
set tunerAudio period size success!
tunerAudio card handler name = hw:1,0
tunerAudio pcm state = OPEN
tunerAudio access type = MMAP_INTERLEAVED
tunerAudio format = S16_LE (Signed 16 bit Little Endian)
format = 'S16_LE' (Signed 16 bit Little Endian)
subformat = 'STD' (Standard)
channels = 2
rate = 32000 bps
period time = 16000 us
period size = 512 frames
buffer time = 512000 us
buffer size = 16384 frames
periods per buffer = 32 frames
set autioTunner HW pameter success!!


piotreks 05-05-2010 08:36 AM

Quote:

Originally Posted by aayu09 (Post 3957362)
I found the problem was caused by not setting the proper buffersize and period size. After calling the snd_pcm_hw_params_set_buffer_size() and snd_pcm_hw_params_set_period_size(). It worked fine.

Awesome!!!!
Glad you got it working!
P

gbmkrao 05-29-2012 01:14 AM

snd_pcm_hw_params_set_format : error: -22
 
I am also getting the same error: -22 for snd_pcm_hw_params_set_format with SND_PCM_FORMAT_S16_LE. Could some please explain how to set proper parameters (like buffer size, period size...). Did these these parameters depends on audio card (hardware specific)?

please check the code below i am using now.
code:

snd_pcm_t *pcm;

assert(snd_pcm_open(&pcm, name, SND_PCM_STREAM_CAPTURE, 0) == 0);

snd_pcm_hw_params_t *pcm_hw_params;

assert(snd_pcm_hw_params_malloc(&pcm_hw_params) == 0);

assert(snd_pcm_hw_params_any(pcm, pcm_hw_params) == 0);

assert(snd_pcm_hw_params_set_access(pcm, pcm_hw_params, SND_PCM_ACCESS_MMAP_INTERLEAVED) == 0);

assert(snd_pcm_hw_params_set_buffer_size(pcm, pcm_hw_params, 16384) == 0);

assert(snd_pcm_hw_params_set_period_size(pcm, pcm_hw_params, (snd_pcm_uframes_t){ 1024 }, (int){ 0 }) == 0);

assert(snd_pcm_hw_params_set_format(pcm, pcm_hw_params, SND_PCM_FORMAT_S16_LE) == 0);


All times are GMT -5. The time now is 10:53 PM.