linux下基于ALSA驱动录制wav文件

    //linux下ALSA录制声音的源程序 //欧德浪18年2月2日整理
    /* Use the newer ALSA API */
    #define ALSA_PCM_NEW_HW_PARAMS_API

    #include <alsa/asoundlib.h>

    /* this buffer holds the digitized audio */
    //unsigned char buf[LENGTH*RATE*SIZE*CHANNELS/8];
    typedef unsigned char   BYTE;
    typedef unsigned short  WORD;
    typedef unsigned int  DWORD;
    typedef unsigned int  FOURCC;    /* a four character code */

    /* flags for 'wFormatTag' field of WAVEFORMAT */
    #define WAVE_FORMAT_PCM 1

    /* MMIO macros */
    #define mmioFOURCC(ch0, ch1, ch2, ch3) \
      ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
      ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))

    #define FOURCC_RIFF    mmioFOURCC ('R', 'I', 'F', 'F')
    #define FOURCC_LIST    mmioFOURCC ('L', 'I', 'S', 'T')
    #define FOURCC_WAVE    mmioFOURCC ('W', 'A', 'V', 'E')
    #define FOURCC_FMT    mmioFOURCC ('f', 'm', 't', ' ')
    #define FOURCC_DATA    mmioFOURCC ('d', 'a', 't', 'a')

    typedef struct CHUNKHDR {
        FOURCC ckid;        /* chunk ID */
        DWORD dwSize;             /* chunk size */
    } CHUNKHDR;

    /* simplified Header for standard WAV files */
    typedef struct WAVEHDR {
        CHUNKHDR chkRiff;
        FOURCC fccWave;
        CHUNKHDR chkFmt;
        WORD wFormatTag;       /* format type */
        WORD nChannels;       /* number of channels (i.e. mono, stereo, etc.) */
        DWORD nSamplesPerSec;  /* sample rate */
        DWORD nAvgBytesPerSec; /* for buffer estimation */
        WORD nBlockAlign;       /* block size of data */
        WORD wBitsPerSample;
        CHUNKHDR chkData;
    } WAVEHDR;

    #if BYTE_ORDER == BIG_ENDIAN
    # define cpu_to_le32(x) SWAP4((x))
    # define cpu_to_le16(x) SWAP2((x))
    # define le32_to_cpu(x) SWAP4((x))
    # define le16_to_cpu(x) SWAP2((x))
    #else
    # define cpu_to_le32(x) (x)
    # define cpu_to_le16(x) (x)
    # define le32_to_cpu(x) (x)
    # define le16_to_cpu(x) (x)
    #endif

    static void wav_init_header(WAVEHDR *fileheader)
    {
        /* stolen from cdda2wav */
        int nBitsPerSample = 16;
        int channels       = 1;
        int rate           = 8000;

        unsigned long nBlockAlign = channels * ((nBitsPerSample + 7) / 8);
        unsigned long nAvgBytesPerSec = nBlockAlign * rate;
        unsigned long temp = /* data length */ 0 +
        sizeof(WAVEHDR) - sizeof(CHUNKHDR);

        fileheader->chkRiff.ckid    = cpu_to_le32(FOURCC_RIFF);
        fileheader->fccWave         = cpu_to_le32(FOURCC_WAVE);
        fileheader->chkFmt.ckid     = cpu_to_le32(FOURCC_FMT);
        fileheader->chkFmt.dwSize   = cpu_to_le32(16);
        fileheader->wFormatTag      = cpu_to_le16(WAVE_FORMAT_PCM);
        fileheader->nChannels       = cpu_to_le16(channels);
        fileheader->nSamplesPerSec  = cpu_to_le32(rate);
        fileheader->nAvgBytesPerSec = cpu_to_le32(nAvgBytesPerSec);
        fileheader->nBlockAlign     = cpu_to_le16(nBlockAlign);
        fileheader->wBitsPerSample  = cpu_to_le16(nBitsPerSample);
        fileheader->chkData.ckid    = cpu_to_le32(FOURCC_DATA);
        fileheader->chkRiff.dwSize  = cpu_to_le32(temp);
        fileheader->chkData.dwSize  = cpu_to_le32(0 /* data length */);
    }

    static void wav_start_write(FILE* fd, WAVEHDR *fileheader)
    {
        wav_init_header(fileheader);
        fwrite(fileheader,1, sizeof(WAVEHDR), fd);
    }

    static void wav_stop_write(FILE* fd, WAVEHDR *fileheader, int wav_size)
    {
        unsigned long temp = wav_size + sizeof(WAVEHDR) - sizeof(CHUNKHDR);

        fileheader->chkRiff.dwSize = cpu_to_le32(temp);
        fileheader->chkData.dwSize = cpu_to_le32(wav_size);
        fseek(fd,0,SEEK_SET);
           fwrite(fileheader,1, sizeof(WAVEHDR), fd);
    }

    int main() 
    {
        long loops;
        int rc;
        int size;
        snd_pcm_t *rec_handle;
        snd_pcm_hw_params_t *rec_params;
        unsigned int val;
        int dir;
        snd_pcm_uframes_t frames;
        char *buffer;
        WAVEHDR wavheader;
        int total_len = 0;
        FILE *fp_rec = fopen("rec.wav", "wb");
        if(fp_rec==NULL)
        {
            return 0;
        }
        wav_start_write(fp_rec, &wavheader);
        /* Open PCM device for recording (capture). */
        rc = snd_pcm_open(&rec_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(&rec_params);

        /* Fill it in with default values. */
        snd_pcm_hw_params_any(rec_handle, rec_params);

        /* Set the desired hardware parameters. */

        /* Interleaved mode */
        snd_pcm_hw_params_set_access(rec_handle, rec_params,
                              SND_PCM_ACCESS_RW_INTERLEAVED);

        /* Signed 16-bit little-endian format */
        snd_pcm_hw_params_set_format(rec_handle, rec_params,
                                      SND_PCM_FORMAT_S16_LE);

        /* Two channels (stereo) */
        snd_pcm_hw_params_set_channels(rec_handle, rec_params, 1);

        /* 44100 bits/second sampling rate (CD quality) */
        val = 8000;
        snd_pcm_hw_params_set_rate_near(rec_handle, rec_params,
                                          &val, &dir);

        /* Set period size to 32 frames. */
        frames = 32;
        snd_pcm_hw_params_set_period_size_near(rec_handle,
                                      rec_params, &frames, &dir);

        /* Write the parameters to the driver */
        rc = snd_pcm_hw_params(rec_handle, rec_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(rec_params,  &frames, &dir);
        size = frames * 2; /* 2 bytes/sample, 2 channels */
        buffer = (char *) malloc(size);

        /* We want to loop for 5 seconds */
        snd_pcm_hw_params_get_period_time(rec_params, &val, &dir);
        loops = 2000;

        while (loops-- > 0) 
        {
            rc = snd_pcm_readi(rec_handle, buffer, frames); 

     if (rc == -EPIPE) 
            {
              /* EPIPE means overrun */
              fprintf(stderr, "overrun occurred\n");
              snd_pcm_prepare(rec_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 = fwrite(buffer, 1, size, fp_rec);
            total_len += size;
            printf("#\n");
            if (rc != size)
              fprintf(stderr,"short write: wrote %d bytes\n", rc);
        }
        wav_stop_write(fp_rec, &wavheader, total_len);
        snd_pcm_drain(rec_handle);
        snd_pcm_close(rec_handle);
        free(buffer);
        fclose(fp_rec);
        return 0;
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,755评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,369评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,799评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,910评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,096评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,159评论 3 411
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,917评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,360评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,673评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,814评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,509评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,156评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,123评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,641评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,728评论 2 351

推荐阅读更多精彩内容