tinyalsa-tinycap源码浅析

main()函数

先来看看函数的执行流程

1. 定义、初始化相关参数

FILE *file;
struct wav_header header;
unsigned int card = 0;
unsigned int device = 0;
unsigned int channels = 2;
unsigned int rate = 44100;
unsigned int bits = 16;
unsigned int frames;
unsigned int period_size = 1024;
unsigned int period_count = 4;
unsigned int cap_time = 0;
enum pcm_format format;

2. 不输入参数则打印出可以选择的参数

if (argc < 2) {
    fprintf(stderr, "Usage: %s file.wav [-D card] [-d device]"
            " [-c channels] [-r rate] [-b bits] [-p period_size]"
            " [-n n_periods] [-T capture time]\n", argv[0]);
    return 1;
}

3. 打开或创建用于保存数据的文件

file = fopen(argv[1], "wb");

4. 分析传进来的参数,并填充

argv += 2;
while (*argv) {
    if (strcmp(*argv, "-d") == 0) {
        argv++;
        if (*argv)
            device = atoi(*argv);
    } else if (strcmp(*argv, "-c") == 0) {
        argv++;
        if (*argv)
            channels = atoi(*argv);
    } else if (strcmp(*argv, "-r") == 0) {
        argv++;
        if (*argv)
            rate = atoi(*argv);
    } else if (strcmp(*argv, "-b") == 0) {
        argv++;
        if (*argv)
            bits = atoi(*argv);
    } else if (strcmp(*argv, "-D") == 0) {
        argv++;
        if (*argv)
            card = atoi(*argv);
    } else if (strcmp(*argv, "-p") == 0) {
        argv++;
        if (*argv)
            period_size = atoi(*argv);
    } else if (strcmp(*argv, "-n") == 0) {
        argv++;
        if (*argv)
            period_count = atoi(*argv);
    } else if (strcmp(*argv, "-T") == 0) {
        argv++;
        if (*argv)
            cap_time = atoi(*argv);
    }
    if (*argv)
        argv++;
}

header.riff_id = ID_RIFF;
header.riff_sz = 0;
header.riff_fmt = ID_WAVE;
header.fmt_id = ID_FMT;
header.fmt_sz = 16;
header.audio_format = FORMAT_PCM;
header.num_channels = channels;
header.sample_rate = rate;

switch (bits) {
case 32:
    format = PCM_FORMAT_S32_LE;
    break;
case 24:
    format = PCM_FORMAT_S24_LE;
    break;
case 16:
    format = PCM_FORMAT_S16_LE;
    break;
default:
    fprintf(stderr, "%u bits is not supported.\n", bits);
    fclose(file);
    return 1;
}

header.bits_per_sample = pcm_format_to_bits(format);
header.byte_rate = (header.bits_per_sample / 8) * channels * rate;
header.block_align = channels * (header.bits_per_sample / 8);
header.data_id = ID_DATA;

5. 为头部信息留出空间

fseek(file, sizeof(struct wav_header), SEEK_SET);

6. 设置好信号处理函数,并开始数据采集

signal(SIGINT, sigint_handler);
signal(SIGHUP, sigint_handler);
signal(SIGTERM, sigint_handler);
frames = capture_sample(file, card, device, header.num_channels,
                        header.sample_rate,format, period_size,
                        period_count, cap_time);

7. 数据采集完之后,头部所需信息也已知,填充进去即可

header.data_sz = frames * header.block_align;
header.riff_sz = header.data_sz + sizeof(header) - 8;
fseek(file, 0, SEEK_SET);
fwrite(&header, sizeof(struct wav_header), 1, file);

8. 最后关闭文件

fclose(file);

capture_sample()函数

这个函数用于录音,先来看看函数原型

unsigned int capture_sample(FILE *file, unsigned int card, unsigned int device,
                            unsigned int channels, unsigned int rate,
                            enum pcm_format format, unsigned int period_size,
                            unsigned int period_count, unsigned int cap_time)

再来按顺序看看涉及到的函数

1. 打开一个流

struct pcm *pcm_open(unsigned int card, unsigned int device,
                     unsigned int flags, struct pcm_config *config);

2. 根据传入的格式类型返回对应的一帧的空间大小

unsigned int pcm_format_to_bits(enum pcm_format format);

3. 开一个buffer作为缓冲区

buffer = malloc(size);

4. 设置时间。这里now和end代表了开始和结束,相当于定时

clock_gettime(CLOCK_MONOTONIC, &now);
end.tv_sec = now.tv_sec + cap_time;
end.tv_nsec = now.tv_nsec;

5. 进入循环,写入数据,到时间了也会停止

while (capturing && !pcm_read(pcm, buffer, size)) {
    if (fwrite(buffer, 1, size, file) != size) {
        fprintf(stderr,"Error capturing sample\n");
        break;
    }
    bytes_read += size;
    if (cap_time) {
        clock_gettime(CLOCK_MONOTONIC, &now);
        if (now.tv_sec > end.tv_sec ||
            (now.tv_sec == end.tv_sec && now.tv_nsec >= end.tv_nsec))
            break;
    }
}

6. 做收尾工作并返回帧数(用于计算总大小,填充文件头部信息)

frames = pcm_bytes_to_frames(pcm, bytes_read);
free(buffer);
pcm_close(pcm);
return frames;

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雨天不打滑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值