/**alsa play test*ALSA使用者空間編譯,ALSA驅動的音效卡在使用者空間,不宜直接使用*檔案介面中,而應使用alsa-lib*開啟---->設定參數--->讀寫音頻資料 ALSA全部使用alsa-lib中的API*交叉編譯*export LD_LIBRARY_PATH=$PWD:$LD_LIBRARY_PATH*arm-linux-gcc -o alsa_play alsa_play_test.c -L. -lasound*需要交叉編譯後的libasound.so庫的支援**/#include <stdio.h>#include <stdlib.h>#include "alsa/asoundlib.h"int main(int argc, char *argv[]){int i;int ret;int buf[128];unsigned int val; int dir=0;char *buffer;int size;snd_pcm_uframes_t frames; snd_pcm_uframes_t periodsize;snd_pcm_t *playback_handle;//PCM裝置控制代碼pcm.hsnd_pcm_hw_params_t *hw_params;//硬體資訊和PCM流配置if (argc != 2) {printf("error: alsa_play_test [music name]\n");exit(1);}printf("play song %s by wolf\n", argv[1]);FILE *fp = fopen(argv[1], "rb"); if(fp == NULL) return 0; fseek(fp, 100, SEEK_SET);//1. 開啟PCM,最後一個參數為0意味著標準配置ret = snd_pcm_open(&playback_handle, "default", SND_PCM_STREAM_PLAYBACK, 0);if (ret < 0) {perror("snd_pcm_open");exit(1);}//2. 分配snd_pcm_hw_params_t結構體ret = snd_pcm_hw_params_malloc(&hw_params);if (ret < 0) {perror("snd_pcm_hw_params_malloc");exit(1);}//3. 初始化hw_paramsret = snd_pcm_hw_params_any(playback_handle, hw_params);if (ret < 0) {perror("snd_pcm_hw_params_any");exit(1);}//4. 初始化存取權限ret = snd_pcm_hw_params_set_access(playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);if (ret < 0) {perror("snd_pcm_hw_params_set_access");exit(1);}//5. 初始化採樣格式SND_PCM_FORMAT_U8,8位ret = snd_pcm_hw_params_set_format(playback_handle, hw_params, SND_PCM_FORMAT_U8);if (ret < 0) {perror("snd_pcm_hw_params_set_format");exit(1);}//6. 設定採樣率,如果硬體不支援我們設定的採樣率,將使用最接近的//val = 44100,有些錄音採樣頻率固定為8KHzval = 8000;ret = snd_pcm_hw_params_set_rate_near(playback_handle, hw_params, &val, &dir);if (ret < 0) {perror("snd_pcm_hw_params_set_rate_near");exit(1);}//7. 設定通道數量ret = snd_pcm_hw_params_set_channels(playback_handle, hw_params, 2);if (ret < 0) {perror("snd_pcm_hw_params_set_channels");exit(1);}/* Set period size to 32 frames. */ frames = 32; periodsize = frames * 2; ret = snd_pcm_hw_params_set_buffer_size_near(playback_handle, hw_params, &periodsize); if (ret < 0) { printf("Unable to set buffer size %li : %s\n", frames * 2, snd_strerror(ret)); } periodsize /= 2; ret = snd_pcm_hw_params_set_period_size_near(playback_handle, hw_params, &periodsize, 0); if (ret < 0) { printf("Unable to set period size %li : %s\n", periodsize, snd_strerror(ret)); } //8. 設定hw_paramsret = snd_pcm_hw_params(playback_handle, hw_params);if (ret < 0) {perror("snd_pcm_hw_params");exit(1);} /* Use a buffer large enough to hold one period */ snd_pcm_hw_params_get_period_size(hw_params, &frames, &dir); size = frames * 2; /* 2 bytes/sample, 2 channels */ buffer = (char *) malloc(size); fprintf(stderr, "size = %d\n", size); while (1) { ret = fread(buffer, 1, size, fp); if(ret == 0) { fprintf(stderr, "end of file on input\n"); break; } else if (ret != size) { }//9. 寫音頻資料到PCM裝置 while(ret = snd_pcm_writei(playback_handle, buffer, frames)<0) { usleep(2000); if (ret == -EPIPE) { /* EPIPE means underrun */ fprintf(stderr, "underrun occurred\n"); //完成硬體參數設定,使裝置準備好 snd_pcm_prepare(playback_handle); } else if (ret < 0) { fprintf(stderr, "error from writei: %s\n", snd_strerror(ret)); } } }//10. 關閉PCM裝置控制代碼snd_pcm_close(playback_handle);return 0;}