代码片段:ALSA回放

#include <stdio.h>
#include <stdint.h>
#include <alsa/asoundlib.h>

#define  PERIOD_SIZE     128
#define  BUFFER_SIZE    (PERIOD_SIZE*8)
#define  THRESHOLD_SIZE  0

typedef struct {
    int16_t left;
    int16_t right;
} PCM_FRAME;

// 打开alsa
static void* alsa_open(uint32_t rate){
    snd_pcm_t *handle = NULL;
    snd_pcm_hw_params_t *hw_params;
    snd_pcm_sw_params_t *sw_params;
    snd_pcm_hw_params_malloc(&hw_params);
    snd_pcm_sw_params_malloc(&sw_params);
    
    // 打开alsa
    if(snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0) < 0){
        snd_pcm_sw_params_free(sw_params);
        snd_pcm_hw_params_free(hw_params);
        return NULL;
    }
    
    // 取所有参数?还是设置所以参数默认值?
    if(snd_pcm_hw_params_any(handle, hw_params) < 0){
        snd_pcm_sw_params_free(sw_params);
        snd_pcm_hw_params_free(hw_params);
        snd_pcm_close(handle);
        return NULL;
    }
    
    // 设置频率可重采样?
    if(snd_pcm_hw_params_set_rate_resample(handle, hw_params, 1) < 0){
        snd_pcm_sw_params_free(sw_params);
        snd_pcm_hw_params_free(hw_params);
        snd_pcm_close(handle);
        return NULL;
    }
    
    // 设置访问模式
    if(snd_pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED) < 0){
        snd_pcm_sw_params_free(sw_params);
        snd_pcm_hw_params_free(hw_params);
        snd_pcm_close(handle);
        return NULL;
    }
    
    // 设置格式
    if(snd_pcm_hw_params_set_format(handle, hw_params, SND_PCM_FORMAT_S16_LE) < 0){
        snd_pcm_sw_params_free(sw_params);
        snd_pcm_hw_params_free(hw_params);
        snd_pcm_close(handle);
        return NULL;
    }
    
    // 设置声道数
    if(snd_pcm_hw_params_set_channels(handle, hw_params, 2) < 0){
        snd_pcm_sw_params_free(sw_params);
        snd_pcm_hw_params_free(hw_params);
        snd_pcm_close(handle);
        return NULL;
    }
    
    // 设置采样频率
    if(snd_pcm_hw_params_set_rate_near(handle, hw_params, &rate, 0) < 0){
        snd_pcm_sw_params_free(sw_params);
        snd_pcm_hw_params_free(hw_params);
        snd_pcm_close(handle);
        return NULL;
    }
    
    // 设置环buffer大小,单位是帧
    if(snd_pcm_hw_params_set_buffer_size(handle, hw_params, BUFFER_SIZE) < 0){
        snd_pcm_sw_params_free(sw_params);
        snd_pcm_hw_params_free(hw_params);
        snd_pcm_close(handle);
        return NULL;
    }
    
    // 设置周期大小,单位是帧
    if(snd_pcm_hw_params_set_period_size(handle, hw_params, PERIOD_SIZE, 0) < 0){
        snd_pcm_sw_params_free(sw_params);
        snd_pcm_hw_params_free(hw_params);
        snd_pcm_close(handle);
        return NULL;
    }
    
    // 硬参数设置生效
    if(snd_pcm_hw_params(handle, hw_params) < 0){
        snd_pcm_sw_params_free(sw_params);
        snd_pcm_hw_params_free(hw_params);
        snd_pcm_close(handle);
        return NULL;
    }
    
    // 取所有参数?还是设置所以参数默认值?
    if(snd_pcm_sw_params_current(handle, sw_params) < 0){
        snd_pcm_sw_params_free(sw_params);
        snd_pcm_hw_params_free(hw_params);
        snd_pcm_close(handle);
        return NULL;
    }
    
    // 设置开始回放的阈值,单位是帧
    if(snd_pcm_sw_params_set_start_threshold(handle, sw_params, THRESHOLD_SIZE) < 0){
        snd_pcm_sw_params_free(sw_params);
        snd_pcm_hw_params_free(hw_params);
        snd_pcm_close(handle);
        return NULL;
    }
    
    // 软参数设置生效
    if(snd_pcm_sw_params(handle, sw_params) < 0){
        snd_pcm_sw_params_free(sw_params);
        snd_pcm_hw_params_free(hw_params);
        snd_pcm_close(handle);
        return NULL;
    }
    
    // 进入准备状态
    if(snd_pcm_prepare(handle) < 0){
        snd_pcm_sw_params_free(sw_params);
        snd_pcm_hw_params_free(hw_params);
        snd_pcm_close(handle);
        return NULL;
    }
    
    snd_pcm_sw_params_free(sw_params);
    snd_pcm_hw_params_free(hw_params);
    return handle;
}

// 回放
static int alsa_write(void *handle, void *buffer, int frameNum){
    int err;
    int ready = 0;
    PCM_FRAME *frame = buffer;
    do{
        while((err = snd_pcm_writei(handle, frame+ready, frameNum-ready)) == -EAGAIN);
        if(err > 0){
            ready += err;
        }else{
            if(err == -EPIPE){
                err = snd_pcm_prepare(handle);
                if(err != 0) return -1;
            }else{
                return -2;
            }
        }
    }while(ready < frameNum);
    return ready;
}

// 关闭alsa
static void alsa_close(void *handle){
    if(handle){
        snd_pcm_drop(handle);
        snd_pcm_close(handle);
    }
}
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容