c语言调用asound播放wav格式音乐

1.源码实现

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <math.h>
#include <unistd.h>
#include <alsa/asoundlib.h>

#pragma pack(push, 1)
typedef struct {
    char riff[4];           //"RIFF"
    uint32_t file_size;     //文件总大小
    char wave[4];           //"WAVE"
    char fmt[4];            //"fmt "
    uint32_t fmt_size;      //fmt chunk大小(至少16)
    uint16_t audio_format;      //1 = PCM
    uint16_t num_channels;      //声道数
    uint32_t sample_rate;       //采样率
    uint32_t byte_rate;     //每秒字节数
    uint16_t block_align;       //每样本字节数
    uint16_t bits_per_sample;   //位深度
    char data[4];           //"data"
    uint32_t data_size;     //音频数据大小
} WavHeader;
#pragma pack(pop)

int play_wav(const char *filename, const char *alsa_device)
{
    FILE *file = fopen(filename, "rb");

    if (!file)
    {
        perror("can not open file\n");

        return -1;
    }

    //1.读取并验证wav头
    WavHeader header;

    if (fread(&header, sizeof(WavHeader), 1, file) != 1)
    {
        fprintf(stderr, "file header read failed\n");

        fclose(file);

        return -2;
    }

    if (memcmp(header.riff, "RIFF", 4) != 0 ||
        memcmp(header.wave, "WAVE", 4) != 0 ||
        memcmp(header.fmt, "fmt ", 4) != 0 ||
        header.audio_format != 1)
    {
        fprintf(stderr, "not pcm wav file\n");

        fclose(file);

        return -3;
    }

    //2.配置ALSA设备
    snd_pcm_t *pcm;
    int err;

    if ((err == snd_pcm_open(&pcm, alsa_device, SND_PCM_STREAM_PLAYBACK, 0)) < 0)
    {
        fprintf(stderr, "alsa device open failed: %s\n", snd_strerror(err));

        fclose(file);

        return -4;
    }

    //根据wav参数设置硬件
    snd_pcm_format_t format;

    if (header.bits_per_sample == 16)
    {
        format = SND_PCM_FORMAT_S16_LE;
    }
    else if (header.bits_per_sample == 24)
    {
        format = SND_PCM_FORMAT_S24_LE;
    }
    else if (header.bits_per_sample == 32)
    {
        format = SND_PCM_FORMAT_S32_LE;
    }
    else
    {
        fprintf(stderr, "not support bit deep: %d\n", header.bits_per_sample);

        fclose(file);

        snd_pcm_close(pcm);

        return -5;
    }

    if ((err = snd_pcm_set_params(
        pcm,
        format,
        SND_PCM_ACCESS_RW_INTERLEAVED,
        header.num_channels,
        header.sample_rate,
        1,
        50000)
        ) < 0
    )
    {
        fprintf(stderr, "params set failed: %s\n", snd_strerror(err));

        fclose(file);

        snd_pcm_close(pcm);

        return -6;
    }

    //3.播放音频数据
    const size_t buffer_size = 4096;
    uint8_t *buffer = malloc(buffer_size);
    size_t remaining = header.data_size;

    while (remaining > 0)
    {
        size_t to_read = (remaining > buffer_size) ? buffer_size : remaining;
        size_t read = fread(buffer, 1, to_read, file);

        if (read == 0)
        {
            break;
        }

        snd_pcm_uframes_t frames = read / header.block_align;

        int write_result = snd_pcm_writei(pcm, buffer, frames);

        if (write_result == -EPIPE)
        {
            fprintf(stderr, "no prepare buffer\n");

            snd_pcm_prepare(pcm);
        }
        else if (write_result < 0)
        {
            fprintf(stderr, "Write failed: %s\n", snd_strerror(write_result));

            break;
        }

        remaining -= read;
    }

    //4.等待播放完成
    snd_pcm_drain(pcm);

    //5.清理资源
    free(buffer);

    fclose(file);

    snd_pcm_close(pcm);

    return 0;
}

int main(int argc, char **argv)
{
    if (argc != 3)
    {
        return -1;
    }

    return play_wav(argv[1], argv[2]);
}

2.编译源码

$ gcc -g -o alsa_demo alsa_demo.c -lasound -lm
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容