接下来笔者介绍一下Android中播放音频的几种方式,android.media包下面包含了Android开发中媒体类,当然笔者不会依次去介绍,下面介绍几个音频播放中常用的类:
1.使用MediaPlayer播放音频
MediaPlayer的功能很强大,下面附上一张该类封装音频的生命周期图:
MediaPlayer支持AAC、AMR、FLAC、MP3、MIDI、OGG、PCM等格式,MediaPlayer可以通过设置元数据和播放源来音频。
1.1播放Raw文件夹下面音频的元数据
//直接创建,不需要设置setDataSource
MediaPlayer mMediaPlayer;
mMediaPlayer=MediaPlayer.create(this, R.raw.audio);
mMediaPlayer.start();
1.2通过设置播放源来播放音频文件
setDataSource(String path)
//如果从sd卡中加载音乐
//经过笔者的测试,需要加载sd卡的读权限,这里明明是从sd卡中读取文件
// <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
//然后就可以利用 Environment.getExternalStorageDirectory() 获取SD卡的根目录了,一般为/storage/emulated/0
//接下来把xxx.wav放到SD的根目录下,就可以获得文件的路径了 String path=Environment.getExternalStorageDirectory()+"/xxx.wav";
mMediaPlayer.setDataSource(path) ;
//如果从网络加载音乐,如果是从网络中加载那么需要设置网络权限
//<uses-permission android:name="android.permission.INTERNET"/>
mMediaPlayer.setDataSource("http://..../xxx.mp3") ;
//需使用异步缓冲
mMediaPlayer.prepareAsync() ;
setDataSource(FileDescriptor fd)
//需将资源文件放在assets文件夹
AssetFileDescriptor fd = getAssets().openFd("samsara.mp3");
mMediaPlayer.setDataSource(fd.getFileDescriptor());//经过笔者的测试,发现这个方法有时候不能播放成功,尽量使用该方法的另一个重载方法 setDataSource(FileDescptor fd,long offset,long length)
mMediaPlayer.prepare() ;
Ps:此方法系统需大于等于android
setDataSource(Context context,Uri uri)
这个方法没什么好说的,一般通过ContentProvider获取Android系统提供
的共享music获取uri,然后设置数据播放
setDataSource(FileDescptor fd,long offset,long length)
//需将资源文件放在assets文件夹
AssetFileDescriptor fd = getAssets().openFd("samsara.mp3");
mMediaPlayer.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());
mMediaPlayer.prepare();
设置完数据源,不要忘记prepare(),尽量使用异步prepareAync(),这样不会阻塞UI线程。
1.3 MediaPlayer的常用方法
start();//开始播放
pause();//暂停播放
reset()//清空MediaPlayer中的数据
setLooping(boolean);//设置是否循环播放
seekTo(msec)//定位到音频数据的位置,单位毫秒
stop();//停止播放
relase();//释放资源
2.使用SoundPool播放音频
SoundPool支持多个音频文件同时播放(组合音频也是有上限的),延时短,比较适合短促、密集的场景,是游戏开发中音效播放的福音。
2.1 SoundPool实例化方式
1. new SoundPool(适用与5.0以下)
SoundPool(int maxStreams, int streamType, int srcQuality)
从android5.0开始此方法被标记为过时,稍微说以下几个参数。
1.maxStreams :允许同时播放的流的最大值
2.streamType :音频流的类型描述,
在Audiomanager中有种类型声明,游戏应用通常会使用流媒体音乐(AudioManager.STREAM_MUSIC)
3. srcQuality:采样率转化质量,默认值为0 。
2. SoundPool.Builder(从5.0开始支持)
//设置描述音频流信息的属性
AudioAttributes abs = new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build() ;
SoundPool mSoundPoll = new SoundPool.Builder()
.setMaxStreams(100) //设置允许同时播放的流的最大值
.setAudioAttributes(abs) //完全可以设置为null
.build() ;
2.2 SoundPool的几个重要的方法
// 几个load方法和上文提到的MediaPlayer基本一致,这里的每个load都会返回一个SoundId值,这个值可以用来播放和卸载音乐。
//------------------------------------------------------------
int load(AssetFileDescriptor afd, int priority)
int load(Context context, int resId, int priority)
int load(String path, int priority)
int load(FileDescriptor fd, long offset, long length, int priority)
//-------------------------------------------------------------
// 通过流id暂停播放
final void pause(int streamID)
// 播放声音,soundID:音频id(这个id来自load的返回值); left/rightVolume:左右声道(默认1,1);loop:循环次数(-1无限循环,0代表不循环);rate:播放速率(1为标准),该方法会返回一个streamID,如果StreamID为0表示播放失败,否则为播放成功
final int play(int soundID, float leftVolume, float rightVolume, int priority, int loop, float rate)
//释放资源(很重要)
final void release()
//恢复播放
final void resume(int streamID)
//设置指定id的音频循环播放次数
final void setLoop(int streamID, int loop)
//设置加载监听(因为加载是异步的,需要监听加载,完成后再播放)
void setOnLoadCompleteListener(SoundPool.OnLoadCompleteListener listener)
//设置优先级(同时播放个数超过最大值时,优先级低的先被移除)
final void setPriority(int streamID, int priority)
//设置指定音频的播放速率,0.5~2.0(rate>1:加快播放,反之慢速播放)
final void setRate(int streamID, float rate)
//停止指定音频播放
final void stop(int streamID)
//卸载指定音频,soundID来自load()方法的返回值
final boolean unload(int soundID)
//暂停所有音频的播放
final void autoPause()
//恢复所有暂停的音频播放
final void autoResum()
下面简单演示一下SoundPool如何播放音乐:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SoundPool soundPool=new SoundPool(100,AudioManager.STREAM_MUSIC,0);//构建对象
int soundId=soundPool.load(context,R.raw.test,1);//加载资源,得到soundId
int streamId= soundPool.play(soundId, 1,1,1,-1,1);//播放,得到StreamId
// soundPool.stop(streamId);//暂停
3.使用AudioTrack播放音频
AudioTrack属于更偏底层的音频播放,MediaPlayerService的内部就是使用了AudioTrack。
AudioTrack用于单个音频播放和管理,相比于MediaPlayer具有:精炼、高效的优点。
更适合实时产生播放数据的情况,如加密的音频,
MediaPlayer是束手无策的,AudioTrack却可以。
AudioTrack用于播放PCM(PCM无压缩的音频格式)音乐流的回放,
如果要播需放其它格式音频,需要响应的解码器,
这也是AudioTrack用的比较少的原因,需要自己解码音频。
AudioTreack的2种播放模式
静态模式—static
静态的言下之意就是数据一次性交付给接收方。好处是简单高效,只需要进行一次操作就完成了数据的传递;缺点当然也很明显,对于数据量较大的音频回放,显然它是无法胜任的,因而通常只用于播放铃声、系统提醒等对内存小的操作
流模式streaming
流模式和网络上播放视频是类似的,即数据是按照一定规律不断地传递给接收方的。理论上它可用于任何音频播放的场景,不过我们一般在以下情况下采用:
音频文件过大
音频属性要求高,比如采样率高、深度大的数据
音频数据是实时产生的,这种情况就只能用流模式了
通过write(byte[], int, int), write(short[], int, int)等方法推送解码数据到AudioTrack
4.使用Ringtone播放音频
Ringtone为铃声、通知和其他类似声音提供快速播放的方法,这里还不得不提到一个管理类”RingtoneManager”,提供系统铃声列表检索方法,并且,Ringtone实例需要从RingtoneManager获取。
1. 获取实例
//获取实例方法,均为RingtoneManager类提供
//1.通过铃声uri获取
static Ringtone getRingtone(Context context, Uri ringtoneUri)
//2.通过铃声检索位置获取
Ringtone getRingtone(int position)
2. RingtoneManager几个重要的方法
1. // 两个构造方法
RingtoneManager(Activity activity)
RingtoneManager(Context context)
2. // 获取指定声音类型(铃声、通知、闹铃等)的默认声音的Uri
static Uri getDefaultUri(int type)
3. // 获取系统所有Ringtone的cursor
Cursor getCursor()
4. // 获取cursor指定位置的Ringtone uri
Uri getRingtoneUri(int position)
5. // 判断指定Uri是否为默认铃声
static boolean isDefault(Uri ringtoneUri)
6. //获取指定uri的所属类型
static int getDefaultType(Uri defaultRingtoneUri)
7. //将指定Uri设置为指定声音类型的默认声音
static void setActualDefaultRingtoneUri(Context context, int type, Uri ringtoneUri)
从api看,Ringtone和RingtoneManager还是比较简单的,不多做解释了,直接放上一段使用代码。
* 播放来电铃声的默认音乐
private void playRingtoneDefault(){
Uri uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE) ;
Ringtone mRingtone = RingtoneManager.getRingtone(this,uri);
mRingtone.play();
* 随机播放一个Ringtone(有可能是提示音、铃声等)
private void ShufflePlayback(){
RingtoneManager manager = new RingtoneManager(this) ;
Cursor cursor = manager.getCursor();
int count = cursor.getCount() ;
int position = (int)(Math.random()*count) ;
Ringtone mRingtone = manager.getRingtone(position) ;
mRingtone.play();
最后记得添加权限:
<uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
其实,Rington这个类比较简单,只需要掌握,播放、停止(paly(),stop())等方法就可以了,而RingtoneManager却是比较重要的。
1.对于延迟度要求不高,并且希望能够更全面的控制音乐的播放,MediaPlayer比较适合
2.声音短小,延迟度小,并且需要几种声音同时播放的场景,适合使用SoundPool
3.播放大文件音乐,如WAV无损音频和PCM无压缩音频,可使用更底层的播放方式AudioTrack。它支持流式播放,可以读取(可来自本地和网络)音频流,却播放延迟较小。
ps:据我测试AudioTrack直接支持WAV和PCM,其他音频需要解码成PCM格式才能播放。(其他无损格式没有尝试,有兴趣可以使本文提供的例子测试一下)
4. .jet的音频比较少见(有的游戏中在使用),可使用专门的播放器JetPlayer播放
5.对于系统类声音的播放和操作,Ringtone更适合、
Android中播放音乐的几种方式
前几天一直在研究RxJava2,也写了记录了几篇博客,但因为工作任务原因,需要研究音频相关的知识,暂时放下Rxjava,本文的demo中,MediaPalyer
部分使用RxJava编写一点逻辑,其中涉及,RxJava2的被压、解除订阅等知识点,虽然简单,最起码没有丢了RxJava,后续Rxjava会继续研究,做记录.
andorid提供了对声音和视频处理的api包android.media.本文编写了针对这几种方式播放的Demo,文章最后贴出。
对于android音频的播放,这个类可能是大家最熟悉的了,从入门就一直想编写一个自己的音乐播放器,有木有?MediaPlayer确实强大,提供了对音频播放的各种控制,生命周期:
2. 播放Raw下的元数据
//直接创建,不需要设置setDataSource
mMediaPlayer=MediaPlayer.create(this, R.raw.audio);
mMediaPlayer.start();
3. MediaPlayer设置播放源的4中方式
setDataSource (String path)
mMediaPlayer.setDataSource("../music/samsara.mp3") ;
mMediaPlayer.setDataSource("http://..../xxx.mp3") ;
mMediaPlayer.prepareAsync() ;
setDataSource (FileDescriptor fd)
//需将资源文件放在assets文件夹
AssetFileDescriptor fd = getAssets().openFd("samsara.mp3")
mMediaPlayer.setDataSource(fd)
mMediaPlayer.prepare()
Ps:此方法系统需大于等于android
setDataSource (Context context, Uri uri)
这个方法没什么好说的,一般通过ContentProvider获取Android系统提供
的共享music获取uri,然后设置数据播放
setDataSource (FileDescriptor fd, long offset, long length)
//需将资源文件放在assets文件夹
AssetFileDescriptor fd = getAssets().openFd("samsara.mp3")
mMediaPlayer.setDataSource(fd, fd.getStartOffset(), fd.getLegth())
mMediaPlayer.prepare()
4. 注意点
设置完数据源,不要忘记prepare(),尽量使用异步prepareAync(),这样不会阻塞UI线程。
播放完毕即使释放资源
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
资源占用量较高、延迟时间较长、不支持多个音频同时播放等
### MeidaPlayer demo片段
mFormat = new SimpleDateFormat("mm:ss");
mPlayer = new MediaPlayer() ;
mSeekBar.setOnSeekBarChangeListener(new MySeekBarChangeListener());
mPlayer.setOnPreparedListener(new MyOnPrepareListener());
mPlayer.setOnCompletionListener(new MyOnCompletionListener());
* 从assets资源文件夹中播放
* @param name
private void playSoundFromA(String name) {
if (mPlayer.isPlaying()) {
mPlayer.stop();
title.setText(names[current]);
mPlayer.reset();
AssetFileDescriptor afd = getAssetFileDescriptor(name);
try {
mPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
hasResource = true;
mPlayer.prepareAsync();
} catch (IOException e) {
e.printStackTrace();
SoundPool支持多个音频文件同时播放(组合音频也是有上限的),延时短,比较适合短促、密集的场景,是游戏开发中音效播放的福音。
SoundPool实例化方式
1. new SoundPool(适用与5.0以下)
SoundPool(int maxStreams, int streamType, int srcQuality)
从android5.0开始此方法被标记为过时,稍微说以下几个参数。
1.maxStreams :允许同时播放的流的最大值
2.streamType :音频流的类型描述,
在Audiomanager中有种类型声明,游戏应用通常会使用流媒体音乐。
3. srcQuality:采样率转化质量
2. SoundPool.Builder(从5.0开始支持)
//设置描述音频流信息的属性
AudioAttributes abs = new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build()
SoundPool mSoundPoll = new SoundPool.Builder()
.setMaxStreams(100) //设置允许同时播放的流的最大值
.setAudioAttributes(abs) //完全可以设置为null
.build()
3. 几个重要的方法
int load(AssetFileDescriptor afd, int priority)
int load(Context context, int resId, int priority)
int load(String path, int priority)
int load(FileDescriptor fd, long offset, long length, int priority)
final void pause(int streamID)
final int play(int soundID, float leftVolume, float rightVolume, int priority, int loop, float rate)
final void release()
final void resume(int streamID)
final void setLoop(int streamID, int loop)
void setOnLoadCompleteListener(SoundPool.OnLoadCompleteListener listener)
final void setPriority(int streamID, int priority)
final void setRate(int streamID, float rate)
final void stop(int streamID)
final boolean unload(int soundID)
final void autoPause()
final void autoResum()
以上方法基本上是SoundPool的所有方法了,也都很常用。
4. 区分2个概念
看了Sounpool的api,是不是感觉对 streamID 和 soundID 一脸懵逼?
1. soundID:加载音乐资源时的返回值,int load(String path, int priority),这个int返回值就是soundID
2. streamID:播放时返回的值,即play()方法的返回值
这两个值都很重要,需要缓存下来
5. SoundPool Demo片段
注:我把SoundPool做了简单封装,SoundPoolUtil,会在文末上传,
有兴趣可下载看一下,时间比较急,还有很多不足的地方
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
AudioAttributes aab = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.setUsage(AudioAttributes.USAGE_MEDIA)
.build() ;
mSoundPool = new SoundPool.Builder()
.setMaxStreams(10)
.setAudioAttributes(aab)
.build() ;
}else{
mSoundPool = new SoundPool(60, AudioManager.STREAM_MUSIC,8) ;
mSoundPool = new SoundPool(60, AudioManager.STREAM_MUSIC,8) ;
mSoundPool.setOnLoadCompleteListener(new MyOnLoadCompleteListener());
* 加载指定路径列表的资源
* @param map
public void loadR(Map<String, String> map){
Set<Map.Entry<String, String>> entries = map.entrySet();
for(Map.Entry<String, String> entry : entries){
String key = entry.getKey() ;
if(checkSoundPool()){
if(!idCache.containsKey(key)){
idCache.put(key, mSoundPool.load(entry.getValue(),1)) ;
* 播放指定音频,并返用于停止、暂停、恢复的StreamId
* @param name
* @param times
* @return
public int play(String name, int times){
return this.play(name,1,1,1,times,1) ;
AudioTrack属于更偏底层的音频播放,MediaPlayerService的内部就是使用了AudioTrack。
AudioTrack用于单个音频播放和管理,相比于MediaPlayer具有:精炼、高效的优点。
更适合实时产生播放数据的情况,如加密的音频,
MediaPlayer是束手无策的,AudioTrack却可以。
AudioTrack用于播放PCM(PCM无压缩的音频格式)音乐流的回放,
如果需要播放其它格式音频,需要响应的解码器,
这也是AudioTrack用的比较少的原因,需要自己解码音频。
AudioTreack的2种播放模式
静态模式—static
静态的言下之意就是数据一次性交付给接收方。好处是简单高效,只需要进行一次操作就完成了数据的传递;缺点当然也很明显,对于数据量较大的音频回放,显然它是无法胜任的,因而通常只用于播放铃声、系统提醒等对内存小的操作
流模式streaming
流模式和网络上播放视频是类似的,即数据是按照一定规律不断地传递给接收方的。理论上它可用于任何音频播放的场景,不过我们一般在以下情况下采用:
音频文件过大
音频属性要求高,比如采样率高、深度大的数据
音频数据是实时产生的,这种情况就只能用流模式了
通过write(byte[], int, int), write(short[], int, int)
write(float[], int, int, int)等方法推送解码数据到AudioTrack
使用Demo
private void jetPlayStream(){
new Thread(new Runnable() {
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
public void run() {
int bufSize = AudioTrack.getMinBufferSize(44100, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT);
AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_OUT_STEREO,
AudioFormat.ENCODING_PCM_16BIT, bufSize*2, AudioTrack.MODE_STREAM);
audioTrack.setVolume(2f) ;
audioTrack.setPlaybackRate(10) ;
audioTrack.play();
InputStream is = getResources().openRawResource(R.raw.zbc);
byte[] buffer = new byte[bufSize*2] ;
int len ;
try {
while((len=is.read(buffer,0,buffer.length)) != -1){
System.out.println("读取数据中...");
audioTrack.write(buffer,0,buffer.length) ;
is.close();
} catch (Exception e) {
e.printStackTrace();
}).start();
更深入的研究,请参考以下博客
http://blog.csdn.net/edmond999/article/details/18600323
http://blog.csdn.net/conowen/article/details/7799155/
从名字就可看出AsyncPlayer属于异步播放器,官方给出的说明是:所有工作都在子线程进行,不影响调用线程任何操作。
AsyncPlayer就是对MediaPlayer的一次简单的封装,对MediaPlaer所有的操作都在新开线程中执行。
AsyncPlayer只适合简单的异步播放,不能控制进度,只能开始或停止播放。如果播放在此调用play()方法,AsyncPlayer会停止当前播放,开始新的播放。
*内部线程类
private final class Thread extends java.lang.Thread {
public void run() {
while (true) {
Command cmd = null;
synchronized (mCmdQueue) {
cmd = mCmdQueue.removeFirst();
switch (cmd.code) {
case PLAY:
if (mDebug) Log.d(mTag, "PLAY");
startSound(cmd);
break;
private void startSound(Command cmd) {
if (mDebug) Log.d(mTag, "Starting playback");
MediaPlayer player = new MediaPlayer();
player.setAudioStreamType(cmd.stream);
player.setDataSource(cmd.context, cmd.uri);
player.setLooping(cmd.looping);
player.prepare();
player.start();
2.简单demo
十分简单,不再贴出,可以在文末Demo中看到
Jet是由OHA联盟成员SONiVOX开发的一个交互音乐引擎。其包括两部分:JET播放器和JET引擎。JET常用于控制游戏的声音特效,采用MIDI(Musical Instrument Digital Interface)格式。
ps:以后遇到手机中的”.jet”文件,就只到它究竟是什么东东了。。。
//获取JetPlayer播放器
JetPlayer mJet = JetPlayer.getJetPlayer() ;
几个重要方法
1. boolean clearQueue()
2. boolean loadJetFile(String path)
boolean loadJetFile(AssetFileDescriptor afd)
3. boolean play()
4. boolean pause()
5. void release()
6. boolean queueJetSegment(int segmentNum, int libNum, int repeatCount, int transpose, int muteFlags, byte userID)
JetPlayer Demo
private void jetPlayer(){
JetPlayer mJet = JetPlayer.getJetPlayer() ;
mJet.clearQueue() ;
mJet.setEventListener(new JetPlayer.OnJetEventListener() {
int playNum = 1 ;
@Override
public void onJetEvent(JetPlayer player, short segment, byte track, byte channel, byte controller, byte value) {
Log.i(TAG,"----->onJetEvent") ;
@Override
public void onJetUserIdUpdate(JetPlayer player, int userId, int repeatCount) {
Log.i(TAG,"----->onJetUserIdUpdate") ;
@Override
public void onJetNumQueuedSegmentUpdate(JetPlayer player, int nbSegments) {
Log.i(TAG,"----->onJetNumQueuedSegmentUpdate") ;
@Override
public void onJetPauseUpdate(JetPlayer player, int paused) {
Log.i(TAG,"----->onJetPauseUpdate") ;
if(playNum == 2){
playNum = -1 ;
player.release();
player.closeJetFile() ;
}else{
playNum++ ;
mJet.loadJetFile(getResources().openRawResourceFd(R.raw.level1)) ;
byte sSegmentID = 0 ;
mJet.queueJetSegment(0, 0, 0, 0, 0, sSegmentID);
mJet.queueJetSegment(1, 0, 1, 0, 0, sSegmentID);
mJet.play() ;
Ringtone为铃声、通知和其他类似声音提供快速播放的方法,这里还不得不提到一个管理类”RingtoneManager”,提供系统铃声列表检索方法,并且,Ringtone实例需要从RingtoneManager获取。
1. 获取实例
获取实例方法,均为RingtoneManager类提供
static Ringtone getRingtone(Context context, Uri ringtoneUri)
Ringtone getRingtone(int position)
其实,Rington这个类比较简单,只需要掌握,播放、停止(paly(),stop())等方法就可以了,而RingtoneManager却是比较重要的。
2. RingtoneManager几个钟要的方法
1.
RingtoneManager(Activity activity)
RingtoneManager(Context context)
2.
static Uri getDefaultUri(int type)
3.
Cursor getCursor()
4.
Uri getRingtoneUri(int position)
5.
static boolean isDefault(Uri ringtoneUri)
6.
static int getDefaultType(Uri defaultRingtoneUri)
7.
static void setActualDefaultRingtoneUri(Context context, int type, Uri ringtoneUri)
从api看,Ringtone和RingtoneManager还是比较简单的,不多做解释了,直接放上一段使用代码。
* 播放来电铃声的默认音乐
private void playRingtoneDefault(){
Uri uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE) ;
Ringtone mRingtone = RingtoneManager.getRingtone(this,uri);
mRingtone.play();
* 随机播放一个Ringtone(有可能是提示音、铃声等)
private void ShufflePlayback(){
RingtoneManager manager = new RingtoneManager(this) ;
Cursor cursor = manager.getCursor();
int count = cursor.getCount() ;
int position = (int)(Math.random()*count) ;
Ringtone mRingtone = manager.getRingtone(position) ;
mRingtone.play();
<uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
以上介绍了几种播放方式,可以说各有优劣。
本文写的不够详细,只是大概的介绍一下几种播放方式。在此做下简单的总结。
对于延迟度要求不高,并且希望能够更全面的控制音乐的播放,MediaPlayer比较适合
声音短小,延迟度小,并且需要几种声音同时播放的场景,适合使用SoundPool
对于简单的播放,不需要复杂控制的播放,可以给使用AsyncPlayer,所有操作均在子线程不阻塞UI
播放大文件音乐,如WAV无损音频和PCM无压缩音频,可使用更底层的播放方式AudioTrack。它支持流式播放,可以读取(可来自本地和网络)音频流,却播放延迟较小。
ps:据我测试AudioTrack直接支持WAV和PCM,其他音频需要解码成PCM格式才能播放。(其他无损格式没有尝试,有兴趣可以使本文提供的例子测试一下)
.jet的音频比较少见(有的游戏中在使用),可使用专门的播放器JetPlayer播放
对于系统类声音的播放和操作,Ringtone更适合(主要是掌握好RingtoneManager)
android.media包中提供的播放音频的方式,远不止这些,本文只是参考api和其他大牛的博客做一些研究和记录,android.media种还有很多只是等着我们探索……