织梦CMS - 轻松建站从此开始!

罗索

当前位置: 主页>嵌入式开发>Android>

使用NDK 播放和录制声音

jackyhwei 发布于 2012-01-02 00:20 点击:次 
落鹤生:Android的source code里使用NDK 播放和录制声音,没有任何说明,希望你能看得懂。
TAG:

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

 */

#include <stdio.h>

#include <stdlib.h>

#include <fcntl.h>

#include <stdint.h>

#include <sys/mman.h>

#include <sys/ioctl.h>

#include <linux/ioctl.h>

#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;

}

/* http://ccrma.stanford.edu/courses/422/projects/WaveFormat/ */

#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;

}

(AppleDragon)
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/201201/15575.html]
本文出处:happ.blog.chinaunix.net 作者:AppleDragon 原文
顶一下
(1)
100%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容