1. System preparation
- Embedded system with Debian based OS such Raspberry Pi in this tutorial
- Microphone, to check whether your system having any microphone or not, run command below
sudo arecord -L
hw:CARD=Device,DEV=0
USB PnP Sound Device, USB Audio
Direct hardware device without any conversions
plughw:CARD=Device,DEV=0
USB PnP Sound Device, USB Audio
Hardware device with all software conversions
usbstream:CARD=Device
USB PnP Sound Device
USB Stream Output
2. Install libraries
sudo apt install -y libsndfile1-dev libasound2-dev
3. Code
3.1 Include
#include <stdio.h>
#include <stdint.h>
#include <sys/time.h>
#include <unistd.h>
#include <alsa/asoundlib.h>
3.2 Define for default values
#define RECORD_SAMPLE_RATE 22000
#define RECORD_RATE_OFFSET 0
#define RECORD_FRAME 32
3.3 Global variables
snd_pcm_t *_soundDevice;
snd_pcm_uframes_t frames;
int cycleSize;
3.4 Initialize
int recorder_init(const char *name, unsigned int rate, snd_pcm_uframes_t fr){
int err;
int dir;
snd_pcm_hw_params_t *hw_params;
unsigned int actualRate = RECORD_SAMPLE_RATE + RECORD_RATE_OFFSET;
unsigned int usCycle = 0;
/* Open PCM device for recording (capture). */
printf("[%lu] [Recorder] Open device \"%s\" for recording...\r\n",time(NULL),name);
if( name == NULL ){
// Try to open the default device
err = snd_pcm_open( &_soundDevice, "default", SND_PCM_STREAM_CAPTURE, 0 );
}
else{
// Open the device we were told to open.
err = snd_pcm_open (&_soundDevice, name, SND_PCM_STREAM_CAPTURE, 0);
}
// Check for error on open.
if( err < 0 ){
printf("[%lu] [Recorder] Cannot open audio device %s ( %s )...Try default device...\r\n",time(NULL),name,snd_strerror (err));
// Try to open the default device
err = snd_pcm_open( &_soundDevice, "default", SND_PCM_STREAM_CAPTURE, 0 );
}
// Check for error on open.
if( err < 0 ){
printf("[%lu] [Recorder] Cannot open default audio device ( %s )\r\n",time(NULL),snd_strerror (err));
return -1;
}
// Allocate the hardware parameter structure.
if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0){
printf("[%lu] [Recorder] Cannot allocate hardware parameter structure ( %s )\r\n",time(NULL),snd_strerror (err));
return -2;
}
/* Fill it in with default values. */
if ((err = snd_pcm_hw_params_any (_soundDevice, hw_params)) < 0){
printf("[%lu] [Recorder] Cannot initialize hardware parameter structure ( %s )",time(NULL),snd_strerror (err));
return -3;
}
/* Set the desired hardware parameters. */
// Set access to RW interleaved.
if ((err = snd_pcm_hw_params_set_access (_soundDevice, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0){
printf("[%lu] [Recorder] Cannot set access type ( %s )\r\n",time(NULL),snd_strerror (err));
return -4;
}
// Signed 16-bit little-endian format
if ((err = snd_pcm_hw_params_set_format (_soundDevice, hw_params, SND_PCM_FORMAT_S16_LE)) < 0){
printf("[%lu] [Recorder] Cannot set sample format ( %s )\r\n",time(NULL),snd_strerror (err));
return -5;
}
// Set channels to stereo (2).
if ((err = snd_pcm_hw_params_set_channels (_soundDevice, hw_params, 2)) < 0){
printf("[%lu] [Recorder] Cannot set channel count ( %s )\r\n",time(NULL),snd_strerror (err));
return -6;
}
// Set sample rate.
actualRate = rate + RECORD_RATE_OFFSET;
if ((err = snd_pcm_hw_params_set_rate_near (_soundDevice, hw_params, &actualRate, &dir)) < 0){
printf("[%lu] [Recorder] Cannot set sample rate to %u. ( %s )\r\n",time(NULL),rate,snd_strerror (err));
return -7;
}
if ((err = snd_pcm_hw_params_get_rate(hw_params, &actualRate, &dir)) < 0){
printf("[%lu] [Recorder] Cannot get sample rate: ( %s )\r\n",time(NULL),snd_strerror (err));
return -8;
}
if( actualRate < rate ){
printf("[%lu] [Recorder] Sample rate does not match requested rate ( %u requested, %u acquired ).\r\n",time(NULL),rate,actualRate);
}
// Set period size to 32 frames.
frames = fr;
snd_pcm_hw_params_set_period_size_near(_soundDevice, hw_params,&frames, &dir);
// Write the parameters to the driver
if ((err = snd_pcm_hw_params (_soundDevice, hw_params)) < 0){
printf("[%lu] [Recorder] Cannot write the parameters to the driver ( %s )\r\n",time(NULL),snd_strerror (err));
return -9;
}
// Use a buffer large enough to hold one period */
snd_pcm_hw_params_get_period_size(hw_params, &frames,&dir);
cycleSize = frames * 1; /* 2 bytes/sample, 2 channels */
/* Extract period time from a configuration space */
snd_pcm_hw_params_get_period_time(hw_params,&usCycle, &dir);
printf("[%lu] [Recorder] Rate = %d,\tframe = %lu\r\n",time(NULL),actualRate,frames);
printf("[%lu] [Recorder] cycleSize = %d,\tusCycle = %d\r\n",time(NULL),cycleSize,usCycle);
printf("[%lu] [Recorder] Audio device has been prepared for use.\r\n",time(NULL));
return cycleSize;
}
3.5 Deinitialize
int recorder_uninit(){
snd_pcm_drain (_soundDevice);
snd_pcm_close (_soundDevice);
printf("[%lu] [Recorder] Audio device has been uninitialized.\r\n",time(NULL));
return 0;
}
3.6 Read frame
int recorder_readFrame(int16_t *buff, int len){
int16_t *cycleBuff;
int rc;
cycleBuff = (int16_t *) malloc(cycleSize*sizeof(cycleBuff));
if(cycleBuff == NULL){
return 0;
}
memset(cycleBuff,0,cycleSize*sizeof(cycleBuff));
memset(buff,0,len);
rc = snd_pcm_readi(_soundDevice, cycleBuff, frames);
if(rc == -EPIPE){
/* EPIPE means overrun */
//printf("[%lu] [Recorder] Overrun!\r\n",time(NULL));
snd_pcm_prepare(_soundDevice);
free(cycleBuff);
return 0;
}
else{
if(rc != (int)frames){
printf("[%lu] [Recorder] Short read, read %d frames\r\n",time(NULL),rc);
}
}
if(len>cycleSize){
memcpy(buff,cycleBuff,cycleSize * sizeof(cycleBuff));
}
else{
memcpy(buff,cycleBuff,len * sizeof(cycleBuff));
}
free(cycleBuff);
return cycleSize;
}
3.7 Main program
In this example, “plughw:CARD=Device,DEV=0” is my audio device, replace it to fit into your system.
int main(){
// Recorder settings
snd_pcm_uframes_t record_frame = RECORD_FRAME;
int record_rate = RECORD_SAMPLE_RATE;
int record_len = 0;
// Data frame
int16_t *dat;
int dat_len;
// Init recorder
record_len = recorder_init("plughw:CARD=Device,DEV=0",record_rate,record_frame);
if(record_len<0){
printf("[%lu] Cannot init recorder...\r\n",time(NULL));
return -1;
}
// Allocate buffer
dat = (int16_t *) malloc(record_len*sizeof(dat));
if(dat){
dat_len = recorder_readFrame(dat,record_len);
if(dat_len>0){
printf("[%lu] Recoreded %d bytes: ",time(NULL),dat_len);
for(int i = 0; i < dat_len; i++){
printf("%d ",dat[i]);
}
printf("\r\n");
}
free(dat);
}
// Release resource
recorder_uninit();
return 0;
}
3.8 Compile
gcc record.c -o rec -lsndfile -lasound
3.9 Test
sudo ./rec
[1641549685] [Recorder] Open device "plughw:CARD=Device,DEV=0" for recording…
[1641549685] [Recorder] Rate = 22001, frame = 32
[1641549685] [Recorder] cycleSize = 32, usCycle = 1496
[1641549685] [Recorder] Audio device has been prepared for use.
[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
[1641549685] [Recorder] Audio device has been uninitialized.
Leave a Reply