C 语言

关注公众号 jb51net

关闭
首页 > 软件编程 > C 语言 > C++ alsa播放声音文件

C++使用alsa库实现播放声音文件

作者:洛克希德马丁

这篇文章主要为大家详细介绍了Linux系统上C++如何使用alsa库播放声音文件,文中示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下

前言

平常读麦克风的场景居多,有时候也需要播放一个声音文件,这里就介绍怎么处理。

一、命令行

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(&params);
    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,&params,&frames,&buffer,&size);
CaptureAudio(&handle,&frames,&buffer,&size,&pFile);
CloseCaptureDevice(&pFile,&handle,&buffer);
printf(“write file exit\n”);

return 0;
}

到此这篇关于C++使用alsa库实现播放声音文件的文章就介绍到这了,更多相关C++ alsa播放声音文件内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文