参数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();
//清除播放缓冲器
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
![](https://i-blog.csdnimg.cn/blog_migrate/07d44f2c1e2e33a8de429139a90a01c4.jpeg)
总结
Android架构学习进阶是一条漫长而艰苦的道路,不能靠一时激情,更不是熬几天几夜就能学好的,必须养成平时努力学习的习惯。所以:贵在坚持!
上面分享的字节跳动公司2021年的面试真题解析大全,笔者还把一线互联网企业主流面试技术要点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节。
【Android高级架构视频学习资源】
Android部分精讲视频领取学习后更加是如虎添翼!进军BATJ大厂等(备战)!现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧!
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧!
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!