Android 音视频深刻 二 AudioTrack播放pcm(附源码下载)

本篇项目地址,名字是录音和播放PCM,求star
https://github.com/979451341/Audio-and-video-learning-materials

java

1.AudioTrack官方说明

AudioTrack容许PCM音频缓冲器流到音频接收器进行回放。这是经过“推”的数据对象的信号使用 write(byte[], int, int) and write(short[], int, int) 方法。
一个信号能够在两种模式下运行:静态或流。
在流模式中,应用程序写一个连续的数据流的信号,采用write()方法。这些都是封闭和返回时,数据已经从java层转移到本地层排队等候播放。在播放音频数据块时,流模式最为有用:
因为播放声音的持续时间太大而不适合于记忆,由于音频数据的特性(采样率高)
在处理适合于内存的短声音时,应该选择静态模式,而且须要以最小的延迟进行播放。所以,静态模式更适合于常常播放的UI和游戏声音,而且可能开销最小。
在创做中,一个声道对象初始化其相关音频缓冲区。这个缓冲区的大小,规定在施工过程当中,肯定多长时间的信号能够跑出来的数据以前玩。
使用静态模式的信号,这是声音的大小,能够发挥它的最大尺寸。
对于流模式,数据将被写入音频接收器,其大小小于或等于总缓冲区大小。信号不是终点,从而容许子类,但不推荐使用。


git

2.AudioTrack何如建立和配置

    static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat)

    public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat,
            int bufferSizeInBytes, int mode)

sampleRateInHz:采集率,有8000、20100等,通常来讲越高音质越好,但文件体积就越大

streamType:音频流的类型,STREAM_VOICE_CALL, STREAM_SYSTEM, STREAM_RING, STREAM_MUSIC, STREAM_ALARM, and STREAM_NOTIFICATION,这个参数和Android中的AudioManager有关系,涉及到手机上的音频管理策略。

channelConfig:声道,单声道CHANNEL_OUT_MONO 和双声道 CHANNEL_OUT_STEREO

audioFormat:采样点大小,只有ENCODING_PCM_16BIT 和 ENCODING_PCM_8BIT两种选择,意思是一个采集点16bit或8bit

bufferSizeInBytes:AudioTrack一次所能接收最小的声音资源大小,经过getMinBufferSize函数获取,

mode:有MODE_STATIC和MODE_STREAM两种分类。
STREAM的意思是由用户在应用程序经过write方式把数据一次一次得写到audiotrack中,效率低。
而STATIC的意思是一开始建立的时候,就把音频数据放到一个固定的buffer,而后直接传给audiotrack,只有读取一次,这种方法对于铃声等内存占用较小,延时要求较高的声音来讲很适用。github

3.AudioTrack使用


其实这个和AudioRecord同样的道理,由于是播放,因此播放文件存在,直接读取文件,经过流的形式一次一次的读取数据,同时播放

首先建立AudioTrack
        bufferSize = AudioTrack.getMinBufferSize(8000,
                AudioFormat.CHANNEL_IN_STEREO,  AudioFormat.ENCODING_PCM_16BIT);

        // 实例AudioTrack
        track = new AudioTrack(AudioManager.STREAM_MUSIC,
                8000,
                AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_PCM_16BIT, bufferSize,
                AudioTrack.MODE_STREAM);


接着

track.play()

而后循环读取数据,读完了就stop(),本身中断的话就中止循环

                track.play();
                //writeToFileHead();
                while (isStart) {
                    if (null != track&&dis.available() > 0) {

                        int i = 0;

                        while (dis.available() > 0 && i < buffer.length){
                            buffer[i] = dis.readShort();
                            i++;
                        }

                        track.write(buffer,0,buffer.length);

                    }
                }
                track.stop();


须要注意的是资源的及时释放

            if (track != null) {
                if (track.getState() == AudioRecord.STATE_INITIALIZED) {
                    track.stop();
                }
                if (track != null) {
                    track.release();
                }
            }
            if (dis != null) {
                dis.close();
            }

服务器

4.AudioRecord和AudioTrack的对比


二者的功能恰好相反,一个产生pcm一个读取pcm,而运做的过程很是类似,都对流情有独钟,都是一次吃不了这么多,慢慢的吃,

                mRecorder.startRecording();
                //writeToFileHead();
                while (isStart) {
                    if (null != mRecorder) {
                        bytesRecord = mRecorder.read(tempBuffer, 0, bufferSize);
                        if (bytesRecord == AudioRecord.ERROR_INVALID_OPERATION || bytesRecord == AudioRecord.ERROR_BAD_VALUE) {
                            continue;
                        }
                        if (bytesRecord != 0 && bytesRecord != -1) {
                            //在此能够对录制音频的数据进行二次处理 好比变声,压缩,降噪,增益等操做
                            //咱们这里直接将pcm音频原数据写入文件 这里能够直接发送至服务器 对方采用AudioTrack进行播放原数据
                            dos.write(tempBuffer, 0, bytesRecord);
                        } else {
                            break;
                        }
                    }
                }

就连资源释放都类似

            if (mRecorder != null) {
                if (mRecorder.getState() == AudioRecord.STATE_INITIALIZED) {
                    mRecorder.stop();
                }
                if (mRecorder != null) {
                    mRecorder.release();
                }
            }
            if (dos != null) {
                dos.flush();
                dos.close();
            }

完整的代码请看文章首部项目地址

ide

相关文章
相关标签/搜索