Android音视频之AudioTrack播放音频(二)
前一篇讲了如何录制wav音频文件,本篇就来讲讲如何播放wav文件,这里就是使用AudioTrack来播放音频,确切的说是播放pcm格式数据,使用AudioTrack播放也没什么难度,主要就是将数据写入到AudioTrack中就可以了,先贴代码
package cn.sskbskdrin.record.audio; import android.media.AudioManager;
import android.media.AudioTrack; import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile; /**
* @author sskbskdrin
* @date 2019/April/3
*/
public class AudioTrackManager {
private AudioTrack audioTrack; private boolean playing = false; public AudioParams playWav(String filepath, AudioRecordManager.RecordCallback callback) {
RandomAccessFile file = null;
AudioParams params = null;
try {
file = new RandomAccessFile(filepath, "r");
params = readWavHeader(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
if (params == null) {
return null;
}
int simpleRate = params.simpleRate;
int channelConfig = params.getOutChannelConfig();
int audioFormat = params.getEncodingFormat();
int minBufSize = AudioTrack.getMinBufferSize(simpleRate, channelConfig, audioFormat);
audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, simpleRate, channelConfig, audioFormat, minBufSize,
AudioTrack.MODE_STREAM);
final RandomAccessFile finalFile = file;
new Thread(() -> {
playing = true;
audioTrack.play();
byte[] buffer = new byte[minBufSize];
try {
finalFile.seek(44);
while (playing) {
int read = finalFile.read(buffer);
if (read > 0) {
audioTrack.write(buffer, 0, read);
} else {
finalFile.close();
playing = false;
audioTrack.stop();
audioTrack.release();
}
if (callback != null) {
callback.onRecord(buffer, read);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
return params;
} public static AudioParams readWavHeader(RandomAccessFile file) throws IOException {
file.seek(22);
byte channelCount = file.readByte();
file.seek(24);
int sampleRate = file.readByte() & 0xff;
sampleRate |= (file.readByte() & 0xff) << 8;
sampleRate |= (file.readByte() & 0xff) << 16;
sampleRate |= (file.readByte() & 0xff) << 24; file.seek(34);
byte bits = file.readByte();
return new AudioParams(sampleRate, channelCount, bits);
} }
播放的方法,是传入文件路径,AudioRecordManager.RecordCallback可以为空。先是通过readWavHeader()方法读取wav文件的文件头信息,返回AudioParams,这个类是我前一篇文章有列出来,可以得到一些需要的数据。
关于读数据头部信息,可以参考这里,读取重要数据。
AudioTrack.getMinBufferSize(simpleRate, channelConfig, audioFormat)可以获取最小缓存大小。
AudioTrack的构造方法中,第一个参数为播放流的类型,有下面几种
AudioManager.STREAM_MUSIC //音乐
AudioManager.STREAM_VOICE_CALL //电话
AudioManager.STREAM_RING //铃声
AudioManager.STREAM_ALARM //闹钟
AudioManager.STREAM_NOTIFICATION //通知
最后了个参数是流写入的方式,有两种
AudioTrack.MODE_STREAM // 流写入
AudioTrack.MODE_STATIC //静态写入
AudioTrack.MODE_STREAM看名字大概就能知道是流的方式写入,边写边播。
AudioTrack.MODE_STATIC就是一次写完,然后播放,这种方式更适合比较短的声音播放,比如通知声音
开始播放时,先调用AudioTrack.play(),然后从wav文件的数据块开始读,即第44个字节开始,读完调用audioTrack.write写入pcm数据。当读不到数据时,停止AudioTrack,释放资源即可。
通过RandomAccessFile方式读取文件,可以记录读取的位置,并通过seek方法跳转到指定位置,可实现播放、暂停、继续播放的功能。
Android音视频之AudioTrack播放音频(二)的更多相关文章
- android音视频点/直播模块开发
音视频 版权声明:本文为博主原创文章,未经博主允许不得转载. 前言 随着音视频领域的火热,在很多领域(教育,游戏,娱乐,体育,跑步,餐饮,音乐等)尝试做音视频直播/点播功能,那么作为开发一个小白, ...
- Android音视频点/直播模块开发实践总结-zz
随着音视频领域的火热,在很多领域(教育,游戏,娱乐,体育,跑步,餐饮,音乐等)尝试做音视频直播/点播功能.那么作为开发一个小白,如何快速学习音视频基础知识,了解音视频编解码的传输协议,编解码方式,以及 ...
- Android 音视频开发(一):PCM 格式音频的播放与采集
什么是 PCM 格式 声音从模拟信号转化为数字信号的技术,经过采样.量化.编码三个过程将模拟信号数字化. 采样 顾名思义,对模拟信号采集样本,该过程是从时间上对信号进行数字化,例如每秒采集 44100 ...
- Android Webview中解决H5的音视频不能自动播放的问题
在开发webview的时候,当加载有声音的网页的时候,声音不会自动播放, 解决方法:在webview中调用js方法.这个方法需要在webview的setWebViewClient方法之后在onPage ...
- Android 音视频开发学习思路
Android 音视频开发这块目前的确没有比较系统的教程或者书籍,网上的博客文章也都是比较零散的.只能通过一点点的学习和积累把这块的知识串联积累起来. 初级入门篇: Android 音视频开发(一) ...
- Android 音视频同步机制
一.概述 音视频同步(avsync),是影响多媒体应用体验质量的一个重要因素.而我们在看到音视频同步的时候,最先想到的就是对齐两者的pts,但是实际使用中的各类播放器,其音视频同步机制都比这些复杂的多 ...
- Android 音视频开发(七): 音视频录制流程总结
在前面我们学习和使用了AudioRecord.AudioTrack.Camera.MediaExtractor.MediaMuxer API.MediaCodec. 学习和使用了上述的API之后,相信 ...
- Android音视频开发(1):H264 基本原理
前言 H264 视频压缩算法现在无疑是所有视频压缩技术中使用最广泛,最流行的.随着 x264/openh264 以及 ffmpeg 等开源库的推出,大多数使用者无需再对H264的细节做过多的研究,这大 ...
- Android 音视频开发(六): MediaCodec API 详解
在学习了Android 音视频的基本的相关知识,并整理了相关的API之后,我们应该对基本的音视频有一定的轮廓了. 下面开始接触一个Android音视频中相当重要的一个API: MediaCodec.通 ...
随机推荐
- Python_重写集合
class Set(object): def __init__(self,data=None): if data == None: self.__data = [] else: if not hasa ...
- Pat1071: Speech Patterns
1071. Speech Patterns (25) 时间限制 300 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 HOU, Qiming Peo ...
- PAT1125:Chain the Ropes
1125. Chain the Ropes (25) 时间限制 200 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue Given ...
- Js的String对象
Js的String对象常用方法: 方法一.得到某字符在字符串中的索引位置. str.indexOf(findStr,[index])--返回的是要查找字符在字符串中的位置索引 ,index开始查找 ...
- 关于js中循环遍历中顺序执行多个嵌套ajax的问题
就是业务上需要完成一个功能,这个功能需要依次调用四个接口,后面接口的参数都依赖于前一个接口的返回值. 类似这样: var objArr = "从其他逻辑获得"; for(var n ...
- Zepto源码(2016)——Zepto模块(核心模块)
// Zepto.js // (c) 2010-2016 Thomas Fuchs // Zepto.js may be freely distributed under the MIT licens ...
- 实际项目开发需要注意的tips
1.尽量少用== 或者 != ,除非能够保证这里不会出现强制类型转换,严格起见,最好用 === 与 !==
- 你不知道的JavaScript--Item23 定时器的合理使用
1.定时器概述 window对象提供了两个方法来实现定时器的效果,分别是window.setTimeout()和window.setInterval.其中前者可以使一段代码在指定时间后运行:而后者则可 ...
- BZOJ_4873_[Shoi2017]寿司餐厅_最大权闭合子图
BZOJ_4873_[Shoi2017]寿司餐厅_最大权闭合子图 题意:http://www.lydsy.com/JudgeOnline/problem.php?id=4873 分析:我们发现分数正负 ...
- 种树 BZOJ2151 模拟费用流
分析: 我们如果选择点i,那么我们不能选择i-1和i+1,如果没有这个限制,直接贪心就可行,而加上这个限制,我们考虑同样贪心,每次选择i后,将点i-1,i+1从双向链表中删除,并且将-a[i]+a[i ...