音频(二) - AudioRecord&AudioTrack

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/KevinDGK/article/details/52924790

版权声明:本文为原创文章,未经允许不得转载

博客地址:http://blog.csdn.net/kevindgk

GitHub地址:https://github.com/KevinDGK/MyAudioDemo

一、AudioRecord

简介

在Java应用中,AudioRecord类管理着音频来源,使用平台的音频输入硬件来录音。然后,我们可以从AudioRecord类中将录音的数据“拉”出来。其中,我们获取数据的方法有三种:

- read(byte[],int, int)
- read(short[], int, int)
- sread(ByteBuffer, int)

至于选择哪个方法来获取数据,取决于我们需要的数据格式,需要哪种格式就使用哪种方法。

一旦我们创建成功了AudioRecord类并调用了read方法,它就会使用新的录音得到的数据来填充与之相关的音频缓冲区。缓冲区的大小是在构造方法中定义的,长度取决于不会使得有多余的音频没有录制到。

源码分析

  • 构造方法
/**
    构造方法
    - 由于一些无效的参数或者其他错误会抛出IllegalArgumentException,所以在你构造了一个AudioRecord实例之后,需要立刻调用 getState() 方法来判断这个实例的状态是否可以使用。
    参数:
    - audioSource:录音来源,查看MediaRecorder.AudioSource类对录音来源的定义。
        MediaRecorder.AudioSource.DEFAULT   默认音频来源
        MediaRecorder.AudioSource.MIC       麦克风
        MediaRecorder.AudioSource.VOICE_UPLINK  上行线路的声音来源
        ...
        一般情况下,我们使用麦克风即可。
    - sampleRateInHz:采样率,单位Hz(赫兹)。44100Hz是目前唯一一个能够在所有的设备上使用的频率,但是一些其他的例如22050、16000、11025也能够在一部分设备上使用。
    - channelConfig:音频声道的配置(输入)
        AudioFormat.CHANNEL_IN_MONO:单声道
        AudioFormat.CHANNEL_IN_STEREO:立体声
        其中,CHANNEL_IN_MONO可以保证在所有设备上使用。
    - audioFormat:返回的音频数据的编码格式
        AudioFormat.ENCODING_INVALID:无效的编码格式
        AudioFormat.ENCODING_DEFAULT:默认的编码格式
        AudioFormat.ENCODING_PCM_16BIT:每份采样数据为PCM 16bit,保证所有设备支持
        AudioFormat.ENCODING_PCM_8BIT:样本数据格式为PCM 8bit,不保证所有设备支持
        AudioFormat.ENCODING_PCM_FLOAT:单精度浮点样本
        ...
    - bufferSizeInBytes:在录音时期,音频数据写入的缓冲区的整体大小(单位字节),即缓冲区的大小。我们能够从这个缓冲区中读取到不超过缓冲区长度的整块数据。可以通过 getMinBufferSize(int, int, int) 这个方法来决定我们使用的AudioRecord实例所需要的最小的缓冲区的大小,如果我们使用的数值比这个还要小,则会导致AudioRecord实例初始化失败。
*/
public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat,
            int bufferSizeInBytes);
  • 初始化相关方法
/**
    获取我们要创建的AudioRecord实例所需要的缓冲区的最小长度
    该方法是AudioRecord类的静态方法哦~
*/
static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat);

/**
    获得AudioRecord实例的状态
    - 该方法在AudioRecord实例被创建之后调用来判断是否成功的初始化。
    确保获取(占用)到了合适的硬件资源。
    返回结果:
        STATE_INITIALIZED:1, 初始化成功,等待被使用;
        STATE_UNINITIALIZED:0, 初始化失败。
*/
public int getState();

小编看完构造方法和初始化相关的方法之后就无语了,参数很多,但是能够在所有的Android设备上使用的话,公共的参数都已经确定了,根据API获得了通用的使用麦克风录音的AudioRecord实例的方法:

//1. 获取最小的缓冲区大小
int recordBufferSize = AudioRecord.getMinBufferSize(44100, AudioFormat.CHANNEL_IN_MONO,
                    AudioFormat.ENCODING_PCM_16BIT);

 //2. 创建AudioRecord实例
AudioRecord recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, 44100, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, recordBufferSize);
  • 录音相关方法
/**
    获得AudioRecord实例的录音状态
    返回结果:
        RECORDSTATE_STOPPED:1,录音停止,表示没有在录音;
        RECORDSTATE_RECORDING:3, 正在录音。
*/
public int getRecordingState();

/**
    开始录音
     - 调用该方法后,会调用本地方法,使得录音设备开始录音。
        如果当前AudioRecord实例没有初始化成功,则此时会抛出违法状态异常。
        录音的过程中添加了同步锁,即同一时间只能有一个设备在使用麦克风。在该方法中就会获得该锁,然后修改当前的录音状态为正在录音,并开始录制声音。这个时候,我们初始化的时候使用的录音设备就会将录制到的音频的数据写入到我们定义的缓冲区中。
*/
public void startRecording();

/**
    获取录音数据
     - 从录音硬件设备中读取录音数据,放入到字节数组中。具体我们使用那个方法来获取数据,根据我们设置的AudioRecord录制返回的音频数据的编码格式来定。由于ENCODING_PCM_16BIT是所有设备都支持的,所以我们也使用这个参数对应的read方法来获取录制的音频数据。
     参数:
     - audioData:需要写入音频数据的数组,即AudioRecord实例会将缓冲区中的数据根据指定的长度取出来放到这个给定的数组中,由于我们构造实例的时候设置的返回数据的格式是16bit,所以我们这里的audioData的格式为short[]
     - offsetInxxx:在audioData数组中写入数据的起始索引
     - sizeInShorts:请求的数据的大小
     - readMode:read模式
            READ_BLOCKING:获取数据会阻塞,直到所有的请求的数据被获得;
            READ_NON_BLOCKING:获取尽可能多的录音数据后会立刻返回,不会造成阻塞。
            该参数需要高版本的sdk,>=android.os.Build.VERSION_CODES.M (23),所以可以不设置。
*/
public int read(byte[] audioData, int offsetInBytes, int sizeInBytes);      //8BIT
public int read(byte[] audioData, int offsetInBytes, int sizeInBytes,int readMode);

public int read(short[] audioData, int offsetInShorts, int sizeInShorts);//16BIT,用这个
public int read(short[] audioData, int offsetInShorts, int sizeInShorts,int readMode);

public int read(float[] audioData, int offsetInFloats, int sizeInFloats,int readMode);//FLOAT

public int read(ByteBuffer audioBuffer, int sizeInBytes);   // ByteBuffer
public int read(ByteBuffer audioBuffer, int sizeInBytes, @ReadMode int readMode) 

/**
    停止录音
    - 调用本地方法会使得硬件设备停止录音,设置当前录音状态为停止录音。
*/
public void stop();

/**
    释放资源
    - 释放本地的AudioRecord资源,AudioRecord实例就不能够使用了,
    在调用完该方法之后,引用应该被置为null。
*/
public void release();

二、AudioTrack类解析

简介

声道/音轨,该类为Java应用管理和播放一个单声道资源。它可以使用音频接收器来回放PCM格式的音频缓冲流。我们通过AudioTrack实例的write方法将数据写入进去,就可以达到回放的效果。

源码分析

  • 构造方法
/**
    构造方法
    - streamType:音频流的类型
        AudioManager.STREAM_VOICE_CALL:电话的音频流
        AudioManager.STREAM_SYSTEM:系统的音频流
        AudioManager.STREAM_RING:闹钟
        AudioManager.STREAM_MUSIC:音乐
        AudioManager.STREAM_ALARM:警告声
        AudioManager.STREAM_NOTIFICATION:通知
    - sampleRateInHz:来源的音频的采样频率,单位Hz
    - channelConfig:音频声道的配置
        AudioFormat.CHANNEL_OUT_MONO:单声道输出(左)
        AudioFormat.CHANNEL_OUT_STEREO:立体声输出(左和右)
    - audioFormat:音频格式
        AudioFormat.ENCODING_INVALID:无效的编码格式
        AudioFormat.ENCODING_DEFAULT:默认的编码格式
        AudioFormat.ENCODING_PCM_16BIT:每份采样数据为PCM 16bit,保证所有设备支持
        AudioFormat.ENCODING_PCM_8BIT:样本数据格式为PCM 8bit,不保证所有设备支持
        AudioFormat.ENCODING_PCM_FLOAT:单精度浮点样本
        ...
    - bufferSizeInBytes:缓冲区的大小
        该缓冲区是为了存放需要回放的音频流数据,单位为字节。AudioTrack实例不断的从该缓冲区内读取写入的音频流数据,然后播放出来。它的大小应该是框架层尺寸的数倍。
        如果该声轨的创建模式是"AudioTrack.MODE_STATIC",
    - mode:流或者是静态缓存
        AudioTrack.MODE_STATIC:创建模式-在音频开始播放之前,音频数据仅仅只会从Java层写入到本地层中一次。即开始播放前一次性写入音频数据。
        AudioTrack.MODE_STREAM:创建模式-在音频播放的时候,音频数据会同时会以流的形式写入到本地层中。即一边播放,一边写入数据。(很明显,如果实现一边录音一边播放的话,用这个模式创建声轨)
    - 

*/
public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat,
            int bufferSizeInBytes, int mode);
  • 初始化相关方法
/**
    获取缓冲区大小
    返回使用音频流模式创建声轨的实例时所需要的最小的缓冲区的大小。注意,该尺寸并不会保证在加载音频数据的时候能够平滑的播放数据,应该根据预期的频率来选择更高的缓冲区大小,可以被填充额外的数据。例如,如果你想要动态地提高回放的采样频率,那么也要确保配置比之前设置的缓冲区尺寸更高。简单讲,就是如果提高音频的频率,那么就得相应的提高缓冲区的大小。
    - sampleRateInHz:采样频率
    - channelConfig:声轨的配置
    - audioFormat:音频的格式
    返回值:
      AudioTrack.ERROR_BAD_VALUE:有无效的参数 -2
      AudioTrack.ERROR:不能够查询音频输出的性能 -1
      最小的缓冲区的尺寸,单位为Hz
*/
static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat);

/**
    返回AudioTrack实例的状态
    该方法十分有用,可以在创建完AudioTrack实例之后来检查该实例是否初始化成功,来确保获得了合适的硬件资源。返回值如下:
    AudioTrack.STATE_UNINITIALIZED:没有初始化成功
    AudioTrack.STATE_INITIALIZED:初始化成功AudioTrack实例,等待被使用
    AudioTrack.STATE_NO_STATIC_DATA:初始化成功一个使用静态数据的AudioTrack实例,但是该实例还没有获取到任何的数据呢。

*/
public int getState();
  • 播放音频相关方法
/**
    获取AudioTrack实例的回放状态
    AudioTrack.PLAYSTATE_STOPPED:停止 1
    AudioTrack.PLAYSTATE_PAUSED:暂停  2
    AudioTrack.PLAYSTATE_PLAYING:正在播放   3
*/
public int getPlayState();

/**
    启动回放的实例,开始播放写入的音频数据
    如果AudioTrack的创建模式是"MODE_STATIC",即播放静态资源模式,必须在调用该方法之前调用写入数据的方法,一次性写入音频数据;
    如果AudioTrack的创建模式是"MODE_STREAM",即音频流模式,你可以随意的在调用play()方法之前,通过向缓冲区写入数据来填充音轨数据。
*/
public void play();

/**
    停止播放音频数据
    当使用音频流模式创建的AudioTrack实例来播放音频数据的时候,该实例会在播放完上一个写入的音频缓冲数据之后停止播放。如果想要立刻马上停止播放,请见下面的方法。
*/
public void stop();

/**
    暂停音频数据的回放。
    立刻马上瞬间暂停,此时,未播放的数据不会被丢弃掉,如果重新调用play()方法,会继续之前的数据进行播放。如果想要丢弃剩下未播放的音频数据,应该在调用该方法之后调用flush()方法。
*/
public void pause();

/**
    立刻刷新已经排队等待回放的音频数据
    所有被写入的,但是还没有被播放的数据都会被丢弃。
*/
public void flush();

/**
    释放本地AudioTrack资源
*/
public void release();

联系方式

邮箱:[email protected]

微信:

猜你喜欢

转载自blog.csdn.net/KevinDGK/article/details/52924790