Android多媒体三:MediaPlayer播放音频

Android多媒体三:MediaPlayer播放音频

主要介绍MediaPlayer、SoundPool、Ringtone

一:加载音频文件

1,第一种方式:使用create方法

			static MediaPlayer create(Context contect,Uri uri):从指定Uri来装载音频文件,并返回新创建的MediaPlayer对象。

			static MediaPlayer create(Context context,int resid):从resident资源ID对应的资源文件装载音频,并返回新创建的MediaPlayer对象。
			
		这两个方法都返回新创建的MediaPlayer对象,如果程序需要使用MediaPlayer循环播放多个音频文件,再使用MediaPlayer的静态create方法就不合适了,那么此时就需要通过MediaPlayer的setDataSource()方法来加载指定的音频文件。

2,第二种方式:通过MediaPlayer的setDataSource

		    void setDataSource(String path) :指定装载path路径所代表的文件。

			void setDataSource(FileDescriptor fd,long offset,long length):指定装载fd所代表的文件中从offset开始,长度为length的文件内容。

			void setDataSource(FileDescriptor fd):指定装载fd所代表的文件。

			void setDataSource(Context context,Uri uri):指定装载Uri所代表的文件

			setDataSource()方法之后,MediaPlayer并非真正去装载那些音频文件,还需要调用MediaPlayer的prepare()方法去准备音频,就是去真正装载音频文件。
二、MediaPlayer监听
			1、setOnCompletionListener(MediaPlayer.OnCompletionListener listener):为MediaPlayer的播放完成事件绑定监听
			
			2、setOnErrorListener(MediaPlayer.OnErrorListener listener):为MediaPlayer的播放错误事件绑定监听器。
			
			3、setOnPreparedListener( MediaPlayer.OnpreparedListener listener):当MediaPlayer调用prepare()方法时触发该监听
			
			4、setOnSeekCompleteListener(MediaPlayer.OnSeekCompleteListener listener):当MediaPlayer调用seek()方法时触发该监听
三、MediaPlayer的常用方法
	​start();//开始播放
	​pause();//暂停播放
	​reset()//清空MediaPlayer中的数据
	​setLooping(boolean);//设置是否循环播放
	​seekTo(msec)//定位到音频数据的位置,单位毫秒
	​stop();//停止播放
	​relase();//释放资源
	getDuration();//总时长
	getCurrentPosition();//当前位置
四、MediaPlayer播放不同来源的音频文件

1.播放Raw文件夹下面音频的元数据

		//直接创建,不需要设置setDataSource
		MediaPlayer mMediaPlayer;
		mMediaPlayer=MediaPlayer.create(this, R.raw.audio); 
		mMediaPlayer.start();

2.播放assets文件夹下面音频的元数据

		//需将资源文件放在assets文件夹
		 AssetFileDescriptor fd = getAssets().openFd("samsara.mp3");
		 mMediaPlayer.setDataSource(fd.getFileDescriptor());
		 或
		 //mMediaPlayer.setDataSource(fd.getFileDescriptor(),fd.getStartOffset(),fd.getLength())
		 mMediaPlayer.prepare() ;

		setDataSource(String path)
		设置完数据源,不要忘记prepare(),尽量使用异步prepareAync(),这样不会阻塞UI线程

3.播放外部存储器上的文件

		//如果从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) ;

4,播放网络数据

		//如果从网络加载音乐,如果是从网络中加载那么需要设置网络权限
		//<uses-permission android:name="android.permission.INTERNET"/>
		mMediaPlayer.setDataSource("http://..../xxx.mp3") ;
		//需使用异步缓冲
		mMediaPlayer.prepareAsync() ;

5.播放通过ContentProvider获取的数据

setDataSource(Context context,Uri uri)
SoundPool播放音频

1. 创建一个SoundPool (构造函数)

	public SoundPool(int maxStream, int streamType, int srcQuality) 
		maxStream —— 同时播放的流的最大数量
		streamType —— 流的类型,一般为STREAM_MUSIC(具体在AudioManager类中列出)
		srcQuality —— 采样率转化质量,当前无效果,使用0作为默认值


	初始化一个实例:
		SoundPool soundPool = new SoundPool(5, AudioManager.STREAM_MUSIC, 0); 
		创建了一个最多支持5个流同时播放的,类型标记为音乐的SoundPool。

2. 加载音频资源

	int load(AssetFileDescriptor afd, int priority) 
	通过一个AssetFileDescriptor对象
	
	int load(Context context, int resId, int priority) 
	通过一个资源ID
	
	int load(String path, int priority) 
	通过指定的路径加载
	
	int load(FileDescriptor fd, long offset, long length, int priority) 
	通过FileDescriptor加载

	其中的priority参数目前没有效果,建议设置为1。 

	一个SoundPool能同时管理多个音频,所以可以通过多次调用load函数来记载,如果记载成功将返回一个非0的soundID ,用于播放时指定特定的音频。

3. 播放控制

	final int play(int soundID, float leftVolume, float rightVolume, int priority, int loop, float rate) 
	播放指定音频的音效,并返回一个streamID 。
    priority —— 流的优先级,值越大优先级高,影响当同时播放数量超出了最大支持数时SoundPool对该流的处理;
    loop —— 循环播放的次数,0为值播放一次,-1为无限循环,其他值为播放loop+1次(例如,3为一共播放4次).
    rate —— 播放的速率,范围0.5-2.0(0.5为一半速率,1.0为正常速率,2.0为两倍速率)
	
	final void pause(int streamID) 
	暂停指定播放流的音效(streamID 应通过play()返回)。
	
	final void resume(int streamID) 
	继续播放指定播放流的音效(streamID 应通过play()返回)。
	
	final void stop(int streamID) 
	终止指定播放流的音效(streamID 应通过play()返回)。



	这里需要注意的是, 
		1.play()函数传递的是一个load()返回的soundID——指向一个被记载的音频资源 ,如果播放成功则返回一个非0的streamID——指向一个成功播放的流 ;
			同一个soundID 可以通过多次调用play()而获得多个不同的streamID (只要不超出同时播放的最大数量);
		2.pause()、resume()和stop()是针对播放流操作的,传递的是play()返回的streamID ;
		3.play()中的priority参数,只在同时播放的流的数量超过了预先设定的最大数量才起作用,管理器将自动终止优先级低的播放流。
			如果存在多个同样优先级的流,再进一步根据其创建事件来处理,新创建的流的年龄是最小的,将被终止;
		4.无论如何,程序退出时,手动终止播放并释放资源是必要的。

4. 更多属性设置

	final void setLoop(int streamID, int loop) 
	设置指定播放流的循环.
	
	final void setVolume(int streamID, float leftVolume, float rightVolume) 
	设置指定播放流的音量.
	
	final void setPriority(int streamID, int priority) 
	设置指定播放流的优先级,上面已说明priority的作用.
	
	final void setRate(int streamID, float rate) 
	设置指定播放流的速率,0.5-2.0.

5. 释放资源

	final boolean unload(int soundID) 
	卸载一个指定的音频资源.
	
	final void release() 
	释放SoundPool中的所有音频资源.

总结:

	1.管理多个音频资源,通过load()函数,成功则返回非0的soundID;
	2.同时播放多个音频,通过play()函数,成功则返回非0的streamID;
	3.pause()、resume()和stop()等操作是针对streamID(播放流)的;
	4.当设置为无限循环时,需要手动调用stop()来终止播放;
	5.播放流的优先级(play()中的priority参数),只在同时播放数超过设定的最大数时起作用;
	6.程序中不用考虑(play触发的)播放流的生命周期,无效的soundID/streamID不会导致程序错误。

示例代码:

	SoundPool sp;
	HashMap<Integer, Integer> sounddata;
	Context mcontext;
	Boolean isLoaded;

	//初始化声音
	public void InitSound() {
					 sp = new SoundPool(5, AudioManager.STREAM_MUSIC, 0);
					 sounddata = new HashMap<Integer, Integer>();
					 sounddata.put(1, sp.load(this, R.raw.mp31, 1));
					 sounddata.put(2, sp.load(this, R.raw.mp32, 1));
			  sp.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener(){
					@Override 
					public void onLoadComplete(SoundPool sound,int sampleId,int status){
						isLoaded=true;
						Toast.makeText(mcontext, 
								"音效加载完成!",
								Toast.LENGTH_SHORT);
				  }
			  });
			}

	……
		public void playSound(int sound, int number) {
			AudioManager am = (AudioManager) this
					.getSystemService(Context.AUDIO_SERVICE);
			float audioMaxVolumn = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
			float volumnCurrent = am.getStreamVolume(AudioManager.STREAM_MUSIC);
			float volumnRatio = volumnCurrent / audioMaxVolumn;

			sp.play(sounddata.get(sound),   
					volumnRatio,// 左声道音量  
					volumnRatio,// 右声道音量  
					1, // 优先级  
					number,// 循环播放次数  
					1);// 回放速度,该值在0.5-2.0之间 1为正常速度  
		}

	……

	//2.播放声音
	 if(isLoaded==true)
		playSound(1,1);
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)

实例代码:

	/**
	 * 播放来电铃声的默认音乐
	*/
	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"/>
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值