接下来笔者介绍一下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);//暂停
}

利用上面的播放方式可能会播放不成功,这是因为把一段音频加载到内存在还需要一段时间,所以如果在Load方法后立即调用play,可能会播放不成功。对于这种的解决方案:

a.加载音频在OnCreate方法完成,播放在按钮中完成。

b.设置OnLoadCompleteListener监听。

栗子:

        SoundPool soundPool=new  SoundPool(100,AudioManager.STREAM_MUSIC,5);//构建对象
soundPool.setOnLoadCompleteListener(new OnLoadCompleteListener() {
@Override
public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
soundPool.play(sampleId,1,1,1,0,1);//播放
}
});
soundPool.load(this,R.raw.victory,1);//加载资源

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却是比较重要的。

5.总结

1.对于延迟度要求不高,并且希望能够更全面的控制音乐的播放,MediaPlayer比较适合
2.声音短小,延迟度小,并且需要几种声音同时播放的场景,适合使用SoundPool
3.播放大文件音乐,如WAV无损音频和PCM无压缩音频,可使用更底层的播放方式AudioTrack。它支持流式播放,可以读取(可来自本地和网络)音频流,却播放延迟较小。
ps:据我测试AudioTrack直接支持WAV和PCM,其他音频需要解码成PCM格式才能播放。(其他无损格式没有尝试,有兴趣可以使本文提供的例子测试一下)
4. .jet的音频比较少见(有的游戏中在使用),可使用专门的播放器JetPlayer播放
5.对于系统类声音的播放和操作,Ringtone更适合、

原文连接:Android中播放音频的几种方式

【Android】播放音频的几种方式介绍的更多相关文章

  1. Android播放音频的两种方式

    一种使用MediaPlayer,使用这种方式通常是播放比较长的音频,如游戏中的背景音乐. 代码如下: private MediaPlayer mPlayer = null; mPlayer = Med ...

  2. Android录制音频的三种方式

    对于录制音频,Android系统就都自带了一个小小的应用,可是使用起来可能不是特别的灵活.所以有提供了另外的俩种. 下边来介绍下这三种录制的方式; 1.通过Intent调用系统的录音器功能,然后在录制 ...

  3. 【转】Android播放音频MediaPlayer的几种方式介绍

    接下来笔者介绍一下Android中播放音频的几种方式,android.media包下面包含了Android开发中媒体类,当然笔者不会依次去介绍,下面介绍几个音频播放中常用的类: 1.使用MediaPl ...

  4. android 定位的几种方式介绍

    [地理位置] android 定位的几种方式介绍 开发中对于地图及地理位置的定位是我们经常要用地,地图功能的使用使得我们应用功能更加完善,下面 www.androidkaifa.com 总结了一下网络 ...

  5. uni-app&H5&Android混合开发三 || uni-app调用Android原生方法的三种方式

    前言: 关于H5的调用Android原生方法的方式有很多,在该片文章中我主要简单介绍三种与Android原生方法交互的方式. 一.H5+方法调用android原生方法 H5+ Android开发规范官 ...

  6. Spark部署三种方式介绍:YARN模式、Standalone模式、HA模式

    参考自:Spark部署三种方式介绍:YARN模式.Standalone模式.HA模式http://www.aboutyun.com/forum.php?mod=viewthread&tid=7 ...

  7. Mysql查看版本号的五种方式介绍

    Mysql查看版本号的五种方式介绍 作者: 字体:[增加 减小] 类型:转载 时间:2013-05-03   一.使用命令行模式进入mysql会看到最开始的提示符;二.命令行中使用status可以看到 ...

  8. MySQL查看版本号的五种方式介绍1111111

    MySQL查看版本号的五种方式介绍 1 命令行模式登录MySQL [root@localhost ~]# mysql -uroot -p Enter password: Welcome to the ...

  9. Android中播放音乐的几种方式

    前言 前几天一直在研究RxJava2,也写了记录了几篇博客,但因为工作任务原因,需要研究音频相关的知识,暂时放下Rxjava,本文的demo中,MediaPalyer 部分使用RxJava编写一点逻辑 ...

随机推荐

  1. Linux下逻辑地址-线性地址-物理地址图解(转)

    一.逻辑地址转线性地址 机器语言指令中出现的内存地址,都是逻辑地址,需要转换成线性地址,再经过MMU(CPU中的内存管理单元)转换成物理地址才能够被访问到. 我们写个最简单的hello world程序 ...

  2. Uniform and Interpolator Packing的作用

    All of the packing that is done is completely transparent to the user of the OpenGL ES Shading Langu ...

  3. stl 迭代器失效

    1.对于基于连续内存的容器,容器元素的增删,有可能会导致迭代器的失效.考虑: int main(int argc, char* argv[]) { vector<int> intVec; ...

  4. LeetCode Anagrams My solution

    Anagrams Given an array of strings, return all groups of strings that are anagrams. Note: All inputs ...

  5. CAD中批量打印

    同事在网上找各种软件来实现CAD图的批量打印,总是问题多多.于是,我想到一个更方便的解决方法,即只要我将一个打印出来,然后就可以用批量处理来实现. 1.在CAD中输入plot命令(或快捷键Ctrl+P ...

  6. Windows平台查看端口占用的程序

    一.方法:管理员权限打开Cmd窗口:netstat -obna

  7. 这两天使用JSP开发程序,记录一些基本方法

    一.截取字符串 第一步 导入包:<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn ...

  8. MAVEN创建JAVA的Web工程

    maven命令:http://blog.csdn.net/edward0830ly/article/details/8748986 1.创建MAVEN的Web工程 mvn archetype:gene ...

  9. umeng友盟消息推送功能集成

    umeng友盟消息推送功能集成(本人使用的是eclipse开发) 1.首先请自行观看友盟消息推送集成的API文档. 观看地址如下: http://dev.umeng.com/push/android/ ...

  10. CentOS安装Oracle 11gR2(x64)

    本文主要步骤是参考:https://www.linuxidc.com/Linux/2014-02/97374.htm 后来自己加入了一些安装过程中遇到的问题和解决方法.使用图形界面安装Oracle已经 ...