Chinaunix首页 | 论坛 | 博客
  • 博客访问: 341797
  • 博文数量: 89
  • 博客积分: 5152
  • 博客等级: 大校
  • 技术积分: 1155
  • 用 户 组: 普通用户
  • 注册时间: 2006-02-25 15:12
文章分类

全部博文(89)

文章存档

2012年(1)

2011年(5)

2010年(14)

2009年(69)

我的朋友

分类: 嵌入式

2010-07-07 10:22:40

/* Copyright (C) 2008 The Android Open Source Project
*/


#include
#include
#include
#include
#include
#include

#include

#define AUDIO_IOCTL_MAGIC 'a'

#define AUDIO_START _IOW(AUDIO_IOCTL_MAGIC, 0, unsigned)
#define AUDIO_STOP _IOW(AUDIO_IOCTL_MAGIC, 1, unsigned)
#define AUDIO_FLUSH _IOW(AUDIO_IOCTL_MAGIC, 2, unsigned)
#define AUDIO_GET_CONFIG _IOR(AUDIO_IOCTL_MAGIC, 3, unsigned)
#define AUDIO_SET_CONFIG _IOW(AUDIO_IOCTL_MAGIC, 4, unsigned)
#define AUDIO_GET_STATS _IOR(AUDIO_IOCTL_MAGIC, 5, unsigned)

struct msm_audio_config {
uint32_t buffer_size;
uint32_t buffer_count;
uint32_t channel_count;
uint32_t sample_rate;
uint32_t codec_type;
uint32_t unused[3];
};

struct msm_audio_stats {
uint32_t out_bytes;
uint32_t unused[3];
};

int pcm_play(unsigned rate, unsigned channels,
int (*fill)(void *buf, unsigned sz, void *cookie),
void *cookie)
{
struct msm_audio_config config;
struct msm_audio_stats stats;
unsigned sz, n;
char buf[8192];
int afd;

afd = open("/dev/msm_pcm_out", O_RDWR);
if (afd < 0) {
perror("pcm_play: cannot open audio device");
return -1;
}

if(ioctl(afd, AUDIO_GET_CONFIG, &config)) {
perror("could not get config");
return -1;
}

config.channel_count = channels;
config.sample_rate = rate;
if (ioctl(afd, AUDIO_SET_CONFIG, &config)) {
perror("could not set config");
return -1;
}
sz = config.buffer_size;
if (sz > sizeof(buf)) {
fprintf(stderr,"too big\n");
return -1;
}

fprintf(stderr,"prefill\n");
for (n = 0; n < config.buffer_count; n++) {
if (fill(buf, sz, cookie))
break;
if (write(afd, buf, sz) != sz)
break;
}

fprintf(stderr,"start\n");
ioctl(afd, AUDIO_START, 0);

for (;;) {
#if 0
if (ioctl(afd, AUDIO_GET_STATS, &stats) == 0)
fprintf(stderr,"%10d\n", stats.out_bytes);
#endif
if (fill(buf, sz, cookie))
break;
if (write(afd, buf, sz) != sz)
break;
}

done:
close(afd);
return 0;
}

/* */

#define ID_RIFF 0x46464952
#define ID_WAVE 0x45564157
#define ID_FMT 0x20746d66
#define ID_DATA 0x61746164

#define FORMAT_PCM 1

struct wav_header {
uint32_t riff_id;
uint32_t riff_sz;
uint32_t riff_fmt;
uint32_t fmt_id;
uint32_t fmt_sz;
uint16_t audio_format;
uint16_t num_channels;
uint32_t sample_rate;
uint32_t byte_rate; /* sample_rate * num_channels * bps / 8 */
uint16_t block_align; /* num_channels * bps / 8 */
uint16_t bits_per_sample;
uint32_t data_id;
uint32_t data_sz;
};


static char *next;
static unsigned avail;

int fill_buffer(void *buf, unsigned sz, void *cookie)
{
if (sz > avail)
return -1;
memcpy(buf, next, sz);
next += sz;
avail -= sz;
return 0;
}

void play_file(unsigned rate, unsigned channels,
int fd, unsigned count)
{
next = malloc(count);
if (!next) {
fprintf(stderr,"could not allocate %d bytes\n", count);
return;
}
if (read(fd, next, count) != count) {
fprintf(stderr,"could not read %d bytes\n", count);
return;
}
avail = count;
pcm_play(rate, channels, fill_buffer, 0);
}

int wav_play(const char *fn)
{
struct wav_header hdr;
unsigned rate, channels;
int fd;
fd = open(fn, O_RDONLY);
if (fd < 0) {
fprintf(stderr, "playwav: cannot open '%s'\n", fn);
return -1;
}
if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
fprintf(stderr, "playwav: cannot read header\n");
return -1;
}
fprintf(stderr,"playwav: %d ch, %d hz, %d bit, %s\n",
hdr.num_channels, hdr.sample_rate, hdr.bits_per_sample,
hdr.audio_format == FORMAT_PCM ? "PCM" : "unknown");

if ((hdr.riff_id != ID_RIFF) ||
(hdr.riff_fmt != ID_WAVE) ||
(hdr.fmt_id != ID_FMT)) {
fprintf(stderr, "playwav: '%s' is not a riff/wave file\n", fn);
return -1;
}
if ((hdr.audio_format != FORMAT_PCM) ||
(hdr.fmt_sz != 16)) {
fprintf(stderr, "playwav: '%s' is not pcm format\n", fn);
return -1;
}
if (hdr.bits_per_sample != 16) {
fprintf(stderr, "playwav: '%s' is not 16bit per sample\n", fn);
return -1;
}

play_file(hdr.sample_rate, hdr.num_channels,
fd, hdr.data_sz);

return 0;
}

int wav_rec(const char *fn, unsigned channels, unsigned rate)
{
struct wav_header hdr;
unsigned char buf[8192];
struct msm_audio_config cfg;
unsigned sz, n;
int fd, afd;
unsigned total = 0;
unsigned char tmp;

hdr.riff_id = ID_RIFF;
hdr.riff_sz = 0;
hdr.riff_fmt = ID_WAVE;
hdr.fmt_id = ID_FMT;
hdr.fmt_sz = 16;
hdr.audio_format = FORMAT_PCM;
hdr.num_channels = channels;
hdr.sample_rate = rate;
hdr.byte_rate = hdr.sample_rate * hdr.num_channels * 2;
hdr.block_align = hdr.num_channels * 2;
hdr.bits_per_sample = 16;
hdr.data_id = ID_DATA;
hdr.data_sz = 0;

fd = open(fn, O_CREAT | O_RDWR, 0666);
if (fd < 0) {
perror("cannot open output file");
return -1;
}
write(fd, &hdr, sizeof(hdr));

afd = open("/dev/msm_pcm_in", O_RDWR);
if (afd < 0) {
perror("cannot open msm_pcm_in");
close(fd);
return -1;
}

/* config change should be a read-modify-write operation */
if (ioctl(afd, AUDIO_GET_CONFIG, &cfg)) {
perror("cannot read audio config");
goto fail;
}

cfg.channel_count = hdr.num_channels;
cfg.sample_rate = hdr.sample_rate;
if (ioctl(afd, AUDIO_SET_CONFIG, &cfg)) {
perror("cannot write audio config");
goto fail;
}

if (ioctl(afd, AUDIO_GET_CONFIG, &cfg)) {
perror("cannot read audio config");
goto fail;
}

sz = cfg.buffer_size;
fprintf(stderr,"buffer size %d x %d\n", sz, cfg.buffer_count);
if (sz > sizeof(buf)) {
fprintf(stderr,"buffer size %d too large\n", sz);
goto fail;
}

if (ioctl(afd, AUDIO_START, 0)) {
perror("cannot start audio");
goto fail;
}

fcntl(0, F_SETFL, O_NONBLOCK);
fprintf(stderr,"\n*** RECORDING * HIT ENTER TO STOP ***\n");

for (;;) {
while (read(0, &tmp, 1) == 1) {
if ((tmp == 13) || (tmp == 10)) goto done;
}
if (read(afd, buf, sz) != sz) {
perror("cannot read buffer");
goto fail;
}
if (write(fd, buf, sz) != sz) {
perror("cannot write buffer");
goto fail;
}
total += sz;

}
done:
close(afd);

/* update lengths in header */
hdr.data_sz = total;
hdr.riff_sz = total + 8 + 16 + 8;
lseek(fd, 0, SEEK_SET);
write(fd, &hdr, sizeof(hdr));
close(fd);
return 0;

fail:
close(afd);
close(fd);
unlink(fn);
return -1;
}

int mp3_play(const char *fn)
{
char buf[64*1024];
int r;
int fd, afd;

fd = open(fn, O_RDONLY);
if (fd < 0) {
perror("cannot open mp3 file");
return -1;
}

afd = open("/dev/msm_mp3", O_RDWR);
if (afd < 0) {
close(fd);
perror("cannot open mp3 output device");
return -1;
}

fprintf(stderr,"MP3 PLAY\n");
ioctl(afd, AUDIO_START, 0);

for (;;) {
r = read(fd, buf, 64*1024);
if (r <= 0) break;
r = write(afd, buf, r);
if (r < 0) break;
}

close(fd);
close(afd);
return 0;
}

int main(int argc, char **argv)
{
const char *fn = 0;
int play = 1;
unsigned channels = 1;
unsigned rate = 44100;

argc--;
argv++;
while (argc > 0) {
if (!strcmp(argv[0],"-rec")) {
play = 0;
} else if (!strcmp(argv[0],"-play")) {
play = 1;
} else if (!strcmp(argv[0],"-stereo")) {
channels = 2;
} else if (!strcmp(argv[0],"-mono")) {
channels = 1;
} else if (!strcmp(argv[0],"-rate")) {
argc--;
argv++;
if (argc == 0) {
fprintf(stderr,"playwav: -rate requires a parameter\n");
return -1;
}
rate = atoi(argv[0]);
} else {
fn = argv[0];
}
argc--;
argv++;
}

if (fn == 0) {
fn = play ? "/data/out.wav" : "/data/rec.wav";
}

if (play) {
const char *dot = strrchr(fn, '.');
if (dot && !strcmp(dot,".mp3")) {
return mp3_play(fn);
} else {
return wav_play(fn);
}
} else {
return wav_rec(fn, channels, rate);
}
return 0;
}


syntax highlighted by , v. 0.9.1
阅读(3625) | 评论(8) | 转发(0) |
给主人留下些什么吧!~~

appledragon2010-08-06 09:18:52

其实这是android的源码,在模拟器上,没有这些设备,在真机上,需要root权限才可以open这些设备,所以。。。。

chinaunix网友2010-08-05 19:44:35

請問這個範例是否能夠在模擬器下面執行呢?我嘗試一下,似乎在 open("/dev/msm_pcm_out", O_RDWR); open("/dev/msm_pcm_in", O_RDWR); 會有問題?還是只能在實機上面運作?

chinaunix网友2010-07-14 15:59:34

谢谢楼主 学习了