/*modify by hfl 2014-2-16*/ /* Use the newer ALSA API */ #define ALSA_PCM_NEW_HW_PARAMS_API #include <alsa/asoundlib.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> int main(int argc, char *argv[]) { long loops; int rc; int size; snd_pcm_t *handle; snd_pcm_hw_params_t *params; unsigned int val; int dir; snd_pcm_uframes_t frames; printf("222133n"); char buffer[20*2];/*size=frame*channles*byte persaple*/ int fd,i; if (argc != 2) { fprintf (stderr, "usage: %s <filename>!n", argv[0]); exit ( -1 ) ; } if ( ( fd = open (argv[1],O_RDONLY))<0) { fprintf ( stderr, " Can't open sound file!n"); exit (-1 ); } /* Open PCM device for playback. */ rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0); if (rc < 0) { fprintf(stderr, "unable to open pcm device: %sn", snd_strerror(rc)); exit(1); } /* Allocate a hardware parameters object. */ snd_pcm_hw_params_alloca(¶ms); /* Fill it in with default values. */ snd_pcm_hw_params_any(handle, params); /* Set the desired hardware parameters. */ /* Interleaved mode */ snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); /* Signed 16-bit little-endian format */ snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE); /* Two channels (stereo) */ snd_pcm_hw_params_set_channels(handle, params, 1); /* 44100 bits/second sampling rate (CD quality) */ val = 16000; snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir); /* Set period size to 32 frames. */ frames =20;/*一次送人的帧太少,会下溢冲(至少15帧)*/ // snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir); /* Write the parameters to the driver */ rc = snd_pcm_hw_params(handle, params); if (rc < 0) { fprintf(stderr, "unable to set hw parameters: %sn", snd_strerror(rc)); exit(1); } /* Use a buffer large enough to hold one period */ // snd_pcm_hw_params_get_period_size(params, &frames,&dir); //size = frames * 4; /* 2 bytes/sample, 2 channels */ // buffer = (char *) malloc(size); long s=0; i =0; while(i = read(fd,buffer, sizeof(buffer))>0) { //s =i; //printf("s=%ldn",s); #if 0 rc = read(0, buffer, size); if (rc == 0) { fprintf(stderr, "end of file on inputn"); break; } else if (rc != size) { fprintf(stderr, "short read: read %d bytesn", rc); } #endif rc = snd_pcm_writei(handle, buffer, frames); if (rc==frames*2) { printf("read data oKn"); } if (rc == -EPIPE) { /* EPIPE means underrun */ fprintf(stderr, "underrun occurredn"); snd_pcm_prepare(handle); } else if (rc < 0) { fprintf(stderr, "error from writei: %sn", snd_strerror(rc)); } else if (rc != (int)frames) { fprintf(stderr, "short write, write %d framesn", rc); } } snd_pcm_drain(handle); snd_pcm_close(handle); printf("play end n"); // free(buffer); close(fd); return 0;
}
因为alsa 架构开放给用户的接口不是直接操作驱动,而是操作一个库的接口,相当于在驱动的上层做了一层封装的SDK。因此编译是要链接到一个动态库,并包含相应的头文件。注意alsa架构送数据是以frame为单位送的。size=frames*channel*每个采样的字节数。frame不能太小,否则会产生下溢,造成卡顿。在读文件的环境当中,frame至少15以上。
编译命令:
gcc -o pcmplayalsa pcmplayalsa.c -I/usr/include/alsa -lasound