美文网首页
代码片段:ALSA回放

代码片段:ALSA回放

作者: 客昂康 | 来源:发表于2021-08-23 11:06 被阅读0次
    #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);
        }
    }
    

    相关文章

      网友评论

          本文标题:代码片段:ALSA回放

          本文链接:https://www.haomeiwen.com/subject/stnkiltx.html