使用 ALSAlib 播放 wav

在 ARM 2440 开发板上正常播放 16bit  44100 采样率的wav , 为了程序简单,没有判断返回值。

补充,在 ubunto 上也能正常播放。

编译方法: arm-linux-gcc -lasound wplay.c -o wplay  或在 ubuntu 上编译 gcc -lasound wplay.c -o wplay 

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 #include <sys/types.h>
  5 #include <sys/stat.h>
  6 #include <fcntl.h>
  7 #include <sys/mman.h>
  8 #include <alsa/asoundlib.h>
  9 #ifndef WORD
 10 #define WORD unsigned short
 11 #endif
 12 
 13 #ifndef DWORD
 14 #define DWORD unsigned int
 15 #endif
 16     
 17 struct RIFF_HEADER
 18 {
 19     char szRiffID[4];  // 'R','I','F','F'
 20     DWORD dwRiffSize;
 21     char szRiffFormat[4]; // 'W','A','V','E'
 22 };
 23 
 24 struct WAVE_FORMAT
 25 {
 26     WORD wFormatTag;
 27     WORD wChannels;
 28     DWORD dwSamplesPerSec;
 29     DWORD dwAvgBytesPerSec;
 30     WORD wBlockAlign;
 31     WORD wBitsPerSample;
 32 };
 33 
 34 struct FMT_BLOCK
 35 {
 36     char  szFmtID[4]; // 'f','m','t',' '
 37     DWORD  dwFmtSize;
 38     struct WAVE_FORMAT wavFormat;
 39 };
 40 
 41 struct DATA_BLOCK
 42 {
 43     char szDataID[4]; // 'd','a','t','a'
 44     DWORD dwDataSize;
 45 };
 46 
 47 void read_wav(unsigned char *wav_buf, int *fs, int *channels, int *bits_per_sample, int *wav_size, int *file_size)
 48 {
 49     struct RIFF_HEADER *headblk;
 50     struct FMT_BLOCK   *fmtblk;
 51     struct DATA_BLOCK  *datblk;
 52 
 53     headblk = (struct RIFF_HEADER *) wav_buf;
 54     fmtblk  = (struct FMT_BLOCK *) &headblk[1];
 55     datblk  = (struct DATA_BLOCK *) &fmtblk[1];
 56     
 57     *file_size = headblk->dwRiffSize;
 58 
 59     //采样频率
 60     *fs         = fmtblk->wavFormat.dwSamplesPerSec;
 61 
 62     //通道数
 63     *channels  = fmtblk->wavFormat.wChannels;
 64     
 65     *wav_size  = datblk->dwDataSize;
 66     //采样bit数 16 24
 67     *bits_per_sample = fmtblk->wavFormat.wBitsPerSample;
 68 }
 69 
 70 int main(int argc, char ** argv)
 71 {
 72     int fs, channels, bits_per_sample, wav_size, file_size;
 73     unsigned char *wav_buf;
 74     unsigned char *audio_buf;
 75     unsigned char *audio_p;
 76     int fd;
 77     struct stat stat;
 78     
 79     int size;
 80     snd_pcm_t *playback_handle;
 81     snd_pcm_hw_params_t *hw_params;//硬件信息和PCM流配置
 82     
 83     snd_pcm_uframes_t chunk_size = 0;
 84     unsigned int rate;
 85     snd_pcm_format_t format;
 86 
 87     if(2 != argc)
 88     {
 89         printf("usage:%s wav file\n", argv[0]);
 90         return -1;
 91     }
 92 
 93     fd = open(argv[1], O_RDONLY);
 94     fstat(fd, &stat);
 95     wav_buf = mmap(NULL, stat.st_size, PROT_READ, MAP_SHARED, fd, 0);
 96     read_wav(wav_buf, &fs, &channels, &bits_per_sample, &wav_size, &file_size);
 97     printf("wav format: fs = %d, channels = %d, bits_per_sample = %d, wav_size = %d file_size = %d\n\r", fs, channels, bits_per_sample, wav_size, file_size);
 98     
 99     //真实wav 跳过头部
100     audio_buf = wav_buf + sizeof(struct RIFF_HEADER) + sizeof(struct FMT_BLOCK) + sizeof(struct DATA_BLOCK);
101     
102     rate = fs;
103     //初始化声卡
104     //1. 打开PCM,最后一个参数为0意味着标准配置
105     if (0 > snd_pcm_open(&playback_handle, "default", SND_PCM_STREAM_PLAYBACK, 0)) 
106     {
107         printf("snd_pcm_open err\n");
108         return -1;
109     }
110     //2. 分配snd_pcm_hw_params_t结构体
111     if(0 > snd_pcm_hw_params_malloc (&hw_params))
112     {
113         printf("snd_pcm_hw_params_malloc err\n");
114         return -1;
115     }
116     //3. 初始化hw_params
117     if(0 > snd_pcm_hw_params_any (playback_handle, hw_params))
118     {
119         printf("snd_pcm_hw_params_any err\n");
120         return -1;
121     }
122     //4. 初始化访问权限
123     if (0 > snd_pcm_hw_params_set_access (playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) 
124     {
125         printf("snd_pcm_hw_params_any err\n");
126         return -1;
127     }
128     //5. 初始化采样格式SND_PCM_FORMAT_U8,8位
129     if(8 == bits_per_sample)
130     {
131         if (0 > snd_pcm_hw_params_set_format (playback_handle, hw_params, SND_PCM_FORMAT_U8)) 
132         {
133             printf("snd_pcm_hw_params_set_format err\n");
134             return -1;
135         }
136         format = SND_PCM_FORMAT_U8;
137     }
138     
139     if(16 == bits_per_sample)
140     {
141         if (0 > snd_pcm_hw_params_set_format (playback_handle, hw_params, SND_PCM_FORMAT_S16_LE)) 
142         {
143             printf("snd_pcm_hw_params_set_format err\n");
144             return -1;
145         }
146         format = SND_PCM_FORMAT_S16_LE;
147     }
148     //6. 设置采样率
149     if (0 > snd_pcm_hw_params_set_rate_near (playback_handle, hw_params, &rate, 0)) 
150     {
151         printf("snd_pcm_hw_params_set_rate_near err\n");
152         return -1;
153     }
154     //7. 设置通道数量
155     if (0 > snd_pcm_hw_params_set_channels(playback_handle, hw_params, 2)) 
156     {
157         printf("snd_pcm_hw_params_set_channels err\n");
158         return -1;
159     }
160     
161     //8. 设置hw_params    
162     if (0 > snd_pcm_hw_params (playback_handle, hw_params)) 
163     {
164         printf("snd_pcm_hw_params err\n");
165         return -1;
166     }
167 
168     snd_pcm_hw_params_get_period_size(hw_params, &chunk_size, 0);
169     
170     snd_pcm_hw_params_free (hw_params);
171     if (0 > snd_pcm_prepare (playback_handle)) 
172     {
173         printf("snd_pcm_prepare err\n");
174         return -1;
175     }
176     //chunk_size = ?;
177     printf("chunk_size:%ld \n", chunk_size);
178     audio_p = audio_buf;
179     while((audio_p - audio_buf) <= stat.st_size)
180     {
181         snd_pcm_writei(playback_handle, audio_p, chunk_size);
182         audio_p += chunk_size * 4; //16位 双声道
183     }
184     printf("play ok \n");
185     snd_pcm_close(playback_handle);
186     return 0;
187 }

 

转载于:https://www.cnblogs.com/ningci/p/6857043.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值