alsa播放wav文件

#ifndef _PCM_MNGR_H_
#define _PCM_MNGR_H_

#include <alsa/asoundlib.h>
#include <vector>

class WaveFile;
class PcmMngr
{
private:
    PcmMngr();
public:
    ~PcmMngr();
    static PcmMngr *Instance();

public:
    bool open();
    bool close();
    bool fast_play(const WaveFile &wav);//播放一个文件
    bool fast_play(const WaveFile &wav, uint32_t time, uint32_t interval_ms = 0);//一个文件播放多次
    bool fast_play(const std::vector<WaveFile *> &wav_vec, uint32_t interval_ms = 0);//连续播放多个文件

private:
    bool fast_set_pcm_params(const WaveFile &wav);

private:
    snd_pcm_t               *m_handle;
};

#endif
#include "PcmMngr.h"
#include "WaveFile.h"
#include <unistd.h>

PcmMngr::PcmMngr()
    : m_handle(nullptr)
{

}

PcmMngr::~PcmMngr()
{

}

PcmMngr *PcmMngr::Instance()
{
    static PcmMngr obj;
    return &obj;
}

bool PcmMngr::open()
{
    int ret = snd_pcm_open(&m_handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
	if (ret < 0)
	{
		printf("Playback open error: %s\n", snd_strerror(ret));
		return false;
	}	
	return true;
}

bool PcmMngr::close()
{
    if (m_handle)
	{
		snd_pcm_close(m_handle);
		m_handle = nullptr;
	}
	return true;
}

bool PcmMngr::fast_set_pcm_params(const WaveFile &wav)
{
    snd_pcm_format_t format;
    switch (wav.get_sample_length()) {  
        case 16:  
            format = SND_PCM_FORMAT_S16_LE;  
            break;  
        case 8:  
            format = SND_PCM_FORMAT_U8;  
            break;  
        default:  
            format = SND_PCM_FORMAT_UNKNOWN;  
            break;  
    }

    int err;
    if (err = snd_pcm_set_params(m_handle, format, SND_PCM_ACCESS_RW_INTERLEAVED, wav.get_channels(), wav.get_sample_rate(), 1, 500) < 0) 
    {
        printf("Playback open error: %s\n", snd_strerror(err));
        return false;
    }

    return true;
}

/*
    异步播放:先读文件,再播放
*/
bool PcmMngr::fast_play(const WaveFile &wav)
{
    if (!wav.is_ok())
    {
        printf("wav file invalid \n");
        return false;
    }

    if (!fast_set_pcm_params(wav))
    {
        printf("fast_set_pcm_params failed \n");
        return false;
    }

    const char *data = wav.get_data(); 
    uint32_t data_len = wav.get_data_len(); 
    uint32_t frame_size = wav.get_frame_size();
    if (!data || data_len <= 0 || frame_size <= 0)
    {
        return false;
    }

    int ret = 0;
    snd_pcm_sframes_t frames = 0;
    uint32_t tmpDataLen = data_len;
    uint32_t frame_cnt = data_len / frame_size; //剩余要播放的帧数
    const char *ptr = data;//数据偏移指针

    do
    {
        frames = snd_pcm_writei(m_handle, ptr, frame_cnt);//将交错帧写入PCM,返回实际写入PCM的帧数,失败时返回错误码
        if (frames < 0)
        {
            if (ret = snd_pcm_recover(m_handle, frames, 0) < 0) //从错误中恢复流状态或暂停
            {
                printf("snd_pcm_writei failed: %s\n", snd_strerror(ret));
                break;
            }
        }
        else
        {
            frame_cnt -= frames;
            ptr += frame_size * frames;
            tmpDataLen -= frame_size * frames;
        }
    } while (tmpDataLen > 0);
    
    //停止PCM保存待处理的帧
    /*
    ret = snd_pcm_drain(m_handle);
    if (ret < 0)
    {
        printf("snd_pcm_drain failed: %s\n", snd_strerror(ret));
    } 
    */    
    return true;
}

bool PcmMngr::fast_play(const WaveFile &wav, uint32_t time, uint32_t interval_ms)
{
    for (uint32_t i = 0; i < time; i++)
    {
        fast_play(wav);
        usleep(interval_ms*1000);
    }
    return true;
}

bool PcmMngr::fast_play(const std::vector<WaveFile *> &wav_vec, uint32_t interval_ms)
{
    for (WaveFile *wav : wav_vec)
    {
        fast_play(*wav);
        usleep(interval_ms*1000);
    }
    return true;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值