Thread: Sound Recording By Using ALSA-lib Pls Help

  1. #1
    Registered User
    Join Date
    Aug 2015
    Posts
    3

    Sound Recording By Using ALSA-lib Pls Help

    Hello guys,
    I am new in Linux programming,but i need to write a c program which uses the ALSA library and records sound to a file.In fact I found a code does this,but the recorded sound file is in .pcm format and i can't play it. The code is below:


    Code:
       /*
    
    
    This example reads from the default PCM device
    and writes to standard output for 5 seconds of data.
    
    
    */
    
    
    /* Use the newer ALSA API */
    #define ALSA_PCM_NEW_HW_PARAMS_API
    
    
    #include <alsa/asoundlib.h>
    
    
    int main() {
      long loops;
      int rc;
      int size;
      snd_pcm_t *handle;
      snd_pcm_hw_params_t *params;
      unsigned int val;
      int dir;
      snd_pcm_uframes_t frames;
      char *buffer;
    
    
      /* Open PCM device for recording (capture). */
      rc = snd_pcm_open(&handle, "default",
                        SND_PCM_STREAM_CAPTURE, 0);
      if (rc < 0) {
        fprintf(stderr,
                "unable to open pcm device: %s\n",
                snd_strerror(rc));
        exit(1);
      }
    
    
      /* Allocate a hardware parameters object. */
      snd_pcm_hw_params_alloca(&params);
    
    
      /* Fill it in with default values. */
      snd_pcm_hw_params_any(handle, params);
    
    
      /* Set the desired hardware parameters. */
    
    
      /* Interleaved mode */
      snd_pcm_hw_params_set_access(handle, params,
                          SND_PCM_ACCESS_RW_INTERLEAVED);
    
    
      /* Signed 16-bit little-endian format */
      snd_pcm_hw_params_set_format(handle, params,
                                  SND_PCM_FORMAT_S16_LE);                                 
    
    
      /* Two channels (stereo) */
      snd_pcm_hw_params_set_channels(handle, params, 2);                                 
    
    
      /* 44100 bits/second sampling rate (CD quality) */
      val = 44100;                                                     
      snd_pcm_hw_params_set_rate_near(handle, params,
                                      &val, &dir);
    
    
      /* Set period size to 32 frames. */
      frames = 32;
      snd_pcm_hw_params_set_period_size_near(handle,
                                  params, &frames, &dir);
    
    
      /* Write the parameters to the driver */
      rc = snd_pcm_hw_params(handle, params);
      if (rc < 0) {
        fprintf(stderr,
                "unable to set hw parameters: %s\n",
                snd_strerror(rc));
        exit(1);
      }
    
    
      /* Use a buffer large enough to hold one period */
      snd_pcm_hw_params_get_period_size(params,
                                          &frames, &dir);
      size = frames * 4; /* 2 bytes/sample, 2 channels */
      buffer = (char *) malloc(size);
    
    
      /* We want to loop for 5 seconds */
      snd_pcm_hw_params_get_period_time(params,
                                             &val, &dir);
      loops = 5000000 / val;
    
    
      while (loops > 0) {
        loops--;
        rc = snd_pcm_readi(handle, buffer, frames);
        if (rc == -EPIPE) {
          /* EPIPE means overrun */
          fprintf(stderr, "overrun occurred\n");
          snd_pcm_prepare(handle);
        } else if (rc < 0) {
          fprintf(stderr,
                  "error from read: %s\n",
                  snd_strerror(rc));
        } else if (rc != (int)frames) {
          fprintf(stderr, "short read, read %d frames\n", rc);
        }
        rc = write(1, buffer, size);
        if (rc != size)
          fprintf(stderr,
                  "short write: wrote %d bytes\n", rc);
      }
    
    
      snd_pcm_drain(handle);
      snd_pcm_close(handle);
      free(buffer);
    
    
      return 0;
    }
    The thing i did not understand,when i use arecord >sample.pcm command in terminal,i can play the pcm file well.But in this program i can't.Is that because the frequency and mono/stereo stuff? How can i fix that problem?

  2. #2
    Ticked and off
    Join Date
    Oct 2011
    Location
    La-la land
    Posts
    1,728
    Quote Originally Posted by gokseld7 View Post
    when i use arecord >sample.pcm command in terminal,i can play the pcm file well.
    That is because by default, arecord outputs WAV format audio (uncompressed), not raw data.

    Quote Originally Posted by gokseld7 View Post
    But in this program i can't.
    You can, if you tell aplay the exact format:
    aplay -t raw -f S16_LE -c2 -r44100 sample.pcm

    A better solution is to make your program output WAV data, too. All you need to do is construct a 44-byte header chunk (which does have to include the total number of samples in the file -- but you already know that beforehand, so it's not a problem), and save it before the sample data.

    The format is described in various places on the internet, for example here and here. To get you started, I recommend you begin with a helper function:
    Code:
    static void set16le(void *const ptr, const unsigned int value)
    {
        unsigned char *const data = ptr;
        data[0] = value & 255U;
        data[1] = (value >> 8) & 255U;
    }
    
    static void set32le(void *const ptr, const unsigned int value)
    {
        unsigned char *const data = ptr;
        data[0] = value & 255U;
        data[1] = (value >> 8) & 255U;
        data[2] = (value >> 16) & 255U;
        data[3] = (value >> 24) & 255U;
    }
    
    int write_wav_header_s16le(FILE *const out, const int samplesperchannel, const int channels, const int rate)
    {
        unsigned char header[44];
    
        header[0] = 'R';
        header[1] = 'I';
        header[2] = 'F';
        header[3] = 'F';
        set32le(header + 4, 36U + 2U*channels*samplesperchannel);
        header[8] = 'W';
        header[9] = 'A';
        header[10] = 'V';
        header[11] = 'E';
        header[12] = 'f';
        header[13] = 'm';
        header[14] = 't';
        header[15] = ' ';
        set32le(header + 16, 16U);
        set16le(header + 20, 1U); /* PCM format */
        set16le(header + 22, channels);
        set32le(header + 24, rate);
        set32le(header + 28, rate * 2U * channels);
        set16le(header + 32, 2U * channels);
        set16le(header + 34, 16U); /* Bits per sample */
        header[36] = 'd';
        header[37] = 'a';
        header[38] = 't';
        header[39] = 'a';
        set32le(header + 40, 2U*channels*samplesperchannel);
    
        if (fwrite(header, 44, 1, out) != 1)
            return -1;
        else
            return 0;
    }
    This is untested; I suggest you read the aforementioned links, and compare the header part to what e.g. arecord generates, using for example dd if=sound.pcm bs=1 count=44 status=none | hexdump -C or similar.

    To use, you just need to call write_wav_header_s16le() before writing out the data.

    Also, instead of the low-level write() call on lines 115-118, you should use
    Code:
    if (fwrite(buffer, size, 1, stdout) != 1) {
        fflush(stdout);
        fprintf(stderr, "Error writing to standard output.\n");
        break;
    }
    No need to prematurely optimize your code. Make sure it works first, then consider if avoiding the overhead (very small for binary data) with standard I/O is worth it.

  3. #3
    Registered User
    Join Date
    Aug 2015
    Posts
    3
    Thank you so much for all advises,i played that pcm file,now i'm gonna try to make the output waw

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 3
    Last Post: 07-28-2012, 03:29 PM
  2. ALSA programming
    By kot in forum Linux Programming
    Replies: 3
    Last Post: 12-29-2011, 05:54 PM
  3. Trouble recording sound
    By Longie in forum Windows Programming
    Replies: 1
    Last Post: 05-08-2005, 11:51 PM
  4. recording sound from your computer
    By Leeman_s in forum A Brief History of Cprogramming.com
    Replies: 2
    Last Post: 07-09-2003, 11:36 AM
  5. ALSA sound problem in Linux
    By MathFan in forum Tech Board
    Replies: 0
    Last Post: 04-24-2003, 10:05 AM