前言
平常读麦克风的场景居多,有时候也需要播放一个声音文件,这里就介绍怎么处理。
一、命令行
1.ffmpeg
ffmpeg -i <filename.wav> -f alsa default
2.aplay
aplay -i <filename.wav>
如果提示找不到aplay就安装工具:
sudo apt install alsa-utils
二、代码实现
main.cpp
#include <alsa/asoundlib.h> #include <iostream> #include <fstream> #define PCM_DEVICE "default"//默认的播放设备,你可以在settings里面调换 int main(int argc, char *argv[]) { const char *audioFilename = "../wakeup.wav"; // 配置ALSA参数 snd_pcm_t *pcmHandle; if (snd_pcm_open(&pcmHandle, PCM_DEVICE, SND_PCM_STREAM_PLAYBACK, 0) < 0) { std::cerr << "Error: Failed to open PCM device" << std::endl; return 1; } snd_pcm_hw_params_t *params; snd_pcm_hw_params_alloca(¶ms); snd_pcm_hw_params_any(pcmHandle, params); snd_pcm_hw_params_set_access(pcmHandle, params, SND_PCM_ACCESS_RW_INTERLEAVED); snd_pcm_hw_params_set_format(pcmHandle, params, SND_PCM_FORMAT_S16_LE); snd_pcm_hw_params_set_channels(pcmHandle, params, 2); unsigned int sampleRate = 48000; snd_pcm_hw_params_set_rate_near(pcmHandle, params, &sampleRate, nullptr); snd_pcm_uframes_t bufferSize = 512; snd_pcm_hw_params_set_buffer_size_near(pcmHandle, params, &bufferSize); snd_pcm_hw_params(pcmHandle, params); std::ifstream ifs("../wakeup.wav"); if (ifs.is_open()) { std::string data; size_t size; char buffer[8192]; while ((size = ifs.readsome(buffer, 8192)) > 0) { data.append(buffer, size); } snd_pcm_sframes_t err = snd_pcm_writei(pcmHandle, (const void *) data.c_str(), data.size()); if (err < 0) { std::cerr << "Error: Failed to write PCM device" << std::endl; } ifs.close(); } // 关闭PCM设备和文件 snd_pcm_close(pcmHandle); return 0; }
CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(write_speaker)
set(CMAKE_CXX_STANDARD 11)
add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME} asound)
三、知识补充
C++使用Alsa采集linux音频
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
以下是代码
#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,¶ms,&frames,&buffer,&size); CaptureAudio(&handle,&frames,&buffer,&size,&pFile); CloseCaptureDevice(&pFile,&handle,&buffer); printf(“write file exit\n”); return 0; }