Android SDK 提供的3套音频播放的API之窥探AudioTrack

参数bufferSizeInBytes:AudioTrack一次所能接收最小的声音资源大小,通过getMinBufferSize函数获取,用于读取音频数据的内部缓冲区的总大小(以byte为单位)。

  • mode:

参数mode:有MODE_STATIC和MODE_STREAM两种分类。

1.2、初始化方式:AudioTrack.Builder
  • setAudioAttributes 设置AudioAttributes 实例,不能为空

  • setUsage 设置 AudioTrack 的使用场景;

  • setContentType 设置输入的音频文件内容的类型;

  • setAudioFormat AudioFormat是咧 用于描述播放的数据格式,AudioFormat 中包含了编码格式,声道和采样率等,不能为空

  • setEncoding 设置 采样格式

  • setSampleRate 设置采样率

  • setChannelMask设置声道

  • setTransferMode int模式二选一 MODE_STATIC 与 MODE_STREAM

静态模式(MODE_STATIC) & 流模式(MODE_STREAM)

在流模式下,应用程序使用write()方法之一向AudioTrack写入连续的数据流。
当数据从Java层传输到本机层并排队等待回放时,它们会阻塞并返回。
流媒体模式在播放音频数据块时最有用

当处理适合内存且需要以最小延迟播放的短声音时,应该选择静态模式。
因此,静态模式更适合那些经常玩的UI和游戏声音,并且开销尽可能小。

  • setBufferSizeInBytes setBufferSizeInBytes:int: 用于读取音频数据的内部缓冲区的总大小(以byte为单位)。

如果 mode 是 MODE_STATIC ,其为音频最大长度; 如果是 MODE_STREAM ,其值要大于等于接收流的最小缓冲区大小, 建议使用 getMinBufferSize(int, int, int) 方法来估算 AudioTrack的实例在流模式下的最小缓冲区大小.

1.3、初始化代码

private AudioTrack mAudioTrack;
private int SMPL = 44100;
private int mode = AudioTrack.MODE_STREAM;
//获取最小缓冲区大小
int minBufferSize = AudioTrack.getMinBufferSize(SMPL,//采样率
AudioFormat.CHANNEL_OUT_STEREO, //双声道
AudioFormat.ENCODING_PCM_16BIT //采样格式
);
public void initAudioTrack(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
//AudioTrack.Builder
mAudioTrack = new AudioTrack.Builder()
//1、setAudioAttributes:AudioAttributes 实例,不能为空
.setAudioAttributes(new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)//setUsage 设置 AudioTrack 的使用场景;
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)//setContentType 设置输入的音频文件内容的类型;
.build())
//2、setAudioFormat:AudioFormat是咧 用于描述播放的数据格式,AudioFormat 中包含了编码
//格式,声道和采样率等,不能为空
.setAudioFormat(new AudioFormat.Builder()
.setEncoding(AudioFormat.ENCODING_PCM_16BIT)//采样格式
.setSampleRate(SMPL)//设置采样率
.setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)//设置声道
.build())
//3、setTransferMode:int模式二选一 MODE_STATIC 与 MODE_STREAM
.setTransferMode(mode)
//4、setBufferSizeInBytes:int: 用于读取音频数据的内部缓冲区的总大小(以byte为单位)。
//如果 mode 是 MODE_STATIC ,其为音频最大长度;
//如果是 MODE_STREAM ,其值要大于等于接收流的最小缓冲区大小,建议使用 getMinBufferSize(int, int, int) 方法来估算 AudioTrack的实例在流模式下的最小缓冲区大小
.setBufferSizeInBytes(minBufferSize)

.build();
} else {
//public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes, int mode)
mAudioTrack = new AudioTrack(
//1、参数streamType:媒体类型有STREAM_VOICE_CALL, STREAM_SYSTEM, STREAM_RING, STREAM_MUSIC, STREAM_ALARM, STREAM_NOTIFICATION
AudioManager.STREAM_MUSIC
//2、参数sampleRateInHz:采样率,有8000、20100等,一般来说越高音质越好,但文件体积就越大
, SMPL
//3、参数channelConfig:声道,单声道CHANNEL_OUT_MONO 和双声道 CHANNEL_OUT_STEREO
, AudioFormat.CHANNEL_IN_STEREO//双声道
//4、参数audioFormat:采样点大小,只有ENCODING_PCM_16BIT 和 ENCODING_PCM_8BIT两种选择,意思是一个采集点16bit或8bit
, AudioFormat.ENCODING_PCM_16BIT//采样格式
//5、参数bufferSizeInBytes:AudioTrack一次所能接收最小的声音资源大小,通过getMinBufferSize函数获取,
, minBufferSize//缓冲区大小
//6、参数mode:有MODE_STATIC和MODE_STREAM两种分类。
, mode
);
}
}

2、AudioTrack的主要方法

在没有看文档之前,我不太清楚调用的顺序。

开始播放声音的时机,直觉上以为是play,没想到是调用write。

这还挺另类。

方法目的
play将playState设置为播放状态(PLAYSTATE_PLAYING)
stop将playState置于停止状态(PLAYSTATE_STOPPED)。
write将数据写入播放缓冲区。
flush清除播放缓冲区中的数据。
release销毁AudioTrack对象。
3、AudioTrack播放声音

在实现逻辑中,initAudioTrack→ready之后,重复play。

MODE_STATIC:静态模式场景播放
  • 通过预处理来设置数据,
  • 然后用reloadStaticData()将静态缓冲区内的播放头位置设置为零,即将其回退到静态缓冲区的开始位置。
  • 重复播放相同模式的音频
  • 这个好像比较合适。
  • 虽然每次都stop(),但是没有stop()也能连续播放。

/**

  • 准备数据:MODE_STATIC
  • @param data
    */
    private void readyModeStatic(byte[] data){
    //在缓存器中预先设置数据
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
    mAudioTrack.write(data, 0, data.length, AudioTrack.WRITE_BLOCKING);
    }else{
    mAudioTrack.write(data, 0, data.length);
    }
    }

/**

  • 播放:MODE_STATIC
  • @param data
    */
    private void playModeStatic(byte[] data){
    if(mAudioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING){
    //播放中停止播放
    mAudioTrack.stop();
    //清除播放器缓存器
    mAudioTrack.flush();
    }
    //重新读取准备数据
    mAudioTrack.reloadStaticData();
    //向播放缓冲器写入数据
    readyModeStatic(data);
    //播放
    mAudioTrack.play();
    }
MODE_STREAM:流模式场景播放

如果播放完成后没有停止(),将不会输出声音。

另外,如果缓冲区的内容已用完,则会发生错误,并且将跳过一次播放。

我通过用预处理填充缓冲区来解决它

/**

  • 准备数据:MODE_STREAM
  • @param data
    */
    private void readyModeStream(byte[] data){

if(mAudioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING){
mAudioTrack.stop();
mAudioTrack.flush();
}
if(mAudioTrack != null){
//填充缓冲区
int loopCount = minBufferSize / data.length;
for (int i = 0 ; i < loopCount ; i++){
//在缓存器中预先设置数据
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
mAudioTrack.write(data, 0, data.length, AudioTrack.WRITE_BLOCKING);
}else{
mAudioTrack.write(data, 0, data.length);
}
}
}

}

/**

  • 播放:MODE_STREAM
  • @param data
    */
    private void playModeStream(byte[] data){
    readyModeStream(data);
    //监听播放中停止
    mAudioTrack.setPlaybackPositionUpdateListener(new AudioTrack.OnPlaybackPositionUpdateListener() {
    @Override
    public void onMarkerReached(AudioTrack track) {
    if(track.getPlayState() == AudioTrack.PLAYSTATE_PLAYING){
    track.stop();
    }
    }

@Override
public void onPeriodicNotification(AudioTrack track) {

}
});

mAudioTrack.setNotificationMarkerPosition(data.length);
//进入播放状态
if(mAudioTrack.getPlayState() != AudioTrack.PLAYSTATE_PLAYING){
mAudioTrack.play();
}
}

4、AudioTrack停止播放&释放

//停止
private void stop(){
if(mAudioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING){
//播放中停止播放
mAudioTrack.stop();
//清除播放缓冲器

最后我想说

为什么很多程序员做不了架构师?
1、良好健康的职业规划很重要,但大多数人都忽略了
2、学习的习惯很重要,持之以恒才是正解。
3、编程思维没能提升一个台阶,局限在了编码,业务,没考虑过选型、扩展
4、身边没有好的架构师引导、培养。所处的圈子对程序员的成长影响巨大。

金九银十面试季,跳槽季,整理面试题已经成了我多年的习惯!在这里我和身边一些朋友特意整理了一份快速进阶为Android高级工程师的系统且全面的学习资料。涵盖了Android初级——Android高级架构师进阶必备的一些学习技能。

附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题(含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)

里面包含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中…
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!
、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)

[外链图片转存中…(img-gsZtduok-1714400505863)]

里面包含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中…
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

  • 22
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值