#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);
}
}
网友评论