{"id":1172,"date":"2022-01-07T16:39:08","date_gmt":"2022-01-07T09:39:08","guid":{"rendered":"https:\/\/bigdolphin.com.vn\/?p=1172"},"modified":"2024-03-26T15:25:19","modified_gmt":"2024-03-26T08:25:19","slug":"recording-sound-using-alsa-and-c-c-for-embedded-systems","status":"publish","type":"post","link":"https:\/\/bigdolphin.com.vn\/?p=1172","title":{"rendered":"Recording sound using ALSA and C\/C++ for embedded systems"},"content":{"rendered":"\n<h3 class=\"wp-block-heading\">1. System preparation<\/h3>\n\n\n\n<ul><li>Embedded system with Debian based OS such Raspberry Pi in this tutorial<\/li><li>Microphone, to check whether your system having any microphone or not, run command below<\/li><\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"bash\" class=\"language-bash line-numbers\">sudo arecord -L<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"bash\" class=\"language-bash\">hw:CARD=Device,DEV=0\n     USB PnP Sound Device, USB Audio\n     Direct hardware device without any conversions\nplughw:CARD=Device,DEV=0\n     USB PnP Sound Device, USB Audio\n     Hardware device with all software conversions\nusbstream:CARD=Device\n     USB PnP Sound Device\n     USB Stream Output<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">2. Install libraries<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"bash\" class=\"language-bash line-numbers\">sudo apt install -y libsndfile1-dev libasound2-dev<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">3. Code<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\">3.1 Include<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"cpp\" class=\"language-cpp line-numbers\">#include &lt;stdio.h&gt;\n#include &lt;stdint.h&gt;\n#include &lt;sys\/time.h&gt;\n#include &lt;unistd.h&gt;\n#include &lt;alsa\/asoundlib.h&gt;<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">3.2 Define for default values<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"cpp\" class=\"language-cpp line-numbers\">#define RECORD_SAMPLE_RATE  22000\n#define RECORD_RATE_OFFSET  0\n#define RECORD_FRAME        32<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">3.3 Global variables<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"cpp\" class=\"language-cpp line-numbers\">snd_pcm_t *_soundDevice;\nsnd_pcm_uframes_t frames;\nint cycleSize;<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">3.4 Initialize<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"cpp\" class=\"language-cpp line-numbers\">int recorder_init(const char *name, unsigned int rate, snd_pcm_uframes_t fr){\n  int err;\n  int dir;\n  snd_pcm_hw_params_t *hw_params;  \n  unsigned int actualRate = RECORD_SAMPLE_RATE + RECORD_RATE_OFFSET;\n  unsigned int usCycle = 0;  \n\n  \/* Open PCM device for recording (capture). *\/\n  printf(\"[%lu] [Recorder] Open device \\\"%s\\\" for recording...\\r\\n\",time(NULL),name);\n  if( name == NULL ){\n    \/\/ Try to open the default device\n    err = snd_pcm_open( &amp;_soundDevice, \"default\", SND_PCM_STREAM_CAPTURE, 0 );\n  }\n  else{\n    \/\/ Open the device we were told to open.\n    err = snd_pcm_open (&amp;_soundDevice, name, SND_PCM_STREAM_CAPTURE, 0);\n  }\n\n  \/\/ Check for error on open.\n  if( err &lt; 0 ){\n    printf(\"[%lu] [Recorder] Cannot open audio device %s ( %s )...Try default device...\\r\\n\",time(NULL),name,snd_strerror (err));\n    \/\/ Try to open the default device\n    err = snd_pcm_open( &amp;_soundDevice, \"default\", SND_PCM_STREAM_CAPTURE, 0 );\n  }\n\n  \/\/ Check for error on open.\n  if( err &lt; 0 ){\n    printf(\"[%lu] [Recorder] Cannot open default audio device ( %s )\\r\\n\",time(NULL),snd_strerror (err));\n    return -1;\n  }\n\n  \/\/ Allocate the hardware parameter structure.\n  if ((err = snd_pcm_hw_params_malloc (&amp;hw_params)) &lt; 0){\n    printf(\"[%lu] [Recorder] Cannot allocate hardware parameter structure ( %s )\\r\\n\",time(NULL),snd_strerror (err));\n    return -2;\n  }\n\n  \/* Fill it in with default values. *\/\n  if ((err = snd_pcm_hw_params_any (_soundDevice, hw_params)) &lt; 0){\n    printf(\"[%lu] [Recorder] Cannot initialize hardware parameter structure ( %s )\",time(NULL),snd_strerror (err));\n    return -3;\n  }\n\n  \/* Set the desired hardware parameters. *\/\n  \/\/ Set access to RW interleaved.\n  if ((err = snd_pcm_hw_params_set_access (_soundDevice, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) &lt; 0){\n    printf(\"[%lu] [Recorder] Cannot set access type ( %s )\\r\\n\",time(NULL),snd_strerror (err));\n    return -4;\n  }\n\n  \/\/ Signed 16-bit little-endian format\n  if ((err = snd_pcm_hw_params_set_format (_soundDevice, hw_params, SND_PCM_FORMAT_S16_LE)) &lt; 0){\n    printf(\"[%lu] [Recorder] Cannot set sample format ( %s )\\r\\n\",time(NULL),snd_strerror (err));\n    return -5;\n  }\n  \/\/ Set channels to stereo (2).\n  if ((err = snd_pcm_hw_params_set_channels (_soundDevice, hw_params, 2)) &lt; 0){\n    printf(\"[%lu] [Recorder] Cannot set channel count ( %s )\\r\\n\",time(NULL),snd_strerror (err));\n    return -6;\n  }\n  \/\/ Set sample rate.\n  actualRate = rate + RECORD_RATE_OFFSET;\n  if ((err = snd_pcm_hw_params_set_rate_near (_soundDevice, hw_params, &amp;actualRate, &amp;dir)) &lt; 0){\n    printf(\"[%lu] [Recorder] Cannot set sample rate to %u. ( %s )\\r\\n\",time(NULL),rate,snd_strerror (err));\n    return -7;\n  }\n  if ((err = snd_pcm_hw_params_get_rate(hw_params, &amp;actualRate, &amp;dir)) &lt; 0){\n    printf(\"[%lu] [Recorder] Cannot get sample rate: ( %s )\\r\\n\",time(NULL),snd_strerror (err));\n    return -8;\n  }\n  if( actualRate &lt; rate ){\n    printf(\"[%lu] [Recorder] Sample rate does not match requested rate ( %u requested, %u acquired ).\\r\\n\",time(NULL),rate,actualRate);\n  }\n  \/\/ Set period size to 32 frames.\n  frames = fr;\n  snd_pcm_hw_params_set_period_size_near(_soundDevice, hw_params,&amp;frames, &amp;dir);\n  \/\/ Write the parameters to the driver\n  if ((err = snd_pcm_hw_params (_soundDevice, hw_params)) &lt; 0){\n    printf(\"[%lu] [Recorder] Cannot write the parameters to the driver ( %s )\\r\\n\",time(NULL),snd_strerror (err));\n    return -9;\n  }\n  \/\/ Use a buffer large enough to hold one period *\/\n  snd_pcm_hw_params_get_period_size(hw_params, &amp;frames,&amp;dir);\n  cycleSize = frames * 1; \/* 2 bytes\/sample, 2 channels *\/\n  \/* Extract period time from a configuration space *\/\n  snd_pcm_hw_params_get_period_time(hw_params,&amp;usCycle, &amp;dir);\n  printf(\"[%lu] [Recorder] Rate       = %d,\\tframe   = %lu\\r\\n\",time(NULL),actualRate,frames);\n  printf(\"[%lu] [Recorder] cycleSize  = %d,\\tusCycle = %d\\r\\n\",time(NULL),cycleSize,usCycle);\n  printf(\"[%lu] [Recorder] Audio device has been prepared for use.\\r\\n\",time(NULL));\n\n  return cycleSize;\n}<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">3.5 Deinitialize<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"cpp\" class=\"language-cpp line-numbers\">int recorder_uninit(){\n  snd_pcm_drain (_soundDevice);\n  snd_pcm_close (_soundDevice);\n  printf(\"[%lu] [Recorder] Audio device has been uninitialized.\\r\\n\",time(NULL));\n  return 0;\n}<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">3.6 Read frame<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"cpp\" class=\"language-cpp line-numbers\">int recorder_readFrame(int16_t *buff, int len){\n  int16_t *cycleBuff;\n  int rc;\n  cycleBuff = (int16_t *) malloc(cycleSize*sizeof(cycleBuff));\n  if(cycleBuff == NULL){\n    return 0;\n  }\n  memset(cycleBuff,0,cycleSize*sizeof(cycleBuff));\n  memset(buff,0,len);\n  rc = snd_pcm_readi(_soundDevice, cycleBuff, frames);\n  if(rc == -EPIPE){\n    \/* EPIPE means overrun *\/\n    \/\/printf(\"[%lu] [Recorder] Overrun!\\r\\n\",time(NULL));\n    snd_pcm_prepare(_soundDevice);\n    free(cycleBuff);\n    return 0;\n  }\n  else{\n    if(rc != (int)frames){\n      printf(\"[%lu] [Recorder] Short read, read %d frames\\r\\n\",time(NULL),rc);\n    }        \n  }\n  if(len&gt;cycleSize){\n    memcpy(buff,cycleBuff,cycleSize * sizeof(cycleBuff));\n  }\n  else{\n    memcpy(buff,cycleBuff,len * sizeof(cycleBuff));\n  }        \n  free(cycleBuff);\n  return cycleSize;\n}<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">3.7 Main program<\/h4>\n\n\n\n<p>In this example, <strong>&#8220;plughw:CARD=Device,DEV=0&#8221;<\/strong> is my audio device, replace it to fit into your system.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"cpp\" class=\"language-cpp line-numbers\">int main(){\n  \/\/ Recorder settings\n  snd_pcm_uframes_t record_frame = RECORD_FRAME;\n  int record_rate                = RECORD_SAMPLE_RATE;  \n  int record_len                 = 0;\n  \/\/ Data frame\n  int16_t *dat;\n  int dat_len;\n\n  \/\/ Init recorder\n  record_len = recorder_init(\"plughw:CARD=Device,DEV=0\",record_rate,record_frame);\n  if(record_len&lt;0){\n    printf(\"[%lu] Cannot init recorder...\\r\\n\",time(NULL));\n    return -1;\n  }\n  \/\/ Allocate buffer\n  dat = (int16_t *) malloc(record_len*sizeof(dat));\n  if(dat){\n    dat_len = recorder_readFrame(dat,record_len);\n    if(dat_len&gt;0){\n      printf(\"[%lu] Recoreded %d bytes: \",time(NULL),dat_len);\n      for(int i = 0; i &lt; dat_len; i++){\n        printf(\"%d \",dat[i]);\n      }\n      printf(\"\\r\\n\");\n    }\n    free(dat);\n  }\n  \/\/ Release resource\n  recorder_uninit();\n  return 0;\n}<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">3.8 Compile<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"bash\" class=\"language-bash line-numbers\">gcc record.c -o rec -lsndfile -lasound<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">3.9 Test<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"bash\" class=\"language-bash line-numbers\">sudo .\/rec<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"bash\" class=\"language-bash\">[1641549685] [Recorder] Open device \"plughw:CARD=Device,DEV=0\" for recording\u2026\n[1641549685] [Recorder] Rate       = 22001,    frame   = 32\n[1641549685] [Recorder] cycleSize  = 32,    usCycle = 1496\n[1641549685] [Recorder] Audio device has been prepared for use.\n[1641549685] Recoreded 32 bytes: 0 0 0 0 0 0 -1 -1 2 2 -2 -2 3 3 -3 -3 2 2 1 1 -6 -6 13 13 -22 -22 32 32 -41 -41 47 47 \n[1641549685] [Recorder] Audio device has been uninitialized.<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>This tutorial shows you how to record sound on embedded system using ALSA and C\/C++.<\/p>\n","protected":false},"author":2,"featured_media":1189,"comment_status":"open","ping_status":"open","sticky":false,"template":"single-with-sidebar","format":"standard","meta":{"gtb_hide_title":false,"gtb_wrap_title":false,"gtb_class_title":"","gtb_remove_headerfooter":false,"footnotes":""},"categories":[10],"tags":[53,56,57,55,51,54],"_links":{"self":[{"href":"https:\/\/bigdolphin.com.vn\/index.php?rest_route=\/wp\/v2\/posts\/1172"}],"collection":[{"href":"https:\/\/bigdolphin.com.vn\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bigdolphin.com.vn\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bigdolphin.com.vn\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/bigdolphin.com.vn\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1172"}],"version-history":[{"count":20,"href":"https:\/\/bigdolphin.com.vn\/index.php?rest_route=\/wp\/v2\/posts\/1172\/revisions"}],"predecessor-version":[{"id":1202,"href":"https:\/\/bigdolphin.com.vn\/index.php?rest_route=\/wp\/v2\/posts\/1172\/revisions\/1202"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/bigdolphin.com.vn\/index.php?rest_route=\/wp\/v2\/media\/1189"}],"wp:attachment":[{"href":"https:\/\/bigdolphin.com.vn\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1172"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bigdolphin.com.vn\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1172"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bigdolphin.com.vn\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1172"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}