对于Linux alsa设备写操作

set_pcm_play函数用于播放长度为datalen的buffer中的字符串,其中buffer中字符串为除去WAV文件头得到的二进制歌曲文件。

int demo_sound::set_pcm_play(char *buffer,int datalen)
{
        int    rc;
        int    ret=0;
        int    size;
        snd_pcm_t*       handle;        //PCI设备句柄
        snd_pcm_hw_params_t*      params;//硬件信息和PCM流配置
        unsigned int       val;
        int                dir=0;
        snd_pcm_uframes_t  frames;
        int channels=1;
        int frequency=16000;
        int bit=16;
        int datablock=2;
        unsigned char ch[100];  //用来存储wav文件的头信息

        rc=snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
        if(rc<0)
        {
                perror("\nopen PCM device failed:");
                exit(1);
        }


        snd_pcm_hw_params_alloca(&params); //分配params结构体
        if(rc<0)
        {
                perror("\nsnd_pcm_hw_params_alloca:");
                exit(1);
        }
         rc=snd_pcm_hw_params_any(handle, params);//初始化params
        if(rc<0)
        {
                perror("\nsnd_pcm_hw_params_any:");
                exit(1);
        }

        rc=snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);                                 //初始化访问权限
        if(rc<0)
        {
                perror("\nsed_pcm_hw_set_access:");
                exit(1);

        }

        /* Signed 16-bit little-endian format */
        snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);


        rc=snd_pcm_hw_params_set_channels(handle, params, 1);  //设置声道,1表示单声>道,2表示立体声
        if(rc<0)
        {
                perror("\nsnd_pcm_hw_params_set_channels:");
                exit(1);
        }
        val = frequency;
        rc=snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);  //设置>频率
        if(rc<0)
        {
                perror("\nsnd_pcm_hw_params_set_rate_near:");
                exit(1);
        }

        rc = snd_pcm_hw_params(handle, params);
        if(rc<0)
        {
        perror("\nsnd_pcm_hw_params: ");
        exit(1);
        }

        if ((rc = snd_pcm_set_params(handle,
                                              SND_PCM_FORMAT_S16_LE,
                                              SND_PCM_ACCESS_RW_INTERLEAVED,
                                              1,
                                              16000,
                                              1,
                                              500000)) < 0) {   /* 0.5sec */
                        printf("Playback open error: %s\n", snd_strerror(rc));
                        exit(EXIT_FAILURE);
                }

        rc=snd_pcm_hw_params_get_period_size(params, &frames, &dir);  /*获取周期长度*/
        if(rc<0)
        {
                perror("\nsnd_pcm_hw_params_get_period_size:");
                exit(1);
        }

        size = frames * datablock;   /*4 代表数据快长度*/
        int readlen=0;
        while (1)
        {        
        // 写音频数据到PCM设备     
        int try_count=0;        //错误重试计数
        while((ret = snd_pcm_writei(handle, buffer+readlen, frames))<0)
       {            
//          usleep(2000);
            if (ret == -EPIPE)          /*设备被抢占,重新配置设备*/
            {
                SYS_LOG(INFO,"underrun occurred\n");
                int err = snd_pcm_prepare(handle);              //完成硬件参数设置,使设备准备好
                if (err < 0){
                    printf("Can't recovery from underrun, prepare failed: %s\n", snd_strerror(err));
                    goto ERROR_MASK;
                }     
                err = snd_pcm_recover(handle, ret, 0);
                if (err < 0){
                    printf("snd_pcm_recover prepare failed: %s\n", snd_strerror(err));
                    goto ERROR_MASK;
                } 
                printf("err  %d",err);
            }
            else if (ret < 0)
            {
                SYS_LOG(INFO,"error from writei: %s\n",snd_strerror(ret));
            }
            printf("try_count   %d      ",try_count);   
            /*写设备出错,重试10次,避免死循环*/
            {
                try_count++;
                if(try_count>10)
                {
                    SYS_LOG(INFO,"the count of retry  out of time !\n");
                    try_count=0;
                    goto ERROR_MASK;
                    break;
                }
            }
        }
        readlen+=size;
        if(readlen+size>datalen)
            break;
        }
        snd_pcm_drain(handle);
        snd_pcm_close(handle);
        return 0;
ERROR_MASK:
        snd_pcm_drain(handle);
        snd_pcm_close(handle);
        return -1;
}

错误:出现underrun的原因是:初始化配置有问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值