ALSA arm下录音

碰到一个开发 板录音的项目,结合网上的资料,自己总结 了一篇

头文件

#ifndef __RECORD_H
#define __RECORD_H
#include <alsa/asoundlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include "threadsafe_queue.h"

typedef long long off64_t;
typedef struct SNDPCMContainer {
    snd_pcm_t *handle;
    snd_output_t *log;
    snd_pcm_uframes_t chunk_size;
    snd_pcm_uframes_t buffer_size;
    snd_pcm_format_t format;
    uint16_t channels;//声道
    size_t chunk_bytes;
    uint32_t sample_rate;//采样率
    size_t bits_per_sample;//比特率
    size_t bits_per_frame;
    uint8_t *data_buf;
    //uint16_t isrecord;
} SNDPCMContainer_t;


ssize_t SND_ReadPcm(SNDPCMContainer_t *sndpcm, size_t rcount);
void SND_Record(SNDPCMContainer_t *sndpcm, int duration_time, int fd);
int SND_SetParams(SNDPCMContainer_t *sndpcm, uint32_t sample_rate,uint16_t channels,uint16_t bits);
ssize_t SNDWAV_ReadPcm(SNDPCMContainer_t *sndpcm, size_t rcount);


#endif


实现文件

#include <stdio.h>
#include <malloc.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <fcntl.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <time.h>
#include <locale.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "record.h"
#include <assert.h>
#include <sys/time.h>
#include "common.h"
#define DEFAULT_CHANNELS    (8)
#define DEFAULT_SAMPLE_RATE    (96000)
#define DEFAULT_BITS    (32)
#define DEFAULT_DURATION_TIME    (10)


ssize_t SND_ReadPcm(SNDPCMContainer_t *sndpcm, size_t rcount)
{
    ssize_t r;
    size_t result = 0;
    size_t count = rcount;
    uint8_t *data = sndpcm->data_buf;
    
    if (count != sndpcm->chunk_size) {
        count = sndpcm->chunk_size;
    }
    
    while (count > 0) {
        r = snd_pcm_readi(sndpcm->handle, data, count);
        
        if (r == -EAGAIN || (r >= 0 && (size_t)r < count)) {
            snd_pcm_wait(sndpcm->handle, 1000);
        } else if (r == -EPIPE) {
            snd_pcm_prepare(sndpcm->handle);
            fprintf(stderr, "<<<<<<<<<<<<<<< Buffer Underrun >>>>>>>>>>>>>>>\n");
        } else if (r == -ESTRPIPE) {
            fprintf(stderr, "<<<<<<<<<<<<<<< Need suspend >>>>>>>>>>>>>>>\n");
        } else if (r < 0) {
            fprintf(stderr, "Error snd_pcm_writei: [%s]", snd_strerror(r));
            return -1;
        }
        
        if (r > 0) {
            result += r;
            count -= r;
            data += r * sndpcm->bits_per_frame / 8;
        }
    }
    return rcount;
}

int SND_SetParams(SNDPCMContainer_t *sndpcm, uint32_t sample_rate,uint16_t channels,uint16_t bits )
{
    snd_pcm_hw_params_t *hwparams;
    snd_pcm_format_t format;
    switch (bits) {
    case 16:
        format = SND_PCM_FORMAT_S16_LE;
        break;
    case 8:
        format = SND_PCM_FORMAT_U8;
        break;
    case 32:
        format = SND_PCM_FORMAT_S32_LE;
        break;
    default:
            format = SND_PCM_FORMAT_UNKNOWN;
        break;
    }
    uint32_t exact_rate;
    uint32_t buffer_time, period_time;

    /* Allocate the snd_pcm_hw_params_t structure on the stack. */
    snd_pcm_hw_params_alloca(&hwparams);
    
    /* Init hwparams with full configuration space */
    if (snd_pcm_hw_params_any(sndpcm->handle, hwparams) < 0) {
        fprintf(stderr, "Error snd_pcm_hw_params_any\n");
        goto ERR_SET_PARAMS;
    }

    if (snd_pcm_hw_params_set_access(sndpcm->handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
        fprintf(stderr, "Error snd_pcm_hw_params_set_access\n");
        goto ERR_SET_PARAMS;
    }
    if (snd_pcm_hw_params_set_format(sndpcm->handle, hwparams, format) < 0) {
        fprintf(stderr, "Error snd_pcm_hw_params_set_format\n");
        goto ERR_SET_PARAMS;
    }
    sndpcm->format = format;

    /* Set number of channels */
    if (snd_pcm_hw_params_set_channels(sndpcm->handle, hwparams, channels) < 0) {
        fprintf(stderr, "Error snd_pcm_hw_params_set_channels\n");
        goto ERR_SET_PARAMS;
    }
    sndpcm->channels = channels;

    /* Set sample rate. If the exact rate is not supported */
    /* by the hardware, use nearest possible rate.         */
    exact_rate = sample_rate;
    if (snd_pcm_hw_params_set_rate_near(sndpcm->handle, hwparams, &exact_rate, 0) < 0) {
        fprintf(stderr, "Error snd_pcm_hw_params_set_rate_near\n");
        goto ERR_SET_PARAMS;
    }
    if (sample_rate != exact_rate) {
        fprintf(stderr, "The rate %d Hz is not supported by your hardware.\n ==> Using %d Hz instead.\n",
            sample_rate, exact_rate);
    }
    sndpcm->sample_rate = exact_rate;
    
    if (snd_pcm_hw_params_get_buffer_time_max(hwparams, &buffer_time, 0) < 0) {
        fprintf(stderr, "Error snd_pcm_hw_params_get_buffer_time_max\n");
        goto ERR_SET_PARAMS;
    }
    //printf("buffer_time = %ld\n",buffer_time);
    
    if (buffer_time > 40000) buffer_time = 40000;
    //printf("buffer_time2 = %ld\n",buffer_time);
    period_time = buffer_time / 4;
    if (snd_pcm_hw_params_set_buffer_time_near(sndpcm->handle, hwparams, &buffer_time, 0) < 0) {
        fprintf(stderr, "Error snd_pcm_hw_params_set_buffer_time_near\n");
        goto ERR_SET_PARAMS;
    }
    if (snd_pcm_hw_params_set_period_time_near(sndpcm->handle, hwparams, &period_time, 0) < 0) {
        fprintf(stderr, "Error snd_pcm_hw_params_set_period_time_near\n");
        goto ERR_SET_PARAMS;
    }
    /* Set hw params */
    if (snd_pcm_hw_params(sndpcm->handle, hwparams) < 0) {
        fprintf(stderr, "Error snd_pcm_hw_params(handle, params)\n");
        goto ERR_SET_PARAMS;
    }
    snd_pcm_hw_params_get_period_size(hwparams, &sndpcm->chunk_size, 0);
    snd_pcm_hw_params_get_buffer_size(hwparams, &sndpcm->buffer_size);
    if (sndpcm->chunk_size == sndpcm->buffer_size) {        
        fprintf(stderr, ("Can't use period equal to buffer size (%lu == %lu)\n"), sndpcm->chunk_size, sndpcm->buffer_size);        
        goto ERR_SET_PARAMS;
    }
    sndpcm->bits_per_sample = snd_pcm_format_physical_width(format);
    sndpcm->bits_per_frame = sndpcm->bits_per_sample * channels;
    sndpcm->chunk_bytes = sndpcm->chunk_size * sndpcm->bits_per_frame / 8;
    /* Allocate audio data buffer */
    sndpcm->data_buf = (uint8_t *)malloc(sndpcm->chunk_bytes);
    if (!sndpcm->data_buf) {
        fprintf(stderr, "Error malloc: [data_buf]\n");
        goto ERR_SET_PARAMS;
    }
    return 0;
    ERR_SET_PARAMS:
    return -1;
}

int main(){
    
    
    
    char curtime[20] = {'\0'};
    int recordState = 1;
    const char *devicename = "hw:0,0";
    SNDPCMContainer_t sndpcm;
    memset(&sndpcm, 0x0, sizeof(sndpcm));
    
    
     const char *filename;
     filename = "test.pcm";
      int fd;
     if ((fd = open(filename, O_WRONLY | O_CREAT, 0644)) == -1) {  
            fprintf(stderr, "Error open: [%s]/n", filename);  
            return -1;
        }  
    
    
    if (snd_output_stdio_attach(&sndpcm.log, stderr, 0) < 0) {
        fprintf(stderr, "Error snd_output_stdio_attach\n");
        snd_pcm_drain(sndpcm.handle);
        free(sndpcm.data_buf);
        snd_output_close(sndpcm.log);
        snd_pcm_close(sndpcm.handle);
        
        return -1;
    }
    if (snd_pcm_open(&sndpcm.handle, devicename, SND_PCM_STREAM_CAPTURE, 0) < 0) {
        fprintf(stderr, "Error snd_pcm_open [ %s]\n", devicename);
        snd_pcm_drain(sndpcm.handle);
        free(sndpcm.data_buf);
        snd_output_close(sndpcm.log);
        snd_pcm_close(sndpcm.handle);
        return -1;
    }
    uint16_t channels = DEFAULT_CHANNELS;
    uint32_t sample_rate = DEFAULT_SAMPLE_RATE;
    uint16_t bits = DEFAULT_BITS;
    uint32_t duration_time = DEFAULT_DURATION_TIME;
    if (SND_SetParams(&sndpcm, sample_rate,channels,bits ) < 0) {
        fprintf(stderr, "Error set_snd_pcm_params\n");
        snd_pcm_drain(sndpcm.handle);
        free(sndpcm.data_buf);
        snd_output_close(sndpcm.log);
        snd_pcm_close(sndpcm.handle);
        return -1;
    }
    snd_pcm_dump(sndpcm.handle, sndpcm.log);
    uint32_t c,frame_size;
    getTime(curtime);
    printf("%s 准备进入录音流程,录音状态码=%d\n",curtime,*(pcapture_info->isrecord));
    
    while (recordState) {
        //printf("进入录音流程,录音状态码=%d\n",*(pcapture_info->isrecord));
        c = sndpcm.chunk_bytes;
        frame_size = sndpcm.chunk_bytes * 8 / sndpcm.bits_per_frame;
        if (SND_ReadPcm(&sndpcm, frame_size) != frame_size){
            getTime(curtime);
            printf("%s 读PCM失败\n",curtime);
            snd_pcm_drain(sndpcm.handle);
            free(sndpcm.data_buf);
            snd_output_close(sndpcm.log);
            snd_pcm_close(sndpcm.handle);
            return -2;
        }
        
        write(fd, sndpcm.data_buf, c);

    
        

    }
    close(fd);
    snd_pcm_drain(sndpcm.handle);
    free(sndpcm.data_buf);
    snd_output_close(sndpcm.log);
    snd_pcm_close(sndpcm.handle);
    getTime(curtime);
    printf("%s 录音任务结束,文件关闭!\n",curtime);
    
    return 0;
    
}


编译


arm-linux-g++ -o record record.cpp   -lasound  -std=c++11


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值