C++使用alsa庫實現(xiàn)播放聲音文件
前言
平常讀麥克風(fēng)的場景居多,有時候也需要播放一個聲音文件,這里就介紹怎么處理。
一、命令行
1.ffmpeg
ffmpeg -i <filename.wav> -f alsa default
2.aplay
aplay -i <filename.wav>
如果提示找不到aplay就安裝工具:
sudo apt install alsa-utils
二、代碼實現(xiàn)
main.cpp
#include <alsa/asoundlib.h>
#include <iostream>
#include <fstream>
#define PCM_DEVICE "default"http://默認(rèn)的播放設(shè)備,你可以在settings里面調(diào)換
int main(int argc, char *argv[]) {
const char *audioFilename = "../wakeup.wav";
// 配置ALSA參數(shù)
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();
}
// 關(guān)閉PCM設(shè)備和文件
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、編譯執(zhí)行腳本,gcc -o main main.c -lasound;
3、執(zhí)行 ./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;
//打開設(shè)備
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);
}
//分配一個硬件參數(shù)結(jié)構(gòu)體
snd_pcm_hw_params_alloca(params);
//使用默認(rèn)參數(shù)
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);
//參數(shù)生效
ret = snd_pcm_hw_params(*handle, *params);
if (ret<0)
{
fprintf(stderr, "unable to set hw parameters:%s\n", snd_strerror(ret));
exit(1);
}
//得到一個周期的數(shù)據(jù)大小
snd_pcm_hw_params_get_period_size(*params, frames, &dir);
//16位雙通道,16位為2字節(jié),2字節(jié)*2通道=4,假如frames=1024,則size是1024*4 = 4096
*size = *frames * 4;
*buffer = (char*)malloc(*size);
//設(shè)置一個周期的時間長度
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);
//寫到標(biāo)準(zhǔn)輸出中去
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;
//硬件參數(shù)
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;
}到此這篇關(guān)于C++使用alsa庫實現(xiàn)播放聲音文件的文章就介紹到這了,更多相關(guān)C++ alsa播放聲音文件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語言動態(tài)分配二維字符串?dāng)?shù)組的方法
小編最近忙里偷閑,給大家整理一份教程關(guān)于C語言動態(tài)分配二維字符串?dāng)?shù)組的方法,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2021-10-10

