第一次写C++程序,完成使用Alsa采集linux音频

本文分享了作者首次使用C++结合ALSA在Linux环境下进行音频采集的实践过程,从安装依赖库、编译执行脚本到具体代码实现,详细记录了如何设置音频参数、读取音频数据并写入文件,旨在纪念个人技术成长之路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

利用alsa 完成linux下音频采集,第一次用C++写程序,很菜,很水,记录下当时的水平,以后肯定会有提高,算是一个纪念吧

1、运行时前先装库,sudo apt-get install libalsa
2遍tab自动提示出库文件,选择库,alsa-ocaml-dev,最终的命令行为:sudo apt-get install libalsa-ocaml-dev
2、编译执行脚本,gcc -o main main.c -lasound;
3、执行 ./main
以下是代码`#define LSA_PCM_NEW_HW_PARAMS_API
#include <stdlib.h>
#include <stdio.h>
#include <alsa/asoundlib.h>
#include <signal.h>
static int recording;

void stop_record(int param)
{
recording = 0;
}
void InitCapture(snd_pcm_t ** handle,snd_pcm_hw_params_t ** params,snd_pcm_uframes_t* frames,char ** buffer,int* size)
{
int ret;
unsigned int val;
int dir;
//打开设备
ret = snd_pcm_open(handle, “default”, SND_PCM_STREAM_CAPTURE, 0);
printf(“after open file\n”);
if (ret < 0)
{
fprintf(stderr, “unable to open device:%s\n”, snd_strerror(ret));
exit(1);
}
//分配一个硬件参数结构体
snd_pcm_hw_params_alloca(params);

//使用默认参数
snd_pcm_hw_params_any(*handle, *params);

//翻译
    snd_pcm_hw_params_set_access(*handle, *params, SND_PCM_ACCESS_RW_INTERLEAVED);

//S16小端
snd_pcm_hw_params_set_format(*handle, *params, SND_PCM_FORMAT_S16_LE);

//双通道,立体声
snd_pcm_hw_params_set_channels(*handle, *params, 2);

//采样率
val = 44100;
snd_pcm_hw_params_set_rate_near(*handle, *params,&val,&dir);

*frames = 32;
snd_pcm_hw_params_set_period_size_near(*handle, *params,frames,&dir);

//参数生效
ret = snd_pcm_hw_params(*handle, *params);
if (ret<0)
{
	fprintf(stderr, "unable to set hw parameters:%s\n", snd_strerror(ret));
		exit(1);
}
//得到一个周期的数据大小
snd_pcm_hw_params_get_period_size(*params, frames, &dir);

//16位双通道,16位为2字节,2字节*2通道=4,假如frames=1024,则size是1024*4 = 4096
*size = *frames * 4;
*buffer = (char*)malloc(*size); 

//设置一个周期的时间长度
snd_pcm_hw_params_get_period_time(*params, &val, &dir);

}

void CaptureAudio(snd_pcm_t ** handle,snd_pcm_uframes_t* frames,char ** buffer,int* size,FILE ** pFile)
{
int ret;

recording = 1;
while (recording)
{
	ret = snd_pcm_readi(*handle, *buffer,*frames);
	if (ret == -EPIPE )
	{
		fprintf(stderr, "overrun occurred\n");
		snd_pcm_prepare(*handle);
	}
	else if (ret < 0)
	{
		fprintf(stderr, "error from read\n");
		snd_strerror(ret);
	}
	else if (ret != (int)(*frames))
	{
		fprintf(stderr, "short read %d frames\n",ret);
	}
	printf("write to file......%d\n", *size);
	//写到标准输出中去
	ret = fwrite(*buffer, sizeof(char), *size, *pFile);
	if (ret != *size)
	{
		fprintf(stderr, "short write :write %d bytes\n", ret);
	}
	if (signal(SIGINT, stop_record)==SIG_ERR)
	{
		fprintf(stderr, "signal failed\n");
	}
}

}

void CloseCaptureDevice(FILE ** pFile,snd_pcm_t ** handle,char ** buffer)
{
printf(“write file exit\n”);
snd_pcm_drain(*handle);
snd_pcm_close(*handle);
free(*buffer);
fclose(*pFile);
}

int main()
{
FILE * pFile;
pFile = fopen(“test.pcm”, “wb”);
int size;
//给文件操作分配一个句柄
snd_pcm_t * handle;
//硬件参数
snd_pcm_hw_params_t * params;
//
snd_pcm_uframes_t frames;
char * buffer;
printf(“before open file\n”);
InitCapture(&handle,&params,&frames,&buffer,&size);
CaptureAudio(&handle,&frames,&buffer,&size,&pFile);
CloseCaptureDevice(&pFile,&handle,&buffer);
printf(“write file exit\n”);

return 0;

}
`

在Ubuntu上使用C++alsa采集Linux音频并将之存储为WAV文件,你需要先安装必要的库,比如`libasound2-dev`和`libavformat-dev`。以下是一个基本的流程和代码片段: 1. 包含头文件: ```cpp #include <alsa/asoundlib.h> #include <avformat/avformat.h> #include <iostream> #include <string> ``` 2. 初始化alsa: ```cpp int init_alsa() { alsa_dev_t *dev; int error = asound_open(&dev, "default", AF_INPUT, 0); if (error < 0) { std::cerr << "Failed to open ALSA device: " << strerror(-error) << std::endl; return error; } return 0; } ``` 3. 采集音频入WAV文件: ```cpp void capture_and_write_wav(const char* wav_filename, alsa_dev_t* dev) { AVFormatContext *format_ctx = avformat_alloc_context(); if (!format_ctx) { std::cerr << "Failed to allocate AVFormatContext" << std::endl; return; } format_ctx->oformat = av_guess_format("wav", nullptr, nullptr); AVIOContext *io_ctx = NULL; if (avio_open(&io_ctx, wav_filename, AVIO_FLAG_WRITE | AVIO_FLAG_TRUNCATE) < 0) { std::cerr << "Failed to open WAV file for writing: " << strerror(errno) << std::endl; return; } format_ctx->pb = io_ctx; int samples_per_frame = 16; // 根据设备设置可能不同 int channels = 1; // 单声道 int rate = 44100; // CD品质采样率 AVStream *audio_stream = av_new_stream(format_ctx, 0); audio_stream->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; audio_stream->codecpar->codec_id = format_ctx->oformat->codec_id; audio_stream->codecpar->sample_rate = rate; audio_stream->codecpar->channels = channels; audio_stream->codecpar->bits_per_coded_sample = 16; audio_stream->codecpar->frame_size = samples_per_frame * channels; int frames_written = 0; uint8_t buffer[samples_per_frame * channels]; int bytes_per_frame = sizeof(buffer); while (true) { // 使用alsa获取音频数据并入缓冲区 // 这里省略了具体的alsa读取部分,因为alsa回调函数会自动处理 int16_t* raw_samples = read_audio_from_alsa(dev, buffer, bytes_per_frame); if (!raw_samples) break; // 将缓冲区的数据入AVStream av_write_frame(audio_stream, (AVPacket*)buffer); frames_written++; } // 结束入 av_write_trailer(format_ctx); avio_close(io_ctx); avformat_free_context(format_ctx); } ``` 4. 主函数中调用上述函数: ```cpp int main() { alsa_dev_t* dev; if (init_alsa() != 0) { return -1; } std::string wav_filename = "/path/to/output.wav"; capture_and_write_wav(wav_filename.c_str(), dev); asound_close(dev); return 0; } ``` 注意:此代码仅作为示例,实际应用中可能需要处理更复杂的错误情况,以及根据设备特性调整音频参数。同时,alsa读取部分需要实现alsa的回调函数以连续采集音频
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值