Alsa-lib实现播放wav音频

Alsa-lib实现播放wav音频

1.alsa-lib移植

例程中使用的alsa-lib库是1.2.6版本的,目前最新的release版本已经到1.2.7版本了,可以根据自身需求下载。

具体下载链接可以访问下面alsa官网的下载链接

https://www.alsa-project.org/files/pub/lib/

下载完alsa-lib库后,我们解压后进入文件夹然后执行下列命令,进行交叉编译

mkdir builds
./configure --prefix=$PWD/builds --host=arm cc=arm-linux-gnueabihf-gcc 
make
make install

所有的lib库和头文件都会在builds文件夹下,执行file + lib库,查看交叉编译是否完成,下列是32bit 小端模式,表示交叉编译完成

/project/alsa-lib-1.2.6$ file build/lib/libasound.so.2.0.0 
build/lib/libasound.so.2.0.0: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, BuildID[sha1]=568ab75e8ab65df19ba5f34b536694ee4449ce6f, not stripped

2.播放wav音频

1.实现流程

alsa-lib具体的播放音频步骤如下,可以参照官网的例程

1.相关变量定义

2.申请hwparams变量内存 snd_pcm_hw_params_alloca(&pcm->hwparams)

3.打开pcm设备snd_pcm_open

4.初始化hwparams的结构体空间

5.设置数据的属性

​ 1.设置数据的读写模式(一般音频双通道分交错访问模式)

​ 2.设置数据的采样格式(每bit的样本长度)

​ 3.设置数据的通道数

​ 4.设置数据的采样速率

​ 5.设置数据的采样周期

​ 每帧的大小 = 采样格式 * 通道数 / 8bit

​ 特定的周期内的帧数 = 周期大小 * 周期数 / 每帧的大小

​ 比如 某个音频的 采样格式是SND_PCM_FORMAT_S16_LE , 通道数是 2 ,所以一帧的音频大小是 16 x 2 /8 = 4个字节,

周期数为20,周期大小为8192,这个周期内帧数一共有 20 x 8192 >> 2 = 40960 帧

6.申请存放buff的空间 (按帧数计算)snd_pcm_hw_params_set_buffer_size

7.读取音频数据

8.调用snd_pcm_writei 进行播放

2.具体实现

具体的代码在,这个例程只实现了播放wav文件,后续继续更新其他功能

git@github.com:lilixinxin/Alsa_example.git

alsa-lib的封装的结构体

typedef struct pcm_params {
    //pcm name like plughw:0,0
    char pcm_card_name[64];
    //pcm device handle
    snd_pcm_t *pcm_handle;
    //pcm stream direction
    snd_pcm_stream_t stream_direction;
    //specify configution for pcm
    snd_pcm_hw_params_t *hwparams;
    //channel num
    int channel_num;
    //周期数
    int periods;
    //sample format bit per sample
    snd_pcm_format_t sample_format;
    //PCM access type 交错模式或者交错
    snd_pcm_access_t access_type;
    //采样率
    int sample_rate;
    //每个周期的大小
    int period_szie;
    //frames 帧数
    int frames;
}Pcm_params;

初始化alsa 相关参数

//初始化alsa device
int Alsa_Dev_init(Pcm_params *pcm)
{
    int ret;

    //allocate snd_pcm_hw_params_t
    snd_pcm_hw_params_alloca(&pcm->hwparams);

        //open pcm device
    if(snd_pcm_open(&pcm->pcm_handle, pcm->pcm_card_name, pcm->stream_direction, 0) < 0)
    {
        fprintf(stderr, "Error opening PCM device %s\n", pcm->pcm_card_name);
        return -1;
    }

    /* Init hwparams with full configuration space */
    if (snd_pcm_hw_params_any(pcm->pcm_handle, pcm->hwparams) < 0) {
      fprintf(stderr, "Can not configure this PCM device.\n");
      return -1;
    }

    //设置数据访问模式
    if (snd_pcm_hw_params_set_access(pcm->pcm_handle, pcm->hwparams, pcm->access_type) < 0) {

        fprintf(stderr, "Can not set hw params access\n");
        return -1;
    }
    //set sample format bit per sample
    if(snd_pcm_hw_params_set_format(pcm->pcm_handle, pcm->hwparams, pcm->sample_format) < 0)
    {
        fprintf(stderr, "snd_pcm_hw_params_set_format fail\n");
        return -1;

    }
    //set channel num
    if(snd_pcm_hw_params_set_channels(pcm->pcm_handle, pcm->hwparams, pcm->channel_num) < 0)
    {
        fprintf(stderr, "snd_pcm_hw_params_set_channels fail\n");
        return -1;
    }
    //set period
    if(snd_pcm_hw_params_set_periods(pcm->pcm_handle, pcm->hwparams, pcm->periods, 0) < 0)
    {
        fprintf(stderr, "snd_pcm_hw_params_set_periods fail\n");
        return -1;
    }

    //set sample rate
    if(snd_pcm_hw_params_set_rate_near(pcm->pcm_handle, pcm->hwparams, &pcm->sample_rate, 0) < 0)
    {
        fprintf(stderr, "snd_pcm_hw_params_set_rate_near fail\n");
        return -1;
    }
    //每帧大小  每bit样本长度 * channel_num / 8bit
    //buffer size 按帧计算器 周期数 * 每个周期时间
    /* Set buffer size (in frames). The resulting latency is given by */
        /* latency = periodsize * periods / (rate * bytes_per_frame)     */
    //pcm->frames = (pcm->period_szie * pcm->periods) >> 2;
    if (snd_pcm_hw_params_set_buffer_size(pcm->pcm_handle, pcm->hwparams, pcm->frames) < 0) {
      fprintf(stderr, "Error setting buffersize.\n");
      return(-1);
    }

            /* Apply HW parameter settings to */
    /* PCM device and prepare device  */
    if (snd_pcm_hw_params(pcm->pcm_handle, pcm->hwparams) < 0) {
      fprintf(stderr, "Error setting HW params.\n");
      return(-1);
    }

    return 0;

}
//播放
int Alsa_Playback(Pcm_params *pcm, char **buf)
{
    int pcmreturn;
    while ((pcmreturn = snd_pcm_writei(pcm->pcm_handle, buf, pcm->frames)) < 0) {
            snd_pcm_prepare(pcm->pcm_handle);
            fprintf(stderr, "<<<<<<<<<<<<<<< Buffer Underrun >>>>>>>>>>>>>>>\n");
      }
    return 0;
}

实现播放

  //申请buff空间
    int buffsize = pcm.period_szie * pcm.periods;
    buff = (char *)malloc(buffsize);
    if(buff == NULL)
    {
        fprintf(stderr, "malloc fail\n");
        return -1;
        
    }

    while(1)
    {
        ret = fread(buff, 1, buffsize, fp);
        printf("read buff len, :%d\n", ret);
        if(ret == 0){
            printf("end of music file input! \n");
           exit(1);
        }
    
        if(ret < 0){
            printf("read pcm from file! \n");
            exit(1);
        }
        while ((ret = snd_pcm_writei(pcm.pcm_handle, buff, pcm.frames)) < 0) {
            snd_pcm_prepare(pcm.pcm_handle);
            fprintf(stderr, "<<<<<<<<<<<<<<< Buffer Underrun >>>>>>>>>>>>>>>\n");
      }
        //Alsa_Playback(&pcm, &buff);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值