Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2116712
  • 博文数量: 438
  • 博客积分: 3871
  • 博客等级: 中校
  • 技术积分: 6075
  • 用 户 组: 普通用户
  • 注册时间: 2011-09-10 00:11
个人简介

邮箱: wangcong02345@163.com

文章分类

全部博文(438)

文章存档

2017年(15)

2016年(119)

2015年(91)

2014年(62)

2013年(56)

2012年(79)

2011年(16)

分类: LINUX

2015-09-09 18:36:39

一.
1.用alsa播放wav文件的过程
  a. 打开snd_pcm_open
  b. 为param分配空间,并初始化参数
      b.1 这儿为了确认参数需要读取wav文件的头,并根据wav文件来确认参数
            需要确认的参数有三个: format(即SND_PCM_FORMAT_S16_LE类似) channels rate
  c. snd_pcm_hw_params将参数设到driver中去
  d. 循环读取wav文件中的数据,并把数据snd_pcm_writei写到驱动中进行播放
2.代码
  1. #include "utils.h"
  2. //#define ALSA_PCM_NEW_HW_PARAMS_API
  3. #include <alsa/asoundlib.h>
  4. #include <stdlib.h>
  5. //需要从wav文件中读取的三个参数
  6. typedef struct {
  7.     snd_pcm_format_t format;
  8.     unsigned int channels;
  9.     unsigned int rate;
  10. }HWParams;
  11. //下面这四个结构体是为了分析wav头的
  12. typedef struct {
  13.     u_int magic;   /* 'RIFF' */
  14.     u_int length;  /* filelen */
  15.     u_int type;    /* 'WAVE' */
  16. } WaveHeader;

  17. typedef struct {
  18.     u_short format;       /* see WAV_FMT_* */
  19.     u_short channels;
  20.     u_int sample_fq;     /* frequence of sample */
  21.     u_int byte_p_sec;
  22.     u_short byte_p_spl;  /* samplesize; 1 or 2 bytes */
  23.     u_short bit_p_spl;   /* 8, 12 or 16 bit */
  24. } WaveFmtBody;

  25. typedef struct {
  26.     WaveFmtBody format;
  27.     u_short ext_size;
  28.     u_short bit_p_spl;
  29.     u_int channel_mask;
  30.     u_short guid_format; /* WAV_FMT_* */
  31.     u_char guid_tag[14]; /* WAV_GUID_TAG */
  32. } WaveFmtExtensibleBody;

  33. typedef struct {
  34.     u_int type; /* 'data' */
  35.     u_int length; /* samplecount */
  36. } WaveChunkHeader;

  37. #define COMPOSE_ID(a,b,c,d) ((a) | ((b)<<8) | ((c)<<16) | ((d)<<24))
  38. #define WAV_RIFF COMPOSE_ID('R','I','F','F')
  39. #define WAV_WAVE COMPOSE_ID('W','A','V','E')
  40. #define WAV_FMT COMPOSE_ID('f','m','t',' ')
  41. #define WAV_DATA COMPOSE_ID('d','a','t','a')
  42. //分析wav的头,并解析出alsa的param需要的三个参数
  43. int check_wavfile(int fd, HWParams* hw_params)
  44. {
  45.     int ret;
  46.     int i, len;
  47.     WaveHeader* header;
  48.     WaveFmtBody* fmt;
  49.     WaveChunkHeader* chunk_header;
  50.     unsigned char* pbuf = (unsigned char*)malloc(128);
  51.     if(NULL == pbuf)
  52.     {
  53.         dbmsg("pbuf malloc error");
  54.         return -1;
  55.     }
  56.     //1. check Wave Header
  57.     len = sizeof(WaveHeader);
  58.     if( (ret=read(fd, pbuf, len)) != len)
  59.     {
  60.         dbmsg("read error");
  61.         return -1;
  62.     }
  63.     header = (WaveHeader*)pbuf;
  64.     if( (header->magic!=WAV_RIFF) || (header->type!=WAV_WAVE))
  65.     {
  66.         dbmsg("not a wav file");
  67.         return -1;
  68.     }
  69.     //2. check Wave Fmt
  70.     len = sizeof(WaveChunkHeader)+sizeof(WaveFmtBody);
  71.     if( (ret=read(fd, pbuf, len)) != len)
  72.     {
  73.         dbmsg("read error");
  74.         return -1;
  75.     }
  76.     chunk_header = (WaveChunkHeader*)pbuf;
  77.     if( chunk_header->type!=WAV_FMT)
  78.     {
  79.         dbmsg("fmt body error");
  80.         return -1;
  81.     }
  82.     fmt = (WaveFmtBody*)(pbuf+sizeof(WaveChunkHeader));
  83.     if(fmt->format != 0x0001) //WAV_FMT_PCM
  84.     {
  85.         dbmsg("format is not pcm");
  86.         return -1;
  87.     }
  88.     dbmsg("format=0x%x, channels=0x%x,sample_fq=%d,byte_p_sec=%d,byte_p_sample=%d,bit_p_sample=%d",
  89.             fmt->format, fmt->channels,fmt->sample_fq, fmt->byte_p_sec,
  90.             fmt->byte_p_spl, fmt->bit_p_spl);
  91.     //copy params
  92.     hw_params->channels = fmt->channels;
  93.     hw_params->rate = fmt->sample_fq;
  94.     switch(fmt->bit_p_spl)
  95.     {
  96.         case 8:
  97.             hw_params->format = SND_PCM_FORMAT_U8;
  98.             break;
  99.         case 16:
  100.             hw_params->format = SND_PCM_FORMAT_S16_LE;
  101.             break;
  102.         default:
  103.             dbmsg("FIXME: add more format");
  104.             break;
  105.     }
  106.     //3. check data chunk
  107.     len = sizeof(WaveChunkHeader);
  108.     if( (ret=read(fd, pbuf, len)) != len)
  109.     {
  110.         dbmsg("read error");
  111.         return -1;
  112.     }
  113.     chunk_header = (WaveChunkHeader*)pbuf;
  114.     if(chunk_header->type != WAV_DATA)
  115.     {
  116.         dbmsg("not data chunk");
  117.         return -1;
  118.     }
  119.     dbmsg("pcm_data_size=0x%x",chunk_header->length);

  120.     free(pbuf);
  121.     pbuf = NULL;
  122.     return -1;
  123. }

  124. int main ( int argc, char *argv[] )
  125. {
  126.     int i, fd;
  127.     int ret, dir, size;
  128.     unsigned int val, val2;
  129.     char* buffer;
  130.     snd_pcm_t* handle;
  131.     snd_pcm_hw_params_t* params;
  132.     snd_pcm_uframes_t periodsize;
  133.     snd_pcm_uframes_t frames;
  134.     HWParams hw_params;
  135.     if(argc<2)
  136.     {
  137.         dbmsg("usage ./play ");
  138.         return -1;
  139.     }
  140.     fd = open(argv[1], O_RDWR);
  141.     if(fd<0)
  142.     {
  143.         dbmsg("file open error");
  144.         return -1;
  145.     }
  146.     check_wavfile(fd, &hw_params);   //从wav头中分析出的参数,保存在hw_param中
  147.     //1. 打开alsa
  148.     if( (ret = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0)) < 0)
  149.     {
  150.         dbmsg("open pcm device error:%s", snd_strerror(ret));
  151.         return -1;
  152.     }
  153.     //2. 给参数分配空间,并用hw_param(从wav头中分析出的参数)初始化
  154.     snd_pcm_hw_params_alloca(&params);
  155.     snd_pcm_hw_params_any(handle, params);
  156.     snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
  157.     //snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE); //last param get from wav file
  158.     snd_pcm_hw_params_set_format(handle, params, hw_params.format);

  159.     //snd_pcm_hw_params_set_channels(handle, params, 2);
  160.     snd_pcm_hw_params_set_channels(handle, params, hw_params.channels); //last param get from wav file
  161.     dbmsg("hw_params: format=%d, channels=%d", hw_params.format, hw_params.channels);

  162.     val = 44100;
  163.     snd_pcm_hw_params_set_rate_near(handle,params, &val, &dir);

  164.     frames = 32*4;
  165.     snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);
  166.     //3. set param to driver
  167.     if((ret=snd_pcm_hw_params(handle, params)) < 0)
  168.     {
  169.         dbmsg("set hw params error:%s", snd_strerror(ret));
  170.         return -1;
  171.     }

  172.     snd_pcm_hw_params_get_period_size(params, &frames, &dir);
  173.     size = frames*4; //2byte/smaple, 2 channels
  174.     buffer = (char*)malloc(size);

  175.     snd_pcm_hw_params_get_period_time(params, &val, &dir);
  176.     while(1)
  177.     {
  178.         ret = read(fd, buffer, size);                //3.从wav文件中读取数据
  179.         if(ret==0)
  180.         {
  181.             dbmsg("end of file");
  182.             return 0;
  183.         }else if (ret!=size)
  184.         {
  185.             dbmsg("short read");
  186.         }

  187.         ret = snd_pcm_writei(handle, buffer, frames);   //4.将读取数据写到driver中进行播放
  188.         if(ret == -EPIPE)
  189.         {
  190.             //dbmsg("-EPIPE");
  191.             snd_pcm_prepare(handle);
  192.         }
  193.     }

  194.     snd_pcm_drain(handle);
  195.     snd_pcm_close(handle);
  196.     free(buffer);
  197.     return EXIT_SUCCESS;
  198. }
3. 运行结果
  1. cong@msi:/work/ffmpeg/test/alsa/testalsa/4player$ make run
  2. export LD_LIBRARY_PATH=/work/ffmpeg/out/lib/ \
  3.     && ./play /work/ffmpeg/test/resource//test.wav
  4. play.c:check_wavfile[94]: format=0x1, channels=0x2,sample_fq=44100,byte_p_sec=176400,byte_p_sample=4,bit_p_sample=16
  5. play.c:check_wavfile[123]: pcm_data_size=0x25c9b20
  6. play.c:main[168]: hw_params: format=2, channels=2
4.代码打包
4player.rar(下载后改名为4player.tar.gz)


阅读(3347) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~