在 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 ", 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 ", 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 "); 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 "); 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 "); 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 "); 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 "); 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 "); 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 "); 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 "); 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 "); 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 "); 174 return -1; 175 } 176 //chunk_size = ?; 177 printf("chunk_size:%ld ", 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 "); 185 snd_pcm_close(playback_handle); 186 return 0; 187 }