• 全志 A40i alsalib 关于 -EPIPE 错误


    问题和现象:

    由于网络语音通话存在网络延时问题,导致声卡发出 杂音.

    分析思路:

    查看dmesg 发现 底层驱动出现不停的开关声卡.

    [ 3011.197736] Enter sunxi_daudio_txctrl_enable, enable 1
    [ 3011.197763] End sunxi_daudio_txctrl_enable, enable 1
    [ 3011.793949] Enter sunxi_daudio_txctrl_enable, enable 0
    [ 3011.793980] End sunxi_daudio_txctrl_enable, enable 0

    跟踪发现是出现了XRUN 现象,XRUN详解可参考:

    https://blog.csdn.net/u010872301/article/details/84397167

    解决方法:

    增加period_time 和 buffer_time 的初始大小.

    网上扒的测试代码.

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <getopt.h>
    #include <alsa/asoundlib.h>
    #include <unistd.h>
    
    typedef struct {
        char *file_name;
        char *device;
        int ch;
        int bit;
        int rate;
        snd_pcm_format_t format;
        unsigned int buffer_time;
        unsigned int period_time;
        snd_pcm_uframes_t buffer;
        snd_pcm_uframes_t period;
    }CONFIG_T;
    
    typedef struct {
        char id[4];
        int size;
    }RIFF_HEADER_T;
    
    typedef struct {
        char format[4];
        char sub_id_1[4];
        int sub_size_1;
        short fmt;
        short ch;
        int sample_rate;
        int byte_rate;
        short block_align;
        short bits_per_sample;
    }WAVE_HEADER_T;
    
    typedef struct {
        char sub_id_2[4];
        int sub_size_2;
    }DATA_HEADER_T;
    
    RIFF_HEADER_T riff_header;
    WAVE_HEADER_T wave_header;
    DATA_HEADER_T data_header;
    CONFIG_T config;
    
    static void help(void)
    {
        printf(
    "Usage: pcm [OPTION]... [FILE]...
    "
    "-h,--help  help
    "
    "-D,--device    playback device
    "
    "-i,--input_file only support wav file
    "
    "
    ");
    }
    
    static void parse_cmd(int argc, char **argv)
    {
        struct option long_option[] =
        {
            {"help", 0, NULL, 'h'},
            {"device", 1, NULL, 'D'},
            {"input_file", 1, NULL, 'i'},
            {NULL, 0, NULL, 0},
        };
        while (1) {
            int c;
            if ((c = getopt_long(argc, argv, "hD:i:", long_option, NULL)) < 0)
                break;
            switch (c) {
            case 'h':
                help();
                break;
            case 'D':
                config.device = strdup(optarg);
                break;
            case 'i':
                config.file_name = strdup(optarg);
                break;
            }
        }  
    }
    
    static snd_pcm_format_t get_format(int bits_per_sample)
    {
        snd_pcm_format_t format = SND_PCM_FORMAT_S8;
        switch(bits_per_sample) {
            case 8:
               format =  SND_PCM_FORMAT_S8;
               break;
            case 16:
               format =  SND_PCM_FORMAT_S16_LE;
               break;
           case 24:
               format =  SND_PCM_FORMAT_S24_LE;
               break;
           case 32:
               format =  SND_PCM_FORMAT_S32_LE;
               break;
        }
        return format;
    }
    
    static int config_init(CONFIG_T *pConfig)
    {
        FILE *fp = NULL;
        if (NULL == pConfig) {
            return -1;
        }
        fp = fopen(pConfig->file_name, "rb");
        if (NULL == fp) {
            return -1;
        }
        
        fread((void *)&riff_header, sizeof(RIFF_HEADER_T), 1, fp);
        fread((void *)&wave_header, sizeof(WAVE_HEADER_T), 1, fp);
         if (wave_header.sub_size_1 > sizeof (WAVE_HEADER_T) -12)
            fseek(fp, wave_header.sub_size_1 - (sizeof (WAVE_HEADER_T) - 12), SEEK_CUR);
        fread((void *)&data_header, sizeof(DATA_HEADER_T), 1, fp);
        pConfig->ch = wave_header.ch;
        pConfig->rate= wave_header.sample_rate;
        pConfig->bit= wave_header.bits_per_sample;
        pConfig->format = get_format(wave_header.bits_per_sample);
        fclose(fp);
        return 0;
    }
    
    static int set_hwparams(snd_pcm_t *handle)
    {
        snd_pcm_hw_params_t *params;
        unsigned int rrate;
        snd_pcm_uframes_t size;
        int err, dir;
        snd_pcm_hw_params_alloca(&params);
        /* choose all parameters */
        err = snd_pcm_hw_params_any(handle, params);
        if (err < 0) {
            printf("Broken configuration for playback: no configurations available: %s
    ", snd_strerror(err));
            return err;
        }
          /* set the interleaved read/write format */
        err = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
        if (err < 0) {
            printf("Access type not available for playback: %s
    ", snd_strerror(err));
            return err;
        }
        /* set the sample format */
        err = snd_pcm_hw_params_set_format(handle, params, config.format);
        if (err < 0) {
            printf("Sample format not available for playback: %s
    ", snd_strerror(err));
            return err;
        }
        /* set the count of channels */
        err = snd_pcm_hw_params_set_channels(handle, params, config.ch);
        if (err < 0) {
            printf("Channels count (%u) not available for playbacks: %s
    ", config.ch, snd_strerror(err));
            return err;
        }
        /* set the stream rate */
        rrate = config.rate;
        err = snd_pcm_hw_params_set_rate_near(handle, params, &rrate, 0);
        if (err < 0) {
            printf("Rate %uHz not available for playback: %s
    ", config.rate, snd_strerror(err));
            return err;
        }
        if (rrate != config.rate) {
            printf("Rate doesn't match (requested %uHz, get %iHz)
    ", config.rate, err);
            return -EINVAL;
        }
        /* set the buffer time */
        err = snd_pcm_hw_params_set_buffer_time_near(handle, params, &config.buffer_time, &dir);
        if (err < 0) {
            printf("Unable to set buffer time %u for playback: %s
    ", config.buffer_time, snd_strerror(err));
            return err;
        }
        err = snd_pcm_hw_params_get_buffer_size(params, &size);
        if (err < 0) {
            printf("Unable to get buffer size for playback: %s
    ", snd_strerror(err));
            return err;
        }
        config.buffer = size;
        /* set the period time */
        err = snd_pcm_hw_params_set_period_time_near(handle, params, &config.period_time, &dir);
        if (err < 0) {
            printf("Unable to set period time %u for playback: %s
    ", config.period_time, snd_strerror(err));
            return err;
        }
        err = snd_pcm_hw_params_get_period_size(params, &size, &dir);
        if (err < 0) {
            printf("Unable to get period size for playback: %s
    ", snd_strerror(err));
            return err;
        }
        config.period = size;
        /* write the parameters to device */
        err = snd_pcm_hw_params(handle, params);
        if (err < 0) {
            printf("Unable to set hw params for playback: %s
    ", snd_strerror(err));
            return err;
        }
        return 0;
    }
    static int set_swparams(snd_pcm_t *handle)
    {
        int err;    snd_pcm_sw_params_t *swparams;
        snd_pcm_sw_params_alloca(&swparams);
        /* get the current swparams */
        err = snd_pcm_sw_params_current(handle, swparams);
        if (err < 0) {
            printf("Unable to determine current swparams for playback: %s
    ", snd_strerror(err));
            return err;
        }
        /* start the transfer when the buffer is almost full: */
        /* (buffer_size / avail_min) * avail_min */
        err = snd_pcm_sw_params_set_start_threshold(handle, swparams, (config.buffer / config.period) * config.period);
        if (err < 0) {
            printf("Unable to set start threshold mode for playback: %s
    ", snd_strerror(err));
            return err;
        }
    	printf(stderr, "---%d--
    ", (config.buffer / config.period) * config.period);
    	err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, (config.buffer / config.period) * config.period);
        /* write the parameters to the playback device */
        err = snd_pcm_sw_params(handle, swparams);
        if (err < 0) {
            printf("Unable to set sw params for playback: %s
    ", snd_strerror(err));
            return err;
        }
        return 0;
    }
    
    /*
     *   Underrun and suspend recovery
     */
     
    static int xrun_recovery(snd_pcm_t *handle, int err)
    {
        printf("stream recovery
    ");
        if (err == -EPIPE) {    /* under-run */
        printf("stream recovery----%d
    ", __LINE__);
            //err = snd_pcm_prepare(handle);
            if (err < 0)
                printf("Can't recovery from underrun, prepare failed: %s
    ", snd_strerror(err));
            return 0;
        } else if (err == -ESTRPIPE) {
            while ((err = snd_pcm_resume(handle)) == -EAGAIN)
                sleep(1);   /* wait until the suspend flag is released */
            if (err < 0) {
    		printf("stream recovery----%d
    ", __LINE__);
                err = snd_pcm_prepare(handle);
                if (err < 0)
                    printf("Can't recovery from suspend, prepare failed: %s
    ", snd_strerror(err));
            }
            return 0;
        }
        return err;
    }
    
    static int write_loop(snd_pcm_t *handle)
    {
        int err;
        size_t remain, read_size;
        FILE *fp = NULL;
        char *read_buffer = NULL, *offset = NULL;
        int bytes_per_frame = config.ch * (config.bit >> 3);
        read_size = config.period * bytes_per_frame;
        fp = fopen(config.file_name, "rb");
        if (NULL == fp) {
            return -1;
        }
        read_buffer = (char * )malloc(read_size);
        fseek(fp, 44, SEEK_CUR);
    
        while (1) {
            memset(read_buffer ,0, read_size);
            err = fread(read_buffer ,1, read_size, fp);
            if (err <= 0)
                break;
            offset = read_buffer;
            remain = err / bytes_per_frame;
            while (remain> 0) {
    			usleep(300000);
                err = snd_pcm_writei(handle, offset, remain);
                if (err == -EAGAIN)
                    continue;
    #if 1
                if (err < 0) {
                    if (xrun_recovery(handle, err) < 0) {
                        printf("Write error: %s
    ", snd_strerror(err));
                        exit(EXIT_FAILURE);
                    }
                    continue; 
                }
    #endif
                offset += err * bytes_per_frame;
                remain -= err;
            }
        }
        free(read_buffer);
        fclose(fp);
        return 0;
    }
    
    int main(int argc, char **argv)
    {
        int err = 0;
        snd_pcm_t *handle;
        memset (&config, 0, sizeof(CONFIG_T));
        config.buffer_time = 900000;//us
        config.period_time = 500000;
        parse_cmd(argc, argv);
        config_init(&config);
        if ((err = snd_pcm_open(&handle, config.device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
            printf("Playback open error: %s
    ", snd_strerror(err));
            return 0;
        }
        
        if ((err = set_hwparams(handle)) < 0) {
            printf("Setting of hwparams failed: %s
    ", snd_strerror(err));
            exit(EXIT_FAILURE);
        }
        if ((err = set_swparams(handle)) < 0) {
            printf("Setting of swparams failed: %s
    ", snd_strerror(err));
            exit(EXIT_FAILURE);
        }
        write_loop(handle);
        snd_pcm_close(handle);    return 0;
    }
    
  • 相关阅读:
    kindeditor扩展粘贴截图功能&修改图片上传路径并通过webapi上传图片到图片服务器
    解决VS2015 VBCSCompiler.exe 占用CPU100%的问题
    电商网站商品模型之商品详情页设计方案
    大三那年在某宝8块钱买的.NET视频决定了我的职业生涯
    单点登录改进版-使用ajax分发cookie避免重定向轮询
    可跨域的单点登录(SSO)实现方案【附.net代码】
    使用ANTS Performance Profiler&ANTS Memory Profiler工具分析IIS进程内存和CPU占用过高问题
    js封装的三级联动菜单(使用时只需要一行js代码)
    EF查询之性能优化技巧
    EF使用CodeFirst方式生成数据库&技巧经验
  • 原文地址:https://www.cnblogs.com/okshall/p/14084995.html
Copyright © 2020-2023  润新知